From 4e3d290c780cd8bf17ce41b5c5271b7e791f8eb5 Mon Sep 17 00:00:00 2001 From: Tinkerer Date: Sun, 5 Oct 2025 11:39:06 -0700 Subject: [PATCH] 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" + ] +}