Skip to content

Timer

4.6. Timer

4.6.1. Overview

The system timer peripheral on RP2040 provides a global microsecond timebase for the system, and generates interrupts based on this timebase. It supports the following features:

  • [A single 64-bit counter, incrementing once per microsecond]

  • [This counter can be read from a pair of latching registers, for race-free reads over a 32-bit bus.]

  • [Four alarms: match on the lower 32 bits of counter, IRQ on match.]

The timer uses a one microsecond reference that is generated in the Watchdog (see Section 4.7.2), and derived from

4.6. Timer

534

RP2040 Datasheet

the reference clock (Figure 28), which itself is usually connected directly to the crystal oscillator (Section 2.16).

The 64-bit counter effectively can not overflow (thousands of years at 1MHz), so the system timer is completely monotonic in practice.

4.6.1.1. Other Timer Resources on RP2040

The system timer is intended to provide a global timebase for software. RP2040 has a number of other programmable counter resources which can provide regular interrupts, or trigger DMA transfers.

  • [The PWM (][Section 4.5][) contains 8× 16-bit programmable counters, which run at up to system speed, can generate] interrupts, and can be continuously reprogrammed via the DMA, or trigger DMA transfers to other peripherals.

  • [8× PIO state machines (][Chapter 3][) can count 32-bit values at system speed, and generate interrupts.]

  • [The DMA (][Section 2.5][) has four internal pacing timers, which trigger transfers at regular intervals.]

  • [Each Cortex-M0+ core (][Section 2.4][) has a standard 24-bit SysTick timer, counting either the microsecond tick] (Section 4.7.2) or the system clock.

4.6.2. Counter

The timer has a 64-bit counter, but RP2040 only has a 32-bit data bus. This means that the TIME value is accessed through a pair of registers. These are:

  • [TIMEHW][ and ][TIMELW][ to write the time]

  • [TIMEHR][ and ][TIMELR][ to read the time]

These pairs are used by accessing the lower register, L, followed by the higher register, H. In the read case, reading the L register latches the value in the H register so that an accurate time can be read. Alternatively, TIMERAWH and TIMERAWL can be used to read the raw time without any latching.

CAUTION

While it is technically possible to force a new time value by writing to the TIMEHW and TIMELW registers, programmers are discouraged from doing this. This is because the timer value is expected to be monotonically increasing by the SDK which uses it for timeouts, elapsed time etc.

4.6.3. Alarms

The timer has 4 alarms, and outputs a separate interrupt for each alarm. The alarms match on the lower 32 bits of the 64-bit counter which means they can be fired at a maximum of 2[32] microseconds into the future. This is equivalent to:

  • [2][32][ ÷ 10][6][: ~4295 seconds]

  • [4295 ÷ 60: ~72 minutes]

NOTE

This timer is expected to be used for short sleeps. If you want a longer alarm see Section 4.8.

To enable an alarm:

  • [Enable the interrupt at the timer with a write to the appropriate alarm bit in ][INTE][: i.e. ][(1 << 0)][ for ][ALARM0]

  • [Enable the appropriate timer interrupt at the processor (see ][Section 2.3.2][)]

  • [Write the time you would like the interrupt to fire to ][ALARM0][ (i.e. the current value in ][TIMERAWL][ plus your desired] alarm time in microseconds). Writing the time to the ALARM register sets the ARMED bit as a side effect.

4.6. Timer

535

RP2040 Datasheet

Once the alarm has fired, the ARMED bit will be set to 0. To clear the latched interrupt, write a 1 to the appropriate bit in INTR.

4.6.4. Programmer’s Model

NOTE

The Watchdog tick (see Section 4.7.2) must be running for the timer to start counting. The SDK starts this tick as part of the platform initialisation code.

4.6.4.1. Reading the time

NOTE

Time here refers to the number of microseconds since the timer was started, it is not a clock. For that - see Section 4.8.

The simplest form of reading the 64-bit time is to read TIMELR followed by TIMEHR. However, because RP2040 has 2 cores, it is unsafe to do this if the second core is executing code that can also access the timer, or if the timer is read concurrently in an IRQ handler and in thread mode. This is because reading TIMELR latches the value in TIMEHR (i.e. stops it updating) until TIMEHR is read. If one core reads TIMELR followed by another core reading TIMELR, the value in TIMEHR isn’t necessarily accurate. The example below shows the simplest form of getting the 64-bit time.

Pico Examples: https://github.com/raspberrypi/pico-examples/blob/master/timer/timer_lowlevel/timer_lowlevel.c Lines 15 - 23

15 // Simplest form of getting 64 bit time from the timer. 16 // It isn't safe when called from 2 cores because of the latching 17 // so isn't implemented this way in the sdk 18 static uint64_t get_time(void) { 19 // Reading low latches the high value 20 uint32_t lo = timer_hw->timelr; 21 uint32_t hi = timer_hw->timehr; 22 return ((uint64_t) hi << 32u) | lo; 23 }

The SDK provides a time_us_64 function that uses a more thorough method to get the 64-bit time, which makes use of the TIMERAWH and TIMERAWL registers. The RAW registers don’t latch, and therefore make time_us_64 safe to call from multiple cores at once.

SDK: https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_timer/timer.c Lines 57 - 73

57 uint64_t timer_time_us_64(timer_hw_t *timer) { 58 // Need to make sure that the upper 32 bits of the timer 59 // don't change, so read that first 60 uint32_t hi = timer->timerawh; 61 uint32_t lo; 62 do { 63 // Read the lower 32 bits 64 lo = timer->timerawl; 65 // Now read the upper 32 bits again and 66 // check that it hasn't incremented. If it has loop around 67 // and read the lower 32 bits again to get an accurate value 68 uint32_t next_hi = timer->timerawh; 69 if (hi == next_hi) break; 70 hi = next_hi;

4.6. Timer

536

RP2040 Datasheet

71 } while (true); 72 return ((uint64_t) hi << 32u) | lo; 73 }

4.6.4.2. Set an alarm

The standalone timer example, timer_lowlevel, demonstrates how to set an alarm at a hardware level, without the additional abstraction over the timer that the SDK provides. To use these abstractions see Section 4.6.4.4.

Pico Examples: https://github.com/raspberrypi/pico-examples/blob/master/timer/timer_lowlevel/timer_lowlevel.c Lines 27 - 74

27 // Use alarm 0 28 #define ALARM_NUM 0 29 #define ALARM_IRQ timer_hardware_alarm_get_irq_num(timer_hw, ALARM_NUM) 30 31 // Alarm interrupt handler 32 static volatile bool alarm_fired; 33 34 static void alarm_irq(void) { 35 // Clear the alarm irq 36 hw_clear_bits(&timer_hw->intr, 1u << ALARM_NUM); 37 38 // Assume alarm 0 has fired 39 printf("Alarm IRQ fired\n"); 40 alarm_fired = true; 41 } 42 43 static void alarm_in_us(uint32_t delay_us) { 44 // Enable the interrupt for our alarm (the timer outputs 4 alarm irqs) 45 hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM); 46 // Set irq handler for alarm irq 47 irq_set_exclusive_handler(ALARM_IRQ, alarm_irq); 48 // Enable the alarm irq 49 irq_set_enabled(ALARM_IRQ, true); 50 // Enable interrupt in block and at processor 51 52 // Alarm is only 32 bits so if trying to delay more 53 // than that need to be careful and keep track of the upper 54 // bits 55 uint64_t target = timer_hw->timerawl + delay_us; 56 57 // Write the lower 32 bits of the target time to the alarm which 58 // will arm it 59 timer_hw->alarm[ALARM_NUM] = (uint32_t) target; 60 } 61 62 int main() { 63 stdio_init_all(); 64 printf("Timer lowlevel!\n"); 65 66 // Set alarm every 2 seconds 67 while (1) { 68 alarm_fired = false; 69 alarm_in_us(1000000 * 2); 70 // Wait for alarm to fire 71 while (!alarm_fired); 72 } 73 }

4.6. Timer

537

RP2040 Datasheet

4.6.4.3. Busy wait

If you don’t want to use an alarm to wait for a period of time, instead use a while loop. The SDK provides various busy_wait_ functions to do this:

SDK: https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_timer/timer.c Lines 77 - 122

77 void timer_busy_wait_us_32(timer_hw_t timer, uint32_t delay_us) { 78 if (0 <= (int32_t)delay_us) { 79 // we only allow 31 bits, otherwise we could have a race in the loop below with 80 // values very close to 2^32 81 uint32_t start = timer->timerawl; 82 while (timer->timerawl - start < delay_us) { 83 tight_loop_contents(); 84 } 85 } else { 86 busy_wait_us(delay_us); 87 } 88 } 89 90 void timer_busy_wait_us(timer_hw_t timer, uint64_t delay_us) { 91 uint64_t base = timer_time_us_64(timer); 92 uint64_t target = base + delay_us; 93 if (target < base) { 94 target = (uint64_t)-1; 95 } 96 absolute_time_t t; 97 update_us_since_boot(&t, target); 98 timer_busy_wait_until(timer, t); 99 } 100 101 void timer_busy_wait_ms(timer_hw_t timer, uint32_t delay_ms) 102 { 103 if (delay_ms <= 0x7fffffffu / 1000) { 104 timer_busy_wait_us_32(timer, delay_ms * 1000); 105 } else { 106 timer_busy_wait_us(timer, delay_ms * 1000ull); 107 } 108 } 109 110 void timer_busy_wait_until(timer_hw_t timer, absolute_time_t t) { 111 uint64_t target = to_us_since_boot(t); 112 uint32_t hi_target = (uint32_t)(target >> 32u); 113 uint32_t hi = timer->timerawh; 114 while (hi < hi_target) { 115 hi = timer->timerawh; 116 tight_loop_contents(); 117 } 118 while (hi == hi_target && timer->timerawl < (uint32_t) target) { 119 hi = timer->timerawh; 120 tight_loop_contents(); 121 } 122 }

4.6.4.4. Complete example using SDK

4.6. Timer

538

RP2040 Datasheet

Pico Examples: https://github.com/raspberrypi/pico-examples/blob/master/timer/hello_timer/hello_timer.c Lines 11 - 57

11 volatile bool timer_fired = false; 12 13 int64_t alarm_callback(alarm_id_t id, __unused void user_data) { 14 printf("Timer %d fired!\n", (int) id); 15 timer_fired = true; 16 // Can return a value here in us to fire in the future 17 return 0; 18 } 19 20 bool repeating_timer_callback(__unused struct repeating_timer t) { 21 printf("Repeat at %lld\n", time_us_64()); 22 return true; 23 } 24 25 int main() { 26 stdio_init_all(); 27 printf("Hello Timer!\n"); 28 29 // Call alarm_callback in 2 seconds 30 add_alarm_in_ms(2000, alarm_callback, NULL, false); 31 32 // Wait for alarm callback to set timer_fired 33 while (!timer_fired) { 34 tight_loop_contents(); 35 } 36 37 // Create a repeating timer that calls repeating_timer_callback. 38 // If the delay is > 0 then this is the delay between the previous callback ending and the next starting. 39 // If the delay is negative (see below) then the next call to the callback will be exactly 500ms after the 40 // start of the call to the last callback 41 struct repeating_timer timer; 42 add_repeating_timer_ms(500, repeating_timer_callback, NULL, &timer); 43 sleep_ms(3000); 44 bool cancelled = cancel_repeating_timer(&timer); 45 printf("cancelled... %d\n", cancelled); 46 sleep_ms(2000); 47 48 // Negative delay so means we will call repeating_timer_callback, and call it again 49 // 500ms later regardless of how long the callback took to execute 50 add_repeating_timer_ms(-500, repeating_timer_callback, NULL, &timer); 51 sleep_ms(3000); 52 cancelled = cancel_repeating_timer(&timer); 53 printf("cancelled... %d\n", cancelled); 54 sleep_ms(2000); 55 printf("Done\n"); 56 return 0; 57 }

4.6.5. List of Registers

The Timer registers start at a base address of 0x40054000 (defined as TIMER_BASE in SDK).

Table 527. List of TIMER registers

Offset Name Info
0x00 TIMEHW Write to bits 63:32 of time
always write timelw before timehw

4.6. Timer

539

RP2040 Datasheet

Offset Name Info
0x04 TIMELW Write to bits 31:0 of time
writes do not get copied to time until timehw is written
0x08 TIMEHR Read from bits 63:32 of time
always read timelr before timehr
0x0c TIMELR Read from bits 31:0 of time
0x10 ALARM0 Arm alarm 0, and configure the time it will fire.
Once armed, the alarm fires when TIMER_ALARM0 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
0x14 ALARM1 Arm alarm 1, and configure the time it will fire.
Once armed, the alarm fires when TIMER_ALARM1 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
0x18 ALARM2 Arm alarm 2, and configure the time it will fire.
Once armed, the alarm fires when TIMER_ALARM2 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
0x1c ALARM3 Arm alarm 3, and configure the time it will fire.
Once armed, the alarm fires when TIMER_ALARM3 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
0x20 ARMED Indicates the armed/disarmed status of each alarm.
A write to the corresponding ALARMx register arms the alarm.
Alarms automatically disarm upon firing, but writing ones here
will disarm immediately without waiting to fire.
0x24 TIMERAWH Raw read from bits 63:32 of time (no side effects)
0x28 TIMERAWL Raw read from bits 31:0 of time (no side effects)
0x2c DBGPAUSE Set bits high to enable pause when the corresponding debug
ports are active
0x30 PAUSE Set high to pause the timer
0x34 INTR Raw Interrupts
0x38 INTE Interrupt Enable
0x3c INTF Interrupt Force
0x40 INTS Interrupt status after masking & forcing

TIMER: TIMEHW Register

Offset : 0x00

4.6. Timer

540

RP2040 Datasheet

Table 528. TIMEHW
Register
Table 529. TIMELW
Register
Table 530. TIMEHR
Register
Table 531. TIMELR
Register
Table 532. ALARM0
Register
Table 533. ALARM1
Register
Bits Description Type Reset
31:0 Write to bits 63:32 of time
always write timelw before timehw
WF 0x00000000
TIMER: TIMELW Register
Offset: 0x04
Bits Description Type Reset
31:0 Write to bits 31:0 of time
writes do not get copied to time until timehw is written
WF 0x00000000
TIMER: TIMEHR Register
Offset: 0x08
Bits Description Type Reset
31:0 Read from bits 63:32 of time
always read timelr before timehr
RO 0x00000000
TIMER: TIMELR Register
Offset: 0x0c
Bits Description Type Reset
31:0 Read from bits 31:0 of time RO 0x00000000
TIMER: ALARM0 Register
Offset: 0x10
Bits Description Type Reset
31:0 Arm alarm 0, and configure the time it will fire.
Once armed, the alarm fires when TIMER_ALARM0 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
RW 0x00000000
TIMER: ALARM1 Register
Offset: 0x14
Bits Description Type Reset
31:0 Arm alarm 1, and configure the time it will fire.
Once armed, the alarm fires when TIMER_ALARM1 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
RW 0x00000000

TIMER: ALARM2 Register

Offset : 0x18

Table 534. ALARM2 Register

4.6. Timer

541

RP2040 Datasheet

Bits Description Type Reset
31:0 Arm alarm 2, and configure the time it will fire.
Once armed, the alarm fires when TIMER_ALARM2 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
RW 0x00000000

TIMER: ALARM3 Register

Offset : 0x1c

Table 535. ALARM3
Register
Table 536. ARMED
Register
Bits Description Type Reset
31:0 Arm alarm 3, and configure the time it will fire.
Once armed, the alarm fires when TIMER_ALARM3 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
RW 0x00000000
TIMER: ARMED Register
Offset: 0x20
Bits Description Type Reset
31:4 Reserved. - -
3:0 Indicates the armed/disarmed status of each alarm.
A write to the corresponding ALARMx register arms the alarm.
Alarms automatically disarm upon firing, but writing ones here
will disarm immediately without waiting to fire.
WC 0x0

TIMER: TIMERAWH Register

Offset : 0x24

Table 537. TIMERAWH
Register
Table 538. TIMERAWL
Register
Bits Description Type Reset
31:0 Raw read from bits 63:32 of time (no side effects) RO 0x00000000
TIMER: TIMERAWL Register
Offset: 0x28
Bits Description Type Reset
31:0 Raw read from bits 31:0 of time (no side effects) RO 0x00000000
TIMER: DBGPAUSE Register
Offset: 0x2c

Description

Set bits high to enable pause when the corresponding debug ports are active

Table 539. DBGPAUSE
Register
Bits Description Type Reset
31:3 Reserved. - -
2 DBG1: Pause when processor 1 is in debug mode RW 0x1
1 DBG0: Pause when processor 0 is in debug mode RW 0x1

4.6. Timer

542

RP2040 Datasheet

Bits Description Type Reset
0 Reserved. - -

TIMER: PAUSE Register

Offset : 0x30

Table 540. PAUSE Register

Bits Description Type Reset
31:1 Reserved. - -
0 Set high to pause the timer RW 0x0

TIMER: INTR Register

Offset : 0x34

Description

Raw Interrupts

Table 541. INTR Register

Bits Description Type Reset
31:4 Reserved. - -
3 ALARM_3 WC 0x0
2 ALARM_2 WC 0x0
1 ALARM_1 WC 0x0
0 ALARM_0 WC 0x0

TIMER: INTE Register

Offset : 0x38

Description

Interrupt Enable

Table 542. INTE Register

Bits Description Type Reset
31:4 Reserved. - -
3 ALARM_3 RW 0x0
2 ALARM_2 RW 0x0
1 ALARM_1 RW 0x0
0 ALARM_0 RW 0x0

TIMER: INTF Register

Offset : 0x3c

Description

Interrupt Force

Table 543. INTF Register

Bits Description Type Reset
31:4 Reserved. - -
3 ALARM_3 RW 0x0

4.6. Timer

543

RP2040 Datasheet

Bits Description Type Reset
2 ALARM_2 RW 0x0
1 ALARM_1 RW 0x0
0 ALARM_0 RW 0x0

TIMER: INTS Register

Offset : 0x40

Description

Interrupt status after masking & forcing

Table 544. INTS Register

Bits Description Type Reset
31:4 Reserved. - -
3 ALARM_3 RO 0x0
2 ALARM_2 RO 0x0
1 ALARM_1 RO 0x0
0 ALARM_0 RO 0x0