Browse Source

add rp2040, pico

adds preliminary support (just enough to run blinky1) for the Raspberry Pi Pico board along with the rp2040 mcu.
pull/1914/head
Rajiv Kanchan 4 years ago
committed by Ron Evans
parent
commit
722a3a5c94
  1. 9
      Makefile
  2. 43
      src/machine/board_pico.go
  3. 44
      src/machine/machine_rp2040.go
  4. 251
      src/machine/machine_rp2040_clocks.go
  5. 131
      src/machine/machine_rp2040_gpio.go
  6. 100
      src/machine/machine_rp2040_pll.go
  7. 43
      src/machine/machine_rp2040_resets.go
  8. 51
      src/machine/machine_rp2040_timer.go
  9. 27
      src/machine/machine_rp2040_watchdog.go
  10. 42
      src/machine/machine_rp2040_xosc.go
  11. 58
      src/runtime/runtime_rp2040.go
  12. 10
      targets/pico.json
  13. 31
      targets/pico.ld
  14. 23
      targets/pico_boot_stage2.S
  15. 12
      targets/rp2040.json
  16. 9
      targets/rp2040.ld

9
Makefile

@ -36,7 +36,7 @@ else
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=OFF'
endif
.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-nxp gen-device-avr
.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-nxp gen-device-avr gen-device-rp
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf executionengine frontendopenmp instrumentation interpreter ipo irreader linker lto mc mcjit objcarcopts option profiledata scalaropts support target
@ -107,7 +107,7 @@ fmt-check:
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
gen-device: gen-device-avr gen-device-esp gen-device-nrf gen-device-sam gen-device-sifive gen-device-kendryte gen-device-nxp
gen-device: gen-device-avr gen-device-esp gen-device-nrf gen-device-sam gen-device-sifive gen-device-kendryte gen-device-nxp gen-device-rp
ifneq ($(STM32), 0)
gen-device: gen-device-stm32
endif
@ -150,6 +150,9 @@ gen-device-stm32: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/tinygo-org/stm32-svd lib/stm32-svd/svd src/device/stm32/
GO111MODULE=off $(GO) fmt ./src/device/stm32
gen-device-rp: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/RaspberryPi lib/cmsis-svd/data/RaspberryPi/ src/device/rp/
GO111MODULE=off $(GO) fmt ./src/device/rp
# Get LLVM sources.
$(LLVM_PROJECTDIR)/llvm:
@ -351,6 +354,8 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-nano33 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pico examples/blinky1
@$(MD5SUM) test.hex
# test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex

43
src/machine/board_pico.go

@ -0,0 +1,43 @@
// +build pico
package machine
// GPIO pins
const (
GP0 Pin = 0
GP1 Pin = 1
GP2 Pin = 2
GP3 Pin = 3
GP4 Pin = 4
GP5 Pin = 5
GP6 Pin = 6
GP7 Pin = 7
GP8 Pin = 8
GP9 Pin = 9
GP10 Pin = 10
GP11 Pin = 11
GP12 Pin = 12
GP13 Pin = 13
GP14 Pin = 14
GP15 Pin = 15
GP16 Pin = 16
GP17 Pin = 17
GP18 Pin = 18
GP19 Pin = 19
GP20 Pin = 20
GP21 Pin = 21
GP22 Pin = 22
GP23 Pin = 23
GP24 Pin = 24
GP25 Pin = 25
GP26 Pin = 26
GP27 Pin = 27
GP28 Pin = 28
GP29 Pin = 29
// Onboard LED
LED Pin = GP25
// Onboard crystal oscillator frequency, in MHz.
xoscFreq = 12 // MHz
)

44
src/machine/machine_rp2040.go

@ -0,0 +1,44 @@
// +build rp2040
package machine
import (
"device/rp"
_ "unsafe"
)
//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)
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)
unresetBlockWait(bits)
clocks.init()
// Peripheral clocks should now all be running
unresetBlockWait(RESETS_RESET_Msk)
}
//go:linkname ticks runtime.machineTicks
func ticks() uint64 {
return timer.timeElapsed()
}

251
src/machine/machine_rp2040_clocks.go

@ -0,0 +1,251 @@
// +build rp2040
package machine
import (
"device/arm"
"device/rp"
"runtime/volatile"
"unsafe"
)
const (
KHz = 1000
MHz = 1000000
)
// clockIndex identifies a hardware clock
type clockIndex uint8
const (
clkGPOUT0 clockIndex = iota // GPIO Muxing 0
clkGPOUT1 // GPIO Muxing 1
clkGPOUT2 // GPIO Muxing 2
clkGPOUT3 // GPIO Muxing 3
clkRef // Watchdog and timers reference clock
clkSys // Processors, bus fabric, memory, memory mapped registers
clkPeri // Peripheral clock for UART and SPI
clkUSB // USB clock
clkADC // ADC clock
clkRTC // Real time clock
numClocks
)
type clockType struct {
ctrl volatile.Register32
div volatile.Register32
selected volatile.Register32
}
type fc struct {
refKHz volatile.Register32
minKHz volatile.Register32
maxKHz volatile.Register32
delay volatile.Register32
interval volatile.Register32
src volatile.Register32
status volatile.Register32
result volatile.Register32
}
type clocksType struct {
clk [numClocks]clockType
resus struct {
ctrl volatile.Register32
status volatile.Register32
}
fc0 fc
wakeEN0 volatile.Register32
wakeEN1 volatile.Register32
sleepEN0 volatile.Register32
sleepEN1 volatile.Register32
enabled0 volatile.Register32
enabled1 volatile.Register32
intR volatile.Register32
intE volatile.Register32
intF volatile.Register32
intS volatile.Register32
}
var clocks = (*clocksType)(unsafe.Pointer(rp.CLOCKS))
var configuredFreq [numClocks]uint32
type clock struct {
*clockType
cix clockIndex
}
// clock returns the clock identified by cix.
func (clks *clocksType) clock(cix clockIndex) *clock {
return &clock{
&clks.clk[cix],
cix,
}
}
// hasGlitchlessMux returns true if clock contains a glitchless multiplexer.
//
// Clock muxing consists of two components:
//
// A glitchless mux, which can be switched freely, but whose inputs must be
// free-running.
//
// An auxiliary (glitchy) mux, whose output glitches when switched, but has
// no constraints on its inputs.
//
// Not all clocks have both types of mux.
func (clk *clock) hasGlitchlessMux() bool {
return clk.cix == clkSys || clk.cix == clkRef
}
// configure configures the clock by selecting the main clock source src
// and the auxiliary clock source auxsrc
// and finally setting the clock frequency to freq
// given the input clock source frequency srcFreq.
func (clk *clock) configure(src, auxsrc, srcFreq, freq uint32) {
if freq > srcFreq {
panic("clock frequency cannot be greater than source frequency")
}
// Div register is 24.8 int.frac divider so multiply by 2^8 (left shift by 8)
div := uint32((uint64(srcFreq) << 8) / uint64(freq))
// If increasing divisor, set divisor before source. Otherwise set source
// before divisor. This avoids a momentary overspeed when e.g. switching
// to a faster source and increasing divisor to compensate.
if div > clk.div.Get() {
clk.div.Set(div)
}
// If switching a glitchless slice (ref or sys) to an aux source, switch
// away from aux *first* to avoid passing glitches when changing aux mux.
// Assume (!!!) glitchless source 0 is no faster than the aux source.
if clk.hasGlitchlessMux() && src == rp.CLOCKS_CLK_SYS_CTRL_SRC_CLKSRC_CLK_SYS_AUX {
clk.ctrl.ClearBits(rp.CLOCKS_CLK_REF_CTRL_SRC_Msk)
for !clk.selected.HasBits(1) {
}
} else
// If no glitchless mux, cleanly stop the clock to avoid glitches
// propagating when changing aux mux. Note it would be a really bad idea
// to do this on one of the glitchless clocks (clkSys, clkRef).
{
// Disable clock. On clkRef and clkSys this does nothing,
// all other clocks have the ENABLE bit in the same position.
clk.ctrl.ClearBits(rp.CLOCKS_CLK_GPOUT0_CTRL_ENABLE_Msk)
if configuredFreq[clk.cix] > 0 {
// Delay for 3 cycles of the target clock, for ENABLE propagation.
// Note XOSC_COUNT is not helpful here because XOSC is not
// necessarily running, nor is timer... so, 3 cycles per loop:
delayCyc := configuredFreq[clkSys]/configuredFreq[clk.cix] + 1
arm.AsmFull(
`
ldr r0, {cyc}
1:
subs r0, #1
bne 1b
`,
map[string]interface{}{
"cyc": &delayCyc,
})
}
}
// Set aux mux first, and then glitchless mux if this clock has one.
clk.ctrl.ReplaceBits(auxsrc<<rp.CLOCKS_CLK_SYS_CTRL_AUXSRC_Pos,
rp.CLOCKS_CLK_SYS_CTRL_AUXSRC_Msk, 0)
if clk.hasGlitchlessMux() {
clk.ctrl.ReplaceBits(src<<rp.CLOCKS_CLK_REF_CTRL_SRC_Pos,
rp.CLOCKS_CLK_REF_CTRL_SRC_Msk, 0)
for !clk.selected.HasBits(1 << src) {
}
}
// Enable clock. On clkRef and clkSys this does nothing,
// all other clocks have the ENABLE bit in the same position.
clk.ctrl.SetBits(rp.CLOCKS_CLK_GPOUT0_CTRL_ENABLE)
// Now that the source is configured, we can trust that the user-supplied
// divisor is a safe value.
clk.div.Set(div)
// Store the configured frequency
configuredFreq[clk.cix] = freq
}
// init initializes the clock hardware.
//
// Must be called before any other clock function.
func (clks *clocksType) init() {
// Start the watchdog tick
watchdog.startTick(xoscFreq)
// Disable resus that may be enabled from previous software
clks.resus.ctrl.Set(0)
// Enable the xosc
xosc.init()
// Before we touch PLLs, switch sys and ref cleanly away from their aux sources.
clks.clk[clkSys].ctrl.ClearBits(rp.CLOCKS_CLK_SYS_CTRL_SRC_Msk)
for !clks.clk[clkSys].selected.HasBits(0x1) {
}
clks.clk[clkRef].ctrl.ClearBits(rp.CLOCKS_CLK_REF_CTRL_SRC_Msk)
for !clks.clk[clkRef].selected.HasBits(0x1) {
}
// Configure PLLs
// REF FBDIV VCO POSTDIV
// pllSys: 12 / 1 = 12MHz * 125 = 1500MHZ / 6 / 2 = 125MHz
// pllUSB: 12 / 1 = 12MHz * 40 = 480 MHz / 5 / 2 = 48MHz
pllSys.init(1, 1500*MHz, 6, 2)
pllUSB.init(1, 480*MHz, 5, 2)
// Configure clocks
// clkRef = xosc (12MHz) / 1 = 12MHz
clkref := clks.clock(clkRef)
clkref.configure(rp.CLOCKS_CLK_REF_CTRL_SRC_XOSC_CLKSRC,
0, // No aux mux
12*MHz,
12*MHz)
// clkSys = pllSys (125MHz) / 1 = 125MHz
clksys := clks.clock(clkSys)
clksys.configure(rp.CLOCKS_CLK_SYS_CTRL_SRC_CLKSRC_CLK_SYS_AUX,
rp.CLOCKS_CLK_SYS_CTRL_AUXSRC_CLKSRC_PLL_SYS,
125*MHz,
125*MHz)
// clkUSB = pllUSB (48MHz) / 1 = 48MHz
clkusb := clks.clock(clkUSB)
clkusb.configure(0, // No GLMUX
rp.CLOCKS_CLK_USB_CTRL_AUXSRC_CLKSRC_PLL_USB,
48*MHz,
48*MHz)
// clkADC = pllUSB (48MHZ) / 1 = 48MHz
clkadc := clks.clock(clkADC)
clkadc.configure(0, // No GLMUX
rp.CLOCKS_CLK_ADC_CTRL_AUXSRC_CLKSRC_PLL_USB,
48*MHz,
48*MHz)
// clkRTC = pllUSB (48MHz) / 1024 = 46875Hz
clkrtc := clks.clock(clkRTC)
clkrtc.configure(0, // No GLMUX
rp.CLOCKS_CLK_RTC_CTRL_AUXSRC_CLKSRC_PLL_USB,
48*MHz,
46875)
// clkPeri = clkSys. Used as reference clock for Peripherals.
// No dividers so just select and enable.
// Normally choose clkSys or clkUSB.
clkperi := clks.clock(clkPeri)
clkperi.configure(0,
rp.CLOCKS_CLK_PERI_CTRL_AUXSRC_CLK_SYS,
125*MHz,
125*MHz)
}

131
src/machine/machine_rp2040_gpio.go

@ -0,0 +1,131 @@
// +build rp2040
package machine
import (
"device/rp"
"runtime/volatile"
"unsafe"
)
type io struct {
status volatile.Register32
ctrl volatile.Register32
}
type irqCtrl struct {
intE [4]volatile.Register32
intS [4]volatile.Register32
intF [4]volatile.Register32
}
type ioBank0Type struct {
io [30]io
intR [4]volatile.Register32
proc0IRQctrl irqCtrl
proc1IRQctrl irqCtrl
dormantWakeIRQctrl irqCtrl
}
var ioBank0 = (*ioBank0Type)(unsafe.Pointer(rp.IO_BANK0))
type padsBank0Type struct {
voltageSelect volatile.Register32
io [30]volatile.Register32
}
var padsBank0 = (*padsBank0Type)(unsafe.Pointer(rp.PADS_BANK0))
// pinFunc represents a GPIO function.
//
// Each GPIO can have one function selected at a time.
// Likewise, each peripheral input (e.g. UART0 RX) should only be selected
// on one GPIO at a time. If the same peripheral input is connected to multiple GPIOs,
// the peripheral sees the logical OR of these GPIO inputs.
type pinFunc uint8
// GPIO function selectors
const (
fnJTAG pinFunc = 0
fnSPI pinFunc = 1
fnUART pinFunc = 2
fnI2C pinFunc = 3
fnPWM pinFunc = 4
fnSIO pinFunc = 5
fnPIO0 pinFunc = 6
fnPIO1 pinFunc = 7
fnGPCK pinFunc = 8
fnUSB pinFunc = 9
fnNULL pinFunc = 0x1f
fnXIP pinFunc = 0
)
const (
PinOutput PinMode = iota
)
// set drives the pin high
func (p Pin) set() {
mask := uint32(1) << p
rp.SIO.GPIO_OUT_SET.Set(mask)
}
// clr drives the pin low
func (p Pin) clr() {
mask := uint32(1) << p
rp.SIO.GPIO_OUT_CLR.Set(mask)
}
// xor toggles the pin
func (p Pin) xor() {
mask := uint32(1) << p
rp.SIO.GPIO_OUT_XOR.Set(mask)
}
func (p Pin) ioCtrl() *volatile.Register32 {
return &ioBank0.io[p].ctrl
}
func (p Pin) padCtrl() *volatile.Register32 {
return &padsBank0.io[p]
}
// setFunc will set pin function to fn.
func (p Pin) setFunc(fn pinFunc) {
// Set input enable, Clear output disable
p.padCtrl().ReplaceBits(rp.PADS_BANK0_GPIO0_IE,
rp.PADS_BANK0_GPIO0_IE_Msk|rp.PADS_BANK0_GPIO0_OD_Msk, 0)
// Zero all fields apart from fsel; we want this IO to do what the peripheral tells it.
// This doesn't affect e.g. pullup/pulldown, as these are in pad controls.
p.ioCtrl().Set(uint32(fn) << rp.IO_BANK0_GPIO0_CTRL_FUNCSEL_Pos)
}
// init initializes the gpio pin
func (p Pin) init() {
mask := uint32(1) << p
rp.SIO.GPIO_OE_CLR.Set(mask)
p.clr()
p.setFunc(fnSIO)
}
// Configure configures the gpio pin as per mode.
func (p Pin) Configure(config PinConfig) {
p.init()
mask := uint32(1) << p
switch config.Mode {
case PinOutput:
rp.SIO.GPIO_OE_SET.Set(mask)
}
}
// Set drives the pin high if value is true else drives it low.
func (p Pin) Set(value bool) {
if value {
p.set()
} else {
p.clr()
}
}

100
src/machine/machine_rp2040_pll.go

@ -0,0 +1,100 @@
// +build rp2040
package machine
import (
"device/rp"
"runtime/volatile"
"unsafe"
)
type pll struct {
cs volatile.Register32
pwr volatile.Register32
fbDivInt volatile.Register32
prim volatile.Register32
}
var (
pllSys = (*pll)(unsafe.Pointer(rp.PLL_SYS))
pllUSB = (*pll)(unsafe.Pointer(rp.PLL_USB))
)
// init initializes pll (Sys or USB) given the following parameters.
//
// Input clock divider, refdiv.
//
// Requested output frequency from the VCO (voltage controlled oscillator), vcoFreq.
//
// Post Divider 1, postDiv1 with range 1-7 and be >= postDiv2.
//
// Post Divider 2, postDiv2 with range 1-7.
func (pll *pll) init(refdiv, vcoFreq, postDiv1, postDiv2 uint32) {
refFreq := xoscFreq / refdiv
// What are we multiplying the reference clock by to get the vco freq
// (The regs are called div, because you divide the vco output and compare it to the refclk)
fbdiv := vcoFreq / (refFreq * MHz)
// Check fbdiv range
if !(fbdiv >= 16 && fbdiv <= 320) {
panic("fbdiv should be in the range [16,320]")
}
// Check divider ranges
if !((postDiv1 >= 1 && postDiv1 <= 7) && (postDiv2 >= 1 && postDiv2 <= 7)) {
panic("postdiv1, postdiv1 should be in the range [1,7]")
}
// postDiv1 should be >= postDiv2
// from appnote page 11
// postdiv1 is designed to operate with a higher input frequency
// than postdiv2
if postDiv1 < postDiv2 {
panic("postdiv1 should be greater than or equal to postdiv2")
}
// Check that reference frequency is no greater than vco / 16
if refFreq > vcoFreq/16 {
panic("reference frequency should not be greater than vco frequency divided by 16")
}
// div1 feeds into div2 so if div1 is 5 and div2 is 2 then you get a divide by 10
pdiv := postDiv1<<rp.PLL_SYS_PRIM_POSTDIV1_Pos | postDiv2<<rp.PLL_SYS_PRIM_POSTDIV2_Pos
if pll.cs.HasBits(rp.PLL_SYS_CS_LOCK) &&
refdiv == pll.cs.Get()&rp.PLL_SYS_CS_REFDIV_Msk &&
fbdiv == pll.fbDivInt.Get()&rp.PLL_SYS_FBDIV_INT_FBDIV_INT_Msk &&
pdiv == pll.prim.Get()&(rp.PLL_SYS_PRIM_POSTDIV1_Msk&rp.PLL_SYS_PRIM_POSTDIV2_Msk) {
// do not disrupt PLL that is already correctly configured and operating
return
}
var pllRst uint32
if pll == pllSys {
pllRst = rp.RESETS_RESET_PLL_SYS
} else {
pllRst = rp.RESETS_RESET_PLL_USB
}
resetBlock(pllRst)
unresetBlockWait(pllRst)
// Load VCO-related dividers before starting VCO
pll.cs.Set(refdiv)
pll.fbDivInt.Set(fbdiv)
// Turn on PLL
pwr := uint32(rp.PLL_SYS_PWR_PD | rp.PLL_SYS_PWR_VCOPD)
pll.pwr.ClearBits(pwr)
// Wait for PLL to lock
for !(pll.cs.HasBits(rp.PLL_SYS_CS_LOCK)) {
}
// Set up post dividers
pll.prim.Set(pdiv)
// Turn on post divider
pll.pwr.ClearBits(rp.PLL_SYS_PWR_POSTDIVPD)
}

43
src/machine/machine_rp2040_resets.go

@ -0,0 +1,43 @@
// +build rp2040
package machine
import (
"device/rp"
"runtime/volatile"
"unsafe"
)
// RESETS_RESET_Msk is bitmask to reset all peripherals
//
// TODO: This field is not available in the device file.
const RESETS_RESET_Msk = 0x01ffffff
type resetsType struct {
reset volatile.Register32
wdSel volatile.Register32
resetDone volatile.Register32
}
var resets = (*resetsType)(unsafe.Pointer(rp.RESETS))
// resetBlock resets hardware blocks specified
// by the bit pattern in bits.
func resetBlock(bits uint32) {
resets.reset.SetBits(bits)
}
// unresetBlock brings hardware blocks specified by the
// bit pattern in bits out of reset.
func unresetBlock(bits uint32) {
resets.reset.ClearBits(bits)
}
// unresetBlockWait brings specified hardware blocks
// specified by the bit pattern in bits
// out of reset and wait for completion.
func unresetBlockWait(bits uint32) {
unresetBlock(bits)
for !resets.resetDone.HasBits(bits) {
}
}

51
src/machine/machine_rp2040_timer.go

@ -0,0 +1,51 @@
// +build rp2040
package machine
import (
"device/rp"
"runtime/volatile"
"unsafe"
)
const numTimers = 4
type timerType struct {
timeHW volatile.Register32
timeLW volatile.Register32
timeHR volatile.Register32
timeLR volatile.Register32
alarm [numTimers]volatile.Register32
armed volatile.Register32
timeRawH volatile.Register32
timeRawL volatile.Register32
dbgPause volatile.Register32
pause volatile.Register32
intR volatile.Register32
intE volatile.Register32
intF volatile.Register32
intS volatile.Register32
}
var timer = (*timerType)(unsafe.Pointer(rp.TIMER))
// TimeElapsed returns time elapsed since power up, in microseconds.
func (tmr *timerType) timeElapsed() (us uint64) {
// Need to make sure that the upper 32 bits of the timer
// don't change, so read that first
hi := tmr.timeRawH.Get()
var lo, nextHi uint32
for {
// Read the lower 32 bits
lo = tmr.timeRawL.Get()
// Now read the upper 32 bits again and
// check that it hasn't incremented. If it has, loop around
// and read the lower 32 bits again to get an accurate value
nextHi = tmr.timeRawH.Get()
if hi == nextHi {
break
}
hi = nextHi
}
return uint64(hi)<<32 | uint64(lo)
}

27
src/machine/machine_rp2040_watchdog.go

@ -0,0 +1,27 @@
// +build rp2040
package machine
import (
"device/rp"
"runtime/volatile"
"unsafe"
)
type watchdogType struct {
ctrl volatile.Register32
load volatile.Register32
reason volatile.Register32
scratch [8]volatile.Register32
tick volatile.Register32
}
var watchdog = (*watchdogType)(unsafe.Pointer(rp.WATCHDOG))
// startTick starts the watchdog tick.
// cycles needs to be a divider that when applied to the xosc input,
// produces a 1MHz clock. So if the xosc frequency is 12MHz,
// this will need to be 12.
func (wd *watchdogType) startTick(cycles uint32) {
wd.tick.Set(cycles | rp.WATCHDOG_TICK_ENABLE)
}

42
src/machine/machine_rp2040_xosc.go

@ -0,0 +1,42 @@
// +build rp2040
package machine
import (
"device/rp"
"runtime/volatile"
"unsafe"
)
type xoscType struct {
ctrl volatile.Register32
status volatile.Register32
dormant volatile.Register32
startup volatile.Register32
reserved [3]volatile.Register32
count volatile.Register32
}
var xosc = (*xoscType)(unsafe.Pointer(rp.XOSC))
// init initializes the crystal oscillator system.
//
// This function will block until the crystal oscillator has stabilised.
func (osc *xoscType) init() {
// Assumes 1-15 MHz input
if xoscFreq > 15 {
panic("xosc frequency cannot be greater than 15MHz")
}
osc.ctrl.Set(rp.XOSC_CTRL_FREQ_RANGE_1_15MHZ)
// Set xosc startup delay
delay := (((xoscFreq * MHz) / 1000) + 128) / 256
osc.startup.Set(uint32(delay))
// Set the enable bit now that we have set freq range and startup delay
osc.ctrl.SetBits(rp.XOSC_CTRL_ENABLE_ENABLE << rp.XOSC_CTRL_ENABLE_Pos)
// Wait for xosc to be stable
for !osc.status.HasBits(rp.XOSC_STATUS_STABLE) {
}
}

58
src/runtime/runtime_rp2040.go

@ -0,0 +1,58 @@
// +build rp2040
package runtime
import (
"device/arm"
)
// machineTicks is provided by package machine.
func machineTicks() uint64
type timeUnit uint64
// ticks returns the number of ticks (microseconds) elapsed since power up.
func ticks() timeUnit {
t := machineTicks()
return timeUnit(t)
}
func ticksToNanoseconds(ticks timeUnit) int64 {
return int64(ticks) * 1000
}
func nanosecondsToTicks(ns int64) timeUnit {
return timeUnit(ns / 1000)
}
func sleepTicks(d timeUnit) {
if d == 0 {
return
}
sleepUntil := ticks() + d
for ticks() < sleepUntil {
}
}
func waitForEvents() {
arm.Asm("wfe")
}
func putchar(c byte) {
}
// machineInit is provided by package machine.
func machineInit()
func init() {
machineInit()
}
func postinit() {}
//export Reset_Handler
func main() {
preinit()
run()
abort()
}

10
targets/pico.json

@ -0,0 +1,10 @@
{
"inherits": [
"rp2040"
],
"build-tags": ["pico"],
"linkerscript": "targets/pico.ld",
"extra-files": [
"targets/pico_boot_stage2.S"
]
}

31
targets/pico.ld

@ -0,0 +1,31 @@
MEMORY
{
FLASH_TEXT (rx) : ORIGIN = 0x10000000, LENGTH = 2048k
}
SECTIONS
{
/* Second stage bootloader is prepended to the image. It must be 256 bytes big
and checksummed. It is usually built by the boot_stage2 target
in the Raspberry Pi Pico SDK
*/
.boot2 : {
__boot2_start__ = .;
KEEP (*(.boot2))
__boot2_end__ = .;
} > FLASH_TEXT
ASSERT(__boot2_end__ - __boot2_start__ == 256,
"ERROR: Pico second stage bootloader must be 256 bytes in size")
/* The second stage will always enter the image at the start of .text.
The debugger will use the ELF entry point, which is the _entry_point
symbol if present, otherwise defaults to start of .text.
This can be used to transfer control back to the bootrom on debugger
launches only, to perform proper flash setup.
*/
}
INCLUDE "targets/rp2040.ld"

23
targets/pico_boot_stage2.S

@ -0,0 +1,23 @@
// Padded and checksummed version of: /home/rkanchan/src/pico-sdk/build/src/rp2_common/boot_stage2/bs2_default.bin
.cpu cortex-m0plus
.thumb
.section .boot2, "ax"
.byte 0x00, 0xb5, 0x32, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, 0x88, 0x43, 0x98, 0x60
.byte 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2e, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x02, 0x21, 0x59, 0x61
.byte 0x01, 0x21, 0xf0, 0x22, 0x99, 0x50, 0x2b, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20
.byte 0x00, 0xf0, 0x44, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x14, 0xd0, 0x06, 0x21, 0x19, 0x66, 0x00, 0xf0
.byte 0x34, 0xf8, 0x19, 0x6e, 0x01, 0x21, 0x19, 0x66, 0x00, 0x20, 0x18, 0x66, 0x1a, 0x66, 0x00, 0xf0
.byte 0x2c, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x19, 0x6e, 0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21
.byte 0x08, 0x42, 0xf9, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60
.byte 0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xeb, 0x21, 0x19, 0x66, 0xa0, 0x21
.byte 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21, 0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60
.byte 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x12, 0x48, 0x13, 0x49
.byte 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5, 0x99, 0x6a, 0x04, 0x20
.byte 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42, 0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66
.byte 0x18, 0x66, 0xff, 0xf7, 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x02, 0x40
.byte 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0x5f, 0x00, 0x21, 0x22, 0x00, 0x00
.byte 0xf4, 0x00, 0x00, 0x18, 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0xb2, 0x4e, 0x7a

12
targets/rp2040.json

@ -0,0 +1,12 @@
{
"inherits": ["cortex-m0plus"],
"build-tags": ["rp2040", "rp"],
"flash-method": "msd",
"msd-volume-name": "RPI-RP2",
"msd-firmware-name": "firmware.uf2",
"binary-format": "uf2",
"uf2-family-id": "0xe48bff56",
"extra-files": [
"src/device/rp/rp2040.s"
]
}

9
targets/rp2040.ld

@ -0,0 +1,9 @@
MEMORY
{
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256k
}
_stack_size = 2K;
INCLUDE "targets/arm.ld"
Loading…
Cancel
Save