mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-02 14:44:42 +00:00
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:
parent
81a40703bd
commit
256d7198f9
@ -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 I2C (#1376)
|
||||
- `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
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use critical_section::{CriticalSection, Mutex};
|
||||
use procmacros::handler;
|
||||
|
||||
use super::AlarmState;
|
||||
use crate::{
|
||||
@ -9,22 +10,22 @@ use crate::{
|
||||
|
||||
pub const ALARM_COUNT: usize = 3;
|
||||
|
||||
pub type TimerType = SystemTimer<'static>;
|
||||
pub type TimerType = SystemTimer<'static, crate::Async>;
|
||||
|
||||
pub struct EmbassyTimer {
|
||||
pub(crate) alarms: Mutex<[AlarmState; ALARM_COUNT]>,
|
||||
pub(crate) alarm0: Alarm<Target, 0>,
|
||||
pub(crate) alarm1: Alarm<Target, 1>,
|
||||
pub(crate) alarm2: Alarm<Target, 2>,
|
||||
pub(crate) alarm0: Alarm<Target, crate::Async, 0>,
|
||||
pub(crate) alarm1: Alarm<Target, crate::Async, 1>,
|
||||
pub(crate) alarm2: Alarm<Target, crate::Async, 2>,
|
||||
}
|
||||
|
||||
const ALARM_STATE_NONE: AlarmState = AlarmState::new();
|
||||
|
||||
embassy_time_driver::time_driver_impl!(static DRIVER: EmbassyTimer = EmbassyTimer {
|
||||
alarms: Mutex::new([ALARM_STATE_NONE; ALARM_COUNT]),
|
||||
alarm0: unsafe { Alarm::<_, 0>::conjure() },
|
||||
alarm1: unsafe { Alarm::<_, 1>::conjure() },
|
||||
alarm2: unsafe { Alarm::<_, 2>::conjure() },
|
||||
alarm0: unsafe { Alarm::<_, crate::Async, 0>::conjure() },
|
||||
alarm1: unsafe { Alarm::<_, crate::Async, 1>::conjure() },
|
||||
alarm2: unsafe { Alarm::<_, crate::Async, 2>::conjure() },
|
||||
});
|
||||
|
||||
impl EmbassyTimer {
|
||||
@ -42,9 +43,9 @@ impl EmbassyTimer {
|
||||
|
||||
pub(super) fn on_alarm_allocated(&self, n: usize) {
|
||||
match n {
|
||||
0 => self.alarm0.enable_interrupt(true),
|
||||
1 => self.alarm1.enable_interrupt(true),
|
||||
2 => self.alarm2.enable_interrupt(true),
|
||||
0 => self.alarm0.enable_interrupt_internal(true),
|
||||
1 => self.alarm1.enable_interrupt_internal(true),
|
||||
2 => self.alarm2.enable_interrupt_internal(true),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -57,31 +58,47 @@ impl EmbassyTimer {
|
||||
}
|
||||
|
||||
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(
|
||||
peripherals::Interrupt::SYSTIMER_TARGET0,
|
||||
Priority::max()
|
||||
));
|
||||
unwrap!(interrupt::enable(
|
||||
peripherals::Interrupt::SYSTIMER_TARGET1,
|
||||
Priority::max()
|
||||
));
|
||||
unwrap!(interrupt::enable(
|
||||
peripherals::Interrupt::SYSTIMER_TARGET2,
|
||||
Priority::max()
|
||||
));
|
||||
crate::interrupt::bind_interrupt(
|
||||
peripherals::Interrupt::SYSTIMER_TARGET1,
|
||||
target1_handler.handler(),
|
||||
);
|
||||
unwrap!(crate::interrupt::enable(
|
||||
peripherals::Interrupt::SYSTIMER_TARGET1,
|
||||
target1_handler.priority()
|
||||
));
|
||||
|
||||
#[interrupt]
|
||||
fn SYSTIMER_TARGET0() {
|
||||
crate::interrupt::bind_interrupt(
|
||||
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);
|
||||
}
|
||||
#[interrupt]
|
||||
fn SYSTIMER_TARGET1() {
|
||||
|
||||
#[handler]
|
||||
fn target1_handler() {
|
||||
DRIVER.on_interrupt(1);
|
||||
}
|
||||
#[interrupt]
|
||||
fn SYSTIMER_TARGET2() {
|
||||
|
||||
#[handler]
|
||||
fn target2_handler() {
|
||||
DRIVER.on_interrupt(2);
|
||||
}
|
||||
}
|
||||
@ -109,9 +126,9 @@ impl EmbassyTimer {
|
||||
|
||||
fn clear_interrupt(&self, id: usize) {
|
||||
match id {
|
||||
0 => self.alarm0.clear_interrupt(),
|
||||
1 => self.alarm1.clear_interrupt(),
|
||||
2 => self.alarm2.clear_interrupt(),
|
||||
0 => self.alarm0.clear_interrupt_internal(),
|
||||
1 => self.alarm1.clear_interrupt_internal(),
|
||||
2 => self.alarm2.clear_interrupt_internal(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ pub const ALARM_COUNT: usize = 1;
|
||||
#[cfg(any(esp32, esp32s2, esp32s3))]
|
||||
pub const ALARM_COUNT: usize = 2;
|
||||
|
||||
pub type TimerType = TimerGroup<'static, TIMG0>;
|
||||
pub type TimerType = TimerGroup<'static, TIMG0, crate::Async>;
|
||||
|
||||
pub struct EmbassyTimer {
|
||||
pub(crate) alarms: Mutex<[AlarmState; ALARM_COUNT]>,
|
||||
@ -51,8 +51,6 @@ impl EmbassyTimer {
|
||||
}
|
||||
|
||||
pub fn init(clocks: &Clocks, mut timer: TimerType) {
|
||||
use crate::{interrupt, interrupt::Priority};
|
||||
|
||||
// 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
|
||||
// divider
|
||||
@ -65,25 +63,39 @@ impl EmbassyTimer {
|
||||
timer.timer1.set_counter_active(true);
|
||||
}
|
||||
|
||||
unwrap!(interrupt::enable(
|
||||
peripherals::Interrupt::TG0_T0_LEVEL,
|
||||
Priority::max()
|
||||
));
|
||||
unsafe {
|
||||
crate::interrupt::bind_interrupt(
|
||||
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))]
|
||||
unwrap!(interrupt::enable(
|
||||
peripherals::Interrupt::TG0_T1_LEVEL,
|
||||
Priority::max()
|
||||
));
|
||||
unsafe {
|
||||
crate::interrupt::bind_interrupt(
|
||||
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]
|
||||
fn TG0_T0_LEVEL() {
|
||||
#[handler(priority = crate::interrupt::Priority::max())]
|
||||
fn tg0_t0_level() {
|
||||
let timer = unsafe { Timer0::<TIMG0>::steal() };
|
||||
DRIVER.on_interrupt(0, timer);
|
||||
}
|
||||
|
||||
#[cfg(any(esp32, esp32s2, esp32s3))]
|
||||
#[interrupt]
|
||||
fn TG0_T1_LEVEL() {
|
||||
#[handler(priority = crate::interrupt::Priority::max())]
|
||||
fn tg0_t1_level() {
|
||||
let timer = unsafe { Timer1::<TIMG0>::steal() };
|
||||
DRIVER.on_interrupt(1, timer);
|
||||
}
|
||||
|
@ -96,6 +96,6 @@ unsafe fn post_init() {
|
||||
let mut rtc = Rtc::new(LPWR::steal());
|
||||
rtc.rwdt.disable();
|
||||
|
||||
Wdt::<TIMG0>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG1>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG1, crate::Blocking>::set_wdt_enabled(false);
|
||||
}
|
||||
|
@ -31,5 +31,5 @@ unsafe fn post_init() {
|
||||
rtc.swd.disable();
|
||||
rtc.rwdt.disable();
|
||||
|
||||
Wdt::<TIMG0>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
|
||||
}
|
||||
|
@ -43,6 +43,6 @@ unsafe fn post_init() {
|
||||
rtc.swd.disable();
|
||||
rtc.rwdt.disable();
|
||||
|
||||
Wdt::<TIMG0>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG1>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG1, crate::Blocking>::set_wdt_enabled(false);
|
||||
}
|
||||
|
@ -49,6 +49,6 @@ unsafe fn post_init() {
|
||||
rtc.swd.disable();
|
||||
rtc.rwdt.disable();
|
||||
|
||||
Wdt::<TIMG0>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG1>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG1, crate::Blocking>::set_wdt_enabled(false);
|
||||
}
|
||||
|
@ -48,6 +48,6 @@ unsafe fn post_init() {
|
||||
rtc.swd.disable();
|
||||
rtc.rwdt.disable();
|
||||
|
||||
Wdt::<TIMG0>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG1>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG1, crate::Blocking>::set_wdt_enabled(false);
|
||||
}
|
||||
|
@ -100,6 +100,6 @@ unsafe fn post_init() {
|
||||
let mut rtc = Rtc::new(LPWR::steal());
|
||||
rtc.rwdt.disable();
|
||||
|
||||
Wdt::<TIMG0>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG1>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG1, crate::Blocking>::set_wdt_enabled(false);
|
||||
}
|
||||
|
@ -134,6 +134,6 @@ unsafe fn post_init() {
|
||||
let mut rtc = Rtc::new(LPWR::steal());
|
||||
rtc.rwdt.disable();
|
||||
|
||||
Wdt::<TIMG0>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG1>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG0, crate::Blocking>::set_wdt_enabled(false);
|
||||
Wdt::<TIMG1, crate::Blocking>::set_wdt_enabled(false);
|
||||
}
|
||||
|
@ -31,7 +31,8 @@ use core::{marker::PhantomData, mem::transmute};
|
||||
use fugit::MicrosDurationU32;
|
||||
|
||||
use crate::{
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
interrupt::InterruptHandler,
|
||||
peripheral::Peripheral,
|
||||
peripherals::{
|
||||
generic::Reg,
|
||||
systimer::{
|
||||
@ -45,42 +46,45 @@ use crate::{
|
||||
|
||||
// TODO this only handles unit0 of the systimer
|
||||
|
||||
pub struct SystemTimer<'d> {
|
||||
_inner: PeripheralRef<'d, SYSTIMER>,
|
||||
pub alarm0: Alarm<Target, 0>,
|
||||
pub alarm1: Alarm<Target, 1>,
|
||||
pub alarm2: Alarm<Target, 2>,
|
||||
/// The SystemTimer
|
||||
pub struct SystemTimer<'d, DM: crate::Mode> {
|
||||
pub alarm0: Alarm<Target, DM, 0>,
|
||||
pub alarm1: Alarm<Target, DM, 1>,
|
||||
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)]
|
||||
pub const BIT_MASK: u64 = u64::MAX;
|
||||
#[cfg(not(esp32s2))]
|
||||
pub const BIT_MASK: u64 = 0xF_FFFF_FFFF_FFFF;
|
||||
|
||||
/// The ticks per second the underlying peripheral uses
|
||||
#[cfg(esp32s2)]
|
||||
pub const TICKS_PER_SECOND: u64 = 80_000_000; // TODO this can change when we have support for changing APB frequency
|
||||
#[cfg(not(esp32s2))]
|
||||
pub const TICKS_PER_SECOND: u64 = 16_000_000;
|
||||
|
||||
pub fn new(p: impl Peripheral<P = SYSTIMER> + 'd) -> Self {
|
||||
crate::into_ref!(p);
|
||||
|
||||
/// Create a new instance in [crate::Blocking] mode.
|
||||
pub fn new(_p: impl Peripheral<P = SYSTIMER> + 'd) -> Self {
|
||||
#[cfg(soc_etm)]
|
||||
etm::enable_etm();
|
||||
|
||||
Self {
|
||||
_inner: p,
|
||||
alarm0: Alarm::new(),
|
||||
alarm1: Alarm::new(),
|
||||
alarm2: Alarm::new(),
|
||||
_phantom: &PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO use fugit types
|
||||
/// Get the current count of the system-timer.
|
||||
pub fn now() -> u64 {
|
||||
// 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
|
||||
let systimer = unsafe { &*SYSTIMER::ptr() };
|
||||
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)]
|
||||
pub struct Target;
|
||||
|
||||
/// A marker for a [Alarm] in periodic mode.
|
||||
#[derive(Debug)]
|
||||
pub struct Periodic; // TODO, also impl e-h timer traits
|
||||
|
||||
/// A single alarm.
|
||||
#[derive(Debug)]
|
||||
pub struct Alarm<MODE, const CHANNEL: u8> {
|
||||
_pd: PhantomData<MODE>,
|
||||
pub struct Alarm<MODE, DM: crate::Mode, const CHANNEL: u8> {
|
||||
_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
|
||||
fn new() -> Self {
|
||||
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(
|
||||
&self,
|
||||
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) {
|
||||
self.configure(|tconf, hi, lo| unsafe {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
let us = period.ticks();
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Alarm<T, 0> {
|
||||
impl<T, DM: crate::Mode> Alarm<T, DM, 0> {
|
||||
/// Conjure an alarm out of thin air.
|
||||
///
|
||||
/// # 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.
|
||||
///
|
||||
/// # 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.
|
||||
///
|
||||
/// # Safety
|
||||
@ -286,13 +360,8 @@ impl<T> Alarm<T, 2> {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: The `embedded_hal_async::delay::DelayUs` trait implementation
|
||||
// interferes with the embassy time driver, which also uses the
|
||||
// `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))]
|
||||
// Async functionality of the system timer.
|
||||
#[cfg(feature = "async")]
|
||||
mod asynch {
|
||||
use core::{
|
||||
pin::Pin,
|
||||
@ -300,7 +369,7 @@ mod asynch {
|
||||
};
|
||||
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use procmacros::interrupt;
|
||||
use procmacros::handler;
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -310,13 +379,34 @@ mod asynch {
|
||||
static WAKERS: [AtomicWaker; NUM_ALARMS] = [INIT; NUM_ALARMS];
|
||||
|
||||
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> {
|
||||
pub(crate) fn new(alarm: &'a Alarm<Periodic, N>) -> Self {
|
||||
alarm.clear_interrupt();
|
||||
alarm.enable_interrupt(true);
|
||||
pub(crate) fn new(alarm: &'a Alarm<Periodic, crate::Async, N>) -> Self {
|
||||
alarm.clear_interrupt_internal();
|
||||
|
||||
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 {
|
||||
phantom: PhantomData,
|
||||
@ -325,7 +415,7 @@ mod asynch {
|
||||
|
||||
fn event_bit_is_clear(&self) -> bool {
|
||||
let r = unsafe { &*crate::peripherals::SYSTIMER::PTR }
|
||||
.int_ena
|
||||
.int_ena()
|
||||
.read();
|
||||
|
||||
match N {
|
||||
@ -351,9 +441,11 @@ mod asynch {
|
||||
}
|
||||
}
|
||||
|
||||
impl<const CHANNEL: u8> embedded_hal_async::delay::DelayUs for Alarm<Periodic, CHANNEL> {
|
||||
async fn delay_us(&mut self, us: u32) {
|
||||
let period = MicrosDurationU32::from_ticks(us);
|
||||
impl<const CHANNEL: u8> embedded_hal_async::delay::DelayNs
|
||||
for Alarm<Periodic, crate::Async, CHANNEL>
|
||||
{
|
||||
async fn delay_ns(&mut self, ns: u32) {
|
||||
let period = MicrosDurationU32::from_ticks(ns / 1000);
|
||||
self.set_period(period);
|
||||
|
||||
AlarmFuture::new(self).await;
|
||||
@ -366,28 +458,28 @@ mod asynch {
|
||||
}
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn SYSTIMER_TARGET0() {
|
||||
#[handler]
|
||||
fn target0_handler() {
|
||||
unsafe { &*crate::peripherals::SYSTIMER::PTR }
|
||||
.int_ena
|
||||
.int_ena()
|
||||
.modify(|_, w| w.target0().clear_bit());
|
||||
|
||||
WAKERS[0].wake();
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn SYSTIMER_TARGET1() {
|
||||
#[handler]
|
||||
fn target1_handler() {
|
||||
unsafe { &*crate::peripherals::SYSTIMER::PTR }
|
||||
.int_ena
|
||||
.int_ena()
|
||||
.modify(|_, w| w.target1().clear_bit());
|
||||
|
||||
WAKERS[1].wake();
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn SYSTIMER_TARGET2() {
|
||||
#[handler]
|
||||
fn target2_handler() {
|
||||
unsafe { &*crate::peripherals::SYSTIMER::PTR }
|
||||
.int_ena
|
||||
.int_ena()
|
||||
.modify(|_, w| w.target2().clear_bit());
|
||||
|
||||
WAKERS[2].wake();
|
||||
@ -420,26 +512,29 @@ pub mod etm {
|
||||
use super::*;
|
||||
|
||||
/// An ETM controlled SYSTIMER event
|
||||
pub struct SysTimerEtmEvent<'a, M, const N: u8> {
|
||||
alarm: &'a mut Alarm<M, N>,
|
||||
pub struct SysTimerEtmEvent<'a, M, DM: crate::Mode, const N: u8> {
|
||||
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]
|
||||
pub fn new(alarm: &'a mut Alarm<M, N>) -> Self {
|
||||
pub fn new(alarm: &'a mut Alarm<M, DM, N>) -> Self {
|
||||
Self { 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;
|
||||
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 {
|
||||
50 + N
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ use crate::peripherals::TIMG1;
|
||||
use crate::soc::constants::TIMG_DEFAULT_CLK_SRC;
|
||||
use crate::{
|
||||
clock::Clocks,
|
||||
interrupt::InterruptHandler,
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::{timg0::RegisterBlock, TIMG0},
|
||||
system::PeripheralClockControl,
|
||||
@ -61,17 +62,32 @@ pub enum Error {
|
||||
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
|
||||
// timer
|
||||
pub struct TimerGroup<'d, T>
|
||||
pub struct TimerGroup<'d, T, DM>
|
||||
where
|
||||
T: TimerGroupInstance,
|
||||
DM: crate::Mode,
|
||||
{
|
||||
_timer_group: PeripheralRef<'d, T>,
|
||||
pub timer0: Timer<Timer0<T>>,
|
||||
pub timer0: Timer<Timer0<T>, DM>,
|
||||
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
|
||||
pub timer1: Timer<Timer1<T>>,
|
||||
pub wdt: Wdt<T>,
|
||||
pub timer1: Timer<Timer1<T>, DM>,
|
||||
pub wdt: Wdt<T, DM>,
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
T::configure_src_clk();
|
||||
@ -220,12 +369,13 @@ where
|
||||
}
|
||||
|
||||
/// General-purpose Timer driver
|
||||
pub struct Timer<T> {
|
||||
pub struct Timer<T, DM: crate::Mode> {
|
||||
timg: T,
|
||||
apb_clk_freq: HertzU32,
|
||||
phantom: PhantomData<DM>,
|
||||
}
|
||||
|
||||
impl<T> Timer<T>
|
||||
impl<T, DM: crate::Mode> Timer<T, DM>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
@ -236,7 +386,11 @@ where
|
||||
|
||||
timg.enable_peripheral();
|
||||
|
||||
Self { timg, apb_clk_freq }
|
||||
Self {
|
||||
timg,
|
||||
apb_clk_freq,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Start the timer with the given time period.
|
||||
@ -278,14 +432,9 @@ where
|
||||
pub fn wait(&mut self) {
|
||||
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
|
||||
T: Instance,
|
||||
{
|
||||
@ -296,7 +445,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for Timer<T>
|
||||
impl<T, DM: crate::Mode> DerefMut for Timer<T, DM>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
@ -531,9 +680,10 @@ where
|
||||
}
|
||||
|
||||
#[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
|
||||
T: Instance,
|
||||
DM: crate::Mode,
|
||||
{
|
||||
type Time = MicrosDurationU64;
|
||||
|
||||
@ -554,9 +704,10 @@ where
|
||||
}
|
||||
|
||||
#[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
|
||||
T: Instance,
|
||||
DM: crate::Mode,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
@ -574,17 +725,23 @@ where
|
||||
}
|
||||
|
||||
#[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
|
||||
pub struct Wdt<TG> {
|
||||
phantom: PhantomData<TG>,
|
||||
pub struct Wdt<TG, DM> {
|
||||
phantom: PhantomData<(TG, DM)>,
|
||||
}
|
||||
|
||||
/// Watchdog driver
|
||||
impl<TG> Wdt<TG>
|
||||
impl<TG, DM> Wdt<TG, DM>
|
||||
where
|
||||
TG: TimerGroupInstance,
|
||||
DM: crate::Mode,
|
||||
{
|
||||
/// Create a new watchdog timer instance
|
||||
pub fn new() -> Self {
|
||||
@ -697,9 +854,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<TG> Default for Wdt<TG>
|
||||
impl<TG, DM> Default for Wdt<TG, DM>
|
||||
where
|
||||
TG: TimerGroupInstance,
|
||||
DM: crate::Mode,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
@ -707,9 +865,10 @@ where
|
||||
}
|
||||
|
||||
#[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
|
||||
TG: TimerGroupInstance,
|
||||
DM: crate::Mode,
|
||||
{
|
||||
fn disable(&mut self) {
|
||||
self.disable();
|
||||
@ -717,9 +876,10 @@ where
|
||||
}
|
||||
|
||||
#[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
|
||||
TG: TimerGroupInstance,
|
||||
DM: crate::Mode,
|
||||
{
|
||||
type Time = MicrosDurationU64;
|
||||
|
||||
@ -733,9 +893,10 @@ where
|
||||
}
|
||||
|
||||
#[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
|
||||
TG: TimerGroupInstance,
|
||||
DM: crate::Mode,
|
||||
{
|
||||
fn feed(&mut self) {
|
||||
self.feed();
|
||||
|
@ -63,6 +63,7 @@ embassy = ["esp-hal/embassy"]
|
||||
embassy-executor-thread = ["esp-hal/embassy-executor-thread"]
|
||||
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-generic-timers = ["embassy-time/generic-queue-8"]
|
||||
|
||||
|
@ -36,7 +36,7 @@ async fn main(spawner: Spawner) {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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);
|
||||
|
||||
spawner.spawn(run()).ok();
|
||||
|
50
examples/src/bin/embassy_hello_world_systimer.rs
Normal file
50
examples/src/bin/embassy_hello_world_systimer.rs
Normal 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;
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ async fn main(_spawner: Spawner) {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
@ -63,7 +63,7 @@ async fn main(_spawner: Spawner) {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
@ -57,7 +57,7 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
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);
|
||||
|
||||
let mut cpu_control = CpuControl::new(system.cpu_control);
|
||||
|
@ -92,7 +92,7 @@ fn main() -> ! {
|
||||
|
||||
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);
|
||||
|
||||
let mut cpu_control = CpuControl::new(system.cpu_control);
|
||||
|
@ -84,7 +84,7 @@ async fn main(low_prio_spawner: Spawner) {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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);
|
||||
|
||||
let spawner = INT_EXECUTOR_0.start(Priority::Priority2);
|
||||
|
@ -33,7 +33,7 @@ async fn main(_spawner: Spawner) {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
@ -45,7 +45,7 @@ async fn main(spawner: Spawner) {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
@ -80,7 +80,7 @@ async fn main(spawner: Spawner) {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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);
|
||||
|
||||
let mut uart0 = Uart::new_async(peripherals.UART0, &clocks);
|
||||
|
@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
42
examples/src/bin/embassy_systimer_delay.rs
Normal file
42
examples/src/bin/embassy_systimer_delay.rs
Normal 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;
|
||||
}
|
||||
}
|
@ -80,7 +80,7 @@ async fn main(spawner: Spawner) {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
@ -71,7 +71,7 @@ async fn main(spawner: Spawner) -> () {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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();
|
||||
|
||||
|
@ -29,7 +29,7 @@ async fn main(_spawner: Spawner) {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
@ -14,18 +14,19 @@ use esp_hal::{
|
||||
clock::ClockControl,
|
||||
delay::Delay,
|
||||
etm::Etm,
|
||||
interrupt::{self, Priority},
|
||||
peripherals::{Interrupt, Peripherals, TIMG0},
|
||||
peripherals::{Peripherals, TIMG0},
|
||||
prelude::*,
|
||||
timer::{
|
||||
etm::{TimerEtmEvents, TimerEtmTasks},
|
||||
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]
|
||||
fn main() -> ! {
|
||||
@ -33,7 +34,14 @@ fn main() -> ! {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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;
|
||||
|
||||
// Configure ETM to stop timer0 when alarm is triggered
|
||||
@ -50,14 +58,10 @@ fn main() -> ! {
|
||||
// 80 / 2 (default divider) timer clock cycles == 1 us
|
||||
timer0.load_alarm_value(100 * 1_000 * 40);
|
||||
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);
|
||||
|
||||
critical_section::with(|cs| {
|
||||
timer0.listen();
|
||||
TIMER0.borrow_ref_mut(cs).replace(timer0);
|
||||
});
|
||||
|
||||
@ -75,8 +79,8 @@ fn main() -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn TG0_T0_LEVEL() {
|
||||
#[handler]
|
||||
fn tg0_t0_level() {
|
||||
critical_section::with(|cs| {
|
||||
let mut timer0 = TIMER0.borrow_ref_mut(cs);
|
||||
let timer0 = timer0.as_mut().unwrap();
|
||||
|
@ -18,13 +18,15 @@ use esp_hal::{
|
||||
peripherals::{Interrupt, Peripherals},
|
||||
prelude::*,
|
||||
systimer::{Alarm, Periodic, SystemTimer, Target},
|
||||
Blocking,
|
||||
};
|
||||
use esp_println::println;
|
||||
use fugit::ExtU32;
|
||||
|
||||
static ALARM0: Mutex<RefCell<Option<Alarm<Periodic, 0>>>> = Mutex::new(RefCell::new(None));
|
||||
static ALARM1: Mutex<RefCell<Option<Alarm<Target, 1>>>> = Mutex::new(RefCell::new(None));
|
||||
static ALARM2: Mutex<RefCell<Option<Alarm<Target, 2>>>> = Mutex::new(RefCell::new(None));
|
||||
static ALARM0: Mutex<RefCell<Option<Alarm<Periodic, Blocking, 0>>>> =
|
||||
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]
|
||||
fn main() -> ! {
|
||||
@ -36,19 +38,22 @@ fn main() -> ! {
|
||||
|
||||
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| {
|
||||
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);
|
||||
ALARM1.borrow_ref_mut(cs).replace(alarm1);
|
||||
ALARM2.borrow_ref_mut(cs).replace(alarm2);
|
||||
@ -67,8 +72,8 @@ fn main() -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn SYSTIMER_TARGET0() {
|
||||
#[handler(priority = esp_hal::interrupt::Priority::min())]
|
||||
fn systimer_target0() {
|
||||
println!("Interrupt lvl1 (alarm0)");
|
||||
critical_section::with(|cs| {
|
||||
ALARM0
|
||||
@ -79,8 +84,8 @@ fn SYSTIMER_TARGET0() {
|
||||
});
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn SYSTIMER_TARGET1() {
|
||||
#[handler(priority = esp_hal::interrupt::Priority::Priority1)]
|
||||
fn systimer_target1() {
|
||||
println!("Interrupt lvl2 (alarm1)");
|
||||
critical_section::with(|cs| {
|
||||
ALARM1
|
||||
@ -91,8 +96,8 @@ fn SYSTIMER_TARGET1() {
|
||||
});
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn SYSTIMER_TARGET2() {
|
||||
#[handler(priority = esp_hal::interrupt::Priority::max())]
|
||||
fn systimer_target2() {
|
||||
println!("Interrupt lvl2 (alarm2)");
|
||||
critical_section::with(|cs| {
|
||||
ALARM2
|
||||
|
@ -16,10 +16,11 @@ use esp_hal::{
|
||||
interrupt::{self, Priority},
|
||||
peripherals::{Interrupt, Peripherals, TIMG0},
|
||||
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]
|
||||
fn main() -> ! {
|
||||
@ -27,7 +28,14 @@ fn main() -> ! {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
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;
|
||||
|
||||
interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap();
|
||||
@ -41,8 +49,8 @@ fn main() -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn TG0_T0_LEVEL() {
|
||||
#[handler]
|
||||
fn tg0_t0_level() {
|
||||
critical_section::with(|cs| {
|
||||
esp_println::println!("Interrupt 1");
|
||||
|
||||
|
@ -26,7 +26,7 @@ fn main() -> ! {
|
||||
|
||||
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;
|
||||
wdt0.enable();
|
||||
wdt0.set_timeout(2u64.secs());
|
||||
|
@ -45,7 +45,7 @@ impl Context {
|
||||
|
||||
let delay = Delay::new(&clocks);
|
||||
|
||||
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
|
||||
embassy::init(&clocks, timg0);
|
||||
|
||||
Context {
|
||||
|
Loading…
x
Reference in New Issue
Block a user