use core::marker::PhantomData;
use common::Constrain;
use rcc;
use stm32l0x1::{pwr, PWR};
use time::Hertz;
mod private {
pub trait Sealed {}
impl Sealed for super::VCoreRange1 {}
impl Sealed for super::VCoreRange2 {}
impl Sealed for super::VCoreRange3 {}
}
impl Constrain<Power<VddLow, VCoreRange2, RtcDis>> for PWR {
fn constrain(self) -> Power<VddLow, VCoreRange2, RtcDis> {
Power {
cr: CR(()),
csr: CSR(()),
_vdd: PhantomData,
_vcore: PhantomData,
_rtc: PhantomData,
}
}
}
impl Constrain<Power<VddHigh, VCoreRange2, RtcDis>> for PWR {
fn constrain(self) -> Power<VddHigh, VCoreRange2, RtcDis> {
Power {
cr: CR(()),
csr: CSR(()),
_vdd: PhantomData,
_vcore: PhantomData,
_rtc: PhantomData,
}
}
}
pub struct Power<VDD, VCORE, RTC> {
cr: CR,
csr: CSR,
#[doc(hidden)]
_vdd: PhantomData<VDD>,
#[doc(hidden)]
_vcore: PhantomData<VCORE>,
#[doc(hidden)]
_rtc: PhantomData<RTC>,
}
pub struct CR(());
impl CR {
#[inline]
pub fn inner(&self) -> &pwr::CR {
unsafe { &(*PWR::ptr()).cr }
}
}
pub struct CSR(());
impl CSR {
#[inline]
pub fn inner(&self) -> &pwr::CSR {
unsafe { &(*PWR::ptr()).csr }
}
}
pub struct VddHigh(());
pub struct VddLow(());
#[derive(PartialOrd, PartialEq)]
pub enum VCoreRange {
Range3,
Range2,
Range1,
}
impl VCoreRange {
#[doc(hidden)]
pub fn bits(&self) -> u8 {
match self {
VCoreRange::Range1 => 0b01,
VCoreRange::Range2 => 0b10,
VCoreRange::Range3 => 0b11,
}
}
}
#[doc(hidden)]
pub trait Vos: private::Sealed {
fn range() -> VCoreRange;
}
#[doc(hidden)]
pub trait FreqLimit: private::Sealed {
fn max_freq() -> Hertz;
}
pub struct VCoreRange1(());
impl Vos for VCoreRange1 {
fn range() -> VCoreRange {
VCoreRange::Range1
}
}
impl FreqLimit for VCoreRange1 {
fn max_freq() -> Hertz {
Hertz(32_000_000)
}
}
pub struct VCoreRange2(());
impl Vos for VCoreRange2 {
fn range() -> VCoreRange {
VCoreRange::Range2
}
}
impl FreqLimit for VCoreRange2 {
fn max_freq() -> Hertz {
Hertz(16_000_000)
}
}
pub struct VCoreRange3(());
impl Vos for VCoreRange3 {
fn range() -> VCoreRange {
VCoreRange::Range3
}
}
impl FreqLimit for VCoreRange3 {
fn max_freq() -> Hertz {
Hertz(4_200_000)
}
}
impl<VDD, RTC> Power<VDD, VCoreRange2, RTC> {
pub fn into_vdd_range<NEWVDD>(self) -> Power<VDD, VCoreRange2, RTC> {
Power {
cr: self.cr,
csr: self.csr,
_vdd: PhantomData,
_vcore: PhantomData,
_rtc: PhantomData,
}
}
}
impl<VDD, RTC> Power<VDD, VCoreRange3, RTC> {
pub fn into_vdd_range<NEWVDD>(self) -> Power<VDD, VCoreRange3, RTC> {
Power {
cr: self.cr,
csr: self.csr,
_vdd: PhantomData,
_vcore: PhantomData,
_rtc: PhantomData,
}
}
}
impl<VCORE, RTC> Power<VddHigh, VCORE, RTC> {
pub fn into_vcore_range<NEWRANGE>(self) -> Power<VddHigh, NEWRANGE, RTC>
where
NEWRANGE: Vos,
{
Power {
cr: self.cr,
csr: self.csr,
_vdd: PhantomData,
_vcore: PhantomData,
_rtc: PhantomData,
}
}
}
impl<RTC> Power<VddLow, VCoreRange2, RTC> {
pub fn into_vcore_range(self) -> Power<VddLow, VCoreRange3, RTC> {
Power {
cr: self.cr,
csr: self.csr,
_vdd: PhantomData,
_vcore: PhantomData,
_rtc: PhantomData,
}
}
}
impl<RTC> Power<VddLow, VCoreRange3, RTC> {
pub fn into_vcore_range(self) -> Power<VddLow, VCoreRange2, RTC> {
Power {
cr: self.cr,
csr: self.csr,
_vdd: PhantomData,
_vcore: PhantomData,
_rtc: PhantomData,
}
}
}
impl<VDD, VCORE, RTC> Power<VDD, VCORE, RTC>
where
VCORE: Vos,
{
fn while_clk_en<F>(apb1: &mut rcc::APB1, mut op: F)
where
F: FnMut(),
{
apb1.enr().modify(|_, w| w.pwren().set_bit());
while !apb1.enr().read().pwren().bit_is_set() {}
op();
apb1.enr().modify(|_, w| w.pwren().clear_bit());
while apb1.enr().read().pwren().bit_is_set() {}
}
pub fn dbp_context<F>(&mut self, mut op: F)
where
F: FnMut(),
{
self.cr.inner().modify(|_, w| w.dbp().set_bit());
while self.cr.inner().read().dbp().bit_is_clear() {}
op();
self.cr.inner().modify(|_, w| w.dbp().clear_bit());
while self.cr.inner().read().dbp().bit_is_set() {}
}
pub unsafe fn enact(&mut self, apb1: &mut rcc::APB1) {
Power::<VDD, VCORE, RTC>::while_clk_en(apb1, || {
self.cr
.inner()
.modify(|_, w| w.vos().bits(VCORE::range().bits()));
while self.csr.inner().read().vosf().bit_is_set() {}
});
}
pub fn read_vcore_range(&self) -> VCoreRange {
match self.cr.inner().read().vos().bits() {
0b01 => VCoreRange::Range1,
0b10 => VCoreRange::Range2,
0b11 => VCoreRange::Range3,
_ => unreachable!(),
}
}
}
pub struct RtcEn(());
pub struct RtcDis(());
impl<VDD, VCORE> Power<VDD, VCORE, RtcEn>
where
VCORE: Vos,
{
pub fn disable_rtc(self, apb1: &mut rcc::APB1) -> Power<VDD, VCORE, RtcDis> {
apb1.enr().modify(|_, w| w.pwren().clear_bit());
while apb1.enr().read().pwren().bit_is_set() {}
self.cr.inner().modify(|_, w| w.dbp().clear_bit());
Power {
cr: self.cr,
csr: self.csr,
_vdd: PhantomData,
_vcore: PhantomData,
_rtc: PhantomData,
}
}
}
impl<VDD, VCORE> Power<VDD, VCORE, RtcDis>
where
VCORE: Vos,
{
pub fn enable_rtc(
mut self,
cr: &mut rcc::CR,
apb1: &mut rcc::APB1,
) -> Power<VDD, VCORE, RtcEn> {
if cr.inner().read().rtcpre().bits() == 0 {
self.cr.inner().modify(|_, w| w.dbp().clear_bit());
} else {
self.cr.inner().modify(|_, w| w.dbp().set_bit());
}
apb1.enr().modify(|_, w| w.pwren().set_bit());
while !apb1.enr().read().pwren().bit_is_set() {}
self.dbp_context(|| {
});
Power {
cr: self.cr,
csr: self.csr,
_vdd: PhantomData,
_vcore: PhantomData,
_rtc: PhantomData,
}
}
}