你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32Cube_FW_F4 中 RTC_Calendar例程的 BUG

[复制链接]
STMCU小助手 发布时间:2022-2-24 21:17
前言
实时时钟(RTC)是一个独立的 BCD 定时器/计数器,用来提供准确的日历和时间信息。准确性是其重要的指标。

问题
某客户在其产品的设计中,使用了 STM32F429IIT6。客户在使用过程发现一个问题,虽然已经有使用电池对 VBAT 进行供电,但是在经常频繁的 VDD 上下电之后,发现时钟会比准确的时间慢几秒钟。

调研
1.了解问题
向客户了解其使用的固件库,得知他的程序是参考 STM32Cube_FW_F4_V1.3.0\Projects\STM324x9I_EVAL\Examples\RTC中的 RTC_Calendar 例程。于是找来 STM32439I-EVAL2 来进行验证,测试发现,
STM32Cube_FW_F4_V1.3.0\Projects\STM324x9I_EVAL\Examples\RTC 中的 RTC_Calendar 例程确实存在频繁上下电会导致时间变慢的情况;而对标准外设库
STM32F4xx_DSP_StdPeriph_Lib_V1.4.0\Project\STM32F4xx_StdPeriph_Examples\RTC 中的 RTC_Calendar 例程进行测试,则不存在此问题。所以,怀疑 STM32Cube_FW_F4_V1.3.0\Projects\STM324x9I_EVAL\Examples\RTC 中的 RTC_Calendar例程存在 Bug。

2.问题分析
仔细阅读 STM32Cube_FW_F4_V1.3.0\Projects\STM324x9I_EVAL\Examples\RTC 中的 RTC_Calendar 例程,分析一下main.c 主程序,“if(HAL_RTCEx_BKUPRead(&RtcHandle, RTC_BKP_DR0) != 0x32F2)”是用来判断 RTC 是否是已经被配置过的,所以怀疑的重点可放在这之前的“if(HAL_RTC_Init(&RtcHandle) != HAL_OK)”中的 HAL_RTC_Init()函数。


进入位于 stm32f4xx_hal_rtc.c 中的 HAL_RTC_Init()函数,再进入其调用的位于 stm32f4xx_hal_msp.c 中的HAL_RTC_MspInit()函数,在这个函数中,可以看到以下代码:
  1. /*##-1- Configue LSE as RTC clock soucre ###################################*/
  2. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
  3. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  4. RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  5. RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
  6. if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  7. {
  8. Error_Handler();
  9. }

  10. PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  11. PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
  12. if(HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  13. {
  14. Error_Handler();
  15. }
复制代码

这段代码中由于选中了 LSE,在其所调用的 HAL_RCC_OscConfig()中对 LSE 进行了重新配置。在 stm32f4xx_hal_rcc.c 中找到 HAL_RCC_OscConfig()函数,发现其对 LSE 重新配置的时候,对 LSE 进行关闭,然后再配置。

到此,回来再看 main.c,由于“if(HAL_RTC_Init(&RtcHandle) != HAL_OK)”位于“if(HAL_RTCEx_BKUPRead(&RtcHandle, RTC_BKP_DR0) != 0x32F2)”之前,从程序流程来看,每次 VDD 上电,都会进行一次 HAL_RTC_Init(),也就是说,每次上电都会有一个关闭 LSE 再打开的动作,这个动作多了,时间变慢的现象就变得很明显了。

3.问题解决
问题原因很明显了,那么解决办法也很简单,只需要将 HAL_RTC_Init()这个初始化函数挪到判断 RTC 是否是已经被配置过的if…else…语句里边就行了。如果是 RTC 已经被配置过的,就不需要再重新初始化一次了。如下:
  1. /*##-1- Configure the RTC peripheral #######################################*/
  2. RtcHandle.Instance = RTC;

  3. /*##-2- Check if Data stored in BackUp register0: No Need to reconfigure RTC#*/
  4. /* Read the BackUp Register 0 Data */
  5. if(HAL_RTCEx_BKUPRead(&RtcHandle, RTC_BKP_DR0) != 0x32F2)
  6. {
  7. /* Configure RTC prescaler and RTC data registers */
  8. /* RTC configured as follow:

  9. - Hour Format = Format 24
  10. - Asynch Prediv = Value according to source clock
  11. - Synch Prediv = Value according to source clock
  12. - OutPut = Output Disable
  13. - OutPutPolarity = High Polarity
  14. - OutPutType = Open Drain */
  15.   RtcHandle.Init.HourFormat = RTC_HOURFORMAT_24;
  16.   RtcHandle.Init.AsynchPrediv = RTC_ASYNCH_PREDIV;
  17.   RtcHandle.Init.SynchPrediv = RTC_SYNCH_PREDIV;
  18.   RtcHandle.Init.OutPut = RTC_OUTPUT_DISABLE;
  19.   RtcHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  20.   RtcHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;

  21. if(HAL_RTC_Init(&RtcHandle) != HAL_OK)
  22. {
  23. /* Initialization Error */
  24. Error_Handler();
  25. }

  26. /* Configure RTC Calendar */
  27. RTC_CalendarConfig();
  28. }
  29. else
  30. {
  31. /* Check if the Power On Reset flag is set */
  32. if(__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET)
  33. {
  34. /* Power on reset occured: Turn LED2 on */
  35. BSP_LED_On(LED2);
  36. }
  37. /* Check if Pin Reset flag is set */
  38. if(__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST) != RESET)
  39. {
  40. /* External reset occured: Turn LED4 on */
  41. BSP_LED_On(LED4);
  42. }

  43. /* Enable the PWR clock */
  44. __PWR_CLK_ENABLE();

  45. /* Allow access to RTC */
  46. HAL_PWR_EnableBkUpAccess();

  47. /* Wait for RTC APB registers synchronisation */
  48. if(HAL_RTC_WaitForSynchro(&RtcHandle) != HAL_OK)
  49. {
  50. /* synchronisation Error */
  51. Error_Handler();
  52. }

  53. /* Clear the RTC Alarm Flag */
  54. __HAL_RTC_ALARM_CLEAR_FLAG(&RtcHandle,RTC_FLAG_ALRAF);

  55. /* Clear the EXTI Line 17 Pending bit (Connected internally to RTC Alarm) */
  56. __HAL_RTC_EXTI_CLEAR_FLAG(RTC_EXTI_LINE_ALARM_EVENT);

  57. /* Clear Reset Flag */
  58. __HAL_RCC_CLEAR_RESET_FLAGS();
  59. }
复制代码

结论
由于 STM32Cube_FW_F4_V1.3.0\Projects\STM324x9I_EVAL\Examples\RTC 中的 RTC_Calendar 例程没有注意到HAL_RTC_Init()函数里边会有关闭 LSE 的动作,而每次上电都会运行这个函数,每次上电都会导致时间变慢,上电的次数多了,变慢就很明显了。所以,例程上是有 Bug 的,需要进行修复。

处理
需要将 HAL_RTC_Init()这个初始化函数的位置做个修改。如果 RTC 未被配置过,则进行配置;如果是已经被配置过的,就不需要再重新初始化一次了。标准外设库STM32F4xx_DSP_StdPeriph_Lib_V1.4.0\Project\STM32F4xx_StdPeriph_Examples\RTC 中的 RTC_Calendar 例程是没有问题的,参考此例程,修改得一基于 STM32Cube_FW_F4 的 RTC_Calendar 例程,见附件。


建议
上电时对 LSE 进行重新初始化可能会导致 RTC 计时不准确,所以在实际应用过程中应该对此注意一下。

收藏 评论0 发布时间:2022-2-24 21:17

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版