diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f2082df..b99f3e44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,15 +9,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- `count_down` constructor for `Timer` -> `CountDownTimer` without start [#382] - Implementation of RTIC Monotonic for TIM2 & TIM5 under `rtic` feature [#380] - `IoPin` for `Output> <-> Input>` [#374] +[#382]: https://github.com/stm32-rs/stm32f4xx-hal/pull/382 [#380]: https://github.com/stm32-rs/stm32f4xx-hal/pull/380 [#374]: https://github.com/stm32-rs/stm32f4xx-hal/pull/374 ### Changed -- [breaking-change] Remove all deprecated - [breaking-change] Bump `stm32f4` to 0.14. Update RTIC based examples to use `rtic` 0.6 [#367] - [breaking-change] Bump `bxcan` to 0.6 [#371] diff --git a/examples/analog-stopwatch-with-spi-ssd1306.rs b/examples/analog-stopwatch-with-spi-ssd1306.rs index 4e06e60d..08d941be 100644 --- a/examples/analog-stopwatch-with-spi-ssd1306.rs +++ b/examples/analog-stopwatch-with-spi-ssd1306.rs @@ -127,7 +127,8 @@ fn main() -> ! { disp.flush().unwrap(); // Create a 1ms periodic interrupt from TIM2 - let mut timer = Timer::new(dp.TIM2, &clocks).start_count_down(1.hz()); + let mut timer = Timer::new(dp.TIM2, &clocks).count_down(); + timer.start(1.hz()); timer.listen(Event::TimeOut); free(|cs| { diff --git a/examples/blinky-timer-irq.rs b/examples/blinky-timer-irq.rs index 9f6c6731..0654e322 100644 --- a/examples/blinky-timer-irq.rs +++ b/examples/blinky-timer-irq.rs @@ -79,7 +79,8 @@ fn main() -> ! { cortex_m::interrupt::free(|cs| *G_LED.borrow(cs).borrow_mut() = Some(led)); // Set up a timer expiring after 1s - let mut timer = Timer::new(dp.TIM2, &clocks).start_count_down(1.hz()); + let mut timer = Timer::new(dp.TIM2, &clocks).count_down(); + timer.start(1.hz()); // Generate an interrupt when the timer expires timer.listen(Event::TimeOut); diff --git a/examples/stopwatch-with-ssd1306-and-interrupts.rs b/examples/stopwatch-with-ssd1306-and-interrupts.rs index 0153a523..283ca90d 100644 --- a/examples/stopwatch-with-ssd1306-and-interrupts.rs +++ b/examples/stopwatch-with-ssd1306-and-interrupts.rs @@ -93,7 +93,8 @@ fn main() -> ! { disp.flush().unwrap(); // Create a 1ms periodic interrupt from TIM2 - let mut timer = Timer::new(dp.TIM2, &clocks).start_count_down(1.hz()); + let mut timer = Timer::new(dp.TIM2, &clocks).count_down(); + timer.start(1.hz()); timer.listen(Event::TimeOut); free(|cs| { diff --git a/examples/timer-periph.rs b/examples/timer-periph.rs index 00e10d26..55c37058 100644 --- a/examples/timer-periph.rs +++ b/examples/timer-periph.rs @@ -29,7 +29,8 @@ fn main() -> ! { let clocks = rcc.cfgr.sysclk(24.mhz()).freeze(); // Create a timer based on SysTick - let mut timer = Timer::new(dp.TIM1, &clocks).start_count_down(1.hz()); + let mut timer = Timer::new(dp.TIM1, &clocks).count_down(); + timer.start(1.hz()); hprintln!("hello!").unwrap(); // wait until timer expires diff --git a/examples/timer-syst.rs b/examples/timer-syst.rs index c9e91fad..36beb9bc 100644 --- a/examples/timer-syst.rs +++ b/examples/timer-syst.rs @@ -30,7 +30,8 @@ fn main() -> ! { let clocks = rcc.cfgr.sysclk(24.mhz()).freeze(); // Create a timer based on SysTick - let mut timer = Timer::syst(cp.SYST, &clocks).start_count_down(24.hz()); + let mut timer = Timer::syst(cp.SYST, &clocks).count_down(); + timer.start(24.hz()); hprintln!("hello!").unwrap(); // wait until timer expires diff --git a/src/delay/timer.rs b/src/delay/timer.rs index f6a011ac..534d1db8 100644 --- a/src/delay/timer.rs +++ b/src/delay/timer.rs @@ -8,7 +8,11 @@ use core::cmp::max; use cast::{u16, u32}; use embedded_hal::blocking::delay::{DelayMs, DelayUs}; -use crate::{pac, rcc::Clocks, timer::Timer}; +use crate::{ + pac, + rcc::Clocks, + timer::{General, Timer}, +}; use super::Delay; @@ -17,25 +21,23 @@ macro_rules! hal { $( fn $waitfn(tim: &mut $TIM, prescaler: u16, auto_reload_register: u32) { // Write Prescaler (PSC) - tim.psc.write(|w| w.psc().bits(prescaler)); + tim.set_prescaler(prescaler); // Write Auto-Reload Register (ARR) // Note: Make it impossible to set the ARR value to 0, since this // would cause an infinite loop. - tim.arr.write(|w| unsafe { w.bits(max(1, auto_reload_register)) }); + tim.set_auto_reload(max(1, auto_reload_register)).unwrap(); // Trigger update event (UEV) in the event generation register (EGR) // in order to immediately apply the config - tim.cr1.modify(|_, w| w.urs().set_bit()); - tim.egr.write(|w| w.ug().set_bit()); - tim.cr1.modify(|_, w| w.urs().clear_bit()); + tim.trigger_update(); // Configure the counter in one-pulse mode (counter stops counting at // the next updateevent, clearing the CEN bit) and enable the counter. tim.cr1.write(|w| w.opm().set_bit().cen().set_bit()); // Wait for CEN bit to clear - while tim.cr1.read().cen().is_enabled() { /* wait */ } + while tim.is_counter_enabled() { /* wait */ } } impl Timer<$TIM> { diff --git a/src/pwm.rs b/src/pwm.rs index 66c3142c..830cd906 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -1,5 +1,9 @@ -use crate::{bb, hal as pwm, time::Hertz, timer::Timer}; -use cast::{u16, u32}; +use crate::{ + bb, hal as pwm, + time::Hertz, + timer::{General, Timer}, +}; +use cast::u16; use core::{marker::PhantomData, mem::MaybeUninit}; pub trait Pins { @@ -112,19 +116,19 @@ macro_rules! pwm_pin { //NOTE(unsafe) atomic read with no side effects #[inline] pub fn get_duty(&self) -> u16 { - unsafe { (*<$TIMX>::ptr()).$ccr.read().ccr().bits() as u16 } + unsafe { (*<$TIMX>::ptr()).$ccr.read().bits() as u16 } } //NOTE(unsafe) atomic read with no side effects #[inline] pub fn get_max_duty(&self) -> u16 { - unsafe { (*<$TIMX>::ptr()).arr.read().arr().bits() as u16 } + unsafe { (*<$TIMX>::ptr()).arr.read().bits() as u16 } } //NOTE(unsafe) atomic write with no side effects #[inline] pub fn set_duty(&mut self, duty: u16) { - unsafe { (*<$TIMX>::ptr()).$ccr.write(|w| w.ccr().bits(duty.into())) } + unsafe { (*<$TIMX>::ptr()).$ccr.write(|w| w.bits(duty.into())) } } } @@ -153,7 +157,7 @@ macro_rules! pwm_all_channels { ($($TIMX:ident,)+) => { $( impl Timer { - pub fn pwm(self, _pins: PINS, freq: T) -> PINS::Channels + pub fn pwm(mut self, _pins: PINS, freq: T) -> PINS::Channels where PINS: Pins, T: Into, @@ -182,14 +186,12 @@ macro_rules! pwm_all_channels { let ticks = self.clk.0 / freq.into().0; let psc = (ticks - 1) / (1 << 16); - self.tim.psc.write(|w| w.psc().bits(u16(psc).unwrap()) ); - let arr = u16(ticks / (psc + 1)).unwrap(); - self.tim.arr.write(|w| unsafe { w.bits(u32(arr)) }); + self.tim.set_prescaler(u16(psc).unwrap()); + let arr = ticks / (psc + 1); + self.tim.set_auto_reload(arr).unwrap(); // Trigger update event to load the registers - self.tim.cr1.modify(|_, w| w.urs().set_bit()); - self.tim.egr.write(|w| w.ug().set_bit()); - self.tim.cr1.modify(|_, w| w.urs().clear_bit()); + self.tim.trigger_update(); let _tim = &self.tim; brk!($TIMX, _tim); @@ -220,7 +222,7 @@ macro_rules! pwm_2_channels { ($($TIMX:ident,)+) => { $( impl Timer { - pub fn pwm(self, _pins: PINS, freq: T) -> PINS::Channels + pub fn pwm(mut self, _pins: PINS, freq: T) -> PINS::Channels where PINS: Pins, T: Into, @@ -245,14 +247,12 @@ macro_rules! pwm_2_channels { let ticks = self.clk.0 / freq.into().0; let psc = (ticks - 1) / (1 << 16); - self.tim.psc.write(|w| w.psc().bits(u16(psc).unwrap()) ); - let arr = u16(ticks / (psc + 1)).unwrap(); - self.tim.arr.write(|w| unsafe { w.bits(u32(arr)) }); + self.tim.set_prescaler(u16(psc).unwrap()); + let arr = ticks / (psc + 1); + self.tim.set_auto_reload(arr).unwrap(); // Trigger update event to load the registers - self.tim.cr1.modify(|_, w| w.urs().set_bit()); - self.tim.egr.write(|w| w.ug().set_bit()); - self.tim.cr1.modify(|_, w| w.urs().clear_bit()); + self.tim.trigger_update(); self.tim.cr1.write(|w| w.opm() @@ -275,7 +275,7 @@ macro_rules! pwm_1_channel { ($($TIMX:ident,)+) => { $( impl Timer { - pub fn pwm(self, _pins: PINS, freq: T) -> PINS::Channels + pub fn pwm(mut self, _pins: PINS, freq: T) -> PINS::Channels where PINS: Pins, T: Into, @@ -295,14 +295,12 @@ macro_rules! pwm_1_channel { let ticks = self.clk.0 / freq.into().0; let psc = (ticks - 1) / (1 << 16); - self.tim.psc.write(|w| w.psc().bits(u16(psc).unwrap()) ); - let arr = u16(ticks / (psc + 1)).unwrap(); - self.tim.arr.write(|w| unsafe { w.bits(u32(arr)) }); + self.tim.set_prescaler(u16(psc).unwrap()); + let arr = ticks / (psc + 1); + self.tim.set_auto_reload(arr).unwrap(); // Trigger update event to load the registers - self.tim.cr1.modify(|_, w| w.urs().set_bit()); - self.tim.egr.write(|w| w.ug().set_bit()); - self.tim.cr1.modify(|_, w| w.urs().clear_bit()); + self.tim.trigger_update(); self.tim.cr1.write(|w| w.cen() @@ -318,133 +316,7 @@ macro_rules! pwm_1_channel { }; } -#[cfg(feature = "stm32f410")] -macro_rules! pwm_pin_tim5 { - ($TIMX:ty, $C:ty, $ccr: ident, $bit:literal) => { - impl PwmChannels<$TIMX, $C> { - //NOTE(unsafe) atomic write with no side effects - #[inline] - pub fn disable(&mut self) { - unsafe { bb::clear(&(*<$TIMX>::ptr()).ccer, 0) } - } - - //NOTE(unsafe) atomic write with no side effects - #[inline] - pub fn enable(&mut self) { - unsafe { bb::set(&(*<$TIMX>::ptr()).ccer, 0) } - } - - //NOTE(unsafe) atomic read with no side effects - #[inline] - pub fn get_duty(&self) -> u16 { - unsafe { (*<$TIMX>::ptr()).$ccr.read().ccr1_l().bits() as u16 } - } - - //NOTE(unsafe) atomic read with no side effects - #[inline] - pub fn get_max_duty(&self) -> u16 { - unsafe { (*<$TIMX>::ptr()).arr.read().arr_l().bits() as u16 } - } - - //NOTE(unsafe) atomic write with no side effects - #[inline] - pub fn set_duty(&mut self, duty: u16) { - unsafe { - (*<$TIMX>::ptr()) - .$ccr - .write(|w| w.ccr1_l().bits(duty.into())) - } - } - } - - impl pwm::PwmPin for PwmChannels<$TIMX, $C> { - type Duty = u16; - fn disable(&mut self) { - self.disable() - } - fn enable(&mut self) { - self.enable() - } - fn get_duty(&self) -> Self::Duty { - self.get_duty() - } - fn get_max_duty(&self) -> Self::Duty { - self.get_max_duty() - } - fn set_duty(&mut self, duty: Self::Duty) { - self.set_duty(duty) - } - } - }; -} - -#[cfg(feature = "stm32f410")] -macro_rules! pwm_tim5_f410 { - ($($TIMX:ident,)+) => { - $( - impl Timer { - pub fn pwm(self, _pins: PINS, freq: T) -> PINS::Channels - where - PINS: Pins, - T: Into, - { - if PINS::C1 { - self.tim.ccmr1_output() - .modify(|_, w| w.oc1pe().set_bit().oc1m().pwm_mode1() ); - } - if PINS::C2 { - self.tim.ccmr1_output() - .modify(|_, w| w.oc2pe().set_bit().oc2m().pwm_mode1() ); - } - if PINS::C3 { - self.tim.ccmr2_output() - .modify(|_, w| w.oc3pe().set_bit().oc3m().pwm_mode1() ); - } - if PINS::C4 { - self.tim.ccmr2_output() - .modify(|_, w| w.oc4pe().set_bit().oc4m().pwm_mode1() ); - } - - // The reference manual is a bit ambiguous about when enabling this bit is really - // necessary, but since we MUST enable the preload for the output channels then we - // might as well enable for the auto-reload too - self.tim.cr1.modify(|_, w| w.arpe().set_bit()); - - let ticks = self.clk.0 / freq.into().0; - let psc = (ticks - 1) / (1 << 16); - self.tim.psc.write(|w| w.psc().bits(u16(psc).unwrap()) ); - let arr = u16(ticks / (psc + 1)).unwrap(); - self.tim.arr.write(|w| unsafe { w.arr_l().bits(arr) }); - - // Trigger update event to load the registers - self.tim.cr1.modify(|_, w| w.urs().set_bit()); - self.tim.egr.write(|w| w.ug().set_bit()); - self.tim.cr1.modify(|_, w| w.urs().clear_bit()); - - self.tim.cr1.write(|w| - w.cms() - .bits(0b00) - .dir() - .clear_bit() - .opm() - .clear_bit() - .cen() - .set_bit() - ); - //NOTE(unsafe) `PINS::Channels` is a ZST - unsafe { MaybeUninit::uninit().assume_init() } - } - } - - pwm_pin_tim5!(crate::pac::$TIMX, C1, ccr1, 0); - pwm_pin_tim5!(crate::pac::$TIMX, C2, ccr2, 4); - pwm_pin_tim5!(crate::pac::$TIMX, C3, ccr3, 8); - pwm_pin_tim5!(crate::pac::$TIMX, C4, ccr4, 12); - )+ - }; -} - -pwm_all_channels!(TIM1,); +pwm_all_channels!(TIM1, TIM5,); pwm_2_channels!(TIM9,); @@ -468,7 +340,7 @@ pwm_1_channel!(TIM11,); feature = "stm32f469", feature = "stm32f479" ))] -pwm_all_channels!(TIM2, TIM3, TIM4, TIM5,); +pwm_all_channels!(TIM2, TIM3, TIM4,); #[cfg(any( feature = "stm32f401", @@ -543,6 +415,3 @@ pwm_2_channels!(TIM12,); feature = "stm32f479" ))] pwm_1_channel!(TIM13, TIM14,); - -#[cfg(feature = "stm32f410")] -pwm_tim5_f410!(TIM5,); diff --git a/src/pwm_input.rs b/src/pwm_input.rs index 02cbbd1e..194c3fd1 100644 --- a/src/pwm_input.rs +++ b/src/pwm_input.rs @@ -1,6 +1,6 @@ use crate::{ time::Hertz, - timer::{PinC1, Timer}, + timer::{General, PinC1, Timer}, }; use cast::u16; @@ -42,7 +42,7 @@ pub struct PwmInput> { #[cfg(not(feature = "stm32f410"))] macro_rules! hal { - ($($TIM:ident: ($bits:ident),)+) => { + ($($TIM:ident,)+) => { $( // Drag the associated TIM object into scope. // Note: its drawn in via the macro to avoid duplicating the feature gate this macro is @@ -59,7 +59,7 @@ macro_rules! hal { /// 2. When the period is captured. the duty cycle will be an observable value. /// See the pwm input example for an suitable interrupt handler. #[allow(unused_unsafe)] //for some chips the operations are considered safe. - pub fn pwm_input(self, best_guess: T, pins: PINS) -> PwmInput<$TIM, PINS> + pub fn pwm_input(mut self, best_guess: T, pins: PINS) -> PwmInput<$TIM, PINS> where T: Into, PINS: Pins<$TIM>, @@ -71,7 +71,7 @@ macro_rules! hal { */ let ticks = self.clk.0 / best_guess.into().0; let psc = u16((ticks - 1) / (1 << 16)).unwrap(); - self.tim.psc.write(|w| w.psc().bits(psc)); + self.tim.set_prescaler(psc); // Seemingly this needs to be written to // self.tim.arr.write(|w| w.arr().bits(u16::MAX)); @@ -137,7 +137,7 @@ macro_rules! hal { // enable interrupts. self.tim.dier.modify(|_, w| w.cc2ie().set_bit()); // enable the counter. - self.tim.cr1.modify(|_, w| w.cen().enabled()); + self.tim.enable_counter(); let Self { tim, clk } = self; @@ -158,11 +158,11 @@ macro_rules! hal { (Timer { tim, clk }, pins) } /// Period of PWM signal in terms of clock cycles - pub fn get_period_clocks(&self) -> $bits { + pub fn get_period_clocks(&self) -> <$TIM as General>::Width { self.tim.ccr1.read().ccr().bits() } /// Duty cycle in terms of clock cycles - pub fn get_duty_cycle_clocks(&self) -> $bits { + pub fn get_duty_cycle_clocks(&self) -> <$TIM as General>::Width { self.tim.ccr2.read().ccr().bits() } /// Observed duty cycle as a float in range [0.00, 1.00] @@ -186,9 +186,9 @@ macro_rules! hal { #[cfg(any(feature = "stm32f411",))] /* red group */ hal! { - TIM4: (u16), - TIM3: (u16), - TIM2: (u32), + TIM4, + TIM3, + TIM2, } /* orange group */ @@ -210,9 +210,9 @@ hal! { feature = "stm32f479", ))] hal! { - TIM2: (u32), - TIM3: (u16), - TIM4: (u16), + TIM2, + TIM3, + TIM4, } /* green group */ #[cfg(any( @@ -232,8 +232,8 @@ hal! { feature = "stm32f479", ))] hal! { - TIM8: (u16), - TIM12: (u16), + TIM8, + TIM12, } /* every chip across the series have these timers with support for this feature. @@ -243,7 +243,7 @@ hal! { /* yellow group */ #[cfg(not(feature = "stm32f410"))] hal! { - TIM1: (u16), - TIM5: (u32), - TIM9: (u16), + TIM1, + TIM5, + TIM9, } diff --git a/src/timer.rs b/src/timer.rs index 2ab2b002..c4c18db1 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -3,7 +3,7 @@ //! Pins can be used for PWM output in both push-pull mode (`Alternate`) and open-drain mode //! (`AlternateOD`). -use cast::{u16, u32}; +use cast::u16; use cortex_m::peripheral::syst::SystClkSource; use cortex_m::peripheral::{DCB, DWT, SYST}; use embedded_hal::timer::{Cancel, CountDown, Periodic}; @@ -30,6 +30,14 @@ pub struct CountDownTimer { clk: Hertz, } +impl Timer { + /// Creates CountDownTimer + pub fn count_down(self) -> CountDownTimer { + let Self { tim, clk } = self; + CountDownTimer { tim, clk } + } +} + impl Timer where CountDownTimer: CountDown