mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 04:40:52 +00:00

* Rework hal initialization * Turn sw interrupt control into a virtual peripheral * Return a tuple instead of a named struct * Fix docs * Remove SystemClockControl * Move software interrupts under interrupt * Re-document what's left in system * Update time docs * Update sw int docs * Introduce Config * Fix tests * Remove redundant inits * Doc * Clean up examples&tests * Update tests * Add changelog entry * Start migration guide * Restore some convenience-imports * Remove Config from prelude
186 lines
5.1 KiB
Rust
186 lines
5.1 KiB
Rust
//! System Timer Test
|
|
|
|
// esp32 disabled as it does not have a systimer
|
|
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
|
|
|
|
#![no_std]
|
|
#![no_main]
|
|
|
|
use core::cell::RefCell;
|
|
|
|
use critical_section::Mutex;
|
|
use embedded_hal::delay::DelayNs;
|
|
use esp_hal::{
|
|
clock::Clocks,
|
|
delay::Delay,
|
|
prelude::*,
|
|
timer::systimer::{
|
|
Alarm,
|
|
FrozenUnit,
|
|
Periodic,
|
|
SpecificComparator,
|
|
SpecificUnit,
|
|
SystemTimer,
|
|
Target,
|
|
},
|
|
Blocking,
|
|
};
|
|
use fugit::ExtU32;
|
|
use hil_test as _;
|
|
use portable_atomic::{AtomicUsize, Ordering};
|
|
use static_cell::StaticCell;
|
|
|
|
type TestAlarm<M, const C: u8> =
|
|
Alarm<'static, M, Blocking, SpecificComparator<'static, C>, SpecificUnit<'static, 0>>;
|
|
|
|
static ALARM_TARGET: Mutex<RefCell<Option<TestAlarm<Target, 0>>>> = Mutex::new(RefCell::new(None));
|
|
static ALARM_PERIODIC: Mutex<RefCell<Option<TestAlarm<Periodic, 1>>>> =
|
|
Mutex::new(RefCell::new(None));
|
|
|
|
struct Context {
|
|
unit: FrozenUnit<'static, SpecificUnit<'static, 0>>,
|
|
comparator0: SpecificComparator<'static, 0>,
|
|
comparator1: SpecificComparator<'static, 1>,
|
|
clocks: Clocks<'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]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[init]
|
|
fn init() -> Context {
|
|
let (peripherals, clocks) = esp_hal::init(esp_hal::Config::default());
|
|
|
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
|
static UNIT0: StaticCell<SpecificUnit<'static, 0>> = StaticCell::new();
|
|
|
|
let unit0 = UNIT0.init(systimer.unit0);
|
|
let frozen_unit = FrozenUnit::new(unit0);
|
|
|
|
Context {
|
|
clocks,
|
|
unit: frozen_unit,
|
|
comparator0: systimer.comparator0,
|
|
comparator1: systimer.comparator1,
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[timeout(3)]
|
|
fn target_interrupt_is_handled(ctx: Context) {
|
|
let alarm0 = Alarm::new(ctx.comparator0, &ctx.unit);
|
|
|
|
critical_section::with(|cs| {
|
|
alarm0.set_interrupt_handler(pass_test_if_called);
|
|
alarm0.set_target(SystemTimer::now() + SystemTimer::ticks_per_second() / 10);
|
|
alarm0.enable_interrupt(true);
|
|
|
|
ALARM_TARGET.borrow_ref_mut(cs).replace(alarm0);
|
|
});
|
|
|
|
// We'll end the test in the interrupt handler.
|
|
loop {}
|
|
}
|
|
|
|
#[test]
|
|
#[timeout(3)]
|
|
fn target_interrupt_is_handled_once(ctx: Context) {
|
|
let alarm0 = Alarm::new(ctx.comparator0, &ctx.unit);
|
|
let alarm1 = Alarm::new(ctx.comparator1, &ctx.unit);
|
|
|
|
COUNTER.store(0, Ordering::Relaxed);
|
|
|
|
critical_section::with(|cs| {
|
|
alarm0.set_interrupt_handler(target_fail_test_if_called_twice);
|
|
alarm0.set_target(SystemTimer::now() + SystemTimer::ticks_per_second() / 10);
|
|
alarm0.enable_interrupt(true);
|
|
|
|
let alarm1 = alarm1.into_periodic();
|
|
alarm1.set_interrupt_handler(handle_periodic_interrupt);
|
|
alarm1.set_period(100u32.millis());
|
|
alarm1.enable_interrupt(true);
|
|
|
|
ALARM_TARGET.borrow_ref_mut(cs).replace(alarm0);
|
|
ALARM_PERIODIC.borrow_ref_mut(cs).replace(alarm1);
|
|
});
|
|
|
|
let mut delay = Delay::new(&ctx.clocks);
|
|
delay.delay_ms(300);
|
|
}
|
|
|
|
#[test]
|
|
#[timeout(3)]
|
|
fn periodic_interrupt_is_handled(ctx: Context) {
|
|
let alarm1 = Alarm::new(ctx.comparator1, &ctx.unit);
|
|
|
|
COUNTER.store(0, Ordering::Relaxed);
|
|
|
|
critical_section::with(|cs| {
|
|
let alarm1 = alarm1.into_periodic();
|
|
alarm1.set_interrupt_handler(pass_test_if_called_twice);
|
|
alarm1.set_period(100u32.millis());
|
|
alarm1.enable_interrupt(true);
|
|
|
|
ALARM_PERIODIC.borrow_ref_mut(cs).replace(alarm1);
|
|
});
|
|
|
|
// We'll end the test in the interrupt handler.
|
|
loop {}
|
|
}
|
|
}
|