Skip to content

Commit

Permalink
Add RP2350 support (#4459)
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
4 people authored Dec 18, 2024
1 parent 0d13e61 commit 37f35f8
Show file tree
Hide file tree
Showing 33 changed files with 1,349 additions and 294 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,9 @@ test.exe
test.gba
test.hex
test.nro
test.uf2
test.wasm
wasm.wasm

*.uf2
*.elf
2 changes: 2 additions & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,8 @@ endif
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=thumby examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pico2 examples/blinky1
@$(MD5SUM) test.hex
# test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex
Expand Down
32 changes: 31 additions & 1 deletion builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,12 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
return fmt.Errorf("could not modify stack sizes: %w", err)
}
}

// Apply patches of bootloader in the order they appear.
if len(config.Target.BootPatches) > 0 {
err = applyPatches(result.Executable, config.Target.BootPatches)
}

if config.RP2040BootPatch() {
// Patch the second stage bootloader CRC into the .boot2 section
err = patchRP2040BootCRC(result.Executable)
Expand Down Expand Up @@ -1434,6 +1440,23 @@ func printStacks(calculatedStacks []string, stackSizes map[string]functionStackS
}
}

func applyPatches(executable string, bootPatches []string) (err error) {
for _, patch := range bootPatches {
switch patch {
case "rp2040":
err = patchRP2040BootCRC(executable)
// case "rp2350":
// err = patchRP2350BootIMAGE_DEF(executable)
default:
err = errors.New("undefined boot patch name")
}
if err != nil {
return fmt.Errorf("apply boot patch %q: %w", patch, err)
}
}
return nil
}

// RP2040 second stage bootloader CRC32 calculation
//
// Spec: https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf
Expand All @@ -1445,7 +1468,7 @@ func patchRP2040BootCRC(executable string) error {
}

if len(bytes) != 256 {
return fmt.Errorf("rp2040 .boot2 section must be exactly 256 bytes")
return fmt.Errorf("rp2040 .boot2 section must be exactly 256 bytes, got %d", len(bytes))
}

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

return func() { flock.Close() }
}

func b2u8(b bool) uint8 {
if b {
return 1
}
return 0
}
1 change: 1 addition & 0 deletions compileopts/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type TargetSpec struct {
LinkerScript string `json:"linkerscript,omitempty"`
ExtraFiles []string `json:"extra-files,omitempty"`
RP2040BootPatch *bool `json:"rp2040-boot-patch,omitempty"` // Patch RP2040 2nd stage bootloader checksum
BootPatches []string `json:"boot-patches,omitempty"` // Bootloader patches to be applied in the order they appear.
Emulator string `json:"emulator,omitempty"`
FlashCommand string `json:"flash-command,omitempty"`
GDB []string `json:"gdb,omitempty"`
Expand Down
88 changes: 88 additions & 0 deletions src/machine/board_pico2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//go:build pico2

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
GP26 Pin = GPIO26
GP27 Pin = GPIO27
GP28 Pin = GPIO28

// Onboard LED
LED Pin = GPIO25

// Onboard crystal oscillator frequency, in MHz.
xoscFreq = 12 // MHz
)

// I2C Default pins on Raspberry Pico.
const (
I2C0_SDA_PIN = GP4
I2C0_SCL_PIN = GP5

I2C1_SDA_PIN = GP2
I2C1_SCL_PIN = GP3
)

// 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
)
68 changes: 53 additions & 15 deletions src/machine/machine_rp2040.go → src/machine/machine_rp2.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,55 @@
//go:build rp2040
//go:build rp2040 || rp2350

package machine

import (
"device/rp"
"runtime/interrupt"
"runtime/volatile"
"unsafe"
)

const deviceName = rp.Device

const (
// Number of spin locks available
// Note: On RP2350, most spinlocks are unusable due to Errata 2
_NUMSPINLOCKS = 32
_PICO_SPINLOCK_ID_IRQ = 9
)

// UART on the RP2040
var (
UART0 = &_UART0
_UART0 = UART{
Buffer: NewRingBuffer(),
Bus: rp.UART0,
}

UART1 = &_UART1
_UART1 = UART{
Buffer: NewRingBuffer(),
Bus: rp.UART1,
}
)

func init() {
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
UART1.Interrupt = interrupt.New(rp.IRQ_UART1_IRQ, _UART1.handleInterrupt)
}

//go:linkname machineInit runtime.machineInit
func machineInit() {
// Reset all peripherals to put system into a known state,
// except for QSPI pads and the XIP IO bank, as this is fatal if running from flash
// and the PLLs, as this is fatal if clock muxing has not been reset on this boot
// and USB, syscfg, as this disturbs USB-to-SWD on core 1
bits := ^uint32(rp.RESETS_RESET_IO_QSPI |
rp.RESETS_RESET_PADS_QSPI |
rp.RESETS_RESET_PLL_USB |
rp.RESETS_RESET_USBCTRL |
rp.RESETS_RESET_SYSCFG |
rp.RESETS_RESET_PLL_SYS)
bits := ^uint32(initDontReset)
resetBlock(bits)

// Remove reset from peripherals which are clocked only by clkSys and
// clkRef. Other peripherals stay in reset until we've configured clocks.
bits = ^uint32(rp.RESETS_RESET_ADC |
rp.RESETS_RESET_RTC |
rp.RESETS_RESET_SPI0 |
rp.RESETS_RESET_SPI1 |
rp.RESETS_RESET_UART0 |
rp.RESETS_RESET_UART1 |
rp.RESETS_RESET_USBCTRL)
bits = ^uint32(initUnreset)
unresetBlockWait(bits)

clocks.init()
Expand Down Expand Up @@ -94,4 +111,25 @@ const (
)

// DMA channels usable on the RP2040.
var dmaChannels = (*[12]dmaChannel)(unsafe.Pointer(rp.DMA))
var dmaChannels = (*[12 + 4*rp2350ExtraReg]dmaChannel)(unsafe.Pointer(rp.DMA))

//go:inline
func boolToBit(a bool) uint32 {
if a {
return 1
}
return 0
}

//go:inline
func u32max(a, b uint32) uint32 {
if a > b {
return a
}
return b
}

//go:inline
func isReservedI2CAddr(addr uint8) bool {
return (addr&0x78) == 0 || (addr&0x78) == 0x78
}
21 changes: 0 additions & 21 deletions src/machine/machine_rp2040_i2c.go
Original file line number Diff line number Diff line change
Expand Up @@ -631,24 +631,3 @@ func (b i2cAbortError) Reasons() (reasons []string) {
}
return reasons
}

//go:inline
func boolToBit(a bool) uint32 {
if a {
return 1
}
return 0
}

//go:inline
func u32max(a, b uint32) uint32 {
if a > b {
return a
}
return b
}

//go:inline
func isReservedI2CAddr(addr uint8) bool {
return (addr&0x78) == 0 || (addr&0x78) == 0x78
}
2 changes: 1 addition & 1 deletion src/machine/machine_rp2040_rtc.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func toAlarmTime(delay uint32) rtcTime {

func (rtc *rtcType) setDivider() {
// Get clk_rtc freq and make sure it is running
rtcFreq := configuredFreq[clkRTC]
rtcFreq := configuredFreq[ClkRTC]
if rtcFreq == 0 {
panic("can not set RTC divider, clock is not running")
}
Expand Down
Loading

0 comments on commit 37f35f8

Please sign in to comment.