Forked from
PMRust / website
28 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
- Timers
- Bibliography
- Clocks
- Frequency divider
- layout: two-cols
- Counter
- layout: two-cols
- SysTick
- SYST_CSR register
- layout: two-cols
- SysTick
- SYST_CSR register
- Register SysTick handler
- layout: two-cols
- Alarm
- RP2350's Timers
- layout: two-cols
- RP2350's Timer instance
- Reading the time elapsed since restart
- layout: two-cols
- Alarm
slides.md 5.66 KiB
layout: section
Timers
Bibliography
for this section
Raspberry Pi Ltd, RP2350 Datasheet
- Chapter 8 - Clocks
- Chapter 8.1 - Overview
- Subchapter 8.1.1
- Subchapter 8.1.2
- Chapter 8.1 - Overview
- Chapter 12 - Peripherals
- Chapter 12.8 - System Timers
Clocks
all peripherals and the MCU use a clock to execute at certain intervals
Source | Usage |
---|---|
external crystal (XOSC) | a stable frequency is required, for instance when using USB |
internal ring (ROSC) | low frequency, in between 1.8 - 12 MHz (varies) |
Embassy initializes the Raspberry Pi Pico with the clock source from the 12 MHz crystal.
let p = embassy_rp::init(Default::default());
Frequency divider
stabilizing the signal and adjusting it
- divides down the clock signals used for the timer, giving reduced overflow rates
- allows the timer to be clocked at a user desired rate
layout: two-cols
Counter
increments a register at every clock cycle
Registers | Description |
---|---|
value |
the current value of the counter |
direction |
set to count UP or DOWN |
reset |
UP: the value at which the counter resets to 0 DOWN: the value to which the counter resets after getting to 0
|
:: right ::
layout: two-cols
SysTick
ARM Cortex-M time counter

- decrements the value of
SYST_CVR
every μs - when
SYST_CVR
becomes0
:- triggers the
SysTick
exception - next clock cycle sets the value of
SYST_CVR
toSYST_RVR
- triggers the
-
SYST_CALIB
is the value ofSYST_RVR
for a 10ms interval (might not be available)
:: right ::
SYST_CSR
register

layout: two-cols
SysTick
ARM Cortex-M peripheral

const SYST_RVR: *mut u32 = 0xe000_e014 as *mut u32;
const SYST_CVR: *mut u32 = 0xe000_e018 as *mut u32;
const SYST_CSR: *mut u32 = 0xe000_e010 as *mut u32;
// fire systick every 5 seconds
let interval: u32 = 5_000_000;
unsafe {
write_volatile(SYST_RVR, interval);
write_volatile(SYST_CVR, 0);
// set fields `ENABLE` and `TICKINT`
write_volatile(SYST_CSR, 0b11);
}
:: right ::
SYST_CSR
register

SysTick
handler
Register #[exception]
unsafe fn SysTick() {
/* systick fired */
}
layout: two-cols
Alarm
counter that triggers interrupts after a time interval
Registers | Description |
---|---|
value |
the current value of the counter |
direction |
set to count UP or DOWN |
reset |
UP: max value before 0 DOWN: value after 0
|
alarm_x |
when value == alarm_x , triggers an interrupt, x in 1 .. n
|
:: right ::
RP2350's Timers
two timers, TIMER0
and TIMER1
- store a 64 bit number (
reset
is 264-1 ) - start with
0
at (the peripheral's) reset - increment the number every μs
- in practice fully monotonic (cannot over flow)
- allow 4 alarms that trigger interrupts
-
TIMER0_IRQ_0
andTIMER1_IRQ_0
-
TIMER0_IRQ_1
andTIMER1_IRQ_1
-
TIMER0_IRQ_2
andTIMER1_IRQ_2
-
TIMER0_IRQ_3
andTIMER1_IRQ_3
-
-
alarm_0
...alarm_3
registers are only 32 bits wide
layout: two-cols
RP2350's Timer instance
read the number of elapsed μs since reset
Reading the time elapsed since restart
const TIMERLR: *const u32 = 0x400b_000c;
const TIMERHR: *const u32 = 0x400b_0008;
let time: u64 = unsafe {
let low = read_volatile(TIMERLR);
let high = read_volatile(TIMERHR);
high as u64 << 32 | low
}
The reading order maters as reading TIMELR
latches the value in TIMEHR
(stops being updated) until TIMEHR
is read. Works only in single core.
:: right ::
layout: two-cols
Alarm
triggering an interrupt at an interval
#[interrupt]
unsafe fn TIMER0_IRQ_0() { /* alarm fired */ }
const TIMERLR: *const u32 = 0x400b_000c;
const ALARM0: *mut u32 = 0x400b_0010;
// + 0x2000 is bitwise set
const INTE_SET: *mut u32 = 0x400b_0040;
// set an alarm after 3 seconds
let us = 3_0000_0000;
unsafe {
let time = read_volatile(TIMERLR);
// use `wrapping_add` as overflowing may panic
write_volatile(ALARM0, time.wrapping_add(us));
write_volatile(INTE_SET, 1 << 0);
};
- the alarm can be set only for the lower 32 bits
- maximum 72 minutes (use RTC for longer alarms)
:: right ::