embassy/embassy-stm32/src/rcc/bd.rs

169 lines
5.1 KiB
Rust
Raw Normal View History

2023-08-27 16:07:34 +02:00
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(u8)]
pub enum RtcClockSource {
/// 00: No clock
NoClock = 0b00,
/// 01: LSE oscillator clock used as RTC clock
LSE = 0b01,
/// 10: LSI oscillator clock used as RTC clock
LSI = 0b10,
/// 11: HSE oscillator clock divided by 32 used as RTC clock
HSE = 0b11,
}
pub struct BackupDomain {}
impl BackupDomain {
#[cfg(any(
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
))]
fn unlock_registers() {
#[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))]
let cr = crate::pac::PWR.cr();
#[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
let cr = crate::pac::PWR.cr1();
// TODO: Missing from PAC for l0 and f0?
#[cfg(not(any(rtc_v2f0, rtc_v2l0)))]
{
if !cr.read().dbp() {
cr.modify(|w| w.set_dbp(true));
while !cr.read().dbp() {}
}
}
}
#[cfg(any(rtc_v3, rtc_v3u5))]
fn unlock_registers() {
// Unlock the backup domain
#[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))]
{
if !crate::pac::PWR.cr1().read().dbp() {
crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
while !crate::pac::PWR.cr1().read().dbp() {}
}
}
#[cfg(any(rcc_wl5, rcc_wle))]
{
use crate::pac::pwr::vals::Dbp;
if crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {
crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED));
while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {}
}
}
}
#[cfg(any(
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
))]
pub fn set_rtc_clock_source(clock_source: RtcClockSource) {
#[cfg(not(rtc_v2wb))]
use stm32_metapac::rcc::vals::Rtcsel;
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
let cr = crate::pac::RCC.bdcr();
#[cfg(any(rtc_v2l0, rtc_v2l1))]
let cr = crate::pac::RCC.csr();
Self::unlock_registers();
cr.modify(|w| {
// Select RTC source
#[cfg(not(rtc_v2wb))]
w.set_rtcsel(Rtcsel::from_bits(clock_source as u8));
#[cfg(rtc_v2wb)]
w.set_rtcsel(clock_source as u8);
});
}
#[cfg(any(rtc_v3, rtc_v3u5))]
pub fn set_rtc_clock_source(clock_source: RtcClockSource) {
let clock_source = clock_source as u8;
#[cfg(not(any(rcc_wl5, rcc_wle)))]
let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source);
Self::unlock_registers();
crate::pac::RCC.bdcr().modify(|w| {
// Select RTC source
w.set_rtcsel(clock_source);
});
}
#[cfg(any(
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
))]
pub fn enable_rtc() {
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
let reg = crate::pac::RCC.bdcr().read();
#[cfg(any(rtc_v2l0, rtc_v2l1))]
let reg = crate::pac::RCC.csr().read();
#[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))]
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
if !reg.rtcen() {
Self::unlock_registers();
#[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))]
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
let cr = crate::pac::RCC.bdcr();
#[cfg(any(rtc_v2l0, rtc_v2l1))]
let cr = crate::pac::RCC.csr();
cr.modify(|w| {
// Reset
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
w.set_bdrst(false);
w.set_rtcen(true);
w.set_rtcsel(reg.rtcsel());
// Restore bcdr
#[cfg(any(rtc_v2l4, rtc_v2wb))]
w.set_lscosel(reg.lscosel());
#[cfg(any(rtc_v2l4, rtc_v2wb))]
w.set_lscoen(reg.lscoen());
w.set_lseon(reg.lseon());
#[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
w.set_lsedrv(reg.lsedrv());
w.set_lsebyp(reg.lsebyp());
});
}
}
#[cfg(any(rtc_v3, rtc_v3u5))]
pub fn enable_rtc() {
let bdcr = crate::pac::RCC.bdcr();
let reg = bdcr.read();
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
if !reg.rtcen() {
Self::unlock_registers();
bdcr.modify(|w| w.set_bdrst(true));
bdcr.modify(|w| {
// Reset
w.set_bdrst(false);
w.set_rtcen(true);
w.set_rtcsel(reg.rtcsel());
// Restore bcdr
w.set_lscosel(reg.lscosel());
w.set_lscoen(reg.lscoen());
w.set_lseon(reg.lseon());
w.set_lsedrv(reg.lsedrv());
w.set_lsebyp(reg.lsebyp());
});
}
}
}