2022-01-10 01:41 AM
Hardware 1: STM32F767ZGT6 with LSE Crystal Model: CM9V-T1A-32.768KHZ-7PF-20PPM-TA-QC Maker: Micro Crystal AG
Hardware 2: STM32F767IIT6 with LSE Crystal Model: ECS-.327-12.5-12R-C-TR Maker: ECS Inc
Compiler: IAR Workbench v8.32.1
Driver: STM32Cube_FW_F7_V1.15.0
Hi.
I have two PCB designs with the above different MCU and LSE crystals chosen from AN4759. However, HAL_RTC_Init(…) usually fails and when it does work the RTC clock is very inaccurate. Can someone please advise what I am doing wrong in by code?
Regards, Andrew
#include "stm32f7xx_ll_bus.h"
#include "stm32f7xx_ll_rcc.h"
#include "stm32f7xx_ll_system.h"
#include "stm32f7xx_ll_utils.h"
#include "stm32f7xx_ll_gpio.h"
#include "stm32f7xx_ll_rtc.h"
#include "stm32f7xx_ll_pwr.h"
#include "stm32f7xx_ll_cortex.h"
#include "main.h"
extern RTC_HandleTypeDef hRTC_Handle;
int main(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
HAL_StatusTypeDef ret = HAL_OK;
uint8_t aShowTime[50] = {0};
uint8_t aShowDate[50] = {0};
/* Enable the CPU Cache */
CPU_CACHE_Enable();
/* STM32F7xx HAL library initialization */
HAL_Init();
/* Resets the RCC clock configuration to the default reset state. */
HAL_RCC_DeInit();
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 24;
RCC_OscInitStruct.PLL.PLLN = 400;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 8;
RCC_OscInitStruct.PLL.PLLR = 2;
ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
if(ret != HAL_OK)
{
while(1) { ; }
}
/* Activate the OverDrive to reach the 200 MHz Frequency */
ret = HAL_PWREx_EnableOverDrive();
if(ret != HAL_OK)
{
while(1) { ; }
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6);
if(ret != HAL_OK)
{
while(1) { ; }
}
/* Select PLLSAI output as USB clock source */
PeriphClkInitStruct.PeriphClockSelection = (RCC_PERIPHCLK_RTC | RCC_PERIPHCLK_UART7 | RCC_PERIPHCLK_CLK48 | RCC_PERIPHCLK_UART5 | RCC_PERIPHCLK_LTDC);
PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
PeriphClkInitStruct.Clk48ClockSelection = RCC_CLK48SOURCE_PLLSAIP;
PeriphClkInitStruct.Uart7ClockSelection = RCC_UART7CLKSOURCE_PCLK1;
PeriphClkInitStruct.Uart5ClockSelection = RCC_UART5CLKSOURCE_PCLK1;
PeriphClkInitStruct.PLLSAI.PLLSAIN = 192;
PeriphClkInitStruct.PLLSAI.PLLSAIP = RCC_PLLSAIP_DIV4;
PeriphClkInitStruct.PLLSAI.PLLSAIQ = 2;
PeriphClkInitStruct.PLLSAIDivQ = 1;
PeriphClkInitStruct.PLLSAI.PLLSAIR = 5;
PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_4;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
while(1) { ; }
}
/* Setup UART DeBug Terminal */
Print_DeBug_Initialise();
/* Enable RTC Clock */
__HAL_RCC_RTC_ENABLE();
/* Setup RTCC */
hRTC_Handle.Instance = RTC;
hRTC_Handle.Init.HourFormat = RTC_HOURFORMAT_12;
hRTC_Handle.Init.AsynchPrediv = 127; // 127 + 1 = 128
hRTC_Handle.Init.SynchPrediv = 255; // 255 + 1 = 256 32768Hz / 128 / 256 = 1Hz
hRTC_Handle.Init.OutPut = RTC_OUTPUT_DISABLE;
hRTC_Handle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hRTC_Handle.Init.OutPutType = RTC_OUTPUT_TYPE_PUSHPULL;
/*********************** Need to add this to allow PC13 to work as normal GPIO ***********************************/
hRTC_Handle.Instance->CR &= ((uint32_t) ~(RTC_CR_COE | RTC_CR_OSEL | RTC_CR_TSE));
hRTC_Handle.Instance->TAMPCR &= ((uint32_t) ~(RTC_TAMPCR_TAMP1E) );
/*********************** Need to add this to allow PC13 to work as normal GPIO ***********************************/
ret = HAL_RTC_Init(&hRTC_Handle);
if(ret != HAL_OK)
{
printf("ERROR - HAL_RTC_Init(&hRTC_Handle)\n\r");
}
while (1)
{
sprintf((char*)aShowTime,"%.2d:%.2d:%.2d", __LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetHour(RTC)),
__LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetMinute(RTC)),
__LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetSecond(RTC)));
/* Display date Format : mm-dd-yy */
sprintf((char*)aShowDate,"%.2d-%.2d-%.2d", __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetMonth(RTC)),
__LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetDay(RTC)),
2000 + __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetYear(RTC)));
printf( "%s\n\r", aShowTime );
printf( "%s\n\r", aShowDate );
HAL_Delay(1000);
}
}
Solved! Go to Solution.
2022-01-10 04:28 PM
Hi.
Thank you for your time. I found that I forgot to enable the LSE with the HAL_RCC_OscConfig(&RCC_OscInitStruct) function. The code should have been as per the below:
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 24;
RCC_OscInitStruct.PLL.PLLN = 400;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 8;
RCC_OscInitStruct.PLL.PLLR = 2;
ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
I have also included the LSEDRIVE function that appear to be working well.
void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc)
{
/* Disable the write protection for RTC registers. */
__HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);
/* Enable RTC Clock */
__HAL_RCC_RTC_ENABLE();
/* Configures the External Low Speed oscillator (LSE) drive capability */
__HAL_RCC_LSEDRIVE_CONFIG( RCC_LSEDRIVE_MEDIUMHIGH );
}
I am able to measure the 512Hz clock with the oscilloscope as an output on the PC13 pin.
HAL_RTCEx_SetCalibrationOutPut( &hRTC_Handle, RTC_CALIBOUTPUT_512HZ );
Thank you.
2022-01-10 03:54 AM
Layout of the LSE circuitry matters. Review and/or post it.
Try your code on a known-good board such as Nucleo or Disco.
Experiment with the LSE drive level, see RCC_BDCR.LSEDRV.
Read AN2867.
JW
2022-01-10 06:03 AM
I did a quick calculation of your crystals after AN2867, as mentioned by @Community member - for both of them the default drive level (low) is not sufficient and must be set at least to medium low or even medium high.
It looks like you are working with HAL, so you can very easily insert a macro to set LSEDRV in the initialization of HAL_RTC_MspInit() right after the clock selection (because LSE is located in the backup domain and write access to this domain is denied after reset). The macro is defined in stm32f7xx_hal_rcc.h:
/* Configures the External Low Speed oscillator (LSE) drive capability */
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_MEDIUMHIGH);
Good luck!
Regards
/Peter
2022-01-10 04:28 PM
Hi.
Thank you for your time. I found that I forgot to enable the LSE with the HAL_RCC_OscConfig(&RCC_OscInitStruct) function. The code should have been as per the below:
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 24;
RCC_OscInitStruct.PLL.PLLN = 400;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 8;
RCC_OscInitStruct.PLL.PLLR = 2;
ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
I have also included the LSEDRIVE function that appear to be working well.
void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc)
{
/* Disable the write protection for RTC registers. */
__HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);
/* Enable RTC Clock */
__HAL_RCC_RTC_ENABLE();
/* Configures the External Low Speed oscillator (LSE) drive capability */
__HAL_RCC_LSEDRIVE_CONFIG( RCC_LSEDRIVE_MEDIUMHIGH );
}
I am able to measure the 512Hz clock with the oscilloscope as an output on the PC13 pin.
HAL_RTCEx_SetCalibrationOutPut( &hRTC_Handle, RTC_CALIBOUTPUT_512HZ );
Thank you.
2022-01-10 11:17 PM
So it looks like it's working now?
When your question is answered, please mark this topic as answered by choosing Select as Best for the favourite answer. This will help other users find that answer faster.
/Peter