1use core::mem::ManuallyDrop;
14
15use crate::pac;
16use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
17pub 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#[derive(Clone, Copy)]
27pub enum InputCaptureMode {
28 Rising,
30 Falling,
32 BothEdges,
34}
35
36#[derive(Clone, Copy)]
38pub enum InputTISelection {
39 Normal,
41 Alternate,
43 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#[repr(u8)]
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
60pub enum CountingMode {
61 #[default]
62 EdgeAlignedUp,
64 EdgeAlignedDown,
66 CenterAlignedDownInterrupts,
71 CenterAlignedUpInterrupts,
76 CenterAlignedBothInterrupts,
81}
82
83impl CountingMode {
84 pub fn is_edge_aligned(&self) -> bool {
86 matches!(
87 self,
88 CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown
89 )
90 }
91
92 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#[derive(Clone, Copy)]
129pub enum OutputCompareMode {
130 Frozen,
134 ActiveOnMatch,
137 InactiveOnMatch,
140 Toggle,
142 ForceInactive,
144 ForceActive,
146 PwmMode1,
150 PwmMode2,
154 }
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#[derive(Clone, Copy)]
174pub enum OutputPolarity {
175 ActiveHigh,
177 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
190pub 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 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 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 pub fn start(&self) {
233 self.regs_core().cr1().modify(|r| r.set_cen(true));
234 }
235
236 pub fn stop(&self) {
238 self.regs_core().cr1().modify(|r| r.set_cen(false));
239 }
240
241 pub fn reset(&self) {
243 self.regs_core().cnt().write(|r| r.set_cnt(0));
244 }
245
246 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 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 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 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 regs.egr().write(|r| r.set_ug(true));
308 }
309
310 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 pub fn enable_update_interrupt(&self, enable: bool) {
328 self.regs_core().dier().modify(|r| r.set_uie(enable));
329 }
330
331 pub fn set_autoreload_preload(&self, enable: bool) {
333 self.regs_core().cr1().modify(|r| r.set_arpe(enable));
334 }
335
336 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 pub fn get_clock_frequency(&self) -> Hertz {
361 T::frequency()
362 }
363}
364
365impl<'d, T: BasicNoCr2Instance> Timer<'d, T> {
366 pub fn regs_basic_no_cr2(&self) -> crate::pac::timer::TimBasicNoCr2 {
373 unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(T::regs()) }
374 }
375
376 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 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 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 pub fn regs_1ch(&self) -> crate::pac::timer::Tim1ch {
409 unsafe { crate::pac::timer::Tim1ch::from_ptr(T::regs()) }
410 }
411
412 pub fn set_clock_division(&self, ckd: vals::Ckd) {
414 self.regs_1ch().cr1().modify(|r| r.set_ckd(ckd));
415 }
416
417 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 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 pub fn regs_gp16(&self) -> crate::pac::timer::TimGp16 {
447 unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) }
448 }
449
450 pub fn enable_outputs(&self) {
452 self.tim.enable_outputs()
453 }
454
455 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 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 pub fn get_counting_mode(&self) -> CountingMode {
470 let cr1 = self.regs_gp16().cr1().read();
471 (cr1.cms(), cr1.dir()).into()
472 }
473
474 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 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 pub fn get_input_interrupt(&self, channel: Channel) -> bool {
491 self.regs_gp16().sr().read().ccif(channel.index())
492 }
493
494 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 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 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 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 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 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 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 pub fn get_channel_enable_state(&self, channel: Channel) -> bool {
559 self.regs_gp16().ccer().read().cce(channel.index())
560 }
561
562 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 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 pub fn get_capture_value(&self, channel: Channel) -> u32 {
591 self.get_compare_value(channel)
592 }
593
594 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 pub fn get_cc_dma_selection(&self) -> vals::Ccds {
604 self.regs_gp16().cr2().read().ccds()
605 }
606
607 pub fn set_cc_dma_selection(&self, ccds: vals::Ccds) {
609 self.regs_gp16().cr2().modify(|w| w.set_ccds(ccds))
610 }
611
612 pub fn get_cc_dma_enable_state(&self, channel: Channel) -> bool {
614 self.regs_gp16().dier().read().ccde(channel.index())
615 }
616
617 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 pub fn set_slave_mode(&self, sms: SlaveMode) {
626 self.regs_gp16().smcr().modify(|r| r.set_sms(sms));
627 }
628
629 pub fn set_trigger_source(&self, ts: TriggerSource) {
631 self.regs_gp16().smcr().modify(|r| r.set_ts(ts));
632 }
633}
634
635impl<'d, T: AdvancedInstance1Channel> Timer<'d, T> {
649 pub fn regs_1ch_cmp(&self) -> crate::pac::timer::Tim1chCmp {
656 unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) }
657 }
658
659 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 pub fn set_dead_time_value(&self, value: u8) {
666 self.regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value));
667 }
668
669 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 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 pub fn regs_advanced(&self) -> crate::pac::timer::TimAdv {
690 unsafe { crate::pac::timer::TimAdv::from_ptr(T::regs()) }
691 }
692
693 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 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}