stm32_hrtim/
lib.rs

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