From c113526d2cbf00fe0909f95f4354bff89d2d99ea Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Tue, 14 Apr 2020 16:51:48 -0700 Subject: [PATCH 01/16] Added bkp struct to Rcc struct --- src/rcc.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/rcc.rs b/src/rcc.rs index f237a70f3..c2d5aee44 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -5,8 +5,10 @@ use core::cmp; use crate::stm32::{ rcc::{self, cfgr}, RCC, + PWR, }; +use crate::stm32::rcc::BDCR; use crate::flash::ACR; use crate::time::Hertz; @@ -22,6 +24,7 @@ impl RccExt for RCC { ahb: AHB { _0: () }, apb1: APB1 { _0: () }, apb2: APB2 { _0: () }, + bkp: BKP { _0: ()}, cfgr: CFGR { hse: None, hclk: None, @@ -41,6 +44,8 @@ pub struct Rcc { pub apb1: APB1, /// Advanced Peripheral Bus 2 (APB2) registers pub apb2: APB2, + /// RTC domain control register + pub bkp: BKP, /// Clock configuration pub cfgr: CFGR, } @@ -96,6 +101,40 @@ impl APB2 { } } +/// RTC domain control register +pub struct BKP { + _0: (), +} + +impl BKP { + pub fn bdcr(&mut self) -> &rcc::BDCR { + // NOTE(unsafe) this proxy grants exclusive access to this register + unsafe { &(*RCC::ptr()).bdcr } + } + + pub fn constrain(&mut self, apb1: &mut APB1, pwr: &mut PWR) -> BackupDomain { + apb1.enr().modify(|_ , w| { + w + // Enable the backup interface by setting PWREN + .pwren().set_bit() + }); + pwr.cr.modify(|_ , w| { + w + // Enable access to the backup registers + .dbp().set_bit() + }); + let _bdcr = self.bdcr(); + BackupDomain { + _regs: _bdcr, + } + } +} + +pub struct BackupDomain <'a> { + pub(crate) _regs: &'a rcc::BDCR, +} + + const HSI: u32 = 8_000_000; // Hz // some microcontrollers do not have USB From 5a7723a466136d971cc0bc25cc6264a16d4b8e28 Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Thu, 16 Apr 2020 15:35:38 -0700 Subject: [PATCH 02/16] Added Rcc helper functions for Rtc support --- src/rcc.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/rcc.rs b/src/rcc.rs index c2d5aee44..44970ab71 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -50,6 +50,82 @@ pub struct Rcc { pub cfgr: CFGR, } +impl Rcc { + + pub(crate) fn enable_rtc(&mut self, src: &RTCSrc) { + match src { + RTCSrc::LSI => self.enable_lsi(), + RTCSrc::HSE => self.enable_hse(false), + RTCSrc::LSE => self.enable_lse(false), + } + self.unlock_rtc(); + self.bdcr().modify(|_ , w| { + w + // RTC Backup Domain reset bit set high + .bdrst().set_bit() + }); + self.bdcr().modify(|_ , w| { + w + // RTC clock source selection + .rtcsel().bits(*src as u8) + // Enable RTC + .rtcen().set_bit() + // RTC backup Domain reset bit set low + .bdrst().clear_bit() + }); + } + + pub(crate) fn unlock_rtc(&mut self) { + let pwr = unsafe { &(*PWR::ptr()) }; + self.apb1.enr().modify(|_, w| { + w + // Enable the backup interface by setting PWREN + .pwren().set_bit() + }); + pwr.cr.modify(|_, w| { + w + // Enable access to the backup registers + .dbp().set_bit() + }); + + while pwr.cr.read().dbp().bit_is_clear() {} + } + + pub(crate) fn enable_lsi(&mut self) { + self.csr().write(|w| w.lsion().set_bit()); + while self.csr().read().lsirdy().bit_is_clear() {} + } + + pub(crate) fn enable_hsi(&mut self) { + self.cr().write(|w| w.hsion().set_bit()); + while self.cr().read().hsirdy().bit_is_clear() {} + } + + pub(crate) fn enable_hse(&mut self, bypass: bool) { + self.cr() + .write(|w| w.hseon().set_bit().hsebyp().bit(bypass)); + while self.cr().read().hserdy().bit_is_clear() {} + } + + pub(crate) fn enable_lse(&mut self, bypass: bool) { + self.bdcr() + .write(|w| w.lseon().set_bit().lsebyp().bit(bypass)); + while self.bdcr().read().lserdy().bit_is_clear() {} + } + + pub(crate) fn cr(&mut self) -> &rcc::CR { + unsafe { &(*RCC::ptr()).cr } + } + + pub(crate) fn csr(&mut self) -> &rcc::CSR { + unsafe { &(*RCC::ptr()).csr } + } + + pub(crate) fn bdcr(&mut self) -> &rcc::BDCR { + unsafe { &(*RCC::ptr()).bdcr } + } +} + /// AMBA High-performance Bus (AHB) registers pub struct AHB { _0: (), @@ -190,6 +266,7 @@ mod usb_clocking { } /// Clock configuration +#[derive(Clone, Copy)] pub struct CFGR { hse: Option, hclk: Option, From b24c4f9b97eee11b89b3a927623d3f7b45f3aaaa Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Thu, 16 Apr 2020 15:41:15 -0700 Subject: [PATCH 03/16] Rcc helper functions for Rtc --- src/rcc.rs | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/src/rcc.rs b/src/rcc.rs index 44970ab71..f6895ba8c 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -24,7 +24,6 @@ impl RccExt for RCC { ahb: AHB { _0: () }, apb1: APB1 { _0: () }, apb2: APB2 { _0: () }, - bkp: BKP { _0: ()}, cfgr: CFGR { hse: None, hclk: None, @@ -44,8 +43,6 @@ pub struct Rcc { pub apb1: APB1, /// Advanced Peripheral Bus 2 (APB2) registers pub apb2: APB2, - /// RTC domain control register - pub bkp: BKP, /// Clock configuration pub cfgr: CFGR, } @@ -177,35 +174,6 @@ impl APB2 { } } -/// RTC domain control register -pub struct BKP { - _0: (), -} - -impl BKP { - pub fn bdcr(&mut self) -> &rcc::BDCR { - // NOTE(unsafe) this proxy grants exclusive access to this register - unsafe { &(*RCC::ptr()).bdcr } - } - - pub fn constrain(&mut self, apb1: &mut APB1, pwr: &mut PWR) -> BackupDomain { - apb1.enr().modify(|_ , w| { - w - // Enable the backup interface by setting PWREN - .pwren().set_bit() - }); - pwr.cr.modify(|_ , w| { - w - // Enable access to the backup registers - .dbp().set_bit() - }); - let _bdcr = self.bdcr(); - BackupDomain { - _regs: _bdcr, - } - } -} - pub struct BackupDomain <'a> { pub(crate) _regs: &'a rcc::BDCR, } From 9175483ad8bc1b737e85ad264f23b6772f7b73c0 Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Thu, 16 Apr 2020 15:46:09 -0700 Subject: [PATCH 04/16] Add rcc helper functions for rtc module --- src/rcc.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/rcc.rs b/src/rcc.rs index f6895ba8c..487a2d984 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -8,7 +8,6 @@ use crate::stm32::{ PWR, }; -use crate::stm32::rcc::BDCR; use crate::flash::ACR; use crate::time::Hertz; @@ -539,3 +538,11 @@ impl Clocks { self.usbclk_valid } } + +/// RTC clock input source +#[derive(Clone, Copy)] +pub enum RTCSrc { + LSE = 0b01, + LSI = 0b10, + HSE = 0b11, +} From 7cf382942fd39b76a5e4bd299480444e5a9eb1cc Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Thu, 16 Apr 2020 15:49:05 -0700 Subject: [PATCH 05/16] Add rcc helper functions for future rtc module --- src/rcc.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/rcc.rs b/src/rcc.rs index 487a2d984..a39096203 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -173,11 +173,6 @@ impl APB2 { } } -pub struct BackupDomain <'a> { - pub(crate) _regs: &'a rcc::BDCR, -} - - const HSI: u32 = 8_000_000; // Hz // some microcontrollers do not have USB From 476a92ceeb88a3968b622d5587b61c8a055eb6ca Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Thu, 16 Apr 2020 16:16:15 -0700 Subject: [PATCH 06/16] Fix format --- src/rcc.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/rcc.rs b/src/rcc.rs index a39096203..c11569b19 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -4,8 +4,7 @@ use core::cmp; use crate::stm32::{ rcc::{self, cfgr}, - RCC, - PWR, + RCC, PWR, }; use crate::flash::ACR; @@ -55,19 +54,23 @@ impl Rcc { RTCSrc::LSE => self.enable_lse(false), } self.unlock_rtc(); - self.bdcr().modify(|_ , w| { + self.bdcr().modify(|_, w| { w // RTC Backup Domain reset bit set high - .bdrst().set_bit() + .bdrst() + .set_bit() }); self.bdcr().modify(|_ , w| { w // RTC clock source selection - .rtcsel().bits(*src as u8) + .rtcsel() + .bits(*src as u8) // Enable RTC - .rtcen().set_bit() + .rtcen() + .set_bit() // RTC backup Domain reset bit set low - .bdrst().clear_bit() + .bdrst() + .clear_bit() }); } @@ -76,12 +79,14 @@ impl Rcc { self.apb1.enr().modify(|_, w| { w // Enable the backup interface by setting PWREN - .pwren().set_bit() + .pwren() + .set_bit() }); pwr.cr.modify(|_, w| { w // Enable access to the backup registers - .dbp().set_bit() + .dbp() + .set_bit() }); while pwr.cr.read().dbp().bit_is_clear() {} From 44fe6fcb5705893900871e7e1773ad44354444b6 Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Thu, 16 Apr 2020 16:28:10 -0700 Subject: [PATCH 07/16] Fix more formatting --- src/rcc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rcc.rs b/src/rcc.rs index c11569b19..e82bf5036 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -4,7 +4,7 @@ use core::cmp; use crate::stm32::{ rcc::{self, cfgr}, - RCC, PWR, + PWR, RCC, }; use crate::flash::ACR; @@ -60,7 +60,7 @@ impl Rcc { .bdrst() .set_bit() }); - self.bdcr().modify(|_ , w| { + self.bdcr().modify(|_, w| { w // RTC clock source selection .rtcsel() @@ -81,7 +81,7 @@ impl Rcc { // Enable the backup interface by setting PWREN .pwren() .set_bit() - }); + }); pwr.cr.modify(|_, w| { w // Enable access to the backup registers From fb505ec7c0fece1412677708ed4699bd2a7a31c8 Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Thu, 16 Apr 2020 16:40:05 -0700 Subject: [PATCH 08/16] ran 'cargo fmt' to format file --- src/rcc.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/rcc.rs b/src/rcc.rs index e82bf5036..20ef82fd3 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -46,7 +46,6 @@ pub struct Rcc { } impl Rcc { - pub(crate) fn enable_rtc(&mut self, src: &RTCSrc) { match src { RTCSrc::LSI => self.enable_lsi(), @@ -77,12 +76,12 @@ impl Rcc { pub(crate) fn unlock_rtc(&mut self) { let pwr = unsafe { &(*PWR::ptr()) }; self.apb1.enr().modify(|_, w| { - w + w // Enable the backup interface by setting PWREN .pwren() .set_bit() }); - pwr.cr.modify(|_, w| { + pwr.cr.modify(|_, w| { w // Enable access to the backup registers .dbp() From 1422683c1e3b1824eca56a6c5f4f0e9dce6259a3 Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Thu, 16 Apr 2020 23:07:57 -0700 Subject: [PATCH 09/16] Added rtc module. Added functions to time module --- src/rcc.rs | 9 +-- src/rtc.rs | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/time.rs | 112 ++++++++++++++++++++++++++++++ 3 files changed, 305 insertions(+), 8 deletions(-) create mode 100644 src/rtc.rs diff --git a/src/rcc.rs b/src/rcc.rs index 20ef82fd3..779c6e5f3 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -8,6 +8,7 @@ use crate::stm32::{ }; use crate::flash::ACR; +use crate::rtc::RTCSrc; use crate::time::Hertz; /// Extension trait that constrains the `RCC` peripheral @@ -537,11 +538,3 @@ impl Clocks { self.usbclk_valid } } - -/// RTC clock input source -#[derive(Clone, Copy)] -pub enum RTCSrc { - LSE = 0b01, - LSI = 0b10, - HSE = 0b11, -} diff --git a/src/rtc.rs b/src/rtc.rs new file mode 100644 index 000000000..dd1a65f6a --- /dev/null +++ b/src/rtc.rs @@ -0,0 +1,192 @@ +use crate::rcc::Rcc; +use crate::stm32::RTC; +use crate::time::{Date, Time, U32Ext}; + +/** + Interface to the real time clock +**/ + +pub struct Rtc { + regs: RTC, +} + +impl Rtc { + /** + Initializes the RTC + **/ + // Sets default clock source to LSI, since LSE is not included on STM32f3 discovery boards + pub fn rtc(regs: RTC, src: RTCSrc, rcc: &mut Rcc) -> Self { + let mut result = Rtc { regs }; + + rcc.enable_rtc(&src); + + result.regs.cr.modify(|_, w| { + w + // sets hour format to 24 hours + .fmt() + .clear_bit() + }); + + // Prescalers set to produce a 1 hz signal + let (prediv_s, prediv_a) = match src { + RTCSrc::LSI => (311_u32, 127_u32), + RTCSrc::HSE => (62992_u32, 127_u32), + RTCSrc::LSE => (255_u32, 127_u32), + }; + + let raw_bits: u32 = prediv_s | (prediv_a << 16); + result.modify(|regs| { + regs.prer.write(|w| unsafe { w.bits(raw_bits) }); + }); + result + } + + pub fn set_time(&mut self, time: &Time) { + let (ht, hu) = bcd2_encode(time.hours); + let (mnt, mnu) = bcd2_encode(time.minutes); + let (st, su) = bcd2_encode(time.seconds); + self.modify(|regs| { + regs.tr.write(|w| unsafe { + w.ht() + .bits(ht) + .hu() + .bits(hu) + .mnt() + .bits(mnt) + .mnu() + .bits(mnu) + .st() + .bits(st) + .su() + .bits(su) + .pm() + .clear_bit() + }); + regs.cr.modify(|_, w| w.fmt().bit(time.daylight_savings)); + }); + } + + pub fn set_date(&mut self, date: &Date) { + let (yt, yu) = bcd2_encode(date.year - 1970); + let (mt, mu) = bcd2_encode(date.month); + let (dt, du) = bcd2_encode(date.day); + + self.modify(|regs| { + regs.dr.write(|w| unsafe { + w.dt() + .bits(dt) + .du() + .bits(du) + .mt() + .bit(mt > 0) + .mu() + .bits(mu) + .yt() + .bits(yt) + .yu() + .bits(yu) + .wdu() + .bits(date.day as u8) + }); + }); + } + + pub fn get_time(&self) -> Time { + let timer = self.regs.tr.read(); + Time::new( + bcd2_decode(timer.ht().bits(), timer.hu().bits()).hours(), + bcd2_decode(timer.mnt().bits(), timer.mnu().bits()).minutes(), + bcd2_decode(timer.st().bits(), timer.su().bits()).seconds(), + self.regs.cr.read().fmt().bit(), + ) + } + + pub fn get_date(&self) -> Date { + let date = self.regs.dr.read(); + Date::new( + (bcd2_decode(date.yt().bits(), date.yu().bits()) + 1970).year(), + bcd2_decode(date.mt().bit() as u8, date.mu().bits()).month(), + bcd2_decode(date.dt().bits(), date.du().bits()).day(), + ) + } + + pub fn get_week_day(&self) -> u8 { + self.regs.dr.read().wdu().bits() + } + // fn perform_write(&mut self, mut func: impl FnMut(&mut Self)) { + // // Disabling write protection to RTC reg block + // self.regs.wpr.write(|w| unsafe { w.bits(0xCA) }); + // self.regs.wpr.write(|w| unsafe { w.bits(0x53) }); + + // // Setting RTC Initialization bit to make prescalers programmable + // self.regs.isr.modify(|_, w| { w.init().set_bit()}); + + // // wait for initilization mode to take effect + // while self.regs.isr.read().initf().bit() == false {} + + // // Perform write operation + // func(self); + + // // Take device out of Initialization mode + // self.regs.isr.modify(|_, w| { w.init().clear_bit()}); + + // // wait for last write to be done + // while !self.regs.isr.read().initf().bit() == false {} + // } + + fn modify(&mut self, mut closure: F) + where + F: FnMut(&mut RTC) -> (), + { + // Disable write protection + self.regs.wpr.write(|w| unsafe { w.bits(0xCA) }); + self.regs.wpr.write(|w| unsafe { w.bits(0x53) }); + // Enter init mode + let isr = self.regs.isr.read(); + if isr.initf().bit_is_clear() { + self.regs.isr.write(|w| w.init().set_bit()); + while self.regs.isr.read().initf().bit_is_clear() {} + } + // Invoke closure + closure(&mut self.regs); + // Exit init mode + self.regs.isr.write(|w| w.init().clear_bit()); + // wait for last write to be done + while !self.regs.isr.read().initf().bit_is_clear() {} + } +} + +/// RTC clock input source +#[derive(Clone, Copy)] +pub enum RTCSrc { + LSE = 0b01, + LSI = 0b10, + HSE = 0b11, +} + +pub trait RtcExt { + fn constrain(self, rcc: &mut Rcc) -> Rtc; +} + +impl RtcExt for RTC { + fn constrain(self, rcc: &mut Rcc) -> Rtc { + Rtc::rtc(self, RTCSrc::LSI, rcc) + } +} + +fn bcd2_encode(word: u32) -> (u8, u8) { + let mut value = word as u8; + let mut bcd_high: u8 = 0; + while value >= 10 { + bcd_high += 1; + value -= 10; + } + let bcd_low = ((bcd_high << 4) | value) as u8; + (bcd_high, bcd_low) +} + +fn bcd2_decode(fst: u8, snd: u8) -> u32 { + let value = snd | fst << 4; + let value = (value & 0x0F) + ((value & 0xF0) >> 4) * 10; + value as u32 +} diff --git a/src/time.rs b/src/time.rs index 706e7e1b5..80465bdca 100644 --- a/src/time.rs +++ b/src/time.rs @@ -4,6 +4,8 @@ use cortex_m::peripheral::DWT; use crate::rcc::Clocks; +use core::fmt; + /// Bits per second #[derive(Clone, Copy)] pub struct Bps(pub u32); @@ -24,6 +26,74 @@ pub struct MegaHertz(pub u32); #[derive(PartialEq, PartialOrd, Clone, Copy)] pub struct MilliSeconds(pub u32); +/// Seconds +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Second(pub u32); + +/// Minutes +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Minute(pub u32); + +/// Hours +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Hour(pub u32); + +/// WeekDay (1-7) +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct WeekDay(pub u32); + +/// Date (1-31) +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct MonthDay(pub u32); + +/// Week (1-52) +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Week(pub u32); + +/// Month (1-12) +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Month(pub u32); + +/// Year +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Year(pub u32); + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Time { + pub hours: u32, + pub minutes: u32, + pub seconds: u32, + pub daylight_savings: bool, +} + +impl Time { + pub fn new(hours: Hour, minutes: Minute, seconds: Second, daylight_savings: bool) -> Self { + Self { + hours: hours.0, + minutes: minutes.0, + seconds: seconds.0, + daylight_savings, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Date { + pub day: u32, + pub month: u32, + pub year: u32, +} + +impl Date { + pub fn new(year: Year, month: Month, day: MonthDay) -> Self { + Self { + day: day.0, + month: month.0, + year: year.0, + } + } +} + /// Extension trait that adds convenience methods to the `u32` type pub trait U32Ext { /// Wrap in `Bps` @@ -40,6 +110,24 @@ pub trait U32Ext { /// Wrap in `MilliSeconds` fn ms(self) -> MilliSeconds; + + /// Seconds + fn seconds(self) -> Second; + + /// Minutes + fn minutes(self) -> Minute; + + /// Hours + fn hours(self) -> Hour; + + /// Day in month + fn day(self) -> MonthDay; + + /// Month + fn month(self) -> Month; + + /// Year + fn year(self) -> Year; } impl U32Ext for u32 { @@ -62,6 +150,30 @@ impl U32Ext for u32 { fn ms(self) -> MilliSeconds { MilliSeconds(self) } + + fn seconds(self) -> Second { + Second(self) + } + + fn minutes(self) -> Minute { + Minute(self) + } + + fn hours(self) -> Hour { + Hour(self) + } + + fn day(self) -> MonthDay { + MonthDay(self) + } + + fn month(self) -> Month { + Month(self) + } + + fn year(self) -> Year { + Year(self) + } } impl From for Hertz { From 98c3f24ee64fe166bff124dcda0d49b924ecd464 Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Thu, 16 Apr 2020 23:10:44 -0700 Subject: [PATCH 10/16] Removed unused 'perform_write' function from rtc module --- src/rtc.rs | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/rtc.rs b/src/rtc.rs index dd1a65f6a..ced9844dd 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -113,26 +113,6 @@ impl Rtc { pub fn get_week_day(&self) -> u8 { self.regs.dr.read().wdu().bits() } - // fn perform_write(&mut self, mut func: impl FnMut(&mut Self)) { - // // Disabling write protection to RTC reg block - // self.regs.wpr.write(|w| unsafe { w.bits(0xCA) }); - // self.regs.wpr.write(|w| unsafe { w.bits(0x53) }); - - // // Setting RTC Initialization bit to make prescalers programmable - // self.regs.isr.modify(|_, w| { w.init().set_bit()}); - - // // wait for initilization mode to take effect - // while self.regs.isr.read().initf().bit() == false {} - - // // Perform write operation - // func(self); - - // // Take device out of Initialization mode - // self.regs.isr.modify(|_, w| { w.init().clear_bit()}); - - // // wait for last write to be done - // while !self.regs.isr.read().initf().bit() == false {} - // } fn modify(&mut self, mut closure: F) where From c629df94b8e2ad2a0a8df37cf51c64a92f6320d0 Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Thu, 16 Apr 2020 23:18:11 -0700 Subject: [PATCH 11/16] Added lib.rs to changes --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 2723c67a6..33d9afe2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,8 @@ pub mod pwm; #[cfg(feature = "device-selected")] pub mod rcc; #[cfg(feature = "device-selected")] +pub mod rtc; +#[cfg(feature = "device-selected")] pub mod serial; #[cfg(feature = "device-selected")] pub mod spi; From 15337497d5ee2f159613facf49fb08b9533c8f7b Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Thu, 16 Apr 2020 23:26:50 -0700 Subject: [PATCH 12/16] Removed unused dependency 'core::fmt' from time.rs --- src/time.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/time.rs b/src/time.rs index 80465bdca..274cfd1b3 100644 --- a/src/time.rs +++ b/src/time.rs @@ -4,8 +4,6 @@ use cortex_m::peripheral::DWT; use crate::rcc::Clocks; -use core::fmt; - /// Bits per second #[derive(Clone, Copy)] pub struct Bps(pub u32); From 144588e97e25ae883472ed7eb2f4c1e1cfb78111 Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Mon, 27 Apr 2020 19:01:39 -0700 Subject: [PATCH 13/16] Update src/rtc.rs Co-Authored-By: Fabian --- src/rtc.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/rtc.rs b/src/rtc.rs index ced9844dd..3e604816d 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -36,7 +36,9 @@ impl Rtc { let raw_bits: u32 = prediv_s | (prediv_a << 16); result.modify(|regs| { - regs.prer.write(|w| unsafe { w.bits(raw_bits) }); + regs.prer.write(|w| unsafe { + w.prediv_s().bits(prediv_s).prediv_a().bits(prediv_a) + }); }); result } From 4c6d8d62d8cc8bb6765ee0004d887251b239a712 Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Mon, 27 Apr 2020 19:02:09 -0700 Subject: [PATCH 14/16] Update src/rtc.rs Co-Authored-By: Fabian --- src/rtc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rtc.rs b/src/rtc.rs index 3e604816d..a756fc35e 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -118,7 +118,7 @@ impl Rtc { fn modify(&mut self, mut closure: F) where - F: FnMut(&mut RTC) -> (), + F: FnMut(&mut Self) -> (), { // Disable write protection self.regs.wpr.write(|w| unsafe { w.bits(0xCA) }); From 91f831b535593160f19c6ab23de28666ed75db46 Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Tue, 26 May 2020 14:30:42 -0700 Subject: [PATCH 15/16] implement rtcc traits --- Cargo.toml | 1 + src/rcc.rs | 45 ++++++ src/rtc.rs | 406 ++++++++++++++++++++++++++++++++++++++++++---------- src/time.rs | 110 -------------- 4 files changed, 380 insertions(+), 182 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 90af1377c..fed26346b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ cortex-m-rt = "0.6" embedded-hal = "0.2" nb = "0.1" stm32f3 = "0.10" +rtcc = "0.2.0" [dependencies.bare-metal] version = "0.2" diff --git a/src/rcc.rs b/src/rcc.rs index 779c6e5f3..59b302273 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -23,6 +23,7 @@ impl RccExt for RCC { ahb: AHB { _0: () }, apb1: APB1 { _0: () }, apb2: APB2 { _0: () }, + bdcr: BDCR { _0: () }, cfgr: CFGR { hse: None, hclk: None, @@ -30,6 +31,8 @@ impl RccExt for RCC { pclk2: None, sysclk: None, }, + cr: CR { _0: () }, + csr: CSR { _0: () }, } } } @@ -42,8 +45,14 @@ pub struct Rcc { pub apb1: APB1, /// Advanced Peripheral Bus 2 (APB2) registers pub apb2: APB2, + /// RCC Backup Domain + pub bdcr: BDCR, /// Clock configuration pub cfgr: CFGR, + /// RCC Clock Control register + pub cr: CR, + /// RCC Control/Status register + pub csr: CSR, } impl Rcc { @@ -232,6 +241,18 @@ mod usb_clocking { } } +/// Backup Domain Control register (RCC_BDCR) +pub struct BDCR { + _0: (), +} + +impl BDCR { + pub(crate) fn bdcr(&mut self) -> &rcc::BDCR { + // NOTE(unsafe) this proxy grants exclusive access to this register + unsafe { &(*RCC::ptr()).bdcr } + } +} + /// Clock configuration #[derive(Clone, Copy)] pub struct CFGR { @@ -486,6 +507,30 @@ impl CFGR { } } +/// RCC Clock Control register (RCC_CR) +pub struct CR { + _0: (), +} + +impl CR { + pub(crate) fn cr(&mut self) -> &rcc::CR { + // NOTE(unsafe) this proxy grants exclusive access to this register + unsafe { &(*RCC::ptr()).cr } + } +} + +/// RCC Control/Status register +pub struct CSR { + _0: (), +} + +impl CSR { + pub(crate) fn csr(&mut self) -> &rcc::CSR { + // NOTE(unsafe) this proxy grants exclusive access to this register + unsafe { &(*RCC::ptr()).csr } + } +} + /// Frozen clock frequencies /// /// The existence of this value indicates that the clock configuration can no longer be changed diff --git a/src/rtc.rs b/src/rtc.rs index a756fc35e..b9689ad19 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -1,20 +1,49 @@ +/*! Interface to the real time clock */ + use crate::rcc::Rcc; use crate::stm32::RTC; -use crate::time::{Date, Time, U32Ext}; +use rtcc::{Datelike, Hours, NaiveDate, NaiveDateTime, NaiveTime, Rtcc, Timelike}; + +/// Invalid input error +// #[derive(Clone, Copy)] +#[derive(Debug)] +pub enum Error { + InvalidInputData, +} + +/// RTC clock input source +#[derive(Clone, Copy)] +pub enum RTCSrc { + LSE = 0b01, + LSI = 0b10, + HSE = 0b11, +} + +/// RTC configuration struct +pub struct cfgRTC { + src: RTCSrc, + prediv_s: u16, + prediv_a: u8, +} -/** - Interface to the real time clock -**/ +impl cfgRTC { + pub fn new(source: RTCSrc, prescaler_sync: u16, prescaler_async: u8) -> cfgRTC { + let config = cfgRTC { + src: source, + prediv_s: prescaler_sync, + prediv_a: prescaler_async, + }; + config + } +} pub struct Rtc { regs: RTC, } impl Rtc { - /** - Initializes the RTC - **/ - // Sets default clock source to LSI, since LSE is not included on STM32f3 discovery boards + /// initializes RTC, using the RTCSrc selected. The Prescalers will + /// be automatically set to produce a 1 hz clock source pub fn rtc(regs: RTC, src: RTCSrc, rcc: &mut Rcc) -> Self { let mut result = Rtc { regs }; @@ -29,25 +58,68 @@ impl Rtc { // Prescalers set to produce a 1 hz signal let (prediv_s, prediv_a) = match src { - RTCSrc::LSI => (311_u32, 127_u32), - RTCSrc::HSE => (62992_u32, 127_u32), - RTCSrc::LSE => (255_u32, 127_u32), + RTCSrc::LSI => (311, 127), + RTCSrc::HSE => (62992, 127), + RTCSrc::LSE => (255, 127), }; - let raw_bits: u32 = prediv_s | (prediv_a << 16); result.modify(|regs| { - regs.prer.write(|w| unsafe { - w.prediv_s().bits(prediv_s).prediv_a().bits(prediv_a) - }); + regs.prer + .write(|w| unsafe { w.prediv_s().bits(prediv_s).prediv_a().bits(prediv_a) }); }); result } - pub fn set_time(&mut self, time: &Time) { - let (ht, hu) = bcd2_encode(time.hours); - let (mnt, mnu) = bcd2_encode(time.minutes); - let (st, su) = bcd2_encode(time.seconds); - self.modify(|regs| { + /// Sets calendar clock to 24 hr format + pub fn set_24h_fmt(&mut self) { + self.regs.cr.modify(|_, w| w.fmt().set_bit()); + } + /// Sets calendar clock to 12 hr format + pub fn set_12h_fmt(&mut self) { + self.regs.cr.modify(|_, w| w.fmt().clear_bit()); + } + + /// Reads current hour format selection + pub fn is_24h_fmt(&self) -> bool { + self.regs.cr.read().fmt().bit() + } + + /// As described in Section 27.3.7 in RM0316, + /// this function is used to disable write protection + /// when modifying an RTC register + fn modify(&mut self, mut closure: F) + where + F: FnMut(&mut RTC) -> (), + { + // Disable write protection + self.regs.wpr.write(|w| unsafe { w.bits(0xCA) }); + self.regs.wpr.write(|w| unsafe { w.bits(0x53) }); + // Enter init mode + let isr = self.regs.isr.read(); + if isr.initf().bit_is_clear() { + self.regs.isr.write(|w| w.init().set_bit()); + while self.regs.isr.read().initf().bit_is_clear() {} + } + // Invoke closure + closure(&mut self.regs); + // Exit init mode + self.regs.isr.write(|w| w.init().clear_bit()); + // wait for last write to be done + while !self.regs.isr.read().initf().bit_is_clear() {} + } +} + +impl Rtcc for Rtc { + type Error = Error; + + /// set time using NaiveTime (ISO 8601 time without timezone) + /// Hour format is 24h + fn set_time(&mut self, time: &NaiveTime) -> Result<(), Self::Error> { + self.set_24h_fmt(); + let (ht, hu) = bcd2_encode(time.hour()); + let (mnt, mnu) = bcd2_encode(time.minute()); + let (st, su) = bcd2_encode(time.second()); + Ok(self.modify(|regs| { regs.tr.write(|w| unsafe { w.ht() .bits(ht) @@ -64,14 +136,112 @@ impl Rtc { .pm() .clear_bit() }); - regs.cr.modify(|_, w| w.fmt().bit(time.daylight_savings)); - }); + })) + } + + fn set_seconds(&mut self, seconds: u8) -> Result<(), Self::Error> { + if seconds > 59 { + return Err(Error::InvalidInputData); + } + let (st, su) = bcd2_encode(seconds as u32); + Ok(self.modify(|regs| regs.tr.write(|w| unsafe { w.st().bits(st).su().bits(su) }))) + } + + fn set_minutes(&mut self, minutes: u8) -> Result<(), Self::Error> { + if minutes > 59 { + return Err(Error::InvalidInputData); + } + let (mnt, mnu) = bcd2_encode(minutes as u32); + Ok(self.modify(|regs| { + regs.tr + .write(|w| unsafe { w.mnt().bits(mnt).mnu().bits(mnu) }) + })) + } + + fn set_hours(&mut self, hours: rtcc::Hours) -> Result<(), Self::Error> { + let (ht, hu) = hours_to_register(hours)?; + match hours { + Hours::H24(_h) => { + self.set_24h_fmt(); + Ok(self.modify(|regs| regs.tr.write(|w| unsafe { w.ht().bits(ht).hu().bits(hu) }))) + } + Hours::AM(_h) | Hours::PM(_h) => { + self.set_12h_fmt(); + Ok(self.modify(|regs| regs.tr.write(|w| unsafe { w.ht().bits(ht).hu().bits(hu) }))) + } + } + } + + fn set_weekday(&mut self, weekday: u8) -> Result<(), Self::Error> { + if (weekday < 1) | (weekday > 7) { + return Err(Error::InvalidInputData); + } + Ok(self.modify(|regs| regs.dr.write(|w| unsafe { w.wdu().bits(weekday) }))) + } + + fn set_day(&mut self, day: u8) -> Result<(), Self::Error> { + if (day < 1) | (day > 31) { + return Err(Error::InvalidInputData); + } + let (dt, du) = bcd2_encode(day as u32); + Ok(self.modify(|regs| regs.dr.write(|w| unsafe { w.dt().bits(dt).du().bits(du) }))) + } + + fn set_month(&mut self, month: u8) -> Result<(), Self::Error> { + if (month < 1) | (month > 12) { + return Err(Error::InvalidInputData); + } + let (mt, mu) = bcd2_encode(month as u32); + Ok(self.modify(|regs| { + regs.dr + .write(|w| unsafe { w.mt().bit(mt > 0).mu().bits(mu) }) + })) + } + + fn set_year(&mut self, year: u16) -> Result<(), Self::Error> { + if (year < 1970) | (year > 2038) { + return Err(Error::InvalidInputData); + } + let (yt, yu) = bcd2_encode(year as u32); + Ok(self.modify(|regs| regs.dr.write(|w| unsafe { w.yt().bits(yt).yu().bits(yu) }))) + } + + /// set date using NaiveDate (ISO 8601 calendar date without timezone) + /// WeekDay is set using set_weekday method + fn set_date(&mut self, date: &NaiveDate) -> Result<(), Self::Error> { + let (yt, yu) = bcd2_encode((date.year() - 1970) as u32); + let (mt, mu) = bcd2_encode(date.month()); + let (dt, du) = bcd2_encode(date.day()); + + Ok(self.modify(|regs| { + regs.dr.write(|w| unsafe { + w.dt() + .bits(dt) + .du() + .bits(du) + .mt() + .bit(mt > 0) + .mu() + .bits(mu) + .yt() + .bits(yt) + .yu() + .bits(yu) + }); + })) } - pub fn set_date(&mut self, date: &Date) { - let (yt, yu) = bcd2_encode(date.year - 1970); - let (mt, mu) = bcd2_encode(date.month); - let (dt, du) = bcd2_encode(date.day); + fn set_datetime(&mut self, date: &NaiveDateTime) -> Result<(), Self::Error> { + // Check if unsigned integer affects encoding to bcd + + self.set_24h_fmt(); + let (yt, yu) = bcd2_encode((date.year() - 1970) as u32); + let (mt, mu) = bcd2_encode(date.month()); + let (dt, du) = bcd2_encode(date.day()); + + let (ht, hu) = bcd2_encode(date.hour()); + let (mnt, mnu) = bcd2_encode(date.minute()); + let (st, su) = bcd2_encode(date.second()); self.modify(|regs| { regs.dr.write(|w| unsafe { @@ -87,63 +257,117 @@ impl Rtc { .bits(yt) .yu() .bits(yu) - .wdu() - .bits(date.day as u8) }); }); + Ok(self.modify(|regs| { + regs.tr.write(|w| unsafe { + w.ht() + .bits(ht) + .hu() + .bits(hu) + .mnt() + .bits(mnt) + .mnu() + .bits(mnu) + .st() + .bits(st) + .su() + .bits(su) + .pm() + .clear_bit() + }); + })) } - pub fn get_time(&self) -> Time { - let timer = self.regs.tr.read(); - Time::new( - bcd2_decode(timer.ht().bits(), timer.hu().bits()).hours(), - bcd2_decode(timer.mnt().bits(), timer.mnu().bits()).minutes(), - bcd2_decode(timer.st().bits(), timer.su().bits()).seconds(), - self.regs.cr.read().fmt().bit(), - ) + fn get_seconds(&mut self) -> Result { + let tr = self.regs.tr.read(); + let seconds = bcd2_decode(tr.st().bits(), tr.su().bits()); + Ok(seconds as u8) } - pub fn get_date(&self) -> Date { - let date = self.regs.dr.read(); - Date::new( - (bcd2_decode(date.yt().bits(), date.yu().bits()) + 1970).year(), - bcd2_decode(date.mt().bit() as u8, date.mu().bits()).month(), - bcd2_decode(date.dt().bits(), date.du().bits()).day(), - ) + fn get_minutes(&mut self) -> Result { + let tr = self.regs.tr.read(); + let minutes = bcd2_decode(tr.mnt().bits(), tr.mnu().bits()); + Ok(minutes as u8) } - pub fn get_week_day(&self) -> u8 { - self.regs.dr.read().wdu().bits() + fn get_hours(&mut self) -> Result { + let tr = self.regs.tr.read(); + let hours = bcd2_decode(tr.ht().bits(), tr.hu().bits()); + if self.is_24h_fmt() { + return Ok(rtcc::Hours::H24(hours as u8)); + } + if hours < 12 { + return Ok(rtcc::Hours::AM(hours as u8)); + } + Ok(rtcc::Hours::PM(hours as u8)) } - fn modify(&mut self, mut closure: F) - where - F: FnMut(&mut Self) -> (), - { - // Disable write protection - self.regs.wpr.write(|w| unsafe { w.bits(0xCA) }); - self.regs.wpr.write(|w| unsafe { w.bits(0x53) }); - // Enter init mode - let isr = self.regs.isr.read(); - if isr.initf().bit_is_clear() { - self.regs.isr.write(|w| w.init().set_bit()); - while self.regs.isr.read().initf().bit_is_clear() {} - } - // Invoke closure - closure(&mut self.regs); - // Exit init mode - self.regs.isr.write(|w| w.init().clear_bit()); - // wait for last write to be done - while !self.regs.isr.read().initf().bit_is_clear() {} + fn get_time(&mut self) -> Result { + self.set_24h_fmt(); + let seconds = self.get_seconds().unwrap(); + let minutes = self.get_minutes().unwrap(); + let hours = hours_to_u8(self.get_hours().unwrap()); + + Ok(NaiveTime::from_hms( + hours.into(), + minutes.into(), + seconds.into(), + )) } -} -/// RTC clock input source -#[derive(Clone, Copy)] -pub enum RTCSrc { - LSE = 0b01, - LSI = 0b10, - HSE = 0b11, + fn get_weekday(&mut self) -> Result { + let dr = self.regs.dr.read(); + let weekday = bcd2_decode(dr.wdu().bits(), 0x00); + Ok(weekday as u8) + } + + fn get_day(&mut self) -> Result { + let dr = self.regs.dr.read(); + let day = bcd2_decode(dr.dt().bits(), dr.du().bits()); + Ok(day as u8) + } + + fn get_month(&mut self) -> Result { + let dr = self.regs.dr.read(); + let mt: u8 = if dr.mt().bit() { 1 } else { 0 }; + let month = bcd2_decode(mt, dr.mu().bits()); + Ok(month as u8) + } + + fn get_year(&mut self) -> Result { + let dr = self.regs.dr.read(); + let year = bcd2_decode(dr.yt().bits(), dr.yu().bits()); + Ok(year as u16) + } + + fn get_date(&mut self) -> Result { + let day = self.get_day().unwrap(); + let month = self.get_month().unwrap(); + let year = self.get_year().unwrap(); + + Ok(NaiveDate::from_ymd(year.into(), month.into(), day.into())) + } + + fn get_datetime(&mut self) -> Result { + self.set_24h_fmt(); + + let day = self.get_day().unwrap(); + let month = self.get_month().unwrap(); + let year = self.get_year().unwrap(); + + let seconds = self.get_seconds().unwrap(); + let minutes = self.get_minutes().unwrap(); + let hours = hours_to_u8(self.get_hours().unwrap()); + + Ok( + NaiveDate::from_ymd(year.into(), month.into(), day.into()).and_hms( + hours.into(), + minutes.into(), + seconds.into(), + ), + ) + } } pub trait RtcExt { @@ -156,6 +380,12 @@ impl RtcExt for RTC { } } +// Two 32-bit registers (RTC_TR and RTC_DR) contain the seconds, minutes, hours (12- or 24-hour format), day (day +// of week), date (day of month), month, and year, expressed in binary coded decimal format +// (BCD). The sub-seconds value is also available in binary format. +// +// The following helper functions are encode into BCD format from integer and +// decode to an integer from a BCD value respectively. fn bcd2_encode(word: u32) -> (u8, u8) { let mut value = word as u8; let mut bcd_high: u8 = 0; @@ -163,7 +393,8 @@ fn bcd2_encode(word: u32) -> (u8, u8) { bcd_high += 1; value -= 10; } - let bcd_low = ((bcd_high << 4) | value) as u8; + // let bcd_low = ((bcd_high << 4) | value) as u8; + let bcd_low = value as u8; (bcd_high, bcd_low) } @@ -172,3 +403,34 @@ fn bcd2_decode(fst: u8, snd: u8) -> u32 { let value = (value & 0x0F) + ((value & 0xF0) >> 4) * 10; value as u32 } + +fn hours_to_register(hours: Hours) -> Result<(u8, u8), Error> { + match hours { + Hours::H24(h) if h > 23 => Err(Error::InvalidInputData), + Hours::H24(h) => Ok(bcd2_encode(h as u32)), + Hours::AM(h) if h < 1 || h > 12 => Err(Error::InvalidInputData), + Hours::AM(h) => Ok(bcd2_encode(h as u32)), + Hours::PM(h) if h < 1 || h > 12 => Err(Error::InvalidInputData), + Hours::PM(h) => Ok(bcd2_encode(h as u32)), + } +} + +fn hours_to_u8(_hours: rtcc::Hours) -> u8 { + if let rtcc::Hours::H24(h) = _hours { + h + } else { + panic!("_hours could not be destructured into rtc::Hours::H24(h)"); + } +} +// TODO: make unit tests for the bcd decode and encode functions +// #[cfg(test)] +// mod test { +// use super::*; + +// #[test] +// fn test_bcd_encode() { +// assert_eq!(bcd2_encode(5), (0, 5)); +// assert_eq!(bcd2_encode(24), (2, 36)); +// } + +// } diff --git a/src/time.rs b/src/time.rs index 274cfd1b3..706e7e1b5 100644 --- a/src/time.rs +++ b/src/time.rs @@ -24,74 +24,6 @@ pub struct MegaHertz(pub u32); #[derive(PartialEq, PartialOrd, Clone, Copy)] pub struct MilliSeconds(pub u32); -/// Seconds -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Second(pub u32); - -/// Minutes -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Minute(pub u32); - -/// Hours -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Hour(pub u32); - -/// WeekDay (1-7) -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct WeekDay(pub u32); - -/// Date (1-31) -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct MonthDay(pub u32); - -/// Week (1-52) -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Week(pub u32); - -/// Month (1-12) -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Month(pub u32); - -/// Year -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Year(pub u32); - -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Time { - pub hours: u32, - pub minutes: u32, - pub seconds: u32, - pub daylight_savings: bool, -} - -impl Time { - pub fn new(hours: Hour, minutes: Minute, seconds: Second, daylight_savings: bool) -> Self { - Self { - hours: hours.0, - minutes: minutes.0, - seconds: seconds.0, - daylight_savings, - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Date { - pub day: u32, - pub month: u32, - pub year: u32, -} - -impl Date { - pub fn new(year: Year, month: Month, day: MonthDay) -> Self { - Self { - day: day.0, - month: month.0, - year: year.0, - } - } -} - /// Extension trait that adds convenience methods to the `u32` type pub trait U32Ext { /// Wrap in `Bps` @@ -108,24 +40,6 @@ pub trait U32Ext { /// Wrap in `MilliSeconds` fn ms(self) -> MilliSeconds; - - /// Seconds - fn seconds(self) -> Second; - - /// Minutes - fn minutes(self) -> Minute; - - /// Hours - fn hours(self) -> Hour; - - /// Day in month - fn day(self) -> MonthDay; - - /// Month - fn month(self) -> Month; - - /// Year - fn year(self) -> Year; } impl U32Ext for u32 { @@ -148,30 +62,6 @@ impl U32Ext for u32 { fn ms(self) -> MilliSeconds { MilliSeconds(self) } - - fn seconds(self) -> Second { - Second(self) - } - - fn minutes(self) -> Minute { - Minute(self) - } - - fn hours(self) -> Hour { - Hour(self) - } - - fn day(self) -> MonthDay { - MonthDay(self) - } - - fn month(self) -> Month { - Month(self) - } - - fn year(self) -> Year { - Year(self) - } } impl From for Hertz { From 158632a5f14f1f8e82df8ef6d830b16c48e92844 Mon Sep 17 00:00:00 2001 From: Scott Medellin Date: Fri, 5 Jun 2020 12:52:01 -0700 Subject: [PATCH 16/16] move rtc initialization functions from rcc.rs to rtc.rs --- Cargo.toml | 2 +- src/rcc.rs | 86 +-------------------------------- src/rtc.rs | 138 ++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 96 insertions(+), 130 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fed26346b..5471aa1fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ cortex-m = "0.6" cortex-m-rt = "0.6" embedded-hal = "0.2" nb = "0.1" -stm32f3 = "0.10" +stm32f3 = "0.11" rtcc = "0.2.0" [dependencies.bare-metal] diff --git a/src/rcc.rs b/src/rcc.rs index 59b302273..56bdf7ea8 100644 --- a/src/rcc.rs +++ b/src/rcc.rs @@ -3,12 +3,11 @@ use core::cmp; use crate::stm32::{ - rcc::{self, cfgr}, - PWR, RCC, + rcc::{self, cfgr, cfgr2}, + RCC, }; use crate::flash::ACR; -use crate::rtc::RTCSrc; use crate::time::Hertz; /// Extension trait that constrains the `RCC` peripheral @@ -55,87 +54,6 @@ pub struct Rcc { pub csr: CSR, } -impl Rcc { - pub(crate) fn enable_rtc(&mut self, src: &RTCSrc) { - match src { - RTCSrc::LSI => self.enable_lsi(), - RTCSrc::HSE => self.enable_hse(false), - RTCSrc::LSE => self.enable_lse(false), - } - self.unlock_rtc(); - self.bdcr().modify(|_, w| { - w - // RTC Backup Domain reset bit set high - .bdrst() - .set_bit() - }); - self.bdcr().modify(|_, w| { - w - // RTC clock source selection - .rtcsel() - .bits(*src as u8) - // Enable RTC - .rtcen() - .set_bit() - // RTC backup Domain reset bit set low - .bdrst() - .clear_bit() - }); - } - - pub(crate) fn unlock_rtc(&mut self) { - let pwr = unsafe { &(*PWR::ptr()) }; - self.apb1.enr().modify(|_, w| { - w - // Enable the backup interface by setting PWREN - .pwren() - .set_bit() - }); - pwr.cr.modify(|_, w| { - w - // Enable access to the backup registers - .dbp() - .set_bit() - }); - - while pwr.cr.read().dbp().bit_is_clear() {} - } - - pub(crate) fn enable_lsi(&mut self) { - self.csr().write(|w| w.lsion().set_bit()); - while self.csr().read().lsirdy().bit_is_clear() {} - } - - pub(crate) fn enable_hsi(&mut self) { - self.cr().write(|w| w.hsion().set_bit()); - while self.cr().read().hsirdy().bit_is_clear() {} - } - - pub(crate) fn enable_hse(&mut self, bypass: bool) { - self.cr() - .write(|w| w.hseon().set_bit().hsebyp().bit(bypass)); - while self.cr().read().hserdy().bit_is_clear() {} - } - - pub(crate) fn enable_lse(&mut self, bypass: bool) { - self.bdcr() - .write(|w| w.lseon().set_bit().lsebyp().bit(bypass)); - while self.bdcr().read().lserdy().bit_is_clear() {} - } - - pub(crate) fn cr(&mut self) -> &rcc::CR { - unsafe { &(*RCC::ptr()).cr } - } - - pub(crate) fn csr(&mut self) -> &rcc::CSR { - unsafe { &(*RCC::ptr()).csr } - } - - pub(crate) fn bdcr(&mut self) -> &rcc::BDCR { - unsafe { &(*RCC::ptr()).bdcr } - } -} - /// AMBA High-performance Bus (AHB) registers pub struct AHB { _0: (), diff --git a/src/rtc.rs b/src/rtc.rs index b9689ad19..3564a9015 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -1,7 +1,7 @@ /*! Interface to the real time clock */ -use crate::rcc::Rcc; -use crate::stm32::RTC; +use crate::rcc::{APB1, BDCR, CR, CSR}; +use crate::stm32::{PWR, RTC}; use rtcc::{Datelike, Hours, NaiveDate, NaiveDateTime, NaiveTime, Rtcc, Timelike}; /// Invalid input error @@ -12,7 +12,7 @@ pub enum Error { } /// RTC clock input source -#[derive(Clone, Copy)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum RTCSrc { LSE = 0b01, LSI = 0b10, @@ -20,12 +20,25 @@ pub enum RTCSrc { } /// RTC configuration struct +#[derive(Copy, Clone, Debug, PartialEq)] pub struct cfgRTC { src: RTCSrc, prediv_s: u16, prediv_a: u8, } +/// LSI clock source with prescalers +/// set clock frequency to 1 hz +impl Default for cfgRTC { + fn default() -> Self { + cfgRTC { + src: RTCSrc::LSI, + prediv_s: 311, + prediv_a: 127, + } + } +} + impl cfgRTC { pub fn new(source: RTCSrc, prescaler_sync: u16, prescaler_async: u8) -> cfgRTC { let config = cfgRTC { @@ -42,32 +55,89 @@ pub struct Rtc { } impl Rtc { - /// initializes RTC, using the RTCSrc selected. The Prescalers will - /// be automatically set to produce a 1 hz clock source - pub fn rtc(regs: RTC, src: RTCSrc, rcc: &mut Rcc) -> Self { - let mut result = Rtc { regs }; + pub fn rtc( + regs: RTC, + apb1: &mut APB1, + bdcr: &mut BDCR, + cr: &mut CR, + csr: &mut CSR, + cfg_rtc: cfgRTC, + ) -> Self { + match &cfg_rtc.src { + RTCSrc::LSI => Rtc::enable_lsi(csr), + RTCSrc::HSE => Rtc::enable_hse(cr, false), + RTCSrc::LSE => Rtc::enable_lse(bdcr, false), + } + Rtc::unlock_rtc(apb1); + Rtc::enable_rtc(bdcr, &cfg_rtc); - rcc.enable_rtc(&src); + let mut result = Self { regs }; + result.set_12h_fmt(); + result.modify(|regs| { + regs.prer.write(|w| unsafe { + w.prediv_s() + .bits(cfg_rtc.prediv_s) + .prediv_a() + .bits(cfg_rtc.prediv_a) + }); + }); + result + } + + fn enable_lsi(csr: &mut CSR) { + csr.csr().write(|w| w.lsion().set_bit()); + while csr.csr().read().lsirdy().bit_is_clear() {} + } + + fn enable_hse(cr: &mut CR, bypass: bool) { + cr.cr().write(|w| w.hseon().set_bit().hsebyp().bit(bypass)); + while cr.cr().read().hserdy().bit_is_clear() {} + } + + fn enable_lse(bdcr: &mut BDCR, bypass: bool) { + bdcr.bdcr() + .write(|w| w.lseon().set_bit().lsebyp().bit(bypass)); + while bdcr.bdcr().read().lserdy().bit_is_clear() {} + } - result.regs.cr.modify(|_, w| { + fn unlock_rtc(apb1: &mut APB1) { + let pwr = unsafe { &(*PWR::ptr()) }; + apb1.enr().modify(|_, w| { w - // sets hour format to 24 hours - .fmt() - .clear_bit() + // Enable the backup interface by setting PWREN + .pwren() + .set_bit() + }); + pwr.cr.modify(|_, w| { + w + // Enable access to the backup registers + .dbp() + .set_bit() }); - // Prescalers set to produce a 1 hz signal - let (prediv_s, prediv_a) = match src { - RTCSrc::LSI => (311, 127), - RTCSrc::HSE => (62992, 127), - RTCSrc::LSE => (255, 127), - }; + while pwr.cr.read().dbp().bit_is_clear() {} + } - result.modify(|regs| { - regs.prer - .write(|w| unsafe { w.prediv_s().bits(prediv_s).prediv_a().bits(prediv_a) }); + fn enable_rtc(bdcr: &mut BDCR, cfg_rtc: &cfgRTC) { + bdcr.bdcr().modify(|_, w| { + w + // RTC Backup Domain reset bit set high + .bdrst() + .set_bit() + }); + + bdcr.bdcr().modify(|_, w| { + w + // RTC clock source selection + .rtcsel() + .bits(cfg_rtc.src as u8) + // Enable RTC + .rtcen() + .set_bit() + // RTC backup Domain reset bit set low + .bdrst() + .clear_bit() }); - result } /// Sets calendar clock to 24 hr format @@ -297,7 +367,7 @@ impl Rtcc for Rtc { if self.is_24h_fmt() { return Ok(rtcc::Hours::H24(hours as u8)); } - if hours < 12 { + if !tr.pm().bit() { return Ok(rtcc::Hours::AM(hours as u8)); } Ok(rtcc::Hours::PM(hours as u8)) @@ -370,16 +440,6 @@ impl Rtcc for Rtc { } } -pub trait RtcExt { - fn constrain(self, rcc: &mut Rcc) -> Rtc; -} - -impl RtcExt for RTC { - fn constrain(self, rcc: &mut Rcc) -> Rtc { - Rtc::rtc(self, RTCSrc::LSI, rcc) - } -} - // Two 32-bit registers (RTC_TR and RTC_DR) contain the seconds, minutes, hours (12- or 24-hour format), day (day // of week), date (day of month), month, and year, expressed in binary coded decimal format // (BCD). The sub-seconds value is also available in binary format. @@ -422,15 +482,3 @@ fn hours_to_u8(_hours: rtcc::Hours) -> u8 { panic!("_hours could not be destructured into rtc::Hours::H24(h)"); } } -// TODO: make unit tests for the bcd decode and encode functions -// #[cfg(test)] -// mod test { -// use super::*; - -// #[test] -// fn test_bcd_encode() { -// assert_eq!(bcd2_encode(5), (0, 5)); -// assert_eq!(bcd2_encode(24), (2, 36)); -// } - -// }