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'
|
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=OFF'
|
||||||
endif
|
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
|
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
|
@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)
|
ifneq ($(STM32), 0)
|
||||||
gen-device: gen-device-stm32
|
gen-device: gen-device-stm32
|
||||||
endif
|
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/
|
./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
|
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.
|
# Get LLVM sources.
|
||||||
$(LLVM_PROJECTDIR)/llvm:
|
$(LLVM_PROJECTDIR)/llvm:
|
||||||
|
@ -351,6 +354,8 @@ smoketest:
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=arduino-nano33 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=arduino-nano33 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=pico examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
# test pwm
|
# test pwm
|
||||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
||||||
@$(MD5SUM) test.hex
|
@$(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"
|
Загрузка…
Создание таблицы
Сослаться в новой задаче