I can't get PWM to work on the STM32F3Discovery

Hi,
I am having some trouble with getting PWM to work on the STM32F3Discovery.

So fare I can get a timer to count and then manually switch leds on/off, but I can't get any pins or leds to properly function in alternate mode where it is "directly activated" by the timer.

Has anyone been able to get a PWM signal to control any pins/leds on the STM32F3Discovery?

In the below code I manually switch on/off the LED connected to PE15 according to the counter for TIM1,
and I have configured PE9 so it should react to the PWM generated by TIM1, but it doesn't.
My current code looks like this:
main.rs:

#![no_main]
#![no_std]

use aux8::{entry, Timer};
use aux8::gpioc::afrl::AFRL2R;

#[inline(never)]
fn delay(ms: u16) {
    for i in 0..ms {}
}

#[entry]
unsafe fn main() -> ! {
    let (gpioe, rcc, tim1) = aux8::init();
    /// Init LEDs
    // Initialize IO pin and set it to alternate mode.
    rcc.ahbenr.modify(|_, w| w.iopeen().set_bit());
    // Set alternate function for PE9 to AF2.
    gpioe.afrh.write(|w| w.afrh9().bits(0010));
    gpioe.pupdr.write(|w| w.pupdr9().bits(00));
    gpioe.otyper.write(|w| w.ot9().set_bit());
    gpioe.ospeedr.write(|w| w.ospeedr9().bits(11));
    gpioe.moder.write(|w| w.moder9().alternate().moder15().output().moder10().output());

    /// INIT timer
    // Initialize tim1
    rcc.apb2enr.modify(|_, w| w.tim1en().set_bit());

    // Set prescaler
    tim1.psc.write(|w| w.psc().bits(7999));

    // Set frequency
    tim1.arr.write(|w| unsafe { w.arr().bits(2000- 1)});

    // Set duty cycle
    tim1.ccr1.write(|w| unsafe { w.ccr1().bits(1000 - 1)});

    // Set clock
    // tim1.cr1.write(|w| w.ckd().bits(00));

    /// INIT pwm channel

    // Enable OCx output, and set polarity.
    tim1.ccer.write(|w| w.cc1e().set_bit().cc1p().clear_bit());

    // Initialize all registers
    tim1.egr.write(|w| w.ug().set_bit());

    // Set pwm mode to mode 1
    tim1.ccmr1_output.write(|w| unsafe { w.oc1m().bits(0110) }.oc1pe().set_bit());

    // Enable auto reload
    tim1.cr1.write(|w| w.dir().clear_bit().arpe().set_bit().cen().clear_bit());

    // Set counter to 0
    tim1.cnt.write(|w| w.cnt().bits(0));

    // Enable counter
    tim1.cr1.write(|w| w.cen().set_bit());

    loop {
        if tim1.cnt.read().bits() < tim1.ccr1.read().bits(){
            gpioe.odr.write(|w| w.odr15().set_bit());
        } else {
            gpioe.odr.write(|w| w.odr15().clear_bit());
        }
    }
}

lib.rs:

//! Initialization code
#![no_std]

#[allow(unused_extern_crates)] // NOTE(allow) bug rust-lang/rust#53964 
extern crate panic_itm; // panic handler

pub use cortex_m::asm::bkpt;
pub use cortex_m_rt::entry;
pub use f3::hal::stm32f30x::{gpioc, rcc, tim1};
pub use f3::hal::timer::Timer;

use f3::hal::stm32f30x::{self, GPIOE, RCC, TIM1};

pub fn init() -> (&'static gpioc::RegisterBlock, &'static rcc::RegisterBlock, &'static tim1::RegisterBlock)     {
     // restrict access to the other peripherals
    (stm32f30x::Peripherals::take().unwrap());

    unsafe { (&*GPIOE::ptr(), &*RCC::ptr(), &*TIM1::ptr()) }
}

I am also trying to do PWM on the discovery board after going through the Discovery tutorial, and I have not found any helpful resources about doing PWM with Rust. If anybody knowledgeable could point me in the right direction, I would be grateful!

@jmintb I found that the copterust project has an alternate implementation of the HAL for the STM32F3Discovery board here with an example of how to use the PWM interface here. I haven't tried this yet, but it looks promising.

You're not setting the alternate function to AF2, you're setting it to AF10. 0010 is a decimal number. You probably meant 0b0010. (Or just 2, which is what I'd do.)

1 Like