mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-27 12:20:56 +00:00

* More consistent naming of interrupt-related functions * MG entry * changelog * use correct package for MG * fix hil * other drivers * address review comments
167 lines
4.3 KiB
Rust
167 lines
4.3 KiB
Rust
//! System Timer Test
|
|
|
|
// esp32 disabled as it does not have a systimer
|
|
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
|
|
//% FEATURES: unstable
|
|
|
|
#![no_std]
|
|
#![no_main]
|
|
|
|
use core::cell::RefCell;
|
|
|
|
use critical_section::Mutex;
|
|
use embedded_hal::delay::DelayNs;
|
|
use esp_hal::{
|
|
Blocking,
|
|
delay::Delay,
|
|
handler,
|
|
time::Duration,
|
|
timer::{
|
|
OneShotTimer,
|
|
PeriodicTimer,
|
|
systimer::{Alarm, SystemTimer},
|
|
},
|
|
};
|
|
use hil_test as _;
|
|
use portable_atomic::{AtomicUsize, Ordering};
|
|
|
|
esp_bootloader_esp_idf::esp_app_desc!();
|
|
|
|
static ALARM_TARGET: Mutex<RefCell<Option<OneShotTimer<'static, Blocking>>>> =
|
|
Mutex::new(RefCell::new(None));
|
|
static ALARM_PERIODIC: Mutex<RefCell<Option<PeriodicTimer<'static, Blocking>>>> =
|
|
Mutex::new(RefCell::new(None));
|
|
|
|
struct Context {
|
|
alarm0: Alarm<'static>,
|
|
alarm1: Alarm<'static>,
|
|
}
|
|
|
|
#[handler(priority = esp_hal::interrupt::Priority::min())]
|
|
fn pass_test_if_called() {
|
|
critical_section::with(|cs| {
|
|
ALARM_TARGET
|
|
.borrow_ref_mut(cs)
|
|
.as_mut()
|
|
.unwrap()
|
|
.clear_interrupt()
|
|
});
|
|
embedded_test::export::check_outcome(());
|
|
}
|
|
|
|
#[handler(priority = esp_hal::interrupt::Priority::min())]
|
|
fn handle_periodic_interrupt() {
|
|
critical_section::with(|cs| {
|
|
ALARM_PERIODIC
|
|
.borrow_ref_mut(cs)
|
|
.as_mut()
|
|
.unwrap()
|
|
.clear_interrupt()
|
|
});
|
|
}
|
|
|
|
static COUNTER: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
#[handler(priority = esp_hal::interrupt::Priority::min())]
|
|
fn pass_test_if_called_twice() {
|
|
critical_section::with(|cs| {
|
|
ALARM_PERIODIC
|
|
.borrow_ref_mut(cs)
|
|
.as_mut()
|
|
.unwrap()
|
|
.clear_interrupt()
|
|
});
|
|
COUNTER.fetch_add(1, Ordering::Relaxed);
|
|
if COUNTER.load(Ordering::Relaxed) == 2 {
|
|
embedded_test::export::check_outcome(());
|
|
}
|
|
}
|
|
|
|
#[handler(priority = esp_hal::interrupt::Priority::min())]
|
|
fn target_fail_test_if_called_twice() {
|
|
critical_section::with(|cs| {
|
|
ALARM_TARGET
|
|
.borrow_ref_mut(cs)
|
|
.as_mut()
|
|
.unwrap()
|
|
.clear_interrupt()
|
|
});
|
|
COUNTER.fetch_add(1, Ordering::Relaxed);
|
|
assert!(COUNTER.load(Ordering::Relaxed) != 2);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[embedded_test::tests(default_timeout = 3)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[init]
|
|
fn init() -> Context {
|
|
let peripherals = esp_hal::init(esp_hal::Config::default());
|
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
|
|
|
Context {
|
|
alarm0: systimer.alarm0,
|
|
alarm1: systimer.alarm1,
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn target_interrupt_is_handled(ctx: Context) {
|
|
let mut alarm0 = OneShotTimer::new(ctx.alarm0);
|
|
|
|
critical_section::with(|cs| {
|
|
alarm0.set_interrupt_handler(pass_test_if_called);
|
|
alarm0.listen();
|
|
alarm0.schedule(Duration::from_millis(10)).unwrap();
|
|
|
|
ALARM_TARGET.borrow_ref_mut(cs).replace(alarm0);
|
|
});
|
|
|
|
// We'll end the test in the interrupt handler.
|
|
loop {}
|
|
}
|
|
|
|
#[test]
|
|
fn target_interrupt_is_handled_once(ctx: Context) {
|
|
let mut alarm0 = OneShotTimer::new(ctx.alarm0);
|
|
let mut alarm1 = PeriodicTimer::new(ctx.alarm1);
|
|
|
|
COUNTER.store(0, Ordering::Relaxed);
|
|
|
|
critical_section::with(|cs| {
|
|
alarm0.set_interrupt_handler(target_fail_test_if_called_twice);
|
|
alarm0.listen();
|
|
alarm0.schedule(Duration::from_millis(10)).unwrap();
|
|
|
|
alarm1.set_interrupt_handler(handle_periodic_interrupt);
|
|
alarm1.listen();
|
|
alarm1.start(Duration::from_millis(100)).unwrap();
|
|
|
|
ALARM_TARGET.borrow_ref_mut(cs).replace(alarm0);
|
|
ALARM_PERIODIC.borrow_ref_mut(cs).replace(alarm1);
|
|
});
|
|
|
|
let mut delay = Delay::new();
|
|
delay.delay_ms(300);
|
|
}
|
|
|
|
#[test]
|
|
fn periodic_interrupt_is_handled(ctx: Context) {
|
|
let mut alarm1 = PeriodicTimer::new(ctx.alarm1);
|
|
|
|
COUNTER.store(0, Ordering::Relaxed);
|
|
|
|
critical_section::with(|cs| {
|
|
alarm1.set_interrupt_handler(pass_test_if_called_twice);
|
|
alarm1.listen();
|
|
alarm1.start(Duration::from_millis(100)).unwrap();
|
|
|
|
ALARM_PERIODIC.borrow_ref_mut(cs).replace(alarm1);
|
|
});
|
|
|
|
// We'll end the test in the interrupt handler.
|
|
loop {}
|
|
}
|
|
}
|