diff options
author | Patricio Whittingslow <[email protected]> | 2024-12-18 15:36:30 -0300 |
---|---|---|
committer | GitHub <[email protected]> | 2024-12-18 19:36:30 +0100 |
commit | 37f35f8c910b05e2040433448546f41b34535b32 (patch) | |
tree | 32bdf01b1c2b8d75e9a7f1a24e5c62be9d432ce0 /src/machine/machine_rp2_timer.go | |
parent | 0d13e61d0cbe7aa82678a6dec7dda0115db82397 (diff) | |
download | tinygo-37f35f8c910b05e2040433448546f41b34535b32.tar.gz tinygo-37f35f8c910b05e2040433448546f41b34535b32.zip |
Add RP2350 support (#4459)
machine/rp2350: add support
* add linker scripts for rp2350
* add bootloader
* begin melding rp2040 and rp2350 APIs
* add UART
* add rp2350 boot patching
* Fix RP2350 memory layout (#4626)
* Remove rp2040-style second stage bootloader.
* Add 'minimum viable' IMAGE_DEF embedded block
* Create a pico2 specific target
* Implement rp2350 init, clock, and uart support
* Merge rp2 reset code back together
* Separate chip-specific clock definitions
* Clear pad isolation bit on rp2350
* Init UART in rp2350 runtime
* Correct usb/serial initialization order
* Implement jump-to-bootloader
* test: add pico2 to smoketests
---------
Signed-off-by: deadprogram <[email protected]>
Co-authored-by: Matthew Mets <[email protected]>
Co-authored-by: Matt Mets <[email protected]>
Co-authored-by: deadprogram <[email protected]>
Diffstat (limited to 'src/machine/machine_rp2_timer.go')
-rw-r--r-- | src/machine/machine_rp2_timer.go | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/machine/machine_rp2_timer.go b/src/machine/machine_rp2_timer.go new file mode 100644 index 000000000..a78ed70bb --- /dev/null +++ b/src/machine/machine_rp2_timer.go @@ -0,0 +1,103 @@ +//go:build rp2040 || rp2350 + +package machine + +import ( + "device/arm" + "runtime/interrupt" + "runtime/volatile" +) + +const numTimers = 4 + +// Alarm0 is reserved for sleeping by tinygo runtime code for RP2040. +// Alarm0 is also IRQ0 +const sleepAlarm = 0 +const sleepAlarmIRQ = 0 + +// The minimum sleep duration in μs (ticks) +const minSleep = 10 + +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 + locked [rp2350ExtraReg]volatile.Register32 + source [rp2350ExtraReg]volatile.Register32 + intR volatile.Register32 + intE volatile.Register32 + intF volatile.Register32 + intS volatile.Register32 +} + +// 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) +} + +// lightSleep will put the processor into a sleep state a short period +// (up to approx 72mins per RP2040 datasheet, 4.6.3. Alarms). +// +// This function is a 'light' sleep and will return early if another +// interrupt or event triggers. This is intentional since the +// primary use-case is for use by the TinyGo scheduler which will +// re-sleep if needed. +func (tmr *timerType) lightSleep(us uint64) { + // minSleep is a way to avoid race conditions for short + // sleeps by ensuring there is enough time to setup the + // alarm before sleeping. For very short sleeps, this + // effectively becomes a 'busy loop'. + if us < minSleep { + return + } + + // Interrupt handler is essentially a no-op, we're just relying + // on the side-effect of waking the CPU from "wfe" + intr := interrupt.New(sleepAlarmIRQ, func(interrupt.Interrupt) { + // Clear the IRQ + timer.intR.Set(1 << sleepAlarm) + }) + + // Reset interrupt flag + tmr.intR.Set(1 << sleepAlarm) + + // Enable interrupt + tmr.intE.SetBits(1 << sleepAlarm) + intr.Enable() + + // Only the low 32 bits of time can be used for alarms + target := uint64(tmr.timeRawL.Get()) + us + tmr.alarm[sleepAlarm].Set(uint32(target)) + + // Wait for sleep (or any other) interrupt + arm.Asm("wfe") + + // Disarm timer + tmr.armed.Set(1 << sleepAlarm) + + // Disable interrupt + intr.Disable() +} |