Expand description
AON (Always-On) Timer driver for RP2350
The AON Timer is a 64-bit counter that typically runs at 1 kHz (1ms resolution) and can operate during low-power modes. It’s part of the POWMAN peripheral and provides:
- Millisecond resolution counter
- Alarm support for wakeup from low-power modes (WFI/WFE and DORMANT)
- Async alarm waiting with interrupt support (POWMAN_IRQ_TIMER)
- Choice of XOSC or LPOSC clock sources
§Alarm Wake Modes
The AON Timer supports multiple wake modes via the AlarmWakeMode enum:
-
WfiOnly(default): Alarm triggersPOWMAN_IRQ_TIMERinterrupt to wake from WFI/WFE (light sleep). Usewait_for_alarm().awaitfor async waiting. Works with both XOSC and LPOSC clock sources. -
DormantOnly: Hardware power-up wake from DORMANT (deep sleep). Sets thePWRUP_ON_ALARMbit to trigger hardware power-up event (no interrupt, since CPU clock is stopped). Requirements:- Must use LPOSC clock source (XOSC is powered down in DORMANT)
- Requires Secure privilege level (TIMER register is Secure-only)
-
Both: Enables both interrupt wake (WFI/WFE) and hardware power-up wake (DORMANT). Subject to the same requirements asDormantOnlyfor DORMANT support. -
Disabled: Alarm flag is set but no wake mechanisms are enabled. Usealarm_fired()to manually poll the alarm status.
You can set the wake mode either in Config at initialization, or at runtime via
AonTimer::set_wake_mode().
§Security Considerations
The TIMER register (including the PWRUP_ON_ALARM bit) is Secure-only per the
RP2350 datasheet. Setting wake modes that involve DORMANT wake (DormantOnly or Both)
may fail silently or have no effect when running in Non-secure contexts. Methods
enable_dormant_wake(), disable_dormant_wake(), and set_wake_mode() that configure
DORMANT wake are subject to this restriction.
§Important Notes
- All POWMAN registers require password
0x5AFEin upper 16 bits for writes - Timer must be stopped before setting the counter value
- Resolution is 1ms (1 kHz tick rate)
§Example - WFI/WFE Wake (Default)
use embassy_rp::aon_timer::{AonTimer, Config, ClockSource, AlarmWakeMode};
use embassy_rp::bind_interrupts;
use embassy_time::Duration;
// Bind the interrupt handler
bind_interrupts!(struct Irqs {
POWMAN_IRQ_TIMER => embassy_rp::aon_timer::InterruptHandler;
});
let config = Config {
clock_source: ClockSource::Xosc,
clock_freq_khz: 12000, // 12 MHz
alarm_wake_mode: AlarmWakeMode::WfiOnly, // Default
};
let mut timer = AonTimer::new(p.POWMAN, Irqs, config);
timer.set_counter(0);
timer.start();
// Set an alarm and wait asynchronously (interrupt-based wake)
timer.set_alarm_after(Duration::from_secs(5)).unwrap();
timer.wait_for_alarm().await; // CPU enters WFI low-power mode§Example - DORMANT Wake
use embassy_rp::aon_timer::{AonTimer, Config, ClockSource, AlarmWakeMode};
use embassy_rp::bind_interrupts;
use embassy_time::Duration;
bind_interrupts!(struct Irqs {
POWMAN_IRQ_TIMER => embassy_rp::aon_timer::InterruptHandler;
});
let config = Config {
clock_source: ClockSource::Lposc, // Required for DORMANT
clock_freq_khz: 32, // ~32 kHz LPOSC
alarm_wake_mode: AlarmWakeMode::DormantOnly,
};
let mut timer = AonTimer::new(p.POWMAN, Irqs, config);
timer.set_counter(0);
timer.start();
// Set alarm for DORMANT wake (hardware power-up)
timer.set_alarm_after(Duration::from_secs(10)).unwrap();
// Enter DORMANT mode here - alarm will wake via power-up event§Example - Runtime Wake Mode Change
use embassy_rp::aon_timer::{AonTimer, Config, ClockSource, AlarmWakeMode};
use embassy_rp::bind_interrupts;
use embassy_time::Duration;
bind_interrupts!(struct Irqs {
POWMAN_IRQ_TIMER => embassy_rp::aon_timer::InterruptHandler;
});
let mut timer = AonTimer::new(p.POWMAN, Irqs, Config::default());
timer.set_counter(0);
timer.start();
// Use WFI wake initially
timer.set_alarm_after(Duration::from_secs(5)).unwrap();
timer.wait_for_alarm().await;
// Switch to both wake modes at runtime
timer.set_wake_mode(AlarmWakeMode::Both);
timer.set_alarm_after(Duration::from_secs(10)).unwrap();
// Now supports both WFI and DORMANT wake§Example - Using DateTime with AON Timer
use embassy_rp::aon_timer::{AonTimer, Config, DateTime, DayOfWeek};
use embassy_rp::bind_interrupts;
bind_interrupts!(struct Irqs {
POWMAN_IRQ_TIMER => embassy_rp::aon_timer::InterruptHandler;
});
let mut timer = AonTimer::new(p.POWMAN, Irqs, Config::default());
// Set timer to a specific DateTime (e.g., 2024-06-15 12:30:00 UTC)
let start_time = DateTime {
year: 2024,
month: 6,
day: 15,
day_of_week: DayOfWeek::Saturday,
hour: 12,
minute: 30,
second: 0,
};
timer.set_datetime(start_time).unwrap();
timer.start();
// Later, read current DateTime
let current = timer.now_as_datetime().unwrap();
info!("Current time: {}-{:02}-{:02} {:02}:{:02}:{:02}",
current.year, current.month, current.day,
current.hour, current.minute, current.second);
// Set alarm for specific DateTime (1 hour later)
let alarm_time = DateTime {
year: 2024,
month: 6,
day: 15,
day_of_week: DayOfWeek::Saturday,
hour: 13,
minute: 30,
second: 0,
};
timer.set_alarm_at_datetime(alarm_time).unwrap();
timer.wait_for_alarm().await;Structs§
- AonTimer
- AON Timer driver
- Config
- AON Timer configuration
- Date
Time - Structure containing date and time information
- Interrupt
Handler - Interrupt handler for AON Timer alarms
Enums§
- Alarm
Wake Mode - Alarm wake mode configuration
- Clock
Source - Clock source for the AON Timer
- Date
Time Error - Errors regarding the
DateTimestruct. - DayOf
Week - A day of the week
- Error
- AON Timer errors