stm32f7xx_hal/timer/
pwm.rs

1use super::{compute_arr_presc, Channel, FTimer, Instance, Ocm, Timer, WithPwm};
2use crate::rcc::Clocks;
3use core::marker::PhantomData;
4use core::ops::{Deref, DerefMut};
5use fugit::{HertzU32 as Hertz, TimerDurationU32};
6
7pub trait Pins<TIM, P> {
8    const C1: bool = false;
9    const C2: bool = false;
10    const C3: bool = false;
11    const C4: bool = false;
12    type Channels;
13
14    fn check_used(c: Channel) -> Channel {
15        if (c == Channel::C1 && Self::C1)
16            || (c == Channel::C2 && Self::C2)
17            || (c == Channel::C3 && Self::C3)
18            || (c == Channel::C4 && Self::C4)
19        {
20            c
21        } else {
22            panic!("Unused channel")
23        }
24    }
25
26    fn split() -> Self::Channels;
27}
28pub use super::{CPin, Ch, C1, C2, C3, C4};
29
30pub struct PwmChannel<TIM, const C: u8> {
31    pub(super) _tim: PhantomData<TIM>,
32}
33
34macro_rules! pins_impl {
35    ( $( ( $($PINX:ident),+ ), ( $($ENCHX:ident),+ ); )+ ) => {
36        $(
37            #[allow(unused_parens)]
38            impl<TIM, $($PINX,)+> Pins<TIM, ($(Ch<$ENCHX>),+)> for ($($PINX),+)
39            where
40                TIM: Instance + WithPwm,
41                $($PINX: CPin<TIM, $ENCHX>,)+
42            {
43                $(const $ENCHX: bool = true;)+
44                type Channels = ($(PwmChannel<TIM, $ENCHX>),+);
45                fn split() -> Self::Channels {
46                    ($(PwmChannel::<TIM, $ENCHX>::new()),+)
47                }
48            }
49        )+
50    };
51}
52
53pins_impl!(
54    (P1, P2, P3, P4), (C1, C2, C3, C4);
55    (P2, P3, P4), (C2, C3, C4);
56    (P1, P3, P4), (C1, C3, C4);
57    (P1, P2, P4), (C1, C2, C4);
58    (P1, P2, P3), (C1, C2, C3);
59    (P3, P4), (C3, C4);
60    (P2, P4), (C2, C4);
61    (P2, P3), (C2, C3);
62    (P1, P4), (C1, C4);
63    (P1, P3), (C1, C3);
64    (P1, P2), (C1, C2);
65    (P1), (C1);
66    (P2), (C2);
67    (P3), (C3);
68    (P4), (C4);
69);
70
71impl<TIM, P1, P2, const C: u8> CPin<TIM, C> for (P1, P2)
72where
73    P1: CPin<TIM, C>,
74    P2: CPin<TIM, C>,
75{
76}
77impl<TIM, P1, P2, P3, const C: u8> CPin<TIM, C> for (P1, P2, P3)
78where
79    P1: CPin<TIM, C>,
80    P2: CPin<TIM, C>,
81    P3: CPin<TIM, C>,
82{
83}
84impl<TIM, P1, P2, P3, P4, const C: u8> CPin<TIM, C> for (P1, P2, P3, P4)
85where
86    P1: CPin<TIM, C>,
87    P2: CPin<TIM, C>,
88    P3: CPin<TIM, C>,
89    P4: CPin<TIM, C>,
90{
91}
92
93pub trait PwmExt
94where
95    Self: Sized + Instance + WithPwm,
96{
97    fn pwm<P, PINS, const FREQ: u32>(
98        self,
99        pins: PINS,
100        time: TimerDurationU32<FREQ>,
101        clocks: &Clocks,
102    ) -> Pwm<Self, P, PINS, FREQ>
103    where
104        PINS: Pins<Self, P>;
105
106    fn pwm_hz<P, PINS>(self, pins: PINS, freq: Hertz, clocks: &Clocks) -> PwmHz<Self, P, PINS>
107    where
108        PINS: Pins<Self, P>;
109
110    fn pwm_us<P, PINS>(
111        self,
112        pins: PINS,
113        time: TimerDurationU32<1_000_000>,
114        clocks: &Clocks,
115    ) -> Pwm<Self, P, PINS, 1_000_000>
116    where
117        PINS: Pins<Self, P>,
118    {
119        self.pwm::<_, _, 1_000_000>(pins, time, clocks)
120    }
121}
122
123impl<TIM> PwmExt for TIM
124where
125    Self: Sized + Instance + WithPwm,
126{
127    fn pwm<P, PINS, const FREQ: u32>(
128        self,
129        pins: PINS,
130        time: TimerDurationU32<FREQ>,
131        clocks: &Clocks,
132    ) -> Pwm<TIM, P, PINS, FREQ>
133    where
134        PINS: Pins<Self, P>,
135    {
136        FTimer::<Self, FREQ>::new(self, clocks).pwm(pins, time)
137    }
138
139    fn pwm_hz<P, PINS>(self, pins: PINS, time: Hertz, clocks: &Clocks) -> PwmHz<TIM, P, PINS>
140    where
141        PINS: Pins<Self, P>,
142    {
143        Timer::new(self, clocks).pwm_hz(pins, time)
144    }
145}
146
147impl<TIM: Instance + WithPwm, const C: u8> PwmChannel<TIM, C> {
148    pub(crate) fn new() -> Self {
149        Self {
150            _tim: core::marker::PhantomData,
151        }
152    }
153}
154
155impl<TIM: Instance + WithPwm, const C: u8> PwmChannel<TIM, C> {
156    #[inline]
157    pub fn disable(&mut self) {
158        TIM::enable_channel(C, false);
159    }
160
161    #[inline]
162    pub fn enable(&mut self) {
163        TIM::enable_channel(C, true);
164    }
165
166    #[inline]
167    pub fn get_duty(&self) -> u16 {
168        TIM::read_cc_value(C) as u16
169    }
170
171    /// If `0` returned means max_duty is 2^16
172    #[inline]
173    pub fn get_max_duty(&self) -> u16 {
174        (TIM::read_auto_reload() as u16).wrapping_add(1)
175    }
176
177    #[inline]
178    pub fn set_duty(&mut self, duty: u16) {
179        TIM::set_cc_value(C, duty as u32)
180    }
181}
182
183pub struct PwmHz<TIM, P, PINS>
184where
185    TIM: Instance + WithPwm,
186    PINS: Pins<TIM, P>,
187{
188    timer: Timer<TIM>,
189    _pins: PhantomData<(P, PINS)>,
190}
191
192impl<TIM, P, PINS> PwmHz<TIM, P, PINS>
193where
194    TIM: Instance + WithPwm,
195    PINS: Pins<TIM, P>,
196{
197    pub fn release(mut self) -> Timer<TIM> {
198        // stop timer
199        self.tim.cr1_reset();
200        self.timer
201    }
202
203    pub fn split(self) -> PINS::Channels {
204        PINS::split()
205    }
206}
207
208impl<TIM, P, PINS> Deref for PwmHz<TIM, P, PINS>
209where
210    TIM: Instance + WithPwm,
211    PINS: Pins<TIM, P>,
212{
213    type Target = Timer<TIM>;
214    fn deref(&self) -> &Self::Target {
215        &self.timer
216    }
217}
218
219impl<TIM, P, PINS> DerefMut for PwmHz<TIM, P, PINS>
220where
221    TIM: Instance + WithPwm,
222    PINS: Pins<TIM, P>,
223{
224    fn deref_mut(&mut self) -> &mut Self::Target {
225        &mut self.timer
226    }
227}
228
229impl<TIM: Instance + WithPwm> Timer<TIM> {
230    pub fn pwm_hz<P, PINS>(mut self, _pins: PINS, freq: Hertz) -> PwmHz<TIM, P, PINS>
231    where
232        PINS: Pins<TIM, P>,
233    {
234        if PINS::C1 {
235            self.tim
236                .preload_output_channel_in_mode(Channel::C1, Ocm::PwmMode1);
237        }
238        if PINS::C2 && TIM::CH_NUMBER > 1 {
239            self.tim
240                .preload_output_channel_in_mode(Channel::C2, Ocm::PwmMode1);
241        }
242        if PINS::C3 && TIM::CH_NUMBER > 2 {
243            self.tim
244                .preload_output_channel_in_mode(Channel::C3, Ocm::PwmMode1);
245        }
246        if PINS::C4 && TIM::CH_NUMBER > 3 {
247            self.tim
248                .preload_output_channel_in_mode(Channel::C4, Ocm::PwmMode1);
249        }
250
251        // The reference manual is a bit ambiguous about when enabling this bit is really
252        // necessary, but since we MUST enable the preload for the output channels then we
253        // might as well enable for the auto-reload too
254        self.tim.enable_preload(true);
255
256        let (psc, arr) = compute_arr_presc(freq.raw(), self.clk.raw());
257        self.tim.set_prescaler(psc);
258        self.tim.set_auto_reload(arr).unwrap();
259
260        // Trigger update event to load the registers
261        self.tim.trigger_update();
262
263        self.tim.start_pwm();
264
265        PwmHz {
266            timer: self,
267            _pins: PhantomData,
268        }
269    }
270}
271
272impl<TIM, P, PINS> PwmHz<TIM, P, PINS>
273where
274    TIM: Instance + WithPwm,
275    PINS: Pins<TIM, P>,
276{
277    pub fn enable(&mut self, channel: Channel) {
278        TIM::enable_channel(PINS::check_used(channel) as u8, true)
279    }
280
281    pub fn disable(&mut self, channel: Channel) {
282        TIM::enable_channel(PINS::check_used(channel) as u8, false)
283    }
284
285    pub fn get_duty(&self, channel: Channel) -> u16 {
286        TIM::read_cc_value(PINS::check_used(channel) as u8) as u16
287    }
288
289    pub fn set_duty(&mut self, channel: Channel, duty: u16) {
290        TIM::set_cc_value(PINS::check_used(channel) as u8, duty as u32)
291    }
292
293    /// If `0` returned means max_duty is 2^16
294    pub fn get_max_duty(&self) -> u16 {
295        (TIM::read_auto_reload() as u16).wrapping_add(1)
296    }
297
298    pub fn get_period(&self) -> Hertz {
299        let clk = self.clk;
300        let psc = self.tim.read_prescaler() as u32;
301        let arr = TIM::read_auto_reload();
302
303        // Length in ms of an internal clock pulse
304        clk / (psc * arr)
305    }
306
307    pub fn set_period(&mut self, period: Hertz) {
308        let clk = self.clk;
309
310        let (psc, arr) = compute_arr_presc(period.raw(), clk.raw());
311        self.tim.set_prescaler(psc);
312        self.tim.set_auto_reload(arr).unwrap();
313    }
314}
315
316pub struct Pwm<TIM, P, PINS, const FREQ: u32>
317where
318    TIM: Instance + WithPwm,
319    PINS: Pins<TIM, P>,
320{
321    timer: FTimer<TIM, FREQ>,
322    _pins: PhantomData<(P, PINS)>,
323}
324
325impl<TIM, P, PINS, const FREQ: u32> Pwm<TIM, P, PINS, FREQ>
326where
327    TIM: Instance + WithPwm,
328    PINS: Pins<TIM, P>,
329{
330    pub fn split(self) -> PINS::Channels {
331        PINS::split()
332    }
333
334    pub fn release(mut self) -> FTimer<TIM, FREQ> {
335        // stop counter
336        self.tim.cr1_reset();
337        self.timer
338    }
339}
340
341impl<TIM, P, PINS, const FREQ: u32> Deref for Pwm<TIM, P, PINS, FREQ>
342where
343    TIM: Instance + WithPwm,
344    PINS: Pins<TIM, P>,
345{
346    type Target = FTimer<TIM, FREQ>;
347    fn deref(&self) -> &Self::Target {
348        &self.timer
349    }
350}
351
352impl<TIM, P, PINS, const FREQ: u32> DerefMut for Pwm<TIM, P, PINS, FREQ>
353where
354    TIM: Instance + WithPwm,
355    PINS: Pins<TIM, P>,
356{
357    fn deref_mut(&mut self) -> &mut Self::Target {
358        &mut self.timer
359    }
360}
361
362impl<TIM: Instance + WithPwm, const FREQ: u32> FTimer<TIM, FREQ> {
363    pub fn pwm<P, PINS>(
364        mut self,
365        _pins: PINS,
366        time: TimerDurationU32<FREQ>,
367    ) -> Pwm<TIM, P, PINS, FREQ>
368    where
369        PINS: Pins<TIM, P>,
370    {
371        if PINS::C1 {
372            self.tim
373                .preload_output_channel_in_mode(Channel::C1, Ocm::PwmMode1);
374        }
375        if PINS::C2 && TIM::CH_NUMBER > 1 {
376            self.tim
377                .preload_output_channel_in_mode(Channel::C2, Ocm::PwmMode1);
378        }
379        if PINS::C3 && TIM::CH_NUMBER > 2 {
380            self.tim
381                .preload_output_channel_in_mode(Channel::C3, Ocm::PwmMode1);
382        }
383        if PINS::C4 && TIM::CH_NUMBER > 3 {
384            self.tim
385                .preload_output_channel_in_mode(Channel::C4, Ocm::PwmMode1);
386        }
387
388        // The reference manual is a bit ambiguous about when enabling this bit is really
389        // necessary, but since we MUST enable the preload for the output channels then we
390        // might as well enable for the auto-reload too
391        self.tim.enable_preload(true);
392
393        self.tim.set_auto_reload(time.ticks() - 1).unwrap();
394
395        // Trigger update event to load the registers
396        self.tim.trigger_update();
397
398        self.tim.start_pwm();
399
400        Pwm {
401            timer: self,
402            _pins: PhantomData,
403        }
404    }
405}
406
407impl<TIM, P, PINS, const FREQ: u32> Pwm<TIM, P, PINS, FREQ>
408where
409    TIM: Instance + WithPwm,
410    PINS: Pins<TIM, P>,
411{
412    pub fn enable(&mut self, channel: Channel) {
413        TIM::enable_channel(PINS::check_used(channel) as u8, true)
414    }
415
416    pub fn disable(&mut self, channel: Channel) {
417        TIM::enable_channel(PINS::check_used(channel) as u8, false)
418    }
419
420    pub fn get_duty(&self, channel: Channel) -> u16 {
421        TIM::read_cc_value(PINS::check_used(channel) as u8) as u16
422    }
423
424    pub fn set_duty(&mut self, channel: Channel, duty: u16) {
425        TIM::set_cc_value(PINS::check_used(channel) as u8, duty.into())
426    }
427
428    /// If `0` returned means max_duty is 2^16
429    pub fn get_max_duty(&self) -> u16 {
430        (TIM::read_auto_reload() as u16).wrapping_add(1)
431    }
432
433    pub fn get_period(&self) -> TimerDurationU32<FREQ> {
434        TimerDurationU32::from_ticks(TIM::read_auto_reload() + 1)
435    }
436
437    pub fn set_period(&mut self, period: TimerDurationU32<FREQ>) {
438        self.tim.set_auto_reload(period.ticks() - 1).unwrap();
439    }
440}