iT邦幫忙

2021 iThome 鐵人賽

DAY 28
0
Arm Platforms

基於ARM-M0架構MCU之落摔檢測韌體開發系列 第 28

[DAY 28] _看門狗簡介_視窗看門狗(2)

昨天主要介紹了視窗看門狗和獨立看門狗的差別,今天來看這如何計算,這計算方式再參考手冊裡面有舉例說明,如下圖:
https://ithelp.ithome.com.tw/upload/images/20211011/20141979i3lHJcz5kw.png
從圖的下方可以看到,他已Tpclk=48MHz來舉例,最下有個式子48000k,這手冊沒標示出來我也不知道位什麼?或許這是常識?...哈哈剛開始懷疑了一下子為甚麼是48000,經過按計算機才確定那是指48M分之1。

WWDG如何用:

WWDG一般用來監測外部干擾或不可預見的邏輯條件,造成的應用程式背離正常的運行序列而產生的軟體故障。
假設一個程式段正常運行的時間是50ms,在運行完這個段程式之後緊接著進行喂狗,如果在規定的時間視窗內還沒有喂狗,那就說明我們監控的程式出故障了,那麼就會產生系統重置,讓程式重新運行。

WWDG實驗:

硬體需兩個LED來觀看餵狗狀態。

bsp_wwdg.h

#ifndef __WWDG_H
#define	__WWDG_H

#include "stm32f0xx.h"

void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv);
void WWDG_Feed(void);

#endif 

宣告兩個函式,初始化WWDG,餵狗

再來看中斷的部分

stm32f4xx_it.c

void WWDG_IRQHandler(void)
{
	// 清除中斷標誌位元
	WWDG_ClearFlag();
	
	//黃燈亮,點亮LED只是示意性的操作,
	//真正使用的時候,這裡應該是做最重要的事情
	LED1_ON; 
}

bsp_wwdg.c

#include "./wwdg/bsp_wwdg.h"   

static uint8_t wwdg_cnt;             //用於記錄看門狗 遞減計數器的值,方便喂狗函數直接使用

static void WWDG_NVIC_Config(void)   // WWDG 中斷優先順序初始化
{
  NVIC_InitTypeDef NVIC_InitStructure; 
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 
  NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

在遞減計數器減到0X40的時候,我們開啟了提前喚醒中斷,這個中斷我們稱它為死前中斷或者叫遺囑中斷,在中斷函數裡面我們應該出來,是很重要的事情而且必須得快,因為遞減計數器再減一次,就會產生系統重置。

void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv)
{	
	wwdg_cnt = tr;   //保存CNT配置,用在喂狗函數
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // 開啟 WWDG 時鐘

	WWDG_SetPrescaler(prv);              // 設置預分頻器的值
	WWDG_SetWindowValue(wr);             // 設置上視窗值              
	WWDG_Enable(tr);	                 // 設置計數器的值,使能WWDG
	WWDG_ClearFlag();	                 // 清除提前喚醒中斷標誌位元
	WWDG_NVIC_Config();	 	             // 配置WWDG中斷優先順序
	WWDG_EnableIT();                     // 開WWDG 中斷
}
void WWDG_Feed(void)   // 喂狗
{
	WWDG_SetCounter( wwdg_cnt ); // 喂狗,刷新遞減計數器的值,設置成最大WDG_CNT=0X7F
}

void WWDG_Config,來解釋這函式裡的三個數值要填怎樣的數值
WWDG 配置函數
tr :遞減計時器的值, 取值範圍為:0x7f~0x40,超出範圍會直接復位
wr :視窗值,取值範圍為:0x7f~0x40
prv:預分頻器值,取值可以是
WWDG_Prescaler_1: WWDG counter clock = (PCLK1(45MHz)/4096)/1 約10968Hz 91us
WWDG_Prescaler_2: WWDG counter clock = (PCLK1(45MHz)/4096)/2 約5484Hz 182us
WWDG_Prescaler_4: WWDG counter clock = (PCLK1(45MHz)/4096)/4 約2742Hz 364us
WWDG_Prescaler_8: WWDG counter clock = (PCLK1(45MHz)/4096)/8 約1371Hz 728us
例:tr = 127(0x7f,tr的最大值) wr = 80(0x50, 0x40為最小wr最小值) prv = WWDG_Prescaler_8~728 * (127-80) = 34.2ms < 刷新窗口 < ~728 * 64 = 46.6ms也就是說調用WWDG_Config進行這樣的配置,若在之後的34.2ms前喂狗,系統會重定,在46.6ms後沒有喂狗,系統也會重定。需要在刷新視窗的時間內喂狗,系統才不會重定。再來看main.c

main.c

#include "stm32f0xx.h"
#include "bsp_led.h" 
#include "bsp_wwdg.h"

int main(void)
{
    uint8_t wwdg_tr, wwdg_wr;
	LED_GPIO_Config();  // LED_GPIO初始化
	
	LED2_ON();   //LED2量
	delay_ms(20); 

	WWDG_Config(127,80,WWDG_Prescaler_8); // 初始化WWDG
    wwdg_wr = WWDG->CFR & 0X7F;   //視窗值我們在初始化的時候設置成0x5F,這個值不會改變
	while(1)
	{
	  LED2(OFF);
      
	  wwdg_tr = WWDG->CR & 0X7F;
	  if( wwdg_tr < wwdg_wr )
	  {
	   WWDG_Feed(); // 喂狗,重新設置計數器的值為最大0X7F
	  }
	}
}

燒入後的動作:
把編譯好的程式下載到開發板,LED2 被點亮一段時間之後熄滅,之後LED2 一直就沒有被點亮過,說明系統沒有產生重定,如果產生重置的話LED2會再被點亮一次。中斷服務程式中的LED1也沒被點亮過,說明喂狗正常。

看門狗的介紹就到這了,目前我在練習韌體還沒實際用到這個功能。


上一篇
[DAY 27] _看門狗簡介_視窗看門狗(1)
下一篇
[DAY 29] _STM32_內部Flash
系列文
基於ARM-M0架構MCU之落摔檢測韌體開發32

尚未有邦友留言

立即登入留言