1use core::mem::ManuallyDrop;
10
11use embassy_hal_internal::Peri;
12#[cfg(not(stm32l0))]
13pub use stm32_metapac::timer::vals::{Bkinp as BreakComparatorPolarity, Bkp as BreakInputPolarity};
14pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as SlaveMode, Ts as TriggerSource};
16
17use super::*;
18use crate::dma::{self, Transfer, WritableRingBuffer};
19use crate::pac::timer::vals;
20use crate::rcc;
21use crate::time::Hertz;
22
23#[derive(Clone, Copy)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub enum InputCaptureMode {
27 Rising,
29 Falling,
31 BothEdges,
33}
34
35#[derive(Clone, Copy)]
37#[cfg_attr(feature = "defmt", derive(defmt::Format))]
38pub enum InputTISelection {
39 Normal,
41 Alternate,
43 TRC,
45}
46
47impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs {
48 fn from(tisel: InputTISelection) -> Self {
49 match tisel {
50 InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4,
51 InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3,
52 InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC,
53 }
54 }
55}
56
57#[repr(u8)]
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
61pub enum CountingMode {
62 #[default]
63 EdgeAlignedUp,
65 EdgeAlignedDown,
67 CenterAlignedDownInterrupts,
72 CenterAlignedUpInterrupts,
77 CenterAlignedBothInterrupts,
82}
83
84impl CountingMode {
85 pub fn is_edge_aligned(&self) -> bool {
87 matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown)
88 }
89
90 pub fn is_center_aligned(&self) -> bool {
92 matches!(
93 self,
94 CountingMode::CenterAlignedDownInterrupts
95 | CountingMode::CenterAlignedUpInterrupts
96 | CountingMode::CenterAlignedBothInterrupts
97 )
98 }
99}
100
101impl From<CountingMode> for (vals::Cms, vals::Dir) {
102 fn from(value: CountingMode) -> Self {
103 match value {
104 CountingMode::EdgeAlignedUp => (vals::Cms::EDGE_ALIGNED, vals::Dir::UP),
105 CountingMode::EdgeAlignedDown => (vals::Cms::EDGE_ALIGNED, vals::Dir::DOWN),
106 CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTER_ALIGNED1, vals::Dir::UP),
107 CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTER_ALIGNED2, vals::Dir::UP),
108 CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTER_ALIGNED3, vals::Dir::UP),
109 }
110 }
111}
112
113impl From<(vals::Cms, vals::Dir)> for CountingMode {
114 fn from(value: (vals::Cms, vals::Dir)) -> Self {
115 match value {
116 (vals::Cms::EDGE_ALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp,
117 (vals::Cms::EDGE_ALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown,
118 (vals::Cms::CENTER_ALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts,
119 (vals::Cms::CENTER_ALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts,
120 (vals::Cms::CENTER_ALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts,
121 }
122 }
123}
124
125#[derive(Clone, Copy)]
127#[cfg_attr(feature = "defmt", derive(defmt::Format))]
128pub enum OutputCompareMode {
129 Frozen,
133 ActiveOnMatch,
136 InactiveOnMatch,
139 Toggle,
141 ForceInactive,
143 ForceActive,
145 PwmMode1,
149 PwmMode2,
153
154 #[cfg(timer_v2)]
155 OnePulseMode1,
162
163 #[cfg(timer_v2)]
164 OnePulseMode2,
171
172 #[cfg(timer_v2)]
173 CombinedPwmMode1,
176
177 #[cfg(timer_v2)]
178 CombinedPwmMode2,
181
182 #[cfg(timer_v2)]
183 AsymmetricPwmMode1,
186
187 #[cfg(timer_v2)]
188 AsymmetricPwmMode2,
191}
192
193#[cfg(timer_v3)]
194impl From<OutputCompareMode> for crate::pac::timer::vals::OcmGp {
195 fn from(mode: OutputCompareMode) -> Self {
196 match mode {
197 OutputCompareMode::Frozen => crate::pac::timer::vals::OcmGp::FROZEN,
198 OutputCompareMode::ActiveOnMatch => crate::pac::timer::vals::OcmGp::ACTIVE_ON_MATCH,
199 OutputCompareMode::InactiveOnMatch => crate::pac::timer::vals::OcmGp::INACTIVE_ON_MATCH,
200 OutputCompareMode::Toggle => crate::pac::timer::vals::OcmGp::TOGGLE,
201 OutputCompareMode::ForceInactive => crate::pac::timer::vals::OcmGp::FORCE_INACTIVE,
202 OutputCompareMode::ForceActive => crate::pac::timer::vals::OcmGp::FORCE_ACTIVE,
203 OutputCompareMode::PwmMode1 => crate::pac::timer::vals::OcmGp::PWM_MODE1,
204 OutputCompareMode::PwmMode2 => crate::pac::timer::vals::OcmGp::PWM_MODE2,
205 }
206 }
207}
208
209impl From<OutputCompareMode> for crate::pac::timer::vals::Ocm {
210 fn from(mode: OutputCompareMode) -> Self {
211 match mode {
212 OutputCompareMode::Frozen => crate::pac::timer::vals::Ocm::FROZEN,
213 OutputCompareMode::ActiveOnMatch => crate::pac::timer::vals::Ocm::ACTIVE_ON_MATCH,
214 OutputCompareMode::InactiveOnMatch => crate::pac::timer::vals::Ocm::INACTIVE_ON_MATCH,
215 OutputCompareMode::Toggle => crate::pac::timer::vals::Ocm::TOGGLE,
216 OutputCompareMode::ForceInactive => crate::pac::timer::vals::Ocm::FORCE_INACTIVE,
217 OutputCompareMode::ForceActive => crate::pac::timer::vals::Ocm::FORCE_ACTIVE,
218 OutputCompareMode::PwmMode1 => crate::pac::timer::vals::Ocm::PWM_MODE1,
219 OutputCompareMode::PwmMode2 => crate::pac::timer::vals::Ocm::PWM_MODE2,
220 #[cfg(timer_v2)]
221 OutputCompareMode::OnePulseMode1 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_1,
222 #[cfg(timer_v2)]
223 OutputCompareMode::OnePulseMode2 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_2,
224 #[cfg(timer_v2)]
225 OutputCompareMode::CombinedPwmMode1 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_1,
226 #[cfg(timer_v2)]
227 OutputCompareMode::CombinedPwmMode2 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_2,
228 #[cfg(timer_v2)]
229 OutputCompareMode::AsymmetricPwmMode1 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_1,
230 #[cfg(timer_v2)]
231 OutputCompareMode::AsymmetricPwmMode2 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_2,
232 }
233 }
234}
235
236#[derive(Clone, Copy)]
238#[cfg_attr(feature = "defmt", derive(defmt::Format))]
239pub enum OutputPolarity {
240 ActiveHigh,
242 ActiveLow,
244}
245
246impl From<OutputPolarity> for bool {
247 fn from(mode: OutputPolarity) -> Self {
248 match mode {
249 OutputPolarity::ActiveHigh => false,
250 OutputPolarity::ActiveLow => true,
251 }
252 }
253}
254
255#[derive(Debug, Clone, Copy, PartialEq, Eq)]
261#[cfg_attr(feature = "defmt", derive(defmt::Format))]
262pub enum RoundTo {
263 Slower,
267 Faster,
271}
272
273#[derive(Debug, Clone, Copy, PartialEq, Eq)]
275#[cfg_attr(feature = "defmt", derive(defmt::Format))]
276struct PscArrConfig {
277 psc: u16,
279 arr: u64,
281 actual_period_clocks: u64,
283}
284
285#[derive(Debug, Clone, Copy, PartialEq, Eq)]
291#[cfg_attr(feature = "defmt", derive(defmt::Format))]
292pub struct OutOfRangeError;
293
294fn calculate_psc_arr(period_clocks: u64, round: RoundTo, max_arr_bits: usize) -> Result<PscArrConfig, OutOfRangeError> {
310 let max_arr: u64 = (1 << max_arr_bits) - 1;
311
312 const MIN_PERIOD: u64 = 2;
314
315 if round == RoundTo::Faster && period_clocks < MIN_PERIOD {
318 return Err(OutOfRangeError);
319 }
320
321 let psc_min = period_clocks.saturating_sub(1) / (max_arr + 1);
324 let psc: u16 = match psc_min.try_into() {
325 Ok(v) => v,
326 Err(_) => {
327 match round {
329 RoundTo::Slower => return Err(OutOfRangeError), RoundTo::Faster => u16::MAX, }
332 }
333 };
334
335 let psc_plus_1 = u64::from(psc) + 1;
337
338 let arr = match round {
341 RoundTo::Faster => {
342 (period_clocks / psc_plus_1).saturating_sub(1)
346 }
347 RoundTo::Slower => {
348 period_clocks.div_ceil(psc_plus_1).saturating_sub(1)
352 }
353 };
354
355 let arr = arr.clamp(1, max_arr);
357 let actual_period_clocks = psc_plus_1 * (arr + 1);
358
359 Ok(PscArrConfig {
360 psc,
361 arr,
362 actual_period_clocks,
363 })
364}
365
366fn div_round(numerator: u64, denominator: u64, round: RoundTo) -> u64 {
368 match round {
369 RoundTo::Faster => numerator / denominator,
370 RoundTo::Slower => numerator.div_ceil(denominator),
371 }
372}
373
374pub struct Timer<'d, T: CoreInstance> {
376 tim: Peri<'d, T>,
377}
378
379impl<'d, T: CoreInstance> Drop for Timer<'d, T> {
380 fn drop(&mut self) {
381 rcc::disable::<T>();
382 }
383}
384
385impl<'d, T: CoreInstance> Timer<'d, T> {
386 pub fn new(tim: Peri<'d, T>) -> Self {
388 rcc::enable_and_reset::<T>();
389
390 Self { tim }
391 }
392
393 pub(crate) unsafe fn clone_unchecked(&self) -> ManuallyDrop<Self> {
394 let tim = unsafe { self.tim.clone_unchecked() };
395 ManuallyDrop::new(Self { tim })
396 }
397
398 pub fn regs_core(&self) -> crate::pac::timer::TimCore {
405 unsafe { crate::pac::timer::TimCore::from_ptr(T::regs()) }
406 }
407
408 #[cfg(not(stm32l0))]
409 fn regs_gp32_unchecked(&self) -> crate::pac::timer::TimGp32 {
410 unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) }
411 }
412
413 #[cfg(stm32l0)]
414 fn regs_gp32_unchecked(&self) -> crate::pac::timer::TimGp16 {
415 unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) }
416 }
417
418 pub fn start(&self) {
420 self.regs_core().cr1().modify(|r| r.set_cen(true));
421 }
422
423 pub fn generate_update_event(&self) {
429 self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
430 self.regs_core().egr().write(|r| r.set_ug(true));
431 self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
432 }
433
434 pub fn stop(&self) {
436 self.regs_core().cr1().modify(|r| r.set_cen(false));
437 }
438
439 pub fn reset(&self) {
441 self.regs_core().cnt().write(|r| r.set_cnt(0));
442 }
443
444 pub fn bits(&self) -> TimerBits {
446 match T::Word::bits() {
447 16 => TimerBits::Bits16,
448 #[cfg(not(stm32l0))]
449 32 => TimerBits::Bits32,
450 _ => unreachable!(),
451 }
452 }
453
454 pub fn set_period_clocks(&self, clocks: u64, round: RoundTo) {
460 self.set_period_clocks_internal(clocks, round, T::Word::bits());
461 }
462
463 pub(crate) fn set_period_clocks_internal(&self, clocks: u64, round: RoundTo, max_arr_bits: usize) {
464 let config = unwrap!(calculate_psc_arr(clocks, round, max_arr_bits));
466 let arr: T::Word = unwrap!(T::Word::try_from(config.arr));
467
468 let regs = self.regs_gp32_unchecked();
469 regs.psc().write_value(config.psc);
470 #[cfg(stm32l0)]
471 regs.arr().write(|r| r.set_arr(unwrap!(arr.try_into())));
472 #[cfg(not(stm32l0))]
473 regs.arr().write_value(arr.into());
474 }
475
476 pub fn set_frequency(&self, frequency: Hertz, round: RoundTo) {
486 let f = frequency.0;
487 assert!(f > 0);
488 let timer_f = T::frequency().0 as u64;
489 let clocks = div_round(timer_f, f as u64, round);
490 self.set_period_clocks(clocks, round);
491 }
492
493 pub fn set_period_ms(&self, ms: u32, round: RoundTo) {
498 let timer_f = T::frequency().0 as u64;
499 let clocks = div_round(timer_f * ms as u64, 1_000, round);
500 self.set_period_clocks(clocks, round);
501 }
502
503 pub fn set_period_us(&self, us: u32, round: RoundTo) {
508 let timer_f = T::frequency().0 as u64;
509 let clocks = div_round(timer_f * us as u64, 1_000_000, round);
510 self.set_period_clocks(clocks, round);
511 }
512
513 pub fn set_period_secs(&self, secs: u32, round: RoundTo) {
518 let timer_f = T::frequency().0 as u64;
519 let clocks = timer_f * secs as u64;
520 self.set_period_clocks(clocks, round);
521 }
522
523 #[cfg(feature = "time")]
528 pub fn set_period(&self, period: embassy_time::Duration, round: RoundTo) {
529 let timer_f = T::frequency().0 as u64;
530 let clocks = div_round(timer_f * period.as_ticks(), embassy_time::TICK_HZ, round);
531 self.set_period_clocks(clocks, round);
532 }
533
534 pub fn set_tick_freq(&mut self, freq: Hertz) {
536 let f = freq;
537 assert!(f.0 > 0);
538 let timer_f = self.get_clock_frequency();
539
540 let pclk_ticks_per_timer_period = timer_f / f;
541 let psc: u16 = unwrap!((pclk_ticks_per_timer_period - 1).try_into());
542
543 let regs = self.regs_core();
544 regs.psc().write_value(psc);
545
546 regs.egr().write(|r| r.set_ug(true));
548 }
549
550 pub fn clear_update_interrupt(&self) -> bool {
554 let regs = self.regs_core();
555 let sr = regs.sr().read();
556 if sr.uif() {
557 regs.sr().modify(|r| {
558 r.set_uif(false);
559 });
560 true
561 } else {
562 false
563 }
564 }
565
566 pub fn enable_update_interrupt(&self, enable: bool) {
568 self.regs_core().dier().modify(|r| r.set_uie(enable));
569 }
570
571 pub fn set_autoreload_preload(&self, enable: bool) {
573 self.regs_core().cr1().modify(|r| r.set_arpe(enable));
574 }
575
576 pub fn get_frequency(&self) -> Hertz {
578 let timer_f = T::frequency();
579
580 let regs = self.regs_gp32_unchecked();
581 #[cfg(not(stm32l0))]
582 let arr = regs.arr().read();
583 #[cfg(stm32l0)]
584 let arr = regs.arr().read().arr();
585 let psc = regs.psc().read();
586
587 timer_f / arr / (psc + 1)
588 }
589
590 pub fn get_clock_frequency(&self) -> Hertz {
592 T::frequency()
593 }
594}
595
596impl<'d, T: BasicNoCr2Instance> Timer<'d, T> {
597 pub fn regs_basic_no_cr2(&self) -> crate::pac::timer::TimBasicNoCr2 {
604 unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(T::regs()) }
605 }
606
607 pub fn enable_update_dma(&self, enable: bool) {
609 self.regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable));
610 }
611
612 pub fn get_update_dma_state(&self) -> bool {
614 self.regs_basic_no_cr2().dier().read().ude()
615 }
616}
617
618impl<'d, T: BasicInstance> Timer<'d, T> {
619 pub fn regs_basic(&self) -> crate::pac::timer::TimBasic {
626 unsafe { crate::pac::timer::TimBasic::from_ptr(T::regs()) }
627 }
628}
629
630impl<'d, T: GeneralInstance1Channel> Timer<'d, T> {
631 pub fn regs_1ch(&self) -> crate::pac::timer::Tim1ch {
638 unsafe { crate::pac::timer::Tim1ch::from_ptr(T::regs()) }
639 }
640
641 pub fn set_clock_division(&self, ckd: vals::Ckd) {
643 self.regs_1ch().cr1().modify(|r| r.set_ckd(ckd));
644 }
645
646 pub fn get_max_compare_value(&self) -> T::Word {
648 #[cfg(not(stm32l0))]
649 return unwrap!(self.regs_gp32_unchecked().arr().read().try_into());
650 #[cfg(stm32l0)]
651 return unwrap!(self.regs_gp32_unchecked().arr().read().arr().try_into());
652 }
653
654 pub fn set_max_compare_value(&self, ticks: T::Word) {
659 let arr = ticks;
660
661 let regs = self.regs_gp32_unchecked();
662 #[cfg(not(stm32l0))]
663 regs.arr().write_value(arr.into());
664 #[cfg(stm32l0)]
665 regs.arr().write(|r| r.set_arr(unwrap!(arr.try_into())));
666
667 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
668 regs.egr().write(|r| r.set_ug(true));
669 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
670 }
671}
672
673impl<'d, T: GeneralInstance2Channel> Timer<'d, T> {
674 pub fn regs_2ch(&self) -> crate::pac::timer::Tim2ch {
681 unsafe { crate::pac::timer::Tim2ch::from_ptr(T::regs()) }
682 }
683}
684
685impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
686 pub fn regs_gp16(&self) -> crate::pac::timer::TimGp16 {
693 unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) }
694 }
695
696 pub fn enable_outputs(&self) {
698 self.tim.enable_outputs()
699 }
700
701 pub fn set_counting_mode(&self, mode: CountingMode) {
703 let (cms, dir) = mode.into();
704
705 let timer_enabled = self.regs_core().cr1().read().cen();
706 assert!(!timer_enabled);
709
710 self.regs_gp16().cr1().modify(|r| r.set_dir(dir));
711 self.regs_gp16().cr1().modify(|r| r.set_cms(cms))
712 }
713
714 pub fn get_counting_mode(&self) -> CountingMode {
716 let cr1 = self.regs_gp16().cr1().read();
717 (cr1.cms(), cr1.dir()).into()
718 }
719
720 pub fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) {
722 let raw_channel = channel.index();
723 self.regs_gp16()
724 .ccmr_input(raw_channel / 2)
725 .modify(|r| r.set_icf(raw_channel % 2, icf));
726 }
727
728 pub fn clear_input_interrupt(&self, channel: Channel) {
730 self.regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false));
731 }
732
733 pub fn get_input_interrupt(&self, channel: Channel) -> bool {
735 self.regs_gp16().sr().read().ccif(channel.index())
736 }
737
738 pub fn enable_input_interrupt(&self, channel: Channel, enable: bool) {
740 self.regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable));
741 }
742
743 pub fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) {
745 let raw_channel = channel.index();
746 self.regs_gp16()
747 .ccmr_input(raw_channel / 2)
748 .modify(|r| r.set_icpsc(raw_channel % 2, factor));
749 }
750
751 pub fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) {
753 let raw_channel = channel.index();
754 self.regs_gp16()
755 .ccmr_input(raw_channel / 2)
756 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
757 }
758
759 pub fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) {
761 self.regs_gp16().ccer().modify(|r| match mode {
762 InputCaptureMode::Rising => {
763 r.set_ccnp(channel.index(), false);
764 r.set_ccp(channel.index(), false);
765 }
766 InputCaptureMode::Falling => {
767 r.set_ccnp(channel.index(), false);
768 r.set_ccp(channel.index(), true);
769 }
770 InputCaptureMode::BothEdges => {
771 r.set_ccnp(channel.index(), true);
772 r.set_ccp(channel.index(), true);
773 }
774 });
775 }
776
777 pub fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) {
779 let raw_channel: usize = channel.index();
780 self.regs_gp16()
781 .ccmr_output(raw_channel / 2)
782 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
783 }
784
785 pub fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
787 self.regs_gp16()
788 .ccer()
789 .modify(|w| w.set_ccp(channel.index(), polarity.into()));
790 }
791
792 pub fn enable_channel(&self, channel: Channel, enable: bool) {
794 self.regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable));
795 }
796
797 pub fn get_channel_enable_state(&self, channel: Channel) -> bool {
799 self.regs_gp16().ccer().read().cce(channel.index())
800 }
801
802 pub fn set_compare_value(&self, channel: Channel, value: T::Word) {
804 #[cfg(not(stm32l0))]
805 self.regs_gp32_unchecked()
806 .ccr(channel.index())
807 .write_value(value.into());
808 #[cfg(stm32l0)]
809 self.regs_gp16()
810 .ccr(channel.index())
811 .modify(|w| w.set_ccr(unwrap!(value.try_into())));
812 }
813
814 pub fn get_compare_value(&self, channel: Channel) -> T::Word {
816 #[cfg(not(stm32l0))]
817 return unwrap!(self.regs_gp32_unchecked().ccr(channel.index()).read().try_into());
818 #[cfg(stm32l0)]
819 return unwrap!(self.regs_gp32_unchecked().ccr(channel.index()).read().ccr().try_into());
820 }
821
822 pub(crate) fn clamp_compare_value<W: Word>(&mut self, channel: Channel) {
823 self.set_compare_value(
824 channel,
825 unwrap!(
826 self.get_compare_value(channel)
827 .into()
828 .clamp(0, W::max() as u32)
829 .try_into()
830 ),
831 );
832 }
833
834 pub fn setup_ring_buffer<'a, W: Word + Into<T::Word>, D: super::UpDma<T>>(
836 &mut self,
837 dma: Peri<'a, D>,
838 irq: impl crate::interrupt::typelevel::Binding<D::Interrupt, crate::dma::InterruptHandler<D>> + 'a,
839 channel: Channel,
840 dma_buf: &'a mut [W],
841 ) -> WritableRingBuffer<'a, W> {
842 #[allow(clippy::let_unit_value)] let req = dma.request();
844
845 unsafe {
846 use crate::dma::TransferOptions;
847 #[cfg(not(any(bdma, gpdma)))]
848 use crate::dma::{Burst, FifoThreshold};
849
850 let dma_transfer_option = TransferOptions {
851 #[cfg(not(any(bdma, gpdma)))]
852 fifo_threshold: Some(FifoThreshold::Full),
853 #[cfg(not(any(bdma, gpdma)))]
854 mburst: Burst::Incr8,
855 ..Default::default()
856 };
857
858 WritableRingBuffer::new(
859 dma::Channel::new(dma, irq),
860 req,
861 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut W,
862 dma_buf,
863 dma_transfer_option,
864 )
865 }
866 }
867
868 pub fn setup_update_dma<'a, W: Word + Into<T::Word>, D: super::UpDma<T>>(
873 &mut self,
874 dma: Peri<'a, D>,
875 irq: impl crate::interrupt::typelevel::Binding<D::Interrupt, crate::dma::InterruptHandler<D>> + 'a,
876 channel: Channel,
877 duty: &'a [W],
878 ) -> Transfer<'a> {
879 self.setup_update_dma_inner(dma.request(), dma, irq, channel, duty)
880 }
881
882 pub fn setup_channel_update_dma<'a, C: TimerChannel, W: Word + Into<T::Word>, D: super::Dma<T, C>>(
887 &mut self,
888 dma: Peri<'a, D>,
889 irq: impl crate::interrupt::typelevel::Binding<D::Interrupt, crate::dma::InterruptHandler<D>> + 'a,
890 channel: Channel,
891 duty: &'a [W],
892 ) -> Transfer<'a> {
893 self.setup_update_dma_inner(dma.request(), dma, irq, channel, duty)
894 }
895
896 fn setup_update_dma_inner<'a, W: Word + Into<T::Word>, D: dma::ChannelInstance>(
897 &mut self,
898 request: dma::Request,
899 dma: Peri<'a, D>,
900 irq: impl crate::interrupt::typelevel::Binding<D::Interrupt, crate::dma::InterruptHandler<D>> + 'a,
901 channel: Channel,
902 duty: &'a [W],
903 ) -> Transfer<'a> {
904 unsafe {
905 use crate::dma::TransferOptions;
906 #[cfg(not(any(bdma, gpdma)))]
907 use crate::dma::{Burst, FifoThreshold};
908
909 let dma_transfer_option = TransferOptions {
910 #[cfg(not(any(bdma, gpdma)))]
911 fifo_threshold: Some(FifoThreshold::Full),
912 #[cfg(not(any(bdma, gpdma)))]
913 mburst: Burst::Incr8,
914 ..Default::default()
915 };
916
917 let mut dma_channel = dma::Channel::new(dma, irq);
918 dma_channel
919 .write(
920 request,
921 duty,
922 self.regs_gp16().ccr(channel.index()).as_ptr() as *mut W,
923 dma_transfer_option,
924 )
925 .unchecked_extend_lifetime()
926 }
927 }
928
929 pub fn setup_update_dma_burst<'a, W: Word + Into<T::Word>, D: super::UpDma<T>>(
959 &mut self,
960 dma: Peri<'a, D>,
961 irq: impl crate::interrupt::typelevel::Binding<D::Interrupt, crate::dma::InterruptHandler<D>> + 'a,
962 starting_channel: Channel,
963 ending_channel: Channel,
964 duty: &'a [W],
965 ) -> Transfer<'a> {
966 let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32;
967 let start_ch_index = starting_channel.index();
968 let end_ch_index = ending_channel.index();
969
970 assert!(start_ch_index <= end_ch_index);
971
972 let ccrx_addr = self.regs_gp16().ccr(start_ch_index).as_ptr() as u32;
973 self.regs_gp16()
974 .dcr()
975 .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8));
976 self.regs_gp16()
977 .dcr()
978 .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8));
979
980 #[allow(clippy::let_unit_value)] let req = dma.request();
982
983 unsafe {
984 use crate::dma::TransferOptions;
985 #[cfg(not(any(bdma, gpdma)))]
986 use crate::dma::{Burst, FifoThreshold};
987
988 let dma_transfer_option = TransferOptions {
989 #[cfg(not(any(bdma, gpdma)))]
990 fifo_threshold: Some(FifoThreshold::Full),
991 #[cfg(not(any(bdma, gpdma)))]
992 mburst: Burst::Incr4,
993 ..Default::default()
994 };
995
996 let mut dma_channel = dma::Channel::new(dma, irq);
997 dma_channel
998 .write(
999 req,
1000 duty,
1001 self.regs_gp16().dmar().as_ptr() as *mut W,
1002 dma_transfer_option,
1003 )
1004 .unchecked_extend_lifetime()
1005 }
1006 }
1007
1008 pub fn get_capture_value(&self, channel: Channel) -> T::Word {
1010 self.get_compare_value(channel)
1011 }
1012
1013 pub fn set_output_compare_preload(&self, channel: Channel, preload: bool) {
1015 let channel_index = channel.index();
1016 self.regs_gp16()
1017 .ccmr_output(channel_index / 2)
1018 .modify(|w| w.set_ocpe(channel_index % 2, preload));
1019 }
1020
1021 pub fn get_cc_dma_selection(&self) -> vals::Ccds {
1023 self.regs_gp16().cr2().read().ccds()
1024 }
1025
1026 pub fn set_cc_dma_selection(&self, ccds: vals::Ccds) {
1028 self.regs_gp16().cr2().modify(|w| w.set_ccds(ccds))
1029 }
1030
1031 pub fn get_cc_dma_enable_state(&self, channel: Channel) -> bool {
1033 self.regs_gp16().dier().read().ccde(channel.index())
1034 }
1035
1036 pub fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) {
1038 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
1039 }
1040
1041 pub fn set_master_mode(&self, mms: MasterMode) {
1043 self.regs_gp16().cr2().modify(|w| w.set_mms(mms));
1044 }
1045
1046 pub fn set_slave_mode(&self, sms: SlaveMode) {
1048 self.regs_gp16().smcr().modify(|r| r.set_sms(sms));
1049 }
1050
1051 pub fn set_trigger_source(&self, ts: TriggerSource) {
1053 self.regs_gp16().smcr().modify(|r| r.set_ts(ts));
1054 }
1055
1056 #[cfg(not(stm32l0))]
1058 pub fn set_etr_in_source(&self, val: u8) {
1059 self.regs_gp16().af1().modify(|w| w.set_etrsel(val));
1060 }
1061
1062 pub fn set_external_trigger_filter(&self, fv: FilterValue) {
1064 self.regs_gp16().smcr().modify(|w| w.set_etf(fv));
1065 }
1066
1067 pub fn set_external_trigger_prescaler(&self, etp: vals::Etps) {
1069 self.regs_gp16().smcr().modify(|w| w.set_etps(etp));
1070 }
1071
1072 pub fn set_external_trigger_polarity(&self, etp: vals::Etp) {
1074 self.regs_gp16().smcr().modify(|w| w.set_etp(etp));
1075 }
1076
1077 pub fn set_external_clock_mode_2_enable_state(&self, val: bool) {
1079 self.regs_gp16().smcr().modify(|w| w.set_ece(val));
1080 }
1081}
1082
1083#[cfg(not(stm32l0))]
1084impl<'d, T: GeneralInstance32bit4Channel> Timer<'d, T> {
1085 pub fn regs_gp32(&self) -> crate::pac::timer::TimGp32 {
1092 unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) }
1093 }
1094}
1095
1096#[cfg(not(stm32l0))]
1097impl<'d, T: AdvancedInstance1Channel> Timer<'d, T> {
1098 pub fn regs_1ch_cmp(&self) -> crate::pac::timer::Tim1chCmp {
1105 unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) }
1106 }
1107
1108 pub fn set_dead_time_clock_division(&self, value: vals::Ckd) {
1110 self.regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value));
1111 }
1112
1113 pub fn set_dead_time_value(&self, value: u8) {
1115 self.regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value));
1116 }
1117
1118 pub fn set_ossi(&self, val: vals::Ossi) {
1120 self.regs_1ch_cmp().bdtr().modify(|w| w.set_ossi(val));
1121 }
1122
1123 pub fn get_ossi(&self) -> vals::Ossi {
1125 self.regs_1ch_cmp().bdtr().read().ossi()
1126 }
1127
1128 pub fn set_ossr(&self, val: vals::Ossr) {
1130 self.regs_1ch_cmp().bdtr().modify(|w| w.set_ossr(val));
1131 }
1132
1133 pub fn get_ossr(&self) -> vals::Ossr {
1135 self.regs_1ch_cmp().bdtr().read().ossr()
1136 }
1137
1138 pub fn set_moe(&self, enable: bool) {
1140 self.regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable));
1141 }
1142
1143 pub fn get_moe(&self) -> bool {
1145 self.regs_1ch_cmp().bdtr().read().moe()
1146 }
1147
1148 pub fn set_break_enable(&self, enable: bool) {
1153 self.regs_1ch_cmp().bdtr().modify(|w| w.set_bke(0, enable));
1154 }
1155
1156 pub fn get_break_enable(&self) -> bool {
1158 self.regs_1ch_cmp().bdtr().read().bke(0)
1159 }
1160
1161 pub fn set_break_polarity(&self, polarity: vals::Bkp) {
1163 self.regs_1ch_cmp().bdtr().modify(|w| w.set_bkp(0, polarity));
1164 }
1165
1166 pub fn get_break_polarity(&self) -> vals::Bkp {
1168 self.regs_1ch_cmp().bdtr().read().bkp(0)
1169 }
1170
1171 pub fn set_break_filter(&self, filter: FilterValue) {
1176 self.regs_1ch_cmp().bdtr().modify(|w| w.set_bkf(0, filter));
1177 }
1178
1179 pub fn get_break_filter(&self) -> FilterValue {
1181 self.regs_1ch_cmp().bdtr().read().bkf(0)
1182 }
1183
1184 pub fn set_automatic_output_enable(&self, enable: bool) {
1190 self.regs_1ch_cmp().bdtr().modify(|w| w.set_aoe(enable));
1191 }
1192
1193 pub fn get_automatic_output_enable(&self) -> bool {
1195 self.regs_1ch_cmp().bdtr().read().aoe()
1196 }
1197
1198 pub fn set_break_comparator_enable(&self, comp_index: usize, enable: bool) {
1206 self.regs_1ch_cmp().af1().modify(|w| w.set_bkcmpe(comp_index, enable));
1207 }
1208
1209 pub fn get_break_comparator_enable(&self, comp_index: usize) -> bool {
1211 self.regs_1ch_cmp().af1().read().bkcmpe(comp_index)
1212 }
1213
1214 pub fn set_break_comparator_polarity(&self, comp_index: usize, polarity: vals::Bkinp) {
1219 self.regs_1ch_cmp().af1().modify(|w| w.set_bkcmpp(comp_index, polarity));
1220 }
1221
1222 pub fn get_break_comparator_polarity(&self, comp_index: usize) -> vals::Bkinp {
1224 self.regs_1ch_cmp().af1().read().bkcmpp(comp_index)
1225 }
1226
1227 pub fn set_break_input_pin_enable(&self, enable: bool) {
1232 self.regs_1ch_cmp().af1().modify(|w| w.set_bkine(enable));
1233 }
1234
1235 pub fn get_break_input_pin_enable(&self) -> bool {
1237 self.regs_1ch_cmp().af1().read().bkine()
1238 }
1239}
1240
1241#[cfg(not(stm32l0))]
1242impl<'d, T: AdvancedInstance2Channel> Timer<'d, T> {
1243 pub fn regs_2ch_cmp(&self) -> crate::pac::timer::Tim2chCmp {
1250 unsafe { crate::pac::timer::Tim2chCmp::from_ptr(T::regs()) }
1251 }
1252}
1253
1254#[cfg(not(stm32l0))]
1255impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> {
1256 pub fn regs_advanced(&self) -> crate::pac::timer::TimAdv {
1258 unsafe { crate::pac::timer::TimAdv::from_ptr(T::regs()) }
1259 }
1260
1261 pub fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
1263 self.regs_advanced()
1264 .ccer()
1265 .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
1266 }
1267
1268 pub fn enable_complementary_channel(&self, channel: Channel, enable: bool) {
1270 self.regs_advanced()
1271 .ccer()
1272 .modify(|w| w.set_ccne(channel.index(), enable));
1273 }
1274
1275 pub fn set_ois(&self, channel: Channel, val: bool) {
1277 self.regs_advanced().cr2().modify(|w| w.set_ois(channel.index(), val));
1278 }
1279 pub fn set_oisn(&self, channel: Channel, val: bool) {
1281 self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val));
1282 }
1283
1284 pub fn set_mms2_selection(&self, mms2: vals::Mms2) {
1286 self.regs_advanced().cr2().modify(|w| w.set_mms2(mms2));
1287 }
1288
1289 pub fn set_repetition_counter(&self, val: u16) {
1291 self.regs_advanced().rcr().modify(|w| w.set_rep(val));
1292 }
1293
1294 pub fn set_break2_enable(&self, enable: bool) {
1299 self.regs_advanced().bdtr().modify(|w| w.set_bke(1, enable));
1300 }
1301
1302 pub fn get_break2_enable(&self) -> bool {
1304 self.regs_advanced().bdtr().read().bke(1)
1305 }
1306
1307 pub fn set_break2_polarity(&self, polarity: vals::Bkp) {
1309 self.regs_advanced().bdtr().modify(|w| w.set_bkp(1, polarity));
1310 }
1311
1312 pub fn get_break2_polarity(&self) -> vals::Bkp {
1314 self.regs_advanced().bdtr().read().bkp(1)
1315 }
1316
1317 pub fn set_break2_filter(&self, filter: FilterValue) {
1319 self.regs_advanced().bdtr().modify(|w| w.set_bkf(1, filter));
1320 }
1321
1322 pub fn get_break2_filter(&self) -> FilterValue {
1324 self.regs_advanced().bdtr().read().bkf(1)
1325 }
1326
1327 pub fn trigger_software_break(&self, n: usize) {
1330 self.regs_advanced().egr().write(|r| r.set_bg(n, true));
1331 }
1332
1333 pub fn set_break2_comparator_enable(&self, comp_index: usize, enable: bool) {
1338 self.regs_advanced().af2().modify(|w| w.set_bk2cmpe(comp_index, enable));
1339 }
1340
1341 pub fn get_break2_comparator_enable(&self, comp_index: usize) -> bool {
1343 self.regs_advanced().af2().read().bk2cmpe(comp_index)
1344 }
1345
1346 pub fn set_break2_comparator_polarity(&self, comp_index: usize, polarity: vals::Bkinp) {
1348 self.regs_advanced()
1349 .af2()
1350 .modify(|w| w.set_bk2cmpp(comp_index, polarity));
1351 }
1352
1353 pub fn get_break2_comparator_polarity(&self, comp_index: usize) -> vals::Bkinp {
1355 self.regs_advanced().af2().read().bk2cmpp(comp_index)
1356 }
1357
1358 pub fn set_break2_input_pin_enable(&self, enable: bool) {
1360 self.regs_advanced().af2().modify(|w| w.set_bk2ine(enable));
1361 }
1362
1363 pub fn get_break2_input_pin_enable(&self) -> bool {
1365 self.regs_advanced().af2().read().bk2ine()
1366 }
1367}
1368
1369#[cfg(test)]
1370mod tests {
1371 use super::*;
1372
1373 const TEST_CASES: &[(u64, usize, bool, bool)] = &[
1375 (0, 16, false, true),
1378 (1, 16, false, true),
1379 (2, 16, false, false), (100, 16, false, false),
1381 (1000, 16, false, false),
1382 (65535, 16, false, false),
1383 (65536, 16, false, false),
1384 (65537, 16, false, false),
1386 (100_000, 16, false, false),
1387 (1_000_000, 16, false, false),
1388 (10_000_000, 16, false, false),
1389 (131070, 16, false, false), (131072, 16, false, false), (196605, 16, false, false), (0, 32, false, true),
1395 (1, 32, false, true),
1396 (2, 32, false, false),
1397 (100_000, 32, false, false),
1398 (1_000_000_000, 32, false, false),
1399 (4_294_967_295, 32, false, false), (4_294_967_296, 32, false, false), (4_294_967_297, 16, true, false), ];
1407
1408 fn actual_clocks(psc: u16, arr: u64) -> u64 {
1409 (psc as u64 + 1) * (arr + 1)
1410 }
1411
1412 #[test]
1413 fn test_calculate_psc_arr() {
1414 for &(period_clocks, max_arr_bits, expect_fail_slower, expect_fail_faster) in TEST_CASES {
1415 let max_arr: u64 = (1 << max_arr_bits) - 1;
1416
1417 for round in [RoundTo::Slower, RoundTo::Faster] {
1418 let expect_fail = match round {
1419 RoundTo::Slower => expect_fail_slower,
1420 RoundTo::Faster => expect_fail_faster,
1421 };
1422
1423 let result = calculate_psc_arr(period_clocks, round, max_arr_bits);
1424
1425 if expect_fail {
1426 assert!(
1427 result.is_err(),
1428 "Expected failure for period_clocks={}, round={:?}, max_arr_bits={}, but got {:?}",
1429 period_clocks,
1430 round,
1431 max_arr_bits,
1432 result
1433 );
1434 continue;
1435 }
1436
1437 let config = result.unwrap_or_else(|_| {
1438 panic!(
1439 "Unexpected failure for period_clocks={}, round={:?}, max_arr_bits={}",
1440 period_clocks, round, max_arr_bits
1441 )
1442 });
1443
1444 let computed_actual = actual_clocks(config.psc, config.arr);
1446 assert_eq!(
1447 config.actual_period_clocks, computed_actual,
1448 "actual_period_clocks mismatch for period_clocks={}, round={:?}",
1449 period_clocks, round
1450 );
1451
1452 assert!(
1454 config.arr >= 1 && config.arr <= max_arr,
1455 "arr {} out of bounds [1, {}] for period_clocks={}, round={:?}",
1456 config.arr,
1457 max_arr,
1458 period_clocks,
1459 round
1460 );
1461
1462 match round {
1464 RoundTo::Slower => {
1465 assert!(
1466 config.actual_period_clocks >= period_clocks,
1467 "Slower: actual {} < requested {} for period_clocks={}, max_arr_bits={}",
1468 config.actual_period_clocks,
1469 period_clocks,
1470 period_clocks,
1471 max_arr_bits
1472 );
1473 }
1474 RoundTo::Faster => {
1475 assert!(
1476 config.actual_period_clocks <= period_clocks,
1477 "Faster: actual {} > requested {} for period_clocks={}, max_arr_bits={}",
1478 config.actual_period_clocks,
1479 period_clocks,
1480 period_clocks,
1481 max_arr_bits
1482 );
1483 }
1484 }
1485
1486 let mutations: [(i32, i64); 8] = [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)];
1491
1492 for (psc_delta, arr_delta) in mutations {
1493 let new_psc = config.psc as i32 + psc_delta;
1494 let new_arr = config.arr as i64 + arr_delta;
1495
1496 if new_psc < 0 || new_psc > u16::MAX as i32 {
1498 continue;
1499 }
1500 if new_arr < 1 || new_arr > max_arr as i64 {
1501 continue;
1502 }
1503
1504 let new_psc = new_psc as u16;
1505 let new_arr = new_arr as u64;
1506 let new_actual = actual_clocks(new_psc, new_arr);
1507
1508 let satisfies_constraint = match round {
1510 RoundTo::Slower => new_actual >= period_clocks,
1511 RoundTo::Faster => new_actual <= period_clocks,
1512 };
1513
1514 if satisfies_constraint {
1515 let our_distance = (config.actual_period_clocks as i64 - period_clocks as i64).abs();
1517 let new_distance = (new_actual as i64 - period_clocks as i64).abs();
1518
1519 assert!(
1520 new_distance >= our_distance,
1521 "Found better solution via mutation for period_clocks={}, round={:?}, max_arr_bits={}: \
1522 original (psc={}, arr={}, actual={}, dist={}) vs \
1523 mutated (psc={}, arr={}, actual={}, dist={})",
1524 period_clocks,
1525 round,
1526 max_arr_bits,
1527 config.psc,
1528 config.arr,
1529 config.actual_period_clocks,
1530 our_distance,
1531 new_psc,
1532 new_arr,
1533 new_actual,
1534 new_distance
1535 );
1536 }
1537 }
1539 }
1540 }
1541 }
1542
1543 #[test]
1544 fn test_div_round() {
1545 assert_eq!(div_round(10, 3, RoundTo::Faster), 3);
1547 assert_eq!(div_round(9, 3, RoundTo::Faster), 3);
1548 assert_eq!(div_round(11, 3, RoundTo::Faster), 3);
1549 assert_eq!(div_round(12, 3, RoundTo::Faster), 4);
1550
1551 assert_eq!(div_round(10, 3, RoundTo::Slower), 4);
1553 assert_eq!(div_round(9, 3, RoundTo::Slower), 3);
1554 assert_eq!(div_round(11, 3, RoundTo::Slower), 4);
1555 assert_eq!(div_round(12, 3, RoundTo::Slower), 4);
1556 }
1557}