diff --git a/include/libopencm3/stm32/h7/rcc.h b/include/libopencm3/stm32/h7/rcc.h index 36716be1bb..db85fa5327 100644 --- a/include/libopencm3/stm32/h7/rcc.h +++ b/include/libopencm3/stm32/h7/rcc.h @@ -843,6 +843,15 @@ uint32_t rcc_get_fdcan_clk_freq(uint32_t fdcan); */ void rcc_set_peripheral_clk_sel(uint32_t periph, uint32_t clksel); +/** + * Set the clksel value for the RTC and bring it up + * + * NB: This function may only be called on real POR or after BDRST, it will + * internally turn into a no-op if it detects the RTC clock source has already + * been defined to protect from misconfiguration + */ +void rcc_rtc_clock_enable(uint32_t clksel); + /** * Set the clock select for the FDCAN devices. * @param[in] clksel Clock source to configure for, @ref rcc_d2ccip1r_values diff --git a/lib/stm32/h7/rcc.c b/lib/stm32/h7/rcc.c index ecfc487ee3..c4ad816f03 100644 --- a/lib/stm32/h7/rcc.c +++ b/lib/stm32/h7/rcc.c @@ -448,6 +448,19 @@ void rcc_set_peripheral_clk_sel(uint32_t periph, uint32_t sel) *reg = regval; } +void rcc_rtc_clock_enable(uint32_t clksel) +{ + // Make this function a no-op if the RTC has already been set up + if (RCC_BDCR & (RCC_BDCR_RTCSEL_MASK << RCC_BDCR_RTCSEL_SHIFT)) + return; + // Start operations by disabling the write protections for the BDCR + PWR_CR1 |= PWR_CR1_DBP; + // Now configure the clock bits and bring the RTC up + RCC_BDCR |= (clksel << RCC_BDCR_RTCSEL_SHIFT) | RCC_BDCR_RTCEN; + // Protect the BDCR again as we don't need to poke it further + PWR_CR1 &= ~PWR_CR1_DBP; +} + void rcc_set_fdcan_clksel(uint8_t clksel) { RCC_D2CCIP1R &= ~(RCC_D2CCIP1R_FDCANSEL_MASK << RCC_D2CCIP1R_FDCANSEL_SHIFT);