I can't get PWM to work on the STM32F3Discovery ( Solved )

Edit, the solution is at the bottom The code is ugly but it works, I will update with a nicer version once I get around to refactoring.

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()) }
}

Ugly working example
revised main.rs:
#![no_main]
#![no_std]

use aux8::entry;

#[inline(never)]
fn delay(ms: u16) {
    for _ 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());

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

    tim1.ccmr1_output.modify(|_r, w| w.oc1m().bits(6));

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

    // Set frequency
    tim1.arr.write(|w| w.arr().bits(10));

    // Set duty cycle
    tim1.ccr1.write(|w| w.ccr1().bits(2));

    // Enable OCx output, and set polarity.
    tim1.ccer.modify(|_r, w| w.cc1e().set_bit());

    // INIT pwm channel
    // Enable auto reload
    tim1.cr1.modify(
        |_r, w| w.cen().set_bit(), //        .arpe().set_bit()
    );
    tim1.bdtr.modify(|_, w| w.moe().set_bit());

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

    // Set alternate function for PE9 to AF2.
    gpioe.moder.modify(|_, w| w.moder9().alternate());
    gpioe.afrh.modify(|_, w| w.afrh9().bits(0b0010));

    loop {
        for i in 0..10 {
            tim1.ccr1.write(|w| w.ccr1().bits(i));
            delay(2000);
        }

        for i in 0..10 {
            tim1.ccr1.write(|w| w.ccr1().bits(10 - i));
            delay(2000);
        }
    }
}
1 Like

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.

1 Like

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.)

2 Likes

Thanks for the input, I finally managed to get it working.
I noticed there is an example https://github.com/stm32-rs/stm32f3xx-hal/blob/master/examples/pwm.rs aswell.

@jmintb bro i am new to rust, [https://github.com/stm32-rs/stm32f3xx-hal/blob/master/examples/pwm.rs ] i am using this code for pwm but there is an error and i am unable to get rid of it, the error says "This crate requires one of the following device features enabled". Please help how to enable my stm32f30x

Post a new question. That's unrelated to this question.

Look in Cargo.toml to see which features are required to run the examples. For example you can build the pwm example with cargo build --example pwm --features stm32f303xc

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.