Timeout in RTC_INIT with HSE if an unused register does not have a unspecific entry is set!?
I have an STM32F446 with a HSE attached. Everything works fine (freeRTOS, CAN, I2C, ADC).
Now I want to use the RTC but I cannot initialized it if I not set PeriphClkInitStruct.PLLI2SDivQ to an unspecific value. RTC_EnterInitMode() from the HAL library does not receive the INIT state of the RTC->ISR.
I don't understand what's happening, because this variable is never read or used else where. There must be a rare side-effect which I don't see.
I compared the assembly output of the whole program with and without `PeriphClkInitStruct.PLLI2SDivQ`. There is no different besides the 0xFFFFFFFF write. :( I compiled the code with GCC 9.2/9.3 for C++ with and without optimization.
The example is from RTC_Calendar of the STM32F446 Nucleo Board. Adjusted to my needs.
RTC_HandleTypeDef RtcHandle{};
#define RTC_ASYNCH_PREDIV 124
#define RTC_SYNCH_PREDIV 7999
void Error_Handler() {
while (true) {}
}
void init_rtc() {
RtcHandle.Instance = RTC;
RtcHandle.Init.HourFormat = RTC_HOURFORMAT_24;
RtcHandle.Init.AsynchPrediv = RTC_ASYNCH_PREDIV;
RtcHandle.Init.SynchPrediv = RTC_SYNCH_PREDIV;
RtcHandle.Init.OutPut = RTC_OUTPUT_DISABLE;
RtcHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
RtcHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
__HAL_RTC_RESET_HANDLE_STATE(&RtcHandle);
// Fails with timeout if for ever reason, PLLI2SDivQ is not set to some specific value?
if (HAL_RTC_Init(&RtcHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
}
extern "C" void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{
RCC_OscInitTypeDef RCC_OscInitStruct{};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct{};
/*##-1- Enables the PWR Clock and Enables access to the backup domain ###################################*/
/* To change the source clock of the RTC feature (LSE, LSI), You have to:
- Enable the power clock using __HAL_RCC_PWR_CLK_ENABLE()
- Enable write access using HAL_PWR_EnableBkUpAccess() function before to
configure the RTC clock source (to be done once after reset).
- Reset the Back up Domain using __HAL_RCC_BACKUPRESET_FORCE() and
__HAL_RCC_BACKUPRESET_RELEASE().
- Configure the needed RTc clock source */
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess();
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV16;
// ??????????????????????????????????????????????????????????????????
// If this particular member is initialized (not all values work)
// RTC is in INIT state, otherwise RTC_EnterInitMode timeouts.
// This value is not used in HAL_RCCEx_PeriphCLKConfig at all!
// What is happening?
PeriphClkInitStruct.PLLI2SDivQ = 0xFFFFFFFF;
if(HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/*##-3- Enable RTC peripheral Clocks #######################################*/
/* Enable RTC Clock */
__HAL_RCC_RTC_ENABLE();
}
void SystemClock_Init() {
if (HAL_Init() != HAL_OK) {
Error_Handler();
}
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitTypeDef RCC_OscInitStruct{.OscillatorType = RCC_OSCILLATORTYPE_HSE,
.HSEState = RCC_HSE_ON,
.LSEState = RCC_LSE_OFF,
.HSIState = RCC_HSI_OFF,
.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT,
.LSIState = RCC_LSI_OFF,
.PLL = {
.PLLState = RCC_PLL_ON,
.PLLSource = RCC_PLLSOURCE_HSE,
.PLLM = 16,
.PLLN = 288,
.PLLP = RCC_PLLP_DIV2,
.PLLQ = 2,
.PLLR = 2,
}};
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
/* Activate the Over-Drive mode */
if (HAL_PWREx_EnableOverDrive() != HAL_OK) {
Error_Handler();
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitTypeDef RCC_ClkInitStruct{
.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2,
.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK,
.AHBCLKDivider = RCC_SYSCLK_DIV1,
.APB1CLKDivider = RCC_HCLK_DIV4,
.APB2CLKDivider = RCC_HCLK_DIV2,
};
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
Error_Handler();
}
// Check clock configuration.
// If any value has been changed, the peripheral clocks (PWM, CAN...) have to be adjusted.
if (HAL_RCC_GetSysClockFreq() != 144000000) {
Error_Handler();
}
if (HAL_RCC_GetHCLKFreq() != 144000000) {
Error_Handler();
}
if (HAL_RCC_GetPCLK1Freq() != 36000000) {
Error_Handler();
}
if (HAL_RCC_GetPCLK2Freq() != 72000000) {
Error_Handler();
}
}
int main() {
SystemClock_Init();
init_rtc();
return 0;
}