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::Peri;
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: Peri<'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: Peri<'d, T>) -> Self {
196        rcc::enable_and_reset::<T>();
197
198        Self { tim }
199    }
200
201    pub(crate) unsafe fn clone_unchecked(&self) -> ManuallyDrop<Self> {
202        let tim = unsafe { self.tim.clone_unchecked() };
203        ManuallyDrop::new(Self { tim })
204    }
205
206    /// Get access to the virutal core 16bit timer registers.
207    ///
208    /// Note: This works even if the timer is more capable, because registers
209    /// for the less capable timers are a subset. This allows writing a driver
210    /// for a given set of capabilities, and having it transparently work with
211    /// more capable timers.
212    pub fn regs_core(&self) -> crate::pac::timer::TimCore {
213        unsafe { crate::pac::timer::TimCore::from_ptr(T::regs()) }
214    }
215
216    #[cfg(not(stm32l0))]
217    fn regs_gp32_unchecked(&self) -> crate::pac::timer::TimGp32 {
218        unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) }
219    }
220
221    /// Start the timer.
222    pub fn start(&self) {
223        self.regs_core().cr1().modify(|r| r.set_cen(true));
224    }
225
226    /// Stop the timer.
227    pub fn stop(&self) {
228        self.regs_core().cr1().modify(|r| r.set_cen(false));
229    }
230
231    /// Reset the counter value to 0
232    pub fn reset(&self) {
233        self.regs_core().cnt().write(|r| r.set_cnt(0));
234    }
235
236    /// get the capability of the timer
237    pub fn bits(&self) -> TimerBits {
238        T::BITS
239    }
240
241    /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
242    ///
243    /// This means that in the default edge-aligned mode,
244    /// the timer counter will wrap around at the same frequency as is being set.
245    /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved
246    /// because it needs to count up and down.
247    pub fn set_frequency(&self, frequency: Hertz) {
248        match T::BITS {
249            TimerBits::Bits16 => {
250                self.set_frequency_internal(frequency, 16);
251            }
252            #[cfg(not(stm32l0))]
253            TimerBits::Bits32 => {
254                self.set_frequency_internal(frequency, 32);
255            }
256        }
257    }
258
259    pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: u8) {
260        let f = frequency.0;
261        assert!(f > 0);
262        let timer_f = T::frequency().0;
263
264        let pclk_ticks_per_timer_period = (timer_f / f) as u64;
265        let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << max_divide_by_bits)).try_into());
266        let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1);
267
268        match T::BITS {
269            TimerBits::Bits16 => {
270                // the timer counts `0..=arr`, we want it to count `0..divide_by`
271                let arr = unwrap!(u16::try_from(divide_by - 1));
272
273                let regs = self.regs_core();
274                regs.psc().write_value(psc);
275                regs.arr().write(|r| r.set_arr(arr));
276
277                regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
278                regs.egr().write(|r| r.set_ug(true));
279                regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
280            }
281            #[cfg(not(stm32l0))]
282            TimerBits::Bits32 => {
283                // the timer counts `0..=arr`, we want it to count `0..divide_by`
284                let arr: u32 = unwrap!(u32::try_from(divide_by - 1));
285
286                let regs = self.regs_gp32_unchecked();
287                regs.psc().write_value(psc);
288                regs.arr().write_value(arr);
289
290                regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
291                regs.egr().write(|r| r.set_ug(true));
292                regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
293            }
294        }
295    }
296
297    /// Set tick frequency.
298    pub fn set_tick_freq(&mut self, freq: Hertz) {
299        let f = freq;
300        assert!(f.0 > 0);
301        let timer_f = self.get_clock_frequency();
302
303        let pclk_ticks_per_timer_period = timer_f / f;
304        let psc: u16 = unwrap!((pclk_ticks_per_timer_period - 1).try_into());
305
306        let regs = self.regs_core();
307        regs.psc().write_value(psc);
308
309        // Generate an Update Request
310        regs.egr().write(|r| r.set_ug(true));
311    }
312
313    /// Clear update interrupt.
314    ///
315    /// Returns whether the update interrupt flag was set.
316    pub fn clear_update_interrupt(&self) -> bool {
317        let regs = self.regs_core();
318        let sr = regs.sr().read();
319        if sr.uif() {
320            regs.sr().modify(|r| {
321                r.set_uif(false);
322            });
323            true
324        } else {
325            false
326        }
327    }
328
329    /// Enable/disable the update interrupt.
330    pub fn enable_update_interrupt(&self, enable: bool) {
331        self.regs_core().dier().modify(|r| r.set_uie(enable));
332    }
333
334    /// Enable/disable autoreload preload.
335    pub fn set_autoreload_preload(&self, enable: bool) {
336        self.regs_core().cr1().modify(|r| r.set_arpe(enable));
337    }
338
339    /// Get the timer frequency.
340    pub fn get_frequency(&self) -> Hertz {
341        let timer_f = T::frequency();
342
343        match T::BITS {
344            TimerBits::Bits16 => {
345                let regs = self.regs_core();
346                let arr = regs.arr().read().arr();
347                let psc = regs.psc().read();
348
349                timer_f / arr / (psc + 1)
350            }
351            #[cfg(not(stm32l0))]
352            TimerBits::Bits32 => {
353                let regs = self.regs_gp32_unchecked();
354                let arr = regs.arr().read();
355                let psc = regs.psc().read();
356
357                timer_f / arr / (psc + 1)
358            }
359        }
360    }
361
362    /// Get the clock frequency of the timer (before prescaler is applied).
363    pub fn get_clock_frequency(&self) -> Hertz {
364        T::frequency()
365    }
366}
367
368impl<'d, T: BasicNoCr2Instance> Timer<'d, T> {
369    /// Get access to the Baisc 16bit timer registers.
370    ///
371    /// Note: This works even if the timer is more capable, because registers
372    /// for the less capable timers are a subset. This allows writing a driver
373    /// for a given set of capabilities, and having it transparently work with
374    /// more capable timers.
375    pub fn regs_basic_no_cr2(&self) -> crate::pac::timer::TimBasicNoCr2 {
376        unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(T::regs()) }
377    }
378
379    /// Enable/disable the update dma.
380    pub fn enable_update_dma(&self, enable: bool) {
381        self.regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable));
382    }
383
384    /// Get the update dma enable/disable state.
385    pub fn get_update_dma_state(&self) -> bool {
386        self.regs_basic_no_cr2().dier().read().ude()
387    }
388}
389
390impl<'d, T: BasicInstance> Timer<'d, T> {
391    /// Get access to the Baisc 16bit timer registers.
392    ///
393    /// Note: This works even if the timer is more capable, because registers
394    /// for the less capable timers are a subset. This allows writing a driver
395    /// for a given set of capabilities, and having it transparently work with
396    /// more capable timers.
397    pub fn regs_basic(&self) -> crate::pac::timer::TimBasic {
398        unsafe { crate::pac::timer::TimBasic::from_ptr(T::regs()) }
399    }
400}
401
402impl<'d, T: GeneralInstance1Channel> Timer<'d, T> {
403    /// Get access to the general purpose 1 channel 16bit timer registers.
404    ///
405    /// Note: This works even if the timer is more capable, because registers
406    /// for the less capable timers are a subset. This allows writing a driver
407    /// for a given set of capabilities, and having it transparently work with
408    /// more capable timers.
409    pub fn regs_1ch(&self) -> crate::pac::timer::Tim1ch {
410        unsafe { crate::pac::timer::Tim1ch::from_ptr(T::regs()) }
411    }
412
413    /// Set clock divider.
414    pub fn set_clock_division(&self, ckd: vals::Ckd) {
415        self.regs_1ch().cr1().modify(|r| r.set_ckd(ckd));
416    }
417
418    /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
419    pub fn get_max_compare_value(&self) -> u32 {
420        match T::BITS {
421            TimerBits::Bits16 => self.regs_1ch().arr().read().arr() as u32,
422            #[cfg(not(stm32l0))]
423            TimerBits::Bits32 => self.regs_gp32_unchecked().arr().read(),
424        }
425    }
426
427    /// Set the max compare value.
428    ///
429    /// An update event is generated to load the new value. The update event is
430    /// generated such that it will not cause an interrupt or DMA request.
431    pub fn set_max_compare_value(&self, ticks: u32) {
432        match T::BITS {
433            TimerBits::Bits16 => {
434                let arr = unwrap!(u16::try_from(ticks));
435
436                let regs = self.regs_1ch();
437                regs.arr().write(|r| r.set_arr(arr));
438
439                regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
440                regs.egr().write(|r| r.set_ug(true));
441                regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
442            }
443            #[cfg(not(stm32l0))]
444            TimerBits::Bits32 => {
445                let arr = ticks;
446
447                let regs = self.regs_gp32_unchecked();
448                regs.arr().write_value(arr);
449
450                regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
451                regs.egr().write(|r| r.set_ug(true));
452                regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
453            }
454        }
455    }
456}
457
458impl<'d, T: GeneralInstance2Channel> Timer<'d, T> {
459    /// Get access to the general purpose 2 channel 16bit timer registers.
460    ///
461    /// Note: This works even if the timer is more capable, because registers
462    /// for the less capable timers are a subset. This allows writing a driver
463    /// for a given set of capabilities, and having it transparently work with
464    /// more capable timers.
465    pub fn regs_2ch(&self) -> crate::pac::timer::Tim2ch {
466        unsafe { crate::pac::timer::Tim2ch::from_ptr(T::regs()) }
467    }
468}
469
470impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
471    /// Get access to the general purpose 16bit timer registers.
472    ///
473    /// Note: This works even if the timer is more capable, because registers
474    /// for the less capable timers are a subset. This allows writing a driver
475    /// for a given set of capabilities, and having it transparently work with
476    /// more capable timers.
477    pub fn regs_gp16(&self) -> crate::pac::timer::TimGp16 {
478        unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) }
479    }
480
481    /// Enable timer outputs.
482    pub fn enable_outputs(&self) {
483        self.tim.enable_outputs()
484    }
485
486    /// Set counting mode.
487    pub fn set_counting_mode(&self, mode: CountingMode) {
488        let (cms, dir) = mode.into();
489
490        let timer_enabled = self.regs_core().cr1().read().cen();
491        // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running.
492        // Changing direction is discouraged while the timer is running.
493        assert!(!timer_enabled);
494
495        self.regs_gp16().cr1().modify(|r| r.set_dir(dir));
496        self.regs_gp16().cr1().modify(|r| r.set_cms(cms))
497    }
498
499    /// Get counting mode.
500    pub fn get_counting_mode(&self) -> CountingMode {
501        let cr1 = self.regs_gp16().cr1().read();
502        (cr1.cms(), cr1.dir()).into()
503    }
504
505    /// Set input capture filter.
506    pub fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) {
507        let raw_channel = channel.index();
508        self.regs_gp16()
509            .ccmr_input(raw_channel / 2)
510            .modify(|r| r.set_icf(raw_channel % 2, icf));
511    }
512
513    /// Clear input interrupt.
514    pub fn clear_input_interrupt(&self, channel: Channel) {
515        self.regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false));
516    }
517
518    /// Get input interrupt.
519    pub fn get_input_interrupt(&self, channel: Channel) -> bool {
520        self.regs_gp16().sr().read().ccif(channel.index())
521    }
522
523    /// Enable input interrupt.
524    pub fn enable_input_interrupt(&self, channel: Channel, enable: bool) {
525        self.regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable));
526    }
527
528    /// Set input capture prescaler.
529    pub fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) {
530        let raw_channel = channel.index();
531        self.regs_gp16()
532            .ccmr_input(raw_channel / 2)
533            .modify(|r| r.set_icpsc(raw_channel % 2, factor));
534    }
535
536    /// Set input TI selection.
537    pub fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) {
538        let raw_channel = channel.index();
539        self.regs_gp16()
540            .ccmr_input(raw_channel / 2)
541            .modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
542    }
543
544    /// Set input capture mode.
545    pub fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) {
546        self.regs_gp16().ccer().modify(|r| match mode {
547            InputCaptureMode::Rising => {
548                r.set_ccnp(channel.index(), false);
549                r.set_ccp(channel.index(), false);
550            }
551            InputCaptureMode::Falling => {
552                r.set_ccnp(channel.index(), false);
553                r.set_ccp(channel.index(), true);
554            }
555            InputCaptureMode::BothEdges => {
556                r.set_ccnp(channel.index(), true);
557                r.set_ccp(channel.index(), true);
558            }
559        });
560    }
561
562    /// Set output compare mode.
563    pub fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) {
564        let raw_channel: usize = channel.index();
565        self.regs_gp16()
566            .ccmr_output(raw_channel / 2)
567            .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
568    }
569
570    /// Set output polarity.
571    pub fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
572        self.regs_gp16()
573            .ccer()
574            .modify(|w| w.set_ccp(channel.index(), polarity.into()));
575    }
576
577    /// Enable/disable a channel.
578    pub fn enable_channel(&self, channel: Channel, enable: bool) {
579        self.regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable));
580    }
581
582    /// Get enable/disable state of a channel
583    pub fn get_channel_enable_state(&self, channel: Channel) -> bool {
584        self.regs_gp16().ccer().read().cce(channel.index())
585    }
586
587    /// Set compare value for a channel.
588    pub fn set_compare_value(&self, channel: Channel, value: u32) {
589        match T::BITS {
590            TimerBits::Bits16 => {
591                let value = unwrap!(u16::try_from(value));
592                self.regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value));
593            }
594            #[cfg(not(stm32l0))]
595            TimerBits::Bits32 => {
596                self.regs_gp32_unchecked().ccr(channel.index()).write_value(value);
597            }
598        }
599    }
600
601    /// Get compare value for a channel.
602    pub fn get_compare_value(&self, channel: Channel) -> u32 {
603        match T::BITS {
604            TimerBits::Bits16 => self.regs_gp16().ccr(channel.index()).read().ccr() as u32,
605            #[cfg(not(stm32l0))]
606            TimerBits::Bits32 => self.regs_gp32_unchecked().ccr(channel.index()).read(),
607        }
608    }
609
610    /// Get capture value for a channel.
611    pub fn get_capture_value(&self, channel: Channel) -> u32 {
612        self.get_compare_value(channel)
613    }
614
615    /// Set output compare preload.
616    pub fn set_output_compare_preload(&self, channel: Channel, preload: bool) {
617        let channel_index = channel.index();
618        self.regs_gp16()
619            .ccmr_output(channel_index / 2)
620            .modify(|w| w.set_ocpe(channel_index % 2, preload));
621    }
622
623    /// Get capture compare DMA selection
624    pub fn get_cc_dma_selection(&self) -> vals::Ccds {
625        self.regs_gp16().cr2().read().ccds()
626    }
627
628    /// Set capture compare DMA selection
629    pub fn set_cc_dma_selection(&self, ccds: vals::Ccds) {
630        self.regs_gp16().cr2().modify(|w| w.set_ccds(ccds))
631    }
632
633    /// Get capture compare DMA enable state
634    pub fn get_cc_dma_enable_state(&self, channel: Channel) -> bool {
635        self.regs_gp16().dier().read().ccde(channel.index())
636    }
637
638    /// Set capture compare DMA enable state
639    pub fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) {
640        self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
641    }
642
643    /// Set Timer Slave Mode
644    pub fn set_slave_mode(&self, sms: SlaveMode) {
645        self.regs_gp16().smcr().modify(|r| r.set_sms(sms));
646    }
647
648    /// Set Timer Trigger Source
649    pub fn set_trigger_source(&self, ts: TriggerSource) {
650        self.regs_gp16().smcr().modify(|r| r.set_ts(ts));
651    }
652}
653
654#[cfg(not(stm32l0))]
655impl<'d, T: GeneralInstance32bit4Channel> Timer<'d, T> {
656    /// Get access to the general purpose 32bit timer registers.
657    ///
658    /// Note: This works even if the timer is more capable, because registers
659    /// for the less capable timers are a subset. This allows writing a driver
660    /// for a given set of capabilities, and having it transparently work with
661    /// more capable timers.
662    pub fn regs_gp32(&self) -> crate::pac::timer::TimGp32 {
663        unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) }
664    }
665}
666
667#[cfg(not(stm32l0))]
668impl<'d, T: AdvancedInstance1Channel> Timer<'d, T> {
669    /// Get access to the general purpose 1 channel with one complementary 16bit timer registers.
670    ///
671    /// Note: This works even if the timer is more capable, because registers
672    /// for the less capable timers are a subset. This allows writing a driver
673    /// for a given set of capabilities, and having it transparently work with
674    /// more capable timers.
675    pub fn regs_1ch_cmp(&self) -> crate::pac::timer::Tim1chCmp {
676        unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) }
677    }
678
679    /// Set clock divider for the dead time.
680    pub fn set_dead_time_clock_division(&self, value: vals::Ckd) {
681        self.regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value));
682    }
683
684    /// Set dead time, as a fraction of the max duty value.
685    pub fn set_dead_time_value(&self, value: u8) {
686        self.regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value));
687    }
688
689    /// Set state of OSSI-bit in BDTR register
690    pub fn set_ossi(&self, val: vals::Ossi) {
691        self.regs_1ch_cmp().bdtr().modify(|w| w.set_ossi(val));
692    }
693
694    /// Get state of OSSI-bit in BDTR register
695    pub fn get_ossi(&self) -> vals::Ossi {
696        self.regs_1ch_cmp().bdtr().read().ossi()
697    }
698
699    /// Set state of OSSR-bit in BDTR register
700    pub fn set_ossr(&self, val: vals::Ossr) {
701        self.regs_1ch_cmp().bdtr().modify(|w| w.set_ossr(val));
702    }
703
704    /// Get state of OSSR-bit in BDTR register
705    pub fn get_ossr(&self) -> vals::Ossr {
706        self.regs_1ch_cmp().bdtr().read().ossr()
707    }
708
709    /// Set state of MOE-bit in BDTR register to en-/disable output
710    pub fn set_moe(&self, enable: bool) {
711        self.regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable));
712    }
713
714    /// Get state of MOE-bit in BDTR register
715    pub fn get_moe(&self) -> bool {
716        self.regs_1ch_cmp().bdtr().read().moe()
717    }
718}
719
720#[cfg(not(stm32l0))]
721impl<'d, T: AdvancedInstance2Channel> Timer<'d, T> {
722    /// Get access to the general purpose 2 channel with one complementary 16bit timer registers.
723    ///
724    /// Note: This works even if the timer is more capable, because registers
725    /// for the less capable timers are a subset. This allows writing a driver
726    /// for a given set of capabilities, and having it transparently work with
727    /// more capable timers.
728    pub fn regs_2ch_cmp(&self) -> crate::pac::timer::Tim2chCmp {
729        unsafe { crate::pac::timer::Tim2chCmp::from_ptr(T::regs()) }
730    }
731}
732
733#[cfg(not(stm32l0))]
734impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> {
735    /// Get access to the advanced timer registers.
736    pub fn regs_advanced(&self) -> crate::pac::timer::TimAdv {
737        unsafe { crate::pac::timer::TimAdv::from_ptr(T::regs()) }
738    }
739
740    /// Set complementary output polarity.
741    pub fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
742        self.regs_advanced()
743            .ccer()
744            .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
745    }
746
747    /// Enable/disable a complementary channel.
748    pub fn enable_complementary_channel(&self, channel: Channel, enable: bool) {
749        self.regs_advanced()
750            .ccer()
751            .modify(|w| w.set_ccne(channel.index(), enable));
752    }
753
754    /// Set Output Idle State
755    pub fn set_ois(&self, channel: Channel, val: bool) {
756        self.regs_advanced().cr2().modify(|w| w.set_ois(channel.index(), val));
757    }
758    /// Set Output Idle State Complementary Channel
759    pub fn set_oisn(&self, channel: Channel, val: bool) {
760        self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val));
761    }
762
763    /// Trigger software break 1 or 2
764    /// Setting this bit generates a break event. This bit is automatically cleared by the hardware.
765    pub fn trigger_software_break(&self, n: usize) {
766        self.regs_advanced().egr().write(|r| r.set_bg(n, true));
767    }
768}