Files
tinygo/src/machine/machine_rp2_timer.go
T
Patricio Whittingslow 37f35f8c91 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 <ron@hybridgroup.com>
Co-authored-by: Matthew Mets <matt.mets@cibomahto.com>
Co-authored-by: Matt Mets <matt@blinkinlabs.com>
Co-authored-by: deadprogram <ron@hybridgroup.com>
2024-12-18 19:36:30 +01:00

104 lines
2.7 KiB
Go

//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()
}