stm32/rcc: add better support for L4/L4+ differences.
This commit is contained in:
parent
f54753beaa
commit
5c5e681819
@ -58,7 +58,7 @@ rand_core = "0.6.3"
|
|||||||
sdio-host = "0.5.0"
|
sdio-host = "0.5.0"
|
||||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-01a757e40df688efcda23607185640e1c2396ba9" }
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-73e3f8a965a01fd5a168c3543b93ce49d475e130" }
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
bxcan = "0.7.0"
|
bxcan = "0.7.0"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
proc-macro2 = "1.0.36"
|
proc-macro2 = "1.0.36"
|
||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-01a757e40df688efcda23607185640e1c2396ba9", default-features = false, features = ["metadata"]}
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-73e3f8a965a01fd5a168c3543b93ce49d475e130", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use crate::pac::rcc::regs::Cfgr;
|
use crate::pac::rcc::regs::Cfgr;
|
||||||
|
use crate::pac::rcc::vals::Msirgsel;
|
||||||
pub use crate::pac::rcc::vals::{
|
pub use crate::pac::rcc::vals::{
|
||||||
Hpre as AHBPrescaler, Msirange as MSIRange, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv,
|
Clk48sel as Clk48Src, Hpre as AHBPrescaler, Msirange as MSIRange, Pllm as PllPreDiv, Plln as PllMul,
|
||||||
Pllr as PllRDiv, Pllsrc as PLLSource, Ppre as APBPrescaler, Sw as ClockSrc,
|
Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PLLSource, Ppre as APBPrescaler, Sw as ClockSrc,
|
||||||
};
|
};
|
||||||
use crate::pac::{FLASH, RCC};
|
use crate::pac::{FLASH, RCC};
|
||||||
use crate::rcc::{set_freqs, Clocks};
|
use crate::rcc::{set_freqs, Clocks};
|
||||||
@ -12,6 +13,9 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
|
|||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Pll {
|
pub struct Pll {
|
||||||
|
/// PLL source
|
||||||
|
pub source: PLLSource,
|
||||||
|
|
||||||
/// PLL pre-divider (DIVM).
|
/// PLL pre-divider (DIVM).
|
||||||
pub prediv: PllPreDiv,
|
pub prediv: PllPreDiv,
|
||||||
|
|
||||||
@ -32,11 +36,10 @@ pub struct Config {
|
|||||||
pub msi: Option<MSIRange>,
|
pub msi: Option<MSIRange>,
|
||||||
pub hsi16: bool,
|
pub hsi16: bool,
|
||||||
pub hse: Option<Hertz>,
|
pub hse: Option<Hertz>,
|
||||||
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
|
#[cfg(not(any(stm32l47x, stm32l48x)))]
|
||||||
pub hsi48: bool,
|
pub hsi48: bool,
|
||||||
|
|
||||||
// pll
|
// pll
|
||||||
pub pll_src: PLLSource,
|
|
||||||
pub pll: Option<Pll>,
|
pub pll: Option<Pll>,
|
||||||
pub pllsai1: Option<Pll>,
|
pub pllsai1: Option<Pll>,
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
@ -50,6 +53,9 @@ pub struct Config {
|
|||||||
pub apb1_pre: APBPrescaler,
|
pub apb1_pre: APBPrescaler,
|
||||||
pub apb2_pre: APBPrescaler,
|
pub apb2_pre: APBPrescaler,
|
||||||
|
|
||||||
|
// muxes
|
||||||
|
pub clk48_src: Clk48Src,
|
||||||
|
|
||||||
// low speed LSI/LSE/RTC
|
// low speed LSI/LSE/RTC
|
||||||
pub ls: super::LsConfig,
|
pub ls: super::LsConfig,
|
||||||
}
|
}
|
||||||
@ -65,7 +71,6 @@ impl Default for Config {
|
|||||||
ahb_pre: AHBPrescaler::DIV1,
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
apb1_pre: APBPrescaler::DIV1,
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
apb2_pre: APBPrescaler::DIV1,
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
pll_src: PLLSource::NONE,
|
|
||||||
pll: None,
|
pll: None,
|
||||||
pllsai1: None,
|
pllsai1: None,
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
@ -73,7 +78,8 @@ impl Default for Config {
|
|||||||
))]
|
))]
|
||||||
pllsai2: None,
|
pllsai2: None,
|
||||||
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
|
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
|
||||||
hsi48: false,
|
hsi48: true,
|
||||||
|
clk48_src: Clk48Src::HSI48,
|
||||||
ls: Default::default(),
|
ls: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,7 +90,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
if !RCC.cr().read().msion() {
|
if !RCC.cr().read().msion() {
|
||||||
// Turn on MSI and configure it to 4MHz.
|
// Turn on MSI and configure it to 4MHz.
|
||||||
RCC.cr().modify(|w| {
|
RCC.cr().modify(|w| {
|
||||||
w.set_msirgsel(true); // MSI Range is provided by MSIRANGE[3:0].
|
w.set_msirgsel(Msirgsel::CR);
|
||||||
w.set_msirange(MSIRange::RANGE4M);
|
w.set_msirange(MSIRange::RANGE4M);
|
||||||
w.set_msipllen(false);
|
w.set_msipllen(false);
|
||||||
w.set_msion(true)
|
w.set_msion(true)
|
||||||
@ -106,7 +112,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
// Enable MSI
|
// Enable MSI
|
||||||
RCC.cr().write(|w| {
|
RCC.cr().write(|w| {
|
||||||
w.set_msirange(range);
|
w.set_msirange(range);
|
||||||
w.set_msirgsel(true);
|
w.set_msirgsel(Msirgsel::CR);
|
||||||
w.set_msion(true);
|
w.set_msion(true);
|
||||||
|
|
||||||
// If LSE is enabled, enable calibration of MSI
|
// If LSE is enabled, enable calibration of MSI
|
||||||
@ -115,9 +121,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
while !RCC.cr().read().msirdy() {}
|
while !RCC.cr().read().msirdy() {}
|
||||||
|
|
||||||
// Enable as clock source for USB, RNG if running at 48 MHz
|
// Enable as clock source for USB, RNG if running at 48 MHz
|
||||||
if range == MSIRange::RANGE48M {
|
if range == MSIRange::RANGE48M {}
|
||||||
RCC.ccipr().modify(|w| w.set_clk48sel(0b11));
|
|
||||||
}
|
|
||||||
|
|
||||||
msirange_to_hertz(range)
|
msirange_to_hertz(range)
|
||||||
});
|
});
|
||||||
@ -136,154 +140,66 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
freq
|
freq
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
|
#[cfg(not(any(stm32l47x, stm32l48x)))]
|
||||||
let _hsi48 = config.hsi48.then(|| {
|
let hsi48 = config.hsi48.then(|| {
|
||||||
RCC.crrcr().modify(|w| w.set_hsi48on(true));
|
RCC.crrcr().modify(|w| w.set_hsi48on(true));
|
||||||
while !RCC.crrcr().read().hsi48rdy() {}
|
while !RCC.crrcr().read().hsi48rdy() {}
|
||||||
|
|
||||||
// Enable as clock source for USB, RNG and SDMMC
|
|
||||||
RCC.ccipr().modify(|w| w.set_clk48sel(0));
|
|
||||||
|
|
||||||
Hertz(48_000_000)
|
Hertz(48_000_000)
|
||||||
});
|
});
|
||||||
|
#[cfg(any(stm32l47x, stm32l48x))]
|
||||||
|
let hsi48 = None;
|
||||||
|
|
||||||
let pll_src = match config.pll_src {
|
let _plls = [
|
||||||
PLLSource::NONE => None,
|
&config.pll,
|
||||||
PLLSource::HSE => hse,
|
&config.pllsai1,
|
||||||
PLLSource::HSI16 => hsi16,
|
|
||||||
PLLSource::MSI => msi,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut _pllp = None;
|
|
||||||
let mut _pllq = None;
|
|
||||||
let mut _pllr = None;
|
|
||||||
if let Some(pll) = config.pll {
|
|
||||||
let pll_src = pll_src.unwrap();
|
|
||||||
|
|
||||||
// Disable PLL
|
|
||||||
RCC.cr().modify(|w| w.set_pllon(false));
|
|
||||||
while RCC.cr().read().pllrdy() {}
|
|
||||||
|
|
||||||
let vco_freq = pll_src / pll.prediv * pll.mul;
|
|
||||||
|
|
||||||
_pllp = pll.divp.map(|div| vco_freq / div);
|
|
||||||
_pllq = pll.divq.map(|div| vco_freq / div);
|
|
||||||
_pllr = pll.divr.map(|div| vco_freq / div);
|
|
||||||
|
|
||||||
RCC.pllcfgr().write(move |w| {
|
|
||||||
w.set_plln(pll.mul);
|
|
||||||
w.set_pllm(pll.prediv);
|
|
||||||
w.set_pllsrc(config.pll_src);
|
|
||||||
if let Some(divp) = pll.divp {
|
|
||||||
w.set_pllp(divp);
|
|
||||||
w.set_pllpen(true);
|
|
||||||
}
|
|
||||||
if let Some(divq) = pll.divq {
|
|
||||||
w.set_pllq(divq);
|
|
||||||
w.set_pllqen(true);
|
|
||||||
}
|
|
||||||
if let Some(divr) = pll.divr {
|
|
||||||
w.set_pllr(divr);
|
|
||||||
w.set_pllren(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if _pllq == Some(Hertz(48_000_000)) {
|
|
||||||
RCC.ccipr().modify(|w| w.set_clk48sel(0b10));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable PLL
|
|
||||||
RCC.cr().modify(|w| w.set_pllon(true));
|
|
||||||
while !RCC.cr().read().pllrdy() {}
|
|
||||||
} else {
|
|
||||||
// even if we're not using the main pll, set the source for pllsai
|
|
||||||
RCC.pllcfgr().write(move |w| {
|
|
||||||
w.set_pllsrc(config.pll_src);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(pll) = config.pllsai1 {
|
|
||||||
let pll_src = pll_src.unwrap();
|
|
||||||
|
|
||||||
// Disable PLL
|
|
||||||
RCC.cr().modify(|w| w.set_pllsai1on(false));
|
|
||||||
while RCC.cr().read().pllsai1rdy() {}
|
|
||||||
|
|
||||||
let vco_freq = pll_src / pll.prediv * pll.mul;
|
|
||||||
|
|
||||||
let _pllp = pll.divp.map(|div| vco_freq / div);
|
|
||||||
let _pllq = pll.divq.map(|div| vco_freq / div);
|
|
||||||
let _pllr = pll.divr.map(|div| vco_freq / div);
|
|
||||||
|
|
||||||
RCC.pllsai1cfgr().write(move |w| {
|
|
||||||
w.set_plln(pll.mul);
|
|
||||||
w.set_pllm(pll.prediv);
|
|
||||||
if let Some(divp) = pll.divp {
|
|
||||||
w.set_pllp(divp);
|
|
||||||
w.set_pllpen(true);
|
|
||||||
}
|
|
||||||
if let Some(divq) = pll.divq {
|
|
||||||
w.set_pllq(divq);
|
|
||||||
w.set_pllqen(true);
|
|
||||||
}
|
|
||||||
if let Some(divr) = pll.divr {
|
|
||||||
w.set_pllr(divr);
|
|
||||||
w.set_pllren(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if _pllq == Some(Hertz(48_000_000)) {
|
|
||||||
RCC.ccipr().modify(|w| w.set_clk48sel(0b01));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable PLL
|
|
||||||
RCC.cr().modify(|w| w.set_pllsai1on(true));
|
|
||||||
while !RCC.cr().read().pllsai1rdy() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx
|
stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx
|
||||||
))]
|
))]
|
||||||
if let Some(pll) = config.pllsai2 {
|
&config.pllsai2,
|
||||||
let pll_src = pll_src.unwrap();
|
];
|
||||||
|
|
||||||
// Disable PLL
|
// L4 has shared PLLSRC, PLLM, check it's equal in all PLLs.
|
||||||
RCC.cr().modify(|w| w.set_pllsai2on(false));
|
#[cfg(all(stm32l4, not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))))]
|
||||||
while RCC.cr().read().pllsai2rdy() {}
|
match get_equal(_plls.into_iter().flatten().map(|p| (p.source, p.prediv))) {
|
||||||
|
Err(()) => panic!("Source must be equal across all enabled PLLs."),
|
||||||
|
Ok(None) => {}
|
||||||
|
Ok(Some((source, prediv))) => RCC.pllcfgr().write(|w| {
|
||||||
|
w.set_pllm(prediv);
|
||||||
|
w.set_pllsrc(source);
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
let vco_freq = pll_src / pll.prediv * pll.mul;
|
// L4+ has shared PLLSRC, check it's equal in all PLLs.
|
||||||
|
#[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))]
|
||||||
|
match get_equal(_plls.into_iter().flatten().map(|p| p.source)) {
|
||||||
|
Err(()) => panic!("Source must be equal across all enabled PLLs."),
|
||||||
|
Ok(None) => {}
|
||||||
|
Ok(Some(source)) => RCC.pllcfgr().write(|w| {
|
||||||
|
w.set_pllsrc(source);
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
let _pllp = pll.divp.map(|div| vco_freq / div);
|
let pll_input = PllInput { hse, hsi16, msi };
|
||||||
let _pllq = pll.divq.map(|div| vco_freq / div);
|
let pll = init_pll(PllInstance::Pll, config.pll, &pll_input);
|
||||||
let _pllr = pll.divr.map(|div| vco_freq / div);
|
let pllsai1 = init_pll(PllInstance::Pllsai1, config.pllsai1, &pll_input);
|
||||||
|
#[cfg(any(
|
||||||
RCC.pllsai2cfgr().write(move |w| {
|
stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx
|
||||||
w.set_plln(pll.mul);
|
))]
|
||||||
w.set_pllm(pll.prediv);
|
let _pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input);
|
||||||
if let Some(divp) = pll.divp {
|
|
||||||
w.set_pllp(divp);
|
|
||||||
w.set_pllpen(true);
|
|
||||||
}
|
|
||||||
if let Some(divq) = pll.divq {
|
|
||||||
w.set_pllq(divq);
|
|
||||||
w.set_pllqen(true);
|
|
||||||
}
|
|
||||||
if let Some(divr) = pll.divr {
|
|
||||||
w.set_pllr(divr);
|
|
||||||
w.set_pllren(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Enable PLL
|
|
||||||
RCC.cr().modify(|w| w.set_pllsai2on(true));
|
|
||||||
while !RCC.cr().read().pllsai2rdy() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let sys_clk = match config.mux {
|
let sys_clk = match config.mux {
|
||||||
ClockSrc::HSE => hse.unwrap(),
|
ClockSrc::HSE => hse.unwrap(),
|
||||||
ClockSrc::HSI16 => hsi16.unwrap(),
|
ClockSrc::HSI16 => hsi16.unwrap(),
|
||||||
ClockSrc::MSI => msi.unwrap(),
|
ClockSrc::MSI => msi.unwrap(),
|
||||||
ClockSrc::PLL => _pllr.unwrap(),
|
ClockSrc::PLL => pll._r.unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _clk48 = match config.clk48_src {
|
||||||
|
Clk48Src::HSI48 => hsi48,
|
||||||
|
Clk48Src::MSI => msi,
|
||||||
|
Clk48Src::PLLSAI1_Q => pllsai1._q,
|
||||||
|
Clk48Src::PLL_Q => pll._q,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))]
|
#[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))]
|
||||||
@ -357,3 +273,136 @@ fn msirange_to_hertz(range: MSIRange) -> Hertz {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_equal<T: Eq>(mut iter: impl Iterator<Item = T>) -> Result<Option<T>, ()> {
|
||||||
|
let Some(x) = iter.next() else { return Ok(None) };
|
||||||
|
if !iter.all(|y| y == x) {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
return Ok(Some(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PllInput {
|
||||||
|
hsi16: Option<Hertz>,
|
||||||
|
hse: Option<Hertz>,
|
||||||
|
msi: Option<Hertz>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct PllOutput {
|
||||||
|
_p: Option<Hertz>,
|
||||||
|
_q: Option<Hertz>,
|
||||||
|
_r: Option<Hertz>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
enum PllInstance {
|
||||||
|
Pll,
|
||||||
|
Pllsai1,
|
||||||
|
#[cfg(any(
|
||||||
|
stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx
|
||||||
|
))]
|
||||||
|
Pllsai2,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput {
|
||||||
|
// Disable PLL
|
||||||
|
match instance {
|
||||||
|
PllInstance::Pll => {
|
||||||
|
RCC.cr().modify(|w| w.set_pllon(false));
|
||||||
|
while RCC.cr().read().pllrdy() {}
|
||||||
|
}
|
||||||
|
PllInstance::Pllsai1 => {
|
||||||
|
RCC.cr().modify(|w| w.set_pllsai1on(false));
|
||||||
|
while RCC.cr().read().pllsai1rdy() {}
|
||||||
|
}
|
||||||
|
#[cfg(any(
|
||||||
|
stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx
|
||||||
|
))]
|
||||||
|
PllInstance::Pllsai2 => {
|
||||||
|
RCC.cr().modify(|w| w.set_pllsai2on(false));
|
||||||
|
while RCC.cr().read().pllsai2rdy() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(pll) = config else { return PllOutput::default() };
|
||||||
|
|
||||||
|
let pll_src = match pll.source {
|
||||||
|
PLLSource::NONE => panic!("must not select PLL source as NONE"),
|
||||||
|
PLLSource::HSE => input.hse,
|
||||||
|
PLLSource::HSI16 => input.hsi16,
|
||||||
|
PLLSource::MSI => input.msi,
|
||||||
|
};
|
||||||
|
|
||||||
|
let pll_src = pll_src.unwrap();
|
||||||
|
|
||||||
|
let vco_freq = pll_src / pll.prediv * pll.mul;
|
||||||
|
|
||||||
|
let p = pll.divp.map(|div| vco_freq / div);
|
||||||
|
let q = pll.divq.map(|div| vco_freq / div);
|
||||||
|
let r = pll.divr.map(|div| vco_freq / div);
|
||||||
|
|
||||||
|
macro_rules! write_fields {
|
||||||
|
($w:ident) => {
|
||||||
|
$w.set_plln(pll.mul);
|
||||||
|
if let Some(divp) = pll.divp {
|
||||||
|
$w.set_pllp(divp);
|
||||||
|
$w.set_pllpen(true);
|
||||||
|
}
|
||||||
|
if let Some(divq) = pll.divq {
|
||||||
|
$w.set_pllq(divq);
|
||||||
|
$w.set_pllqen(true);
|
||||||
|
}
|
||||||
|
if let Some(divr) = pll.divr {
|
||||||
|
$w.set_pllr(divr);
|
||||||
|
$w.set_pllren(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
match instance {
|
||||||
|
PllInstance::Pll => RCC.pllcfgr().write(|w| {
|
||||||
|
w.set_pllm(pll.prediv);
|
||||||
|
w.set_pllsrc(pll.source);
|
||||||
|
write_fields!(w);
|
||||||
|
}),
|
||||||
|
PllInstance::Pllsai1 => RCC.pllsai1cfgr().write(|w| {
|
||||||
|
#[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx, stm32l5))]
|
||||||
|
w.set_pllm(pll.prediv);
|
||||||
|
#[cfg(stm32l5)]
|
||||||
|
w.set_pllsrc(pll.source);
|
||||||
|
write_fields!(w);
|
||||||
|
}),
|
||||||
|
#[cfg(any(
|
||||||
|
stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx
|
||||||
|
))]
|
||||||
|
PllInstance::Pllsai2 => RCC.pllsai2cfgr().write(|w| {
|
||||||
|
#[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx, stm32l5))]
|
||||||
|
w.set_pllm(pll.prediv);
|
||||||
|
#[cfg(stm32l5)]
|
||||||
|
w.set_pllsrc(pll.source);
|
||||||
|
write_fields!(w);
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable PLL
|
||||||
|
match instance {
|
||||||
|
PllInstance::Pll => {
|
||||||
|
RCC.cr().modify(|w| w.set_pllon(true));
|
||||||
|
while !RCC.cr().read().pllrdy() {}
|
||||||
|
}
|
||||||
|
PllInstance::Pllsai1 => {
|
||||||
|
RCC.cr().modify(|w| w.set_pllsai1on(true));
|
||||||
|
while !RCC.cr().read().pllsai1rdy() {}
|
||||||
|
}
|
||||||
|
#[cfg(any(
|
||||||
|
stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx
|
||||||
|
))]
|
||||||
|
PllInstance::Pllsai2 => {
|
||||||
|
RCC.cr().modify(|w| w.set_pllsai2on(true));
|
||||||
|
while !RCC.cr().read().pllsai2rdy() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PllOutput { _p: p, _q: q, _r: r }
|
||||||
|
}
|
||||||
|
@ -104,7 +104,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
// Enable as clock source for USB, RNG if running at 48 MHz
|
// Enable as clock source for USB, RNG if running at 48 MHz
|
||||||
if range == MSIRange::RANGE48M {
|
if range == MSIRange::RANGE48M {
|
||||||
RCC.ccipr1().modify(|w| {
|
RCC.ccipr1().modify(|w| {
|
||||||
w.set_clk48msel(0b11);
|
w.set_clk48sel(0b11);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
(msirange_to_hertz(range), Sw::MSI)
|
(msirange_to_hertz(range), Sw::MSI)
|
||||||
@ -173,7 +173,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
let freq = src_freq / prediv * mul / divq;
|
let freq = src_freq / prediv * mul / divq;
|
||||||
assert!(freq.0 == 48_000_000);
|
assert!(freq.0 == 48_000_000);
|
||||||
RCC.ccipr1().modify(|w| {
|
RCC.ccipr1().modify(|w| {
|
||||||
w.set_clk48msel(0b10);
|
w.set_clk48sel(0b10);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +191,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
let freq = src_freq / prediv * mul / q_div;
|
let freq = src_freq / prediv * mul / q_div;
|
||||||
if freq.0 == 48_000_000 {
|
if freq.0 == 48_000_000 {
|
||||||
RCC.ccipr1().modify(|w| {
|
RCC.ccipr1().modify(|w| {
|
||||||
w.set_clk48msel(0b1);
|
w.set_clk48sel(0b1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,7 +218,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
while !RCC.crrcr().read().hsi48rdy() {}
|
while !RCC.crrcr().read().hsi48rdy() {}
|
||||||
|
|
||||||
// Enable as clock source for USB, RNG and SDMMC
|
// Enable as clock source for USB, RNG and SDMMC
|
||||||
RCC.ccipr1().modify(|w| w.set_clk48msel(0));
|
RCC.ccipr1().modify(|w| w.set_clk48sel(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set flash wait states
|
// Set flash wait states
|
||||||
|
@ -20,7 +20,7 @@ pub use mco::*;
|
|||||||
#[cfg_attr(rcc_g4, path = "g4.rs")]
|
#[cfg_attr(rcc_g4, path = "g4.rs")]
|
||||||
#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")]
|
#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")]
|
||||||
#[cfg_attr(any(rcc_l0, rcc_l0_v2, rcc_l1), path = "l0l1.rs")]
|
#[cfg_attr(any(rcc_l0, rcc_l0_v2, rcc_l1), path = "l0l1.rs")]
|
||||||
#[cfg_attr(rcc_l4, path = "l4.rs")]
|
#[cfg_attr(any(rcc_l4, rcc_l4plus), path = "l4.rs")]
|
||||||
#[cfg_attr(rcc_l5, path = "l5.rs")]
|
#[cfg_attr(rcc_l5, path = "l5.rs")]
|
||||||
#[cfg_attr(rcc_u5, path = "u5.rs")]
|
#[cfg_attr(rcc_u5, path = "u5.rs")]
|
||||||
#[cfg_attr(rcc_wb, path = "wb.rs")]
|
#[cfg_attr(rcc_wb, path = "wb.rs")]
|
||||||
@ -65,6 +65,7 @@ pub struct Clocks {
|
|||||||
pub hclk1: Hertz,
|
pub hclk1: Hertz,
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
rcc_l4,
|
rcc_l4,
|
||||||
|
rcc_l4plus,
|
||||||
rcc_l5,
|
rcc_l5,
|
||||||
rcc_f2,
|
rcc_f2,
|
||||||
rcc_f4,
|
rcc_f4,
|
||||||
@ -85,6 +86,7 @@ pub struct Clocks {
|
|||||||
pub hclk2: Hertz,
|
pub hclk2: Hertz,
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
rcc_l4,
|
rcc_l4,
|
||||||
|
rcc_l4plus,
|
||||||
rcc_l5,
|
rcc_l5,
|
||||||
rcc_f2,
|
rcc_f2,
|
||||||
rcc_f4,
|
rcc_f4,
|
||||||
|
@ -13,7 +13,7 @@ fn main() -> ! {
|
|||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
pac::RCC.ccipr().modify(|w| {
|
pac::RCC.ccipr().modify(|w| {
|
||||||
w.set_adcsel(0b11);
|
w.set_adcsel(pac::rcc::vals::Adcsel::SYSCLK);
|
||||||
});
|
});
|
||||||
pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
|
pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
|
||||||
|
|
||||||
|
@ -18,8 +18,8 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.rcc.mux = ClockSrc::PLL;
|
config.rcc.mux = ClockSrc::PLL;
|
||||||
config.rcc.hsi16 = true;
|
config.rcc.hsi16 = true;
|
||||||
config.rcc.pll_src = PLLSource::HSI16;
|
|
||||||
config.rcc.pll = Some(Pll {
|
config.rcc.pll = Some(Pll {
|
||||||
|
source: PLLSource::HSI16,
|
||||||
prediv: PllPreDiv::DIV1,
|
prediv: PllPreDiv::DIV1,
|
||||||
mul: PllMul::MUL18,
|
mul: PllMul::MUL18,
|
||||||
divp: None,
|
divp: None,
|
||||||
|
@ -17,8 +17,8 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.rcc.mux = ClockSrc::PLL;
|
config.rcc.mux = ClockSrc::PLL;
|
||||||
config.rcc.hse = Some(Hertz::mhz(8));
|
config.rcc.hse = Some(Hertz::mhz(8));
|
||||||
config.rcc.pll_src = PLLSource::HSE;
|
|
||||||
config.rcc.pll = Some(Pll {
|
config.rcc.pll = Some(Pll {
|
||||||
|
source: PLLSource::HSE,
|
||||||
prediv: PllPreDiv::DIV1,
|
prediv: PllPreDiv::DIV1,
|
||||||
mul: PllMul::MUL20,
|
mul: PllMul::MUL20,
|
||||||
divp: None,
|
divp: None,
|
||||||
|
@ -79,8 +79,8 @@ async fn main(spawner: Spawner) {
|
|||||||
// 80MHz highest frequency for flash 0 wait.
|
// 80MHz highest frequency for flash 0 wait.
|
||||||
config.rcc.mux = ClockSrc::PLL;
|
config.rcc.mux = ClockSrc::PLL;
|
||||||
config.rcc.hse = Some(Hertz::mhz(8));
|
config.rcc.hse = Some(Hertz::mhz(8));
|
||||||
config.rcc.pll_src = PLLSource::HSE;
|
|
||||||
config.rcc.pll = Some(Pll {
|
config.rcc.pll = Some(Pll {
|
||||||
|
source: PLLSource::HSE,
|
||||||
prediv: PllPreDiv::DIV1,
|
prediv: PllPreDiv::DIV1,
|
||||||
mul: PllMul::MUL20,
|
mul: PllMul::MUL20,
|
||||||
divp: None,
|
divp: None,
|
||||||
|
@ -26,8 +26,8 @@ async fn main(_spawner: Spawner) {
|
|||||||
config.rcc.hsi48 = true;
|
config.rcc.hsi48 = true;
|
||||||
config.rcc.mux = ClockSrc::PLL;
|
config.rcc.mux = ClockSrc::PLL;
|
||||||
config.rcc.hsi16 = true;
|
config.rcc.hsi16 = true;
|
||||||
config.rcc.pll_src = PLLSource::HSI16;
|
|
||||||
config.rcc.pll = Some(Pll {
|
config.rcc.pll = Some(Pll {
|
||||||
|
source: PLLSource::HSI16,
|
||||||
prediv: PllPreDiv::DIV1,
|
prediv: PllPreDiv::DIV1,
|
||||||
mul: PllMul::MUL10,
|
mul: PllMul::MUL10,
|
||||||
divp: None,
|
divp: None,
|
||||||
|
@ -289,8 +289,8 @@ pub fn config() -> Config {
|
|||||||
use embassy_stm32::rcc::*;
|
use embassy_stm32::rcc::*;
|
||||||
config.rcc.mux = ClockSrc::PLL;
|
config.rcc.mux = ClockSrc::PLL;
|
||||||
config.rcc.hsi16 = true;
|
config.rcc.hsi16 = true;
|
||||||
config.rcc.pll_src = PLLSource::HSI16;
|
|
||||||
config.rcc.pll = Some(Pll {
|
config.rcc.pll = Some(Pll {
|
||||||
|
source: PLLSource::HSI16,
|
||||||
prediv: PllPreDiv::DIV1,
|
prediv: PllPreDiv::DIV1,
|
||||||
mul: PllMul::MUL18,
|
mul: PllMul::MUL18,
|
||||||
divp: None,
|
divp: None,
|
||||||
|
Loading…
Reference in New Issue
Block a user