stm32f1xx_hal_bxcan/
pwm.rs

1/*!
2  # Pulse width modulation
3
4  The general purpose timers (`TIM2`, `TIM3`, and `TIM4`) can be used to output
5  pulse width modulated signals on some pins. The timers support up to 4
6  simultaneous pwm outputs in separate `Channels`
7
8  ## Usage for pre-defined channel combinations
9
10  This crate only defines basic channel combinations for default AFIO remappings,
11  where all the channels are enabled. Start by setting all the pins for the
12  timer you want to use to alternate push pull pins:
13
14  ```rust
15  let gpioa = ..; // Set up and split GPIOA
16  // Select the pins you want to use
17  let pins = (
18      gpioa.pa0.into_alternate_push_pull(&mut gpioa.crl),
19      gpioa.pa1.into_alternate_push_pull(&mut gpioa.crl),
20      gpioa.pa2.into_alternate_push_pull(&mut gpioa.crl),
21      gpioa.pa3.into_alternate_push_pull(&mut gpioa.crl),
22  );
23
24  // Set up the timer as a PWM output. If selected pins may correspond to different remap options,
25  // then you must specify the remap generic parameter. Otherwise, if there is no such ambiguity,
26  // the remap generic parameter can be omitted without complains from the compiler.
27  let (c1, c2, c3, c4) = Timer::tim2(p.TIM2, &clocks, &mut rcc.apb1)
28      .pwm::<Tim2NoRemap, _, _, _>(pins, &mut afio.mapr, 1.khz())
29      .3;
30
31  // Start using the channels
32  c1.set_duty(c1.get_max_duty());
33  // ...
34  ```
35
36  Then call the `pwm` function on the corresponding timer.
37
38  NOTE: In some cases you need to specify remap you need, especially for TIM2
39  (see [Alternate function remapping](super::timer)):
40
41  ```
42    let device: pac::Peripherals = ..;
43
44    // Put the timer in PWM mode using the specified pins
45    // with a frequency of 100 hz.
46    let (c0, c1, c2, c3) = Timer::tim2(device.TIM2, &clocks, &mut rcc.apb1)
47        .pwm::<Tim2NoRemap, _, _, _>(pins, &mut afio.mapr, 100.hz());
48
49    // Set the duty cycle of channel 0 to 50%
50    c0.set_duty(c0.get_max_duty() / 2);
51    // PWM outputs are disabled by default
52    c0.enable()
53  ```
54*/
55
56use core::marker::Copy;
57use core::marker::PhantomData;
58
59use crate::hal;
60#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
61use crate::pac::TIM1;
62#[cfg(feature = "medium")]
63use crate::pac::TIM4;
64use crate::pac::{TIM2, TIM3};
65use cast::{u16, u32};
66
67use crate::afio::MAPR;
68use crate::bb;
69use crate::gpio::{self, Alternate, PushPull};
70use crate::time::Hertz;
71use crate::time::U32Ext;
72use crate::timer::Timer;
73
74pub trait Pins<REMAP, P> {
75    const C1: bool = false;
76    const C2: bool = false;
77    const C3: bool = false;
78    const C4: bool = false;
79    type Channels;
80
81    fn check_used(c: Channel) -> Channel {
82        if (c == Channel::C1 && Self::C1)
83            || (c == Channel::C2 && Self::C2)
84            || (c == Channel::C3 && Self::C3)
85            || (c == Channel::C4 && Self::C4)
86        {
87            c
88        } else {
89            panic!("Unused channel")
90        }
91    }
92
93    fn split() -> Self::Channels;
94}
95
96#[derive(Clone, Copy, PartialEq)]
97pub enum Channel {
98    C1,
99    C2,
100    C3,
101    C4,
102}
103
104use crate::timer::sealed::{Ch1, Ch2, Ch3, Ch4, Remap};
105macro_rules! pins_impl {
106    ( $( ( $($PINX:ident),+ ), ( $($TRAIT:ident),+ ), ( $($ENCHX:ident),+ ); )+ ) => {
107        $(
108            #[allow(unused_parens)]
109            impl<TIM, REMAP, $($PINX,)+> Pins<REMAP, ($($ENCHX),+)> for ($($PINX),+)
110            where
111                REMAP: Remap<Periph = TIM>,
112                $($PINX: $TRAIT<REMAP> + gpio::Mode<Alternate<PushPull>>,)+
113            {
114                $(const $ENCHX: bool = true;)+
115                type Channels = ($(PwmChannel<TIM, $ENCHX>),+);
116                fn split() -> Self::Channels {
117                    ($(PwmChannel::<TIM, $ENCHX> { _channel: PhantomData, _tim: PhantomData }),+)
118                }
119            }
120        )+
121    };
122}
123
124pins_impl!(
125    (P1, P2, P3, P4), (Ch1, Ch2, Ch3, Ch4), (C1, C2, C3, C4);
126    (P2, P3, P4), (Ch2, Ch3, Ch4), (C2, C3, C4);
127    (P1, P3, P4), (Ch1, Ch3, Ch4), (C1, C3, C4);
128    (P1, P2, P4), (Ch1, Ch2, Ch4), (C1, C2, C4);
129    (P1, P2, P3), (Ch1, Ch2, Ch3), (C1, C2, C3);
130    (P3, P4), (Ch3, Ch4), (C3, C4);
131    (P2, P4), (Ch2, Ch4), (C2, C4);
132    (P2, P3), (Ch2, Ch3), (C2, C3);
133    (P1, P4), (Ch1, Ch4), (C1, C4);
134    (P1, P3), (Ch1, Ch3), (C1, C3);
135    (P1, P2), (Ch1, Ch2), (C1, C2);
136    (P1), (Ch1), (C1);
137    (P2), (Ch2), (C2);
138    (P3), (Ch3), (C3);
139    (P4), (Ch4), (C4);
140);
141
142#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
143impl Timer<TIM1> {
144    pub fn pwm<REMAP, P, PINS, T>(
145        self,
146        _pins: PINS,
147        mapr: &mut MAPR,
148        freq: T,
149    ) -> Pwm<TIM1, REMAP, P, PINS>
150    where
151        REMAP: Remap<Periph = TIM1>,
152        PINS: Pins<REMAP, P>,
153        T: Into<Hertz>,
154    {
155        mapr.modify_mapr(|_, w| unsafe { w.tim1_remap().bits(REMAP::REMAP) });
156
157        // TIM1 has a break function that deactivates the outputs, this bit automatically activates
158        // the output when no break input is present
159        self.tim.bdtr.modify(|_, w| w.aoe().set_bit());
160
161        let Self { tim, clk } = self;
162        tim1(tim, _pins, freq.into(), clk)
163    }
164}
165
166impl Timer<TIM2> {
167    pub fn pwm<REMAP, P, PINS, T>(
168        self,
169        _pins: PINS,
170        mapr: &mut MAPR,
171        freq: T,
172    ) -> Pwm<TIM2, REMAP, P, PINS>
173    where
174        REMAP: Remap<Periph = TIM2>,
175        PINS: Pins<REMAP, P>,
176        T: Into<Hertz>,
177    {
178        mapr.modify_mapr(|_, w| unsafe { w.tim2_remap().bits(REMAP::REMAP) });
179
180        let Self { tim, clk } = self;
181        tim2(tim, _pins, freq.into(), clk)
182    }
183}
184
185impl Timer<TIM3> {
186    pub fn pwm<REMAP, P, PINS, T>(
187        self,
188        _pins: PINS,
189        mapr: &mut MAPR,
190        freq: T,
191    ) -> Pwm<TIM3, REMAP, P, PINS>
192    where
193        REMAP: Remap<Periph = TIM3>,
194        PINS: Pins<REMAP, P>,
195        T: Into<Hertz>,
196    {
197        mapr.modify_mapr(|_, w| unsafe { w.tim3_remap().bits(REMAP::REMAP) });
198
199        let Self { tim, clk } = self;
200        tim3(tim, _pins, freq.into(), clk)
201    }
202}
203
204#[cfg(feature = "medium")]
205impl Timer<TIM4> {
206    pub fn pwm<REMAP, P, PINS, T>(
207        self,
208        _pins: PINS,
209        mapr: &mut MAPR,
210        freq: T,
211    ) -> Pwm<TIM4, REMAP, P, PINS>
212    where
213        REMAP: Remap<Periph = TIM4>,
214        PINS: Pins<REMAP, P>,
215        T: Into<Hertz>,
216    {
217        mapr.modify_mapr(|_, w| w.tim4_remap().bit(REMAP::REMAP == 1));
218
219        let Self { tim, clk } = self;
220        tim4(tim, _pins, freq.into(), clk)
221    }
222}
223
224pub struct Pwm<TIM, REMAP, P, PINS>
225where
226    REMAP: Remap<Periph = TIM>,
227    PINS: Pins<REMAP, P>,
228{
229    clk: Hertz,
230    _pins: PhantomData<(TIM, REMAP, P, PINS)>,
231}
232
233impl<TIM, REMAP, P, PINS> Pwm<TIM, REMAP, P, PINS>
234where
235    REMAP: Remap<Periph = TIM>,
236    PINS: Pins<REMAP, P>,
237{
238    pub fn split(self) -> PINS::Channels {
239        PINS::split()
240    }
241}
242
243pub struct PwmChannel<TIM, CHANNEL> {
244    _channel: PhantomData<CHANNEL>,
245    _tim: PhantomData<TIM>,
246}
247
248pub struct C1;
249pub struct C2;
250pub struct C3;
251pub struct C4;
252
253macro_rules! hal {
254    ($($TIMX:ident: ($timX:ident),)+) => {
255        $(
256            fn $timX<REMAP, P, PINS>(
257                tim: $TIMX,
258                _pins: PINS,
259                freq: Hertz,
260                clk: Hertz,
261            ) -> Pwm<$TIMX, REMAP, P, PINS>
262            where
263                REMAP: Remap<Periph = $TIMX>,
264                PINS: Pins<REMAP, P>,
265            {
266                if PINS::C1 {
267                    tim.ccmr1_output()
268                        .modify(|_, w| w.oc1pe().set_bit().oc1m().pwm_mode1() );
269                }
270
271                if PINS::C2 {
272                    tim.ccmr1_output()
273                        .modify(|_, w| w.oc2pe().set_bit().oc2m().pwm_mode1() );
274                }
275
276                if PINS::C3 {
277                    tim.ccmr2_output()
278                        .modify(|_, w| w.oc3pe().set_bit().oc3m().pwm_mode1() );
279                }
280
281                if PINS::C4 {
282                    tim.ccmr2_output()
283                        .modify(|_, w| w.oc4pe().set_bit().oc4m().pwm_mode1() );
284                }
285                let ticks = clk.0 / freq.0;
286                let psc = u16(ticks / (1 << 16)).unwrap();
287                tim.psc.write(|w| w.psc().bits(psc) );
288                let arr = u16(ticks / u32(psc + 1)).unwrap();
289                tim.arr.write(|w| w.arr().bits(arr));
290
291                // The psc register is buffered, so we trigger an update event to update it
292                // Sets the URS bit to prevent an interrupt from being triggered by the UG bit
293                tim.cr1.modify(|_, w| w.urs().set_bit());
294                tim.egr.write(|w| w.ug().set_bit());
295                tim.cr1.modify(|_, w| w.urs().clear_bit());
296
297                tim.cr1.write(|w|
298                    w.cms()
299                        .bits(0b00)
300                        .dir()
301                        .clear_bit()
302                        .opm()
303                        .clear_bit()
304                        .cen()
305                        .set_bit()
306                );
307
308                Pwm {
309                    clk,
310                    _pins: PhantomData
311                }
312            }
313
314        /*
315        The following implemention of the embedded_hal::Pwm uses Hertz as a time type.  This was choosen
316        because of the timescales of operations being on the order of nanoseconds and not being able to
317        efficently represent a float on the hardware.  It might be possible to change the time type to
318        a different time based using such as the nanosecond.  The issue with doing so is that the max
319        delay would then be at just a little over 2 seconds because of the 32 bit depth of the number.
320        Using milliseconds is also an option, however, using this as a base unit means that only there
321        could be resolution issues when trying to get a specific value, because of the integer nature.
322
323        To find a middle ground, the Hertz type is used as a base here and the Into trait has been
324        defined for several base time units.  This will allow for calling the set_period method with
325        something that is natural to both the MCU and the end user.
326        */
327        impl<REMAP, P, PINS> hal::Pwm for Pwm<$TIMX, REMAP, P, PINS> where
328            REMAP: Remap<Periph = $TIMX>,
329            PINS: Pins<REMAP, P>,
330            {
331                type Channel = Channel;
332                type Duty = u16;
333                type Time = Hertz;
334
335                fn enable(&mut self, channel: Self::Channel) {
336                    match PINS::check_used(channel) {
337                        Channel::C1 => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) },
338                        Channel::C2 => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) },
339                        Channel::C3 => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 8) },
340                        Channel::C4 => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 12) }
341                    }
342                }
343
344                fn disable(&mut self, channel: Self::Channel) {
345                    match PINS::check_used(channel) {
346                        Channel::C1 => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) },
347                        Channel::C2 => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) },
348                        Channel::C3 => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 8) },
349                        Channel::C4 => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 12) },
350                    }
351                }
352
353                fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
354                    match PINS::check_used(channel) {
355                        Channel::C1 => unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() },
356                        Channel::C2 => unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() },
357                        Channel::C3 => unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() },
358                        Channel::C4 => unsafe { (*$TIMX::ptr()).ccr4.read().ccr().bits() },
359                    }
360                }
361
362                fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
363                    match PINS::check_used(channel) {
364                        Channel::C1 => unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty)) },
365                        Channel::C2 => unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty)) },
366                        Channel::C3 => unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty)) },
367                        Channel::C4 => unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr().bits(duty)) },
368                    }
369                }
370
371                fn get_max_duty(&self) -> Self::Duty {
372                    unsafe { (*$TIMX::ptr()).arr.read().arr().bits() }
373                }
374
375                fn get_period(&self) -> Self::Time {
376                    let clk = self.clk;
377                    let psc: u16 = unsafe{(*$TIMX::ptr()).psc.read().psc().bits()};
378                    let arr: u16 = unsafe{(*$TIMX::ptr()).arr.read().arr().bits()};
379
380                    // Length in ms of an internal clock pulse
381                    (clk.0 / u32(psc * arr)).hz()
382                }
383
384                fn set_period<T>(&mut self, period: T) where
385                    T: Into<Self::Time> {
386                        let clk = self.clk;
387
388                        let ticks = clk.0 / period.into().0;
389                        let psc = u16(ticks / (1 << 16)).unwrap();
390                        let arr = u16(ticks / u32(psc + 1)).unwrap();
391                        unsafe {
392                            (*$TIMX::ptr()).psc.write(|w| w.psc().bits(psc));
393                            (*$TIMX::ptr()).arr.write(|w| w.arr().bits(arr));
394                        }
395                }
396            }
397
398            impl hal::PwmPin for PwmChannel<$TIMX, C1> {
399                type Duty = u16;
400
401                fn disable(&mut self) {
402                    unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) }
403                }
404
405                fn enable(&mut self) {
406                    unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) }
407                }
408
409                fn get_duty(&self) -> u16 {
410                    unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() }
411                }
412
413                fn get_max_duty(&self) -> u16 {
414                    unsafe { (*$TIMX::ptr()).arr.read().arr().bits() }
415                }
416
417                fn set_duty(&mut self, duty: u16) {
418                    unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty)) }
419                }
420            }
421
422            impl hal::PwmPin for PwmChannel<$TIMX, C2> {
423                type Duty = u16;
424
425                fn disable(&mut self) {
426                    unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) }
427                }
428
429                fn enable(&mut self) {
430                    unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) }
431                }
432
433                fn get_duty(&self) -> u16 {
434                    unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() }
435                }
436
437                fn get_max_duty(&self) -> u16 {
438                    unsafe { (*$TIMX::ptr()).arr.read().arr().bits() }
439                }
440
441                fn set_duty(&mut self, duty: u16) {
442                    unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty)) }
443                }
444            }
445
446            impl hal::PwmPin for PwmChannel<$TIMX, C3> {
447                type Duty = u16;
448
449                fn disable(&mut self) {
450                    unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 8) }
451                }
452
453                fn enable(&mut self) {
454                    unsafe { bb::set(&(*$TIMX::ptr()).ccer, 8) }
455                }
456
457                fn get_duty(&self) -> u16 {
458                    unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() }
459                }
460
461                fn get_max_duty(&self) -> u16 {
462                    unsafe { (*$TIMX::ptr()).arr.read().arr().bits() }
463                }
464
465                fn set_duty(&mut self, duty: u16) {
466                    unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty)) }
467                }
468            }
469
470            impl hal::PwmPin for PwmChannel<$TIMX, C4> {
471                type Duty = u16;
472
473                fn disable(&mut self) {
474                    unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 12) }
475                }
476
477                fn enable(&mut self) {
478                    unsafe { bb::set(&(*$TIMX::ptr()).ccer, 12) }
479                }
480
481                fn get_duty(&self) -> u16 {
482                    unsafe { (*$TIMX::ptr()).ccr4.read().ccr().bits() }
483                }
484
485                fn get_max_duty(&self) -> u16 {
486                    unsafe { (*$TIMX::ptr()).arr.read().arr().bits() }
487                }
488
489                fn set_duty(&mut self, duty: u16) {
490                    unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr().bits(duty)) }
491                }
492            }
493        )+
494    }
495}
496
497#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
498hal! {
499    TIM1: (tim1),
500}
501
502hal! {
503    TIM2: (tim2),
504    TIM3: (tim3),
505}
506
507#[cfg(feature = "medium")]
508hal! {
509    TIM4: (tim4),
510}