diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index ff77399b2..b548a0343 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -189,6 +189,18 @@ pub struct Config { /// Defaults to P0 (highest). #[cfg(gpdma)] pub gpdma_interrupt_priority: Priority, + + /// Enables UCPD1 dead battery functionality. + /// + /// Defaults to false (disabled). + #[cfg(peri_ucpd1)] + pub enable_ucpd1_dead_battery: bool, + + /// Enables UCPD2 dead battery functionality. + /// + /// Defaults to false (disabled). + #[cfg(peri_ucpd2)] + pub enable_ucpd2_dead_battery: bool, } impl Default for Config { @@ -203,6 +215,10 @@ impl Default for Config { dma_interrupt_priority: Priority::P0, #[cfg(gpdma)] gpdma_interrupt_priority: Priority::P0, + #[cfg(peri_ucpd1)] + enable_ucpd1_dead_battery: false, + #[cfg(peri_ucpd2)] + enable_ucpd2_dead_battery: false, } } } @@ -254,7 +270,27 @@ pub fn init(config: Config) -> Peripherals { #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] peripherals::FLASH::enable_and_reset_with_cs(cs); + // dead battery functionality is still present on these + // chips despite them not having UCPD- disable it + #[cfg(any(stm32g070, stm32g0b0))] + { + crate::pac::SYSCFG.cfgr1().modify(|w| { + w.set_ucpd1_strobe(true); + w.set_ucpd2_strobe(true); + }); + } + unsafe { + // TODO: refactor into mod ucpd + #[cfg(ucpd)] + ucpd_init( + cs, + #[cfg(peri_ucpd1)] + config.enable_ucpd1_dead_battery, + #[cfg(peri_ucpd2)] + config.enable_ucpd2_dead_battery, + ); + #[cfg(feature = "_split-pins-enabled")] crate::pac::SYSCFG.pmcr().modify(|pmcr| { #[cfg(feature = "split-pa0")] @@ -296,3 +332,41 @@ pub fn init(config: Config) -> Peripherals { p }) } + +#[cfg(ucpd)] +/// Safety: must only be called when all UCPDs are disabled (e.g. at startup) +unsafe fn ucpd_init( + _cs: critical_section::CriticalSection, + #[cfg(peri_ucpd1)] ucpd1_db_enable: bool, + #[cfg(peri_ucpd2)] ucpd2_db_enable: bool, +) { + #[cfg(stm32g0x1)] + { + // according to RM0444 (STM32G0x1) section 8.1.1: + // when UCPD is disabled setting the strobe will disable dead battery + // (which is enabled after reset) but if UCPD is enabled, setting the + // strobe will apply the CC pin configuration from the control register + // (which is why we need to be careful about when we call this) + crate::pac::SYSCFG.cfgr1().modify(|w| { + w.set_ucpd1_strobe(ucpd1_db_enable); + w.set_ucpd2_strobe(ucpd2_db_enable); + }); + } + + #[cfg(any(stm32g4, stm32l5))] + { + crate::pac::PWR.cr3().modify(|w| { + #[cfg(stm32g4)] + w.set_ucpd1_dbdis(!ucpd1_db_enable); + #[cfg(stm32l5)] + w.set_ucpd_dbdis(!ucpd1_db_enable); + }) + } + + #[cfg(any(stm32h5, stm32u5))] + { + crate::pac::PWR.ucpdr().modify(|w| { + w.set_ucpd_dbdis(!ucpd1_db_enable); + }) + } +}