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:
commit
0d0fbe957e
@ -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 }
|
||||||
|
@ -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" }
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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> {
|
||||||
|
@ -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();
|
||||||
|
@ -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]
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -19,8 +19,10 @@ pub(crate) unsafe fn lock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn unlock() {
|
pub(crate) unsafe fn unlock() {
|
||||||
pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123));
|
if pac::FLASH.cr().read().lock() {
|
||||||
pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
|
pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123));
|
||||||
|
pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn enable_blocking_write() {
|
pub(crate) unsafe fn enable_blocking_write() {
|
||||||
|
@ -19,8 +19,10 @@ pub(crate) unsafe fn lock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn unlock() {
|
pub(crate) unsafe fn unlock() {
|
||||||
pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123));
|
if pac::FLASH.cr().read().lock() {
|
||||||
pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
|
pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123));
|
||||||
|
pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn enable_blocking_write() {
|
pub(crate) unsafe fn enable_blocking_write() {
|
||||||
|
@ -228,8 +228,10 @@ pub(crate) unsafe fn lock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn unlock() {
|
pub(crate) unsafe fn unlock() {
|
||||||
pac::FLASH.keyr().write(|w| w.set_key(0x45670123));
|
if pac::FLASH.cr().read().lock() {
|
||||||
pac::FLASH.keyr().write(|w| w.set_key(0xCDEF89AB));
|
pac::FLASH.keyr().write(|w| w.set_key(0x45670123));
|
||||||
|
pac::FLASH.keyr().write(|w| w.set_key(0xCDEF89AB));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn enable_write() {
|
pub(crate) unsafe fn enable_write() {
|
||||||
|
@ -19,8 +19,10 @@ pub(crate) unsafe fn lock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn unlock() {
|
pub(crate) unsafe fn unlock() {
|
||||||
pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123));
|
if pac::FLASH.cr().read().lock() {
|
||||||
pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
|
pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123));
|
||||||
|
pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn enable_blocking_write() {
|
pub(crate) unsafe fn enable_blocking_write() {
|
||||||
|
@ -24,8 +24,10 @@ pub(crate) unsafe fn unlock() {
|
|||||||
while pac::FLASH.sr().read().bsy() {}
|
while pac::FLASH.sr().read().bsy() {}
|
||||||
|
|
||||||
// Unlock flash
|
// Unlock flash
|
||||||
pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123));
|
if pac::FLASH.cr().read().lock() {
|
||||||
pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB));
|
pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123));
|
||||||
|
pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn enable_blocking_write() {
|
pub(crate) unsafe fn enable_blocking_write() {
|
||||||
|
@ -26,11 +26,15 @@ pub(crate) unsafe fn lock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn unlock() {
|
pub(crate) unsafe fn unlock() {
|
||||||
pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123));
|
if pac::FLASH.bank(0).cr().read().lock() {
|
||||||
pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
|
pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123));
|
||||||
|
pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
|
||||||
|
}
|
||||||
if is_dual_bank() {
|
if is_dual_bank() {
|
||||||
pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123));
|
if pac::FLASH.bank(1).cr().read().lock() {
|
||||||
pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
|
pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123));
|
||||||
|
pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,17 +28,23 @@ 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))]
|
||||||
{
|
{
|
||||||
pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123));
|
if pac::FLASH.cr().read().lock() {
|
||||||
pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB));
|
pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123));
|
||||||
|
pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(flash_l0, flash_l1))]
|
#[cfg(any(flash_l0, flash_l1))]
|
||||||
{
|
{
|
||||||
pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x89ABCDEF));
|
if pac::FLASH.pecr().read().pelock() {
|
||||||
pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x02030405));
|
pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x89ABCDEF));
|
||||||
|
pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x02030405));
|
||||||
|
}
|
||||||
|
|
||||||
pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x8C9DAEBF));
|
if pac::FLASH.pecr().read().prglock() {
|
||||||
pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x13141516));
|
pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x8C9DAEBF));
|
||||||
|
pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x13141516));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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::*;
|
||||||
|
|
||||||
|
@ -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
|
let cr = crate::pac::PWR.cr();
|
||||||
))]
|
#[cfg(not(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba)))]
|
||||||
#[allow(dead_code, unused_variables)]
|
let cr = crate::pac::PWR.cr1();
|
||||||
fn modify<R>(f: impl FnOnce(&mut Bdcr) -> R) -> R {
|
#[cfg(any(stm32u5, stm32h5, stm32wba))]
|
||||||
#[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1, rtc_v2l0))]
|
let cr = crate::pac::PWR.dbpcr();
|
||||||
let cr = crate::pac::PWR.cr();
|
|
||||||
#[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
|
|
||||||
let cr = crate::pac::PWR.cr1();
|
|
||||||
|
|
||||||
// TODO: Missing from PAC for l0 and f0?
|
cr.modify(|w| w.set_dbp(true));
|
||||||
#[cfg(not(any(rtc_v2f0, rtc_v3u5)))]
|
while !cr.read().dbp() {}
|
||||||
{
|
}
|
||||||
cr.modify(|w| w.set_dbp(true));
|
|
||||||
while !cr.read().dbp() {}
|
fn bdcr() -> Reg<Bdcr, RW> {
|
||||||
|
#[cfg(any(rtc_v2l0, rtc_v2l1))]
|
||||||
|
return crate::pac::RCC.csr();
|
||||||
|
#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))]
|
||||||
|
return crate::pac::RCC.bdcr();
|
||||||
|
#[cfg(any(stm32c0))]
|
||||||
|
return crate::pac::RCC.csr1();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LsConfig {
|
||||||
|
pub rtc: RtcClockSource,
|
||||||
|
pub lsi: bool,
|
||||||
|
pub lse: Option<LseConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LsConfig {
|
||||||
|
pub const fn default_lse() -> Self {
|
||||||
|
Self {
|
||||||
|
rtc: RtcClockSource::LSE,
|
||||||
|
lse: Some(LseConfig {
|
||||||
|
frequency: Hertz(32_768),
|
||||||
|
mode: LseMode::Oscillator(LseDrive::MediumHigh),
|
||||||
|
}),
|
||||||
|
lsi: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(rtc_v2l0, rtc_v2l1))]
|
|
||||||
let cr = crate::pac::RCC.csr();
|
|
||||||
|
|
||||||
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
|
|
||||||
let cr = crate::pac::RCC.bdcr();
|
|
||||||
|
|
||||||
cr.modify(|w| f(w))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(
|
pub const fn default_lsi() -> Self {
|
||||||
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3,
|
Self {
|
||||||
rtc_v3u5
|
rtc: RtcClockSource::LSI,
|
||||||
))]
|
lsi: true,
|
||||||
#[allow(dead_code)]
|
lse: None,
|
||||||
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(
|
pub const fn off() -> Self {
|
||||||
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3,
|
Self {
|
||||||
rtc_v3u5
|
rtc: RtcClockSource::NOCLOCK,
|
||||||
))]
|
lsi: false,
|
||||||
#[allow(dead_code, unused_variables)]
|
lse: None,
|
||||||
pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option<LseCfg>) {
|
}
|
||||||
use atomic_polyfill::{compiler_fence, Ordering};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match clock_source {
|
impl Default for LsConfig {
|
||||||
RtcClockSource::LSI => assert!(lsi),
|
fn default() -> Self {
|
||||||
RtcClockSource::LSE => assert!(lse.is_some()),
|
// 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 {
|
// Disable backup domain write protection
|
||||||
#[cfg(rtc_v3u5)]
|
unlock();
|
||||||
|
|
||||||
|
if self.lsi {
|
||||||
|
#[cfg(any(stm32u5, stm32h5, stm32wba))]
|
||||||
let csr = crate::pac::RCC.bdcr();
|
let csr = crate::pac::RCC.bdcr();
|
||||||
|
#[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0)))]
|
||||||
#[cfg(not(rtc_v3u5))]
|
|
||||||
let csr = crate::pac::RCC.csr();
|
let csr = crate::pac::RCC.csr();
|
||||||
|
#[cfg(any(stm32c0))]
|
||||||
// Disable backup domain write protection
|
let csr = crate::pac::RCC.csr2();
|
||||||
Self::modify(|_| {});
|
|
||||||
|
|
||||||
#[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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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| {
|
|
||||||
assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1));
|
|
||||||
|
|
||||||
w.set_ckmode(adc.into());
|
|
||||||
|
|
||||||
Hertz(sysclk / adc.bus_div() as u32)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
_ => crate::pac::ADC_COMMON.ccr().modify(|w| {
|
||||||
|
assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1));
|
||||||
|
|
||||||
|
w.set_ckmode(adc.into());
|
||||||
|
|
||||||
|
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| {
|
|
||||||
assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1));
|
|
||||||
|
|
||||||
w.set_ckmode(adc.into());
|
|
||||||
|
|
||||||
Hertz(sysclk / adc.bus_div() as u32)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
_ => crate::pac::ADC_COMMON.ccr().modify(|w| {
|
||||||
|
assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1));
|
||||||
|
|
||||||
|
w.set_ckmode(adc.into());
|
||||||
|
|
||||||
|
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"
|
||||||
),
|
),
|
||||||
|
@ -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,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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),
|
|
||||||
});
|
|
||||||
}
|
|
219
embassy-stm32/src/rcc/l0l1.rs
Normal file
219
embassy-stm32/src/rcc/l0l1.rs
Normal 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,
|
||||||
|
});
|
||||||
|
}
|
@ -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),
|
|
||||||
});
|
|
||||||
}
|
|
@ -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(config.ls.lse.is_some());
|
||||||
w.set_msipllen(true);
|
|
||||||
} 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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(config.ls.lse.is_some());
|
||||||
w.set_msipllen(true);
|
|
||||||
} 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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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(config.ls.lse.is_some());
|
||||||
w.set_msipllen(true);
|
|
||||||
} 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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 ()) {
|
||||||
|
@ -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"
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
@ -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!");
|
||||||
|
@ -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());
|
||||||
|
@ -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);
|
||||||
|
@ -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());
|
||||||
|
@ -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());
|
||||||
|
@ -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));
|
||||||
|
@ -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.ls = LsConfig::default_lse();
|
||||||
config.rcc.lse = Some(Lse::Oscillator);
|
|
||||||
config.rcc.rtc_mux = Some(RtcClockSource::LSE);
|
let p = embassy_stm32::init(config);
|
||||||
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)
|
||||||
|
@ -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!");
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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| {
|
||||||
|
@ -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!");
|
||||||
|
@ -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");
|
||||||
|
@ -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 = []
|
||||||
|
@ -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());
|
||||||
|
@ -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!");
|
||||||
|
@ -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!");
|
||||||
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user