embassy_stm32/hrtim/
traits.rs

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