Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rtc refactor #174

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 60 additions & 33 deletions src/rtc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,51 @@ pub enum Error {
InvalidInputData,
}

/// RTC Clock input source ???
/// https://github.com/stm32-rs/stm32f3xx-hal/pull/93/files#diff-27f77b66fb3d3624adbb9ac9e90b661819630850787da3b9f47a48a663a5634cR16
/// And what about RTCSEL_A?
/// https://docs.rs/stm32f3/0.12.1/stm32f3/stm32f303/rcc/bdcr/enum.RTCSEL_A.html
pub const LSE_BITS: u8 = 0b01;

pub struct Rtc {
pub regs: RTC,
rtc: RTC,
}

impl Rtc {
/// Create and enable a new RTC, and configure its clock source and prescalers.
// TODO Even though LSE is the only supported type for now,
// the API should be flexible enough tot allow further imporvements
// wither (at least a major) breaking API change.
/// From AN4759, Table 7, when using the LSE (The only clock source this module
/// supports currently), set `prediv_s` to 255, and `prediv_a` to 127 to get a
/// calendar clock of 1Hz.
// TODO could'nt that be determined via clocks?
/// The `bypass` argument is `true` if you're using an external oscillator that
/// doesn't connect to `OSC32_IN`, such as a MEMS resonator.
// TODO what to pass to prediv_s and prediv_a
// TODO bypass to enum?
pub fn new(
regs: RTC,
rtc: RTC,
prediv_s: u16,
prediv_a: u8,
bypass: bool,
apb1: &mut APB1,
bdcr: &mut BDCR,
pwr: &mut PWR,
) -> Self {
let mut result = Self { regs };
let mut result = Self { rtc };

// TODO
// These are one time used functions and not very
// long ones either,
// expand them up to here
enable_lse(bdcr, bypass);
unlock(apb1, pwr);
// Support
enable(bdcr);
result.set_24h_fmt();

result.regs.prer.modify(|_, w| {
result.rtc.prer.modify(|_, w| {
w.prediv_s().bits(prediv_s);
w.prediv_a().bits(prediv_a)
});
Expand All @@ -55,16 +70,21 @@ impl Rtc {

/// Sets calendar clock to 24 hr format
pub fn set_24h_fmt(&mut self) {
self.regs.cr.modify(|_, w| w.fmt().set_bit());
self.rtc.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());
self.rtc.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()
self.rtc.cr.read().fmt().bit()
}

/// Release the RTC peripheral
pub fn free(self) -> RTC {
self.rtc
}

/// As described in Section 27.3.7 in RM0316,
Expand All @@ -75,20 +95,20 @@ impl Rtc {
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) });
self.rtc.wpr.write(|w| unsafe { w.bits(0xCA) });
self.rtc.wpr.write(|w| unsafe { w.bits(0x53) });
// Enter init mode
let isr = self.regs.isr.read();
let isr = self.rtc.isr.read();
if isr.initf().bit_is_clear() {
self.regs.isr.modify(|_, w| w.init().set_bit());
while self.regs.isr.read().initf().bit_is_clear() {}
self.rtc.isr.modify(|_, w| w.init().set_bit());
while self.rtc.isr.read().initf().bit_is_clear() {}
}
// Invoke closure
closure(&mut self.regs);
closure(&mut self.rtc);
// Exit init mode
self.regs.isr.modify(|_, w| w.init().clear_bit());
self.rtc.isr.modify(|_, w| w.init().clear_bit());
// wait for last write to be done
while !self.regs.isr.read().initf().bit_is_clear() {}
while !self.rtc.isr.read().initf().bit_is_clear() {}
}
}

Expand All @@ -102,7 +122,7 @@ impl Rtcc for Rtc {
let (ht, hu) = bcd2_encode(time.hour())?;
let (mnt, mnu) = bcd2_encode(time.minute())?;
let (st, su) = bcd2_encode(time.second())?;
self.regs.tr.write(|w| {
self.rtc.tr.write(|w| {
w.ht().bits(ht);
w.hu().bits(hu);
w.mnt().bits(mnt);
Expand All @@ -120,7 +140,7 @@ impl Rtcc for Rtc {
return Err(Error::InvalidInputData);
}
let (st, su) = bcd2_encode(seconds as u32)?;
self.modify(|regs| regs.tr.modify(|_, w| w.st().bits(st).su().bits(su)));
self.modify(|rtc| rtc.tr.modify(|_, w| w.st().bits(st).su().bits(su)));

Ok(())
}
Expand All @@ -130,7 +150,7 @@ impl Rtcc for Rtc {
return Err(Error::InvalidInputData);
}
let (mnt, mnu) = bcd2_encode(minutes as u32)?;
self.modify(|regs| regs.tr.modify(|_, w| w.mnt().bits(mnt).mnu().bits(mnu)));
self.modify(|rtc| rtc.tr.modify(|_, w| w.mnt().bits(mnt).mnu().bits(mnu)));

Ok(())
}
Expand All @@ -142,7 +162,7 @@ impl Rtcc for Rtc {
Hours::AM(_h) | Hours::PM(_h) => self.set_12h_fmt(),
}

self.regs.tr.modify(|_, w| w.ht().bits(ht).hu().bits(hu));
self.rtc.tr.modify(|_, w| w.ht().bits(ht).hu().bits(hu));

Ok(())
}
Expand All @@ -151,7 +171,7 @@ impl Rtcc for Rtc {
if !(1..=7).contains(&weekday) {
return Err(Error::InvalidInputData);
}
self.modify(|regs| regs.dr.modify(|_, w| unsafe { w.wdu().bits(weekday) }));
self.modify(|rtc| rtc.dr.modify(|_, w| unsafe { w.wdu().bits(weekday) }));

Ok(())
}
Expand All @@ -161,7 +181,7 @@ impl Rtcc for Rtc {
return Err(Error::InvalidInputData);
}
let (dt, du) = bcd2_encode(day as u32)?;
self.modify(|regs| regs.dr.modify(|_, w| w.dt().bits(dt).du().bits(du)));
self.modify(|rtc| rtc.dr.modify(|_, w| w.dt().bits(dt).du().bits(du)));

Ok(())
}
Expand All @@ -171,7 +191,7 @@ impl Rtcc for Rtc {
return Err(Error::InvalidInputData);
}
let (mt, mu) = bcd2_encode(month as u32)?;
self.modify(|regs| regs.dr.modify(|_, w| w.mt().bit(mt > 0).mu().bits(mu)));
self.modify(|rtc| rtc.dr.modify(|_, w| w.mt().bit(mt > 0).mu().bits(mu)));

Ok(())
}
Expand All @@ -181,7 +201,7 @@ impl Rtcc for Rtc {
return Err(Error::InvalidInputData);
}
let (yt, yu) = bcd2_encode(year as u32)?;
self.modify(|regs| regs.dr.modify(|_, w| w.yt().bits(yt).yu().bits(yu)));
self.modify(|rtc| rtc.dr.modify(|_, w| w.yt().bits(yt).yu().bits(yu)));

Ok(())
}
Expand All @@ -197,7 +217,7 @@ impl Rtcc for Rtc {
let (mt, mu) = bcd2_encode(date.month())?;
let (dt, du) = bcd2_encode(date.day())?;

self.regs.dr.write(|w| {
self.rtc.dr.write(|w| {
w.dt().bits(dt);
w.du().bits(du);
w.mt().bit(mt > 0);
Expand All @@ -223,7 +243,7 @@ impl Rtcc for Rtc {
let (mnt, mnu) = bcd2_encode(date.minute())?;
let (st, su) = bcd2_encode(date.second())?;

self.regs.dr.write(|w| {
self.rtc.dr.write(|w| {
w.dt().bits(dt);
w.du().bits(du);
w.mt().bit(mt > 0);
Expand All @@ -232,7 +252,7 @@ impl Rtcc for Rtc {
w.yu().bits(yu)
});

self.regs.tr.write(|w| {
self.rtc.tr.write(|w| {
w.ht().bits(ht);
w.hu().bits(hu);
w.mnt().bits(mnt);
Expand All @@ -246,19 +266,19 @@ impl Rtcc for Rtc {
}

fn get_seconds(&mut self) -> Result<u8, Self::Error> {
let tr = self.regs.tr.read();
let tr = self.rtc.tr.read();
let seconds = bcd2_decode(tr.st().bits(), tr.su().bits());
Ok(seconds as u8)
}

fn get_minutes(&mut self) -> Result<u8, Self::Error> {
let tr = self.regs.tr.read();
let tr = self.rtc.tr.read();
let minutes = bcd2_decode(tr.mnt().bits(), tr.mnu().bits());
Ok(minutes as u8)
}

fn get_hours(&mut self) -> Result<Hours, Self::Error> {
let tr = self.regs.tr.read();
let tr = self.rtc.tr.read();
let hours = bcd2_decode(tr.ht().bits(), tr.hu().bits());
if self.is_24h_fmt() {
return Ok(Hours::H24(hours as u8));
Expand All @@ -283,26 +303,26 @@ impl Rtcc for Rtc {
}

fn get_weekday(&mut self) -> Result<u8, Self::Error> {
let dr = self.regs.dr.read();
let dr = self.rtc.dr.read();
let weekday = bcd2_decode(dr.wdu().bits(), 0x00);
Ok(weekday as u8)
}

fn get_day(&mut self) -> Result<u8, Self::Error> {
let dr = self.regs.dr.read();
let dr = self.rtc.dr.read();
let day = bcd2_decode(dr.dt().bits(), dr.du().bits());
Ok(day as u8)
}

fn get_month(&mut self) -> Result<u8, Self::Error> {
let dr = self.regs.dr.read();
let dr = self.rtc.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<u16, Self::Error> {
let dr = self.regs.dr.read();
let dr = self.rtc.dr.read();
let year = bcd2_decode(dr.yt().bits(), dr.yu().bits());
Ok(year as u16)
}
Expand Down Expand Up @@ -381,6 +401,9 @@ fn hours_to_u8(hours: Hours) -> Result<u8, Error> {

/// Enable the low frequency external oscillator. This is the only mode currently
/// supported, to avoid exposing the `CR` and `CRS` registers.
// TODO If these limitations are the problem,
// why not use something like a builder pattern
// to bee able to avoid these dependencies on CR and CRS?
fn enable_lse(bdcr: &mut BDCR, bypass: bool) {
bdcr.bdcr()
.modify(|_, w| w.lseon().set_bit().lsebyp().bit(bypass));
Expand All @@ -407,6 +430,10 @@ fn unlock(apb1: &mut APB1, pwr: &mut PWR) {
fn enable(bdcr: &mut BDCR) {
bdcr.bdcr().modify(|_, w| w.bdrst().enabled());
bdcr.bdcr().modify(|_, w| {
// FIXME LSE BITS is a pub const
// but here we just set it?
// What about lsi and hsi
// and does bypass play a role here?
w.rtcsel().lse();
w.rtcen().enabled();
w.bdrst().disabled()
Expand Down