embassy_stm32/timer/
low_level.rs

1//! Low-level timer driver.
2//!
3//! This is an unopinionated, very low-level driver for all STM32 timers. It allows direct register
4//! manipulation with the `regs_*()` methods, and has utility functions that are thin wrappers
5//! over the registers.
6//!
7//! The available functionality depends on the timer type.
8
9use core::mem::ManuallyDrop;
10
11use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
12// Re-export useful enums
13pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource};
14
15use super::*;
16use crate::pac::timer::vals;
17use crate::rcc;
18use crate::time::Hertz;
19
20/// Input capture mode.
21#[derive(Clone, Copy)]
22pub enum InputCaptureMode {
23    /// Rising edge only.
24    Rising,
25    /// Falling edge only.
26    Falling,
27    /// Both rising or falling edges.
28    BothEdges,
29}
30
31/// Input TI selection.
32#[derive(Clone, Copy)]
33pub enum InputTISelection {
34    /// Normal
35    Normal,
36    /// Alternate
37    Alternate,
38    /// TRC
39    TRC,
40}
41
42impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs {
43    fn from(tisel: InputTISelection) -> Self {
44        match tisel {
45            InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4,
46            InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3,
47            InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC,
48        }
49    }
50}
51
52/// Timer counting mode.
53#[repr(u8)]
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
55pub enum CountingMode {
56    #[default]
57    /// The timer counts up to the reload value and then resets back to 0.
58    EdgeAlignedUp,
59    /// The timer counts down to 0 and then resets back to the reload value.
60    EdgeAlignedDown,
61    /// The timer counts up to the reload value and then counts back to 0.
62    ///
63    /// The output compare interrupt flags of channels configured in output are
64    /// set when the counter is counting down.
65    CenterAlignedDownInterrupts,
66    /// The timer counts up to the reload value and then counts back to 0.
67    ///
68    /// The output compare interrupt flags of channels configured in output are
69    /// set when the counter is counting up.
70    CenterAlignedUpInterrupts,
71    /// The timer counts up to the reload value and then counts back to 0.
72    ///
73    /// The output compare interrupt flags of channels configured in output are
74    /// set when the counter is counting both up or down.
75    CenterAlignedBothInterrupts,
76}
77
78impl CountingMode {
79    /// Return whether this mode is edge-aligned (up or down).
80    pub fn is_edge_aligned(&self) -> bool {
81        matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown)
82    }
83
84    /// Return whether this mode is center-aligned.
85    pub fn is_center_aligned(&self) -> bool {
86        matches!(
87            self,
88            CountingMode::CenterAlignedDownInterrupts
89                | CountingMode::CenterAlignedUpInterrupts
90                | CountingMode::CenterAlignedBothInterrupts
91        )
92    }
93}
94
95impl From<CountingMode> for (vals::Cms, vals::Dir) {
96    fn from(value: CountingMode) -> Self {
97        match value {
98            CountingMode::EdgeAlignedUp => (vals::Cms::EDGE_ALIGNED, vals::Dir::UP),
99            CountingMode::EdgeAlignedDown => (vals::Cms::EDGE_ALIGNED, vals::Dir::DOWN),
100            CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTER_ALIGNED1, vals::Dir::UP),
101            CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTER_ALIGNED2, vals::Dir::UP),
102            CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTER_ALIGNED3, vals::Dir::UP),
103        }
104    }
105}
106
107impl From<(vals::Cms, vals::Dir)> for CountingMode {
108    fn from(value: (vals::Cms, vals::Dir)) -> Self {
109        match value {
110            (vals::Cms::EDGE_ALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp,
111            (vals::Cms::EDGE_ALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown,
112            (vals::Cms::CENTER_ALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts,
113            (vals::Cms::CENTER_ALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts,
114            (vals::Cms::CENTER_ALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts,
115        }
116    }
117}
118
119/// Output compare mode.
120#[derive(Clone, Copy)]
121pub enum OutputCompareMode {
122    /// The comparison between the output compare register TIMx_CCRx and
123    /// the counter TIMx_CNT has no effect on the outputs.
124    /// (this mode is used to generate a timing base).
125    Frozen,
126    /// Set channel to active level on match. OCxREF signal is forced high when the
127    /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
128    ActiveOnMatch,
129    /// Set channel to inactive level on match. OCxREF signal is forced low when the
130    /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
131    InactiveOnMatch,
132    /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx.
133    Toggle,
134    /// Force inactive level - OCxREF is forced low.
135    ForceInactive,
136    /// Force active level - OCxREF is forced high.
137    ForceActive,
138    /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx
139    /// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as
140    /// TIMx_CNT>TIMx_CCRx else active (OCxREF=1).
141    PwmMode1,
142    /// PWM mode 2 - In upcounting, channel is inactive as long as
143    /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as
144    /// TIMx_CNT>TIMx_CCRx else inactive.
145    PwmMode2,
146    // TODO: there's more modes here depending on the chip family.
147}
148
149impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
150    fn from(mode: OutputCompareMode) -> Self {
151        match mode {
152            OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN,
153            OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVE_ON_MATCH,
154            OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVE_ON_MATCH,
155            OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE,
156            OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCE_INACTIVE,
157            OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCE_ACTIVE,
158            OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWM_MODE1,
159            OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWM_MODE2,
160        }
161    }
162}
163
164/// Timer output pin polarity.
165#[derive(Clone, Copy)]
166pub enum OutputPolarity {
167    /// Active high (higher duty value makes the pin spend more time high).
168    ActiveHigh,
169    /// Active low (higher duty value makes the pin spend more time low).
170    ActiveLow,
171}
172
173impl From<OutputPolarity> for bool {
174    fn from(mode: OutputPolarity) -> Self {
175        match mode {
176            OutputPolarity::ActiveHigh => false,
177            OutputPolarity::ActiveLow => true,
178        }
179    }
180}
181
182/// Low-level timer driver.
183pub struct Timer<'d, T: CoreInstance> {
184    tim: PeripheralRef<'d, T>,
185}
186
187impl<'d, T: CoreInstance> Drop for Timer<'d, T> {
188    fn drop(&mut self) {
189        rcc::disable::<T>();
190    }
191}
192
193impl<'d, T: CoreInstance> Timer<'d, T> {
194    /// Create a new timer driver.
195    pub fn new(tim: impl Peripheral<P = T> + 'd) -> Self {
196        into_ref!(tim);
197
198        rcc::enable_and_reset::<T>();
199
200        Self { tim }
201    }
202
203    pub(crate) unsafe fn clone_unchecked(&self) -> ManuallyDrop<Self> {
204        let tim = unsafe { self.tim.clone_unchecked() };
205        ManuallyDrop::new(Self { tim })
206    }
207
208    /// Get access to the virutal core 16bit timer registers.
209    ///
210    /// Note: This works even if the timer is more capable, because registers
211    /// for the less capable timers are a subset. This allows writing a driver
212    /// for a given set of capabilities, and having it transparently work with
213    /// more capable timers.
214    pub fn regs_core(&self) -> crate::pac::timer::TimCore {
215        unsafe { crate::pac::timer::TimCore::from_ptr(T::regs()) }
216    }
217
218    #[cfg(not(stm32l0))]
219    fn regs_gp32_unchecked(&self) -> crate::pac::timer::TimGp32 {
220        unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) }
221    }
222
223    /// Start the timer.
224    pub fn start(&self) {
225        self.regs_core().cr1().modify(|r| r.set_cen(true));
226    }
227
228    /// Stop the timer.
229    pub fn stop(&self) {
230        self.regs_core().cr1().modify(|r| r.set_cen(false));
231    }
232
233    /// Reset the counter value to 0
234    pub fn reset(&self) {
235        self.regs_core().cnt().write(|r| r.set_cnt(0));
236    }
237
238    /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
239    ///
240    /// This means that in the default edge-aligned mode,
241    /// the timer counter will wrap around at the same frequency as is being set.
242    /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved
243    /// because it needs to count up and down.
244    pub fn set_frequency(&self, frequency: Hertz) {
245        match T::BITS {
246            TimerBits::Bits16 => {
247                self.set_frequency_internal(frequency, 16);
248            }
249            #[cfg(not(stm32l0))]
250            TimerBits::Bits32 => {
251                self.set_frequency_internal(frequency, 32);
252            }
253        }
254    }
255
256    pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: u8) {
257        let f = frequency.0;
258        assert!(f > 0);
259        let timer_f = T::frequency().0;
260
261        let pclk_ticks_per_timer_period = (timer_f / f) as u64;
262        let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << max_divide_by_bits)).try_into());
263        let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1);
264
265        match T::BITS {
266            TimerBits::Bits16 => {
267                // the timer counts `0..=arr`, we want it to count `0..divide_by`
268                let arr = unwrap!(u16::try_from(divide_by - 1));
269
270                let regs = self.regs_core();
271                regs.psc().write_value(psc);
272                regs.arr().write(|r| r.set_arr(arr));
273
274                regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
275                regs.egr().write(|r| r.set_ug(true));
276                regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
277            }
278            #[cfg(not(stm32l0))]
279            TimerBits::Bits32 => {
280                // the timer counts `0..=arr`, we want it to count `0..divide_by`
281                let arr: u32 = unwrap!(u32::try_from(divide_by - 1));
282
283                let regs = self.regs_gp32_unchecked();
284                regs.psc().write_value(psc);
285                regs.arr().write_value(arr);
286
287                regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
288                regs.egr().write(|r| r.set_ug(true));
289                regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
290            }
291        }
292    }
293
294    /// Set tick frequency.
295    pub fn set_tick_freq(&mut self, freq: Hertz) {
296        let f = freq;
297        assert!(f.0 > 0);
298        let timer_f = self.get_clock_frequency();
299
300        let pclk_ticks_per_timer_period = timer_f / f;
301        let psc: u16 = unwrap!((pclk_ticks_per_timer_period - 1).try_into());
302
303        let regs = self.regs_core();
304        regs.psc().write_value(psc);
305
306        // Generate an Update Request
307        regs.egr().write(|r| r.set_ug(true));
308    }
309
310    /// Clear update interrupt.
311    ///
312    /// Returns whether the update interrupt flag was set.
313    pub fn clear_update_interrupt(&self) -> bool {
314        let regs = self.regs_core();
315        let sr = regs.sr().read();
316        if sr.uif() {
317            regs.sr().modify(|r| {
318                r.set_uif(false);
319            });
320            true
321        } else {
322            false
323        }
324    }
325
326    /// Enable/disable the update interrupt.
327    pub fn enable_update_interrupt(&self, enable: bool) {
328        self.regs_core().dier().modify(|r| r.set_uie(enable));
329    }
330
331    /// Enable/disable autoreload preload.
332    pub fn set_autoreload_preload(&self, enable: bool) {
333        self.regs_core().cr1().modify(|r| r.set_arpe(enable));
334    }
335
336    /// Get the timer frequency.
337    pub fn get_frequency(&self) -> Hertz {
338        let timer_f = T::frequency();
339
340        match T::BITS {
341            TimerBits::Bits16 => {
342                let regs = self.regs_core();
343                let arr = regs.arr().read().arr();
344                let psc = regs.psc().read();
345
346                timer_f / arr / (psc + 1)
347            }
348            #[cfg(not(stm32l0))]
349            TimerBits::Bits32 => {
350                let regs = self.regs_gp32_unchecked();
351                let arr = regs.arr().read();
352                let psc = regs.psc().read();
353
354                timer_f / arr / (psc + 1)
355            }
356        }
357    }
358
359    /// Get the clock frequency of the timer (before prescaler is applied).
360    pub fn get_clock_frequency(&self) -> Hertz {
361        T::frequency()
362    }
363}
364
365impl<'d, T: BasicNoCr2Instance> Timer<'d, T> {
366    /// Get access to the Baisc 16bit timer registers.
367    ///
368    /// Note: This works even if the timer is more capable, because registers
369    /// for the less capable timers are a subset. This allows writing a driver
370    /// for a given set of capabilities, and having it transparently work with
371    /// more capable timers.
372    pub fn regs_basic_no_cr2(&self) -> crate::pac::timer::TimBasicNoCr2 {
373        unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(T::regs()) }
374    }
375
376    /// Enable/disable the update dma.
377    pub fn enable_update_dma(&self, enable: bool) {
378        self.regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable));
379    }
380
381    /// Get the update dma enable/disable state.
382    pub fn get_update_dma_state(&self) -> bool {
383        self.regs_basic_no_cr2().dier().read().ude()
384    }
385}
386
387impl<'d, T: BasicInstance> Timer<'d, T> {
388    /// Get access to the Baisc 16bit timer registers.
389    ///
390    /// Note: This works even if the timer is more capable, because registers
391    /// for the less capable timers are a subset. This allows writing a driver
392    /// for a given set of capabilities, and having it transparently work with
393    /// more capable timers.
394    pub fn regs_basic(&self) -> crate::pac::timer::TimBasic {
395        unsafe { crate::pac::timer::TimBasic::from_ptr(T::regs()) }
396    }
397}
398
399impl<'d, T: GeneralInstance1Channel> Timer<'d, T> {
400    /// Get access to the general purpose 1 channel 16bit timer registers.
401    ///
402    /// Note: This works even if the timer is more capable, because registers
403    /// for the less capable timers are a subset. This allows writing a driver
404    /// for a given set of capabilities, and having it transparently work with
405    /// more capable timers.
406    pub fn regs_1ch(&self) -> crate::pac::timer::Tim1ch {
407        unsafe { crate::pac::timer::Tim1ch::from_ptr(T::regs()) }
408    }
409
410    /// Set clock divider.
411    pub fn set_clock_division(&self, ckd: vals::Ckd) {
412        self.regs_1ch().cr1().modify(|r| r.set_ckd(ckd));
413    }
414
415    /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
416    pub fn get_max_compare_value(&self) -> u32 {
417        match T::BITS {
418            TimerBits::Bits16 => self.regs_1ch().arr().read().arr() as u32,
419            #[cfg(not(stm32l0))]
420            TimerBits::Bits32 => self.regs_gp32_unchecked().arr().read(),
421        }
422    }
423}
424
425impl<'d, T: GeneralInstance2Channel> Timer<'d, T> {
426    /// Get access to the general purpose 2 channel 16bit timer registers.
427    ///
428    /// Note: This works even if the timer is more capable, because registers
429    /// for the less capable timers are a subset. This allows writing a driver
430    /// for a given set of capabilities, and having it transparently work with
431    /// more capable timers.
432    pub fn regs_2ch(&self) -> crate::pac::timer::Tim2ch {
433        unsafe { crate::pac::timer::Tim2ch::from_ptr(T::regs()) }
434    }
435}
436
437impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
438    /// Get access to the general purpose 16bit timer registers.
439    ///
440    /// Note: This works even if the timer is more capable, because registers
441    /// for the less capable timers are a subset. This allows writing a driver
442    /// for a given set of capabilities, and having it transparently work with
443    /// more capable timers.
444    pub fn regs_gp16(&self) -> crate::pac::timer::TimGp16 {
445        unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) }
446    }
447
448    /// Enable timer outputs.
449    pub fn enable_outputs(&self) {
450        self.tim.enable_outputs()
451    }
452
453    /// Set counting mode.
454    pub fn set_counting_mode(&self, mode: CountingMode) {
455        let (cms, dir) = mode.into();
456
457        let timer_enabled = self.regs_core().cr1().read().cen();
458        // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running.
459        // Changing direction is discouraged while the timer is running.
460        assert!(!timer_enabled);
461
462        self.regs_gp16().cr1().modify(|r| r.set_dir(dir));
463        self.regs_gp16().cr1().modify(|r| r.set_cms(cms))
464    }
465
466    /// Get counting mode.
467    pub fn get_counting_mode(&self) -> CountingMode {
468        let cr1 = self.regs_gp16().cr1().read();
469        (cr1.cms(), cr1.dir()).into()
470    }
471
472    /// Set input capture filter.
473    pub fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) {
474        let raw_channel = channel.index();
475        self.regs_gp16()
476            .ccmr_input(raw_channel / 2)
477            .modify(|r| r.set_icf(raw_channel % 2, icf));
478    }
479
480    /// Clear input interrupt.
481    pub fn clear_input_interrupt(&self, channel: Channel) {
482        self.regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false));
483    }
484
485    /// Get input interrupt.
486    pub fn get_input_interrupt(&self, channel: Channel) -> bool {
487        self.regs_gp16().sr().read().ccif(channel.index())
488    }
489
490    /// Enable input interrupt.
491    pub fn enable_input_interrupt(&self, channel: Channel, enable: bool) {
492        self.regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable));
493    }
494
495    /// Set input capture prescaler.
496    pub fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) {
497        let raw_channel = channel.index();
498        self.regs_gp16()
499            .ccmr_input(raw_channel / 2)
500            .modify(|r| r.set_icpsc(raw_channel % 2, factor));
501    }
502
503    /// Set input TI selection.
504    pub fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) {
505        let raw_channel = channel.index();
506        self.regs_gp16()
507            .ccmr_input(raw_channel / 2)
508            .modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
509    }
510
511    /// Set input capture mode.
512    pub fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) {
513        self.regs_gp16().ccer().modify(|r| match mode {
514            InputCaptureMode::Rising => {
515                r.set_ccnp(channel.index(), false);
516                r.set_ccp(channel.index(), false);
517            }
518            InputCaptureMode::Falling => {
519                r.set_ccnp(channel.index(), false);
520                r.set_ccp(channel.index(), true);
521            }
522            InputCaptureMode::BothEdges => {
523                r.set_ccnp(channel.index(), true);
524                r.set_ccp(channel.index(), true);
525            }
526        });
527    }
528
529    /// Set output compare mode.
530    pub fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) {
531        let raw_channel: usize = channel.index();
532        self.regs_gp16()
533            .ccmr_output(raw_channel / 2)
534            .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
535    }
536
537    /// Set output polarity.
538    pub fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
539        self.regs_gp16()
540            .ccer()
541            .modify(|w| w.set_ccp(channel.index(), polarity.into()));
542    }
543
544    /// Enable/disable a channel.
545    pub fn enable_channel(&self, channel: Channel, enable: bool) {
546        self.regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable));
547    }
548
549    /// Get enable/disable state of a channel
550    pub fn get_channel_enable_state(&self, channel: Channel) -> bool {
551        self.regs_gp16().ccer().read().cce(channel.index())
552    }
553
554    /// Set compare value for a channel.
555    pub fn set_compare_value(&self, channel: Channel, value: u32) {
556        match T::BITS {
557            TimerBits::Bits16 => {
558                let value = unwrap!(u16::try_from(value));
559                self.regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value));
560            }
561            #[cfg(not(stm32l0))]
562            TimerBits::Bits32 => {
563                self.regs_gp32_unchecked().ccr(channel.index()).write_value(value);
564            }
565        }
566    }
567
568    /// Get compare value for a channel.
569    pub fn get_compare_value(&self, channel: Channel) -> u32 {
570        match T::BITS {
571            TimerBits::Bits16 => self.regs_gp16().ccr(channel.index()).read().ccr() as u32,
572            #[cfg(not(stm32l0))]
573            TimerBits::Bits32 => self.regs_gp32_unchecked().ccr(channel.index()).read(),
574        }
575    }
576
577    /// Get capture value for a channel.
578    pub fn get_capture_value(&self, channel: Channel) -> u32 {
579        self.get_compare_value(channel)
580    }
581
582    /// Set output compare preload.
583    pub fn set_output_compare_preload(&self, channel: Channel, preload: bool) {
584        let channel_index = channel.index();
585        self.regs_gp16()
586            .ccmr_output(channel_index / 2)
587            .modify(|w| w.set_ocpe(channel_index % 2, preload));
588    }
589
590    /// Get capture compare DMA selection
591    pub fn get_cc_dma_selection(&self) -> vals::Ccds {
592        self.regs_gp16().cr2().read().ccds()
593    }
594
595    /// Set capture compare DMA selection
596    pub fn set_cc_dma_selection(&self, ccds: vals::Ccds) {
597        self.regs_gp16().cr2().modify(|w| w.set_ccds(ccds))
598    }
599
600    /// Get capture compare DMA enable state
601    pub fn get_cc_dma_enable_state(&self, channel: Channel) -> bool {
602        self.regs_gp16().dier().read().ccde(channel.index())
603    }
604
605    /// Set capture compare DMA enable state
606    pub fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) {
607        self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
608    }
609
610    /// Set Timer Slave Mode
611    pub fn set_slave_mode(&self, sms: SlaveMode) {
612        self.regs_gp16().smcr().modify(|r| r.set_sms(sms));
613    }
614
615    /// Set Timer Trigger Source
616    pub fn set_trigger_source(&self, ts: TriggerSource) {
617        self.regs_gp16().smcr().modify(|r| r.set_ts(ts));
618    }
619}
620
621#[cfg(not(stm32l0))]
622impl<'d, T: GeneralInstance32bit4Channel> Timer<'d, T> {
623    /// Get access to the general purpose 32bit timer registers.
624    ///
625    /// Note: This works even if the timer is more capable, because registers
626    /// for the less capable timers are a subset. This allows writing a driver
627    /// for a given set of capabilities, and having it transparently work with
628    /// more capable timers.
629    pub fn regs_gp32(&self) -> crate::pac::timer::TimGp32 {
630        unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) }
631    }
632}
633
634#[cfg(not(stm32l0))]
635impl<'d, T: AdvancedInstance1Channel> Timer<'d, T> {
636    /// Get access to the general purpose 1 channel with one complementary 16bit timer registers.
637    ///
638    /// Note: This works even if the timer is more capable, because registers
639    /// for the less capable timers are a subset. This allows writing a driver
640    /// for a given set of capabilities, and having it transparently work with
641    /// more capable timers.
642    pub fn regs_1ch_cmp(&self) -> crate::pac::timer::Tim1chCmp {
643        unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) }
644    }
645
646    /// Set clock divider for the dead time.
647    pub fn set_dead_time_clock_division(&self, value: vals::Ckd) {
648        self.regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value));
649    }
650
651    /// Set dead time, as a fraction of the max duty value.
652    pub fn set_dead_time_value(&self, value: u8) {
653        self.regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value));
654    }
655
656    /// Set state of MOE-bit in BDTR register to en-/disable output
657    pub fn set_moe(&self, enable: bool) {
658        self.regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable));
659    }
660}
661
662#[cfg(not(stm32l0))]
663impl<'d, T: AdvancedInstance2Channel> Timer<'d, T> {
664    /// Get access to the general purpose 2 channel with one complementary 16bit timer registers.
665    ///
666    /// Note: This works even if the timer is more capable, because registers
667    /// for the less capable timers are a subset. This allows writing a driver
668    /// for a given set of capabilities, and having it transparently work with
669    /// more capable timers.
670    pub fn regs_2ch_cmp(&self) -> crate::pac::timer::Tim2chCmp {
671        unsafe { crate::pac::timer::Tim2chCmp::from_ptr(T::regs()) }
672    }
673}
674
675#[cfg(not(stm32l0))]
676impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> {
677    /// Get access to the advanced timer registers.
678    pub fn regs_advanced(&self) -> crate::pac::timer::TimAdv {
679        unsafe { crate::pac::timer::TimAdv::from_ptr(T::regs()) }
680    }
681
682    /// Set complementary output polarity.
683    pub fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
684        self.regs_advanced()
685            .ccer()
686            .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
687    }
688
689    /// Enable/disable a complementary channel.
690    pub fn enable_complementary_channel(&self, channel: Channel, enable: bool) {
691        self.regs_advanced()
692            .ccer()
693            .modify(|w| w.set_ccne(channel.index(), enable));
694    }
695}