embassy_stm32/timer/
mod.rs

1//! Timers, PWM, quadrature decoder.
2
3use core::marker::PhantomData;
4
5use embassy_hal_internal::Peripheral;
6use embassy_sync::waitqueue::AtomicWaker;
7
8#[cfg(not(stm32l0))]
9pub mod complementary_pwm;
10pub mod input_capture;
11pub mod low_level;
12pub mod pwm_input;
13pub mod qei;
14pub mod simple_pwm;
15
16use crate::interrupt;
17use crate::rcc::RccPeripheral;
18
19/// Timer channel.
20#[derive(Clone, Copy)]
21pub enum Channel {
22    /// Channel 1.
23    Ch1,
24    /// Channel 2.
25    Ch2,
26    /// Channel 3.
27    Ch3,
28    /// Channel 4.
29    Ch4,
30}
31
32impl Channel {
33    /// Get the channel index (0..3)
34    pub fn index(&self) -> usize {
35        match self {
36            Channel::Ch1 => 0,
37            Channel::Ch2 => 1,
38            Channel::Ch3 => 2,
39            Channel::Ch4 => 3,
40        }
41    }
42}
43
44/// Amount of bits of a timer.
45#[derive(Clone, Copy, PartialEq, Eq, Debug)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub enum TimerBits {
48    /// 16 bits.
49    Bits16,
50    /// 32 bits.
51    #[cfg(not(stm32l0))]
52    Bits32,
53}
54
55struct State {
56    up_waker: AtomicWaker,
57    cc_waker: [AtomicWaker; 4],
58}
59
60impl State {
61    const fn new() -> Self {
62        Self {
63            up_waker: AtomicWaker::new(),
64            cc_waker: [const { AtomicWaker::new() }; 4],
65        }
66    }
67}
68
69trait SealedInstance: RccPeripheral + Peripheral<P = Self> {
70    /// Async state for this timer
71    fn state() -> &'static State;
72}
73
74/// Core timer instance.
75#[allow(private_bounds)]
76pub trait CoreInstance: SealedInstance + 'static {
77    /// Update Interrupt for this timer.
78    type UpdateInterrupt: interrupt::typelevel::Interrupt;
79
80    /// Amount of bits this timer has.
81    const BITS: TimerBits;
82
83    /// Registers for this timer.
84    ///
85    /// This is a raw pointer to the register block. The actual register block layout varies depending on the timer type.
86    fn regs() -> *mut ();
87}
88/// Cut-down basic timer instance.
89pub trait BasicNoCr2Instance: CoreInstance {}
90/// Basic timer instance.
91pub trait BasicInstance: BasicNoCr2Instance {}
92
93/// General-purpose 16-bit timer with 1 channel instance.
94pub trait GeneralInstance1Channel: CoreInstance {
95    /// Capture compare interrupt for this timer.
96    type CaptureCompareInterrupt: interrupt::typelevel::Interrupt;
97}
98
99/// General-purpose 16-bit timer with 2 channels instance.
100pub trait GeneralInstance2Channel: GeneralInstance1Channel {
101    /// Trigger event interrupt for this timer.
102    type TriggerInterrupt: interrupt::typelevel::Interrupt;
103}
104
105// This trait add *extra* methods to GeneralInstance4Channel,
106// that GeneralInstance4Channel doesn't use, but the "AdvancedInstance"s need.
107// And it's a private trait, so it's content won't leak to outer namespace.
108//
109// If you want to add a new method to it, please leave a detail comment to explain it.
110trait General4ChBlankSealed {
111    // SimplePwm<'d, T> is implemented for T: GeneralInstance4Channel
112    // Advanced timers implement this trait, but the output needs to be
113    // enabled explicitly.
114    // To support general-purpose and advanced timers, this function is added
115    // here defaulting to noop and overwritten for advanced timers.
116    //
117    // Enable timer outputs.
118    fn enable_outputs(&self) {}
119}
120
121/// General-purpose 16-bit timer with 4 channels instance.
122#[allow(private_bounds)]
123pub trait GeneralInstance4Channel: BasicInstance + GeneralInstance2Channel + General4ChBlankSealed {}
124
125/// General-purpose 32-bit timer with 4 channels instance.
126pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {}
127
128/// Advanced 16-bit timer with 1 channel instance.
129pub trait AdvancedInstance1Channel: BasicNoCr2Instance + GeneralInstance1Channel {
130    /// Communication interrupt for this timer.
131    type CommunicationInterrupt: interrupt::typelevel::Interrupt;
132    /// Break input interrupt for this timer.
133    type BreakInputInterrupt: interrupt::typelevel::Interrupt;
134}
135/// Advanced 16-bit timer with 2 channels instance.
136
137pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + AdvancedInstance1Channel {}
138
139/// Advanced 16-bit timer with 4 channels instance.
140pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {}
141
142pin_trait!(Channel1Pin, GeneralInstance4Channel);
143pin_trait!(Channel2Pin, GeneralInstance4Channel);
144pin_trait!(Channel3Pin, GeneralInstance4Channel);
145pin_trait!(Channel4Pin, GeneralInstance4Channel);
146pin_trait!(ExternalTriggerPin, GeneralInstance4Channel);
147
148pin_trait!(Channel1ComplementaryPin, AdvancedInstance4Channel);
149pin_trait!(Channel2ComplementaryPin, AdvancedInstance4Channel);
150pin_trait!(Channel3ComplementaryPin, AdvancedInstance4Channel);
151pin_trait!(Channel4ComplementaryPin, AdvancedInstance4Channel);
152
153pin_trait!(BreakInputPin, AdvancedInstance4Channel);
154pin_trait!(BreakInput2Pin, AdvancedInstance4Channel);
155
156pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel);
157pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel);
158
159pin_trait!(BreakInput2Comparator1Pin, AdvancedInstance4Channel);
160pin_trait!(BreakInput2Comparator2Pin, AdvancedInstance4Channel);
161
162// Update Event trigger DMA for every timer
163dma_trait!(UpDma, BasicInstance);
164
165dma_trait!(Ch1Dma, GeneralInstance4Channel);
166dma_trait!(Ch2Dma, GeneralInstance4Channel);
167dma_trait!(Ch3Dma, GeneralInstance4Channel);
168dma_trait!(Ch4Dma, GeneralInstance4Channel);
169
170#[allow(unused)]
171macro_rules! impl_core_timer {
172    ($inst:ident, $bits:expr) => {
173        impl SealedInstance for crate::peripherals::$inst {
174            fn state() -> &'static State {
175                static STATE: State = State::new();
176                &STATE
177            }
178        }
179
180        impl CoreInstance for crate::peripherals::$inst {
181            type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP;
182
183            const BITS: TimerBits = $bits;
184
185            fn regs() -> *mut () {
186                crate::pac::$inst.as_ptr()
187            }
188        }
189    };
190}
191
192#[allow(unused)]
193macro_rules! impl_general_1ch {
194    ($inst:ident) => {
195        impl GeneralInstance1Channel for crate::peripherals::$inst {
196            type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC;
197        }
198    };
199}
200
201#[allow(unused)]
202macro_rules! impl_general_2ch {
203    ($inst:ident) => {
204        impl GeneralInstance2Channel for crate::peripherals::$inst {
205            type TriggerInterrupt = crate::_generated::peripheral_interrupts::$inst::TRG;
206        }
207    };
208}
209
210#[allow(unused)]
211macro_rules! impl_advanced_1ch {
212    ($inst:ident) => {
213        impl AdvancedInstance1Channel for crate::peripherals::$inst {
214            type CommunicationInterrupt = crate::_generated::peripheral_interrupts::$inst::COM;
215            type BreakInputInterrupt = crate::_generated::peripheral_interrupts::$inst::BRK;
216        }
217    };
218}
219
220// This macro only apply to "AdvancedInstance(s)",
221// not "GeneralInstance4Channel" itself.
222#[allow(unused)]
223macro_rules! impl_general_4ch_blank_sealed {
224    ($inst:ident) => {
225        impl General4ChBlankSealed for crate::peripherals::$inst {
226            fn enable_outputs(&self) {
227                unsafe { crate::pac::timer::Tim1chCmp::from_ptr(Self::regs()) }
228                    .bdtr()
229                    .modify(|w| w.set_moe(true));
230            }
231        }
232    };
233}
234
235foreach_interrupt! {
236    ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
237        impl_core_timer!($inst, TimerBits::Bits16);
238        impl BasicNoCr2Instance for crate::peripherals::$inst {}
239        impl BasicInstance for crate::peripherals::$inst {}
240    };
241
242    ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => {
243        impl_core_timer!($inst, TimerBits::Bits16);
244        impl BasicNoCr2Instance for crate::peripherals::$inst {}
245        impl BasicInstance for crate::peripherals::$inst {}
246        impl_general_1ch!($inst);
247        impl_general_2ch!($inst);
248        impl GeneralInstance4Channel for crate::peripherals::$inst {}
249        impl General4ChBlankSealed for crate::peripherals::$inst {}
250    };
251
252    ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => {
253        impl_core_timer!($inst, TimerBits::Bits16);
254        impl BasicNoCr2Instance for crate::peripherals::$inst {}
255        impl BasicInstance for crate::peripherals::$inst {}
256        impl_general_1ch!($inst);
257        impl_general_2ch!($inst);
258        impl GeneralInstance4Channel for crate::peripherals::$inst {}
259        impl General4ChBlankSealed for crate::peripherals::$inst {}
260    };
261
262    ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
263        impl_core_timer!($inst, TimerBits::Bits16);
264        impl BasicNoCr2Instance for crate::peripherals::$inst {}
265        impl BasicInstance for crate::peripherals::$inst {}
266        impl_general_1ch!($inst);
267        impl_general_2ch!($inst);
268        impl GeneralInstance4Channel for crate::peripherals::$inst {}
269        impl General4ChBlankSealed for crate::peripherals::$inst {}
270    };
271
272    ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
273        impl_core_timer!($inst, TimerBits::Bits32);
274        impl BasicNoCr2Instance for crate::peripherals::$inst {}
275        impl BasicInstance for crate::peripherals::$inst {}
276        impl_general_1ch!($inst);
277        impl_general_2ch!($inst);
278        impl GeneralInstance4Channel for crate::peripherals::$inst {}
279        impl GeneralInstance32bit4Channel for crate::peripherals::$inst {}
280        impl General4ChBlankSealed for crate::peripherals::$inst {}
281    };
282
283    ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => {
284        impl_core_timer!($inst, TimerBits::Bits16);
285        impl BasicNoCr2Instance for crate::peripherals::$inst {}
286        impl BasicInstance for crate::peripherals::$inst {}
287        impl_general_1ch!($inst);
288        impl_general_2ch!($inst);
289        impl GeneralInstance4Channel for crate::peripherals::$inst {}
290        impl_general_4ch_blank_sealed!($inst);
291        impl_advanced_1ch!($inst);
292        impl AdvancedInstance2Channel for crate::peripherals::$inst {}
293        impl AdvancedInstance4Channel for crate::peripherals::$inst {}
294    };
295
296    ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => {
297        impl_core_timer!($inst, TimerBits::Bits16);
298        impl BasicNoCr2Instance for crate::peripherals::$inst {}
299        impl BasicInstance for crate::peripherals::$inst {}
300        impl_general_1ch!($inst);
301        impl_general_2ch!($inst);
302        impl GeneralInstance4Channel for crate::peripherals::$inst {}
303        impl_general_4ch_blank_sealed!($inst);
304        impl_advanced_1ch!($inst);
305        impl AdvancedInstance2Channel for crate::peripherals::$inst {}
306        impl AdvancedInstance4Channel for crate::peripherals::$inst {}
307    };
308
309    ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
310        impl_core_timer!($inst, TimerBits::Bits16);
311        impl BasicNoCr2Instance for crate::peripherals::$inst {}
312        impl BasicInstance for crate::peripherals::$inst {}
313        impl_general_1ch!($inst);
314        impl_general_2ch!($inst);
315        impl GeneralInstance4Channel for crate::peripherals::$inst {}
316        impl_general_4ch_blank_sealed!($inst);
317        impl_advanced_1ch!($inst);
318        impl AdvancedInstance2Channel for crate::peripherals::$inst {}
319        impl AdvancedInstance4Channel for crate::peripherals::$inst {}
320    };
321}
322
323/// Update interrupt handler.
324pub struct UpdateInterruptHandler<T: CoreInstance> {
325    _phantom: PhantomData<T>,
326}
327
328impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> {
329    unsafe fn on_interrupt() {
330        #[cfg(feature = "low-power")]
331        crate::low_power::on_wakeup_irq();
332
333        let regs = crate::pac::timer::TimCore::from_ptr(T::regs());
334
335        // Read TIM interrupt flags.
336        let sr = regs.sr().read();
337
338        // Mask relevant interrupts (UIE).
339        let bits = sr.0 & 0x00000001;
340
341        // Mask all the channels that fired.
342        regs.dier().modify(|w| w.0 &= !bits);
343
344        // Wake the tasks
345        if sr.uif() {
346            T::state().up_waker.wake();
347        }
348    }
349}
350
351/// Capture/Compare interrupt handler.
352pub struct CaptureCompareInterruptHandler<T: GeneralInstance1Channel> {
353    _phantom: PhantomData<T>,
354}
355
356impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompareInterrupt>
357    for CaptureCompareInterruptHandler<T>
358{
359    unsafe fn on_interrupt() {
360        #[cfg(feature = "low-power")]
361        crate::low_power::on_wakeup_irq();
362
363        let regs = crate::pac::timer::TimGp16::from_ptr(T::regs());
364
365        // Read TIM interrupt flags.
366        let sr = regs.sr().read();
367
368        // Mask relevant interrupts (CCIE).
369        let bits = sr.0 & 0x0000001E;
370
371        // Mask all the channels that fired.
372        regs.dier().modify(|w| w.0 &= !bits);
373
374        // Wake the tasks
375        for ch in 0..4 {
376            if sr.ccif(ch) {
377                T::state().cc_waker[ch].wake();
378            }
379        }
380    }
381}