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: &mut DierBasicNoCr2| r.set_ude(val: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: &mut CcerAdv| w.set_ccnp(n:channel.index(), val: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: &mut CcerAdv| w.set_ccne(n:channel.index(), val:enable));
694 }
695}
696