Hardware Timers

zeptoforth on the RP2040 (i.e. the Raspberry Pi Pico) and the RP2350 (i.e. the Raspberry Pi Pico 2) has support for hardware timers and delays at up to a microsecond precision. Note that in practice microsecond precision is not necessarily possible, due to interrupts being disabled, interrupt priorities, busy-waits having a limited time resolution, and the chance of busy-waits being preempted if interrupts are not disabled during them.

The 64-bit microsecond timer can represent a sufficiently large range of values, i.e. it can represent thousands of years of time, such that it can be treated as effectively monotonic. Note that the user can change the value of the microsecond timer or pause it, but this is not recommended in most use cases.

The hardware timer on the RP2040 has one shared 64-bit microsecond counter and four “alarms” which are triggered by a set value to be compared with the lower 32 bits of the microsecond counter. The RP2350 is like the RP2040 in this regard except that it has a second identical hardare timer. Alarm handlers execute at interrupt time, so they must be interrupt-safe. Alarms must be enabled for each time they are used and are disabled when they are triggered. However, the interrupt state must be disabled before leaving the alarm interrupt handler or else they will be triggered repeatedly in an infinite loop. Also note that alarm handlers always execute on core 0 even when core 1 has been booted.

There are also busy-loop microsecond delays which wait until a given 64-bit microsecond time. Because the 64-bit microsecond counter can be reasonably treated as not wrapping, only a fixed 64-bit microsecond time is provided. On top of this, busy-loop microsecond delays which wait a given 64-bit microsecond interval are also available. This may be easier to use, but when waiting at repeated intervals maintaining a separate counter, incrementing it for each interval, and waiting until that time is likely to provide better behavior than waiting for intervals relative to the start of the wait.

The RP2350 also supports setting hardware timers to use the system clock for timing rather than the microsecond tick clock.

timer

The following words are in the timer module on the rp2040 and rp2350 platform:

us-counter-lsb

( – us )

Get the lower 32 bits in the current time in microseconds.

us-counter

( – us-d )

Get the current time in microseconds as a 64-bit value.

us-counter!

( us-d – )

Set the microsecond counter to a 64-bit value.

pause-us

( – )

Pause the microsecond counter.

unpause-us

( – )

Unpause the microsecond counter.

delay-until-us

( us-d – )

Delay until at least a 64-bit microsecond value, even though it may take longer considering the practical delay resolution, interrupts, and whether the microsecond counter is set or paused.

delay-us

( us-d – )

Delay a given number of microseconds, even though it may take longer considering the practical delay resolution, interrupts, and whether the microsecond counter is set or paused.

set-alarm

( us xt alarm – )

Set an alarm at a time. alarm is an alarm index from 0 to 3. xt is the execution token for the alarm handler. us is the lower 32 bits of the microsecond counter to trigger the alarm at.

clear-alarm

( alarm – )

Clear an alarm. alarm is an alarm index from 0 to 3.

clear-alarm-int

( alarm – )

Clear an alarm interrupt. alarm is an alarm index from 0 to 3. This must be called with the approriate alarm index inside an alarm handler for a given alarm or else the alarm handler will be called in an infinite loop.

alarm-set?

( alarm – set? )

Get whether an alarm is set.

x-out-of-range-alarm

Out of range alarm index exception.

The rp2350 platform also has the following words for controlling hardware clocks:

lock-timer

( – )

Lock a timer so it cannot be written to without a reset.

timer-locked?

( – locked? )

Get whether a timer is locked.

sysclk-timer

( – )

Set a timer to use the system clock as a source.

tick-timer

( – )

Set a timer to sue the microsecond tick clock as a source.

timer-sysclk?

( – sysclk? )

Get whether a timer is set to use the system clock as a source.

timer1

This module on the rp2350 only is identical to the timer module except that it controls a second hardware timer. It contains the same words as the timer module.