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

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

[复制链接]
攻城狮Melo 发布时间:2023-4-6 15:13
一、stm32的WWDG说明
% a, a3 F; o. ?; ]4 _4 m6 L0 Z       1.1  WWDG特点:
0 V" Y" X6 D0 _: ^: o
        在前一篇博文介绍独立看门狗时就指出STM32 MCU提供两个看门狗,独立看门狗和窗口看门狗。
1 B0 a; i# U0 @) {, I! H5 O, e
- f7 ~  Q, C/ m! S        相比独立看门狗,窗口看门狗WWDG有以下特点:
  V! ?8 R& x; z3 g% F        【1】WWDG计数器依赖于系统时钟,准确来说依赖于系统时钟通过分频、倍频得到的PCLK1时钟,即APB1 peripheral clocks输出频率。
9 a1 b' T; P, J- `        【2】WWDG支持中断功能以及早期唤醒中断。
! h( r0 \! F7 p' l( h/ S
+ W7 d/ W' t) O5 E8 }+ I) F        1.2 WWDG的cubeMX配置及说明
. f0 f: q' }9 c- {1 W2 q& g* N        现在看一下WWDG在CubeMX中的设置问题,WWDG和IWDG一样,在系统内核栏目开启,开启激活选项后,可以设置5项参数,分别是计数时钟分频值,窗口值、递减计数预设值、早期唤醒中断使能以及中断功能。- E8 s' W; U+ P% R4 Y! @
98991825d78f4fbaa73212a13f1a399f.png
* F' Z( w4 U1 Z: C& K  s$ L/ T9 n* Y$ ^6 x' u4 n
        【1】 一旦WWDG启用,将生成系统重置功能并启动其递减计数器,喂狗时,必须在设定的上限时间和下限时间之间喂狗,如果喂狗时间高于上限时间或者低于下限时间,都会导致看门狗触发重启机制。其中下限时间是系统固定的0X40。上限时间(窗口值)是用户可以定义的,大于0X40同时小于0X7F即可。
# b; x% l& j9 ?, e: \( e  L
2 G, D5 }* `9 H
        【2】程序在达到0x3F值之前刷新计数器(计数器的低六位值,最大值111111=0X3F),到期时触发系统重置(即,当计数器值从0x40向下滚动到0x3F时生成重置,即再次减一时,0x40=0X3F+0X01)。并在计数器达到刷新窗口值之前刷新了计数器值,也会生成MCU重置。这就要求必须在有限的窗口中刷新计数器。另外WWDG启用后,除非通过系统重置,否则无法禁用WWDG。2 a8 ^5 w4 b8 K* R; ~6 e5 ?
. M' |# c! H2 D( @3 y
        【3】如果启用了早期唤醒中断(Early Wakeup Interrupt,EWI)功能,在WWDG到期之前发出警告(即计数器达到0x40时会产生中断)。使用早期唤醒中断(EWI),在生成MCU重置之前可执行特定的安全操作或数据记录。此机制要求在NVIC中启用WWDG中断设置。同样,EWI启用后,EWI中断不能被禁用,除非通过系统重置。中断状态感知可在RCC_CSR寄存器中的WWDGRST标志判断何时发生WWDG重置。3 r* Z' g. }5 u/ ?; x- A5 J
6 Q  B3 I7 A: O# i3 |* v1 j
: x3 \, y0 c3 [  }- G
        1.3 WWDG喂狗时间计算

! L5 a8 |# w' }0 a        WWDG计数器输入时钟由PCLK1频率(APB1 peripheral clocks输出频率)除以计数时钟分频值得出。
. l/ l) @  H6 J* g9 z' Y' [) O9 I' W) f1 b: D  {: @$ `0 H6 c  o
e61915a0f0ff49f69ba6ec1fa1697eef.png 3 r6 |$ a  |! |, P+ u4 v/ i* R2 _- T
; d* ~4 o' b8 I  G7 U6 o) a
         WWDG时钟(Hz)=PCLK1/(4096*预分频器);
- P9 L: M7 v1 M* E  d8 k: p8 C6 l' s
        WWDG周期(mS)=1000/WWDG时钟(Hz);5 n( e4 z1 w; C6 m9 j9 l/ g

5 \' T3 k% m) Z# T& A( v% M        WWDG超时MinT(mS)=WWDG周期(mS)*(计数器-窗口),因此最好设置递减计数值≥窗口值。! D( b3 }+ ^! |/ k. g6 D( L6 _
& ?1 v- t1 [8 D/ ]9 i
        WWDG超时MaxT(mS)=WWDG周期(mS)*(计数器-0x40),0x40=0X3F+0X01;5 @! O9 _7 ]4 l/ H

! o! e( [3 s6 K$ E& u        WWDG喂狗时间MinT(mS)<t<MaxT(mS)。
6 l+ V. [9 {3 ^1 l
, r! m9 A! w. m5 R" @
二、WWDG工程创建及源码分析
" h# t0 S  |* G) D  B# X6 B: I       2.1 cubeMX界面配置WWDG
: B4 r$ D  L6 A& o% }6 i3 o
         本博文基于前面独立看门狗的工程直接增加窗口看门狗功能,并关闭独立看门狗。% z. k$ v! j. P

3 _6 c8 {& i9 d% u4 j9 R  o' I        双击.ioc文件打开cubeMX界面,开启WWDG,设置其参数如下,其中分频值2,窗口值0X64(100),递减计数预设值0X64(100),开启早期唤醒中断:
4 T' D" ~1 F. v7 o4 V: x
5 D8 [9 z  Y, C
f1f7497080cd40f1853040eb75b2a652.png - c6 K2 Y3 {& a9 p  I

2 t/ a0 }; A' O  E5 M2 q         开启WWDG中断功能  ]. z  [" P' z% i

) r* W: w3 K2 L' {; e, Y2 |
261f23989a6b41498df65be316df09cf.png - X# g' Y; V. w: h" x
, q- l; t  U3 t( {1 ?+ _
         APB1时钟输出频率设置10MHz(10 000 000Hz),设置该值小一些,主要是本博文采用按键触发切换喂狗时间间隔,而按键捕获到松开是人为操作,反应较慢,实时性不好体现。. w+ M8 R# A% D
$ h# J, o. w( p/ z! F/ I
         2.2 WWDG超时时间实例计算, e& g3 u% W  s7 J$ f- ?
        在WWDG的喂狗时间按前面计算公式,喂狗时间范围:
; r" t7 w, l. `, S2 C
4 o% x, C$ Z- g9 B3 ?0 g        WWDG周期(mS)=1000ms/10MHz/(4096*8)=3.2768ms。
2 W) E7 j8 |8 @3 |! n
, J7 D/ v9 V- `: B        WWDG喂狗时间是在WWDG启动后的t时间内:
$ j  ^* q) _) ]2 p* z( C/ ^: ]2 C: o* B
        t>3.2768ms*(0X64-0X64)=0ms;5 c# `5 N2 p7 k
4 \5 m( G+ a1 O& T3 V& t
        t<3.2768ms*(0X64-0X40)=117.9648ms。
7 O5 K7 p7 z( u8 \8 A3 \! u3 J% }9 ^! t* J) U% H
1 g& w" [4 F/ k1 z0 z4 X
       2.3 工程高级配置
( T$ Z; d- t, L: w! z         在工程高级配置中,取消WWDG的自动初始化,本博文将自己添加初始化,主要是HLA的WWDG初始化启动就立即进入计数,会给第一次喂狗造成时间差异较大。3 A. }4 e1 L  i5 q8 j5 K) N: ?
  ]' t) W/ {4 E/ X( E! U  ]( T
1bfc3d8fa7d24e54a97dbc87ab8f4317.png
/ ~, o9 O7 L8 l. R) r- e
. A3 a: i2 k' ?        生成代码输出。
) @$ C3 x* v* z4 K  J
" ?% ~1 W; s& }: W三、WWDG源码分析及应用$ |1 Y( E( H+ E  t' n3 B  g) E
        3.1 WWDG的HLA库源码分析
( G6 k" U, u, u) s) e% U5 o& B6 T# Z
        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函数。
6 i# A" q% ^1 w9 a1 P+ }( r6 w8 c3 M- j3 [1 r5 q
2b4c2b5b42104381bb7a213382fff3ca.png
; T" s- G% s$ E# k& Y/ Z
, r+ ~# C6 @5 }+ ^/ G1 q$ z- l         在stm32l4xx_hal_wwdt.c源文件中定义了HAL_WWDG_Init函数,它做以下事情:诊断配置参数是否合规(如果不是采用CubeMX配置,而是自己手动配置或调整过参数的,这里可能异常);调用HAL_WWDG_MspInit函数完成WWDG时钟以及中断初始化;最后将依据参数写入WWDG寄存器。
) [- }& N: n: y% w+ O$ c0 `  b- Z
136b6b9e484a4fc2ad6b049467a4542a.png
; t+ s* d1 m7 x/ Y
. @& M+ ?0 C' z. R+ v  f/ _) R         程序在依据参数将WWDG计数器值写入WWDG寄存器CR,将窗口值和时钟分频值写入WWDG寄存器CFR内。- y/ U% q% J( W: r# f6 ?" X

+ M" `! ~! [! \& U" a
d799e52574e943baa64598274903a5ed.png $ Q! @+ V7 L( I6 N6 {

& e# h4 L% d+ @! J' L" L% Y/ g eb67a4bdb772428e92f464444c98c2a1.png
! l, `' n! W4 Q, G2 N# K( }# D1 m5 Y8 l
         再回到wwdg.c内,HAL_WWDG_MspInit函数实现了WWDG时钟启动设置和中断初始及启动设置。
* ^) w- p; _: z2 D: u' ?, S! c/ c1 d- z
d081f9832148473daa7a3f8b7bb2009c.png
' e  F2 _& W! b3 g) A, f' G
7 @# @& a3 Y# R' |8 T         HAL_NVIC_EnableIRQ启动后,如果有WWDG中断事件时,当中断服务例程触发HAL_WWDG_IRQHandler时,将自动清除标志,并执行HAL_WWDG_WakeupCallback用户回调函数报警。该回调函数在stm32l4xx_hal_wwdt.c定义,是个弱函数,用户可以通过自定义回调AL_WWDG_WakeupCallback来添加自己的代码。例如本文将在wwdg.c文件内重新定义该函数:9 \* }" I' j3 j" W  R* f! h
  1. /* USER CODE BEGIN 1 */$ Z9 ^0 T4 p4 |6 I/ [
  2. void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
    2 }" M; m- Y; L! W+ o; J; y
  3. {
    8 C1 ~( E0 r( d. K- x  {' e) G0 ?
  4.         printf("I know, but do nothing!\r\n");( n: c9 C! h  i% d6 e( O
  5. }# {' x! L: [3 u5 Z; t0 J: a
  6. /* USER CODE END 1 */
复制代码
5 }$ y& F3 N; N- z" p3 L% x' A
         3.2 延时函数设计
# J( V, T4 E- n        在ICore目录下添加delay目录,并在该目录下创建delay.h和delay.c源文件,实现自定义延时函数,主要满足本博文更高精度的延时要求。3 ^# b, q: }5 c) ^- a6 f

7 a* C1 r- d9 w8 B# G; ?        delay.h,声明微妙、毫秒、秒的延时函数。
" M$ G' n8 o* R  G
  1. #ifndef DELAY_DELAY_H_
    : x+ {; s' A9 D- r# ^
  2. #define DELAY_DELAY_H_
    ) g6 x( ^, [8 d6 q
  3. 5 x9 z5 O1 z. _
  4. #include "stm32l4xx_hal.h" //HAL库文件声明
    3 j3 G. X8 N' }) h- M
  5. + Q' t; D/ @/ Z+ Q( }; j! j
  6. void delay_us(uint32_t us);        //延时微妙  |8 Q% \2 L6 h0 ?; j, k' X" ^
  7. void delay_ms(uint32_t ms);        //延时毫秒
    8 x- U- R: m5 ~  q
  8. void delay_s(uint32_t s);        //延时秒
    & B) d2 A5 g+ D9 }  X% X* Y

  9. - |* J7 _$ Y% s# F3 t5 q3 I9 p3 W5 z& {
  10. #endif /* DELAY_DELAY_H_ */
复制代码
% f/ N* [( e1 N# J' l
        delay.c,$ A( D( k2 X& w, I8 Y% |' p8 e# y
  1. #include "delay.h"
    / E4 c# J0 D- V; N6 y

  2. $ {8 {3 q. u8 P9 j
  3. #define MFP_VAL 8000000    //80MHz- ?( t( r9 k- I& R" y* g) _* r

  4. . H, D- P2 F- A$ S
  5. void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数& c0 v1 s. s' K* J5 ?
  6. {
    : G/ d' ?8 ]0 X. [- t
  7.     uint32_t delay = (HAL_RCC_GetHCLKFreq() /  MFP_VAL* us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数/ A0 |9 _% F* ]; W& Q+ j- O
  8.     while (delay--); //循环delay次,达到1微秒延时6 @+ h/ }) J! p- {
  9. }) {, ~* y3 k: P

  10. 9 S: _& p3 n) D- n% L* m1 \
  11. void delay_ms(uint32_t ms){ //mS毫秒级延时程序/ A5 H* z" ?& ]. }
  12.         while( ms-- != 0){# ]2 r2 v, p. i# F
  13.                 delay_us(1000);        //调用1000微秒的延时
    7 U# s% h7 x3 H0 m! w
  14.         }% V4 S! p7 G" P4 _
  15. }* [& D6 f& L  }2 a% ?, G

  16. # A% R" U$ h4 r5 T
  17. void delay_s(uint32_t s){ //S秒级延时程序+ `* i/ E9 ^5 S* h
  18.         while( s-- != 0){4 O7 L2 d0 N/ T7 k  _- u* ^3 s
  19.                 delay_ms(1000);        //调用1000毫秒的延时
    ' Y( l5 }$ b3 \4 `6 [1 `' v
  20.         }
      d8 C( }( i4 x. H- c
  21. }
复制代码

$ U; U. Z! U# ~9 u2 Y        3.3 WWDG使用程序设计+ \! Y3 w% V/ d5 s
        在本博文中,我们设计通过按键切换喂狗时间间隔,来测试喂狗窗口及时间间隔效果。1 U* [: f  V7 I; Y
" I  L/ z. j! ]+ S( }

1 \9 Y, ~0 l- x# N3 j8 }# J! l        在main.c源文件中,添加驱动头文件,注意由于在CubeMX取消了自动初始化WWDG,因此需要手动添加wwdg.h头文件:
2 N4 g% Y: _$ t# O0 |% }
  1. /* Private includes ----------------------------------------------------------*/
    % J1 l& ]! ^% f1 \
  2. /* USER CODE BEGIN Includes */: m, f+ p+ I% v$ @# R0 H
  3. #include "wwdg.h"* K9 r  |* ?; d4 D8 @' \
  4. #include "../../ICore/key/key.h"( |& B% A* B0 T( B8 g; r) s
  5. #include "../../ICore/led/led.h"
    1 F$ S- c6 _3 ~
  6. #include "../../ICore/print/print.h"" f0 ]/ F: c# _
  7. #include "../../ICore/usart/usart.h"' I% D& n4 ?5 Z! s  m
  8. #include "../../ICore/delay/delay.h"
    ( S0 H+ z, N0 R. G
  9. /* USER CODE END Includes */
复制代码
* Q+ P3 Y( F+ W% z& V9 {
        在main主函数前,声明WWDG句柄,用于喂狗函数是调用8 u5 ]% v  G8 u  {; l  g
  1. /* Private user code ---------------------------------------------------------*/
    . A  i7 ~/ K2 Q5 e0 c" N4 M2 ?
  2. /* USER CODE BEGIN 0 */. m9 d& h. y+ `* c1 L
  3. extern WWDG_HandleTypeDef hwwdg;9 Q/ V: ?  E, P7 k1 N! m+ C* b
  4. /* USER CODE END 0 */
复制代码
3 Y3 m; K, H; a6 r$ u8 V8 E
        在main主函数内,设置各外设功能及手动初始化WWDG驱动。
- z  V8 {: |; S# s
  1.   /* Initialize all configured peripherals */  r* F5 M2 \, K
  2.   MX_GPIO_Init();8 ~- Y! w4 W& z: i3 p, y! A. I
  3.   MX_LPUART1_UART_Init();
    5 o  |2 S. D2 D$ ]
  4.   /* USER CODE BEGIN 2 */
    0 ~  A0 d6 F4 x- w) V
  5.   ResetPrintInit(&hlpuart1);0 N# N% s; D  ]# ]: E* E
  6.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断# r4 ]; v, \1 i; `( U$ _3 q
  7.   HLPUSART_RX_STA = 0;
    % w3 C3 A8 w* ?; o2 S
  8.   //* A6 j, k" E  c
  9.   printf("app restart now!\r\n");: w  P3 J# m4 f* N+ @- E
  10.   uint8_t wdt_flag = 1;+ }8 e& f9 n" O
  11.   uint8_t printf_flag = 1;
    2 R1 L0 d$ A# A; v  ^
  12.   MX_WWDG_Init();
    - c  s, d! ]! C/ o4 ]
  13.   /* USER CODE END 2 */
复制代码

4 L0 a% E% ?. @8 c9 r% n; ?6 Y. _        在main函数主循环体内,进行喂狗测试,默认是10微妙喂狗一次,按键0停止喂狗,按键1间隔10毫秒喂狗,按键2间隔1秒喂狗。注意前面计算得知0<t<117.9648ms内喂狗有效。按键1间隔10毫秒喂狗主要考虑到按键按下及松开时间效应问题,因此不能设置太大,否则可能因为按键动作耽搁时间太久无效。在实际项目中,我们通常会采用独立线程持续喂狗,各种异常触发打断喂狗来设计。+ z5 A6 r0 G1 H' p
  1. /* Infinite loop */
    ! Y" q, ]' d- j4 g) ~# R
  2.   /* USER CODE BEGIN WHILE */% K: y+ D1 q' t
  3.   while (1)
    + e& K5 T6 m6 |$ T1 F: L
  4.   {: I( Y" [7 G' R8 ?: J  N: V
  5.           if(1==wdt_flag){( T1 d4 \% y3 x' b; p2 f8 |  Y, k
  6.                   HAL_WWDG_Refresh(&hwwdg);
    0 O0 h  x2 D# n. I
  7.                   delay_us(10);//等待
    7 Y+ w8 d( N7 y( V5 x
  8.           }* O' h2 X4 X; l6 b4 \( ~6 Q- B
  9.           if(2==wdt_flag){
    & s2 @# V+ x7 y
  10.                   HAL_WWDG_Refresh(&hwwdg);0 [. z/ H% P  q* C* q3 M5 ?
  11.                     delay_ms(10);//等待
    . O4 J8 a6 \. x6 R, {
  12.             }- E% n% M" \3 _  W9 c
  13.           if(3==wdt_flag){" G0 r7 _2 [9 O
  14.                   HAL_WWDG_Refresh(&hwwdg);  P0 U4 q+ ]. J' A" v. @
  15.                   delay_s(1);//等待6 I7 n" d7 K1 F9 v3 `; D1 _
  16.           }
    4 e  i2 n! Z) Y, O2 `" k
  17.           if(printf_flag)4 g) a" ]4 w0 x( v' N
  18.           {  M" z( Y6 z2 M. v
  19.                   printf("current wdt_flag=%u!\r\n",wdt_flag);
    $ G$ ~8 H0 g$ h/ O
  20.                   printf_flag = 0;. p0 r7 E5 i2 @( w2 `0 a5 u3 H& k
  21.           }* F4 E0 s3 P/ d& E6 z
  22.           if(KEY_0()); t% u$ m+ O9 f' n
  23.           {+ H# z3 M$ k' C/ e; o' ^; V  m
  24.                   wdt_flag = 0;
    5 Y1 y6 v+ ]7 j# z
  25.                   printf("WWDG_Refresh stop!\r\n");
    ( L& I' X0 d; Z" B- U& a
  26.                   delay_us(1);//等待
    2 [* X6 o/ m4 o0 D, i
  27.                   printf_flag =1;0 b* d5 B& S5 i( [# ^: J* \/ v+ y$ T
  28.           }' L$ m1 |+ W$ D# {: m1 }" r
  29.           if(KEY_1())+ }& [/ v+ r) I. e, o" y; p
  30.             {
    . ~% J) x8 W, U; v! K6 X9 n
  31.                   wdt_flag = 2;# [$ K4 X7 k9 {' e: G$ }
  32.                   printf("WWDG_Refresh before WIN Time!\r\n");. x! Q; n& j; M! o. l
  33.                   delay_us(1);//等待
    . {1 H6 V; V* C7 ?7 ]+ h7 `
  34.                   printf_flag =1;$ ~' V1 C. B/ [3 d7 ]
  35.             }  k2 B8 c2 g7 T4 A3 A+ n' {
  36.           if(KEY_2())
    6 n# D  P* V6 @5 v* X% B; z0 A
  37.             {
    4 x% R0 [$ X4 @* v+ K& C* K
  38.                   wdt_flag = 3;
    % o. k$ y9 Q* ~! q$ A; P1 K  w
  39.                   printf("WWDG_Refresh after 0X40 Time!\r\n");
    1 ?( x' E3 S5 M1 c& h% U
  40.                   delay_us(1);//等待) p# C) u" X0 Q) A+ ~( S
  41.                   printf_flag =1;8 P0 q  K+ I' q3 _$ o8 r
  42.             }
    , i- m' _9 S7 N: E4 e6 I5 q
  43.     /* USER CODE END WHILE */
复制代码

" O' _7 V# A2 F' u" G/ |" g; h四、编译及测试$ f2 `/ _* J1 x; l
        4.1 编译' I5 y4 ~5 J$ y! P, a; y, D0 Z$ C
; p0 Z& x! a8 ]
d6fbffd0d40342e296933a45a64771c8.png , e! H% J% B! f9 h
$ e. U1 z8 T5 W4 V- |6 s

7 ]0 Y$ r0 `/ u2 j! P         4.2 测试
+ i& F, S1 _0 u: N0 s, [
        打开串口助手,连接上开发板,按键0、1、2观察效果:
: M. v. h( g# z$ Y' S0 z/ p! }0 ]
9 e" e# K$ G, `( K
5886dd71a550426786ef791de6427f51.png
2 l; f" H4 d: M8 z9 T- k, `( c2 ]0 _4 i1 L8 Y+ L6 ~4 b" D6 K5 z  W
————————————————1 M' l& W2 f, D! {- Z
版权声明:py_free-物联智能
" C' n  I& ^* J2 P. A8 N如有侵权请联系删除/ F/ J. t/ ^0 M4 t

' }$ @! h, N5 l8 j' `' S& w5 w6 ~0 G& s
013d642e04b445829bf93b4b52820792.png
收藏 评论0 发布时间:2023-4-6 15:13

举报

0个回答

所属标签

相似技术帖

官网相关资源

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