From c97f65ac609221067f7af4deb69d5b7d66d57c7a Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Fri, 1 Dec 2023 15:05:31 +0100 Subject: [PATCH] stm32/rcc: make h7 rm0399 power supply configurable --- embassy-stm32/src/rcc/h.rs | 148 ++++++++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 1a9603d0..2d3550da 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -117,6 +117,57 @@ impl From for Timpre { } } +/// Power supply configuration +/// See RM0433 Rev 4 7.4 +#[cfg(pwr_h7rm0399)] +pub enum SupplyConfig { + /// Default power supply configuration. + /// V CORE Power Domains are supplied from the LDO according to VOS. + /// SMPS step-down converter enabled at 1.2V, may be used to supply the LDO. + Default, + + /// Power supply configuration using the LDO. + /// V CORE Power Domains are supplied from the LDO according to VOS. + /// LDO power mode (Main, LP, Off) will follow system low-power modes. + /// SMPS step-down converter disabled. + LDO, + + /// Power supply configuration directly from the SMPS step-down converter. + /// V CORE Power Domains are supplied from SMPS step-down converter according to VOS. + /// LDO bypassed. + /// SMPS step-down converter power mode (MR, LP, Off) will follow system low-power modes. + DirectSMPS, + + /// Power supply configuration from the SMPS step-down converter, that supplies the LDO. + /// V CORE Power Domains are supplied from the LDO according to VOS + /// LDO power mode (Main, LP, Off) will follow system low-power modes. + /// SMPS step-down converter enabled according to SDLEVEL, and supplies the LDO. + /// SMPS step-down converter power mode (MR, LP, Off) will follow system low-power modes. + SMPSLDO, + + /// Power supply configuration from SMPS supplying external circuits and potentially the LDO. + /// V CORE Power Domains are supplied from voltage regulator according to VOS + /// LDO power mode (Main, LP, Off) will follow system low-power modes. + /// SMPS step-down converter enabled according to SDLEVEL used to supply external circuits and may supply the LDO. + /// SMPS step-down converter forced ON in MR mode. + SMPSExternalLDO, + + /// Power supply configuration from SMPS supplying external circuits and bypassing the LDO. + /// V CORE supplied from external source + /// SMPS step-down converter enabled according to SDLEVEL used to supply external circuits and may supply the external source for V CORE . + /// SMPS step-down converter forced ON in MR mode. + SMPSExternalLDOBypass, +} + +/// SMPS step-down converter voltage output level. +/// This is only used in certain power supply configurations: +/// SMPSLDO, SMPSExternalLDO, SMPSExternalLDOBypass. +#[cfg(pwr_h7rm0399)] +pub enum SMPSSupplyVoltage { + V1_8, + V2_5, +} + /// Configuration of the core clocks #[non_exhaustive] pub struct Config { @@ -144,6 +195,10 @@ pub struct Config { pub timer_prescaler: TimerPrescaler, pub voltage_scale: VoltageScale, pub ls: super::LsConfig, + + #[cfg(pwr_h7rm0399)] + pub supply_config: SupplyConfig, + pub smps_supply_voltage: Option, } impl Default for Config { @@ -177,6 +232,10 @@ impl Default for Config { timer_prescaler: TimerPrescaler::DefaultX2, voltage_scale: VoltageScale::Scale0, ls: Default::default(), + + #[cfg(pwr_h7rm0399)] + supply_config: SupplyConfig::Default, + smps_supply_voltage: None, } } } @@ -194,7 +253,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_bypass(false); }); - #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] + #[cfg(any(pwr_h7rm0455, pwr_h7rm0468))] PWR.cr3().modify(|w| { // hardcode "Direct SPMS" for now, this is what works on nucleos with the // default solderbridge configuration. @@ -202,6 +261,93 @@ pub(crate) unsafe fn init(config: Config) { w.set_ldoen(false); }); + #[cfg(pwr_h7rm0399)] + { + match config.supply_config { + SupplyConfig::Default => { + PWR.cr3().modify(|w| { + w.set_sdlevel(0b00); + w.set_sdexthp(false); + w.set_sden(true); + w.set_ldoen(true); + w.set_bypass(false); + }); + } + SupplyConfig::LDO => { + PWR.cr3().modify(|w| { + w.set_sden(false); + w.set_ldoen(true); + w.set_bypass(false); + }); + } + SupplyConfig::DirectSMPS => { + PWR.cr3().modify(|w| { + w.set_sdexthp(false); + w.set_sden(true); + w.set_ldoen(false); + w.set_bypass(false); + }); + } + SupplyConfig::SMPSLDO => { + PWR.cr3().modify(|w| { + match config.smps_supply_voltage { + Some(SMPSSupplyVoltage::V1_8) => { + PWR.cr3().modify(|w| w.set_sdlevel(0b01)); + } + Some(SMPSSupplyVoltage::V2_5) => { + PWR.cr3().modify(|w| w.set_sdlevel(0b10)); + } + None => { + panic!("Supply configuration SMPSLDO requires a supply voltage to be set."); + } + } + w.set_sdexthp(false); + w.set_sden(true); + w.set_ldoen(true); + w.set_bypass(false); + }); + } + SupplyConfig::SMPSExternalLDO => { + PWR.cr3().modify(|w| { + match config.smps_supply_voltage { + Some(SMPSSupplyVoltage::V1_8) => { + PWR.cr3().modify(|w| w.set_sdlevel(0b01)); + } + Some(SMPSSupplyVoltage::V2_5) => { + PWR.cr3().modify(|w| w.set_sdlevel(0b10)); + } + None => { + panic!("Supply configuration SMPSExternalLDO requires a supply voltage to be set."); + } + } + w.set_sdexthp(true); + w.set_sden(true); + w.set_ldoen(true); + w.set_bypass(false); + }); + } + SupplyConfig::SMPSExternalLDOBypass => { + PWR.cr3().modify(|w| { + match config.smps_supply_voltage { + Some(SMPSSupplyVoltage::V1_8) => { + PWR.cr3().modify(|w| w.set_sdlevel(0b01)); + } + Some(SMPSSupplyVoltage::V2_5) => { + PWR.cr3().modify(|w| w.set_sdlevel(0b10)); + } + None => { + panic!("Supply configuration SMPSExternalLDOBypass requires a supply voltage to be set."); + } + } + w.set_sdexthp(true); + w.set_sden(true); + w.set_ldoen(false); + w.set_bypass(true); + }); + } + } + } + // Validate the supply configuration. If you are stuck here, it is // because the voltages on your board do not match those specified // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset