From 4e3d290c780cd8bf17ce41b5c5271b7e791f8eb5 Mon Sep 17 00:00:00 2001 From: Tinkerer Date: Sun, 5 Oct 2025 11:39:06 -0700 Subject: [PATCH 1/5] Create "pico2-ice" target board This board has an rp2350b chip on it, as well as a Lattice Semiconductor iCE40UP5K FPGA. More details of this open hardware board here: https://pico2-ice.tinyvision.ai/ Tested on a pico2-ice board with: ~/go/bin/tinygo flash -target=pico2-ice src/examples/blinky1/blinky1.go which blinks the GREEN LED (connected to GPIO0) on this board. Signed-off-by: Tinkerer --- src/machine/board_pico2_ice.go | 152 +++++++++++++++++++++++++++++++ src/machine/machine_rp2_2040.go | 25 +++++ src/machine/machine_rp2_2350a.go | 27 ++++++ src/machine/machine_rp2_2350b.go | 27 ++++++ src/machine/machine_rp2_spi.go | 22 +---- targets/pico2-ice.json | 11 +++ 6 files changed, 244 insertions(+), 20 deletions(-) create mode 100644 src/machine/board_pico2_ice.go create mode 100644 targets/pico2-ice.json diff --git a/src/machine/board_pico2_ice.go b/src/machine/board_pico2_ice.go new file mode 100644 index 0000000000..cc84191821 --- /dev/null +++ b/src/machine/board_pico2_ice.go @@ -0,0 +1,152 @@ +//go:build pico2_ice + +// Most of the info is from +// https://pico2-ice.tinyvision.ai/md_pinout.html although +// (2025-09-07) RP4 appears twice in that pinout - the schematic is +// more clear. Consistent with other RPi boards, we use GPn instead of +// RPn to reference the RPi connected pins. + +package machine + +// GPIO pins +const ( + GP0 Pin = GPIO0 + GP1 Pin = GPIO1 + GP2 Pin = GPIO2 + GP3 Pin = GPIO3 + GP4 Pin = GPIO4 + GP5 Pin = GPIO5 + GP6 Pin = GPIO6 + GP7 Pin = GPIO7 + GP8 Pin = GPIO8 + GP9 Pin = GPIO9 + GP10 Pin = GPIO10 + GP11 Pin = GPIO11 + GP12 Pin = GPIO12 + GP13 Pin = GPIO13 + GP14 Pin = GPIO14 + GP15 Pin = GPIO15 + GP16 Pin = GPIO16 + GP17 Pin = GPIO17 + GP18 Pin = GPIO18 + GP19 Pin = GPIO19 + GP20 Pin = GPIO20 + GP21 Pin = GPIO21 + GP22 Pin = GPIO22 + GP23 Pin = GPIO23 + GP24 Pin = GPIO24 + GP25 Pin = GPIO25 + GP26 Pin = GPIO26 + GP27 Pin = GPIO27 + GP28 Pin = GPIO28 + GP29 Pin = GPIO29 + GP30 Pin = 30 + GP31 Pin = 31 + GP32 Pin = 32 + GP33 Pin = 33 + GP34 Pin = 34 + GP35 Pin = 35 + GP36 Pin = 36 + GP37 Pin = 37 + GP38 Pin = 38 + GP39 Pin = 39 + GP40 Pin = 40 + GP41 Pin = 41 + GP42 Pin = 42 + GP43 Pin = 43 + GP44 Pin = 44 + GP45 Pin = 45 + GP46 Pin = 46 + GP47 Pin = 47 + + // RPi pins shared with ICE + ICE9 = GP28 + ICE11 = GP29 + ICE14 = GP7 + ICE15 = GP6 + ICE16 = GP5 + ICE17 = GP4 + ICE18 = GP27 + ICE19 = GP23 + ICE20 = GP22 + ICE21 = GP26 + ICE23 = GP25 + ICE25 = GP30 + ICE26 = GP24 + ICE27 = GP20 + + // FPGA Clock pin. + ICE35_G0 = GP21 + + // Silkscreen & Pinout names + ICE_SSN = ICE16 + ICE_SO = ICE14 + ICE_SI = ICE17 + ICE_CK = ICE15 + FPGA_RSTN = GP31 + ICE_DONE = GP40 + USB_BOOT = GP42 + + // Button + SW1 = GP42 + BOOTSEL = GP42 + + // Tricolor LEDs + RED Pin = GP1 + GREEN Pin = GP0 + BLUE Pin = GP9 + + // Onboard LED + LED Pin = GREEN + + // Onboard crystal oscillator frequency, in MHz. + xoscFreq = 12 // MHz +) + +// This board does not define default i2c pins. +const ( + I2C0_SDA_PIN Pin = 0 + I2C0_SCL_PIN Pin = 0 + I2C1_SDA_PIN Pin = 0 + I2C1_SCL_PIN Pin = 0 +) + +// SPI default pins +const ( + // Default Serial Clock Bus 0 for SPI communications + SPI0_SCK_PIN = GPIO18 + // Default Serial Out Bus 0 for SPI communications + SPI0_SDO_PIN = GPIO19 // Tx + // Default Serial In Bus 0 for SPI communications + SPI0_SDI_PIN = GPIO16 // Rx + + // Default Serial Clock Bus 1 for SPI communications + SPI1_SCK_PIN = GPIO10 + // Default Serial Out Bus 1 for SPI communications + SPI1_SDO_PIN = GPIO11 // Tx + // Default Serial In Bus 1 for SPI communications + SPI1_SDI_PIN = GPIO12 // Rx +) + +// UART pins +const ( + UART0_TX_PIN = GPIO0 + UART0_RX_PIN = GPIO1 + UART1_TX_PIN = GPIO8 + UART1_RX_PIN = GPIO9 + UART_TX_PIN = UART0_TX_PIN + UART_RX_PIN = UART0_RX_PIN +) + +var DefaultUART = UART0 + +// USB identifiers +const ( + usb_STRING_PRODUCT = "Pico2" + usb_STRING_MANUFACTURER = "Raspberry Pi" +) + +var ( + usb_VID uint16 = 0x2E8A + usb_PID uint16 = 0x000A +) diff --git a/src/machine/machine_rp2_2040.go b/src/machine/machine_rp2_2040.go index 9cdb3a072e..78336a3b76 100644 --- a/src/machine/machine_rp2_2040.go +++ b/src/machine/machine_rp2_2040.go @@ -124,6 +124,31 @@ const ( fnXIP pinFunc = 0 ) +// validPins confirms that the SPI pin selection is a legitimate one +// for the the 2040 chip. +func (spi *SPI) validPins(config SPIConfig) error { + var okSDI, okSDO, okSCK bool + switch spi.Bus { + case rp.SPI0: + okSDI = config.SDI == 0 || config.SDI == 4 || config.SDI == 16 || config.SDI == 20 + okSDO = config.SDO == 3 || config.SDO == 7 || config.SDO == 19 || config.SDO == 23 + okSCK = config.SCK == 2 || config.SCK == 6 || config.SCK == 18 || config.SCK == 22 + case rp.SPI1: + okSDI = config.SDI == 8 || config.SDI == 12 || config.SDI == 24 || config.SDI == 28 + okSDO = config.SDO == 11 || config.SDO == 15 || config.SDO == 27 + okSCK = config.SCK == 10 || config.SCK == 14 || config.SCK == 26 + } + switch { + case !okSDI: + return errSPIInvalidSDI + case !okSDO: + return errSPIInvalidSDO + case !okSCK: + return errSPIInvalidSCK + } + return nil +} + // Configure configures the gpio pin as per mode. func (p Pin) Configure(config PinConfig) { if p == NoPin { diff --git a/src/machine/machine_rp2_2350a.go b/src/machine/machine_rp2_2350a.go index 09ec8a1190..6918d22978 100644 --- a/src/machine/machine_rp2_2350a.go +++ b/src/machine/machine_rp2_2350a.go @@ -2,6 +2,8 @@ package machine +import "device/rp" + // Analog pins on RP2350a. const ( ADC0 Pin = GPIO26 @@ -12,3 +14,28 @@ const ( // fifth ADC channel. thermADC = 30 ) + +// validPins confirms that the SPI pin selection is a legitimate one +// for the the 2350a chip. +func (spi *SPI) validPins(config SPIConfig) error { + var okSDI, okSDO, okSCK bool + switch spi.Bus { + case rp.SPI0: + okSDI = config.SDI == 0 || config.SDI == 4 || config.SDI == 16 || config.SDI == 20 + okSDO = config.SDO == 3 || config.SDO == 7 || config.SDO == 19 || config.SDO == 23 + okSCK = config.SCK == 2 || config.SCK == 6 || config.SCK == 18 || config.SCK == 22 + case rp.SPI1: + okSDI = config.SDI == 8 || config.SDI == 12 || config.SDI == 24 || config.SDI == 28 + okSDO = config.SDO == 11 || config.SDO == 15 || config.SDO == 27 + okSCK = config.SCK == 10 || config.SCK == 14 || config.SCK == 26 + } + switch { + case !okSDI: + return errSPIInvalidSDI + case !okSDO: + return errSPIInvalidSDO + case !okSCK: + return errSPIInvalidSCK + } + return nil +} diff --git a/src/machine/machine_rp2_2350b.go b/src/machine/machine_rp2_2350b.go index 0fb5893f31..5f5a76da67 100644 --- a/src/machine/machine_rp2_2350b.go +++ b/src/machine/machine_rp2_2350b.go @@ -2,6 +2,8 @@ package machine +import "device/rp" + // RP2350B has additional pins. const ( @@ -46,3 +48,28 @@ var ( PWM10 = getPWMGroup(10) PWM11 = getPWMGroup(11) ) + +// validPins confirms that the SPI pin selection is a legitimate one +// for the the 2350b chip. +func (spi *SPI) validPins(config SPIConfig) error { + var okSDI, okSDO, okSCK bool + switch spi.Bus { + case rp.SPI0: + okSDI = config.SDI == 0 || config.SDI == 4 || config.SDI == 16 || config.SDI == 20 || config.SDI == 32 || config.SDI == 36 + okSDO = config.SDO == 3 || config.SDO == 7 || config.SDO == 19 || config.SDO == 23 || config.SDO == 35 || config.SDO == 39 + okSCK = config.SCK == 2 || config.SCK == 6 || config.SCK == 18 || config.SCK == 22 || config.SCK == 34 || config.SCK == 38 + case rp.SPI1: + okSDI = config.SDI == 8 || config.SDI == 12 || config.SDI == 24 || config.SDI == 28 || config.SDI == 40 || config.SDI == 44 + okSDO = config.SDO == 11 || config.SDO == 15 || config.SDO == 27 || config.SDO == 31 || config.SDO == 43 || config.SDO == 47 + okSCK = config.SCK == 10 || config.SCK == 14 || config.SCK == 26 || config.SCK == 30 || config.SCK == 42 || config.SCK == 46 + } + switch { + case !okSDI: + return errSPIInvalidSDI + case !okSDO: + return errSPIInvalidSDO + case !okSCK: + return errSPIInvalidSCK + } + return nil +} diff --git a/src/machine/machine_rp2_spi.go b/src/machine/machine_rp2_spi.go index d9cfc11d18..b64309fcc1 100644 --- a/src/machine/machine_rp2_spi.go +++ b/src/machine/machine_rp2_spi.go @@ -165,27 +165,9 @@ func (spi *SPI) Configure(config SPIConfig) error { config.SDI = SPI1_SDI_PIN } } - var okSDI, okSDO, okSCK bool - switch spi.Bus { - case rp.SPI0: - okSDI = config.SDI == 0 || config.SDI == 4 || config.SDI == 16 || config.SDI == 20 - okSDO = config.SDO == 3 || config.SDO == 7 || config.SDO == 19 || config.SDO == 23 - okSCK = config.SCK == 2 || config.SCK == 6 || config.SCK == 18 || config.SCK == 22 - case rp.SPI1: - okSDI = config.SDI == 8 || config.SDI == 12 || config.SDI == 24 || config.SDI == 28 - okSDO = config.SDO == 11 || config.SDO == 15 || config.SDO == 27 - okSCK = config.SCK == 10 || config.SCK == 14 || config.SCK == 26 + if err := spi.validPins(config); err != nil { + return err } - - switch { - case !okSDI: - return errSPIInvalidSDI - case !okSDO: - return errSPIInvalidSDO - case !okSCK: - return errSPIInvalidSCK - } - if config.Frequency == 0 { config.Frequency = defaultBaud } diff --git a/targets/pico2-ice.json b/targets/pico2-ice.json new file mode 100644 index 0000000000..379d531207 --- /dev/null +++ b/targets/pico2-ice.json @@ -0,0 +1,11 @@ +{ + "inherits": [ + "rp2350b" + ], + "build-tags": ["pico2_ice"], + "serial-port": ["2e8a:000A"], + "default-stack-size": 8192, + "ldflags": [ + "--defsym=__flash_size=4M" + ] +} From 72e19f50c33f49b35a39202f080b8b292a62c941 Mon Sep 17 00:00:00 2001 From: Tinkerer Date: Wed, 8 Oct 2025 21:24:40 -0700 Subject: [PATCH 2/5] More silkscreen labels for pico2-ice board Reading the schematic and the rev2 board viewer: https://raw.githubusercontent.com/tinyvision-ai-inc/pico2-ice/refs/heads/main/Board/Rev2/bom/ibom.html concluded that the RP2350B GPIO pins are not labeled with these pin numbers in the silkscreen. Instead, the silkscreen refers to uses of the GPIOs or the ICE numbered pins. RP2340B devoted pins map to the A1..4 B1..4 pins on the RP PMOD connector. Also silkscreen "~0".."~6" are labeled as pins N0..N6. Signed-off-by: Tinkerer --- src/machine/board_pico2_ice.go | 35 +++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/machine/board_pico2_ice.go b/src/machine/board_pico2_ice.go index cc84191821..0806d4f57d 100644 --- a/src/machine/board_pico2_ice.go +++ b/src/machine/board_pico2_ice.go @@ -59,7 +59,8 @@ const ( GP46 Pin = 46 GP47 Pin = 47 - // RPi pins shared with ICE + // RPi pins shared with ICE. The ICE number is what appears on + // the board silkscreen. ICE9 = GP28 ICE11 = GP29 ICE14 = GP7 @@ -79,13 +80,33 @@ const ( ICE35_G0 = GP21 // Silkscreen & Pinout names - ICE_SSN = ICE16 - ICE_SO = ICE14 - ICE_SI = ICE17 - ICE_CK = ICE15 + ICE_SSN = ICE16 + ICE_SO = ICE14 + ICE_SI = ICE17 + ICE_CK = ICE15 + SD = GP2 + SC = GP3 + FPGA_RSTN = GP31 - ICE_DONE = GP40 - USB_BOOT = GP42 + A3 = GP32 + A1 = GP33 + A4 = GP34 + A2 = GP35 + B3 = GP36 + B1 = GP37 + B4 = GP38 + B2 = GP39 + N0 = GP40 // On the board these are labeled "~0" + N1 = GP41 + N2 = GP42 + N3 = GP43 + N4 = GP44 + N5 = GP45 + N6 = GP46 + + // Functions from Schematic. + ICE_DONE = GP40 + USB_BOOT = GP42 // Button SW1 = GP42 From 1701bda17fcb23894d94996e28f6d13e8d93f359 Mon Sep 17 00:00:00 2001 From: Tinkerer Date: Fri, 10 Oct 2025 20:36:07 -0700 Subject: [PATCH 3/5] Added a smoketest for pico2-ice board and tidied up GPIO defs Addresses review comments from aykevl. Signed-off-by: Tinkerer --- GNUmakefile | 2 + src/machine/board_pico2_ice.go | 112 ++++++++++++++++----------------- 2 files changed, 58 insertions(+), 56 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 962b2e2613..e3c1cbf2e9 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -621,6 +621,8 @@ smoketest: testchdir @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/device-id @$(MD5SUM) test.hex + $(TINYGO) build -size short -o test.hex -target=pico2-ice examples/blinky1 + @$(MD5SUM) test.hex # test simulated boards on play.tinygo.org ifneq ($(WASM), 0) GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1 diff --git a/src/machine/board_pico2_ice.go b/src/machine/board_pico2_ice.go index 0806d4f57d..de3b9845b9 100644 --- a/src/machine/board_pico2_ice.go +++ b/src/machine/board_pico2_ice.go @@ -10,54 +10,54 @@ package machine // GPIO pins const ( - GP0 Pin = GPIO0 - GP1 Pin = GPIO1 - GP2 Pin = GPIO2 - GP3 Pin = GPIO3 - GP4 Pin = GPIO4 - GP5 Pin = GPIO5 - GP6 Pin = GPIO6 - GP7 Pin = GPIO7 - GP8 Pin = GPIO8 - GP9 Pin = GPIO9 - GP10 Pin = GPIO10 - GP11 Pin = GPIO11 - GP12 Pin = GPIO12 - GP13 Pin = GPIO13 - GP14 Pin = GPIO14 - GP15 Pin = GPIO15 - GP16 Pin = GPIO16 - GP17 Pin = GPIO17 - GP18 Pin = GPIO18 - GP19 Pin = GPIO19 - GP20 Pin = GPIO20 - GP21 Pin = GPIO21 - GP22 Pin = GPIO22 - GP23 Pin = GPIO23 - GP24 Pin = GPIO24 - GP25 Pin = GPIO25 - GP26 Pin = GPIO26 - GP27 Pin = GPIO27 - GP28 Pin = GPIO28 - GP29 Pin = GPIO29 - GP30 Pin = 30 - GP31 Pin = 31 - GP32 Pin = 32 - GP33 Pin = 33 - GP34 Pin = 34 - GP35 Pin = 35 - GP36 Pin = 36 - GP37 Pin = 37 - GP38 Pin = 38 - GP39 Pin = 39 - GP40 Pin = 40 - GP41 Pin = 41 - GP42 Pin = 42 - GP43 Pin = 43 - GP44 Pin = 44 - GP45 Pin = 45 - GP46 Pin = 46 - GP47 Pin = 47 + GP0 = GPIO0 + GP1 = GPIO1 + GP2 = GPIO2 + GP3 = GPIO3 + GP4 = GPIO4 + GP5 = GPIO5 + GP6 = GPIO6 + GP7 = GPIO7 + GP8 = GPIO8 + GP9 = GPIO9 + GP10 = GPIO10 + GP11 = GPIO11 + GP12 = GPIO12 + GP13 = GPIO13 + GP14 = GPIO14 + GP15 = GPIO15 + GP16 = GPIO16 + GP17 = GPIO17 + GP18 = GPIO18 + GP19 = GPIO19 + GP20 = GPIO20 + GP21 = GPIO21 + GP22 = GPIO22 + GP23 = GPIO23 + GP24 = GPIO24 + GP25 = GPIO25 + GP26 = GPIO26 + GP27 = GPIO27 + GP28 = GPIO28 + GP29 = GPIO29 + GP30 = GPIO30 + GP31 = GPIO31 + GP32 = GPIO32 + GP33 = GPIO33 + GP34 = GPIO34 + GP35 = GPIO35 + GP36 = GPIO36 + GP37 = GPIO37 + GP38 = GPIO38 + GP39 = GPIO39 + GP40 = GPIO40 + GP41 = GPIO41 + GP42 = GPIO42 + GP43 = GPIO43 + GP44 = GPIO44 + GP45 = GPIO45 + GP46 = GPIO46 + GP47 = GPIO47 // RPi pins shared with ICE. The ICE number is what appears on // the board silkscreen. @@ -113,12 +113,12 @@ const ( BOOTSEL = GP42 // Tricolor LEDs - RED Pin = GP1 - GREEN Pin = GP0 - BLUE Pin = GP9 + LED_RED = GP1 + LED_GREEN = GP0 + LED_BLUE = GP9 // Onboard LED - LED Pin = GREEN + LED = LED_GREEN // Onboard crystal oscillator frequency, in MHz. xoscFreq = 12 // MHz @@ -126,10 +126,10 @@ const ( // This board does not define default i2c pins. const ( - I2C0_SDA_PIN Pin = 0 - I2C0_SCL_PIN Pin = 0 - I2C1_SDA_PIN Pin = 0 - I2C1_SCL_PIN Pin = 0 + I2C0_SDA_PIN = NoPin + I2C0_SCL_PIN = NoPin + I2C1_SDA_PIN = NoPin + I2C1_SCL_PIN = NoPin ) // SPI default pins From a582f7740007b57625a98c1e052a1addf3e1e4f8 Mon Sep 17 00:00:00 2001 From: tinkerator Date: Sat, 11 Oct 2025 09:03:26 -0700 Subject: [PATCH 4/5] Update GNUmakefile Co-authored-by: Ayke --- GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GNUmakefile b/GNUmakefile index e3c1cbf2e9..0d1f98fc25 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -621,7 +621,7 @@ smoketest: testchdir @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/device-id @$(MD5SUM) test.hex - $(TINYGO) build -size short -o test.hex -target=pico2-ice examples/blinky1 + $(TINYGO) build -size short -o test.hex -target=pico2-ice examples/blinky1 @$(MD5SUM) test.hex # test simulated boards on play.tinygo.org ifneq ($(WASM), 0) From 8b0ea1cfb467551f49c23b2ab501ff2e81ae95c4 Mon Sep 17 00:00:00 2001 From: Ayke Date: Mon, 13 Oct 2025 13:17:06 +0200 Subject: [PATCH 5/5] Update GNUmakefile --- GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GNUmakefile b/GNUmakefile index 0d1f98fc25..b29b0952e4 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -621,7 +621,7 @@ smoketest: testchdir @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/device-id @$(MD5SUM) test.hex - $(TINYGO) build -size short -o test.hex -target=pico2-ice examples/blinky1 + $(TINYGO) build -size short -o test.hex -target=pico2-ice examples/blinky1 @$(MD5SUM) test.hex # test simulated boards on play.tinygo.org ifneq ($(WASM), 0)