From c97f65ac609221067f7af4deb69d5b7d66d57c7a Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Fri, 1 Dec 2023 15:05:31 +0100 Subject: [PATCH 1/4] 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 From 87c0f1525dee9c2762872426076ffa82dc45900b Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Sat, 2 Dec 2023 14:45:36 +0100 Subject: [PATCH 2/4] stm32/rcc: enable power supply configurability for rm0455 and rm0468 --- embassy-stm32/src/rcc/h.rs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 2d3550da..55543472 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -119,7 +119,7 @@ impl From for Timpre { /// Power supply configuration /// See RM0433 Rev 4 7.4 -#[cfg(pwr_h7rm0399)] +#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] pub enum SupplyConfig { /// Default power supply configuration. /// V CORE Power Domains are supplied from the LDO according to VOS. @@ -162,7 +162,7 @@ pub enum SupplyConfig { /// SMPS step-down converter voltage output level. /// This is only used in certain power supply configurations: /// SMPSLDO, SMPSExternalLDO, SMPSExternalLDOBypass. -#[cfg(pwr_h7rm0399)] +#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] pub enum SMPSSupplyVoltage { V1_8, V2_5, @@ -196,7 +196,7 @@ pub struct Config { pub voltage_scale: VoltageScale, pub ls: super::LsConfig, - #[cfg(pwr_h7rm0399)] + #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] pub supply_config: SupplyConfig, pub smps_supply_voltage: Option, } @@ -233,7 +233,7 @@ impl Default for Config { voltage_scale: VoltageScale::Scale0, ls: Default::default(), - #[cfg(pwr_h7rm0399)] + #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] supply_config: SupplyConfig::Default, smps_supply_voltage: None, } @@ -253,15 +253,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_bypass(false); }); - #[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. - w.set_sden(true); - w.set_ldoen(false); - }); - - #[cfg(pwr_h7rm0399)] + #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] { match config.supply_config { SupplyConfig::Default => { From 22c39fd6970ceb335949e6cef15331c993105a14 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Sat, 2 Dec 2023 14:47:36 +0100 Subject: [PATCH 3/4] stm32/rcc: refactor h7 rm0455,rm0468 and rm0468 power management --- embassy-stm32/src/rcc/h.rs | 87 +++++++++++++------------------------- 1 file changed, 29 insertions(+), 58 deletions(-) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 55543472..644647d9 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -120,6 +120,7 @@ impl From for Timpre { /// Power supply configuration /// See RM0433 Rev 4 7.4 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] +#[derive(PartialEq)] pub enum SupplyConfig { /// Default power supply configuration. /// V CORE Power Domains are supplied from the LDO according to VOS. @@ -143,31 +144,43 @@ pub enum SupplyConfig { /// 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, + SMPSLDO(SMPSSupplyVoltage), /// 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, + SMPSExternalLDO(SMPSSupplyVoltage), /// 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, + SMPSExternalLDOBypass(SMPSSupplyVoltage), } /// SMPS step-down converter voltage output level. /// This is only used in certain power supply configurations: /// SMPSLDO, SMPSExternalLDO, SMPSExternalLDOBypass. #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] +#[derive(PartialEq)] pub enum SMPSSupplyVoltage { V1_8, V2_5, } +#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] +impl SMPSSupplyVoltage { + /// Convert SMPSSupplyVoltage to u8 representation. + fn to_u8(&self) -> u8 { + match self { + SMPSSupplyVoltage::V1_8 => 0b01, + SMPSSupplyVoltage::V2_5 => 0b10, + } + } +} + /// Configuration of the core clocks #[non_exhaustive] pub struct Config { @@ -198,7 +211,6 @@ pub struct Config { #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] pub supply_config: SupplyConfig, - pub smps_supply_voltage: Option, } impl Default for Config { @@ -235,7 +247,6 @@ impl Default for Config { #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] supply_config: SupplyConfig::Default, - smps_supply_voltage: None, } } } @@ -280,61 +291,21 @@ pub(crate) unsafe fn init(config: Config) { w.set_bypass(false); }); } - SupplyConfig::SMPSLDO => { + SupplyConfig::SMPSLDO(ref smps_supply_voltage) + | SupplyConfig::SMPSExternalLDO(ref smps_supply_voltage) + | SupplyConfig::SMPSExternalLDOBypass(ref smps_supply_voltage) => { 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_sdlevel(smps_supply_voltage.to_u8()); + w.set_sdexthp(matches!( + config.supply_config, + SupplyConfig::SMPSExternalLDO(_) | SupplyConfig::SMPSExternalLDOBypass(_) + )); 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); + w.set_ldoen(matches!( + config.supply_config, + SupplyConfig::SMPSLDO(_) | SupplyConfig::SMPSExternalLDO(_) + )); + w.set_bypass(matches!(config.supply_config, SupplyConfig::SMPSExternalLDOBypass(_))); }); } } From ea43d74780fd801a6e68820d01fd7dd21287acf8 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Sat, 2 Dec 2023 14:55:00 +0100 Subject: [PATCH 4/4] stm32/rcc: add missing h7 power config --- embassy-stm32/src/rcc/h.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 644647d9..1889eb28 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -158,6 +158,11 @@ pub enum SupplyConfig { /// 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(SMPSSupplyVoltage), + + /// Power supply configuration from an external source, SMPS disabled and the LDO bypassed. + /// V CORE supplied from external source + /// SMPS step-down converter disabled and LDO bypassed, voltage monitoring still active. + SMPSDisabledLDOBypass, } /// SMPS step-down converter voltage output level. @@ -308,6 +313,13 @@ pub(crate) unsafe fn init(config: Config) { w.set_bypass(matches!(config.supply_config, SupplyConfig::SMPSExternalLDOBypass(_))); }); } + SupplyConfig::SMPSDisabledLDOBypass => { + PWR.cr3().modify(|w| { + w.set_sden(false); + w.set_ldoen(false); + w.set_bypass(true); + }); + } } }