-
Notifications
You must be signed in to change notification settings - Fork 195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement embedded_hal_async::delay::DelayNs
for TIMGx
timers
#2084
base: main
Are you sure you want to change the base?
Changes from all commits
f615e97
b188b57
bc1065e
206367f
715b61b
7d7d630
2de7745
de9c2ac
68a9d40
0b12115
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -303,6 +303,57 @@ where | |
{ | ||
/// Construct a new instance of [`TimerGroup`] in asynchronous mode | ||
pub fn new_async(_timer_group: impl Peripheral<P = T> + 'd) -> Self { | ||
match T::id() { | ||
0 => { | ||
use crate::timer::timg::asynch::timg0_timer0_handler; | ||
unsafe { | ||
interrupt::bind_interrupt( | ||
Interrupt::TG0_T0_LEVEL, | ||
timg0_timer0_handler.handler(), | ||
); | ||
interrupt::enable(Interrupt::TG0_T0_LEVEL, timg0_timer0_handler.priority()) | ||
.unwrap(); | ||
|
||
#[cfg(timg_timer1)] | ||
{ | ||
use crate::timer::timg::asynch::timg0_timer1_handler; | ||
|
||
interrupt::bind_interrupt( | ||
Interrupt::TG0_T1_LEVEL, | ||
timg0_timer1_handler.handler(), | ||
); | ||
interrupt::enable(Interrupt::TG0_T1_LEVEL, timg0_timer1_handler.priority()) | ||
.unwrap(); | ||
} | ||
} | ||
} | ||
#[cfg(timg1)] | ||
1 => { | ||
use crate::timer::timg::asynch::timg1_timer0_handler; | ||
unsafe { | ||
{ | ||
interrupt::bind_interrupt( | ||
Interrupt::TG1_T0_LEVEL, | ||
timg1_timer0_handler.handler(), | ||
); | ||
interrupt::enable(Interrupt::TG1_T0_LEVEL, timg1_timer0_handler.priority()) | ||
.unwrap(); | ||
} | ||
#[cfg(timg_timer1)] | ||
{ | ||
use crate::timer::timg::asynch::timg1_timer1_handler; | ||
interrupt::bind_interrupt( | ||
Interrupt::TG1_T1_LEVEL, | ||
timg1_timer1_handler.handler(), | ||
); | ||
interrupt::enable(Interrupt::TG1_T1_LEVEL, timg1_timer1_handler.priority()) | ||
.unwrap(); | ||
} | ||
} | ||
} | ||
_ => unreachable!(), | ||
} | ||
|
||
Self::new_inner(_timer_group) | ||
} | ||
} | ||
|
@@ -1039,6 +1090,157 @@ where | |
} | ||
} | ||
|
||
// Async functionality of the timer groups. | ||
mod asynch { | ||
use core::{ | ||
pin::Pin, | ||
task::{Context, Poll}, | ||
}; | ||
|
||
use embassy_sync::waitqueue::AtomicWaker; | ||
use procmacros::handler; | ||
|
||
use super::*; | ||
|
||
cfg_if::cfg_if! { | ||
if #[cfg(all(timg1, timg_timer1))] { | ||
const NUM_WAKERS: usize = 4; | ||
} else if #[cfg(timg1)] { | ||
const NUM_WAKERS: usize = 2; | ||
} else { | ||
const NUM_WAKERS: usize = 1; | ||
} | ||
} | ||
|
||
#[allow(clippy::declare_interior_mutable_const)] | ||
const INIT: AtomicWaker = AtomicWaker::new(); | ||
static WAKERS: [AtomicWaker; NUM_WAKERS] = [INIT; NUM_WAKERS]; | ||
|
||
pub(crate) struct TimerFuture<'a, T> | ||
where | ||
T: Instance, | ||
{ | ||
timer: &'a Timer<T, crate::Async>, | ||
} | ||
|
||
impl<'a, T> TimerFuture<'a, T> | ||
where | ||
T: Instance, | ||
{ | ||
pub(crate) fn new(timer: &'a Timer<T, crate::Async>) -> Self { | ||
use crate::timer::Timer; | ||
|
||
timer.enable_interrupt(true); | ||
|
||
Self { timer } | ||
} | ||
|
||
fn event_bit_is_clear(&self) -> bool { | ||
self.timer | ||
.register_block() | ||
.int_ena() | ||
.read() | ||
.t(self.timer.timer_number()) | ||
.bit_is_clear() | ||
} | ||
} | ||
|
||
impl<'a, T> core::future::Future for TimerFuture<'a, T> | ||
where | ||
T: Instance, | ||
{ | ||
type Output = (); | ||
|
||
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { | ||
let index = (self.timer.timer_number() << 1) | self.timer.timer_group(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mind making a (const) function for this math? Then it can be used in the interrupt handlers as well, just so we know the indexing is consistent/correct. |
||
WAKERS[index as usize].register(ctx.waker()); | ||
|
||
if self.event_bit_is_clear() { | ||
Poll::Ready(()) | ||
} else { | ||
Poll::Pending | ||
} | ||
} | ||
} | ||
|
||
impl<T> embedded_hal_async::delay::DelayNs for Timer<T, crate::Async> | ||
where | ||
T: Instance, | ||
{ | ||
async fn delay_ns(&mut self, ns: u32) { | ||
use crate::timer::Timer as _; | ||
|
||
let period = MicrosDurationU64::from_ticks(ns.div_ceil(1000) as u64); | ||
self.load_value(period).unwrap(); | ||
self.start(); | ||
self.listen(); | ||
Comment on lines
+1175
to
+1176
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably not super important for this PR but if the user cancels the future returned by this delay function, the call to |
||
|
||
TimerFuture::new(self).await; | ||
} | ||
} | ||
|
||
#[handler] | ||
pub(crate) fn timg0_timer0_handler() { | ||
lock(&INT_ENA_LOCK, || { | ||
unsafe { &*crate::peripherals::TIMG0::PTR } | ||
.int_ena() | ||
.modify(|_, w| w.t(0).clear_bit()) | ||
}); | ||
|
||
unsafe { &*crate::peripherals::TIMG0::PTR } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you mind adding a comment here explaining why this INT_CLR is necessary even though the INT_ENA has been cleared above. |
||
.int_clr() | ||
.write(|w| w.t(0).clear_bit_by_one()); | ||
|
||
WAKERS[0].wake(); | ||
} | ||
|
||
#[cfg(timg1)] | ||
#[handler] | ||
pub(crate) fn timg1_timer0_handler() { | ||
lock(&INT_ENA_LOCK, || { | ||
unsafe { &*crate::peripherals::TIMG1::PTR } | ||
.int_ena() | ||
.modify(|_, w| w.t(0).clear_bit()) | ||
}); | ||
unsafe { &*crate::peripherals::TIMG1::PTR } | ||
.int_clr() | ||
.write(|w| w.t(0).clear_bit_by_one()); | ||
|
||
WAKERS[1].wake(); | ||
} | ||
|
||
#[cfg(timg_timer1)] | ||
#[handler] | ||
pub(crate) fn timg0_timer1_handler() { | ||
lock(&INT_ENA_LOCK, || { | ||
unsafe { &*crate::peripherals::TIMG0::PTR } | ||
.int_ena() | ||
.modify(|_, w| w.t(1).clear_bit()) | ||
}); | ||
unsafe { &*crate::peripherals::TIMG0::PTR } | ||
.int_clr() | ||
.write(|w| w.t(1).clear_bit_by_one()); | ||
|
||
WAKERS[2].wake(); | ||
} | ||
|
||
#[cfg(all(timg1, timg_timer1))] | ||
#[handler] | ||
pub(crate) fn timg1_timer1_handler() { | ||
lock(&INT_ENA_LOCK, || { | ||
unsafe { &*crate::peripherals::TIMG1::PTR } | ||
.int_ena() | ||
.modify(|_, w| w.t(1).clear_bit()) | ||
}); | ||
|
||
unsafe { &*crate::peripherals::TIMG1::PTR } | ||
.int_clr() | ||
.write(|w| w.t(1).clear_bit_by_one()); | ||
|
||
WAKERS[3].wake(); | ||
} | ||
} | ||
|
||
/// Event Task Matrix | ||
#[cfg(soc_etm)] | ||
pub mod etm { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When this future is dropped (early) it should disable the interrupt.