From 562b4c50202a7f1cc36a2f1b02248b35f8812791 Mon Sep 17 00:00:00 2001 From: tinkerator Date: Mon, 13 Oct 2025 04:19:04 -0700 Subject: [PATCH] Create "pico2-ice" target board (#5062) * 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 * 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 * 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 | 173 +++++++++++++++++++++++++++++++ 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 ++ 7 files changed, 267 insertions(+), 20 deletions(-) create mode 100644 src/machine/board_pico2_ice.go create mode 100644 targets/pico2-ice.json diff --git a/GNUmakefile b/GNUmakefile index 962b2e261..b29b0952e 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 new file mode 100644 index 000000000..de3b9845b --- /dev/null +++ b/src/machine/board_pico2_ice.go @@ -0,0 +1,173 @@ +//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 = 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. + 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 + SD = GP2 + SC = GP3 + + FPGA_RSTN = GP31 + 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 + BOOTSEL = GP42 + + // Tricolor LEDs + LED_RED = GP1 + LED_GREEN = GP0 + LED_BLUE = GP9 + + // Onboard LED + LED = LED_GREEN + + // Onboard crystal oscillator frequency, in MHz. + xoscFreq = 12 // MHz +) + +// This board does not define default i2c pins. +const ( + I2C0_SDA_PIN = NoPin + I2C0_SCL_PIN = NoPin + I2C1_SDA_PIN = NoPin + I2C1_SCL_PIN = NoPin +) + +// 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 9cdb3a072..78336a3b7 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 09ec8a119..6918d2297 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 0fb5893f3..5f5a76da6 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 693b9ab3f..759f84b79 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 000000000..379d53120 --- /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" + ] +}