embassy_stm32/hrtim/
traits.rs

1use embassy_hal_internal::PeripheralType;
2
3use crate::rcc::RccPeripheral;
4use crate::time::Hertz;
5
6#[repr(u8)]
7#[derive(Clone, Copy)]
8pub(crate) enum Prescaler {
9    Div1 = 1,
10    Div2 = 2,
11    Div4 = 4,
12    Div8 = 8,
13    Div16 = 16,
14    Div32 = 32,
15    Div64 = 64,
16    Div128 = 128,
17}
18
19impl From<Prescaler> for u8 {
20    fn from(val: Prescaler) -> Self {
21        match val {
22            Prescaler::Div1 => 0b000,
23            Prescaler::Div2 => 0b001,
24            Prescaler::Div4 => 0b010,
25            Prescaler::Div8 => 0b011,
26            Prescaler::Div16 => 0b100,
27            Prescaler::Div32 => 0b101,
28            Prescaler::Div64 => 0b110,
29            Prescaler::Div128 => 0b111,
30        }
31    }
32}
33
34impl From<u8> for Prescaler {
35    fn from(val: u8) -> Self {
36        match val {
37            0b000 => Prescaler::Div1,
38            0b001 => Prescaler::Div2,
39            0b010 => Prescaler::Div4,
40            0b011 => Prescaler::Div8,
41            0b100 => Prescaler::Div16,
42            0b101 => Prescaler::Div32,
43            0b110 => Prescaler::Div64,
44            0b111 => Prescaler::Div128,
45            _ => unreachable!(),
46        }
47    }
48}
49
50impl Prescaler {
51    pub fn compute_min_high_res(val: u32) -> Self {
52        *[
53            Prescaler::Div1,
54            Prescaler::Div2,
55            Prescaler::Div4,
56            Prescaler::Div8,
57            Prescaler::Div16,
58            Prescaler::Div32,
59            Prescaler::Div64,
60            Prescaler::Div128,
61        ]
62        .iter()
63        .skip_while(|psc| **psc as u32 <= val)
64        .next()
65        .unwrap()
66    }
67
68    pub fn compute_min_low_res(val: u32) -> Self {
69        *[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128]
70            .iter()
71            .skip_while(|psc| **psc as u32 <= val)
72            .next()
73            .unwrap()
74    }
75}
76
77pub(crate) trait SealedInstance: RccPeripheral {
78    fn regs() -> crate::pac::hrtim::Hrtim;
79
80    #[allow(unused)]
81    fn set_master_frequency(frequency: Hertz) {
82        let f = frequency.0;
83
84        // TODO: wire up HRTIM to the RCC mux infra.
85        //#[cfg(stm32f334)]
86        //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
87        //#[cfg(not(stm32f334))]
88        let timer_f = Self::frequency().0;
89
90        let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
91        let psc = if Self::regs().isr().read().dllrdy() {
92            Prescaler::compute_min_high_res(psc_min)
93        } else {
94            Prescaler::compute_min_low_res(psc_min)
95        };
96
97        let timer_f = 32 * (timer_f / psc as u32);
98        let per: u16 = (timer_f / f) as u16;
99
100        let regs = Self::regs();
101
102        regs.mcr().modify(|w| w.set_ckpsc(psc.into()));
103        regs.mper().modify(|w| w.set_mper(per));
104    }
105
106    fn set_channel_frequency(channel: usize, frequency: Hertz) {
107        let f = frequency.0;
108
109        // TODO: wire up HRTIM to the RCC mux infra.
110        //#[cfg(stm32f334)]
111        //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
112        //#[cfg(not(stm32f334))]
113        let timer_f = Self::frequency().0;
114
115        let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
116        let psc = if Self::regs().isr().read().dllrdy() {
117            Prescaler::compute_min_high_res(psc_min)
118        } else {
119            Prescaler::compute_min_low_res(psc_min)
120        };
121
122        let timer_f = 32 * (timer_f / psc as u32);
123        let per: u16 = (timer_f / f) as u16;
124
125        let regs = Self::regs();
126
127        regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into()));
128        regs.tim(channel).per().modify(|w| w.set_per(per));
129    }
130
131    /// Set the dead time as a proportion of max_duty
132    fn set_channel_dead_time(channel: usize, dead_time: u16) {
133        let regs = Self::regs();
134
135        let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into();
136
137        // The dead-time base clock runs 4 times slower than the hrtim base clock
138        // u9::MAX = 511
139        let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511);
140        let psc = if Self::regs().isr().read().dllrdy() {
141            Prescaler::compute_min_high_res(psc_min)
142        } else {
143            Prescaler::compute_min_low_res(psc_min)
144        };
145
146        let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32);
147
148        regs.tim(channel).dt().modify(|w| {
149            w.set_dtprsc(psc.into());
150            w.set_dtf(dt_val as u16);
151            w.set_dtr(dt_val as u16);
152        });
153    }
154}
155
156/// HRTIM instance trait.
157#[allow(private_bounds)]
158pub trait Instance: SealedInstance + PeripheralType + 'static {}
159
160foreach_interrupt! {
161    ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => {
162        impl SealedInstance for crate::peripherals::$inst {
163            fn regs() -> crate::pac::hrtim::Hrtim {
164                crate::pac::$inst
165            }
166        }
167
168        impl Instance for crate::peripherals::$inst {
169
170        }
171    };
172}