STM32L5 periph_rtc

Hi guys, continuing the work with CPU_FAM_STM32L5 I have got some progress with cpu/stm32/periph/rtc_all. When trying examples/default and using rtc commands through shell the RTC seems to be setting and tracking time 'bout well. The outputs:

main(): This is RIOT! (Version: 2021.07-devel-247-gd2fa7-periph_rtc_l5)
Welcome to RIOT!
> help
help
Command              Description
---------------------------------------
reboot               Reboot the node
version              Prints current RIOT_VERSION
pm                   interact with layered PM subsystem
ps                   Prints information about running threads.
rtc                  control RTC peripheral interface
saul                 interact with sensors and actuators using SAUL
> rtc poweron
rtc poweron
> rtc settime 2021-06-16 19:48:30
rtc settime 2021-06-16 19:48:30
> rtc gettime 
rtc gettime
2021-06-16 19:48:35
> rtc help
rtc help
unknown command or missing parameters: help

usage: rtc <command> [arguments]
commands:
	poweron		power the interface on
	poweroff	power the interface off
	clearalarm	deactivate the current alarm
	getalarm	print the currently alarm time
	setalarm YYYY-MM-DD HH:MM:SS
			set an alarm for the specified time
	gettime		print the current time
	settime YYYY-MM-DD HH:MM:SS
			set the current time
> rtc setalarm 2021-06-16 19:49:00
rtc setalarm 2021-06-16 19:49:00
> rtc get aThe alarm rang
The alarm rang
The alarm rang
The alarm rang
The alarm rang
The alarm rang
The alarm rang
The alarm rang
The alarm rang
The alarm rang
The alarm rang
The alarm rang
The alarm rang
The alarm rang
The alarm rang
The alarm rang

When using tests/periph_rtc it’s seems to have problems with the mutex module, I assume it’s something with the ISR flags and registers. The output:

main(): This is RIOT! (Version: 2021.07-devel-247-gd2fa7-periph_rtc_l5)

RIOT RTC low-level driver test
This test will display 'Alarm!' every 2 seconds for 4 times
  Setting clock to   2020-02-28 23:59:57
Clock value is now   2020-02-28 23:59:57
  Setting alarm to   2020-02-28 23:59:59
   Alarm is set to   2020-02-28 23:59:59
  Alarm cleared at   2020-02-28 23:59:57
PID[1] mutex_lock().
PID[1] mutex_lock(): early out.
PID[1] mutex_lock().
PID[1] mutex_lock() Adding node to mutex queue: prio: 7
PID[1] mutex_unlock(): queue.next: 0x20000864
PID[1] mutex_unlock(): waking up waiting thread 1
       No alarm at   2020-02-28 23:59:59
  Setting alarm to   2020-02-29 00:00:01

PID[1] mutex_lock().
PID[1] mutex_lock() Adding node to mutex queue: prio: 7
PID[1] mutex_unlock(): queue.next: 0x20000864
PID[1] mutex_unlock(): waking up waiting thread 1
PID[1] mutex_unlock(): queue.next: 0xffffffff
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0
PID[1] mutex_unlock(): queue.next: 0

Any suggestions or ideas? I’m so close to get all the peripherals needed, hope we can get to something.

Greetings!

Hi @aidiaz, can you post or link the patch you applied for the rtc on stm32l5?

Sure, I just discovered how to do this :sweat_smile:

    diff --git a/cpu/stm32/periph/rtc_all.c b/cpu/stm32/periph/rtc_all.c
    index 148fb4046c..c29acb4c72 100644
    --- a/cpu/stm32/periph/rtc_all.c
    +++ b/cpu/stm32/periph/rtc_all.c
    @@ -49,6 +49,8 @@
     #define EXTI_REG_FTSR       (EXTI->FTSR1)
     #define EXTI_REG_PR         (EXTI->PR1)
     #define EXTI_REG_IMR        (EXTI->IMR1)
    +#elif defined(CPU_FAM_STM32L5)
    +#define EXTI_REG_IMR        (EXTI->IMR1)
     #else
     #define EXTI_REG_RTSR       (EXTI->RTSR)
     #define EXTI_REG_FTSR       (EXTI->FTSR)
    @@ -65,12 +67,22 @@
     #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_ISR_CALRAF      RTC_SCR_CALRAF
    +#define RTC_ISR_ALRAF       RTC_SR_ALRAF
     #else
     #define RTC_REG_ISR         RTC->ISR
     #endif
     
     /* 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)
     #define IRQN                (RTC_IRQn)
     #define ISR_NAME            isr_rtc
     #else
    @@ -84,6 +96,8 @@
     #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)
     #elif defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32G4)
     #define EXTI_IMR_BIT        (EXTI_IMR1_IM17)
     #define EXTI_FTSR_BIT       (EXTI_FTSR1_FT17)
    @@ -237,6 +251,9 @@ void rtc_init(void)
     
         /* enable low frequency clock */
         stmclk_enable_lfclk();
    +    #if defined(CPU_FAM_STM32L5)
    +    RCC->APB1ENR1 |= (RCC_APB1ENR1_PWREN|RCC_APB1ENR1_RTCAPBEN);
    +    #endif
     
         /* select input clock and enable the RTC */
         stmclk_dbp_unlock();
    @@ -257,10 +274,12 @@ void rtc_init(void)
     
         /* 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)
         EXTI_REG_FTSR &= ~(EXTI_FTSR_BIT);
         EXTI_REG_RTSR |= EXTI_RTSR_BIT;
    -    EXTI_REG_IMR  |= EXTI_IMR_BIT;
         EXTI_REG_PR   = EXTI_PR_BIT;
    +    #endif
         /* enable global RTC interrupt */
         NVIC_EnableIRQ(IRQN);
     }
    @@ -312,7 +331,9 @@ int rtc_set_alarm(struct tm *time, rtc_alarm_cb_t cb, void *arg)
         /* save callback and argument */
         isr_ctx.cb = cb;
         isr_ctx.arg = arg;
    -
    +    #if defined(CPU_FAM_STM32L5)
    +    RTC_REG_SCR = RTC_ISR_CALRAF;
    +    #endif
         /* set wakeup time */
         RTC->ALRMAR = (val2bcd(time->tm_mday, RTC_ALRMAR_DU_Pos, ALRM_D_MASK) |
                        val2bcd(time->tm_hour, RTC_ALRMAR_HU_Pos, ALRM_H_MASK) |
    @@ -320,7 +341,9 @@ 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 */
    -    RTC_REG_ISR &= ~(RTC_ISR_ALRAF);
    +    #if !defined(CPU_FAM_STM32L5)
    +    RTC_REG_ISR &= ~RTC_ISR_ALRAF;
    +    #endif
         RTC->CR |= (RTC_CR_ALRAE | RTC_CR_ALRAIE);
     
         rtc_lock();
    @@ -348,7 +371,9 @@ void rtc_clear_alarm(void)
         rtc_unlock();
     
         RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE);
    +    #if !defined(CPU_FAM_STM32L5)
         while (!(RTC_REG_ISR & RTC_ISR_ALRAWF)) {}
    +    #endif
     
         isr_ctx.cb = NULL;
         isr_ctx.arg = NULL;
    @@ -371,13 +396,24 @@ void rtc_poweroff(void)
     }
     
     void ISR_NAME(void)
    -{
    +{   
    +    #if defined(CPU_FAM_STM32L5)
    +    if (RTC_REG_SR & RTC_ISR_ALRAF) {
    +        if (isr_ctx.cb != NULL) {
    +        isr_ctx.cb(isr_ctx.arg);
    +        
    +        }
    +    }
    +    RTC_REG_SCR |= RTC_ISR_CALRAF;
    +    #else
         if (RTC_REG_ISR & RTC_ISR_ALRAF) {
             if (isr_ctx.cb != NULL) {
                 isr_ctx.cb(isr_ctx.arg);
             }
             RTC_REG_ISR &= ~RTC_ISR_ALRAF;
         }
    -    EXTI_REG_PR = EXTI_PR_BIT; /* only clear the associated bit */
    +     EXTI_REG_PR = EXTI_PR_BIT; /* only clear the associated bit */
    +    #endif
    +   
         cortexm_isr_end();
     }
    (END)

So the main differences, is that the RTC interrupt line in L5 is “direct”, instead of “configurable” (just similar to the rtt_all implementation where FTSR, RTSR, RPR registers are avoided for L5. Also other difference is that the ISR registers are separated in writable and readable (SCR (status clear register) and SR (status register), respectively).

My insight is that the ISR routine is not working fine, since the example/default works right (time is updated) and in tests/periph_rtc program faults afterwards locking mutex and wait for the next alarm interrupt to occur.

I’ll try to take a look next week, but I haven’t work with L5 before… @aabadie did the initial port maybe he could take a look?

Thanks! I’ll keep working by my side too. As stated, using examples/default the rtc commands seem to work just fine but when a set alarm interrupt triggers, the code gets stuck when the interrupt flag is read (puts("STUCK")).

void ISR_NAME(void)
{   
    #if defined(CPU_FAM_STM32L5)
    if (RTC_REG_SR & RTC_ISR_ALRAF) {
        if (isr_ctx.cb != NULL) {
        isr_ctx.cb(isr_ctx.arg);
        puts("STUCK");
        }
        RTC_REG_SCR = RTC_ISR_CALRAF;
    }
    
    #else
    if (RTC_REG_ISR & RTC_ISR_ALRAF) {
        if (isr_ctx.cb != NULL) {
            isr_ctx.cb(isr_ctx.arg);
        }
        RTC_REG_ISR &= ~RTC_ISR_ALRAF;
    }
    EXTI_REG_PR = EXTI_PR_BIT; /* only clear the associated bit */
    #endif
    cortexm_isr_end();
}

It’s me … again

Noticed this (CPU_FAM_STM32L5):

When it should be like this (I could be wrong but my research through issues on github concluded this. Tested BOARD=bluepill-128kib to confirm):

Setting alarm to 2020-02-28 23:59:61

Anyways, still stuck on the ISR conflict explained b4.

From what I can tell the alarm flag is never cleared…

I’m having the same results as you, I can see that in the ISR the alarm flag does not get reset, I’m don’t think the register protection for those registers is enabled by default… so I’m not sure what’s going on. I also seem to have bricked the BOARD I was working on, but I don’t have physical access to the BOARD right now…

This is unrelated, Setting alarm to 2020-02-29 00:00:01 is the correct message, bluepill shows the first message because stm32f1 does not really have a a real time calendar, but a real time counter, son when you do set time the time structure is not normalized but directly converted to an “epoch” to then set the time/alarm. So what you are seeing for l5 is not incorrect. The issue I don’t seem to grasp is why the alarm flag does not get cleared, I also checked the stm32l5 errata but found nothing…

Sounds like really bad news to me :frowning:

Finally I got it to work, soon I’ll pull-request the contribution!

Going to close this topics since the issues has been addressed, thanks again @aidiaz!

1 Like