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