1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-16 01:53:51 +01:00

Merge pull request #21837 from crasbe/pr/nucleo-wl55jc-rtc-support_new

boards/nucleo-wl55jc, cpu/stm32: enable RTC support, increase RTC accuracy
This commit is contained in:
crasbe 2025-11-07 08:16:46 +00:00 committed by GitHub
commit b1256ffb1b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 158 additions and 126 deletions

View File

@ -5,6 +5,7 @@ CPU_MODEL = stm32wle5jc
FEATURES_PROVIDED += periph_adc FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_lpuart FEATURES_PROVIDED += periph_lpuart
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_rtt FEATURES_PROVIDED += periph_rtt
FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_timer

View File

@ -5,6 +5,7 @@ CPU_MODEL = stm32wl55jc
FEATURES_PROVIDED += periph_adc FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_lpuart FEATURES_PROVIDED += periph_lpuart
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_rtt FEATURES_PROVIDED += periph_rtt
FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_timer

View File

@ -35,7 +35,8 @@ ifneq (,$(filter $(CPU_FAM),c0 f0 f1 f3 g0 g4 l0 l1 l4 l5 u5 wb wl))
endif endif
ifneq (,$(filter $(CPU_FAM),f0 f2 f3 f4 f7 l0 l1 l4 l5 u5 wb wl)) ifneq (,$(filter $(CPU_FAM),f0 f2 f3 f4 f7 l0 l1 l4 l5 u5 wb wl))
CPU_MODELS_WITHOUT_RTC_BKPR += stm32f030% stm32f070% CPU_MODELS_WITHOUT_RTC_BKPR += stm32f030% stm32f070% \
stm32f302%
ifeq (,$(filter $(CPU_MODELS_WITHOUT_RTC_BKPR),$(CPU_MODEL))) ifeq (,$(filter $(CPU_MODELS_WITHOUT_RTC_BKPR),$(CPU_MODEL)))
FEATURES_PROVIDED += periph_rtc_mem FEATURES_PROVIDED += periph_rtc_mem
endif endif

View File

@ -26,109 +26,112 @@
/* map some CPU specific register names */ /* map some CPU specific register names */
#if defined (CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) #if defined (CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
#define EN_REG (RCC->CSR) # define EN_REG (RCC->CSR)
#define EN_BIT (RCC_CSR_RTCEN) # define EN_BIT (RCC_CSR_RTCEN)
#define CLKSEL_MASK (RCC_CSR_RTCSEL) # define CLKSEL_MASK (RCC_CSR_RTCSEL)
#define CLKSEL_LSE (RCC_CSR_RTCSEL_LSE) # define CLKSEL_LSE (RCC_CSR_RTCSEL_LSE)
#define CLKSEL_LSI (RCC_CSR_RTCSEL_LSI) # define CLKSEL_LSI (RCC_CSR_RTCSEL_LSI)
#else #else
#define EN_REG (RCC->BDCR) # define EN_REG (RCC->BDCR)
#define EN_BIT (RCC_BDCR_RTCEN) # define EN_BIT (RCC_BDCR_RTCEN)
#define CLKSEL_MASK (RCC_BDCR_RTCSEL_0 | RCC_BDCR_RTCSEL_1) # define CLKSEL_MASK (RCC_BDCR_RTCSEL_0 | RCC_BDCR_RTCSEL_1)
#define CLKSEL_LSE (RCC_BDCR_RTCSEL_0) # define CLKSEL_LSE (RCC_BDCR_RTCSEL_0)
#define CLKSEL_LSI (RCC_BDCR_RTCSEL_1) # define CLKSEL_LSI (RCC_BDCR_RTCSEL_1)
#endif #endif
/* map some EXTI register names */ /* map some EXTI register names */
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ #if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \
defined(CPU_FAM_STM32G4) defined(CPU_FAM_STM32G4)
#define EXTI_REG_RTSR (EXTI->RTSR1) # define EXTI_REG_RTSR (EXTI->RTSR1)
#define EXTI_REG_FTSR (EXTI->FTSR1) # define EXTI_REG_FTSR (EXTI->FTSR1)
#define EXTI_REG_PR (EXTI->PR1) # define EXTI_REG_PR (EXTI->PR1)
#define EXTI_REG_IMR (EXTI->IMR1) # define EXTI_REG_IMR (EXTI->IMR1)
#elif defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32U5) #elif defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32U5) || defined(CPU_FAM_STM32WL)
#define EXTI_REG_RTSR (EXTI->RTSR1) # define EXTI_REG_RTSR (EXTI->RTSR1)
#define EXTI_REG_FTSR (EXTI->FTSR1) # define EXTI_REG_FTSR (EXTI->FTSR1)
#define EXTI_REG_PR (EXTI->RPR1) # define EXTI_REG_PR (EXTI->RPR1)
#define EXTI_REG_IMR (EXTI->IMR1) # define EXTI_REG_IMR (EXTI->IMR1)
#elif defined(CPU_FAM_STM32L5) #elif defined(CPU_FAM_STM32L5)
#define EXTI_REG_IMR (EXTI->IMR1) # define EXTI_REG_IMR (EXTI->IMR1)
#else #else
#define EXTI_REG_RTSR (EXTI->RTSR) # define EXTI_REG_RTSR (EXTI->RTSR)
#define EXTI_REG_FTSR (EXTI->FTSR) # define EXTI_REG_FTSR (EXTI->FTSR)
#define EXTI_REG_PR (EXTI->PR) # define EXTI_REG_PR (EXTI->PR)
#define EXTI_REG_IMR (EXTI->IMR) # define EXTI_REG_IMR (EXTI->IMR)
#endif #endif
/* map some RTC register names and bitfield */ /* map some RTC register names and bitfield */
#if defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) #if defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0)
#define RTC_REG_ISR RTC->ICSR # define RTC_REG_ISR RTC->ICSR
#define RTC_REG_SR RTC->SR # define RTC_REG_SR RTC->SR
#define RTC_REG_SCR RTC->SCR # define RTC_REG_SCR RTC->SCR
#define RTC_ISR_RSF RTC_ICSR_RSF # define RTC_ISR_RSF RTC_ICSR_RSF
#define RTC_ISR_INIT RTC_ICSR_INIT # define RTC_ISR_INIT RTC_ICSR_INIT
#define RTC_ISR_INITF RTC_ICSR_INITF # define RTC_ISR_INITF RTC_ICSR_INITF
#define RTC_ISR_ALRAWF RTC_ICSR_ALRAWF # define RTC_ISR_INITS RTC_ICSR_INITS
#define RTC_ISR_ALRAF RTC_SR_ALRAF # define RTC_ISR_ALRAWF RTC_ICSR_ALRAWF
#elif defined(CPU_FAM_STM32L5) # define RTC_ISR_ALRAF RTC_SR_ALRAF
#define RTC_REG_ISR RTC->ICSR #elif defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32WL)
#define RTC_REG_SR RTC->SR # define RTC_REG_ISR RTC->ICSR
#define RTC_REG_SCR RTC->SCR # define RTC_REG_SR RTC->SR
#define RTC_ISR_RSF RTC_ICSR_RSF # define RTC_REG_SCR RTC->SCR
#define RTC_ISR_INIT RTC_ICSR_INIT # define RTC_ISR_RSF RTC_ICSR_RSF
#define RTC_ISR_INITF RTC_ICSR_INITF # define RTC_ISR_INIT RTC_ICSR_INIT
# define RTC_ISR_INITF RTC_ICSR_INITF
# define RTC_ISR_INITS RTC_ICSR_INITS
#elif defined(CPU_FAM_STM32U5) #elif defined(CPU_FAM_STM32U5)
#define RTC_REG_ISR RTC->ICSR # define RTC_REG_ISR RTC->ICSR
#define RTC_REG_SR RTC->SR # define RTC_REG_SR RTC->SR
#define RTC_REG_SCR RTC->SCR # define RTC_REG_SCR RTC->SCR
#define RTC_ISR_RSF RTC_ICSR_RSF # define RTC_ISR_RSF RTC_ICSR_RSF
#define RTC_ISR_INIT RTC_ICSR_INIT # define RTC_ISR_INIT RTC_ICSR_INIT
#define RTC_ISR_INITF RTC_ICSR_INITF # define RTC_ISR_INITF RTC_ICSR_INITF
#define RTC_ISR_ALRAF RTC_SR_ALRAF # define RTC_ISR_INITS RTC_ICSR_INITS
# define RTC_ISR_ALRAF RTC_SR_ALRAF
#else #else
#define RTC_REG_ISR RTC->ISR # define RTC_REG_ISR RTC->ISR
#endif #endif
/* interrupt line name mapping */ /* interrupt line name mapping */
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) || \ #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) || \
defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32U5) defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32U5)
#define IRQN (RTC_IRQn) # define IRQN (RTC_IRQn)
#define ISR_NAME isr_rtc # define ISR_NAME isr_rtc
#elif defined(CPU_FAM_STM32G0) #elif defined(CPU_FAM_STM32G0)
#define IRQN (RTC_TAMP_IRQn) # define IRQN (RTC_TAMP_IRQn)
#define ISR_NAME isr_rtc_tamp # define ISR_NAME isr_rtc_tamp
#else #else
#define IRQN (RTC_Alarm_IRQn) # define IRQN (RTC_Alarm_IRQn)
#define ISR_NAME isr_rtc_alarm # define ISR_NAME isr_rtc_alarm
#endif #endif
/* EXTI bitfield mapping */ /* EXTI bitfield mapping */
#if defined(CPU_FAM_STM32L4) #if defined(CPU_FAM_STM32L4)
#define EXTI_IMR_BIT (EXTI_IMR1_IM18) # define EXTI_IMR_BIT (EXTI_IMR1_IM18)
#define EXTI_FTSR_BIT (EXTI_FTSR1_FT18) # define EXTI_FTSR_BIT (EXTI_FTSR1_FT18)
#define EXTI_RTSR_BIT (EXTI_RTSR1_RT18) # define EXTI_RTSR_BIT (EXTI_RTSR1_RT18)
#define EXTI_PR_BIT (EXTI_PR1_PIF18) # define EXTI_PR_BIT (EXTI_PR1_PIF18)
#elif defined(CPU_FAM_STM32L5) #elif defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32WL)
#define EXTI_IMR_BIT (EXTI_IMR1_IM17) # define EXTI_IMR_BIT (EXTI_IMR1_IM17)
#elif defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4) #elif defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4)
#define EXTI_IMR_BIT (EXTI_IMR1_IM17) # define EXTI_IMR_BIT (EXTI_IMR1_IM17)
#define EXTI_FTSR_BIT (EXTI_FTSR1_FT17) # define EXTI_FTSR_BIT (EXTI_FTSR1_FT17)
#define EXTI_RTSR_BIT (EXTI_RTSR1_RT17) # define EXTI_RTSR_BIT (EXTI_RTSR1_RT17)
#define EXTI_PR_BIT (EXTI_PR1_PIF17) # define EXTI_PR_BIT (EXTI_PR1_PIF17)
#elif defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32U5) #elif defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32U5)
#define EXTI_IMR_BIT (EXTI_IMR1_IM11) # define EXTI_IMR_BIT (EXTI_IMR1_IM11)
#define EXTI_FTSR_BIT (EXTI_FTSR1_FT11) # define EXTI_FTSR_BIT (EXTI_FTSR1_FT11)
#define EXTI_RTSR_BIT (EXTI_RTSR1_RT11) # define EXTI_RTSR_BIT (EXTI_RTSR1_RT11)
#define EXTI_PR_BIT (EXTI_RPR1_RPIF11) # define EXTI_PR_BIT (EXTI_RPR1_RPIF11)
#else #else
#if defined(CPU_FAM_STM32L0) # if defined(CPU_FAM_STM32L0)
#define EXTI_IMR_BIT (EXTI_IMR_IM17) # define EXTI_IMR_BIT (EXTI_IMR_IM17)
#else # else
#define EXTI_IMR_BIT (EXTI_IMR_MR17) # define EXTI_IMR_BIT (EXTI_IMR_MR17)
#endif # endif
#define EXTI_FTSR_BIT (EXTI_FTSR_TR17) # define EXTI_FTSR_BIT (EXTI_FTSR_TR17)
#define EXTI_RTSR_BIT (EXTI_RTSR_TR17) # define EXTI_RTSR_BIT (EXTI_RTSR_TR17)
#define EXTI_PR_BIT (EXTI_PR_PR17) # define EXTI_PR_BIT (EXTI_PR_PR17)
#endif #endif
/* write protection values */ /* write protection values */
@ -147,62 +150,62 @@
#define ALRM_M_MASK (RTC_ALRMAR_MNU | RTC_ALRMAR_MNT) #define ALRM_M_MASK (RTC_ALRMAR_MNU | RTC_ALRMAR_MNT)
#define ALRM_S_MASK (RTC_ALRMAR_SU | RTC_ALRMAR_ST) #define ALRM_S_MASK (RTC_ALRMAR_SU | RTC_ALRMAR_ST)
#ifndef RTC_DR_YU_Pos #ifndef RTC_DR_YU_Pos
#define RTC_DR_YU_Pos (16U) # define RTC_DR_YU_Pos (16U)
#endif #endif
#ifndef RTC_DR_MU_Pos #ifndef RTC_DR_MU_Pos
#define RTC_DR_MU_Pos (8U) # define RTC_DR_MU_Pos (8U)
#endif #endif
#ifndef RTC_DR_DU_Pos #ifndef RTC_DR_DU_Pos
#define RTC_DR_DU_Pos (0U) # define RTC_DR_DU_Pos (0U)
#endif #endif
#ifndef RTC_TR_HU_Pos #ifndef RTC_TR_HU_Pos
#define RTC_TR_HU_Pos (16U) # define RTC_TR_HU_Pos (16U)
#endif #endif
#ifndef RTC_TR_MNU_Pos #ifndef RTC_TR_MNU_Pos
#define RTC_TR_MNU_Pos (8U) # define RTC_TR_MNU_Pos (8U)
#endif #endif
#ifndef RTC_TR_SU_Pos #ifndef RTC_TR_SU_Pos
#define RTC_TR_SU_Pos (0U) # define RTC_TR_SU_Pos (0U)
#endif #endif
#ifndef RTC_ALRMAR_DU_Pos #ifndef RTC_ALRMAR_DU_Pos
#define RTC_ALRMAR_DU_Pos (24U) # define RTC_ALRMAR_DU_Pos (24U)
#endif #endif
#ifndef RTC_ALRMAR_HU_Pos #ifndef RTC_ALRMAR_HU_Pos
#define RTC_ALRMAR_HU_Pos (16U) # define RTC_ALRMAR_HU_Pos (16U)
#endif #endif
#ifndef RTC_ALRMAR_MNU_Pos #ifndef RTC_ALRMAR_MNU_Pos
#define RTC_ALRMAR_MNU_Pos (8U) # define RTC_ALRMAR_MNU_Pos (8U)
#endif #endif
#ifndef RTC_ALRMAR_SU_Pos #ifndef RTC_ALRMAR_SU_Pos
#define RTC_ALRMAR_SU_Pos (0U) # define RTC_ALRMAR_SU_Pos (0U)
#endif #endif
/* figure out sync and async prescaler */ /* figure out sync and async prescaler */
#if IS_ACTIVE(CONFIG_BOARD_HAS_LSE) #if IS_ACTIVE(CONFIG_BOARD_HAS_LSE)
#define PRE_SYNC (255) # define PRE_SYNC (255)
#define PRE_ASYNC (127) # define PRE_ASYNC (127)
#elif (CLOCK_LSI == 40000) #elif (CLOCK_LSI == 40000)
#define PRE_SYNC (319) # define PRE_SYNC (319)
#define PRE_ASYNC (124) # define PRE_ASYNC (124)
#elif (CLOCK_LSI == 37000) #elif (CLOCK_LSI == 37000)
#define PRE_SYNC (295) # define PRE_SYNC (295)
#define PRE_ASYNC (124) # define PRE_ASYNC (124)
#elif (CLOCK_LSI == 32000) #elif (CLOCK_LSI == 32000)
#define PRE_SYNC (249) # define PRE_SYNC (249)
#define PRE_ASYNC (127) # define PRE_ASYNC (127)
#else #else
#error "rtc: unable to determine RTC SYNC and ASYNC prescalers from LSI value" # error "RTC: unable to determine RTC SYNC and ASYNC prescalers from LSI value"
#endif #endif
/* struct tm counts years since 1900 but RTC has only two-digit year, hence the offset */ /* struct tm counts years since 1900 but RTC has only two-digit year, hence the offset */
#define YEAR_OFFSET (RIOT_EPOCH - 1900) #define YEAR_OFFSET (RIOT_EPOCH - 1900)
/* Use a magic number to determine the initial RTC source. This will be used /* Use a magic number to determine the initial RTC source. This will be used
to know if a reset of the RTC is required at initialization. */ * to know if a reset of the RTC is required at initialization. */
#if IS_ACTIVE(CONFIG_BOARD_HAS_LSE) #if IS_ACTIVE(CONFIG_BOARD_HAS_LSE)
#define MAGIC_CLCK_NUMBER (0x1970) # define MAGIC_CLCK_NUMBER (0x1970)
#else #else
#define MAGIC_CLCK_NUMBER (0x1971) # define MAGIC_CLCK_NUMBER (0x1971)
#endif #endif
static struct { static struct {
@ -228,6 +231,14 @@ static int bcd2val(uint32_t val, int shift, uint32_t mask)
return (((tmp >> 4) * 10) + (tmp & 0x0f)); return (((tmp >> 4) * 10) + (tmp & 0x0f));
} }
void rtc_lock(void)
{
/* lock RTC device */
RTC->WPR = 0xff;
/* disable backup clock domain */
stmclk_dbp_lock();
}
void rtc_unlock(void) void rtc_unlock(void)
{ {
/* enable backup clock domain */ /* enable backup clock domain */
@ -235,20 +246,22 @@ void rtc_unlock(void)
/* unlock RTC */ /* unlock RTC */
RTC->WPR = WPK1; RTC->WPR = WPK1;
RTC->WPR = WPK2; RTC->WPR = WPK2;
}
static inline void rtc_enter_init_mode(void)
{
rtc_unlock();
/* enter RTC init mode */ /* enter RTC init mode */
RTC_REG_ISR |= RTC_ISR_INIT; RTC_REG_ISR |= RTC_ISR_INIT;
while (!(RTC_REG_ISR & RTC_ISR_INITF)) {} while (!(RTC_REG_ISR & RTC_ISR_INITF)) {}
} }
void rtc_lock(void) static inline void rtc_exit_init_mode(void)
{ {
/* exit RTC init mode */ /* exit RTC init mode */
RTC_REG_ISR &= ~RTC_ISR_INIT; RTC_REG_ISR &= ~RTC_ISR_INIT;
while (RTC_REG_ISR & RTC_ISR_INITF) {} while (RTC_REG_ISR & RTC_ISR_INITF) {}
/* lock RTC device */ rtc_lock();
RTC->WPR = 0xff;
/* disable backup clock domain */
stmclk_dbp_lock();
} }
void rtc_init(void) void rtc_init(void)
@ -256,47 +269,53 @@ void rtc_init(void)
stmclk_dbp_unlock(); stmclk_dbp_unlock();
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) #if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
/* Compare the stored magic number with the current one. If it's different /* Compare the stored magic number with the current one. If it's different
it means the clock source has changed and thus a RTC reset is * it means the clock source has changed and thus a RTC reset is
required. */ * required. */
if (RTC->BKP0R != MAGIC_CLCK_NUMBER) { if (RTC->BKP0R != MAGIC_CLCK_NUMBER) {
RCC->CSR |= RCC_CSR_RTCRST; RCC->CSR |= RCC_CSR_RTCRST;
RCC->CSR &= ~RCC_CSR_RTCRST; RCC->CSR &= ~RCC_CSR_RTCRST;
RTC->BKP0R = MAGIC_CLCK_NUMBER; /* Store the new magic number */ RTC->BKP0R = MAGIC_CLCK_NUMBER; /* Store the new magic number */
} }
#endif #endif
stmclk_dbp_lock();
/* enable low frequency clock */ /* enable low frequency clock */
stmclk_enable_lfclk(); stmclk_enable_lfclk();
/* select input clock and enable the RTC */ /* select input clock and enable the RTC */
stmclk_dbp_unlock(); stmclk_dbp_unlock();
#if defined(CPU_FAM_STM32L5) #if defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32WL)
periph_clk_en(APB1, RCC_APB1ENR1_RTCAPBEN); periph_clk_en(APB1, RCC_APB1ENR1_RTCAPBEN);
#elif defined(CPU_FAM_STM32G0) #elif defined(CPU_FAM_STM32G0)
periph_clk_en(APB1, RCC_APBENR1_RTCAPBEN); periph_clk_en(APB1, RCC_APBENR1_RTCAPBEN);
#elif defined(CPU_FAM_STM32U5) #elif defined(CPU_FAM_STM32U5)
periph_clk_en(APB3, RCC_APB3ENR_RTCAPBEN); periph_clk_en(APB3, RCC_APB3ENR_RTCAPBEN);
#endif #endif
EN_REG &= ~(CLKSEL_MASK);
#if IS_ACTIVE(CONFIG_BOARD_HAS_LSE) #if IS_ACTIVE(CONFIG_BOARD_HAS_LSE)
EN_REG |= (CLKSEL_LSE | EN_BIT); if ((EN_REG & (CLKSEL_MASK | EN_BIT)) != (CLKSEL_LSE | EN_BIT)) {
EN_REG &= ~(CLKSEL_MASK);
EN_REG |= (CLKSEL_LSE | EN_BIT);
}
#else #else
EN_REG |= (CLKSEL_LSI | EN_BIT); if ((EN_REG & (CLKSEL_MASK | EN_BIT)) != (CLKSEL_LSI | EN_BIT)) {
EN_REG &= ~(CLKSEL_MASK);
EN_REG |= (CLKSEL_LSI | EN_BIT);
}
#endif #endif
rtc_unlock(); if (!(RTC_REG_ISR & RTC_ISR_INITS))
/* reset configuration */ {
RTC->CR = 0; rtc_enter_init_mode();
RTC_REG_ISR = RTC_ISR_INIT; /* reset configuration */
/* configure prescaler (RTC PRER) */ RTC->CR = 0;
RTC->PRER = (PRE_SYNC | (PRE_ASYNC << 16)); /* configure prescaler (RTC PRER) */
rtc_lock(); RTC->PRER = (PRE_SYNC | (PRE_ASYNC << 16));
rtc_exit_init_mode();
}
/* configure the EXTI channel, as RTC interrupts are routed through it. /* configure the EXTI channel, as RTC interrupts are routed through it.
* Needs to be configured to trigger on rising edges. */ * Needs to be configured to trigger on rising edges. */
EXTI_REG_IMR |= EXTI_IMR_BIT; EXTI_REG_IMR |= EXTI_IMR_BIT;
#if !defined(CPU_FAM_STM32L5) #if !(defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32WL))
EXTI_REG_FTSR &= ~(EXTI_FTSR_BIT); EXTI_REG_FTSR &= ~(EXTI_FTSR_BIT);
EXTI_REG_RTSR |= EXTI_RTSR_BIT; EXTI_REG_RTSR |= EXTI_RTSR_BIT;
EXTI_REG_PR = EXTI_PR_BIT; EXTI_REG_PR = EXTI_PR_BIT;
@ -310,15 +329,14 @@ int rtc_set_time(struct tm *time)
/* normalize input */ /* normalize input */
rtc_tm_normalize(time); rtc_tm_normalize(time);
rtc_unlock(); rtc_enter_init_mode();
RTC->DR = (val2bcd((time->tm_year - YEAR_OFFSET), RTC_DR_YU_Pos, DR_Y_MASK) | RTC->DR = (val2bcd((time->tm_year - YEAR_OFFSET), RTC_DR_YU_Pos, DR_Y_MASK) |
val2bcd(time->tm_mon + 1, RTC_DR_MU_Pos, DR_M_MASK) | val2bcd(time->tm_mon + 1, RTC_DR_MU_Pos, DR_M_MASK) |
val2bcd(time->tm_mday, RTC_DR_DU_Pos, DR_D_MASK)); val2bcd(time->tm_mday, RTC_DR_DU_Pos, DR_D_MASK));
RTC->TR = (val2bcd(time->tm_hour, RTC_TR_HU_Pos, TR_H_MASK) | RTC->TR = (val2bcd(time->tm_hour, RTC_TR_HU_Pos, TR_H_MASK) |
val2bcd(time->tm_min, RTC_TR_MNU_Pos, TR_M_MASK) | val2bcd(time->tm_min, RTC_TR_MNU_Pos, TR_M_MASK) |
val2bcd(time->tm_sec, RTC_TR_SU_Pos, TR_S_MASK)); val2bcd(time->tm_sec, RTC_TR_SU_Pos, TR_S_MASK));
rtc_lock(); rtc_exit_init_mode();
while (!(RTC_REG_ISR & RTC_ISR_RSF)) {} while (!(RTC_REG_ISR & RTC_ISR_RSF)) {}
return 0; return 0;
@ -326,6 +344,16 @@ int rtc_set_time(struct tm *time)
int rtc_get_time(struct tm *time) int rtc_get_time(struct tm *time)
{ {
/* After waking up from standby, the RSF flag has to be manually cleared.
* To be safe, we do it every time even though we might not have been in
* standby before. */
rtc_unlock();
RTC_REG_ISR &= ~RTC_ISR_RSF;
rtc_lock();
/* waiting for the RSF bit to be set again before accessing the time */
while (!(RTC_REG_ISR & RTC_ISR_RSF)) {};
/* save current time */ /* save current time */
uint32_t tr = RTC->TR; uint32_t tr = RTC->TR;
uint32_t dr = RTC->DR; uint32_t dr = RTC->DR;
@ -360,7 +388,7 @@ int rtc_set_alarm(struct tm *time, rtc_alarm_cb_t cb, void *arg)
val2bcd(time->tm_sec, RTC_ALRMAR_SU_Pos, ALRM_S_MASK)); val2bcd(time->tm_sec, RTC_ALRMAR_SU_Pos, ALRM_S_MASK));
/* Enable Alarm A */ /* Enable Alarm A */
#if !defined(CPU_FAM_STM32L5) #if !(defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32WL))
RTC_REG_ISR &= ~(RTC_ISR_ALRAF); RTC_REG_ISR &= ~(RTC_ISR_ALRAF);
#else #else
RTC_REG_SCR = RTC_SCR_CALRAF; RTC_REG_SCR = RTC_SCR_CALRAF;
@ -393,7 +421,7 @@ void rtc_clear_alarm(void)
RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE); RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE);
#if !defined(CPU_FAM_STM32L5) && !defined(CPU_FAM_STM32U5) #if !(defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32U5) || defined(CPU_FAM_STM32WL))
while (!(RTC_REG_ISR & RTC_ISR_ALRAWF)) {} while (!(RTC_REG_ISR & RTC_ISR_ALRAWF)) {}
#else #else
RTC_REG_SCR = RTC_SCR_CALRAF; RTC_REG_SCR = RTC_SCR_CALRAF;
@ -421,7 +449,8 @@ void rtc_poweroff(void)
void ISR_NAME(void) void ISR_NAME(void)
{ {
#if !defined(CPU_FAM_STM32L5) && !defined(CPU_FAM_STM32G0) && !defined(CPU_FAM_STM32U5) #if !(defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32WL) || defined(CPU_FAM_STM32G0) || \
defined(CPU_FAM_STM32U5))
if (RTC_REG_ISR & RTC_ISR_ALRAF) { if (RTC_REG_ISR & RTC_ISR_ALRAF) {
if (isr_ctx.cb != NULL) { if (isr_ctx.cb != NULL) {
isr_ctx.cb(isr_ctx.arg); isr_ctx.cb(isr_ctx.arg);

View File

@ -138,7 +138,7 @@ int main(void)
} }
time = (struct tm){ time = (struct tm){
.tm_year = 2020 - 1900, /* years are counted from 1900 */ .tm_year = 2025 - 1900, /* years are counted from 1900 */
.tm_mon = 1, /* 0 = January, 11 = December */ .tm_mon = 1, /* 0 = January, 11 = December */
.tm_mday = 28, .tm_mday = 28,
.tm_hour = 23, .tm_hour = 23,