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