2022-09-10 12:34 AM
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.
2022-09-10 03:18 AM
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
2022-09-10 04:53 PM
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...
2022-09-10 05:22 PM
Rewrite the code using normal register defines.
And for a start - all modifications of registers RTC_ISR and EXTI_PR are broken.
2022-09-11 12:46 AM
> 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
I wonder where do you have these values from, as I've seen them in other confused post, too.
JW
2022-09-11 07:43 AM
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.
2022-09-12 08:03 AM
@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.
2022-09-12 08:06 AM
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?
2022-09-12 08:41 AM
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.
2022-09-12 08:45 AM
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.