aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src
diff options
context:
space:
mode:
authorBruno Bousquet <[email protected]>2024-05-06 02:47:42 -0400
committerBruno Bousquet <[email protected]>2024-05-06 02:47:42 -0400
commit55c8d3f4743bc653c1659dc3e961df86afe7d3db (patch)
tree3ec6a5afaf16d4a7aa38fd532a661e597a832acd /embassy-stm32/src
parentb662dfb1838a72d243e939da9349c68c8fef5bdc (diff)
add async capture
Diffstat (limited to 'embassy-stm32/src')
-rw-r--r--embassy-stm32/src/timer/input_capture.rs100
-rw-r--r--embassy-stm32/src/timer/mod.rs93
2 files changed, 185 insertions, 8 deletions
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs
index bc7614cda..e5ec2505a 100644
--- a/embassy-stm32/src/timer/input_capture.rs
+++ b/embassy-stm32/src/timer/input_capture.rs
@@ -1,12 +1,17 @@
1//! Input capture driver. 1//! Input capture driver.
2 2
3use core::future::Future;
3use core::marker::PhantomData; 4use core::marker::PhantomData;
5use core::pin::Pin;
6use core::task::{Context, Poll};
4 7
5use embassy_hal_internal::{into_ref, PeripheralRef}; 8use embassy_hal_internal::{into_ref, PeripheralRef};
6 9
7use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, Timer}; 10use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, Timer};
11use super::CaptureCompareInterruptHandler;
8use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel}; 12use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel};
9use crate::gpio::{AFType, AnyPin, Pull}; 13use crate::gpio::{AFType, AnyPin, Pull};
14use crate::interrupt::typelevel::{Binding, Interrupt};
10use crate::time::Hertz; 15use crate::time::Hertz;
11use crate::Peripheral; 16use crate::Peripheral;
12 17
@@ -65,6 +70,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
65 _ch2: Option<CapturePin<'d, T, Ch2>>, 70 _ch2: Option<CapturePin<'d, T, Ch2>>,
66 _ch3: Option<CapturePin<'d, T, Ch3>>, 71 _ch3: Option<CapturePin<'d, T, Ch3>>,
67 _ch4: Option<CapturePin<'d, T, Ch4>>, 72 _ch4: Option<CapturePin<'d, T, Ch4>>,
73 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
68 freq: Hertz, 74 freq: Hertz,
69 counting_mode: CountingMode, 75 counting_mode: CountingMode,
70 ) -> Self { 76 ) -> Self {
@@ -79,13 +85,9 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
79 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details 85 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
80 this.inner.start(); 86 this.inner.start();
81 87
82 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] 88 // enable NVIC interrupt
83 .iter() 89 T::CaptureCompareInterrupt::unpend();
84 .for_each(|&channel| { 90 unsafe { T::CaptureCompareInterrupt::enable() };
85 this.inner.set_input_capture_mode(channel, InputCaptureMode::Rising);
86
87 this.inner.set_input_ti_selection(channel, InputTISelection::Normal);
88 });
89 91
90 this 92 this
91 } 93 }
@@ -142,4 +144,88 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
142 pub fn get_input_interrupt(&self, channel: Channel) -> bool { 144 pub fn get_input_interrupt(&self, channel: Channel) -> bool {
143 self.inner.get_input_interrupt(channel) 145 self.inner.get_input_interrupt(channel)
144 } 146 }
147
148 fn new_future(&self, channel: Channel, mode: InputCaptureMode, tisel: InputTISelection) -> InputCaptureFuture<T> {
149 self.inner.enable_channel(channel, true);
150 self.inner.set_input_capture_mode(channel, mode);
151 self.inner.set_input_ti_selection(channel, tisel);
152 self.inner.clear_input_interrupt(channel);
153 self.inner.enable_input_interrupt(channel, true);
154
155 InputCaptureFuture {
156 channel,
157 phantom: PhantomData,
158 }
159 }
160
161 /// Asynchronously wait until the pin sees a rising edge.
162 pub async fn wait_for_rising_edge(&mut self, channel: Channel) -> u32 {
163 self.new_future(channel, InputCaptureMode::Rising, InputTISelection::Normal)
164 .await
165 }
166
167 /// Asynchronously wait until the pin sees a falling edge.
168 pub async fn wait_for_falling_edge(&mut self, channel: Channel) -> u32 {
169 self.new_future(channel, InputCaptureMode::Falling, InputTISelection::Normal)
170 .await
171 }
172
173 /// Asynchronously wait until the pin sees any edge.
174 pub async fn wait_for_any_edge(&mut self, channel: Channel) -> u32 {
175 self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Normal)
176 .await
177 }
178
179 /// Asynchronously wait until the (alternate) pin sees a rising edge.
180 pub async fn wait_for_rising_edge_alternate(&mut self, channel: Channel) -> u32 {
181 self.new_future(channel, InputCaptureMode::Rising, InputTISelection::Alternate)
182 .await
183 }
184
185 /// Asynchronously wait until the (alternate) pin sees a falling edge.
186 pub async fn wait_for_falling_edge_alternate(&mut self, channel: Channel) -> u32 {
187 self.new_future(channel, InputCaptureMode::Falling, InputTISelection::Alternate)
188 .await
189 }
190
191 /// Asynchronously wait until the (alternate) pin sees any edge.
192 pub async fn wait_for_any_edge_alternate(&mut self, channel: Channel) -> u32 {
193 self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Alternate)
194 .await
195 }
196}
197
198#[must_use = "futures do nothing unless you `.await` or poll them"]
199struct InputCaptureFuture<T: GeneralInstance4Channel> {
200 channel: Channel,
201 phantom: PhantomData<T>,
202}
203
204impl<T: GeneralInstance4Channel> Drop for InputCaptureFuture<T> {
205 fn drop(&mut self) {
206 critical_section::with(|_| {
207 let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
208
209 // disable interrupt enable
210 regs.dier().modify(|w| w.set_ccie(self.channel.index(), false));
211 });
212 }
213}
214
215impl<T: GeneralInstance4Channel> Future for InputCaptureFuture<T> {
216 type Output = u32;
217
218 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
219 T::state().cc_waker[self.channel.index()].register(cx.waker());
220
221 let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
222
223 let dier = regs.dier().read();
224 if !dier.ccie(self.channel.index()) {
225 let val = regs.ccr(self.channel.index()).read().0;
226 Poll::Ready(val)
227 } else {
228 Poll::Pending
229 }
230 }
145} 231}
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 9a1fbcd61..4b4929aeb 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -1,5 +1,8 @@
1//! Timers, PWM, quadrature decoder. 1//! Timers, PWM, quadrature decoder.
2 2
3use core::marker::PhantomData;
4use embassy_sync::waitqueue::AtomicWaker;
5
3#[cfg(not(stm32l0))] 6#[cfg(not(stm32l0))]
4pub mod complementary_pwm; 7pub mod complementary_pwm;
5pub mod input_capture; 8pub mod input_capture;
@@ -46,8 +49,29 @@ pub enum TimerBits {
46 Bits32, 49 Bits32,
47} 50}
48 51
52struct State {
53 up_waker: AtomicWaker,
54 cc_waker: [AtomicWaker; 4],
55}
56
57impl State {
58 const fn new() -> Self {
59 const NEW_AW: AtomicWaker = AtomicWaker::new();
60 Self {
61 up_waker: NEW_AW,
62 cc_waker: [NEW_AW; 4],
63 }
64 }
65}
66
67trait SealedInstance: RccPeripheral {
68 /// Async state for this timer
69 fn state() -> &'static State;
70}
71
49/// Core timer instance. 72/// Core timer instance.
50pub trait CoreInstance: RccPeripheral + 'static { 73#[allow(private_bounds)]
74pub trait CoreInstance: SealedInstance + 'static {
51 /// Update Interrupt for this timer. 75 /// Update Interrupt for this timer.
52 type UpdateInterrupt: interrupt::typelevel::Interrupt; 76 type UpdateInterrupt: interrupt::typelevel::Interrupt;
53 77
@@ -144,6 +168,13 @@ dma_trait!(Ch4Dma, GeneralInstance4Channel);
144#[allow(unused)] 168#[allow(unused)]
145macro_rules! impl_core_timer { 169macro_rules! impl_core_timer {
146 ($inst:ident, $bits:expr) => { 170 ($inst:ident, $bits:expr) => {
171 impl SealedInstance for crate::peripherals::$inst {
172 fn state() -> &'static State {
173 static STATE: State = State::new();
174 &STATE
175 }
176 }
177
147 impl CoreInstance for crate::peripherals::$inst { 178 impl CoreInstance for crate::peripherals::$inst {
148 type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP; 179 type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP;
149 180
@@ -286,3 +317,63 @@ foreach_interrupt! {
286 impl AdvancedInstance4Channel for crate::peripherals::$inst {} 317 impl AdvancedInstance4Channel for crate::peripherals::$inst {}
287 }; 318 };
288} 319}
320
321/// Update interrupt handler.
322pub struct UpdateInterruptHandler<T: CoreInstance> {
323 _phantom: PhantomData<T>,
324}
325
326impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> {
327 unsafe fn on_interrupt() {
328 #[cfg(feature = "low-power")]
329 crate::low_power::on_wakeup_irq();
330
331 let regs = crate::pac::timer::TimCore::from_ptr(T::regs());
332
333 // Read TIM interrupt flags.
334 let sr = regs.sr().read();
335
336 // Mask relevant interrupts (UIE).
337 let bits = sr.0 & 0x00000001;
338
339 // Mask all the channels that fired.
340 regs.dier().modify(|w| w.0 &= !bits);
341
342 // Wake the tasks
343 if sr.uif() {
344 T::state().up_waker.wake();
345 }
346 }
347}
348
349/// Capture/Compare interrupt handler.
350pub struct CaptureCompareInterruptHandler<T: GeneralInstance1Channel> {
351 _phantom: PhantomData<T>,
352}
353
354impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompareInterrupt>
355 for CaptureCompareInterruptHandler<T>
356{
357 unsafe fn on_interrupt() {
358 #[cfg(feature = "low-power")]
359 crate::low_power::on_wakeup_irq();
360
361 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs());
362
363 // Read TIM interrupt flags.
364 let sr = regs.sr().read();
365
366 // Mask relevant interrupts (CCIE).
367 let bits = sr.0 & 0x0000001E;
368
369 // Mask all the channels that fired.
370 regs.dier().modify(|w| w.0 &= !bits);
371
372 // Wake the tasks
373 for ch in 0..4 {
374 if sr.ccif(ch) {
375 T::state().cc_waker[ch].wake();
376 }
377 }
378 }
379}