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

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

[复制链接]
STMCU小助手 发布时间:2022-2-24 21:17
前言; y$ q7 F7 W0 Y" u4 X0 v# g" p
实时时钟(RTC)是一个独立的 BCD 定时器/计数器,用来提供准确的日历和时间信息。准确性是其重要的指标。! j4 Y: h. S6 E1 T/ M
' Y" C+ f$ J! A! A: y, z! e: v
问题1 h' \" V( i' L: C8 ]3 L1 [
某客户在其产品的设计中,使用了 STM32F429IIT6。客户在使用过程发现一个问题,虽然已经有使用电池对 VBAT 进行供电,但是在经常频繁的 VDD 上下电之后,发现时钟会比准确的时间慢几秒钟。
( w+ @" L/ N' Y! l; d& p1 Q& X6 e2 H
$ V4 _; s( I$ I; {- p3 m9 m  r8 X调研
) h; B$ N( `/ u  U! G1.了解问题! f+ e' G& q; S! @/ n
向客户了解其使用的固件库,得知他的程序是参考 STM32Cube_FW_F4_V1.3.0\Projects\STM324x9I_EVAL\Examples\RTC中的 RTC_Calendar 例程。于是找来 STM32439I-EVAL2 来进行验证,测试发现,
/ O( Z2 R6 v. \0 M: uSTM32Cube_FW_F4_V1.3.0\Projects\STM324x9I_EVAL\Examples\RTC 中的 RTC_Calendar 例程确实存在频繁上下电会导致时间变慢的情况;而对标准外设库6 n" x: V3 r/ s! ?7 w
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。' F! [2 R0 H: ~% B1 M

; O  c$ V1 t. L1 J8 K# x- r2.问题分析$ I2 \; T( a' o/ z. t5 p& ?0 h
仔细阅读 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()函数。$ V2 d+ l$ L+ S1 Y1 R5 W& w) x
1 L1 ~& O! n. J" D7 h5 y

4 L) e! Z3 g: I5 m进入位于 stm32f4xx_hal_rtc.c 中的 HAL_RTC_Init()函数,再进入其调用的位于 stm32f4xx_hal_msp.c 中的HAL_RTC_MspInit()函数,在这个函数中,可以看到以下代码:
' I1 E4 q+ ]# I) P/ K8 P
  1. /*##-1- Configue LSE as RTC clock soucre ###################################*/
      H7 X% W0 y  C0 f2 m2 O
  2. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
    0 K8 J( t+ p' O* \
  3. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    5 E1 M4 h- m/ E2 v
  4. RCC_OscInitStruct.LSEState = RCC_LSE_ON;% }4 T  k% h) R7 U6 C
  5. RCC_OscInitStruct.LSIState = RCC_LSI_OFF;1 G3 q* Q1 q& }
  6. if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    0 u5 g1 C# v" q3 u. B8 P! \( I  S
  7. {
    * n) y2 \& _7 |( P
  8. Error_Handler();$ n6 E* O$ y4 G2 E6 }
  9. }8 i( P) ?' \- Y* i
  10. 5 ^. }6 s/ j; X( {3 L
  11. PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;0 s' _- c4 v- r! c6 S, @) p' z5 ^9 B
  12. PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;- X6 R8 V2 R2 K3 v, L: g
  13. if(HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    & ~4 A7 }* s  U$ g$ a6 w; ]' r
  14. {
    8 u  f0 j9 z; B1 |$ v
  15. Error_Handler();
    # C' E+ N& ?( w2 Z
  16. }
复制代码

; J; @+ k2 a5 v) h+ z3 X这段代码中由于选中了 LSE,在其所调用的 HAL_RCC_OscConfig()中对 LSE 进行了重新配置。在 stm32f4xx_hal_rcc.c 中找到 HAL_RCC_OscConfig()函数,发现其对 LSE 重新配置的时候,对 LSE 进行关闭,然后再配置。
8 s# T% Q: k! @! R+ n7 t  ^+ E
2 z" G7 u2 u0 e! \5 K4 T) d到此,回来再看 main.c,由于“if(HAL_RTC_Init(&RtcHandle) != HAL_OK)”位于“if(HAL_RTCEx_BKUPRead(&RtcHandle, RTC_BKP_DR0) != 0x32F2)”之前,从程序流程来看,每次 VDD 上电,都会进行一次 HAL_RTC_Init(),也就是说,每次上电都会有一个关闭 LSE 再打开的动作,这个动作多了,时间变慢的现象就变得很明显了。
& X8 E( E2 k/ \# C: Z# p/ Q1 F( h2 Z7 C# z1 {
3.问题解决
) H' J# s  U, ?' ]$ z问题原因很明显了,那么解决办法也很简单,只需要将 HAL_RTC_Init()这个初始化函数挪到判断 RTC 是否是已经被配置过的if…else…语句里边就行了。如果是 RTC 已经被配置过的,就不需要再重新初始化一次了。如下:
7 h  D* @3 Y" c9 f* Q1 s* U) b
  1. /*##-1- Configure the RTC peripheral #######################################*/
    3 x( }* h( l. g! ]  v& S5 R
  2. RtcHandle.Instance = RTC;. g7 Q9 c1 S* J3 J
  3. 1 Q3 M0 m7 _& ~. V6 Z; q1 S0 P
  4. /*##-2- Check if Data stored in BackUp register0: No Need to reconfigure RTC#*/
    7 m. K. _4 C& X' n, }, E
  5. /* Read the BackUp Register 0 Data */
    3 k( e1 Z+ K% E" k9 H0 L
  6. if(HAL_RTCEx_BKUPRead(&RtcHandle, RTC_BKP_DR0) != 0x32F2)
    : g: n4 m5 T+ n
  7. {0 ]( z# d7 R: F1 _
  8. /* Configure RTC prescaler and RTC data registers */0 c3 p# P8 E& R4 Z6 e" S" J
  9. /* RTC configured as follow:
    4 ^* M4 B; ]" @
  10. * T7 I# j; i8 n: K$ x3 }
  11. - Hour Format = Format 242 I8 A, F1 S2 E6 w1 g- v
  12. - Asynch Prediv = Value according to source clock
    9 L) j5 T( F5 X# t/ I
  13. - Synch Prediv = Value according to source clock
    * E8 y  s; ^4 A8 X8 C- z1 ?* R. M
  14. - OutPut = Output Disable$ n2 R3 }# c  h
  15. - OutPutPolarity = High Polarity
    5 t9 z" ^! c1 U
  16. - OutPutType = Open Drain */
      G6 V; B5 \# K7 p
  17.   RtcHandle.Init.HourFormat = RTC_HOURFORMAT_24;
    2 k- C$ W7 e) A2 V( [- d* V
  18.   RtcHandle.Init.AsynchPrediv = RTC_ASYNCH_PREDIV;
    9 n/ p5 B. O+ i
  19.   RtcHandle.Init.SynchPrediv = RTC_SYNCH_PREDIV;
    6 r2 i, d$ r  p! K
  20.   RtcHandle.Init.OutPut = RTC_OUTPUT_DISABLE;1 B: B. T+ n4 v: P7 v. J
  21.   RtcHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;5 }8 [! \, {* L+ A+ W2 l/ X6 W
  22.   RtcHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;1 O6 z7 \: P5 n, x* @" X$ b

  23. 1 x7 L# h- I4 v) Z# p0 g5 J3 f
  24. if(HAL_RTC_Init(&RtcHandle) != HAL_OK). _7 q% x: j9 I$ d9 F2 c8 C( Y3 L( u
  25. {$ g7 o& f( {% Z# S" z! m) Z: ]
  26. /* Initialization Error */7 M8 Y4 Z& Q: C, `- Q: f$ W
  27. Error_Handler();* E$ U8 f" S0 t* n% I0 E
  28. }
    % a3 N! y# h- |0 a& o

  29. ) {) F+ G" [9 G; J3 o- O# b) R5 Q
  30. /* Configure RTC Calendar */
    1 T: V5 R( T. q
  31. RTC_CalendarConfig();- Q- ]: Z& j7 s4 X' e
  32. }
    " A. \3 u7 n, o. N: `
  33. else- s" c( z- G7 S, ~  L
  34. {) ^$ W6 ?$ j9 W+ p. J( V
  35. /* Check if the Power On Reset flag is set */
    0 Q- M8 d2 V5 }& A) M! O
  36. if(__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET)$ ]" m0 u/ E9 s5 R$ j
  37. {) x, y8 @! h- L% `: `
  38. /* Power on reset occured: Turn LED2 on */  {/ u8 k# _6 o; y' r
  39. BSP_LED_On(LED2);
    & B% u5 F' G) L" f
  40. }
    + J. v& y7 b! D* M
  41. /* Check if Pin Reset flag is set */
    ' l8 I' \# M" q. G: c; F
  42. if(__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST) != RESET)
    9 O; ^7 T: C7 s! c+ B1 a" A
  43. {
    + ^0 x3 _, e! U3 S9 L
  44. /* External reset occured: Turn LED4 on */
    * q9 p5 z% m0 ]
  45. BSP_LED_On(LED4);8 ^6 v  ?  v$ _* p- H& M  _
  46. }/ e/ m5 O# q: K6 T" S. F) K
  47. 6 f6 i4 o+ Z- O
  48. /* Enable the PWR clock */
    - Z4 V, U/ w2 k7 ]! I& o  ]
  49. __PWR_CLK_ENABLE();1 V# ~) g7 t3 ~# V

  50. ! u& r8 @/ Q$ Y% f( W) A
  51. /* Allow access to RTC */
      g, ?) B( n. M9 U' \5 `) c3 ^
  52. HAL_PWR_EnableBkUpAccess();
    6 w1 r$ z6 I1 `! d! D) }

  53. ; h' J" P# E; r8 o2 ?( a
  54. /* Wait for RTC APB registers synchronisation */0 F4 \6 V( Z+ b5 z" T& @
  55. if(HAL_RTC_WaitForSynchro(&RtcHandle) != HAL_OK)
    / ~1 K; {5 R$ s, }; G; G
  56. {
    2 w0 F" p. U7 j
  57. /* synchronisation Error */
    9 C3 H* d/ _! i$ M6 r: f
  58. Error_Handler();
    * }9 }1 f7 M! Y9 Z: Z
  59. }
    6 H" ?1 G3 ^) d
  60. 3 |3 }0 }. Q" O; m! \( u- i; F
  61. /* Clear the RTC Alarm Flag */; g) S; J; Z6 N8 \4 @. R4 [/ z: C
  62. __HAL_RTC_ALARM_CLEAR_FLAG(&RtcHandle,RTC_FLAG_ALRAF);" m, z  M7 W3 c! H; z* I* S6 g+ D
  63. 1 I, F# e6 G6 o# p4 N, r
  64. /* Clear the EXTI Line 17 Pending bit (Connected internally to RTC Alarm) */
    % ~8 ^$ F4 s: ~% D$ D
  65. __HAL_RTC_EXTI_CLEAR_FLAG(RTC_EXTI_LINE_ALARM_EVENT);
    & B3 j; `$ F9 l* z3 Y0 x9 T  O8 s
  66. " w$ U9 w+ a" e
  67. /* Clear Reset Flag */# }9 X9 M8 Q+ V# m
  68. __HAL_RCC_CLEAR_RESET_FLAGS();' d0 V# |% c( n) ^
  69. }
复制代码

. g9 Z* ^( F8 Y8 w# D, p1 o' |结论  W* l9 H4 H& S, y
由于 STM32Cube_FW_F4_V1.3.0\Projects\STM324x9I_EVAL\Examples\RTC 中的 RTC_Calendar 例程没有注意到HAL_RTC_Init()函数里边会有关闭 LSE 的动作,而每次上电都会运行这个函数,每次上电都会导致时间变慢,上电的次数多了,变慢就很明显了。所以,例程上是有 Bug 的,需要进行修复。
' W. K) q% w. Z0 |
' N0 m' W! v. i2 ?: g; \0 e1 H/ T* z处理) I5 z7 [4 O. t) l6 [; C* c# G
需要将 HAL_RTC_Init()这个初始化函数的位置做个修改。如果 RTC 未被配置过,则进行配置;如果是已经被配置过的,就不需要再重新初始化一次了。标准外设库STM32F4xx_DSP_StdPeriph_Lib_V1.4.0\Project\STM32F4xx_StdPeriph_Examples\RTC 中的 RTC_Calendar 例程是没有问题的,参考此例程,修改得一基于 STM32Cube_FW_F4 的 RTC_Calendar 例程,见附件。) B+ k$ u# P' g
- p( c* \) v' z- C

* P  `* I& Q4 L" v2 _+ e6 F4 L建议2 A9 i4 B0 q! ?7 {
上电时对 LSE 进行重新初始化可能会导致 RTC 计时不准确,所以在实际应用过程中应该对此注意一下。
- R! o( R% ]# Z3 U/ S
! u: }' l+ @6 i, ?0 x
赞 收藏 评论0 发布时间:2022-2-24 21:17

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版