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