mirror of https://github.com/tinygo-org/tinygo.git
Browse Source
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
16 changed files with 882 additions and 2 deletions
@ -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
|
|||
) |
@ -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() |
|||
} |
@ -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) |
|||
} |
@ -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() |
|||
} |
|||
} |
@ -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) |
|||
|
|||
} |
@ -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) { |
|||
} |
|||
} |
@ -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) |
|||
} |
@ -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) |
|||
} |
@ -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) { |
|||
} |
|||
} |
@ -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() |
|||
} |
@ -0,0 +1,10 @@ |
|||
{ |
|||
"inherits": [ |
|||
"rp2040" |
|||
], |
|||
"build-tags": ["pico"], |
|||
"linkerscript": "targets/pico.ld", |
|||
"extra-files": [ |
|||
"targets/pico_boot_stage2.S" |
|||
] |
|||
} |
@ -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" |
@ -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 |
@ -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" |
|||
] |
|||
} |
@ -0,0 +1,9 @@ |
|||
|
|||
MEMORY |
|||
{ |
|||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256k |
|||
} |
|||
|
|||
_stack_size = 2K; |
|||
|
|||
INCLUDE "targets/arm.ld" |
Loading…
Reference in new issue