atsamd_hal/peripherals/timer/
async_api.rs
1use crate::{
7 async_hal::interrupts::{Binding, Handler, Interrupt},
8 pac,
9 timer_traits::InterruptDrivenTimer,
10 typelevel::Sealed,
11};
12use atsamd_hal_macros::hal_cfg;
13use core::{
14 future::poll_fn,
15 marker::PhantomData,
16 sync::atomic::Ordering,
17 task::{Poll, Waker},
18};
19use embassy_sync::waitqueue::AtomicWaker;
20use fugit::NanosDurationU32;
21use portable_atomic::AtomicBool;
22
23use crate::peripherals::timer;
24
25#[hal_cfg("tc1")]
26#[allow(unused_imports)]
27use crate::pac::Tc1;
28
29#[hal_cfg("tc2")]
30#[allow(unused_imports)]
31use crate::pac::Tc2;
32
33#[hal_cfg("tc3")]
34#[allow(unused_imports)]
35use crate::pac::Tc3;
36
37#[hal_cfg("tc4")]
38#[allow(unused_imports)]
39use crate::pac::Tc4;
40
41#[hal_cfg("tc5")]
42#[allow(unused_imports)]
43use crate::pac::Tc5;
44
45use timer::{Count16, TimerCounter};
46
47#[hal_cfg("tc1-d11")]
48type RegBlock = pac::tc1::RegisterBlock;
49
50#[hal_cfg("tc3-d21")]
51type RegBlock = pac::tc3::RegisterBlock;
52
53#[hal_cfg("tc1-d5x")]
54type RegBlock = pac::tc0::RegisterBlock;
55
56pub trait AsyncCount16: Count16 + Sealed {
61 const STATE_ID: usize;
63
64 fn reg_block(peripherals: &pac::Peripherals) -> &RegBlock;
66
67 type Interrupt: Interrupt;
69}
70
71pub struct InterruptHandler<T: AsyncCount16> {
73 _private: (),
74 _tc: PhantomData<T>,
75}
76
77impl<T: AsyncCount16> crate::typelevel::Sealed for InterruptHandler<T> {}
78
79impl<A: AsyncCount16> Handler<A::Interrupt> for InterruptHandler<A> {
80 unsafe fn on_interrupt() {
91 let periph = unsafe { crate::pac::Peripherals::steal() };
92 let tc = A::reg_block(&periph);
93 let intflag = &tc.count16().intflag();
94
95 if intflag.read().ovf().bit_is_set() {
96 intflag.modify(|_, w| w.ovf().set_bit());
98 STATE[A::STATE_ID].wake();
99 }
100 }
101}
102
103macro_rules! impl_async_count16 {
104 ($TC: ident, $id: expr) => {
105 paste::paste! {
106 impl AsyncCount16 for $TC {
107 const STATE_ID: usize = $id;
108
109 type Interrupt = crate::async_hal::interrupts::[< $TC:upper >];
110
111 fn reg_block(peripherals: &pac::Peripherals) -> &RegBlock {
112 &*peripherals.[< $TC:lower >]
113 }
114 }
115
116 impl Sealed for $TC {}
117 }
118 };
119}
120
121#[hal_cfg("tc1-d11")]
122impl_async_count16!(Tc1, 0);
123
124#[hal_cfg("tc3-d21")]
125impl_async_count16!(Tc3, 0);
126
127#[hal_cfg("tc4-d21")]
128impl_async_count16!(Tc4, 1);
129
130#[hal_cfg("tc5-d21")]
131impl_async_count16!(Tc5, 2);
132
133#[hal_cfg("tc2-d5x")]
134impl_async_count16!(Tc2, 0);
135
136#[hal_cfg("tc3-d5x")]
137impl_async_count16!(Tc3, 1);
138
139#[hal_cfg("tc4-d5x")]
140impl_async_count16!(Tc4, 2);
141
142#[hal_cfg("tc5-d5x")]
143impl_async_count16!(Tc5, 3);
144
145#[hal_cfg("tc1-d11")]
149const NUM_TIMERS: usize = 1;
150
151#[hal_cfg("tc3-d21")]
152const NUM_TIMERS: usize = 3;
153
154#[hal_cfg("tc3-d5x")]
155const NUM_TIMERS: usize = 4;
156
157impl<T> TimerCounter<T>
158where
159 T: AsyncCount16,
160{
161 #[inline]
163 pub fn into_future<I>(mut self, _irq: I) -> TimerFuture<T>
164 where
165 I: Binding<T::Interrupt, InterruptHandler<T>>,
166 {
167 T::Interrupt::unpend();
168 unsafe { T::Interrupt::enable() };
169 self.enable_interrupt();
170
171 TimerFuture { timer: self }
172 }
173}
174
175pub struct TimerFuture<T>
177where
178 T: AsyncCount16,
179{
180 timer: TimerCounter<T>,
181}
182
183impl<T> TimerFuture<T>
184where
185 T: AsyncCount16,
186{
187 #[inline]
189 pub async fn delay(&mut self, count: NanosDurationU32) {
190 self.timer.start(count);
191 self.timer.enable_interrupt();
192
193 poll_fn(|cx| {
194 STATE[T::STATE_ID].register(cx.waker());
195 if STATE[T::STATE_ID].ready() {
196 return Poll::Ready(());
197 }
198
199 Poll::Pending
200 })
201 .await;
202 }
203}
204
205impl<T> Drop for TimerFuture<T>
206where
207 T: AsyncCount16,
208{
209 #[inline]
210 fn drop(&mut self) {
211 T::Interrupt::disable();
212 }
213}
214
215impl<T> embedded_hal_async::delay::DelayNs for TimerFuture<T>
216where
217 T: AsyncCount16,
218{
219 async fn delay_ns(&mut self, ns: u32) {
220 self.delay(NanosDurationU32::from_ticks(ns).convert()).await;
221 }
222}
223
224struct State {
227 waker: AtomicWaker,
228 ready: AtomicBool,
229}
230
231impl State {
232 #[inline]
233 const fn new() -> Self {
234 Self {
235 waker: AtomicWaker::new(),
236 ready: AtomicBool::new(false),
237 }
238 }
239
240 #[inline]
241 fn register(&self, waker: &Waker) {
242 self.waker.register(waker)
243 }
244
245 #[inline]
246 fn wake(&self) {
247 self.ready.store(true, Ordering::SeqCst);
248 self.waker.wake()
249 }
250
251 #[inline]
252 fn ready(&self) -> bool {
253 self.ready.swap(false, Ordering::SeqCst)
254 }
255}
256
257#[allow(clippy::declare_interior_mutable_const)]
258const STATE_NEW: State = State::new();
259static STATE: [State; NUM_TIMERS] = [STATE_NEW; NUM_TIMERS];