Merge branch 'issue-1974-add-sai-driver' of https://github.com/tyler-gilbert/embassy into issue-1974-add-sai-driver

This commit is contained in:
Tyler Gilbert
2023-09-29 21:08:21 -05:00
304 changed files with 11897 additions and 5157 deletions

View File

@ -1,16 +1,37 @@
use core::future::poll_fn;
use core::marker::PhantomData;
use core::task::Poll;
use embassy_hal_internal::into_ref;
use embedded_hal_02::blocking::delay::DelayUs;
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
use crate::rcc::get_freqs;
use crate::time::Hertz;
use crate::Peripheral;
use crate::{interrupt, Peripheral};
pub const VDDA_CALIB_MV: u32 = 3300;
pub const ADC_MAX: u32 = (1 << 12) - 1;
// No calibration data for F103, voltage should be 1.2v
pub const VREF_INT: u32 = 1200;
/// Interrupt handler.
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
if T::regs().sr().read().eoc() {
T::regs().cr1().modify(|w| w.set_eocie(false));
} else {
return;
}
T::state().waker.wake();
}
}
pub struct Vref;
impl<T: Instance> AdcPin<T> for Vref {}
impl<T: Instance> super::sealed::AdcPin<T> for Vref {
@ -60,7 +81,7 @@ impl<'d, T: Instance> Adc<'d, T> {
}
fn freq() -> Hertz {
unsafe { get_freqs() }.adc
unsafe { get_freqs() }.adc.unwrap()
}
pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
@ -95,18 +116,28 @@ impl<'d, T: Instance> Adc<'d, T> {
}
/// Perform a single conversion.
fn convert(&mut self) -> u16 {
async fn convert(&mut self) -> u16 {
T::regs().cr2().modify(|reg| {
reg.set_adon(true);
reg.set_swstart(true);
});
while T::regs().cr2().read().swstart() {}
while !T::regs().sr().read().eoc() {}
T::regs().cr1().modify(|w| w.set_eocie(true));
poll_fn(|cx| {
T::state().waker.register(cx.waker());
if !T::regs().cr2().read().swstart() && T::regs().sr().read().eoc() {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
T::regs().dr().read().0 as u16
}
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
Self::set_channel_sample_time(pin.channel(), self.sample_time);
T::regs().cr1().modify(|reg| {
reg.set_scan(false);
@ -123,7 +154,7 @@ impl<'d, T: Instance> Adc<'d, T> {
// Configure the channel to sample
T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel()));
self.convert()
self.convert().await
}
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
@ -135,3 +166,11 @@ impl<'d, T: Instance> Adc<'d, T> {
}
}
}
impl<'d, T: Instance> Drop for Adc<'d, T> {
fn drop(&mut self) {
T::regs().cr2().modify(|reg| reg.set_adon(false));
T::disable();
}
}

195
embassy-stm32/src/adc/f3.rs Normal file
View File

@ -0,0 +1,195 @@
use core::future::poll_fn;
use core::marker::PhantomData;
use core::task::Poll;
use embassy_hal_internal::into_ref;
use embedded_hal_02::blocking::delay::DelayUs;
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
use crate::interrupt::typelevel::Interrupt;
use crate::time::Hertz;
use crate::{interrupt, Peripheral};
pub const VDDA_CALIB_MV: u32 = 3300;
pub const ADC_MAX: u32 = (1 << 12) - 1;
pub const VREF_INT: u32 = 1230;
/// Interrupt handler.
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
if T::regs().isr().read().eoc() {
T::regs().ier().modify(|w| w.set_eocie(false));
} else {
return;
}
T::state().waker.wake();
}
}
pub struct Vref;
impl<T: Instance> AdcPin<T> for Vref {}
impl<T: Instance> super::sealed::AdcPin<T> for Vref {
fn channel(&self) -> u8 {
18
}
}
impl Vref {
/// The value that vref would be if vdda was at 3300mv
pub fn value(&self) -> u16 {
crate::pac::VREFINTCAL.data().read().value()
}
}
pub struct Temperature;
impl<T: Instance> AdcPin<T> for Temperature {}
impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
fn channel(&self) -> u8 {
16
}
}
impl<'d, T: Instance> Adc<'d, T> {
pub fn new(
adc: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
delay: &mut impl DelayUs<u32>,
) -> Self {
use crate::pac::adc::vals;
into_ref!(adc);
T::enable();
T::reset();
// Enable the adc regulator
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::ENABLED));
// Wait for the regulator to stabilize
delay.delay_us(10);
assert!(!T::regs().cr().read().aden());
// Begin calibration
T::regs().cr().modify(|w| w.set_adcaldif(false));
T::regs().cr().modify(|w| w.set_adcal(true));
while T::regs().cr().read().adcal() {}
// Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223)
delay.delay_us(1 + (6 * 1_000_000 / Self::freq().0));
// Enable the adc
T::regs().cr().modify(|w| w.set_aden(true));
// Wait until the adc is ready
while !T::regs().isr().read().adrdy() {}
T::Interrupt::unpend();
unsafe {
T::Interrupt::enable();
}
Self {
adc,
sample_time: Default::default(),
}
}
fn freq() -> Hertz {
<T as crate::adc::sealed::Instance>::frequency()
}
pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
match us * Self::freq().0 / 1_000_000 {
0..=1 => SampleTime::Cycles1_5,
2..=4 => SampleTime::Cycles4_5,
5..=7 => SampleTime::Cycles7_5,
8..=19 => SampleTime::Cycles19_5,
20..=61 => SampleTime::Cycles61_5,
62..=181 => SampleTime::Cycles181_5,
_ => SampleTime::Cycles601_5,
}
}
pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref {
T::common_regs().ccr().modify(|w| w.set_vrefen(true));
Vref {}
}
pub fn enable_temperature(&self) -> Temperature {
T::common_regs().ccr().modify(|w| w.set_tsen(true));
Temperature {}
}
pub fn set_sample_time(&mut self, sample_time: SampleTime) {
self.sample_time = sample_time;
}
/// Perform a single conversion.
async fn convert(&mut self) -> u16 {
T::regs().isr().write(|_| {});
T::regs().ier().modify(|w| w.set_eocie(true));
T::regs().cr().modify(|w| w.set_adstart(true));
poll_fn(|cx| {
T::state().waker.register(cx.waker());
if T::regs().isr().read().eoc() {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
T::regs().isr().write(|_| {});
T::regs().dr().read().rdata()
}
pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
Self::set_channel_sample_time(pin.channel(), self.sample_time);
// Configure the channel to sample
T::regs().sqr1().write(|w| w.set_sq(0, pin.channel()));
self.convert().await
}
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
let sample_time = sample_time.into();
if ch <= 9 {
T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time));
} else {
T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
}
}
}
impl<'d, T: Instance> Drop for Adc<'d, T> {
fn drop(&mut self) {
use crate::pac::adc::vals;
T::regs().cr().modify(|w| w.set_adstp(true));
while T::regs().cr().read().adstp() {}
T::regs().cr().modify(|w| w.set_addis(true));
while T::regs().cr().read().aden() {}
// Disable the adc regulator
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::DISABLED));
T::disable();
}
}

View File

@ -1,23 +1,24 @@
#![macro_use]
#[cfg(not(any(adc_f3, adc_f3_v2)))]
#[cfg(not(adc_f3_v2))]
#[cfg_attr(adc_f1, path = "f1.rs")]
#[cfg_attr(adc_f3, path = "f3.rs")]
#[cfg_attr(adc_v1, path = "v1.rs")]
#[cfg_attr(adc_v2, path = "v2.rs")]
#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")]
#[cfg_attr(adc_v4, path = "v4.rs")]
mod _version;
#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))]
#[cfg(not(any(adc_f1, adc_f3_v2)))]
mod resolution;
mod sample_time;
#[cfg(not(any(adc_f3, adc_f3_v2)))]
#[allow(unused)]
#[cfg(not(adc_f3_v2))]
pub use _version::*;
#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))]
pub use resolution::Resolution;
#[cfg(not(any(adc_f3, adc_f3_v2)))]
#[cfg(not(adc_f3_v2))]
pub use sample_time::SampleTime;
use crate::peripherals;
@ -25,18 +26,46 @@ use crate::peripherals;
pub struct Adc<'d, T: Instance> {
#[allow(unused)]
adc: crate::PeripheralRef<'d, T>,
#[cfg(not(any(adc_f3, adc_f3_v2)))]
#[cfg(not(adc_f3_v2))]
sample_time: SampleTime,
}
pub(crate) mod sealed {
pub trait Instance {
#[cfg(any(adc_f1, adc_f3, adc_v1))]
use embassy_sync::waitqueue::AtomicWaker;
#[cfg(any(adc_f1, adc_f3, adc_v1))]
pub struct State {
pub waker: AtomicWaker,
}
#[cfg(any(adc_f1, adc_f3, adc_v1))]
impl State {
pub const fn new() -> Self {
Self {
waker: AtomicWaker::new(),
}
}
}
pub trait InterruptableInstance {
type Interrupt: crate::interrupt::typelevel::Interrupt;
}
pub trait Instance: InterruptableInstance {
fn regs() -> crate::pac::adc::Adc;
#[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))]
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))]
fn common_regs() -> crate::pac::adccommon::AdcCommon;
#[cfg(adc_f3)]
fn frequency() -> crate::time::Hertz;
#[cfg(any(adc_f1, adc_f3, adc_v1))]
fn state() -> &'static State;
}
pub trait AdcPin<T: Instance> {
#[cfg(any(adc_v1, adc_v2))]
fn set_as_analog(&mut self) {}
fn channel(&self) -> u8;
}
@ -45,68 +74,45 @@ pub(crate) mod sealed {
}
}
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4)))]
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3)))]
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4))]
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3))]
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
#[cfg(not(stm32h7))]
foreach_peripheral!(
(adc, $inst:ident) => {
foreach_adc!(
($inst:ident, $common_inst:ident, $clock:ident) => {
impl crate::adc::sealed::Instance for peripherals::$inst {
fn regs() -> crate::pac::adc::Adc {
crate::pac::$inst
}
#[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))]
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))]
fn common_regs() -> crate::pac::adccommon::AdcCommon {
foreach_peripheral!{
(adccommon, $common_inst:ident) => {
return crate::pac::$common_inst
};
}
return crate::pac::$common_inst
}
#[cfg(adc_f3)]
fn frequency() -> crate::time::Hertz {
unsafe { crate::rcc::get_freqs() }.$clock.unwrap()
}
#[cfg(any(adc_f1, adc_f3, adc_v1))]
fn state() -> &'static sealed::State {
static STATE: sealed::State = sealed::State::new();
&STATE
}
}
impl crate::adc::Instance for peripherals::$inst {}
};
);
#[cfg(stm32h7)]
foreach_peripheral!(
(adc, ADC3) => {
impl crate::adc::sealed::Instance for peripherals::ADC3 {
fn regs() -> crate::pac::adc::Adc {
crate::pac::ADC3
}
#[cfg(all(not(adc_f1), not(adc_v1)))]
fn common_regs() -> crate::pac::adccommon::AdcCommon {
foreach_peripheral!{
(adccommon, ADC3_COMMON) => {
return crate::pac::ADC3_COMMON
};
foreach_interrupt!(
($inst,adc,ADC,GLOBAL,$irq:ident) => {
impl sealed::InterruptableInstance for peripherals::$inst {
type Interrupt = crate::interrupt::typelevel::$irq;
}
}
}
impl crate::adc::Instance for peripherals::ADC3 {}
};
(adc, $inst:ident) => {
impl crate::adc::sealed::Instance for peripherals::$inst {
fn regs() -> crate::pac::adc::Adc {
crate::pac::$inst
}
#[cfg(all(not(adc_f1), not(adc_v1)))]
fn common_regs() -> crate::pac::adccommon::AdcCommon {
foreach_peripheral!{
(adccommon, ADC_COMMON) => {
return crate::pac::ADC_COMMON
};
}
}
}
};
);
impl crate::adc::Instance for peripherals::$inst {}
};
@ -117,6 +123,11 @@ macro_rules! impl_adc_pin {
impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {}
impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin {
#[cfg(any(adc_v1, adc_v2))]
fn set_as_analog(&mut self) {
<Self as crate::gpio::sealed::Pin>::set_as_analog(self);
}
fn channel(&self) -> u8 {
$ch
}

View File

@ -1,4 +1,4 @@
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Resolution {
TwelveBit,
@ -19,7 +19,7 @@ pub enum Resolution {
impl Default for Resolution {
fn default() -> Self {
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
{
Self::TwelveBit
}
@ -40,7 +40,7 @@ impl From<Resolution> for crate::pac::adc::vals::Res {
Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
}
}
@ -56,7 +56,7 @@ impl Resolution {
Resolution::TwelveBit => (1 << 12) - 1,
Resolution::TenBit => (1 << 10) - 1,
Resolution::EightBit => (1 << 8) - 1,
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
Resolution::SixBit => (1 << 6) - 1,
}
}

View File

@ -1,4 +1,4 @@
#[cfg(not(any(adc_f3, adc_f3_v2)))]
#[cfg(not(adc_f3_v2))]
macro_rules! impl_sample_time {
($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => {
#[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")]
@ -105,3 +105,19 @@ impl_sample_time!(
("810.5", Cycles810_5, CYCLES810_5)
)
);
#[cfg(adc_f3)]
impl_sample_time!(
"1.5",
Cycles1_5,
(
("1.5", Cycles1_5, CYCLES1_5),
("2.5", Cycles2_5, CYCLES2_5),
("4.5", Cycles4_5, CYCLES4_5),
("7.5", Cycles7_5, CYCLES7_5),
("19.5", Cycles19_5, CYCLES19_5),
("61.5", Cycles61_5, CYCLES61_5),
("181.5", Cycles181_5, CYCLES181_5),
("601.5", Cycles601_5, CYCLES601_5)
)
);

View File

@ -1,39 +1,65 @@
use core::future::poll_fn;
use core::marker::PhantomData;
use core::task::Poll;
use embassy_hal_internal::into_ref;
use embedded_hal_02::blocking::delay::DelayUs;
use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
use crate::interrupt::typelevel::Interrupt;
use crate::peripherals::ADC;
use crate::Peripheral;
use crate::{interrupt, Peripheral};
pub const VDDA_CALIB_MV: u32 = 3300;
pub const VREF_INT: u32 = 1230;
/// Interrupt handler.
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
if T::regs().isr().read().eoc() {
T::regs().ier().modify(|w| w.set_eocie(false));
} else {
return;
}
T::state().waker.wake();
}
}
pub struct Vbat;
impl InternalChannel<ADC> for Vbat {}
impl super::sealed::InternalChannel<ADC> for Vbat {
impl AdcPin<ADC> for Vbat {}
impl super::sealed::AdcPin<ADC> for Vbat {
fn channel(&self) -> u8 {
18
}
}
pub struct Vref;
impl InternalChannel<ADC> for Vref {}
impl super::sealed::InternalChannel<ADC> for Vref {
impl AdcPin<ADC> for Vref {}
impl super::sealed::AdcPin<ADC> for Vref {
fn channel(&self) -> u8 {
17
}
}
pub struct Temperature;
impl InternalChannel<ADC> for Temperature {}
impl super::sealed::InternalChannel<ADC> for Temperature {
impl AdcPin<ADC> for Temperature {}
impl super::sealed::AdcPin<ADC> for Temperature {
fn channel(&self) -> u8 {
16
}
}
impl<'d, T: Instance> Adc<'d, T> {
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
pub fn new(
adc: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
delay: &mut impl DelayUs<u32>,
) -> Self {
into_ref!(adc);
T::enable();
T::reset();
@ -44,12 +70,32 @@ impl<'d, T: Instance> Adc<'d, T> {
// tstab = 14 * 1/fadc
delay.delay_us(1);
let s = Self {
// A.7.1 ADC calibration code example
T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
T::regs().cr().modify(|reg| reg.set_adcal(true));
while T::regs().cr().read().adcal() {}
// A.7.2 ADC enable sequence code example
if T::regs().isr().read().adrdy() {
T::regs().isr().modify(|reg| reg.set_adrdy(true));
}
T::regs().cr().modify(|reg| reg.set_aden(true));
while !T::regs().isr().read().adrdy() {
// ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration
// Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the
// ADEN bit until the ADRDY flag goes high.
T::regs().cr().modify(|reg| reg.set_aden(true));
}
T::Interrupt::unpend();
unsafe {
T::Interrupt::enable();
}
Self {
adc,
sample_time: Default::default(),
};
s.calibrate();
s
}
}
pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat {
@ -80,21 +126,6 @@ impl<'d, T: Instance> Adc<'d, T> {
Temperature
}
fn calibrate(&self) {
// A.7.1 ADC calibration code example
if T::regs().cr().read().aden() {
T::regs().cr().modify(|reg| reg.set_addis(true));
}
while T::regs().cr().read().aden() {
// spin
}
T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
T::regs().cr().modify(|reg| reg.set_adcal(true));
while T::regs().cr().read().adcal() {
// spin
}
}
pub fn set_sample_time(&mut self, sample_time: SampleTime) {
self.sample_time = sample_time;
}
@ -103,57 +134,50 @@ impl<'d, T: Instance> Adc<'d, T> {
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
}
pub fn read<P>(&mut self, pin: &mut P) -> u16
where
P: AdcPin<T> + crate::gpio::sealed::Pin,
{
pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
let channel = pin.channel();
pin.set_as_analog();
self.read_channel(channel)
// A.7.5 Single conversion sequence code example - Software trigger
T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true));
self.convert().await
}
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
let channel = channel.channel();
self.read_channel(channel)
}
fn read_channel(&mut self, channel: u8) -> u16 {
// A.7.2 ADC enable sequence code example
if T::regs().isr().read().adrdy() {
T::regs().isr().modify(|reg| reg.set_adrdy(true));
}
T::regs().cr().modify(|reg| reg.set_aden(true));
while !T::regs().isr().read().adrdy() {
// ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration
// Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the
// ADEN bit until the ADRDY flag goes high.
T::regs().cr().modify(|reg| reg.set_aden(true));
}
async fn convert(&mut self) -> u16 {
T::regs().isr().modify(|reg| {
reg.set_eoc(true);
reg.set_eosmp(true);
});
// A.7.5 Single conversion sequence code example - Software trigger
T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true));
T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into()));
T::regs().ier().modify(|w| w.set_eocie(true));
T::regs().cr().modify(|reg| reg.set_adstart(true));
while !T::regs().isr().read().eoc() {
// spin
}
let value = T::regs().dr().read().0 as u16;
// A.7.3 ADC disable code example
T::regs().cr().modify(|reg| reg.set_adstp(true));
while T::regs().cr().read().adstp() {
// spin
}
T::regs().cr().modify(|reg| reg.set_addis(true));
while T::regs().cr().read().aden() {
// spin
}
poll_fn(|cx| {
T::state().waker.register(cx.waker());
value
if T::regs().isr().read().eoc() {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
T::regs().dr().read().data()
}
}
impl<'d, T: Instance> Drop for Adc<'d, T> {
fn drop(&mut self) {
// A.7.3 ADC disable code example
T::regs().cr().modify(|reg| reg.set_adstp(true));
while T::regs().cr().read().adstp() {}
T::regs().cr().modify(|reg| reg.set_addis(true));
while T::regs().cr().read().aden() {}
T::disable();
}
}

View File

@ -1,7 +1,6 @@
use embassy_hal_internal::into_ref;
use embedded_hal_02::blocking::delay::DelayUs;
use super::InternalChannel;
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
use crate::peripherals::ADC1;
use crate::time::Hertz;
@ -16,8 +15,8 @@ pub const VREF_CALIB_MV: u32 = 3300;
pub const ADC_POWERUP_TIME_US: u32 = 3;
pub struct VrefInt;
impl InternalChannel<ADC1> for VrefInt {}
impl super::sealed::InternalChannel<ADC1> for VrefInt {
impl AdcPin<ADC1> for VrefInt {}
impl super::sealed::AdcPin<ADC1> for VrefInt {
fn channel(&self) -> u8 {
17
}
@ -31,8 +30,8 @@ impl VrefInt {
}
pub struct Temperature;
impl InternalChannel<ADC1> for Temperature {}
impl super::sealed::InternalChannel<ADC1> for Temperature {
impl AdcPin<ADC1> for Temperature {}
impl super::sealed::AdcPin<ADC1> for Temperature {
fn channel(&self) -> u8 {
cfg_if::cfg_if! {
if #[cfg(any(stm32f40, stm32f41))] {
@ -52,8 +51,8 @@ impl Temperature {
}
pub struct Vbat;
impl InternalChannel<ADC1> for Vbat {}
impl super::sealed::InternalChannel<ADC1> for Vbat {
impl AdcPin<ADC1> for Vbat {}
impl super::sealed::AdcPin<ADC1> for Vbat {
fn channel(&self) -> u8 {
18
}
@ -102,7 +101,7 @@ where
let presc = Prescaler::from_pclk2(T::frequency());
T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
T::regs().cr2().modify(|reg| {
reg.set_adon(crate::pac::adc::vals::Adon::ENABLED);
reg.set_adon(true);
});
delay.delay_us(ADC_POWERUP_TIME_US);
@ -125,7 +124,7 @@ where
/// [Adc::read_internal()] to perform conversion.
pub fn enable_vrefint(&self) -> VrefInt {
T::common_regs().ccr().modify(|reg| {
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
reg.set_tsvrefe(true);
});
VrefInt {}
@ -138,7 +137,7 @@ where
/// temperature sensor will return vbat value.
pub fn enable_temperature(&self) -> Temperature {
T::common_regs().ccr().modify(|reg| {
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
reg.set_tsvrefe(true);
});
Temperature {}
@ -148,7 +147,7 @@ where
/// [Adc::read_internal()] to perform conversion.
pub fn enable_vbat(&self) -> Vbat {
T::common_regs().ccr().modify(|reg| {
reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED);
reg.set_vbate(true);
});
Vbat {}
@ -176,22 +175,11 @@ where
T::regs().dr().read().0 as u16
}
pub fn read<P>(&mut self, pin: &mut P) -> u16
where
P: AdcPin<T>,
P: crate::gpio::sealed::Pin,
{
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
pin.set_as_analog();
self.read_channel(pin.channel())
}
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
self.read_channel(channel.channel())
}
fn read_channel(&mut self, channel: u8) -> u16 {
// Configure ADC
let channel = pin.channel();
// Select channel
T::regs().sqr3().write(|reg| reg.set_sq(0, channel));
@ -199,9 +187,7 @@ where
// Configure channel
Self::set_channel_sample_time(channel, self.sample_time);
let val = self.convert();
val
self.convert()
}
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
@ -216,6 +202,10 @@ where
impl<'d, T: Instance> Drop for Adc<'d, T> {
fn drop(&mut self) {
T::regs().cr2().modify(|reg| {
reg.set_adon(false);
});
T::disable();
}
}

View File

@ -13,7 +13,7 @@ pub const VREF_CALIB_MV: u32 = 3000;
/// configuration.
fn enable() {
critical_section::with(|_| {
#[cfg(stm32h7)]
#[cfg(any(stm32h7, stm32wl))]
crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true));
#[cfg(stm32g0)]
crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true));
@ -26,9 +26,9 @@ pub struct VrefInt;
impl<T: Instance> AdcPin<T> for VrefInt {}
impl<T: Instance> super::sealed::AdcPin<T> for VrefInt {
fn channel(&self) -> u8 {
#[cfg(not(stm32g0))]
#[cfg(not(adc_g0))]
let val = 0;
#[cfg(stm32g0)]
#[cfg(adc_g0)]
let val = 13;
val
}
@ -38,9 +38,9 @@ pub struct Temperature;
impl<T: Instance> AdcPin<T> for Temperature {}
impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
fn channel(&self) -> u8 {
#[cfg(not(stm32g0))]
#[cfg(not(adc_g0))]
let val = 17;
#[cfg(stm32g0)]
#[cfg(adc_g0)]
let val = 12;
val
}
@ -50,9 +50,9 @@ pub struct Vbat;
impl<T: Instance> AdcPin<T> for Vbat {}
impl<T: Instance> super::sealed::AdcPin<T> for Vbat {
fn channel(&self) -> u8 {
#[cfg(not(stm32g0))]
#[cfg(not(adc_g0))]
let val = 18;
#[cfg(stm32g0)]
#[cfg(adc_g0)]
let val = 14;
val
}
@ -92,9 +92,14 @@ impl<'d, T: Instance> Adc<'d, T> {
}
pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt {
#[cfg(not(adc_g0))]
T::common_regs().ccr().modify(|reg| {
reg.set_vrefen(true);
});
#[cfg(adc_g0)]
T::regs().ccr().modify(|reg| {
reg.set_vrefen(true);
});
// "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
// to stabilize the internal voltage reference, we wait a little more.
@ -106,17 +111,27 @@ impl<'d, T: Instance> Adc<'d, T> {
}
pub fn enable_temperature(&self) -> Temperature {
#[cfg(not(adc_g0))]
T::common_regs().ccr().modify(|reg| {
reg.set_ch17sel(true);
});
#[cfg(adc_g0)]
T::regs().ccr().modify(|reg| {
reg.set_tsen(true);
});
Temperature {}
}
pub fn enable_vbat(&self) -> Vbat {
#[cfg(not(adc_g0))]
T::common_regs().ccr().modify(|reg| {
reg.set_ch18sel(true);
});
#[cfg(adc_g0)]
T::regs().ccr().modify(|reg| {
reg.set_vbaten(true);
});
Vbat {}
}
@ -126,9 +141,9 @@ impl<'d, T: Instance> Adc<'d, T> {
}
pub fn set_resolution(&mut self, resolution: Resolution) {
#[cfg(not(stm32g0))]
#[cfg(not(adc_g0))]
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
#[cfg(stm32g0)]
#[cfg(adc_g0)]
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
}
@ -182,9 +197,9 @@ impl<'d, T: Instance> Adc<'d, T> {
Self::set_channel_sample_time(pin.channel(), self.sample_time);
// Select channel
#[cfg(not(stm32g0))]
#[cfg(not(adc_g0))]
T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
#[cfg(stm32g0)]
#[cfg(adc_g0)]
T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel()));
// Some models are affected by an erratum:
@ -203,12 +218,12 @@ impl<'d, T: Instance> Adc<'d, T> {
val
}
#[cfg(stm32g0)]
#[cfg(adc_g0)]
fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
}
#[cfg(not(stm32g0))]
#[cfg(not(adc_g0))]
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
let sample_time = sample_time.into();
T::regs()

View File

@ -1,6 +1,5 @@
use core::sync::atomic::{AtomicU8, Ordering};
use embedded_hal_02::blocking::delay::DelayUs;
#[allow(unused)]
use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel};
use pac::adccommon::vals::Presc;
@ -13,12 +12,31 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
/// VREF voltage used for factory calibration of VREFINTCAL register.
pub const VREF_CALIB_MV: u32 = 3300;
// NOTE: Vrefint/Temperature/Vbat are only available on ADC3 on H7, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
/// Max single ADC operation clock frequency
#[cfg(stm32g4)]
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
#[cfg(stm32h7)]
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
#[cfg(stm32g4)]
const VREF_CHANNEL: u8 = 18;
#[cfg(stm32g4)]
const TEMP_CHANNEL: u8 = 16;
#[cfg(stm32h7)]
const VREF_CHANNEL: u8 = 19;
#[cfg(stm32h7)]
const TEMP_CHANNEL: u8 = 18;
// TODO this should be 14 for H7a/b/35
const VBAT_CHANNEL: u8 = 17;
// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
pub struct VrefInt;
impl<T: Instance> InternalChannel<T> for VrefInt {}
impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt {
fn channel(&self) -> u8 {
19
VREF_CHANNEL
}
}
@ -26,7 +44,7 @@ pub struct Temperature;
impl<T: Instance> InternalChannel<T> for Temperature {}
impl<T: Instance> super::sealed::InternalChannel<T> for Temperature {
fn channel(&self) -> u8 {
18
TEMP_CHANNEL
}
}
@ -34,128 +52,10 @@ pub struct Vbat;
impl<T: Instance> InternalChannel<T> for Vbat {}
impl<T: Instance> super::sealed::InternalChannel<T> for Vbat {
fn channel(&self) -> u8 {
// TODO this should be 14 for H7a/b/35
17
VBAT_CHANNEL
}
}
static ADC12_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0);
#[cfg(stm32h7)]
foreach_peripheral!(
(adc, ADC1) => {
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| {
match unsafe { crate::rcc::get_freqs() }.adc {
Some(ck) => ck,
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
}
})
}
fn enable() {
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
});
ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
}
fn disable() {
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
})
}
ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst);
}
fn reset() {
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
critical_section::with(|_| {
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
});
}
}
}
impl crate::rcc::RccPeripheral for crate::peripherals::ADC1 {}
};
(adc, ADC2) => {
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| {
match unsafe { crate::rcc::get_freqs() }.adc {
Some(ck) => ck,
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
}
})
}
fn enable() {
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
});
ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
}
fn disable() {
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
})
}
ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst);
}
fn reset() {
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
critical_section::with(|_| {
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
});
}
}
}
impl crate::rcc::RccPeripheral for crate::peripherals::ADC2 {}
};
(adc, ADC3) => {
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| {
match unsafe { crate::rcc::get_freqs() }.adc {
Some(ck) => ck,
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
}
})
}
fn enable() {
critical_section::with(|_| {
crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true))
});
}
fn disable() {
critical_section::with(|_| {
crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false));
})
}
fn reset() {
critical_section::with(|_| {
crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true));
crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false));
});
}
}
impl crate::rcc::RccPeripheral for crate::peripherals::ADC3 {}
};
);
// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
// but high prescaling doesn't make a lot of sense in the current implementation and is ommited.
#[allow(unused)]
@ -176,7 +76,7 @@ enum Prescaler {
impl Prescaler {
fn from_ker_ck(frequency: Hertz) -> Self {
let raw_prescaler = frequency.0 / 50_000_000;
let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
match raw_prescaler {
0 => Self::NotDivided,
1 => Self::DividedBy2,
@ -237,20 +137,23 @@ impl<'d, T: Instance> Adc<'d, T> {
let frequency = Hertz(T::frequency().0 / prescaler.divisor());
info!("ADC frequency set to {} Hz", frequency.0);
if frequency > Hertz::mhz(50) {
panic!("Maximal allowed frequency for the ADC is 50 MHz and it varies with different packages, refer to ST docs for more information.");
if frequency > MAX_ADC_CLK_FREQ {
panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 );
}
let boost = if frequency < Hertz::khz(6_250) {
Boost::LT6_25
} else if frequency < Hertz::khz(12_500) {
Boost::LT12_5
} else if frequency < Hertz::mhz(25) {
Boost::LT25
} else {
Boost::LT50
};
T::regs().cr().modify(|w| w.set_boost(boost));
#[cfg(stm32h7)]
{
let boost = if frequency < Hertz::khz(6_250) {
Boost::LT6_25
} else if frequency < Hertz::khz(12_500) {
Boost::LT12_5
} else if frequency < Hertz::mhz(25) {
Boost::LT25
} else {
Boost::LT50
};
T::regs().cr().modify(|w| w.set_boost(boost));
}
let mut s = Self {
adc,
sample_time: Default::default(),
@ -379,10 +282,14 @@ impl<'d, T: Instance> Adc<'d, T> {
// Configure channel
Self::set_channel_sample_time(channel, self.sample_time);
T::regs().cfgr2().modify(|w| w.set_lshift(0));
T::regs()
.pcsel()
.write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
#[cfg(stm32h7)]
{
T::regs().cfgr2().modify(|w| w.set_lshift(0));
T::regs()
.pcsel()
.write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
}
T::regs().sqr1().write(|reg| {
reg.set_sq(0, channel);
reg.set_l(0);

View File

@ -129,7 +129,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
#[cfg(any(eth_v1b, eth_v1c))]
critical_section::with(|_| {
RCC.apb2enr().modify(|w| w.set_syscfgen(true));
RCC.ahb1enr().modify(|w| {
w.set_ethen(true);
w.set_ethtxen(true);

View File

@ -34,8 +34,6 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
}
}
const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet
pub struct Ethernet<'d, T: Instance, P: PHY> {
_peri: PeripheralRef<'d, T>,
pub(crate) tx: TDesRing<'d>,
@ -80,7 +78,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
// Enable the necessary Clocks
#[cfg(not(rcc_h5))]
critical_section::with(|_| {
crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true));
crate::pac::RCC.ahb1enr().modify(|w| {
w.set_eth1macen(true);
w.set_eth1txen(true);
@ -102,9 +99,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
});
// RMII
crate::pac::SBS
crate::pac::SYSCFG
.pmcr()
.modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4));
.modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4));
});
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
@ -164,7 +161,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ?
dma.dmacrx_cr().modify(|w| {
w.set_rxpbl(1); // 32 ?
w.set_rbsz(MTU as u16);
w.set_rbsz(RX_BUFFER_SIZE as u16);
});
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called

View File

@ -6,7 +6,7 @@ use core::task::{Context, Poll};
use embassy_hal_internal::impl_peripheral;
use embassy_sync::waitqueue::AtomicWaker;
use crate::gpio::{AnyPin, Input, Pin as GpioPin};
use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin};
use crate::pac::exti::regs::Lines;
use crate::pac::EXTI;
use crate::{interrupt, pac, peripherals, Peripheral};
@ -39,6 +39,9 @@ fn exticr_regs() -> pac::afio::Afio {
}
pub unsafe fn on_irq() {
#[cfg(feature = "low-power")]
crate::low_power::on_wakeup_irq();
#[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))]
let bits = EXTI.pr(0).read().0;
#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
@ -98,6 +101,10 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
self.pin.is_low()
}
pub fn get_level(&self) -> Level {
self.pin.get_level()
}
pub async fn wait_for_high<'a>(&'a mut self) {
let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false);
if self.is_high() {
@ -364,9 +371,4 @@ pub(crate) unsafe fn init() {
use crate::interrupt::typelevel::Interrupt;
foreach_exti_irq!(enable_irq);
#[cfg(not(any(rcc_wb, rcc_wl5, rcc_wle, stm32f1, exti_h5, exti_h50)))]
<crate::peripherals::SYSCFG as crate::rcc::sealed::RccPeripheral>::enable();
#[cfg(stm32f1)]
<crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable();
}

View File

@ -1,6 +1,8 @@
#![macro_use]
#![allow(unused_macros)]
use core::fmt::{Debug, Display, LowerHex};
#[cfg(all(feature = "defmt", feature = "log"))]
compile_error!("You may not enable both `defmt` and `log` features.");
@ -81,14 +83,17 @@ macro_rules! todo {
};
}
#[cfg(not(feature = "defmt"))]
macro_rules! unreachable {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::unreachable!($($x)*);
#[cfg(feature = "defmt")]
::defmt::unreachable!($($x)*);
}
::core::unreachable!($($x)*)
};
}
#[cfg(feature = "defmt")]
macro_rules! unreachable {
($($x:tt)*) => {
::defmt::unreachable!($($x)*)
};
}
@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
self
}
}
#[allow(unused)]
pub(crate) struct Bytes<'a>(pub &'a [u8]);
impl<'a> Debug for Bytes<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#02x?}", self.0)
}
}
impl<'a> Display for Bytes<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#02x?}", self.0)
}
}
impl<'a> LowerHex for Bytes<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#02x?}", self.0)
}
}
#[cfg(feature = "defmt")]
impl<'a> defmt::Format for Bytes<'a> {
fn format(&self, fmt: defmt::Formatter) {
defmt::write!(fmt, "{:02x}", self.0)
}
}

View File

@ -758,6 +758,9 @@ foreach_pin!(
);
pub(crate) unsafe fn init() {
#[cfg(afio)]
<crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable();
crate::_generated::init_gpio();
}

View File

@ -8,6 +8,8 @@ pub use traits::Instance;
#[allow(unused_imports)]
use crate::gpio::sealed::{AFType, Pin};
use crate::gpio::AnyPin;
#[cfg(stm32f334)]
use crate::rcc::get_freqs;
use crate::time::Hertz;
use crate::Peripheral;
@ -158,17 +160,29 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
T::enable();
<T as crate::rcc::sealed::RccPeripheral>::reset();
// // Enable and and stabilize the DLL
// T::regs().dllcr().modify(|w| {
// // w.set_calen(true);
// // w.set_calrte(11);
// w.set_cal(true);
// });
//
// debug!("wait for dll calibration");
// while !T::regs().isr().read().dllrdy() {}
//
// debug!("dll calibration complete");
#[cfg(stm32f334)]
if unsafe { get_freqs() }.hrtim.is_some() {
// Enable and and stabilize the DLL
T::regs().dllcr().modify(|w| {
w.set_cal(true);
});
trace!("hrtim: wait for dll calibration");
while !T::regs().isr().read().dllrdy() {}
trace!("hrtim: dll calibration complete");
// Enable periodic calibration
// Cal must be disabled before we can enable it
T::regs().dllcr().modify(|w| {
w.set_cal(false);
});
T::regs().dllcr().modify(|w| {
w.set_calen(true);
w.set_calrte(11);
});
}
Self {
_inner: tim,

View File

@ -1,31 +1,17 @@
use crate::rcc::sealed::RccPeripheral;
use crate::time::Hertz;
#[repr(u8)]
#[derive(Clone, Copy)]
pub(crate) enum Prescaler {
Div1,
Div2,
Div4,
Div8,
Div16,
Div32,
Div64,
Div128,
}
impl From<Prescaler> for u32 {
fn from(val: Prescaler) -> Self {
match val {
Prescaler::Div1 => 1,
Prescaler::Div2 => 2,
Prescaler::Div4 => 4,
Prescaler::Div8 => 8,
Prescaler::Div16 => 16,
Prescaler::Div32 => 32,
Prescaler::Div64 => 64,
Prescaler::Div128 => 128,
}
}
Div1 = 1,
Div2 = 2,
Div4 = 4,
Div8 = 8,
Div16 = 16,
Div32 = 32,
Div64 = 64,
Div128 = 128,
}
impl From<Prescaler> for u8 {
@ -72,7 +58,7 @@ impl Prescaler {
Prescaler::Div128,
]
.iter()
.skip_while(|psc| <Prescaler as Into<u32>>::into(**psc) <= val)
.skip_while(|psc| **psc as u32 <= val)
.next()
.unwrap()
}
@ -80,7 +66,7 @@ impl Prescaler {
pub fn compute_min_low_res(val: u32) -> Self {
*[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128]
.iter()
.skip_while(|psc| <Prescaler as Into<u32>>::into(**psc) <= val)
.skip_while(|psc| **psc as u32 <= val)
.next()
.unwrap()
}
@ -92,12 +78,76 @@ pub(crate) mod sealed {
pub trait Instance: RccPeripheral {
fn regs() -> crate::pac::hrtim::Hrtim;
fn set_master_frequency(frequency: Hertz);
fn set_master_frequency(frequency: Hertz) {
let f = frequency.0;
#[cfg(not(stm32f334))]
let timer_f = Self::frequency().0;
#[cfg(stm32f334)]
let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
fn set_channel_frequency(channnel: usize, frequency: Hertz);
let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
let psc = if Self::regs().isr().read().dllrdy() {
Prescaler::compute_min_high_res(psc_min)
} else {
Prescaler::compute_min_low_res(psc_min)
};
let timer_f = 32 * (timer_f / psc as u32);
let per: u16 = (timer_f / f) as u16;
let regs = Self::regs();
regs.mcr().modify(|w| w.set_ckpsc(psc.into()));
regs.mper().modify(|w| w.set_mper(per));
}
fn set_channel_frequency(channel: usize, frequency: Hertz) {
let f = frequency.0;
#[cfg(not(stm32f334))]
let timer_f = Self::frequency().0;
#[cfg(stm32f334)]
let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
let psc = if Self::regs().isr().read().dllrdy() {
Prescaler::compute_min_high_res(psc_min)
} else {
Prescaler::compute_min_low_res(psc_min)
};
let timer_f = 32 * (timer_f / psc as u32);
let per: u16 = (timer_f / f) as u16;
let regs = Self::regs();
regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into()));
regs.tim(channel).per().modify(|w| w.set_per(per));
}
/// Set the dead time as a proportion of max_duty
fn set_channel_dead_time(channnel: usize, dead_time: u16);
fn set_channel_dead_time(channel: usize, dead_time: u16) {
let regs = Self::regs();
let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into();
// The dead-time base clock runs 4 times slower than the hrtim base clock
// u9::MAX = 511
let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511);
let psc = if Self::regs().isr().read().dllrdy() {
Prescaler::compute_min_high_res(psc_min)
} else {
Prescaler::compute_min_low_res(psc_min)
};
let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32);
regs.tim(channel).dt().modify(|w| {
w.set_dtprsc(psc.into());
w.set_dtf(dt_val as u16);
w.set_dtr(dt_val as u16);
});
}
// fn enable_outputs(enable: bool);
//
@ -113,77 +163,6 @@ foreach_interrupt! {
fn regs() -> crate::pac::hrtim::Hrtim {
crate::pac::$inst
}
fn set_master_frequency(frequency: Hertz) {
use crate::rcc::sealed::RccPeripheral;
let f = frequency.0;
let timer_f = Self::frequency().0;
let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
let psc = if Self::regs().isr().read().dllrdy() {
Prescaler::compute_min_high_res(psc_min)
} else {
Prescaler::compute_min_low_res(psc_min)
};
let psc_val: u32 = psc.into();
let timer_f = 32 * (timer_f / psc_val);
let per: u16 = (timer_f / f) as u16;
let regs = Self::regs();
regs.mcr().modify(|w| w.set_ckpsc(psc.into()));
regs.mper().modify(|w| w.set_mper(per));
}
fn set_channel_frequency(channel: usize, frequency: Hertz) {
use crate::rcc::sealed::RccPeripheral;
let f = frequency.0;
let timer_f = Self::frequency().0;
let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
let psc = if Self::regs().isr().read().dllrdy() {
Prescaler::compute_min_high_res(psc_min)
} else {
Prescaler::compute_min_low_res(psc_min)
};
let psc_val: u32 = psc.into();
let timer_f = 32 * (timer_f / psc_val);
let per: u16 = (timer_f / f) as u16;
let regs = Self::regs();
regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into()));
regs.tim(channel).per().modify(|w| w.set_per(per));
}
fn set_channel_dead_time(channel: usize, dead_time: u16) {
let regs = Self::regs();
let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into();
let psc_val: u32 = channel_psc.into();
// The dead-time base clock runs 4 times slower than the hrtim base clock
// u9::MAX = 511
let psc_min = (psc_val * dead_time as u32) / (4 * 511);
let psc = if Self::regs().isr().read().dllrdy() {
Prescaler::compute_min_high_res(psc_min)
} else {
Prescaler::compute_min_low_res(psc_min)
};
let dt_psc_val: u32 = psc.into();
let dt_val = (dt_psc_val * dead_time as u32) / (4 * psc_val);
regs.tim(channel).dt().modify(|w| {
w.set_dtprsc(psc.into());
w.set_dtf(dt_val as u16);
w.set_dtr(dt_val as u16);
});
}
}
impl Instance for crate::peripherals::$inst {

View File

@ -339,6 +339,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
}
}
impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
fn drop(&mut self) {
T::disable();
}
}
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
type Error = Error;

View File

@ -838,6 +838,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
}
}
impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
fn drop(&mut self) {
T::disable();
}
}
mod eh02 {
use super::*;

View File

@ -90,6 +90,7 @@ pub use crate::_generated::interrupt;
#[macro_export]
macro_rules! bind_interrupts {
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
#[derive(Copy, Clone)]
$vis struct $name;
$(
@ -119,6 +120,7 @@ pub(crate) use stm32_metapac as pac;
use crate::interrupt::Priority;
#[cfg(feature = "rt")]
pub use crate::pac::NVIC_PRIO_BITS;
use crate::rcc::sealed::RccPeripheral;
#[non_exhaustive]
pub struct Config {
@ -156,7 +158,7 @@ pub fn init(config: Config) -> Peripherals {
#[cfg(dbgmcu)]
if config.enable_debug_during_sleep {
crate::pac::DBGMCU.cr().modify(|cr| {
#[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))]
#[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))]
{
cr.set_dbg_stop(true);
cr.set_dbg_standby(true);
@ -181,6 +183,13 @@ pub fn init(config: Config) -> Peripherals {
});
}
#[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
peripherals::SYSCFG::enable();
#[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))]
peripherals::PWR::enable();
#[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))]
peripherals::FLASH::enable();
unsafe {
gpio::init();
dma::init(
@ -199,6 +208,11 @@ pub fn init(config: Config) -> Peripherals {
// must be after rcc init
#[cfg(feature = "_time-driver")]
time_driver::init();
#[cfg(feature = "low-power")]
while !crate::rcc::low_power_ready() {
crate::rcc::clock_refcount_sub();
}
}
p

View File

@ -3,45 +3,33 @@ use core::marker::PhantomData;
use cortex_m::peripheral::SCB;
use embassy_executor::*;
use embassy_time::Duration;
use crate::interrupt;
use crate::interrupt::typelevel::Interrupt;
use crate::pac::EXTI;
use crate::rcc::low_power_ready;
use crate::time_driver::{get_driver, RtcDriver};
const THREAD_PENDER: usize = usize::MAX;
const THRESHOLD: Duration = Duration::from_millis(500);
use crate::rtc::{Rtc, RtcInstant};
use crate::rtc::Rtc;
static mut RTC: Option<&'static Rtc> = None;
static mut EXECUTOR: Option<Executor> = None;
foreach_interrupt! {
(RTC, rtc, $block:ident, WKUP, $irq:ident) => {
#[interrupt]
unsafe fn $irq() {
Executor::on_wakeup_irq();
EXECUTOR.as_mut().unwrap().on_wakeup_irq();
}
};
}
#[allow(dead_code)]
pub(crate) unsafe fn on_wakeup_irq() {
EXECUTOR.as_mut().unwrap().on_wakeup_irq();
}
pub fn stop_with_rtc(rtc: &'static Rtc) {
crate::interrupt::typelevel::RTC_WKUP::unpend();
unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() };
EXTI.rtsr(0).modify(|w| w.set_line(22, true));
EXTI.imr(0).modify(|w| w.set_line(22, true));
unsafe { RTC = Some(rtc) };
}
pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) -> RtcInstant {
unsafe { RTC }.unwrap().start_wakeup_alarm(requested_duration)
}
pub fn stop_wakeup_alarm() -> RtcInstant {
unsafe { RTC }.unwrap().stop_wakeup_alarm()
unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
}
/// Thread mode executor, using WFE/SEV.
@ -57,54 +45,58 @@ pub fn stop_wakeup_alarm() -> RtcInstant {
pub struct Executor {
inner: raw::Executor,
not_send: PhantomData<*mut ()>,
scb: SCB,
time_driver: &'static RtcDriver,
}
impl Executor {
/// Create a new Executor.
pub fn new() -> Self {
Self {
inner: raw::Executor::new(THREAD_PENDER as *mut ()),
not_send: PhantomData,
pub fn take() -> &'static mut Self {
unsafe {
assert!(EXECUTOR.is_none());
EXECUTOR = Some(Self {
inner: raw::Executor::new(THREAD_PENDER as *mut ()),
not_send: PhantomData,
scb: cortex_m::Peripherals::steal().SCB,
time_driver: get_driver(),
});
EXECUTOR.as_mut().unwrap()
}
}
unsafe fn on_wakeup_irq() {
info!("on wakeup irq");
unsafe fn on_wakeup_irq(&mut self) {
trace!("low power: on wakeup irq");
cortex_m::asm::bkpt();
self.time_driver.resume_time();
trace!("low power: resume time");
}
fn time_until_next_alarm(&self) -> Duration {
Duration::from_secs(3)
pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) {
self.time_driver.set_rtc(rtc);
rtc.enable_wakeup_line();
trace!("low power: stop with rtc configured");
}
fn get_scb() -> SCB {
unsafe { cortex_m::Peripherals::steal() }.SCB
}
fn configure_pwr(&self) {
trace!("configure_pwr");
fn configure_pwr(&mut self) {
trace!("low power: configure_pwr");
self.scb.clear_sleepdeep();
if !low_power_ready() {
trace!("low power: configure_pwr: low power not ready");
return;
}
let time_until_next_alarm = self.time_until_next_alarm();
if time_until_next_alarm < THRESHOLD {
if self.time_driver.pause_time().is_err() {
trace!("low power: configure_pwr: time driver failed to pause");
return;
}
trace!("low power stop required");
critical_section::with(|_| {
trace!("executor: set wakeup alarm...");
start_wakeup_alarm(time_until_next_alarm);
trace!("low power wait for rtc ready...");
Self::get_scb().set_sleepdeep();
});
trace!("low power: enter stop...");
self.scb.set_sleepdeep();
}
/// Run the executor.
@ -126,11 +118,11 @@ impl Executor {
///
/// This function never returns.
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
init(self.inner.spawner());
init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner());
loop {
unsafe {
self.inner.poll();
EXECUTOR.as_mut().unwrap().inner.poll();
self.configure_pwr();
asm!("wfe");
};

176
embassy-stm32/src/rcc/bd.rs Normal file
View File

@ -0,0 +1,176 @@
#[allow(dead_code)]
#[derive(Default, Clone, Copy)]
pub enum LseDrive {
#[cfg(any(rtc_v2f7, rtc_v2l4))]
Low = 0,
MediumLow = 0x01,
#[default]
MediumHigh = 0x02,
#[cfg(any(rtc_v2f7, rtc_v2l4))]
High = 0x03,
}
#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))]
impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
fn from(value: LseDrive) -> Self {
use crate::pac::rcc::vals::Lsedrv;
match value {
#[cfg(any(rtc_v2f7, rtc_v2l4))]
LseDrive::Low => Lsedrv::LOW,
LseDrive::MediumLow => Lsedrv::MEDIUMLOW,
LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH,
#[cfg(any(rtc_v2f7, rtc_v2l4))]
LseDrive::High => Lsedrv::HIGH,
}
}
}
pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource;
#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))]
#[allow(dead_code)]
type Bdcr = crate::pac::rcc::regs::Bdcr;
#[cfg(any(rtc_v2l0, rtc_v2l1))]
#[allow(dead_code)]
type Bdcr = crate::pac::rcc::regs::Csr;
#[allow(dead_code)]
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, rtc_v3,
rtc_v3u5
))]
#[allow(dead_code, unused_variables)]
fn modify<R>(f: impl FnOnce(&mut Bdcr) -> R) -> R {
#[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1, rtc_v2l0))]
let cr = crate::pac::PWR.cr();
#[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
let cr = crate::pac::PWR.cr1();
// TODO: Missing from PAC for l0 and f0?
#[cfg(not(any(rtc_v2f0, rtc_v3u5)))]
{
cr.modify(|w| w.set_dbp(true));
while !cr.read().dbp() {}
}
#[cfg(any(rtc_v2l0, rtc_v2l1))]
let cr = crate::pac::RCC.csr();
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
let cr = crate::pac::RCC.bdcr();
cr.modify(|w| f(w))
}
#[cfg(any(
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3,
rtc_v3u5
))]
#[allow(dead_code)]
fn read() -> Bdcr {
#[cfg(any(rtc_v2l0, rtc_v2l1))]
let r = crate::pac::RCC.csr().read();
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
let r = crate::pac::RCC.bdcr().read();
r
}
#[cfg(any(
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3,
rtc_v3u5
))]
#[allow(dead_code, unused_variables)]
pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option<LseDrive>) {
if lsi {
#[cfg(rtc_v3u5)]
let csr = crate::pac::RCC.bdcr();
#[cfg(not(rtc_v3u5))]
let csr = crate::pac::RCC.csr();
// Disable backup domain write protection
Self::modify(|_| {});
#[cfg(not(any(rcc_wb, rcc_wba)))]
csr.modify(|w| w.set_lsion(true));
#[cfg(any(rcc_wb, rcc_wba))]
csr.modify(|w| w.set_lsi1on(true));
#[cfg(not(any(rcc_wb, rcc_wba)))]
while !csr.read().lsirdy() {}
#[cfg(any(rcc_wb, rcc_wba))]
while !csr.read().lsi1rdy() {}
}
if let Some(lse_drive) = lse {
Self::modify(|w| {
#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))]
w.set_lsedrv(lse_drive.into());
w.set_lseon(true);
});
while !Self::read().lserdy() {}
}
match clock_source {
RtcClockSource::LSI => assert!(lsi),
RtcClockSource::LSE => assert!(&lse.is_some()),
_ => {}
};
if clock_source == RtcClockSource::NOCLOCK {
// disable it
Self::modify(|w| {
#[cfg(not(rcc_wba))]
w.set_rtcen(false);
w.set_rtcsel(clock_source);
});
} else {
// check if it's already enabled and in the source we want.
let reg = Self::read();
let ok = reg.rtcsel() == clock_source;
#[cfg(not(rcc_wba))]
let ok = ok & reg.rtcen();
// if not, configure it.
if !ok {
#[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
#[cfg(not(any(rcc_l0, rcc_l1)))]
Self::modify(|w| w.set_bdrst(true));
Self::modify(|w| {
// Reset
#[cfg(not(any(rcc_l0, rcc_l1)))]
w.set_bdrst(false);
#[cfg(not(rcc_wba))]
w.set_rtcen(true);
w.set_rtcsel(clock_source);
// Restore bcdr
#[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
w.set_lscosel(reg.lscosel());
#[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
w.set_lscoen(reg.lscoen());
w.set_lseon(reg.lseon());
#[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
w.set_lsedrv(reg.lsedrv());
w.set_lsebyp(reg.lsebyp());
});
}
}
}
}

View File

@ -0,0 +1,56 @@
use core::ops::Div;
#[allow(unused_imports)]
use crate::pac::rcc;
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
use crate::time::Hertz;
impl Div<AHBPrescaler> for Hertz {
type Output = Hertz;
fn div(self, rhs: AHBPrescaler) -> Self::Output {
let divisor = match rhs {
AHBPrescaler::DIV1 => 1,
AHBPrescaler::DIV2 => 2,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::DIV3 => 3,
AHBPrescaler::DIV4 => 4,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::DIV5 => 5,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::DIV6 => 6,
AHBPrescaler::DIV8 => 8,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::DIV10 => 10,
AHBPrescaler::DIV16 => 16,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::DIV32 => 32,
#[cfg(not(rcc_wba))]
AHBPrescaler::DIV64 => 64,
#[cfg(not(rcc_wba))]
AHBPrescaler::DIV128 => 128,
#[cfg(not(rcc_wba))]
AHBPrescaler::DIV256 => 256,
#[cfg(not(rcc_wba))]
AHBPrescaler::DIV512 => 512,
_ => unreachable!(),
};
Hertz(self.0 / divisor)
}
}
impl Div<APBPrescaler> for Hertz {
type Output = Hertz;
fn div(self, rhs: APBPrescaler) -> Self::Output {
let divisor = match rhs {
APBPrescaler::DIV1 => 1,
APBPrescaler::DIV2 => 2,
APBPrescaler::DIV4 => 4,
APBPrescaler::DIV8 => 8,
APBPrescaler::DIV16 => 16,
_ => unreachable!(),
};
Hertz(self.0 / divisor)
}
}

View File

@ -1,4 +1,4 @@
pub use super::common::{AHBPrescaler, APBPrescaler};
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{Hsidiv, Ppre, Sw};
use crate::pac::{FLASH, RCC};
@ -58,8 +58,8 @@ impl Default for Config {
fn default() -> Config {
Config {
mux: ClockSrc::HSI(HSIPrescaler::NotDivided),
ahb_pre: AHBPrescaler::NotDivided,
apb_pre: APBPrescaler::NotDivided,
ahb_pre: AHBPrescaler::DIV1,
apb_pre: APBPrescaler::DIV1,
}
}
}
@ -151,20 +151,21 @@ pub(crate) unsafe fn init(config: Config) {
}
let ahb_div = match config.ahb_pre {
AHBPrescaler::NotDivided => 1,
AHBPrescaler::Div2 => 2,
AHBPrescaler::Div4 => 4,
AHBPrescaler::Div8 => 8,
AHBPrescaler::Div16 => 16,
AHBPrescaler::Div64 => 64,
AHBPrescaler::Div128 => 128,
AHBPrescaler::Div256 => 256,
AHBPrescaler::Div512 => 512,
AHBPrescaler::DIV1 => 1,
AHBPrescaler::DIV2 => 2,
AHBPrescaler::DIV4 => 4,
AHBPrescaler::DIV8 => 8,
AHBPrescaler::DIV16 => 16,
AHBPrescaler::DIV64 => 64,
AHBPrescaler::DIV128 => 128,
AHBPrescaler::DIV256 => 256,
AHBPrescaler::DIV512 => 512,
_ => unreachable!(),
};
let ahb_freq = sys_clk / ahb_div;
let (apb_freq, apb_tim_freq) = match config.apb_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);

View File

@ -1,174 +0,0 @@
use core::ops::Div;
#[allow(unused_imports)]
use crate::pac::rcc;
use crate::time::Hertz;
/// Voltage Scale
///
/// Represents the voltage range feeding the CPU core. The maximum core
/// clock frequency depends on this value.
///
/// Scale0 represents the highest voltage range
#[derive(Copy, Clone, PartialEq)]
pub enum VoltageScale {
Scale0,
Scale1,
#[cfg(not(any(rcc_wl5, rcc_wle)))]
Scale2,
#[cfg(not(any(rcc_wl5, rcc_wle)))]
Scale3,
}
/// AHB prescaler
#[derive(Clone, Copy, PartialEq)]
pub enum AHBPrescaler {
NotDivided,
Div2,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
Div3,
Div4,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
Div5,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
Div6,
Div8,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
Div10,
Div16,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
Div32,
Div64,
Div128,
Div256,
Div512,
}
impl Div<AHBPrescaler> for Hertz {
type Output = Hertz;
fn div(self, rhs: AHBPrescaler) -> Self::Output {
let divisor = match rhs {
AHBPrescaler::NotDivided => 1,
AHBPrescaler::Div2 => 2,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::Div3 => 3,
AHBPrescaler::Div4 => 4,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::Div5 => 5,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::Div6 => 6,
AHBPrescaler::Div8 => 8,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::Div10 => 10,
AHBPrescaler::Div16 => 16,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::Div32 => 32,
AHBPrescaler::Div64 => 64,
AHBPrescaler::Div128 => 128,
AHBPrescaler::Div256 => 256,
AHBPrescaler::Div512 => 512,
};
Hertz(self.0 / divisor)
}
}
#[cfg(not(any(rcc_g4, rcc_wb, rcc_wl5, rcc_wle)))]
impl From<AHBPrescaler> for rcc::vals::Hpre {
fn from(val: AHBPrescaler) -> rcc::vals::Hpre {
use rcc::vals::Hpre;
match val {
#[cfg(not(rcc_u5))]
AHBPrescaler::NotDivided => Hpre::DIV1,
#[cfg(rcc_u5)]
AHBPrescaler::NotDivided => Hpre::NONE,
AHBPrescaler::Div2 => Hpre::DIV2,
AHBPrescaler::Div4 => Hpre::DIV4,
AHBPrescaler::Div8 => Hpre::DIV8,
AHBPrescaler::Div16 => Hpre::DIV16,
AHBPrescaler::Div64 => Hpre::DIV64,
AHBPrescaler::Div128 => Hpre::DIV128,
AHBPrescaler::Div256 => Hpre::DIV256,
AHBPrescaler::Div512 => Hpre::DIV512,
}
}
}
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
impl From<AHBPrescaler> for u8 {
fn from(val: AHBPrescaler) -> u8 {
match val {
AHBPrescaler::NotDivided => 0x0,
AHBPrescaler::Div2 => 0x08,
AHBPrescaler::Div3 => 0x01,
AHBPrescaler::Div4 => 0x09,
AHBPrescaler::Div5 => 0x02,
AHBPrescaler::Div6 => 0x05,
AHBPrescaler::Div8 => 0x0a,
AHBPrescaler::Div10 => 0x06,
AHBPrescaler::Div16 => 0x0b,
AHBPrescaler::Div32 => 0x07,
AHBPrescaler::Div64 => 0x0c,
AHBPrescaler::Div128 => 0x0d,
AHBPrescaler::Div256 => 0x0e,
AHBPrescaler::Div512 => 0x0f,
}
}
}
/// APB prescaler
#[derive(Clone, Copy)]
pub enum APBPrescaler {
NotDivided,
Div2,
Div4,
Div8,
Div16,
}
impl Div<APBPrescaler> for Hertz {
type Output = Hertz;
fn div(self, rhs: APBPrescaler) -> Self::Output {
let divisor = match rhs {
APBPrescaler::NotDivided => 1,
APBPrescaler::Div2 => 2,
APBPrescaler::Div4 => 4,
APBPrescaler::Div8 => 8,
APBPrescaler::Div16 => 16,
};
Hertz(self.0 / divisor)
}
}
#[cfg(not(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_g4, rcc_h7, rcc_h7ab, rcc_wb, rcc_wl5, rcc_wle)))]
impl From<APBPrescaler> for rcc::vals::Ppre {
fn from(val: APBPrescaler) -> rcc::vals::Ppre {
use rcc::vals::Ppre;
match val {
#[cfg(not(rcc_u5))]
APBPrescaler::NotDivided => Ppre::DIV1,
#[cfg(rcc_u5)]
APBPrescaler::NotDivided => Ppre::NONE,
APBPrescaler::Div2 => Ppre::DIV2,
APBPrescaler::Div4 => Ppre::DIV4,
APBPrescaler::Div8 => Ppre::DIV8,
APBPrescaler::Div16 => Ppre::DIV16,
}
}
}
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
impl From<APBPrescaler> for u8 {
fn from(val: APBPrescaler) -> u8 {
match val {
APBPrescaler::NotDivided => 1,
APBPrescaler::Div2 => 0x04,
APBPrescaler::Div4 => 0x05,
APBPrescaler::Div8 => 0x06,
APBPrescaler::Div16 => 0x07,
}
}
}

View File

@ -163,8 +163,8 @@ pub(crate) unsafe fn init(config: Config) {
// Only needed for stm32f103?
RCC.cfgr().modify(|w| {
w.set_adcpre(Adcpre::from_bits(apre_bits));
w.set_ppre2(Ppre1::from_bits(ppre2_bits));
w.set_ppre1(Ppre1::from_bits(ppre1_bits));
w.set_ppre2(Ppre::from_bits(ppre2_bits));
w.set_ppre1(Ppre::from_bits(ppre1_bits));
w.set_hpre(Hpre::from_bits(hpre_bits));
#[cfg(not(rcc_f100))]
w.set_usbpre(Usbpre::from_bits(usbpre as u8));
@ -184,6 +184,6 @@ pub(crate) unsafe fn init(config: Config) {
apb1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2),
ahb1: Hertz(hclk),
adc: Hertz(adcclk),
adc: Some(Hertz(adcclk)),
});
}

View File

@ -1,11 +1,13 @@
use core::convert::TryFrom;
use core::ops::{Div, Mul};
pub use super::common::{AHBPrescaler, APBPrescaler};
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw};
use crate::pac::{FLASH, RCC};
use crate::rcc::bd::BackupDomain;
use crate::rcc::{set_freqs, Clocks};
use crate::rtc::RtcClockSource;
use crate::time::Hertz;
/// HSI speed
@ -201,7 +203,20 @@ pub struct PLLClocks {
pub pll48_freq: Hertz,
}
pub use super::common::VoltageScale;
/// Voltage range of the power supply used.
///
/// Used to calculate flash waitstates. See
/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency
pub enum VoltageScale {
/// 2.7 to 3.6 V
Range0,
/// 2.4 to 2.7 V
Range1,
/// 2.1 to 2.4 V
Range2,
/// 1.8 to 2.1 V
Range3,
}
impl VoltageScale {
const fn wait_states(&self, ahb_freq: Hertz) -> Option<Latency> {
@ -209,7 +224,7 @@ impl VoltageScale {
// Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock
// frequency
match self {
VoltageScale::Scale3 => {
VoltageScale::Range3 => {
if ahb_freq <= 16_000_000 {
Some(Latency::WS0)
} else if ahb_freq <= 32_000_000 {
@ -230,7 +245,7 @@ impl VoltageScale {
None
}
}
VoltageScale::Scale2 => {
VoltageScale::Range2 => {
if ahb_freq <= 18_000_000 {
Some(Latency::WS0)
} else if ahb_freq <= 36_000_000 {
@ -249,7 +264,7 @@ impl VoltageScale {
None
}
}
VoltageScale::Scale1 => {
VoltageScale::Range1 => {
if ahb_freq <= 24_000_000 {
Some(Latency::WS0)
} else if ahb_freq <= 48_000_000 {
@ -264,7 +279,7 @@ impl VoltageScale {
None
}
}
VoltageScale::Scale0 => {
VoltageScale::Range0 => {
if ahb_freq <= 30_000_000 {
Some(Latency::WS0)
} else if ahb_freq <= 60_000_000 {
@ -288,6 +303,9 @@ pub struct Config {
pub pll_mux: PLLSrc,
pub pll: PLLConfig,
pub mux: ClockSrc,
pub rtc: Option<RtcClockSource>,
pub lsi: bool,
pub lse: Option<Hertz>,
pub voltage: VoltageScale,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
@ -302,11 +320,14 @@ impl Default for Config {
hsi: true,
pll_mux: PLLSrc::HSI,
pll: PLLConfig::default(),
voltage: VoltageScale::Scale3,
voltage: VoltageScale::Range3,
mux: ClockSrc::HSI,
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
rtc: None,
lsi: false,
lse: None,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
}
}
}
@ -379,7 +400,7 @@ pub(crate) unsafe fn init(config: Config) {
assert!(ahb_freq <= Hertz(120_000_000));
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let freq = ahb_freq / pre;
(freq, Hertz(freq.0 * 2))
@ -389,7 +410,7 @@ pub(crate) unsafe fn init(config: Config) {
assert!(apb1_freq <= Hertz(30_000_000));
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let freq = ahb_freq / pre;
(freq, Hertz(freq.0 * 2))
@ -414,6 +435,12 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().modify(|w| w.set_hsion(false));
}
BackupDomain::configure_ls(
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
set_freqs(Clocks {
sys: sys_clk,
ahb1: ahb_freq,

View File

@ -1,5 +1,7 @@
#[cfg(rcc_f3)]
use crate::pac::adccommon::vals::Ckmode;
use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
use crate::pac::rcc::vals::{Adcpres, Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
@ -10,6 +12,82 @@ pub const HSI_FREQ: Hertz = Hertz(8_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(40_000);
impl From<AdcClockSource> for Adcpres {
fn from(value: AdcClockSource) -> Self {
match value {
AdcClockSource::PllDiv1 => Adcpres::DIV1,
AdcClockSource::PllDiv2 => Adcpres::DIV2,
AdcClockSource::PllDiv4 => Adcpres::DIV4,
AdcClockSource::PllDiv6 => Adcpres::DIV6,
AdcClockSource::PllDiv8 => Adcpres::DIV8,
AdcClockSource::PllDiv12 => Adcpres::DIV12,
AdcClockSource::PllDiv16 => Adcpres::DIV16,
AdcClockSource::PllDiv32 => Adcpres::DIV32,
AdcClockSource::PllDiv64 => Adcpres::DIV64,
AdcClockSource::PllDiv128 => Adcpres::DIV128,
AdcClockSource::PllDiv256 => Adcpres::DIV256,
_ => unreachable!(),
}
}
}
#[cfg(rcc_f3)]
impl From<AdcClockSource> for Ckmode {
fn from(value: AdcClockSource) -> Self {
match value {
AdcClockSource::BusDiv1 => Ckmode::SYNCDIV1,
AdcClockSource::BusDiv2 => Ckmode::SYNCDIV2,
AdcClockSource::BusDiv4 => Ckmode::SYNCDIV4,
_ => unreachable!(),
}
}
}
#[derive(Clone, Copy)]
pub enum AdcClockSource {
PllDiv1 = 1,
PllDiv2 = 2,
PllDiv4 = 4,
PllDiv6 = 6,
PllDiv8 = 8,
PllDiv12 = 12,
PllDiv16 = 16,
PllDiv32 = 32,
PllDiv64 = 64,
PllDiv128 = 128,
PllDiv256 = 256,
BusDiv1,
BusDiv2,
BusDiv4,
}
impl AdcClockSource {
pub fn is_bus(&self) -> bool {
match self {
Self::BusDiv1 => true,
Self::BusDiv2 => true,
Self::BusDiv4 => true,
_ => false,
}
}
pub fn bus_div(&self) -> u32 {
match self {
Self::BusDiv1 => 1,
Self::BusDiv2 => 2,
Self::BusDiv4 => 4,
_ => unreachable!(),
}
}
}
#[derive(Default)]
pub enum HrtimClockSource {
#[default]
BusClk,
PllClk,
}
/// Clocks configutation
#[non_exhaustive]
#[derive(Default)]
@ -36,9 +114,20 @@ pub struct Config {
/// - The System clock frequency is either 48MHz or 72MHz
/// - APB1 clock has a minimum frequency of 10MHz
pub pll48: bool,
#[cfg(rcc_f3)]
/// ADC clock setup
/// - For AHB, a psc of 4 or less must be used
pub adc: Option<AdcClockSource>,
#[cfg(rcc_f3)]
/// ADC clock setup
/// - For AHB, a psc of 4 or less must be used
pub adc34: Option<AdcClockSource>,
#[cfg(stm32f334)]
pub hrtim: HrtimClockSource,
}
// Information required to setup the PLL clock
#[derive(Clone, Copy)]
struct PllConfig {
pll_src: Pllsrc,
pll_mul: Pllmul,
@ -170,6 +259,65 @@ pub(crate) unsafe fn init(config: Config) {
})
});
#[cfg(rcc_f3)]
let adc = config.adc.map(|adc| {
if !adc.is_bus() {
RCC.cfgr2().modify(|w| {
// Make sure that we're using the PLL
pll_config.unwrap();
w.set_adc12pres(adc.into());
Hertz(sysclk / adc as u32)
})
} else {
crate::pac::ADC_COMMON.ccr().modify(|w| {
assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1));
w.set_ckmode(adc.into());
Hertz(sysclk / adc.bus_div() as u32)
})
}
});
#[cfg(all(rcc_f3, adc3_common))]
let adc34 = config.adc.map(|adc| {
if !adc.is_bus() {
RCC.cfgr2().modify(|w| {
// Make sure that we're using the PLL
pll_config.unwrap();
w.set_adc12pres(adc.into());
Hertz(sysclk / adc as u32)
})
} else {
crate::pac::ADC3_COMMON.ccr().modify(|w| {
assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1));
w.set_ckmode(adc.into());
Hertz(sysclk / adc.bus_div() as u32)
})
}
});
#[cfg(stm32f334)]
let hrtim = match config.hrtim {
// Must be configured after the bus is ready, otherwise it won't work
HrtimClockSource::BusClk => None,
HrtimClockSource::PllClk => {
use crate::pac::rcc::vals::Timsw;
// Make sure that we're using the PLL
pll_config.unwrap();
assert!((pclk2 == sysclk) || (pclk2 * 2 == sysclk));
RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL));
Some(Hertz(sysclk * 2))
}
};
set_freqs(Clocks {
sys: Hertz(sysclk),
apb1: Hertz(pclk1),
@ -177,6 +325,14 @@ pub(crate) unsafe fn init(config: Config) {
apb1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2),
ahb1: Hertz(hclk),
#[cfg(rcc_f3)]
adc: adc,
#[cfg(all(rcc_f3, adc3_common))]
adc34: adc34,
#[cfg(all(rcc_f3, not(adc3_common)))]
adc34: None,
#[cfg(stm32f334)]
hrtim: hrtim,
});
}
@ -201,9 +357,9 @@ fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) {
// Calculates the Multiplier and the Divisor to arrive at
// the required System clock from PLL source frequency
let get_mul_div = |sysclk, pllsrcclk| {
let common_div = gcd(sysclk, pllsrcclk);
let mut multiplier = sysclk / common_div;
let mut divisor = pllsrcclk / common_div;
let bus_div = gcd(sysclk, pllsrcclk);
let mut multiplier = sysclk / bus_div;
let mut divisor = pllsrcclk / bus_div;
// Minimum PLL multiplier is two
if multiplier == 1 {
multiplier *= 2;

View File

@ -3,13 +3,12 @@ use core::marker::PhantomData;
use embassy_hal_internal::into_ref;
use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre};
use super::sealed::RccPeripheral;
use crate::gpio::sealed::AFType;
use crate::gpio::Speed;
use crate::pac::rcc::vals::{Hpre, Ppre, Sw};
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::{set_freqs, Clocks};
use crate::rtc::{Rtc, RtcClockSource};
use crate::time::Hertz;
use crate::{peripherals, Peripheral};
@ -38,6 +37,8 @@ pub struct Config {
pub pll48: bool,
pub rtc: Option<RtcClockSource>,
pub lsi: bool,
pub lse: Option<Hertz>,
}
#[cfg(stm32f410)]
@ -360,8 +361,6 @@ fn flash_setup(sysclk: u32) {
}
pub(crate) unsafe fn init(config: Config) {
crate::peripherals::PWR::enable();
let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0);
let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
let sysclk_on_pll = sysclk != pllsrcclk;
@ -501,20 +500,15 @@ pub(crate) unsafe fn init(config: Config) {
})
});
match config.rtc {
Some(RtcClockSource::LSI) => {
RCC.csr().modify(|w| w.set_lsion(true));
while !RCC.csr().read().lsirdy() {}
}
_ => {}
}
config.rtc.map(|clock_source| {
Rtc::set_clock_source(clock_source);
});
BackupDomain::configure_ls(
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
let rtc = match config.rtc {
Some(RtcClockSource::LSI) => Some(LSI_FREQ),
Some(RtcClockSource::LSE) => Some(config.lse.unwrap()),
_ => None,
};
@ -539,6 +533,7 @@ pub(crate) unsafe fn init(config: Config) {
pllsai: plls.pllsaiclk.map(Hertz),
rtc: rtc,
rtc_hse: None,
});
}

View File

@ -1,7 +1,7 @@
use super::sealed::RccPeripheral;
use crate::pac::pwr::vals::Vos;
use crate::pac::rcc::vals::{Hpre, Ppre, Sw};
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
@ -23,6 +23,9 @@ pub struct Config {
pub pclk2: Option<Hertz>,
pub pll48: bool,
pub rtc: Option<RtcClockSource>,
pub lsi: bool,
pub lse: Option<Hertz>,
}
fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
@ -111,8 +114,6 @@ fn flash_setup(sysclk: u32) {
}
pub(crate) unsafe fn init(config: Config) {
crate::peripherals::PWR::enable();
if let Some(hse) = config.hse {
if config.bypass_hse {
assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0));
@ -212,10 +213,7 @@ pub(crate) unsafe fn init(config: Config) {
if plls.use_pll {
RCC.cr().modify(|w| w.set_pllon(false));
// enable PWR and setup VOSScale
RCC.apb1enr().modify(|w| w.set_pwren(true));
// setup VOSScale
let vos_scale = if sysclk <= 144_000_000 {
3
} else if sysclk <= 168_000_000 {
@ -265,6 +263,18 @@ pub(crate) unsafe fn init(config: Config) {
})
});
BackupDomain::configure_ls(
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
let rtc = match config.rtc {
Some(RtcClockSource::LSI) => Some(LSI_FREQ),
Some(RtcClockSource::LSE) => Some(config.lse.unwrap()),
_ => None,
};
set_freqs(Clocks {
sys: Hertz(sysclk),
apb1: Hertz(pclk1),
@ -278,6 +288,8 @@ pub(crate) unsafe fn init(config: Config) {
ahb3: Hertz(hclk),
pll48: plls.pll48clk.map(Hertz),
rtc,
});
}

View File

@ -1,4 +1,4 @@
pub use super::common::{AHBPrescaler, APBPrescaler};
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{self, Hsidiv, Ppre, Sw};
use crate::pac::{FLASH, PWR, RCC};
@ -186,8 +186,8 @@ impl Default for Config {
fn default() -> Config {
Config {
mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided),
ahb_pre: AHBPrescaler::NotDivided,
apb_pre: APBPrescaler::NotDivided,
ahb_pre: AHBPrescaler::DIV1,
apb_pre: APBPrescaler::DIV1,
low_power_run: false,
}
}
@ -377,7 +377,7 @@ pub(crate) unsafe fn init(config: Config) {
let ahb_freq = Hertz(sys_clk) / config.ahb_pre;
let (apb_freq, apb_tim_freq) = match config.apb_pre {
APBPrescaler::NotDivided => (ahb_freq.0, ahb_freq.0),
APBPrescaler::DIV1 => (ahb_freq.0, ahb_freq.0),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);

View File

@ -1,8 +1,8 @@
use stm32_metapac::flash::vals::Latency;
use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw};
use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw};
use stm32_metapac::FLASH;
pub use super::common::{AHBPrescaler, APBPrescaler};
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::pac::{PWR, RCC};
use crate::rcc::sealed::RccPeripheral;
use crate::rcc::{set_freqs, Clocks};
@ -14,6 +14,29 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
#[derive(Clone, Copy)]
pub enum AdcClockSource {
NoClk,
SysClk,
PllP,
}
impl AdcClockSource {
pub fn adcsel(&self) -> Adcsel {
match self {
AdcClockSource::NoClk => Adcsel::NOCLK,
AdcClockSource::SysClk => Adcsel::SYSCLK,
AdcClockSource::PllP => Adcsel::PLLP,
}
}
}
impl Default for AdcClockSource {
fn default() -> Self {
Self::NoClk
}
}
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
@ -238,59 +261,29 @@ pub struct Pll {
pub div_r: Option<PllR>,
}
impl AHBPrescaler {
const fn div(self) -> u32 {
match self {
AHBPrescaler::NotDivided => 1,
AHBPrescaler::Div2 => 2,
AHBPrescaler::Div4 => 4,
AHBPrescaler::Div8 => 8,
AHBPrescaler::Div16 => 16,
AHBPrescaler::Div64 => 64,
AHBPrescaler::Div128 => 128,
AHBPrescaler::Div256 => 256,
AHBPrescaler::Div512 => 512,
}
fn ahb_div(ahb: AHBPrescaler) -> u32 {
match ahb {
AHBPrescaler::DIV1 => 1,
AHBPrescaler::DIV2 => 2,
AHBPrescaler::DIV4 => 4,
AHBPrescaler::DIV8 => 8,
AHBPrescaler::DIV16 => 16,
AHBPrescaler::DIV64 => 64,
AHBPrescaler::DIV128 => 128,
AHBPrescaler::DIV256 => 256,
AHBPrescaler::DIV512 => 512,
_ => unreachable!(),
}
}
impl APBPrescaler {
const fn div(self) -> u32 {
match self {
APBPrescaler::NotDivided => 1,
APBPrescaler::Div2 => 2,
APBPrescaler::Div4 => 4,
APBPrescaler::Div8 => 8,
APBPrescaler::Div16 => 16,
}
}
}
impl Into<Ppre> for APBPrescaler {
fn into(self) -> Ppre {
match self {
APBPrescaler::NotDivided => Ppre::DIV1,
APBPrescaler::Div2 => Ppre::DIV2,
APBPrescaler::Div4 => Ppre::DIV4,
APBPrescaler::Div8 => Ppre::DIV8,
APBPrescaler::Div16 => Ppre::DIV16,
}
}
}
impl Into<Hpre> for AHBPrescaler {
fn into(self) -> Hpre {
match self {
AHBPrescaler::NotDivided => Hpre::DIV1,
AHBPrescaler::Div2 => Hpre::DIV2,
AHBPrescaler::Div4 => Hpre::DIV4,
AHBPrescaler::Div8 => Hpre::DIV8,
AHBPrescaler::Div16 => Hpre::DIV16,
AHBPrescaler::Div64 => Hpre::DIV64,
AHBPrescaler::Div128 => Hpre::DIV128,
AHBPrescaler::Div256 => Hpre::DIV256,
AHBPrescaler::Div512 => Hpre::DIV512,
}
fn apb_div(apb: APBPrescaler) -> u32 {
match apb {
APBPrescaler::DIV1 => 1,
APBPrescaler::DIV2 => 2,
APBPrescaler::DIV4 => 4,
APBPrescaler::DIV8 => 8,
APBPrescaler::DIV16 => 16,
_ => unreachable!(),
}
}
@ -327,6 +320,8 @@ pub struct Config {
pub pll: Option<Pll>,
/// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
pub clock_48mhz_src: Option<Clock48MhzSrc>,
pub adc12_clock_source: AdcClockSource,
pub adc345_clock_source: AdcClockSource,
}
/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
@ -340,12 +335,14 @@ impl Default for Config {
fn default() -> Config {
Config {
mux: ClockSrc::HSI16,
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
low_power_run: false,
pll: None,
clock_48mhz_src: None,
adc12_clock_source: Default::default(),
adc345_clock_source: Default::default(),
}
}
}
@ -485,22 +482,22 @@ pub(crate) unsafe fn init(config: Config) {
});
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
pre => sys_clk / pre.div(),
AHBPrescaler::DIV1 => sys_clk,
pre => sys_clk / ahb_div(pre),
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let freq = ahb_freq / pre.div();
let freq = ahb_freq / apb_div(pre);
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let freq = ahb_freq / pre.div();
let freq = ahb_freq / apb_div(pre);
(freq, freq * 2)
}
};
@ -549,6 +546,29 @@ pub(crate) unsafe fn init(config: Config) {
RCC.ccipr().modify(|w| w.set_clk48sel(source));
}
RCC.ccipr()
.modify(|w| w.set_adc12sel(config.adc12_clock_source.adcsel()));
RCC.ccipr()
.modify(|w| w.set_adc345sel(config.adc345_clock_source.adcsel()));
let adc12_ck = match config.adc12_clock_source {
AdcClockSource::NoClk => None,
AdcClockSource::PllP => match &pll_freq {
Some(pll) => pll.pll_p,
None => None,
},
AdcClockSource::SysClk => Some(Hertz(sys_clk)),
};
let adc345_ck = match config.adc345_clock_source {
AdcClockSource::NoClk => None,
AdcClockSource::PllP => match &pll_freq {
Some(pll) => pll.pll_p,
None => None,
},
AdcClockSource::SysClk => Some(Hertz(sys_clk)),
};
if config.low_power_run {
assert!(sys_clk <= 2_000_000);
PWR.cr1().modify(|w| w.set_lpr(true));
@ -562,5 +582,7 @@ pub(crate) unsafe fn init(config: Config) {
apb1_tim: Hertz(apb1_tim_freq),
apb2: Hertz(apb2_freq),
apb2_tim: Hertz(apb2_tim_freq),
adc: adc12_ck,
adc34: adc345_ck,
});
}

772
embassy-stm32/src/rcc/h.rs Normal file
View File

@ -0,0 +1,772 @@
use core::ops::RangeInclusive;
use crate::pac;
use crate::pac::pwr::vals::Vos;
#[cfg(stm32h5)]
pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
#[cfg(stm32h7)]
pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
pub use crate::pac::rcc::vals::Ckpersel as PerClockSource;
use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre};
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(64_000_000);
/// CSI speed
pub const CSI_FREQ: Hertz = Hertz(4_000_000);
/// HSI48 speed
pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
const VCO_RANGE: RangeInclusive<u32> = 150_000_000..=420_000_000;
#[cfg(any(stm32h5, pwr_h7rm0455))]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 128_000_000..=560_000_000;
#[cfg(pwr_h7rm0468)]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=836_000_000;
#[cfg(any(pwr_h7rm0399, pwr_h7rm0433))]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=960_000_000;
pub use super::bus::{AHBPrescaler, APBPrescaler};
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum VoltageScale {
Scale0,
Scale1,
Scale2,
Scale3,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum HseMode {
/// crystal/ceramic oscillator (HSEBYP=0)
Oscillator,
/// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
Bypass,
/// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
#[cfg(any(rcc_h5, rcc_h50))]
BypassDigital,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Hse {
/// HSE frequency.
pub freq: Hertz,
/// HSE mode.
pub mode: HseMode,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Hsi {
/// 64Mhz
Mhz64,
/// 32Mhz (divided by 2)
Mhz32,
/// 16Mhz (divided by 4)
Mhz16,
/// 8Mhz (divided by 8)
Mhz8,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Sysclk {
/// HSI selected as sysclk
HSI,
/// HSE selected as sysclk
HSE,
/// CSI selected as sysclk
CSI,
/// PLL1_P selected as sysclk
Pll1P,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum PllSource {
Hsi,
Csi,
Hse,
}
#[derive(Clone, Copy)]
pub struct Pll {
/// Source clock selection.
#[cfg(stm32h5)]
pub source: PllSource,
/// PLL pre-divider (DIVM). Must be between 1 and 63.
pub prediv: u8,
/// PLL multiplication factor. Must be between 4 and 512.
pub mul: u16,
/// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128.
/// On PLL1, it must be even (in particular, it cannot be 1.)
pub divp: Option<u16>,
/// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
pub divq: Option<u16>,
/// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
pub divr: Option<u16>,
}
fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz {
match (tim, apb) {
(TimerPrescaler::DefaultX2, APBPrescaler::DIV1) => clk,
(TimerPrescaler::DefaultX2, APBPrescaler::DIV2) => clk,
(TimerPrescaler::DefaultX2, APBPrescaler::DIV4) => clk / 2u32,
(TimerPrescaler::DefaultX2, APBPrescaler::DIV8) => clk / 4u32,
(TimerPrescaler::DefaultX2, APBPrescaler::DIV16) => clk / 8u32,
(TimerPrescaler::DefaultX4, APBPrescaler::DIV1) => clk,
(TimerPrescaler::DefaultX4, APBPrescaler::DIV2) => clk,
(TimerPrescaler::DefaultX4, APBPrescaler::DIV4) => clk,
(TimerPrescaler::DefaultX4, APBPrescaler::DIV8) => clk / 2u32,
(TimerPrescaler::DefaultX4, APBPrescaler::DIV16) => clk / 4u32,
_ => unreachable!(),
}
}
/// Timer prescaler
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum TimerPrescaler {
/// The timers kernel clock is equal to hclk if PPREx corresponds to a
/// division by 1 or 2, else it is equal to 2*pclk
DefaultX2,
/// The timers kernel clock is equal to hclk if PPREx corresponds to a
/// division by 1, 2 or 4, else it is equal to 4*pclk
DefaultX4,
}
impl From<TimerPrescaler> for Timpre {
fn from(value: TimerPrescaler) -> Self {
match value {
TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2,
TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4,
}
}
}
/// Configuration of the core clocks
#[non_exhaustive]
pub struct Config {
pub hsi: Option<Hsi>,
pub hse: Option<Hse>,
pub csi: bool,
pub hsi48: bool,
pub sys: Sysclk,
#[cfg(stm32h7)]
pub pll_src: PllSource,
pub pll1: Option<Pll>,
pub pll2: Option<Pll>,
#[cfg(any(rcc_h5, stm32h7))]
pub pll3: Option<Pll>,
pub d1c_pre: AHBPrescaler,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
pub apb3_pre: APBPrescaler,
#[cfg(stm32h7)]
pub apb4_pre: APBPrescaler,
pub per_clock_source: PerClockSource,
pub adc_clock_source: AdcClockSource,
pub timer_prescaler: TimerPrescaler,
pub voltage_scale: VoltageScale,
}
impl Default for Config {
fn default() -> Self {
Self {
hsi: Some(Hsi::Mhz64),
hse: None,
csi: false,
hsi48: false,
sys: Sysclk::HSI,
#[cfg(stm32h7)]
pll_src: PllSource::Hsi,
pll1: None,
pll2: None,
#[cfg(any(rcc_h5, stm32h7))]
pll3: None,
d1c_pre: AHBPrescaler::DIV1,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
apb3_pre: APBPrescaler::DIV1,
#[cfg(stm32h7)]
apb4_pre: APBPrescaler::DIV1,
per_clock_source: PerClockSource::HSI,
adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5
timer_prescaler: TimerPrescaler::DefaultX2,
voltage_scale: VoltageScale::Scale0,
}
}
}
pub(crate) unsafe fn init(config: Config) {
// NB. The lower bytes of CR3 can only be written once after
// POR, and must be written with a valid combination. Refer to
// RM0433 Rev 7 6.8.4. This is partially enforced by dropping
// `self` at the end of this method, but of course we cannot
// know what happened between the previous POR and here.
#[cfg(pwr_h7rm0433)]
PWR.cr3().modify(|w| {
w.set_scuen(true);
w.set_ldoen(true);
w.set_bypass(false);
});
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
PWR.cr3().modify(|w| {
// hardcode "Direct SPMS" for now, this is what works on nucleos with the
// default solderbridge configuration.
w.set_sden(true);
w.set_ldoen(false);
});
// Validate the supply configuration. If you are stuck here, it is
// because the voltages on your board do not match those specified
// in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
// VOS = Scale 3, so check that the voltage on the VCAP pins =
// 1.0V.
#[cfg(any(pwr_h7rm0433, pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
while !PWR.csr1().read().actvosrdy() {}
// Configure voltage scale.
#[cfg(any(pwr_h5, pwr_h50))]
{
PWR.voscr().modify(|w| {
w.set_vos(match config.voltage_scale {
VoltageScale::Scale0 => Vos::SCALE0,
VoltageScale::Scale1 => Vos::SCALE1,
VoltageScale::Scale2 => Vos::SCALE2,
VoltageScale::Scale3 => Vos::SCALE3,
})
});
while !PWR.vossr().read().vosrdy() {}
}
#[cfg(syscfg_h7)]
{
// in chips without the overdrive bit, we can go from any scale to any scale directly.
PWR.d3cr().modify(|w| {
w.set_vos(match config.voltage_scale {
VoltageScale::Scale0 => Vos::SCALE0,
VoltageScale::Scale1 => Vos::SCALE1,
VoltageScale::Scale2 => Vos::SCALE2,
VoltageScale::Scale3 => Vos::SCALE3,
})
});
while !PWR.d3cr().read().vosrdy() {}
}
#[cfg(syscfg_h7od)]
{
match config.voltage_scale {
VoltageScale::Scale0 => {
// to go to scale0, we must go to Scale1 first...
PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1));
while !PWR.d3cr().read().vosrdy() {}
// Then enable overdrive.
critical_section::with(|_| pac::SYSCFG.pwrcr().modify(|w| w.set_oden(1)));
while !PWR.d3cr().read().vosrdy() {}
}
_ => {
// for all other scales, we can go directly.
PWR.d3cr().modify(|w| {
w.set_vos(match config.voltage_scale {
VoltageScale::Scale0 => unreachable!(),
VoltageScale::Scale1 => Vos::SCALE1,
VoltageScale::Scale2 => Vos::SCALE2,
VoltageScale::Scale3 => Vos::SCALE3,
})
});
while !PWR.d3cr().read().vosrdy() {}
}
}
}
// Configure HSI
let hsi = match config.hsi {
None => {
RCC.cr().modify(|w| w.set_hsion(false));
None
}
Some(hsi) => {
let (freq, hsidiv) = match hsi {
Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1),
Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2),
Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4),
Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8),
};
RCC.cr().modify(|w| {
w.set_hsidiv(hsidiv);
w.set_hsion(true);
});
while !RCC.cr().read().hsirdy() {}
Some(freq)
}
};
// Configure HSE
let hse = match config.hse {
None => {
RCC.cr().modify(|w| w.set_hseon(false));
None
}
Some(hse) => {
RCC.cr().modify(|w| {
w.set_hsebyp(hse.mode != HseMode::Oscillator);
#[cfg(any(rcc_h5, rcc_h50))]
w.set_hseext(match hse.mode {
HseMode::Oscillator | HseMode::Bypass => pac::rcc::vals::Hseext::ANALOG,
HseMode::BypassDigital => pac::rcc::vals::Hseext::DIGITAL,
});
});
RCC.cr().modify(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
Some(hse.freq)
}
};
// Configure HSI48.
RCC.cr().modify(|w| w.set_hsi48on(config.hsi48));
let _hsi48 = match config.hsi48 {
false => None,
true => {
while !RCC.cr().read().hsi48rdy() {}
Some(CSI_FREQ)
}
};
// Configure CSI.
RCC.cr().modify(|w| w.set_csion(config.csi));
let csi = match config.csi {
false => None,
true => {
while !RCC.cr().read().csirdy() {}
Some(CSI_FREQ)
}
};
// Configure PLLs.
let pll_input = PllInput {
csi,
hse,
hsi,
#[cfg(stm32h7)]
source: config.pll_src,
};
let pll1 = init_pll(0, config.pll1, &pll_input);
let pll2 = init_pll(1, config.pll2, &pll_input);
#[cfg(any(rcc_h5, stm32h7))]
let _pll3 = init_pll(2, config.pll3, &pll_input);
// Configure sysclk
let (sys, sw) = match config.sys {
Sysclk::HSI => (unwrap!(hsi), Sw::HSI),
Sysclk::HSE => (unwrap!(hse), Sw::HSE),
Sysclk::CSI => (unwrap!(csi), Sw::CSI),
Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1),
};
// Check limits.
#[cfg(stm32h5)]
let (hclk_max, pclk_max) = match config.voltage_scale {
VoltageScale::Scale0 => (Hertz(250_000_000), Hertz(250_000_000)),
VoltageScale::Scale1 => (Hertz(200_000_000), Hertz(200_000_000)),
VoltageScale::Scale2 => (Hertz(150_000_000), Hertz(150_000_000)),
VoltageScale::Scale3 => (Hertz(100_000_000), Hertz(100_000_000)),
};
#[cfg(stm32h7)]
let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)),
VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)),
VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)),
VoltageScale::Scale3 => (Hertz(200_000_000), Hertz(100_000_000), Hertz(50_000_000)),
};
#[cfg(stm32h7)]
let hclk = {
let d1cpre_clk = sys / config.d1c_pre;
assert!(d1cpre_clk <= d1cpre_clk_max);
sys / config.ahb_pre
};
#[cfg(stm32h5)]
let hclk = sys / config.ahb_pre;
assert!(hclk <= hclk_max);
let apb1 = hclk / config.apb1_pre;
let apb1_tim = apb_div_tim(&config.apb1_pre, hclk, config.timer_prescaler);
assert!(apb1 <= pclk_max);
let apb2 = hclk / config.apb2_pre;
let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler);
assert!(apb2 <= pclk_max);
let apb3 = hclk / config.apb3_pre;
assert!(apb3 <= pclk_max);
#[cfg(stm32h7)]
let apb4 = hclk / config.apb4_pre;
#[cfg(stm32h7)]
assert!(apb4 <= pclk_max);
let _per_ck = match config.per_clock_source {
Ckpersel::HSI => hsi,
Ckpersel::CSI => csi,
Ckpersel::HSE => hse,
_ => unreachable!(),
};
#[cfg(stm32h7)]
let adc = match config.adc_clock_source {
AdcClockSource::PLL2_P => pll2.p,
AdcClockSource::PLL3_R => _pll3.r,
AdcClockSource::PER => _per_ck,
_ => unreachable!(),
};
#[cfg(stm32h5)]
let adc = match config.adc_clock_source {
AdcClockSource::HCLK => Some(hclk),
AdcClockSource::SYSCLK => Some(sys),
AdcClockSource::PLL2_R => pll2.r,
AdcClockSource::HSE => hse,
AdcClockSource::HSI_KER => hsi,
AdcClockSource::CSI_KER => csi,
_ => unreachable!(),
};
flash_setup(hclk, config.voltage_scale);
#[cfg(stm32h7)]
{
RCC.d1cfgr().modify(|w| {
w.set_d1cpre(config.d1c_pre);
w.set_d1ppre(config.apb3_pre);
w.set_hpre(config.ahb_pre);
});
// Ensure core prescaler value is valid before future lower core voltage
while RCC.d1cfgr().read().d1cpre() != config.d1c_pre {}
RCC.d2cfgr().modify(|w| {
w.set_d2ppre1(config.apb1_pre);
w.set_d2ppre2(config.apb2_pre);
});
RCC.d3cfgr().modify(|w| {
w.set_d3ppre(config.apb4_pre);
});
RCC.d1ccipr().modify(|w| {
w.set_ckpersel(config.per_clock_source);
});
RCC.d3ccipr().modify(|w| {
w.set_adcsel(config.adc_clock_source);
});
}
#[cfg(stm32h5)]
{
// Set hpre
RCC.cfgr2().modify(|w| w.set_hpre(config.ahb_pre));
while RCC.cfgr2().read().hpre() != config.ahb_pre {}
// set ppre
RCC.cfgr2().modify(|w| {
w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre);
w.set_ppre3(config.apb3_pre);
});
RCC.ccipr5().modify(|w| {
w.set_ckpersel(config.per_clock_source);
w.set_adcdacsel(config.adc_clock_source)
});
}
RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
RCC.cfgr().modify(|w| w.set_sw(sw));
while RCC.cfgr().read().sws() != sw {}
// IO compensation cell - Requires CSI clock and SYSCFG
#[cfg(stm32h7)] // TODO h5
if csi.is_some() {
// Enable the compensation cell, using back-bias voltage code
// provide by the cell.
critical_section::with(|_| {
pac::SYSCFG.cccsr().modify(|w| {
w.set_en(true);
w.set_cs(false);
w.set_hslv(false);
})
});
while !pac::SYSCFG.cccsr().read().ready() {}
}
set_freqs(Clocks {
sys,
ahb1: hclk,
ahb2: hclk,
ahb3: hclk,
ahb4: hclk,
apb1,
apb2,
apb3,
#[cfg(stm32h7)]
apb4,
apb1_tim,
apb2_tim,
adc: adc,
});
}
struct PllInput {
hsi: Option<Hertz>,
hse: Option<Hertz>,
csi: Option<Hertz>,
#[cfg(stm32h7)]
source: PllSource,
}
struct PllOutput {
p: Option<Hertz>,
#[allow(dead_code)]
q: Option<Hertz>,
#[allow(dead_code)]
r: Option<Hertz>,
}
fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
let Some(config) = config else {
// Stop PLL
RCC.cr().modify(|w| w.set_pllon(num, false));
while RCC.cr().read().pllrdy(num) {}
// "To save power when PLL1 is not used, the value of PLL1M must be set to 0.""
#[cfg(stm32h7)]
RCC.pllckselr().write(|w| w.set_divm(num, 0));
#[cfg(stm32h5)]
RCC.pllcfgr(num).write(|w| w.set_divm(0));
return PllOutput {
p: None,
q: None,
r: None,
};
};
assert!(1 <= config.prediv && config.prediv <= 63);
assert!(4 <= config.mul && config.mul <= 512);
#[cfg(stm32h5)]
let source = config.source;
#[cfg(stm32h7)]
let source = input.source;
let (in_clk, src) = match source {
PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI),
PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE),
PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI),
};
let ref_clk = in_clk / config.prediv as u32;
let ref_range = match ref_clk.0 {
..=1_999_999 => Pllrge::RANGE1,
..=3_999_999 => Pllrge::RANGE2,
..=7_999_999 => Pllrge::RANGE4,
..=16_000_000 => Pllrge::RANGE8,
x => panic!("pll ref_clk out of range: {} mhz", x),
};
// The smaller range (150 to 420 MHz) must
// be chosen when the reference clock frequency is lower than 2 MHz.
let wide_allowed = ref_range != Pllrge::RANGE1;
let vco_clk = ref_clk * config.mul;
let vco_range = if VCO_RANGE.contains(&vco_clk.0) {
Pllvcosel::MEDIUMVCO
} else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk.0) {
Pllvcosel::WIDEVCO
} else {
panic!("pll vco_clk out of range: {} mhz", vco_clk.0)
};
let p = config.divp.map(|div| {
assert!(1 <= div && div <= 128);
if num == 0 {
// on PLL1, DIVP must be even.
assert!(div % 2 == 0);
}
vco_clk / div
});
let q = config.divq.map(|div| {
assert!(1 <= div && div <= 128);
vco_clk / div
});
let r = config.divr.map(|div| {
assert!(1 <= div && div <= 128);
vco_clk / div
});
#[cfg(stm32h5)]
RCC.pllcfgr(num).write(|w| {
w.set_pllsrc(src);
w.set_divm(config.prediv);
w.set_pllvcosel(vco_range);
w.set_pllrge(ref_range);
w.set_pllfracen(false);
w.set_pllpen(p.is_some());
w.set_pllqen(q.is_some());
w.set_pllren(r.is_some());
});
#[cfg(stm32h7)]
{
RCC.pllckselr().modify(|w| {
w.set_divm(num, config.prediv);
w.set_pllsrc(src);
});
RCC.pllcfgr().modify(|w| {
w.set_pllvcosel(num, vco_range);
w.set_pllrge(num, ref_range);
w.set_pllfracen(num, false);
w.set_divpen(num, p.is_some());
w.set_divqen(num, q.is_some());
w.set_divren(num, r.is_some());
});
}
RCC.plldivr(num).write(|w| {
w.set_plln(config.mul - 1);
w.set_pllp((config.divp.unwrap_or(1) - 1) as u8);
w.set_pllq((config.divq.unwrap_or(1) - 1) as u8);
w.set_pllr((config.divr.unwrap_or(1) - 1) as u8);
});
RCC.cr().modify(|w| w.set_pllon(num, true));
while !RCC.cr().read().pllrdy(num) {}
PllOutput { p, q, r }
}
fn flash_setup(clk: Hertz, vos: VoltageScale) {
// RM0481 Rev 1, table 37
// LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0
// 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz
// 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz
// 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz
// 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz
// 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz
// 5 2 170 to 200 MHz 210 to 250 MHz
#[cfg(stm32h5)]
let (latency, wrhighfreq) = match (vos, clk.0) {
(VoltageScale::Scale0, ..=42_000_000) => (0, 0),
(VoltageScale::Scale0, ..=84_000_000) => (1, 0),
(VoltageScale::Scale0, ..=126_000_000) => (2, 1),
(VoltageScale::Scale0, ..=168_000_000) => (3, 1),
(VoltageScale::Scale0, ..=210_000_000) => (4, 2),
(VoltageScale::Scale0, ..=250_000_000) => (5, 2),
(VoltageScale::Scale1, ..=34_000_000) => (0, 0),
(VoltageScale::Scale1, ..=68_000_000) => (1, 0),
(VoltageScale::Scale1, ..=102_000_000) => (2, 1),
(VoltageScale::Scale1, ..=136_000_000) => (3, 1),
(VoltageScale::Scale1, ..=170_000_000) => (4, 2),
(VoltageScale::Scale1, ..=200_000_000) => (5, 2),
(VoltageScale::Scale2, ..=30_000_000) => (0, 0),
(VoltageScale::Scale2, ..=60_000_000) => (1, 0),
(VoltageScale::Scale2, ..=90_000_000) => (2, 1),
(VoltageScale::Scale2, ..=120_000_000) => (3, 1),
(VoltageScale::Scale2, ..=150_000_000) => (4, 2),
(VoltageScale::Scale3, ..=20_000_000) => (0, 0),
(VoltageScale::Scale3, ..=40_000_000) => (1, 0),
(VoltageScale::Scale3, ..=60_000_000) => (2, 1),
(VoltageScale::Scale3, ..=80_000_000) => (3, 1),
(VoltageScale::Scale3, ..=100_000_000) => (4, 2),
_ => unreachable!(),
};
#[cfg(flash_h7)]
let (latency, wrhighfreq) = match (vos, clk.0) {
// VOS 0 range VCORE 1.26V - 1.40V
(VoltageScale::Scale0, ..=70_000_000) => (0, 0),
(VoltageScale::Scale0, ..=140_000_000) => (1, 1),
(VoltageScale::Scale0, ..=185_000_000) => (2, 1),
(VoltageScale::Scale0, ..=210_000_000) => (2, 2),
(VoltageScale::Scale0, ..=225_000_000) => (3, 2),
(VoltageScale::Scale0, ..=240_000_000) => (4, 2),
// VOS 1 range VCORE 1.15V - 1.26V
(VoltageScale::Scale1, ..=70_000_000) => (0, 0),
(VoltageScale::Scale1, ..=140_000_000) => (1, 1),
(VoltageScale::Scale1, ..=185_000_000) => (2, 1),
(VoltageScale::Scale1, ..=210_000_000) => (2, 2),
(VoltageScale::Scale1, ..=225_000_000) => (3, 2),
// VOS 2 range VCORE 1.05V - 1.15V
(VoltageScale::Scale2, ..=55_000_000) => (0, 0),
(VoltageScale::Scale2, ..=110_000_000) => (1, 1),
(VoltageScale::Scale2, ..=165_000_000) => (2, 1),
(VoltageScale::Scale2, ..=224_000_000) => (3, 2),
// VOS 3 range VCORE 0.95V - 1.05V
(VoltageScale::Scale3, ..=45_000_000) => (0, 0),
(VoltageScale::Scale3, ..=90_000_000) => (1, 1),
(VoltageScale::Scale3, ..=135_000_000) => (2, 1),
(VoltageScale::Scale3, ..=180_000_000) => (3, 2),
(VoltageScale::Scale3, ..=224_000_000) => (4, 2),
_ => unreachable!(),
};
// See RM0455 Rev 10 Table 16. FLASH recommended number of wait
// states and programming delay
#[cfg(flash_h7ab)]
let (latency, wrhighfreq) = match (vos, clk.0) {
// VOS 0 range VCORE 1.25V - 1.35V
(VoltageScale::Scale0, ..=42_000_000) => (0, 0),
(VoltageScale::Scale0, ..=84_000_000) => (1, 0),
(VoltageScale::Scale0, ..=126_000_000) => (2, 1),
(VoltageScale::Scale0, ..=168_000_000) => (3, 1),
(VoltageScale::Scale0, ..=210_000_000) => (4, 2),
(VoltageScale::Scale0, ..=252_000_000) => (5, 2),
(VoltageScale::Scale0, ..=280_000_000) => (6, 3),
// VOS 1 range VCORE 1.15V - 1.25V
(VoltageScale::Scale1, ..=38_000_000) => (0, 0),
(VoltageScale::Scale1, ..=76_000_000) => (1, 0),
(VoltageScale::Scale1, ..=114_000_000) => (2, 1),
(VoltageScale::Scale1, ..=152_000_000) => (3, 1),
(VoltageScale::Scale1, ..=190_000_000) => (4, 2),
(VoltageScale::Scale1, ..=225_000_000) => (5, 2),
// VOS 2 range VCORE 1.05V - 1.15V
(VoltageScale::Scale2, ..=34) => (0, 0),
(VoltageScale::Scale2, ..=68) => (1, 0),
(VoltageScale::Scale2, ..=102) => (2, 1),
(VoltageScale::Scale2, ..=136) => (3, 1),
(VoltageScale::Scale2, ..=160) => (4, 2),
// VOS 3 range VCORE 0.95V - 1.05V
(VoltageScale::Scale3, ..=22) => (0, 0),
(VoltageScale::Scale3, ..=44) => (1, 0),
(VoltageScale::Scale3, ..=66) => (2, 1),
(VoltageScale::Scale3, ..=88) => (3, 1),
_ => unreachable!(),
};
debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
FLASH.acr().write(|w| {
w.set_wrhighfreq(wrhighfreq);
w.set_latency(latency);
});
while FLASH.acr().read().latency() != latency {}
}

View File

@ -1,511 +0,0 @@
use core::marker::PhantomData;
use stm32_metapac::rcc::vals::Timpre;
use crate::pac::pwr::vals::Vos;
use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw};
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
use crate::{peripherals, Peripheral};
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(64_000_000);
/// CSI speed
pub const CSI_FREQ: Hertz = Hertz(4_000_000);
/// HSI48 speed
pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
const VCO_MIN: u32 = 150_000_000;
const VCO_MAX: u32 = 420_000_000;
const VCO_WIDE_MIN: u32 = 128_000_000;
const VCO_WIDE_MAX: u32 = 560_000_000;
pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale};
pub enum HseMode {
/// crystal/ceramic oscillator (HSEBYP=0)
Oscillator,
/// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
BypassAnalog,
/// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
BypassDigital,
}
pub struct Hse {
/// HSE frequency.
pub freq: Hertz,
/// HSE mode.
pub mode: HseMode,
}
pub enum Hsi {
/// 64Mhz
Mhz64,
/// 32Mhz (divided by 2)
Mhz32,
/// 16Mhz (divided by 4)
Mhz16,
/// 8Mhz (divided by 8)
Mhz8,
}
pub enum Sysclk {
/// HSI selected as sysclk
HSI,
/// HSE selected as sysclk
HSE,
/// CSI selected as sysclk
CSI,
/// PLL1_P selected as sysclk
Pll1P,
}
pub enum PllSource {
Hsi,
Csi,
Hse,
}
pub struct Pll {
/// Source clock selection.
pub source: PllSource,
/// PLL pre-divider (DIVM). Must be between 1 and 63.
pub prediv: u8,
/// PLL multiplication factor. Must be between 4 and 512.
pub mul: u16,
/// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128.
/// On PLL1, it must be even (in particular, it cannot be 1.)
pub divp: Option<u16>,
/// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
pub divq: Option<u16>,
/// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
pub divr: Option<u16>,
}
impl APBPrescaler {
fn div_tim(&self, clk: Hertz, tim: TimerPrescaler) -> Hertz {
match (tim, self) {
// The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a
// division by 1 or 2, else it is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2
(TimerPrescaler::DefaultX2, Self::NotDivided) => clk,
(TimerPrescaler::DefaultX2, Self::Div2) => clk,
(TimerPrescaler::DefaultX2, Self::Div4) => clk / 2u32,
(TimerPrescaler::DefaultX2, Self::Div8) => clk / 4u32,
(TimerPrescaler::DefaultX2, Self::Div16) => clk / 8u32,
// The timers kernel clock is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 if PPRE1 or PPRE2
// corresponds to a division by 1, 2 or 4, else it is equal to 4 x Frcc_pclk1 or 4 x Frcc_pclk2
// this makes NO SENSE and is different than in the H7. Mistake in the RM??
(TimerPrescaler::DefaultX4, Self::NotDivided) => clk * 2u32,
(TimerPrescaler::DefaultX4, Self::Div2) => clk,
(TimerPrescaler::DefaultX4, Self::Div4) => clk / 2u32,
(TimerPrescaler::DefaultX4, Self::Div8) => clk / 2u32,
(TimerPrescaler::DefaultX4, Self::Div16) => clk / 4u32,
}
}
}
/// APB prescaler
#[derive(Clone, Copy)]
pub enum TimerPrescaler {
DefaultX2,
DefaultX4,
}
impl From<TimerPrescaler> for Timpre {
fn from(value: TimerPrescaler) -> Self {
match value {
TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2,
TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4,
}
}
}
/// Configuration of the core clocks
#[non_exhaustive]
pub struct Config {
pub hsi: Option<Hsi>,
pub hse: Option<Hse>,
pub csi: bool,
pub hsi48: bool,
pub sys: Sysclk,
pub pll1: Option<Pll>,
pub pll2: Option<Pll>,
#[cfg(rcc_h5)]
pub pll3: Option<Pll>,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
pub apb3_pre: APBPrescaler,
pub timer_prescaler: TimerPrescaler,
pub voltage_scale: VoltageScale,
}
impl Default for Config {
fn default() -> Self {
Self {
hsi: Some(Hsi::Mhz64),
hse: None,
csi: false,
hsi48: false,
sys: Sysclk::HSI,
pll1: None,
pll2: None,
#[cfg(rcc_h5)]
pll3: None,
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
apb3_pre: APBPrescaler::NotDivided,
timer_prescaler: TimerPrescaler::DefaultX2,
voltage_scale: VoltageScale::Scale3,
}
}
}
pub(crate) mod sealed {
pub trait McoInstance {
type Source;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
}
}
pub trait McoInstance: sealed::McoInstance + 'static {}
pin_trait!(McoPin, McoInstance);
macro_rules! impl_peri {
($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
impl sealed::McoInstance for peripherals::$peri {
type Source = $source;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
RCC.cfgr().modify(|w| {
w.$set_source(source);
w.$set_prescaler(prescaler);
});
}
}
impl McoInstance for peripherals::$peri {}
};
}
impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre);
impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre);
pub struct Mco<'d, T: McoInstance> {
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: McoInstance> Mco<'d, T> {
pub fn new(
_peri: impl Peripheral<P = T> + 'd,
_pin: impl Peripheral<P = impl McoPin<T>> + 'd,
_source: T::Source,
) -> Self {
todo!();
}
}
pub(crate) unsafe fn init(config: Config) {
let (vos, max_clk) = match config.voltage_scale {
VoltageScale::Scale0 => (Vos::SCALE0, Hertz(250_000_000)),
VoltageScale::Scale1 => (Vos::SCALE1, Hertz(200_000_000)),
VoltageScale::Scale2 => (Vos::SCALE2, Hertz(150_000_000)),
VoltageScale::Scale3 => (Vos::SCALE3, Hertz(100_000_000)),
};
// Configure voltage scale.
PWR.voscr().modify(|w| w.set_vos(vos));
while !PWR.vossr().read().vosrdy() {}
// Configure HSI
let hsi = match config.hsi {
None => {
RCC.cr().modify(|w| w.set_hsion(false));
None
}
Some(hsi) => {
let (freq, hsidiv) = match hsi {
Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1),
Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2),
Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4),
Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8),
};
RCC.cr().modify(|w| {
w.set_hsidiv(hsidiv);
w.set_hsion(true);
});
while !RCC.cr().read().hsirdy() {}
Some(freq)
}
};
// Configure HSE
let hse = match config.hse {
None => {
RCC.cr().modify(|w| w.set_hseon(false));
None
}
Some(hse) => {
let (byp, ext) = match hse.mode {
HseMode::Oscillator => (false, Hseext::ANALOG),
HseMode::BypassAnalog => (true, Hseext::ANALOG),
HseMode::BypassDigital => (true, Hseext::DIGITAL),
};
RCC.cr().modify(|w| {
w.set_hsebyp(byp);
w.set_hseext(ext);
});
RCC.cr().modify(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
Some(hse.freq)
}
};
// Configure HSI48.
RCC.cr().modify(|w| w.set_hsi48on(config.hsi48));
let _hsi48 = match config.hsi48 {
false => None,
true => {
while !RCC.cr().read().hsi48rdy() {}
Some(CSI_FREQ)
}
};
// Configure CSI.
RCC.cr().modify(|w| w.set_csion(config.csi));
let csi = match config.csi {
false => None,
true => {
while !RCC.cr().read().csirdy() {}
Some(CSI_FREQ)
}
};
// Configure PLLs.
let pll_input = PllInput { csi, hse, hsi };
let pll1 = init_pll(0, config.pll1, &pll_input);
let _pll2 = init_pll(1, config.pll2, &pll_input);
#[cfg(rcc_h5)]
let _pll3 = init_pll(2, config.pll3, &pll_input);
// Configure sysclk
let (sys, sw) = match config.sys {
Sysclk::HSI => (unwrap!(hsi), Sw::HSI),
Sysclk::HSE => (unwrap!(hse), Sw::HSE),
Sysclk::CSI => (unwrap!(csi), Sw::CSI),
Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1),
};
assert!(sys <= max_clk);
let hclk = sys / config.ahb_pre;
let apb1 = hclk / config.apb1_pre;
let apb1_tim = config.apb1_pre.div_tim(hclk, config.timer_prescaler);
let apb2 = hclk / config.apb2_pre;
let apb2_tim = config.apb2_pre.div_tim(hclk, config.timer_prescaler);
let apb3 = hclk / config.apb3_pre;
flash_setup(hclk, config.voltage_scale);
// Set hpre
let hpre = config.ahb_pre.into();
RCC.cfgr2().modify(|w| w.set_hpre(hpre));
while RCC.cfgr2().read().hpre() != hpre {}
// set ppre
RCC.cfgr2().modify(|w| {
w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre.into());
w.set_ppre3(config.apb3_pre.into());
});
RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
RCC.cfgr().modify(|w| w.set_sw(sw));
while RCC.cfgr().read().sws() != sw {}
set_freqs(Clocks {
sys,
ahb1: hclk,
ahb2: hclk,
ahb3: hclk,
ahb4: hclk,
apb1,
apb2,
apb3,
apb1_tim,
apb2_tim,
adc: None,
});
}
struct PllInput {
hsi: Option<Hertz>,
hse: Option<Hertz>,
csi: Option<Hertz>,
}
struct PllOutput {
p: Option<Hertz>,
#[allow(dead_code)]
q: Option<Hertz>,
#[allow(dead_code)]
r: Option<Hertz>,
}
fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
let Some(config) = config else {
// Stop PLL
RCC.cr().modify(|w| w.set_pllon(num, false));
while RCC.cr().read().pllrdy(num) {}
// "To save power when PLL1 is not used, the value of PLL1M must be set to 0.""
RCC.pllcfgr(num).write(|w| {
w.set_divm(0);
});
return PllOutput {
p: None,
q: None,
r: None,
};
};
assert!(1 <= config.prediv && config.prediv <= 63);
assert!(4 <= config.mul && config.mul <= 512);
let (in_clk, src) = match config.source {
PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI),
PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE),
PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI),
};
let ref_clk = in_clk / config.prediv as u32;
let ref_range = match ref_clk.0 {
..=1_999_999 => Pllrge::RANGE1,
..=3_999_999 => Pllrge::RANGE2,
..=7_999_999 => Pllrge::RANGE4,
..=16_000_000 => Pllrge::RANGE8,
x => panic!("pll ref_clk out of range: {} mhz", x),
};
// The smaller range (150 to 420 MHz) must
// be chosen when the reference clock frequency is lower than 2 MHz.
let wide_allowed = ref_range != Pllrge::RANGE1;
let vco_clk = ref_clk * config.mul;
let vco_range = match vco_clk.0 {
VCO_MIN..=VCO_MAX => Pllvcosel::MEDIUMVCO,
VCO_WIDE_MIN..=VCO_WIDE_MAX if wide_allowed => Pllvcosel::WIDEVCO,
x => panic!("pll vco_clk out of range: {} mhz", x),
};
let p = config.divp.map(|div| {
assert!(1 <= div && div <= 128);
if num == 0 {
// on PLL1, DIVP must be even.
assert!(div % 2 == 0);
}
vco_clk / div
});
let q = config.divq.map(|div| {
assert!(1 <= div && div <= 128);
vco_clk / div
});
let r = config.divr.map(|div| {
assert!(1 <= div && div <= 128);
vco_clk / div
});
RCC.pllcfgr(num).write(|w| {
w.set_pllsrc(src);
w.set_divm(config.prediv);
w.set_pllvcosel(vco_range);
w.set_pllrge(ref_range);
w.set_pllfracen(false);
w.set_pllpen(p.is_some());
w.set_pllqen(q.is_some());
w.set_pllren(r.is_some());
});
RCC.plldivr(num).write(|w| {
w.set_plln(config.mul - 1);
w.set_pllp((config.divp.unwrap_or(1) - 1) as u8);
w.set_pllq((config.divq.unwrap_or(1) - 1) as u8);
w.set_pllr((config.divr.unwrap_or(1) - 1) as u8);
});
RCC.cr().modify(|w| w.set_pllon(num, true));
while !RCC.cr().read().pllrdy(num) {}
PllOutput { p, q, r }
}
fn flash_setup(clk: Hertz, vos: VoltageScale) {
// RM0481 Rev 1, table 37
// LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0
// 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz
// 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz
// 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz
// 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz
// 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz
// 5 2 170 to 200 MHz 210 to 250 MHz
// See RM0433 Rev 7 Table 17. FLASH recommended number of wait
// states and programming delay
let (latency, wrhighfreq) = match (vos, clk.0) {
(VoltageScale::Scale0, ..=42_000_000) => (0, 0),
(VoltageScale::Scale0, ..=84_000_000) => (1, 0),
(VoltageScale::Scale0, ..=126_000_000) => (2, 1),
(VoltageScale::Scale0, ..=168_000_000) => (3, 1),
(VoltageScale::Scale0, ..=210_000_000) => (4, 2),
(VoltageScale::Scale0, ..=250_000_000) => (5, 2),
(VoltageScale::Scale1, ..=34_000_000) => (0, 0),
(VoltageScale::Scale1, ..=68_000_000) => (1, 0),
(VoltageScale::Scale1, ..=102_000_000) => (2, 1),
(VoltageScale::Scale1, ..=136_000_000) => (3, 1),
(VoltageScale::Scale1, ..=170_000_000) => (4, 2),
(VoltageScale::Scale1, ..=200_000_000) => (5, 2),
(VoltageScale::Scale2, ..=30_000_000) => (0, 0),
(VoltageScale::Scale2, ..=60_000_000) => (1, 0),
(VoltageScale::Scale2, ..=90_000_000) => (2, 1),
(VoltageScale::Scale2, ..=120_000_000) => (3, 1),
(VoltageScale::Scale2, ..=150_000_000) => (4, 2),
(VoltageScale::Scale3, ..=20_000_000) => (0, 0),
(VoltageScale::Scale3, ..=40_000_000) => (1, 0),
(VoltageScale::Scale3, ..=60_000_000) => (2, 1),
(VoltageScale::Scale3, ..=80_000_000) => (3, 1),
(VoltageScale::Scale3, ..=100_000_000) => (4, 2),
_ => unreachable!(),
};
defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
FLASH.acr().write(|w| {
w.set_wrhighfreq(wrhighfreq);
w.set_latency(latency);
});
while FLASH.acr().read().latency() != latency {}
}

View File

@ -1,879 +0,0 @@
use core::marker::PhantomData;
use embassy_hal_internal::into_ref;
pub use pll::PllConfig;
use stm32_metapac::rcc::vals::{Mco1, Mco2};
use crate::gpio::sealed::AFType;
use crate::gpio::Speed;
use crate::pac::rcc::vals::{Adcsel, Ckpersel, Dppre, Hpre, Hsidiv, Pllsrc, Sw, Timpre};
use crate::pac::{PWR, RCC, SYSCFG};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
use crate::{peripherals, Peripheral};
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(64_000_000);
/// CSI speed
pub const CSI_FREQ: Hertz = Hertz(4_000_000);
/// HSI48 speed
pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
pub use super::common::VoltageScale;
#[derive(Clone, Copy)]
pub enum AdcClockSource {
Pll2PCk,
Pll3RCk,
PerCk,
}
impl AdcClockSource {
pub fn adcsel(&self) -> Adcsel {
match self {
AdcClockSource::Pll2PCk => Adcsel::PLL2_P,
AdcClockSource::Pll3RCk => Adcsel::PLL3_R,
AdcClockSource::PerCk => Adcsel::PER,
}
}
}
impl Default for AdcClockSource {
fn default() -> Self {
Self::Pll2PCk
}
}
/// Core clock frequencies
#[derive(Clone, Copy)]
pub struct CoreClocks {
pub hclk: Hertz,
pub pclk1: Hertz,
pub pclk2: Hertz,
pub pclk3: Hertz,
pub pclk4: Hertz,
pub ppre1: u8,
pub ppre2: u8,
pub ppre3: u8,
pub ppre4: u8,
pub csi_ck: Option<Hertz>,
pub hsi_ck: Option<Hertz>,
pub hsi48_ck: Option<Hertz>,
pub lsi_ck: Option<Hertz>,
pub per_ck: Option<Hertz>,
pub hse_ck: Option<Hertz>,
pub pll1_p_ck: Option<Hertz>,
pub pll1_q_ck: Option<Hertz>,
pub pll1_r_ck: Option<Hertz>,
pub pll2_p_ck: Option<Hertz>,
pub pll2_q_ck: Option<Hertz>,
pub pll2_r_ck: Option<Hertz>,
pub pll3_p_ck: Option<Hertz>,
pub pll3_q_ck: Option<Hertz>,
pub pll3_r_ck: Option<Hertz>,
pub timx_ker_ck: Option<Hertz>,
pub timy_ker_ck: Option<Hertz>,
pub adc_ker_ck: Option<Hertz>,
pub sys_ck: Hertz,
pub c_ck: Hertz,
}
/// Configuration of the core clocks
#[non_exhaustive]
#[derive(Default)]
pub struct Config {
pub hse: Option<Hertz>,
pub bypass_hse: bool,
pub sys_ck: Option<Hertz>,
pub per_ck: Option<Hertz>,
pub hclk: Option<Hertz>,
pub pclk1: Option<Hertz>,
pub pclk2: Option<Hertz>,
pub pclk3: Option<Hertz>,
pub pclk4: Option<Hertz>,
pub pll1: PllConfig,
pub pll2: PllConfig,
pub pll3: PllConfig,
pub adc_clock_source: AdcClockSource,
}
/// Setup traceclk
/// Returns a pll1_r_ck
fn traceclk_setup(config: &mut Config, sys_use_pll1_p: bool) {
let pll1_r_ck = match (sys_use_pll1_p, config.pll1.r_ck) {
// pll1_p_ck selected as system clock but pll1_r_ck not
// set. The traceclk mux is synchronous with the system
// clock mux, but has pll1_r_ck as an input. In order to
// keep traceclk running, we force a pll1_r_ck.
(true, None) => Some(Hertz(unwrap!(config.pll1.p_ck).0 / 2)),
// Either pll1 not selected as system clock, free choice
// of pll1_r_ck. Or pll1 is selected, assume user has set
// a suitable pll1_r_ck frequency.
_ => config.pll1.r_ck,
};
config.pll1.r_ck = pll1_r_ck;
}
/// Divider calculator for pclk 1 - 4
///
/// Returns real pclk, bits, ppre and the timer kernel clock
fn ppre_calculate(
requested_pclk: u32,
hclk: u32,
max_pclk: u32,
tim_pre: Option<Timpre>,
) -> (u32, u8, u8, Option<u32>) {
let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk {
0 => panic!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let real_pclk = hclk / u32::from(ppre);
assert!(real_pclk <= max_pclk);
let tim_ker_clk = if let Some(tim_pre) = tim_pre {
let clk = match (bits, tim_pre) {
(0b101, Timpre::DEFAULTX2) => hclk / 2,
(0b110, Timpre::DEFAULTX4) => hclk / 2,
(0b110, Timpre::DEFAULTX2) => hclk / 4,
(0b111, Timpre::DEFAULTX4) => hclk / 4,
(0b111, Timpre::DEFAULTX2) => hclk / 8,
_ => hclk,
};
Some(clk)
} else {
None
};
(real_pclk, bits, ppre, tim_ker_clk)
}
/// Setup sys_ck
/// Returns sys_ck frequency, and a pll1_p_ck
fn sys_ck_setup(config: &mut Config, srcclk: Hertz) -> (Hertz, bool) {
// Compare available with wanted clocks
let sys_ck = config.sys_ck.unwrap_or(srcclk);
if sys_ck != srcclk {
// The requested system clock is not the immediately available
// HSE/HSI clock. Perhaps there are other ways of obtaining
// the requested system clock (such as `HSIDIV`) but we will
// ignore those for now.
//
// Therefore we must use pll1_p_ck
let pll1_p_ck = match config.pll1.p_ck {
Some(p_ck) => {
assert!(
p_ck == sys_ck,
"Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck"
);
Some(p_ck)
}
None => Some(sys_ck),
};
config.pll1.p_ck = pll1_p_ck;
(sys_ck, true)
} else {
// sys_ck is derived directly from a source clock
// (HSE/HSI). pll1_p_ck can be as requested
(sys_ck, false)
}
}
fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
use crate::pac::FLASH;
// ACLK in MHz, round down and subtract 1 from integers. eg.
// 61_999_999 -> 61MHz
// 62_000_000 -> 61MHz
// 62_000_001 -> 62MHz
let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000;
// See RM0433 Rev 7 Table 17. FLASH recommended number of wait
// states and programming delay
#[cfg(flash_h7)]
let (wait_states, progr_delay) = match vos {
// VOS 0 range VCORE 1.26V - 1.40V
VoltageScale::Scale0 => match rcc_aclk_mhz {
0..=69 => (0, 0),
70..=139 => (1, 1),
140..=184 => (2, 1),
185..=209 => (2, 2),
210..=224 => (3, 2),
225..=239 => (4, 2),
_ => (7, 3),
},
// VOS 1 range VCORE 1.15V - 1.26V
VoltageScale::Scale1 => match rcc_aclk_mhz {
0..=69 => (0, 0),
70..=139 => (1, 1),
140..=184 => (2, 1),
185..=209 => (2, 2),
210..=224 => (3, 2),
_ => (7, 3),
},
// VOS 2 range VCORE 1.05V - 1.15V
VoltageScale::Scale2 => match rcc_aclk_mhz {
0..=54 => (0, 0),
55..=109 => (1, 1),
110..=164 => (2, 1),
165..=224 => (3, 2),
_ => (7, 3),
},
// VOS 3 range VCORE 0.95V - 1.05V
VoltageScale::Scale3 => match rcc_aclk_mhz {
0..=44 => (0, 0),
45..=89 => (1, 1),
90..=134 => (2, 1),
135..=179 => (3, 2),
180..=224 => (4, 2),
_ => (7, 3),
},
};
// See RM0455 Rev 10 Table 16. FLASH recommended number of wait
// states and programming delay
#[cfg(flash_h7ab)]
let (wait_states, progr_delay) = match vos {
// VOS 0 range VCORE 1.25V - 1.35V
VoltageScale::Scale0 => match rcc_aclk_mhz {
0..=42 => (0, 0),
43..=84 => (1, 0),
85..=126 => (2, 1),
127..=168 => (3, 1),
169..=210 => (4, 2),
211..=252 => (5, 2),
253..=280 => (6, 3),
_ => (7, 3),
},
// VOS 1 range VCORE 1.15V - 1.25V
VoltageScale::Scale1 => match rcc_aclk_mhz {
0..=38 => (0, 0),
39..=76 => (1, 0),
77..=114 => (2, 1),
115..=152 => (3, 1),
153..=190 => (4, 2),
191..=225 => (5, 2),
_ => (7, 3),
},
// VOS 2 range VCORE 1.05V - 1.15V
VoltageScale::Scale2 => match rcc_aclk_mhz {
0..=34 => (0, 0),
35..=68 => (1, 0),
69..=102 => (2, 1),
103..=136 => (3, 1),
137..=160 => (4, 2),
_ => (7, 3),
},
// VOS 3 range VCORE 0.95V - 1.05V
VoltageScale::Scale3 => match rcc_aclk_mhz {
0..=22 => (0, 0),
23..=44 => (1, 0),
45..=66 => (2, 1),
67..=88 => (3, 1),
_ => (7, 3),
},
};
FLASH.acr().write(|w| {
w.set_wrhighfreq(progr_delay);
w.set_latency(wait_states)
});
while FLASH.acr().read().latency() != wait_states {}
}
pub enum McoClock {
Disabled,
Bypassed,
Divided(u8),
}
impl McoClock {
fn into_raw(&self) -> u8 {
match self {
McoClock::Disabled => 0,
McoClock::Bypassed => 1,
McoClock::Divided(divisor) => {
if *divisor > 15 {
panic!("Mco divisor must be less than 15. Refer to the reference manual for more information.")
}
*divisor
}
}
}
}
#[derive(Copy, Clone)]
pub enum Mco1Source {
Hsi,
Lse,
Hse,
Pll1Q,
Hsi48,
}
impl Default for Mco1Source {
fn default() -> Self {
Self::Hsi
}
}
pub trait McoSource {
type Raw;
fn into_raw(&self) -> Self::Raw;
}
impl McoSource for Mco1Source {
type Raw = Mco1;
fn into_raw(&self) -> Self::Raw {
match self {
Mco1Source::Hsi => Mco1::HSI,
Mco1Source::Lse => Mco1::LSE,
Mco1Source::Hse => Mco1::HSE,
Mco1Source::Pll1Q => Mco1::PLL1_Q,
Mco1Source::Hsi48 => Mco1::HSI48,
}
}
}
#[derive(Copy, Clone)]
pub enum Mco2Source {
SysClk,
Pll2Q,
Hse,
Pll1Q,
Csi,
Lsi,
}
impl Default for Mco2Source {
fn default() -> Self {
Self::SysClk
}
}
impl McoSource for Mco2Source {
type Raw = Mco2;
fn into_raw(&self) -> Self::Raw {
match self {
Mco2Source::SysClk => Mco2::SYSCLK,
Mco2Source::Pll2Q => Mco2::PLL2_P,
Mco2Source::Hse => Mco2::HSE,
Mco2Source::Pll1Q => Mco2::PLL1_P,
Mco2Source::Csi => Mco2::CSI,
Mco2Source::Lsi => Mco2::LSI,
}
}
}
pub(crate) mod sealed {
pub trait McoInstance {
type Source;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
}
}
pub trait McoInstance: sealed::McoInstance + 'static {}
pin_trait!(McoPin, McoInstance);
macro_rules! impl_peri {
($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
impl sealed::McoInstance for peripherals::$peri {
type Source = $source;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
RCC.cfgr().modify(|w| {
w.$set_source(source);
w.$set_prescaler(prescaler);
});
}
}
impl McoInstance for peripherals::$peri {}
};
}
impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre);
impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre);
pub struct Mco<'d, T: McoInstance> {
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: McoInstance> Mco<'d, T> {
pub fn new(
_peri: impl Peripheral<P = T> + 'd,
pin: impl Peripheral<P = impl McoPin<T>> + 'd,
source: impl McoSource<Raw = T::Source>,
prescaler: McoClock,
) -> Self {
into_ref!(pin);
critical_section::with(|_| unsafe {
T::apply_clock_settings(source.into_raw(), prescaler.into_raw());
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
pin.set_speed(Speed::VeryHigh);
});
Self { phantom: PhantomData }
}
}
pub(crate) unsafe fn init(mut config: Config) {
// TODO make configurable?
let enable_overdrive = false;
// NB. The lower bytes of CR3 can only be written once after
// POR, and must be written with a valid combination. Refer to
// RM0433 Rev 7 6.8.4. This is partially enforced by dropping
// `self` at the end of this method, but of course we cannot
// know what happened between the previous POR and here.
#[cfg(pwr_h7)]
PWR.cr3().modify(|w| {
w.set_scuen(true);
w.set_ldoen(true);
w.set_bypass(false);
});
#[cfg(pwr_h7smps)]
PWR.cr3().modify(|w| {
// hardcode "Direct SPMS" for now, this is what works on nucleos with the
// default solderbridge configuration.
w.set_sden(true);
w.set_ldoen(false);
});
// Validate the supply configuration. If you are stuck here, it is
// because the voltages on your board do not match those specified
// in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
// VOS = Scale 3, so check that the voltage on the VCAP pins =
// 1.0V.
while !PWR.csr1().read().actvosrdy() {}
// Go to Scale 1
PWR.d3cr().modify(|w| w.set_vos(0b11));
while !PWR.d3cr().read().vosrdy() {}
let pwr_vos = if !enable_overdrive {
VoltageScale::Scale1
} else {
critical_section::with(|_| {
RCC.apb4enr().modify(|w| w.set_syscfgen(true));
SYSCFG.pwrcr().modify(|w| w.set_oden(1));
});
while !PWR.d3cr().read().vosrdy() {}
VoltageScale::Scale0
};
// Freeze the core clocks, returning a Core Clocks Distribution
// and Reset (CCDR) structure. The actual frequency of the clocks
// configured is returned in the `clocks` member of the CCDR
// structure.
//
// Note that `freeze` will never result in a clock _faster_ than
// that specified. It may result in a clock that is a factor of [1,
// 2) slower.
//
// `syscfg` is required to enable the I/O compensation cell.
//
// # Panics
//
// If a clock specification cannot be achieved within the
// hardware specification then this function will panic. This
// function may also panic if a clock specification can be
// achieved, but the mechanism for doing so is not yet
// implemented here.
let srcclk = config.hse.unwrap_or(HSI_FREQ); // Available clocks
let (sys_ck, sys_use_pll1_p) = sys_ck_setup(&mut config, srcclk);
// Configure traceclk from PLL if needed
traceclk_setup(&mut config, sys_use_pll1_p);
let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0);
let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1);
let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2);
let sys_ck = if sys_use_pll1_p {
Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
} else {
sys_ck
};
// This routine does not support HSIDIV != 1. To
// do so it would need to ensure all PLLxON bits are clear
// before changing the value of HSIDIV
let cr = RCC.cr().read();
assert!(cr.hsion());
assert!(cr.hsidiv() == Hsidiv::DIV1);
RCC.csr().modify(|w| w.set_lsion(true));
while !RCC.csr().read().lsirdy() {}
// per_ck from HSI by default
let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) {
(true, Some(hse)) => (hse, Ckpersel::HSE), // HSE
(_, Some(CSI_FREQ)) => (CSI_FREQ, Ckpersel::CSI), // CSI
_ => (HSI_FREQ, Ckpersel::HSI), // HSI
};
// D1 Core Prescaler
// Set to 1
let d1cpre_bits = 0;
let d1cpre_div = 1;
let sys_d1cpre_ck = sys_ck.0 / d1cpre_div;
// Refer to part datasheet "General operating conditions"
// table for (rev V). We do not assert checks for earlier
// revisions which may have lower limits.
let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr_vos {
VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000),
VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000),
VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000),
_ => (200_000_000, 100_000_000, 50_000_000),
};
assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max);
let rcc_hclk = config.hclk.map(|v| v.0).unwrap_or(sys_d1cpre_ck / 2);
assert!(rcc_hclk <= rcc_hclk_max);
// Estimate divisor
let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk {
0 => panic!(),
1 => (Hpre::DIV1, 1),
2 => (Hpre::DIV2, 2),
3..=5 => (Hpre::DIV4, 4),
6..=11 => (Hpre::DIV8, 8),
12..=39 => (Hpre::DIV16, 16),
40..=95 => (Hpre::DIV64, 64),
96..=191 => (Hpre::DIV128, 128),
192..=383 => (Hpre::DIV256, 256),
_ => (Hpre::DIV512, 512),
};
// Calculate real AXI and AHB clock
let rcc_hclk = sys_d1cpre_ck / hpre_div;
assert!(rcc_hclk <= rcc_hclk_max);
let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7
// Timer prescaler selection
let timpre = Timpre::DEFAULTX2;
let requested_pclk1 = config.pclk1.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) =
ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre));
let requested_pclk2 = config.pclk2.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) =
ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre));
let requested_pclk3 = config.pclk3.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
let (rcc_pclk3, ppre3_bits, ppre3, _) = ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None);
let requested_pclk4 = config.pclk4.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
let (rcc_pclk4, ppre4_bits, ppre4, _) = ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None);
// Start switching clocks -------------------
// Ensure CSI is on and stable
RCC.cr().modify(|w| w.set_csion(true));
while !RCC.cr().read().csirdy() {}
// Ensure HSI48 is on and stable
RCC.cr().modify(|w| w.set_hsi48on(true));
while !RCC.cr().read().hsi48on() {}
// XXX: support MCO ?
let hse_ck = match config.hse {
Some(hse) => {
// Ensure HSE is on and stable
RCC.cr().modify(|w| {
w.set_hseon(true);
w.set_hsebyp(config.bypass_hse);
});
while !RCC.cr().read().hserdy() {}
Some(hse)
}
None => None,
};
let pllsrc = if config.hse.is_some() { Pllsrc::HSE } else { Pllsrc::HSI };
RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc));
let enable_pll = |pll| {
RCC.cr().modify(|w| w.set_pllon(pll, true));
while !RCC.cr().read().pllrdy(pll) {}
};
if pll1_p_ck.is_some() {
enable_pll(0);
}
if pll2_p_ck.is_some() {
enable_pll(1);
}
if pll3_p_ck.is_some() {
enable_pll(2);
}
// Core Prescaler / AHB Prescaler / APB3 Prescaler
RCC.d1cfgr().modify(|w| {
w.set_d1cpre(Hpre::from_bits(d1cpre_bits));
w.set_d1ppre(Dppre::from_bits(ppre3_bits));
w.set_hpre(hpre_bits)
});
// Ensure core prescaler value is valid before future lower
// core voltage
while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {}
flash_setup(rcc_aclk, pwr_vos);
// APB1 / APB2 Prescaler
RCC.d2cfgr().modify(|w| {
w.set_d2ppre1(Dppre::from_bits(ppre1_bits));
w.set_d2ppre2(Dppre::from_bits(ppre2_bits));
});
// APB4 Prescaler
RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre::from_bits(ppre4_bits)));
// Peripheral Clock (per_ck)
RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
// ADC clock MUX
RCC.d3ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel()));
let adc_ker_ck = match config.adc_clock_source {
AdcClockSource::Pll2PCk => pll2_p_ck.map(Hertz),
AdcClockSource::Pll3RCk => pll3_r_ck.map(Hertz),
AdcClockSource::PerCk => Some(per_ck),
};
// Set timer clocks prescaler setting
RCC.cfgr().modify(|w| w.set_timpre(timpre));
// Select system clock source
let sw = match (sys_use_pll1_p, config.hse.is_some()) {
(true, _) => Sw::PLL1,
(false, true) => Sw::HSE,
_ => Sw::HSI,
};
RCC.cfgr().modify(|w| w.set_sw(sw));
while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
// IO compensation cell - Requires CSI clock and SYSCFG
assert!(RCC.cr().read().csirdy());
RCC.apb4enr().modify(|w| w.set_syscfgen(true));
// Enable the compensation cell, using back-bias voltage code
// provide by the cell.
critical_section::with(|_| {
SYSCFG.cccsr().modify(|w| {
w.set_en(true);
w.set_cs(false);
w.set_hslv(false);
})
});
while !SYSCFG.cccsr().read().ready() {}
let core_clocks = CoreClocks {
hclk: Hertz(rcc_hclk),
pclk1: Hertz(rcc_pclk1),
pclk2: Hertz(rcc_pclk2),
pclk3: Hertz(rcc_pclk3),
pclk4: Hertz(rcc_pclk4),
ppre1,
ppre2,
ppre3,
ppre4,
csi_ck: Some(CSI_FREQ),
hsi_ck: Some(HSI_FREQ),
hsi48_ck: Some(HSI48_FREQ),
lsi_ck: Some(LSI_FREQ),
per_ck: Some(per_ck),
hse_ck,
pll1_p_ck: pll1_p_ck.map(Hertz),
pll1_q_ck: pll1_q_ck.map(Hertz),
pll1_r_ck: pll1_r_ck.map(Hertz),
pll2_p_ck: pll2_p_ck.map(Hertz),
pll2_q_ck: pll2_q_ck.map(Hertz),
pll2_r_ck: pll2_r_ck.map(Hertz),
pll3_p_ck: pll3_p_ck.map(Hertz),
pll3_q_ck: pll3_q_ck.map(Hertz),
pll3_r_ck: pll3_r_ck.map(Hertz),
timx_ker_ck: rcc_timerx_ker_ck.map(Hertz),
timy_ker_ck: rcc_timery_ker_ck.map(Hertz),
adc_ker_ck,
sys_ck,
c_ck: Hertz(sys_d1cpre_ck),
};
set_freqs(Clocks {
sys: core_clocks.c_ck,
ahb1: core_clocks.hclk,
ahb2: core_clocks.hclk,
ahb3: core_clocks.hclk,
ahb4: core_clocks.hclk,
apb1: core_clocks.pclk1,
apb2: core_clocks.pclk2,
apb4: core_clocks.pclk4,
apb1_tim: core_clocks.timx_ker_ck.unwrap_or(core_clocks.pclk1),
apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2),
adc: core_clocks.adc_ker_ck,
});
}
mod pll {
use super::{Hertz, RCC};
const VCO_MIN: u32 = 150_000_000;
const VCO_MAX: u32 = 420_000_000;
#[derive(Default)]
pub struct PllConfig {
pub p_ck: Option<Hertz>,
pub q_ck: Option<Hertz>,
pub r_ck: Option<Hertz>,
}
pub(super) struct PllConfigResults {
pub ref_x_ck: u32,
pub pll_x_m: u32,
pub pll_x_p: u32,
pub vco_ck_target: u32,
}
fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) {
let pll_x_p = if plln == 0 {
if output > VCO_MAX / 2 {
1
} else {
((VCO_MAX / output) | 1) - 1 // Must be even or unity
}
} else {
// Specific to PLL2/3, will subtract 1 later
if output > VCO_MAX / 2 {
1
} else {
VCO_MAX / output
}
};
let vco_ck = output * pll_x_p;
assert!(pll_x_p < 128);
assert!(vco_ck >= VCO_MIN);
assert!(vco_ck <= VCO_MAX);
(vco_ck, pll_x_p)
}
/// # Safety
///
/// Must have exclusive access to the RCC register block
fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
// Input divisor, resulting in a reference clock in the range
// 1 to 2 MHz. Choose the highest reference clock (lowest m)
let pll_x_m = (pll_src + 1_999_999) / 2_000_000;
assert!(pll_x_m < 64);
// Calculate resulting reference clock
let ref_x_ck = pll_src / pll_x_m;
assert!((1_000_000..=2_000_000).contains(&ref_x_ck));
RCC.pllcfgr().modify(|w| {
w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO);
w.set_pllrge(plln, Pllrge::RANGE1);
});
PllConfigResults {
ref_x_ck,
pll_x_m,
pll_x_p,
vco_ck_target,
}
}
/// # Safety
///
/// Must have exclusive access to the RCC register block
pub(super) fn pll_setup(pll_src: u32, config: &PllConfig, plln: usize) -> (Option<u32>, Option<u32>, Option<u32>) {
use crate::pac::rcc::vals::Divp;
match config.p_ck {
Some(requested_output) => {
let config_results = vco_setup(pll_src, requested_output.0, plln);
let PllConfigResults {
ref_x_ck,
pll_x_m,
pll_x_p,
vco_ck_target,
} = config_results;
RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8));
// Feedback divider. Integer only
let pll_x_n = vco_ck_target / ref_x_ck;
assert!(pll_x_n >= 4);
assert!(pll_x_n <= 512);
RCC.plldivr(plln).modify(|w| w.set_divn1((pll_x_n - 1) as u16));
// No FRACN
RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
let vco_ck = ref_x_ck * pll_x_n;
RCC.plldivr(plln)
.modify(|w| w.set_divp1(Divp::from_bits((pll_x_p - 1) as u8)));
RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
// Calulate additional output dividers
let q_ck = match config.q_ck {
Some(Hertz(ck)) if ck > 0 => {
let div = (vco_ck + ck - 1) / ck;
RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8));
RCC.pllcfgr().modify(|w| w.set_divqen(plln, true));
Some(vco_ck / div)
}
_ => None,
};
let r_ck = match config.r_ck {
Some(Hertz(ck)) if ck > 0 => {
let div = (vco_ck + ck - 1) / ck;
RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8));
RCC.pllcfgr().modify(|w| w.set_divren(plln, true));
Some(vco_ck / div)
}
_ => None,
};
(Some(vco_ck / pll_x_p), q_ck, r_ck)
}
None => {
assert!(
config.q_ck.is_none(),
"Must set PLL P clock for Q clock to take effect!"
);
assert!(
config.r_ck.is_none(),
"Must set PLL P clock for R clock to take effect!"
);
(None, None, None)
}
}
}
}

View File

@ -1,8 +1,11 @@
pub use super::common::{AHBPrescaler, APBPrescaler};
use super::bd::BackupDomain;
pub use super::bus::{AHBPrescaler, APBPrescaler};
use super::RtcClockSource;
pub use crate::pac::pwr::vals::Vos as VoltageScale;
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
use crate::pac::RCC;
#[cfg(crs)]
use crate::pac::{crs, CRS, SYSCFG};
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
@ -135,6 +138,10 @@ pub struct Config {
pub apb2_pre: APBPrescaler,
#[cfg(crs)]
pub enable_hsi48: bool,
pub rtc: Option<RtcClockSource>,
pub lse: Option<Hertz>,
pub lsi: bool,
pub voltage_scale: VoltageScale,
}
impl Default for Config {
@ -142,16 +149,25 @@ impl Default for Config {
fn default() -> Config {
Config {
mux: ClockSrc::MSI(MSIRange::default()),
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
#[cfg(crs)]
enable_hsi48: false,
rtc: None,
lse: None,
lsi: false,
voltage_scale: VoltageScale::RANGE1,
}
}
}
pub(crate) unsafe fn init(config: Config) {
// Set voltage scale
while PWR.csr().read().vosf() {}
PWR.cr().write(|w| w.set_vos(config.voltage_scale));
while PWR.csr().read().vosf() {}
let (sys_clk, sw) = match config.mux {
ClockSrc::MSI(range) => {
// Set MSI range
@ -231,6 +247,28 @@ pub(crate) unsafe fn init(config: Config) {
}
};
BackupDomain::configure_ls(
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
let wait_states = match config.voltage_scale {
VoltageScale::RANGE1 => match sys_clk {
..=16_000_000 => 0,
_ => 1,
},
VoltageScale::RANGE2 => match sys_clk {
..=8_000_000 => 0,
_ => 1,
},
VoltageScale::RANGE3 => 0,
_ => unreachable!(),
};
FLASH.acr().modify(|w| {
w.set_latency(wait_states != 0);
});
RCC.cfgr().modify(|w| {
w.set_sw(sw);
w.set_hpre(config.ahb_pre.into());
@ -239,7 +277,7 @@ pub(crate) unsafe fn init(config: Config) {
});
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.to_bits() as u32 - 7);
@ -248,7 +286,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);
@ -258,7 +296,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);
@ -269,13 +307,6 @@ pub(crate) unsafe fn init(config: Config) {
#[cfg(crs)]
if config.enable_hsi48 {
// Reset SYSCFG peripheral
RCC.apb2rstr().modify(|w| w.set_syscfgrst(true));
RCC.apb2rstr().modify(|w| w.set_syscfgrst(false));
// Enable SYSCFG peripheral
RCC.apb2enr().modify(|w| w.set_syscfgen(true));
// Reset CRS peripheral
RCC.apb1rstr().modify(|w| w.set_crsrst(true));
RCC.apb1rstr().modify(|w| w.set_crsrst(false));

View File

@ -1,4 +1,4 @@
pub use super::common::{AHBPrescaler, APBPrescaler};
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks};
@ -138,9 +138,9 @@ impl Default for Config {
fn default() -> Config {
Config {
mux: ClockSrc::MSI(MSIRange::default()),
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
}
}
}
@ -240,7 +240,7 @@ pub(crate) unsafe fn init(config: Config) {
});
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.to_bits() as u32 - 7);
@ -249,7 +249,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);
@ -259,7 +259,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);

View File

@ -2,15 +2,15 @@ use core::marker::PhantomData;
use embassy_hal_internal::into_ref;
use stm32_metapac::rcc::regs::Cfgr;
use stm32_metapac::rcc::vals::{Lsedrv, Mcopre, Mcosel};
use stm32_metapac::rcc::vals::{Mcopre, Mcosel};
pub use super::common::{AHBPrescaler, APBPrescaler};
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::gpio::sealed::AFType;
use crate::gpio::Speed;
use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw};
use crate::pac::{FLASH, PWR, RCC};
use crate::pac::{FLASH, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::{set_freqs, Clocks};
use crate::rtc::{Rtc, RtcClockSource as RCS};
use crate::time::Hertz;
use crate::{peripherals, Peripheral};
@ -241,6 +241,8 @@ pub struct Config {
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
pub hsi48: bool,
pub rtc_mux: RtcClockSource,
pub lse: Option<Hertz>,
pub lsi: bool,
}
impl Default for Config {
@ -248,22 +250,19 @@ impl Default for Config {
fn default() -> Config {
Config {
mux: ClockSrc::MSI(MSIRange::Range6),
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
pllsai1: None,
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
hsi48: false,
rtc_mux: RtcClockSource::LSI32,
rtc_mux: RtcClockSource::LSI,
lsi: true,
lse: None,
}
}
}
pub enum RtcClockSource {
LSE32,
LSI32,
}
pub enum McoClock {
DIV1,
DIV2,
@ -410,37 +409,7 @@ pub(crate) unsafe fn init(config: Config) {
while RCC.cfgr().read().sws() != Sw::MSI {}
}
RCC.apb1enr1().modify(|w| w.set_pwren(true));
match config.rtc_mux {
RtcClockSource::LSE32 => {
// 1. Unlock the backup domain
PWR.cr1().modify(|w| w.set_dbp(true));
// 2. Setup the LSE
RCC.bdcr().modify(|w| {
// Enable LSE
w.set_lseon(true);
// Max drive strength
// TODO: should probably be settable
w.set_lsedrv(Lsedrv::HIGH);
});
// Wait until LSE is running
while !RCC.bdcr().read().lserdy() {}
Rtc::set_clock_source(RCS::LSE);
}
RtcClockSource::LSI32 => {
// Turn on the internal 32 kHz LSI oscillator
RCC.csr().modify(|w| w.set_lsion(true));
// Wait until LSI is running
while !RCC.csr().read().lsirdy() {}
Rtc::set_clock_source(RCS::LSI);
}
}
BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default()));
let (sys_clk, sw) = match config.mux {
ClockSrc::MSI(range) => {
@ -451,7 +420,7 @@ pub(crate) unsafe fn init(config: Config) {
w.set_msirgsel(true);
w.set_msion(true);
if let RtcClockSource::LSE32 = config.rtc_mux {
if let RtcClockSource::LSE = config.rtc_mux {
// If LSE is enabled, enable calibration of MSI
w.set_msipllen(true);
} else {
@ -609,7 +578,7 @@ pub(crate) unsafe fn init(config: Config) {
});
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.to_bits() as u32 - 7);
@ -618,7 +587,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);
@ -628,7 +597,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);
@ -637,8 +606,6 @@ pub(crate) unsafe fn init(config: Config) {
}
};
RCC.apb1enr1().modify(|w| w.set_pwren(true));
set_freqs(Clocks {
sys: Hertz(sys_clk),
ahb1: Hertz(ahb_freq),

View File

@ -1,6 +1,6 @@
use stm32_metapac::PWR;
pub use super::common::{AHBPrescaler, APBPrescaler};
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw};
use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks};
@ -238,9 +238,9 @@ impl Default for Config {
fn default() -> Config {
Config {
mux: ClockSrc::MSI(MSIRange::Range6),
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
pllsai1: None,
hsi48: false,
}
@ -317,11 +317,6 @@ pub(crate) unsafe fn init(config: Config) {
let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div();
#[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))]
assert!(freq <= 120_000_000);
#[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))]
assert!(freq <= 80_000_000);
RCC.pllcfgr().write(move |w| {
w.set_plln(mul.into());
w.set_pllm(prediv.into());
@ -407,7 +402,7 @@ pub(crate) unsafe fn init(config: Config) {
});
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.to_bits() as u32 - 7);
@ -416,7 +411,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);
@ -426,7 +421,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);

View File

@ -0,0 +1,71 @@
use core::marker::PhantomData;
use embassy_hal_internal::into_ref;
use crate::gpio::sealed::AFType;
use crate::gpio::Speed;
pub use crate::pac::rcc::vals::{Mco1 as Mco1Source, Mco2 as Mco2Source};
use crate::pac::RCC;
use crate::{peripherals, Peripheral};
pub(crate) mod sealed {
pub trait McoInstance {
type Source;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
}
}
pub trait McoInstance: sealed::McoInstance + 'static {}
pin_trait!(McoPin, McoInstance);
macro_rules! impl_peri {
($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
impl sealed::McoInstance for peripherals::$peri {
type Source = $source;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
RCC.cfgr().modify(|w| {
w.$set_source(source);
w.$set_prescaler(prescaler);
});
}
}
impl McoInstance for peripherals::$peri {}
};
}
impl_peri!(MCO1, Mco1Source, set_mco1, set_mco1pre);
impl_peri!(MCO2, Mco2Source, set_mco2, set_mco2pre);
pub struct Mco<'d, T: McoInstance> {
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: McoInstance> Mco<'d, T> {
/// Create a new MCO instance.
///
/// `prescaler` must be between 1 and 15.
pub fn new(
_peri: impl Peripheral<P = T> + 'd,
pin: impl Peripheral<P = impl McoPin<T>> + 'd,
source: T::Source,
prescaler: u8,
) -> Self {
into_ref!(pin);
assert!(
1 <= prescaler && prescaler <= 15,
"Mco prescaler must be between 1 and 15. Refer to the reference manual for more information."
);
critical_section::with(|_| unsafe {
T::apply_clock_settings(source, prescaler);
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
pin.set_speed(Speed::VeryHigh);
});
Self { phantom: PhantomData }
}
}

View File

@ -1,11 +1,17 @@
#![macro_use]
pub mod common;
use core::mem::MaybeUninit;
pub use crate::rcc::bd::RtcClockSource;
use crate::time::Hertz;
pub(crate) mod bd;
mod bus;
#[cfg(any(stm32h5, stm32h7))]
mod mco;
#[cfg(any(stm32h5, stm32h7))]
pub use mco::*;
#[cfg_attr(rcc_f0, path = "f0.rs")]
#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")]
#[cfg_attr(rcc_f2, path = "f2.rs")]
@ -15,20 +21,30 @@ use crate::time::Hertz;
#[cfg_attr(rcc_c0, path = "c0.rs")]
#[cfg_attr(rcc_g0, path = "g0.rs")]
#[cfg_attr(rcc_g4, path = "g4.rs")]
#[cfg_attr(any(rcc_h7, rcc_h7ab), path = "h7.rs")]
#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab), path = "h.rs")]
#[cfg_attr(rcc_l0, path = "l0.rs")]
#[cfg_attr(rcc_l1, path = "l1.rs")]
#[cfg_attr(rcc_l4, path = "l4.rs")]
#[cfg_attr(rcc_l5, path = "l5.rs")]
#[cfg_attr(rcc_u5, path = "u5.rs")]
#[cfg_attr(rcc_wb, path = "wb.rs")]
#[cfg_attr(rcc_wba, path = "wba.rs")]
#[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")]
#[cfg_attr(any(rcc_h5, rcc_h50), path = "h5.rs")]
mod _version;
pub use _version::*;
#[cfg(feature = "low-power")]
use atomic_polyfill::{AtomicU32, Ordering};
// Model Clock Configuration
//
// pub struct Clocks {
// hse: Option<Hertz>,
// hsi: bool,
// lse: Option<Hertz>,
// lsi: bool,
// rtc: RtcSource,
// }
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Clocks {
@ -41,16 +57,18 @@ pub struct Clocks {
pub apb2: Hertz,
#[cfg(not(any(rcc_c0, rcc_g0)))]
pub apb2_tim: Hertz,
#[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_u5))]
#[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5))]
pub apb3: Hertz,
#[cfg(any(rcc_h7, rcc_h7ab))]
pub apb4: Hertz,
#[cfg(any(rcc_wba))]
pub apb7: Hertz,
// AHB
pub ahb1: Hertz,
#[cfg(any(
rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb,
rcc_wl5, rcc_wle
rcc_wba, rcc_wl5, rcc_wle
))]
pub ahb2: Hertz,
#[cfg(any(
@ -58,7 +76,7 @@ pub struct Clocks {
rcc_wle
))]
pub ahb3: Hertz,
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))]
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_wba))]
pub ahb4: Hertz,
#[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))]
@ -70,15 +88,22 @@ pub struct Clocks {
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
pub pllsai: Option<Hertz>,
#[cfg(stm32f1)]
pub adc: Hertz,
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))]
#[cfg(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3, rcc_g4))]
pub adc: Option<Hertz>,
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
/// Set only if the lsi or lse is configured
#[cfg(any(rcc_f3, rcc_g4))]
pub adc34: Option<Hertz>,
#[cfg(stm32f334)]
pub hrtim: Option<Hertz>,
#[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_f7))]
/// Set only if the lsi or lse is configured, indicates stop is supported
pub rtc: Option<Hertz>,
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
/// Set if the hse is configured, indicates stop is not supported
pub rtc_hse: Option<Hertz>,
}
#[cfg(feature = "low-power")]
@ -86,6 +111,8 @@ static CLOCK_REFCOUNT: AtomicU32 = AtomicU32::new(0);
#[cfg(feature = "low-power")]
pub fn low_power_ready() -> bool {
trace!("clock refcount: {}", CLOCK_REFCOUNT.load(Ordering::SeqCst));
CLOCK_REFCOUNT.load(Ordering::SeqCst) == 0
}

View File

@ -1,6 +1,6 @@
use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllsrc, Sw};
pub use super::common::{AHBPrescaler, APBPrescaler};
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
@ -11,7 +11,7 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
pub use super::common::VoltageScale;
pub use crate::pac::pwr::vals::Vos as VoltageScale;
#[derive(Copy, Clone)]
pub enum ClockSrc {
@ -119,53 +119,13 @@ impl Into<Pllm> for PllM {
}
}
impl Into<u8> for AHBPrescaler {
fn into(self) -> u8 {
match self {
AHBPrescaler::NotDivided => 1,
AHBPrescaler::Div2 => 0x08,
AHBPrescaler::Div4 => 0x09,
AHBPrescaler::Div8 => 0x0a,
AHBPrescaler::Div16 => 0x0b,
AHBPrescaler::Div64 => 0x0c,
AHBPrescaler::Div128 => 0x0d,
AHBPrescaler::Div256 => 0x0e,
AHBPrescaler::Div512 => 0x0f,
}
}
}
impl Default for AHBPrescaler {
fn default() -> Self {
AHBPrescaler::NotDivided
}
}
impl Default for APBPrescaler {
fn default() -> Self {
APBPrescaler::NotDivided
}
}
impl Into<u8> for APBPrescaler {
fn into(self) -> u8 {
match self {
APBPrescaler::NotDivided => 1,
APBPrescaler::Div2 => 0x04,
APBPrescaler::Div4 => 0x05,
APBPrescaler::Div8 => 0x06,
APBPrescaler::Div16 => 0x07,
}
}
}
impl Into<Sw> for ClockSrc {
fn into(self) -> Sw {
match self {
ClockSrc::MSI(..) => Sw::MSIS,
ClockSrc::HSE(..) => Sw::HSE,
ClockSrc::HSI16 => Sw::HSI16,
ClockSrc::PLL1R(..) => Sw::PLL1R,
ClockSrc::PLL1R(..) => Sw::PLL1_R,
}
}
}
@ -239,10 +199,10 @@ impl Default for Config {
fn default() -> Self {
Self {
mux: ClockSrc::MSI(MSIRange::default()),
ahb_pre: Default::default(),
apb1_pre: Default::default(),
apb2_pre: Default::default(),
apb3_pre: Default::default(),
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
apb3_pre: APBPrescaler::DIV1,
hsi48: false,
}
}
@ -326,12 +286,12 @@ pub(crate) unsafe fn init(config: Config) {
}
// TODO make configurable
let power_vos = VoltageScale::Scale3;
let power_vos = VoltageScale::RANGE3;
// states and programming delay
let wait_states = match power_vos {
// VOS 0 range VCORE 1.26V - 1.40V
VoltageScale::Scale0 => {
// VOS 1 range VCORE 1.26V - 1.40V
VoltageScale::RANGE1 => {
if sys_clk < 32_000_000 {
0
} else if sys_clk < 64_000_000 {
@ -344,8 +304,8 @@ pub(crate) unsafe fn init(config: Config) {
4
}
}
// VOS 1 range VCORE 1.15V - 1.26V
VoltageScale::Scale1 => {
// VOS 2 range VCORE 1.15V - 1.26V
VoltageScale::RANGE2 => {
if sys_clk < 30_000_000 {
0
} else if sys_clk < 60_000_000 {
@ -356,8 +316,8 @@ pub(crate) unsafe fn init(config: Config) {
3
}
}
// VOS 2 range VCORE 1.05V - 1.15V
VoltageScale::Scale2 => {
// VOS 3 range VCORE 1.05V - 1.15V
VoltageScale::RANGE3 => {
if sys_clk < 24_000_000 {
0
} else if sys_clk < 48_000_000 {
@ -366,8 +326,8 @@ pub(crate) unsafe fn init(config: Config) {
2
}
}
// VOS 3 range VCORE 0.95V - 1.05V
VoltageScale::Scale3 => {
// VOS 4 range VCORE 0.95V - 1.05V
VoltageScale::RANGE4 => {
if sys_clk < 12_000_000 {
0
} else {
@ -395,7 +355,7 @@ pub(crate) unsafe fn init(config: Config) {
});
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1 << (pre as u32 - 7);
@ -404,7 +364,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
@ -414,7 +374,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
@ -424,7 +384,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);

View File

@ -1,6 +1,6 @@
pub use super::common::{AHBPrescaler, APBPrescaler};
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::Clocks;
use crate::rtc::{Rtc, RtcClockSource};
use crate::time::{khz, mhz, Hertz};
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
@ -108,6 +108,7 @@ pub struct Pll {
pub struct Config {
pub hse: Option<Hse>,
pub lse: Option<Hertz>,
pub lsi: bool,
pub sys: Sysclk,
pub mux: Option<PllMux>,
pub pll48: Option<Pll48Source>,
@ -135,7 +136,8 @@ pub const WPAN_DEFAULT: Config = Config {
prediv: 2,
}),
pll48: None,
rtc: None,
rtc: Some(RtcClockSource::LSE),
lsi: false,
pll: Some(Pll {
mul: 12,
@ -145,11 +147,11 @@ pub const WPAN_DEFAULT: Config = Config {
}),
pllsai: None,
ahb1_pre: AHBPrescaler::NotDivided,
ahb2_pre: AHBPrescaler::Div2,
ahb3_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
ahb1_pre: AHBPrescaler::DIV1,
ahb2_pre: AHBPrescaler::DIV2,
ahb3_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
};
impl Default for Config {
@ -164,12 +166,13 @@ impl Default for Config {
pll: None,
pllsai: None,
rtc: None,
lsi: false,
ahb1_pre: AHBPrescaler::NotDivided,
ahb2_pre: AHBPrescaler::NotDivided,
ahb3_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
ahb1_pre: AHBPrescaler::DIV1,
ahb2_pre: AHBPrescaler::DIV1,
ahb3_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
}
}
}
@ -209,7 +212,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
};
let ahb1_clk = match config.ahb1_pre {
AHBPrescaler::NotDivided => sys_clk,
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1u32 << (pre as u32 - 7);
@ -218,7 +221,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
};
let ahb2_clk = match config.ahb2_pre {
AHBPrescaler::NotDivided => sys_clk,
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1u32 << (pre as u32 - 7);
@ -227,7 +230,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
};
let ahb3_clk = match config.ahb3_pre {
AHBPrescaler::NotDivided => sys_clk,
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1u32 << (pre as u32 - 7);
@ -236,7 +239,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
};
let (apb1_clk, apb1_tim_clk) = match config.apb1_pre {
APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk),
APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
@ -246,7 +249,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
};
let (apb2_clk, apb2_tim_clk) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk),
APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
@ -271,11 +274,11 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
apb1_tim: apb1_tim_clk,
apb2_tim: apb2_tim_clk,
rtc: rtc_clk,
rtc_hse: None,
}
}
pub(crate) fn configure_clocks(config: &Config) {
let pwr = crate::pac::PWR;
let rcc = crate::pac::RCC;
let needs_hsi = if let Some(pll_mux) = &config.mux {
@ -292,29 +295,13 @@ pub(crate) fn configure_clocks(config: &Config) {
while !rcc.cr().read().hsirdy() {}
}
let needs_lsi = if let Some(rtc_mux) = &config.rtc {
*rtc_mux == RtcClockSource::LSI
} else {
false
};
rcc.cfgr().modify(|w| w.set_stopwuck(true));
if needs_lsi {
rcc.csr().modify(|w| w.set_lsi1on(true));
while !rcc.csr().read().lsi1rdy() {}
}
match &config.lse {
Some(_) => {
rcc.cfgr().modify(|w| w.set_stopwuck(true));
pwr.cr1().modify(|w| w.set_dbp(true));
pwr.cr1().modify(|w| w.set_dbp(true));
rcc.bdcr().modify(|w| w.set_lseon(true));
}
_ => {}
}
BackupDomain::configure_ls(
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
match &config.hse {
Some(hse) => {
@ -374,6 +361,4 @@ pub(crate) fn configure_clocks(config: &Config) {
w.set_c2hpre(config.ahb2_pre.into());
w.set_shdhpre(config.ahb3_pre.into());
});
config.rtc.map(|clock_source| Rtc::set_clock_source(clock_source));
}

View File

@ -0,0 +1,154 @@
use stm32_metapac::rcc::vals::{Pllsrc, Sw};
use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
pub use crate::pac::pwr::vals::Vos as VoltageScale;
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
#[derive(Copy, Clone)]
pub enum ClockSrc {
HSE(Hertz),
HSI16,
}
#[derive(Clone, Copy, Debug)]
pub enum PllSrc {
HSE(Hertz),
HSI16,
}
impl Into<Pllsrc> for PllSrc {
fn into(self) -> Pllsrc {
match self {
PllSrc::HSE(..) => Pllsrc::HSE32,
PllSrc::HSI16 => Pllsrc::HSI16,
}
}
}
impl Into<Sw> for ClockSrc {
fn into(self) -> Sw {
match self {
ClockSrc::HSE(..) => Sw::HSE32,
ClockSrc::HSI16 => Sw::HSI16,
}
}
}
#[derive(Copy, Clone)]
pub struct Config {
pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
pub apb7_pre: APBPrescaler,
}
impl Default for Config {
fn default() -> Self {
Self {
mux: ClockSrc::HSI16,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
apb7_pre: APBPrescaler::DIV1,
}
}
}
pub(crate) unsafe fn init(config: Config) {
let sys_clk = match config.mux {
ClockSrc::HSE(freq) => {
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
freq
}
ClockSrc::HSI16 => {
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
HSI_FREQ
}
};
// TODO make configurable
let power_vos = VoltageScale::RANGE1;
// states and programming delay
let wait_states = match power_vos {
VoltageScale::RANGE1 => match sys_clk.0 {
..=32_000_000 => 0,
..=64_000_000 => 1,
..=96_000_000 => 2,
..=100_000_000 => 3,
_ => 4,
},
VoltageScale::RANGE2 => match sys_clk.0 {
..=8_000_000 => 0,
..=16_000_000 => 1,
_ => 2,
},
};
FLASH.acr().modify(|w| {
w.set_latency(wait_states);
});
RCC.cfgr1().modify(|w| {
w.set_sw(config.mux.into());
});
RCC.cfgr2().modify(|w| {
w.set_hpre(config.ahb_pre.into());
w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre.into());
});
RCC.cfgr3().modify(|w| {
w.set_ppre7(config.apb7_pre.into());
});
let ahb_freq = sys_clk / config.ahb_pre;
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let freq = ahb_freq / pre;
(freq, freq * 2u32)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let freq = ahb_freq / pre;
(freq, freq * 2u32)
}
};
let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let freq = ahb_freq / pre;
(freq, freq * 2u32)
}
};
set_freqs(Clocks {
sys: sys_clk,
ahb1: ahb_freq,
ahb2: ahb_freq,
ahb4: ahb_freq,
apb1: apb1_freq,
apb2: apb2_freq,
apb7: apb7_freq,
apb1_tim: apb1_tim_freq,
apb2_tim: apb2_tim_freq,
});
}

View File

@ -1,8 +1,9 @@
pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale};
use crate::pac::pwr::vals::Dbp;
use crate::pac::{FLASH, PWR, RCC};
pub use super::bus::{AHBPrescaler, APBPrescaler};
pub use crate::pac::pwr::vals::Vos as VoltageScale;
use crate::pac::rcc::vals::Adcsel;
use crate::pac::{FLASH, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::{set_freqs, Clocks};
use crate::rtc::{Rtc, RtcClockSource as RCS};
use crate::time::Hertz;
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
@ -75,9 +76,9 @@ impl MSIRange {
fn vos(&self) -> VoltageScale {
if self > &MSIRange::Range8 {
VoltageScale::Scale0
VoltageScale::RANGE1
} else {
VoltageScale::Scale1
VoltageScale::RANGE2
}
}
}
@ -107,6 +108,29 @@ impl Into<u8> for MSIRange {
}
}
#[derive(Clone, Copy)]
pub enum AdcClockSource {
HSI16,
PLLPCLK,
SYSCLK,
}
impl AdcClockSource {
pub fn adcsel(&self) -> Adcsel {
match self {
AdcClockSource::HSI16 => Adcsel::HSI16,
AdcClockSource::PLLPCLK => Adcsel::PLLPCLK,
AdcClockSource::SYSCLK => Adcsel::SYSCLK,
}
}
}
impl Default for AdcClockSource {
fn default() -> Self {
Self::HSI16
}
}
/// Clocks configutation
pub struct Config {
pub mux: ClockSrc,
@ -114,9 +138,10 @@ pub struct Config {
pub shd_ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
pub enable_lsi: bool,
pub enable_rtc_apb: bool,
pub rtc_mux: RtcClockSource,
pub lse: Option<Hertz>,
pub lsi: bool,
pub adc_clock_source: AdcClockSource,
}
impl Default for Config {
@ -124,22 +149,18 @@ impl Default for Config {
fn default() -> Config {
Config {
mux: ClockSrc::MSI(MSIRange::default()),
ahb_pre: AHBPrescaler::NotDivided,
shd_ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
enable_lsi: false,
enable_rtc_apb: false,
rtc_mux: RtcClockSource::LSI32,
ahb_pre: AHBPrescaler::DIV1,
shd_ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
rtc_mux: RtcClockSource::LSI,
lsi: true,
lse: None,
adc_clock_source: AdcClockSource::default(),
}
}
}
pub enum RtcClockSource {
LSE32,
LSI32,
}
#[repr(u8)]
pub enum Lsedrv {
Low = 0,
@ -150,13 +171,13 @@ pub enum Lsedrv {
pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw, vos) = match config.mux {
ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::Scale1),
ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::Scale0),
ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::RANGE2),
ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::RANGE1),
ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()),
};
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1 << (pre as u32 - 7);
@ -165,7 +186,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let shd_ahb_freq: u32 = match config.shd_ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1 << (pre as u32 - 7);
@ -174,7 +195,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
@ -184,7 +205,7 @@ pub(crate) unsafe fn init(config: Config) {
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
@ -196,16 +217,17 @@ pub(crate) unsafe fn init(config: Config) {
// Adjust flash latency
let flash_clk_src_freq: u32 = shd_ahb_freq;
let ws = match vos {
VoltageScale::Scale0 => match flash_clk_src_freq {
VoltageScale::RANGE1 => match flash_clk_src_freq {
0..=18_000_000 => 0b000,
18_000_001..=36_000_000 => 0b001,
_ => 0b010,
},
VoltageScale::Scale1 => match flash_clk_src_freq {
VoltageScale::RANGE2 => match flash_clk_src_freq {
0..=6_000_000 => 0b000,
6_000_001..=12_000_000 => 0b001,
_ => 0b010,
},
_ => unreachable!(),
};
FLASH.acr().modify(|w| {
@ -214,35 +236,8 @@ pub(crate) unsafe fn init(config: Config) {
while FLASH.acr().read().latency() != ws {}
match config.rtc_mux {
RtcClockSource::LSE32 => {
// 1. Unlock the backup domain
PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED));
// 2. Setup the LSE
RCC.bdcr().modify(|w| {
// Enable LSE
w.set_lseon(true);
// Max drive strength
// TODO: should probably be settable
w.set_lsedrv(Lsedrv::High as u8); //---// PAM - should not be commented
});
// Wait until LSE is running
while !RCC.bdcr().read().lserdy() {}
Rtc::set_clock_source(RCS::LSE);
}
RtcClockSource::LSI32 => {
// Turn on the internal 32 kHz LSI oscillator
RCC.csr().modify(|w| w.set_lsion(true));
// Wait until LSI is running
while !RCC.csr().read().lsirdy() {}
Rtc::set_clock_source(RCS::LSI);
}
}
// Enables the LSI if configured
BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default()));
match config.mux {
ClockSrc::HSI16 => {
@ -266,7 +261,7 @@ pub(crate) unsafe fn init(config: Config) {
w.set_msirange(range.into());
w.set_msion(true);
if let RtcClockSource::LSE32 = config.rtc_mux {
if let RtcClockSource::LSE = config.rtc_mux {
// If LSE is enabled, enable calibration of MSI
w.set_msipllen(true);
} else {
@ -277,16 +272,8 @@ pub(crate) unsafe fn init(config: Config) {
}
}
if config.enable_rtc_apb {
// enable peripheral clock for communication
crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true));
// read to allow the pwr clock to enable
crate::pac::PWR.cr1().read();
}
RCC.extcfgr().modify(|w| {
if config.shd_ahb_pre == AHBPrescaler::NotDivided {
if config.shd_ahb_pre == AHBPrescaler::DIV1 {
w.set_shdhpre(0);
} else {
w.set_shdhpre(config.shd_ahb_pre.into());
@ -295,24 +282,15 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| {
w.set_sw(sw.into());
if config.ahb_pre == AHBPrescaler::NotDivided {
w.set_hpre(0);
} else {
w.set_hpre(config.ahb_pre.into());
}
w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre.into());
});
// TODO: switch voltage range
// ADC clock MUX
RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel()));
if config.enable_lsi {
let csr = RCC.csr().read();
if !csr.lsion() {
RCC.csr().modify(|w| w.set_lsion(true));
while !RCC.csr().read().lsirdy() {}
}
}
// TODO: switch voltage range
set_freqs(Clocks {
sys: Hertz(sys_clk),

View File

@ -119,7 +119,31 @@ impl<'d, T: Instance> Rng<'d, T> {
pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
for chunk in dest.chunks_mut(4) {
let bits = T::regs().sr().read();
let mut bits = T::regs().sr().read();
if !bits.seis() && !bits.ceis() && !bits.drdy() {
// wait for interrupt
poll_fn(|cx| {
// quick check to avoid registration if already done.
let bits = T::regs().sr().read();
if bits.drdy() || bits.seis() || bits.ceis() {
return Poll::Ready(());
}
RNG_WAKER.register(cx.waker());
T::regs().cr().modify(|reg| reg.set_ie(true));
// Need to check condition **after** `register` to avoid a race
// condition that would result in lost notifications.
let bits = T::regs().sr().read();
if bits.drdy() || bits.seis() || bits.ceis() {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
// Re-read the status register after wait.
bits = T::regs().sr().read()
}
if bits.seis() {
// in case of noise-source or seed error we try to recover here
// but we must not use the data in DR and we return an error
@ -143,26 +167,6 @@ impl<'d, T: Instance> Rng<'d, T> {
for (dest, src) in chunk.iter_mut().zip(random_word.to_be_bytes().iter()) {
*dest = *src
}
} else {
// wait for interrupt
poll_fn(|cx| {
// quick check to avoid registration if already done.
let bits = T::regs().sr().read();
if bits.drdy() || bits.seis() || bits.ceis() {
return Poll::Ready(());
}
RNG_WAKER.register(cx.waker());
T::regs().cr().modify(|reg| reg.set_ie(true));
// Need to check condition **after** `register` to avoid a race
// condition that would result in lost notifications.
let bits = T::regs().sr().read();
if bits.drdy() || bits.seis() || bits.ceis() {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
}
}

View File

@ -89,7 +89,7 @@ pub enum DayOfWeek {
#[cfg(feature = "chrono")]
impl From<chrono::Weekday> for DayOfWeek {
fn from(weekday: Weekday) -> Self {
day_of_week_from_u8(weekday.number_from_monday() as u8).unwrap()
day_of_week_from_u8(weekday.num_days_from_monday() as u8).unwrap()
}
}

View File

@ -1,7 +1,17 @@
//! RTC peripheral abstraction
mod datetime;
#[cfg(feature = "low-power")]
use core::cell::Cell;
#[cfg(feature = "low-power")]
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
#[cfg(feature = "low-power")]
use embassy_sync::blocking_mutex::Mutex;
pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
pub use crate::rcc::RtcClockSource;
use crate::time::Hertz;
/// refer to AN4759 to compare features of RTC2 and RTC3
#[cfg_attr(any(rtc_v1), path = "v1.rs")]
@ -30,106 +40,53 @@ pub enum RtcError {
NotRunning,
}
/// RTC Abstraction
pub struct Rtc {
rtc_config: RtcConfig,
#[cfg(feature = "low-power")]
/// Represents an instant in time that can be substracted to compute a duration
struct RtcInstant {
second: u8,
subsecond: u16,
}
#[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,
}
#[derive(Copy, Clone, PartialEq)]
pub struct RtcConfig {
/// Asynchronous prescaler factor
/// This is the asynchronous division factor:
/// ck_apre frequency = RTCCLK frequency/(PREDIV_A+1)
/// ck_apre drives the subsecond register
async_prescaler: u8,
/// Synchronous prescaler factor
/// This is the synchronous division factor:
/// ck_spre frequency = ck_apre frequency/(PREDIV_S+1)
/// ck_spre must be 1Hz
sync_prescaler: u16,
}
impl Default for RtcConfig {
/// LSI with prescalers assuming 32.768 kHz.
/// Raw sub-seconds in 1/256.
fn default() -> Self {
RtcConfig {
async_prescaler: 127,
sync_prescaler: 255,
}
#[cfg(all(feature = "low-power", feature = "defmt"))]
impl defmt::Format for RtcInstant {
fn format(&self, fmt: defmt::Formatter) {
defmt::write!(
fmt,
"{}:{}",
self.second,
RTC::regs().prer().read().prediv_s() - self.subsecond,
)
}
}
impl RtcConfig {
/// Set the asynchronous prescaler of RTC config
pub fn async_prescaler(mut self, prescaler: u8) -> Self {
self.async_prescaler = prescaler;
self
}
#[cfg(feature = "low-power")]
impl core::ops::Sub for RtcInstant {
type Output = embassy_time::Duration;
/// Set the synchronous prescaler of RTC config
pub fn sync_prescaler(mut self, prescaler: u16) -> Self {
self.sync_prescaler = prescaler;
self
fn sub(self, rhs: Self) -> Self::Output {
use embassy_time::{Duration, TICK_HZ};
let second = if self.second < rhs.second {
self.second + 60
} else {
self.second
};
let psc = RTC::regs().prer().read().prediv_s() as u32;
let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32);
let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32);
let rtc_ticks = self_ticks - other_ticks;
Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64)
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(u8)]
pub enum RtcCalibrationCyclePeriod {
/// 8-second calibration period
Seconds8,
/// 16-second calibration period
Seconds16,
/// 32-second calibration period
Seconds32,
pub struct RtcTimeProvider {
_private: (),
}
impl Default for RtcCalibrationCyclePeriod {
fn default() -> Self {
RtcCalibrationCyclePeriod::Seconds32
}
}
impl Rtc {
pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self {
RTC::enable_peripheral_clk();
let mut rtc_struct = Self { rtc_config };
Self::enable();
rtc_struct.configure(rtc_config);
rtc_struct.rtc_config = rtc_config;
rtc_struct
}
/// Set the datetime to a new value.
///
/// # Errors
///
/// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range.
pub fn set_datetime(&mut self, t: DateTime) -> Result<(), RtcError> {
self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
self.write(true, |rtc| self::datetime::write_date_time(rtc, t));
Ok(())
}
impl RtcTimeProvider {
/// Return the current datetime.
///
/// # Errors
@ -152,6 +109,126 @@ impl Rtc {
self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
}
}
/// RTC Abstraction
pub struct Rtc {
#[cfg(feature = "low-power")]
stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>,
#[cfg(not(feature = "low-power"))]
_private: (),
}
#[non_exhaustive]
#[derive(Copy, Clone, PartialEq)]
pub struct RtcConfig {
/// The subsecond counter frequency; default is 256
///
/// A high counter frequency may impact stop power consumption
pub frequency: Hertz,
}
impl Default for RtcConfig {
/// LSI with prescalers assuming 32.768 kHz.
/// Raw sub-seconds in 1/256.
fn default() -> Self {
RtcConfig { frequency: Hertz(256) }
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(u8)]
pub enum RtcCalibrationCyclePeriod {
/// 8-second calibration period
Seconds8,
/// 16-second calibration period
Seconds16,
/// 32-second calibration period
Seconds32,
}
impl Default for RtcCalibrationCyclePeriod {
fn default() -> Self {
RtcCalibrationCyclePeriod::Seconds32
}
}
impl Rtc {
pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self {
#[cfg(any(rcc_wle, rcc_wl5, rcc_g4, rcc_g0, rtc_v2l4, rtc_v2wb))]
<RTC as crate::rcc::sealed::RccPeripheral>::enable();
let mut this = Self {
#[cfg(feature = "low-power")]
stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)),
#[cfg(not(feature = "low-power"))]
_private: (),
};
let frequency = Self::frequency();
let async_psc = ((frequency.0 / rtc_config.frequency.0) - 1) as u8;
let sync_psc = (rtc_config.frequency.0 - 1) as u16;
this.configure(async_psc, sync_psc);
this
}
fn frequency() -> Hertz {
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
let freqs = unsafe { crate::rcc::get_freqs() };
// Load the clock frequency from the rcc mod, if supported
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
match freqs.rtc {
Some(hertz) => hertz,
None => freqs.rtc_hse.unwrap(),
}
// Assume the default value, if not supported
#[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))]
Hertz(32_768)
}
/// Acquire a [`RtcTimeProvider`] instance.
pub const fn time_provider(&self) -> RtcTimeProvider {
RtcTimeProvider { _private: () }
}
/// Set the datetime to a new value.
///
/// # Errors
///
/// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range.
pub fn set_datetime(&mut self, t: DateTime) -> Result<(), RtcError> {
self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
self.write(true, |rtc| self::datetime::write_date_time(rtc, t));
Ok(())
}
#[cfg(feature = "low-power")]
/// Return the current instant.
fn instant(&self) -> RtcInstant {
let r = RTC::regs();
let tr = r.tr().read();
let subsecond = r.ssr().read().ss();
let second = bcd2_to_byte((tr.st(), tr.su()));
// Unlock the registers
r.dr().read();
RtcInstant { second, subsecond }
}
/// Return the current datetime.
///
/// # Errors
///
/// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
pub fn now(&self) -> Result<DateTime, RtcError> {
self.time_provider().now()
}
/// Check if daylight savings time is active.
pub fn get_daylight_savings(&self) -> bool {
@ -166,10 +243,6 @@ impl Rtc {
})
}
pub fn get_config(&self) -> RtcConfig {
self.rtc_config
}
pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT;
/// Read content of the backup register.
@ -215,12 +288,16 @@ pub(crate) mod sealed {
pub trait Instance {
const BACKUP_REGISTER_COUNT: usize;
#[cfg(feature = "low-power")]
const EXTI_WAKEUP_LINE: usize;
#[cfg(feature = "low-power")]
type WakeupInterrupt: crate::interrupt::typelevel::Interrupt;
fn regs() -> Rtc {
crate::pac::RTC
}
fn enable_peripheral_clk() {}
/// Read content of the backup register.
///
/// The registers retain their values during wakes from standby mode or system resets. They also

View File

@ -1,77 +1,21 @@
use stm32_metapac::rtc::vals::{Init, Osel, Pol};
use super::{sealed, RtcClockSource, RtcConfig};
use super::sealed;
use crate::pac::rtc::Rtc;
use crate::peripherals::RTC;
use crate::rtc::sealed::Instance;
#[cfg(all(feature = "time", any(stm32wb, stm32f4)))]
pub struct RtcInstant {
ssr: u16,
st: u8,
}
#[cfg(all(feature = "time", any(stm32wb, stm32f4)))]
impl RtcInstant {
pub fn now() -> Self {
// TODO: read value twice
use crate::rtc::bcd2_to_byte;
let tr = RTC::regs().tr().read();
let tr2 = RTC::regs().tr().read();
let ssr = RTC::regs().ssr().read().ss();
let ssr2 = RTC::regs().ssr().read().ss();
let st = bcd2_to_byte((tr.st(), tr.su()));
let st2 = bcd2_to_byte((tr2.st(), tr2.su()));
assert!(st == st2);
assert!(ssr == ssr2);
let _ = RTC::regs().dr().read();
trace!("ssr: {}", ssr);
trace!("st: {}", st);
Self { ssr, st }
}
}
#[cfg(all(feature = "time", any(stm32wb, stm32f4)))]
impl core::ops::Sub for RtcInstant {
type Output = embassy_time::Duration;
fn sub(self, rhs: Self) -> Self::Output {
use embassy_time::{Duration, TICK_HZ};
let st = if self.st < rhs.st { self.st + 60 } else { self.st };
// TODO: read prescaler
let self_ticks = st as u32 * 256 + (255 - self.ssr as u32);
let other_ticks = rhs.st as u32 * 256 + (255 - rhs.ssr as u32);
let rtc_ticks = self_ticks - other_ticks;
trace!("self, other, rtc ticks: {}, {}, {}", self_ticks, other_ticks, rtc_ticks);
Duration::from_ticks(
((((st as u32 * 256 + (255u32 - self.ssr as u32)) - (rhs.st as u32 * 256 + (255u32 - rhs.ssr as u32)))
* TICK_HZ as u32) as u32
/ 256u32) as u64,
)
}
}
#[allow(dead_code)]
#[repr(u8)]
#[derive(Clone, Copy, Debug)]
pub(crate) enum WakeupPrescaler {
Div2,
Div4,
Div8,
Div16,
Div2 = 2,
Div4 = 4,
Div8 = 8,
Div16 = 16,
}
#[cfg(any(stm32wb, stm32f4))]
#[cfg(any(stm32wb, stm32f4, stm32l0))]
impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
fn from(val: WakeupPrescaler) -> Self {
use crate::pac::rtc::vals::Wucksel;
@ -85,7 +29,7 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
}
}
#[cfg(any(stm32wb, stm32f4))]
#[cfg(any(stm32wb, stm32f4, stm32l0))]
impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
use crate::pac::rtc::vals::Wucksel;
@ -100,17 +44,6 @@ impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
}
}
impl From<WakeupPrescaler> for u32 {
fn from(val: WakeupPrescaler) -> Self {
match val {
WakeupPrescaler::Div2 => 2,
WakeupPrescaler::Div4 => 4,
WakeupPrescaler::Div8 => 8,
WakeupPrescaler::Div16 => 16,
}
}
}
#[allow(dead_code)]
impl WakeupPrescaler {
pub fn compute_min(val: u32) -> Self {
@ -121,158 +54,100 @@ impl WakeupPrescaler {
WakeupPrescaler::Div16,
]
.iter()
.skip_while(|psc| <WakeupPrescaler as Into<u32>>::into(**psc) <= val)
.skip_while(|psc| **psc as u32 <= val)
.next()
.unwrap_or(&WakeupPrescaler::Div16)
}
}
impl super::Rtc {
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() {}
}
}
}
#[allow(dead_code)]
#[cfg(all(feature = "time", any(stm32wb, stm32f4)))]
/// start the wakeup alarm and return the actual duration of the alarm
/// the actual duration will be the closest value possible that is less
/// than the requested duration.
///
/// note: this api is exposed for testing purposes until low power is implemented.
/// it is not intended to be public
pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) -> RtcInstant {
#[cfg(feature = "low-power")]
/// start the wakeup alarm and wtih a duration that is as close to but less than
/// the requested duration, and record the instant the wakeup alarm was started
pub(crate) fn start_wakeup_alarm(
&self,
requested_duration: embassy_time::Duration,
cs: critical_section::CriticalSection,
) {
use embassy_time::{Duration, TICK_HZ};
use crate::rcc::get_freqs;
// Panic if the rcc mod knows we're not using low-power rtc
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
unsafe { crate::rcc::get_freqs() }.rtc.unwrap();
let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64;
let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ;
let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64);
let rtc_hz = Self::frequency().0 as u64;
let rtc_ticks = requested_duration * rtc_hz / TICK_HZ;
let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32);
// adjust the rtc ticks to the prescaler
let rtc_ticks = rtc_ticks / (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64);
let rtc_ticks = if rtc_ticks >= u16::MAX as u64 {
u16::MAX - 1
} else {
rtc_ticks as u16
};
let duration = Duration::from_ticks(
rtc_ticks as u64 * TICK_HZ * (<WakeupPrescaler as Into<u32>>::into(prescaler) as u64) / rtc_hz,
);
trace!("set wakeup timer for {} ms", duration.as_millis());
// adjust the rtc ticks to the prescaler and subtract one rtc tick
let rtc_ticks = rtc_ticks / prescaler as u64;
let rtc_ticks = rtc_ticks.clamp(0, (u16::MAX - 1) as u64).saturating_sub(1) as u16;
self.write(false, |regs| {
regs.cr().modify(|w| w.set_wutie(true));
regs.cr().modify(|w| w.set_wute(false));
regs.isr().modify(|w| w.set_wutf(false));
while !regs.isr().read().wutwf() {}
regs.cr().modify(|w| w.set_wucksel(prescaler.into()));
regs.wutr().write(|w| w.set_wut(rtc_ticks));
regs.cr().modify(|w| w.set_wute(true));
regs.cr().modify(|w| w.set_wutie(true));
});
RtcInstant::now()
trace!(
"rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}",
Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(),
prescaler as u32,
rtc_ticks,
self.instant(),
);
assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())
}
#[allow(dead_code)]
#[cfg(all(feature = "time", any(stm32wb, stm32f4)))]
/// stop the wakeup alarm and return the time remaining
///
/// note: this api is exposed for testing purposes until low power is implemented.
/// it is not intended to be public
pub(crate) fn stop_wakeup_alarm(&self) -> RtcInstant {
trace!("disable wakeup timer...");
#[cfg(feature = "low-power")]
/// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
/// was called, otherwise none
pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
use crate::interrupt::typelevel::Interrupt;
trace!("rtc: stop wakeup alarm at {}", self.instant());
self.write(false, |regs| {
regs.cr().modify(|w| w.set_wutie(false));
regs.cr().modify(|w| w.set_wute(false));
regs.isr().modify(|w| w.set_wutf(false));
crate::pac::EXTI
.pr(0)
.modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
<RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
});
RtcInstant::now()
}
#[allow(dead_code)]
pub(crate) fn set_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);
});
}
pub(super) fn enable() {
#[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());
});
if let Some(stop_time) = self.stop_time.borrow(cs).take() {
Some(self.instant() - stop_time)
} else {
None
}
}
#[cfg(feature = "low-power")]
pub(crate) fn enable_wakeup_line(&self) {
use crate::interrupt::typelevel::Interrupt;
use crate::pac::EXTI;
<RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
unsafe { <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::enable() };
EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
}
/// Applies the RTC config
/// It this changes the RTC clock source the time will be reset
pub(super) fn configure(&mut self, rtc_config: RtcConfig) {
pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) {
self.write(true, |rtc| {
rtc.cr().modify(|w| {
#[cfg(rtc_v2f2)]
@ -284,8 +159,8 @@ impl super::Rtc {
});
rtc.prer().modify(|w| {
w.set_prediv_s(rtc_config.sync_prescaler);
w.set_prediv_a(rtc_config.async_prescaler);
w.set_prediv_s(sync_psc);
w.set_prediv_a(async_psc);
});
});
}
@ -390,21 +265,17 @@ impl super::Rtc {
impl sealed::Instance for crate::peripherals::RTC {
const BACKUP_REGISTER_COUNT: usize = 20;
fn enable_peripheral_clk() {
#[cfg(any(rtc_v2l4, rtc_v2wb))]
{
// enable peripheral clock for communication
crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true));
#[cfg(all(feature = "low-power", stm32f4))]
const EXTI_WAKEUP_LINE: usize = 22;
// read to allow the pwr clock to enable
crate::pac::PWR.cr1().read();
}
#[cfg(any(rtc_v2f2))]
{
crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true));
crate::pac::PWR.cr().read();
}
}
#[cfg(all(feature = "low-power", stm32l0))]
const EXTI_WAKEUP_LINE: usize = 20;
#[cfg(all(feature = "low-power", stm32f4))]
type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
#[cfg(all(feature = "low-power", stm32l0))]
type WakeupInterrupt = crate::interrupt::typelevel::RTC;
fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> {
if register < Self::BACKUP_REGISTER_COUNT {

View File

@ -1,77 +1,14 @@
use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType};
use super::{sealed, RtcCalibrationCyclePeriod, RtcClockSource, RtcConfig};
use super::{sealed, RtcCalibrationCyclePeriod};
use crate::pac::rtc::Rtc;
use crate::peripherals::RTC;
use crate::rtc::sealed::Instance;
impl super::Rtc {
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 {}
}
}
}
#[allow(dead_code)]
pub(crate) fn set_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);
});
}
pub(super) fn enable() {
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());
});
}
}
/// Applies the RTC config
/// It this changes the RTC clock source the time will be reset
pub(super) fn configure(&mut self, rtc_config: RtcConfig) {
pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) {
self.write(true, |rtc| {
rtc.cr().modify(|w| {
w.set_fmt(Fmt::TWENTYFOURHOUR);
@ -80,8 +17,8 @@ impl super::Rtc {
});
rtc.prer().modify(|w| {
w.set_prediv_s(rtc_config.sync_prescaler);
w.set_prediv_a(rtc_config.async_prescaler);
w.set_prediv_s(sync_psc);
w.set_prediv_a(async_psc);
});
// TODO: configuration for output pins

View File

@ -33,6 +33,8 @@ impl<T: Instance> InterruptHandler<T> {
w.set_dtimeoutie(enable);
w.set_dataendie(enable);
#[cfg(sdmmc_v1)]
w.set_stbiterre(enable);
#[cfg(sdmmc_v2)]
w.set_dabortie(enable);
});
@ -102,6 +104,8 @@ pub enum Error {
BadClock,
SignalingSwitchFailed,
PeripheralBusy,
#[cfg(sdmmc_v1)]
StBitErr,
}
/// A SD command
@ -707,9 +711,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
} else if status.dtimeout() {
}
if status.dtimeout() {
return Poll::Ready(Err(Error::Timeout));
} else if status.dataend() {
}
#[cfg(sdmmc_v1)]
if status.stbiterr() {
return Poll::Ready(Err(Error::StBitErr));
}
if status.dataend() {
return Poll::Ready(Ok(()));
}
Poll::Pending
@ -782,9 +792,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
} else if status.dtimeout() {
}
if status.dtimeout() {
return Poll::Ready(Err(Error::Timeout));
} else if status.dataend() {
}
#[cfg(sdmmc_v1)]
if status.stbiterr() {
return Poll::Ready(Err(Error::StBitErr));
}
if status.dataend() {
return Poll::Ready(Ok(()));
}
Poll::Pending
@ -836,6 +852,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
w.set_dataendc(true);
w.set_dbckendc(true);
w.set_sdioitc(true);
#[cfg(sdmmc_v1)]
w.set_stbiterrc(true);
#[cfg(sdmmc_v2)]
{
@ -873,9 +891,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
} else if status.dtimeout() {
}
if status.dtimeout() {
return Poll::Ready(Err(Error::Timeout));
} else if status.dataend() {
}
#[cfg(sdmmc_v1)]
if status.stbiterr() {
return Poll::Ready(Err(Error::StBitErr));
}
if status.dataend() {
return Poll::Ready(Ok(()));
}
Poll::Pending
@ -1156,9 +1180,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
} else if status.dtimeout() {
}
if status.dtimeout() {
return Poll::Ready(Err(Error::Timeout));
} else if status.dataend() {
}
#[cfg(sdmmc_v1)]
if status.stbiterr() {
return Poll::Ready(Err(Error::StBitErr));
}
if status.dataend() {
return Poll::Ready(Ok(()));
}
Poll::Pending
@ -1207,9 +1237,15 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
} else if status.dtimeout() {
}
if status.dtimeout() {
return Poll::Ready(Err(Error::Timeout));
} else if status.dataend() {
}
#[cfg(sdmmc_v1)]
if status.stbiterr() {
return Poll::Ready(Err(Error::StBitErr));
}
if status.dataend() {
return Poll::Ready(Ok(()));
}
Poll::Pending

View File

@ -323,7 +323,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
/// Reconfigures it with the supplied config.
pub fn reconfigure(&mut self, config: Config) {
pub fn set_config(&mut self, config: Config) {
let cpha = config.raw_phase();
let cpol = config.raw_polarity();
@ -646,6 +646,8 @@ impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
self.sck.as_ref().map(|x| x.set_as_disconnected());
self.mosi.as_ref().map(|x| x.set_as_disconnected());
self.miso.as_ref().map(|x| x.set_as_disconnected());
T::disable();
}
}
@ -1060,6 +1062,6 @@ foreach_peripheral!(
impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> {
type Config = Config;
fn set_config(&mut self, config: &Self::Config) {
self.reconfigure(*config);
self.set_config(*config);
}
}

View File

@ -14,6 +14,8 @@ use stm32_metapac::timer::regs;
use crate::interrupt::typelevel::Interrupt;
use crate::pac::timer::vals;
use crate::rcc::sealed::RccPeripheral;
#[cfg(feature = "low-power")]
use crate::rtc::Rtc;
use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance};
use crate::{interrupt, peripherals};
@ -130,12 +132,14 @@ impl AlarmState {
}
}
struct RtcDriver {
pub(crate) struct RtcDriver {
/// Number of 2^15 periods elapsed since boot.
period: AtomicU32,
alarm_count: AtomicU8,
/// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>,
#[cfg(feature = "low-power")]
rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>,
}
const ALARM_STATE_NEW: AlarmState = AlarmState::new();
@ -144,6 +148,8 @@ embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
period: AtomicU32::new(0),
alarm_count: AtomicU8::new(0),
alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]),
#[cfg(feature = "low-power")]
rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)),
});
impl RtcDriver {
@ -259,6 +265,127 @@ impl RtcDriver {
let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
f(alarm.ctx.get());
}
/*
Low-power private functions: all operate within a critical seciton
*/
#[cfg(feature = "low-power")]
/// Compute the approximate amount of time until the next alarm
fn time_until_next_alarm(&self, cs: CriticalSection) -> embassy_time::Duration {
let now = self.now() + 32;
embassy_time::Duration::from_ticks(
self.alarms
.borrow(cs)
.iter()
.map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now))
.min()
.unwrap_or(u64::MAX),
)
}
#[cfg(feature = "low-power")]
/// Add the given offset to the current time
fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) {
let offset = offset.as_ticks();
let cnt = T::regs_gp16().cnt().read().cnt() as u32;
let period = self.period.load(Ordering::SeqCst);
// Correct the race, if it exists
let period = if period & 1 == 1 && cnt < u16::MAX as u32 / 2 {
period + 1
} else {
period
};
// Normalize to the full overflow
let period = (period / 2) * 2;
// Add the offset
let period = period + 2 * (offset / u16::MAX as u64) as u32;
let cnt = cnt + (offset % u16::MAX as u64) as u32;
let (cnt, period) = if cnt > u16::MAX as u32 {
(cnt - u16::MAX as u32, period + 2)
} else {
(cnt, period)
};
let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period };
self.period.store(period, Ordering::SeqCst);
T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16));
// Now, recompute all alarms
for i in 0..ALARM_COUNT {
let alarm_handle = unsafe { AlarmHandle::new(i as u8) };
let alarm = self.get_alarm(cs, alarm_handle);
self.set_alarm(alarm_handle, alarm.timestamp.get());
}
}
#[cfg(feature = "low-power")]
/// Stop the wakeup alarm, if enabled, and add the appropriate offset
fn stop_wakeup_alarm(&self, cs: CriticalSection) {
if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(cs) {
self.add_time(offset, cs);
}
}
/*
Low-power public functions: all create a critical section
*/
#[cfg(feature = "low-power")]
/// Set the rtc but panic if it's already been set
pub(crate) fn set_rtc(&self, rtc: &'static Rtc) {
critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none()));
}
#[cfg(feature = "low-power")]
/// Pause the timer if ready; return err if not
pub(crate) fn pause_time(&self) -> Result<(), ()> {
critical_section::with(|cs| {
/*
If the wakeup timer is currently running, then we need to stop it and
add the elapsed time to the current time, as this will impact the result
of `time_until_next_alarm`.
*/
self.stop_wakeup_alarm(cs);
let time_until_next_alarm = self.time_until_next_alarm(cs);
if time_until_next_alarm < embassy_time::Duration::from_millis(250) {
Err(())
} else {
self.rtc
.borrow(cs)
.get()
.unwrap()
.start_wakeup_alarm(time_until_next_alarm, cs);
T::regs_gp16().cr1().modify(|w| w.set_cen(false));
Ok(())
}
})
}
#[cfg(feature = "low-power")]
/// Resume the timer with the given offset
pub(crate) fn resume_time(&self) {
if T::regs_gp16().cr1().read().cen() {
// Time isn't currently stopped
return;
}
critical_section::with(|cs| {
self.stop_wakeup_alarm(cs);
T::regs_gp16().cr1().modify(|w| w.set_cen(true));
})
}
}
impl Driver for RtcDriver {
@ -329,6 +456,11 @@ impl Driver for RtcDriver {
}
}
#[cfg(feature = "low-power")]
pub(crate) fn get_driver() -> &'static RtcDriver {
&DRIVER
}
pub(crate) fn init() {
DRIVER.init()
}

View File

@ -1,4 +1,5 @@
pub mod complementary_pwm;
pub mod qei;
pub mod simple_pwm;
use stm32_metapac::timer::vals;
@ -14,6 +15,7 @@ pub mod low_level {
}
pub(crate) mod sealed {
use super::*;
pub trait Basic16bitInstance: RccPeripheral {
type Interrupt: interrupt::typelevel::Interrupt;
@ -31,10 +33,16 @@ pub(crate) mod sealed {
fn clear_update_interrupt(&mut self) -> bool;
fn enable_update_interrupt(&mut self, enable: bool);
fn set_autoreload_preload(&mut self, enable: vals::Arpe);
}
pub trait GeneralPurpose16bitInstance: Basic16bitInstance {
fn regs_gp16() -> crate::pac::timer::TimGp16;
fn set_count_direction(&mut self, direction: vals::Dir);
fn set_clock_division(&mut self, ckd: vals::Ckd);
}
pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
@ -48,6 +56,18 @@ pub(crate) mod sealed {
}
pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf);
fn clear_input_interrupt(&mut self, channel: Channel);
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool);
fn set_input_capture_prescaler(&mut self, channel: Channel, val: u8);
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection);
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode);
/// Global output enable. Does not do anything on non-advanced timers.
fn enable_outputs(&mut self, enable: bool);
@ -59,6 +79,8 @@ pub(crate) mod sealed {
fn set_compare_value(&mut self, channel: Channel, value: u16);
fn get_capture_value(&mut self, channel: Channel) -> u16;
fn get_max_compare_value(&self) -> u16;
}
@ -73,6 +95,18 @@ pub(crate) mod sealed {
}
pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance {
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf);
fn clear_input_interrupt(&mut self, channel: Channel);
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool);
fn set_input_capture_prescaler(&mut self, channel: Channel, val: u8);
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection);
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode);
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity);
@ -81,6 +115,8 @@ pub(crate) mod sealed {
fn set_compare_value(&mut self, channel: Channel, value: u32);
fn get_capture_value(&mut self, channel: Channel) -> u32;
fn get_max_compare_value(&self) -> u32;
}
}
@ -104,6 +140,30 @@ impl Channel {
}
}
#[derive(Clone, Copy)]
pub enum InputCaptureMode {
Rising,
Falling,
BothEdges,
}
#[derive(Clone, Copy)]
pub enum InputTISelection {
Normal,
Alternate,
TRC,
}
impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs {
fn from(tisel: InputTISelection) -> Self {
match tisel {
InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4,
InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3,
InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC,
}
}
}
#[derive(Clone, Copy)]
pub enum OutputCompareMode {
Frozen,
@ -211,6 +271,7 @@ macro_rules! impl_basic_16bit_timer {
use core::convert::TryInto;
let f = frequency.0;
let timer_f = Self::frequency().0;
assert!(f > 0);
let pclk_ticks_per_timer_period = timer_f / f;
let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into());
let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into());
@ -240,6 +301,10 @@ macro_rules! impl_basic_16bit_timer {
fn enable_update_interrupt(&mut self, enable: bool) {
Self::regs().dier().write(|r| r.set_uie(enable));
}
fn set_autoreload_preload(&mut self, enable: vals::Arpe) {
Self::regs().cr1().modify(|r| r.set_arpe(enable));
}
}
};
}
@ -255,6 +320,7 @@ macro_rules! impl_32bit_timer {
fn set_frequency(&mut self, frequency: Hertz) {
use core::convert::TryInto;
let f = frequency.0;
assert!(f > 0);
let timer_f = Self::frequency().0;
let pclk_ticks_per_timer_period = (timer_f / f) as u64;
let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
@ -276,6 +342,59 @@ macro_rules! impl_32bit_timer {
macro_rules! impl_compare_capable_16bit {
($inst:ident) => {
impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
use sealed::GeneralPurpose16bitInstance;
let raw_channel = channel.raw();
Self::regs_gp16()
.ccmr_input(raw_channel / 2)
.modify(|r| r.set_icf(raw_channel % 2, icf));
}
fn clear_input_interrupt(&mut self, channel: Channel) {
use sealed::GeneralPurpose16bitInstance;
Self::regs_gp16()
.sr()
.modify(|r| r.set_ccif(channel.raw(), false));
}
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
use sealed::GeneralPurpose16bitInstance;
Self::regs_gp16()
.dier()
.modify(|r| r.set_ccie(channel.raw(), enable));
}
fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
use sealed::GeneralPurpose16bitInstance;
let raw_channel = channel.raw();
Self::regs_gp16()
.ccmr_input(raw_channel / 2)
.modify(|r| r.set_icpsc(raw_channel % 2, factor));
}
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
use sealed::GeneralPurpose16bitInstance;
let raw_channel = channel.raw();
Self::regs_gp16()
.ccmr_input(raw_channel / 2)
.modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
}
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
use sealed::GeneralPurpose16bitInstance;
Self::regs_gp16().ccer().modify(|r| match mode {
InputCaptureMode::Rising => {
r.set_ccnp(channel.raw(), false);
r.set_ccp(channel.raw(), false);
}
InputCaptureMode::Falling => {
r.set_ccnp(channel.raw(), false);
r.set_ccp(channel.raw(), true);
}
InputCaptureMode::BothEdges => {
r.set_ccnp(channel.raw(), true);
r.set_ccp(channel.raw(), true);
}
});
}
fn enable_outputs(&mut self, _enable: bool) {}
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
@ -305,6 +424,11 @@ macro_rules! impl_compare_capable_16bit {
Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value));
}
fn get_capture_value(&mut self, channel: Channel) -> u16 {
use sealed::GeneralPurpose16bitInstance;
Self::regs_gp16().ccr(channel.raw()).read().ccr()
}
fn get_max_compare_value(&self) -> u16 {
use sealed::GeneralPurpose16bitInstance;
Self::regs_gp16().arr().read().arr()
@ -329,6 +453,14 @@ foreach_interrupt! {
fn regs_gp16() -> crate::pac::timer::TimGp16 {
crate::pac::$inst
}
fn set_count_direction(&mut self, direction: vals::Dir) {
Self::regs_gp16().cr1().modify(|r| r.set_dir(direction));
}
fn set_clock_division(&mut self, ckd: vals::Ckd) {
Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
}
}
};
@ -343,6 +475,59 @@ foreach_interrupt! {
impl GeneralPurpose32bitInstance for crate::peripherals::$inst {}
impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
use sealed::GeneralPurpose32bitInstance;
let raw_channel = channel.raw();
Self::regs_gp32()
.ccmr_input(raw_channel / 2)
.modify(|r| r.set_icf(raw_channel % 2, icf));
}
fn clear_input_interrupt(&mut self, channel: Channel) {
use sealed::GeneralPurpose32bitInstance;
Self::regs_gp32()
.sr()
.modify(|r| r.set_ccif(channel.raw(), false));
}
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
use sealed::GeneralPurpose32bitInstance;
Self::regs_gp32()
.dier()
.modify(|r| r.set_ccie(channel.raw(), enable));
}
fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
use crate::timer::sealed::GeneralPurpose32bitInstance;
let raw_channel = channel.raw();
Self::regs_gp32()
.ccmr_input(raw_channel / 2)
.modify(|r| r.set_icpsc(raw_channel % 2, factor));
}
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
use crate::timer::sealed::GeneralPurpose32bitInstance;
let raw_channel = channel.raw();
Self::regs_gp32()
.ccmr_input(raw_channel / 2)
.modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
}
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
use crate::timer::sealed::GeneralPurpose32bitInstance;
Self::regs_gp32().ccer().modify(|r| match mode {
InputCaptureMode::Rising => {
r.set_ccnp(channel.raw(), false);
r.set_ccp(channel.raw(), false);
}
InputCaptureMode::Falling => {
r.set_ccnp(channel.raw(), false);
r.set_ccp(channel.raw(), true);
}
InputCaptureMode::BothEdges => {
r.set_ccnp(channel.raw(), true);
r.set_ccp(channel.raw(), true);
}
});
}
fn set_output_compare_mode(
&mut self,
channel: Channel,
@ -370,6 +555,11 @@ foreach_interrupt! {
Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
}
fn get_capture_value(&mut self, channel: Channel) -> u32 {
use crate::timer::sealed::GeneralPurpose32bitInstance;
Self::regs_gp32().ccr(channel.raw()).read().ccr()
}
fn get_max_compare_value(&self) -> u32 {
use crate::timer::sealed::GeneralPurpose32bitInstance;
Self::regs_gp32().arr().read().arr() as u32
@ -380,6 +570,14 @@ foreach_interrupt! {
fn regs_gp16() -> crate::pac::timer::TimGp16 {
unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
}
fn set_count_direction(&mut self, direction: vals::Dir) {
Self::regs_gp16().cr1().modify(|r| r.set_dir(direction));
}
fn set_clock_division(&mut self, ckd: vals::Ckd) {
Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
}
}
};
@ -396,6 +594,14 @@ foreach_interrupt! {
fn regs_gp16() -> crate::pac::timer::TimGp16 {
unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
}
fn set_count_direction(&mut self, direction: vals::Dir) {
Self::regs_gp16().cr1().modify(|r| r.set_dir(direction));
}
fn set_clock_division(&mut self, ckd: vals::Ckd) {
Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
}
}
impl sealed::AdvancedControlInstance for crate::peripherals::$inst {
@ -405,6 +611,57 @@ foreach_interrupt! {
}
impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
use crate::timer::sealed::AdvancedControlInstance;
let raw_channel = channel.raw();
Self::regs_advanced()
.ccmr_input(raw_channel / 2)
.modify(|r| r.set_icf(raw_channel % 2, icf));
}
fn clear_input_interrupt(&mut self, channel: Channel) {
use crate::timer::sealed::AdvancedControlInstance;
Self::regs_advanced()
.sr()
.modify(|r| r.set_ccif(channel.raw(), false));
}
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
use crate::timer::sealed::AdvancedControlInstance;
Self::regs_advanced()
.dier()
.modify(|r| r.set_ccie(channel.raw(), enable));
}
fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
use crate::timer::sealed::AdvancedControlInstance;
let raw_channel = channel.raw();
Self::regs_advanced()
.ccmr_input(raw_channel / 2)
.modify(|r| r.set_icpsc(raw_channel % 2, factor));
}
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
use crate::timer::sealed::AdvancedControlInstance;
let raw_channel = channel.raw();
Self::regs_advanced()
.ccmr_input(raw_channel / 2)
.modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
}
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
use crate::timer::sealed::AdvancedControlInstance;
Self::regs_advanced().ccer().modify(|r| match mode {
InputCaptureMode::Rising => {
r.set_ccnp(channel.raw(), false);
r.set_ccp(channel.raw(), false);
}
InputCaptureMode::Falling => {
r.set_ccnp(channel.raw(), false);
r.set_ccp(channel.raw(), true);
}
InputCaptureMode::BothEdges => {
r.set_ccnp(channel.raw(), true);
r.set_ccp(channel.raw(), true);
}
});
}
fn enable_outputs(&mut self, enable: bool) {
use crate::timer::sealed::AdvancedControlInstance;
let r = Self::regs_advanced();
@ -437,6 +694,11 @@ foreach_interrupt! {
.modify(|w| w.set_cce(channel.raw(), enable));
}
fn get_capture_value(&mut self, channel: Channel) -> u16 {
use crate::timer::sealed::AdvancedControlInstance;
Self::regs_advanced().ccr(channel.raw()).read().ccr()
}
fn set_compare_value(&mut self, channel: Channel, value: u16) {
use crate::timer::sealed::AdvancedControlInstance;
Self::regs_advanced()

View File

@ -0,0 +1,96 @@
use core::marker::PhantomData;
use embassy_hal_internal::{into_ref, PeripheralRef};
use super::*;
use crate::gpio::sealed::AFType;
use crate::gpio::AnyPin;
use crate::Peripheral;
pub enum Direction {
Upcounting,
Downcounting,
}
pub struct Ch1;
pub struct Ch2;
pub struct QeiPin<'d, Perip, Channel> {
_pin: PeripheralRef<'d, AnyPin>,
phantom: PhantomData<(Perip, Channel)>,
}
macro_rules! channel_impl {
($new_chx:ident, $channel:ident, $pin_trait:ident) => {
impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> {
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
into_ref!(pin);
critical_section::with(|_| {
pin.set_low();
pin.set_as_af(pin.af_num(), AFType::Input);
#[cfg(gpio_v2)]
pin.set_speed(crate::gpio::Speed::VeryHigh);
});
QeiPin {
_pin: pin.map_into(),
phantom: PhantomData,
}
}
}
};
}
channel_impl!(new_ch1, Ch1, Channel1Pin);
channel_impl!(new_ch2, Ch2, Channel2Pin);
pub struct Qei<'d, T> {
_inner: PeripheralRef<'d, T>,
}
impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self {
Self::new_inner(tim)
}
fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self {
into_ref!(tim);
T::enable();
<T as crate::rcc::sealed::RccPeripheral>::reset();
// Configure TxC1 and TxC2 as captures
T::regs_gp16().ccmr_input(0).modify(|w| {
w.set_ccs(0, vals::CcmrInputCcs::TI4);
w.set_ccs(1, vals::CcmrInputCcs::TI4);
});
// enable and configure to capture on rising edge
T::regs_gp16().ccer().modify(|w| {
w.set_cce(0, true);
w.set_cce(1, true);
w.set_ccp(0, false);
w.set_ccp(1, false);
});
T::regs_gp16().smcr().modify(|w| {
w.set_sms(vals::Sms::ENCODER_MODE_3);
});
T::regs_gp16().arr().modify(|w| w.set_arr(u16::MAX));
T::regs_gp16().cr1().modify(|w| w.set_cen(true));
Self { _inner: tim }
}
pub fn read_direction(&self) -> Direction {
match T::regs_gp16().cr1().read().dir() {
vals::Dir::DOWN => Direction::Downcounting,
vals::Dir::UP => Direction::Upcounting,
}
}
pub fn count(&self) -> u16 {
T::regs_gp16().cnt().read().cnt()
}
}

View File

@ -114,6 +114,30 @@ pub struct BufferedUartRx<'d, T: BasicInstance> {
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: BasicInstance> SetConfig for BufferedUart<'d, T> {
type Config = Config;
fn set_config(&mut self, config: &Self::Config) {
unwrap!(self.set_config(config))
}
}
impl<'d, T: BasicInstance> SetConfig for BufferedUartRx<'d, T> {
type Config = Config;
fn set_config(&mut self, config: &Self::Config) {
unwrap!(self.set_config(config))
}
}
impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> {
type Config = Config;
fn set_config(&mut self, config: &Self::Config) {
unwrap!(self.set_config(config))
}
}
impl<'d, T: BasicInstance> BufferedUart<'d, T> {
pub fn new(
peri: impl Peripheral<P = T> + 'd,
@ -123,7 +147,9 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
config: Config,
) -> BufferedUart<'d, T> {
) -> Result<Self, ConfigError> {
// UartRx and UartTx have one refcount ea.
T::enable();
T::enable();
T::reset();
@ -140,9 +166,11 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
config: Config,
) -> BufferedUart<'d, T> {
) -> Result<Self, ConfigError> {
into_ref!(cts, rts);
// UartRx and UartTx have one refcount ea.
T::enable();
T::enable();
T::reset();
@ -166,9 +194,11 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
config: Config,
) -> BufferedUart<'d, T> {
) -> Result<Self, ConfigError> {
into_ref!(de);
// UartRx and UartTx have one refcount ea.
T::enable();
T::enable();
T::reset();
@ -187,7 +217,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
config: Config,
) -> BufferedUart<'d, T> {
) -> Result<Self, ConfigError> {
into_ref!(_peri, rx, tx);
let state = T::buffered_state();
@ -200,7 +230,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
configure(r, &config, T::frequency(), T::KIND, true, true);
configure(r, &config, T::frequency(), T::KIND, true, true)?;
r.cr1().modify(|w| {
#[cfg(lpuart_v2)]
@ -213,15 +243,19 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
Self {
Ok(Self {
rx: BufferedUartRx { phantom: PhantomData },
tx: BufferedUartTx { phantom: PhantomData },
}
})
}
pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
(self.tx, self.rx)
}
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)
}
}
impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
@ -298,6 +332,10 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
T::Interrupt::pend();
}
}
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)
}
}
impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
@ -368,6 +406,10 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
}
}
}
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)
}
}
impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> {
@ -382,6 +424,8 @@ impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> {
T::Interrupt::disable();
}
}
T::disable();
}
}
@ -397,12 +441,8 @@ impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> {
T::Interrupt::disable();
}
}
}
}
impl embedded_io_async::Error for Error {
fn kind(&self) -> embedded_io_async::ErrorKind {
embedded_io_async::ErrorKind::Other
T::disable();
}
}

View File

@ -5,6 +5,7 @@ use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use embassy_embedded_hal::SetConfig;
use embassy_hal_internal::drop::OnDrop;
use embassy_hal_internal::{into_ref, PeripheralRef};
use futures::future::{select, Either};
@ -12,11 +13,10 @@ use futures::future::{select, Either};
use crate::dma::{NoDma, Transfer};
use crate::gpio::sealed::AFType;
use crate::interrupt::typelevel::Interrupt;
#[cfg(not(any(usart_v1, usart_v2)))]
#[allow(unused_imports)]
#[cfg(not(any(usart_v1, usart_v2)))]
use crate::pac::usart::regs::Isr as Sr;
#[cfg(any(usart_v1, usart_v2))]
#[allow(unused_imports)]
use crate::pac::usart::regs::Sr;
#[cfg(not(any(usart_v1, usart_v2)))]
use crate::pac::usart::Lpuart as Regs;
@ -75,12 +75,14 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DataBits {
DataBits8,
DataBits9,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Parity {
ParityNone,
ParityEven,
@ -88,6 +90,7 @@ pub enum Parity {
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum StopBits {
#[doc = "1 stop bit"]
STOP1,
@ -99,6 +102,14 @@ pub enum StopBits {
STOP1P5,
}
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ConfigError {
BaudrateTooLow,
BaudrateTooHigh,
}
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Config {
@ -168,11 +179,28 @@ pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> {
rx: UartRx<'d, T, RxDma>,
}
impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> {
type Config = Config;
fn set_config(&mut self, config: &Self::Config) {
unwrap!(self.tx.set_config(config));
unwrap!(self.rx.set_config(config));
}
}
pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> {
phantom: PhantomData<&'d mut T>,
tx_dma: PeripheralRef<'d, TxDma>,
}
impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> {
type Config = Config;
fn set_config(&mut self, config: &Self::Config) {
unwrap!(self.set_config(config));
}
}
pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
_peri: PeripheralRef<'d, T>,
rx_dma: PeripheralRef<'d, RxDma>,
@ -181,6 +209,14 @@ pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
buffered_sr: stm32_metapac::usart::regs::Sr,
}
impl<'d, T: BasicInstance, RxDma> SetConfig for UartRx<'d, T, RxDma> {
type Config = Config;
fn set_config(&mut self, config: &Self::Config) {
unwrap!(self.set_config(config));
}
}
impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
/// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
pub fn new(
@ -188,7 +224,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
config: Config,
) -> Self {
) -> Result<Self, ConfigError> {
T::enable();
T::reset();
@ -201,7 +237,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
config: Config,
) -> Self {
) -> Result<Self, ConfigError> {
into_ref!(cts);
T::enable();
@ -219,22 +255,26 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
config: Config,
) -> Self {
) -> Result<Self, ConfigError> {
into_ref!(_peri, tx, tx_dma);
let r = T::regs();
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
configure(r, &config, T::frequency(), T::KIND, false, true);
configure(r, &config, T::frequency(), T::KIND, false, true)?;
// create state once!
let _s = T::state();
Self {
Ok(Self {
tx_dma,
phantom: PhantomData,
}
})
}
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)
}
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
@ -277,7 +317,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
) -> Result<Self, ConfigError> {
T::enable();
T::reset();
@ -291,7 +331,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
) -> Result<Self, ConfigError> {
into_ref!(rts);
T::enable();
@ -310,14 +350,14 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
) -> Result<Self, ConfigError> {
into_ref!(peri, rx, rx_dma);
let r = T::regs();
rx.set_as_af(rx.af_num(), AFType::Input);
configure(r, &config, T::frequency(), T::KIND, true, false);
configure(r, &config, T::frequency(), T::KIND, true, false)?;
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
@ -325,13 +365,17 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
// create state once!
let _s = T::state();
Self {
Ok(Self {
_peri: peri,
rx_dma,
detect_previous_overrun: config.detect_previous_overrun,
#[cfg(any(usart_v1, usart_v2))]
buffered_sr: stm32_metapac::usart::regs::Sr(0),
}
})
}
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)
}
#[cfg(any(usart_v1, usart_v2))]
@ -545,6 +589,13 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
unsafe { rdr(r).read_volatile() };
clear_interrupt_flags(r, sr);
if enable_idle_line_detection {
// enable idle interrupt
r.cr1().modify(|w| {
w.set_idleie(true);
});
}
compiler_fence(Ordering::SeqCst);
let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore();
@ -618,6 +669,18 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
}
}
impl<'d, T: BasicInstance, TxDma> Drop for UartTx<'d, T, TxDma> {
fn drop(&mut self) {
T::disable();
}
}
impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> {
fn drop(&mut self) {
T::disable();
}
}
impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
pub fn new(
peri: impl Peripheral<P = T> + 'd,
@ -627,7 +690,9 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
tx_dma: impl Peripheral<P = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
) -> Result<Self, ConfigError> {
// UartRx and UartTx have one refcount ea.
T::enable();
T::enable();
T::reset();
@ -644,9 +709,11 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
tx_dma: impl Peripheral<P = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
) -> Result<Self, ConfigError> {
into_ref!(cts, rts);
// UartRx and UartTx have one refcount ea.
T::enable();
T::enable();
T::reset();
@ -669,9 +736,11 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
tx_dma: impl Peripheral<P = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
) -> Result<Self, ConfigError> {
into_ref!(de);
// UartRx and UartTx have one refcount ea.
T::enable();
T::enable();
T::reset();
@ -689,7 +758,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
tx_dma: impl Peripheral<P = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
) -> Result<Self, ConfigError> {
into_ref!(peri, rx, tx, tx_dma, rx_dma);
let r = T::regs();
@ -711,7 +780,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
}
}
configure(r, &config, T::frequency(), T::KIND, true, true);
configure(r, &config, T::frequency(), T::KIND, true, true)?;
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
@ -719,7 +788,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
// create state once!
let _s = T::state();
Self {
Ok(Self {
tx: UartTx {
tx_dma,
phantom: PhantomData,
@ -731,7 +800,11 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
#[cfg(any(usart_v1, usart_v2))]
buffered_sr: stm32_metapac::usart::regs::Sr(0),
},
}
})
}
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)
}
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
@ -779,7 +852,27 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
}
}
fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: bool, enable_tx: bool) {
fn reconfigure<T: BasicInstance>(config: &Config) -> Result<(), ConfigError> {
T::Interrupt::disable();
let r = T::regs();
let cr = r.cr1().read();
configure(r, config, T::frequency(), T::KIND, cr.re(), cr.te())?;
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
Ok(())
}
fn configure(
r: Regs,
config: &Config,
pclk_freq: Hertz,
kind: Kind,
enable_rx: bool,
enable_tx: bool,
) -> Result<(), ConfigError> {
if !enable_rx && !enable_tx {
panic!("USART: At least one of RX or TX should be enabled");
}
@ -847,7 +940,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
found_brr = Some(brr);
break;
}
panic!("USART: baudrate too high");
return Err(ConfigError::BaudrateTooHigh);
}
if brr < brr_max {
@ -859,7 +952,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
}
}
let brr = found_brr.expect("USART: baudrate too low");
let brr = found_brr.ok_or(ConfigError::BaudrateTooLow)?;
#[cfg(not(usart_v1))]
let oversampling = if over8 { "8 bit" } else { "16 bit" };
@ -905,12 +998,16 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
});
#[cfg(not(usart_v1))]
w.set_over8(vals::Over8::from_bits(over8 as _));
#[cfg(usart_v4)]
w.set_fifoen(true);
});
#[cfg(not(usart_v1))]
r.cr3().modify(|w| {
w.set_onebit(config.assume_noise_free);
});
Ok(())
}
mod eh02 {
@ -1012,20 +1109,61 @@ mod eh1 {
}
}
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
mod eio {
use embedded_io_async::{ErrorType, Write};
impl embedded_io::Error for Error {
fn kind(&self) -> embedded_io::ErrorKind {
embedded_io::ErrorKind::Other
}
}
use super::*;
impl<T, TxDma, RxDma> embedded_io::ErrorType for Uart<'_, T, TxDma, RxDma>
where
T: BasicInstance,
{
type Error = Error;
}
impl<T, TxDma, RxDma> ErrorType for Uart<'_, T, TxDma, RxDma>
where
T: BasicInstance,
{
type Error = Error;
impl<T, TxDma> embedded_io::ErrorType for UartTx<'_, T, TxDma>
where
T: BasicInstance,
{
type Error = Error;
}
impl<T, TxDma, RxDma> embedded_io::Write for Uart<'_, T, TxDma, RxDma>
where
T: BasicInstance,
TxDma: crate::usart::TxDma<T>,
{
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.blocking_write(buf)?;
Ok(buf.len())
}
impl<T, TxDma, RxDma> Write for Uart<'_, T, TxDma, RxDma>
fn flush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
}
}
impl<T, TxDma> embedded_io::Write for UartTx<'_, T, TxDma>
where
T: BasicInstance,
TxDma: crate::usart::TxDma<T>,
{
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.blocking_write(buf)?;
Ok(buf.len())
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
}
}
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
mod eio {
use super::*;
impl<T, TxDma, RxDma> embedded_io_async::Write for Uart<'_, T, TxDma, RxDma>
where
T: BasicInstance,
TxDma: super::TxDma<T>,
@ -1040,14 +1178,7 @@ mod eio {
}
}
impl<T, TxDma> ErrorType for UartTx<'_, T, TxDma>
where
T: BasicInstance,
{
type Error = Error;
}
impl<T, TxDma> Write for UartTx<'_, T, TxDma>
impl<T, TxDma> embedded_io_async::Write for UartTx<'_, T, TxDma>
where
T: BasicInstance,
TxDma: super::TxDma<T>,

View File

@ -1,11 +1,13 @@
use core::future::poll_fn;
use core::mem;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use embassy_embedded_hal::SetConfig;
use embassy_hal_internal::PeripheralRef;
use futures::future::{select, Either};
use super::{clear_interrupt_flags, rdr, sr, BasicInstance, Error, UartRx};
use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx};
use crate::dma::ReadableRingBuffer;
use crate::usart::{Regs, Sr};
@ -14,6 +16,14 @@ pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> {
ring_buf: ReadableRingBuffer<'d, RxDma, u8>,
}
impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> SetConfig for RingBufferedUartRx<'d, T, RxDma> {
type Config = Config;
fn set_config(&mut self, config: &Self::Config) {
unwrap!(self.set_config(config));
}
}
impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
/// Turn the `UartRx` into a buffered uart which can continously receive in the background
/// without the possibility of loosing bytes. The `dma_buf` is a buffer registered to the
@ -24,12 +34,16 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
let request = self.rx_dma.request();
let opts = Default::default();
let ring_buf = unsafe { ReadableRingBuffer::new_read(self.rx_dma, request, rdr(T::regs()), dma_buf, opts) };
// Safety: we forget the struct before this function returns.
let rx_dma = unsafe { self.rx_dma.clone_unchecked() };
let _peri = unsafe { self._peri.clone_unchecked() };
RingBufferedUartRx {
_peri: self._peri,
ring_buf,
}
let ring_buf = unsafe { ReadableRingBuffer::new_read(rx_dma, request, rdr(T::regs()), dma_buf, opts) };
// Don't disable the clock
mem::forget(self);
RingBufferedUartRx { _peri, ring_buf }
}
}
@ -49,6 +63,11 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
Err(err)
}
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
self.teardown_uart();
reconfigure::<T>(config)
}
/// Start uart background receive
fn setup_uart(&mut self) {
// fence before starting DMA.
@ -186,6 +205,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
impl<T: BasicInstance, RxDma: super::RxDma<T>> Drop for RingBufferedUartRx<'_, T, RxDma> {
fn drop(&mut self) {
self.teardown_uart();
T::disable();
}
}
/// Return an error result if the Sr register has errors

View File

@ -264,10 +264,7 @@ impl<'d, T: Instance> Driver<'d, T> {
let regs = T::regs();
#[cfg(stm32l5)]
{
crate::peripherals::PWR::enable();
crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
}
crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
#[cfg(pwr_h5)]
crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true));

View File

@ -540,10 +540,7 @@ impl<'d, T: Instance> Bus<'d, T> {
impl<'d, T: Instance> Bus<'d, T> {
fn init(&mut self) {
#[cfg(stm32l4)]
{
crate::peripherals::PWR::enable();
critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
}
critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
#[cfg(stm32f7)]
{
@ -618,15 +615,10 @@ impl<'d, T: Instance> Bus<'d, T> {
{
// Enable USB power
critical_section::with(|_| {
crate::pac::RCC.ahb3enr().modify(|w| {
w.set_pwren(true);
});
cortex_m::asm::delay(2);
crate::pac::PWR.svmcr().modify(|w| {
w.set_usv(true);
w.set_uvmen(true);
});
})
});
// Wait for USB power to stabilize