Timers runtime isr binding (#1348)

* Runtime ISR binding for TIMG/SYSTIMER

* CHANGELOG.md

* Implement `set_interrupt_handler` only for blocking

* Adapt HIL test
This commit is contained in:
Björn Quentin 2024-04-03 10:14:27 +02:00 committed by GitHub
parent 81a40703bd
commit 256d7198f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 612 additions and 215 deletions

View File

@ -49,6 +49,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Runtime ISR binding for SHA,ECC and RSA (#1354) - Runtime ISR binding for SHA,ECC and RSA (#1354)
- Runtime ISR binding for I2C (#1376) - Runtime ISR binding for I2C (#1376)
- `UsbSerialJtag` can be created in async or blocking mode. The blocking constructor takes an optional interrupt handler argument (#1377) - `UsbSerialJtag` can be created in async or blocking mode. The blocking constructor takes an optional interrupt handler argument (#1377)
- SYSTIMER and TIMG instances can now be created in async or blocking mode. The blocking constructor takes an optional argument to set interrupt handlers. The constructors are named `create`/`create_async` (#1348)
- SYSTIMER and TIMG instances can now be created in async or blocking mode (#1348)
### Removed ### Removed

View File

@ -1,4 +1,5 @@
use critical_section::{CriticalSection, Mutex}; use critical_section::{CriticalSection, Mutex};
use procmacros::handler;
use super::AlarmState; use super::AlarmState;
use crate::{ use crate::{
@ -9,22 +10,22 @@ use crate::{
pub const ALARM_COUNT: usize = 3; pub const ALARM_COUNT: usize = 3;
pub type TimerType = SystemTimer<'static>; pub type TimerType = SystemTimer<'static, crate::Async>;
pub struct EmbassyTimer { pub struct EmbassyTimer {
pub(crate) alarms: Mutex<[AlarmState; ALARM_COUNT]>, pub(crate) alarms: Mutex<[AlarmState; ALARM_COUNT]>,
pub(crate) alarm0: Alarm<Target, 0>, pub(crate) alarm0: Alarm<Target, crate::Async, 0>,
pub(crate) alarm1: Alarm<Target, 1>, pub(crate) alarm1: Alarm<Target, crate::Async, 1>,
pub(crate) alarm2: Alarm<Target, 2>, pub(crate) alarm2: Alarm<Target, crate::Async, 2>,
} }
const ALARM_STATE_NONE: AlarmState = AlarmState::new(); const ALARM_STATE_NONE: AlarmState = AlarmState::new();
embassy_time_driver::time_driver_impl!(static DRIVER: EmbassyTimer = EmbassyTimer { embassy_time_driver::time_driver_impl!(static DRIVER: EmbassyTimer = EmbassyTimer {
alarms: Mutex::new([ALARM_STATE_NONE; ALARM_COUNT]), alarms: Mutex::new([ALARM_STATE_NONE; ALARM_COUNT]),
alarm0: unsafe { Alarm::<_, 0>::conjure() }, alarm0: unsafe { Alarm::<_, crate::Async, 0>::conjure() },
alarm1: unsafe { Alarm::<_, 1>::conjure() }, alarm1: unsafe { Alarm::<_, crate::Async, 1>::conjure() },
alarm2: unsafe { Alarm::<_, 2>::conjure() }, alarm2: unsafe { Alarm::<_, crate::Async, 2>::conjure() },
}); });
impl EmbassyTimer { impl EmbassyTimer {
@ -42,9 +43,9 @@ impl EmbassyTimer {
pub(super) fn on_alarm_allocated(&self, n: usize) { pub(super) fn on_alarm_allocated(&self, n: usize) {
match n { match n {
0 => self.alarm0.enable_interrupt(true), 0 => self.alarm0.enable_interrupt_internal(true),
1 => self.alarm1.enable_interrupt(true), 1 => self.alarm1.enable_interrupt_internal(true),
2 => self.alarm2.enable_interrupt(true), 2 => self.alarm2.enable_interrupt_internal(true),
_ => {} _ => {}
} }
} }
@ -57,31 +58,47 @@ impl EmbassyTimer {
} }
pub fn init(_clocks: &Clocks, _systimer: TimerType) { pub fn init(_clocks: &Clocks, _systimer: TimerType) {
use crate::{interrupt, interrupt::Priority, macros::interrupt}; unsafe {
crate::interrupt::bind_interrupt(
peripherals::Interrupt::SYSTIMER_TARGET0,
target0_handler.handler(),
);
unwrap!(crate::interrupt::enable(
peripherals::Interrupt::SYSTIMER_TARGET0,
target0_handler.priority()
));
unwrap!(interrupt::enable( crate::interrupt::bind_interrupt(
peripherals::Interrupt::SYSTIMER_TARGET0, peripherals::Interrupt::SYSTIMER_TARGET1,
Priority::max() target1_handler.handler(),
)); );
unwrap!(interrupt::enable( unwrap!(crate::interrupt::enable(
peripherals::Interrupt::SYSTIMER_TARGET1, peripherals::Interrupt::SYSTIMER_TARGET1,
Priority::max() target1_handler.priority()
)); ));
unwrap!(interrupt::enable(
peripherals::Interrupt::SYSTIMER_TARGET2,
Priority::max()
));
#[interrupt] crate::interrupt::bind_interrupt(
fn SYSTIMER_TARGET0() { peripherals::Interrupt::SYSTIMER_TARGET2,
target2_handler.handler(),
);
unwrap!(crate::interrupt::enable(
peripherals::Interrupt::SYSTIMER_TARGET2,
target2_handler.priority()
));
}
#[handler]
fn target0_handler() {
DRIVER.on_interrupt(0); DRIVER.on_interrupt(0);
} }
#[interrupt]
fn SYSTIMER_TARGET1() { #[handler]
fn target1_handler() {
DRIVER.on_interrupt(1); DRIVER.on_interrupt(1);
} }
#[interrupt]
fn SYSTIMER_TARGET2() { #[handler]
fn target2_handler() {
DRIVER.on_interrupt(2); DRIVER.on_interrupt(2);
} }
} }
@ -109,9 +126,9 @@ impl EmbassyTimer {
fn clear_interrupt(&self, id: usize) { fn clear_interrupt(&self, id: usize) {
match id { match id {
0 => self.alarm0.clear_interrupt(), 0 => self.alarm0.clear_interrupt_internal(),
1 => self.alarm1.clear_interrupt(), 1 => self.alarm1.clear_interrupt_internal(),
2 => self.alarm2.clear_interrupt(), 2 => self.alarm2.clear_interrupt_internal(),
_ => {} _ => {}
} }
} }

View File

@ -16,7 +16,7 @@ pub const ALARM_COUNT: usize = 1;
#[cfg(any(esp32, esp32s2, esp32s3))] #[cfg(any(esp32, esp32s2, esp32s3))]
pub const ALARM_COUNT: usize = 2; pub const ALARM_COUNT: usize = 2;
pub type TimerType = TimerGroup<'static, TIMG0>; pub type TimerType = TimerGroup<'static, TIMG0, crate::Async>;
pub struct EmbassyTimer { pub struct EmbassyTimer {
pub(crate) alarms: Mutex<[AlarmState; ALARM_COUNT]>, pub(crate) alarms: Mutex<[AlarmState; ALARM_COUNT]>,
@ -51,8 +51,6 @@ impl EmbassyTimer {
} }
pub fn init(clocks: &Clocks, mut timer: TimerType) { pub fn init(clocks: &Clocks, mut timer: TimerType) {
use crate::{interrupt, interrupt::Priority};
// set divider to get a 1mhz clock. APB (80mhz) / 80 = 1mhz... // set divider to get a 1mhz clock. APB (80mhz) / 80 = 1mhz...
// TODO: assert APB clock is the source and its at the correct speed for the // TODO: assert APB clock is the source and its at the correct speed for the
// divider // divider
@ -65,25 +63,39 @@ impl EmbassyTimer {
timer.timer1.set_counter_active(true); timer.timer1.set_counter_active(true);
} }
unwrap!(interrupt::enable( unsafe {
peripherals::Interrupt::TG0_T0_LEVEL, crate::interrupt::bind_interrupt(
Priority::max() crate::peripherals::Interrupt::TG0_T0_LEVEL,
)); tg0_t0_level.handler(),
);
crate::interrupt::enable(
crate::peripherals::Interrupt::TG0_T0_LEVEL,
tg0_t0_level.priority(),
)
.unwrap();
}
#[cfg(any(esp32, esp32s2, esp32s3))] #[cfg(any(esp32, esp32s2, esp32s3))]
unwrap!(interrupt::enable( unsafe {
peripherals::Interrupt::TG0_T1_LEVEL, crate::interrupt::bind_interrupt(
Priority::max() crate::peripherals::Interrupt::TG0_T1_LEVEL,
)); tg0_t1_level.handler(),
);
crate::interrupt::enable(
crate::peripherals::Interrupt::TG0_T1_LEVEL,
tg0_t1_level.priority(),
)
.unwrap();
}
#[interrupt] #[handler(priority = crate::interrupt::Priority::max())]
fn TG0_T0_LEVEL() { fn tg0_t0_level() {
let timer = unsafe { Timer0::<TIMG0>::steal() }; let timer = unsafe { Timer0::<TIMG0>::steal() };
DRIVER.on_interrupt(0, timer); DRIVER.on_interrupt(0, timer);
} }
#[cfg(any(esp32, esp32s2, esp32s3))] #[cfg(any(esp32, esp32s2, esp32s3))]
#[interrupt] #[handler(priority = crate::interrupt::Priority::max())]
fn TG0_T1_LEVEL() { fn tg0_t1_level() {
let timer = unsafe { Timer1::<TIMG0>::steal() }; let timer = unsafe { Timer1::<TIMG0>::steal() };
DRIVER.on_interrupt(1, timer); DRIVER.on_interrupt(1, timer);
} }

View File

@ -96,6 +96,6 @@ unsafe fn post_init() {
let mut rtc = Rtc::new(LPWR::steal()); let mut rtc = Rtc::new(LPWR::steal());
rtc.rwdt.disable(); rtc.rwdt.disable();
Wdt::<TIMG0>::set_wdt_enabled(false); Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
Wdt::<TIMG1>::set_wdt_enabled(false); Wdt::<TIMG1, crate::Blocking>::set_wdt_enabled(false);
} }

View File

@ -31,5 +31,5 @@ unsafe fn post_init() {
rtc.swd.disable(); rtc.swd.disable();
rtc.rwdt.disable(); rtc.rwdt.disable();
Wdt::<TIMG0>::set_wdt_enabled(false); Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
} }

View File

@ -43,6 +43,6 @@ unsafe fn post_init() {
rtc.swd.disable(); rtc.swd.disable();
rtc.rwdt.disable(); rtc.rwdt.disable();
Wdt::<TIMG0>::set_wdt_enabled(false); Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
Wdt::<TIMG1>::set_wdt_enabled(false); Wdt::<TIMG1, crate::Blocking>::set_wdt_enabled(false);
} }

View File

@ -49,6 +49,6 @@ unsafe fn post_init() {
rtc.swd.disable(); rtc.swd.disable();
rtc.rwdt.disable(); rtc.rwdt.disable();
Wdt::<TIMG0>::set_wdt_enabled(false); Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
Wdt::<TIMG1>::set_wdt_enabled(false); Wdt::<TIMG1, crate::Blocking>::set_wdt_enabled(false);
} }

View File

@ -48,6 +48,6 @@ unsafe fn post_init() {
rtc.swd.disable(); rtc.swd.disable();
rtc.rwdt.disable(); rtc.rwdt.disable();
Wdt::<TIMG0>::set_wdt_enabled(false); Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
Wdt::<TIMG1>::set_wdt_enabled(false); Wdt::<TIMG1, crate::Blocking>::set_wdt_enabled(false);
} }

View File

@ -100,6 +100,6 @@ unsafe fn post_init() {
let mut rtc = Rtc::new(LPWR::steal()); let mut rtc = Rtc::new(LPWR::steal());
rtc.rwdt.disable(); rtc.rwdt.disable();
Wdt::<TIMG0>::set_wdt_enabled(false); Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
Wdt::<TIMG1>::set_wdt_enabled(false); Wdt::<TIMG1, crate::Blocking>::set_wdt_enabled(false);
} }

View File

@ -134,6 +134,6 @@ unsafe fn post_init() {
let mut rtc = Rtc::new(LPWR::steal()); let mut rtc = Rtc::new(LPWR::steal());
rtc.rwdt.disable(); rtc.rwdt.disable();
Wdt::<TIMG0>::set_wdt_enabled(false); Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
Wdt::<TIMG1>::set_wdt_enabled(false); Wdt::<TIMG1, crate::Blocking>::set_wdt_enabled(false);
} }

View File

@ -31,7 +31,8 @@ use core::{marker::PhantomData, mem::transmute};
use fugit::MicrosDurationU32; use fugit::MicrosDurationU32;
use crate::{ use crate::{
peripheral::{Peripheral, PeripheralRef}, interrupt::InterruptHandler,
peripheral::Peripheral,
peripherals::{ peripherals::{
generic::Reg, generic::Reg,
systimer::{ systimer::{
@ -45,42 +46,45 @@ use crate::{
// TODO this only handles unit0 of the systimer // TODO this only handles unit0 of the systimer
pub struct SystemTimer<'d> { /// The SystemTimer
_inner: PeripheralRef<'d, SYSTIMER>, pub struct SystemTimer<'d, DM: crate::Mode> {
pub alarm0: Alarm<Target, 0>, pub alarm0: Alarm<Target, DM, 0>,
pub alarm1: Alarm<Target, 1>, pub alarm1: Alarm<Target, DM, 1>,
pub alarm2: Alarm<Target, 2>, pub alarm2: Alarm<Target, DM, 2>,
_phantom: &'d PhantomData<()>,
} }
impl<'d> SystemTimer<'d> { impl<'d> SystemTimer<'d, crate::Blocking> {
/// Bitmask to be applied to the raw register value
#[cfg(esp32s2)] #[cfg(esp32s2)]
pub const BIT_MASK: u64 = u64::MAX; pub const BIT_MASK: u64 = u64::MAX;
#[cfg(not(esp32s2))] #[cfg(not(esp32s2))]
pub const BIT_MASK: u64 = 0xF_FFFF_FFFF_FFFF; pub const BIT_MASK: u64 = 0xF_FFFF_FFFF_FFFF;
/// The ticks per second the underlying peripheral uses
#[cfg(esp32s2)] #[cfg(esp32s2)]
pub const TICKS_PER_SECOND: u64 = 80_000_000; // TODO this can change when we have support for changing APB frequency pub const TICKS_PER_SECOND: u64 = 80_000_000; // TODO this can change when we have support for changing APB frequency
#[cfg(not(esp32s2))] #[cfg(not(esp32s2))]
pub const TICKS_PER_SECOND: u64 = 16_000_000; pub const TICKS_PER_SECOND: u64 = 16_000_000;
pub fn new(p: impl Peripheral<P = SYSTIMER> + 'd) -> Self { /// Create a new instance in [crate::Blocking] mode.
crate::into_ref!(p); pub fn new(_p: impl Peripheral<P = SYSTIMER> + 'd) -> Self {
#[cfg(soc_etm)] #[cfg(soc_etm)]
etm::enable_etm(); etm::enable_etm();
Self { Self {
_inner: p,
alarm0: Alarm::new(), alarm0: Alarm::new(),
alarm1: Alarm::new(), alarm1: Alarm::new(),
alarm2: Alarm::new(), alarm2: Alarm::new(),
_phantom: &PhantomData,
} }
} }
// TODO use fugit types // TODO use fugit types
/// Get the current count of the system-timer.
pub fn now() -> u64 { pub fn now() -> u64 {
// This should be safe to access from multiple contexts // This should be safe to access from multiple contexts
// worst case scenario the second accesor ends up reading // worst case scenario the second accessor ends up reading
// an older time stamp // an older time stamp
let systimer = unsafe { &*SYSTIMER::ptr() }; let systimer = unsafe { &*SYSTIMER::ptr() };
systimer systimer
@ -101,43 +105,41 @@ impl<'d> SystemTimer<'d> {
} }
} }
impl<'d> SystemTimer<'d, crate::Async> {
/// Create a new instance in [crate::Async] mode.
pub fn new_async(_p: impl Peripheral<P = SYSTIMER> + 'd) -> Self {
#[cfg(soc_etm)]
etm::enable_etm();
Self {
alarm0: Alarm::new(),
alarm1: Alarm::new(),
alarm2: Alarm::new(),
_phantom: &PhantomData,
}
}
}
/// A marker for a [Alarm] in target mode.
#[derive(Debug)] #[derive(Debug)]
pub struct Target; pub struct Target;
/// A marker for a [Alarm] in periodic mode.
#[derive(Debug)] #[derive(Debug)]
pub struct Periodic; // TODO, also impl e-h timer traits pub struct Periodic; // TODO, also impl e-h timer traits
/// A single alarm.
#[derive(Debug)] #[derive(Debug)]
pub struct Alarm<MODE, const CHANNEL: u8> { pub struct Alarm<MODE, DM: crate::Mode, const CHANNEL: u8> {
_pd: PhantomData<MODE>, _pd: PhantomData<(MODE, DM)>,
} }
impl<T, const CHANNEL: u8> Alarm<T, CHANNEL> { impl<T, DM: crate::Mode, const CHANNEL: u8> Alarm<T, DM, CHANNEL> {
// private constructor // private constructor
fn new() -> Self { fn new() -> Self {
Self { _pd: PhantomData } Self { _pd: PhantomData }
} }
pub fn enable_interrupt(&self, val: bool) {
let systimer = unsafe { &*SYSTIMER::ptr() };
match CHANNEL {
0 => systimer.int_ena().modify(|_, w| w.target0().bit(val)),
1 => systimer.int_ena().modify(|_, w| w.target1().bit(val)),
2 => systimer.int_ena().modify(|_, w| w.target2().bit(val)),
_ => unreachable!(),
}
}
pub fn clear_interrupt(&self) {
let systimer = unsafe { &*SYSTIMER::ptr() };
match CHANNEL {
0 => systimer.int_clr().write(|w| w.target0().clear_bit_by_one()),
1 => systimer.int_clr().write(|w| w.target1().clear_bit_by_one()),
2 => systimer.int_clr().write(|w| w.target2().clear_bit_by_one()),
_ => unreachable!(),
}
}
fn configure( fn configure(
&self, &self,
conf: impl FnOnce(&Reg<TARGET0_CONF_SPEC>, &Reg<TARGET0_HI_SPEC>, &Reg<TARGET0_LO_SPEC>), conf: impl FnOnce(&Reg<TARGET0_CONF_SPEC>, &Reg<TARGET0_HI_SPEC>, &Reg<TARGET0_LO_SPEC>),
@ -212,9 +214,78 @@ impl<T, const CHANNEL: u8> Alarm<T, CHANNEL> {
}); });
} }
} }
pub(crate) fn enable_interrupt_internal(&self, val: bool) {
let systimer = unsafe { &*SYSTIMER::ptr() };
match CHANNEL {
0 => systimer.int_ena().modify(|_, w| w.target0().bit(val)),
1 => systimer.int_ena().modify(|_, w| w.target1().bit(val)),
2 => systimer.int_ena().modify(|_, w| w.target2().bit(val)),
_ => unreachable!(),
}
}
pub(crate) fn clear_interrupt_internal(&self) {
let systimer = unsafe { &*SYSTIMER::ptr() };
match CHANNEL {
0 => systimer.int_clr().write(|w| w.target0().clear_bit_by_one()),
1 => systimer.int_clr().write(|w| w.target1().clear_bit_by_one()),
2 => systimer.int_clr().write(|w| w.target2().clear_bit_by_one()),
_ => unreachable!(),
}
}
} }
impl<const CHANNEL: u8> Alarm<Target, CHANNEL> { impl<T, const CHANNEL: u8> Alarm<T, crate::Blocking, CHANNEL> {
/// Set the interrupt handler for this alarm.
pub fn set_interrupt_handler(&self, handler: InterruptHandler) {
match CHANNEL {
0 => unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::SYSTIMER_TARGET0,
handler.handler(),
);
unwrap!(crate::interrupt::enable(
crate::peripherals::Interrupt::SYSTIMER_TARGET0,
handler.priority(),
));
},
1 => unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::SYSTIMER_TARGET1,
handler.handler(),
);
unwrap!(crate::interrupt::enable(
crate::peripherals::Interrupt::SYSTIMER_TARGET1,
handler.priority(),
));
},
2 => unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::SYSTIMER_TARGET2,
handler.handler(),
);
unwrap!(crate::interrupt::enable(
crate::peripherals::Interrupt::SYSTIMER_TARGET2,
handler.priority(),
));
},
_ => unreachable!(),
}
}
/// Enable the interrupt for this alarm.
pub fn enable_interrupt(&self, val: bool) {
self.enable_interrupt_internal(val);
}
/// Enable the interrupt pending status for this alarm.
pub fn clear_interrupt(&self) {
self.clear_interrupt_internal();
}
}
impl<DM: crate::Mode, const CHANNEL: u8> Alarm<Target, DM, CHANNEL> {
/// Set the target value of this [Alarm]
pub fn set_target(&self, timestamp: u64) { pub fn set_target(&self, timestamp: u64) {
self.configure(|tconf, hi, lo| unsafe { self.configure(|tconf, hi, lo| unsafe {
tconf.write(|w| w.target0_period_mode().clear_bit()); // target mode tconf.write(|w| w.target0_period_mode().clear_bit()); // target mode
@ -223,12 +294,14 @@ impl<const CHANNEL: u8> Alarm<Target, CHANNEL> {
}) })
} }
pub fn into_periodic(self) -> Alarm<Periodic, CHANNEL> { /// Converts this [Alarm] into [Periodic] mode
pub fn into_periodic(self) -> Alarm<Periodic, DM, CHANNEL> {
Alarm { _pd: PhantomData } Alarm { _pd: PhantomData }
} }
} }
impl<const CHANNEL: u8> Alarm<Periodic, CHANNEL> { impl<DM: crate::Mode, const CHANNEL: u8> Alarm<Periodic, DM, CHANNEL> {
/// Set the period of this [Alarm]
pub fn set_period(&self, period: MicrosDurationU32) { pub fn set_period(&self, period: MicrosDurationU32) {
let us = period.ticks(); let us = period.ticks();
let ticks = us * (SystemTimer::TICKS_PER_SECOND / 1_000_000) as u32; let ticks = us * (SystemTimer::TICKS_PER_SECOND / 1_000_000) as u32;
@ -245,12 +318,13 @@ impl<const CHANNEL: u8> Alarm<Periodic, CHANNEL> {
}); });
} }
pub fn into_target(self) -> Alarm<Target, CHANNEL> { /// Converts this [Alarm] into [Target] mode
pub fn into_target(self) -> Alarm<Target, DM, CHANNEL> {
Alarm { _pd: PhantomData } Alarm { _pd: PhantomData }
} }
} }
impl<T> Alarm<T, 0> { impl<T, DM: crate::Mode> Alarm<T, DM, 0> {
/// Conjure an alarm out of thin air. /// Conjure an alarm out of thin air.
/// ///
/// # Safety /// # Safety
@ -262,7 +336,7 @@ impl<T> Alarm<T, 0> {
} }
} }
impl<T> Alarm<T, 1> { impl<T, DM: crate::Mode> Alarm<T, DM, 1> {
/// Conjure an alarm out of thin air. /// Conjure an alarm out of thin air.
/// ///
/// # Safety /// # Safety
@ -274,7 +348,7 @@ impl<T> Alarm<T, 1> {
} }
} }
impl<T> Alarm<T, 2> { impl<T, DM: crate::Mode> Alarm<T, DM, 2> {
/// Conjure an alarm out of thin air. /// Conjure an alarm out of thin air.
/// ///
/// # Safety /// # Safety
@ -286,13 +360,8 @@ impl<T> Alarm<T, 2> {
} }
} }
// FIXME: The `embedded_hal_async::delay::DelayUs` trait implementation // Async functionality of the system timer.
// interferes with the embassy time driver, which also uses the #[cfg(feature = "async")]
// `SYSTIMER` peripheral. Until we come up with a solution, do not
// implement this trait if the `embassy-time-systick` feature is enabled.
// #[cfg(all(feature = "async", not(feature = "embassy-time-systick")))]
// HACK: disable `asynch` module *always* until we come up with a solution
#[cfg(not(systimer))]
mod asynch { mod asynch {
use core::{ use core::{
pin::Pin, pin::Pin,
@ -300,7 +369,7 @@ mod asynch {
}; };
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use procmacros::interrupt; use procmacros::handler;
use super::*; use super::*;
@ -310,13 +379,34 @@ mod asynch {
static WAKERS: [AtomicWaker; NUM_ALARMS] = [INIT; NUM_ALARMS]; static WAKERS: [AtomicWaker; NUM_ALARMS] = [INIT; NUM_ALARMS];
pub(crate) struct AlarmFuture<'a, const N: u8> { pub(crate) struct AlarmFuture<'a, const N: u8> {
phantom: PhantomData<&'a Alarm<Periodic, N>>, phantom: PhantomData<&'a Alarm<Periodic, crate::Async, N>>,
} }
impl<'a, const N: u8> AlarmFuture<'a, N> { impl<'a, const N: u8> AlarmFuture<'a, N> {
pub(crate) fn new(alarm: &'a Alarm<Periodic, N>) -> Self { pub(crate) fn new(alarm: &'a Alarm<Periodic, crate::Async, N>) -> Self {
alarm.clear_interrupt(); alarm.clear_interrupt_internal();
alarm.enable_interrupt(true);
let (interrupt, handler) = match N {
0 => (
crate::peripherals::Interrupt::SYSTIMER_TARGET0,
target0_handler,
),
1 => (
crate::peripherals::Interrupt::SYSTIMER_TARGET1,
target1_handler,
),
_ => (
crate::peripherals::Interrupt::SYSTIMER_TARGET2,
target2_handler,
),
};
unsafe {
crate::interrupt::bind_interrupt(interrupt, handler.handler());
crate::interrupt::enable(interrupt, handler.priority()).unwrap();
}
alarm.enable_interrupt_internal(true);
Self { Self {
phantom: PhantomData, phantom: PhantomData,
@ -325,7 +415,7 @@ mod asynch {
fn event_bit_is_clear(&self) -> bool { fn event_bit_is_clear(&self) -> bool {
let r = unsafe { &*crate::peripherals::SYSTIMER::PTR } let r = unsafe { &*crate::peripherals::SYSTIMER::PTR }
.int_ena .int_ena()
.read(); .read();
match N { match N {
@ -351,9 +441,11 @@ mod asynch {
} }
} }
impl<const CHANNEL: u8> embedded_hal_async::delay::DelayUs for Alarm<Periodic, CHANNEL> { impl<const CHANNEL: u8> embedded_hal_async::delay::DelayNs
async fn delay_us(&mut self, us: u32) { for Alarm<Periodic, crate::Async, CHANNEL>
let period = MicrosDurationU32::from_ticks(us); {
async fn delay_ns(&mut self, ns: u32) {
let period = MicrosDurationU32::from_ticks(ns / 1000);
self.set_period(period); self.set_period(period);
AlarmFuture::new(self).await; AlarmFuture::new(self).await;
@ -366,28 +458,28 @@ mod asynch {
} }
} }
#[interrupt] #[handler]
fn SYSTIMER_TARGET0() { fn target0_handler() {
unsafe { &*crate::peripherals::SYSTIMER::PTR } unsafe { &*crate::peripherals::SYSTIMER::PTR }
.int_ena .int_ena()
.modify(|_, w| w.target0().clear_bit()); .modify(|_, w| w.target0().clear_bit());
WAKERS[0].wake(); WAKERS[0].wake();
} }
#[interrupt] #[handler]
fn SYSTIMER_TARGET1() { fn target1_handler() {
unsafe { &*crate::peripherals::SYSTIMER::PTR } unsafe { &*crate::peripherals::SYSTIMER::PTR }
.int_ena .int_ena()
.modify(|_, w| w.target1().clear_bit()); .modify(|_, w| w.target1().clear_bit());
WAKERS[1].wake(); WAKERS[1].wake();
} }
#[interrupt] #[handler]
fn SYSTIMER_TARGET2() { fn target2_handler() {
unsafe { &*crate::peripherals::SYSTIMER::PTR } unsafe { &*crate::peripherals::SYSTIMER::PTR }
.int_ena .int_ena()
.modify(|_, w| w.target2().clear_bit()); .modify(|_, w| w.target2().clear_bit());
WAKERS[2].wake(); WAKERS[2].wake();
@ -420,26 +512,29 @@ pub mod etm {
use super::*; use super::*;
/// An ETM controlled SYSTIMER event /// An ETM controlled SYSTIMER event
pub struct SysTimerEtmEvent<'a, M, const N: u8> { pub struct SysTimerEtmEvent<'a, M, DM: crate::Mode, const N: u8> {
alarm: &'a mut Alarm<M, N>, alarm: &'a mut Alarm<M, DM, N>,
} }
impl<'a, M, const N: u8> SysTimerEtmEvent<'a, M, N> { impl<'a, M, DM: crate::Mode, const N: u8> SysTimerEtmEvent<'a, M, DM, N> {
/// Creates an ETM event from the given [Alarm] /// Creates an ETM event from the given [Alarm]
pub fn new(alarm: &'a mut Alarm<M, N>) -> Self { pub fn new(alarm: &'a mut Alarm<M, DM, N>) -> Self {
Self { alarm } Self { alarm }
} }
/// Execute closure f with mutable access to the wrapped [Alarm]. /// Execute closure f with mutable access to the wrapped [Alarm].
pub fn with<R>(&self, f: impl FnOnce(&&'a mut Alarm<M, N>) -> R) -> R { pub fn with<R>(&self, f: impl FnOnce(&&'a mut Alarm<M, DM, N>) -> R) -> R {
let alarm = &self.alarm; let alarm = &self.alarm;
f(alarm) f(alarm)
} }
} }
impl<'a, M, const N: u8> crate::private::Sealed for SysTimerEtmEvent<'a, M, N> {} impl<'a, M, DM: crate::Mode, const N: u8> crate::private::Sealed
for SysTimerEtmEvent<'a, M, DM, N>
{
}
impl<'a, M, const N: u8> crate::etm::EtmEvent for SysTimerEtmEvent<'a, M, N> { impl<'a, M, DM: crate::Mode, const N: u8> crate::etm::EtmEvent for SysTimerEtmEvent<'a, M, DM, N> {
fn id(&self) -> u8 { fn id(&self) -> u8 {
50 + N 50 + N
} }

View File

@ -47,6 +47,7 @@ use crate::peripherals::TIMG1;
use crate::soc::constants::TIMG_DEFAULT_CLK_SRC; use crate::soc::constants::TIMG_DEFAULT_CLK_SRC;
use crate::{ use crate::{
clock::Clocks, clock::Clocks,
interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::{timg0::RegisterBlock, TIMG0}, peripherals::{timg0::RegisterBlock, TIMG0},
system::PeripheralClockControl, system::PeripheralClockControl,
@ -61,17 +62,32 @@ pub enum Error {
AlarmInactive, AlarmInactive,
} }
/// Interrupts which can be registered in [crate::Blocking] mode
#[derive(Debug, Default)]
pub struct TimerInterrupts {
pub timer0_t0: Option<InterruptHandler>,
pub timer0_t1: Option<InterruptHandler>,
pub timer0_wdt: Option<InterruptHandler>,
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
pub timer1_t0: Option<InterruptHandler>,
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
pub timer1_t1: Option<InterruptHandler>,
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
pub timer1_wdt: Option<InterruptHandler>,
}
// A timergroup consisting of up to 2 timers (chip dependent) and a watchdog // A timergroup consisting of up to 2 timers (chip dependent) and a watchdog
// timer // timer
pub struct TimerGroup<'d, T> pub struct TimerGroup<'d, T, DM>
where where
T: TimerGroupInstance, T: TimerGroupInstance,
DM: crate::Mode,
{ {
_timer_group: PeripheralRef<'d, T>, _timer_group: PeripheralRef<'d, T>,
pub timer0: Timer<Timer0<T>>, pub timer0: Timer<Timer0<T>, DM>,
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
pub timer1: Timer<Timer1<T>>, pub timer1: Timer<Timer1<T>, DM>,
pub wdt: Wdt<T>, pub wdt: Wdt<T, DM>,
} }
pub trait TimerGroupInstance { pub trait TimerGroupInstance {
@ -181,11 +197,144 @@ impl TimerGroupInstance for TIMG1 {
} }
} }
impl<'d, T> TimerGroup<'d, T> impl<'d, T> TimerGroup<'d, T, crate::Blocking>
where where
T: TimerGroupInstance, T: TimerGroupInstance,
{ {
pub fn new(timer_group: impl Peripheral<P = T> + 'd, clocks: &Clocks) -> Self { pub fn new(
timer_group: impl Peripheral<P = T> + 'd,
clocks: &Clocks,
isr: Option<TimerInterrupts>,
) -> Self {
crate::into_ref!(timer_group);
T::configure_src_clk();
// ESP32-H2 is using PLL_48M_CLK source instead of APB_CLK
let timer0 = Timer::new(
Timer0 {
phantom: PhantomData,
},
#[cfg(not(esp32h2))]
clocks.apb_clock,
#[cfg(esp32h2)]
clocks.pll_48m_clock,
);
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
let timer1 = Timer::new(
Timer1 {
phantom: PhantomData,
},
clocks.apb_clock,
);
if let Some(isr) = isr {
if let Some(handler) = isr.timer0_t0 {
unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::TG0_T0_LEVEL,
handler.handler(),
);
crate::interrupt::enable(
crate::peripherals::Interrupt::TG0_T0_LEVEL,
handler.priority(),
)
.unwrap();
}
}
#[cfg(any(esp32, esp32s2, esp32s3))]
if let Some(handler) = isr.timer0_t1 {
unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::TG0_T1_LEVEL,
handler.handler(),
);
crate::interrupt::enable(
crate::peripherals::Interrupt::TG0_T1_LEVEL,
handler.priority(),
)
.unwrap();
}
}
if let Some(handler) = isr.timer0_wdt {
unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::TG0_WDT_LEVEL,
handler.handler(),
);
crate::interrupt::enable(
crate::peripherals::Interrupt::TG0_WDT_LEVEL,
handler.priority(),
)
.unwrap();
}
}
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
{
if let Some(handler) = isr.timer1_t0 {
unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::TG1_T0_LEVEL,
handler.handler(),
);
crate::interrupt::enable(
crate::peripherals::Interrupt::TG1_T0_LEVEL,
handler.priority(),
)
.unwrap();
}
}
#[cfg(any(esp32, esp32s2, esp32s3))]
if let Some(handler) = isr.timer1_t1 {
unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::TG1_T1_LEVEL,
handler.handler(),
);
crate::interrupt::enable(
crate::peripherals::Interrupt::TG1_T1_LEVEL,
handler.priority(),
)
.unwrap();
}
}
if let Some(handler) = isr.timer1_wdt {
unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::TG1_WDT_LEVEL,
handler.handler(),
);
crate::interrupt::enable(
crate::peripherals::Interrupt::TG1_WDT_LEVEL,
handler.priority(),
)
.unwrap();
}
}
}
}
Self {
_timer_group: timer_group,
timer0,
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
timer1,
wdt: Wdt::new(),
}
}
}
impl<'d, T> TimerGroup<'d, T, crate::Async>
where
T: TimerGroupInstance,
{
pub fn new_async(timer_group: impl Peripheral<P = T> + 'd, clocks: &Clocks) -> Self {
crate::into_ref!(timer_group); crate::into_ref!(timer_group);
T::configure_src_clk(); T::configure_src_clk();
@ -220,12 +369,13 @@ where
} }
/// General-purpose Timer driver /// General-purpose Timer driver
pub struct Timer<T> { pub struct Timer<T, DM: crate::Mode> {
timg: T, timg: T,
apb_clk_freq: HertzU32, apb_clk_freq: HertzU32,
phantom: PhantomData<DM>,
} }
impl<T> Timer<T> impl<T, DM: crate::Mode> Timer<T, DM>
where where
T: Instance, T: Instance,
{ {
@ -236,7 +386,11 @@ where
timg.enable_peripheral(); timg.enable_peripheral();
Self { timg, apb_clk_freq } Self {
timg,
apb_clk_freq,
phantom: PhantomData,
}
} }
/// Start the timer with the given time period. /// Start the timer with the given time period.
@ -278,14 +432,9 @@ where
pub fn wait(&mut self) { pub fn wait(&mut self) {
while !self.has_elapsed() {} while !self.has_elapsed() {}
} }
/// Return the raw interface to the underlying timer instance
pub fn free(self) -> T {
self.timg
}
} }
impl<T> Deref for Timer<T> impl<T, DM: crate::Mode> Deref for Timer<T, DM>
where where
T: Instance, T: Instance,
{ {
@ -296,7 +445,7 @@ where
} }
} }
impl<T> DerefMut for Timer<T> impl<T, DM: crate::Mode> DerefMut for Timer<T, DM>
where where
T: Instance, T: Instance,
{ {
@ -531,9 +680,10 @@ where
} }
#[cfg(feature = "embedded-hal-02")] #[cfg(feature = "embedded-hal-02")]
impl<T> embedded_hal_02::timer::CountDown for Timer<T> impl<T, DM> embedded_hal_02::timer::CountDown for Timer<T, DM>
where where
T: Instance, T: Instance,
DM: crate::Mode,
{ {
type Time = MicrosDurationU64; type Time = MicrosDurationU64;
@ -554,9 +704,10 @@ where
} }
#[cfg(feature = "embedded-hal-02")] #[cfg(feature = "embedded-hal-02")]
impl<T> embedded_hal_02::timer::Cancel for Timer<T> impl<T, DM> embedded_hal_02::timer::Cancel for Timer<T, DM>
where where
T: Instance, T: Instance,
DM: crate::Mode,
{ {
type Error = Error; type Error = Error;
@ -574,17 +725,23 @@ where
} }
#[cfg(feature = "embedded-hal-02")] #[cfg(feature = "embedded-hal-02")]
impl<T> embedded_hal_02::timer::Periodic for Timer<T> where T: Instance {} impl<T, DM> embedded_hal_02::timer::Periodic for Timer<T, DM>
where
T: Instance,
DM: crate::Mode,
{
}
/// Watchdog timer /// Watchdog timer
pub struct Wdt<TG> { pub struct Wdt<TG, DM> {
phantom: PhantomData<TG>, phantom: PhantomData<(TG, DM)>,
} }
/// Watchdog driver /// Watchdog driver
impl<TG> Wdt<TG> impl<TG, DM> Wdt<TG, DM>
where where
TG: TimerGroupInstance, TG: TimerGroupInstance,
DM: crate::Mode,
{ {
/// Create a new watchdog timer instance /// Create a new watchdog timer instance
pub fn new() -> Self { pub fn new() -> Self {
@ -697,9 +854,10 @@ where
} }
} }
impl<TG> Default for Wdt<TG> impl<TG, DM> Default for Wdt<TG, DM>
where where
TG: TimerGroupInstance, TG: TimerGroupInstance,
DM: crate::Mode,
{ {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
@ -707,9 +865,10 @@ where
} }
#[cfg(feature = "embedded-hal-02")] #[cfg(feature = "embedded-hal-02")]
impl<TG> embedded_hal_02::watchdog::WatchdogDisable for Wdt<TG> impl<TG, DM> embedded_hal_02::watchdog::WatchdogDisable for Wdt<TG, DM>
where where
TG: TimerGroupInstance, TG: TimerGroupInstance,
DM: crate::Mode,
{ {
fn disable(&mut self) { fn disable(&mut self) {
self.disable(); self.disable();
@ -717,9 +876,10 @@ where
} }
#[cfg(feature = "embedded-hal-02")] #[cfg(feature = "embedded-hal-02")]
impl<TG> embedded_hal_02::watchdog::WatchdogEnable for Wdt<TG> impl<TG, DM> embedded_hal_02::watchdog::WatchdogEnable for Wdt<TG, DM>
where where
TG: TimerGroupInstance, TG: TimerGroupInstance,
DM: crate::Mode,
{ {
type Time = MicrosDurationU64; type Time = MicrosDurationU64;
@ -733,9 +893,10 @@ where
} }
#[cfg(feature = "embedded-hal-02")] #[cfg(feature = "embedded-hal-02")]
impl<TG> embedded_hal_02::watchdog::Watchdog for Wdt<TG> impl<TG, DM> embedded_hal_02::watchdog::Watchdog for Wdt<TG, DM>
where where
TG: TimerGroupInstance, TG: TimerGroupInstance,
DM: crate::Mode,
{ {
fn feed(&mut self) { fn feed(&mut self) {
self.feed(); self.feed();

View File

@ -63,6 +63,7 @@ embassy = ["esp-hal/embassy"]
embassy-executor-thread = ["esp-hal/embassy-executor-thread"] embassy-executor-thread = ["esp-hal/embassy-executor-thread"]
embassy-executor-interrupt = ["esp-hal/embassy-executor-interrupt"] embassy-executor-interrupt = ["esp-hal/embassy-executor-interrupt"]
embassy-time-systick-16mhz = ["esp-hal/embassy-time-systick-16mhz"]
embassy-time-timg0 = ["esp-hal/embassy-time-timg0"] embassy-time-timg0 = ["esp-hal/embassy-time-timg0"]
embassy-generic-timers = ["embassy-time/generic-queue-8"] embassy-generic-timers = ["embassy-time/generic-queue-8"]

View File

@ -36,7 +36,7 @@ async fn main(spawner: Spawner) {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
spawner.spawn(run()).ok(); spawner.spawn(run()).ok();

View File

@ -0,0 +1,50 @@
//! embassy hello world systimer
//!
//! This is an example of running the embassy executor with multiple tasks
//! concurrently using the systimer time driver.
//!
//! It's not supported on ESP32, on ESP32-S2 the frequency of the systimer is different (so it's left out here)
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s3
//% FEATURES: embassy embassy-time-systick-16mhz embassy-executor-thread embassy-generic-timers
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use embassy_executor::Spawner;
use embassy_time::{Duration, Timer};
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
embassy,
peripherals::Peripherals,
prelude::*,
systimer::SystemTimer,
};
#[embassy_executor::task]
async fn run() {
loop {
esp_println::println!("Hello world from embassy using esp-hal-async!");
Timer::after(Duration::from_millis(1_000)).await;
}
}
#[main]
async fn main(spawner: Spawner) {
esp_println::println!("Init!");
let peripherals = Peripherals::take();
let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let systimer = SystemTimer::new_async(peripherals.SYSTIMER);
embassy::init(&clocks, systimer);
spawner.spawn(run()).ok();
loop {
esp_println::println!("Bing!");
Timer::after(Duration::from_millis(5_000)).await;
}
}

View File

@ -37,7 +37,7 @@ async fn main(_spawner: Spawner) {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

View File

@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

View File

@ -63,7 +63,7 @@ async fn main(_spawner: Spawner) {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

View File

@ -57,7 +57,7 @@ async fn main(_spawner: Spawner) {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
let mut cpu_control = CpuControl::new(system.cpu_control); let mut cpu_control = CpuControl::new(system.cpu_control);

View File

@ -92,7 +92,7 @@ fn main() -> ! {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
let mut cpu_control = CpuControl::new(system.cpu_control); let mut cpu_control = CpuControl::new(system.cpu_control);

View File

@ -84,7 +84,7 @@ async fn main(low_prio_spawner: Spawner) {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
let spawner = INT_EXECUTOR_0.start(Priority::Priority2); let spawner = INT_EXECUTOR_0.start(Priority::Priority2);

View File

@ -33,7 +33,7 @@ async fn main(_spawner: Spawner) {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

View File

@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

View File

@ -45,7 +45,7 @@ async fn main(spawner: Spawner) {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timer_group0 = esp_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks); let timer_group0 = esp_hal::timer::TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timer_group0); embassy::init(&clocks, timer_group0);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

View File

@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

View File

@ -80,7 +80,7 @@ async fn main(spawner: Spawner) {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
let mut uart0 = Uart::new_async(peripherals.UART0, &clocks); let mut uart0 = Uart::new_async(peripherals.UART0, &clocks);

View File

@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

View File

@ -0,0 +1,42 @@
//! embassy systimer delay
//!
//! This is an example of using the `DelayNs` trait implementation
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: embassy embassy-time-timg0 embassy-executor-thread embassy-generic-timers async
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use embassy_executor::Spawner;
use embedded_hal_async::delay::DelayNs;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
embassy,
peripherals::Peripherals,
prelude::*,
systimer::SystemTimer,
timer::TimerGroup,
};
#[main]
async fn main(_spawner: Spawner) {
esp_println::println!("Init!");
let peripherals = Peripherals::take();
let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0);
let mut alarm0 = SystemTimer::new_async(peripherals.SYSTIMER)
.alarm0
.into_periodic();
loop {
esp_println::println!("Bing!");
alarm0.delay_ms(1000).await;
}
}

View File

@ -80,7 +80,7 @@ async fn main(spawner: Spawner) {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

View File

@ -71,7 +71,7 @@ async fn main(spawner: Spawner) -> () {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
embassy::init(&clocks, TimerGroup::new(peripherals.TIMG0, &clocks)); embassy::init(&clocks, TimerGroup::new_async(peripherals.TIMG0, &clocks));
let (tx, rx) = UsbSerialJtag::new_async(peripherals.USB_DEVICE).split(); let (tx, rx) = UsbSerialJtag::new_async(peripherals.USB_DEVICE).split();

View File

@ -29,7 +29,7 @@ async fn main(_spawner: Spawner) {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

View File

@ -14,18 +14,19 @@ use esp_hal::{
clock::ClockControl, clock::ClockControl,
delay::Delay, delay::Delay,
etm::Etm, etm::Etm,
interrupt::{self, Priority}, peripherals::{Peripherals, TIMG0},
peripherals::{Interrupt, Peripherals, TIMG0},
prelude::*, prelude::*,
timer::{ timer::{
etm::{TimerEtmEvents, TimerEtmTasks}, etm::{TimerEtmEvents, TimerEtmTasks},
Timer, Timer,
Timer0, Timer0,
TimerGroup, TimerGroup,
TimerInterrupts,
}, },
}; };
static TIMER0: Mutex<RefCell<Option<Timer<Timer0<TIMG0>>>>> = Mutex::new(RefCell::new(None)); static TIMER0: Mutex<RefCell<Option<Timer<Timer0<TIMG0>, esp_hal::Blocking>>>> =
Mutex::new(RefCell::new(None));
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
@ -33,7 +34,14 @@ fn main() -> ! {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new(
peripherals.TIMG0,
&clocks,
Some(TimerInterrupts {
timer0_t0: Some(tg0_t0_level),
..Default::default()
}),
);
let mut timer0 = timg0.timer0; let mut timer0 = timg0.timer0;
// Configure ETM to stop timer0 when alarm is triggered // Configure ETM to stop timer0 when alarm is triggered
@ -50,14 +58,10 @@ fn main() -> ! {
// 80 / 2 (default divider) timer clock cycles == 1 us // 80 / 2 (default divider) timer clock cycles == 1 us
timer0.load_alarm_value(100 * 1_000 * 40); timer0.load_alarm_value(100 * 1_000 * 40);
timer0.set_alarm_active(true); timer0.set_alarm_active(true);
// Enable interrupt that will be triggered by the alarm
interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap();
timer0.listen();
timer0.set_counter_active(true); timer0.set_counter_active(true);
critical_section::with(|cs| { critical_section::with(|cs| {
timer0.listen();
TIMER0.borrow_ref_mut(cs).replace(timer0); TIMER0.borrow_ref_mut(cs).replace(timer0);
}); });
@ -75,8 +79,8 @@ fn main() -> ! {
} }
} }
#[interrupt] #[handler]
fn TG0_T0_LEVEL() { fn tg0_t0_level() {
critical_section::with(|cs| { critical_section::with(|cs| {
let mut timer0 = TIMER0.borrow_ref_mut(cs); let mut timer0 = TIMER0.borrow_ref_mut(cs);
let timer0 = timer0.as_mut().unwrap(); let timer0 = timer0.as_mut().unwrap();

View File

@ -18,13 +18,15 @@ use esp_hal::{
peripherals::{Interrupt, Peripherals}, peripherals::{Interrupt, Peripherals},
prelude::*, prelude::*,
systimer::{Alarm, Periodic, SystemTimer, Target}, systimer::{Alarm, Periodic, SystemTimer, Target},
Blocking,
}; };
use esp_println::println; use esp_println::println;
use fugit::ExtU32; use fugit::ExtU32;
static ALARM0: Mutex<RefCell<Option<Alarm<Periodic, 0>>>> = Mutex::new(RefCell::new(None)); static ALARM0: Mutex<RefCell<Option<Alarm<Periodic, Blocking, 0>>>> =
static ALARM1: Mutex<RefCell<Option<Alarm<Target, 1>>>> = Mutex::new(RefCell::new(None)); Mutex::new(RefCell::new(None));
static ALARM2: Mutex<RefCell<Option<Alarm<Target, 2>>>> = Mutex::new(RefCell::new(None)); static ALARM1: Mutex<RefCell<Option<Alarm<Target, Blocking, 1>>>> = Mutex::new(RefCell::new(None));
static ALARM2: Mutex<RefCell<Option<Alarm<Target, Blocking, 2>>>> = Mutex::new(RefCell::new(None));
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
@ -36,19 +38,22 @@ fn main() -> ! {
println!("SYSTIMER Current value = {}", SystemTimer::now()); println!("SYSTIMER Current value = {}", SystemTimer::now());
let alarm0 = systimer.alarm0.into_periodic();
alarm0.set_period(1u32.secs());
alarm0.enable_interrupt(true);
let alarm1 = systimer.alarm1;
alarm1.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 2));
alarm1.enable_interrupt(true);
let alarm2 = systimer.alarm2;
alarm2.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 3));
alarm2.enable_interrupt(true);
critical_section::with(|cs| { critical_section::with(|cs| {
let alarm0 = systimer.alarm0.into_periodic();
alarm0.set_interrupt_handler(systimer_target0);
alarm0.set_period(1u32.secs());
alarm0.enable_interrupt(true);
let alarm1 = systimer.alarm1;
alarm1.set_interrupt_handler(systimer_target1);
alarm1.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 2));
alarm1.enable_interrupt(true);
let alarm2 = systimer.alarm2;
alarm2.set_interrupt_handler(systimer_target2);
alarm2.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 3));
alarm2.enable_interrupt(true);
ALARM0.borrow_ref_mut(cs).replace(alarm0); ALARM0.borrow_ref_mut(cs).replace(alarm0);
ALARM1.borrow_ref_mut(cs).replace(alarm1); ALARM1.borrow_ref_mut(cs).replace(alarm1);
ALARM2.borrow_ref_mut(cs).replace(alarm2); ALARM2.borrow_ref_mut(cs).replace(alarm2);
@ -67,8 +72,8 @@ fn main() -> ! {
} }
} }
#[interrupt] #[handler(priority = esp_hal::interrupt::Priority::min())]
fn SYSTIMER_TARGET0() { fn systimer_target0() {
println!("Interrupt lvl1 (alarm0)"); println!("Interrupt lvl1 (alarm0)");
critical_section::with(|cs| { critical_section::with(|cs| {
ALARM0 ALARM0
@ -79,8 +84,8 @@ fn SYSTIMER_TARGET0() {
}); });
} }
#[interrupt] #[handler(priority = esp_hal::interrupt::Priority::Priority1)]
fn SYSTIMER_TARGET1() { fn systimer_target1() {
println!("Interrupt lvl2 (alarm1)"); println!("Interrupt lvl2 (alarm1)");
critical_section::with(|cs| { critical_section::with(|cs| {
ALARM1 ALARM1
@ -91,8 +96,8 @@ fn SYSTIMER_TARGET1() {
}); });
} }
#[interrupt] #[handler(priority = esp_hal::interrupt::Priority::max())]
fn SYSTIMER_TARGET2() { fn systimer_target2() {
println!("Interrupt lvl2 (alarm2)"); println!("Interrupt lvl2 (alarm2)");
critical_section::with(|cs| { critical_section::with(|cs| {
ALARM2 ALARM2

View File

@ -16,10 +16,11 @@ use esp_hal::{
interrupt::{self, Priority}, interrupt::{self, Priority},
peripherals::{Interrupt, Peripherals, TIMG0}, peripherals::{Interrupt, Peripherals, TIMG0},
prelude::*, prelude::*,
timer::{Timer, Timer0, TimerGroup}, timer::{Timer, Timer0, TimerGroup, TimerInterrupts},
}; };
static TIMER0: Mutex<RefCell<Option<Timer<Timer0<TIMG0>>>>> = Mutex::new(RefCell::new(None)); static TIMER0: Mutex<RefCell<Option<Timer<Timer0<TIMG0>, esp_hal::Blocking>>>> =
Mutex::new(RefCell::new(None));
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
@ -27,7 +28,14 @@ fn main() -> ! {
let system = peripherals.SYSTEM.split(); let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new(
peripherals.TIMG0,
&clocks,
Some(TimerInterrupts {
timer0_t0: Some(tg0_t0_level),
..Default::default()
}),
);
let mut timer0 = timg0.timer0; let mut timer0 = timg0.timer0;
interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap(); interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap();
@ -41,8 +49,8 @@ fn main() -> ! {
loop {} loop {}
} }
#[interrupt] #[handler]
fn TG0_T0_LEVEL() { fn tg0_t0_level() {
critical_section::with(|cs| { critical_section::with(|cs| {
esp_println::println!("Interrupt 1"); esp_println::println!("Interrupt 1");

View File

@ -26,7 +26,7 @@ fn main() -> ! {
let delay = Delay::new(&clocks); let delay = Delay::new(&clocks);
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
let mut wdt0 = timg0.wdt; let mut wdt0 = timg0.wdt;
wdt0.enable(); wdt0.enable();
wdt0.set_timeout(2u64.secs()); wdt0.set_timeout(2u64.secs());

View File

@ -45,7 +45,7 @@ impl Context {
let delay = Delay::new(&clocks); let delay = Delay::new(&clocks);
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0); embassy::init(&clocks, timg0);
Context { Context {