Skip to content

Commit 37f35f8

Browse files
soypatcibomahtodeadprogram
authored
Add RP2350 support (#4459)
machine/rp2350: add support * add linker scripts for rp2350 * add bootloader * begin melding rp2040 and rp2350 APIs * add UART * add rp2350 boot patching * Fix RP2350 memory layout (#4626) * Remove rp2040-style second stage bootloader. * Add 'minimum viable' IMAGE_DEF embedded block * Create a pico2 specific target * Implement rp2350 init, clock, and uart support * Merge rp2 reset code back together * Separate chip-specific clock definitions * Clear pad isolation bit on rp2350 * Init UART in rp2350 runtime * Correct usb/serial initialization order * Implement jump-to-bootloader * test: add pico2 to smoketests --------- Signed-off-by: deadprogram <[email protected]> Co-authored-by: Matthew Mets <[email protected]> Co-authored-by: Matt Mets <[email protected]> Co-authored-by: deadprogram <[email protected]>
1 parent 0d13e61 commit 37f35f8

33 files changed

+1349
-294
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,9 @@ test.exe
3737
test.gba
3838
test.hex
3939
test.nro
40+
test.uf2
4041
test.wasm
4142
wasm.wasm
43+
44+
*.uf2
45+
*.elf

GNUmakefile

+2
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,8 @@ endif
741741
@$(MD5SUM) test.hex
742742
$(TINYGO) build -size short -o test.hex -target=thumby examples/echo
743743
@$(MD5SUM) test.hex
744+
$(TINYGO) build -size short -o test.hex -target=pico2 examples/blinky1
745+
@$(MD5SUM) test.hex
744746
# test pwm
745747
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
746748
@$(MD5SUM) test.hex

builder/build.go

+31-1
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,12 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
822822
return fmt.Errorf("could not modify stack sizes: %w", err)
823823
}
824824
}
825+
826+
// Apply patches of bootloader in the order they appear.
827+
if len(config.Target.BootPatches) > 0 {
828+
err = applyPatches(result.Executable, config.Target.BootPatches)
829+
}
830+
825831
if config.RP2040BootPatch() {
826832
// Patch the second stage bootloader CRC into the .boot2 section
827833
err = patchRP2040BootCRC(result.Executable)
@@ -1434,6 +1440,23 @@ func printStacks(calculatedStacks []string, stackSizes map[string]functionStackS
14341440
}
14351441
}
14361442

1443+
func applyPatches(executable string, bootPatches []string) (err error) {
1444+
for _, patch := range bootPatches {
1445+
switch patch {
1446+
case "rp2040":
1447+
err = patchRP2040BootCRC(executable)
1448+
// case "rp2350":
1449+
// err = patchRP2350BootIMAGE_DEF(executable)
1450+
default:
1451+
err = errors.New("undefined boot patch name")
1452+
}
1453+
if err != nil {
1454+
return fmt.Errorf("apply boot patch %q: %w", patch, err)
1455+
}
1456+
}
1457+
return nil
1458+
}
1459+
14371460
// RP2040 second stage bootloader CRC32 calculation
14381461
//
14391462
// Spec: https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf
@@ -1445,7 +1468,7 @@ func patchRP2040BootCRC(executable string) error {
14451468
}
14461469

14471470
if len(bytes) != 256 {
1448-
return fmt.Errorf("rp2040 .boot2 section must be exactly 256 bytes")
1471+
return fmt.Errorf("rp2040 .boot2 section must be exactly 256 bytes, got %d", len(bytes))
14491472
}
14501473

14511474
// From the 'official' RP2040 checksum script:
@@ -1484,3 +1507,10 @@ func lock(path string) func() {
14841507

14851508
return func() { flock.Close() }
14861509
}
1510+
1511+
func b2u8(b bool) uint8 {
1512+
if b {
1513+
return 1
1514+
}
1515+
return 0
1516+
}

compileopts/target.go

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type TargetSpec struct {
4646
LinkerScript string `json:"linkerscript,omitempty"`
4747
ExtraFiles []string `json:"extra-files,omitempty"`
4848
RP2040BootPatch *bool `json:"rp2040-boot-patch,omitempty"` // Patch RP2040 2nd stage bootloader checksum
49+
BootPatches []string `json:"boot-patches,omitempty"` // Bootloader patches to be applied in the order they appear.
4950
Emulator string `json:"emulator,omitempty"`
5051
FlashCommand string `json:"flash-command,omitempty"`
5152
GDB []string `json:"gdb,omitempty"`

src/machine/board_pico2.go

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//go:build pico2
2+
3+
package machine
4+
5+
// GPIO pins
6+
const (
7+
GP0 Pin = GPIO0
8+
GP1 Pin = GPIO1
9+
GP2 Pin = GPIO2
10+
GP3 Pin = GPIO3
11+
GP4 Pin = GPIO4
12+
GP5 Pin = GPIO5
13+
GP6 Pin = GPIO6
14+
GP7 Pin = GPIO7
15+
GP8 Pin = GPIO8
16+
GP9 Pin = GPIO9
17+
GP10 Pin = GPIO10
18+
GP11 Pin = GPIO11
19+
GP12 Pin = GPIO12
20+
GP13 Pin = GPIO13
21+
GP14 Pin = GPIO14
22+
GP15 Pin = GPIO15
23+
GP16 Pin = GPIO16
24+
GP17 Pin = GPIO17
25+
GP18 Pin = GPIO18
26+
GP19 Pin = GPIO19
27+
GP20 Pin = GPIO20
28+
GP21 Pin = GPIO21
29+
GP22 Pin = GPIO22
30+
GP26 Pin = GPIO26
31+
GP27 Pin = GPIO27
32+
GP28 Pin = GPIO28
33+
34+
// Onboard LED
35+
LED Pin = GPIO25
36+
37+
// Onboard crystal oscillator frequency, in MHz.
38+
xoscFreq = 12 // MHz
39+
)
40+
41+
// I2C Default pins on Raspberry Pico.
42+
const (
43+
I2C0_SDA_PIN = GP4
44+
I2C0_SCL_PIN = GP5
45+
46+
I2C1_SDA_PIN = GP2
47+
I2C1_SCL_PIN = GP3
48+
)
49+
50+
// SPI default pins
51+
const (
52+
// Default Serial Clock Bus 0 for SPI communications
53+
SPI0_SCK_PIN = GPIO18
54+
// Default Serial Out Bus 0 for SPI communications
55+
SPI0_SDO_PIN = GPIO19 // Tx
56+
// Default Serial In Bus 0 for SPI communications
57+
SPI0_SDI_PIN = GPIO16 // Rx
58+
59+
// Default Serial Clock Bus 1 for SPI communications
60+
SPI1_SCK_PIN = GPIO10
61+
// Default Serial Out Bus 1 for SPI communications
62+
SPI1_SDO_PIN = GPIO11 // Tx
63+
// Default Serial In Bus 1 for SPI communications
64+
SPI1_SDI_PIN = GPIO12 // Rx
65+
)
66+
67+
// UART pins
68+
const (
69+
UART0_TX_PIN = GPIO0
70+
UART0_RX_PIN = GPIO1
71+
UART1_TX_PIN = GPIO8
72+
UART1_RX_PIN = GPIO9
73+
UART_TX_PIN = UART0_TX_PIN
74+
UART_RX_PIN = UART0_RX_PIN
75+
)
76+
77+
var DefaultUART = UART0
78+
79+
// USB identifiers
80+
const (
81+
usb_STRING_PRODUCT = "Pico2"
82+
usb_STRING_MANUFACTURER = "Raspberry Pi"
83+
)
84+
85+
var (
86+
usb_VID uint16 = 0x2E8A
87+
usb_PID uint16 = 0x000A
88+
)

src/machine/machine_rp2040.go src/machine/machine_rp2.go

+53-15
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,55 @@
1-
//go:build rp2040
1+
//go:build rp2040 || rp2350
22

33
package machine
44

55
import (
66
"device/rp"
7+
"runtime/interrupt"
78
"runtime/volatile"
89
"unsafe"
910
)
1011

1112
const deviceName = rp.Device
1213

14+
const (
15+
// Number of spin locks available
16+
// Note: On RP2350, most spinlocks are unusable due to Errata 2
17+
_NUMSPINLOCKS = 32
18+
_PICO_SPINLOCK_ID_IRQ = 9
19+
)
20+
21+
// UART on the RP2040
22+
var (
23+
UART0 = &_UART0
24+
_UART0 = UART{
25+
Buffer: NewRingBuffer(),
26+
Bus: rp.UART0,
27+
}
28+
29+
UART1 = &_UART1
30+
_UART1 = UART{
31+
Buffer: NewRingBuffer(),
32+
Bus: rp.UART1,
33+
}
34+
)
35+
36+
func init() {
37+
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
38+
UART1.Interrupt = interrupt.New(rp.IRQ_UART1_IRQ, _UART1.handleInterrupt)
39+
}
40+
1341
//go:linkname machineInit runtime.machineInit
1442
func machineInit() {
1543
// Reset all peripherals to put system into a known state,
1644
// except for QSPI pads and the XIP IO bank, as this is fatal if running from flash
1745
// and the PLLs, as this is fatal if clock muxing has not been reset on this boot
1846
// and USB, syscfg, as this disturbs USB-to-SWD on core 1
19-
bits := ^uint32(rp.RESETS_RESET_IO_QSPI |
20-
rp.RESETS_RESET_PADS_QSPI |
21-
rp.RESETS_RESET_PLL_USB |
22-
rp.RESETS_RESET_USBCTRL |
23-
rp.RESETS_RESET_SYSCFG |
24-
rp.RESETS_RESET_PLL_SYS)
47+
bits := ^uint32(initDontReset)
2548
resetBlock(bits)
2649

2750
// Remove reset from peripherals which are clocked only by clkSys and
2851
// clkRef. Other peripherals stay in reset until we've configured clocks.
29-
bits = ^uint32(rp.RESETS_RESET_ADC |
30-
rp.RESETS_RESET_RTC |
31-
rp.RESETS_RESET_SPI0 |
32-
rp.RESETS_RESET_SPI1 |
33-
rp.RESETS_RESET_UART0 |
34-
rp.RESETS_RESET_UART1 |
35-
rp.RESETS_RESET_USBCTRL)
52+
bits = ^uint32(initUnreset)
3653
unresetBlockWait(bits)
3754

3855
clocks.init()
@@ -94,4 +111,25 @@ const (
94111
)
95112

96113
// DMA channels usable on the RP2040.
97-
var dmaChannels = (*[12]dmaChannel)(unsafe.Pointer(rp.DMA))
114+
var dmaChannels = (*[12 + 4*rp2350ExtraReg]dmaChannel)(unsafe.Pointer(rp.DMA))
115+
116+
//go:inline
117+
func boolToBit(a bool) uint32 {
118+
if a {
119+
return 1
120+
}
121+
return 0
122+
}
123+
124+
//go:inline
125+
func u32max(a, b uint32) uint32 {
126+
if a > b {
127+
return a
128+
}
129+
return b
130+
}
131+
132+
//go:inline
133+
func isReservedI2CAddr(addr uint8) bool {
134+
return (addr&0x78) == 0 || (addr&0x78) == 0x78
135+
}

src/machine/machine_rp2040_i2c.go

-21
Original file line numberDiff line numberDiff line change
@@ -631,24 +631,3 @@ func (b i2cAbortError) Reasons() (reasons []string) {
631631
}
632632
return reasons
633633
}
634-
635-
//go:inline
636-
func boolToBit(a bool) uint32 {
637-
if a {
638-
return 1
639-
}
640-
return 0
641-
}
642-
643-
//go:inline
644-
func u32max(a, b uint32) uint32 {
645-
if a > b {
646-
return a
647-
}
648-
return b
649-
}
650-
651-
//go:inline
652-
func isReservedI2CAddr(addr uint8) bool {
653-
return (addr&0x78) == 0 || (addr&0x78) == 0x78
654-
}

src/machine/machine_rp2040_rtc.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func toAlarmTime(delay uint32) rtcTime {
9797

9898
func (rtc *rtcType) setDivider() {
9999
// Get clk_rtc freq and make sure it is running
100-
rtcFreq := configuredFreq[clkRTC]
100+
rtcFreq := configuredFreq[ClkRTC]
101101
if rtcFreq == 0 {
102102
panic("can not set RTC divider, clock is not running")
103103
}

0 commit comments

Comments
 (0)