add rp2040, pico
adds preliminary support (just enough to run blinky1) for the Raspberry Pi Pico board along with the rp2040 mcu.
Этот коммит содержится в:
родитель
ed2db8a26d
коммит
722a3a5c94
16 изменённых файлов: 882 добавлений и 2 удалений
9
Makefile
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
9
targets/rp2040.ld
Обычный файл
|
@ -0,0 +1,9 @@
|
|||
|
||||
MEMORY
|
||||
{
|
||||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256k
|
||||
}
|
||||
|
||||
_stack_size = 2K;
|
||||
|
||||
INCLUDE "targets/arm.ld"
|
Загрузка…
Создание таблицы
Сослаться в новой задаче