From af2d39bb018122076f017e51ba518b94cf13ab4f Mon Sep 17 00:00:00 2001 From: Nicolas Raynaud Date: Mon, 4 Feb 2019 13:32:46 -0700 Subject: [PATCH 1/3] add warning about timer interrupts. --- src/timer.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/timer.rs b/src/timer.rs index 86707d721..00f3098ab 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -34,6 +34,8 @@ impl Timer { } /// Starts listening for an `event` + /// You *have* to call `wait()` from your event handler to clear the interrupt flag (UIF), + /// otherwise the interrupt handler will execute continuously. pub fn listen(&mut self, event: Event) { match event { Event::Update => self.tim.enable_interrupt(), From 2645a150aad286d3bc3fdcdbc581c17692bf81ec Mon Sep 17 00:00:00 2001 From: Nicolas Raynaud Date: Mon, 4 Feb 2019 14:04:42 -0700 Subject: [PATCH 2/3] expose pre-divided Timer clock speeds in rcc.Clocks --- src/pwm.rs | 2 +- src/rcc.rs | 10 ++++++++++ src/timer.rs | 23 ++--------------------- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index cd09c6fc4..3d634e18e 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -208,7 +208,7 @@ macro_rules! hal { .modify(|_, w| w.oc4pe().set_bit().oc4m().pwm1()); } - let clk = clocks.pclk1().0 * if clocks.ppre1() == 1 { 1 } else { 2 }; + let clk = clocks.pclk1_tim().0; let freq = freq.0; let ticks = clk / freq; let psc = u16(ticks / (1 << 16)).unwrap(); diff --git a/src/rcc.rs b/src/rcc.rs index e39696f6c..868b8f467 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -318,11 +318,21 @@ impl Clocks { self.pclk1 } + /// Returns the frequency of the APB1 Timers + pub fn pclk1_tim(&self) -> Hertz { + Hertz(self.pclk1.0 * if self.ppre1() == 1 { 1 } else { 2 }) + } + /// Returns the frequency of the APB2 pub fn pclk2(&self) -> Hertz { self.pclk2 } + /// Returns the frequency of the APB2 Timers + pub fn pclk2_tim(&self) -> Hertz { + Hertz(self.pclk2.0 * if self.ppre2() == 1 { 1 } else { 2 }) + } + pub(crate) fn ppre1(&self) -> u8 { self.ppre1 } diff --git a/src/timer.rs b/src/timer.rs index 00f3098ab..48c3f3a9b 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -113,28 +113,9 @@ macro_rules! hal { /// Return the bus clock frequency in hertz. fn get_bus_clock(&self) -> Hertz { if TypeId::of::<$apbX>() == TypeId::of::() { - Hertz(self.clocks.pclk1().0 * self.get_bus_frequency_multiplier()) + self.clocks.pclk1_tim() } else if TypeId::of::<$apbX>() == TypeId::of::() { - Hertz(self.clocks.pclk2().0 * self.get_bus_frequency_multiplier()) - } else { - unreachable!() - } - } - - /// Return the bus frequency multiplier. - fn get_bus_frequency_multiplier(&self) -> u32 { - if TypeId::of::<$apbX>() == TypeId::of::() { - if self.clocks.ppre1() == 1 { - 1 - } else { - 2 - } - } else if TypeId::of::<$apbX>() == TypeId::of::() { - if self.clocks.ppre2() == 1 { - 1 - } else { - 2 - } + self.clocks.pclk2_tim() } else { unreachable!() } From 9f132cd3a8a95d0b726f925c239fad6e74b60d76 Mon Sep 17 00:00:00 2001 From: Nicolas Raynaud Date: Mon, 4 Feb 2019 14:29:50 -0700 Subject: [PATCH 3/3] add variable frequency pwm, implementing the embedded_hal::Pwm trait --- src/lib.rs | 1 + src/pwm2.rs | 351 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 352 insertions(+) create mode 100644 src/pwm2.rs diff --git a/src/lib.rs b/src/lib.rs index 34e4ccd18..34151979d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,6 +55,7 @@ pub mod gpio; pub mod i2c; pub mod prelude; pub mod pwm; +pub mod pwm2; pub mod qei; pub mod rcc; pub mod serial; diff --git a/src/pwm2.rs b/src/pwm2.rs new file mode 100644 index 000000000..969a43a0b --- /dev/null +++ b/src/pwm2.rs @@ -0,0 +1,351 @@ +use core::marker::PhantomData; + +use cast::{u16, u32}; +use crate::device::{TIM1, TIM2, TIM3, TIM4, tim2, tim1}; +use crate::gpio::gpioa::{PA0, PA1, PA2, PA3, PA6, PA7, PA8, PA9, PA10, PA11, PA15}; +use crate::gpio::gpiob::{PB0, PB1, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PB10, PB11}; +use crate::afio::MAPR; +use crate::bb; +use crate::rcc::{APB1, APB2, Clocks}; +use crate::gpio::Alternate; +use crate::time::{U32Ext, Hertz}; + +pub trait PwmTrait: Sized + where MAPPING: TimChannelsMapping, + REGISTERBLOCK: TimRegisterType { + fn create_pwm(&self, clocks: Clocks, _pins: MAPPING, apb: &mut BUS, mapr: &mut MAPR) + -> PwmTimer { + self.enable_and_reset_tim(apb); + self.configure_pin_mapping(mapr); + >::get_register_block().configure(); + PwmTimer { + _tim: PhantomData, + _bus: PhantomData, + _mapping: PhantomData, + _register: PhantomData, + clock_freq: Self::get_tim_clock_freq(clocks), + } + } + fn enable_and_reset_tim(&self, apb: &mut BUS); + fn configure_pin_mapping(&self, mapr: &mut MAPR); + fn get_tim_clock_freq(clocks: Clocks) -> Hertz { + // by default we return the apb1 clocks because it's the bus with most timers + clocks.pclk1_tim() + } + fn write_ccer(ccer_bit: u8, value: bool) { + >::get_register_block().write_ccer(ccer_bit, value) + } + fn get_period(clock_freq: u32) -> u32 { + clock_freq / >::get_register_block().get_clock_division() + } + fn get_register_block<'a>() -> &'a REGISTERBLOCK; +} + +pub trait TimerMapping { + type Channels; +} + +pub struct PwmTimer { + _tim: PhantomData, + _bus: PhantomData, + _mapping: PhantomData, + _register: PhantomData, + clock_freq: Hertz, +} + +pub enum Channel { _1, _2, _3, _4 } + +impl PwmTimer + where TIM: PwmTrait, + MAPPING: TimChannelsMapping, + REGISTERBLOCK: TimRegisterType { + fn channel_to_ccer_bit(channel: Channel) -> u8 { + match channel { + Channel::_1 => 0u8, + Channel::_2 => 4u8, + Channel::_3 => 8u8, + Channel::_4 => 12u8, + } + } +} + +impl crate::hal::Pwm for PwmTimer + where TIM: PwmTrait, + MAPPING: TimChannelsMapping, + REGISTERBLOCK: TimRegisterType { + type Channel = Channel; + type Time = Hertz; + type Duty = u16; + + fn disable(&mut self, channel: Self::Channel) { + TIM::write_ccer(Self::channel_to_ccer_bit(channel), false); + } + + fn enable(&mut self, channel: Self::Channel) { + TIM::write_ccer(Self::channel_to_ccer_bit(channel), true); + } + + fn get_period(&self) -> Self::Time { + TIM::get_period(self.clock_freq.0).hz() + } + + fn get_duty(&self, channel: Self::Channel) -> Self::Duty { + TIM::get_register_block().get_channel_duty(channel) + } + + fn get_max_duty(&self) -> Self::Duty { + TIM::get_register_block().get_counter_autoreload() + } + + fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { + TIM::get_register_block().set_channel_duty(channel, duty) + } + + fn set_period

(&mut self, period: P) where + P: Into { + let ticks = self.clock_freq.0 / period.into().0; + let psc = u16(ticks / (1 << 16)).unwrap(); + TIM::get_register_block().write_prescaler(psc); + let arr = u16(ticks / u32(psc + 1)).unwrap(); + TIM::get_register_block().write_counter_autoreload(arr); + } +} + +pub trait TimChannelsMapping: Sized { + const MAPPING: u8; +} + +// this trait unifies Advanced Control timers and General-purpose timers +pub trait TimRegisterType { + fn get_counter_autoreload(&self) -> u16; + fn get_clock_division(&self) -> u32; + fn write_ccer(&self, ccer_bits: u8, value: bool); + fn write_prescaler(&self, value: u16); + fn write_counter_autoreload(&self, value: u16); + fn configure(&self); + fn set_channel_duty(&self, channel: Channel, value: u16); + fn get_channel_duty(&self, channel: Channel) -> u16; +} + +impl TimRegisterType for tim2::RegisterBlock { + fn get_counter_autoreload(&self) -> u16 { + self.arr.read().arr().bits() + } + fn get_clock_division(&self) -> u32 { + (u32(self.psc.read().psc().bits()) + 1) + * (u32(self.get_counter_autoreload()) + 1) + } + fn write_ccer(&self, ccer_bits: u8, value: bool) { + bb::write(&self.ccer, ccer_bits, value) + } + fn write_prescaler(&self, value: u16) { + self.psc.write(|w| w.psc().bits(value)); + } + fn write_counter_autoreload(&self, value: u16) { + self.arr.write(|w| w.arr().bits(value)); + } + fn configure(&self) { + self.ccmr1_output.modify(|_, w| w.oc1pe().set_bit().oc1m().pwm1()); + self.ccmr1_output.modify(|_, w| w.oc2pe().set_bit().oc2m().pwm1()); + self.ccmr2_output.modify(|_, w| w.oc3pe().set_bit().oc3m().pwm1()); + self.ccmr2_output.modify(|_, w| w.oc4pe().set_bit().oc4m().pwm1()); + self.cr1.write(|w| unsafe { + w.cms().bits(0b00).dir().up().opm().continuous().cen().enabled() + }); + } + fn set_channel_duty(&self, channel: Channel, value: u16) { + match channel { + Channel::_1 => { self.ccr1.write(|w| w.ccr1().bits(value)) } + Channel::_2 => { self.ccr2.write(|w| w.ccr2().bits(value)) } + Channel::_3 => { self.ccr3.write(|w| w.ccr3().bits(value)) } + Channel::_4 => { self.ccr4.write(|w| w.ccr4().bits(value)) } + } + } + fn get_channel_duty(&self, channel: Channel) -> u16 { + match channel { + Channel::_1 => self.ccr1.read().ccr1().bits(), + Channel::_2 => self.ccr2.read().ccr2().bits(), + Channel::_3 => self.ccr3.read().ccr3().bits(), + Channel::_4 => self.ccr4.read().ccr4().bits() + } + } +} + +impl TimRegisterType for tim1::RegisterBlock { + fn get_counter_autoreload(&self) -> u16 { + self.arr.read().arr().bits() + } + fn get_clock_division(&self) -> u32 { + (u32(self.psc.read().psc().bits()) + 1) + * (u32(self.get_counter_autoreload()) + 1) + } + fn write_ccer(&self, ccer_bits: u8, value: bool) { + bb::write(&self.ccer, ccer_bits, value) + } + fn write_prescaler(&self, value: u16) { + self.psc.write(|w| w.psc().bits(value)); + } + fn write_counter_autoreload(&self, value: u16) { + self.arr.write(|w| w.arr().bits(value)); + } + fn configure(&self) { + self.ccmr1_output.modify(|_, w| w.oc1pe().set_bit().oc1m().pwm1()); + self.ccmr1_output.modify(|_, w| w.oc2pe().set_bit().oc2m().pwm1()); + self.ccmr2_output.modify(|_, w| w.oc3pe().set_bit().oc3m().pwm1()); + self.ccmr2_output.modify(|_, w| w.oc4pe().set_bit().oc4m().pwm1()); + self.cr1.write(|w| unsafe { + w.cms().bits(0b00).dir().up().opm().continuous().cen().enabled() + }); + } + fn set_channel_duty(&self, channel: Channel, value: u16) { + match channel { + Channel::_1 => { self.ccr1.write(|w| w.ccr1().bits(value)) } + Channel::_2 => { self.ccr2.write(|w| w.ccr2().bits(value)) } + Channel::_3 => { self.ccr3.write(|w| w.ccr3().bits(value)) } + Channel::_4 => { self.ccr4.write(|w| w.ccr4().bits(value)) } + } + } + fn get_channel_duty(&self, channel: Channel) -> u16 { + match channel { + Channel::_1 => self.ccr1.read().ccr1().bits(), + Channel::_2 => self.ccr2.read().ccr2().bits(), + Channel::_3 => self.ccr3.read().ccr3().bits(), + Channel::_4 => self.ccr4.read().ccr4().bits() + } + } +} + +// TIM1 //////////////////////// +pub type Pwm1Mapping0 = (Option>>, + Option>>, + Option>>, + Option>>); +pub type PWM1 = PwmTimer; + +impl TimChannelsMapping for Pwm1Mapping0 +{ const MAPPING: u8 = 0; } + +impl PwmTrait for TIM1 + where T: TimChannelsMapping { + fn enable_and_reset_tim(&self, apb: &mut APB2) { + apb.enr().modify(|_, w| w.tim1en().enabled()); + apb.rstr().modify(|_, w| w.tim1rst().set_bit()); + apb.rstr().modify(|_, w| w.tim1rst().clear_bit()); + } + + fn configure_pin_mapping(&self, mapr: &mut MAPR) { + mapr.mapr().modify(|_, w| unsafe { w.tim1_remap().bits(T::MAPPING) }); + } + fn get_tim_clock_freq(clocks: Clocks) -> Hertz { + clocks.pclk2_tim() + } + fn get_register_block<'a>() -> &'a tim1::RegisterBlock { + unsafe { &(*TIM1::ptr()) } + } +} + +// TIM2 //////////////////////// +pub type Pwm2Mapping0 = (Option>>, + Option>>, + Option>>, + Option>>); +pub type Pwm2Mapping01 = (Option>>, + Option>>, + Option>>, + Option>>); +pub type Pwm2Mapping10 = (Option>>, + Option>>, + Option>>, + Option>>); +pub type Pwm2Mapping11 = (Option>>, + Option>>, + Option>>, + Option>>); + +pub type PWM2 = PwmTimer; + +impl TimChannelsMapping for Pwm2Mapping0 +{ const MAPPING: u8 = 0; } + +impl TimChannelsMapping for Pwm2Mapping01 +{ const MAPPING: u8 = 0b01; } + +impl TimChannelsMapping for Pwm2Mapping10 +{ const MAPPING: u8 = 0b10; } + +impl TimChannelsMapping for Pwm2Mapping11 +{ const MAPPING: u8 = 0b11; } + +impl PwmTrait for TIM2 + where T: TimChannelsMapping { + fn enable_and_reset_tim(&self, apb: &mut APB1) { + apb.enr().modify(|_, w| w.tim2en().enabled()); + apb.rstr().modify(|_, w| w.tim2rst().set_bit()); + apb.rstr().modify(|_, w| w.tim2rst().clear_bit()); + } + fn configure_pin_mapping(&self, mapr: &mut MAPR) { + mapr.mapr().modify(|_, w| unsafe { w.tim2_remap().bits(T::MAPPING) }); + } + fn get_register_block<'a>() -> &'a tim2::RegisterBlock { + unsafe { &(*TIM2::ptr()) } + } +} + +// TIM3 //////////////////////// +pub type Pwm3Mapping0 = (Option>>, + Option>>, + Option>>, + Option>>); + +pub type Pwm3Mapping10 = (Option>>, + Option>>, + Option>>, + Option>>); +pub type PWM3 = PwmTimer; + +impl TimChannelsMapping for Pwm3Mapping0 +{ const MAPPING: u8 = 0; } + +impl TimChannelsMapping for Pwm3Mapping10 +{ const MAPPING: u8 = 0b10; } + +impl PwmTrait for TIM3 + where T: TimChannelsMapping { + fn enable_and_reset_tim(&self, apb: &mut APB1) { + apb.enr().modify(|_, w| w.tim3en().enabled()); + apb.rstr().modify(|_, w| w.tim3rst().set_bit()); + apb.rstr().modify(|_, w| w.tim3rst().clear_bit()); + } + fn configure_pin_mapping(&self, mapr: &mut MAPR) { + mapr.mapr().modify(|_, w| unsafe { w.tim3_remap().bits(T::MAPPING) }); + } + fn get_register_block<'a>() -> &'a tim2::RegisterBlock { + unsafe { &(*TIM3::ptr()) } + } +} + +// TIM4 //////////////////////// +pub type Pwm4Mapping0 = (Option>>, + Option>>, + Option>>, + Option>>); +pub type PWM4 = PwmTimer; + +impl TimChannelsMapping for Pwm4Mapping0 +{ const MAPPING: u8 = 0; } + +impl PwmTrait for TIM4 + where T: TimChannelsMapping { + fn enable_and_reset_tim(&self, apb: &mut APB1) { + apb.enr().modify(|_, w| w.tim4en().enabled()); + apb.rstr().modify(|_, w| w.tim4rst().set_bit()); + apb.rstr().modify(|_, w| w.tim4rst().clear_bit()); + } + fn configure_pin_mapping(&self, mapr: &mut MAPR) { + mapr.mapr().modify(|_, w| w.tim4_remap().bit(T::MAPPING != 0)); + } + + fn get_register_block<'a>() -> &'a tim2::RegisterBlock { + unsafe { &(*TIM4::ptr()) } + } +} \ No newline at end of file