Introduce configration options for Pll fast modes.

Ensure that the auto calibration is applied to an active clock.
This commit is contained in:
Frank Stevenson 2025-07-24 13:26:10 +02:00
parent cf9856255e
commit fd3cdfcf25

View File

@ -5,7 +5,7 @@ pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul,
Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
}; };
use crate::pac::rcc::vals::{Hseext, Msipllsel, Msirgsel, Pllmboost, Pllrge}; use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge};
#[cfg(all(peri_usb_otg_hs))] #[cfg(all(peri_usb_otg_hs))]
pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG}; pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
@ -72,12 +72,30 @@ pub enum MsiAutoCalibration {
MSIS, MSIS,
/// MSIK is given priority for auto-calibration /// MSIK is given priority for auto-calibration
MSIK, MSIK,
/// MSIS with fast mode (always on)
MsisFast,
/// MSIK with fast mode (always on)
MsikFast,
} }
impl MsiAutoCalibration { impl MsiAutoCalibration {
const fn default() -> Self { const fn default() -> Self {
MsiAutoCalibration::Disabled MsiAutoCalibration::Disabled
} }
fn base_mode(&self) -> Self {
match self {
MsiAutoCalibration::Disabled => MsiAutoCalibration::Disabled,
MsiAutoCalibration::MSIS => MsiAutoCalibration::MSIS,
MsiAutoCalibration::MSIK => MsiAutoCalibration::MSIK,
MsiAutoCalibration::MsisFast => MsiAutoCalibration::MSIS,
MsiAutoCalibration::MsikFast => MsiAutoCalibration::MSIK,
}
}
fn is_fast(&self) -> bool {
matches!(self, MsiAutoCalibration::MsisFast | MsiAutoCalibration::MsikFast)
}
} }
impl Default for MsiAutoCalibration { impl Default for MsiAutoCalibration {
@ -159,7 +177,23 @@ pub(crate) unsafe fn init(config: Config) {
Some(lse_config) => { Some(lse_config) => {
// Allow +/- 5% tolerance for LSE frequency // Allow +/- 5% tolerance for LSE frequency
if lse_config.peripherals_clocked && (31_100..=34_400).contains(&lse_config.frequency.0) { if lse_config.peripherals_clocked && (31_100..=34_400).contains(&lse_config.frequency.0) {
// Check that the calibration is applied to an active clock
match (
config.auto_calibration.base_mode(),
config.msis.is_some(),
config.msik.is_some(),
) {
(MsiAutoCalibration::MSIS, true, _) => {
// MSIS is active and using LSE for auto-calibration
Some(lse_config.frequency) Some(lse_config.frequency)
}
(MsiAutoCalibration::MSIK, _, true) => {
// MSIK is active and using LSE for auto-calibration
Some(lse_config.frequency)
}
// improper configuration, no LSE calibration
_ => None,
}
} else { } else {
None None
} }
@ -192,7 +226,9 @@ pub(crate) unsafe fn init(config: Config) {
w.set_msipllen(false); w.set_msipllen(false);
w.set_msison(true); w.set_msison(true);
}); });
let msis = if let (Some(freq), MsiAutoCalibration::MSIS) = (lse_calibration_freq, config.auto_calibration) { let msis = if let (Some(freq), MsiAutoCalibration::MSIS) =
(lse_calibration_freq, config.auto_calibration.base_mode())
{
// Enable the MSIS auto-calibration feature // Enable the MSIS auto-calibration feature
RCC.cr().modify(|w| w.set_msipllsel(Msipllsel::MSIS)); RCC.cr().modify(|w| w.set_msipllsel(Msipllsel::MSIS));
RCC.cr().modify(|w| w.set_msipllen(true)); RCC.cr().modify(|w| w.set_msipllen(true));
@ -228,7 +264,9 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().modify(|w| { RCC.cr().modify(|w| {
w.set_msikon(true); w.set_msikon(true);
}); });
let msik = if let (Some(freq), MsiAutoCalibration::MSIK) = (lse_calibration_freq, config.auto_calibration) { let msik = if let (Some(freq), MsiAutoCalibration::MSIK) =
(lse_calibration_freq, config.auto_calibration.base_mode())
{
// Enable the MSIK auto-calibration feature // Enable the MSIK auto-calibration feature
RCC.cr().modify(|w| w.set_msipllsel(Msipllsel::MSIK)); RCC.cr().modify(|w| w.set_msipllsel(Msipllsel::MSIK));
RCC.cr().modify(|w| w.set_msipllen(true)); RCC.cr().modify(|w| w.set_msipllen(true));
@ -242,10 +280,16 @@ pub(crate) unsafe fn init(config: Config) {
// If both MSIS and MSIK are enabled, we need to check if they are using the same internal source. // If both MSIS and MSIK are enabled, we need to check if they are using the same internal source.
if let Some(lse_freq) = lse_calibration_freq { if let Some(lse_freq) = lse_calibration_freq {
// Check if Fast mode should be used
if config.auto_calibration.is_fast() {
RCC.cr().modify(|w| {
w.set_msipllfast(Msipllfast::FAST);
});
}
if let (Some(msis_range), Some(msik_range)) = (config.msis, config.msik) { if let (Some(msis_range), Some(msik_range)) = (config.msis, config.msik) {
if (msis_range as u8 >> 2) == (msik_range as u8 >> 2) { if (msis_range as u8 >> 2) == (msik_range as u8 >> 2) {
// Clock source is shared, both will be auto calibrated. // Clock source is shared, both will be auto calibrated.
match config.auto_calibration { match config.auto_calibration.base_mode() {
MsiAutoCalibration::MSIS => { MsiAutoCalibration::MSIS => {
// MSIS and MSIK are using the same clock source, recalibrate // MSIS and MSIK are using the same clock source, recalibrate
msik = Some(calculate_calibrated_msi_frequency(msik_range, lse_freq)); msik = Some(calculate_calibrated_msi_frequency(msik_range, lse_freq));