[][src]Module stm32f1xx_hal::pwm

Pulse width modulation

The general purpose timers (TIM2, TIM3, and TIM4) can be used to output pulse width modulated signals on some pins. The timers support up to 4 simultaneous pwm outputs in separate Channels

Usage for pre-defined channel combinations

This crate only defines basic channel combinations for default AFIO remappings, where all the channels are enabled. Start by setting all the pins for the timer you want to use to alternate push pull pins:

let gpioa = ..; // Set up and split GPIOA
let pins = (
    gpioa.pa0.into_alternate_push_pull(),
    gpioa.pa1.into_alternate_push_pull(),
    gpioa.pa2.into_alternate_push_pull(),
    gpioa.pa3.into_alternate_push_pull(),
);

Then call the pwm function on the corresponding timer:

  let device: pac::Peripherals = ..;

  // Put the timer in PWM mode using the specified pins
  // with a frequency of 100 hz.
  let (c0, c1, c2, c3) = device.TIM2.pwm(
      pins,
      &mut afio.mapr,
      100.hz(),
      clocks,
      &mut rcc.apb1
  );

  // Set the duty cycle of channel 0 to 50%
  c0.set_duty(c0.get_max_duty() / 2);
  // PWM outputs are disabled by default
  c0.enable()

Usage for custom channel combinations

Note that crate itself defines only basic channel combinations for default AFIO remappings, where all the channels are enabled. Meanwhile it is possible to configure PWM for any custom selection of channels. The Pins trait shows the mapping between timers, output pins and channels. So this trait needs to be implemented for the custom combination of channels and AFIO remappings. However minor additional efforts are needed since it is not possible to implement a foreign trait for a foreign type. The trick is to use the newtype pattern.

The first example selects PB5 channel for TIM3 PWM output:

struct MyChannels(PB5<Alternate<PushPull>>);

impl Pins<TIM3>  for MyChannels {
  const REMAP: u8 = 0b10; // use TIM3 AFIO remapping for PB4, PB5, PB0, PB1 pins
  const C1: bool = false;
  const C2: bool = true;  // use channel C2
  const C3: bool = false;
  const C4: bool = false;
  type Channels = Pwm<TIM3, C2>;
}

The second example selects PC8 and PC9 channels for TIM3 PWM output:

struct MyChannels(PC8<Alternate<PushPull>>, PC9<Alternate<PushPull>>);

impl Pins<TIM3>  for MyChannels {
  const REMAP: u8 = 0b11; // use TIM3 AFIO remapping for PC6, PC7, PC8, PC9 pins
  const C1: bool = false;
  const C2: bool = false;
  const C3: bool = true;  // use channel C3
  const C4: bool = true;  // use channel C4
  type Channels = (Pwm<TIM3, C3>, Pwm<TIM3, C4>);
}

REMAP value and channel pins should be specified according to the stm32f1xx specification, e.g. the section 9.3.7 "Timer alternate function remapping" in RM0008 Rev 20.

Finally, here is a complete example for two channels:

use stm32f1xx_hal::stm32::TIM3;
use stm32f1xx_hal::gpio::gpiob::{PB4, PB5};
use stm32f1xx_hal::gpio::{Alternate, PushPull};
use stm32f1xx_hal::pwm::{Pins, Pwm, C1, C2, C3, C4};

struct MyChannels(PB4<Alternate<PushPull>>,  PB5<Alternate<PushPull>>);

impl Pins<TIM3> for MyChannels
{
  const REMAP: u8 = 0b10;
  const C1: bool = true;
  const C2: bool = true;
  const C3: bool = false;
  const C4: bool = false;
  type Channels = (Pwm<TIM3, C1>, Pwm<TIM3, C2>)
}

...

let gpiob = ..; // Set up and split GPIOB

let p1 = gpiob.pb4.into_alternate_push_pull(&mut gpiob.crl);
let p2 = gpiob.pb5.into_alternate_push_pull(&mut gpiob.crl);

...

let device: pac::Peripherals = ..;

let (mut c1, mut c2) = device.TIM3.pwm(
    MyChannels(p1, p2),
    &mut afio.mapr,
    100.hz(),
    clocks,
    &mut rcc.apb1
);

// Set the duty cycle of channels C1 and C2 to 50% and 25% respectively
c1.set_duty(c1.get_max_duty() / 2);
c2.set_duty(c2.get_max_duty() / 4);

// PWM outputs are disabled by default
c1.enable()
c2.enable()

Structs

C1
C2
C3
C4
Pwm

Traits

Pins
PwmExt