From 07e12217c6197b41dc21d92f41b8ed1d3a9bd901 Mon Sep 17 00:00:00 2001 From: thalesfragoso Date: Sun, 4 Aug 2019 23:42:25 -0300 Subject: [PATCH 1/6] New timer methods --- CHANGELOG.md | 3 ++- src/timer.rs | 21 ++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42c5a602..b70ce4d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,12 +38,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Replace gpio traits with digital::v2 - Bump `stm32f1` dependency (`0.8.0`) -- ADC now requires the clock configuration for intialisation +- ADC now requires the clock configuration for initialisation - `disable_jtag` now transforms PA15, PB3 and PB4 to forbid their use without desactivating JTAG ### Changed - Fix hclk miscalculation +- Starting the timer does not generate interrupt requests anymore ## [v0.3.0] - 2019-04-27 diff --git a/src/timer.rs b/src/timer.rs index 6711c369..f48a35e6 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -173,6 +173,21 @@ macro_rules! hal { pub fn release(self) -> $TIMX { self.stop().release() } + + /// Returns the current counter value + pub fn count(&self) -> u16 { + self.tim.cnt.read().cnt().bits() + } + + /// Resets the counter and generates an update event + pub fn reset(&mut self) { + // Sets the URS bit to prevent an interrupt from being triggered by + // the UG bit. + 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()); + } } impl CountDown for CountDownTimer<$TIMX> { @@ -197,11 +212,7 @@ macro_rules! hal { self.tim.arr.write(|w| w.arr().bits(arr) ); // Trigger an update event to load the prescaler value to the clock - self.tim.egr.write(|w| w.ug().set_bit()); - // The above line raises an update event which will indicate - // that the timer is already finished. Since this is not the case, - // it should be cleared - self.clear_update_interrupt_flag(); + self.reset(); // start counter self.tim.cr1.modify(|_, w| w.cen().set_bit()); From a10e734ddd3a579ede7be88e7bcbbcd38023d1dc Mon Sep 17 00:00:00 2001 From: thalesfragoso Date: Tue, 6 Aug 2019 21:04:12 -0300 Subject: [PATCH 2/6] Adds micros_since method to timers --- src/timer.rs | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/timer.rs b/src/timer.rs index f48a35e6..f2903b8e 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -2,7 +2,7 @@ use crate::hal::timer::{CountDown, Periodic}; use crate::pac::{DBGMCU as DBG, TIM1, TIM2, TIM3, TIM4}; -use cast::{u16, u32}; +use cast::{u16, u32, u64}; use cortex_m::peripheral::syst::SystClkSource; use cortex_m::peripheral::SYST; use nb; @@ -60,6 +60,26 @@ impl CountDownTimer { } } + /// Resets the timer + pub fn reset(&mut self) { + // According to the Cortex-M3 Generic User Guide, the interrupt request is only generated + // when the counter goes from 1 to 0, so writing zero should not trigger an interrupt + self.tim.clear_current(); + } + + /// Returns the number of microseconds since the last update event. + /// *NOTE:* This method is not a very good candidate to keep track of time, because + /// it is very easy to lose an update event. + pub fn micros_since(&self) -> u32 { + let reload_value = SYST::get_reload(); + let timer_clock = u64(self.clocks.sysclk().0); + let ticks = u64(reload_value - SYST::get_current()); + + // It is safe to make this cast since the maximum ticks is (2^24 - 1) and the minimum sysclk + // is 4Mhz, which gives a maximum period of ~4.2 seconds which is < (2^32 - 1) microsenconds + u32(1_000_000 * ticks / timer_clock).unwrap() + } + /// Stops the timer pub fn stop(&mut self) { self.tim.disable_counter(); @@ -174,15 +194,27 @@ macro_rules! hal { self.stop().release() } - /// Returns the current counter value - pub fn count(&self) -> u16 { - self.tim.cnt.read().cnt().bits() + /// Returns the number of microseconds since the last update event. + /// *NOTE:* This method is not a very good candidate to keep track of time, because + /// it is very easy to lose an update event. + pub fn micros_since(&self) -> u32 { + let timer_clock = $TIMX::get_clk(&self.clocks).0; + let psc = u32(self.tim.psc.read().psc().bits()); + + // freq_divider is always bigger than 0, since (psc + 1) is always less than + // timer_clock + let freq_divider = u64(timer_clock / (psc + 1)); + let cnt = u64(self.tim.cnt.read().cnt().bits()); + + // It is safe to make this cast, because the maximum timer period in this HAL is + // 1s (1Hz), then 1 second < (2^32 - 1) microseconds + u32(1_000_000 * cnt / freq_divider).unwrap() } /// Resets the counter and generates an update event pub fn reset(&mut self) { // Sets the URS bit to prevent an interrupt from being triggered by - // the UG bit. + // the UG bit self.tim.cr1.modify(|_, w| w.urs().set_bit()); self.tim.egr.write(|w| w.ug().set_bit()); From 8eed7006d49076a355c5f5929752657489b533fa Mon Sep 17 00:00:00 2001 From: thalesfragoso Date: Mon, 12 Aug 2019 22:55:49 -0300 Subject: [PATCH 3/6] adds select_frequency method to rtc --- CHANGELOG.md | 7 ++++++- src/rtc.rs | 21 +++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b70ce4d3..e782d737 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - DMA traits now require AsSlice instead of AsRef +- Add `micros_since` and `reset` methods to timer +- Add `select_frequency` method to rtc + +### Changed + +- Starting the timer does not generate interrupt requests anymore ## [v0.4.0] - 2019-08-09 @@ -44,7 +50,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - Fix hclk miscalculation -- Starting the timer does not generate interrupt requests anymore ## [v0.3.0] - 2019-04-27 diff --git a/src/rtc.rs b/src/rtc.rs index a12d66d6..67e726ab 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -15,6 +15,7 @@ use crate::pac::{RTC, RCC}; use crate::backup_domain::BackupDomain; +use crate::time::Hertz; use nb; use void::Void; @@ -70,7 +71,23 @@ impl Rtc { }) } - /// Set the current rtc value to the specified amount of seconds + /// Selects the frequency of the counter + /// NOTE: Maximum frequency of 16384 Hz using the internal LSE + pub fn select_frequency(&mut self, timeout: impl Into) { + let frequency = timeout.into().0; + + // The manual says that the zero value for the prescaler is not recommended, thus the + // minimum division factor is 2 (prescaler + 1) + assert!(frequency <= LSE_HERTZ / 2); + + let prescaler = LSE_HERTZ / frequency - 1; + self.perform_write( |s| { + s.regs.prlh.write(|w| unsafe { w.bits(prescaler >> 16) }); + s.regs.prll.write(|w| unsafe { w.bits(prescaler as u16 as u32) }); + }); + } + + /// Set the current rtc counter value to the specified amount pub fn set_seconds(&mut self, seconds: u32) { self.perform_write(|s| { s.regs.cnth.write(|w| unsafe{w.bits(seconds >> 16)}); @@ -111,7 +128,7 @@ impl Rtc { }) } - /// Reads the current time + /// Reads the current counter pub fn seconds(&self) -> u32 { // Wait for the APB1 interface to be ready while self.regs.crl.read().rsf().bit() == false {} From 1b6a080af1d4aae11b4d2f87e4a07844273790b3 Mon Sep 17 00:00:00 2001 From: thalesfragoso Date: Mon, 19 Aug 2019 22:59:27 -0300 Subject: [PATCH 4/6] Rename rtc methods --- CHANGELOG.md | 3 ++- examples/blinky_rtc.rs | 2 +- examples/rtc.rs | 2 +- src/rtc.rs | 5 ++--- src/timer.rs | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e782d737..7dfad468 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,12 +15,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Change timer/pwm init API - Remove `set_low` and `set_high` for pins in Alternate output mode +- Renames `set_seconds` and `seconds` methods on RTC to `set_time` and `current_time`, respectively ### Changed - DMA traits now require AsSlice instead of AsRef - Add `micros_since` and `reset` methods to timer -- Add `select_frequency` method to rtc +- Add `select_frequency` method to RTC ### Changed diff --git a/examples/blinky_rtc.rs b/examples/blinky_rtc.rs index 08ad7ecc..c9f37078 100644 --- a/examples/blinky_rtc.rs +++ b/examples/blinky_rtc.rs @@ -42,7 +42,7 @@ fn main() -> ! { let mut led_on = false; loop { // Set the current time to 0 - rtc.set_seconds(0); + rtc.set_time(0); // Trigger the alarm in 5 seconds rtc.set_alarm(5); block!(rtc.wait_alarm()).unwrap(); diff --git a/examples/rtc.rs b/examples/rtc.rs index 977b5c5c..538bfb75 100644 --- a/examples/rtc.rs +++ b/examples/rtc.rs @@ -26,6 +26,6 @@ fn main() -> ! { let rtc = Rtc::rtc(p.RTC, &mut backup_domain); loop { - hprintln!("time: {}", rtc.seconds()).unwrap(); + hprintln!("time: {}", rtc.current_time()).unwrap(); } } diff --git a/src/rtc.rs b/src/rtc.rs index 67e726ab..ad9726c1 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -31,7 +31,6 @@ pub struct Rtc { regs: RTC, } - impl Rtc { /** Initialises the RTC. The `BackupDomain` struct is created by @@ -88,7 +87,7 @@ impl Rtc { } /// Set the current rtc counter value to the specified amount - pub fn set_seconds(&mut self, seconds: u32) { + pub fn set_time(&mut self, seconds: u32) { self.perform_write(|s| { s.regs.cnth.write(|w| unsafe{w.bits(seconds >> 16)}); s.regs.cntl.write(|w| unsafe{w.bits(seconds as u16 as u32)}); @@ -129,7 +128,7 @@ impl Rtc { } /// Reads the current counter - pub fn seconds(&self) -> u32 { + pub fn current_time(&self) -> u32 { // Wait for the APB1 interface to be ready while self.regs.crl.read().rsf().bit() == false {} diff --git a/src/timer.rs b/src/timer.rs index f2903b8e..cb250090 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -72,7 +72,7 @@ impl CountDownTimer { /// it is very easy to lose an update event. pub fn micros_since(&self) -> u32 { let reload_value = SYST::get_reload(); - let timer_clock = u64(self.clocks.sysclk().0); + let timer_clock = u64(self.clk.0); let ticks = u64(reload_value - SYST::get_current()); // It is safe to make this cast since the maximum ticks is (2^24 - 1) and the minimum sysclk @@ -198,7 +198,7 @@ macro_rules! hal { /// *NOTE:* This method is not a very good candidate to keep track of time, because /// it is very easy to lose an update event. pub fn micros_since(&self) -> u32 { - let timer_clock = $TIMX::get_clk(&self.clocks).0; + let timer_clock = self.clk.0; let psc = u32(self.tim.psc.read().psc().bits()); // freq_divider is always bigger than 0, since (psc + 1) is always less than From 91847a3ef247a0d630417256f43e5a034ad7935b Mon Sep 17 00:00:00 2001 From: thalesfragoso Date: Sun, 25 Aug 2019 21:41:10 -0300 Subject: [PATCH 5/6] Change Timer to match Timer --- CHANGELOG.md | 5 +---- examples/pwm_input.rs | 2 +- examples/serial_config.rs | 1 - src/timer.rs | 16 ++++++++++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dfad468..8aac619a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Change timer/pwm init API - Remove `set_low` and `set_high` for pins in Alternate output mode - Renames `set_seconds` and `seconds` methods on RTC to `set_time` and `current_time`, respectively +- Starting the timer does not generate interrupt requests anymore ### Changed @@ -23,10 +24,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Add `micros_since` and `reset` methods to timer - Add `select_frequency` method to RTC -### Changed - -- Starting the timer does not generate interrupt requests anymore - ## [v0.4.0] - 2019-08-09 ### Added diff --git a/examples/pwm_input.rs b/examples/pwm_input.rs index b24231e0..e4c323ed 100644 --- a/examples/pwm_input.rs +++ b/examples/pwm_input.rs @@ -32,7 +32,7 @@ fn main() -> ! { let (_pa15, _pb3, pb4) = afio.mapr.disable_jtag(gpioa.pa15, gpiob.pb3, gpiob.pb4); let pb5 = gpiob.pb5; - let mut pwm_input = Timer::tim3(p.TIM3, &clocks, &mut rcc.apb1) + let pwm_input = Timer::tim3(p.TIM3, &clocks, &mut rcc.apb1) .pwm_input( (pb4, pb5), &mut afio.mapr, diff --git a/examples/serial_config.rs b/examples/serial_config.rs index 1d089568..cac7853d 100644 --- a/examples/serial_config.rs +++ b/examples/serial_config.rs @@ -14,7 +14,6 @@ use stm32f1xx_hal::{ prelude::*, pac, serial::{self, Serial}, - timer::Timer, }; use cortex_m_rt::entry; diff --git a/src/timer.rs b/src/timer.rs index cb250090..5fb582ff 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -43,6 +43,10 @@ impl Timer { timer.start(timeout); timer } + + pub fn release(self) -> SYST { + self.tim + } } impl CountDownTimer { @@ -81,14 +85,15 @@ impl CountDownTimer { } /// Stops the timer - pub fn stop(&mut self) { + pub fn stop(mut self) -> Timer { self.tim.disable_counter(); + let Self {tim, clk} = self; + Timer {tim, clk} } /// Releases the SYST - pub fn release(mut self) -> SYST { - self.stop(); - self.tim + pub fn release(self) -> SYST { + self.stop().release() } } @@ -177,8 +182,7 @@ macro_rules! hal { } /// Stops the timer - pub fn stop(mut self) -> Timer<$TIMX> { - self.unlisten(Event::Update); + pub fn stop(self) -> Timer<$TIMX> { self.tim.cr1.modify(|_, w| w.cen().clear_bit()); let Self { tim, clk } = self; Timer { tim, clk } From f91f70428e92c938da56281d9cbb5b32168cf565 Mon Sep 17 00:00:00 2001 From: thalesfragoso Date: Tue, 27 Aug 2019 22:41:53 -0300 Subject: [PATCH 6/6] small changes --- CHANGELOG.md | 4 ++-- src/rtc.rs | 14 +++++++------- src/timer.rs | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8aac619a..6da84340 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - RCC `Bus` trait + private `Enable` and `Reset` traits +- Added `micros_since` and `reset` methods to timer +- Added `select_frequency` method to RTC ### Breaking changes @@ -21,8 +23,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - DMA traits now require AsSlice instead of AsRef -- Add `micros_since` and `reset` methods to timer -- Add `select_frequency` method to RTC ## [v0.4.0] - 2019-08-09 diff --git a/src/rtc.rs b/src/rtc.rs index ad9726c1..fafac68a 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -70,7 +70,7 @@ impl Rtc { }) } - /// Selects the frequency of the counter + /// Selects the frequency of the RTC Timer /// NOTE: Maximum frequency of 16384 Hz using the internal LSE pub fn select_frequency(&mut self, timeout: impl Into) { let frequency = timeout.into().0; @@ -86,11 +86,11 @@ impl Rtc { }); } - /// Set the current rtc counter value to the specified amount - pub fn set_time(&mut self, seconds: u32) { + /// Set the current RTC counter value to the specified amount + pub fn set_time(&mut self, counter_value: u32) { self.perform_write(|s| { - s.regs.cnth.write(|w| unsafe{w.bits(seconds >> 16)}); - s.regs.cntl.write(|w| unsafe{w.bits(seconds as u16 as u32)}); + s.regs.cnth.write(|w| unsafe{w.bits(counter_value >> 16)}); + s.regs.cntl.write(|w| unsafe{w.bits(counter_value as u16 as u32)}); }); } @@ -99,10 +99,10 @@ impl Rtc { This also clears the alarm flag if it is set */ - pub fn set_alarm(&mut self, seconds: u32) { + pub fn set_alarm(&mut self, counter_value: u32) { // Set alarm time // See section 18.3.5 for explanation - let alarm_value = seconds - 1; + let alarm_value = counter_value - 1; self.perform_write(|s| { s.regs.alrh.write(|w| unsafe{w.alrh().bits((alarm_value >> 16) as u16)}); s.regs.alrl.write(|w| unsafe{w.alrl().bits(alarm_value as u16)}); diff --git a/src/timer.rs b/src/timer.rs index 5fb582ff..d90f1261 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -64,7 +64,7 @@ impl CountDownTimer { } } - /// Resets the timer + /// Resets the counter pub fn reset(&mut self) { // According to the Cortex-M3 Generic User Guide, the interrupt request is only generated // when the counter goes from 1 to 0, so writing zero should not trigger an interrupt @@ -215,7 +215,7 @@ macro_rules! hal { u32(1_000_000 * cnt / freq_divider).unwrap() } - /// Resets the counter and generates an update event + /// Resets the counter pub fn reset(&mut self) { // Sets the URS bit to prevent an interrupt from being triggered by // the UG bit