1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-15 01:23:49 +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_i2c
FEATURES_PROVIDED += periph_lpuart
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_rtt
FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer

View File

@ -5,6 +5,7 @@ CPU_MODEL = stm32wl55jc
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_lpuart
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_rtt
FEATURES_PROVIDED += periph_spi
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
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)))
FEATURES_PROVIDED += periph_rtc_mem
endif

View File

@ -26,109 +26,112 @@
/* map some CPU specific register names */
#if defined (CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
#define EN_REG (RCC->CSR)
#define EN_BIT (RCC_CSR_RTCEN)
#define CLKSEL_MASK (RCC_CSR_RTCSEL)
#define CLKSEL_LSE (RCC_CSR_RTCSEL_LSE)
#define CLKSEL_LSI (RCC_CSR_RTCSEL_LSI)
# define EN_REG (RCC->CSR)
# define EN_BIT (RCC_CSR_RTCEN)
# define CLKSEL_MASK (RCC_CSR_RTCSEL)
# define CLKSEL_LSE (RCC_CSR_RTCSEL_LSE)
# define CLKSEL_LSI (RCC_CSR_RTCSEL_LSI)
#else
#define EN_REG (RCC->BDCR)
#define EN_BIT (RCC_BDCR_RTCEN)
#define CLKSEL_MASK (RCC_BDCR_RTCSEL_0 | RCC_BDCR_RTCSEL_1)
#define CLKSEL_LSE (RCC_BDCR_RTCSEL_0)
#define CLKSEL_LSI (RCC_BDCR_RTCSEL_1)
# define EN_REG (RCC->BDCR)
# define EN_BIT (RCC_BDCR_RTCEN)
# define CLKSEL_MASK (RCC_BDCR_RTCSEL_0 | RCC_BDCR_RTCSEL_1)
# define CLKSEL_LSE (RCC_BDCR_RTCSEL_0)
# define CLKSEL_LSI (RCC_BDCR_RTCSEL_1)
#endif
/* map some EXTI register names */
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \
defined(CPU_FAM_STM32G4)
#define EXTI_REG_RTSR (EXTI->RTSR1)
#define EXTI_REG_FTSR (EXTI->FTSR1)
#define EXTI_REG_PR (EXTI->PR1)
#define EXTI_REG_IMR (EXTI->IMR1)
#elif defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32U5)
#define EXTI_REG_RTSR (EXTI->RTSR1)
#define EXTI_REG_FTSR (EXTI->FTSR1)
#define EXTI_REG_PR (EXTI->RPR1)
#define EXTI_REG_IMR (EXTI->IMR1)
# define EXTI_REG_RTSR (EXTI->RTSR1)
# define EXTI_REG_FTSR (EXTI->FTSR1)
# define EXTI_REG_PR (EXTI->PR1)
# define EXTI_REG_IMR (EXTI->IMR1)
#elif defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32U5) || defined(CPU_FAM_STM32WL)
# define EXTI_REG_RTSR (EXTI->RTSR1)
# define EXTI_REG_FTSR (EXTI->FTSR1)
# define EXTI_REG_PR (EXTI->RPR1)
# define EXTI_REG_IMR (EXTI->IMR1)
#elif defined(CPU_FAM_STM32L5)
#define EXTI_REG_IMR (EXTI->IMR1)
# define EXTI_REG_IMR (EXTI->IMR1)
#else
#define EXTI_REG_RTSR (EXTI->RTSR)
#define EXTI_REG_FTSR (EXTI->FTSR)
#define EXTI_REG_PR (EXTI->PR)
#define EXTI_REG_IMR (EXTI->IMR)
# define EXTI_REG_RTSR (EXTI->RTSR)
# define EXTI_REG_FTSR (EXTI->FTSR)
# define EXTI_REG_PR (EXTI->PR)
# define EXTI_REG_IMR (EXTI->IMR)
#endif
/* map some RTC register names and bitfield */
#if defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0)
#define RTC_REG_ISR RTC->ICSR
#define RTC_REG_SR RTC->SR
#define RTC_REG_SCR RTC->SCR
#define RTC_ISR_RSF RTC_ICSR_RSF
#define RTC_ISR_INIT RTC_ICSR_INIT
#define RTC_ISR_INITF RTC_ICSR_INITF
#define RTC_ISR_ALRAWF RTC_ICSR_ALRAWF
#define RTC_ISR_ALRAF RTC_SR_ALRAF
#elif defined(CPU_FAM_STM32L5)
#define RTC_REG_ISR RTC->ICSR
#define RTC_REG_SR RTC->SR
#define RTC_REG_SCR RTC->SCR
#define RTC_ISR_RSF RTC_ICSR_RSF
#define RTC_ISR_INIT RTC_ICSR_INIT
#define RTC_ISR_INITF RTC_ICSR_INITF
# define RTC_REG_ISR RTC->ICSR
# define RTC_REG_SR RTC->SR
# define RTC_REG_SCR RTC->SCR
# define RTC_ISR_RSF RTC_ICSR_RSF
# define RTC_ISR_INIT RTC_ICSR_INIT
# define RTC_ISR_INITF RTC_ICSR_INITF
# define RTC_ISR_INITS RTC_ICSR_INITS
# define RTC_ISR_ALRAWF RTC_ICSR_ALRAWF
# define RTC_ISR_ALRAF RTC_SR_ALRAF
#elif defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32WL)
# define RTC_REG_ISR RTC->ICSR
# define RTC_REG_SR RTC->SR
# define RTC_REG_SCR RTC->SCR
# define RTC_ISR_RSF RTC_ICSR_RSF
# 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)
#define RTC_REG_ISR RTC->ICSR
#define RTC_REG_SR RTC->SR
#define RTC_REG_SCR RTC->SCR
#define RTC_ISR_RSF RTC_ICSR_RSF
#define RTC_ISR_INIT RTC_ICSR_INIT
#define RTC_ISR_INITF RTC_ICSR_INITF
#define RTC_ISR_ALRAF RTC_SR_ALRAF
# define RTC_REG_ISR RTC->ICSR
# define RTC_REG_SR RTC->SR
# define RTC_REG_SCR RTC->SCR
# define RTC_ISR_RSF RTC_ICSR_RSF
# define RTC_ISR_INIT RTC_ICSR_INIT
# define RTC_ISR_INITF RTC_ICSR_INITF
# define RTC_ISR_INITS RTC_ICSR_INITS
# define RTC_ISR_ALRAF RTC_SR_ALRAF
#else
#define RTC_REG_ISR RTC->ISR
# define RTC_REG_ISR RTC->ISR
#endif
/* interrupt line name mapping */
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) || \
defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32U5)
#define IRQN (RTC_IRQn)
#define ISR_NAME isr_rtc
# define IRQN (RTC_IRQn)
# define ISR_NAME isr_rtc
#elif defined(CPU_FAM_STM32G0)
#define IRQN (RTC_TAMP_IRQn)
#define ISR_NAME isr_rtc_tamp
# define IRQN (RTC_TAMP_IRQn)
# define ISR_NAME isr_rtc_tamp
#else
#define IRQN (RTC_Alarm_IRQn)
#define ISR_NAME isr_rtc_alarm
# define IRQN (RTC_Alarm_IRQn)
# define ISR_NAME isr_rtc_alarm
#endif
/* EXTI bitfield mapping */
#if defined(CPU_FAM_STM32L4)
#define EXTI_IMR_BIT (EXTI_IMR1_IM18)
#define EXTI_FTSR_BIT (EXTI_FTSR1_FT18)
#define EXTI_RTSR_BIT (EXTI_RTSR1_RT18)
#define EXTI_PR_BIT (EXTI_PR1_PIF18)
#elif defined(CPU_FAM_STM32L5)
#define EXTI_IMR_BIT (EXTI_IMR1_IM17)
# define EXTI_IMR_BIT (EXTI_IMR1_IM18)
# define EXTI_FTSR_BIT (EXTI_FTSR1_FT18)
# define EXTI_RTSR_BIT (EXTI_RTSR1_RT18)
# define EXTI_PR_BIT (EXTI_PR1_PIF18)
#elif defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32WL)
# define EXTI_IMR_BIT (EXTI_IMR1_IM17)
#elif defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4)
#define EXTI_IMR_BIT (EXTI_IMR1_IM17)
#define EXTI_FTSR_BIT (EXTI_FTSR1_FT17)
#define EXTI_RTSR_BIT (EXTI_RTSR1_RT17)
#define EXTI_PR_BIT (EXTI_PR1_PIF17)
# define EXTI_IMR_BIT (EXTI_IMR1_IM17)
# define EXTI_FTSR_BIT (EXTI_FTSR1_FT17)
# define EXTI_RTSR_BIT (EXTI_RTSR1_RT17)
# define EXTI_PR_BIT (EXTI_PR1_PIF17)
#elif defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32U5)
#define EXTI_IMR_BIT (EXTI_IMR1_IM11)
#define EXTI_FTSR_BIT (EXTI_FTSR1_FT11)
#define EXTI_RTSR_BIT (EXTI_RTSR1_RT11)
#define EXTI_PR_BIT (EXTI_RPR1_RPIF11)
# define EXTI_IMR_BIT (EXTI_IMR1_IM11)
# define EXTI_FTSR_BIT (EXTI_FTSR1_FT11)
# define EXTI_RTSR_BIT (EXTI_RTSR1_RT11)
# define EXTI_PR_BIT (EXTI_RPR1_RPIF11)
#else
#if defined(CPU_FAM_STM32L0)
#define EXTI_IMR_BIT (EXTI_IMR_IM17)
#else
#define EXTI_IMR_BIT (EXTI_IMR_MR17)
#endif
#define EXTI_FTSR_BIT (EXTI_FTSR_TR17)
#define EXTI_RTSR_BIT (EXTI_RTSR_TR17)
#define EXTI_PR_BIT (EXTI_PR_PR17)
# if defined(CPU_FAM_STM32L0)
# define EXTI_IMR_BIT (EXTI_IMR_IM17)
# else
# define EXTI_IMR_BIT (EXTI_IMR_MR17)
# endif
# define EXTI_FTSR_BIT (EXTI_FTSR_TR17)
# define EXTI_RTSR_BIT (EXTI_RTSR_TR17)
# define EXTI_PR_BIT (EXTI_PR_PR17)
#endif
/* write protection values */
@ -147,62 +150,62 @@
#define ALRM_M_MASK (RTC_ALRMAR_MNU | RTC_ALRMAR_MNT)
#define ALRM_S_MASK (RTC_ALRMAR_SU | RTC_ALRMAR_ST)
#ifndef RTC_DR_YU_Pos
#define RTC_DR_YU_Pos (16U)
# define RTC_DR_YU_Pos (16U)
#endif
#ifndef RTC_DR_MU_Pos
#define RTC_DR_MU_Pos (8U)
# define RTC_DR_MU_Pos (8U)
#endif
#ifndef RTC_DR_DU_Pos
#define RTC_DR_DU_Pos (0U)
# define RTC_DR_DU_Pos (0U)
#endif
#ifndef RTC_TR_HU_Pos
#define RTC_TR_HU_Pos (16U)
# define RTC_TR_HU_Pos (16U)
#endif
#ifndef RTC_TR_MNU_Pos
#define RTC_TR_MNU_Pos (8U)
# define RTC_TR_MNU_Pos (8U)
#endif
#ifndef RTC_TR_SU_Pos
#define RTC_TR_SU_Pos (0U)
# define RTC_TR_SU_Pos (0U)
#endif
#ifndef RTC_ALRMAR_DU_Pos
#define RTC_ALRMAR_DU_Pos (24U)
# define RTC_ALRMAR_DU_Pos (24U)
#endif
#ifndef RTC_ALRMAR_HU_Pos
#define RTC_ALRMAR_HU_Pos (16U)
# define RTC_ALRMAR_HU_Pos (16U)
#endif
#ifndef RTC_ALRMAR_MNU_Pos
#define RTC_ALRMAR_MNU_Pos (8U)
# define RTC_ALRMAR_MNU_Pos (8U)
#endif
#ifndef RTC_ALRMAR_SU_Pos
#define RTC_ALRMAR_SU_Pos (0U)
# define RTC_ALRMAR_SU_Pos (0U)
#endif
/* figure out sync and async prescaler */
#if IS_ACTIVE(CONFIG_BOARD_HAS_LSE)
#define PRE_SYNC (255)
#define PRE_ASYNC (127)
# define PRE_SYNC (255)
# define PRE_ASYNC (127)
#elif (CLOCK_LSI == 40000)
#define PRE_SYNC (319)
#define PRE_ASYNC (124)
# define PRE_SYNC (319)
# define PRE_ASYNC (124)
#elif (CLOCK_LSI == 37000)
#define PRE_SYNC (295)
#define PRE_ASYNC (124)
# define PRE_SYNC (295)
# define PRE_ASYNC (124)
#elif (CLOCK_LSI == 32000)
#define PRE_SYNC (249)
#define PRE_ASYNC (127)
# define PRE_SYNC (249)
# define PRE_ASYNC (127)
#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
/* struct tm counts years since 1900 but RTC has only two-digit year, hence the offset */
#define YEAR_OFFSET (RIOT_EPOCH - 1900)
/* 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)
#define MAGIC_CLCK_NUMBER (0x1970)
# define MAGIC_CLCK_NUMBER (0x1970)
#else
#define MAGIC_CLCK_NUMBER (0x1971)
# define MAGIC_CLCK_NUMBER (0x1971)
#endif
static struct {
@ -228,6 +231,14 @@ static int bcd2val(uint32_t val, int shift, uint32_t mask)
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)
{
/* enable backup clock domain */
@ -235,20 +246,22 @@ void rtc_unlock(void)
/* unlock RTC */
RTC->WPR = WPK1;
RTC->WPR = WPK2;
}
static inline void rtc_enter_init_mode(void)
{
rtc_unlock();
/* enter RTC init mode */
RTC_REG_ISR |= RTC_ISR_INIT;
while (!(RTC_REG_ISR & RTC_ISR_INITF)) {}
}
void rtc_lock(void)
static inline void rtc_exit_init_mode(void)
{
/* exit RTC init mode */
RTC_REG_ISR &= ~RTC_ISR_INIT;
while (RTC_REG_ISR & RTC_ISR_INITF) {}
/* lock RTC device */
RTC->WPR = 0xff;
/* disable backup clock domain */
stmclk_dbp_lock();
rtc_lock();
}
void rtc_init(void)
@ -256,47 +269,53 @@ void rtc_init(void)
stmclk_dbp_unlock();
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
/* 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
required. */
* it means the clock source has changed and thus a RTC reset is
* required. */
if (RTC->BKP0R != MAGIC_CLCK_NUMBER) {
RCC->CSR |= RCC_CSR_RTCRST;
RCC->CSR &= ~RCC_CSR_RTCRST;
RTC->BKP0R = MAGIC_CLCK_NUMBER; /* Store the new magic number */
}
#endif
stmclk_dbp_lock();
/* enable low frequency clock */
stmclk_enable_lfclk();
/* select input clock and enable the RTC */
stmclk_dbp_unlock();
#if defined(CPU_FAM_STM32L5)
#if defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32WL)
periph_clk_en(APB1, RCC_APB1ENR1_RTCAPBEN);
#elif defined(CPU_FAM_STM32G0)
periph_clk_en(APB1, RCC_APBENR1_RTCAPBEN);
#elif defined(CPU_FAM_STM32U5)
periph_clk_en(APB3, RCC_APB3ENR_RTCAPBEN);
#endif
EN_REG &= ~(CLKSEL_MASK);
#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
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
rtc_unlock();
/* reset configuration */
RTC->CR = 0;
RTC_REG_ISR = RTC_ISR_INIT;
/* configure prescaler (RTC PRER) */
RTC->PRER = (PRE_SYNC | (PRE_ASYNC << 16));
rtc_lock();
if (!(RTC_REG_ISR & RTC_ISR_INITS))
{
rtc_enter_init_mode();
/* reset configuration */
RTC->CR = 0;
/* configure prescaler (RTC PRER) */
RTC->PRER = (PRE_SYNC | (PRE_ASYNC << 16));
rtc_exit_init_mode();
}
/* configure the EXTI channel, as RTC interrupts are routed through it.
* Needs to be configured to trigger on rising edges. */
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_RTSR |= EXTI_RTSR_BIT;
EXTI_REG_PR = EXTI_PR_BIT;
@ -310,15 +329,14 @@ int rtc_set_time(struct tm *time)
/* normalize input */
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) |
val2bcd(time->tm_mon + 1, RTC_DR_MU_Pos, DR_M_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) |
val2bcd(time->tm_min, RTC_TR_MNU_Pos, TR_M_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)) {}
return 0;
@ -326,6 +344,16 @@ int rtc_set_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 */
uint32_t tr = RTC->TR;
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));
/* Enable Alarm A */
#if !defined(CPU_FAM_STM32L5)
#if !(defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32WL))
RTC_REG_ISR &= ~(RTC_ISR_ALRAF);
#else
RTC_REG_SCR = RTC_SCR_CALRAF;
@ -393,7 +421,7 @@ void rtc_clear_alarm(void)
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)) {}
#else
RTC_REG_SCR = RTC_SCR_CALRAF;
@ -421,7 +449,8 @@ void rtc_poweroff(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 (isr_ctx.cb != NULL) {
isr_ctx.cb(isr_ctx.arg);

View File

@ -138,7 +138,7 @@ int main(void)
}
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_mday = 28,
.tm_hour = 23,