Merge branch 'rcc-mux' of github.com:xoviat/embassy; branch 'main' of github.com:embassy-rs/embassy into rcc-mux

This commit is contained in:
xoviat 2023-10-11 19:58:38 -05:00
commit 0d0fbe957e
69 changed files with 954 additions and 1813 deletions

View File

@ -15,7 +15,6 @@ embassy-time = { version = "0.1.3", path = "../embassy-time"}
embassy-sync = { version = "0.3.0", path = "../embassy-sync"} embassy-sync = { version = "0.3.0", path = "../embassy-sync"}
embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
atomic-polyfill = "0.1.5"
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
log = { version = "0.4.17", optional = true } log = { version = "0.4.17", optional = true }

View File

@ -64,4 +64,3 @@ stable_deref_trait = { version = "1.2.0", default-features = false }
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
atomic-pool = "1.0" atomic-pool = "1.0"
embedded-nal-async = { version = "0.6.0", optional = true } embedded-nal-async = { version = "0.6.0", optional = true }
atomic-polyfill = { version = "1.0" }

View File

@ -579,11 +579,10 @@ mod embedded_io_impls {
/// TCP client compatible with `embedded-nal-async` traits. /// TCP client compatible with `embedded-nal-async` traits.
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
pub mod client { pub mod client {
use core::cell::UnsafeCell; use core::cell::{Cell, UnsafeCell};
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
use core::ptr::NonNull; use core::ptr::NonNull;
use atomic_polyfill::{AtomicBool, Ordering};
use embedded_nal_async::IpAddr; use embedded_nal_async::IpAddr;
use super::*; use super::*;
@ -702,15 +701,13 @@ pub mod client {
} }
} }
unsafe impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> Sync for TcpClientState<N, TX_SZ, RX_SZ> {}
struct Pool<T, const N: usize> { struct Pool<T, const N: usize> {
used: [AtomicBool; N], used: [Cell<bool>; N],
data: [UnsafeCell<MaybeUninit<T>>; N], data: [UnsafeCell<MaybeUninit<T>>; N],
} }
impl<T, const N: usize> Pool<T, N> { impl<T, const N: usize> Pool<T, N> {
const VALUE: AtomicBool = AtomicBool::new(false); const VALUE: Cell<bool> = Cell::new(false);
const UNINIT: UnsafeCell<MaybeUninit<T>> = UnsafeCell::new(MaybeUninit::uninit()); const UNINIT: UnsafeCell<MaybeUninit<T>> = UnsafeCell::new(MaybeUninit::uninit());
const fn new() -> Self { const fn new() -> Self {
@ -724,7 +721,9 @@ pub mod client {
impl<T, const N: usize> Pool<T, N> { impl<T, const N: usize> Pool<T, N> {
fn alloc(&self) -> Option<NonNull<T>> { fn alloc(&self) -> Option<NonNull<T>> {
for n in 0..N { for n in 0..N {
if self.used[n].swap(true, Ordering::SeqCst) == false { // this can't race because Pool is not Sync.
if !self.used[n].get() {
self.used[n].set(true);
let p = self.data[n].get() as *mut T; let p = self.data[n].get() as *mut T;
return Some(unsafe { NonNull::new_unchecked(p) }); return Some(unsafe { NonNull::new_unchecked(p) });
} }
@ -738,7 +737,7 @@ pub mod client {
let n = p.as_ptr().offset_from(origin); let n = p.as_ptr().offset_from(origin);
assert!(n >= 0); assert!(n >= 0);
assert!((n as usize) < N); assert!((n as usize) < N);
self.used[n as usize].store(false, Ordering::SeqCst); self.used[n as usize].set(false);
} }
} }
} }

View File

@ -6,7 +6,6 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use pac::i2c; use pac::i2c;
use crate::gpio::sealed::Pin;
use crate::gpio::AnyPin; use crate::gpio::AnyPin;
use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::interrupt::typelevel::{Binding, Interrupt};
use crate::{interrupt, pac, peripherals, Peripheral}; use crate::{interrupt, pac, peripherals, Peripheral};
@ -295,13 +294,24 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> { pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> {
Self::setup(addr)?; Self::setup(addr)?;
self.read_async_internal(buffer, false, true).await self.read_async_internal(buffer, true, true).await
} }
pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> { pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> {
Self::setup(addr)?; Self::setup(addr)?;
self.write_async_internal(bytes, true).await self.write_async_internal(bytes, true).await
} }
pub async fn write_read_async(
&mut self,
addr: u16,
bytes: impl IntoIterator<Item = u8>,
buffer: &mut [u8],
) -> Result<(), Error> {
Self::setup(addr)?;
self.write_async_internal(bytes, false).await?;
self.read_async_internal(buffer, true, true).await
}
} }
pub struct InterruptHandler<T: Instance> { pub struct InterruptHandler<T: Instance> {
@ -318,6 +328,22 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
} }
} }
pub(crate) fn set_up_i2c_pin<'d, P, T>(pin: &P)
where
P: core::ops::Deref<Target = T>,
T: crate::gpio::Pin,
{
pin.gpio().ctrl().write(|w| w.set_funcsel(3));
pin.pad_ctrl().write(|w| {
w.set_schmitt(true);
w.set_slewfast(false);
w.set_ie(true);
w.set_od(false);
w.set_pue(true);
w.set_pde(false);
});
}
impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
fn new_inner( fn new_inner(
_peri: impl Peripheral<P = T> + 'd, _peri: impl Peripheral<P = T> + 'd,
@ -355,23 +381,8 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
p.ic_rx_tl().write(|w| w.set_rx_tl(0)); p.ic_rx_tl().write(|w| w.set_rx_tl(0));
// Configure SCL & SDA pins // Configure SCL & SDA pins
scl.gpio().ctrl().write(|w| w.set_funcsel(3)); set_up_i2c_pin(&scl);
sda.gpio().ctrl().write(|w| w.set_funcsel(3)); set_up_i2c_pin(&sda);
scl.pad_ctrl().write(|w| {
w.set_schmitt(true);
w.set_ie(true);
w.set_od(false);
w.set_pue(true);
w.set_pde(false);
});
sda.pad_ctrl().write(|w| {
w.set_schmitt(true);
w.set_ie(true);
w.set_od(false);
w.set_pue(true);
w.set_pde(false);
});
// Configure baudrate // Configure baudrate
@ -713,7 +724,7 @@ mod nightly {
Self::setup(addr)?; Self::setup(addr)?;
self.write_async_internal(write.iter().cloned(), false).await?; self.write_async_internal(write.iter().cloned(), false).await?;
self.read_async_internal(read, false, true).await self.read_async_internal(read, true, true).await
} }
async fn transaction(&mut self, address: A, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { async fn transaction(&mut self, address: A, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> {

View File

@ -5,7 +5,9 @@ use core::task::Poll;
use embassy_hal_internal::into_ref; use embassy_hal_internal::into_ref;
use pac::i2c; use pac::i2c;
use crate::i2c::{i2c_reserved_addr, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE}; use crate::i2c::{
i2c_reserved_addr, set_up_i2c_pin, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE,
};
use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::interrupt::typelevel::{Binding, Interrupt};
use crate::{pac, Peripheral}; use crate::{pac, Peripheral};
@ -100,23 +102,8 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
p.ic_rx_tl().write(|w| w.set_rx_tl(0)); p.ic_rx_tl().write(|w| w.set_rx_tl(0));
// Configure SCL & SDA pins // Configure SCL & SDA pins
scl.gpio().ctrl().write(|w| w.set_funcsel(3)); set_up_i2c_pin(&scl);
sda.gpio().ctrl().write(|w| w.set_funcsel(3)); set_up_i2c_pin(&sda);
scl.pad_ctrl().write(|w| {
w.set_schmitt(true);
w.set_ie(true);
w.set_od(false);
w.set_pue(true);
w.set_pde(false);
});
sda.pad_ctrl().write(|w| {
w.set_schmitt(true);
w.set_ie(true);
w.set_od(false);
w.set_pue(true);
w.set_pde(false);
});
// Clear interrupts // Clear interrupts
p.ic_clr_intr().read(); p.ic_clr_intr().read();

View File

@ -58,8 +58,7 @@ rand_core = "0.6.3"
sdio-host = "0.5.0" sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1" critical-section = "1.1"
atomic-polyfill = "1.0.1" stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6bfa5a0dcec6a9bd42cea94ba11eeae1a17a7f2c" }
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e89b8cfc30e480036aaf502f34c874ee42d68026" }
vcell = "0.1.3" vcell = "0.1.3"
bxcan = "0.7.0" bxcan = "0.7.0"
nb = "1.0.0" nb = "1.0.0"
@ -77,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies] [build-dependencies]
proc-macro2 = "1.0.36" proc-macro2 = "1.0.36"
quote = "1.0.15" quote = "1.0.15"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e89b8cfc30e480036aaf502f34c874ee42d68026", default-features = false, features = ["metadata"]} stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6bfa5a0dcec6a9bd42cea94ba11eeae1a17a7f2c", default-features = false, features = ["metadata"]}
[features] [features]

View File

@ -9,6 +9,32 @@ use stm32_metapac::metadata::ir::{BlockItemInner, Enum};
use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccRegister, METADATA}; use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccRegister, METADATA};
fn main() { fn main() {
let target = env::var("TARGET").unwrap();
if target.starts_with("thumbv6m-") {
println!("cargo:rustc-cfg=cortex_m");
println!("cargo:rustc-cfg=armv6m");
} else if target.starts_with("thumbv7m-") {
println!("cargo:rustc-cfg=cortex_m");
println!("cargo:rustc-cfg=armv7m");
} else if target.starts_with("thumbv7em-") {
println!("cargo:rustc-cfg=cortex_m");
println!("cargo:rustc-cfg=armv7m");
println!("cargo:rustc-cfg=armv7em"); // (not currently used)
} else if target.starts_with("thumbv8m.base") {
println!("cargo:rustc-cfg=cortex_m");
println!("cargo:rustc-cfg=armv8m");
println!("cargo:rustc-cfg=armv8m_base");
} else if target.starts_with("thumbv8m.main") {
println!("cargo:rustc-cfg=cortex_m");
println!("cargo:rustc-cfg=armv8m");
println!("cargo:rustc-cfg=armv8m_main");
}
if target.ends_with("-eabihf") {
println!("cargo:rustc-cfg=has_fpu");
}
let chip_name = match env::vars() let chip_name = match env::vars()
.map(|(a, _)| a) .map(|(a, _)| a)
.filter(|x| x.starts_with("CARGO_FEATURE_STM32")) .filter(|x| x.starts_with("CARGO_FEATURE_STM32"))
@ -531,20 +557,20 @@ fn main() {
#clock_frequency #clock_frequency
} }
fn enable() { fn enable() {
critical_section::with(|_| { critical_section::with(|_cs| {
#before_enable #before_enable
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]
crate::rcc::clock_refcount_add(); crate::rcc::clock_refcount_add(_cs);
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
#after_enable #after_enable
}) })
} }
fn disable() { fn disable() {
critical_section::with(|_| { critical_section::with(|_cs| {
#before_disable #before_disable
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]
crate::rcc::clock_refcount_sub(); crate::rcc::clock_refcount_sub(_cs);
}) })
} }
fn reset() { fn reset() {
@ -1007,7 +1033,7 @@ fn main() {
match e { match e {
"Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" => true, "Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" => true,
"Timpre" | "Pllrclkpre" => false, "Timpre" | "Pllrclkpre" => false,
e if e.ends_with("pre") || e.ends_with("div") || e.ends_with("mul") => true, e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true,
_ => false, _ => false,
} }
} }

View File

@ -2,10 +2,9 @@
use core::future::Future; use core::future::Future;
use core::pin::Pin; use core::pin::Pin;
use core::sync::atomic::{fence, Ordering}; use core::sync::atomic::{fence, AtomicUsize, Ordering};
use core::task::{Context, Poll, Waker}; use core::task::{Context, Poll, Waker};
use atomic_polyfill::AtomicUsize;
use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
@ -127,7 +126,13 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index
} else if isr.tcif(channel_num) && cr.read().tcie() { } else if isr.tcif(channel_num) && cr.read().tcie() {
// Acknowledge transfer complete interrupt // Acknowledge transfer complete interrupt
dma.ifcr().write(|w| w.set_tcif(channel_num, true)); dma.ifcr().write(|w| w.set_tcif(channel_num, true));
#[cfg(not(armv6m))]
STATE.complete_count[index].fetch_add(1, Ordering::Release); STATE.complete_count[index].fetch_add(1, Ordering::Release);
#[cfg(armv6m)]
critical_section::with(|_| {
let x = STATE.complete_count[index].load(Ordering::Relaxed);
STATE.complete_count[index].store(x + 1, Ordering::Release);
})
} else { } else {
return; return;
} }
@ -391,7 +396,14 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
} }
fn reset_complete_count(&mut self) -> usize { fn reset_complete_count(&mut self) -> usize {
STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel) #[cfg(not(armv6m))]
return STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel);
#[cfg(armv6m)]
return critical_section::with(|_| {
let x = STATE.complete_count[self.0.index()].load(Ordering::Acquire);
STATE.complete_count[self.0.index()].store(0, Ordering::Release);
x
});
} }
fn set_waker(&mut self, waker: &Waker) { fn set_waker(&mut self, waker: &Waker) {

View File

@ -41,39 +41,40 @@ mod phy_consts {
} }
use self::phy_consts::*; use self::phy_consts::*;
/// Generic SMI Ethernet PHY /// Generic SMI Ethernet PHY implementation
pub struct GenericSMI { pub struct GenericSMI {
phy_addr: u8,
#[cfg(feature = "time")] #[cfg(feature = "time")]
poll_interval: Duration, poll_interval: Duration,
#[cfg(not(feature = "time"))]
_private: (),
} }
impl GenericSMI { impl GenericSMI {
pub fn new() -> Self { /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication
pub fn new(phy_addr: u8) -> Self {
Self { Self {
phy_addr,
#[cfg(feature = "time")] #[cfg(feature = "time")]
poll_interval: Duration::from_millis(500), poll_interval: Duration::from_millis(500),
#[cfg(not(feature = "time"))]
_private: (),
} }
} }
} }
unsafe impl PHY for GenericSMI { unsafe impl PHY for GenericSMI {
/// Reset PHY and wait for it to come out of reset.
fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) { fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) {
sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET); sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET);
while sm.smi_read(PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
} }
/// PHY initialisation.
fn phy_init<S: StationManagement>(&mut self, sm: &mut S) { fn phy_init<S: StationManagement>(&mut self, sm: &mut S) {
// Clear WU CSR // Clear WU CSR
self.smi_write_ext(sm, PHY_REG_WUCSR, 0); self.smi_write_ext(sm, PHY_REG_WUCSR, 0);
// Enable auto-negotiation // Enable auto-negotiation
sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M); sm.smi_write(
self.phy_addr,
PHY_REG_BCR,
PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M,
);
} }
fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool { fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool {
@ -83,7 +84,7 @@ unsafe impl PHY for GenericSMI {
#[cfg(feature = "time")] #[cfg(feature = "time")]
let _ = Timer::after(self.poll_interval).poll_unpin(cx); let _ = Timer::after(self.poll_interval).poll_unpin(cx);
let bsr = sm.smi_read(PHY_REG_BSR); let bsr = sm.smi_read(self.phy_addr, PHY_REG_BSR);
// No link without autonegotiate // No link without autonegotiate
if bsr & PHY_REG_BSR_ANDONE == 0 { if bsr & PHY_REG_BSR_ANDONE == 0 {
@ -108,9 +109,9 @@ impl GenericSMI {
// Writes a value to an extended PHY register in MMD address space // Writes a value to an extended PHY register in MMD address space
fn smi_write_ext<S: StationManagement>(&mut self, sm: &mut S, reg_addr: u16, reg_data: u16) { fn smi_write_ext<S: StationManagement>(&mut self, sm: &mut S, reg_addr: u16, reg_data: u16) {
sm.smi_write(PHY_REG_CTL, 0x0003); // set address sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x0003); // set address
sm.smi_write(PHY_REG_ADDAR, reg_addr); sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_addr);
sm.smi_write(PHY_REG_CTL, 0x4003); // set data sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x4003); // set data
sm.smi_write(PHY_REG_ADDAR, reg_data); sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_data);
} }
} }

View File

@ -134,9 +134,9 @@ impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> {
/// The methods cannot move out of self /// The methods cannot move out of self
pub unsafe trait StationManagement { pub unsafe trait StationManagement {
/// Read a register over SMI. /// Read a register over SMI.
fn smi_read(&mut self, reg: u8) -> u16; fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16;
/// Write a register over SMI. /// Write a register over SMI.
fn smi_write(&mut self, reg: u8, val: u16); fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16);
} }
/// Traits for an Ethernet PHY /// Traits for an Ethernet PHY

View File

@ -107,7 +107,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd, tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd,
phy: P, phy: P,
mac_addr: [u8; 6], mac_addr: [u8; 6],
phy_addr: u8,
) -> Self { ) -> Self {
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
@ -227,7 +226,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
station_management: EthernetStationManagement { station_management: EthernetStationManagement {
peri: PhantomData, peri: PhantomData,
clock_range: clock_range, clock_range: clock_range,
phy_addr: phy_addr,
}, },
mac_addr, mac_addr,
tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
@ -271,15 +269,14 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
pub struct EthernetStationManagement<T: Instance> { pub struct EthernetStationManagement<T: Instance> {
peri: PhantomData<T>, peri: PhantomData<T>,
clock_range: Cr, clock_range: Cr,
phy_addr: u8,
} }
unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
fn smi_read(&mut self, reg: u8) -> u16 { fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
let mac = ETH.ethernet_mac(); let mac = ETH.ethernet_mac();
mac.macmiiar().modify(|w| { mac.macmiiar().modify(|w| {
w.set_pa(self.phy_addr); w.set_pa(phy_addr);
w.set_mr(reg); w.set_mr(reg);
w.set_mw(Mw::READ); // read operation w.set_mw(Mw::READ); // read operation
w.set_cr(self.clock_range); w.set_cr(self.clock_range);
@ -289,12 +286,12 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
mac.macmiidr().read().md() mac.macmiidr().read().md()
} }
fn smi_write(&mut self, reg: u8, val: u16) { fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
let mac = ETH.ethernet_mac(); let mac = ETH.ethernet_mac();
mac.macmiidr().write(|w| w.set_md(val)); mac.macmiidr().write(|w| w.set_md(val));
mac.macmiiar().modify(|w| { mac.macmiiar().modify(|w| {
w.set_pa(self.phy_addr); w.set_pa(phy_addr);
w.set_mr(reg); w.set_mr(reg);
w.set_mw(Mw::WRITE); // write w.set_mw(Mw::WRITE); // write
w.set_cr(self.clock_range); w.set_cr(self.clock_range);

View File

@ -71,7 +71,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd, tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd,
phy: P, phy: P,
mac_addr: [u8; 6], mac_addr: [u8; 6],
phy_addr: u8,
) -> Self { ) -> Self {
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
@ -202,7 +201,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
station_management: EthernetStationManagement { station_management: EthernetStationManagement {
peri: PhantomData, peri: PhantomData,
clock_range: clock_range, clock_range: clock_range,
phy_addr: phy_addr,
}, },
mac_addr, mac_addr,
}; };
@ -242,15 +240,14 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
pub struct EthernetStationManagement<T: Instance> { pub struct EthernetStationManagement<T: Instance> {
peri: PhantomData<T>, peri: PhantomData<T>,
clock_range: u8, clock_range: u8,
phy_addr: u8,
} }
unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
fn smi_read(&mut self, reg: u8) -> u16 { fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
let mac = ETH.ethernet_mac(); let mac = ETH.ethernet_mac();
mac.macmdioar().modify(|w| { mac.macmdioar().modify(|w| {
w.set_pa(self.phy_addr); w.set_pa(phy_addr);
w.set_rda(reg); w.set_rda(reg);
w.set_goc(0b11); // read w.set_goc(0b11); // read
w.set_cr(self.clock_range); w.set_cr(self.clock_range);
@ -260,12 +257,12 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
mac.macmdiodr().read().md() mac.macmdiodr().read().md()
} }
fn smi_write(&mut self, reg: u8, val: u16) { fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
let mac = ETH.ethernet_mac(); let mac = ETH.ethernet_mac();
mac.macmdiodr().write(|w| w.set_md(val)); mac.macmdiodr().write(|w| w.set_md(val));
mac.macmdioar().modify(|w| { mac.macmdioar().modify(|w| {
w.set_pa(self.phy_addr); w.set_pa(phy_addr);
w.set_rda(reg); w.set_rda(reg);
w.set_goc(0b01); // write w.set_goc(0b01); // write
w.set_cr(self.clock_range); w.set_cr(self.clock_range);

View File

@ -19,9 +19,11 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
if pac::FLASH.cr().read().lock() {
pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123)); pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
} }
}
pub(crate) unsafe fn enable_blocking_write() { pub(crate) unsafe fn enable_blocking_write() {
assert_eq!(0, WRITE_SIZE % 2); assert_eq!(0, WRITE_SIZE % 2);

View File

@ -19,9 +19,11 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
if pac::FLASH.cr().read().lock() {
pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123)); pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
} }
}
pub(crate) unsafe fn enable_blocking_write() { pub(crate) unsafe fn enable_blocking_write() {
assert_eq!(0, WRITE_SIZE % 2); assert_eq!(0, WRITE_SIZE % 2);

View File

@ -228,9 +228,11 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
if pac::FLASH.cr().read().lock() {
pac::FLASH.keyr().write(|w| w.set_key(0x45670123)); pac::FLASH.keyr().write(|w| w.set_key(0x45670123));
pac::FLASH.keyr().write(|w| w.set_key(0xCDEF89AB)); pac::FLASH.keyr().write(|w| w.set_key(0xCDEF89AB));
} }
}
pub(crate) unsafe fn enable_write() { pub(crate) unsafe fn enable_write() {
assert_eq!(0, WRITE_SIZE % 4); assert_eq!(0, WRITE_SIZE % 4);

View File

@ -19,9 +19,11 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
if pac::FLASH.cr().read().lock() {
pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123)); pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
} }
}
pub(crate) unsafe fn enable_blocking_write() { pub(crate) unsafe fn enable_blocking_write() {
assert_eq!(0, WRITE_SIZE % 4); assert_eq!(0, WRITE_SIZE % 4);

View File

@ -24,9 +24,11 @@ pub(crate) unsafe fn unlock() {
while pac::FLASH.sr().read().bsy() {} while pac::FLASH.sr().read().bsy() {}
// Unlock flash // Unlock flash
if pac::FLASH.cr().read().lock() {
pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123)); pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB)); pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB));
} }
}
pub(crate) unsafe fn enable_blocking_write() { pub(crate) unsafe fn enable_blocking_write() {
assert_eq!(0, WRITE_SIZE % 4); assert_eq!(0, WRITE_SIZE % 4);

View File

@ -26,13 +26,17 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
if pac::FLASH.bank(0).cr().read().lock() {
pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123)); pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123));
pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
}
if is_dual_bank() { if is_dual_bank() {
if pac::FLASH.bank(1).cr().read().lock() {
pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123)); pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123));
pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
} }
} }
}
pub(crate) unsafe fn enable_blocking_write() { pub(crate) unsafe fn enable_blocking_write() {
assert_eq!(0, WRITE_SIZE % 4); assert_eq!(0, WRITE_SIZE % 4);

View File

@ -28,19 +28,25 @@ pub(crate) unsafe fn lock() {
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
#[cfg(any(flash_wl, flash_wb, flash_l4))] #[cfg(any(flash_wl, flash_wb, flash_l4))]
{ {
if pac::FLASH.cr().read().lock() {
pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123)); pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB)); pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB));
} }
}
#[cfg(any(flash_l0, flash_l1))] #[cfg(any(flash_l0, flash_l1))]
{ {
if pac::FLASH.pecr().read().pelock() {
pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x89ABCDEF)); pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x89ABCDEF));
pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x02030405)); pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x02030405));
}
if pac::FLASH.pecr().read().prglock() {
pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x8C9DAEBF)); pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x8C9DAEBF));
pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x13141516)); pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x13141516));
} }
} }
}
pub(crate) unsafe fn enable_blocking_write() { pub(crate) unsafe fn enable_blocking_write() {
assert_eq!(0, WRITE_SIZE % 4); assert_eq!(0, WRITE_SIZE % 4);

View File

@ -225,7 +225,9 @@ pub fn init(config: Config) -> Peripherals {
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]
while !crate::rcc::low_power_ready() { while !crate::rcc::low_power_ready() {
crate::rcc::clock_refcount_sub(); critical_section::with(|cs| {
crate::rcc::clock_refcount_sub(cs);
});
} }
} }

View File

@ -1,7 +1,7 @@
use core::arch::asm; use core::arch::asm;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use atomic_polyfill::{compiler_fence, Ordering};
use cortex_m::peripheral::SCB; use cortex_m::peripheral::SCB;
use embassy_executor::*; use embassy_executor::*;

View File

@ -1,14 +1,24 @@
use core::sync::atomic::{compiler_fence, Ordering};
use crate::pac::common::{Reg, RW};
pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource;
use crate::time::Hertz;
#[cfg(any(stm32f0, stm32f1, stm32f3))]
pub const LSI_FREQ: Hertz = Hertz(40_000);
#[cfg(not(any(stm32f0, stm32f1, stm32f3)))]
pub const LSI_FREQ: Hertz = Hertz(32_000);
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum LseCfg { pub enum LseMode {
Oscillator(LseDrive), Oscillator(LseDrive),
Bypass, Bypass,
} }
impl Default for LseCfg { pub struct LseConfig {
fn default() -> Self { pub frequency: Hertz,
Self::Oscillator(Default::default()) pub mode: LseMode,
}
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -36,90 +46,116 @@ impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
} }
} }
pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource;
#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] #[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))]
#[allow(dead_code)]
type Bdcr = crate::pac::rcc::regs::Bdcr; type Bdcr = crate::pac::rcc::regs::Bdcr;
#[cfg(any(rtc_v2l0, rtc_v2l1))] #[cfg(any(rtc_v2l0, rtc_v2l1))]
#[allow(dead_code)]
type Bdcr = crate::pac::rcc::regs::Csr; type Bdcr = crate::pac::rcc::regs::Csr;
#[cfg(any(stm32c0))]
type Bdcr = crate::pac::rcc::regs::Csr1;
#[allow(dead_code)] #[cfg(any(stm32c0))]
pub struct BackupDomain {} fn unlock() {}
impl BackupDomain { #[cfg(not(any(stm32c0)))]
#[cfg(any( fn unlock() {
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, #[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))]
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(); let cr = crate::pac::PWR.cr();
#[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] #[cfg(not(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba)))]
let cr = crate::pac::PWR.cr1(); let cr = crate::pac::PWR.cr1();
#[cfg(any(stm32u5, stm32h5, stm32wba))]
let cr = crate::pac::PWR.dbpcr();
// TODO: Missing from PAC for l0 and f0?
#[cfg(not(any(rtc_v2f0, rtc_v3u5)))]
{
cr.modify(|w| w.set_dbp(true)); cr.modify(|w| w.set_dbp(true));
while !cr.read().dbp() {} while !cr.read().dbp() {}
} }
fn bdcr() -> Reg<Bdcr, RW> {
#[cfg(any(rtc_v2l0, rtc_v2l1))] #[cfg(any(rtc_v2l0, rtc_v2l1))]
let cr = crate::pac::RCC.csr(); return crate::pac::RCC.csr();
#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))]
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))] return crate::pac::RCC.bdcr();
let cr = crate::pac::RCC.bdcr(); #[cfg(any(stm32c0))]
return crate::pac::RCC.csr1();
cr.modify(|w| f(w))
} }
#[cfg(any( pub struct LsConfig {
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, pub rtc: RtcClockSource,
rtc_v3u5 pub lsi: bool,
))] pub lse: Option<LseConfig>,
#[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( impl LsConfig {
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, pub const fn default_lse() -> Self {
rtc_v3u5 Self {
))] rtc: RtcClockSource::LSE,
#[allow(dead_code, unused_variables)] lse: Some(LseConfig {
pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option<LseCfg>) { frequency: Hertz(32_768),
use atomic_polyfill::{compiler_fence, Ordering}; mode: LseMode::Oscillator(LseDrive::MediumHigh),
}),
lsi: false,
}
}
match clock_source { pub const fn default_lsi() -> Self {
RtcClockSource::LSI => assert!(lsi), Self {
RtcClockSource::LSE => assert!(lse.is_some()), rtc: RtcClockSource::LSI,
_ => {} lsi: true,
lse: None,
}
}
pub const fn off() -> Self {
Self {
rtc: RtcClockSource::NOCLOCK,
lsi: false,
lse: None,
}
}
}
impl Default for LsConfig {
fn default() -> Self {
// on L5, just the fact that LSI is enabled makes things crash.
// TODO: investigate.
#[cfg(not(stm32l5))]
return Self::default_lsi();
#[cfg(stm32l5)]
return Self::off();
}
}
impl LsConfig {
pub(crate) fn init(&self) -> Option<Hertz> {
let rtc_clk = match self.rtc {
RtcClockSource::LSI => {
assert!(self.lsi);
Some(LSI_FREQ)
}
RtcClockSource::LSE => Some(self.lse.as_ref().unwrap().frequency),
RtcClockSource::NOCLOCK => None,
_ => todo!(),
}; };
let (lse_en, lse_byp, lse_drv) = match lse {
Some(LseCfg::Oscillator(lse_drv)) => (true, false, Some(lse_drv)), let (lse_en, lse_byp, lse_drv) = match &self.lse {
Some(LseCfg::Bypass) => (true, true, None), Some(c) => match c.mode {
LseMode::Oscillator(lse_drv) => (true, false, Some(lse_drv)),
LseMode::Bypass => (true, true, None),
},
None => (false, false, None), None => (false, false, None),
}; };
_ = lse_drv; // not all chips have it.
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 // Disable backup domain write protection
Self::modify(|_| {}); unlock();
if self.lsi {
#[cfg(any(stm32u5, stm32h5, stm32wba))]
let csr = crate::pac::RCC.bdcr();
#[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0)))]
let csr = crate::pac::RCC.csr();
#[cfg(any(stm32c0))]
let csr = crate::pac::RCC.csr2();
#[cfg(not(any(rcc_wb, rcc_wba)))] #[cfg(not(any(rcc_wb, rcc_wba)))]
csr.modify(|w| w.set_lsion(true)); csr.modify(|w| w.set_lsion(true));
@ -139,12 +175,12 @@ impl BackupDomain {
// first check if the configuration matches what we want. // first check if the configuration matches what we want.
// check if it's already enabled and in the source we want. // check if it's already enabled and in the source we want.
let reg = Self::read(); let reg = bdcr().read();
let mut ok = true; let mut ok = true;
ok &= reg.rtcsel() == clock_source; ok &= reg.rtcsel() == self.rtc;
#[cfg(not(rcc_wba))] #[cfg(not(rcc_wba))]
{ {
ok &= reg.rtcen() == (clock_source != RtcClockSource::NOCLOCK); ok &= reg.rtcen() == (self.rtc != RtcClockSource::NOCLOCK);
} }
ok &= reg.lseon() == lse_en; ok &= reg.lseon() == lse_en;
ok &= reg.lsebyp() == lse_byp; ok &= reg.lsebyp() == lse_byp;
@ -155,22 +191,29 @@ impl BackupDomain {
// if configuration is OK, we're done. // if configuration is OK, we're done.
if ok { if ok {
// RTC code assumes backup domain is unlocked trace!("BDCR ok: {:08x}", bdcr().read().0);
Self::modify(|w| {}); return rtc_clk;
trace!("BDCR ok: {:08x}", Self::read().0);
return;
} }
// If not OK, reset backup domain and configure it. // If not OK, reset backup domain and configure it.
#[cfg(not(any(rcc_l0, rcc_l1)))] #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32c0)))]
{ {
Self::modify(|w| w.set_bdrst(true)); bdcr().modify(|w| w.set_bdrst(true));
Self::modify(|w| w.set_bdrst(false)); bdcr().modify(|w| w.set_bdrst(false));
}
#[cfg(any(stm32h5))]
{
bdcr().modify(|w| w.set_vswrst(true));
bdcr().modify(|w| w.set_vswrst(false));
}
#[cfg(any(stm32c0))]
{
bdcr().modify(|w| w.set_rtcrst(true));
bdcr().modify(|w| w.set_rtcrst(false));
} }
if lse_en { if lse_en {
Self::modify(|w| { bdcr().modify(|w| {
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))] #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
if let Some(lse_drv) = lse_drv { if let Some(lse_drv) = lse_drv {
w.set_lsedrv(lse_drv.into()); w.set_lsedrv(lse_drv.into());
@ -179,22 +222,24 @@ impl BackupDomain {
w.set_lseon(true); w.set_lseon(true);
}); });
while !Self::read().lserdy() {} while !bdcr().read().lserdy() {}
} }
if clock_source != RtcClockSource::NOCLOCK { if self.rtc != RtcClockSource::NOCLOCK {
Self::modify(|w| { bdcr().modify(|w| {
#[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
#[cfg(not(rcc_wba))] #[cfg(not(rcc_wba))]
w.set_rtcen(true); w.set_rtcen(true);
w.set_rtcsel(clock_source); w.set_rtcsel(self.rtc);
}); });
} }
trace!("BDCR configured: {:08x}", Self::read().0); trace!("BDCR configured: {:08x}", bdcr().read().0);
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
rtc_clk
} }
} }

View File

@ -1,6 +1,6 @@
use crate::pac::flash::vals::Latency; use crate::pac::flash::vals::Latency;
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; use crate::pac::rcc::vals::Sw;
use crate::pac::rcc::vals::{Hsidiv, Ppre, Sw}; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Ppre as APBPrescaler};
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -8,9 +8,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(48_000_000); pub const HSI_FREQ: Hertz = Hertz(48_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
@ -19,47 +16,22 @@ pub enum ClockSrc {
LSI, LSI,
} }
#[derive(Clone, Copy)]
pub enum HSIPrescaler {
NotDivided,
Div2,
Div4,
Div8,
Div16,
Div32,
Div64,
Div128,
}
impl Into<Hsidiv> for HSIPrescaler {
fn into(self) -> Hsidiv {
match self {
HSIPrescaler::NotDivided => Hsidiv::DIV1,
HSIPrescaler::Div2 => Hsidiv::DIV2,
HSIPrescaler::Div4 => Hsidiv::DIV4,
HSIPrescaler::Div8 => Hsidiv::DIV8,
HSIPrescaler::Div16 => Hsidiv::DIV16,
HSIPrescaler::Div32 => Hsidiv::DIV32,
HSIPrescaler::Div64 => Hsidiv::DIV64,
HSIPrescaler::Div128 => Hsidiv::DIV128,
}
}
}
/// Clocks configutation /// Clocks configutation
pub struct Config { pub struct Config {
pub mux: ClockSrc, pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler, pub ahb_pre: AHBPrescaler,
pub apb_pre: APBPrescaler, pub apb_pre: APBPrescaler,
pub ls: super::LsConfig,
} }
impl Default for Config { impl Default for Config {
#[inline] #[inline]
fn default() -> Config { fn default() -> Config {
Config { Config {
mux: ClockSrc::HSI(HSIPrescaler::NotDivided), mux: ClockSrc::HSI(HSIPrescaler::DIV1),
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
apb_pre: APBPrescaler::DIV1, apb_pre: APBPrescaler::DIV1,
ls: Default::default(),
} }
} }
} }
@ -68,33 +40,34 @@ pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
ClockSrc::HSI(div) => { ClockSrc::HSI(div) => {
// Enable HSI // Enable HSI
let div: Hsidiv = div.into();
RCC.cr().write(|w| { RCC.cr().write(|w| {
w.set_hsidiv(div); w.set_hsidiv(div);
w.set_hsion(true) w.set_hsion(true)
}); });
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI_FREQ.0 >> div.to_bits(), Sw::HSI) (HSI_FREQ / div, Sw::HSI)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE
RCC.cr().write(|w| w.set_hseon(true)); RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {} while !RCC.cr().read().hserdy() {}
(freq.0, Sw::HSE) (freq, Sw::HSE)
} }
ClockSrc::LSI => { ClockSrc::LSI => {
// Enable LSI // Enable LSI
RCC.csr2().write(|w| w.set_lsion(true)); RCC.csr2().write(|w| w.set_lsion(true));
while !RCC.csr2().read().lsirdy() {} while !RCC.csr2().read().lsirdy() {}
(LSI_FREQ.0, Sw::LSI) (super::LSI_FREQ, Sw::LSI)
} }
}; };
let rtc = config.ls.init();
// Determine the flash latency implied by the target clock speed // Determine the flash latency implied by the target clock speed
// RM0454 § 3.3.4: // RM0454 § 3.3.4:
let target_flash_latency = if sys_clk <= 24_000_000 { let target_flash_latency = if sys_clk <= Hertz(24_000_000) {
Latency::WS0 Latency::WS0
} else { } else {
Latency::WS1 Latency::WS1
@ -129,7 +102,7 @@ pub(crate) unsafe fn init(config: Config) {
} }
// Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
let (sw, hpre, ppre) = (sw.into(), config.ahb_pre.into(), config.apb_pre.into()); let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre);
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(hpre); w.set_hpre(hpre);
@ -150,34 +123,21 @@ pub(crate) unsafe fn init(config: Config) {
FLASH.acr().modify(|w| w.set_latency(target_flash_latency)); FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
} }
let ahb_div = match config.ahb_pre { let ahb_freq = sys_clk / config.ahb_pre;
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 { let (apb_freq, apb_tim_freq) = match config.apb_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let pre: Ppre = pre.into(); let freq = ahb_freq / pre;
let pre: u8 = 1 << (pre.to_bits() - 3); (freq, freq * 2u32)
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sys_clk), sys: sys_clk,
ahb1: Hertz(ahb_freq), ahb1: ahb_freq,
apb1: Hertz(apb_freq), apb1: apb_freq,
apb1_tim: Hertz(apb_tim_freq), apb1_tim: apb_tim_freq,
rtc,
}); });
} }

View File

@ -8,9 +8,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(8_000_000); pub const HSI_FREQ: Hertz = Hertz(8_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(40_000);
/// Configuration of the clocks /// Configuration of the clocks
/// ///
/// hse takes precedence over hsi48 if both are enabled /// hse takes precedence over hsi48 if both are enabled
@ -27,6 +24,8 @@ pub struct Config {
pub sys_ck: Option<Hertz>, pub sys_ck: Option<Hertz>,
pub hclk: Option<Hertz>, pub hclk: Option<Hertz>,
pub pclk: Option<Hertz>, pub pclk: Option<Hertz>,
pub ls: super::LsConfig,
} }
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
@ -159,6 +158,8 @@ pub(crate) unsafe fn init(config: Config) {
}) })
} }
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(real_sysclk), sys: Hertz(real_sysclk),
apb1: Hertz(pclk), apb1: Hertz(pclk),
@ -166,5 +167,6 @@ pub(crate) unsafe fn init(config: Config) {
apb1_tim: Hertz(pclk * timer_mul), apb1_tim: Hertz(pclk * timer_mul),
apb2_tim: Hertz(pclk * timer_mul), apb2_tim: Hertz(pclk * timer_mul),
ahb1: Hertz(hclk), ahb1: Hertz(hclk),
rtc,
}); });
} }

View File

@ -9,9 +9,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(8_000_000); pub const HSI_FREQ: Hertz = Hertz(8_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(40_000);
/// Configuration of the clocks /// Configuration of the clocks
/// ///
#[non_exhaustive] #[non_exhaustive]
@ -25,6 +22,8 @@ pub struct Config {
pub pclk2: Option<Hertz>, pub pclk2: Option<Hertz>,
pub adcclk: Option<Hertz>, pub adcclk: Option<Hertz>,
pub pllxtpre: bool, pub pllxtpre: bool,
pub ls: super::LsConfig,
} }
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
@ -177,6 +176,8 @@ pub(crate) unsafe fn init(config: Config) {
}); });
}); });
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(real_sysclk), sys: Hertz(real_sysclk),
apb1: Hertz(pclk1), apb1: Hertz(pclk1),
@ -185,5 +186,6 @@ pub(crate) unsafe fn init(config: Config) {
apb2_tim: Hertz(pclk2 * timer_mul2), apb2_tim: Hertz(pclk2 * timer_mul2),
ahb1: Hertz(hclk), ahb1: Hertz(hclk),
adc: Some(Hertz(adcclk)), adc: Some(Hertz(adcclk)),
rtc,
}); });
} }

View File

@ -5,17 +5,12 @@ pub use crate::pac::rcc::vals::{
Ppre as APBPrescaler, Ppre as APBPrescaler,
}; };
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::rcc::bd::BackupDomain;
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::rtc::RtcClockSource;
use crate::time::Hertz; use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct HSEConfig { pub struct HSEConfig {
pub frequency: Hertz, pub frequency: Hertz,
@ -180,13 +175,11 @@ pub struct Config {
pub pll_mux: PLLSrc, pub pll_mux: PLLSrc,
pub pll: PLLConfig, pub pll: PLLConfig,
pub mux: ClockSrc, pub mux: ClockSrc,
pub rtc: Option<RtcClockSource>,
pub lsi: bool,
pub lse: Option<Hertz>,
pub voltage: VoltageScale, pub voltage: VoltageScale,
pub ahb_pre: AHBPrescaler, pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler, pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler, pub apb2_pre: APBPrescaler,
pub ls: super::LsConfig,
} }
impl Default for Config { impl Default for Config {
@ -199,12 +192,10 @@ impl Default for Config {
pll: PLLConfig::default(), pll: PLLConfig::default(),
voltage: VoltageScale::Range3, voltage: VoltageScale::Range3,
mux: ClockSrc::HSI, mux: ClockSrc::HSI,
rtc: None,
lsi: false,
lse: None,
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
ls: Default::default(),
} }
} }
} }
@ -301,9 +292,9 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw.into()); w.set_sw(sw.into());
w.set_hpre(config.ahb_pre.into()); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
@ -312,11 +303,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().modify(|w| w.set_hsion(false)); RCC.cr().modify(|w| w.set_hsion(false));
} }
BackupDomain::configure_ls( let rtc = config.ls.init();
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
@ -328,5 +315,6 @@ pub(crate) unsafe fn init(config: Config) {
apb2: apb2_freq, apb2: apb2_freq,
apb2_tim: apb2_tim_freq, apb2_tim: apb2_tim_freq,
pll48: Some(pll_clocks.pll48_freq), pll48: Some(pll_clocks.pll48_freq),
rtc,
}); });
} }

View File

@ -1,7 +1,8 @@
#[cfg(rcc_f3)] #[cfg(rcc_f3)]
use crate::pac::adccommon::vals::Ckmode; use crate::pac::adccommon::vals::Ckmode;
use crate::pac::flash::vals::Latency; use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{Adcpres, Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; pub use crate::pac::rcc::vals::Adcpres;
use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -9,28 +10,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(8_000_000); 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)] #[cfg(rcc_f3)]
impl From<AdcClockSource> for Ckmode { impl From<AdcClockSource> for Ckmode {
fn from(value: AdcClockSource) -> Self { fn from(value: AdcClockSource) -> Self {
@ -45,32 +24,13 @@ impl From<AdcClockSource> for Ckmode {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum AdcClockSource { pub enum AdcClockSource {
PllDiv1 = 1, Pll(Adcpres),
PllDiv2 = 2,
PllDiv4 = 4,
PllDiv6 = 6,
PllDiv8 = 8,
PllDiv12 = 12,
PllDiv16 = 16,
PllDiv32 = 32,
PllDiv64 = 64,
PllDiv128 = 128,
PllDiv256 = 256,
BusDiv1, BusDiv1,
BusDiv2, BusDiv2,
BusDiv4, BusDiv4,
} }
impl AdcClockSource { 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 { pub fn bus_div(&self) -> u32 {
match self { match self {
Self::BusDiv1 => 1, Self::BusDiv1 => 1,
@ -124,6 +84,7 @@ pub struct Config {
pub adc34: Option<AdcClockSource>, pub adc34: Option<AdcClockSource>,
#[cfg(stm32f334)] #[cfg(stm32f334)]
pub hrtim: HrtimClockSource, pub hrtim: HrtimClockSource,
pub ls: super::LsConfig,
} }
// Information required to setup the PLL clock // Information required to setup the PLL clock
@ -137,67 +98,67 @@ struct PllConfig {
/// Initialize and Set the clock frequencies /// Initialize and Set the clock frequencies
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
// Calculate the real System clock, and PLL configuration if applicable // Calculate the real System clock, and PLL configuration if applicable
let (Hertz(sysclk), pll_config) = get_sysclk(&config); let (sysclk, pll_config) = get_sysclk(&config);
assert!(sysclk <= 72_000_000); assert!(sysclk.0 <= 72_000_000);
// Calculate real AHB clock // Calculate real AHB clock
let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk); let hclk = config.hclk.map(|h| h).unwrap_or(sysclk);
let (hpre_bits, hpre_div) = match sysclk / hclk { let hpre = match sysclk.0 / hclk.0 {
0 => unreachable!(), 0 => unreachable!(),
1 => (Hpre::DIV1, 1), 1 => Hpre::DIV1,
2 => (Hpre::DIV2, 2), 2 => Hpre::DIV2,
3..=5 => (Hpre::DIV4, 4), 3..=5 => Hpre::DIV4,
6..=11 => (Hpre::DIV8, 8), 6..=11 => Hpre::DIV8,
12..=39 => (Hpre::DIV16, 16), 12..=39 => Hpre::DIV16,
40..=95 => (Hpre::DIV64, 64), 40..=95 => Hpre::DIV64,
96..=191 => (Hpre::DIV128, 128), 96..=191 => Hpre::DIV128,
192..=383 => (Hpre::DIV256, 256), 192..=383 => Hpre::DIV256,
_ => (Hpre::DIV512, 512), _ => Hpre::DIV512,
}; };
let hclk = sysclk / hpre_div; let hclk = sysclk / hpre;
assert!(hclk <= 72_000_000); assert!(hclk <= Hertz(72_000_000));
// Calculate real APB1 clock // Calculate real APB1 clock
let pclk1 = config.pclk1.map(|p| p.0).unwrap_or(hclk); let pclk1 = config.pclk1.unwrap_or(hclk);
let (ppre1_bits, ppre1) = match hclk / pclk1 { let ppre1 = match hclk / pclk1 {
0 => unreachable!(), 0 => unreachable!(),
1 => (Ppre::DIV1, 1), 1 => Ppre::DIV1,
2 => (Ppre::DIV2, 2), 2 => Ppre::DIV2,
3..=5 => (Ppre::DIV4, 4), 3..=5 => Ppre::DIV4,
6..=11 => (Ppre::DIV8, 8), 6..=11 => Ppre::DIV8,
_ => (Ppre::DIV16, 16), _ => Ppre::DIV16,
}; };
let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; let timer_mul1 = if ppre1 == Ppre::DIV1 { 1u32 } else { 2 };
let pclk1 = hclk / ppre1; let pclk1 = hclk / ppre1;
assert!(pclk1 <= 36_000_000); assert!(pclk1 <= Hertz(36_000_000));
// Calculate real APB2 clock // Calculate real APB2 clock
let pclk2 = config.pclk2.map(|p| p.0).unwrap_or(hclk); let pclk2 = config.pclk2.unwrap_or(hclk);
let (ppre2_bits, ppre2) = match hclk / pclk2 { let ppre2 = match hclk / pclk2 {
0 => unreachable!(), 0 => unreachable!(),
1 => (Ppre::DIV1, 1), 1 => Ppre::DIV1,
2 => (Ppre::DIV2, 2), 2 => Ppre::DIV2,
3..=5 => (Ppre::DIV4, 4), 3..=5 => Ppre::DIV4,
6..=11 => (Ppre::DIV8, 8), 6..=11 => Ppre::DIV8,
_ => (Ppre::DIV16, 16), _ => Ppre::DIV16,
}; };
let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; let timer_mul2 = if ppre2 == Ppre::DIV1 { 1u32 } else { 2 };
let pclk2 = hclk / ppre2; let pclk2 = hclk / ppre2;
assert!(pclk2 <= 72_000_000); assert!(pclk2 <= Hertz(72_000_000));
// Set latency based on HCLK frquency // Set latency based on HCLK frquency
// RM0316: "The prefetch buffer must be kept on when using a prescaler // RM0316: "The prefetch buffer must be kept on when using a prescaler
// different from 1 on the AHB clock.", "Half-cycle access cannot be // different from 1 on the AHB clock.", "Half-cycle access cannot be
// used when there is a prescaler different from 1 on the AHB clock" // used when there is a prescaler different from 1 on the AHB clock"
FLASH.acr().modify(|w| { FLASH.acr().modify(|w| {
w.set_latency(if hclk <= 24_000_000 { w.set_latency(if hclk <= Hertz(24_000_000) {
Latency::WS0 Latency::WS0
} else if hclk <= 48_000_000 { } else if hclk <= Hertz(48_000_000) {
Latency::WS1 Latency::WS1
} else { } else {
Latency::WS2 Latency::WS2
}); });
if hpre_div != 1 { if hpre != Hpre::DIV1 {
w.set_hlfcya(false); w.set_hlfcya(false);
w.set_prftbe(true); w.set_prftbe(true);
} }
@ -240,9 +201,9 @@ pub(crate) unsafe fn init(config: Config) {
// Set prescalers // Set prescalers
// CFGR has been written before (PLL, PLL48) don't overwrite these settings // CFGR has been written before (PLL, PLL48) don't overwrite these settings
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_ppre2(ppre2_bits); w.set_ppre2(ppre2);
w.set_ppre1(ppre1_bits); w.set_ppre1(ppre1);
w.set_hpre(hpre_bits); w.set_hpre(hpre);
}); });
// Wait for the new prescalers to kick in // Wait for the new prescalers to kick in
@ -260,45 +221,43 @@ pub(crate) unsafe fn init(config: Config) {
}); });
#[cfg(rcc_f3)] #[cfg(rcc_f3)]
let adc = config.adc.map(|adc| { let adc = config.adc.map(|adc| match adc {
if !adc.is_bus() { AdcClockSource::Pll(adcpres) => {
RCC.cfgr2().modify(|w| { RCC.cfgr2().modify(|w| {
// Make sure that we're using the PLL // Make sure that we're using the PLL
pll_config.unwrap(); pll_config.unwrap();
w.set_adc12pres(adc.into()); w.set_adc12pres(adcpres);
Hertz(sysclk / adc as u32) sysclk / adcpres
}) })
} else { }
crate::pac::ADC_COMMON.ccr().modify(|w| { _ => crate::pac::ADC_COMMON.ccr().modify(|w| {
assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1)); assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1));
w.set_ckmode(adc.into()); w.set_ckmode(adc.into());
Hertz(sysclk / adc.bus_div() as u32) sysclk / adc.bus_div()
}) }),
}
}); });
#[cfg(all(rcc_f3, adc3_common))] #[cfg(all(rcc_f3, adc3_common))]
let adc34 = config.adc.map(|adc| { let adc34 = config.adc34.map(|adc| match adc {
if !adc.is_bus() { AdcClockSource::Pll(adcpres) => {
RCC.cfgr2().modify(|w| { RCC.cfgr2().modify(|w| {
// Make sure that we're using the PLL // Make sure that we're using the PLL
pll_config.unwrap(); pll_config.unwrap();
w.set_adc12pres(adc.into()); w.set_adc34pres(adcpres);
Hertz(sysclk / adc as u32) sysclk / adcpres
}) })
} else { }
crate::pac::ADC3_COMMON.ccr().modify(|w| { _ => crate::pac::ADC_COMMON.ccr().modify(|w| {
assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1)); assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1));
w.set_ckmode(adc.into()); w.set_ckmode(adc.into());
Hertz(sysclk / adc.bus_div() as u32) sysclk / adc.bus_div()
}) }),
}
}); });
#[cfg(stm32f334)] #[cfg(stm32f334)]
@ -310,21 +269,23 @@ pub(crate) unsafe fn init(config: Config) {
// Make sure that we're using the PLL // Make sure that we're using the PLL
pll_config.unwrap(); pll_config.unwrap();
assert!((pclk2 == sysclk) || (pclk2 * 2 == sysclk)); assert!((pclk2 == sysclk) || (pclk2 * 2u32 == sysclk));
RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL)); RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL));
Some(Hertz(sysclk * 2)) Some(sysclk * 2u32)
} }
}; };
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sysclk), sys: sysclk,
apb1: Hertz(pclk1), apb1: pclk1,
apb2: Hertz(pclk2), apb2: pclk2,
apb1_tim: Hertz(pclk1 * timer_mul1), apb1_tim: pclk1 * timer_mul1,
apb2_tim: Hertz(pclk2 * timer_mul2), apb2_tim: pclk2 * timer_mul2,
ahb1: Hertz(hclk), ahb1: hclk,
#[cfg(rcc_f3)] #[cfg(rcc_f3)]
adc: adc, adc: adc,
#[cfg(all(rcc_f3, adc3_common))] #[cfg(all(rcc_f3, adc3_common))]
@ -333,6 +294,7 @@ pub(crate) unsafe fn init(config: Config) {
adc34: None, adc34: None,
#[cfg(stm32f334)] #[cfg(stm32f334)]
hrtim: hrtim, hrtim: hrtim,
rtc,
}); });
} }
@ -421,16 +383,16 @@ fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) {
#[inline] #[inline]
#[allow(unused_variables)] #[allow(unused_variables)]
fn get_usb_pre(config: &Config, sysclk: u32, pclk1: u32, pll_config: &Option<PllConfig>) -> Usbpre { fn get_usb_pre(config: &Config, sysclk: Hertz, pclk1: Hertz, pll_config: &Option<PllConfig>) -> Usbpre {
cfg_if::cfg_if! { cfg_if::cfg_if! {
// Some chips do not have USB // Some chips do not have USB
if #[cfg(any(stm32f301, stm32f318, stm32f334))] { if #[cfg(any(stm32f301, stm32f318, stm32f334))] {
panic!("USB clock not supported by the chip"); panic!("USB clock not supported by the chip");
} else { } else {
let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000); let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= Hertz(10_000_000));
match (usb_ok, sysclk) { match (usb_ok, sysclk) {
(true, 72_000_000) => Usbpre::DIV1_5, (true, Hertz(72_000_000)) => Usbpre::DIV1_5,
(true, 48_000_000) => Usbpre::DIV1, (true, Hertz(48_000_000)) => Usbpre::DIV1,
_ => panic!( _ => panic!(
"USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz" "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz"
), ),

View File

@ -1,17 +1,11 @@
use stm32_metapac::rcc::vals::{Pllm, Plln, Pllq, Pllr}; use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllq, Pllr, Ppre, Sw};
use crate::pac::rcc::vals::{Hpre, Ppre, Sw};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// Clocks configuration /// Clocks configuration
#[non_exhaustive] #[non_exhaustive]
#[derive(Default)] #[derive(Default)]
@ -30,9 +24,7 @@ pub struct Config {
pub pllsai: Option<Hertz>, pub pllsai: Option<Hertz>,
pub pll48: bool, pub pll48: bool,
pub rtc: Option<RtcClockSource>, pub ls: super::LsConfig,
pub lsi: bool,
pub lse: Option<Hertz>,
} }
#[cfg(stm32f410)] #[cfg(stm32f410)]
@ -344,17 +336,7 @@ pub(crate) unsafe fn init(config: Config) {
}) })
}); });
BackupDomain::configure_ls( let rtc = config.ls.init();
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 { set_freqs(Clocks {
sys: Hertz(sysclk), sys: Hertz(sysclk),
@ -377,7 +359,6 @@ pub(crate) unsafe fn init(config: Config) {
pllsai: plls.pllsaiclk.map(Hertz), pllsai: plls.pllsaiclk.map(Hertz),
rtc, rtc,
rtc_hse: None,
}); });
} }

View File

@ -1,16 +1,12 @@
use crate::pac::pwr::vals::Vos; use crate::pac::pwr::vals::Vos;
use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllp, Pllq, Pllsrc, Ppre, Sw}; use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllp, Pllq, Pllsrc, Ppre, Sw};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// Clocks configuration /// Clocks configuration
#[non_exhaustive] #[non_exhaustive]
#[derive(Default)] #[derive(Default)]
@ -23,9 +19,7 @@ pub struct Config {
pub pclk2: Option<Hertz>, pub pclk2: Option<Hertz>,
pub pll48: bool, pub pll48: bool,
pub rtc: Option<RtcClockSource>, pub ls: super::LsConfig,
pub lsi: bool,
pub lse: Option<Hertz>,
} }
fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults { fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
@ -261,17 +255,7 @@ pub(crate) unsafe fn init(config: Config) {
}) })
}); });
BackupDomain::configure_ls( let rtc = config.ls.init();
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 { set_freqs(Clocks {
sys: Hertz(sysclk), sys: Hertz(sysclk),

View File

@ -1,6 +1,8 @@
use crate::pac::flash::vals::Latency; use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{self, Hsidiv, Sw}; use crate::pac::rcc::vals::{self, Sw};
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler}; pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Hsidiv as HSI16Prescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler,
};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -8,9 +10,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
@ -20,33 +19,6 @@ pub enum ClockSrc {
LSI, LSI,
} }
#[derive(Clone, Copy)]
pub enum HSI16Prescaler {
NotDivided,
Div2,
Div4,
Div8,
Div16,
Div32,
Div64,
Div128,
}
impl Into<Hsidiv> for HSI16Prescaler {
fn into(self) -> Hsidiv {
match self {
HSI16Prescaler::NotDivided => Hsidiv::DIV1,
HSI16Prescaler::Div2 => Hsidiv::DIV2,
HSI16Prescaler::Div4 => Hsidiv::DIV4,
HSI16Prescaler::Div8 => Hsidiv::DIV8,
HSI16Prescaler::Div16 => Hsidiv::DIV16,
HSI16Prescaler::Div32 => Hsidiv::DIV32,
HSI16Prescaler::Div64 => Hsidiv::DIV64,
HSI16Prescaler::Div128 => Hsidiv::DIV128,
}
}
}
/// The PLL configuration. /// The PLL configuration.
/// ///
/// * `VCOCLK = source / m * n` /// * `VCOCLK = source / m * n`
@ -98,16 +70,18 @@ pub struct Config {
pub ahb_pre: AHBPrescaler, pub ahb_pre: AHBPrescaler,
pub apb_pre: APBPrescaler, pub apb_pre: APBPrescaler,
pub low_power_run: bool, pub low_power_run: bool,
pub ls: super::LsConfig,
} }
impl Default for Config { impl Default for Config {
#[inline] #[inline]
fn default() -> Config { fn default() -> Config {
Config { Config {
mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided), mux: ClockSrc::HSI16(HSI16Prescaler::DIV1),
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
apb_pre: APBPrescaler::DIV1, apb_pre: APBPrescaler::DIV1,
low_power_run: false, low_power_run: false,
ls: Default::default(),
} }
} }
} }
@ -195,7 +169,6 @@ pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
ClockSrc::HSI16(div) => { ClockSrc::HSI16(div) => {
// Enable HSI16 // Enable HSI16
let div: Hsidiv = div.into();
RCC.cr().write(|w| { RCC.cr().write(|w| {
w.set_hsidiv(div); w.set_hsidiv(div);
w.set_hsion(true) w.set_hsion(true)
@ -219,7 +192,7 @@ pub(crate) unsafe fn init(config: Config) {
// Enable LSI // Enable LSI
RCC.csr().write(|w| w.set_lsion(true)); RCC.csr().write(|w| w.set_lsion(true));
while !RCC.csr().read().lsirdy() {} while !RCC.csr().read().lsirdy() {}
(LSI_FREQ, Sw::LSI) (super::LSI_FREQ, Sw::LSI)
} }
}; };
@ -262,7 +235,7 @@ pub(crate) unsafe fn init(config: Config) {
} }
// Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
let (sw, hpre, ppre) = (sw.into(), config.ahb_pre.into(), config.apb_pre.into()); let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre);
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(hpre); w.set_hpre(hpre);
@ -298,10 +271,13 @@ pub(crate) unsafe fn init(config: Config) {
PWR.cr1().modify(|w| w.set_lpr(true)); PWR.cr1().modify(|w| w.set_lpr(true));
} }
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
ahb1: ahb_freq, ahb1: ahb_freq,
apb1: apb_freq, apb1: apb_freq,
apb1_tim: apb_tim_freq, apb1_tim: apb_tim_freq,
rtc,
}); });
} }

View File

@ -3,7 +3,8 @@ use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw};
use stm32_metapac::FLASH; use stm32_metapac::FLASH;
pub use crate::pac::rcc::vals::{ pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN, Pllp as PllP, Pllq as PllQ, Pllr as PllR, Ppre as APBPrescaler, Adcsel as AdcClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN, Pllp as PllP, Pllq as PllQ,
Pllr as PllR, Ppre as APBPrescaler,
}; };
use crate::pac::{PWR, RCC}; use crate::pac::{PWR, RCC};
use crate::rcc::sealed::RccPeripheral; use crate::rcc::sealed::RccPeripheral;
@ -13,32 +14,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); 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 /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
@ -88,32 +63,6 @@ pub struct Pll {
pub div_r: Option<PllR>, pub div_r: Option<PllR>,
} }
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!(),
}
}
fn apb_div(apb: APBPrescaler) -> u32 {
match apb {
APBPrescaler::DIV1 => 1,
APBPrescaler::DIV2 => 2,
APBPrescaler::DIV4 => 4,
APBPrescaler::DIV8 => 8,
APBPrescaler::DIV16 => 16,
_ => unreachable!(),
}
}
/// Sets the source for the 48MHz clock to the USB and RNG peripherals. /// Sets the source for the 48MHz clock to the USB and RNG peripherals.
pub enum Clock48MhzSrc { pub enum Clock48MhzSrc {
/// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the /// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the
@ -149,6 +98,8 @@ pub struct Config {
pub clock_48mhz_src: Option<Clock48MhzSrc>, pub clock_48mhz_src: Option<Clock48MhzSrc>,
pub adc12_clock_source: AdcClockSource, pub adc12_clock_source: AdcClockSource,
pub adc345_clock_source: AdcClockSource, pub adc345_clock_source: AdcClockSource,
pub ls: super::LsConfig,
} }
/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator. /// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
@ -168,8 +119,9 @@ impl Default for Config {
low_power_run: false, low_power_run: false,
pll: None, pll: None,
clock_48mhz_src: None, clock_48mhz_src: None,
adc12_clock_source: Default::default(), adc12_clock_source: Adcsel::NOCLK,
adc345_clock_source: Default::default(), adc345_clock_source: Adcsel::NOCLK,
ls: Default::default(),
} }
} }
} }
@ -203,8 +155,8 @@ pub(crate) unsafe fn init(config: Config) {
let internal_freq = src_freq / pll_config.prediv_m * pll_config.mul_n; let internal_freq = src_freq / pll_config.prediv_m * pll_config.mul_n;
RCC.pllcfgr().write(|w| { RCC.pllcfgr().write(|w| {
w.set_plln(pll_config.mul_n.into()); w.set_plln(pll_config.mul_n);
w.set_pllm(pll_config.prediv_m.into()); w.set_pllm(pll_config.prediv_m);
w.set_pllsrc(pll_config.source.into()); w.set_pllsrc(pll_config.source.into());
}); });
@ -249,14 +201,14 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI_FREQ.0, Sw::HSI16) (HSI_FREQ, Sw::HSI16)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE
RCC.cr().write(|w| w.set_hseon(true)); RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {} while !RCC.cr().read().hserdy() {}
(freq.0, Sw::HSE) (freq, Sw::HSE)
} }
ClockSrc::PLL => { ClockSrc::PLL => {
assert!(pll_freq.is_some()); assert!(pll_freq.is_some());
@ -297,35 +249,32 @@ pub(crate) unsafe fn init(config: Config) {
} }
} }
(freq, Sw::PLLRCLK) (Hertz(freq), Sw::PLLRCLK)
} }
}; };
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(config.ahb_pre.into()); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
let ahb_freq: u32 = match config.ahb_pre { let ahb_freq = sys_clk / config.ahb_pre;
AHBPrescaler::DIV1 => sys_clk,
pre => sys_clk / ahb_div(pre),
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let freq = ahb_freq / apb_div(pre); let freq = ahb_freq / pre;
(freq, freq * 2) (freq, freq * 2u32)
} }
}; };
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let freq = ahb_freq / apb_div(pre); let freq = ahb_freq / pre;
(freq, freq * 2) (freq, freq * 2u32)
} }
}; };
@ -373,43 +322,40 @@ pub(crate) unsafe fn init(config: Config) {
RCC.ccipr().modify(|w| w.set_clk48sel(source)); RCC.ccipr().modify(|w| w.set_clk48sel(source));
} }
RCC.ccipr() RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source));
.modify(|w| w.set_adc12sel(config.adc12_clock_source.adcsel())); RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
RCC.ccipr()
.modify(|w| w.set_adc345sel(config.adc345_clock_source.adcsel()));
let adc12_ck = match config.adc12_clock_source { let adc12_ck = match config.adc12_clock_source {
AdcClockSource::NoClk => None, AdcClockSource::NOCLK => None,
AdcClockSource::PllP => match &pll_freq { AdcClockSource::PLLP => pll_freq.as_ref().unwrap().pll_p,
Some(pll) => pll.pll_p, AdcClockSource::SYSCLK => Some(sys_clk),
None => None, _ => unreachable!(),
},
AdcClockSource::SysClk => Some(Hertz(sys_clk)),
}; };
let adc345_ck = match config.adc345_clock_source { let adc345_ck = match config.adc345_clock_source {
AdcClockSource::NoClk => None, AdcClockSource::NOCLK => None,
AdcClockSource::PllP => match &pll_freq { AdcClockSource::PLLP => pll_freq.as_ref().unwrap().pll_p,
Some(pll) => pll.pll_p, AdcClockSource::SYSCLK => Some(sys_clk),
None => None, _ => unreachable!(),
},
AdcClockSource::SysClk => Some(Hertz(sys_clk)),
}; };
if config.low_power_run { if config.low_power_run {
assert!(sys_clk <= 2_000_000); assert!(sys_clk <= Hertz(2_000_000));
PWR.cr1().modify(|w| w.set_lpr(true)); PWR.cr1().modify(|w| w.set_lpr(true));
} }
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sys_clk), sys: sys_clk,
ahb1: Hertz(ahb_freq), ahb1: ahb_freq,
ahb2: Hertz(ahb_freq), ahb2: ahb_freq,
apb1: Hertz(apb1_freq), apb1: apb1_freq,
apb1_tim: Hertz(apb1_tim_freq), apb1_tim: apb1_tim_freq,
apb2: Hertz(apb2_freq), apb2: apb2_freq,
apb2_tim: Hertz(apb2_tim_freq), apb2_tim: apb2_tim_freq,
adc: adc12_ck, adc: adc12_ck,
adc34: adc345_ck, adc34: adc345_ck,
rtc,
}); });
} }

View File

@ -9,8 +9,6 @@ pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre}; use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre};
pub use crate::pac::rcc::vals::{Ckpersel as PerClockSource, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul}; pub use crate::pac::rcc::vals::{Ckpersel as PerClockSource, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
#[cfg(stm32h7)]
use crate::rcc::bd::{BackupDomain, LseCfg, RtcClockSource};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -23,16 +21,13 @@ pub const CSI_FREQ: Hertz = Hertz(4_000_000);
/// HSI48 speed /// HSI48 speed
pub const HSI48_FREQ: Hertz = Hertz(48_000_000); pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
/// LSI speed const VCO_RANGE: RangeInclusive<Hertz> = Hertz(150_000_000)..=Hertz(420_000_000);
pub const LSI_FREQ: Hertz = Hertz(32_000);
const VCO_RANGE: RangeInclusive<u32> = 150_000_000..=420_000_000;
#[cfg(any(stm32h5, pwr_h7rm0455))] #[cfg(any(stm32h5, pwr_h7rm0455))]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 128_000_000..=560_000_000; const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(128_000_000)..=Hertz(560_000_000);
#[cfg(pwr_h7rm0468)] #[cfg(pwr_h7rm0468)]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=836_000_000; const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(192_000_000)..=Hertz(836_000_000);
#[cfg(any(pwr_h7rm0399, pwr_h7rm0433))] #[cfg(any(pwr_h7rm0399, pwr_h7rm0433))]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=960_000_000; const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(192_000_000)..=Hertz(960_000_000);
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
@ -196,8 +191,7 @@ pub struct Config {
pub adc_clock_source: AdcClockSource, pub adc_clock_source: AdcClockSource,
pub timer_prescaler: TimerPrescaler, pub timer_prescaler: TimerPrescaler,
pub voltage_scale: VoltageScale, pub voltage_scale: VoltageScale,
#[cfg(stm32h7)] pub ls: super::LsConfig,
pub rtc_mux: Option<RtcClockSource>,
} }
impl Default for Config { impl Default for Config {
@ -231,8 +225,7 @@ impl Default for Config {
adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5 adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5
timer_prescaler: TimerPrescaler::DefaultX2, timer_prescaler: TimerPrescaler::DefaultX2,
voltage_scale: VoltageScale::Scale0, voltage_scale: VoltageScale::Scale0,
#[cfg(stm32h7)] ls: Default::default(),
rtc_mux: None,
} }
} }
} }
@ -471,18 +464,7 @@ pub(crate) unsafe fn init(config: Config) {
flash_setup(hclk, config.voltage_scale); flash_setup(hclk, config.voltage_scale);
#[cfg(stm32h7)] let rtc = config.ls.init();
{
let lsecfg = config.lse.map(|lse| match lse {
Lse::Bypass(freq) => {
assert!(freq <= Hertz(1_000_000));
LseCfg::Bypass
}
Lse::Oscillator => LseCfg::Oscillator(Default::default()),
});
BackupDomain::configure_ls(config.rtc_mux.unwrap_or(RtcClockSource::NOCLOCK), config.lsi, lsecfg);
}
#[cfg(stm32h7)] #[cfg(stm32h7)]
{ {
@ -548,17 +530,6 @@ pub(crate) unsafe fn init(config: Config) {
while !pac::SYSCFG.cccsr().read().ready() {} while !pac::SYSCFG.cccsr().read().ready() {}
} }
#[cfg(stm32h7)]
let rtc_clk = match config.rtc_mux {
Some(RtcClockSource::LSI) => Some(LSI_FREQ),
Some(RtcClockSource::LSE) => Some(match config.lse {
Some(Lse::Oscillator) => Hertz(32768),
Some(Lse::Bypass(freq)) => freq,
None => panic!("LSE not configured"),
}),
_ => None,
};
set_freqs(Clocks { set_freqs(Clocks {
sys, sys,
ahb1: hclk, ahb1: hclk,
@ -573,10 +544,7 @@ pub(crate) unsafe fn init(config: Config) {
apb1_tim, apb1_tim,
apb2_tim, apb2_tim,
adc, adc,
#[cfg(stm32h7)]
rtc: rtc_clk, rtc: rtc_clk,
#[cfg(stm32h7)]
rtc_hse: None,
#[cfg(stm32h5)] #[cfg(stm32h5)]
mux_rcc_pclk1: None, mux_rcc_pclk1: None,
@ -686,9 +654,9 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
let wide_allowed = ref_range != Pllrge::RANGE1; let wide_allowed = ref_range != Pllrge::RANGE1;
let vco_clk = ref_clk * config.mul; let vco_clk = ref_clk * config.mul;
let vco_range = if VCO_RANGE.contains(&vco_clk.0) { let vco_range = if VCO_RANGE.contains(&vco_clk) {
Pllvcosel::MEDIUMVCO Pllvcosel::MEDIUMVCO
} else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk.0) { } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) {
Pllvcosel::WIDEVCO Pllvcosel::WIDEVCO
} else { } else {
panic!("pll vco_clk out of range: {} mhz", vco_clk.0) panic!("pll vco_clk out of range: {} mhz", vco_clk.0)

View File

@ -1,349 +0,0 @@
use super::bd::BackupDomain;
use super::RtcClockSource;
pub use crate::pac::pwr::vals::Vos as VoltageScale;
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
#[cfg(crs)]
use crate::pac::{crs, CRS, SYSCFG};
use crate::pac::{FLASH, PWR, 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);
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
MSI(MSIRange),
PLL(PLLSource, PLLMul, PLLDiv),
HSE(Hertz),
HSI16,
}
/// MSI Clock Range
///
/// These ranges control the frequency of the MSI. Internally, these ranges map
/// to the `MSIRANGE` bits in the `RCC_ICSCR` register.
#[derive(Clone, Copy)]
pub enum MSIRange {
/// Around 65.536 kHz
Range0,
/// Around 131.072 kHz
Range1,
/// Around 262.144 kHz
Range2,
/// Around 524.288 kHz
Range3,
/// Around 1.048 MHz
Range4,
/// Around 2.097 MHz (reset value)
Range5,
/// Around 4.194 MHz
Range6,
}
impl Default for MSIRange {
fn default() -> MSIRange {
MSIRange::Range5
}
}
/// PLL divider
#[derive(Clone, Copy)]
pub enum PLLDiv {
Div2,
Div3,
Div4,
}
/// PLL multiplier
#[derive(Clone, Copy)]
pub enum PLLMul {
Mul3,
Mul4,
Mul6,
Mul8,
Mul12,
Mul16,
Mul24,
Mul32,
Mul48,
}
/// PLL clock input source
#[derive(Clone, Copy)]
pub enum PLLSource {
HSI16,
HSE(Hertz),
}
impl From<PLLMul> for Pllmul {
fn from(val: PLLMul) -> Pllmul {
match val {
PLLMul::Mul3 => Pllmul::MUL3,
PLLMul::Mul4 => Pllmul::MUL4,
PLLMul::Mul6 => Pllmul::MUL6,
PLLMul::Mul8 => Pllmul::MUL8,
PLLMul::Mul12 => Pllmul::MUL12,
PLLMul::Mul16 => Pllmul::MUL16,
PLLMul::Mul24 => Pllmul::MUL24,
PLLMul::Mul32 => Pllmul::MUL32,
PLLMul::Mul48 => Pllmul::MUL48,
}
}
}
impl From<PLLDiv> for Plldiv {
fn from(val: PLLDiv) -> Plldiv {
match val {
PLLDiv::Div2 => Plldiv::DIV2,
PLLDiv::Div3 => Plldiv::DIV3,
PLLDiv::Div4 => Plldiv::DIV4,
}
}
}
impl From<PLLSource> for Pllsrc {
fn from(val: PLLSource) -> Pllsrc {
match val {
PLLSource::HSI16 => Pllsrc::HSI16,
PLLSource::HSE(_) => Pllsrc::HSE,
}
}
}
impl From<MSIRange> for Msirange {
fn from(val: MSIRange) -> Msirange {
match val {
MSIRange::Range0 => Msirange::RANGE0,
MSIRange::Range1 => Msirange::RANGE1,
MSIRange::Range2 => Msirange::RANGE2,
MSIRange::Range3 => Msirange::RANGE3,
MSIRange::Range4 => Msirange::RANGE4,
MSIRange::Range5 => Msirange::RANGE5,
MSIRange::Range6 => Msirange::RANGE6,
}
}
}
/// Clocks configutation
pub struct Config {
pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
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 {
#[inline]
fn default() -> Config {
Config {
mux: ClockSrc::MSI(MSIRange::default()),
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
RCC.icscr().write(|w| w.set_msirange(range.into()));
// Enable MSI
RCC.cr().write(|w| w.set_msion(true));
while !RCC.cr().read().msirdy() {}
let freq = 32_768 * (1 << (range as u8 + 1));
(freq, Sw::MSI)
}
ClockSrc::HSI16 => {
// Enable HSI16
RCC.cr().write(|w| w.set_hsi16on(true));
while !RCC.cr().read().hsi16rdyf() {}
(HSI_FREQ.0, Sw::HSI16)
}
ClockSrc::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
(freq.0, Sw::HSE)
}
ClockSrc::PLL(src, mul, div) => {
let freq = match src {
PLLSource::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
freq.0
}
PLLSource::HSI16 => {
// Enable HSI
RCC.cr().write(|w| w.set_hsi16on(true));
while !RCC.cr().read().hsi16rdyf() {}
HSI_FREQ.0
}
};
// Disable PLL
RCC.cr().modify(|w| w.set_pllon(false));
while RCC.cr().read().pllrdy() {}
let freq = match mul {
PLLMul::Mul3 => freq * 3,
PLLMul::Mul4 => freq * 4,
PLLMul::Mul6 => freq * 6,
PLLMul::Mul8 => freq * 8,
PLLMul::Mul12 => freq * 12,
PLLMul::Mul16 => freq * 16,
PLLMul::Mul24 => freq * 24,
PLLMul::Mul32 => freq * 32,
PLLMul::Mul48 => freq * 48,
};
let freq = match div {
PLLDiv::Div2 => freq / 2,
PLLDiv::Div3 => freq / 3,
PLLDiv::Div4 => freq / 4,
};
assert!(freq <= 32_000_000);
RCC.cfgr().write(move |w| {
w.set_pllmul(mul.into());
w.set_plldiv(div.into());
w.set_pllsrc(src.into());
});
// Enable PLL
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
(freq, Sw::PLL)
}
};
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());
w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre.into());
});
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.to_bits() as u32 - 7);
sys_clk / pre
}
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
#[cfg(crs)]
if config.enable_hsi48 {
// Reset CRS peripheral
RCC.apb1rstr().modify(|w| w.set_crsrst(true));
RCC.apb1rstr().modify(|w| w.set_crsrst(false));
// Enable CRS peripheral
RCC.apb1enr().modify(|w| w.set_crsen(true));
// Initialize CRS
CRS.cfgr().write(|w|
// Select LSE as synchronization source
w.set_syncsrc(crs::vals::Syncsrc::LSE));
CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
});
// Enable VREFINT reference for HSI48 oscillator
SYSCFG.cfgr3().modify(|w| {
w.set_enref_hsi48(true);
w.set_en_vrefint(true);
});
// Select HSI48 as USB clock
RCC.ccipr().modify(|w| w.set_hsi48msel(true));
// Enable dedicated USB clock
RCC.crrcr().modify(|w| w.set_hsi48on(true));
while !RCC.crrcr().read().hsi48rdy() {}
}
set_freqs(Clocks {
sys: Hertz(sys_clk),
ahb1: Hertz(ahb_freq),
apb1: Hertz(apb1_freq),
apb2: Hertz(apb2_freq),
apb1_tim: Hertz(apb1_tim_freq),
apb2_tim: Hertz(apb2_tim_freq),
});
}

View File

@ -0,0 +1,219 @@
pub use crate::pac::pwr::vals::Vos as VoltageScale;
pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Msirange as MSIRange, Plldiv as PLLDiv, Pllmul as PLLMul, Ppre as APBPrescaler,
};
use crate::pac::rcc::vals::{Pllsrc, Sw};
#[cfg(crs)]
use crate::pac::{crs, CRS, SYSCFG};
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
MSI(MSIRange),
PLL(PLLSource, PLLMul, PLLDiv),
HSE(Hertz),
HSI16,
}
/// PLL clock input source
#[derive(Clone, Copy)]
pub enum PLLSource {
HSI16,
HSE(Hertz),
}
impl From<PLLSource> for Pllsrc {
fn from(val: PLLSource) -> Pllsrc {
match val {
PLLSource::HSI16 => Pllsrc::HSI16,
PLLSource::HSE(_) => Pllsrc::HSE,
}
}
}
/// Clocks configutation
pub struct Config {
pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
#[cfg(crs)]
pub enable_hsi48: bool,
pub ls: super::LsConfig,
pub voltage_scale: VoltageScale,
}
impl Default for Config {
#[inline]
fn default() -> Config {
Config {
mux: ClockSrc::MSI(MSIRange::RANGE5),
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
#[cfg(crs)]
enable_hsi48: false,
voltage_scale: VoltageScale::RANGE1,
ls: Default::default(),
}
}
}
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
RCC.icscr().write(|w| w.set_msirange(range));
// Enable MSI
RCC.cr().write(|w| w.set_msion(true));
while !RCC.cr().read().msirdy() {}
let freq = 32_768 * (1 << (range as u8 + 1));
(Hertz(freq), Sw::MSI)
}
ClockSrc::HSI16 => {
// Enable HSI16
RCC.cr().write(|w| w.set_hsi16on(true));
while !RCC.cr().read().hsi16rdy() {}
(HSI_FREQ, Sw::HSI16)
}
ClockSrc::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
(freq, Sw::HSE)
}
ClockSrc::PLL(src, mul, div) => {
let freq = match src {
PLLSource::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
freq
}
PLLSource::HSI16 => {
// Enable HSI
RCC.cr().write(|w| w.set_hsi16on(true));
while !RCC.cr().read().hsi16rdy() {}
HSI_FREQ
}
};
// Disable PLL
RCC.cr().modify(|w| w.set_pllon(false));
while RCC.cr().read().pllrdy() {}
let freq = freq * mul / div;
assert!(freq <= Hertz(32_000_000));
RCC.cfgr().write(move |w| {
w.set_pllmul(mul);
w.set_plldiv(div);
w.set_pllsrc(src.into());
});
// Enable PLL
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
(freq, Sw::PLL)
}
};
let rtc = config.ls.init();
let wait_states = match (config.voltage_scale, sys_clk.0) {
(VoltageScale::RANGE1, ..=16_000_000) => 0,
(VoltageScale::RANGE2, ..=8_000_000) => 0,
(VoltageScale::RANGE3, ..=4_200_000) => 0,
_ => 1,
};
#[cfg(stm32l1)]
FLASH.acr().write(|w| w.set_acc64(true));
FLASH.acr().modify(|w| w.set_prften(true));
FLASH.acr().modify(|w| w.set_latency(wait_states != 0));
RCC.cfgr().modify(|w| {
w.set_sw(sw);
w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre);
});
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)
}
};
#[cfg(crs)]
if config.enable_hsi48 {
// Reset CRS peripheral
RCC.apb1rstr().modify(|w| w.set_crsrst(true));
RCC.apb1rstr().modify(|w| w.set_crsrst(false));
// Enable CRS peripheral
RCC.apb1enr().modify(|w| w.set_crsen(true));
// Initialize CRS
CRS.cfgr().write(|w|
// Select LSE as synchronization source
w.set_syncsrc(crs::vals::Syncsrc::LSE));
CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
});
// Enable VREFINT reference for HSI48 oscillator
SYSCFG.cfgr3().modify(|w| {
w.set_enref_hsi48(true);
w.set_en_vrefint(true);
});
// Select HSI48 as USB clock
RCC.ccipr().modify(|w| w.set_hsi48msel(true));
// Enable dedicated USB clock
RCC.crrcr().modify(|w| w.set_hsi48on(true));
while !RCC.crrcr().read().hsi48rdy() {}
}
set_freqs(Clocks {
sys: sys_clk,
ahb1: ahb_freq,
apb1: apb1_freq,
apb2: apb2_freq,
apb1_tim: apb1_tim_freq,
apb2_tim: apb2_tim_freq,
rtc,
});
}

View File

@ -1,279 +0,0 @@
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
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);
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
MSI(MSIRange),
PLL(PLLSource, PLLMul, PLLDiv),
HSE(Hertz),
HSI,
}
/// MSI Clock Range
///
/// These ranges control the frequency of the MSI. Internally, these ranges map
/// to the `MSIRANGE` bits in the `RCC_ICSCR` register.
#[derive(Clone, Copy)]
pub enum MSIRange {
/// Around 65.536 kHz
Range0,
/// Around 131.072 kHz
Range1,
/// Around 262.144 kHz
Range2,
/// Around 524.288 kHz
Range3,
/// Around 1.048 MHz
Range4,
/// Around 2.097 MHz (reset value)
Range5,
/// Around 4.194 MHz
Range6,
}
impl Default for MSIRange {
fn default() -> MSIRange {
MSIRange::Range5
}
}
/// PLL divider
#[derive(Clone, Copy)]
pub enum PLLDiv {
Div2,
Div3,
Div4,
}
/// PLL multiplier
#[derive(Clone, Copy)]
pub enum PLLMul {
Mul3,
Mul4,
Mul6,
Mul8,
Mul12,
Mul16,
Mul24,
Mul32,
Mul48,
}
/// PLL clock input source
#[derive(Clone, Copy)]
pub enum PLLSource {
HSI,
HSE(Hertz),
}
impl From<PLLMul> for Pllmul {
fn from(val: PLLMul) -> Pllmul {
match val {
PLLMul::Mul3 => Pllmul::MUL3,
PLLMul::Mul4 => Pllmul::MUL4,
PLLMul::Mul6 => Pllmul::MUL6,
PLLMul::Mul8 => Pllmul::MUL8,
PLLMul::Mul12 => Pllmul::MUL12,
PLLMul::Mul16 => Pllmul::MUL16,
PLLMul::Mul24 => Pllmul::MUL24,
PLLMul::Mul32 => Pllmul::MUL32,
PLLMul::Mul48 => Pllmul::MUL48,
}
}
}
impl From<PLLDiv> for Plldiv {
fn from(val: PLLDiv) -> Plldiv {
match val {
PLLDiv::Div2 => Plldiv::DIV2,
PLLDiv::Div3 => Plldiv::DIV3,
PLLDiv::Div4 => Plldiv::DIV4,
}
}
}
impl From<PLLSource> for Pllsrc {
fn from(val: PLLSource) -> Pllsrc {
match val {
PLLSource::HSI => Pllsrc::HSI,
PLLSource::HSE(_) => Pllsrc::HSE,
}
}
}
impl From<MSIRange> for Msirange {
fn from(val: MSIRange) -> Msirange {
match val {
MSIRange::Range0 => Msirange::RANGE0,
MSIRange::Range1 => Msirange::RANGE1,
MSIRange::Range2 => Msirange::RANGE2,
MSIRange::Range3 => Msirange::RANGE3,
MSIRange::Range4 => Msirange::RANGE4,
MSIRange::Range5 => Msirange::RANGE5,
MSIRange::Range6 => Msirange::RANGE6,
}
}
}
/// Clocks configutation
pub struct Config {
pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
}
impl Default for Config {
#[inline]
fn default() -> Config {
Config {
mux: ClockSrc::MSI(MSIRange::default()),
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
}
}
}
pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw) = match config.mux {
ClockSrc::MSI(range) => {
// Set MSI range
RCC.icscr().write(|w| w.set_msirange(range.into()));
// Enable MSI
RCC.cr().write(|w| w.set_msion(true));
while !RCC.cr().read().msirdy() {}
let freq = 32_768 * (1 << (range as u8 + 1));
(freq, Sw::MSI)
}
ClockSrc::HSI => {
// Enable HSI
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
(HSI_FREQ.0, Sw::HSI)
}
ClockSrc::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
(freq.0, Sw::HSE)
}
ClockSrc::PLL(src, mul, div) => {
let freq = match src {
PLLSource::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
freq.0
}
PLLSource::HSI => {
// Enable HSI
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
HSI_FREQ.0
}
};
// Disable PLL
RCC.cr().modify(|w| w.set_pllon(false));
while RCC.cr().read().pllrdy() {}
let freq = match mul {
PLLMul::Mul3 => freq * 3,
PLLMul::Mul4 => freq * 4,
PLLMul::Mul6 => freq * 6,
PLLMul::Mul8 => freq * 8,
PLLMul::Mul12 => freq * 12,
PLLMul::Mul16 => freq * 16,
PLLMul::Mul24 => freq * 24,
PLLMul::Mul32 => freq * 32,
PLLMul::Mul48 => freq * 48,
};
let freq = match div {
PLLDiv::Div2 => freq / 2,
PLLDiv::Div3 => freq / 3,
PLLDiv::Div4 => freq / 4,
};
assert!(freq <= 32_000_000);
RCC.cfgr().write(move |w| {
w.set_pllmul(mul.into());
w.set_plldiv(div.into());
w.set_pllsrc(src.into());
});
// Enable PLL
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
(freq, Sw::PLL)
}
};
// Set flash 64-bit access, prefetch and wait states
if sys_clk >= 16_000_000 {
FLASH.acr().write(|w| w.set_acc64(true));
FLASH.acr().modify(|w| w.set_prften(true));
FLASH.acr().modify(|w| w.set_latency(true));
}
RCC.cfgr().modify(|w| {
w.set_sw(sw);
w.set_hpre(config.ahb_pre.into());
w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre.into());
});
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.to_bits() as u32 - 7);
sys_clk / pre
}
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
set_freqs(Clocks {
sys: Hertz(sys_clk),
ahb1: Hertz(ahb_freq),
apb1: Hertz(apb1_freq),
apb2: Hertz(apb2_freq),
apb1_tim: Hertz(apb1_tim_freq),
apb2_tim: Hertz(apb2_tim_freq),
});
}

View File

@ -5,16 +5,12 @@ pub use crate::pac::rcc::vals::{
}; };
use crate::pac::rcc::vals::{Msirange, Pllsrc, Sw}; use crate::pac::rcc::vals::{Msirange, Pllsrc, Sw};
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
@ -51,9 +47,7 @@ pub struct Config {
pub pllsai1: Option<(PllMul, PllPreDiv, Option<PllRDiv>, Option<PllQDiv>, Option<PllPDiv>)>, pub pllsai1: Option<(PllMul, PllPreDiv, Option<PllRDiv>, Option<PllQDiv>, Option<PllPDiv>)>,
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
pub hsi48: bool, pub hsi48: bool,
pub rtc_mux: RtcClockSource, pub ls: super::LsConfig,
pub lse: Option<Hertz>,
pub lsi: bool,
} }
impl Default for Config { impl Default for Config {
@ -67,9 +61,7 @@ impl Default for Config {
pllsai1: None, pllsai1: None,
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
hsi48: false, hsi48: false,
rtc_mux: RtcClockSource::LSI, ls: Default::default(),
lsi: true,
lse: None,
} }
} }
} }
@ -95,23 +87,18 @@ pub(crate) unsafe fn init(config: Config) {
while RCC.cfgr().read().sws() != Sw::MSI {} while RCC.cfgr().read().sws() != Sw::MSI {}
} }
BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default())); let rtc = config.ls.init();
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
ClockSrc::MSI(range) => { ClockSrc::MSI(range) => {
// Enable MSI // Enable MSI
RCC.cr().write(|w| { RCC.cr().write(|w| {
let bits: Msirange = range.into(); w.set_msirange(range);
w.set_msirange(bits);
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msion(true); w.set_msion(true);
if config.rtc_mux == RtcClockSource::LSE {
// If LSE is enabled, enable calibration of MSI // If LSE is enabled, enable calibration of MSI
w.set_msipllen(true); w.set_msipllen(config.ls.lse.is_some());
} else {
w.set_msipllen(false);
}
}); });
while !RCC.cr().read().msirdy() {} while !RCC.cr().read().msirdy() {}
@ -154,8 +141,7 @@ pub(crate) unsafe fn init(config: Config) {
PLLSource::MSI(range) => { PLLSource::MSI(range) => {
// Enable MSI // Enable MSI
RCC.cr().write(|w| { RCC.cr().write(|w| {
let bits: Msirange = range.into(); w.set_msirange(range);
w.set_msirange(bits);
w.set_msipllen(false); // should be turned on if LSE is started w.set_msipllen(false); // should be turned on if LSE is started
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msion(true); w.set_msion(true);
@ -255,9 +241,9 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(config.ahb_pre.into()); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
let ahb_freq = sys_clk / config.ahb_pre; let ahb_freq = sys_clk / config.ahb_pre;
@ -287,6 +273,7 @@ pub(crate) unsafe fn init(config: Config) {
apb2: apb2_freq, apb2: apb2_freq,
apb1_tim: apb1_tim_freq, apb1_tim: apb1_tim_freq,
apb2_tim: apb2_tim_freq, apb2_tim: apb2_tim_freq,
rtc,
}); });
} }

View File

@ -5,16 +5,12 @@ pub use crate::pac::rcc::vals::{
}; };
use crate::pac::rcc::vals::{Msirange, Pllsrc, Sw}; use crate::pac::rcc::vals::{Msirange, Pllsrc, Sw};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::bd::RtcClockSource;
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
@ -50,9 +46,7 @@ pub struct Config {
pub apb2_pre: APBPrescaler, pub apb2_pre: APBPrescaler,
pub pllsai1: Option<(PllMul, PllPreDiv, Option<PllRDiv>, Option<PllQDiv>, Option<PllPDiv>)>, pub pllsai1: Option<(PllMul, PllPreDiv, Option<PllRDiv>, Option<PllQDiv>, Option<PllPDiv>)>,
pub hsi48: bool, pub hsi48: bool,
pub rtc_mux: RtcClockSource, pub ls: super::LsConfig,
pub lse: Option<Hertz>,
pub lsi: bool,
} }
impl Default for Config { impl Default for Config {
@ -65,9 +59,7 @@ impl Default for Config {
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
pllsai1: None, pllsai1: None,
hsi48: false, hsi48: false,
rtc_mux: RtcClockSource::LSI, ls: Default::default(),
lsi: true,
lse: None,
} }
} }
} }
@ -93,24 +85,19 @@ pub(crate) unsafe fn init(config: Config) {
while RCC.cfgr().read().sws() != Sw::MSI {} while RCC.cfgr().read().sws() != Sw::MSI {}
} }
//BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default())); let rtc = config.ls.init();
PWR.cr1().modify(|w| w.set_vos(stm32_metapac::pwr::vals::Vos::RANGE0)); PWR.cr1().modify(|w| w.set_vos(stm32_metapac::pwr::vals::Vos::RANGE0));
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
ClockSrc::MSI(range) => { ClockSrc::MSI(range) => {
// Enable MSI // Enable MSI
RCC.cr().write(|w| { RCC.cr().write(|w| {
let bits: Msirange = range.into(); w.set_msirange(range);
w.set_msirange(bits);
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msion(true); w.set_msion(true);
if config.rtc_mux == RtcClockSource::LSE {
// If LSE is enabled, enable calibration of MSI // If LSE is enabled, enable calibration of MSI
w.set_msipllen(true); w.set_msipllen(config.ls.lse.is_some());
} else {
w.set_msipllen(false);
}
}); });
while !RCC.cr().read().msirdy() {} while !RCC.cr().read().msirdy() {}
@ -153,8 +140,7 @@ pub(crate) unsafe fn init(config: Config) {
PLLSource::MSI(range) => { PLLSource::MSI(range) => {
// Enable MSI // Enable MSI
RCC.cr().write(|w| { RCC.cr().write(|w| {
let bits: Msirange = range.into(); w.set_msirange(range);
w.set_msirange(bits);
w.set_msipllen(false); // should be turned on if LSE is started w.set_msipllen(false); // should be turned on if LSE is started
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msion(true); w.set_msion(true);
@ -250,9 +236,9 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(config.ahb_pre.into()); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
let ahb_freq = sys_clk / config.ahb_pre; let ahb_freq = sys_clk / config.ahb_pre;
@ -282,6 +268,7 @@ pub(crate) unsafe fn init(config: Config) {
apb2: apb2_freq, apb2: apb2_freq,
apb1_tim: apb1_tim_freq, apb1_tim: apb1_tim_freq,
apb2_tim: apb2_tim_freq, apb2_tim: apb2_tim_freq,
rtc,
}); });
} }

View File

@ -2,11 +2,11 @@
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
pub use crate::rcc::bd::RtcClockSource;
use crate::time::Hertz; use crate::time::Hertz;
pub(crate) mod bd; mod bd;
mod mco; mod mco;
pub use bd::*;
pub use mco::*; pub use mco::*;
#[cfg_attr(rcc_f0, path = "f0.rs")] #[cfg_attr(rcc_f0, path = "f0.rs")]
@ -19,8 +19,7 @@ pub use mco::*;
#[cfg_attr(rcc_g0, path = "g0.rs")] #[cfg_attr(rcc_g0, path = "g0.rs")]
#[cfg_attr(rcc_g4, path = "g4.rs")] #[cfg_attr(rcc_g4, path = "g4.rs")]
#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")] #[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")]
#[cfg_attr(rcc_l0, path = "l0.rs")] #[cfg_attr(any(rcc_l0, rcc_l0_v2, rcc_l1), path = "l0l1.rs")]
#[cfg_attr(rcc_l1, path = "l1.rs")]
#[cfg_attr(rcc_l4, path = "l4.rs")] #[cfg_attr(rcc_l4, path = "l4.rs")]
#[cfg_attr(rcc_l5, path = "l5.rs")] #[cfg_attr(rcc_l5, path = "l5.rs")]
#[cfg_attr(rcc_u5, path = "u5.rs")] #[cfg_attr(rcc_u5, path = "u5.rs")]
@ -28,9 +27,10 @@ pub use mco::*;
#[cfg_attr(rcc_wba, path = "wba.rs")] #[cfg_attr(rcc_wba, path = "wba.rs")]
#[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")] #[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")]
mod _version; mod _version;
pub use _version::*;
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]
use atomic_polyfill::{AtomicU32, Ordering}; use core::sync::atomic::{AtomicU32, Ordering};
pub use _version::*;
// Model Clock Configuration // Model Clock Configuration
// //
@ -133,14 +133,8 @@ pub struct Clocks {
#[cfg(stm32f334)] #[cfg(stm32f334)]
pub hrtim: Option<Hertz>, pub hrtim: Option<Hertz>,
#[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7rm0433, rcc_h7ab))]
/// Set only if the lsi or lse is configured, indicates stop is supported
pub rtc: Option<Hertz>, pub rtc: Option<Hertz>,
#[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_h7, rcc_h7rm0433, rcc_h7ab))]
/// Set if the hse is configured, indicates stop is not supported
pub rtc_hse: Option<Hertz>,
#[cfg(stm32h5)] #[cfg(stm32h5)]
pub mux_rcc_pclk1: Option<Hertz>, pub mux_rcc_pclk1: Option<Hertz>,
#[cfg(stm32h5)] #[cfg(stm32h5)]
@ -198,14 +192,17 @@ pub fn low_power_ready() -> bool {
} }
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]
pub(crate) fn clock_refcount_add() { pub(crate) fn clock_refcount_add(_cs: critical_section::CriticalSection) {
// We don't check for overflow because constructing more than u32 peripherals is unlikely // We don't check for overflow because constructing more than u32 peripherals is unlikely
CLOCK_REFCOUNT.fetch_add(1, Ordering::Relaxed); let n = CLOCK_REFCOUNT.load(Ordering::Relaxed);
CLOCK_REFCOUNT.store(n + 1, Ordering::Relaxed);
} }
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]
pub(crate) fn clock_refcount_sub() { pub(crate) fn clock_refcount_sub(_cs: critical_section::CriticalSection) {
assert!(CLOCK_REFCOUNT.fetch_sub(1, Ordering::Relaxed) != 0); let n = CLOCK_REFCOUNT.load(Ordering::Relaxed);
assert!(n != 0);
CLOCK_REFCOUNT.store(n - 1, Ordering::Relaxed);
} }
/// Frozen clock frequencies /// Frozen clock frequencies
@ -213,14 +210,6 @@ pub(crate) fn clock_refcount_sub() {
/// The existence of this value indicates that the clock configuration can no longer be changed /// The existence of this value indicates that the clock configuration can no longer be changed
static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit(); static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
#[cfg(stm32wb)]
/// RCC initialization function
pub(crate) unsafe fn init(config: Config) {
set_freqs(compute_clocks(&config));
configure_clocks(&config);
}
/// Sets the clock frequencies /// Sets the clock frequencies
/// ///
/// Safety: Sets a mutable global. /// Safety: Sets a mutable global.

View File

@ -7,9 +7,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); 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::pwr::vals::Vos as VoltageScale;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -111,7 +108,6 @@ impl Into<Sw> for ClockSrc {
} }
} }
#[derive(Copy, Clone)]
pub struct Config { pub struct Config {
pub mux: ClockSrc, pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler, pub ahb_pre: AHBPrescaler,
@ -125,6 +121,7 @@ pub struct Config {
/// ///
/// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits. /// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits.
pub voltage_range: VoltageScale, pub voltage_range: VoltageScale,
pub ls: super::LsConfig,
} }
impl Config { impl Config {
@ -193,6 +190,7 @@ impl Default for Config {
apb3_pre: APBPrescaler::DIV1, apb3_pre: APBPrescaler::DIV1,
hsi48: false, hsi48: false,
voltage_range: VoltageScale::RANGE3, voltage_range: VoltageScale::RANGE3,
ls: Default::default(),
} }
} }
} }
@ -434,6 +432,8 @@ pub(crate) unsafe fn init(config: Config) {
} }
}; };
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
ahb1: ahb_freq, ahb1: ahb_freq,
@ -444,6 +444,7 @@ pub(crate) unsafe fn init(config: Config) {
apb3: apb3_freq, apb3: apb3_freq,
apb1_tim: apb1_tim_freq, apb1_tim: apb1_tim_freq,
apb2_tim: apb2_tim_freq, apb2_tim: apb2_tim_freq,
rtc,
}); });
} }

View File

@ -1,118 +1,45 @@
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; pub use crate::pac::rcc::vals::{
use crate::rcc::bd::{BackupDomain, RtcClockSource}; Hpre as AHBPrescaler, Hsepre as HsePrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Pllsrc as PllSource,
use crate::rcc::Clocks; Ppre as APBPrescaler, Sw as Sysclk,
use crate::time::{khz, mhz, Hertz}; };
use crate::rcc::{set_freqs, Clocks};
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, use crate::time::{mhz, Hertz};
/// and with the addition of the init function to configure a system clock.
/// Only the basic setup using the HSE and HSI clocks are supported as of now.
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
#[derive(Clone, Copy)]
pub enum HsePrescaler {
NotDivided,
Div2,
}
impl From<HsePrescaler> for bool {
fn from(value: HsePrescaler) -> Self {
match value {
HsePrescaler::NotDivided => false,
HsePrescaler::Div2 => true,
}
}
}
pub struct Hse { pub struct Hse {
pub prediv: HsePrescaler, pub prediv: HsePrescaler,
pub frequency: Hertz, pub frequency: Hertz,
} }
/// System clock mux source
#[derive(Clone, Copy, PartialEq)]
pub enum Sysclk {
/// MSI selected as sysclk
MSI,
/// HSI selected as sysclk
HSI,
/// HSE selected as sysclk
HSE,
/// PLL selected as sysclk
Pll,
}
impl From<Sysclk> for u8 {
fn from(value: Sysclk) -> Self {
match value {
Sysclk::MSI => 0b00,
Sysclk::HSI => 0b01,
Sysclk::HSE => 0b10,
Sysclk::Pll => 0b11,
}
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum PllSource {
Hsi,
Msi,
Hse,
}
impl From<PllSource> for u8 {
fn from(value: PllSource) -> Self {
match value {
PllSource::Msi => 0b01,
PllSource::Hsi => 0b10,
PllSource::Hse => 0b11,
}
}
}
pub enum Pll48Source {
PllSai,
Pll,
Msi,
Hsi48,
}
pub struct PllMux { pub struct PllMux {
/// Source clock selection. /// Source clock selection.
pub source: PllSource, pub source: PllSource,
/// PLL pre-divider (DIVM). Must be between 1 and 63. /// PLL pre-divider (DIVM). Must be between 1 and 63.
pub prediv: u8, pub prediv: Pllm,
} }
pub struct Pll { pub struct Pll {
/// PLL multiplication factor. Must be between 4 and 512. /// PLL multiplication factor. Must be between 4 and 512.
pub mul: u16, pub mul: Plln,
/// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128. /// 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.) /// On PLL1, it must be even (in particular, it cannot be 1.)
pub divp: Option<u16>, pub divp: Option<Pllp>,
/// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128. /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
pub divq: Option<u16>, pub divq: Option<Pllq>,
/// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128. /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
pub divr: Option<u16>, pub divr: Option<Pllr>,
} }
/// Clocks configutation /// Clocks configutation
pub struct Config { pub struct Config {
pub hse: Option<Hse>, pub hse: Option<Hse>,
pub lse: Option<Hertz>,
pub lsi: bool,
pub sys: Sysclk, pub sys: Sysclk,
pub mux: Option<PllMux>, pub mux: Option<PllMux>,
pub pll48: Option<Pll48Source>,
pub rtc: Option<RtcClockSource>,
pub pll: Option<Pll>, pub pll: Option<Pll>,
pub pllsai: Option<Pll>, pub pllsai: Option<Pll>,
@ -122,28 +49,28 @@ pub struct Config {
pub ahb3_pre: AHBPrescaler, pub ahb3_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler, pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler, pub apb2_pre: APBPrescaler,
pub ls: super::LsConfig,
} }
pub const WPAN_DEFAULT: Config = Config { pub const WPAN_DEFAULT: Config = Config {
hse: Some(Hse { hse: Some(Hse {
frequency: mhz(32), frequency: mhz(32),
prediv: HsePrescaler::NotDivided, prediv: HsePrescaler::DIV1,
}), }),
lse: Some(khz(32)), sys: Sysclk::PLL,
sys: Sysclk::Pll,
mux: Some(PllMux { mux: Some(PllMux {
source: PllSource::Hse, source: PllSource::HSE,
prediv: 2, prediv: Pllm::DIV2,
}), }),
pll48: None,
rtc: Some(RtcClockSource::LSE), ls: super::LsConfig::default_lse(),
lsi: false,
pll: Some(Pll { pll: Some(Pll {
mul: 12, mul: Plln::MUL12,
divp: Some(3), divp: Some(Pllp::DIV3),
divq: Some(4), divq: Some(Pllq::DIV4),
divr: Some(3), divr: Some(Pllr::DIV3),
}), }),
pllsai: None, pllsai: None,
@ -159,14 +86,12 @@ impl Default for Config {
fn default() -> Config { fn default() -> Config {
Config { Config {
hse: None, hse: None,
lse: None, sys: Sysclk::HSI16,
sys: Sysclk::HSI,
mux: None, mux: None,
pll48: None,
pll: None, pll: None,
pllsai: None, pllsai: None,
rtc: None,
lsi: false, ls: Default::default(),
ahb1_pre: AHBPrescaler::DIV1, ahb1_pre: AHBPrescaler::DIV1,
ahb2_pre: AHBPrescaler::DIV1, ahb2_pre: AHBPrescaler::DIV1,
@ -177,16 +102,15 @@ impl Default for Config {
} }
} }
pub(crate) fn compute_clocks(config: &Config) -> Clocks { #[cfg(stm32wb)]
let hse_clk = config.hse.as_ref().map(|hse| match hse.prediv { /// RCC initialization function
HsePrescaler::NotDivided => hse.frequency, pub(crate) unsafe fn init(config: Config) {
HsePrescaler::Div2 => hse.frequency / 2u32, let hse_clk = config.hse.as_ref().map(|hse| hse.frequency / hse.prediv);
});
let mux_clk = config.mux.as_ref().map(|pll_mux| { let mux_clk = config.mux.as_ref().map(|pll_mux| {
(match pll_mux.source { (match pll_mux.source {
PllSource::Hse => hse_clk.unwrap(), PllSource::HSE => hse_clk.unwrap(),
PllSource::Hsi => HSI_FREQ, PllSource::HSI16 => HSI_FREQ,
_ => unreachable!(), _ => unreachable!(),
} / pll_mux.prediv) } / pll_mux.prediv)
}); });
@ -206,44 +130,19 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
let sys_clk = match config.sys { let sys_clk = match config.sys {
Sysclk::HSE => hse_clk.unwrap(), Sysclk::HSE => hse_clk.unwrap(),
Sysclk::HSI => HSI_FREQ, Sysclk::HSI16 => HSI_FREQ,
Sysclk::Pll => pll_r.unwrap(), Sysclk::PLL => pll_r.unwrap(),
_ => unreachable!(), _ => unreachable!(),
}; };
let ahb1_clk = match config.ahb1_pre { let ahb1_clk = sys_clk / config.ahb1_pre;
AHBPrescaler::DIV1 => sys_clk, let ahb2_clk = sys_clk / config.ahb2_pre;
pre => { let ahb3_clk = sys_clk / config.ahb3_pre;
let pre: u8 = pre.into();
let pre = 1u32 << (pre as u32 - 7);
sys_clk / pre
}
};
let ahb2_clk = match config.ahb2_pre {
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1u32 << (pre as u32 - 7);
sys_clk / pre
}
};
let ahb3_clk = match config.ahb3_pre {
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1u32 << (pre as u32 - 7);
sys_clk / pre
}
};
let (apb1_clk, apb1_tim_clk) = match config.apb1_pre { let (apb1_clk, apb1_tim_clk) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk),
pre => { pre => {
let pre: u8 = pre.into(); let freq = ahb1_clk / pre;
let pre: u8 = 1 << (pre - 3);
let freq = ahb1_clk / pre as u32;
(freq, freq * 2u32) (freq, freq * 2u32)
} }
}; };
@ -251,43 +150,20 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
let (apb2_clk, apb2_tim_clk) = match config.apb2_pre { let (apb2_clk, apb2_tim_clk) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk),
pre => { pre => {
let pre: u8 = pre.into(); let freq = ahb1_clk / pre;
let pre: u8 = 1 << (pre - 3);
let freq = ahb1_clk / pre as u32;
(freq, freq * 2u32) (freq, freq * 2u32)
} }
}; };
let rtc_clk = match config.rtc {
Some(RtcClockSource::LSI) => Some(LSI_FREQ),
Some(RtcClockSource::LSE) => Some(config.lse.unwrap()),
_ => None,
};
Clocks {
sys: sys_clk,
ahb1: ahb1_clk,
ahb2: ahb2_clk,
ahb3: ahb3_clk,
apb1: apb1_clk,
apb2: apb2_clk,
apb1_tim: apb1_tim_clk,
apb2_tim: apb2_tim_clk,
rtc: rtc_clk,
rtc_hse: None,
}
}
pub(crate) fn configure_clocks(config: &Config) {
let rcc = crate::pac::RCC; let rcc = crate::pac::RCC;
let needs_hsi = if let Some(pll_mux) = &config.mux { let needs_hsi = if let Some(pll_mux) = &config.mux {
pll_mux.source == PllSource::Hsi pll_mux.source == PllSource::HSI16
} else { } else {
false false
}; };
if needs_hsi || config.sys == Sysclk::HSI { if needs_hsi || config.sys == Sysclk::HSI16 {
rcc.cr().modify(|w| { rcc.cr().modify(|w| {
w.set_hsion(true); w.set_hsion(true);
}); });
@ -297,16 +173,12 @@ pub(crate) fn configure_clocks(config: &Config) {
rcc.cfgr().modify(|w| w.set_stopwuck(true)); rcc.cfgr().modify(|w| w.set_stopwuck(true));
BackupDomain::configure_ls( let rtc = config.ls.init();
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
match &config.hse { match &config.hse {
Some(hse) => { Some(hse) => {
rcc.cr().modify(|w| { rcc.cr().modify(|w| {
w.set_hsepre(hse.prediv.into()); w.set_hsepre(hse.prediv);
w.set_hseon(true); w.set_hseon(true);
}); });
@ -328,18 +200,18 @@ pub(crate) fn configure_clocks(config: &Config) {
match &config.pll { match &config.pll {
Some(pll) => { Some(pll) => {
rcc.pllcfgr().modify(|w| { rcc.pllcfgr().modify(|w| {
w.set_plln(pll.mul as u8); w.set_plln(pll.mul);
pll.divp.map(|divp| { pll.divp.map(|divp| {
w.set_pllpen(true); w.set_pllpen(true);
w.set_pllp((divp - 1) as u8) w.set_pllp(divp)
}); });
pll.divq.map(|divq| { pll.divq.map(|divq| {
w.set_pllqen(true); w.set_pllqen(true);
w.set_pllq((divq - 1) as u8) w.set_pllq(divq)
}); });
pll.divr.map(|divr| { pll.divr.map(|divr| {
// w.set_pllren(true); w.set_pllren(true);
w.set_pllr((divr - 1) as u8); w.set_pllr(divr);
}); });
}); });
@ -352,13 +224,25 @@ pub(crate) fn configure_clocks(config: &Config) {
rcc.cfgr().modify(|w| { rcc.cfgr().modify(|w| {
w.set_sw(config.sys.into()); w.set_sw(config.sys.into());
w.set_hpre(config.ahb1_pre.into()); w.set_hpre(config.ahb1_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
rcc.extcfgr().modify(|w| { rcc.extcfgr().modify(|w| {
w.set_c2hpre(config.ahb2_pre.into()); w.set_c2hpre(config.ahb2_pre);
w.set_shdhpre(config.ahb3_pre.into()); w.set_shdhpre(config.ahb3_pre);
}); });
set_freqs(Clocks {
sys: sys_clk,
ahb1: ahb1_clk,
ahb2: ahb2_clk,
ahb3: ahb3_clk,
apb1: apb1_clk,
apb2: apb2_clk,
apb1_tim: apb1_tim_clk,
apb2_tim: apb2_tim_clk,
rtc,
})
} }

View File

@ -7,9 +7,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); 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::pwr::vals::Vos as VoltageScale;
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
@ -28,7 +25,7 @@ pub enum PllSrc {
impl Into<Pllsrc> for PllSrc { impl Into<Pllsrc> for PllSrc {
fn into(self) -> Pllsrc { fn into(self) -> Pllsrc {
match self { match self {
PllSrc::HSE(..) => Pllsrc::HSE32, PllSrc::HSE(..) => Pllsrc::HSE,
PllSrc::HSI16 => Pllsrc::HSI16, PllSrc::HSI16 => Pllsrc::HSI16,
} }
} }
@ -37,19 +34,19 @@ impl Into<Pllsrc> for PllSrc {
impl Into<Sw> for ClockSrc { impl Into<Sw> for ClockSrc {
fn into(self) -> Sw { fn into(self) -> Sw {
match self { match self {
ClockSrc::HSE(..) => Sw::HSE32, ClockSrc::HSE(..) => Sw::HSE,
ClockSrc::HSI16 => Sw::HSI16, ClockSrc::HSI16 => Sw::HSI16,
} }
} }
} }
#[derive(Copy, Clone)]
pub struct Config { pub struct Config {
pub mux: ClockSrc, pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler, pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler, pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler, pub apb2_pre: APBPrescaler,
pub apb7_pre: APBPrescaler, pub apb7_pre: APBPrescaler,
pub ls: super::LsConfig,
} }
impl Default for Config { impl Default for Config {
@ -60,6 +57,7 @@ impl Default for Config {
apb1_pre: APBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
apb7_pre: APBPrescaler::DIV1, apb7_pre: APBPrescaler::DIV1,
ls: Default::default(),
} }
} }
} }
@ -108,13 +106,13 @@ pub(crate) unsafe fn init(config: Config) {
}); });
RCC.cfgr2().modify(|w| { RCC.cfgr2().modify(|w| {
w.set_hpre(config.ahb_pre.into()); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
RCC.cfgr3().modify(|w| { RCC.cfgr3().modify(|w| {
w.set_ppre7(config.apb7_pre.into()); w.set_ppre7(config.apb7_pre);
}); });
let ahb_freq = sys_clk / config.ahb_pre; let ahb_freq = sys_clk / config.ahb_pre;
@ -140,6 +138,8 @@ pub(crate) unsafe fn init(config: Config) {
} }
}; };
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
ahb1: ahb_freq, ahb1: ahb_freq,
@ -150,5 +150,6 @@ pub(crate) unsafe fn init(config: Config) {
apb7: apb7_freq, apb7: apb7_freq,
apb1_tim: apb1_tim_freq, apb1_tim: apb1_tim_freq,
apb2_tim: apb2_tim_freq, apb2_tim: apb2_tim_freq,
rtc,
}); });
} }

View File

@ -1,136 +1,27 @@
pub use crate::pac::pwr::vals::Vos as VoltageScale; pub use crate::pac::pwr::vals::Vos as VoltageScale;
use crate::pac::rcc::vals::Adcsel; use crate::pac::rcc::vals::Sw;
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; pub use crate::pac::rcc::vals::{
Adcsel as AdcClockSource, Hpre as AHBPrescaler, Msirange as MSIRange, Pllm, Plln, Pllp, Pllq, Pllr,
Pllsrc as PllSource, Ppre as APBPrescaler,
};
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
/// and with the addition of the init function to configure a system clock.
/// Only the basic setup using the HSE and HSI clocks are supported as of now.
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed /// HSE speed
pub const LSI_FREQ: Hertz = Hertz(32_000); pub const HSE_FREQ: Hertz = Hertz(32_000_000);
/// HSE32 speed
pub const HSE32_FREQ: Hertz = Hertz(32_000_000);
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
MSI(MSIRange), MSI(MSIRange),
HSE32, HSE,
HSI16, HSI16,
} }
#[derive(Clone, Copy, PartialOrd, PartialEq)]
pub enum MSIRange {
/// Around 100 kHz
Range0,
/// Around 200 kHz
Range1,
/// Around 400 kHz
Range2,
/// Around 800 kHz
Range3,
/// Around 1 MHz
Range4,
/// Around 2 MHz
Range5,
/// Around 4 MHz (reset value)
Range6,
/// Around 8 MHz
Range7,
/// Around 16 MHz
Range8,
/// Around 24 MHz
Range9,
/// Around 32 MHz
Range10,
/// Around 48 MHz
Range11,
}
impl MSIRange {
fn freq(&self) -> u32 {
match self {
MSIRange::Range0 => 100_000,
MSIRange::Range1 => 200_000,
MSIRange::Range2 => 400_000,
MSIRange::Range3 => 800_000,
MSIRange::Range4 => 1_000_000,
MSIRange::Range5 => 2_000_000,
MSIRange::Range6 => 4_000_000,
MSIRange::Range7 => 8_000_000,
MSIRange::Range8 => 16_000_000,
MSIRange::Range9 => 24_000_000,
MSIRange::Range10 => 32_000_000,
MSIRange::Range11 => 48_000_000,
}
}
fn vos(&self) -> VoltageScale {
if self > &MSIRange::Range8 {
VoltageScale::RANGE1
} else {
VoltageScale::RANGE2
}
}
}
impl Default for MSIRange {
fn default() -> MSIRange {
MSIRange::Range6
}
}
impl Into<u8> for MSIRange {
fn into(self) -> u8 {
match self {
MSIRange::Range0 => 0b0000,
MSIRange::Range1 => 0b0001,
MSIRange::Range2 => 0b0010,
MSIRange::Range3 => 0b0011,
MSIRange::Range4 => 0b0100,
MSIRange::Range5 => 0b0101,
MSIRange::Range6 => 0b0110,
MSIRange::Range7 => 0b0111,
MSIRange::Range8 => 0b1000,
MSIRange::Range9 => 0b1001,
MSIRange::Range10 => 0b1010,
MSIRange::Range11 => 0b1011,
}
}
}
#[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 /// Clocks configutation
pub struct Config { pub struct Config {
pub mux: ClockSrc, pub mux: ClockSrc,
@ -138,91 +29,60 @@ pub struct Config {
pub shd_ahb_pre: AHBPrescaler, pub shd_ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler, pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler, pub apb2_pre: APBPrescaler,
pub rtc_mux: RtcClockSource,
pub lse: Option<Hertz>,
pub lsi: bool,
pub adc_clock_source: AdcClockSource, pub adc_clock_source: AdcClockSource,
pub ls: super::LsConfig,
} }
impl Default for Config { impl Default for Config {
#[inline] #[inline]
fn default() -> Config { fn default() -> Config {
Config { Config {
mux: ClockSrc::MSI(MSIRange::default()), mux: ClockSrc::MSI(MSIRange::RANGE4M),
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
shd_ahb_pre: AHBPrescaler::DIV1, shd_ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
rtc_mux: RtcClockSource::LSI, adc_clock_source: AdcClockSource::HSI16,
lsi: true, ls: Default::default(),
lse: None,
adc_clock_source: AdcClockSource::default(),
} }
} }
} }
#[repr(u8)]
pub enum Lsedrv {
Low = 0,
MediumLow = 1,
MediumHigh = 2,
High = 3,
}
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw, vos) = match config.mux { let (sys_clk, sw, vos) = match config.mux {
ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::RANGE2), ClockSrc::HSI16 => (HSI_FREQ, Sw::HSI16, VoltageScale::RANGE2),
ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::RANGE1), ClockSrc::HSE => (HSE_FREQ, Sw::HSE, VoltageScale::RANGE1),
ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()), ClockSrc::MSI(range) => (msirange_to_hertz(range), Sw::MSI, msirange_to_vos(range)),
}; };
let ahb_freq: u32 = match config.ahb_pre { let ahb_freq = sys_clk / config.ahb_pre;
AHBPrescaler::DIV1 => sys_clk, let shd_ahb_freq = sys_clk / config.shd_ahb_pre;
pre => {
let pre: u8 = pre.into();
let pre = 1 << (pre as u32 - 7);
sys_clk / pre
}
};
let shd_ahb_freq: u32 = match config.shd_ahb_pre {
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1 << (pre as u32 - 7);
sys_clk / pre
}
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let pre: u8 = pre.into(); let freq = ahb_freq / pre;
let pre: u8 = 1 << (pre - 3); (freq, freq * 2u32)
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let pre: u8 = pre.into(); let freq = ahb_freq / pre;
let pre: u8 = 1 << (pre - 3); (freq, freq * 2u32)
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
// Adjust flash latency // Adjust flash latency
let flash_clk_src_freq: u32 = shd_ahb_freq; let flash_clk_src_freq = shd_ahb_freq;
let ws = match vos { let ws = match vos {
VoltageScale::RANGE1 => match flash_clk_src_freq { VoltageScale::RANGE1 => match flash_clk_src_freq.0 {
0..=18_000_000 => 0b000, 0..=18_000_000 => 0b000,
18_000_001..=36_000_000 => 0b001, 18_000_001..=36_000_000 => 0b001,
_ => 0b010, _ => 0b010,
}, },
VoltageScale::RANGE2 => match flash_clk_src_freq { VoltageScale::RANGE2 => match flash_clk_src_freq.0 {
0..=6_000_000 => 0b000, 0..=6_000_000 => 0b000,
6_000_001..=12_000_000 => 0b001, 6_000_001..=12_000_000 => 0b001,
_ => 0b010, _ => 0b010,
@ -236,17 +96,14 @@ pub(crate) unsafe fn init(config: Config) {
while FLASH.acr().read().latency() != ws {} while FLASH.acr().read().latency() != ws {}
// Enables the LSI if configured
BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default()));
match config.mux { match config.mux {
ClockSrc::HSI16 => { ClockSrc::HSI16 => {
// Enable HSI16 // Enable HSI16
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
} }
ClockSrc::HSE32 => { ClockSrc::HSE => {
// Enable HSE32 // Enable HSE
RCC.cr().write(|w| { RCC.cr().write(|w| {
w.set_hsebyppwr(true); w.set_hsebyppwr(true);
w.set_hseon(true); w.set_hseon(true);
@ -258,49 +115,70 @@ pub(crate) unsafe fn init(config: Config) {
assert!(!cr.msion() || cr.msirdy()); assert!(!cr.msion() || cr.msirdy());
RCC.cr().write(|w| { RCC.cr().write(|w| {
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msirange(range.into()); w.set_msirange(range);
w.set_msion(true); w.set_msion(true);
if config.rtc_mux == RtcClockSource::LSE {
// If LSE is enabled, enable calibration of MSI // If LSE is enabled, enable calibration of MSI
w.set_msipllen(true); w.set_msipllen(config.ls.lse.is_some());
} else {
w.set_msipllen(false);
}
}); });
while !RCC.cr().read().msirdy() {} while !RCC.cr().read().msirdy() {}
} }
} }
RCC.extcfgr().modify(|w| { RCC.extcfgr().modify(|w| {
if config.shd_ahb_pre == AHBPrescaler::DIV1 { w.set_shdhpre(config.shd_ahb_pre);
w.set_shdhpre(0);
} else {
w.set_shdhpre(config.shd_ahb_pre.into());
}
}); });
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw.into()); w.set_sw(sw.into());
w.set_hpre(config.ahb_pre); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
// ADC clock MUX // ADC clock MUX
RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel())); RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source));
// TODO: switch voltage range // TODO: switch voltage range
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sys_clk), sys: sys_clk,
ahb1: Hertz(ahb_freq), ahb1: ahb_freq,
ahb2: Hertz(ahb_freq), ahb2: ahb_freq,
ahb3: Hertz(shd_ahb_freq), ahb3: shd_ahb_freq,
apb1: Hertz(apb1_freq), apb1: apb1_freq,
apb2: Hertz(apb2_freq), apb2: apb2_freq,
apb3: Hertz(shd_ahb_freq), apb3: shd_ahb_freq,
apb1_tim: Hertz(apb1_tim_freq), apb1_tim: apb1_tim_freq,
apb2_tim: Hertz(apb2_tim_freq), apb2_tim: apb2_tim_freq,
rtc,
}); });
} }
fn msirange_to_hertz(range: MSIRange) -> Hertz {
match range {
MSIRange::RANGE100K => Hertz(100_000),
MSIRange::RANGE200K => Hertz(200_000),
MSIRange::RANGE400K => Hertz(400_000),
MSIRange::RANGE800K => Hertz(800_000),
MSIRange::RANGE1M => Hertz(1_000_000),
MSIRange::RANGE2M => Hertz(2_000_000),
MSIRange::RANGE4M => Hertz(4_000_000),
MSIRange::RANGE8M => Hertz(8_000_000),
MSIRange::RANGE16M => Hertz(16_000_000),
MSIRange::RANGE24M => Hertz(24_000_000),
MSIRange::RANGE32M => Hertz(32_000_000),
MSIRange::RANGE48M => Hertz(48_000_000),
_ => unreachable!(),
}
}
fn msirange_to_vos(range: MSIRange) -> VoltageScale {
if range.to_bits() > MSIRange::RANGE16M.to_bits() {
VoltageScale::RANGE1
} else {
VoltageScale::RANGE2
}
}

View File

@ -10,7 +10,6 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::blocking_mutex::Mutex; use embassy_sync::blocking_mutex::Mutex;
pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
pub use crate::rcc::RtcClockSource;
use crate::time::Hertz; use crate::time::Hertz;
/// refer to AN4759 to compare features of RTC2 and RTC3 /// refer to AN4759 to compare features of RTC2 and RTC3
@ -184,7 +183,7 @@ impl Default for RtcCalibrationCyclePeriod {
impl Rtc { impl Rtc {
pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { 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))] #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
<RTC as crate::rcc::sealed::RccPeripheral>::enable(); <RTC as crate::rcc::sealed::RccPeripheral>::enable();
let mut this = Self { let mut this = Self {
@ -204,19 +203,8 @@ impl Rtc {
} }
fn frequency() -> Hertz { fn frequency() -> Hertz {
#[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab))]
let freqs = unsafe { crate::rcc::get_freqs() }; let freqs = unsafe { crate::rcc::get_freqs() };
freqs.rtc.unwrap()
// Load the clock frequency from the rcc mod, if supported
#[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab))]
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, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab)))]
Hertz(32_768)
} }
/// Acquire a [`RtcTimeProvider`] instance. /// Acquire a [`RtcTimeProvider`] instance.

View File

@ -77,3 +77,10 @@ impl Div<u8> for Hertz {
self / (rhs as u32) self / (rhs as u32)
} }
} }
impl Div<Hertz> for Hertz {
type Output = u32;
fn div(self, rhs: Hertz) -> Self::Output {
self.0 / rhs.0
}
}

View File

@ -1,9 +1,8 @@
use core::cell::Cell; use core::cell::Cell;
use core::convert::TryInto; use core::convert::TryInto;
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering};
use core::{mem, ptr}; use core::{mem, ptr};
use atomic_polyfill::{AtomicU32, AtomicU8};
use critical_section::CriticalSection; use critical_section::CriticalSection;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::blocking_mutex::Mutex; use embassy_sync::blocking_mutex::Mutex;
@ -229,7 +228,9 @@ impl RtcDriver {
fn next_period(&self) { fn next_period(&self) {
let r = T::regs_gp16(); let r = T::regs_gp16();
let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; // We only modify the period from the timer interrupt, so we know this can't race.
let period = self.period.load(Ordering::Relaxed) + 1;
self.period.store(period, Ordering::Relaxed);
let t = (period as u64) << 15; let t = (period as u64) << 15;
critical_section::with(move |cs| { critical_section::with(move |cs| {
@ -403,18 +404,15 @@ impl Driver for RtcDriver {
} }
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> { unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { critical_section::with(|_| {
if x < ALARM_COUNT as u8 { let id = self.alarm_count.load(Ordering::Relaxed);
Some(x + 1) if id < ALARM_COUNT as u8 {
self.alarm_count.store(id + 1, Ordering::Relaxed);
Some(AlarmHandle::new(id))
} else { } else {
None None
} }
}); })
match id {
Ok(id) => Some(AlarmHandle::new(id)),
Err(_) => None,
}
} }
fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {

View File

@ -218,7 +218,6 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional =
embedded-hal-async = { version = "=1.0.0-rc.1", optional = true} embedded-hal-async = { version = "=1.0.0-rc.1", optional = true}
futures-util = { version = "0.3.17", default-features = false } futures-util = { version = "0.3.17", default-features = false }
atomic-polyfill = "1.0.1"
critical-section = "1.1" critical-section = "1.1"
cfg-if = "1.0.0" cfg-if = "1.0.0"
heapless = "0.7" heapless = "0.7"

View File

@ -6,7 +6,7 @@ use defmt::info;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::adc::{Adc, SampleTime};
use embassy_stm32::peripherals::ADC1; use embassy_stm32::peripherals::ADC1;
use embassy_stm32::rcc::AdcClockSource; use embassy_stm32::rcc::{AdcClockSource, Adcpres};
use embassy_stm32::time::mhz; use embassy_stm32::time::mhz;
use embassy_stm32::{adc, bind_interrupts, Config}; use embassy_stm32::{adc, bind_interrupts, Config};
use embassy_time::{Delay, Duration, Timer}; use embassy_time::{Delay, Duration, Timer};
@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) -> ! {
config.rcc.hclk = Some(mhz(64)); config.rcc.hclk = Some(mhz(64));
config.rcc.pclk1 = Some(mhz(32)); config.rcc.pclk1 = Some(mhz(32));
config.rcc.pclk2 = Some(mhz(64)); config.rcc.pclk2 = Some(mhz(64));
config.rcc.adc = Some(AdcClockSource::PllDiv1); config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1));
let mut p = embassy_stm32::init(config); let mut p = embassy_stm32::init(config);

View File

@ -7,7 +7,7 @@ use embassy_executor::Spawner;
use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::adc::{Adc, SampleTime};
use embassy_stm32::opamp::{OpAmp, OpAmpGain}; use embassy_stm32::opamp::{OpAmp, OpAmpGain};
use embassy_stm32::peripherals::ADC2; use embassy_stm32::peripherals::ADC2;
use embassy_stm32::rcc::AdcClockSource; use embassy_stm32::rcc::{AdcClockSource, Adcpres};
use embassy_stm32::time::mhz; use embassy_stm32::time::mhz;
use embassy_stm32::{adc, bind_interrupts, Config}; use embassy_stm32::{adc, bind_interrupts, Config};
use embassy_time::{Delay, Duration, Timer}; use embassy_time::{Delay, Duration, Timer};
@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) -> ! {
config.rcc.hclk = Some(mhz(64)); config.rcc.hclk = Some(mhz(64));
config.rcc.pclk1 = Some(mhz(32)); config.rcc.pclk1 = Some(mhz(32));
config.rcc.pclk2 = Some(mhz(64)); config.rcc.pclk2 = Some(mhz(64));
config.rcc.adc = Some(AdcClockSource::PllDiv1); config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1));
let mut p = embassy_stm32::init(config); let mut p = embassy_stm32::init(config);

View File

@ -58,9 +58,8 @@ async fn main(spawner: Spawner) -> ! {
p.PG13, p.PG13,
p.PB13, p.PB13,
p.PG11, p.PG11,
GenericSMI::new(), GenericSMI::new(0),
mac_addr, mac_addr,
0,
); );
let config = embassy_net::Config::dhcpv4(Default::default()); let config = embassy_net::Config::dhcpv4(Default::default());

View File

@ -5,16 +5,14 @@
use chrono::{NaiveDate, NaiveDateTime}; use chrono::{NaiveDate, NaiveDateTime};
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig}; use embassy_stm32::rtc::{Rtc, RtcConfig};
use embassy_stm32::Config; use embassy_stm32::Config;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = Config::default(); let config = Config::default();
config.rcc.lsi = true;
config.rcc.rtc = Option::Some(RtcClockSource::LSI);
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
info!("Hello World!"); info!("Hello World!");

View File

@ -59,9 +59,8 @@ async fn main(spawner: Spawner) -> ! {
p.PG13, p.PG13,
p.PB13, p.PB13,
p.PG11, p.PG11,
GenericSMI::new(), GenericSMI::new(0),
mac_addr, mac_addr,
0,
); );
let config = embassy_net::Config::dhcpv4(Default::default()); let config = embassy_net::Config::dhcpv4(Default::default());

View File

@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
div_r: Some(PllR::DIV2), div_r: Some(PllR::DIV2),
}); });
config.rcc.adc12_clock_source = AdcClockSource::SysClk; config.rcc.adc12_clock_source = AdcClockSource::SYSCLK;
config.rcc.mux = ClockSrc::PLL; config.rcc.mux = ClockSrc::PLL;
let mut p = embassy_stm32::init(config); let mut p = embassy_stm32::init(config);

View File

@ -80,9 +80,8 @@ async fn main(spawner: Spawner) -> ! {
p.PG13, p.PG13,
p.PB15, p.PB15,
p.PG11, p.PG11,
GenericSMI::new(), GenericSMI::new(0),
mac_addr, mac_addr,
0,
); );
let config = embassy_net::Config::dhcpv4(Default::default()); let config = embassy_net::Config::dhcpv4(Default::default());

View File

@ -77,9 +77,8 @@ async fn main(spawner: Spawner) -> ! {
p.PG13, p.PG13,
p.PB13, p.PB13,
p.PG11, p.PG11,
GenericSMI::new(), GenericSMI::new(0),
mac_addr, mac_addr,
0,
); );
let config = embassy_net::Config::dhcpv4(Default::default()); let config = embassy_net::Config::dhcpv4(Default::default());

View File

@ -78,9 +78,8 @@ async fn main(spawner: Spawner) -> ! {
p.PG13, p.PG13,
p.PB13, p.PB13,
p.PG11, p.PG11,
GenericSMI::new(), GenericSMI::new(0),
mac_addr, mac_addr,
0,
); );
let config = embassy_net::Config::dhcpv4(Default::default()); let config = embassy_net::Config::dhcpv4(Default::default());
@ -106,8 +105,8 @@ async fn main(spawner: Spawner) -> ! {
info!("Network task initialized"); info!("Network task initialized");
static STATE: TcpClientState<1, 1024, 1024> = TcpClientState::new(); let state: TcpClientState<1, 1024, 1024> = TcpClientState::new();
let client = TcpClient::new(&stack, &STATE); let client = TcpClient::new(&stack, &state);
loop { loop {
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(10, 42, 0, 1), 8000)); let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(10, 42, 0, 1), 8000));

View File

@ -5,20 +5,18 @@
use chrono::{NaiveDate, NaiveDateTime}; use chrono::{NaiveDate, NaiveDateTime};
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::rcc::Lse; use embassy_stm32::rcc::LsConfig;
use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig}; use embassy_stm32::rtc::{Rtc, RtcConfig};
use embassy_stm32::Config; use embassy_stm32::Config;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = {
let mut config = Config::default(); let mut config = Config::default();
config.rcc.lse = Some(Lse::Oscillator); config.rcc.ls = LsConfig::default_lse();
config.rcc.rtc_mux = Some(RtcClockSource::LSE);
embassy_stm32::init(config) let p = embassy_stm32::init(config);
};
info!("Hello World!"); info!("Hello World!");
let now = NaiveDate::from_ymd_opt(2020, 5, 15) let now = NaiveDate::from_ymd_opt(2020, 5, 15)

View File

@ -5,7 +5,7 @@
use chrono::{NaiveDate, NaiveDateTime}; use chrono::{NaiveDate, NaiveDateTime};
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::rcc::{self, ClockSrc, PLLSource, PllMul, PllPreDiv, PllRDiv}; use embassy_stm32::rcc::{ClockSrc, LsConfig, PLLSource, PllMul, PllPreDiv, PllRDiv};
use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::rtc::{Rtc, RtcConfig};
use embassy_stm32::time::Hertz; use embassy_stm32::time::Hertz;
use embassy_stm32::Config; use embassy_stm32::Config;
@ -23,8 +23,7 @@ async fn main(_spawner: Spawner) {
PllMul::MUL20, PllMul::MUL20,
None, None,
); );
config.rcc.lse = Some(Hertz(32_768)); config.rcc.ls = LsConfig::default_lse();
config.rcc.rtc_mux = rcc::RtcClockSource::LSE;
embassy_stm32::init(config) embassy_stm32::init(config)
}; };
info!("Hello World!"); info!("Hello World!");

View File

@ -32,7 +32,6 @@ use embedded_io::Write as bWrite;
use embedded_io_async::Write; use embedded_io_async::Write;
use hal::gpio::{Input, Level, Output, Speed}; use hal::gpio::{Input, Level, Output, Speed};
use hal::i2c::{self, I2c}; use hal::i2c::{self, I2c};
use hal::rcc::{self};
use hal::rng::{self, Rng}; use hal::rng::{self, Rng};
use hal::{bind_interrupts, exti, pac, peripherals}; use hal::{bind_interrupts, exti, pac, peripherals};
use heapless::Vec; use heapless::Vec;
@ -86,7 +85,6 @@ async fn main(spawner: Spawner) {
None, None,
); );
config.rcc.hsi48 = true; // needed for rng config.rcc.hsi48 = true; // needed for rng
config.rcc.rtc_mux = rcc::RtcClockSource::LSI;
let dp = embassy_stm32::init(config); let dp = embassy_stm32::init(config);

View File

@ -33,8 +33,7 @@ bind_interrupts!(struct Irqs{
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default(); let mut config = embassy_stm32::Config::default();
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE;
config.rcc.rtc_mux = embassy_stm32::rcc::RtcClockSource::LSI;
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)); pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01));

View File

@ -26,7 +26,7 @@ bind_interrupts!(struct Irqs{
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default(); let mut config = embassy_stm32::Config::default();
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE;
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2); let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2);

View File

@ -26,7 +26,7 @@ bind_interrupts!(struct Irqs{
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default(); let mut config = embassy_stm32::Config::default();
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE;
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2); let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2);

View File

@ -15,8 +15,7 @@ bind_interrupts!(struct Irqs{
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default(); let mut config = embassy_stm32::Config::default();
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE;
config.rcc.rtc_mux = embassy_stm32::rcc::RtcClockSource::LSI;
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
pac::RCC.ccipr().modify(|w| { pac::RCC.ccipr().modify(|w| {

View File

@ -5,9 +5,8 @@
use chrono::{NaiveDate, NaiveDateTime}; use chrono::{NaiveDate, NaiveDateTime};
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::rcc::ClockSrc; use embassy_stm32::rcc::{ClockSrc, LsConfig};
use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig}; use embassy_stm32::rtc::{Rtc, RtcConfig};
use embassy_stm32::time::Hertz;
use embassy_stm32::Config; use embassy_stm32::Config;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -16,9 +15,8 @@ use {defmt_rtt as _, panic_probe as _};
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = { let p = {
let mut config = Config::default(); let mut config = Config::default();
config.rcc.mux = ClockSrc::HSE32; config.rcc.mux = ClockSrc::HSE;
config.rcc.lse = Some(Hertz(32_768)); config.rcc.ls = LsConfig::default_lse();
config.rcc.rtc_mux = RtcClockSource::LSE;
embassy_stm32::init(config) embassy_stm32::init(config)
}; };
info!("Hello World!"); info!("Hello World!");

View File

@ -21,7 +21,7 @@ but can be surely changed for your needs.
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default(); let mut config = embassy_stm32::Config::default();
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE;
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
defmt::info!("Starting system"); defmt::info!("Starting system");

View File

@ -10,19 +10,19 @@ stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill
stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac-adc-pin"] # Nucleo "sdmmc" stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac-adc-pin"] # Nucleo "sdmmc"
stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma", "dac-adc-pin"] # Nucleo stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma", "dac-adc-pin"] # Nucleo
stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo
stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "not-gpdma"] # Nucleo
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac-adc-pin"] # Nucleo stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac-adc-pin"] # Nucleo
stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble", "mac" ] # Nucleo stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" ] # Nucleo
stm32h563zi = ["embassy-stm32/stm32h563zi", "eth"] # Nucleo stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth"] # Nucleo
stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono"] # IoT board
stm32l073rz = ["embassy-stm32/stm32l073rz", "not-gpdma"] # Nucleo stm32l073rz = ["embassy-stm32/stm32l073rz", "not-gpdma"] # Nucleo
stm32l152re = ["embassy-stm32/stm32l152re", "not-gpdma"] # Nucleo stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] # Nucleo
stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "not-gpdma"] # Nucleo stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma"] # Nucleo
stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "not-gpdma"] # Nucleo stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma"] # Nucleo
stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma"] # Nucleo stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma"] # Nucleo
stm32f767zi = ["embassy-stm32/stm32f767zi", "not-gpdma", "eth"] # Nucleo stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth"] # Nucleo
stm32f207zg = ["embassy-stm32/stm32f207zg", "not-gpdma", "eth"] # Nucleo stm32f207zg = ["embassy-stm32/stm32f207zg", "chrono", "not-gpdma", "eth"] # Nucleo
stm32f303ze = ["embassy-stm32/stm32f303ze", "not-gpdma"] # Nucleo stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] # Nucleo
stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma"] # Nucleo stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma"] # Nucleo
eth = [] eth = []

View File

@ -85,9 +85,8 @@ async fn main(spawner: Spawner) {
#[cfg(feature = "stm32h563zi")] #[cfg(feature = "stm32h563zi")]
p.PB15, p.PB15,
p.PG11, p.PG11,
GenericSMI::new(), GenericSMI::new(0),
mac_addr, mac_addr,
0,
); );
let config = embassy_net::Config::dhcpv4(Default::default()); let config = embassy_net::Config::dhcpv4(Default::default());

View File

@ -10,26 +10,14 @@ use chrono::{NaiveDate, NaiveDateTime};
use common::*; use common::*;
use defmt::assert; use defmt::assert;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::rcc::RtcClockSource; use embassy_stm32::rcc::LsConfig;
use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::rtc::{Rtc, RtcConfig};
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = config(); let mut config = config();
config.rcc.ls = LsConfig::default_lse();
#[cfg(feature = "stm32h755zi")]
{
use embassy_stm32::rcc::Lse;
config.rcc.lse = Some(Lse::Oscillator);
config.rcc.rtc_mux = Some(RtcClockSource::LSE);
}
#[cfg(not(feature = "stm32h755zi"))]
{
use embassy_stm32::time::Hertz;
config.rcc.lse = Some(Hertz(32_768));
config.rcc.rtc = Some(RtcClockSource::LSE);
}
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
info!("Hello World!"); info!("Hello World!");

View File

@ -11,9 +11,8 @@ use common::*;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::low_power::{stop_with_rtc, Executor}; use embassy_stm32::low_power::{stop_with_rtc, Executor};
use embassy_stm32::rcc::RtcClockSource; use embassy_stm32::rcc::LsConfig;
use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::rtc::{Rtc, RtcConfig};
use embassy_stm32::time::Hertz;
use embassy_stm32::Config; use embassy_stm32::Config;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use static_cell::make_static; use static_cell::make_static;
@ -49,9 +48,7 @@ async fn async_main(spawner: Spawner) {
let _ = config(); let _ = config();
let mut config = Config::default(); let mut config = Config::default();
config.rcc.ls = LsConfig::default_lse();
config.rcc.lse = Some(Hertz(32_768));
config.rcc.rtc = Some(RtcClockSource::LSE);
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
info!("Hello World!"); info!("Hello World!");

View File

@ -322,8 +322,8 @@ pub fn config() -> Config {
config.rcc.mux = ClockSrc::PLL( config.rcc.mux = ClockSrc::PLL(
// 32Mhz clock (16 * 4 / 2) // 32Mhz clock (16 * 4 / 2)
PLLSource::HSI16, PLLSource::HSI16,
PLLMul::Mul4, PLLMul::MUL4,
PLLDiv::Div2, PLLDiv::DIV2,
); );
} }
@ -332,9 +332,9 @@ pub fn config() -> Config {
use embassy_stm32::rcc::*; use embassy_stm32::rcc::*;
config.rcc.mux = ClockSrc::PLL( config.rcc.mux = ClockSrc::PLL(
// 32Mhz clock (16 * 4 / 2) // 32Mhz clock (16 * 4 / 2)
PLLSource::HSI, PLLSource::HSI16,
PLLMul::Mul4, PLLMul::MUL4,
PLLDiv::Div2, PLLDiv::DIV2,
); );
} }