stm32l4xx_hal/
pwm.rs

1//! # Pulse Width Modulation
2
3use core::marker::PhantomData;
4use core::mem;
5
6use crate::hal;
7use crate::stm32::{TIM1, TIM15, TIM2};
8
9use crate::gpio::gpioa::{PA0, PA1, PA10, PA11, PA15, PA2, PA3, PA8, PA9};
10use crate::gpio::gpiob::{PB10, PB11, PB14, PB3};
11use crate::gpio::Alternate;
12use crate::rcc::{Clocks, Enable, Reset, APB1R1, APB2};
13use crate::time::Hertz;
14
15// NB: REMAP is not implemented!
16pub trait Pins<TIM> {
17    // const REMAP: u8;
18    const C1: bool = false;
19    const C2: bool = false;
20    const C3: bool = false;
21    const C4: bool = false;
22    type Channels;
23}
24
25macro_rules! pins_to_channels_mapping {
26    ( $( $TIMX:ident: ( $($PINX:ident),+ ), ( $($ENCHX:ident),+ ), ( $($AF:literal),+ ); )+ ) => {
27        $(
28            #[allow(unused_parens)]
29            impl<OTYPE> Pins<$TIMX> for ($($PINX<Alternate<OTYPE, $AF>>),+)
30            {
31                $(const $ENCHX: bool = true;)+
32                type Channels = ($(Pwm<$TIMX, $ENCHX>),+);
33            }
34        )+
35    };
36}
37
38pins_to_channels_mapping! {
39    // TIM1
40    TIM1: (PA8, PA9, PA10, PA11), (C1, C2, C3, C4), (1, 1, 1, 1);
41    TIM1: (PA9, PA10, PA11), (C2, C3, C4), (1, 1, 1);
42    TIM1: (PA8, PA10, PA11), (C1, C3, C4), (1, 1, 1);
43    TIM1: (PA8, PA9, PA11), (C1, C2, C4), (1, 1, 1);
44    TIM1: (PA8, PA9, PA10), (C1, C2, C3), (1, 1, 1);
45    TIM1: (PA10, PA11), (C3, C4), (1, 1);
46    TIM1: (PA9, PA11), (C2, C4), (1, 1);
47    TIM1: (PA9, PA10), (C2, C3), (1, 1);
48    TIM1: (PA8, PA11), (C1, C4), (1, 1);
49    TIM1: (PA8, PA10), (C1, C3), (1, 1);
50    TIM1: (PA8, PA9), (C1, C2), (1, 1);
51    TIM1: (PA8), (C1), (1);
52    TIM1: (PA9), (C2), (1);
53    TIM1: (PA10), (C3), (1);
54    TIM1: (PA11), (C4), (1);
55
56    // TIM2
57    TIM2: (PA0, PA1, PA2, PA3), (C1, C2, C3, C4), (1, 1, 1, 1);
58    TIM2: (PA0, PA1, PA2, PB11), (C1, C2, C3, C4), (1, 1, 1, 1);
59    TIM2: (PA15, PB3, PB10, PB11), (C1, C2, C3, C4), (1, 1, 1, 1);
60
61    TIM2: (PA1, PA2, PA3), (C2, C3, C4), (1, 1, 1);
62    TIM2: (PA0, PA2, PA3), (C1, C3, C4), (1, 1, 1);
63    TIM2: (PA0, PA1, PA3), (C1, C2, C4), (1, 1, 1);
64    TIM2: (PA0, PA1, PA2), (C1, C2, C3), (1, 1, 1);
65
66    TIM2: (PB3, PB10, PB11), (C2, C3, C4), (1, 1, 1);
67    TIM2: (PA15, PB10, PB11), (C1, C3, C4), (1, 1, 1);
68    TIM2: (PA15, PB3, PB11), (C1, C2, C4), (1, 1, 1);
69    TIM2: (PA15, PB3, PB10), (C1, C2, C3), (1, 1, 1);
70
71    TIM2: (PA2, PA3), (C3, C4), (1, 1);
72    TIM2: (PA1, PA3), (C2, C4), (1, 1);
73    TIM2: (PA1, PA2), (C2, C3), (1, 1);
74    TIM2: (PA0, PA3), (C1, C4), (1, 1);
75    TIM2: (PA0, PA2), (C1, C3), (1, 1);
76    TIM2: (PA0, PA1), (C1, C2), (1, 1);
77
78    TIM2: (PB10, PB11), (C3, C4), (1, 1);
79    TIM2: (PB3, PB11), (C2, C4), (1, 1);
80    TIM2: (PB3, PB10), (C2, C3), (1, 1);
81    TIM2: (PA15, PB11), (C1, C4), (1, 1);
82    TIM2: (PA15, PB10), (C1, C3), (1, 1);
83    TIM2: (PA15, PB3), (C1, C2), (1, 1);
84
85    TIM2: (PA0), (C1), (1);
86    TIM2: (PA1), (C2), (1);
87    TIM2: (PA2), (C3), (1);
88    TIM2: (PA3), (C4), (1);
89
90    TIM2: (PA15), (C1), (1);
91    TIM2: (PB3), (C2), (1);
92    TIM2: (PB10), (C3), (1);
93    TIM2: (PB11), (C4), (1);
94
95    // TIM15 - TODO: The uncommented lines are awaiting PAC updates to be valid.
96    TIM15: (PB14), (C1), (14);
97    // TIM15: (PB15), (C2), (14);
98    TIM15: (PA2), (C1), (14);
99    // TIM15: (PA3), (C2), (14);
100    // TIM15: (PB14, PB15), (C1, C2), (14, 14);
101    // TIM15: (PB14, PA3), (C1, C2), (14, 14);
102    // TIM15: (PA2, PB15), (C1, C2), (14, 14);
103    // TIM15: (PA2, PA3), (C1, C2), (14, 14);
104}
105
106pub trait PwmExt1: Sized {
107    fn pwm<PINS>(self, _: PINS, frequency: Hertz, clocks: Clocks, apb: &mut APB2) -> PINS::Channels
108    where
109        PINS: Pins<Self>;
110}
111
112pub trait PwmExt2: Sized {
113    fn pwm<PINS>(
114        self,
115        _: PINS,
116        frequency: Hertz,
117        clocks: Clocks,
118        apb: &mut APB1R1,
119    ) -> PINS::Channels
120    where
121        PINS: Pins<Self>;
122}
123
124impl PwmExt1 for TIM1 {
125    fn pwm<PINS>(self, _pins: PINS, freq: Hertz, clocks: Clocks, apb: &mut APB2) -> PINS::Channels
126    where
127        PINS: Pins<Self>,
128    {
129        tim1(self, _pins, freq, clocks, apb)
130    }
131}
132
133impl PwmExt1 for TIM15 {
134    fn pwm<PINS>(self, _pins: PINS, freq: Hertz, clocks: Clocks, apb: &mut APB2) -> PINS::Channels
135    where
136        PINS: Pins<Self>,
137    {
138        tim15(self, _pins, freq, clocks, apb)
139    }
140}
141
142impl PwmExt2 for TIM2 {
143    fn pwm<PINS>(self, _pins: PINS, freq: Hertz, clocks: Clocks, apb: &mut APB1R1) -> PINS::Channels
144    where
145        PINS: Pins<Self>,
146    {
147        // TODO: check if this is really not needed (in the f1xx examples value
148        //       of remap is 0x0). if so, what's afio.mapr on l4xx?
149        //
150        // mapr.mapr()
151        //     .modify(|_, w| unsafe { w.tim2_remap().bits(PINS::REMAP) });
152
153        tim2(self, _pins, freq, clocks, apb)
154    }
155}
156
157pub struct Pwm<TIM, CHANNEL> {
158    _channel: PhantomData<CHANNEL>,
159    _tim: PhantomData<TIM>,
160}
161
162pub struct C1;
163pub struct C2;
164pub struct C3;
165pub struct C4;
166
167macro_rules! advanced_timer {
168    ($($TIMX:ident: ($timX:ident, $apb:ident, $psc_width:ident, $arr_width:ident),)+) => {
169        $(
170            fn $timX<PINS>(
171                tim: $TIMX,
172                _pins: PINS,
173                freq: Hertz,
174                clocks: Clocks,
175                apb: &mut $apb,
176            ) -> PINS::Channels
177            where
178                PINS: Pins<$TIMX>,
179            {
180                <$TIMX>::enable(apb);
181                <$TIMX>::reset(apb);
182
183                if PINS::C1 {
184                    tim.ccmr1_output().modify(|_, w| w.oc1pe().set_bit().oc1m().bits(6));
185                }
186
187                if PINS::C2 {
188                    tim.ccmr1_output().modify(|_, w| w.oc2pe().set_bit().oc2m().bits(6));
189                }
190
191                if PINS::C3 {
192                    tim.ccmr2_output().modify(|_, w| w.oc3pe().set_bit().oc3m().bits(6));
193                }
194
195                if PINS::C4 {
196                    tim.ccmr2_output().modify(|_, w| w.oc4pe().set_bit().oc4m().bits(6));
197                }
198
199                let clk = clocks.pclk2();
200                let ticks = clk / freq;
201
202                // maybe this is all u32? also, why no `- 1` vs `timer.rs`?
203                let psc = ticks / (1 << 16);
204                tim.psc.write(|w| { w.psc().bits(psc as $psc_width) });
205                let arr = ticks / (psc + 1);
206                tim.arr.write(|w| { w.arr().bits(arr as $arr_width) });
207
208                // Only for the advanced control timer
209                tim.bdtr.write(|w| w.moe().set_bit());
210                tim.egr.write(|w| w.ug().set_bit());
211
212                tim.cr1.write(|w| {
213                    w.cms()
214                        .bits(0b00)
215                        .dir().clear_bit()
216                        .opm().clear_bit()
217                        .cen().set_bit()
218                        .arpe().set_bit()
219                });
220
221                unsafe { mem::MaybeUninit::uninit().assume_init() }
222            }
223
224            pwm_channels! {
225                $TIMX:  (C1, $arr_width, cc1e, ccr1, ccr),
226                        (C2, $arr_width, cc2e, ccr2, ccr),
227                        (C3, $arr_width, cc3e, ccr3, ccr),
228                        (C4, $arr_width, cc4e, ccr4, ccr),
229            }
230
231        )+
232    }
233}
234
235macro_rules! standard_timer {
236    ($($TIMX:ident: ($timX:ident, $apb:ident, $psc_width:ident, $arr_width:ident),)+) => {
237        $(
238            fn $timX<PINS>(
239                tim: $TIMX,
240                _pins: PINS,
241                freq: Hertz,
242                clocks: Clocks,
243                apb: &mut $apb,
244            ) -> PINS::Channels
245            where
246                PINS: Pins<$TIMX>,
247            {
248                <$TIMX>::enable(apb);
249                <$TIMX>::reset(apb);
250
251                if PINS::C1 {
252                    tim.ccmr1_output().modify(|_, w| w.oc1pe().set_bit().oc1m().bits(6));
253                }
254
255                if PINS::C2 {
256                    tim.ccmr1_output().modify(|_, w| w.oc2pe().set_bit().oc2m().bits(6));
257                }
258
259                if PINS::C3 {
260                    tim.ccmr2_output().modify(|_, w| w.oc3pe().set_bit().oc3m().bits(6));
261                }
262
263                if PINS::C4 {
264                    tim.ccmr2_output().modify(|_, w| w.oc4pe().set_bit().oc4m().bits(6));
265                }
266
267                let clk = clocks.pclk1();
268                let ticks = clk / freq;
269
270                // maybe this is all u32? also, why no `- 1` vs `timer.rs`?
271                let psc = ticks / (1 << 16);
272                tim.psc.write(|w| { w.psc().bits(psc as $psc_width) });
273                let arr = ticks / (psc + 1);
274                tim.arr.write(|w| { w.arr().bits(arr as $arr_width) });
275
276                tim.cr1.write(|w| {
277                    w.cms()
278                        .bits(0b00)
279                        .dir().clear_bit()
280                        .opm().clear_bit()
281                        .cen().set_bit()
282                        .arpe().set_bit()
283                });
284
285                unsafe { mem::MaybeUninit::uninit().assume_init() }
286            }
287
288            pwm_channels! {
289                $TIMX:  (C1, $arr_width, cc1e, ccr1, ccr),
290                        (C2, $arr_width, cc2e, ccr2, ccr),
291                        (C3, $arr_width, cc3e, ccr3, ccr),
292                        (C4, $arr_width, cc4e, ccr4, ccr),
293            }
294
295        )+
296    }
297}
298
299macro_rules! small_timer {
300    ($($TIMX:ident: ($timX:ident, $apb:ident, $psc_width:ident, $arr_width:ident),)+) => {
301        $(
302            fn $timX<PINS>(
303                tim: $TIMX,
304                _pins: PINS,
305                freq: Hertz,
306                clocks: Clocks,
307                apb: &mut $apb,
308            ) -> PINS::Channels
309            where
310                PINS: Pins<$TIMX>,
311            {
312                <$TIMX>::enable(apb);
313                <$TIMX>::reset(apb);
314
315                if PINS::C1 {
316                    tim.ccmr1_output().modify(|_, w| w.oc1pe().set_bit().oc1m().bits(6));
317                }
318
319                // TODO: The uncommented lines are awaiting PAC updates to be valid.
320                // if PINS::C2 {
321                //     tim.ccmr1_output().modify(|_, w| w.oc2pe().set_bit().oc2m().bits(6));
322                // }
323
324                let clk = clocks.pclk1();
325                let ticks = clk / freq;
326
327                // maybe this is all u32? also, why no `- 1` vs `timer.rs`?
328                let psc = ticks / (1 << 16);
329                tim.psc.write(|w| { w.psc().bits(psc as $psc_width) });
330                let arr = ticks / (psc + 1);
331                unsafe { tim.arr.write(|w| { w.arr().bits(arr as $arr_width) }); }
332
333                tim.bdtr.write(|w| w.moe().set_bit());
334                tim.egr.write(|w| w.ug().set_bit());
335
336                tim.cr1.write(|w| {
337                    w.opm().clear_bit()
338                        .cen().set_bit()
339                        .arpe().set_bit()
340                });
341
342                unsafe { mem::MaybeUninit::uninit().assume_init() }
343            }
344
345            pwm_channels! {
346                $TIMX:  (C1, $arr_width, cc1e, ccr1, ccr),
347                // TODO: The uncommented line is awaiting PAC updates to be valid.
348                //        (C2, $arr_width, cc2e, ccr2, ccr2),
349            }
350
351        )+
352    }
353}
354
355macro_rules! pwm_channels {
356    ($TIMX:ident: $(($channel:ident, $arr_width:ident, $ccXe:ident, $ccrX:ident, $ccr:ident),)+) => {
357        $(
358            impl hal::PwmPin for Pwm<$TIMX, $channel> {
359                type Duty = $arr_width;
360
361                #[inline(always)]
362                fn disable(&mut self) {
363                    unsafe { (*$TIMX::ptr()).ccer.modify(|_, w| w.$ccXe().clear_bit()) }
364                }
365
366                #[inline(always)]
367                fn enable(&mut self) {
368                    unsafe { (*$TIMX::ptr()).ccer.modify(|_, w| w.$ccXe().set_bit()) }
369                }
370
371                #[inline(always)]
372                fn get_duty(&self) -> Self::Duty {
373                    unsafe { (*$TIMX::ptr()).$ccrX.read().$ccr().bits() }
374                }
375
376                #[inline(always)]
377                fn get_max_duty(&self) -> Self::Duty {
378                    unsafe { (*$TIMX::ptr()).arr.read().arr().bits() }
379                }
380
381                #[inline(always)]
382                fn set_duty(&mut self, duty: Self::Duty) {
383                    unsafe { (*$TIMX::ptr()).$ccrX.write(|w| w.$ccr().bits(duty)) }
384                }
385            }
386        )+
387    }
388}
389
390advanced_timer! {
391    TIM1: (tim1, APB2, u16, u16),
392}
393
394standard_timer! {
395    TIM2: (tim2, APB1R1, u16, u32),
396}
397
398small_timer! {
399    TIM15: (tim15, APB2, u16, u16),
400}