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

STM32CubeIDE的窗口看门狗WWDG经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-6 15:13
一、stm32的WWDG说明3 J+ j6 _' B, z
       1.1  WWDG特点:

, Q1 H" p5 m) E& X  U8 A/ F        在前一篇博文介绍独立看门狗时就指出STM32 MCU提供两个看门狗,独立看门狗和窗口看门狗。4 ?; a$ h5 a- c, X3 F: c
9 q4 S2 F- Y  D6 F4 y: V0 r
        相比独立看门狗,窗口看门狗WWDG有以下特点:: Q2 s3 D$ z& k8 K5 A7 m' q1 l
        【1】WWDG计数器依赖于系统时钟,准确来说依赖于系统时钟通过分频、倍频得到的PCLK1时钟,即APB1 peripheral clocks输出频率。" `5 J8 L0 ?. V3 f* j
        【2】WWDG支持中断功能以及早期唤醒中断。. q+ d2 C, ^& k% O

9 H5 L  S; r$ u* u4 ?8 W        1.2 WWDG的cubeMX配置及说明
  F* D) h1 d4 z. \* {. S        现在看一下WWDG在CubeMX中的设置问题,WWDG和IWDG一样,在系统内核栏目开启,开启激活选项后,可以设置5项参数,分别是计数时钟分频值,窗口值、递减计数预设值、早期唤醒中断使能以及中断功能。4 }% ^; D7 q* u8 O
98991825d78f4fbaa73212a13f1a399f.png
) ?. ~1 R% @# P$ Z# W
3 b1 j: F3 P# ]' G* F+ Z        【1】 一旦WWDG启用,将生成系统重置功能并启动其递减计数器,喂狗时,必须在设定的上限时间和下限时间之间喂狗,如果喂狗时间高于上限时间或者低于下限时间,都会导致看门狗触发重启机制。其中下限时间是系统固定的0X40。上限时间(窗口值)是用户可以定义的,大于0X40同时小于0X7F即可。
5 T% ^! Y0 ~6 T+ o
, U  l7 \# |5 Q2 D5 y
        【2】程序在达到0x3F值之前刷新计数器(计数器的低六位值,最大值111111=0X3F),到期时触发系统重置(即,当计数器值从0x40向下滚动到0x3F时生成重置,即再次减一时,0x40=0X3F+0X01)。并在计数器达到刷新窗口值之前刷新了计数器值,也会生成MCU重置。这就要求必须在有限的窗口中刷新计数器。另外WWDG启用后,除非通过系统重置,否则无法禁用WWDG。/ i2 J* V1 r; r1 |2 K
6 o9 o. D( P4 R
        【3】如果启用了早期唤醒中断(Early Wakeup Interrupt,EWI)功能,在WWDG到期之前发出警告(即计数器达到0x40时会产生中断)。使用早期唤醒中断(EWI),在生成MCU重置之前可执行特定的安全操作或数据记录。此机制要求在NVIC中启用WWDG中断设置。同样,EWI启用后,EWI中断不能被禁用,除非通过系统重置。中断状态感知可在RCC_CSR寄存器中的WWDGRST标志判断何时发生WWDG重置。; [; `' }4 w3 ^6 Y" {
. X; {/ k# }9 ]5 n4 n5 ^
' f1 L% `3 Y" N+ |. P3 H
        1.3 WWDG喂狗时间计算

( W; ]; I% `9 B        WWDG计数器输入时钟由PCLK1频率(APB1 peripheral clocks输出频率)除以计数时钟分频值得出。
  p3 h* @* M& O2 v  s. j! u; b) J  f0 ?; a
e61915a0f0ff49f69ba6ec1fa1697eef.png , D. ?( V! x+ v, B

, I: t3 A# v5 C2 ], ]7 l         WWDG时钟(Hz)=PCLK1/(4096*预分频器);
1 n  l/ }" K1 b$ p6 Q" e7 ]: J
4 P* _2 v" y) H& }# y        WWDG周期(mS)=1000/WWDG时钟(Hz);
1 k* Z: Y+ }% d6 k
7 c* L# K* `5 ~' B        WWDG超时MinT(mS)=WWDG周期(mS)*(计数器-窗口),因此最好设置递减计数值≥窗口值。
8 T( _) N& ~/ i7 G3 |) m- B% i: H$ q' j! o9 A7 b5 Y
        WWDG超时MaxT(mS)=WWDG周期(mS)*(计数器-0x40),0x40=0X3F+0X01;
- H7 T" N! J. M4 G7 k
# ?. Q& l4 b" ]6 j' |        WWDG喂狗时间MinT(mS)<t<MaxT(mS)。
& U0 k2 g) {" I5 X6 F

/ n9 a) Z" V1 |! U二、WWDG工程创建及源码分析
) g; j: s6 p+ a% R0 N8 y       2.1 cubeMX界面配置WWDG

/ c+ _$ t/ p: {! h, y         本博文基于前面独立看门狗的工程直接增加窗口看门狗功能,并关闭独立看门狗。
- K/ N& b: y! Q$ p# N# h* ?) j) o) u
        双击.ioc文件打开cubeMX界面,开启WWDG,设置其参数如下,其中分频值2,窗口值0X64(100),递减计数预设值0X64(100),开启早期唤醒中断:
# j7 r5 I! w! g" r9 _+ T+ K8 {& Q7 o0 @7 h2 R$ w8 `
f1f7497080cd40f1853040eb75b2a652.png 4 P' z6 h9 P8 V9 }4 G

) @* b+ }( {( O1 u4 [         开启WWDG中断功能0 Y  q9 o* V+ X

+ E9 ^6 F1 ~: X; y: _
261f23989a6b41498df65be316df09cf.png / `6 F+ X( z' T/ A3 j" H

. n: M9 ~) G$ x9 E! z# o         APB1时钟输出频率设置10MHz(10 000 000Hz),设置该值小一些,主要是本博文采用按键触发切换喂狗时间间隔,而按键捕获到松开是人为操作,反应较慢,实时性不好体现。
5 ]( x& Y+ l4 \3 U( }7 N
' c' p/ o( H9 C) T         2.2 WWDG超时时间实例计算2 t2 Y0 J: Q' @1 h
        在WWDG的喂狗时间按前面计算公式,喂狗时间范围:
0 J; s% \; @8 B3 o& x9 b0 B$ [# d4 l9 J4 w9 Y0 t
        WWDG周期(mS)=1000ms/10MHz/(4096*8)=3.2768ms。
( {, X4 O; w4 I! h5 l8 K& i4 |4 s' J* t; C' L, x: w) t& s: S4 g' `1 w. Q9 a
        WWDG喂狗时间是在WWDG启动后的t时间内:
6 J5 X9 ?3 e5 d
4 d% p/ b: k3 L        t>3.2768ms*(0X64-0X64)=0ms;+ J/ D7 D5 X2 S7 Q9 G
& K! `8 f/ j- W% s( J# v( v3 c
        t<3.2768ms*(0X64-0X40)=117.9648ms。
5 \' s8 k9 I5 [) U
: I: y2 d' |6 [+ b/ \
6 v4 u0 A2 S2 U* k; G. k0 g
       2.3 工程高级配置
/ r+ w  z& C6 W8 d5 J         在工程高级配置中,取消WWDG的自动初始化,本博文将自己添加初始化,主要是HLA的WWDG初始化启动就立即进入计数,会给第一次喂狗造成时间差异较大。
! T* _1 L4 l: ?& S- S. Z1 w" T( T; l+ q# x6 d; ~# K2 a+ F
1bfc3d8fa7d24e54a97dbc87ab8f4317.png
8 }" V- n% ~! w7 g: y# N- \) S' t  E) Y
        生成代码输出。3 }# a6 ?0 z! W+ n

9 _& q  m3 x6 r+ j, B% _三、WWDG源码分析及应用
1 }4 c5 R: u% S. }- X9 y# K        3.1 WWDG的HLA库源码分析
- a1 m9 Y4 ?5 `7 P
        WWDG会在Core源码目录下的Inc及Src目录,分别生成wwdg.h和wwdg.c驱动文件。在wwdg.c文件中,主要定义了MX_WWDG_Init函数和HAL_WWDG_MspInit函数。MX_WWDG_Init主要做两件事情,一是将CubeMX上配置的参数传递给WWDG缓存Init和生成WWDG句柄Instance,二是调用HLA库的HAL_WWDG_Init来实现真正的初始化设定。HAL_WWDG_MspInit是HLA内的弱函数,根据实际配置CubeMX会生成新的函数覆盖原来的弱函数,而在HAL_WWDG_Init函数中会调用到HAL_WWDG_MspInit函数。
7 f; d7 I  U" _, S( K9 s' d' k! _) l
2b4c2b5b42104381bb7a213382fff3ca.png ) e! ^! H6 z! u) b1 [' r; |; a

- i, M" U/ s6 v         在stm32l4xx_hal_wwdt.c源文件中定义了HAL_WWDG_Init函数,它做以下事情:诊断配置参数是否合规(如果不是采用CubeMX配置,而是自己手动配置或调整过参数的,这里可能异常);调用HAL_WWDG_MspInit函数完成WWDG时钟以及中断初始化;最后将依据参数写入WWDG寄存器。6 S* y6 L  i8 p1 ~0 [
7 r$ x/ m( l1 _/ @
136b6b9e484a4fc2ad6b049467a4542a.png 7 R, F, E, y8 e5 r0 F; ~3 S- o! P: {
* `& p7 s# _- Q+ Q- i
         程序在依据参数将WWDG计数器值写入WWDG寄存器CR,将窗口值和时钟分频值写入WWDG寄存器CFR内。
( V2 \+ c9 h% T7 F2 E, H3 S# y" }: [$ [
d799e52574e943baa64598274903a5ed.png
' X  b" A/ T, L- q# H6 Q# _# M& g7 l) ?# K4 A; v/ o0 B
eb67a4bdb772428e92f464444c98c2a1.png
" I8 U; \/ W! z) s! X0 l& P8 L; T* B2 m9 ^/ k; \! x
         再回到wwdg.c内,HAL_WWDG_MspInit函数实现了WWDG时钟启动设置和中断初始及启动设置。
( l" J0 @1 l/ V2 a8 P4 c6 Z* t7 ?6 r. s4 R# A4 c7 k
d081f9832148473daa7a3f8b7bb2009c.png 5 x, f3 r+ M- C$ J& F

% `, J" t% A) f         HAL_NVIC_EnableIRQ启动后,如果有WWDG中断事件时,当中断服务例程触发HAL_WWDG_IRQHandler时,将自动清除标志,并执行HAL_WWDG_WakeupCallback用户回调函数报警。该回调函数在stm32l4xx_hal_wwdt.c定义,是个弱函数,用户可以通过自定义回调AL_WWDG_WakeupCallback来添加自己的代码。例如本文将在wwdg.c文件内重新定义该函数:
9 o; O' }7 F9 C
  1. /* USER CODE BEGIN 1 */. Q# ~5 E' P. k
  2. void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
    , N* b! q1 I" ~0 m, ?
  3. {' ?: j9 r( x* u9 q9 [3 d( s
  4.         printf("I know, but do nothing!\r\n");
    5 s8 Q" r0 \) X' y8 S$ U1 w
  5. }
    - |! |- k$ X( r2 r. Q/ W
  6. /* USER CODE END 1 */
复制代码
3 q+ D$ L, B; ?; P
         3.2 延时函数设计
; d+ V* |. i# R" c- U. Z        在ICore目录下添加delay目录,并在该目录下创建delay.h和delay.c源文件,实现自定义延时函数,主要满足本博文更高精度的延时要求。8 @# z: _4 e8 M: c1 M6 w+ _5 ~; J
) O% g, n9 u5 G8 B) j' m' q) P
        delay.h,声明微妙、毫秒、秒的延时函数。/ S3 I+ j* X$ K& {" z0 q
  1. #ifndef DELAY_DELAY_H_
    & p! N( u/ b. x3 f6 a* _
  2. #define DELAY_DELAY_H_
    & z) t6 H. |) z! D! q
  3. - S7 ?- ^( N7 y" g6 F6 S  R
  4. #include "stm32l4xx_hal.h" //HAL库文件声明6 b3 e  W% M( t* v" D6 s

  5. 6 V* S( k3 x5 c* Y
  6. void delay_us(uint32_t us);        //延时微妙! D' c  ^; K$ p9 t' M# E
  7. void delay_ms(uint32_t ms);        //延时毫秒; t3 r4 n! N9 [
  8. void delay_s(uint32_t s);        //延时秒
    * B9 G! i0 K# }
  9. " F* ]% R9 P  Y
  10. #endif /* DELAY_DELAY_H_ */
复制代码
8 B" S& i7 |% G' d( U; j2 g
        delay.c,7 Q* J6 r( D5 h9 e, {1 l5 U+ v
  1. #include "delay.h"
    ' F: U7 R! H5 P1 j, d
  2. & Z. v7 Z, _. f+ C
  3. #define MFP_VAL 8000000    //80MHz& h/ Q* ?2 a# }

  4. 9 P: A. f1 l. u# {8 \) A# n$ o
  5. void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数/ a( ~, R) f% Y0 u9 }
  6. {
    1 m* E, Q- N  h5 L$ o# G; G+ t
  7.     uint32_t delay = (HAL_RCC_GetHCLKFreq() /  MFP_VAL* us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数3 ~% E2 R! G4 P; A' R5 X
  8.     while (delay--); //循环delay次,达到1微秒延时
    : ], U7 Q" z  k# m
  9. }
    4 s+ M( s: e% Y5 H6 k$ \+ @
  10. $ G3 M% p8 t0 ~. x1 t6 I% h
  11. void delay_ms(uint32_t ms){ //mS毫秒级延时程序/ n! A! `; F' m+ ?! E# i) \
  12.         while( ms-- != 0){. M# Z  C8 p- f" W5 H: W; o
  13.                 delay_us(1000);        //调用1000微秒的延时8 \' K! O7 N' O$ l" H3 B) H8 b
  14.         }! c6 j4 G% W! r, l8 G% S5 a
  15. }" N0 ?6 r0 ]1 R$ S* A) e* D
  16. ' e- f7 h$ l) {: `1 j- V( Z( d
  17. void delay_s(uint32_t s){ //S秒级延时程序
    ) A2 P$ @! `6 _. S7 V
  18.         while( s-- != 0){4 H( F. d* {6 |. a2 B
  19.                 delay_ms(1000);        //调用1000毫秒的延时2 z: u' t) M9 n" ?! G2 M- R
  20.         }& B0 \4 q  Z4 q) R+ R( d7 {
  21. }
复制代码

, F- }; @2 ^& u4 K: _        3.3 WWDG使用程序设计4 _( J: ~+ S3 `: N
        在本博文中,我们设计通过按键切换喂狗时间间隔,来测试喂狗窗口及时间间隔效果。" v( r: J5 B1 w* F5 i: w+ {

/ _8 _# [( C. R& F% E' {2 l

5 _# ?7 [+ s* c        在main.c源文件中,添加驱动头文件,注意由于在CubeMX取消了自动初始化WWDG,因此需要手动添加wwdg.h头文件:
& O8 d# ~0 f& Z4 L! [! W6 \
  1. /* Private includes ----------------------------------------------------------*/
    + F6 i0 r6 ^; A8 \
  2. /* USER CODE BEGIN Includes */
    , }; |1 A& X8 O, f6 P6 {! i
  3. #include "wwdg.h"' X8 I" T- j: P+ ?- _: e. a2 }/ r$ X
  4. #include "../../ICore/key/key.h"
    # A7 q5 G. Y! a3 |
  5. #include "../../ICore/led/led.h"( d. ?# k  N6 |& V
  6. #include "../../ICore/print/print.h"% k, T! a) j. b  @3 A- l
  7. #include "../../ICore/usart/usart.h"
    " g5 U5 ]+ n, P9 n# p! G, v  h" R
  8. #include "../../ICore/delay/delay.h"
    * q; ?, x; L4 x; c* F) ?
  9. /* USER CODE END Includes */
复制代码

" h: j/ Z3 ^) o( p! i0 E2 D4 K        在main主函数前,声明WWDG句柄,用于喂狗函数是调用
) i0 y* ^% R/ f% P
  1. /* Private user code ---------------------------------------------------------*/
    2 t2 D+ Z# o5 R& r- G
  2. /* USER CODE BEGIN 0 */* @6 p/ J2 q0 B' f$ [
  3. extern WWDG_HandleTypeDef hwwdg;
    ( E- G# y% h2 X6 Y
  4. /* USER CODE END 0 */
复制代码

* J7 r; y' J3 K        在main主函数内,设置各外设功能及手动初始化WWDG驱动。" h9 c# ?3 v; `4 Y4 j2 R
  1.   /* Initialize all configured peripherals */
    $ E$ [  ?" ~0 `+ Q  M5 J
  2.   MX_GPIO_Init();
    : O- @  M9 v% D5 e5 b+ W
  3.   MX_LPUART1_UART_Init();6 J2 f. S( n* Z( }
  4.   /* USER CODE BEGIN 2 */
    9 s( ~# I, A/ x# H, v
  5.   ResetPrintInit(&hlpuart1);* J  |* |& D1 k- I
  6.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断/ H. z: b* }+ x) E# l1 `- C
  7.   HLPUSART_RX_STA = 0;& B0 B- r5 L0 `: {  u" K
  8.   //
    ( R: M% ?! ]  ]! w2 n$ _% u6 S
  9.   printf("app restart now!\r\n");3 I5 g: H7 Y. ^# _& |- s  D
  10.   uint8_t wdt_flag = 1;
    : D. ~% J+ b0 k
  11.   uint8_t printf_flag = 1;1 F5 g9 O8 @* C6 J& Y& I+ b
  12.   MX_WWDG_Init();, n' l" W- d: O/ ]5 H1 r! ^9 K
  13.   /* USER CODE END 2 */
复制代码
/ q- r  g% J+ y# N5 E& Q& X/ D4 q
        在main函数主循环体内,进行喂狗测试,默认是10微妙喂狗一次,按键0停止喂狗,按键1间隔10毫秒喂狗,按键2间隔1秒喂狗。注意前面计算得知0<t<117.9648ms内喂狗有效。按键1间隔10毫秒喂狗主要考虑到按键按下及松开时间效应问题,因此不能设置太大,否则可能因为按键动作耽搁时间太久无效。在实际项目中,我们通常会采用独立线程持续喂狗,各种异常触发打断喂狗来设计。
2 S# n! J  |6 ~6 b
  1. /* Infinite loop */
      ~3 [6 H8 S/ V2 Y
  2.   /* USER CODE BEGIN WHILE */) }: b8 M! V- Z
  3.   while (1)
    : X/ X; P, ~/ r/ z5 v
  4.   {/ H; p7 o. H+ F) Z( I
  5.           if(1==wdt_flag){
    2 X1 X5 w/ E' D, W2 a( n7 F
  6.                   HAL_WWDG_Refresh(&hwwdg);
    * h' V2 L" U2 Y! n2 J, [+ b& \  e
  7.                   delay_us(10);//等待  S3 I5 J& [# D
  8.           }/ X( d: i8 b$ E3 D+ L9 ]
  9.           if(2==wdt_flag){
      S8 y2 I" P3 q1 Q
  10.                   HAL_WWDG_Refresh(&hwwdg);
    3 X! i4 d7 Z2 Z8 D- p& O
  11.                     delay_ms(10);//等待
    & D8 ]0 ]# Z2 n1 N& h5 W, L! s7 w
  12.             }
    ' ~" k. l; W& ~# k7 X9 i+ u
  13.           if(3==wdt_flag){
      i6 Q4 n" ]9 _7 _4 {% M
  14.                   HAL_WWDG_Refresh(&hwwdg);
    % }( z6 U+ I, Q% t# Z" E/ O* |; ]
  15.                   delay_s(1);//等待, S) R1 s0 T6 G2 ]
  16.           }& U, I7 M: \# N+ ?' J0 Q
  17.           if(printf_flag)1 j7 w; s1 h; {! p  N, Z( N
  18.           {2 J% V) q' J+ Z; _2 `' \
  19.                   printf("current wdt_flag=%u!\r\n",wdt_flag);) E% e( I  P0 Y+ n
  20.                   printf_flag = 0;# O& \% G( h& w
  21.           }% k: V; B4 j  S) ~+ B
  22.           if(KEY_0())/ E% t1 I& V7 Q" r: j3 G, f5 P
  23.           {% c' v. l# O5 W, f0 E  F; x
  24.                   wdt_flag = 0;
    2 ~$ ~/ r0 x* p) H$ t
  25.                   printf("WWDG_Refresh stop!\r\n");5 ?# i2 y% `% y/ N
  26.                   delay_us(1);//等待1 A: [- b9 E9 q6 ]; y
  27.                   printf_flag =1;
    $ ^! A( J3 L! d. L& |; _( V2 U/ z
  28.           }" Z# x' b* U: ?4 W# U: Z$ j
  29.           if(KEY_1())5 W4 ?1 C% {3 n# j& N+ m
  30.             {
    0 e; B1 M* Q' x4 W1 s) Z7 s7 r
  31.                   wdt_flag = 2;0 E7 O7 u, T  G5 |8 h( j5 s( p& Z
  32.                   printf("WWDG_Refresh before WIN Time!\r\n");$ J/ a  k  h2 w* }5 ]' v9 B
  33.                   delay_us(1);//等待
    9 Z0 P/ N% x+ t/ R" J
  34.                   printf_flag =1;& p# M( ?, r# N7 c" ^+ K
  35.             }/ T" H5 {6 w. p! m5 U' n: H
  36.           if(KEY_2())2 F/ p3 \6 ~1 P/ J* p7 g
  37.             {
    1 c3 k8 m0 B. K  x5 G7 P: H; O
  38.                   wdt_flag = 3;
    2 k* e; Z8 Y: n6 \- T/ T" ~5 a" r/ m. I
  39.                   printf("WWDG_Refresh after 0X40 Time!\r\n");6 S: x" O9 {+ b8 R7 v; c$ |0 n: ?6 q
  40.                   delay_us(1);//等待
      L: M3 t4 S5 y, L: \3 h1 A/ B
  41.                   printf_flag =1;! Q! ]3 ?0 n+ A9 S4 A8 H3 ^
  42.             }7 R+ r8 F, X% E- P) O4 {9 c4 e+ [
  43.     /* USER CODE END WHILE */
复制代码
2 d5 v' s% B! b1 D2 v1 [4 e  F
四、编译及测试
0 Q, L# j9 }2 b  v. q* r* y        4.1 编译5 y; T- q) n" _) q0 c

8 e8 r9 s* K  X
d6fbffd0d40342e296933a45a64771c8.png
( w  Q$ L3 O4 g8 T# S" ]% C; ?( j) v! p( f2 b6 i+ H
, E/ K9 o" e& X) r; m
         4.2 测试
. }  C# ]8 T" c# {" K% X' y7 `- E( b
        打开串口助手,连接上开发板,按键0、1、2观察效果:
' U7 ^4 {) ^- t* X( G
# X& B& ^6 l! g3 K+ ]1 D
5886dd71a550426786ef791de6427f51.png 5 b& Q- M! e$ ]( k8 A4 U9 {2 `
0 L. i% T" m7 `
————————————————0 m: _: T2 e0 F: A% I
版权声明:py_free-物联智能) v1 i$ t* l2 N% g
如有侵权请联系删除3 d1 H* t4 |3 D! K! h+ `9 q! J( E! J

/ d- E6 w6 A5 \, C: m3 k: ]# m1 d  w4 L8 ]1 O. I( [1 |7 o9 k
013d642e04b445829bf93b4b52820792.png
赞 收藏 评论0 发布时间:2023-4-6 15:13

举报

0个回答

所属标签

相似技术帖

官网相关资源

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