Skip to main content

stm32_hrtim/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3
4#[cfg(not(any(
5    feature = "stm32f334",
6    feature = "stm32h742",
7    feature = "stm32h743",
8    //feature = "stm32h745",
9    feature = "stm32h747cm7",
10    feature = "stm32h750",
11    feature = "stm32h753",
12    //feature = "stm32h755",
13    //feature = "stm32h757",
14    feature = "stm32g474",
15    feature = "stm32g484",
16)))]
17compile_error!(
18    "This crate requires one of the following features enabled:
19    stm32f334
20
21    stm32h742
22    stm32h743
23    #stm32h745
24    stm32h747cm7
25    stm32h750
26    stm32h753
27    #stm32h755
28    #stm32h757
29
30    stm32g474
31    stm32g484"
32);
33
34pub mod adc_trigger;
35pub mod capture;
36pub mod compare_register;
37pub mod control;
38pub mod deadtime;
39pub mod event;
40pub mod ext;
41pub mod external_event;
42pub mod fault;
43pub mod output;
44pub mod timer;
45pub mod timer_eev_cfg;
46
47#[cfg(feature = "stm32f334")]
48pub use stm32f3::stm32f3x4 as pac;
49
50#[cfg(feature = "stm32h742")]
51pub use stm32h7::stm32h742 as pac;
52
53#[cfg(feature = "stm32h743")]
54pub use stm32h7::stm32h743 as pac;
55
56//#[cfg(feature = "stm32h745")]
57//pub use stm32h7::stm32h745 as pac;
58
59#[cfg(feature = "stm32h747cm7")]
60pub use stm32h7::stm32h747cm7 as pac;
61
62#[cfg(feature = "stm32h750")]
63pub use stm32h7::stm32h750 as pac;
64
65#[cfg(feature = "stm32h753")]
66pub use stm32h7::stm32h753 as pac;
67
68//#[cfg(feature = "stm32h755")]
69//pub use stm32h7::stm32h755 as pac;
70
71//#[cfg(feature = "stm32h757")]
72//pub use stm32h7::stm32h757 as pac;
73
74#[cfg(feature = "stm32g474")]
75pub use stm32g4::stm32g474 as pac;
76
77#[cfg(feature = "stm32g484")]
78pub use stm32g4::stm32g484 as pac;
79
80use core::marker::PhantomData;
81use core::mem::MaybeUninit;
82
83use crate::compare_register::{HrCr1, HrCr2, HrCr3, HrCr4};
84use crate::fault::{FaultAction, FaultSource};
85use crate::output::{HrOut1, HrOut2, Output1Pin, Output2Pin};
86use crate::timer::HrTim;
87#[cfg(feature = "hrtim_v2")]
88use pac::HRTIM_TIMF;
89use pac::{HRTIM_COMMON, HRTIM_MASTER, HRTIM_TIMA, HRTIM_TIMB, HRTIM_TIMC, HRTIM_TIMD, HRTIM_TIME};
90
91use capture::{HrCaptCh1, HrCaptCh2};
92
93use self::control::HrPwmControl;
94
95use self::deadtime::DeadtimeConfig;
96use self::timer_eev_cfg::EevCfgs;
97
98use timer::{Instance, InstanceX};
99/// Internal enum that keeps track of the count settings before PWM is finalized
100enum CountSettings {
101    //Frequency(Hertz),
102    Period(u16),
103}
104
105#[cfg_attr(feature = "defmt", derive(defmt::Format))]
106#[derive(Copy, Clone, PartialEq, Debug)]
107pub enum HrTimerMode {
108    SingleShotNonRetriggerable,
109    SingleShotRetriggerable,
110    Continuous,
111}
112
113#[cfg_attr(feature = "defmt", derive(defmt::Format))]
114#[derive(Copy, Clone, PartialEq, Debug)]
115pub enum HrCountingDirection {
116    /// Asymmetrical up counting mode
117    ///
118    ///
119    ///                   *                  *
120    ///  Counting up   *  |               *  |
121    ///             *                  *
122    ///          *        |         *        |
123    ///       *                  *
124    ///    *              |   *              |
125    /// *                  *
126    /// --------------------------------------
127    ///
128    /// ```txt
129    /// |         *-------*                  *------
130    ///           |       |                  |
131    /// |         |       |                  |
132    ///           |       |                  |
133    /// ----------*       *------------------*
134    /// ```
135    ///
136    /// This is the most common mode with least amount of quirks
137    Up,
138
139    #[cfg(feature = "hrtim_v2")]
140    /// Symmetrical up-down counting mode
141    ///
142    ///
143    /// ```txt
144    /// Period-->                  *                      Counting     *
145    ///           Counting up   *  |  *     Counting        Up      *  |
146    ///                      *           *     down              *
147    ///                   *        |        *                 *        |
148    ///                *                       *           *
149    ///             *              |              *     *              |
150    /// 0     -->*                                   *
151    /// ---------------------------------------------------------------------------
152    ///          |         *---------------*         |         *---------------*
153    ///                    |       |       |                   |       |       |
154    ///          |         |               |         |         |               |
155    ///                    |       |       |                   |       |       |
156    ///          ----------*               *-------------------*               *---
157    /// ```
158    ///
159    /// NOTE: This is incompatible with
160    /// * Auto-delay
161    /// * Balanced Idle
162    /// * Triggered-half mode
163    ///
164    /// There is also differences in (including but not limited to) the following areas:
165    /// * Counter roll over event
166    /// * The events registered with `enable_set_event` will work as normal wen counting up, however when counting down, they will work as rst events.
167    /// * The events registered with `enable_rst_event` will work as normal wen counting up, however when counting down, they will work as set events.
168    UpDown,
169}
170
171#[cfg_attr(feature = "defmt", derive(defmt::Format))]
172#[derive(Copy, Clone, PartialEq, Debug)]
173pub enum InterleavedMode {
174    Disabled,
175
176    /// Dual interleaved or Half mode
177    ///
178    /// Automatically force
179    /// * Cr1 to PERIOD / 2 (not visible through `get_duty`).
180    ///
181    /// Automatically updates when changing period
182    ///
183    /// NOTE: Affects Cr1
184    Dual,
185
186    #[cfg(feature = "hrtim_v2")]
187    /// Triple interleaved mode
188    ///
189    /// Automatically force
190    /// * Cr1 to 1 * PERIOD / 3 and
191    /// * Cr2 to 2 * PERIOD / 3
192    ///
193    /// (not visible through `get_duty`). Automatically updates when changing period.
194    ///
195    /// NOTE: Must not be used simultaneously with other modes
196    /// using CMP2 (dual channel dac trigger and triggered-half modes).
197    Triple,
198
199    #[cfg(feature = "hrtim_v2")]
200    /// Quad interleaved mode
201    ///
202    /// Automatically force
203    /// * Cr1 to 1 * PERIOD / 4,
204    /// * Cr2 to 2 * PERIOD / 4 and
205    /// * Cr3 to 3 * PERIOD / 4
206    ///
207    /// (not visible through `get_duty`). Automatically updates when changing period.
208    ///
209    /// NOTE: Must not be used simultaneously with other modes
210    /// using CMP2 (dual channel dac trigger and triggered-half modes).
211    Quad,
212}
213
214pub trait HrPwmAdvExt: Sized {
215    type PreloadSource;
216
217    fn pwm_advanced<P1, P2>(
218        self,
219        pin1: P1,
220        pin2: P2,
221    ) -> HrPwmBuilder<Self, PsclDefault, Self::PreloadSource, P1, P2>
222    where
223        P1: Output1Pin<Self>,
224        P2: Output2Pin<Self>;
225}
226
227#[cfg_attr(feature = "defmt", derive(defmt::Format))]
228#[derive(Debug, Clone, Copy, PartialEq)]
229pub enum Polarity {
230    ActiveHigh,
231    ActiveLow,
232}
233
234pub trait DacStepTrigger {
235    const IS_CR2: bool;
236    const IS_OUT1_RST: bool;
237    const DCDS_BIT: Option<bool>;
238}
239
240pub trait DacResetTrigger {
241    const IS_TIM_RST: bool;
242    const IS_OUT1_SET: bool;
243    const DCDR_BIT: Option<bool>;
244}
245
246#[cfg_attr(feature = "defmt", derive(defmt::Format))]
247#[derive(Debug, Clone, Copy, PartialEq)]
248pub struct NoDacTrigger;
249
250impl DacStepTrigger for NoDacTrigger {
251    const IS_CR2: bool = false;
252    const IS_OUT1_RST: bool = false;
253
254    const DCDS_BIT: Option<bool> = None;
255}
256
257impl DacResetTrigger for NoDacTrigger {
258    const IS_TIM_RST: bool = false;
259    const IS_OUT1_SET: bool = false;
260
261    const DCDR_BIT: Option<bool> = None;
262}
263
264/// The trigger is generated on counter reset or roll-over event
265#[cfg_attr(feature = "defmt", derive(defmt::Format))]
266#[derive(Debug, Clone, Copy, PartialEq)]
267pub struct DacResetOnCounterReset;
268impl DacResetTrigger for DacResetOnCounterReset {
269    const IS_TIM_RST: bool = true;
270    const IS_OUT1_SET: bool = false;
271    const DCDR_BIT: Option<bool> = Some(false);
272}
273
274/// The trigger is generated on output 1 set event
275#[cfg_attr(feature = "defmt", derive(defmt::Format))]
276#[derive(Debug, Clone, Copy, PartialEq)]
277pub struct DacResetOnOut1Set;
278impl DacResetTrigger for DacResetOnOut1Set {
279    const IS_TIM_RST: bool = false;
280    const IS_OUT1_SET: bool = true;
281    const DCDR_BIT: Option<bool> = Some(true);
282}
283
284/// The trigger is generated on compare 2 event repeatedly
285///
286/// The compare 2 has a particular operating mode when using `OnCmp2`. The active
287/// comparison value is automatically updated as soon as a compare match
288/// has occurred, so that the trigger can be repeated periodically with a period
289/// equal to the CMP2 value.
290///
291/// NOTE:
292/// The dual channel DAC trigger with `OnCmp2` must not be
293/// used simultaneously with modes using CMP2 (triple / quad interleaved
294/// and triggered-half modes).
295///
296/// Example:
297/// Let’s consider a counter period = 8192. Dividing 8192 by 6 yields 1365.33.
298/// – Round down value: 1365: 7 triggers are generated, the 6th and 7th being very
299/// close (respectively for counter = 8190 and 8192)
300/// – Round up value:1366: 6 triggers are generated. The 6th trigger on dac_step_trg
301/// (for counter = 8192) is aborted by the counter roll-over from 8192 to 0.
302#[cfg_attr(feature = "defmt", derive(defmt::Format))]
303#[derive(Debug, Clone, Copy, PartialEq)]
304pub struct DacStepOnCmp2;
305impl DacStepTrigger for DacStepOnCmp2 {
306    const IS_CR2: bool = true;
307    const IS_OUT1_RST: bool = false;
308    const DCDS_BIT: Option<bool> = Some(false);
309}
310
311/// The trigger is generated on output 1 rst event
312#[cfg_attr(feature = "defmt", derive(defmt::Format))]
313#[derive(Debug, Clone, Copy, PartialEq)]
314pub struct DacStepOnOut1Rst;
315impl DacStepTrigger for DacStepOnOut1Rst {
316    const IS_CR2: bool = false;
317    const IS_OUT1_RST: bool = true;
318    const DCDS_BIT: Option<bool> = Some(true);
319}
320
321/// HrPwmBuilder is used to configure advanced HrTim PWM features
322pub struct HrPwmBuilder<
323    TIM,
324    PSCL,
325    PS,
326    P1,
327    P2,
328    DacRst: DacResetTrigger = NoDacTrigger,
329    DacStp: DacStepTrigger = NoDacTrigger,
330> {
331    _tim: PhantomData<TIM>,
332    _prescaler: PhantomData<PSCL>,
333    pin1: P1,
334    pin2: P2,
335    timer_mode: HrTimerMode,
336    counting_direction: HrCountingDirection,
337    //base_freq: HertzU64,
338    count: CountSettings,
339    preload_source: Option<PS>,
340    fault_enable_bits: u8,
341    fault1_bits: u8,
342    fault2_bits: u8,
343    enable_push_pull: bool,
344    interleaved_mode: InterleavedMode, // Also includes half mode
345    repetition_counter: u8,
346    deadtime: Option<DeadtimeConfig>,
347    enable_repetition_interrupt: bool,
348    eev_cfg: EevCfgs<TIM>,
349    // TODO Add DAC triggers for stm32f334 (RM0364 21.3.19) and stm32h7 if applicable
350    dac_rst_trigger: PhantomData<DacRst>,
351    dac_stp_trigger: PhantomData<DacStp>,
352    out1_polarity: Polarity,
353    out2_polarity: Polarity,
354}
355
356pub struct HrParts<
357    TIM,
358    PSCL,
359    DacRst: DacResetTrigger = NoDacTrigger,
360    DacStp: DacStepTrigger = NoDacTrigger,
361> {
362    pub timer: HrTim<TIM, PSCL, HrCaptCh1<TIM, PSCL>, HrCaptCh2<TIM, PSCL>, DacRst>,
363
364    pub cr1: HrCr1<TIM, PSCL>,
365    pub cr2: HrCr2<TIM, PSCL, DacStp>,
366    pub cr3: HrCr3<TIM, PSCL>,
367    pub cr4: HrCr4<TIM, PSCL>,
368
369    pub out1: HrOut1<TIM, PSCL, DacRst, DacStp>,
370    pub out2: HrOut2<TIM, PSCL, DacRst, DacStp>,
371    pub dma_channel: timer::DmaChannel<TIM>,
372}
373
374#[cfg_attr(feature = "defmt", derive(defmt::Format))]
375#[derive(Debug, Clone, Copy)]
376pub enum PreloadSource {
377    /// Preloaded registers are updated on counter roll over or counter reset
378    OnCounterReset,
379
380    /// Preloaded registers are updated by master timer update
381    OnMasterTimerUpdate,
382
383    /// Prealoaded registers are updated when the counter rolls over and the repetition counter is 0
384    OnRepetitionUpdate,
385}
386
387#[cfg_attr(feature = "defmt", derive(defmt::Format))]
388#[derive(Debug, Clone, Copy)]
389pub enum MasterPreloadSource {
390    /// Preloaded registers are updated when the master counter rolls over and the master repetition counter is 0
391    OnMasterRepetitionUpdate,
392}
393
394macro_rules! hrtim_finalize_body {
395    ($this:expr, $PreloadSource:ident, $TIMX:ident, [$($out:ident)*]) => {{
396        let tim = unsafe { &*$TIMX::ptr() };
397        let (period, prescaler_bits) = match $this.count {
398            CountSettings::Period(period) => (period as u32, PSCL::BITS as u16),
399        };
400
401        let (half, _intlvd) = match $this.interleaved_mode {
402            InterleavedMode::Disabled => (false, 0b00),
403            InterleavedMode::Dual => (true, 0b00),
404            #[cfg(feature = "hrtim_v2")]
405            InterleavedMode::Triple => (false, 0b01),
406            #[cfg(feature = "hrtim_v2")]
407            InterleavedMode::Quad => (false, 0b10),
408        };
409
410        // Write prescaler and any special modes
411        tim.cr().modify(|_r, w| unsafe {
412            w
413                // Enable Continuous mode
414                .cont().bit($this.timer_mode == HrTimerMode::Continuous)
415                .retrig().bit($this.timer_mode == HrTimerMode::SingleShotRetriggerable)
416
417                // TODO: add support for more modes
418
419                // half/double interleaved mode
420                .half().bit(half)
421
422                // Set prescaler
423                .ckpsc().bits(prescaler_bits as u8)
424        });
425
426        #[cfg(feature = "hrtim_v2")]
427        tim.cr().modify(|_r, w| unsafe {
428            // Interleaved mode
429            w.intlvd().bits(_intlvd)
430        });
431
432        $(
433            // Only available for timers with outputs(not HRTIM_MASTER)
434            #[allow(unused)]
435            let $out = ();
436
437            // TODO Add DAC triggers for stm32f334 (RM0364 21.3.19) and stm32h7 if applicable
438            #[cfg(feature = "hrtim_v2")]
439            tim.cr2().modify(|_r, w| {
440                // Set counting direction
441                w.udm().bit($this.counting_direction == HrCountingDirection::UpDown);
442                assert!(DacRst::DCDR_BIT.is_some() == DacStp::DCDS_BIT.is_some());
443
444                if let (Some(rst), Some(stp)) = (DacRst::DCDR_BIT, DacStp::DCDS_BIT) {
445                    w
446                        .dcde().set_bit()
447                        .dcds().bit(stp as u8 != 0)
448                        .dcdr().bit(rst as u8 != 0);
449                }
450
451                w
452            });
453
454            tim.cr().modify(|_r, w|
455                // Push-Pull mode
456                w.pshpll().bit($this.enable_push_pull)
457            );
458        )*
459
460        // Write period
461        tim.perr().write(|w| unsafe { w.per().bits(period as u16) });
462
463        // Enable fault sources and lock configuration
464        $(unsafe {
465            // Only available for timers with outputs(not HRTIM_MASTER)
466            #[allow(unused)]
467            let $out = ();
468
469            // Enable fault sources
470            let fault_enable_bits = $this.fault_enable_bits as u32;
471            tim.fltr().write(|w| w
472                .flt1en().bit(fault_enable_bits & (1 << 0) != 0)
473                .flt2en().bit(fault_enable_bits & (1 << 1) != 0)
474                .flt3en().bit(fault_enable_bits & (1 << 2) != 0)
475                .flt4en().bit(fault_enable_bits & (1 << 3) != 0)
476                .flt5en().bit(fault_enable_bits & (1 << 4) != 0)
477            );
478            #[cfg(feature = "hrtim_v2")]
479            tim.fltr().modify(|_, w| w.flt6en().bit(fault_enable_bits & (1 << 5) != 0));
480
481            // ... and lock configuration
482            tim.fltr().modify(|_r, w| w.fltlck().set_bit());
483
484            tim.outr().modify(|_r, w| w
485                // Set actions on fault for both outputs
486                .fault1().bits($this.fault1_bits)
487                .fault2().bits($this.fault2_bits)
488
489                // Set output polarity for both outputs
490                .pol1().bit(matches!($this.out1_polarity, Polarity::ActiveLow))
491                .pol2().bit(matches!($this.out2_polarity, Polarity::ActiveLow))
492            );
493            if let Some(deadtime) = $this.deadtime {
494                let DeadtimeConfig {
495                    prescaler,
496                    deadtime_rising_value,
497                    deadtime_rising_sign,
498                    deadtime_falling_value,
499                    deadtime_falling_sign,
500                } = deadtime;
501
502                // SAFETY: DeadtimeConfig makes sure rising and falling values are valid
503                // and DeadtimePrescaler has its own guarantee
504                tim.dtr().modify(|_r, w| w
505                    .dtprsc().bits(prescaler as u8)
506                    .dtr().bits(deadtime_rising_value)
507                    .sdtr().bit(deadtime_rising_sign)
508                    .dtf().bits(deadtime_falling_value)
509                    .sdtf().bit(deadtime_falling_sign)
510
511                    // Lock configuration
512                    .dtflk().set_bit()
513                    .dtfslk().set_bit()
514                    .dtrlk().set_bit()
515                    .dtrslk().set_bit()
516                );
517                tim.outr().modify(|_r, w| w.dten().set_bit());
518            }
519
520            // External event configs
521            let eev_cfg = $this.eev_cfg.clone();
522            tim.eefr1().write(|w| w
523                .ee1ltch().bit(eev_cfg.eev1.latch_bit).ee1fltr().bits(eev_cfg.eev1.filter_bits)
524                .ee2ltch().bit(eev_cfg.eev2.latch_bit).ee2fltr().bits(eev_cfg.eev2.filter_bits)
525                .ee3ltch().bit(eev_cfg.eev3.latch_bit).ee3fltr().bits(eev_cfg.eev3.filter_bits)
526                .ee4ltch().bit(eev_cfg.eev4.latch_bit).ee4fltr().bits(eev_cfg.eev4.filter_bits)
527                .ee5ltch().bit(eev_cfg.eev5.latch_bit).ee5fltr().bits(eev_cfg.eev5.filter_bits)
528            );
529            tim.eefr2().write(|w| w
530                .ee6ltch().bit(eev_cfg.eev6.latch_bit).ee6fltr().bits(eev_cfg.eev6.filter_bits)
531                .ee7ltch().bit(eev_cfg.eev7.latch_bit).ee7fltr().bits(eev_cfg.eev7.filter_bits)
532                .ee8ltch().bit(eev_cfg.eev8.latch_bit).ee8fltr().bits(eev_cfg.eev8.filter_bits)
533                .ee9ltch().bit(eev_cfg.eev9.latch_bit).ee9fltr().bits(eev_cfg.eev9.filter_bits)
534                .ee10ltch().bit(eev_cfg.eev10.latch_bit).ee10fltr().bits(eev_cfg.eev10.filter_bits)
535            );
536            #[cfg(feature = "hrtim_v2")]
537            tim.eefr3().write(|w| w
538                .eevace().bit(eev_cfg.event_counter_enable_bit)
539                // External Event A Counter Reset"]
540                //.eevacres().bit()
541                .eevarstm().bit(eev_cfg.event_counter_reset_mode_bit)
542                .eevasel().bits(eev_cfg.event_counter_source_bits)
543                .eevacnt().bits(eev_cfg.event_counter_threshold_bits)
544            );
545        })*
546
547
548        hrtim_finalize_body!($PreloadSource, $this, tim);
549
550        // Set repetition counter
551        unsafe { tim.repr().write(|w| w.rep().bits($this.repetition_counter)); }
552
553        // Enable interrupts
554        tim.dier().modify(|_r, w| w.repie().bit($this.enable_repetition_interrupt));
555
556        // Start timer
557        //let master = unsafe { &*HRTIM_MASTER::ptr() };
558        //master.mcr.modify(|_r, w| { w.$tXcen().set_bit() });
559    }};
560
561    (PreloadSource, $this:expr, $tim:expr) => {{
562        match $this.preload_source {
563            Some(PreloadSource::OnCounterReset) => {
564                $tim.cr().modify(|_r, w| w
565                    .trstu().set_bit()
566                    .preen().set_bit()
567                );
568            },
569            Some(PreloadSource::OnMasterTimerUpdate) => {
570                $tim.cr().modify(|_r, w| w
571                    .mstu().set_bit()
572                    .preen().set_bit()
573                );
574            }
575            Some(PreloadSource::OnRepetitionUpdate) => {
576                $tim.cr().modify(|_r, w| w
577                    .trepu().set_bit()
578                    .preen().set_bit()
579                );
580            }
581            None => ()
582        }
583    }};
584
585    (MasterPreloadSource, $this:expr, $tim:expr) => {{
586        match $this.preload_source {
587            Some(MasterPreloadSource::OnMasterRepetitionUpdate) => {
588                $tim.cr().modify(|_r, w| w
589                    .mrepu().set_bit()
590                    .preen().set_bit()
591                );
592            }
593            None => ()
594        }
595    }};
596}
597
598impl<
599        TIM: Instance + HrPwmAdvExt,
600        PSCL,
601        P1,
602        P2,
603        DacRst: DacResetTrigger,
604        DacStp: DacStepTrigger,
605    > HrPwmBuilder<TIM, PSCL, TIM::PreloadSource, P1, P2, DacRst, DacStp>
606where
607    PSCL: HrtimPrescaler,
608    P1: Output1Pin<TIM>,
609    P2: Output2Pin<TIM>,
610{
611    /// Set the prescaler; PWM count runs at base_frequency/(prescaler+1)
612    pub fn prescaler<P>(
613        self,
614        _prescaler: P,
615    ) -> HrPwmBuilder<TIM, P, TIM::PreloadSource, P1, P2, DacRst, DacStp>
616    where
617        P: HrtimPrescaler,
618    {
619        let HrPwmBuilder {
620            _tim,
621            _prescaler: _,
622            pin1,
623            pin2,
624            timer_mode,
625            fault_enable_bits,
626            fault1_bits,
627            fault2_bits,
628            enable_push_pull,
629            interleaved_mode,
630            counting_direction,
631            //base_freq,
632            count,
633            preload_source,
634            repetition_counter,
635            deadtime,
636            enable_repetition_interrupt,
637            eev_cfg,
638            dac_rst_trigger,
639            dac_stp_trigger,
640            out1_polarity,
641            out2_polarity,
642        } = self;
643
644        let period = match count {
645            CountSettings::Period(period) => period,
646        };
647
648        let count = CountSettings::Period(period);
649
650        HrPwmBuilder {
651            _tim,
652            _prescaler: PhantomData,
653            pin1,
654            pin2,
655            timer_mode,
656            fault_enable_bits,
657            fault1_bits,
658            fault2_bits,
659            enable_push_pull,
660            interleaved_mode,
661            counting_direction,
662            //base_freq,
663            count,
664            preload_source,
665            repetition_counter,
666            deadtime,
667            enable_repetition_interrupt,
668            eev_cfg,
669            dac_rst_trigger,
670            dac_stp_trigger,
671            out1_polarity,
672            out2_polarity,
673        }
674    }
675
676    pub fn timer_mode(mut self, timer_mode: HrTimerMode) -> Self {
677        self.timer_mode = timer_mode;
678        self
679    }
680
681    // TODO: Allow setting multiple?
682    pub fn preload(mut self, preload_source: TIM::PreloadSource) -> Self {
683        self.preload_source = Some(preload_source);
684        self
685    }
686
687    /// Set the period; PWM count runs from 0 to period, repeating every (period+1) counts
688    pub fn period(mut self, period: u16) -> Self {
689        self.count = CountSettings::Period(period);
690        self
691    }
692
693    /// Set repetition counter, useful to reduce interrupts generated
694    /// from timer by a factor (repetition_counter + 1)
695    pub fn repetition_counter(mut self, repetition_counter: u8) -> Self {
696        self.repetition_counter = repetition_counter;
697        self
698    }
699
700    pub fn enable_repetition_interrupt(mut self) -> Self {
701        self.enable_repetition_interrupt = true;
702        self
703    }
704
705    pub fn eev_cfg(mut self, eev_cfg: EevCfgs<TIM>) -> Self {
706        self.eev_cfg = eev_cfg;
707        self
708    }
709
710    #[cfg(feature = "hrtim_v2")]
711    /// Enable dac trigger with provided settings
712    ///
713    /// ### Edge-aligned slope compensation
714    ///
715    /// The DAC’s sawtooth starts on PWM period beginning and
716    /// multiple triggers are generated during the timer period
717    /// with a trigger interval equal to the CMP2 value.
718    ///
719    /// NOTE:
720    /// Must not be used simultaneously with modes using
721    /// CMP2 (triple / quad interleaved and triggered-half modes).
722    /// reset_trigger: DacRstTrg::OnCounterReset,
723    /// step_trigger: DacStpTrg::OnCmp2,
724    ///
725    /// ### Center-aligned slope compensation
726    ///
727    /// The DAC’s sawtooth starts on the output 1 set event and
728    /// multiple triggers are generated during the timer period
729    /// with a trigger interval equal to the CMP2 value.
730    ///
731    /// NOTE:
732    /// Must not be used simultaneously with modes using
733    /// CMP2 (triple / quad interleaved and triggered-half modes).
734    ///
735    /// NOTE:
736    /// In centered-pattern mode, it is mandatory to have an even
737    /// number of triggers per switching period, so as to avoid
738    /// unevenly spaced triggers around counter’s peak value.
739    ///
740    /// reset_trigger: DacRstTrg::OnOut1Set,
741    /// step_trigger: DacStpTrg::OnCmp2,
742    ///
743    /// ### Hysteretic controller - Reset on CounterReset
744    ///
745    /// 2 triggers are generated per PWM period.
746    /// In edge-aligned mode the triggers are generated on counter
747    /// reset or rollover and the output is reset
748    ///
749    /// reset_trigger: [`DacResetOnCounterReset,
750    /// step_trigger: [`DacStepOnOut1Rst,
751    ///
752    /// ### Hysteretic controller - Reset on Out1Set
753    ///
754    /// 2 triggers are generated per PWM period.
755    /// In center-aligned mode the triggers are generated when the output is
756    /// set and when it is reset.
757    ///
758    /// reset_trigger: [`DacResetOnOut1Set`],
759    /// step_trigger: [`DacStepOnOut1Rst`],
760    pub fn dac_trigger_cfg<R: DacResetTrigger, S: DacStepTrigger>(
761        self,
762        _rst: R,
763        _step: S,
764    ) -> HrPwmBuilder<TIM, PSCL, TIM::PreloadSource, P1, P2, R, S> {
765        let HrPwmBuilder {
766            _tim,
767            _prescaler: _,
768            pin1,
769            pin2,
770            timer_mode,
771            fault_enable_bits,
772            fault1_bits,
773            fault2_bits,
774            enable_push_pull,
775            interleaved_mode,
776            counting_direction,
777            //base_freq,
778            count,
779            preload_source,
780            repetition_counter,
781            deadtime,
782            enable_repetition_interrupt,
783            eev_cfg,
784            dac_rst_trigger: _,
785            dac_stp_trigger: _,
786            out1_polarity,
787            out2_polarity,
788        } = self;
789
790        HrPwmBuilder {
791            _tim,
792            _prescaler: PhantomData,
793            pin1,
794            pin2,
795            timer_mode,
796            fault_enable_bits,
797            fault1_bits,
798            fault2_bits,
799            enable_push_pull,
800            interleaved_mode,
801            counting_direction,
802            //base_freq,
803            count,
804            preload_source,
805            repetition_counter,
806            deadtime,
807            enable_repetition_interrupt,
808            eev_cfg,
809            dac_rst_trigger: PhantomData,
810            dac_stp_trigger: PhantomData,
811            out1_polarity,
812            out2_polarity,
813        }
814    }
815}
816
817impl HrPwmAdvExt for HRTIM_MASTER {
818    type PreloadSource = MasterPreloadSource;
819
820    fn pwm_advanced<P1, P2>(
821        self,
822        pin1: P1,
823        pin2: P2,
824    ) -> HrPwmBuilder<Self, PsclDefault, Self::PreloadSource, P1, P2>
825    where
826        P1: Output1Pin<Self>,
827        P2: Output2Pin<Self>,
828    {
829        // TODO: That 32x factor... Is that included below, or should we
830        // do that? Also that will likely risk overflowing u32 since
831        // 170MHz * 32 = 5.44GHz > u32::MAX.Hz()
832        //let clk = HertzU64::from(HRTIM_COMMON::get_timer_frequency(&rcc.clocks)) * 32;
833
834        HrPwmBuilder {
835            _tim: PhantomData,
836            _prescaler: PhantomData,
837            pin1,
838            pin2,
839            timer_mode: HrTimerMode::Continuous,
840            fault_enable_bits: 0b000000,
841            fault1_bits: 0b00,
842            fault2_bits: 0b00,
843            counting_direction: HrCountingDirection::Up,
844            //base_freq: clk,
845            count: CountSettings::Period(u16::MAX),
846            preload_source: None,
847            enable_push_pull: false,
848            interleaved_mode: InterleavedMode::Disabled,
849            repetition_counter: 0,
850            deadtime: None,
851            enable_repetition_interrupt: false,
852            eev_cfg: EevCfgs::default(),
853            dac_rst_trigger: PhantomData,
854            dac_stp_trigger: PhantomData,
855            out1_polarity: Polarity::ActiveHigh,
856            out2_polarity: Polarity::ActiveHigh,
857        }
858    }
859}
860
861impl<TIM: InstanceX> HrPwmAdvExt for TIM {
862    type PreloadSource = PreloadSource;
863
864    fn pwm_advanced<P1, P2>(
865        self,
866        pin1: P1,
867        pin2: P2,
868    ) -> HrPwmBuilder<Self, PsclDefault, Self::PreloadSource, P1, P2>
869    where
870        P1: Output1Pin<TIM>,
871        P2: Output2Pin<TIM>,
872    {
873        // TODO: That 32x factor... Is that included below, or should we
874        // do that? Also that will likely risk overflowing u32 since
875        // 170MHz * 32 = 5.44GHz > u32::MAX.Hz()
876        //let clk = HertzU64::from(HRTIM_COMMON::get_timer_frequency(&rcc.clocks)) * 32;
877
878        HrPwmBuilder {
879            _tim: PhantomData,
880            _prescaler: PhantomData,
881            pin1,
882            pin2,
883            timer_mode: HrTimerMode::Continuous,
884            fault_enable_bits: 0b000000,
885            fault1_bits: 0b00,
886            fault2_bits: 0b00,
887            counting_direction: HrCountingDirection::Up,
888            //base_freq: clk,
889            count: CountSettings::Period(u16::MAX),
890            preload_source: None,
891            enable_push_pull: false,
892            interleaved_mode: InterleavedMode::Disabled,
893            repetition_counter: 0,
894            deadtime: None,
895            enable_repetition_interrupt: false,
896            eev_cfg: EevCfgs::default(),
897            dac_rst_trigger: PhantomData,
898            dac_stp_trigger: PhantomData,
899            out1_polarity: Polarity::ActiveHigh,
900            out2_polarity: Polarity::ActiveHigh,
901        }
902    }
903}
904
905impl<TIM: InstanceX, PSCL, P1, P2> HrPwmBuilder<TIM, PSCL, PreloadSource, P1, P2>
906where
907    PSCL: HrtimPrescaler,
908    P1: Output1Pin<TIM>,
909    P2: Output2Pin<TIM>,
910{
911    pub fn with_fault_source<FS>(mut self, _fault_source: FS) -> Self
912    where
913        FS: FaultSource,
914    {
915        self.fault_enable_bits |= FS::ENABLE_BITS;
916
917        self
918    }
919
920    pub fn fault_action1(mut self, fault_action1: FaultAction) -> Self {
921        self.fault1_bits = fault_action1 as _;
922
923        self
924    }
925
926    pub fn fault_action2(mut self, fault_action2: FaultAction) -> Self {
927        self.fault2_bits = fault_action2 as _;
928
929        self
930    }
931
932    pub fn out1_polarity(mut self, polarity: Polarity) -> Self {
933        self.out1_polarity = polarity;
934
935        self
936    }
937
938    pub fn out2_polarity(mut self, polarity: Polarity) -> Self {
939        self.out2_polarity = polarity;
940
941        self
942    }
943
944    /// Enable or disable Push-Pull mode
945    ///
946    /// Enabling Push-Pull mode will make output 1 and 2
947    /// alternate every period with one being
948    /// inactive and the other getting to output its wave form
949    /// as normal
950    ///
951    ///         ----           .                ----
952    ///out1    |    |          .               |    |
953    ///        |    |          .               |    |
954    /// --------    ----------------------------    --------------------
955    ///        .                ------         .                ------
956    ///out2    .               |      |        .               |      |
957    ///        .               |      |        .               |      |
958    /// ------------------------    ----------------------------      --
959    ///
960    /// NOTE: setting this will overide any 'Swap Mode' set
961    pub fn push_pull_mode(mut self, enable: bool) -> Self {
962        // TODO: add check for incompatible modes
963        self.enable_push_pull = enable;
964
965        self
966    }
967
968    /// Set counting direction
969    ///
970    /// See [`HrCountingDirection`]
971    pub fn counting_direction(mut self, counting_direction: HrCountingDirection) -> Self {
972        self.counting_direction = counting_direction;
973
974        self
975    }
976
977    /// Set interleaved or half modes
978    ///
979    /// NOTE: Check [`InterleavedMode`] for more info about special cases
980    pub fn interleaved_mode(mut self, mode: InterleavedMode) -> Self {
981        self.interleaved_mode = mode;
982
983        self
984    }
985
986    pub fn deadtime(mut self, deadtime: DeadtimeConfig) -> Self {
987        self.deadtime = Some(deadtime);
988
989        self
990    }
991
992    //pub fn swap_mode(mut self, enable: bool) -> Self
993}
994
995// Implement PWM configuration for timer
996macro_rules! hrtim_hal {
997    ($($TIMX:ident: $($out:ident)*,)+) => {
998        $(
999            impl<PSCL, P1, P2, DacRst, DacStp>
1000                HrPwmBuilder<$TIMX, PSCL, PreloadSource, P1, P2, DacRst, DacStp>
1001            where
1002                DacRst: DacResetTrigger,
1003                DacStp: DacStepTrigger,
1004                PSCL: HrtimPrescaler,
1005                P1: Output1Pin<$TIMX>,
1006                P2: Output2Pin<$TIMX>,
1007            {
1008                // For HAL writers:
1009                // Make sure to connect gpios after calling this function and then it should be safe to
1010                // conjure an instance of HrParts<$TIMX, PSCL, PINS::Out<PSCL>>
1011                pub fn _init(self, _control: &mut HrPwmControl) -> (P1, P2) {
1012                    hrtim_finalize_body!(self, PreloadSource, $TIMX, [$($out)*]);
1013                    (self.pin1, self.pin2)
1014                }
1015            }
1016        )+
1017    };
1018}
1019
1020hrtim_hal! {
1021    HRTIM_TIMA: out,
1022    HRTIM_TIMB: out,
1023    HRTIM_TIMC: out,
1024    HRTIM_TIMD: out,
1025    HRTIM_TIME: out,
1026}
1027
1028#[cfg(feature = "hrtim_v2")]
1029hrtim_hal! {
1030    HRTIM_TIMF: out,
1031}
1032
1033impl<PSCL, P1, P2, DacRst, DacStp>
1034    HrPwmBuilder<HRTIM_MASTER, PSCL, MasterPreloadSource, P1, P2, DacRst, DacStp>
1035where
1036    DacRst: DacResetTrigger,
1037    DacStp: DacStepTrigger,
1038    PSCL: HrtimPrescaler,
1039    P1: Output1Pin<HRTIM_MASTER>,
1040    P2: Output1Pin<HRTIM_MASTER>,
1041{
1042    pub fn finalize(self, _control: &mut HrPwmControl) -> HrParts<HRTIM_MASTER, PSCL> {
1043        hrtim_finalize_body!(self, MasterPreloadSource, HRTIM_MASTER, []);
1044
1045        unsafe { MaybeUninit::uninit().assume_init() }
1046    }
1047}
1048
1049/// # Safety
1050/// Only implement for valid prescalers with correct values
1051pub unsafe trait HrtimPrescaler: Default {
1052    const BITS: u8;
1053    const VALUE: u8;
1054
1055    /// Minimum allowed value for compare registers used with the timer with this prescaler
1056    ///
1057    /// NOTE: That for CR1 and CR3, 0 is also allowed
1058    const MIN_CR: u16;
1059
1060    /// Maximum allowed value for compare registers used with the timer with this prescaler
1061    const MAX_CR: u16;
1062}
1063
1064macro_rules! impl_pscl {
1065    ($($t:ident => $b:literal, $v:literal, $min:literal, $max:literal)+) => {$(
1066        #[cfg_attr(feature = "defmt", derive(defmt::Format))]
1067        #[derive(Copy, Clone, Default)]
1068        pub struct $t;
1069        unsafe impl HrtimPrescaler for $t {
1070            const BITS: u8 = $b;
1071            const VALUE: u8 = $v;
1072            const MIN_CR: u16 = $min;
1073            const MAX_CR: u16 = $max;
1074        }
1075    )+};
1076}
1077
1078#[cfg(any(feature = "stm32f3", feature = "stm32g4"))]
1079pub type PsclDefault = Pscl128;
1080
1081#[cfg(feature = "stm32h7")]
1082pub type PsclDefault = Pscl4;
1083
1084#[cfg(any(feature = "stm32f3", feature = "stm32g4"))]
1085impl_pscl! {
1086    Pscl1   => 0b000,   1, 0x0060, 0xFFDF
1087    Pscl2   => 0b001,   2, 0x0030, 0xFFEF
1088    Pscl4   => 0b010,   4, 0x0018, 0xFFF7
1089    Pscl8   => 0b011,   8, 0x000C, 0xFFFB
1090    Pscl16  => 0b100,  16, 0x0006, 0xFFFD
1091    Pscl32  => 0b101,  32, 0x0003, 0xFFFD
1092    Pscl64  => 0b110,  64, 0x0003, 0xFFFD
1093    Pscl128 => 0b111, 128, 0x0003, 0xFFFD
1094}
1095
1096#[cfg(feature = "stm32h7")]
1097impl_pscl! {
1098    Pscl1 => 0b101, 1, 0x0003, 0xFFFD
1099    Pscl2 => 0b110, 2, 0x0003, 0xFFFD
1100    Pscl4 => 0b111, 4, 0x0003, 0xFFFD
1101}
1102
1103/*
1104/// HrTim timer
1105struct TimerHrTim<PSC>(PhantomData<PSC>);
1106
1107impl<PSC: HrtimPrescaler> pwm::TimerType for TimerHrTim<PSC> {
1108    // Period calculator for 16-bit hrtimers
1109    //
1110    // NOTE: This function will panic if the calculated period can not fit into 16 bits
1111    fn calculate_frequency(base_freq: HertzU64, freq: Hertz, alignment: Alignment) -> (u32, u16) {
1112        let ideal_period = pwm::Timer32Bit::calculate_frequency(base_freq, freq, alignment).0 + 1;
1113
1114        let prescale = u32::from(PSC::VALUE);
1115
1116        // Round to the nearest period
1117        let period = (ideal_period + (prescale >> 1)) / prescale - 1;
1118
1119        // It IS possible to fail this assert
1120        assert!(period <= 0xFFFF);
1121
1122        (period, PSC::BITS.into())
1123    }
1124}
1125*/