stm32/rcc: remove Rcc struct, RccExt trait.

All the RCC configuration is executed in init().
This commit is contained in:
Dario Nieuwenhuis 2022-01-04 23:58:13 +01:00
parent c3fd9a0f44
commit 2eb0cc5df7
31 changed files with 2586 additions and 3196 deletions

View File

@ -43,8 +43,6 @@ pub mod i2c;
#[cfg(crc)] #[cfg(crc)]
pub mod crc; pub mod crc;
pub mod pwm; pub mod pwm;
#[cfg(pwr)]
pub mod pwr;
#[cfg(rng)] #[cfg(rng)]
pub mod rng; pub mod rng;
#[cfg(sdmmc)] #[cfg(sdmmc)]

View File

@ -1 +0,0 @@

View File

@ -1 +0,0 @@

View File

@ -1 +0,0 @@

View File

@ -1 +0,0 @@

View File

@ -1 +0,0 @@

View File

@ -1,78 +0,0 @@
use crate::pac::{PWR, RCC, SYSCFG};
use crate::peripherals;
/// Voltage Scale
///
/// Represents the voltage range feeding the CPU core. The maximum core
/// clock frequency depends on this value.
#[derive(Copy, Clone, PartialEq)]
pub enum VoltageScale {
/// VOS 0 range VCORE 1.26V - 1.40V
Scale0,
/// VOS 1 range VCORE 1.15V - 1.26V
Scale1,
/// VOS 2 range VCORE 1.05V - 1.15V
Scale2,
/// VOS 3 range VCORE 0.95V - 1.05V
Scale3,
}
/// Power Configuration
///
/// Generated when the PWR peripheral is frozen. The existence of this
/// value indicates that the voltage scaling configuration can no
/// longer be changed.
pub struct Power {
pub(crate) vos: VoltageScale,
}
impl Power {
pub fn new(_peri: peripherals::PWR, enable_overdrive: bool) -> Self {
// NOTE(unsafe) we have the PWR singleton
unsafe {
// NB. The lower bytes of CR3 can only be written once after
// POR, and must be written with a valid combination. Refer to
// RM0433 Rev 7 6.8.4. This is partially enforced by dropping
// `self` at the end of this method, but of course we cannot
// know what happened between the previous POR and here.
#[cfg(pwr_h7)]
PWR.cr3().modify(|w| {
w.set_scuen(true);
w.set_ldoen(true);
w.set_bypass(false);
});
#[cfg(pwr_h7smps)]
PWR.cr3().modify(|w| {
// hardcode "Direct SPMS" for now, this is what works on nucleos with the
// default solderbridge configuration.
w.set_sden(true);
w.set_ldoen(false);
});
// Validate the supply configuration. If you are stuck here, it is
// because the voltages on your board do not match those specified
// in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
// VOS = Scale 3, so check that the voltage on the VCAP pins =
// 1.0V.
while !PWR.csr1().read().actvosrdy() {}
// Go to Scale 1
PWR.d3cr().modify(|w| w.set_vos(0b11));
while !PWR.d3cr().read().vosrdy() {}
let vos = if !enable_overdrive {
VoltageScale::Scale1
} else {
critical_section::with(|_| {
RCC.apb4enr().modify(|w| w.set_syscfgen(true));
SYSCFG.pwrcr().modify(|w| w.set_oden(1));
});
while !PWR.d3cr().read().vosrdy() {}
VoltageScale::Scale0
};
Self { vos }
}
}
}

View File

@ -1 +0,0 @@

View File

@ -1,13 +0,0 @@
#[cfg_attr(any(pwr_h7, pwr_h7smps), path = "h7.rs")]
#[cfg_attr(pwr_f3, path = "f3.rs")]
#[cfg_attr(pwr_f4, path = "f4.rs")]
#[cfg_attr(pwr_f7, path = "f7.rs")]
#[cfg_attr(pwr_wl5, path = "wl5.rs")]
#[cfg_attr(pwr_g0, path = "g0.rs")]
#[cfg_attr(pwr_g4, path = "g4.rs")]
#[cfg_attr(pwr_l1, path = "l1.rs")]
#[cfg_attr(pwr_u5, path = "u5.rs")]
#[cfg_attr(pwr_wb55, path = "wb55.rs")]
mod _version;
pub use _version::*;

View File

@ -1,32 +0,0 @@
use crate::peripherals;
/// Voltage Scale
///
/// Represents the voltage range feeding the CPU core. The maximum core
/// clock frequency depends on this value.
#[derive(Copy, Clone, PartialEq)]
pub enum VoltageScale {
// Highest frequency
Range1,
Range2,
Range3,
// Lowest power
Range4,
}
/// Power Configuration
///
/// Generated when the PWR peripheral is frozen. The existence of this
/// value indicates that the voltage scaling configuration can no
/// longer be changed.
pub struct Power {
pub(crate) vos: VoltageScale,
}
impl Power {
pub fn new(_peri: peripherals::PWR) -> Self {
Self {
vos: VoltageScale::Range4,
}
}
}

View File

@ -1 +0,0 @@

View File

@ -1,9 +1,5 @@
use core::marker::PhantomData; use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
use embassy::util::Unborrow;
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::peripherals;
use crate::time::Hertz; use crate::time::Hertz;
use super::{set_freqs, Clocks}; use super::{set_freqs, Clocks};
@ -28,181 +24,151 @@ pub struct Config {
pub pclk: Option<Hertz>, pub pclk: Option<Hertz>,
} }
pub struct Rcc<'d> {
inner: PhantomData<&'d ()>,
config: Config,
}
impl<'d> Rcc<'d> {
pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
Self {
inner: PhantomData,
config,
}
}
pub fn freeze(self) -> Clocks {
use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
let sysclk = self.config.sys_ck.map(|v| v.0).unwrap_or(HSI);
let (src_clk, use_hsi48) = self.config.hse.map(|v| (v.0, false)).unwrap_or_else(|| {
#[cfg(rcc_f0)]
if self.config.hsi48 {
return (48_000_000, true);
}
(HSI, false)
});
let (pllmul_bits, real_sysclk) = if sysclk == src_clk {
(None, sysclk)
} else {
let prediv = if self.config.hse.is_some() { 1 } else { 2 };
let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2;
let pllmul = pllmul.max(2).min(16);
let pllmul_bits = pllmul as u8 - 2;
let real_sysclk = pllmul * src_clk / prediv;
(Some(pllmul_bits), real_sysclk)
};
let hpre_bits = self
.config
.hclk
.map(|hclk| match real_sysclk / hclk.0 {
0 => unreachable!(),
1 => 0b0111,
2 => 0b1000,
3..=5 => 0b1001,
6..=11 => 0b1010,
12..=39 => 0b1011,
40..=95 => 0b1100,
96..=191 => 0b1101,
192..=383 => 0b1110,
_ => 0b1111,
})
.unwrap_or(0b0111);
let hclk = real_sysclk / (1 << (hpre_bits - 0b0111));
let ppre_bits = self
.config
.pclk
.map(|pclk| match hclk / pclk.0 {
0 => unreachable!(),
1 => 0b011,
2 => 0b100,
3..=5 => 0b101,
6..=11 => 0b110,
_ => 0b111,
})
.unwrap_or(0b011);
let ppre: u8 = 1 << (ppre_bits - 0b011);
let pclk = hclk / u32::from(ppre);
let timer_mul = if ppre == 1 { 1 } else { 2 };
// NOTE(safety) Atomic write
unsafe {
FLASH.acr().write(|w| {
let latency = if real_sysclk <= 24_000_000 {
0
} else if real_sysclk <= 48_000_000 {
1
} else {
2
};
w.latency().0 = latency;
});
}
// NOTE(unsafe) We have exclusive access to the RCC
unsafe {
match (self.config.hse.is_some(), use_hsi48) {
(true, _) => {
RCC.cr().modify(|w| {
w.set_csson(true);
w.set_hseon(true);
if self.config.bypass_hse {
w.set_hsebyp(Hsebyp::BYPASSED);
}
});
while !RCC.cr().read().hserdy() {}
if pllmul_bits.is_some() {
RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV))
}
}
(false, true) => {
// use_hsi48 will always be false for rcc_f0x0
#[cfg(rcc_f0)]
RCC.cr2().modify(|w| w.set_hsi48on(true));
#[cfg(rcc_f0)]
while !RCC.cr2().read().hsi48rdy() {}
#[cfg(rcc_f0)]
if pllmul_bits.is_some() {
RCC.cfgr()
.modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV))
}
}
_ => {
RCC.cr().modify(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
if pllmul_bits.is_some() {
RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2))
}
}
}
if self.config.usb_pll {
RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLLCLK));
}
// TODO: Option to use CRS (Clock Recovery)
if let Some(pllmul_bits) = pllmul_bits {
RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits)));
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
RCC.cfgr().modify(|w| {
w.set_ppre(Ppre(ppre_bits));
w.set_hpre(Hpre(hpre_bits));
w.set_sw(Sw::PLL)
});
} else {
RCC.cfgr().modify(|w| {
w.set_ppre(Ppre(ppre_bits));
w.set_hpre(Hpre(hpre_bits));
if self.config.hse.is_some() {
w.set_sw(Sw::HSE);
} else if use_hsi48 {
#[cfg(rcc_f0)]
w.set_sw(Sw::HSI48);
} else {
w.set_sw(Sw::HSI)
}
})
}
}
Clocks {
sys: Hertz(real_sysclk),
apb1: Hertz(pclk),
apb2: Hertz(pclk),
apb1_tim: Hertz(pclk * timer_mul),
apb2_tim: Hertz(pclk * timer_mul),
ahb: Hertz(hclk),
}
}
}
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config); let sysclk = config.sys_ck.map(|v| v.0).unwrap_or(HSI);
let clocks = rcc.freeze();
set_freqs(clocks); let (src_clk, use_hsi48) = config.hse.map(|v| (v.0, false)).unwrap_or_else(|| {
#[cfg(rcc_f0)]
if config.hsi48 {
return (48_000_000, true);
}
(HSI, false)
});
let (pllmul_bits, real_sysclk) = if sysclk == src_clk {
(None, sysclk)
} else {
let prediv = if config.hse.is_some() { 1 } else { 2 };
let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2;
let pllmul = pllmul.max(2).min(16);
let pllmul_bits = pllmul as u8 - 2;
let real_sysclk = pllmul * src_clk / prediv;
(Some(pllmul_bits), real_sysclk)
};
let hpre_bits = config
.hclk
.map(|hclk| match real_sysclk / hclk.0 {
0 => unreachable!(),
1 => 0b0111,
2 => 0b1000,
3..=5 => 0b1001,
6..=11 => 0b1010,
12..=39 => 0b1011,
40..=95 => 0b1100,
96..=191 => 0b1101,
192..=383 => 0b1110,
_ => 0b1111,
})
.unwrap_or(0b0111);
let hclk = real_sysclk / (1 << (hpre_bits - 0b0111));
let ppre_bits = config
.pclk
.map(|pclk| match hclk / pclk.0 {
0 => unreachable!(),
1 => 0b011,
2 => 0b100,
3..=5 => 0b101,
6..=11 => 0b110,
_ => 0b111,
})
.unwrap_or(0b011);
let ppre: u8 = 1 << (ppre_bits - 0b011);
let pclk = hclk / u32::from(ppre);
let timer_mul = if ppre == 1 { 1 } else { 2 };
FLASH.acr().write(|w| {
let latency = if real_sysclk <= 24_000_000 {
0
} else if real_sysclk <= 48_000_000 {
1
} else {
2
};
w.latency().0 = latency;
});
match (config.hse.is_some(), use_hsi48) {
(true, _) => {
RCC.cr().modify(|w| {
w.set_csson(true);
w.set_hseon(true);
if config.bypass_hse {
w.set_hsebyp(Hsebyp::BYPASSED);
}
});
while !RCC.cr().read().hserdy() {}
if pllmul_bits.is_some() {
RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV))
}
}
(false, true) => {
// use_hsi48 will always be false for rcc_f0x0
#[cfg(rcc_f0)]
RCC.cr2().modify(|w| w.set_hsi48on(true));
#[cfg(rcc_f0)]
while !RCC.cr2().read().hsi48rdy() {}
#[cfg(rcc_f0)]
if pllmul_bits.is_some() {
RCC.cfgr()
.modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV))
}
}
_ => {
RCC.cr().modify(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
if pllmul_bits.is_some() {
RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2))
}
}
}
if config.usb_pll {
RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLLCLK));
}
// TODO: Option to use CRS (Clock Recovery)
if let Some(pllmul_bits) = pllmul_bits {
RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits)));
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
RCC.cfgr().modify(|w| {
w.set_ppre(Ppre(ppre_bits));
w.set_hpre(Hpre(hpre_bits));
w.set_sw(Sw::PLL)
});
} else {
RCC.cfgr().modify(|w| {
w.set_ppre(Ppre(ppre_bits));
w.set_hpre(Hpre(hpre_bits));
if config.hse.is_some() {
w.set_sw(Sw::HSE);
} else if use_hsi48 {
#[cfg(rcc_f0)]
w.set_sw(Sw::HSI48);
} else {
w.set_sw(Sw::HSI)
}
})
}
set_freqs(Clocks {
sys: Hertz(real_sysclk),
apb1: Hertz(pclk),
apb2: Hertz(pclk),
apb1_tim: Hertz(pclk * timer_mul),
apb2_tim: Hertz(pclk * timer_mul),
ahb: Hertz(hclk),
});
} }

View File

@ -1,14 +1,10 @@
use core::convert::TryFrom; use core::convert::TryFrom;
use core::marker::PhantomData;
use embassy::util::Unborrow;
use crate::pac::flash::vals::Latency;
use crate::pac::{FLASH, RCC};
use crate::peripherals;
use crate::time::Hertz;
use super::{set_freqs, Clocks}; use super::{set_freqs, Clocks};
use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{Adcpre, Hpre, Pllmul, Pllsrc, Ppre1, Sw, Usbpre};
use crate::pac::{FLASH, RCC};
use crate::time::Hertz;
const HSI: u32 = 8_000_000; const HSI: u32 = 8_000_000;
@ -26,189 +22,158 @@ pub struct Config {
pub adcclk: Option<Hertz>, pub adcclk: Option<Hertz>,
} }
pub struct Rcc<'d> {
inner: PhantomData<&'d ()>,
config: Config,
}
impl<'d> Rcc<'d> {
pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
Self {
inner: PhantomData,
config,
}
}
pub fn freeze(self) -> Clocks {
use crate::pac::rcc::vals::{Adcpre, Hpre, Pllmul, Pllsrc, Ppre1, Sw, Usbpre};
let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI / 2);
let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
let pllmul = sysclk / pllsrcclk;
let (pllmul_bits, real_sysclk) = if pllmul == 1 {
(None, self.config.hse.map(|hse| hse.0).unwrap_or(HSI))
} else {
let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16);
(Some(pllmul as u8 - 2), pllsrcclk * pllmul)
};
assert!(real_sysclk <= 72_000_000);
let hpre_bits = self
.config
.hclk
.map(|hclk| match real_sysclk / hclk.0 {
0 => unreachable!(),
1 => 0b0111,
2 => 0b1000,
3..=5 => 0b1001,
6..=11 => 0b1010,
12..=39 => 0b1011,
40..=95 => 0b1100,
96..=191 => 0b1101,
192..=383 => 0b1110,
_ => 0b1111,
})
.unwrap_or(0b0111);
let hclk = if hpre_bits >= 0b1100 {
real_sysclk / (1 << (hpre_bits - 0b0110))
} else {
real_sysclk / (1 << (hpre_bits - 0b0111))
};
assert!(hclk <= 72_000_000);
let ppre1_bits = self
.config
.pclk1
.map(|pclk1| match hclk / pclk1.0 {
0 => unreachable!(),
1 => 0b011,
2 => 0b100,
3..=5 => 0b101,
6..=11 => 0b110,
_ => 0b111,
})
.unwrap_or(0b011);
let ppre1 = 1 << (ppre1_bits - 0b011);
let pclk1 = hclk / u32::try_from(ppre1).unwrap();
let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
assert!(pclk1 <= 36_000_000);
let ppre2_bits = self
.config
.pclk2
.map(|pclk2| match hclk / pclk2.0 {
0 => unreachable!(),
1 => 0b011,
2 => 0b100,
3..=5 => 0b101,
6..=11 => 0b110,
_ => 0b111,
})
.unwrap_or(0b011);
let ppre2 = 1 << (ppre2_bits - 0b011);
let pclk2 = hclk / u32::try_from(ppre2).unwrap();
let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
assert!(pclk2 <= 72_000_000);
// Only needed for stm32f103?
// NOTE(safety) Atomic write
unsafe {
FLASH.acr().write(|w| {
w.set_latency(if real_sysclk <= 24_000_000 {
Latency(0b000)
} else if real_sysclk <= 48_000_000 {
Latency(0b001)
} else {
Latency(0b010)
});
})
}
// the USB clock is only valid if an external crystal is used, the PLL is enabled, and the
// PLL output frequency is a supported one.
// usbpre == false: divide clock by 1.5, otherwise no division
let (usbpre, _usbclk_valid) = match (self.config.hse, pllmul_bits, real_sysclk) {
(Some(_), Some(_), 72_000_000) => (false, true),
(Some(_), Some(_), 48_000_000) => (true, true),
_ => (true, false),
};
let apre_bits: u8 = self
.config
.adcclk
.map(|adcclk| match pclk2 / adcclk.0 {
0..=2 => 0b00,
3..=4 => 0b01,
5..=7 => 0b10,
_ => 0b11,
})
.unwrap_or(0b11);
let apre = (apre_bits + 1) << 1;
let adcclk = pclk2 / unwrap!(u32::try_from(apre));
assert!(adcclk <= 14_000_000);
unsafe {
if self.config.hse.is_some() {
// enable HSE and wait for it to be ready
RCC.cr().modify(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
}
if let Some(pllmul_bits) = pllmul_bits {
// enable PLL and wait for it to be ready
RCC.cfgr().modify(|w| {
w.set_pllmul(Pllmul(pllmul_bits));
w.set_pllsrc(Pllsrc(self.config.hse.is_some() as u8));
});
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
}
// Only needed for stm32f103?
RCC.cfgr().modify(|w| {
w.set_adcpre(Adcpre(apre_bits));
w.set_ppre2(Ppre1(ppre2_bits));
w.set_ppre1(Ppre1(ppre1_bits));
w.set_hpre(Hpre(hpre_bits));
w.set_usbpre(Usbpre(usbpre as u8));
w.set_sw(Sw(if pllmul_bits.is_some() {
// PLL
0b10
} else if self.config.hse.is_some() {
// HSE
0b1
} else {
// HSI
0b0
}));
});
}
Clocks {
sys: Hertz(real_sysclk),
apb1: Hertz(pclk1),
apb2: Hertz(pclk2),
apb1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2),
ahb: Hertz(hclk),
adc: Hertz(adcclk),
}
}
}
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config); let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI / 2);
let clocks = rcc.freeze(); let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
set_freqs(clocks); let pllmul = sysclk / pllsrcclk;
let (pllmul_bits, real_sysclk) = if pllmul == 1 {
(None, config.hse.map(|hse| hse.0).unwrap_or(HSI))
} else {
let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16);
(Some(pllmul as u8 - 2), pllsrcclk * pllmul)
};
assert!(real_sysclk <= 72_000_000);
let hpre_bits = config
.hclk
.map(|hclk| match real_sysclk / hclk.0 {
0 => unreachable!(),
1 => 0b0111,
2 => 0b1000,
3..=5 => 0b1001,
6..=11 => 0b1010,
12..=39 => 0b1011,
40..=95 => 0b1100,
96..=191 => 0b1101,
192..=383 => 0b1110,
_ => 0b1111,
})
.unwrap_or(0b0111);
let hclk = if hpre_bits >= 0b1100 {
real_sysclk / (1 << (hpre_bits - 0b0110))
} else {
real_sysclk / (1 << (hpre_bits - 0b0111))
};
assert!(hclk <= 72_000_000);
let ppre1_bits = config
.pclk1
.map(|pclk1| match hclk / pclk1.0 {
0 => unreachable!(),
1 => 0b011,
2 => 0b100,
3..=5 => 0b101,
6..=11 => 0b110,
_ => 0b111,
})
.unwrap_or(0b011);
let ppre1 = 1 << (ppre1_bits - 0b011);
let pclk1 = hclk / u32::try_from(ppre1).unwrap();
let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
assert!(pclk1 <= 36_000_000);
let ppre2_bits = config
.pclk2
.map(|pclk2| match hclk / pclk2.0 {
0 => unreachable!(),
1 => 0b011,
2 => 0b100,
3..=5 => 0b101,
6..=11 => 0b110,
_ => 0b111,
})
.unwrap_or(0b011);
let ppre2 = 1 << (ppre2_bits - 0b011);
let pclk2 = hclk / u32::try_from(ppre2).unwrap();
let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
assert!(pclk2 <= 72_000_000);
// Only needed for stm32f103?
FLASH.acr().write(|w| {
w.set_latency(if real_sysclk <= 24_000_000 {
Latency(0b000)
} else if real_sysclk <= 48_000_000 {
Latency(0b001)
} else {
Latency(0b010)
});
});
// the USB clock is only valid if an external crystal is used, the PLL is enabled, and the
// PLL output frequency is a supported one.
// usbpre == false: divide clock by 1.5, otherwise no division
let (usbpre, _usbclk_valid) = match (config.hse, pllmul_bits, real_sysclk) {
(Some(_), Some(_), 72_000_000) => (false, true),
(Some(_), Some(_), 48_000_000) => (true, true),
_ => (true, false),
};
let apre_bits: u8 = config
.adcclk
.map(|adcclk| match pclk2 / adcclk.0 {
0..=2 => 0b00,
3..=4 => 0b01,
5..=7 => 0b10,
_ => 0b11,
})
.unwrap_or(0b11);
let apre = (apre_bits + 1) << 1;
let adcclk = pclk2 / unwrap!(u32::try_from(apre));
assert!(adcclk <= 14_000_000);
if config.hse.is_some() {
// enable HSE and wait for it to be ready
RCC.cr().modify(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
}
if let Some(pllmul_bits) = pllmul_bits {
// enable PLL and wait for it to be ready
RCC.cfgr().modify(|w| {
w.set_pllmul(Pllmul(pllmul_bits));
w.set_pllsrc(Pllsrc(config.hse.is_some() as u8));
});
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
}
// Only needed for stm32f103?
RCC.cfgr().modify(|w| {
w.set_adcpre(Adcpre(apre_bits));
w.set_ppre2(Ppre1(ppre2_bits));
w.set_ppre1(Ppre1(ppre1_bits));
w.set_hpre(Hpre(hpre_bits));
w.set_usbpre(Usbpre(usbpre as u8));
w.set_sw(Sw(if pllmul_bits.is_some() {
// PLL
0b10
} else if config.hse.is_some() {
// HSE
0b1
} else {
// HSI
0b0
}));
});
set_freqs(Clocks {
sys: Hertz(real_sysclk),
apb1: Hertz(pclk1),
apb2: Hertz(pclk2),
apb1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2),
ahb: Hertz(hclk),
adc: Hertz(adcclk),
});
} }

View File

@ -1,23 +1,11 @@
use core::marker::PhantomData; use crate::pac::flash::vals::Latency;
use embassy::util::Unborrow; use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
use crate::pac::{FLASH, RCC};
use crate::pac::{
flash::vals::Latency,
rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre},
FLASH, RCC,
};
use crate::peripherals;
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
const HSI: u32 = 8_000_000; const HSI: u32 = 8_000_000;
/// RCC peripheral
pub struct Rcc<'d> {
config: Config,
phantom: PhantomData<&'d mut peripherals::RCC>,
}
/// Clocks configutation /// Clocks configutation
#[non_exhaustive] #[non_exhaustive]
#[derive(Default)] #[derive(Default)]
@ -55,259 +43,228 @@ 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) {
let r = <peripherals::RCC as embassy::util::Steal>::steal(); // Calculate the real System clock, and PLL configuration if applicable
let clocks = Rcc::new(r, config).freeze(); let (Hertz(sysclk), pll_config) = get_sysclk(&config);
set_freqs(clocks); assert!(sysclk <= 72_000_000);
// Calculate real AHB clock
let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
let (hpre_bits, hpre_div) = match sysclk / hclk {
0 => unreachable!(),
1 => (Hpre::DIV1, 1),
2 => (Hpre::DIV2, 2),
3..=5 => (Hpre::DIV4, 4),
6..=11 => (Hpre::DIV8, 8),
12..=39 => (Hpre::DIV16, 16),
40..=95 => (Hpre::DIV64, 64),
96..=191 => (Hpre::DIV128, 128),
192..=383 => (Hpre::DIV256, 256),
_ => (Hpre::DIV512, 512),
};
let hclk = sysclk / hpre_div;
assert!(hclk <= 72_000_000);
// Calculate real APB1 clock
let pclk1 = config.pclk1.map(|p| p.0).unwrap_or(hclk);
let (ppre1_bits, ppre1) = match hclk / pclk1 {
0 => unreachable!(),
1 => (Ppre::DIV1, 1),
2 => (Ppre::DIV2, 2),
3..=5 => (Ppre::DIV4, 4),
6..=11 => (Ppre::DIV8, 8),
_ => (Ppre::DIV16, 16),
};
let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
let pclk1 = hclk / ppre1;
assert!(pclk1 <= 36_000_000);
// Calculate real APB2 clock
let pclk2 = config.pclk2.map(|p| p.0).unwrap_or(hclk);
let (ppre2_bits, ppre2) = match hclk / pclk2 {
0 => unreachable!(),
1 => (Ppre::DIV1, 1),
2 => (Ppre::DIV2, 2),
3..=5 => (Ppre::DIV4, 4),
6..=11 => (Ppre::DIV8, 8),
_ => (Ppre::DIV16, 16),
};
let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
let pclk2 = hclk / ppre2;
assert!(pclk2 <= 72_000_000);
// Set latency based on HCLK frquency
FLASH.acr().write(|w| {
w.set_latency(if hclk <= 24_000_000 {
Latency::WS0
} else if hclk <= 48_000_000 {
Latency::WS1
} else {
Latency::WS2
});
});
// Enable HSE
if config.hse.is_some() {
RCC.cr().write(|w| {
w.set_hsebyp(if config.bypass_hse {
Hsebyp::BYPASSED
} else {
Hsebyp::NOTBYPASSED
});
// We turn on clock security to switch to HSI when HSE fails
w.set_csson(true);
w.set_hseon(true);
});
while !RCC.cr().read().hserdy() {}
}
// Enable PLL
if let Some(ref pll_config) = pll_config {
RCC.cfgr().write(|w| {
w.set_pllmul(pll_config.pll_mul);
w.set_pllsrc(pll_config.pll_src);
});
if let Some(pll_div) = pll_config.pll_div {
RCC.cfgr2().write(|w| w.set_prediv(pll_div));
}
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
}
if config.pll48 {
let usb_pre = get_usb_pre(&config, sysclk, pclk1, &pll_config);
RCC.cfgr().write(|w| {
w.set_usbpre(usb_pre);
});
}
// Set prescalers
RCC.cfgr().write(|w| {
w.set_ppre2(ppre2_bits);
w.set_ppre1(ppre1_bits);
w.set_hpre(hpre_bits);
});
// Wait for the new prescalers to kick in
// "The clocks are divided with the new prescaler factor from
// 1 to 16 AHB cycles after write"
cortex_m::asm::delay(16);
RCC.cfgr().write(|w| {
w.set_sw(match (pll_config, config.hse) {
(Some(_), _) => Sw::PLL,
(None, Some(_)) => Sw::HSE,
(None, None) => Sw::HSI,
})
});
set_freqs(Clocks {
sys: Hertz(sysclk),
apb1: Hertz(pclk1),
apb2: Hertz(pclk2),
apb1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2),
ahb: Hertz(hclk),
});
} }
impl<'d> Rcc<'d> { #[inline]
pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self { fn get_sysclk(config: &Config) -> (Hertz, Option<PllConfig>) {
Self { match (config.sysclk, config.hse) {
config, (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None),
phantom: PhantomData, (Some(sysclk), None) if sysclk.0 == HSI => (Hertz(HSI), None),
// If the user selected System clock is different from HSI or HSE
// we will have to setup PLL clock source
(Some(sysclk), _) => {
let (sysclk, pll_config) = calc_pll(config, sysclk);
(sysclk, Some(pll_config))
} }
(None, Some(hse)) => (hse, None),
(None, None) => (Hertz(HSI), None),
} }
}
fn freeze(self) -> Clocks { #[inline]
// Calculate the real System clock, and PLL configuration if applicable fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) {
let (Hertz(sysclk), pll_config) = self.get_sysclk(); // Calculates the Multiplier and the Divisor to arrive at
assert!(sysclk <= 72_000_000); // the required System clock from PLL source frequency
let get_mul_div = |sysclk, pllsrcclk| {
// Calculate real AHB clock let common_div = gcd(sysclk, pllsrcclk);
let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk); let mut multiplier = sysclk / common_div;
let (hpre_bits, hpre_div) = match sysclk / hclk { let mut divisor = pllsrcclk / common_div;
0 => unreachable!(), // Minimum PLL multiplier is two
1 => (Hpre::DIV1, 1), if multiplier == 1 {
2 => (Hpre::DIV2, 2), multiplier *= 2;
3..=5 => (Hpre::DIV4, 4), divisor *= 2;
6..=11 => (Hpre::DIV8, 8), }
12..=39 => (Hpre::DIV16, 16), assert!(multiplier <= 16);
40..=95 => (Hpre::DIV64, 64), assert!(divisor <= 16);
96..=191 => (Hpre::DIV128, 128), (multiplier, divisor)
192..=383 => (Hpre::DIV256, 256), };
_ => (Hpre::DIV512, 512), // Based on the source of Pll, we calculate the actual system clock
}; // frequency, PLL's source identifier, multiplier and divisor
let hclk = sysclk / hpre_div; let (act_sysclk, pll_src, pll_mul, pll_div) = match config.hse {
assert!(hclk <= 72_000_000); Some(Hertz(hse)) => {
let (multiplier, divisor) = get_mul_div(sysclk, hse);
// Calculate real APB1 clock (
let pclk1 = self.config.pclk1.map(|p| p.0).unwrap_or(hclk); Hertz((hse / divisor) * multiplier),
let (ppre1_bits, ppre1) = match hclk / pclk1 { Pllsrc::HSE_DIV_PREDIV,
0 => unreachable!(), into_pll_mul(multiplier),
1 => (Ppre::DIV1, 1), Some(into_pre_div(divisor)),
2 => (Ppre::DIV2, 2), )
3..=5 => (Ppre::DIV4, 4), }
6..=11 => (Ppre::DIV8, 8), None => {
_ => (Ppre::DIV16, 16), cfg_if::cfg_if! {
}; // For some chips PREDIV is always two, and cannot be changed
let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; if #[cfg(any(
let pclk1 = hclk / ppre1; feature="stm32f302xd", feature="stm32f302xe", feature="stm32f303xd",
assert!(pclk1 <= 36_000_000); feature="stm32f303xe", feature="stm32f398xe"
))] {
// Calculate real APB2 clock let (multiplier, divisor) = get_mul_div(sysclk, HSI);
let pclk2 = self.config.pclk2.map(|p| p.0).unwrap_or(hclk); (
let (ppre2_bits, ppre2) = match hclk / pclk2 { Hertz((hse / divisor) * multiplier),
0 => unreachable!(), Pllsrc::HSI_DIV_PREDIV,
1 => (Ppre::DIV1, 1), into_pll_mul(multiplier),
2 => (Ppre::DIV2, 2), Some(into_pre_div(divisor)),
3..=5 => (Ppre::DIV4, 4), )
6..=11 => (Ppre::DIV8, 8),
_ => (Ppre::DIV16, 16),
};
let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
let pclk2 = hclk / ppre2;
assert!(pclk2 <= 72_000_000);
// Set latency based on HCLK frquency
// NOTE(safety) Atomic write
unsafe {
FLASH.acr().write(|w| {
w.set_latency(if hclk <= 24_000_000 {
Latency::WS0
} else if hclk <= 48_000_000 {
Latency::WS1
} else { } else {
Latency::WS2 let pllsrcclk = HSI / 2;
}); let multiplier = sysclk / pllsrcclk;
}) assert!(multiplier <= 16);
} (
Hertz(pllsrcclk * multiplier),
// Enable HSE Pllsrc::HSI_DIV2,
if self.config.hse.is_some() { into_pll_mul(multiplier),
// NOTE(unsafe) We own the peripheral block None,
unsafe { )
RCC.cr().write(|w| {
w.set_hsebyp(if self.config.bypass_hse {
Hsebyp::BYPASSED
} else {
Hsebyp::NOTBYPASSED
});
// We turn on clock security to switch to HSI when HSE fails
w.set_csson(true);
w.set_hseon(true);
});
while !RCC.cr().read().hserdy() {}
}
}
// Enable PLL
if let Some(ref pll_config) = pll_config {
// NOTE(unsafe) We own the peripheral block
unsafe {
RCC.cfgr().write(|w| {
w.set_pllmul(pll_config.pll_mul);
w.set_pllsrc(pll_config.pll_src);
});
if let Some(pll_div) = pll_config.pll_div {
RCC.cfgr2().write(|w| w.set_prediv(pll_div));
}
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
}
}
if self.config.pll48 {
let usb_pre = self.get_usb_pre(sysclk, pclk1, &pll_config);
// NOTE(unsafe) We own the peripheral block
unsafe {
RCC.cfgr().write(|w| {
w.set_usbpre(usb_pre);
});
}
}
// Set prescalers
unsafe {
// NOTE(unsafe) We own the peripheral block
RCC.cfgr().write(|w| {
w.set_ppre2(ppre2_bits);
w.set_ppre1(ppre1_bits);
w.set_hpre(hpre_bits);
});
// Wait for the new prescalers to kick in
// "The clocks are divided with the new prescaler factor from
// 1 to 16 AHB cycles after write"
cortex_m::asm::delay(16);
// NOTE(unsafe) We own the peripheral block
RCC.cfgr().write(|w| {
w.set_sw(match (pll_config, self.config.hse) {
(Some(_), _) => Sw::PLL,
(None, Some(_)) => Sw::HSE,
(None, None) => Sw::HSI,
})
});
}
Clocks {
sys: Hertz(sysclk),
apb1: Hertz(pclk1),
apb2: Hertz(pclk2),
apb1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2),
ahb: Hertz(hclk),
}
}
#[inline]
fn get_sysclk(&self) -> (Hertz, Option<PllConfig>) {
match (self.config.sysclk, self.config.hse) {
(Some(sysclk), Some(hse)) if sysclk == hse => (hse, None),
(Some(sysclk), None) if sysclk.0 == HSI => (Hertz(HSI), None),
// If the user selected System clock is different from HSI or HSE
// we will have to setup PLL clock source
(Some(sysclk), _) => {
let (sysclk, pll_config) = self.calc_pll(sysclk);
(sysclk, Some(pll_config))
}
(None, Some(hse)) => (hse, None),
(None, None) => (Hertz(HSI), None),
}
}
#[inline]
fn calc_pll(&self, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) {
// Calculates the Multiplier and the Divisor to arrive at
// the required System clock from PLL source frequency
let get_mul_div = |sysclk, pllsrcclk| {
let common_div = gcd(sysclk, pllsrcclk);
let mut multiplier = sysclk / common_div;
let mut divisor = pllsrcclk / common_div;
// Minimum PLL multiplier is two
if multiplier == 1 {
multiplier *= 2;
divisor *= 2;
}
assert!(multiplier <= 16);
assert!(divisor <= 16);
(multiplier, divisor)
};
// Based on the source of Pll, we calculate the actual system clock
// frequency, PLL's source identifier, multiplier and divisor
let (act_sysclk, pll_src, pll_mul, pll_div) = match self.config.hse {
Some(Hertz(hse)) => {
let (multiplier, divisor) = get_mul_div(sysclk, hse);
(
Hertz((hse / divisor) * multiplier),
Pllsrc::HSE_DIV_PREDIV,
into_pll_mul(multiplier),
Some(into_pre_div(divisor)),
)
}
None => {
cfg_if::cfg_if! {
// For some chips PREDIV is always two, and cannot be changed
if #[cfg(any(
feature="stm32f302xd", feature="stm32f302xe", feature="stm32f303xd",
feature="stm32f303xe", feature="stm32f398xe"
))] {
let (multiplier, divisor) = get_mul_div(sysclk, HSI);
(
Hertz((hse / divisor) * multiplier),
Pllsrc::HSI_DIV_PREDIV,
into_pll_mul(multiplier),
Some(into_pre_div(divisor)),
)
} else {
let pllsrcclk = HSI / 2;
let multiplier = sysclk / pllsrcclk;
assert!(multiplier <= 16);
(
Hertz(pllsrcclk * multiplier),
Pllsrc::HSI_DIV2,
into_pll_mul(multiplier),
None,
)
}
} }
} }
}; }
( };
act_sysclk, (
PllConfig { act_sysclk,
pll_src, PllConfig {
pll_mul, pll_src,
pll_div, pll_mul,
}, pll_div,
) },
} )
}
#[inline] #[inline]
fn get_usb_pre(&self, sysclk: u32, pclk1: u32, pll_config: &Option<PllConfig>) -> Usbpre { fn get_usb_pre(config: &Config, sysclk: u32, pclk1: u32, 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 = self.config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000); let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000);
match (usb_ok, sysclk) { match (usb_ok, sysclk) {
(true, 72_000_000) => Usbpre::DIV1_5, (true, 72_000_000) => Usbpre::DIV1_5,
(true, 48_000_000) => Usbpre::DIV1, (true, 48_000_000) => Usbpre::DIV1,
_ => panic!( _ => panic!(
"USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz" "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz"
), ),
}
} }
} }
} }

View File

@ -1,9 +1,8 @@
use super::sealed::RccPeripheral;
use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::peripherals; use crate::rcc::{set_freqs, Clocks};
use crate::rcc::{get_freqs, set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
use core::marker::PhantomData;
use embassy::util::Unborrow;
const HSI: u32 = 16_000_000; const HSI: u32 = 16_000_000;
@ -21,284 +20,240 @@ pub struct Config {
pub pll48: bool, pub pll48: bool,
} }
/// RCC peripheral unsafe fn setup_pll(
pub struct Rcc<'d> { pllsrcclk: u32,
config: Config, use_hse: bool,
phantom: PhantomData<&'d mut peripherals::RCC>, pllsysclk: Option<u32>,
pll48clk: bool,
) -> PllResults {
use crate::pac::rcc::vals::{Pllp, Pllsrc};
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
if pllsysclk.is_none() && !pll48clk {
RCC.pllcfgr()
.modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
return PllResults {
use_pll: false,
pllsysclk: None,
pll48clk: None,
};
}
// Input divisor from PLL source clock, must result to frequency in
// the range from 1 to 2 MHz
let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
let pllm_max = pllsrcclk / 1_000_000;
// Sysclk output divisor must be one of 2, 4, 6 or 8
let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
let target_freq = if pll48clk {
48_000_000
} else {
sysclk * sysclk_div
};
// Find the lowest pllm value that minimize the difference between
// target frequency and the real vco_out frequency.
let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
let vco_in = pllsrcclk / pllm;
let plln = target_freq / vco_in;
target_freq - vco_in * plln
}));
let vco_in = pllsrcclk / pllm;
assert!((1_000_000..=2_000_000).contains(&vco_in));
// Main scaler, must result in >= 100MHz (>= 192MHz for F401)
// and <= 432MHz, min 50, max 432
let plln = if pll48clk {
// try the different valid pllq according to the valid
// main scaller values, and take the best
let pllq = unwrap!((4..=9).min_by_key(|pllq| {
let plln = 48_000_000 * pllq / vco_in;
let pll48_diff = 48_000_000 - vco_in * plln / pllq;
let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
(pll48_diff, sysclk_diff)
}));
48_000_000 * pllq / vco_in
} else {
sysclk * sysclk_div / vco_in
};
let pllp = (sysclk_div / 2) - 1;
let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
let real_pll48clk = vco_in * plln / pllq;
RCC.pllcfgr().modify(|w| {
w.set_pllm(pllm as u8);
w.set_plln(plln as u16);
w.set_pllp(Pllp(pllp as u8));
w.set_pllq(pllq as u8);
w.set_pllsrc(Pllsrc(use_hse as u8));
});
let real_pllsysclk = vco_in * plln / sysclk_div;
PllResults {
use_pll: true,
pllsysclk: Some(real_pllsysclk),
pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
}
} }
impl<'d> Rcc<'d> { unsafe fn flash_setup(sysclk: u32) {
pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self { use crate::pac::flash::vals::Latency;
Self {
config,
phantom: PhantomData,
}
}
fn freeze(mut self) -> Clocks { // Be conservative with voltage ranges
use super::sealed::RccPeripheral; const FLASH_LATENCY_STEP: u32 = 30_000_000;
use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
peripherals::PWR::enable(); critical_section::with(|_| {
FLASH
let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI); .acr()
let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
let sysclk_on_pll = sysclk != pllsrcclk; });
let plls = self.setup_pll(
pllsrcclk,
self.config.hse.is_some(),
if sysclk_on_pll { Some(sysclk) } else { None },
self.config.pll48,
);
if self.config.pll48 {
let freq = unwrap!(plls.pll48clk);
assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
}
let sysclk = if sysclk_on_pll {
unwrap!(plls.pllsysclk)
} else {
sysclk
};
// AHB prescaler
let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk);
let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
0 => unreachable!(),
1 => (Hpre::DIV1, 1),
2 => (Hpre::DIV2, 2),
3..=5 => (Hpre::DIV4, 4),
6..=11 => (Hpre::DIV8, 8),
12..=39 => (Hpre::DIV16, 16),
40..=95 => (Hpre::DIV64, 64),
96..=191 => (Hpre::DIV128, 128),
192..=383 => (Hpre::DIV256, 256),
_ => (Hpre::DIV512, 512),
};
// Calculate real AHB clock
let hclk = sysclk / hpre_div;
let pclk1 = self
.config
.pclk1
.map(|p| p.0)
.unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
0 => unreachable!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
// Calculate real APB1 clock
let pclk1 = hclk / ppre1;
assert!(pclk1 <= max::PCLK1_MAX);
let pclk2 = self
.config
.pclk2
.map(|p| p.0)
.unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
0 => unreachable!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
// Calculate real APB2 clock
let pclk2 = hclk / ppre2;
assert!(pclk2 <= max::PCLK2_MAX);
Self::flash_setup(sysclk);
if self.config.hse.is_some() {
// NOTE(unsafe) We own the peripheral block
unsafe {
RCC.cr().modify(|w| {
w.set_hsebyp(Hsebyp(self.config.bypass_hse as u8));
w.set_hseon(true);
});
while !RCC.cr().read().hserdy() {}
}
}
if plls.use_pll {
unsafe {
RCC.cr().modify(|w| w.set_pllon(true));
if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
PWR.cr1().modify(|w| w.set_oden(true));
while !PWR.csr1().read().odrdy() {}
PWR.cr1().modify(|w| w.set_odswen(true));
while !PWR.csr1().read().odswrdy() {}
}
while !RCC.cr().read().pllrdy() {}
}
}
unsafe {
RCC.cfgr().modify(|w| {
w.set_ppre2(Ppre(ppre2_bits));
w.set_ppre1(Ppre(ppre1_bits));
w.set_hpre(hpre_bits);
});
// Wait for the new prescalers to kick in
// "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
cortex_m::asm::delay(16);
RCC.cfgr().modify(|w| {
w.set_sw(if sysclk_on_pll {
Sw::PLL
} else if self.config.hse.is_some() {
Sw::HSE
} else {
Sw::HSI
})
});
}
Clocks {
sys: Hertz(sysclk),
apb1: Hertz(pclk1),
apb2: Hertz(pclk2),
apb1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2),
ahb1: Hertz(hclk),
ahb2: Hertz(hclk),
ahb3: Hertz(hclk),
pll48: plls.pll48clk.map(Hertz),
}
}
// Safety: RCC init must have been called
pub fn clocks(&self) -> &'static Clocks {
unsafe { get_freqs() }
}
fn setup_pll(
&mut self,
pllsrcclk: u32,
use_hse: bool,
pllsysclk: Option<u32>,
pll48clk: bool,
) -> PllResults {
use crate::pac::rcc::vals::{Pllp, Pllsrc};
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
if pllsysclk.is_none() && !pll48clk {
// NOTE(unsafe) We have a mutable borrow to the owner of the RegBlock
unsafe {
RCC.pllcfgr()
.modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
}
return PllResults {
use_pll: false,
pllsysclk: None,
pll48clk: None,
};
}
// Input divisor from PLL source clock, must result to frequency in
// the range from 1 to 2 MHz
let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
let pllm_max = pllsrcclk / 1_000_000;
// Sysclk output divisor must be one of 2, 4, 6 or 8
let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
let target_freq = if pll48clk {
48_000_000
} else {
sysclk * sysclk_div
};
// Find the lowest pllm value that minimize the difference between
// target frequency and the real vco_out frequency.
let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
let vco_in = pllsrcclk / pllm;
let plln = target_freq / vco_in;
target_freq - vco_in * plln
}));
let vco_in = pllsrcclk / pllm;
assert!((1_000_000..=2_000_000).contains(&vco_in));
// Main scaler, must result in >= 100MHz (>= 192MHz for F401)
// and <= 432MHz, min 50, max 432
let plln = if pll48clk {
// try the different valid pllq according to the valid
// main scaller values, and take the best
let pllq = unwrap!((4..=9).min_by_key(|pllq| {
let plln = 48_000_000 * pllq / vco_in;
let pll48_diff = 48_000_000 - vco_in * plln / pllq;
let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
(pll48_diff, sysclk_diff)
}));
48_000_000 * pllq / vco_in
} else {
sysclk * sysclk_div / vco_in
};
let pllp = (sysclk_div / 2) - 1;
let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
let real_pll48clk = vco_in * plln / pllq;
unsafe {
RCC.pllcfgr().modify(|w| {
w.set_pllm(pllm as u8);
w.set_plln(plln as u16);
w.set_pllp(Pllp(pllp as u8));
w.set_pllq(pllq as u8);
w.set_pllsrc(Pllsrc(use_hse as u8));
});
}
let real_pllsysclk = vco_in * plln / sysclk_div;
PllResults {
use_pll: true,
pllsysclk: Some(real_pllsysclk),
pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
}
}
fn flash_setup(sysclk: u32) {
use crate::pac::flash::vals::Latency;
// Be conservative with voltage ranges
const FLASH_LATENCY_STEP: u32 = 30_000_000;
critical_section::with(|_| unsafe {
FLASH
.acr()
.modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
});
}
} }
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let r = <peripherals::RCC as embassy::util::Steal>::steal(); crate::peripherals::PWR::enable();
let clocks = Rcc::new(r, config).freeze();
set_freqs(clocks); let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI);
let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
let sysclk_on_pll = sysclk != pllsrcclk;
let plls = setup_pll(
pllsrcclk,
config.hse.is_some(),
if sysclk_on_pll { Some(sysclk) } else { None },
config.pll48,
);
if config.pll48 {
let freq = unwrap!(plls.pll48clk);
assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
}
let sysclk = if sysclk_on_pll {
unwrap!(plls.pllsysclk)
} else {
sysclk
};
// AHB prescaler
let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
0 => unreachable!(),
1 => (Hpre::DIV1, 1),
2 => (Hpre::DIV2, 2),
3..=5 => (Hpre::DIV4, 4),
6..=11 => (Hpre::DIV8, 8),
12..=39 => (Hpre::DIV16, 16),
40..=95 => (Hpre::DIV64, 64),
96..=191 => (Hpre::DIV128, 128),
192..=383 => (Hpre::DIV256, 256),
_ => (Hpre::DIV512, 512),
};
// Calculate real AHB clock
let hclk = sysclk / hpre_div;
let pclk1 = config
.pclk1
.map(|p| p.0)
.unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
0 => unreachable!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
// Calculate real APB1 clock
let pclk1 = hclk / ppre1;
assert!(pclk1 <= max::PCLK1_MAX);
let pclk2 = config
.pclk2
.map(|p| p.0)
.unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
0 => unreachable!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
// Calculate real APB2 clock
let pclk2 = hclk / ppre2;
assert!(pclk2 <= max::PCLK2_MAX);
flash_setup(sysclk);
if config.hse.is_some() {
RCC.cr().modify(|w| {
w.set_hsebyp(Hsebyp(config.bypass_hse as u8));
w.set_hseon(true);
});
while !RCC.cr().read().hserdy() {}
}
if plls.use_pll {
RCC.cr().modify(|w| w.set_pllon(true));
if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
PWR.cr1().modify(|w| w.set_oden(true));
while !PWR.csr1().read().odrdy() {}
PWR.cr1().modify(|w| w.set_odswen(true));
while !PWR.csr1().read().odswrdy() {}
}
while !RCC.cr().read().pllrdy() {}
}
RCC.cfgr().modify(|w| {
w.set_ppre2(Ppre(ppre2_bits));
w.set_ppre1(Ppre(ppre1_bits));
w.set_hpre(hpre_bits);
});
// Wait for the new prescalers to kick in
// "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
cortex_m::asm::delay(16);
RCC.cfgr().modify(|w| {
w.set_sw(if sysclk_on_pll {
Sw::PLL
} else if config.hse.is_some() {
Sw::HSE
} else {
Sw::HSI
})
});
set_freqs(Clocks {
sys: Hertz(sysclk),
apb1: Hertz(pclk1),
apb2: Hertz(pclk2),
apb1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2),
ahb1: Hertz(hclk),
ahb2: Hertz(hclk),
ahb3: Hertz(hclk),
pll48: plls.pll48clk.map(Hertz),
});
} }
struct PllResults { struct PllResults {

View File

@ -1,9 +1,9 @@
use super::sealed::RccPeripheral;
use crate::pac::pwr::vals::Vos;
use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::peripherals; use crate::rcc::{set_freqs, Clocks};
use crate::rcc::{get_freqs, set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
use core::marker::PhantomData;
use embassy::util::Unborrow;
const HSI: u32 = 16_000_000; const HSI: u32 = 16_000_000;
@ -21,318 +21,274 @@ pub struct Config {
pub pll48: bool, pub pll48: bool,
} }
/// RCC peripheral unsafe fn setup_pll(
pub struct Rcc<'d> { pllsrcclk: u32,
config: Config, use_hse: bool,
phantom: PhantomData<&'d mut peripherals::RCC>, pllsysclk: Option<u32>,
pll48clk: bool,
) -> PllResults {
use crate::pac::rcc::vals::{Pllp, Pllsrc};
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
if pllsysclk.is_none() && !pll48clk {
RCC.pllcfgr()
.modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
return PllResults {
use_pll: false,
pllsysclk: None,
pll48clk: None,
};
}
// Input divisor from PLL source clock, must result to frequency in
// the range from 1 to 2 MHz
let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
let pllm_max = pllsrcclk / 1_000_000;
// Sysclk output divisor must be one of 2, 4, 6 or 8
let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
let target_freq = if pll48clk {
48_000_000
} else {
sysclk * sysclk_div
};
// Find the lowest pllm value that minimize the difference between
// target frequency and the real vco_out frequency.
let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
let vco_in = pllsrcclk / pllm;
let plln = target_freq / vco_in;
target_freq - vco_in * plln
}));
let vco_in = pllsrcclk / pllm;
assert!((1_000_000..=2_000_000).contains(&vco_in));
// Main scaler, must result in >= 100MHz (>= 192MHz for F401)
// and <= 432MHz, min 50, max 432
let plln = if pll48clk {
// try the different valid pllq according to the valid
// main scaller values, and take the best
let pllq = unwrap!((4..=9).min_by_key(|pllq| {
let plln = 48_000_000 * pllq / vco_in;
let pll48_diff = 48_000_000 - vco_in * plln / pllq;
let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
(pll48_diff, sysclk_diff)
}));
48_000_000 * pllq / vco_in
} else {
sysclk * sysclk_div / vco_in
};
let pllp = (sysclk_div / 2) - 1;
let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
let real_pll48clk = vco_in * plln / pllq;
RCC.pllcfgr().modify(|w| {
w.set_pllm(pllm as u8);
w.set_plln(plln as u16);
w.set_pllp(Pllp(pllp as u8));
w.set_pllq(pllq as u8);
w.set_pllsrc(Pllsrc(use_hse as u8));
});
let real_pllsysclk = vco_in * plln / sysclk_div;
PllResults {
use_pll: true,
pllsysclk: Some(real_pllsysclk),
pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
}
} }
impl<'d> Rcc<'d> { unsafe fn flash_setup(sysclk: u32) {
pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self { use crate::pac::flash::vals::Latency;
if let Some(hse) = config.hse {
if config.bypass_hse {
assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0));
} else {
assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0));
}
}
Self {
config,
phantom: PhantomData,
}
}
fn freeze(mut self) -> Clocks { // Be conservative with voltage ranges
use super::sealed::RccPeripheral; const FLASH_LATENCY_STEP: u32 = 30_000_000;
use crate::pac::pwr::vals::Vos;
use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
peripherals::PWR::enable(); critical_section::with(|_| {
FLASH
let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI); .acr()
let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
let sysclk_on_pll = sysclk != pllsrcclk; });
assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk));
let plls = self.setup_pll(
pllsrcclk,
self.config.hse.is_some(),
if sysclk_on_pll { Some(sysclk) } else { None },
self.config.pll48,
);
if self.config.pll48 {
let freq = unwrap!(plls.pll48clk);
assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
}
let sysclk = if sysclk_on_pll {
unwrap!(plls.pllsysclk)
} else {
sysclk
};
// AHB prescaler
let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk);
let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
0 => unreachable!(),
1 => (Hpre::DIV1, 1),
2 => (Hpre::DIV2, 2),
3..=5 => (Hpre::DIV4, 4),
6..=11 => (Hpre::DIV8, 8),
12..=39 => (Hpre::DIV16, 16),
40..=95 => (Hpre::DIV64, 64),
96..=191 => (Hpre::DIV128, 128),
192..=383 => (Hpre::DIV256, 256),
_ => (Hpre::DIV512, 512),
};
// Calculate real AHB clock
let hclk = sysclk / hpre_div;
assert!(hclk < max::HCLK_MAX);
let pclk1 = self
.config
.pclk1
.map(|p| p.0)
.unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
0 => unreachable!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
// Calculate real APB1 clock
let pclk1 = hclk / ppre1;
assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1));
let pclk2 = self
.config
.pclk2
.map(|p| p.0)
.unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
0 => unreachable!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
// Calculate real APB2 clock
let pclk2 = hclk / ppre2;
assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2));
Self::flash_setup(sysclk);
if self.config.hse.is_some() {
// NOTE(unsafe) We own the peripheral block
unsafe {
RCC.cr().modify(|w| {
w.set_hsebyp(Hsebyp(self.config.bypass_hse as u8));
w.set_hseon(true);
});
while !RCC.cr().read().hserdy() {}
}
}
if plls.use_pll {
unsafe {
RCC.cr().modify(|w| w.set_pllon(false));
// enable PWR and setup VOSScale
RCC.apb1enr().modify(|w| w.set_pwren(true));
let vos_scale = if sysclk <= 144_000_000 {
3
} else if sysclk <= 168_000_000 {
2
} else {
1
};
PWR.cr1().modify(|w| {
w.set_vos(match vos_scale {
3 => Vos::SCALE3,
2 => Vos::SCALE2,
1 => Vos::SCALE1,
_ => panic!("Invalid VOS Scale."),
})
});
RCC.cr().modify(|w| w.set_pllon(true));
if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
PWR.cr1().modify(|w| w.set_oden(true));
while !PWR.csr1().read().odrdy() {}
PWR.cr1().modify(|w| w.set_odswen(true));
while !PWR.csr1().read().odswrdy() {}
}
while !RCC.cr().read().pllrdy() {}
}
}
unsafe {
RCC.cfgr().modify(|w| {
w.set_ppre2(Ppre(ppre2_bits));
w.set_ppre1(Ppre(ppre1_bits));
w.set_hpre(hpre_bits);
});
// Wait for the new prescalers to kick in
// "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
cortex_m::asm::delay(16);
RCC.cfgr().modify(|w| {
w.set_sw(if sysclk_on_pll {
Sw::PLL
} else if self.config.hse.is_some() {
Sw::HSE
} else {
Sw::HSI
})
});
}
Clocks {
sys: Hertz(sysclk),
apb1: Hertz(pclk1),
apb2: Hertz(pclk2),
apb1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2),
ahb1: Hertz(hclk),
ahb2: Hertz(hclk),
ahb3: Hertz(hclk),
pll48: plls.pll48clk.map(Hertz),
}
}
// Safety: RCC init must have been called
pub fn clocks(&self) -> &'static Clocks {
unsafe { get_freqs() }
}
fn setup_pll(
&mut self,
pllsrcclk: u32,
use_hse: bool,
pllsysclk: Option<u32>,
pll48clk: bool,
) -> PllResults {
use crate::pac::rcc::vals::{Pllp, Pllsrc};
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
if pllsysclk.is_none() && !pll48clk {
// NOTE(unsafe) We have a mutable borrow to the owner of the RegBlock
unsafe {
RCC.pllcfgr()
.modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
}
return PllResults {
use_pll: false,
pllsysclk: None,
pll48clk: None,
};
}
// Input divisor from PLL source clock, must result to frequency in
// the range from 1 to 2 MHz
let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
let pllm_max = pllsrcclk / 1_000_000;
// Sysclk output divisor must be one of 2, 4, 6 or 8
let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
let target_freq = if pll48clk {
48_000_000
} else {
sysclk * sysclk_div
};
// Find the lowest pllm value that minimize the difference between
// target frequency and the real vco_out frequency.
let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
let vco_in = pllsrcclk / pllm;
let plln = target_freq / vco_in;
target_freq - vco_in * plln
}));
let vco_in = pllsrcclk / pllm;
assert!((1_000_000..=2_000_000).contains(&vco_in));
// Main scaler, must result in >= 100MHz (>= 192MHz for F401)
// and <= 432MHz, min 50, max 432
let plln = if pll48clk {
// try the different valid pllq according to the valid
// main scaller values, and take the best
let pllq = unwrap!((4..=9).min_by_key(|pllq| {
let plln = 48_000_000 * pllq / vco_in;
let pll48_diff = 48_000_000 - vco_in * plln / pllq;
let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
(pll48_diff, sysclk_diff)
}));
48_000_000 * pllq / vco_in
} else {
sysclk * sysclk_div / vco_in
};
let pllp = (sysclk_div / 2) - 1;
let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
let real_pll48clk = vco_in * plln / pllq;
unsafe {
RCC.pllcfgr().modify(|w| {
w.set_pllm(pllm as u8);
w.set_plln(plln as u16);
w.set_pllp(Pllp(pllp as u8));
w.set_pllq(pllq as u8);
w.set_pllsrc(Pllsrc(use_hse as u8));
});
}
let real_pllsysclk = vco_in * plln / sysclk_div;
PllResults {
use_pll: true,
pllsysclk: Some(real_pllsysclk),
pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
}
}
fn flash_setup(sysclk: u32) {
use crate::pac::flash::vals::Latency;
// Be conservative with voltage ranges
const FLASH_LATENCY_STEP: u32 = 30_000_000;
critical_section::with(|_| unsafe {
FLASH
.acr()
.modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
});
}
} }
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let r = <peripherals::RCC as embassy::util::Steal>::steal(); crate::peripherals::PWR::enable();
let clocks = Rcc::new(r, config).freeze();
set_freqs(clocks); if let Some(hse) = config.hse {
if config.bypass_hse {
assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0));
} else {
assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0));
}
}
let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI);
let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
let sysclk_on_pll = sysclk != pllsrcclk;
assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk));
let plls = setup_pll(
pllsrcclk,
config.hse.is_some(),
if sysclk_on_pll { Some(sysclk) } else { None },
config.pll48,
);
if config.pll48 {
let freq = unwrap!(plls.pll48clk);
assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
}
let sysclk = if sysclk_on_pll {
unwrap!(plls.pllsysclk)
} else {
sysclk
};
// AHB prescaler
let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
0 => unreachable!(),
1 => (Hpre::DIV1, 1),
2 => (Hpre::DIV2, 2),
3..=5 => (Hpre::DIV4, 4),
6..=11 => (Hpre::DIV8, 8),
12..=39 => (Hpre::DIV16, 16),
40..=95 => (Hpre::DIV64, 64),
96..=191 => (Hpre::DIV128, 128),
192..=383 => (Hpre::DIV256, 256),
_ => (Hpre::DIV512, 512),
};
// Calculate real AHB clock
let hclk = sysclk / hpre_div;
assert!(hclk < max::HCLK_MAX);
let pclk1 = config
.pclk1
.map(|p| p.0)
.unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
0 => unreachable!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
// Calculate real APB1 clock
let pclk1 = hclk / ppre1;
assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1));
let pclk2 = config
.pclk2
.map(|p| p.0)
.unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
0 => unreachable!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
// Calculate real APB2 clock
let pclk2 = hclk / ppre2;
assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2));
flash_setup(sysclk);
if config.hse.is_some() {
RCC.cr().modify(|w| {
w.set_hsebyp(Hsebyp(config.bypass_hse as u8));
w.set_hseon(true);
});
while !RCC.cr().read().hserdy() {}
}
if plls.use_pll {
RCC.cr().modify(|w| w.set_pllon(false));
// enable PWR and setup VOSScale
RCC.apb1enr().modify(|w| w.set_pwren(true));
let vos_scale = if sysclk <= 144_000_000 {
3
} else if sysclk <= 168_000_000 {
2
} else {
1
};
PWR.cr1().modify(|w| {
w.set_vos(match vos_scale {
3 => Vos::SCALE3,
2 => Vos::SCALE2,
1 => Vos::SCALE1,
_ => panic!("Invalid VOS Scale."),
})
});
RCC.cr().modify(|w| w.set_pllon(true));
if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
PWR.cr1().modify(|w| w.set_oden(true));
while !PWR.csr1().read().odrdy() {}
PWR.cr1().modify(|w| w.set_odswen(true));
while !PWR.csr1().read().odswrdy() {}
}
while !RCC.cr().read().pllrdy() {}
}
RCC.cfgr().modify(|w| {
w.set_ppre2(Ppre(ppre2_bits));
w.set_ppre1(Ppre(ppre1_bits));
w.set_hpre(hpre_bits);
});
// Wait for the new prescalers to kick in
// "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
cortex_m::asm::delay(16);
RCC.cfgr().modify(|w| {
w.set_sw(if sysclk_on_pll {
Sw::PLL
} else if config.hse.is_some() {
Sw::HSE
} else {
Sw::HSI
})
});
set_freqs(Clocks {
sys: Hertz(sysclk),
apb1: Hertz(pclk1),
apb2: Hertz(pclk2),
apb1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2),
ahb1: Hertz(hclk),
ahb2: Hertz(hclk),
ahb3: Hertz(hclk),
pll48: plls.pll48clk.map(Hertz),
});
} }
struct PllResults { struct PllResults {

View File

@ -1,11 +1,7 @@
use crate::pac; use crate::pac::{PWR, RCC};
use crate::peripherals::{self, RCC}; use crate::rcc::{set_freqs, Clocks};
use crate::rcc::{get_freqs, set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
use crate::time::U32Ext; use crate::time::U32Ext;
use core::marker::PhantomData;
use embassy::util::Unborrow;
use embassy_hal_common::unborrow;
/// HSI speed /// HSI speed
pub const HSI_FREQ: u32 = 16_000_000; pub const HSI_FREQ: u32 = 16_000_000;
@ -120,115 +116,68 @@ impl Default for Config {
} }
} }
/// RCC peripheral
pub struct Rcc<'d> {
_rb: peripherals::RCC,
phantom: PhantomData<&'d mut peripherals::RCC>,
}
impl<'d> Rcc<'d> {
pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
unborrow!(rcc);
Self {
_rb: rcc,
phantom: PhantomData,
}
}
// Safety: RCC init must have been called
pub fn clocks(&self) -> &'static Clocks {
unsafe { get_freqs() }
}
}
/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
pub trait RccExt {
fn freeze(self, config: Config) -> Clocks;
}
impl RccExt for RCC {
#[inline]
fn freeze(self, cfgr: Config) -> Clocks {
let rcc = pac::RCC;
let (sys_clk, sw) = match cfgr.mux {
ClockSrc::HSI16(div) => {
// Enable HSI16
let div: u8 = div.into();
unsafe {
rcc.cr().write(|w| {
w.set_hsidiv(div);
w.set_hsion(true)
});
while !rcc.cr().read().hsirdy() {}
}
(HSI_FREQ >> div, 0x00)
}
ClockSrc::HSE(freq) => {
// Enable HSE
unsafe {
rcc.cr().write(|w| w.set_hseon(true));
while !rcc.cr().read().hserdy() {}
}
(freq.0, 0x01)
}
ClockSrc::LSI => {
// Enable LSI
unsafe {
rcc.csr().write(|w| w.set_lsion(true));
while !rcc.csr().read().lsirdy() {}
}
(LSI_FREQ, 0x03)
}
};
unsafe {
rcc.cfgr().modify(|w| {
w.set_sw(sw.into());
w.set_hpre(cfgr.ahb_pre.into());
w.set_ppre(cfgr.apb_pre.into());
});
}
let ahb_freq: u32 = match cfgr.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1 << (pre as u32 - 7);
sys_clk / pre
}
};
let (apb_freq, apb_tim_freq) = match cfgr.apb_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let pwr = pac::PWR;
if cfgr.low_power_run {
assert!(sys_clk.hz() <= 2_000_000.hz());
unsafe {
pwr.cr1().modify(|w| w.set_lpr(true));
}
}
Clocks {
sys: sys_clk.hz(),
ahb: ahb_freq.hz(),
apb: apb_freq.hz(),
apb_tim: apb_tim_freq.hz(),
}
}
}
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let r = <peripherals::RCC as embassy::util::Steal>::steal(); let (sys_clk, sw) = match config.mux {
let clocks = r.freeze(config); ClockSrc::HSI16(div) => {
set_freqs(clocks); // Enable HSI16
let div: u8 = div.into();
RCC.cr().write(|w| {
w.set_hsidiv(div);
w.set_hsion(true)
});
while !RCC.cr().read().hsirdy() {}
(HSI_FREQ >> div, 0x00)
}
ClockSrc::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
(freq.0, 0x01)
}
ClockSrc::LSI => {
// Enable LSI
RCC.csr().write(|w| w.set_lsion(true));
while !RCC.csr().read().lsirdy() {}
(LSI_FREQ, 0x03)
}
};
RCC.cfgr().modify(|w| {
w.set_sw(sw.into());
w.set_hpre(config.ahb_pre.into());
w.set_ppre(config.apb_pre.into());
});
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1 << (pre as u32 - 7);
sys_clk / pre
}
};
let (apb_freq, apb_tim_freq) = match config.apb_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
if config.low_power_run {
assert!(sys_clk.hz() <= 2_000_000.hz());
PWR.cr1().modify(|w| w.set_lpr(true));
}
set_freqs(Clocks {
sys: sys_clk.hz(),
ahb: ahb_freq.hz(),
apb: apb_freq.hz(),
apb_tim: apb_tim_freq.hz(),
});
} }

View File

@ -1,11 +1,7 @@
use crate::pac; use crate::pac::{PWR, RCC};
use crate::peripherals::{self, RCC}; use crate::rcc::{set_freqs, Clocks};
use crate::rcc::{get_freqs, set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
use crate::time::U32Ext; use crate::time::U32Ext;
use core::marker::PhantomData;
use embassy::util::Unborrow;
use embassy_hal_common::unborrow;
/// HSI speed /// HSI speed
pub const HSI_FREQ: u32 = 16_000_000; pub const HSI_FREQ: u32 = 16_000_000;
@ -94,117 +90,72 @@ impl Default for Config {
} }
} }
/// RCC peripheral
pub struct Rcc<'d> {
_rb: peripherals::RCC,
phantom: PhantomData<&'d mut peripherals::RCC>,
}
impl<'d> Rcc<'d> {
pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
unborrow!(rcc);
Self {
_rb: rcc,
phantom: PhantomData,
}
}
// Safety: RCC init must have been called
pub fn clocks(&self) -> &'static Clocks {
unsafe { get_freqs() }
}
}
/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
pub trait RccExt {
fn freeze(self, config: Config) -> Clocks;
}
impl RccExt for RCC {
#[inline]
fn freeze(self, cfgr: Config) -> Clocks {
let rcc = pac::RCC;
let (sys_clk, sw) = match cfgr.mux {
ClockSrc::HSI16 => {
// Enable HSI16
unsafe {
rcc.cr().write(|w| w.set_hsion(true));
while !rcc.cr().read().hsirdy() {}
}
(HSI_FREQ, 0x01)
}
ClockSrc::HSE(freq) => {
// Enable HSE
unsafe {
rcc.cr().write(|w| w.set_hseon(true));
while !rcc.cr().read().hserdy() {}
}
(freq.0, 0x02)
}
};
unsafe {
rcc.cfgr().modify(|w| {
w.set_sw(sw.into());
w.set_hpre(cfgr.ahb_pre.into());
w.set_ppre1(cfgr.apb1_pre.into());
w.set_ppre2(cfgr.apb2_pre.into());
});
}
let ahb_freq: u32 = match cfgr.ahb_pre {
AHBPrescaler::NotDivided => 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 cfgr.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let pwr = pac::PWR;
if cfgr.low_power_run {
assert!(sys_clk.hz() <= 2_000_000.hz());
unsafe {
pwr.cr1().modify(|w| w.set_lpr(true));
}
}
Clocks {
sys: sys_clk.hz(),
ahb1: ahb_freq.hz(),
ahb2: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2: apb2_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
}
}
}
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let r = <peripherals::RCC as embassy::util::Steal>::steal(); let (sys_clk, sw) = match config.mux {
let clocks = r.freeze(config); ClockSrc::HSI16 => {
set_freqs(clocks); // Enable HSI16
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
(HSI_FREQ, 0x01)
}
ClockSrc::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
(freq.0, 0x02)
}
};
RCC.cfgr().modify(|w| {
w.set_sw(sw.into());
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::NotDivided => 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 {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
if config.low_power_run {
assert!(sys_clk.hz() <= 2_000_000.hz());
PWR.cr1().modify(|w| w.set_lpr(true));
}
set_freqs(Clocks {
sys: sys_clk.hz(),
ahb1: ahb_freq.hz(),
ahb2: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2: apb2_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
});
} }

View File

@ -7,9 +7,9 @@ use stm32_metapac::rcc::vals::{Mco1, Mco2};
use crate::gpio::sealed::Pin as __GpioPin; use crate::gpio::sealed::Pin as __GpioPin;
use crate::gpio::Pin; use crate::gpio::Pin;
use crate::pac::rcc::vals::Timpre; use crate::pac::rcc::vals::Timpre;
use crate::pac::{RCC, SYSCFG}; use crate::pac::rcc::vals::{Ckpersel, Dppre, Hpre, Hsebyp, Hsidiv, Pllsrc, Sw};
use crate::pac::{PWR, RCC, SYSCFG};
use crate::peripherals; use crate::peripherals;
use crate::pwr::{Power, VoltageScale};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -20,6 +20,22 @@ const CSI: Hertz = Hertz(4_000_000);
const HSI48: Hertz = Hertz(48_000_000); const HSI48: Hertz = Hertz(48_000_000);
const LSI: Hertz = Hertz(32_000); const LSI: Hertz = Hertz(32_000);
/// Voltage Scale
///
/// Represents the voltage range feeding the CPU core. The maximum core
/// clock frequency depends on this value.
#[derive(Copy, Clone, PartialEq)]
pub enum VoltageScale {
/// VOS 0 range VCORE 1.26V - 1.40V
Scale0,
/// VOS 1 range VCORE 1.15V - 1.26V
Scale1,
/// VOS 2 range VCORE 1.05V - 1.15V
Scale2,
/// VOS 3 range VCORE 0.95V - 1.05V
Scale3,
}
/// Core clock frequencies /// Core clock frequencies
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct CoreClocks { pub struct CoreClocks {
@ -72,439 +88,151 @@ pub struct Config {
pub pll3: PllConfig, pub pll3: PllConfig,
} }
pub struct Rcc<'d> { /// Setup traceclk
inner: PhantomData<&'d ()>, /// Returns a pll1_r_ck
config: Config, fn traceclk_setup(config: &mut Config, sys_use_pll1_p: bool) {
let pll1_r_ck = match (sys_use_pll1_p, config.pll1.r_ck) {
// pll1_p_ck selected as system clock but pll1_r_ck not
// set. The traceclk mux is synchronous with the system
// clock mux, but has pll1_r_ck as an input. In order to
// keep traceclk running, we force a pll1_r_ck.
(true, None) => Some(Hertz(unwrap!(config.pll1.p_ck).0 / 2)),
// Either pll1 not selected as system clock, free choice
// of pll1_r_ck. Or pll1 is selected, assume user has set
// a suitable pll1_r_ck frequency.
_ => config.pll1.r_ck,
};
config.pll1.r_ck = pll1_r_ck;
} }
impl<'d> Rcc<'d> { /// Divider calculator for pclk 1 - 4
pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self { ///
Self { /// Returns real pclk, bits, ppre and the timer kernel clock
inner: PhantomData, fn ppre_calculate(
config, requested_pclk: u32,
} hclk: u32,
} max_pclk: u32,
tim_pre: Option<Timpre>,
) -> (u32, u8, u8, Option<u32>) {
let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk {
0 => panic!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let real_pclk = hclk / u32::from(ppre);
assert!(real_pclk <= max_pclk);
/// Freeze the core clocks, returning a Core Clocks Distribution let tim_ker_clk = if let Some(tim_pre) = tim_pre {
/// and Reset (CCDR) structure. The actual frequency of the clocks let clk = match (bits, tim_pre) {
/// configured is returned in the `clocks` member of the CCDR (0b101, Timpre::DEFAULTX2) => hclk / 2,
/// structure. (0b110, Timpre::DEFAULTX4) => hclk / 2,
/// (0b110, Timpre::DEFAULTX2) => hclk / 4,
/// Note that `freeze` will never result in a clock _faster_ than (0b111, Timpre::DEFAULTX4) => hclk / 4,
/// that specified. It may result in a clock that is a factor of [1, (0b111, Timpre::DEFAULTX2) => hclk / 8,
/// 2) slower. _ => hclk,
///
/// `syscfg` is required to enable the I/O compensation cell.
///
/// # Panics
///
/// If a clock specification cannot be achieved within the
/// hardware specification then this function will panic. This
/// function may also panic if a clock specification can be
/// achieved, but the mechanism for doing so is not yet
/// implemented here.
pub fn freeze(mut self, pwr: &Power) -> CoreClocks {
use crate::pac::rcc::vals::{Ckpersel, Dppre, Hpre, Hsebyp, Hsidiv, Pllsrc, Sw};
let srcclk = self.config.hse.unwrap_or(HSI); // Available clocks
let (sys_ck, sys_use_pll1_p) = self.sys_ck_setup(srcclk);
// Configure traceclk from PLL if needed
self.traceclk_setup(sys_use_pll1_p);
// NOTE(unsafe) We have exclusive access to the RCC
let (pll1_p_ck, pll1_q_ck, pll1_r_ck) =
unsafe { pll::pll_setup(srcclk.0, &self.config.pll1, 0) };
let (pll2_p_ck, pll2_q_ck, pll2_r_ck) =
unsafe { pll::pll_setup(srcclk.0, &self.config.pll2, 1) };
let (pll3_p_ck, pll3_q_ck, pll3_r_ck) =
unsafe { pll::pll_setup(srcclk.0, &self.config.pll3, 2) };
let sys_ck = if sys_use_pll1_p {
Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
} else {
sys_ck
}; };
Some(clk)
} else {
None
};
(real_pclk, bits, ppre, tim_ker_clk)
}
// NOTE(unsafe) We own the regblock /// Setup sys_ck
unsafe { /// Returns sys_ck frequency, and a pll1_p_ck
// This routine does not support HSIDIV != 1. To fn sys_ck_setup(config: &mut Config, srcclk: Hertz) -> (Hertz, bool) {
// do so it would need to ensure all PLLxON bits are clear // Compare available with wanted clocks
// before changing the value of HSIDIV let sys_ck = config.sys_ck.unwrap_or(srcclk);
let cr = RCC.cr().read();
assert!(cr.hsion());
assert!(cr.hsidiv() == Hsidiv::DIV1);
RCC.csr().modify(|w| w.set_lsion(true)); if sys_ck != srcclk {
while !RCC.csr().read().lsirdy() {} // The requested system clock is not the immediately available
} // HSE/HSI clock. Perhaps there are other ways of obtaining
// the requested system clock (such as `HSIDIV`) but we will
// per_ck from HSI by default // ignore those for now.
let (per_ck, ckpersel) = match (self.config.per_ck == self.config.hse, self.config.per_ck) { //
(true, Some(hse)) => (hse, Ckpersel::HSE), // HSE // Therefore we must use pll1_p_ck
(_, Some(CSI)) => (CSI, Ckpersel::CSI), // CSI let pll1_p_ck = match config.pll1.p_ck {
_ => (HSI, Ckpersel::HSI), // HSI Some(p_ck) => {
}; assert!(p_ck == sys_ck,
// D1 Core Prescaler
// Set to 1
let d1cpre_bits = 0;
let d1cpre_div = 1;
let sys_d1cpre_ck = sys_ck.0 / d1cpre_div;
// Refer to part datasheet "General operating conditions"
// table for (rev V). We do not assert checks for earlier
// revisions which may have lower limits.
let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr.vos {
VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000),
VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000),
VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000),
_ => (200_000_000, 100_000_000, 50_000_000),
};
assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max);
let rcc_hclk = self
.config
.rcc_hclk
.map(|v| v.0)
.unwrap_or(sys_d1cpre_ck / 2);
assert!(rcc_hclk <= rcc_hclk_max);
// Estimate divisor
let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk {
0 => panic!(),
1 => (Hpre::DIV1, 1),
2 => (Hpre::DIV2, 2),
3..=5 => (Hpre::DIV4, 4),
6..=11 => (Hpre::DIV8, 8),
12..=39 => (Hpre::DIV16, 16),
40..=95 => (Hpre::DIV64, 64),
96..=191 => (Hpre::DIV128, 128),
192..=383 => (Hpre::DIV256, 256),
_ => (Hpre::DIV512, 512),
};
// Calculate real AXI and AHB clock
let rcc_hclk = sys_d1cpre_ck / hpre_div;
assert!(rcc_hclk <= rcc_hclk_max);
let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7
// Timer prescaler selection
let timpre = Timpre::DEFAULTX2;
let requested_pclk1 = self
.config
.pclk1
.map(|v| v.0)
.unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) =
Self::ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre));
let requested_pclk2 = self
.config
.pclk2
.map(|v| v.0)
.unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) =
Self::ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre));
let requested_pclk3 = self
.config
.pclk3
.map(|v| v.0)
.unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
let (rcc_pclk3, ppre3_bits, ppre3, _) =
Self::ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None);
let requested_pclk4 = self
.config
.pclk4
.map(|v| v.0)
.unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
let (rcc_pclk4, ppre4_bits, ppre4, _) =
Self::ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None);
Self::flash_setup(rcc_aclk, pwr.vos);
// Start switching clocks -------------------
// NOTE(unsafe) We have the RCC singleton
unsafe {
// Ensure CSI is on and stable
RCC.cr().modify(|w| w.set_csion(true));
while !RCC.cr().read().csirdy() {}
// Ensure HSI48 is on and stable
RCC.cr().modify(|w| w.set_hsi48on(true));
while !RCC.cr().read().hsi48on() {}
// XXX: support MCO ?
let hse_ck = match self.config.hse {
Some(hse) => {
// Ensure HSE is on and stable
RCC.cr().modify(|w| {
w.set_hseon(true);
w.set_hsebyp(if self.config.bypass_hse {
Hsebyp::BYPASSED
} else {
Hsebyp::NOTBYPASSED
});
});
while !RCC.cr().read().hserdy() {}
Some(hse)
}
None => None,
};
let pllsrc = if self.config.hse.is_some() {
Pllsrc::HSE
} else {
Pllsrc::HSI
};
RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc));
let enable_pll = |pll| {
RCC.cr().modify(|w| w.set_pllon(pll, true));
while !RCC.cr().read().pllrdy(pll) {}
};
if pll1_p_ck.is_some() {
enable_pll(0);
}
if pll2_p_ck.is_some() {
enable_pll(1);
}
if pll3_p_ck.is_some() {
enable_pll(2);
}
// Core Prescaler / AHB Prescaler / APB3 Prescaler
RCC.d1cfgr().modify(|w| {
w.set_d1cpre(Hpre(d1cpre_bits));
w.set_d1ppre(Dppre(ppre3_bits));
w.set_hpre(hpre_bits)
});
// Ensure core prescaler value is valid before future lower
// core voltage
while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {}
// APB1 / APB2 Prescaler
RCC.d2cfgr().modify(|w| {
w.set_d2ppre1(Dppre(ppre1_bits));
w.set_d2ppre2(Dppre(ppre2_bits));
});
// APB4 Prescaler
RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits)));
// Peripheral Clock (per_ck)
RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
// Set timer clocks prescaler setting
RCC.cfgr().modify(|w| w.set_timpre(timpre));
// Select system clock source
let sw = match (sys_use_pll1_p, self.config.hse.is_some()) {
(true, _) => Sw::PLL1,
(false, true) => Sw::HSE,
_ => Sw::HSI,
};
RCC.cfgr().modify(|w| w.set_sw(sw));
while RCC.cfgr().read().sws() != sw.0 {}
// IO compensation cell - Requires CSI clock and SYSCFG
assert!(RCC.cr().read().csirdy());
RCC.apb4enr().modify(|w| w.set_syscfgen(true));
// Enable the compensation cell, using back-bias voltage code
// provide by the cell.
critical_section::with(|_| {
SYSCFG.cccsr().modify(|w| {
w.set_en(true);
w.set_cs(false);
w.set_hslv(false);
})
});
while !SYSCFG.cccsr().read().ready() {}
CoreClocks {
hclk: Hertz(rcc_hclk),
pclk1: Hertz(rcc_pclk1),
pclk2: Hertz(rcc_pclk2),
pclk3: Hertz(rcc_pclk3),
pclk4: Hertz(rcc_pclk4),
ppre1,
ppre2,
ppre3,
ppre4,
csi_ck: Some(CSI),
hsi_ck: Some(HSI),
hsi48_ck: Some(HSI48),
lsi_ck: Some(LSI),
per_ck: Some(per_ck),
hse_ck,
pll1_p_ck: pll1_p_ck.map(Hertz),
pll1_q_ck: pll1_q_ck.map(Hertz),
pll1_r_ck: pll1_r_ck.map(Hertz),
pll2_p_ck: pll2_p_ck.map(Hertz),
pll2_q_ck: pll2_q_ck.map(Hertz),
pll2_r_ck: pll2_r_ck.map(Hertz),
pll3_p_ck: pll3_p_ck.map(Hertz),
pll3_q_ck: pll3_q_ck.map(Hertz),
pll3_r_ck: pll3_r_ck.map(Hertz),
timx_ker_ck: rcc_timerx_ker_ck.map(Hertz),
timy_ker_ck: rcc_timery_ker_ck.map(Hertz),
sys_ck,
c_ck: Hertz(sys_d1cpre_ck),
}
}
}
/// Setup traceclk
/// Returns a pll1_r_ck
fn traceclk_setup(&mut self, sys_use_pll1_p: bool) {
let pll1_r_ck = match (sys_use_pll1_p, self.config.pll1.r_ck) {
// pll1_p_ck selected as system clock but pll1_r_ck not
// set. The traceclk mux is synchronous with the system
// clock mux, but has pll1_r_ck as an input. In order to
// keep traceclk running, we force a pll1_r_ck.
(true, None) => Some(Hertz(unwrap!(self.config.pll1.p_ck).0 / 2)),
// Either pll1 not selected as system clock, free choice
// of pll1_r_ck. Or pll1 is selected, assume user has set
// a suitable pll1_r_ck frequency.
_ => self.config.pll1.r_ck,
};
self.config.pll1.r_ck = pll1_r_ck;
}
/// Divider calculator for pclk 1 - 4
///
/// Returns real pclk, bits, ppre and the timer kernel clock
fn ppre_calculate(
requested_pclk: u32,
hclk: u32,
max_pclk: u32,
tim_pre: Option<Timpre>,
) -> (u32, u8, u8, Option<u32>) {
let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk {
0 => panic!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let real_pclk = hclk / u32::from(ppre);
assert!(real_pclk <= max_pclk);
let tim_ker_clk = if let Some(tim_pre) = tim_pre {
let clk = match (bits, tim_pre) {
(0b101, Timpre::DEFAULTX2) => hclk / 2,
(0b110, Timpre::DEFAULTX4) => hclk / 2,
(0b110, Timpre::DEFAULTX2) => hclk / 4,
(0b111, Timpre::DEFAULTX4) => hclk / 4,
(0b111, Timpre::DEFAULTX2) => hclk / 8,
_ => hclk,
};
Some(clk)
} else {
None
};
(real_pclk, bits, ppre, tim_ker_clk)
}
/// Setup sys_ck
/// Returns sys_ck frequency, and a pll1_p_ck
fn sys_ck_setup(&mut self, srcclk: Hertz) -> (Hertz, bool) {
// Compare available with wanted clocks
let sys_ck = self.config.sys_ck.unwrap_or(srcclk);
if sys_ck != srcclk {
// The requested system clock is not the immediately available
// HSE/HSI clock. Perhaps there are other ways of obtaining
// the requested system clock (such as `HSIDIV`) but we will
// ignore those for now.
//
// Therefore we must use pll1_p_ck
let pll1_p_ck = match self.config.pll1.p_ck {
Some(p_ck) => {
assert!(p_ck == sys_ck,
"Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck"); "Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck");
Some(p_ck) Some(p_ck)
} }
None => Some(sys_ck), None => Some(sys_ck),
};
self.config.pll1.p_ck = pll1_p_ck;
(sys_ck, true)
} else {
// sys_ck is derived directly from a source clock
// (HSE/HSI). pll1_p_ck can be as requested
(sys_ck, false)
}
}
fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
use crate::pac::FLASH;
// ACLK in MHz, round down and subtract 1 from integers. eg.
// 61_999_999 -> 61MHz
// 62_000_000 -> 61MHz
// 62_000_001 -> 62MHz
let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000;
// See RM0433 Rev 7 Table 17. FLASH recommended number of wait
// states and programming delay
let (wait_states, progr_delay) = match vos {
// VOS 0 range VCORE 1.26V - 1.40V
VoltageScale::Scale0 => match rcc_aclk_mhz {
0..=69 => (0, 0),
70..=139 => (1, 1),
140..=184 => (2, 1),
185..=209 => (2, 2),
210..=224 => (3, 2),
225..=239 => (4, 2),
_ => (7, 3),
},
// VOS 1 range VCORE 1.15V - 1.26V
VoltageScale::Scale1 => match rcc_aclk_mhz {
0..=69 => (0, 0),
70..=139 => (1, 1),
140..=184 => (2, 1),
185..=209 => (2, 2),
210..=224 => (3, 2),
_ => (7, 3),
},
// VOS 2 range VCORE 1.05V - 1.15V
VoltageScale::Scale2 => match rcc_aclk_mhz {
0..=54 => (0, 0),
55..=109 => (1, 1),
110..=164 => (2, 1),
165..=224 => (3, 2),
_ => (7, 3),
},
// VOS 3 range VCORE 0.95V - 1.05V
VoltageScale::Scale3 => match rcc_aclk_mhz {
0..=44 => (0, 0),
45..=89 => (1, 1),
90..=134 => (2, 1),
135..=179 => (3, 2),
180..=224 => (4, 2),
_ => (7, 3),
},
}; };
config.pll1.p_ck = pll1_p_ck;
// NOTE(unsafe) Atomic write (sys_ck, true)
unsafe { } else {
FLASH.acr().write(|w| { // sys_ck is derived directly from a source clock
w.set_wrhighfreq(progr_delay); // (HSE/HSI). pll1_p_ck can be as requested
w.set_latency(wait_states) (sys_ck, false)
});
while FLASH.acr().read().latency() != wait_states {}
}
} }
} }
fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
use crate::pac::FLASH;
// ACLK in MHz, round down and subtract 1 from integers. eg.
// 61_999_999 -> 61MHz
// 62_000_000 -> 61MHz
// 62_000_001 -> 62MHz
let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000;
// See RM0433 Rev 7 Table 17. FLASH recommended number of wait
// states and programming delay
let (wait_states, progr_delay) = match vos {
// VOS 0 range VCORE 1.26V - 1.40V
VoltageScale::Scale0 => match rcc_aclk_mhz {
0..=69 => (0, 0),
70..=139 => (1, 1),
140..=184 => (2, 1),
185..=209 => (2, 2),
210..=224 => (3, 2),
225..=239 => (4, 2),
_ => (7, 3),
},
// VOS 1 range VCORE 1.15V - 1.26V
VoltageScale::Scale1 => match rcc_aclk_mhz {
0..=69 => (0, 0),
70..=139 => (1, 1),
140..=184 => (2, 1),
185..=209 => (2, 2),
210..=224 => (3, 2),
_ => (7, 3),
},
// VOS 2 range VCORE 1.05V - 1.15V
VoltageScale::Scale2 => match rcc_aclk_mhz {
0..=54 => (0, 0),
55..=109 => (1, 1),
110..=164 => (2, 1),
165..=224 => (3, 2),
_ => (7, 3),
},
// VOS 3 range VCORE 0.95V - 1.05V
VoltageScale::Scale3 => match rcc_aclk_mhz {
0..=44 => (0, 0),
45..=89 => (1, 1),
90..=134 => (2, 1),
135..=179 => (3, 2),
180..=224 => (4, 2),
_ => (7, 3),
},
};
// NOTE(unsafe) Atomic write
unsafe {
FLASH.acr().write(|w| {
w.set_wrhighfreq(progr_delay);
w.set_latency(wait_states)
});
while FLASH.acr().read().latency() != wait_states {}
}
}
pub enum McoClock { pub enum McoClock {
Disabled, Disabled,
Bypassed, Bypassed,
@ -681,10 +409,309 @@ impl<'d, T: McoInstance> Mco<'d, T> {
} }
} }
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(mut config: Config) {
let mut power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal(), false); // TODO make configurable?
let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config); let enable_overdrive = false;
let core_clocks = rcc.freeze(&mut power);
// NB. The lower bytes of CR3 can only be written once after
// POR, and must be written with a valid combination. Refer to
// RM0433 Rev 7 6.8.4. This is partially enforced by dropping
// `self` at the end of this method, but of course we cannot
// know what happened between the previous POR and here.
#[cfg(pwr_h7)]
PWR.cr3().modify(|w| {
w.set_scuen(true);
w.set_ldoen(true);
w.set_bypass(false);
});
#[cfg(pwr_h7smps)]
PWR.cr3().modify(|w| {
// hardcode "Direct SPMS" for now, this is what works on nucleos with the
// default solderbridge configuration.
w.set_sden(true);
w.set_ldoen(false);
});
// Validate the supply configuration. If you are stuck here, it is
// because the voltages on your board do not match those specified
// in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
// VOS = Scale 3, so check that the voltage on the VCAP pins =
// 1.0V.
while !PWR.csr1().read().actvosrdy() {}
// Go to Scale 1
PWR.d3cr().modify(|w| w.set_vos(0b11));
while !PWR.d3cr().read().vosrdy() {}
let pwr_vos = if !enable_overdrive {
VoltageScale::Scale1
} else {
critical_section::with(|_| {
RCC.apb4enr().modify(|w| w.set_syscfgen(true));
SYSCFG.pwrcr().modify(|w| w.set_oden(1));
});
while !PWR.d3cr().read().vosrdy() {}
VoltageScale::Scale0
};
// Freeze the core clocks, returning a Core Clocks Distribution
// and Reset (CCDR) structure. The actual frequency of the clocks
// configured is returned in the `clocks` member of the CCDR
// structure.
//
// Note that `freeze` will never result in a clock _faster_ than
// that specified. It may result in a clock that is a factor of [1,
// 2) slower.
//
// `syscfg` is required to enable the I/O compensation cell.
//
// # Panics
//
// If a clock specification cannot be achieved within the
// hardware specification then this function will panic. This
// function may also panic if a clock specification can be
// achieved, but the mechanism for doing so is not yet
// implemented here.
let srcclk = config.hse.unwrap_or(HSI); // Available clocks
let (sys_ck, sys_use_pll1_p) = sys_ck_setup(&mut config, srcclk);
// Configure traceclk from PLL if needed
traceclk_setup(&mut config, sys_use_pll1_p);
// NOTE(unsafe) We have exclusive access to the RCC
let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0);
let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1);
let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2);
let sys_ck = if sys_use_pll1_p {
Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
} else {
sys_ck
};
// This routine does not support HSIDIV != 1. To
// do so it would need to ensure all PLLxON bits are clear
// before changing the value of HSIDIV
let cr = RCC.cr().read();
assert!(cr.hsion());
assert!(cr.hsidiv() == Hsidiv::DIV1);
RCC.csr().modify(|w| w.set_lsion(true));
while !RCC.csr().read().lsirdy() {}
// per_ck from HSI by default
let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) {
(true, Some(hse)) => (hse, Ckpersel::HSE), // HSE
(_, Some(CSI)) => (CSI, Ckpersel::CSI), // CSI
_ => (HSI, Ckpersel::HSI), // HSI
};
// D1 Core Prescaler
// Set to 1
let d1cpre_bits = 0;
let d1cpre_div = 1;
let sys_d1cpre_ck = sys_ck.0 / d1cpre_div;
// Refer to part datasheet "General operating conditions"
// table for (rev V). We do not assert checks for earlier
// revisions which may have lower limits.
let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr_vos {
VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000),
VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000),
VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000),
_ => (200_000_000, 100_000_000, 50_000_000),
};
assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max);
let rcc_hclk = config.rcc_hclk.map(|v| v.0).unwrap_or(sys_d1cpre_ck / 2);
assert!(rcc_hclk <= rcc_hclk_max);
// Estimate divisor
let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk {
0 => panic!(),
1 => (Hpre::DIV1, 1),
2 => (Hpre::DIV2, 2),
3..=5 => (Hpre::DIV4, 4),
6..=11 => (Hpre::DIV8, 8),
12..=39 => (Hpre::DIV16, 16),
40..=95 => (Hpre::DIV64, 64),
96..=191 => (Hpre::DIV128, 128),
192..=383 => (Hpre::DIV256, 256),
_ => (Hpre::DIV512, 512),
};
// Calculate real AXI and AHB clock
let rcc_hclk = sys_d1cpre_ck / hpre_div;
assert!(rcc_hclk <= rcc_hclk_max);
let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7
// Timer prescaler selection
let timpre = Timpre::DEFAULTX2;
let requested_pclk1 = config
.pclk1
.map(|v| v.0)
.unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) =
ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre));
let requested_pclk2 = config
.pclk2
.map(|v| v.0)
.unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) =
ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre));
let requested_pclk3 = config
.pclk3
.map(|v| v.0)
.unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
let (rcc_pclk3, ppre3_bits, ppre3, _) =
ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None);
let requested_pclk4 = config
.pclk4
.map(|v| v.0)
.unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
let (rcc_pclk4, ppre4_bits, ppre4, _) =
ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None);
flash_setup(rcc_aclk, pwr_vos);
// Start switching clocks -------------------
// Ensure CSI is on and stable
RCC.cr().modify(|w| w.set_csion(true));
while !RCC.cr().read().csirdy() {}
// Ensure HSI48 is on and stable
RCC.cr().modify(|w| w.set_hsi48on(true));
while !RCC.cr().read().hsi48on() {}
// XXX: support MCO ?
let hse_ck = match config.hse {
Some(hse) => {
// Ensure HSE is on and stable
RCC.cr().modify(|w| {
w.set_hseon(true);
w.set_hsebyp(if config.bypass_hse {
Hsebyp::BYPASSED
} else {
Hsebyp::NOTBYPASSED
});
});
while !RCC.cr().read().hserdy() {}
Some(hse)
}
None => None,
};
let pllsrc = if config.hse.is_some() {
Pllsrc::HSE
} else {
Pllsrc::HSI
};
RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc));
let enable_pll = |pll| {
RCC.cr().modify(|w| w.set_pllon(pll, true));
while !RCC.cr().read().pllrdy(pll) {}
};
if pll1_p_ck.is_some() {
enable_pll(0);
}
if pll2_p_ck.is_some() {
enable_pll(1);
}
if pll3_p_ck.is_some() {
enable_pll(2);
}
// Core Prescaler / AHB Prescaler / APB3 Prescaler
RCC.d1cfgr().modify(|w| {
w.set_d1cpre(Hpre(d1cpre_bits));
w.set_d1ppre(Dppre(ppre3_bits));
w.set_hpre(hpre_bits)
});
// Ensure core prescaler value is valid before future lower
// core voltage
while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {}
// APB1 / APB2 Prescaler
RCC.d2cfgr().modify(|w| {
w.set_d2ppre1(Dppre(ppre1_bits));
w.set_d2ppre2(Dppre(ppre2_bits));
});
// APB4 Prescaler
RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits)));
// Peripheral Clock (per_ck)
RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
// Set timer clocks prescaler setting
RCC.cfgr().modify(|w| w.set_timpre(timpre));
// Select system clock source
let sw = match (sys_use_pll1_p, config.hse.is_some()) {
(true, _) => Sw::PLL1,
(false, true) => Sw::HSE,
_ => Sw::HSI,
};
RCC.cfgr().modify(|w| w.set_sw(sw));
while RCC.cfgr().read().sws() != sw.0 {}
// IO compensation cell - Requires CSI clock and SYSCFG
assert!(RCC.cr().read().csirdy());
RCC.apb4enr().modify(|w| w.set_syscfgen(true));
// Enable the compensation cell, using back-bias voltage code
// provide by the cell.
critical_section::with(|_| {
SYSCFG.cccsr().modify(|w| {
w.set_en(true);
w.set_cs(false);
w.set_hslv(false);
})
});
while !SYSCFG.cccsr().read().ready() {}
let core_clocks = CoreClocks {
hclk: Hertz(rcc_hclk),
pclk1: Hertz(rcc_pclk1),
pclk2: Hertz(rcc_pclk2),
pclk3: Hertz(rcc_pclk3),
pclk4: Hertz(rcc_pclk4),
ppre1,
ppre2,
ppre3,
ppre4,
csi_ck: Some(CSI),
hsi_ck: Some(HSI),
hsi48_ck: Some(HSI48),
lsi_ck: Some(LSI),
per_ck: Some(per_ck),
hse_ck,
pll1_p_ck: pll1_p_ck.map(Hertz),
pll1_q_ck: pll1_q_ck.map(Hertz),
pll1_r_ck: pll1_r_ck.map(Hertz),
pll2_p_ck: pll2_p_ck.map(Hertz),
pll2_q_ck: pll2_q_ck.map(Hertz),
pll2_r_ck: pll2_r_ck.map(Hertz),
pll3_p_ck: pll3_p_ck.map(Hertz),
pll3_q_ck: pll3_q_ck.map(Hertz),
pll3_r_ck: pll3_r_ck.map(Hertz),
timx_ker_ck: rcc_timerx_ker_ck.map(Hertz),
timy_ker_ck: rcc_timery_ker_ck.map(Hertz),
sys_ck,
c_ck: Hertz(sys_d1cpre_ck),
};
set_freqs(Clocks { set_freqs(Clocks {
sys: core_clocks.c_ck, sys: core_clocks.c_ck,
ahb1: core_clocks.hclk, ahb1: core_clocks.hclk,

View File

@ -1,18 +1,11 @@
use crate::pac; use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
use crate::peripherals::{self, CRS, RCC, SYSCFG}; use crate::pac::{CRS, RCC, SYSCFG};
use crate::rcc::{get_freqs, set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
use crate::time::U32Ext; use crate::time::U32Ext;
use core::marker::PhantomData;
use embassy::util::Unborrow;
use embassy_hal_common::unborrow;
use pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, /// HSI16 speed
/// and with the addition of the init function to configure a system clock. pub const HSI16_FREQ: u32 = 16_000_000;
/// HSI speed
pub const HSI_FREQ: u32 = 16_000_000;
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -104,9 +97,9 @@ pub enum PLLSource {
HSE(Hertz), HSE(Hertz),
} }
impl Into<Pllmul> for PLLMul { impl From<PLLMul> for Pllmul {
fn into(self) -> Pllmul { fn from(val: PLLMul) -> Pllmul {
match self { match val {
PLLMul::Mul3 => Pllmul::MUL3, PLLMul::Mul3 => Pllmul::MUL3,
PLLMul::Mul4 => Pllmul::MUL4, PLLMul::Mul4 => Pllmul::MUL4,
PLLMul::Mul6 => Pllmul::MUL6, PLLMul::Mul6 => Pllmul::MUL6,
@ -120,9 +113,9 @@ impl Into<Pllmul> for PLLMul {
} }
} }
impl Into<Plldiv> for PLLDiv { impl From<PLLDiv> for Plldiv {
fn into(self) -> Plldiv { fn from(val: PLLDiv) -> Plldiv {
match self { match val {
PLLDiv::Div2 => Plldiv::DIV2, PLLDiv::Div2 => Plldiv::DIV2,
PLLDiv::Div3 => Plldiv::DIV3, PLLDiv::Div3 => Plldiv::DIV3,
PLLDiv::Div4 => Plldiv::DIV4, PLLDiv::Div4 => Plldiv::DIV4,
@ -130,18 +123,18 @@ impl Into<Plldiv> for PLLDiv {
} }
} }
impl Into<Pllsrc> for PLLSource { impl From<PLLSource> for Pllsrc {
fn into(self) -> Pllsrc { fn from(val: PLLSource) -> Pllsrc {
match self { match val {
PLLSource::HSI16 => Pllsrc::HSI16, PLLSource::HSI16 => Pllsrc::HSI16,
PLLSource::HSE(_) => Pllsrc::HSE, PLLSource::HSE(_) => Pllsrc::HSE,
} }
} }
} }
impl Into<Ppre> for APBPrescaler { impl From<APBPrescaler> for Ppre {
fn into(self) -> Ppre { fn from(val: APBPrescaler) -> Ppre {
match self { match val {
APBPrescaler::NotDivided => Ppre::DIV1, APBPrescaler::NotDivided => Ppre::DIV1,
APBPrescaler::Div2 => Ppre::DIV2, APBPrescaler::Div2 => Ppre::DIV2,
APBPrescaler::Div4 => Ppre::DIV4, APBPrescaler::Div4 => Ppre::DIV4,
@ -151,9 +144,9 @@ impl Into<Ppre> for APBPrescaler {
} }
} }
impl Into<Hpre> for AHBPrescaler { impl From<AHBPrescaler> for Hpre {
fn into(self) -> Hpre { fn from(val: AHBPrescaler) -> Hpre {
match self { match val {
AHBPrescaler::NotDivided => Hpre::DIV1, AHBPrescaler::NotDivided => Hpre::DIV1,
AHBPrescaler::Div2 => Hpre::DIV2, AHBPrescaler::Div2 => Hpre::DIV2,
AHBPrescaler::Div4 => Hpre::DIV4, AHBPrescaler::Div4 => Hpre::DIV4,
@ -167,9 +160,9 @@ impl Into<Hpre> for AHBPrescaler {
} }
} }
impl Into<Msirange> for MSIRange { impl From<MSIRange> for Msirange {
fn into(self) -> Msirange { fn from(val: MSIRange) -> Msirange {
match self { match val {
MSIRange::Range0 => Msirange::RANGE0, MSIRange::Range0 => Msirange::RANGE0,
MSIRange::Range1 => Msirange::RANGE1, MSIRange::Range1 => Msirange::RANGE1,
MSIRange::Range2 => Msirange::RANGE2, MSIRange::Range2 => Msirange::RANGE2,
@ -187,6 +180,7 @@ pub struct Config {
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 enable_hsi48: bool,
} }
impl Default for Config { impl Default for Config {
@ -197,241 +191,172 @@ impl Default for Config {
ahb_pre: AHBPrescaler::NotDivided, ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided, apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided, apb2_pre: APBPrescaler::NotDivided,
enable_hsi48: false,
} }
} }
} }
/// RCC peripheral
pub struct Rcc<'d> {
_rb: peripherals::RCC,
phantom: PhantomData<&'d mut peripherals::RCC>,
}
impl<'d> Rcc<'d> {
pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
unborrow!(rcc);
Self {
_rb: rcc,
phantom: PhantomData,
}
}
// Safety: RCC init must have been called
pub fn clocks(&self) -> &'static Clocks {
unsafe { get_freqs() }
}
pub fn enable_hsi48(&mut self, _syscfg: &mut SYSCFG, _crs: CRS) -> HSI48 {
let rcc = pac::RCC;
unsafe {
// Reset SYSCFG peripheral
rcc.apb2rstr().modify(|w| w.set_syscfgrst(true));
rcc.apb2rstr().modify(|w| w.set_syscfgrst(false));
// Enable SYSCFG peripheral
rcc.apb2enr().modify(|w| w.set_syscfgen(true));
// Reset CRS peripheral
rcc.apb1rstr().modify(|w| w.set_crsrst(true));
rcc.apb1rstr().modify(|w| w.set_crsrst(false));
// Enable CRS peripheral
rcc.apb1enr().modify(|w| w.set_crsen(true));
// Initialize CRS
let crs = pac::CRS;
crs.cfgr().write(|w|
// Select LSE as synchronization source
w.set_syncsrc(0b01));
crs.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
});
// Enable VREFINT reference for HSI48 oscillator
let syscfg = pac::SYSCFG;
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() {}
}
HSI48(())
}
}
/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
pub trait RccExt {
fn freeze(self, config: Config) -> Clocks;
}
impl RccExt for RCC {
// `cfgr` is almost always a constant, so make sure it can be constant-propagated properly by
// marking this function and all `Config` constructors and setters as `#[inline]`.
// This saves ~900 Bytes for the `pwr.rs` example.
#[inline]
fn freeze(self, cfgr: Config) -> Clocks {
let rcc = pac::RCC;
let (sys_clk, sw) = match cfgr.mux {
ClockSrc::MSI(range) => {
// Set MSI range
unsafe {
rcc.icscr().write(|w| w.set_msirange(range.into()));
}
// Enable MSI
unsafe {
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
unsafe {
rcc.cr().write(|w| w.set_hsi16on(true));
while !rcc.cr().read().hsi16rdyf() {}
}
(HSI_FREQ, Sw::HSI16)
}
ClockSrc::HSE(freq) => {
// Enable HSE
unsafe {
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
unsafe {
rcc.cr().write(|w| w.set_hseon(true));
while !rcc.cr().read().hserdy() {}
}
freq.0
}
PLLSource::HSI16 => {
// Enable HSI
unsafe {
rcc.cr().write(|w| w.set_hsi16on(true));
while !rcc.cr().read().hsi16rdyf() {}
}
HSI_FREQ
}
};
// Disable PLL
unsafe {
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_u32.mhz().0);
unsafe {
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)
}
};
unsafe {
rcc.cfgr().modify(|w| {
w.set_sw(sw.into());
w.set_hpre(cfgr.ahb_pre.into());
w.set_ppre1(cfgr.apb1_pre.into());
w.set_ppre2(cfgr.apb2_pre.into());
});
}
let ahb_freq: u32 = match cfgr.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.0 as u32 - 7);
sys_clk / pre
}
};
let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
Clocks {
sys: sys_clk.hz(),
ahb: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
}
}
}
/// Token that exists only, if the HSI48 clock has been enabled
///
/// You can get an instance of this struct by calling [`Rcc::enable_hsi48`].
#[derive(Clone, Copy)]
pub struct HSI48(());
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let r = <peripherals::RCC as embassy::util::Steal>::steal(); let (sys_clk, sw) = match config.mux {
let clocks = r.freeze(config); ClockSrc::MSI(range) => {
set_freqs(clocks); // 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() {}
(HSI16_FREQ, 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() {}
HSI16_FREQ
}
};
// 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_u32.mhz().0);
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)
}
};
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::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.0 as u32 - 7);
sys_clk / pre
}
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
if config.enable_hsi48 {
// Reset SYSCFG peripheral
RCC.apb2rstr().modify(|w| w.set_syscfgrst(true));
RCC.apb2rstr().modify(|w| w.set_syscfgrst(false));
// Enable SYSCFG peripheral
RCC.apb2enr().modify(|w| w.set_syscfgen(true));
// Reset CRS peripheral
RCC.apb1rstr().modify(|w| w.set_crsrst(true));
RCC.apb1rstr().modify(|w| w.set_crsrst(false));
// 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(0b01));
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.hz(),
ahb: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
});
} }

View File

@ -1,13 +1,8 @@
use crate::pac; use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
use crate::peripherals::{self, RCC}; use crate::pac::RCC;
use crate::rcc::{get_freqs, set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
use crate::time::U32Ext; use crate::time::U32Ext;
use core::marker::PhantomData;
use embassy::util::Unborrow;
use embassy_hal_common::unborrow;
/// Most of clock setup is copied from rcc/l0
/// HSI speed /// HSI speed
pub const HSI_FREQ: u32 = 16_000_000; pub const HSI_FREQ: u32 = 16_000_000;
@ -16,6 +11,7 @@ pub const HSI_FREQ: u32 = 16_000_000;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
MSI(MSIRange), MSI(MSIRange),
PLL(PLLSource, PLLMul, PLLDiv),
HSE(Hertz), HSE(Hertz),
HSI, HSI,
} }
@ -48,6 +44,28 @@ impl Default for MSIRange {
} }
} }
/// 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,
}
/// AHB prescaler /// AHB prescaler
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub enum AHBPrescaler { pub enum AHBPrescaler {
@ -72,46 +90,86 @@ pub enum APBPrescaler {
Div16, Div16,
} }
type Ppre = u8; /// PLL clock input source
impl Into<Ppre> for APBPrescaler { #[derive(Clone, Copy)]
fn into(self) -> Ppre { pub enum PLLSource {
match self { HSI,
APBPrescaler::NotDivided => 0b000, HSE(Hertz),
APBPrescaler::Div2 => 0b100, }
APBPrescaler::Div4 => 0b101,
APBPrescaler::Div8 => 0b110, impl From<PLLMul> for Pllmul {
APBPrescaler::Div16 => 0b111, 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,
} }
} }
} }
type Hpre = u8; impl From<PLLDiv> for Plldiv {
impl Into<Hpre> for AHBPrescaler { fn from(val: PLLDiv) -> Plldiv {
fn into(self) -> Hpre { match val {
match self { PLLDiv::Div2 => Plldiv::DIV2,
AHBPrescaler::NotDivided => 0b0000, PLLDiv::Div3 => Plldiv::DIV3,
AHBPrescaler::Div2 => 0b1000, PLLDiv::Div4 => Plldiv::DIV4,
AHBPrescaler::Div4 => 0b1001,
AHBPrescaler::Div8 => 0b1010,
AHBPrescaler::Div16 => 0b1011,
AHBPrescaler::Div64 => 0b1100,
AHBPrescaler::Div128 => 0b1101,
AHBPrescaler::Div256 => 0b1110,
AHBPrescaler::Div512 => 0b1111,
} }
} }
} }
impl Into<u8> for MSIRange { impl From<PLLSource> for Pllsrc {
fn into(self) -> u8 { fn from(val: PLLSource) -> Pllsrc {
match self { match val {
MSIRange::Range0 => 0b000, PLLSource::HSI => Pllsrc::HSI,
MSIRange::Range1 => 0b001, PLLSource::HSE(_) => Pllsrc::HSE,
MSIRange::Range2 => 0b010, }
MSIRange::Range3 => 0b011, }
MSIRange::Range4 => 0b100, }
MSIRange::Range5 => 0b101,
MSIRange::Range6 => 0b110, impl From<APBPrescaler> for Ppre {
fn from(val: APBPrescaler) -> Ppre {
match val {
APBPrescaler::NotDivided => Ppre::DIV1,
APBPrescaler::Div2 => Ppre::DIV2,
APBPrescaler::Div4 => Ppre::DIV4,
APBPrescaler::Div8 => Ppre::DIV8,
APBPrescaler::Div16 => Ppre::DIV16,
}
}
}
impl From<AHBPrescaler> for Hpre {
fn from(val: AHBPrescaler) -> Hpre {
match val {
AHBPrescaler::NotDivided => Hpre::DIV1,
AHBPrescaler::Div2 => Hpre::DIV2,
AHBPrescaler::Div4 => Hpre::DIV4,
AHBPrescaler::Div8 => Hpre::DIV8,
AHBPrescaler::Div16 => Hpre::DIV16,
AHBPrescaler::Div64 => Hpre::DIV64,
AHBPrescaler::Div128 => Hpre::DIV128,
AHBPrescaler::Div256 => Hpre::DIV256,
AHBPrescaler::Div512 => Hpre::DIV512,
}
}
}
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,
} }
} }
} }
@ -136,126 +194,128 @@ impl Default for Config {
} }
} }
/// RCC peripheral
pub struct Rcc<'d> {
_rb: peripherals::RCC,
phantom: PhantomData<&'d mut peripherals::RCC>,
}
impl<'d> Rcc<'d> {
pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
unborrow!(rcc);
Self {
_rb: rcc,
phantom: PhantomData,
}
}
// Safety: RCC init must have been called
pub fn clocks(&self) -> &'static Clocks {
unsafe { get_freqs() }
}
}
/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
pub trait RccExt {
fn freeze(self, config: Config) -> Clocks;
}
impl RccExt for RCC {
// `cfgr` is almost always a constant, so make sure it can be constant-propagated properly by
// marking this function and all `Config` constructors and setters as `#[inline]`.
// This saves ~900 Bytes for the `pwr.rs` example.
#[inline]
fn freeze(self, cfgr: Config) -> Clocks {
let rcc = pac::RCC;
let (sys_clk, sw) = match cfgr.mux {
ClockSrc::MSI(range) => {
// Set MSI range
unsafe {
rcc.icscr().write(|w| w.set_msirange(range.into()));
}
// Enable MSI
unsafe {
rcc.cr().write(|w| w.set_msion(true));
while !rcc.cr().read().msirdy() {}
}
let freq = 32_768 * (1 << (range as u8 + 1));
(freq, 0b00)
}
ClockSrc::HSI => {
// Enable HSI
unsafe {
rcc.cr().write(|w| w.set_hsion(true));
while !rcc.cr().read().hsirdy() {}
}
(HSI_FREQ, 0b01)
}
ClockSrc::HSE(freq) => {
// Enable HSE
unsafe {
rcc.cr().write(|w| w.set_hseon(true));
while !rcc.cr().read().hserdy() {}
}
(freq.0, 0b10)
}
};
unsafe {
rcc.cfgr().modify(|w| {
w.set_sw(sw.into());
w.set_hpre(cfgr.ahb_pre.into());
w.set_ppre1(cfgr.apb1_pre.into());
w.set_ppre2(cfgr.apb2_pre.into());
});
}
let ahb_freq: u32 = match cfgr.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre as u32 - 7);
sys_clk / pre
}
};
let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
Clocks {
sys: sys_clk.hz(),
ahb: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
}
}
}
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let r = <peripherals::RCC as embassy::util::Steal>::steal(); let (sys_clk, sw) = match config.mux {
let clocks = r.freeze(config); ClockSrc::MSI(range) => {
set_freqs(clocks); // 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, 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
}
};
// 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_u32.mhz().0);
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)
}
};
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::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.0 as u32 - 7);
sys_clk / pre
}
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
set_freqs(Clocks {
sys: sys_clk.hz(),
ahb: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
});
} }

View File

@ -1,17 +1,8 @@
use crate::pac; use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw};
use crate::peripherals::{self, RCC}; use crate::pac::{FLASH, RCC};
use crate::rcc::{get_freqs, set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
use crate::time::U32Ext; use crate::time::U32Ext;
use core::marker::PhantomData;
use embassy::util::Unborrow;
use embassy_hal_common::unborrow;
use stm32_metapac::rcc::vals::Msirange;
/// 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.
/// HSI16 speed /// HSI16 speed
pub const HSI16_FREQ: u32 = 16_000_000; pub const HSI16_FREQ: u32 = 16_000_000;
@ -19,8 +10,8 @@ pub const HSI16_FREQ: u32 = 16_000_000;
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option<PLL48Div>),
MSI(MSIRange), MSI(MSIRange),
PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option<PLL48Div>),
HSE(Hertz), HSE(Hertz),
HSI16, HSI16,
} }
@ -57,25 +48,6 @@ pub enum MSIRange {
Range11, Range11,
} }
impl Into<u32> for MSIRange {
fn into(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,
}
}
}
impl Default for MSIRange { impl Default for MSIRange {
fn default() -> MSIRange { fn default() -> MSIRange {
MSIRange::Range6 MSIRange::Range6
@ -131,9 +103,9 @@ seq_macro::seq!(N in 8..=86 {
)* )*
} }
impl Into<u8> for PLLMul { impl From<PLLMul> for u8 {
fn into(self) -> u8 { fn from(val: PLLMul) -> u8 {
match self { match val {
#( #(
PLLMul::Mul#N => N, PLLMul::Mul#N => N,
)* )*
@ -163,13 +135,13 @@ pub enum PLLClkDiv {
impl PLLClkDiv { impl PLLClkDiv {
pub fn to_div(self) -> u32 { pub fn to_div(self) -> u32 {
let val: u8 = self.into(); let val: u8 = self.into();
val as u32 + 1 * 2 (val as u32 + 1) * 2
} }
} }
impl Into<u8> for PLLClkDiv { impl From<PLLClkDiv> for u8 {
fn into(self) -> u8 { fn from(val: PLLClkDiv) -> u8 {
match self { match val {
PLLClkDiv::Div2 => 0b00, PLLClkDiv::Div2 => 0b00,
PLLClkDiv::Div4 => 0b01, PLLClkDiv::Div4 => 0b01,
PLLClkDiv::Div6 => 0b10, PLLClkDiv::Div6 => 0b10,
@ -197,9 +169,9 @@ impl PLLSrcDiv {
} }
} }
impl Into<u8> for PLLSrcDiv { impl From<PLLSrcDiv> for u8 {
fn into(self) -> u8 { fn from(val: PLLSrcDiv) -> u8 {
match self { match val {
PLLSrcDiv::Div1 => 0b000, PLLSrcDiv::Div1 => 0b000,
PLLSrcDiv::Div2 => 0b001, PLLSrcDiv::Div2 => 0b001,
PLLSrcDiv::Div3 => 0b010, PLLSrcDiv::Div3 => 0b010,
@ -212,18 +184,46 @@ impl Into<u8> for PLLSrcDiv {
} }
} }
impl Into<u8> for PLLSource { impl From<PLLSource> for Pllsrc {
fn into(self) -> u8 { fn from(val: PLLSource) -> Pllsrc {
match self { match val {
PLLSource::HSI16 => 0b10, PLLSource::HSI16 => Pllsrc::HSI16,
PLLSource::HSE(_) => 0b11, PLLSource::HSE(_) => Pllsrc::HSE,
} }
} }
} }
impl Into<Msirange> for MSIRange { impl From<APBPrescaler> for Ppre {
fn into(self) -> Msirange { fn from(val: APBPrescaler) -> Ppre {
match self { match val {
APBPrescaler::NotDivided => Ppre::DIV1,
APBPrescaler::Div2 => Ppre::DIV2,
APBPrescaler::Div4 => Ppre::DIV4,
APBPrescaler::Div8 => Ppre::DIV8,
APBPrescaler::Div16 => Ppre::DIV16,
}
}
}
impl From<AHBPrescaler> for Hpre {
fn from(val: AHBPrescaler) -> Hpre {
match val {
AHBPrescaler::NotDivided => Hpre::DIV1,
AHBPrescaler::Div2 => Hpre::DIV2,
AHBPrescaler::Div4 => Hpre::DIV4,
AHBPrescaler::Div8 => Hpre::DIV8,
AHBPrescaler::Div16 => Hpre::DIV16,
AHBPrescaler::Div64 => Hpre::DIV64,
AHBPrescaler::Div128 => Hpre::DIV128,
AHBPrescaler::Div256 => Hpre::DIV256,
AHBPrescaler::Div512 => Hpre::DIV512,
}
}
}
impl From<MSIRange> for Msirange {
fn from(val: MSIRange) -> Msirange {
match val {
MSIRange::Range0 => Msirange::RANGE100K, MSIRange::Range0 => Msirange::RANGE100K,
MSIRange::Range1 => Msirange::RANGE200K, MSIRange::Range1 => Msirange::RANGE200K,
MSIRange::Range2 => Msirange::RANGE400K, MSIRange::Range2 => Msirange::RANGE400K,
@ -239,30 +239,22 @@ impl Into<Msirange> for MSIRange {
} }
} }
} }
impl Into<u8> for APBPrescaler {
fn into(self) -> u8 {
match self {
APBPrescaler::NotDivided => 1,
APBPrescaler::Div2 => 0x04,
APBPrescaler::Div4 => 0x05,
APBPrescaler::Div8 => 0x06,
APBPrescaler::Div16 => 0x07,
}
}
}
impl Into<u8> for AHBPrescaler { impl From<MSIRange> for u32 {
fn into(self) -> u8 { fn from(val: MSIRange) -> u32 {
match self { match val {
AHBPrescaler::NotDivided => 1, MSIRange::Range0 => 100_000,
AHBPrescaler::Div2 => 0x08, MSIRange::Range1 => 200_000,
AHBPrescaler::Div4 => 0x09, MSIRange::Range2 => 400_000,
AHBPrescaler::Div8 => 0x0a, MSIRange::Range3 => 800_000,
AHBPrescaler::Div16 => 0x0b, MSIRange::Range4 => 1_000_000,
AHBPrescaler::Div64 => 0x0c, MSIRange::Range5 => 2_000_000,
AHBPrescaler::Div128 => 0x0d, MSIRange::Range6 => 4_000_000,
AHBPrescaler::Div256 => 0x0e, MSIRange::Range7 => 8_000_000,
AHBPrescaler::Div512 => 0x0f, MSIRange::Range8 => 16_000_000,
MSIRange::Range9 => 24_000_000,
MSIRange::Range10 => 32_000_000,
MSIRange::Range11 => 48_000_000,
} }
} }
} }
@ -287,203 +279,151 @@ impl Default for Config {
} }
} }
/// RCC peripheral
pub struct Rcc<'d> {
_rb: peripherals::RCC,
phantom: PhantomData<&'d mut peripherals::RCC>,
}
impl<'d> Rcc<'d> {
pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
unborrow!(rcc);
Self {
_rb: rcc,
phantom: PhantomData,
}
}
// Safety: RCC init must have been called
pub fn clocks(&self) -> &'static Clocks {
unsafe { get_freqs() }
}
}
/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
pub trait RccExt {
fn freeze(self, config: Config) -> Clocks;
}
impl RccExt for RCC {
#[inline]
fn freeze(self, cfgr: Config) -> Clocks {
let rcc = pac::RCC;
let (sys_clk, sw) = match cfgr.mux {
ClockSrc::HSI16 => {
// Enable HSI16
unsafe {
rcc.cr().write(|w| w.set_hsion(true));
while !rcc.cr().read().hsirdy() {}
}
(HSI16_FREQ, 0b01)
}
ClockSrc::HSE(freq) => {
// Enable HSE
unsafe {
rcc.cr().write(|w| w.set_hseon(true));
while !rcc.cr().read().hserdy() {}
}
(freq.0, 0b10)
}
ClockSrc::MSI(range) => {
// Enable MSI
unsafe {
rcc.cr().write(|w| {
let bits: Msirange = range.into();
w.set_msirange(bits);
w.set_msipllen(false);
w.set_msirgsel(true);
w.set_msion(true);
});
while !rcc.cr().read().msirdy() {}
// Enable as clock source for USB, RNG if running at 48 MHz
if let MSIRange::Range11 = range {
rcc.ccipr().modify(|w| {
w.set_clk48sel(0b11);
});
}
}
(range.into(), 0b00)
}
ClockSrc::PLL(src, div, prediv, mul, pll48div) => {
let freq = match src {
PLLSource::HSE(freq) => {
// Enable HSE
unsafe {
rcc.cr().write(|w| w.set_hseon(true));
while !rcc.cr().read().hserdy() {}
}
freq.0
}
PLLSource::HSI16 => {
// Enable HSI
unsafe {
rcc.cr().write(|w| w.set_hsion(true));
while !rcc.cr().read().hsirdy() {}
}
HSI16_FREQ
}
};
// Disable PLL
unsafe {
rcc.cr().modify(|w| w.set_pllon(false));
while rcc.cr().read().pllrdy() {}
}
let freq = (freq / prediv.to_div() * mul.to_mul()) / div.to_div();
assert!(freq <= 80_000_000);
unsafe {
rcc.pllcfgr().write(move |w| {
w.set_plln(mul.into());
w.set_pllm(prediv.into());
w.set_pllr(div.into());
if let Some(pll48div) = pll48div {
w.set_pllq(pll48div.into());
w.set_pllqen(true);
}
w.set_pllsrc(src.into());
});
// Enable as clock source for USB, RNG if PLL48 divisor is provided
if pll48div.is_some() {
rcc.ccipr().modify(|w| {
w.set_clk48sel(0b10);
});
}
// Enable PLL
rcc.cr().modify(|w| w.set_pllon(true));
while !rcc.cr().read().pllrdy() {}
rcc.pllcfgr().modify(|w| w.set_pllren(true));
}
(freq, 0b11)
}
};
unsafe {
// Set flash wait states
pac::FLASH.acr().modify(|w| {
w.set_latency(if sys_clk <= 16_000_000 {
0b000
} else if sys_clk <= 32_000_000 {
0b001
} else if sys_clk <= 48_000_000 {
0b010
} else if sys_clk <= 64_000_000 {
0b011
} else {
0b100
});
});
// Switch active clocks to new clock source
rcc.cfgr().modify(|w| {
w.set_sw(sw.into());
w.set_hpre(cfgr.ahb_pre.into());
w.set_ppre1(cfgr.apb1_pre.into());
w.set_ppre2(cfgr.apb2_pre.into());
});
}
let ahb_freq: u32 = match cfgr.ahb_pre {
AHBPrescaler::NotDivided => 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 cfgr.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
Clocks {
sys: sys_clk.hz(),
ahb1: ahb_freq.hz(),
ahb2: ahb_freq.hz(),
ahb3: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
}
}
}
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let r = <peripherals::RCC as embassy::util::Steal>::steal(); let (sys_clk, sw) = match config.mux {
let clocks = r.freeze(config); ClockSrc::MSI(range) => {
set_freqs(clocks); // Enable MSI
RCC.cr().write(|w| {
let bits: Msirange = range.into();
w.set_msirange(bits);
w.set_msipllen(false);
w.set_msirgsel(true);
w.set_msion(true);
});
while !RCC.cr().read().msirdy() {}
// Enable as clock source for USB, RNG if running at 48 MHz
if let MSIRange::Range11 = range {
RCC.ccipr().modify(|w| {
w.set_clk48sel(0b11);
});
}
(range.into(), Sw::MSI)
}
ClockSrc::HSI16 => {
// Enable HSI16
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
(HSI16_FREQ, 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, div, prediv, mul, pll48div) => {
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_hsion(true));
while !RCC.cr().read().hsirdy() {}
HSI16_FREQ
}
};
// Disable PLL
RCC.cr().modify(|w| w.set_pllon(false));
while RCC.cr().read().pllrdy() {}
let freq = (freq / prediv.to_div() * mul.to_mul()) / div.to_div();
assert!(freq <= 80_000_000);
RCC.pllcfgr().write(move |w| {
w.set_plln(mul.into());
w.set_pllm(prediv.into());
w.set_pllr(div.into());
if let Some(pll48div) = pll48div {
w.set_pllq(pll48div.into());
w.set_pllqen(true);
}
w.set_pllsrc(src.into());
});
// Enable as clock source for USB, RNG if PLL48 divisor is provided
if pll48div.is_some() {
RCC.ccipr().modify(|w| {
w.set_clk48sel(0b10);
});
}
// Enable PLL
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
RCC.pllcfgr().modify(|w| w.set_pllren(true));
(freq, Sw::PLL)
}
};
// Set flash wait states
FLASH.acr().modify(|w| {
w.set_latency(if sys_clk <= 16_000_000 {
0b000
} else if sys_clk <= 32_000_000 {
0b001
} else if sys_clk <= 48_000_000 {
0b010
} else if sys_clk <= 64_000_000 {
0b011
} else {
0b100
});
});
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::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.0 as u32 - 7);
sys_clk / pre
}
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
set_freqs(Clocks {
sys: sys_clk.hz(),
ahb1: ahb_freq.hz(),
ahb2: ahb_freq.hz(),
ahb3: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
});
} }

View File

@ -1,6 +1,4 @@
use crate::pac; use crate::pac::{FLASH, RCC};
use crate::peripherals::{self, RCC};
use crate::pwr::{Power, VoltageScale};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::{Hertz, U32Ext}; use crate::time::{Hertz, U32Ext};
use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw}; use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw};
@ -8,6 +6,20 @@ use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw}
/// HSI16 speed /// HSI16 speed
pub const HSI16_FREQ: u32 = 16_000_000; pub const HSI16_FREQ: u32 = 16_000_000;
/// Voltage Scale
///
/// Represents the voltage range feeding the CPU core. The maximum core
/// clock frequency depends on this value.
#[derive(Copy, Clone, PartialEq)]
pub enum VoltageScale {
// Highest frequency
Range1,
Range2,
Range3,
// Lowest power
Range4,
}
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum ClockSrc { pub enum ClockSrc {
MSI(MSIRange), MSI(MSIRange),
@ -293,218 +305,188 @@ impl Default for Config {
} }
} }
/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
pub trait RccExt {
fn freeze(self, config: Config, power: &Power) -> Clocks;
}
impl RccExt for RCC {
#[inline]
fn freeze(self, cfgr: Config, power: &Power) -> Clocks {
let rcc = pac::RCC;
let sys_clk = match cfgr.mux {
ClockSrc::MSI(range) => {
unsafe {
rcc.icscr1().modify(|w| {
let bits: Msirange = range.into();
w.set_msisrange(bits);
w.set_msirgsel(Msirgsel::RCC_ICSCR1);
});
rcc.cr().write(|w| {
w.set_msipllen(false);
w.set_msison(true);
w.set_msison(true);
});
while !rcc.cr().read().msisrdy() {}
}
range.into()
}
ClockSrc::HSE(freq) => {
unsafe {
rcc.cr().write(|w| w.set_hseon(true));
while !rcc.cr().read().hserdy() {}
}
freq.0
}
ClockSrc::HSI16 => {
unsafe {
rcc.cr().write(|w| w.set_hsion(true));
while !rcc.cr().read().hsirdy() {}
}
HSI16_FREQ
}
ClockSrc::PLL1R(src, m, n, div) => {
let freq = match src {
PllSrc::MSI(_) => MSIRange::default().into(),
PllSrc::HSE(hertz) => hertz.0,
PllSrc::HSI16 => HSI16_FREQ,
};
// disable
unsafe {
rcc.cr().modify(|w| w.set_pllon(0, false));
while rcc.cr().read().pllrdy(0) {}
}
let vco = freq * n as u8 as u32;
let pll_ck = vco / (div as u8 as u32 + 1);
unsafe {
rcc.pll1cfgr().write(|w| {
w.set_pllm(m.into());
w.set_pllsrc(src.into());
});
rcc.pll1divr().modify(|w| {
w.set_pllr(div.to_div());
w.set_plln(n.to_mul());
});
// Enable PLL
rcc.cr().modify(|w| w.set_pllon(0, true));
while !rcc.cr().read().pllrdy(0) {}
rcc.pll1cfgr().modify(|w| w.set_pllren(true));
}
unsafe {
rcc.cr().write(|w| w.set_pllon(0, true));
while !rcc.cr().read().pllrdy(0) {}
}
pll_ck
}
};
// states and programming delay
let wait_states = match power.vos {
// VOS 0 range VCORE 1.26V - 1.40V
VoltageScale::Range1 => {
if sys_clk < 32_000_000 {
0
} else if sys_clk < 64_000_000 {
1
} else if sys_clk < 96_000_000 {
2
} else if sys_clk < 128_000_000 {
3
} else {
4
}
}
// VOS 1 range VCORE 1.15V - 1.26V
VoltageScale::Range2 => {
if sys_clk < 30_000_000 {
0
} else if sys_clk < 60_000_000 {
1
} else if sys_clk < 90_000_000 {
2
} else {
3
}
}
// VOS 2 range VCORE 1.05V - 1.15V
VoltageScale::Range3 => {
if sys_clk < 24_000_000 {
0
} else if sys_clk < 48_000_000 {
1
} else {
2
}
}
// VOS 3 range VCORE 0.95V - 1.05V
VoltageScale::Range4 => {
if sys_clk < 12_000_000 {
0
} else {
1
}
}
};
unsafe {
pac::FLASH.acr().modify(|w| {
w.set_latency(wait_states);
})
}
unsafe {
rcc.cfgr1().modify(|w| {
w.set_sw(cfgr.mux.into());
});
rcc.cfgr2().modify(|w| {
w.set_hpre(cfgr.ahb_pre.into());
w.set_ppre1(cfgr.apb1_pre.into());
w.set_ppre2(cfgr.apb2_pre.into());
});
rcc.cfgr3().modify(|w| {
w.set_ppre3(cfgr.apb3_pre.into());
});
}
let ahb_freq: u32 = match cfgr.ahb_pre {
AHBPrescaler::NotDivided => 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 cfgr.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
let (apb3_freq, _apb3_tim_freq) = match cfgr.apb3_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
Clocks {
sys: sys_clk.hz(),
ahb1: ahb_freq.hz(),
ahb2: ahb_freq.hz(),
ahb3: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
apb3: apb3_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
}
}
}
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let r = <peripherals::RCC as embassy::util::Steal>::steal(); let sys_clk = match config.mux {
let power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal()); ClockSrc::MSI(range) => {
let clocks = r.freeze(config, &power); RCC.icscr1().modify(|w| {
set_freqs(clocks); let bits: Msirange = range.into();
w.set_msisrange(bits);
w.set_msirgsel(Msirgsel::RCC_ICSCR1);
});
RCC.cr().write(|w| {
w.set_msipllen(false);
w.set_msison(true);
w.set_msison(true);
});
while !RCC.cr().read().msisrdy() {}
range.into()
}
ClockSrc::HSE(freq) => {
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
freq.0
}
ClockSrc::HSI16 => {
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
HSI16_FREQ
}
ClockSrc::PLL1R(src, m, n, div) => {
let freq = match src {
PllSrc::MSI(_) => MSIRange::default().into(),
PllSrc::HSE(hertz) => hertz.0,
PllSrc::HSI16 => HSI16_FREQ,
};
// disable
RCC.cr().modify(|w| w.set_pllon(0, false));
while RCC.cr().read().pllrdy(0) {}
let vco = freq * n as u8 as u32;
let pll_ck = vco / (div as u8 as u32 + 1);
RCC.pll1cfgr().write(|w| {
w.set_pllm(m.into());
w.set_pllsrc(src.into());
});
RCC.pll1divr().modify(|w| {
w.set_pllr(div.to_div());
w.set_plln(n.to_mul());
});
// Enable PLL
RCC.cr().modify(|w| w.set_pllon(0, true));
while !RCC.cr().read().pllrdy(0) {}
RCC.pll1cfgr().modify(|w| w.set_pllren(true));
RCC.cr().write(|w| w.set_pllon(0, true));
while !RCC.cr().read().pllrdy(0) {}
pll_ck
}
};
// TODO make configurable
let power_vos = VoltageScale::Range4;
// states and programming delay
let wait_states = match power_vos {
// VOS 0 range VCORE 1.26V - 1.40V
VoltageScale::Range1 => {
if sys_clk < 32_000_000 {
0
} else if sys_clk < 64_000_000 {
1
} else if sys_clk < 96_000_000 {
2
} else if sys_clk < 128_000_000 {
3
} else {
4
}
}
// VOS 1 range VCORE 1.15V - 1.26V
VoltageScale::Range2 => {
if sys_clk < 30_000_000 {
0
} else if sys_clk < 60_000_000 {
1
} else if sys_clk < 90_000_000 {
2
} else {
3
}
}
// VOS 2 range VCORE 1.05V - 1.15V
VoltageScale::Range3 => {
if sys_clk < 24_000_000 {
0
} else if sys_clk < 48_000_000 {
1
} else {
2
}
}
// VOS 3 range VCORE 0.95V - 1.05V
VoltageScale::Range4 => {
if sys_clk < 12_000_000 {
0
} else {
1
}
}
};
FLASH.acr().modify(|w| {
w.set_latency(wait_states);
});
RCC.cfgr1().modify(|w| {
w.set_sw(config.mux.into());
});
RCC.cfgr2().modify(|w| {
w.set_hpre(config.ahb_pre.into());
w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre.into());
});
RCC.cfgr3().modify(|w| {
w.set_ppre3(config.apb3_pre.into());
});
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::NotDivided => 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 {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
set_freqs(Clocks {
sys: sys_clk.hz(),
ahb1: ahb_freq.hz(),
ahb2: ahb_freq.hz(),
ahb3: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
apb3: apb3_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
});
} }

View File

@ -1,11 +1,7 @@
use crate::pac; use crate::pac::RCC;
use crate::peripherals::{self, RCC}; use crate::rcc::{set_freqs, Clocks};
use crate::rcc::{get_freqs, set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
use crate::time::U32Ext; use crate::time::U32Ext;
use core::marker::PhantomData;
use embassy::util::Unborrow;
use embassy_hal_common::unborrow;
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, /// 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. /// and with the addition of the init function to configure a system clock.
@ -104,110 +100,68 @@ impl Default for Config {
} }
} }
/// RCC peripheral
pub struct Rcc<'d> {
_rb: peripherals::RCC,
phantom: PhantomData<&'d mut peripherals::RCC>,
}
impl<'d> Rcc<'d> {
pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
unborrow!(rcc);
Self {
_rb: rcc,
phantom: PhantomData,
}
}
// Safety: RCC init must have been called
pub fn clocks(&self) -> &'static Clocks {
unsafe { get_freqs() }
}
}
/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
pub trait RccExt {
fn freeze(self, config: Config) -> Clocks;
}
impl RccExt for RCC {
#[inline]
fn freeze(self, cfgr: Config) -> Clocks {
let rcc = pac::RCC;
let (sys_clk, sw) = match cfgr.mux {
ClockSrc::HSI16 => {
// Enable HSI16
unsafe {
rcc.cr().write(|w| w.set_hsion(true));
while !rcc.cr().read().hsirdy() {}
}
(HSI_FREQ, 0x01)
}
ClockSrc::HSE(freq) => {
// Enable HSE
unsafe {
rcc.cr().write(|w| w.set_hseon(true));
while !rcc.cr().read().hserdy() {}
}
(freq.0, 0x02)
}
};
unsafe {
rcc.cfgr().modify(|w| {
w.set_sw(sw.into());
w.set_hpre(cfgr.ahb_pre.into());
w.set_ppre1(cfgr.apb1_pre.into());
w.set_ppre2(cfgr.apb2_pre.into());
});
}
let ahb_freq: u32 = match cfgr.ahb_pre {
AHBPrescaler::NotDivided => 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 cfgr.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
Clocks {
sys: sys_clk.hz(),
ahb1: ahb_freq.hz(),
ahb2: ahb_freq.hz(),
ahb3: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
}
}
}
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let r = <peripherals::RCC as embassy::util::Steal>::steal(); let (sys_clk, sw) = match config.mux {
let clocks = r.freeze(config); ClockSrc::HSI16 => {
set_freqs(clocks); // Enable HSI16
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
(HSI_FREQ, 0x01)
}
ClockSrc::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
(freq.0, 0x02)
}
};
RCC.cfgr().modify(|w| {
w.set_sw(sw.into());
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::NotDivided => 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 {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
set_freqs(Clocks {
sys: sys_clk.hz(),
ahb1: ahb_freq.hz(),
ahb2: ahb_freq.hz(),
ahb3: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
});
} }

View File

@ -1,10 +1,6 @@
use crate::pac; use crate::pac::RCC;
use crate::peripherals::{self, RCC}; use crate::rcc::{set_freqs, Clocks};
use crate::rcc::{get_freqs, set_freqs, Clocks};
use crate::time::U32Ext; use crate::time::U32Ext;
use core::marker::PhantomData;
use embassy::util::Unborrow;
use embassy_hal_common::unborrow;
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, /// 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. /// and with the addition of the init function to configure a system clock.
@ -91,6 +87,7 @@ pub struct Config {
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 enable_lsi: bool,
} }
impl Default for Config { impl Default for Config {
@ -101,136 +98,92 @@ impl Default for Config {
ahb_pre: AHBPrescaler::NotDivided, ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided, apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided, apb2_pre: APBPrescaler::NotDivided,
} enable_lsi: false,
}
}
/// RCC peripheral
pub struct Rcc<'d> {
_rb: peripherals::RCC,
phantom: PhantomData<&'d mut peripherals::RCC>,
}
impl<'d> Rcc<'d> {
pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
unborrow!(rcc);
Self {
_rb: rcc,
phantom: PhantomData,
}
}
pub fn enable_lsi(&mut self) {
let rcc = pac::RCC;
unsafe {
let csr = rcc.csr().read();
if !csr.lsion() {
rcc.csr().modify(|w| w.set_lsion(true));
while !rcc.csr().read().lsirdy() {}
}
}
}
// Safety: RCC init must have been called
pub fn clocks(&self) -> &'static Clocks {
unsafe { get_freqs() }
}
}
/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
pub trait RccExt {
fn freeze(self, config: Config) -> Clocks;
}
impl RccExt for RCC {
#[inline]
fn freeze(self, cfgr: Config) -> Clocks {
let rcc = pac::RCC;
let (sys_clk, sw) = match cfgr.mux {
ClockSrc::HSI16 => {
// Enable HSI16
unsafe {
rcc.cr().write(|w| w.set_hsion(true));
while !rcc.cr().read().hsirdy() {}
}
(HSI_FREQ, 0x01)
}
ClockSrc::HSE32 => {
// Enable HSE32
unsafe {
rcc.cr().write(|w| {
w.set_hsebyppwr(true);
w.set_hseon(true);
});
while !rcc.cr().read().hserdy() {}
}
(HSE32_FREQ, 0x02)
}
};
unsafe {
rcc.cfgr().modify(|w| {
w.set_sw(sw.into());
if cfgr.ahb_pre == AHBPrescaler::NotDivided {
w.set_hpre(0);
} else {
w.set_hpre(cfgr.ahb_pre.into());
}
w.set_ppre1(cfgr.apb1_pre.into());
w.set_ppre2(cfgr.apb2_pre.into());
});
}
let ahb_freq: u32 = match cfgr.ahb_pre {
AHBPrescaler::NotDivided => 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 cfgr.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
// TODO: completely untested
let apb3_freq = ahb_freq;
Clocks {
sys: sys_clk.hz(),
ahb1: ahb_freq.hz(),
ahb2: ahb_freq.hz(),
ahb3: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
apb3: apb3_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
} }
} }
} }
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let r = <peripherals::RCC as embassy::util::Steal>::steal(); let (sys_clk, sw) = match config.mux {
let clocks = r.freeze(config); ClockSrc::HSI16 => {
set_freqs(clocks); // Enable HSI16
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
(HSI_FREQ, 0x01)
}
ClockSrc::HSE32 => {
// Enable HSE32
RCC.cr().write(|w| {
w.set_hsebyppwr(true);
w.set_hseon(true);
});
while !RCC.cr().read().hserdy() {}
(HSE32_FREQ, 0x02)
}
};
RCC.cfgr().modify(|w| {
w.set_sw(sw.into());
if config.ahb_pre == AHBPrescaler::NotDivided {
w.set_hpre(0);
} else {
w.set_hpre(config.ahb_pre.into());
}
w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre.into());
});
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::NotDivided => 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 {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2)
}
};
// TODO: completely untested
let apb3_freq = ahb_freq;
if config.enable_lsi {
let csr = RCC.csr().read();
if !csr.lsion() {
RCC.csr().modify(|w| w.set_lsion(true));
while !RCC.csr().read().lsirdy() {}
}
}
set_freqs(Clocks {
sys: sys_clk.hz(),
ahb1: ahb_freq.hz(),
ahb2: ahb_freq.hz(),
ahb3: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
apb3: apb3_freq.hz(),
apb1_tim: apb1_tim_freq.hz(),
apb2_tim: apb2_tim_freq.hz(),
});
} }

View File

@ -8,16 +8,18 @@ mod example_common;
use embassy::executor::Spawner; use embassy::executor::Spawner;
use embassy_stm32::exti::ExtiInput; use embassy_stm32::exti::ExtiInput;
use embassy_stm32::gpio::{Input, Pull}; use embassy_stm32::gpio::{Input, Pull};
use embassy_stm32::{rcc, Peripherals}; use embassy_stm32::Peripherals;
use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge}; use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge};
use example_common::*; use example_common::*;
#[embassy::main] fn config() -> embassy_stm32::Config {
async fn main(_spawner: Spawner, mut p: Peripherals) { let mut config = embassy_stm32::Config::default();
let mut rcc = rcc::Rcc::new(p.RCC); config.rcc.enable_hsi48 = true;
// Enables SYSCFG config
let _ = rcc.enable_hsi48(&mut p.SYSCFG, p.CRS); }
#[embassy::main(config = "config()")]
async fn main(_spawner: Spawner, p: Peripherals) {
let button = Input::new(p.PB2, Pull::Up); let button = Input::new(p.PB2, Pull::Up);
let mut button = ExtiInput::new(button, p.EXTI2); let mut button = ExtiInput::new(button, p.EXTI2);

View File

@ -11,10 +11,8 @@ mod example_common;
use embassy_lora::{sx127x::*, LoraTimer}; use embassy_lora::{sx127x::*, LoraTimer};
use embassy_stm32::{ use embassy_stm32::{
dbgmcu::Dbgmcu,
exti::ExtiInput, exti::ExtiInput,
gpio::{Input, Level, Output, Pull, Speed}, gpio::{Input, Level, Output, Pull, Speed},
rcc,
rng::Rng, rng::Rng,
spi, spi,
time::U32Ext, time::U32Ext,
@ -26,18 +24,12 @@ use lorawan_encoding::default_crypto::DefaultFactory as Crypto;
fn config() -> embassy_stm32::Config { fn config() -> embassy_stm32::Config {
let mut config = embassy_stm32::Config::default(); let mut config = embassy_stm32::Config::default();
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16; config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16;
config.rcc.enable_hsi48 = true;
config config
} }
#[embassy::main(config = "config()")] #[embassy::main(config = "config()")]
async fn main(_spawner: embassy::executor::Spawner, mut p: Peripherals) { async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) {
unsafe {
Dbgmcu::enable_all();
}
let mut rcc = rcc::Rcc::new(p.RCC);
let _ = rcc.enable_hsi48(&mut p.SYSCFG, p.CRS);
// SPI for sx127x // SPI for sx127x
let spi = spi::Spi::new( let spi = spi::Spi::new(
p.SPI1, p.SPI1,

View File

@ -10,10 +10,9 @@ mod example_common;
use embassy_lora::{stm32wl::*, LoraTimer}; use embassy_lora::{stm32wl::*, LoraTimer};
use embassy_stm32::{ use embassy_stm32::{
dbgmcu::Dbgmcu,
dma::NoDma, dma::NoDma,
gpio::{Level, Output, Pin, Speed}, gpio::{Level, Output, Pin, Speed},
interrupt, pac, rcc, interrupt, pac,
rng::Rng, rng::Rng,
subghz::*, subghz::*,
Peripherals, Peripherals,
@ -24,19 +23,13 @@ use lorawan_encoding::default_crypto::DefaultFactory as Crypto;
fn config() -> embassy_stm32::Config { fn config() -> embassy_stm32::Config {
let mut config = embassy_stm32::Config::default(); let mut config = embassy_stm32::Config::default();
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16; config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16;
config.rcc.enable_lsi = true;
config config
} }
#[embassy::main(config = "config()")] #[embassy::main(config = "config()")]
async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) {
unsafe { unsafe { pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)) }
Dbgmcu::enable_all();
let mut rcc = rcc::Rcc::new(p.RCC);
rcc.enable_lsi();
pac::RCC.ccipr().modify(|w| {
w.set_rngsel(0b01);
});
}
let ctrl1 = Output::new(p.PC3.degrade(), Level::High, Speed::High); let ctrl1 = Output::new(p.PC3.degrade(), Level::High, Speed::High);
let ctrl2 = Output::new(p.PC4.degrade(), Level::High, Speed::High); let ctrl2 = Output::new(p.PC4.degrade(), Level::High, Speed::High);

View File

@ -11,7 +11,6 @@ mod example_common;
use embassy::channel::signal::Signal; use embassy::channel::signal::Signal;
use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::interrupt::{Interrupt, InterruptExt};
use embassy::traits::gpio::WaitForRisingEdge; use embassy::traits::gpio::WaitForRisingEdge;
use embassy_stm32::dbgmcu::Dbgmcu;
use embassy_stm32::dma::NoDma; use embassy_stm32::dma::NoDma;
use embassy_stm32::exti::ExtiInput; use embassy_stm32::exti::ExtiInput;
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
@ -72,10 +71,6 @@ fn config() -> embassy_stm32::Config {
#[embassy::main(config = "config()")] #[embassy::main(config = "config()")]
async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) {
unsafe {
Dbgmcu::enable_all();
}
let mut led1 = Output::new(p.PB15, Level::High, Speed::Low); let mut led1 = Output::new(p.PB15, Level::High, Speed::Low);
let mut led2 = Output::new(p.PB9, Level::Low, Speed::Low); let mut led2 = Output::new(p.PB9, Level::Low, Speed::Low);
let mut led3 = Output::new(p.PB11, Level::Low, Speed::Low); let mut led3 = Output::new(p.PB11, Level::Low, Speed::Low);

@ -1 +1 @@
Subproject commit 8530a19ffdcdcbc608a97b40895827d09e670eb7 Subproject commit 3fa97966f07d43a28c0031175591e1c2ff5d0831