Skip to main content

embassy_stm32/timer/
mod.rs

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