embassy_stm32/timer/
one_pulse.rs

1//! One pulse mode driver.
2
3use core::future::Future;
4use core::marker::PhantomData;
5use core::mem::ManuallyDrop;
6use core::pin::Pin;
7use core::task::{Context, Poll};
8
9use super::low_level::{
10    CountingMode, FilterValue, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource as Ts,
11};
12use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin};
13pub use super::{Ch1, Ch2};
14use crate::gpio::{AfType, AnyPin, Pull};
15use crate::interrupt::typelevel::{Binding, Interrupt};
16use crate::pac::timer::vals::Etp;
17use crate::time::Hertz;
18use crate::Peri;
19
20/// External input marker type.
21pub enum Ext {}
22
23/// External trigger pin trigger polarity.
24#[derive(Clone, Copy)]
25pub enum ExternalTriggerPolarity {
26    /// Rising edge only.
27    Rising,
28    /// Falling edge only.
29    Falling,
30}
31
32impl From<ExternalTriggerPolarity> for Etp {
33    fn from(mode: ExternalTriggerPolarity) -> Self {
34        match mode {
35            ExternalTriggerPolarity::Rising => 0.into(),
36            ExternalTriggerPolarity::Falling => 1.into(),
37        }
38    }
39}
40
41/// Trigger pin wrapper.
42///
43/// This wraps a pin to make it usable as a timer trigger.
44pub struct TriggerPin<'d, T, C> {
45    _pin: Peri<'d, AnyPin>,
46    phantom: PhantomData<(T, C)>,
47}
48
49trait SealedTriggerSource {}
50
51/// Marker trait for a trigger source.
52#[expect(private_bounds)]
53pub trait TriggerSource: SealedTriggerSource {}
54
55impl TriggerSource for Ch1 {}
56impl TriggerSource for Ch2 {}
57impl TriggerSource for Ext {}
58
59impl SealedTriggerSource for Ch1 {}
60impl SealedTriggerSource for Ch2 {}
61impl SealedTriggerSource for Ext {}
62
63trait SealedTimerTriggerPin<T, S>: crate::gpio::Pin {}
64
65/// Marker trait for a trigger pin.
66#[expect(private_bounds)]
67// TODO: find better naming scheme than prefixing all pin traits with "Timer".
68// The trait name cannot conflict with the corresponding type's name.
69// Applies to other timer submodules as well.
70pub trait TimerTriggerPin<T, S>: SealedTimerTriggerPin<T, S> {
71    /// Get the AF number needed to use this pin as a trigger source.
72    fn af_num(&self) -> u8;
73}
74
75impl<T, P, C> TimerTriggerPin<T, C> for P
76where
77    T: GeneralInstance4Channel,
78    P: TimerPin<T, C>,
79    C: super::TimerChannel + TriggerSource,
80{
81    fn af_num(&self) -> u8 {
82        TimerPin::af_num(self)
83    }
84}
85
86impl<T, P> TimerTriggerPin<T, Ext> for P
87where
88    T: GeneralInstance4Channel,
89    P: ExternalTriggerPin<T>,
90{
91    fn af_num(&self) -> u8 {
92        ExternalTriggerPin::af_num(self)
93    }
94}
95
96impl<T, P, C> SealedTimerTriggerPin<T, C> for P
97where
98    T: GeneralInstance4Channel,
99    P: TimerPin<T, C>,
100    C: super::TimerChannel + TriggerSource,
101{
102}
103
104impl<T, P> SealedTimerTriggerPin<T, Ext> for P
105where
106    T: GeneralInstance4Channel,
107    P: ExternalTriggerPin<T>,
108{
109}
110
111impl<'d, T: GeneralInstance4Channel, C: TriggerSource> TriggerPin<'d, T, C> {
112    /// "Create a new Ch1 trigger pin instance.
113    pub fn new(pin: Peri<'d, impl TimerTriggerPin<T, C>>, pull: Pull) -> Self {
114        pin.set_as_af(pin.af_num(), AfType::input(pull));
115        TriggerPin {
116            _pin: pin.into(),
117            phantom: PhantomData,
118        }
119    }
120}
121
122/// One pulse driver.
123///
124/// Generates a pulse after a trigger and some configurable delay.
125pub struct OnePulse<'d, T: GeneralInstance4Channel> {
126    inner: Timer<'d, T>,
127}
128
129impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
130    /// Create a new one pulse driver.
131    ///
132    /// The pulse is triggered by a channel 1 input pin on both rising and
133    /// falling edges. Channel 1 will unusable as an output.
134    pub fn new_ch1_edge_detect(
135        tim: Peri<'d, T>,
136        _pin: TriggerPin<'d, T, Ch1>,
137        _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
138        freq: Hertz,
139        pulse_end: u32,
140        counting_mode: CountingMode,
141    ) -> Self {
142        let mut this = Self { inner: Timer::new(tim) };
143
144        this.inner.set_trigger_source(Ts::TI1F_ED);
145        this.inner
146            .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal);
147        this.inner
148            .set_input_capture_filter(Channel::Ch1, FilterValue::NO_FILTER);
149        this.new_inner(freq, pulse_end, counting_mode);
150
151        this
152    }
153
154    /// Create a new one pulse driver.
155    ///
156    /// The pulse is triggered by a channel 1 input pin. Channel 1 will unusable
157    /// as an output.
158    pub fn new_ch1(
159        tim: Peri<'d, T>,
160        _pin: TriggerPin<'d, T, Ch1>,
161        _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
162        freq: Hertz,
163        pulse_end: u32,
164        counting_mode: CountingMode,
165        capture_mode: InputCaptureMode,
166    ) -> Self {
167        let mut this = Self { inner: Timer::new(tim) };
168
169        this.inner.set_trigger_source(Ts::TI1FP1);
170        this.inner
171            .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal);
172        this.inner
173            .set_input_capture_filter(Channel::Ch1, FilterValue::NO_FILTER);
174        this.inner.set_input_capture_mode(Channel::Ch1, capture_mode);
175        this.new_inner(freq, pulse_end, counting_mode);
176
177        this
178    }
179
180    /// Create a new one pulse driver.
181    ///
182    /// The pulse is triggered by a channel 2 input pin. Channel 2 will unusable
183    /// as an output.
184    pub fn new_ch2(
185        tim: Peri<'d, T>,
186        _pin: TriggerPin<'d, T, Ch2>,
187        _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
188        freq: Hertz,
189        pulse_end: u32,
190        counting_mode: CountingMode,
191        capture_mode: InputCaptureMode,
192    ) -> Self {
193        let mut this = Self { inner: Timer::new(tim) };
194
195        this.inner.set_trigger_source(Ts::TI2FP2);
196        this.inner
197            .set_input_ti_selection(Channel::Ch2, InputTISelection::Normal);
198        this.inner
199            .set_input_capture_filter(Channel::Ch2, FilterValue::NO_FILTER);
200        this.inner.set_input_capture_mode(Channel::Ch2, capture_mode);
201        this.new_inner(freq, pulse_end, counting_mode);
202
203        this
204    }
205
206    /// Create a new one pulse driver.
207    ///
208    /// The pulse is triggered by a external trigger input pin.
209    pub fn new_ext(
210        tim: Peri<'d, T>,
211        _pin: TriggerPin<'d, T, Ext>,
212        _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
213        freq: Hertz,
214        pulse_end: u32,
215        counting_mode: CountingMode,
216        polarity: ExternalTriggerPolarity,
217    ) -> Self {
218        let mut this = Self { inner: Timer::new(tim) };
219
220        this.inner.regs_gp16().smcr().modify(|r| {
221            r.set_etp(polarity.into());
222            // No pre-scaling
223            r.set_etps(0.into());
224            // No filtering
225            r.set_etf(FilterValue::NO_FILTER);
226        });
227        this.inner.set_trigger_source(Ts::ETRF);
228        this.new_inner(freq, pulse_end, counting_mode);
229
230        this
231    }
232
233    fn new_inner(&mut self, freq: Hertz, pulse_end: u32, counting_mode: CountingMode) {
234        self.inner.set_counting_mode(counting_mode);
235        self.inner.set_tick_freq(freq);
236        self.inner.set_max_compare_value(pulse_end);
237        self.inner.regs_core().cr1().modify(|r| r.set_opm(true));
238        // Required for advanced timers, see GeneralInstance4Channel for details
239        self.inner.enable_outputs();
240        self.inner.set_slave_mode(SlaveMode::TRIGGER_MODE);
241
242        T::CaptureCompareInterrupt::unpend();
243        unsafe { T::CaptureCompareInterrupt::enable() };
244    }
245
246    /// Get the end of the pulse in ticks from the trigger.
247    pub fn pulse_end(&self) -> u32 {
248        let max = self.inner.get_max_compare_value();
249        assert!(max < u32::MAX);
250        max + 1
251    }
252
253    /// Set the end of the pulse in ticks from the trigger.
254    pub fn set_pulse_end(&mut self, ticks: u32) {
255        self.inner.set_max_compare_value(ticks)
256    }
257
258    /// Reset the timer on each trigger
259    #[cfg(not(stm32l0))]
260    pub fn set_reset_on_trigger(&mut self, reset: bool) {
261        let slave_mode = if reset {
262            SlaveMode::COMBINED_RESET_TRIGGER
263        } else {
264            SlaveMode::TRIGGER_MODE
265        };
266        self.inner.set_slave_mode(slave_mode);
267    }
268
269    /// Get a single channel
270    ///
271    /// If you need to use multiple channels, use [`Self::split`].
272    pub fn channel(&mut self, channel: Channel) -> OnePulseChannel<'_, T> {
273        OnePulseChannel {
274            inner: unsafe { self.inner.clone_unchecked() },
275            channel,
276        }
277    }
278
279    /// Channel 1
280    ///
281    /// This is just a convenience wrapper around [`Self::channel`].
282    ///
283    /// If you need to use multiple channels, use [`Self::split`].
284    pub fn ch1(&mut self) -> OnePulseChannel<'_, T> {
285        self.channel(Channel::Ch1)
286    }
287
288    /// Channel 2
289    ///
290    /// This is just a convenience wrapper around [`Self::channel`].
291    ///
292    /// If you need to use multiple channels, use [`Self::split`].
293    pub fn ch2(&mut self) -> OnePulseChannel<'_, T> {
294        self.channel(Channel::Ch2)
295    }
296
297    /// Channel 3
298    ///
299    /// This is just a convenience wrapper around [`Self::channel`].
300    ///
301    /// If you need to use multiple channels, use [`Self::split`].
302    pub fn ch3(&mut self) -> OnePulseChannel<'_, T> {
303        self.channel(Channel::Ch3)
304    }
305
306    /// Channel 4
307    ///
308    /// This is just a convenience wrapper around [`Self::channel`].
309    ///
310    /// If you need to use multiple channels, use [`Self::split`].
311    pub fn ch4(&mut self) -> OnePulseChannel<'_, T> {
312        self.channel(Channel::Ch4)
313    }
314
315    /// Splits a [`OnePulse`] into four output channels.
316    // TODO: I hate the name "split"
317    pub fn split(self) -> OnePulseChannels<'static, T>
318    where
319        // must be static because the timer will never be dropped/disabled
320        'd: 'static,
321    {
322        // without this, the timer would be disabled at the end of this function
323        let timer = ManuallyDrop::new(self.inner);
324
325        let ch = |channel| OnePulseChannel {
326            inner: unsafe { timer.clone_unchecked() },
327            channel,
328        };
329
330        OnePulseChannels {
331            ch1: ch(Channel::Ch1),
332            ch2: ch(Channel::Ch2),
333            ch3: ch(Channel::Ch3),
334            ch4: ch(Channel::Ch4),
335        }
336    }
337}
338
339/// A group of four [`OnePulseChannel`]s, obtained from [`OnePulse::split`].
340pub struct OnePulseChannels<'d, T: GeneralInstance4Channel> {
341    /// Channel 1
342    pub ch1: OnePulseChannel<'d, T>,
343    /// Channel 2
344    pub ch2: OnePulseChannel<'d, T>,
345    /// Channel 3
346    pub ch3: OnePulseChannel<'d, T>,
347    /// Channel 4
348    pub ch4: OnePulseChannel<'d, T>,
349}
350
351/// A single channel of a one pulse-configured timer, obtained from
352/// [`OnePulse::split`],[`OnePulse::channel`], [`OnePulse::ch1`], etc.
353///
354/// It is not possible to change the pulse end tick because the end tick
355/// configuration is shared with all four channels.
356pub struct OnePulseChannel<'d, T: GeneralInstance4Channel> {
357    inner: ManuallyDrop<Timer<'d, T>>,
358    channel: Channel,
359}
360
361impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> {
362    /// Get the end of the pulse in ticks from the trigger.
363    pub fn pulse_end(&self) -> u32 {
364        let max = self.inner.get_max_compare_value();
365        assert!(max < u32::MAX);
366        max + 1
367    }
368
369    /// Get the width of the pulse in ticks.
370    pub fn pulse_width(&mut self) -> u32 {
371        self.pulse_end().saturating_sub(self.pulse_delay())
372    }
373
374    /// Get the start of the pulse in ticks from the trigger.
375    pub fn pulse_delay(&mut self) -> u32 {
376        self.inner.get_compare_value(self.channel)
377    }
378
379    /// Set the start of the pulse in ticks from the trigger.
380    pub fn set_pulse_delay(&mut self, delay: u32) {
381        assert!(delay <= self.pulse_end());
382        self.inner.set_compare_value(self.channel, delay);
383    }
384
385    /// Set the pulse width in ticks.
386    pub fn set_pulse_width(&mut self, width: u32) {
387        assert!(width <= self.pulse_end());
388        self.set_pulse_delay(self.pulse_end() - width);
389    }
390
391    /// Waits until the trigger and following delay has passed.
392    pub async fn wait_for_pulse_start(&mut self) {
393        self.inner.enable_input_interrupt(self.channel, true);
394
395        OnePulseFuture::<T> {
396            channel: self.channel,
397            phantom: PhantomData,
398        }
399        .await
400    }
401}
402
403#[must_use = "futures do nothing unless you `.await` or poll them"]
404struct OnePulseFuture<T: GeneralInstance4Channel> {
405    channel: Channel,
406    phantom: PhantomData<T>,
407}
408
409impl<'d, T: GeneralInstance4Channel> Drop for OnePulseFuture<T> {
410    fn drop(&mut self) {
411        critical_section::with(|_| {
412            let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
413
414            // disable interrupt enable
415            regs.dier().modify(|w| w.set_ccie(self.channel.index(), false));
416        });
417    }
418}
419
420impl<'d, T: GeneralInstance4Channel> Future for OnePulseFuture<T> {
421    type Output = ();
422
423    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
424        T::state().cc_waker[self.channel.index()].register(cx.waker());
425
426        let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
427
428        let dier = regs.dier().read();
429        if !dier.ccie(self.channel.index()) {
430            Poll::Ready(())
431        } else {
432            Poll::Pending
433        }
434    }
435}