-
Notifications
You must be signed in to change notification settings - Fork 214
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Removes _all_ type params on Alarm * Systimer no longer implements peripheral ref, the peripheral ref pattern is instead intended to be used on the higher level timer drivers * Removed `Unit` as a type, in favour of an enum * Alarms are back in the main `SystemTimer` "driver" * Made all `Unit` modification methods unsafe, it's not possible to modify the `Unit`'s safely whilst timers and or the `time::now` API is in use
- Loading branch information
Showing
2 changed files
with
318 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
//! This shows how to use the SYSTIMER peripheral including interrupts. | ||
//! | ||
//! It's an additional timer besides the TIMG peripherals. | ||
|
||
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 | ||
|
||
#![no_std] | ||
#![no_main] | ||
|
||
use core::cell::RefCell; | ||
|
||
use critical_section::Mutex; | ||
use esp_backtrace as _; | ||
use esp_hal::{ | ||
delay::Delay, | ||
prelude::*, | ||
timer::systimer::{ | ||
Alarm, | ||
FrozenUnit, | ||
Periodic, | ||
SpecificComparator, | ||
SpecificUnit, | ||
SystemTimer, | ||
Target, | ||
}, | ||
Blocking, | ||
}; | ||
use esp_println::println; | ||
use fugit::ExtU32; | ||
use static_cell::StaticCell; | ||
|
||
static ALARM0: Mutex< | ||
RefCell< | ||
Option<Alarm<Periodic, Blocking, SpecificComparator<'static, 0>, SpecificUnit<'static, 0>>>, | ||
>, | ||
> = Mutex::new(RefCell::new(None)); | ||
static ALARM1: Mutex< | ||
RefCell< | ||
Option<Alarm<Target, Blocking, SpecificComparator<'static, 1>, SpecificUnit<'static, 0>>>, | ||
>, | ||
> = Mutex::new(RefCell::new(None)); | ||
static ALARM2: Mutex< | ||
RefCell< | ||
Option<Alarm<Target, Blocking, SpecificComparator<'static, 2>, SpecificUnit<'static, 0>>>, | ||
>, | ||
> = Mutex::new(RefCell::new(None)); | ||
|
||
#[entry] | ||
fn main() -> ! { | ||
let peripherals = esp_hal::init(esp_hal::Config::default()); | ||
|
||
let systimer = SystemTimer::new(peripherals.SYSTIMER); | ||
println!( | ||
"SYSTIMER Current value = {}", | ||
SystemTimer::now(Default::default()) | ||
); | ||
|
||
static UNIT0: StaticCell<SpecificUnit<'static, 0>> = StaticCell::new(); | ||
|
||
let unit0 = UNIT0.init(systimer.unit0); | ||
|
||
let frozen_unit = FrozenUnit::new(unit0); | ||
|
||
let alarm0 = Alarm::new(systimer.comparator0, &frozen_unit); | ||
let alarm1 = Alarm::new(systimer.comparator1, &frozen_unit); | ||
let alarm2 = Alarm::new(systimer.comparator2, &frozen_unit); | ||
|
||
critical_section::with(|cs| { | ||
let alarm0 = alarm0.into_periodic(); | ||
alarm0.set_interrupt_handler(systimer_target0); | ||
alarm0.set_period(1u32.secs()); | ||
alarm0.enable_interrupt(true); | ||
|
||
alarm1.set_interrupt_handler(systimer_target1); | ||
alarm1.set_target( | ||
SystemTimer::now(Default::default()) + (SystemTimer::ticks_per_second() * 2), | ||
); | ||
alarm1.enable_interrupt(true); | ||
|
||
alarm2.set_interrupt_handler(systimer_target2); | ||
alarm2.set_target( | ||
SystemTimer::now(Default::default()) + (SystemTimer::ticks_per_second() * 3), | ||
); | ||
alarm2.enable_interrupt(true); | ||
|
||
ALARM0.borrow_ref_mut(cs).replace(alarm0); | ||
ALARM1.borrow_ref_mut(cs).replace(alarm1); | ||
ALARM2.borrow_ref_mut(cs).replace(alarm2); | ||
}); | ||
|
||
let delay = Delay::new(); | ||
|
||
loop { | ||
delay.delay_millis(500); | ||
} | ||
} | ||
|
||
#[handler(priority = esp_hal::interrupt::Priority::min())] | ||
fn systimer_target0() { | ||
println!("Interrupt lvl1 (alarm0)"); | ||
critical_section::with(|cs| { | ||
ALARM0 | ||
.borrow_ref_mut(cs) | ||
.as_mut() | ||
.unwrap() | ||
.clear_interrupt() | ||
}); | ||
} | ||
|
||
#[handler(priority = esp_hal::interrupt::Priority::Priority1)] | ||
fn systimer_target1() { | ||
println!("Interrupt lvl2 (alarm1)"); | ||
critical_section::with(|cs| { | ||
ALARM1 | ||
.borrow_ref_mut(cs) | ||
.as_mut() | ||
.unwrap() | ||
.clear_interrupt() | ||
}); | ||
} | ||
|
||
#[handler(priority = esp_hal::interrupt::Priority::max())] | ||
fn systimer_target2() { | ||
println!("Interrupt lvl2 (alarm2)"); | ||
critical_section::with(|cs| { | ||
ALARM2 | ||
.borrow_ref_mut(cs) | ||
.as_mut() | ||
.unwrap() | ||
.clear_interrupt() | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
//! 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::{ | ||
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>, | ||
} | ||
|
||
#[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 = 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 { | ||
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(Default::default()) + 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(Default::default()) + 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(); | ||
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 {} | ||
} | ||
} |