Skip to main content

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#[cfg(not(stm32l0))]
13pub use stm32_metapac::timer::vals::{Bkinp as BreakComparatorPolarity, Bkp as BreakInputPolarity};
14// Re-export useful enums
15pub 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/// Input capture mode.
24#[derive(Clone, Copy)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub enum InputCaptureMode {
27    /// Rising edge only.
28    Rising,
29    /// Falling edge only.
30    Falling,
31    /// Both rising or falling edges.
32    BothEdges,
33}
34
35/// Input TI selection.
36#[derive(Clone, Copy)]
37#[cfg_attr(feature = "defmt", derive(defmt::Format))]
38pub enum InputTISelection {
39    /// Normal
40    Normal,
41    /// Alternate
42    Alternate,
43    /// TRC
44    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/// Timer counting mode.
58#[repr(u8)]
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
61pub enum CountingMode {
62    #[default]
63    /// The timer counts up to the reload value and then resets back to 0.
64    EdgeAlignedUp,
65    /// The timer counts down to 0 and then resets back to the reload value.
66    EdgeAlignedDown,
67    /// The timer counts up to the reload value and then counts back to 0.
68    ///
69    /// The output compare interrupt flags of channels configured in output are
70    /// set when the counter is counting down.
71    CenterAlignedDownInterrupts,
72    /// The timer counts up to the reload value and then counts back to 0.
73    ///
74    /// The output compare interrupt flags of channels configured in output are
75    /// set when the counter is counting up.
76    CenterAlignedUpInterrupts,
77    /// The timer counts up to the reload value and then counts back to 0.
78    ///
79    /// The output compare interrupt flags of channels configured in output are
80    /// set when the counter is counting both up or down.
81    CenterAlignedBothInterrupts,
82}
83
84impl CountingMode {
85    /// Return whether this mode is edge-aligned (up or down).
86    pub fn is_edge_aligned(&self) -> bool {
87        matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown)
88    }
89
90    /// Return whether this mode is center-aligned.
91    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/// Output compare mode.
126#[derive(Clone, Copy)]
127#[cfg_attr(feature = "defmt", derive(defmt::Format))]
128pub enum OutputCompareMode {
129    /// The comparison between the output compare register TIMx_CCRx and
130    /// the counter TIMx_CNT has no effect on the outputs.
131    /// (this mode is used to generate a timing base).
132    Frozen,
133    /// Set channel to active level on match. OCxREF signal is forced high when the
134    /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
135    ActiveOnMatch,
136    /// Set channel to inactive level on match. OCxREF signal is forced low when the
137    /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
138    InactiveOnMatch,
139    /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx.
140    Toggle,
141    /// Force inactive level - OCxREF is forced low.
142    ForceInactive,
143    /// Force active level - OCxREF is forced high.
144    ForceActive,
145    /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx
146    /// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as
147    /// TIMx_CNT>TIMx_CCRx else active (OCxREF=1).
148    PwmMode1,
149    /// PWM mode 2 - In upcounting, channel is inactive as long as
150    /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as
151    /// TIMx_CNT>TIMx_CCRx else inactive.
152    PwmMode2,
153
154    #[cfg(timer_v2)]
155    /// In up-counting mode, the channel is active until a trigger
156    /// event is detected (on tim_trgi signal). Then, a comparison is performed as in PWM
157    /// mode 1 and the channels becomes active again at the next update. In down-counting
158    /// mode, the channel is inactive until a trigger event is detected (on tim_trgi signal).
159    /// Then, a comparison is performed as in PWM mode 1 and the channels becomes
160    /// inactive again at the next update.
161    OnePulseMode1,
162
163    #[cfg(timer_v2)]
164    /// In up-counting mode, the channel is inactive until a
165    /// trigger event is detected (on tim_trgi signal). Then, a comparison is performed as in
166    /// PWM mode 2 and the channels becomes inactive again at the next update. In down
167    /// counting mode, the channel is active until a trigger event is detected (on tim_trgi
168    /// signal). Then, a comparison is performed as in PWM mode 1 and the channels
169    /// becomes active again at the next update.
170    OnePulseMode2,
171
172    #[cfg(timer_v2)]
173    /// Combined PWM mode 1 - tim_oc1ref has the same behavior as in PWM mode 1.
174    /// tim_oc1refc is the logical OR between tim_oc1ref and tim_oc2ref.
175    CombinedPwmMode1,
176
177    #[cfg(timer_v2)]
178    /// Combined PWM mode 2 - tim_oc1ref has the same behavior as in PWM mode 2.
179    /// tim_oc1refc is the logical AND between tim_oc1ref and tim_oc2ref.
180    CombinedPwmMode2,
181
182    #[cfg(timer_v2)]
183    /// tim_oc1ref has the same behavior as in PWM mode 1. tim_oc1refc outputs tim_oc1ref
184    /// when the counter is counting up, tim_oc2ref when it is counting down.
185    AsymmetricPwmMode1,
186
187    #[cfg(timer_v2)]
188    /// tim_oc1ref has the same behavior as in PWM mode 2. tim_oc1refc outputs tim_oc1ref
189    /// when the counter is counting up, tim_oc2ref when it is counting down.
190    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/// Timer output pin polarity.
237#[derive(Clone, Copy)]
238#[cfg_attr(feature = "defmt", derive(defmt::Format))]
239pub enum OutputPolarity {
240    /// Active high (higher duty value makes the pin spend more time high).
241    ActiveHigh,
242    /// Active low (higher duty value makes the pin spend more time low).
243    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/// Rounding mode for timer period/frequency configuration.
256///
257/// When configuring a timer, the exact requested period may not be achievable
258/// due to hardware limitations (prescaler and counter are integers). This enum
259/// controls how the driver rounds the configuration.
260#[derive(Debug, Clone, Copy, PartialEq, Eq)]
261#[cfg_attr(feature = "defmt", derive(defmt::Format))]
262pub enum RoundTo {
263    /// Round towards a slower timer (higher period, lower frequency).
264    ///
265    /// The actual period will be >= the requested period.
266    Slower,
267    /// Round towards a faster timer (lower period, higher frequency).
268    ///
269    /// The actual period will be <= the requested period.
270    Faster,
271}
272
273/// Result of PSC/ARR calculation for timer configuration.
274#[derive(Debug, Clone, Copy, PartialEq, Eq)]
275#[cfg_attr(feature = "defmt", derive(defmt::Format))]
276struct PscArrConfig {
277    /// Prescaler value (0-65535). The timer clock is divided by `psc + 1`.
278    psc: u16,
279    /// Auto-reload value. The timer counts from 0 to `arr`, then wraps.
280    arr: u64,
281    /// The actual period in clock cycles that will be achieved: `(psc + 1) * (arr + 1)`.
282    actual_period_clocks: u64,
283}
284
285/// Error returned when the requested timer period is out of range.
286///
287/// This occurs when:
288/// - For `RoundTo::Faster`: The requested period is less than 2 (minimum achievable is 2, since ARR >= 1).
289/// - For `RoundTo::Slower`: The required prescaler exceeds 16 bits.
290#[derive(Debug, Clone, Copy, PartialEq, Eq)]
291#[cfg_attr(feature = "defmt", derive(defmt::Format))]
292pub struct OutOfRangeError;
293
294/// Calculate prescaler (PSC) and auto-reload (ARR) values for a desired timer period.
295///
296/// # Arguments
297/// * `period_clocks` - The desired period in timer clock cycles
298/// * `round` - How to round when exact period is not achievable
299/// * `max_arr_bits` - Maximum bits for ARR register (16 or 32)
300///
301/// # Returns
302/// A [`PscArrConfig`] containing the calculated values, or an [`OutOfRangeError`] if the
303/// requested period cannot be achieved with the given rounding mode.
304///
305/// # Errors
306/// Returns `OutOfRangeError` when:
307/// - `RoundTo::Faster` and `period_clocks < 2`: Cannot achieve period <= 1 (minimum is 2 since ARR >= 1).
308/// - `RoundTo::Slower` and the required prescaler exceeds 16 bits.
309fn 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    // Minimum achievable period is 2 (psc=0, arr=1), since ARR=0 is not valid.
313    const MIN_PERIOD: u64 = 2;
314
315    // For Faster, we need actual_period_clocks <= period_clocks
316    // If period_clocks < MIN_PERIOD, we can't achieve this
317    if round == RoundTo::Faster && period_clocks < MIN_PERIOD {
318        return Err(OutOfRangeError);
319    }
320
321    // We need: period_clocks = (psc + 1) * (arr + 1)
322    // Calculate minimum prescaler needed: psc >= period_clocks / (max_arr + 1) - 1
323    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            // Prescaler would overflow
328            match round {
329                RoundTo::Slower => return Err(OutOfRangeError), // Can't achieve actual >= requested
330                RoundTo::Faster => u16::MAX,                    // Use max psc; we only need actual <= requested
331            }
332        }
333    };
334
335    // Calculate arr for this prescaler
336    let psc_plus_1 = u64::from(psc) + 1;
337
338    // actual_clocks = (psc + 1) * (arr + 1), so arr = actual_clocks / (psc + 1) - 1
339    // We want actual_clocks as close to period_clocks as possible, respecting rounding mode
340    let arr = match round {
341        RoundTo::Faster => {
342            // Round down: actual_clocks <= period_clocks
343            // arr + 1 <= period_clocks / (psc + 1)
344            // arr <= period_clocks / (psc + 1) - 1
345            (period_clocks / psc_plus_1).saturating_sub(1)
346        }
347        RoundTo::Slower => {
348            // Round up: actual_clocks >= period_clocks
349            // arr + 1 >= ceil(period_clocks / (psc + 1))
350            // arr >= ceil(period_clocks / (psc + 1)) - 1
351            period_clocks.div_ceil(psc_plus_1).saturating_sub(1)
352        }
353    };
354
355    // Clamp arr to valid range (min is 1, not 0)
356    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
366/// Helper to round a division according to the rounding mode.
367fn 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
374/// Low-level timer driver.
375pub 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    /// Create a new timer driver.
387    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    /// Get access to the virutal core 16bit timer registers.
399    ///
400    /// Note: This works even if the timer is more capable, because registers
401    /// for the less capable timers are a subset. This allows writing a driver
402    /// for a given set of capabilities, and having it transparently work with
403    /// more capable timers.
404    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    /// Start the timer.
419    pub fn start(&self) {
420        self.regs_core().cr1().modify(|r| r.set_cen(true));
421    }
422
423    /// Generate timer update event from software.
424    ///
425    /// Set URS to avoid generating interrupt or DMA request. This update event is only
426    /// used to load value from pre-load registers. If called when the timer is running,
427    /// it may disrupt the output waveform.
428    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    /// Stop the timer.
435    pub fn stop(&self) {
436        self.regs_core().cr1().modify(|r| r.set_cen(false));
437    }
438
439    /// Reset the counter value to 0
440    pub fn reset(&self) {
441        self.regs_core().cnt().write(|r| r.set_cnt(0));
442    }
443
444    /// get the capability of the timer
445    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    /// Set the timer period in timer clock cycles.
455    ///
456    /// The timer will count for `clocks` clock cycles before wrapping.
457    /// The actual period may differ from the requested value due to hardware
458    /// limitations; the `round` parameter controls how rounding is performed.
459    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        // TODO: we might want to propagate errors to the user instead of panicking.
465        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    /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
477    ///
478    /// This means that in the default edge-aligned mode,
479    /// the timer counter will wrap around at the same frequency as is being set.
480    /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved
481    /// because it needs to count up and down.
482    ///
483    /// The actual frequency may differ from the requested value due to hardware
484    /// limitations; the `round` parameter controls how rounding is performed.
485    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    /// Set the timer period in milliseconds.
494    ///
495    /// The actual period may differ from the requested value due to hardware
496    /// limitations; the `round` parameter controls how rounding is performed.
497    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    /// Set the timer period in microseconds.
504    ///
505    /// The actual period may differ from the requested value due to hardware
506    /// limitations; the `round` parameter controls how rounding is performed.
507    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    /// Set the timer period in seconds.
514    ///
515    /// The actual period may differ from the requested value due to hardware
516    /// limitations; the `round` parameter controls how rounding is performed.
517    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    /// Set the timer period using an `embassy_time::Duration`.
524    ///
525    /// The actual period may differ from the requested value due to hardware
526    /// limitations; the `round` parameter controls how rounding is performed.
527    #[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    /// Set tick frequency.
535    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        // Generate an Update Request
547        regs.egr().write(|r| r.set_ug(true));
548    }
549
550    /// Clear update interrupt.
551    ///
552    /// Returns whether the update interrupt flag was set.
553    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    /// Enable/disable the update interrupt.
567    pub fn enable_update_interrupt(&self, enable: bool) {
568        self.regs_core().dier().modify(|r| r.set_uie(enable));
569    }
570
571    /// Enable/disable autoreload preload.
572    pub fn set_autoreload_preload(&self, enable: bool) {
573        self.regs_core().cr1().modify(|r| r.set_arpe(enable));
574    }
575
576    /// Get the timer frequency.
577    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    /// Get the clock frequency of the timer (before prescaler is applied).
591    pub fn get_clock_frequency(&self) -> Hertz {
592        T::frequency()
593    }
594}
595
596impl<'d, T: BasicNoCr2Instance> Timer<'d, T> {
597    /// Get access to the Baisc 16bit timer registers.
598    ///
599    /// Note: This works even if the timer is more capable, because registers
600    /// for the less capable timers are a subset. This allows writing a driver
601    /// for a given set of capabilities, and having it transparently work with
602    /// more capable timers.
603    pub fn regs_basic_no_cr2(&self) -> crate::pac::timer::TimBasicNoCr2 {
604        unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(T::regs()) }
605    }
606
607    /// Enable/disable the update dma.
608    pub fn enable_update_dma(&self, enable: bool) {
609        self.regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable));
610    }
611
612    /// Get the update dma enable/disable state.
613    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    /// Get access to the Baisc 16bit timer registers.
620    ///
621    /// Note: This works even if the timer is more capable, because registers
622    /// for the less capable timers are a subset. This allows writing a driver
623    /// for a given set of capabilities, and having it transparently work with
624    /// more capable timers.
625    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    /// Get access to the general purpose 1 channel 16bit timer registers.
632    ///
633    /// Note: This works even if the timer is more capable, because registers
634    /// for the less capable timers are a subset. This allows writing a driver
635    /// for a given set of capabilities, and having it transparently work with
636    /// more capable timers.
637    pub fn regs_1ch(&self) -> crate::pac::timer::Tim1ch {
638        unsafe { crate::pac::timer::Tim1ch::from_ptr(T::regs()) }
639    }
640
641    /// Set clock divider.
642    pub fn set_clock_division(&self, ckd: vals::Ckd) {
643        self.regs_1ch().cr1().modify(|r| r.set_ckd(ckd));
644    }
645
646    /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
647    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    /// Set the max compare value.
655    ///
656    /// An update event is generated to load the new value. The update event is
657    /// generated such that it will not cause an interrupt or DMA request.
658    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    /// Get access to the general purpose 2 channel 16bit timer registers.
675    ///
676    /// Note: This works even if the timer is more capable, because registers
677    /// for the less capable timers are a subset. This allows writing a driver
678    /// for a given set of capabilities, and having it transparently work with
679    /// more capable timers.
680    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    /// Get access to the general purpose 16bit timer registers.
687    ///
688    /// Note: This works even if the timer is more capable, because registers
689    /// for the less capable timers are a subset. This allows writing a driver
690    /// for a given set of capabilities, and having it transparently work with
691    /// more capable timers.
692    pub fn regs_gp16(&self) -> crate::pac::timer::TimGp16 {
693        unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) }
694    }
695
696    /// Enable timer outputs.
697    pub fn enable_outputs(&self) {
698        self.tim.enable_outputs()
699    }
700
701    /// Set counting mode.
702    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        // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running.
707        // Changing direction is discouraged while the timer is running.
708        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    /// Get counting mode.
715    pub fn get_counting_mode(&self) -> CountingMode {
716        let cr1 = self.regs_gp16().cr1().read();
717        (cr1.cms(), cr1.dir()).into()
718    }
719
720    /// Set input capture filter.
721    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    /// Clear input interrupt.
729    pub fn clear_input_interrupt(&self, channel: Channel) {
730        self.regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false));
731    }
732
733    /// Get input interrupt.
734    pub fn get_input_interrupt(&self, channel: Channel) -> bool {
735        self.regs_gp16().sr().read().ccif(channel.index())
736    }
737
738    /// Enable input interrupt.
739    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    /// Set input capture prescaler.
744    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    /// Set input TI selection.
752    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    /// Set input capture mode.
760    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    /// Set output compare mode.
778    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    /// Set output polarity.
786    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    /// Enable/disable a channel.
793    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    /// Get enable/disable state of a channel
798    pub fn get_channel_enable_state(&self, channel: Channel) -> bool {
799        self.regs_gp16().ccer().read().cce(channel.index())
800    }
801
802    /// Set compare value for a channel.
803    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    /// Get compare value for a channel.
815    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    /// Setup a ring buffer for the channel
835    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)] // eg. stm32f334
843        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    /// Generate a sequence of PWM waveform
869    ///
870    /// Note:
871    /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
872    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    /// Generate a sequence of PWM waveform
883    ///
884    /// Note:
885    /// The DMA channel provided does not need to correspond to the requested channel.
886    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    /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
930    ///
931    /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers
932    /// in sequence on each update event (UEV). The data is written via the DMAR register using the
933    /// DMA base address (DBA) and burst length (DBL) configured in the DCR register.
934    ///
935    /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row
936    /// represents a single update event and each column corresponds to a specific timer channel (starting
937    /// from `starting_channel` up to and including `ending_channel`).
938    ///
939    /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
940    ///
941    /// ```rust,ignore
942    /// let dma_buf: [u16; 16] = [
943    ///     ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
944    ///     ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
945    ///     ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
946    ///     ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
947    /// ];
948    /// ```
949    ///
950    /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
951    /// updating the duty cycles of all selected channels simultaneously.
952    ///
953    /// Note:
954    /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
955    /// Also be aware that embassy timers use one of timers internally. It is possible to
956    /// switch this timer by using `time-driver-timX` feature.
957    ///
958    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)] // eg. stm32f334
981        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    /// Get capture value for a channel.
1009    pub fn get_capture_value(&self, channel: Channel) -> T::Word {
1010        self.get_compare_value(channel)
1011    }
1012
1013    /// Set output compare preload.
1014    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    /// Get capture compare DMA selection
1022    pub fn get_cc_dma_selection(&self) -> vals::Ccds {
1023        self.regs_gp16().cr2().read().ccds()
1024    }
1025
1026    /// Set capture compare DMA selection
1027    pub fn set_cc_dma_selection(&self, ccds: vals::Ccds) {
1028        self.regs_gp16().cr2().modify(|w| w.set_ccds(ccds))
1029    }
1030
1031    /// Get capture compare DMA enable state
1032    pub fn get_cc_dma_enable_state(&self, channel: Channel) -> bool {
1033        self.regs_gp16().dier().read().ccde(channel.index())
1034    }
1035
1036    /// Set capture compare DMA enable state
1037    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    /// Set Timer Master Mode
1042    pub fn set_master_mode(&self, mms: MasterMode) {
1043        self.regs_gp16().cr2().modify(|w| w.set_mms(mms));
1044    }
1045
1046    /// Set Timer Slave Mode
1047    pub fn set_slave_mode(&self, sms: SlaveMode) {
1048        self.regs_gp16().smcr().modify(|r| r.set_sms(sms));
1049    }
1050
1051    /// Set Timer Trigger Source
1052    pub fn set_trigger_source(&self, ts: TriggerSource) {
1053        self.regs_gp16().smcr().modify(|r| r.set_ts(ts));
1054    }
1055
1056    /// Set Timer Etr_in Source
1057    #[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    /// Set Timer External Trigger Filter
1063    pub fn set_external_trigger_filter(&self, fv: FilterValue) {
1064        self.regs_gp16().smcr().modify(|w| w.set_etf(fv));
1065    }
1066
1067    /// Set Timer External Trigger prescaler
1068    pub fn set_external_trigger_prescaler(&self, etp: vals::Etps) {
1069        self.regs_gp16().smcr().modify(|w| w.set_etps(etp));
1070    }
1071
1072    /// Set Timer External Trigger Polarity
1073    pub fn set_external_trigger_polarity(&self, etp: vals::Etp) {
1074        self.regs_gp16().smcr().modify(|w| w.set_etp(etp));
1075    }
1076
1077    /// Set Timer External Clock Mode 2 Enable state
1078    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    /// Get access to the general purpose 32bit timer registers.
1086    ///
1087    /// Note: This works even if the timer is more capable, because registers
1088    /// for the less capable timers are a subset. This allows writing a driver
1089    /// for a given set of capabilities, and having it transparently work with
1090    /// more capable timers.
1091    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    /// Get access to the general purpose 1 channel with one complementary 16bit timer registers.
1099    ///
1100    /// Note: This works even if the timer is more capable, because registers
1101    /// for the less capable timers are a subset. This allows writing a driver
1102    /// for a given set of capabilities, and having it transparently work with
1103    /// more capable timers.
1104    pub fn regs_1ch_cmp(&self) -> crate::pac::timer::Tim1chCmp {
1105        unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) }
1106    }
1107
1108    /// Set clock divider for the dead time.
1109    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    /// Set dead time, as a fraction of the max duty value.
1114    pub fn set_dead_time_value(&self, value: u8) {
1115        self.regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value));
1116    }
1117
1118    /// Set state of OSSI-bit in BDTR register
1119    pub fn set_ossi(&self, val: vals::Ossi) {
1120        self.regs_1ch_cmp().bdtr().modify(|w| w.set_ossi(val));
1121    }
1122
1123    /// Get state of OSSI-bit in BDTR register
1124    pub fn get_ossi(&self) -> vals::Ossi {
1125        self.regs_1ch_cmp().bdtr().read().ossi()
1126    }
1127
1128    /// Set state of OSSR-bit in BDTR register
1129    pub fn set_ossr(&self, val: vals::Ossr) {
1130        self.regs_1ch_cmp().bdtr().modify(|w| w.set_ossr(val));
1131    }
1132
1133    /// Get state of OSSR-bit in BDTR register
1134    pub fn get_ossr(&self) -> vals::Ossr {
1135        self.regs_1ch_cmp().bdtr().read().ossr()
1136    }
1137
1138    /// Set state of MOE-bit in BDTR register to en-/disable output
1139    pub fn set_moe(&self, enable: bool) {
1140        self.regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable));
1141    }
1142
1143    /// Get state of MOE-bit in BDTR register
1144    pub fn get_moe(&self) -> bool {
1145        self.regs_1ch_cmp().bdtr().read().moe()
1146    }
1147
1148    /// Enable/disable break input 1.
1149    ///
1150    /// When enabled, an active level on the break input puts the timer outputs
1151    /// into a safe state (driven by OSSI/OSSR and OIS/OISN settings).
1152    pub fn set_break_enable(&self, enable: bool) {
1153        self.regs_1ch_cmp().bdtr().modify(|w| w.set_bke(0, enable));
1154    }
1155
1156    /// Get break input 1 enable state.
1157    pub fn get_break_enable(&self) -> bool {
1158        self.regs_1ch_cmp().bdtr().read().bke(0)
1159    }
1160
1161    /// Set break input 1 polarity.
1162    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    /// Get break input 1 polarity.
1167    pub fn get_break_polarity(&self) -> vals::Bkp {
1168        self.regs_1ch_cmp().bdtr().read().bkp(0)
1169    }
1170
1171    /// Set break input 1 digital filter.
1172    ///
1173    /// The filter rejects glitches shorter than the configured number of clock
1174    /// cycles, preventing false break events from noise.
1175    pub fn set_break_filter(&self, filter: FilterValue) {
1176        self.regs_1ch_cmp().bdtr().modify(|w| w.set_bkf(0, filter));
1177    }
1178
1179    /// Get break input 1 digital filter.
1180    pub fn get_break_filter(&self) -> FilterValue {
1181        self.regs_1ch_cmp().bdtr().read().bkf(0)
1182    }
1183
1184    /// Enable/disable automatic output enable (AOE).
1185    ///
1186    /// When AOE is set, the MOE bit is automatically set at the next update
1187    /// event after a break event (allowing automatic recovery). When cleared,
1188    /// MOE can only be set by software.
1189    pub fn set_automatic_output_enable(&self, enable: bool) {
1190        self.regs_1ch_cmp().bdtr().modify(|w| w.set_aoe(enable));
1191    }
1192
1193    /// Get automatic output enable (AOE) state.
1194    pub fn get_automatic_output_enable(&self) -> bool {
1195        self.regs_1ch_cmp().bdtr().read().aoe()
1196    }
1197
1198    /// Enable/disable comparator output as break input 1 source.
1199    ///
1200    /// When enabled, the output of comparator `comp_index` (0-based: 0=COMP1, 1=COMP2, etc.)
1201    /// is internally OR'd into the break input 1 signal. Multiple comparators can be
1202    /// enabled simultaneously. This is configured via the TIMx_AF1 register BKCMPE bits.
1203    ///
1204    /// No GPIO pin is needed — the routing is fully internal.
1205    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    /// Get comparator break input 1 enable state.
1210    pub fn get_break_comparator_enable(&self, comp_index: usize) -> bool {
1211        self.regs_1ch_cmp().af1().read().bkcmpe(comp_index)
1212    }
1213
1214    /// Set comparator break input 1 polarity.
1215    ///
1216    /// Controls the polarity of comparator `comp_index` (0-based, max 3) output
1217    /// when used as a break source. Only COMP1-COMP4 have individual polarity control.
1218    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    /// Get comparator break input 1 polarity.
1223    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    /// Enable/disable the external BKIN pin as break input 1 source.
1228    ///
1229    /// This controls whether the TIMx_BKIN GPIO pin contributes to the break input.
1230    /// When using only comparator-based break sources, this can be disabled.
1231    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    /// Get external BKIN pin enable state.
1236    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    /// Get access to the general purpose 2 channel with one complementary 16bit timer registers.
1244    ///
1245    /// Note: This works even if the timer is more capable, because registers
1246    /// for the less capable timers are a subset. This allows writing a driver
1247    /// for a given set of capabilities, and having it transparently work with
1248    /// more capable timers.
1249    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    /// Get access to the advanced timer registers.
1257    pub fn regs_advanced(&self) -> crate::pac::timer::TimAdv {
1258        unsafe { crate::pac::timer::TimAdv::from_ptr(T::regs()) }
1259    }
1260
1261    /// Set complementary output polarity.
1262    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    /// Enable/disable a complementary channel.
1269    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    /// Set Output Idle State
1276    pub fn set_ois(&self, channel: Channel, val: bool) {
1277        self.regs_advanced().cr2().modify(|w| w.set_ois(channel.index(), val));
1278    }
1279    /// Set Output Idle State Complementary Channel
1280    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    /// Set master mode selection 2
1285    pub fn set_mms2_selection(&self, mms2: vals::Mms2) {
1286        self.regs_advanced().cr2().modify(|w| w.set_mms2(mms2));
1287    }
1288
1289    /// Set repetition counter
1290    pub fn set_repetition_counter(&self, val: u16) {
1291        self.regs_advanced().rcr().modify(|w| w.set_rep(val));
1292    }
1293
1294    /// Enable/disable break input 2.
1295    ///
1296    /// When enabled, an active level on break input 2 puts the timer outputs
1297    /// into a safe state. Only available on advanced 4-channel timers.
1298    pub fn set_break2_enable(&self, enable: bool) {
1299        self.regs_advanced().bdtr().modify(|w| w.set_bke(1, enable));
1300    }
1301
1302    /// Get break input 2 enable state.
1303    pub fn get_break2_enable(&self) -> bool {
1304        self.regs_advanced().bdtr().read().bke(1)
1305    }
1306
1307    /// Set break input 2 polarity.
1308    pub fn set_break2_polarity(&self, polarity: vals::Bkp) {
1309        self.regs_advanced().bdtr().modify(|w| w.set_bkp(1, polarity));
1310    }
1311
1312    /// Get break input 2 polarity.
1313    pub fn get_break2_polarity(&self) -> vals::Bkp {
1314        self.regs_advanced().bdtr().read().bkp(1)
1315    }
1316
1317    /// Set break input 2 digital filter.
1318    pub fn set_break2_filter(&self, filter: FilterValue) {
1319        self.regs_advanced().bdtr().modify(|w| w.set_bkf(1, filter));
1320    }
1321
1322    /// Get break input 2 digital filter.
1323    pub fn get_break2_filter(&self) -> FilterValue {
1324        self.regs_advanced().bdtr().read().bkf(1)
1325    }
1326
1327    /// Trigger software break 1 or 2
1328    /// Setting this bit generates a break event. This bit is automatically cleared by the hardware.
1329    pub fn trigger_software_break(&self, n: usize) {
1330        self.regs_advanced().egr().write(|r| r.set_bg(n, true));
1331    }
1332
1333    /// Enable/disable comparator output as break input 2 source.
1334    ///
1335    /// When enabled, the output of comparator `comp_index` (0-based: 0=COMP1, 1=COMP2, etc.)
1336    /// is internally OR'd into the break input 2 signal. Configured via TIMx_AF2 register.
1337    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    /// Get comparator break input 2 enable state.
1342    pub fn get_break2_comparator_enable(&self, comp_index: usize) -> bool {
1343        self.regs_advanced().af2().read().bk2cmpe(comp_index)
1344    }
1345
1346    /// Set comparator break input 2 polarity.
1347    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    /// Get comparator break input 2 polarity.
1354    pub fn get_break2_comparator_polarity(&self, comp_index: usize) -> vals::Bkinp {
1355        self.regs_advanced().af2().read().bk2cmpp(comp_index)
1356    }
1357
1358    /// Enable/disable the external BK2IN pin as break input 2 source.
1359    pub fn set_break2_input_pin_enable(&self, enable: bool) {
1360        self.regs_advanced().af2().modify(|w| w.set_bk2ine(enable));
1361    }
1362
1363    /// Get external BK2IN pin enable state.
1364    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    /// Test cases: (period_clocks, max_arr_bits, expect_fail_slower, expect_fail_faster)
1374    const TEST_CASES: &[(u64, usize, bool, bool)] = &[
1375        // Small periods (no prescaler needed for 16-bit)
1376        // period=0,1 fail for Faster because min achievable is 2 (arr=1)
1377        (0, 16, false, true),
1378        (1, 16, false, true),
1379        (2, 16, false, false), // Minimum achievable period
1380        (100, 16, false, false),
1381        (1000, 16, false, false),
1382        (65535, 16, false, false),
1383        (65536, 16, false, false),
1384        // Periods requiring prescaler for 16-bit
1385        (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        // Edge cases around boundaries
1390        (131070, 16, false, false), // 2 * 65535
1391        (131072, 16, false, false), // 2 * 65536
1392        (196605, 16, false, false), // 3 * 65535
1393        // 32-bit timer cases
1394        (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), // u32::MAX
1400        (4_294_967_296, 32, false, false), // u32::MAX + 1
1401        // Very large periods that would overflow 16-bit prescaler for Slower
1402        // max_arr for 16-bit is 65535, so max period with psc=65535 is 65536*65536 = 4_294_967_296
1403        // Anything larger than that fails for Slower (need actual >= requested, impossible)
1404        // For Faster, it still works (need actual <= requested, can always use max period)
1405        (4_294_967_297, 16, true, false), // Just over 16-bit max, fails Slower only
1406    ];
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                // Verify actual_period_clocks matches (psc + 1) * (arr + 1)
1445                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                // Verify arr is within bounds (min is 1)
1453                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                // Check rounding constraint
1463                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                // Test mutations: verify the solution is not obviously suboptimal.
1487                // Try all combinations of psc +/- 1 and arr +/- 1
1488                // This doesn't guarantee optimality. but it's enough to catch dumb off-by-one bugs.
1489                // Guaranteeing optimality would require searching all divisors of `period_clocks` which is obviously too expensive.
1490                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                    // Skip invalid mutations
1497                    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                    // Check if mutation satisfies the rounding constraint
1509                    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                        // If it satisfies the constraint, it should not be better (closer) than our solution
1516                        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                    // If mutation doesn't satisfy constraint, that's fine - our solution is better
1538                }
1539            }
1540        }
1541    }
1542
1543    #[test]
1544    fn test_div_round() {
1545        // Faster (round down)
1546        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        // Slower (round up)
1552        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}