stm32/rcc: use more PLL etc enums from PAC.

This commit is contained in:
Dario Nieuwenhuis 2023-10-11 00:12:33 +02:00
parent eff73d6dfa
commit 0cfa8d1bb5
20 changed files with 368 additions and 932 deletions

View File

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

View File

@ -908,7 +908,7 @@ fn main() {
match e { match e {
"Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" => true, "Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" => true,
"Timpre" | "Pllrclkpre" => false, "Timpre" | "Pllrclkpre" => false,
e if e.ends_with("pre") || e.ends_with("div") || e.ends_with("mul") => true, e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true,
_ => false, _ => false,
} }
} }

View File

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

View File

@ -301,9 +301,9 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw.into()); w.set_sw(sw.into());
w.set_hpre(config.ahb_pre.into()); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}

View File

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

View File

@ -1,6 +1,8 @@
use crate::pac::flash::vals::Latency; use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{self, Hsidiv, Sw}; use crate::pac::rcc::vals::{self, Sw};
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler}; pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Hsidiv as HSI16Prescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler,
};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -20,33 +22,6 @@ pub enum ClockSrc {
LSI, LSI,
} }
#[derive(Clone, Copy)]
pub enum HSI16Prescaler {
NotDivided,
Div2,
Div4,
Div8,
Div16,
Div32,
Div64,
Div128,
}
impl Into<Hsidiv> for HSI16Prescaler {
fn into(self) -> Hsidiv {
match self {
HSI16Prescaler::NotDivided => Hsidiv::DIV1,
HSI16Prescaler::Div2 => Hsidiv::DIV2,
HSI16Prescaler::Div4 => Hsidiv::DIV4,
HSI16Prescaler::Div8 => Hsidiv::DIV8,
HSI16Prescaler::Div16 => Hsidiv::DIV16,
HSI16Prescaler::Div32 => Hsidiv::DIV32,
HSI16Prescaler::Div64 => Hsidiv::DIV64,
HSI16Prescaler::Div128 => Hsidiv::DIV128,
}
}
}
/// The PLL configuration. /// The PLL configuration.
/// ///
/// * `VCOCLK = source / m * n` /// * `VCOCLK = source / m * n`
@ -104,7 +79,7 @@ impl Default for Config {
#[inline] #[inline]
fn default() -> Config { fn default() -> Config {
Config { Config {
mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided), mux: ClockSrc::HSI16(HSI16Prescaler::DIV1),
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
apb_pre: APBPrescaler::DIV1, apb_pre: APBPrescaler::DIV1,
low_power_run: false, low_power_run: false,
@ -195,7 +170,6 @@ pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
ClockSrc::HSI16(div) => { ClockSrc::HSI16(div) => {
// Enable HSI16 // Enable HSI16
let div: Hsidiv = div.into();
RCC.cr().write(|w| { RCC.cr().write(|w| {
w.set_hsidiv(div); w.set_hsidiv(div);
w.set_hsion(true) w.set_hsion(true)
@ -262,7 +236,7 @@ pub(crate) unsafe fn init(config: Config) {
} }
// Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
let (sw, hpre, ppre) = (sw.into(), config.ahb_pre.into(), config.apb_pre.into()); let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre);
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(hpre); w.set_hpre(hpre);

View File

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

View File

@ -26,13 +26,13 @@ pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
/// LSI speed /// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000); pub const LSI_FREQ: Hertz = Hertz(32_000);
const VCO_RANGE: RangeInclusive<u32> = 150_000_000..=420_000_000; const VCO_RANGE: RangeInclusive<Hertz> = Hertz(150_000_000)..=Hertz(420_000_000);
#[cfg(any(stm32h5, pwr_h7rm0455))] #[cfg(any(stm32h5, pwr_h7rm0455))]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 128_000_000..=560_000_000; const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(128_000_000)..=Hertz(560_000_000);
#[cfg(pwr_h7rm0468)] #[cfg(pwr_h7rm0468)]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=836_000_000; const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(192_000_000)..=Hertz(836_000_000);
#[cfg(any(pwr_h7rm0399, pwr_h7rm0433))] #[cfg(any(pwr_h7rm0399, pwr_h7rm0433))]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=960_000_000; const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(192_000_000)..=Hertz(960_000_000);
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
@ -641,9 +641,9 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
let wide_allowed = ref_range != Pllrge::RANGE1; let wide_allowed = ref_range != Pllrge::RANGE1;
let vco_clk = ref_clk * config.mul; let vco_clk = ref_clk * config.mul;
let vco_range = if VCO_RANGE.contains(&vco_clk.0) { let vco_range = if VCO_RANGE.contains(&vco_clk) {
Pllvcosel::MEDIUMVCO Pllvcosel::MEDIUMVCO
} else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk.0) { } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) {
Pllvcosel::WIDEVCO Pllvcosel::WIDEVCO
} else { } else {
panic!("pll vco_clk out of range: {} mhz", vco_clk.0) panic!("pll vco_clk out of range: {} mhz", vco_clk.0)

View File

@ -1,8 +1,10 @@
use super::bd::BackupDomain; use super::bd::BackupDomain;
use super::RtcClockSource; use super::RtcClockSource;
pub use crate::pac::pwr::vals::Vos as VoltageScale; pub use crate::pac::pwr::vals::Vos as VoltageScale;
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; pub use crate::pac::rcc::vals::{
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; Hpre as AHBPrescaler, Msirange as MSIRange, Plldiv as PLLDiv, Pllmul as PLLMul, Ppre as APBPrescaler,
};
use crate::pac::rcc::vals::{Pllsrc, Sw};
#[cfg(crs)] #[cfg(crs)]
use crate::pac::{crs, CRS, SYSCFG}; use crate::pac::{crs, CRS, SYSCFG};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
@ -24,56 +26,6 @@ pub enum ClockSrc {
HSI16, HSI16,
} }
/// MSI Clock Range
///
/// These ranges control the frequency of the MSI. Internally, these ranges map
/// to the `MSIRANGE` bits in the `RCC_ICSCR` register.
#[derive(Clone, Copy)]
pub enum MSIRange {
/// Around 65.536 kHz
Range0,
/// Around 131.072 kHz
Range1,
/// Around 262.144 kHz
Range2,
/// Around 524.288 kHz
Range3,
/// Around 1.048 MHz
Range4,
/// Around 2.097 MHz (reset value)
Range5,
/// Around 4.194 MHz
Range6,
}
impl Default for MSIRange {
fn default() -> MSIRange {
MSIRange::Range5
}
}
/// PLL divider
#[derive(Clone, Copy)]
pub enum PLLDiv {
Div2,
Div3,
Div4,
}
/// PLL multiplier
#[derive(Clone, Copy)]
pub enum PLLMul {
Mul3,
Mul4,
Mul6,
Mul8,
Mul12,
Mul16,
Mul24,
Mul32,
Mul48,
}
/// PLL clock input source /// PLL clock input source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum PLLSource { pub enum PLLSource {
@ -81,32 +33,6 @@ pub enum PLLSource {
HSE(Hertz), HSE(Hertz),
} }
impl From<PLLMul> for Pllmul {
fn from(val: PLLMul) -> Pllmul {
match val {
PLLMul::Mul3 => Pllmul::MUL3,
PLLMul::Mul4 => Pllmul::MUL4,
PLLMul::Mul6 => Pllmul::MUL6,
PLLMul::Mul8 => Pllmul::MUL8,
PLLMul::Mul12 => Pllmul::MUL12,
PLLMul::Mul16 => Pllmul::MUL16,
PLLMul::Mul24 => Pllmul::MUL24,
PLLMul::Mul32 => Pllmul::MUL32,
PLLMul::Mul48 => Pllmul::MUL48,
}
}
}
impl From<PLLDiv> for Plldiv {
fn from(val: PLLDiv) -> Plldiv {
match val {
PLLDiv::Div2 => Plldiv::DIV2,
PLLDiv::Div3 => Plldiv::DIV3,
PLLDiv::Div4 => Plldiv::DIV4,
}
}
}
impl From<PLLSource> for Pllsrc { impl From<PLLSource> for Pllsrc {
fn from(val: PLLSource) -> Pllsrc { fn from(val: PLLSource) -> Pllsrc {
match val { match val {
@ -116,20 +42,6 @@ impl From<PLLSource> for Pllsrc {
} }
} }
impl From<MSIRange> for Msirange {
fn from(val: MSIRange) -> Msirange {
match val {
MSIRange::Range0 => Msirange::RANGE0,
MSIRange::Range1 => Msirange::RANGE1,
MSIRange::Range2 => Msirange::RANGE2,
MSIRange::Range3 => Msirange::RANGE3,
MSIRange::Range4 => Msirange::RANGE4,
MSIRange::Range5 => Msirange::RANGE5,
MSIRange::Range6 => Msirange::RANGE6,
}
}
}
/// Clocks configutation /// Clocks configutation
pub struct Config { pub struct Config {
pub mux: ClockSrc, pub mux: ClockSrc,
@ -148,7 +60,7 @@ impl Default for Config {
#[inline] #[inline]
fn default() -> Config { fn default() -> Config {
Config { Config {
mux: ClockSrc::MSI(MSIRange::default()), mux: ClockSrc::MSI(MSIRange::RANGE5),
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
@ -171,28 +83,28 @@ pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
ClockSrc::MSI(range) => { ClockSrc::MSI(range) => {
// Set MSI range // Set MSI range
RCC.icscr().write(|w| w.set_msirange(range.into())); RCC.icscr().write(|w| w.set_msirange(range));
// Enable MSI // Enable MSI
RCC.cr().write(|w| w.set_msion(true)); RCC.cr().write(|w| w.set_msion(true));
while !RCC.cr().read().msirdy() {} while !RCC.cr().read().msirdy() {}
let freq = 32_768 * (1 << (range as u8 + 1)); let freq = 32_768 * (1 << (range as u8 + 1));
(freq, Sw::MSI) (Hertz(freq), Sw::MSI)
} }
ClockSrc::HSI16 => { ClockSrc::HSI16 => {
// Enable HSI16 // Enable HSI16
RCC.cr().write(|w| w.set_hsi16on(true)); RCC.cr().write(|w| w.set_hsi16on(true));
while !RCC.cr().read().hsi16rdyf() {} while !RCC.cr().read().hsi16rdyf() {}
(HSI_FREQ.0, Sw::HSI16) (HSI_FREQ, Sw::HSI16)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE
RCC.cr().write(|w| w.set_hseon(true)); RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {} while !RCC.cr().read().hserdy() {}
(freq.0, Sw::HSE) (freq, Sw::HSE)
} }
ClockSrc::PLL(src, mul, div) => { ClockSrc::PLL(src, mul, div) => {
let freq = match src { let freq = match src {
@ -200,13 +112,13 @@ pub(crate) unsafe fn init(config: Config) {
// Enable HSE // Enable HSE
RCC.cr().write(|w| w.set_hseon(true)); RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {} while !RCC.cr().read().hserdy() {}
freq.0 freq
} }
PLLSource::HSI16 => { PLLSource::HSI16 => {
// Enable HSI // Enable HSI
RCC.cr().write(|w| w.set_hsi16on(true)); RCC.cr().write(|w| w.set_hsi16on(true));
while !RCC.cr().read().hsi16rdyf() {} while !RCC.cr().read().hsi16rdyf() {}
HSI_FREQ.0 HSI_FREQ
} }
}; };
@ -214,28 +126,13 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().modify(|w| w.set_pllon(false)); RCC.cr().modify(|w| w.set_pllon(false));
while RCC.cr().read().pllrdy() {} while RCC.cr().read().pllrdy() {}
let freq = match mul { let freq = freq * mul / div;
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 { assert!(freq <= Hertz(32_000_000));
PLLDiv::Div2 => freq / 2,
PLLDiv::Div3 => freq / 3,
PLLDiv::Div4 => freq / 4,
};
assert!(freq <= 32_000_000);
RCC.cfgr().write(move |w| { RCC.cfgr().write(move |w| {
w.set_pllmul(mul.into()); w.set_pllmul(mul);
w.set_plldiv(div.into()); w.set_plldiv(div);
w.set_pllsrc(src.into()); w.set_pllsrc(src.into());
}); });
@ -254,11 +151,11 @@ pub(crate) unsafe fn init(config: Config) {
); );
let wait_states = match config.voltage_scale { let wait_states = match config.voltage_scale {
VoltageScale::RANGE1 => match sys_clk { VoltageScale::RANGE1 => match sys_clk.0 {
..=16_000_000 => 0, ..=16_000_000 => 0,
_ => 1, _ => 1,
}, },
VoltageScale::RANGE2 => match sys_clk { VoltageScale::RANGE2 => match sys_clk.0 {
..=8_000_000 => 0, ..=8_000_000 => 0,
_ => 1, _ => 1,
}, },
@ -271,37 +168,26 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(config.ahb_pre.into()); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
let ahb_freq: u32 = match config.ahb_pre { let ahb_freq = sys_clk / config.ahb_pre;
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.to_bits() as u32 - 7);
sys_clk / pre
}
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let pre: Ppre = pre.into(); let freq = ahb_freq / pre;
let pre: u8 = 1 << (pre.to_bits() - 3); (freq, freq * 2u32)
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let pre: Ppre = pre.into(); let freq = ahb_freq / pre;
let pre: u8 = 1 << (pre.to_bits() - 3); (freq, freq * 2u32)
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
@ -339,11 +225,11 @@ pub(crate) unsafe fn init(config: Config) {
} }
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sys_clk), sys: sys_clk,
ahb1: Hertz(ahb_freq), ahb1: ahb_freq,
apb1: Hertz(apb1_freq), apb1: apb1_freq,
apb2: Hertz(apb2_freq), apb2: apb2_freq,
apb1_tim: Hertz(apb1_tim_freq), apb1_tim: apb1_tim_freq,
apb2_tim: Hertz(apb2_tim_freq), apb2_tim: apb2_tim_freq,
}); });
} }

View File

@ -1,5 +1,7 @@
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; pub use crate::pac::rcc::vals::{
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; Hpre as AHBPrescaler, Msirange as MSIRange, Plldiv as PLLDiv, Pllmul as PLLMul, Ppre as APBPrescaler,
};
use crate::pac::rcc::vals::{Pllsrc, Sw};
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -19,56 +21,6 @@ pub enum ClockSrc {
HSI, HSI,
} }
/// MSI Clock Range
///
/// These ranges control the frequency of the MSI. Internally, these ranges map
/// to the `MSIRANGE` bits in the `RCC_ICSCR` register.
#[derive(Clone, Copy)]
pub enum MSIRange {
/// Around 65.536 kHz
Range0,
/// Around 131.072 kHz
Range1,
/// Around 262.144 kHz
Range2,
/// Around 524.288 kHz
Range3,
/// Around 1.048 MHz
Range4,
/// Around 2.097 MHz (reset value)
Range5,
/// Around 4.194 MHz
Range6,
}
impl Default for MSIRange {
fn default() -> MSIRange {
MSIRange::Range5
}
}
/// PLL divider
#[derive(Clone, Copy)]
pub enum PLLDiv {
Div2,
Div3,
Div4,
}
/// PLL multiplier
#[derive(Clone, Copy)]
pub enum PLLMul {
Mul3,
Mul4,
Mul6,
Mul8,
Mul12,
Mul16,
Mul24,
Mul32,
Mul48,
}
/// PLL clock input source /// PLL clock input source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum PLLSource { pub enum PLLSource {
@ -76,32 +28,6 @@ pub enum PLLSource {
HSE(Hertz), HSE(Hertz),
} }
impl From<PLLMul> for Pllmul {
fn from(val: PLLMul) -> Pllmul {
match val {
PLLMul::Mul3 => Pllmul::MUL3,
PLLMul::Mul4 => Pllmul::MUL4,
PLLMul::Mul6 => Pllmul::MUL6,
PLLMul::Mul8 => Pllmul::MUL8,
PLLMul::Mul12 => Pllmul::MUL12,
PLLMul::Mul16 => Pllmul::MUL16,
PLLMul::Mul24 => Pllmul::MUL24,
PLLMul::Mul32 => Pllmul::MUL32,
PLLMul::Mul48 => Pllmul::MUL48,
}
}
}
impl From<PLLDiv> for Plldiv {
fn from(val: PLLDiv) -> Plldiv {
match val {
PLLDiv::Div2 => Plldiv::DIV2,
PLLDiv::Div3 => Plldiv::DIV3,
PLLDiv::Div4 => Plldiv::DIV4,
}
}
}
impl From<PLLSource> for Pllsrc { impl From<PLLSource> for Pllsrc {
fn from(val: PLLSource) -> Pllsrc { fn from(val: PLLSource) -> Pllsrc {
match val { match val {
@ -111,20 +37,6 @@ impl From<PLLSource> for Pllsrc {
} }
} }
impl From<MSIRange> for Msirange {
fn from(val: MSIRange) -> Msirange {
match val {
MSIRange::Range0 => Msirange::RANGE0,
MSIRange::Range1 => Msirange::RANGE1,
MSIRange::Range2 => Msirange::RANGE2,
MSIRange::Range3 => Msirange::RANGE3,
MSIRange::Range4 => Msirange::RANGE4,
MSIRange::Range5 => Msirange::RANGE5,
MSIRange::Range6 => Msirange::RANGE6,
}
}
}
/// Clocks configutation /// Clocks configutation
pub struct Config { pub struct Config {
pub mux: ClockSrc, pub mux: ClockSrc,
@ -137,7 +49,7 @@ impl Default for Config {
#[inline] #[inline]
fn default() -> Config { fn default() -> Config {
Config { Config {
mux: ClockSrc::MSI(MSIRange::default()), mux: ClockSrc::MSI(MSIRange::RANGE5),
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
@ -149,28 +61,28 @@ pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
ClockSrc::MSI(range) => { ClockSrc::MSI(range) => {
// Set MSI range // Set MSI range
RCC.icscr().write(|w| w.set_msirange(range.into())); RCC.icscr().write(|w| w.set_msirange(range));
// Enable MSI // Enable MSI
RCC.cr().write(|w| w.set_msion(true)); RCC.cr().write(|w| w.set_msion(true));
while !RCC.cr().read().msirdy() {} while !RCC.cr().read().msirdy() {}
let freq = 32_768 * (1 << (range as u8 + 1)); let freq = 32_768 * (1 << (range as u8 + 1));
(freq, Sw::MSI) (Hertz(freq), Sw::MSI)
} }
ClockSrc::HSI => { ClockSrc::HSI => {
// Enable HSI // Enable HSI
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI_FREQ.0, Sw::HSI) (HSI_FREQ, Sw::HSI)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE
RCC.cr().write(|w| w.set_hseon(true)); RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {} while !RCC.cr().read().hserdy() {}
(freq.0, Sw::HSE) (freq, Sw::HSE)
} }
ClockSrc::PLL(src, mul, div) => { ClockSrc::PLL(src, mul, div) => {
let freq = match src { let freq = match src {
@ -178,13 +90,13 @@ pub(crate) unsafe fn init(config: Config) {
// Enable HSE // Enable HSE
RCC.cr().write(|w| w.set_hseon(true)); RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {} while !RCC.cr().read().hserdy() {}
freq.0 freq
} }
PLLSource::HSI => { PLLSource::HSI => {
// Enable HSI // Enable HSI
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
HSI_FREQ.0 HSI_FREQ
} }
}; };
@ -192,28 +104,13 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().modify(|w| w.set_pllon(false)); RCC.cr().modify(|w| w.set_pllon(false));
while RCC.cr().read().pllrdy() {} while RCC.cr().read().pllrdy() {}
let freq = match mul { let freq = freq * mul / div;
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 { assert!(freq <= Hertz(32_000_000));
PLLDiv::Div2 => freq / 2,
PLLDiv::Div3 => freq / 3,
PLLDiv::Div4 => freq / 4,
};
assert!(freq <= 32_000_000);
RCC.cfgr().write(move |w| { RCC.cfgr().write(move |w| {
w.set_pllmul(mul.into()); w.set_pllmul(mul);
w.set_plldiv(div.into()); w.set_plldiv(div);
w.set_pllsrc(src.into()); w.set_pllsrc(src.into());
}); });
@ -226,7 +123,7 @@ pub(crate) unsafe fn init(config: Config) {
}; };
// Set flash 64-bit access, prefetch and wait states // Set flash 64-bit access, prefetch and wait states
if sys_clk >= 16_000_000 { if sys_clk >= Hertz(16_000_000) {
FLASH.acr().write(|w| w.set_acc64(true)); FLASH.acr().write(|w| w.set_acc64(true));
FLASH.acr().modify(|w| w.set_prften(true)); FLASH.acr().modify(|w| w.set_prften(true));
FLASH.acr().modify(|w| w.set_latency(true)); FLASH.acr().modify(|w| w.set_latency(true));
@ -234,46 +131,68 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(config.ahb_pre.into()); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
let ahb_freq: u32 = match config.ahb_pre { let ahb_freq = sys_clk / config.ahb_pre;
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.to_bits() as u32 - 7);
sys_clk / pre
}
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let pre: Ppre = pre.into(); let freq = ahb_freq / pre;
let pre: u8 = 1 << (pre.to_bits() - 3); (freq, freq * 2u32)
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let pre: Ppre = pre.into(); let freq = ahb_freq / pre;
let pre: u8 = 1 << (pre.to_bits() - 3); (freq, freq * 2u32)
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
#[cfg(crs)]
if config.enable_hsi48 {
// Reset CRS peripheral
RCC.apb1rstr().modify(|w| w.set_crsrst(true));
RCC.apb1rstr().modify(|w| w.set_crsrst(false));
// Enable CRS peripheral
RCC.apb1enr().modify(|w| w.set_crsen(true));
// Initialize CRS
CRS.cfgr().write(|w|
// Select LSE as synchronization source
w.set_syncsrc(crs::vals::Syncsrc::LSE));
CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
});
// Enable VREFINT reference for HSI48 oscillator
SYSCFG.cfgr3().modify(|w| {
w.set_enref_hsi48(true);
w.set_en_vrefint(true);
});
// Select HSI48 as USB clock
RCC.ccipr().modify(|w| w.set_hsi48msel(true));
// Enable dedicated USB clock
RCC.crrcr().modify(|w| w.set_hsi48on(true));
while !RCC.crrcr().read().hsi48rdy() {}
}
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sys_clk), sys: sys_clk,
ahb1: Hertz(ahb_freq), ahb1: ahb_freq,
apb1: Hertz(apb1_freq), apb1: apb1_freq,
apb2: Hertz(apb2_freq), apb2: apb2_freq,
apb1_tim: Hertz(apb1_tim_freq), apb1_tim: apb1_tim_freq,
apb2_tim: Hertz(apb2_tim_freq), apb2_tim: apb2_tim_freq,
}); });
} }

View File

@ -101,8 +101,7 @@ pub(crate) unsafe fn init(config: Config) {
ClockSrc::MSI(range) => { ClockSrc::MSI(range) => {
// Enable MSI // Enable MSI
RCC.cr().write(|w| { RCC.cr().write(|w| {
let bits: Msirange = range.into(); w.set_msirange(range);
w.set_msirange(bits);
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msion(true); w.set_msion(true);
@ -154,8 +153,7 @@ pub(crate) unsafe fn init(config: Config) {
PLLSource::MSI(range) => { PLLSource::MSI(range) => {
// Enable MSI // Enable MSI
RCC.cr().write(|w| { RCC.cr().write(|w| {
let bits: Msirange = range.into(); w.set_msirange(range);
w.set_msirange(bits);
w.set_msipllen(false); // should be turned on if LSE is started w.set_msipllen(false); // should be turned on if LSE is started
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msion(true); w.set_msion(true);
@ -255,9 +253,9 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(config.ahb_pre.into()); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
let ahb_freq = sys_clk / config.ahb_pre; let ahb_freq = sys_clk / config.ahb_pre;

View File

@ -100,8 +100,7 @@ pub(crate) unsafe fn init(config: Config) {
ClockSrc::MSI(range) => { ClockSrc::MSI(range) => {
// Enable MSI // Enable MSI
RCC.cr().write(|w| { RCC.cr().write(|w| {
let bits: Msirange = range.into(); w.set_msirange(range);
w.set_msirange(bits);
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msion(true); w.set_msion(true);
@ -153,8 +152,7 @@ pub(crate) unsafe fn init(config: Config) {
PLLSource::MSI(range) => { PLLSource::MSI(range) => {
// Enable MSI // Enable MSI
RCC.cr().write(|w| { RCC.cr().write(|w| {
let bits: Msirange = range.into(); w.set_msirange(range);
w.set_msirange(bits);
w.set_msipllen(false); // should be turned on if LSE is started w.set_msipllen(false); // should be turned on if LSE is started
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msion(true); w.set_msion(true);
@ -250,9 +248,9 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(config.ahb_pre.into()); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
let ahb_freq = sys_clk / config.ahb_pre; let ahb_freq = sys_clk / config.ahb_pre;

View File

@ -1,107 +1,42 @@
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Hsepre as HsePrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Pllsrc as PllSource,
Ppre as APBPrescaler, Sw as Sysclk,
};
use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::Clocks; use crate::rcc::Clocks;
use crate::time::{khz, mhz, Hertz}; use crate::time::{khz, mhz, Hertz};
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
/// and with the addition of the init function to configure a system clock.
/// Only the basic setup using the HSE and HSI clocks are supported as of now.
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed /// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000); pub const LSI_FREQ: Hertz = Hertz(32_000);
#[derive(Clone, Copy)]
pub enum HsePrescaler {
NotDivided,
Div2,
}
impl From<HsePrescaler> for bool {
fn from(value: HsePrescaler) -> Self {
match value {
HsePrescaler::NotDivided => false,
HsePrescaler::Div2 => true,
}
}
}
pub struct Hse { pub struct Hse {
pub prediv: HsePrescaler, pub prediv: HsePrescaler,
pub frequency: Hertz, pub frequency: Hertz,
} }
/// System clock mux source
#[derive(Clone, Copy, PartialEq)]
pub enum Sysclk {
/// MSI selected as sysclk
MSI,
/// HSI selected as sysclk
HSI,
/// HSE selected as sysclk
HSE,
/// PLL selected as sysclk
Pll,
}
impl From<Sysclk> for u8 {
fn from(value: Sysclk) -> Self {
match value {
Sysclk::MSI => 0b00,
Sysclk::HSI => 0b01,
Sysclk::HSE => 0b10,
Sysclk::Pll => 0b11,
}
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum PllSource {
Hsi,
Msi,
Hse,
}
impl From<PllSource> for u8 {
fn from(value: PllSource) -> Self {
match value {
PllSource::Msi => 0b01,
PllSource::Hsi => 0b10,
PllSource::Hse => 0b11,
}
}
}
pub enum Pll48Source {
PllSai,
Pll,
Msi,
Hsi48,
}
pub struct PllMux { pub struct PllMux {
/// Source clock selection. /// Source clock selection.
pub source: PllSource, pub source: PllSource,
/// PLL pre-divider (DIVM). Must be between 1 and 63. /// PLL pre-divider (DIVM). Must be between 1 and 63.
pub prediv: u8, pub prediv: Pllm,
} }
pub struct Pll { pub struct Pll {
/// PLL multiplication factor. Must be between 4 and 512. /// PLL multiplication factor. Must be between 4 and 512.
pub mul: u16, pub mul: Plln,
/// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128. /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128.
/// On PLL1, it must be even (in particular, it cannot be 1.) /// On PLL1, it must be even (in particular, it cannot be 1.)
pub divp: Option<u16>, pub divp: Option<Pllp>,
/// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128. /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
pub divq: Option<u16>, pub divq: Option<Pllq>,
/// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128. /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
pub divr: Option<u16>, pub divr: Option<Pllr>,
} }
/// Clocks configutation /// Clocks configutation
@ -111,7 +46,6 @@ pub struct Config {
pub lsi: bool, pub lsi: bool,
pub sys: Sysclk, pub sys: Sysclk,
pub mux: Option<PllMux>, pub mux: Option<PllMux>,
pub pll48: Option<Pll48Source>,
pub rtc: Option<RtcClockSource>, pub rtc: Option<RtcClockSource>,
pub pll: Option<Pll>, pub pll: Option<Pll>,
@ -127,23 +61,22 @@ pub struct Config {
pub const WPAN_DEFAULT: Config = Config { pub const WPAN_DEFAULT: Config = Config {
hse: Some(Hse { hse: Some(Hse {
frequency: mhz(32), frequency: mhz(32),
prediv: HsePrescaler::NotDivided, prediv: HsePrescaler::DIV1,
}), }),
lse: Some(khz(32)), lse: Some(khz(32)),
sys: Sysclk::Pll, sys: Sysclk::PLL,
mux: Some(PllMux { mux: Some(PllMux {
source: PllSource::Hse, source: PllSource::HSE,
prediv: 2, prediv: Pllm::DIV2,
}), }),
pll48: None,
rtc: Some(RtcClockSource::LSE), rtc: Some(RtcClockSource::LSE),
lsi: false, lsi: false,
pll: Some(Pll { pll: Some(Pll {
mul: 12, mul: Plln::MUL12,
divp: Some(3), divp: Some(Pllp::DIV3),
divq: Some(4), divq: Some(Pllq::DIV4),
divr: Some(3), divr: Some(Pllr::DIV3),
}), }),
pllsai: None, pllsai: None,
@ -160,9 +93,8 @@ impl Default for Config {
Config { Config {
hse: None, hse: None,
lse: None, lse: None,
sys: Sysclk::HSI, sys: Sysclk::HSI16,
mux: None, mux: None,
pll48: None,
pll: None, pll: None,
pllsai: None, pllsai: None,
rtc: None, rtc: None,
@ -178,15 +110,12 @@ impl Default for Config {
} }
pub(crate) fn compute_clocks(config: &Config) -> Clocks { pub(crate) fn compute_clocks(config: &Config) -> Clocks {
let hse_clk = config.hse.as_ref().map(|hse| match hse.prediv { let hse_clk = config.hse.as_ref().map(|hse| hse.frequency / hse.prediv);
HsePrescaler::NotDivided => hse.frequency,
HsePrescaler::Div2 => hse.frequency / 2u32,
});
let mux_clk = config.mux.as_ref().map(|pll_mux| { let mux_clk = config.mux.as_ref().map(|pll_mux| {
(match pll_mux.source { (match pll_mux.source {
PllSource::Hse => hse_clk.unwrap(), PllSource::HSE => hse_clk.unwrap(),
PllSource::Hsi => HSI_FREQ, PllSource::HSI16 => HSI_FREQ,
_ => unreachable!(), _ => unreachable!(),
} / pll_mux.prediv) } / pll_mux.prediv)
}); });
@ -206,44 +135,19 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
let sys_clk = match config.sys { let sys_clk = match config.sys {
Sysclk::HSE => hse_clk.unwrap(), Sysclk::HSE => hse_clk.unwrap(),
Sysclk::HSI => HSI_FREQ, Sysclk::HSI16 => HSI_FREQ,
Sysclk::Pll => pll_r.unwrap(), Sysclk::PLL => pll_r.unwrap(),
_ => unreachable!(), _ => unreachable!(),
}; };
let ahb1_clk = match config.ahb1_pre { let ahb1_clk = sys_clk / config.ahb1_pre;
AHBPrescaler::DIV1 => sys_clk, let ahb2_clk = sys_clk / config.ahb2_pre;
pre => { let ahb3_clk = sys_clk / config.ahb3_pre;
let pre: u8 = pre.into();
let pre = 1u32 << (pre as u32 - 7);
sys_clk / pre
}
};
let ahb2_clk = match config.ahb2_pre {
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1u32 << (pre as u32 - 7);
sys_clk / pre
}
};
let ahb3_clk = match config.ahb3_pre {
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1u32 << (pre as u32 - 7);
sys_clk / pre
}
};
let (apb1_clk, apb1_tim_clk) = match config.apb1_pre { let (apb1_clk, apb1_tim_clk) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk),
pre => { pre => {
let pre: u8 = pre.into(); let freq = ahb1_clk / pre;
let pre: u8 = 1 << (pre - 3);
let freq = ahb1_clk / pre as u32;
(freq, freq * 2u32) (freq, freq * 2u32)
} }
}; };
@ -251,9 +155,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
let (apb2_clk, apb2_tim_clk) = match config.apb2_pre { let (apb2_clk, apb2_tim_clk) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk),
pre => { pre => {
let pre: u8 = pre.into(); let freq = ahb1_clk / pre;
let pre: u8 = 1 << (pre - 3);
let freq = ahb1_clk / pre as u32;
(freq, freq * 2u32) (freq, freq * 2u32)
} }
}; };
@ -282,12 +184,12 @@ pub(crate) fn configure_clocks(config: &Config) {
let rcc = crate::pac::RCC; let rcc = crate::pac::RCC;
let needs_hsi = if let Some(pll_mux) = &config.mux { let needs_hsi = if let Some(pll_mux) = &config.mux {
pll_mux.source == PllSource::Hsi pll_mux.source == PllSource::HSI16
} else { } else {
false false
}; };
if needs_hsi || config.sys == Sysclk::HSI { if needs_hsi || config.sys == Sysclk::HSI16 {
rcc.cr().modify(|w| { rcc.cr().modify(|w| {
w.set_hsion(true); w.set_hsion(true);
}); });
@ -306,7 +208,7 @@ pub(crate) fn configure_clocks(config: &Config) {
match &config.hse { match &config.hse {
Some(hse) => { Some(hse) => {
rcc.cr().modify(|w| { rcc.cr().modify(|w| {
w.set_hsepre(hse.prediv.into()); w.set_hsepre(hse.prediv);
w.set_hseon(true); w.set_hseon(true);
}); });
@ -328,18 +230,18 @@ pub(crate) fn configure_clocks(config: &Config) {
match &config.pll { match &config.pll {
Some(pll) => { Some(pll) => {
rcc.pllcfgr().modify(|w| { rcc.pllcfgr().modify(|w| {
w.set_plln(pll.mul as u8); w.set_plln(pll.mul);
pll.divp.map(|divp| { pll.divp.map(|divp| {
w.set_pllpen(true); w.set_pllpen(true);
w.set_pllp((divp - 1) as u8) w.set_pllp(divp)
}); });
pll.divq.map(|divq| { pll.divq.map(|divq| {
w.set_pllqen(true); w.set_pllqen(true);
w.set_pllq((divq - 1) as u8) w.set_pllq(divq)
}); });
pll.divr.map(|divr| { pll.divr.map(|divr| {
// w.set_pllren(true); w.set_pllren(true);
w.set_pllr((divr - 1) as u8); w.set_pllr(divr);
}); });
}); });
@ -352,13 +254,13 @@ pub(crate) fn configure_clocks(config: &Config) {
rcc.cfgr().modify(|w| { rcc.cfgr().modify(|w| {
w.set_sw(config.sys.into()); w.set_sw(config.sys.into());
w.set_hpre(config.ahb1_pre.into()); w.set_hpre(config.ahb1_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
rcc.extcfgr().modify(|w| { rcc.extcfgr().modify(|w| {
w.set_c2hpre(config.ahb2_pre.into()); w.set_c2hpre(config.ahb2_pre);
w.set_shdhpre(config.ahb3_pre.into()); w.set_shdhpre(config.ahb3_pre);
}); });
} }

View File

@ -108,13 +108,13 @@ pub(crate) unsafe fn init(config: Config) {
}); });
RCC.cfgr2().modify(|w| { RCC.cfgr2().modify(|w| {
w.set_hpre(config.ahb_pre.into()); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
RCC.cfgr3().modify(|w| { RCC.cfgr3().modify(|w| {
w.set_ppre7(config.apb7_pre.into()); w.set_ppre7(config.apb7_pre);
}); });
let ahb_freq = sys_clk / config.ahb_pre; let ahb_freq = sys_clk / config.ahb_pre;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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