cancel
Showing results for 
Search instead for 
Did you mean: 

How can I toggle an LED at 5th second of each minute with RTC Alarm?

akoluacik
Senior

I am working STM32F746-Disco Board, and trying to implement an Alarm in register level. I am trying to implement a system such that it toggles the user led at 5th second of each minute. However, my program toggles differentially. For now, I can notice that it toggles for 2 seconds, but I don't know at which second, or minute?

My codes are below:

RTC_Utils.c

/*
 * RTC_Utils.c
 *
 *  Created on: Sep 8, 2022
 */
 
 
#include "RTC_utils.h"
#include "stm32f746xx.h"
 
 
void RTC_Init(void) {
 
    uint32_t readBit;
 
//  __HAL_RCC_RTC_ENABLE();
    // Enable write access to the backup domain
    if(((RCC->APB1ENR) & (1U << 28)) == 0) {
        // Enable power interface clock
        RCC->APB1ENR |= (1U << 28);
 
        readBit = RCC->APB1ENR;
        //UNUSED(readBit);
    }
 
    // Select LSE as RTC clock source
    if(((PWR->CR1) & (1U << 8)) == 0) {
        PWR->CR1 |= (1U << 8);
        // Wait until the backup domain write protection has been disabled
        while(((PWR->CR1) & (1U << 8)) == 0);
    }
 
    // Reset LSEON and LSEBY before configuring
    RCC->BDCR &= ~((1U << 0) | (1U << 2));
 
    RCC->BDCR |= (1U << 16);
    RCC->BDCR &= ~(1U << 16);
 
    // Wait until LSE clock is ready
//  while(((RCC->BDCR) & (1U << 1)) == 0);
 
    RCC->BDCR |= (1U << 0);
 
    // Select LSE as RTC clock source
    RCC->BDCR |= 1U << 8;
    RCC->BDCR &= ~(1U << 9);
 
    // Disable power interface clock
    RCC->APB1ENR &= ~(1U << 28);
 
    RCC->BDCR |= 1U << 15;
 
    // Remove Write Protection
    RTC->WPR = 0xCA;
    RTC->WPR = 0x53;
 
    // Set INIT bit to 1 in the RTC_ISR register to enter initialization mode
    RTC->ISR |= 1U << 7;
 
    // Poll INITF bit of in the RTC_ISR register
    while((RTC->ISR & (1U << 6)) == 0);
 
    RTC->CR &= (1U << 6);
 
    // program both the prescaler factors to generate 1 Hz clock
    RTC->PRER |= ((2U << 7) - 1) << 16;
    RTC->PRER |= (2U << 8) - 1;
 
    // Load the initial time and date values in the shadow registers
    RTC->TR |= (1U << 22) | (1U << 21) | (8U << 16) | (4U << 12) | (5U << 8);
    RTC->DR |= (2U << 20) | (2U << 16) | (5U << 13) | (0U << 12) | (9U << 8) | (0U << 4) || (8U << 0);
 
    // configure the time format (12 or 24 hours)
    RTC->CR &= ~(1U << 6);
 
    // Disable Initialization
    RTC->ISR &= ~(1U << 7);
 
    // Enable WPR
    RTC->WPR = 0xFF;
}
 
void RTC_Set_Alarm(void) {
 
    RTC->WPR = 0xCA;
    RTC->WPR = 0x53;
 
    // Clear ALRAE in RTC_CR to disable Alarm A
    RTC->CR &= ~(1U << 8);
 
    // Set off alarm A if the second is 5
    RTC->ALRMAR |= 0x5;
 
    // Program the Alarm A registers (RTC_ALRMASSR/RTC_ALRMAR).
    // Mask every second option
    RTC->ALRMAR |= (1U << 23) | (1U << 15) | (1U << 31);
    RTC->ALRMAR &= ~(1U << 7);
 
    RTC->CR |= (1U << 8);
    RTC->CR |= 1U << 12;
 
    RTC->WPR = 0xFF;
}
 
void RTC_Alarm_Enable(void) {
    RTC_Init();
    RTC_Set_Alarm();
    // Configure EXTI17
    // Select Triggering Edge
    EXTI -> RTSR |= EXTI_RTSR_TR17;
 
    // Interrupt Mask Register
    EXTI -> IMR |= EXTI_IMR_IM17;
 
    // Event Mask Register
    EXTI -> EMR |= EXTI_EMR_EM17;
 
    // Interrupt Pending Register
    EXTI -> PR |= EXTI_PR_PR17;
 
    // Set It Priority Most Urgent
    NVIC_EnableIRQ(RTC_Alarm_IRQn);
    NVIC_SetPriority(RTC_Alarm_IRQn, 0);
}
 
void RTC_Alarm_IRQHandler(void) {
    if (RTC->ISR & (1U << 8)) {
        GPIOI->ODR ^= (1U << 1);
        RTC->ISR &= ~(1U << 8); // Clear the flag
    }
    EXTI -> PR |= EXTI_PR_PR17; // Clear pending interrupt flag
}

What is wrong with my code and what to do to toggle led at the 5th second of each minute? Furthermore, I have some doubts about RTC->TR and RTC->DR registers. What happened if I don't make any adjustments on them and how do they work? When and why we should use them? Thx in advance for your response.

11 REPLIES 11
MM..1
Chief II

As first normal peaple dont waste capacity for learn every bits in ARM registers...

My tip only you dont setup mask seconds for alarm

    // Program the Alarm A registers (RTC_ALRMASSR/RTC_ALRMAR).
    // Mask every second option
    RTC->ALRMAR |= (1U << 23) | (1U << 15) | (1U << 31);
    RTC->ALRMAR &= ~(1U << 7);

try use LL STM32F439xx HAL User Manual: stm32f4xx_ll_rtc.h File Reference (upv.es)

#define 	LL_RTC_ALMA_MASK_NONE   0x00000000U
#define 	LL_RTC_ALMA_MASK_DATEWEEKDAY   RTC_ALRMAR_MSK4
#define 	LL_RTC_ALMA_MASK_HOURS   RTC_ALRMAR_MSK3
#define 	LL_RTC_ALMA_MASK_MINUTES   RTC_ALRMAR_MSK2
#define 	LL_RTC_ALMA_MASK_SECONDS   RTC_ALRMAR_MSK1
#define 	LL_RTC_ALMA_MASK_ALL   (RTC_ALRMAR_MSK4 | RTC_ALRMAR_MSK3 | RTC_ALRMAR_MSK2 | RTC_ALRMAR_MSK1)

usw

It's better to use normal register names and definitions, not LL, because using LL doubles the amount of work. When reading reference manual and looking at registers with a debugger, one has to translate LL names to register names and back all the time. In the end it's just a useless waste of time and adds another layer of potential bugs and inefficiency...

Piranha
Chief II

Rewrite the code using normal register defines.

And for a start - all modifications of registers RTC_ISR and EXTI_PR are broken.

> Rewrite the code using normal register defines.

+1

> And for a start - all modifications of registers RTC_ISR and EXTI_PR broken.

... in the interrupt (setting of INIT bit in RTC_ISR isOK), because status flags are not to be cleared by RMW operation.

> RTC->PRER |= ((2U << 7) - 1) << 16;

> RTC->PRER |= (2U << 8) - 1;

This is wrong, because

  • the reset value of RTC_PRER is nonzero (OK in this particular case it does not matter, but generally it's wrong)
  • this value results in RTC to run half as fast as it should, when using the standard 32.768kHz crystal - and this maybe is why you see LED blink once in 2.5sec rather than once in 5sec (I haven't checked rest of the code)

I wonder where do you have these values from, as I've seen them in other confused post, too.

JW

RTC_ISR flag clearing code is broken because it will also clear other flags which are set by hardware (interrupts become pending) during the RMW operation.

@Community member​  I am using a book for these purposes(low-level coding), and it is best practice to use LSE clock, which has 32768 Hz frequency, or 32kHz. To have 1Hz signal, I adjusted the PRER value as in the book.

Why RTC_ISR and EXTI_PR broken? Because I set and reset the specific bits, and didn't make a change on any other bits?

Well doing a RMW action on EXTI_PR is apt to clear things unrelated to the bits you want.

Just write the mask for the bit(s) you actually own/manage at that point.

With register level code you likely need to own all the debugging, as very few want to spend hours walking thru others buggy code.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

The LSI tends to be very unstable, and not suitable for powered down operation. Certainly in older STM32 the LSI was typically in the 37 KHz realm

A properly implemented LSE circuit with an appropriated loaded crystal should be a lot closer to 32.768 KHz and you'd pick the appropriate prescalers. The LSE should be testable via the export of the signal via a TAMPER or PA8/MCO pin, or via a TIM clocking via a different/better clock.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..