開發(fā)環(huán)境:
MDK:Keil 5.30
開發(fā)板:GD32F207I-EVAL
MCU:GD32F207IK
GD32 有兩個看門狗, 一個是獨(dú)立看門狗,另外一個是窗口看門狗 ,獨(dú)立看門狗號稱寵物狗,窗口看門狗號稱警犬,本章我們主要分析這兩只看門狗的功能框圖和它的應(yīng)用。
1 獨(dú)立看門狗
1.1 獨(dú)立看門狗工作原理
獨(dú)立看門狗用通俗一點(diǎn)的話來解釋就是一個 12 位的遞減計(jì)數(shù)器, 當(dāng)計(jì)數(shù)器的值從某個值一直減到 0 的時候,系統(tǒng)就會產(chǎn)生一個復(fù)位信號,即 IWDG_RESET 。如果在計(jì)數(shù)沒減到 0 之前,刷新了計(jì)數(shù)器的值的話,那么就不會產(chǎn)生復(fù)位信號,這個動作就是我們經(jīng)常說的__喂狗__。 看門狗功能由 VDD 電壓域供電,在停止模式和待機(jī)模式下仍能工作 。
獨(dú)立看門狗由內(nèi)部專門的 40Khz 低速時鐘驅(qū)動,即使主時鐘發(fā)生故障,它也仍然有效 。這里需要注意獨(dú)立看門狗的時鐘是一個內(nèi)部 RC 時鐘,所以并不是準(zhǔn)確的 40Khz,而是在 30~60Khz 之間的一個可變化的時鐘,只是我們在估算的時候,以 40Khz 的頻率來計(jì)算,看門狗對時間的要求不是很精確,所以,時鐘有些偏差,都是可以接受的。
獨(dú)立看門狗的架構(gòu)是很簡單的,本質(zhì)就是一個遞減計(jì)數(shù)器,和Systick有些類似,只是運(yùn)行在低速時鐘下,另外還有寄存器訪問保護(hù)功能。
【注】看門狗功能處于VDD供電區(qū),即在深度睡眠和待機(jī)模式時仍能正常工作。
FWDGT最適合應(yīng)用于那些需要看門狗作為一個在主程序之外,能夠完全獨(dú)立工作,并且對時間精度要求較低的場合。WWDGT最適合那些要求看門狗在精確計(jì)時窗口起作用的應(yīng)用程序。
【注】這些時間是按照40kHz時鐘給出。實(shí)際上,MCU內(nèi)部的RC頻率會在30kHz到60kHz之間變化。此外,即使RC振蕩器的頻率是精確的,確切的時序仍然依賴于APB接口時鐘與RC振蕩器時鐘之間的相位差,因此總會有一個完整的RC周期是不確定的。通過對IRC40K進(jìn)行校準(zhǔn)可獲得相對精確的看門狗超時時間。
1.2 獨(dú)立看門狗的寄存器描述
首先是鍵值寄存器FWDGT_CTL,該寄存器的各位描述如下圖所示。
在鍵值寄存器(FWDGT_CTL)中寫入 0xCCCC,開始啟用獨(dú)立看門狗;此時計(jì)數(shù)器開始從其復(fù)位值 0xFFF 遞減計(jì)數(shù)。當(dāng)計(jì)數(shù)器計(jì)數(shù)到末尾 0x000 時,會產(chǎn)生一個復(fù)位信號(FWDGT_RESET)。無論何時,只要鍵寄存器FWDGT_CTL中被寫入 0xAAAA,F(xiàn)WDGT_RLD中的值就會被重新加載到計(jì)數(shù)器中從而避免產(chǎn)生看門狗復(fù)位 。
FWDGT_PSC和FWDGT_RLD寄存器具有寫保護(hù)功能。要修改這兩個寄存器的值,必須先向FWDGT_CTL寄存器中寫入 0x5555。將其他值寫入這個寄存器將會打亂操作順序,寄存器將重新被保護(hù)。重裝載操作(即寫入 0xAAAA)也會啟動寫保護(hù)功能。預(yù)分頻寄存器(FWDGT_PSC)用來設(shè)置看門狗時鐘的分頻系數(shù)。重裝載寄存器用來保存重裝載到計(jì)數(shù)器中的值,該寄存器也是一個 32位寄存器,但是只有低 12 位是有效的。
1.3 獨(dú)立看門狗的具體代碼實(shí)現(xiàn)
獨(dú)立看門狗一般用來檢測和解決由程序引起的故障 ,比如一個程序正常運(yùn)行的時間是50ms,在運(yùn)行完這段程序之后緊接著進(jìn)行喂狗,我們設(shè)置獨(dú)立看門狗的定時溢出時間為60ms,比我們需要監(jiān)控的程序 50ms 多一點(diǎn),如果超過 60ms 還沒有喂狗,那就說明我們監(jiān)控的程序出故障了,跑飛了,那么就會產(chǎn)生系統(tǒng)復(fù)位,讓程序重新運(yùn)行。
獨(dú)立看門的啟動過程可以按如下步驟實(shí)現(xiàn)。
1)取消寄存器寫保護(hù)(向FWDGT_CTL寫入 0X5555)
通過這步,我們?nèi)∠鸉WDGT_PSC和FWDGT_RLD的寫保護(hù),使后面可以操作這兩個寄存器,設(shè)置FWDGT_PSC和FWDGT_RLD的值。 這在庫函數(shù)中的實(shí)現(xiàn)函數(shù)是:
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
這個函數(shù)非常簡單,顧名思義就是開啟/取消寫保護(hù),也就是使能/失能寫權(quán)限。這里的IWDG_WriteAccess_Enable的值就是0x5555,而IWDG_WriteAccess_Disable就是0x0000。
2)設(shè)置獨(dú)立看門狗的預(yù)分頻系數(shù)和重裝載值
設(shè)置看門狗的分頻系數(shù)的函數(shù)是:
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler); //設(shè)置 IWDG 預(yù)分頻值
設(shè)置看門狗的重裝載值的函數(shù)是:
void IWDG_SetReload(uint16_t Reload); //設(shè)置 IWDG 重裝載值
設(shè)置好看門狗的分頻系數(shù) prer 和重裝載值就可以知道看門狗的喂狗時間(也就是看門狗溢出時間),該時間的計(jì)算方式為:
Tout=((4×2^prer) ×rlr) /40
其中 Tout 為看門狗溢出時間(單位為 ms); prer 為看門狗時鐘預(yù)分頻值(FWDGT_PSC值),范圍為 0~7;rlr為看門狗的重裝載值(FWDGT_RLD的值);
比如我們設(shè)定 prer 值為 4, rlr 值為 625,那么就可以得到 Tout=64×625/40=1000ms,這樣,看門狗的溢出時間就是 1s,只要你在一秒鐘之內(nèi),有一次寫入 0XAAAA 到FWDGT_CTL,就不會導(dǎo)致看門狗復(fù)位(當(dāng)然寫入多次也是可以的)。這里需要提醒大家的是,看門狗的時鐘不是準(zhǔn)確的 40Khz,所以在喂狗的時候,最好不要太晚了,否則,有可能發(fā)生看門狗復(fù)位。
3) 啟動看門狗(向FWDGT_CTL寫入 0XCCCC)
庫函數(shù)里面啟動獨(dú)立看門狗的函數(shù)是:
IWDG_Enable(); //使能 IWDG
通過這句,來啟動GD32 的看門狗。注意FWDGT在一旦啟用,就不能再被關(guān)閉!想要關(guān)閉,只能重啟,并且重啟之后不能打開FWDGT,否則問題依舊,所以在這里提醒大家,如果不用 FWDGT的話,就不要去打開它,免得麻煩。
4)重載計(jì)數(shù)值喂狗(向FWDGT_CTL寫入 0XAAAA)
庫函數(shù)里面重載計(jì)數(shù)值的函數(shù)是:
IWDG_ReloadCounter(); //按照 IWDG 重裝載寄存器的值重裝載 IWDG 計(jì)數(shù)器
通過這句,將使GD32重新加載FWDGT_RLD的值到看門狗計(jì)數(shù)器里面,即實(shí)現(xiàn)獨(dú)立看門狗的喂狗操作。
因此獨(dú)立看門狗的配置如下:
/**
* @brief 看門狗初始化
* @param None
* @retval None
*/
void fwdgt_configuration(void)
{
//使能寄存器 寫功能
fwdgt_write_enable();
//設(shè)置預(yù)分頻 40K/64=0.625k 一個周期是 1.6ms
//設(shè)置初值
fwdgt_config(800, FWDGT_PSC_DIV64); //800*1.6ms=1.28S
//喂狗
fwdgt_counter_reload();
//使能獨(dú)立看門狗
fwdgt_enable();
}
主函數(shù)如下:
/*
brief main function
param[in] none
param[out] none
retval none
*/
int main(void)
{
/* systick init*/
sysTick_init();
//usart init 115200 8-N-1
com_init(COM1, 115200, 0, 1);
/*獨(dú)立看門狗初始化*/
fwdgt_configuration();
printf("Independent watchdog
");
while(1)
{
//喂狗
fwdgt_counter_reload();
printf("
Feed the dog
");
delay_ms(800);
}
}
主函數(shù)很簡單,初始化獨(dú)立看門狗后,在主循環(huán)里不斷喂狗即可。
1.4 獨(dú)立看門狗實(shí)現(xiàn)現(xiàn)象
編譯無誤,打開串口,現(xiàn)象如下:
當(dāng)注釋掉喂狗語句后,板子就會不斷重啟,因?yàn)闆]有喂狗就導(dǎo)致板子不斷復(fù)位。
2 窗口看門狗
2.1 窗口看門狗工作原理
窗口看門狗通常被用來監(jiān)測,由外部干擾或不可預(yù)見的邏輯條件造成的應(yīng)用程序背離正常的運(yùn)行序列而產(chǎn)生的軟件故障 。窗口看門狗跟獨(dú)立看門狗一樣,也是一個遞減計(jì)數(shù)器不斷的往下遞減計(jì)數(shù),當(dāng)減到一個__固定值 0X40 時還不喂狗的話,產(chǎn)生復(fù)位,這個值叫窗口的下限, 是固定的值,不能改變。這個是跟獨(dú)立看門狗類似的地方,不同的地方是窗口看門狗的計(jì)數(shù)器的值在減到某一個數(shù)之前喂狗的話也會產(chǎn)生復(fù)位,這個值叫窗口的上限,上限值由用戶獨(dú)立設(shè)置。因此__窗口看門狗計(jì)數(shù)器的值必須在上窗口和下窗口之間才可以喂狗 ,除非遞減計(jì)數(shù)器的值在T6位變成0前被刷新,看門狗電路在達(dá)到預(yù)置的時間周期時,會產(chǎn)生一個MCU復(fù)位。在遞減計(jì)數(shù)器達(dá)到窗口寄存器數(shù)值之前,如果7位的遞減計(jì)數(shù)器數(shù)值(在控制寄存器中)被刷新,那么也將產(chǎn)生一個MCU復(fù)位。這表明遞減計(jì)數(shù)器需要在一個有限的時間窗口中被刷新。
窗口看門狗時鐘來自 PCLK1, PCLK1 最大是60M,由 RCC 時鐘控制器開啟。計(jì)數(shù)器時鐘由 CK 計(jì)時器時鐘經(jīng)過預(yù)分頻器分頻得到,分頻系數(shù)由配置寄存器 CFG的位 8:7 PSC[1:0]配置,可以是[0,1,2,3],其中 CK 計(jì)時器時鐘=PCLK1/4096,除以 4096是手冊規(guī)定的,沒有為什么。所以計(jì)數(shù)器的時鐘 CNT_CK=PCLK1/4096/(2^ PSC),這就可以算出計(jì)數(shù)器減一個數(shù)的時間 T= 1/CNT_CK = Tpclk1 * 4096 * (2^ PSC)
窗口看門狗的計(jì)數(shù)器是一個遞減計(jì)數(shù)器,共有 7 位,其值存在控制寄存器 CTL的位 6:0,即 CNT[6:0],當(dāng) 7 個位全部為 1 時是 0X7F,這個是最大值,當(dāng)遞減到 CNT6 位變成 0 時,即從0X40 變?yōu)?0X3F 時候,會產(chǎn)生看門狗復(fù)位。這個值 0X40 是看門狗能夠遞減到的最小值,所以計(jì)數(shù)器的值只能是: 0X40~0X7F 之間 ,實(shí)際上真正用來計(jì)數(shù)的是 CNT[5:0]。當(dāng)遞減計(jì)數(shù)器遞減到 0X40 的時候,還不會馬上產(chǎn)生復(fù)位,如果使能了提前喚醒中斷:WWDGT_CFG寄存器的EWIE位置 1,則產(chǎn)生提前喚醒中斷,如果真進(jìn)入了這個中斷的話,就說明程序肯定是出問題了,進(jìn)入中斷后就是作重要的一些保護(hù)操作,如保存數(shù)據(jù)等。
我們知道窗口看門狗必須在計(jì)數(shù)器的值在一個范圍內(nèi)才可以喂狗,其中下窗口的值是固定的 0X40,上窗口的值可以改變,具體的由配置寄存器 CFG的位 6:0 WIN[6:0]設(shè)置。其值必須大于 0X40,如果小于或者等于 0X40 就是失去了窗口的價(jià)值,而且也不能大于計(jì)數(shù)器的值,所以必須得小于 0X7F。因此我們設(shè)置的窗口上限值在0X40-0X7F之間。
上窗口時間:T_min = 4096 * (2^ PSC)*(T - W + 1)/60 (us)
下窗口時間:T_max = 4096 * (2^ PSC)*(T - 0x40 + 1)/60 (us)
2.2 窗口看門狗的寄存器描述
首先介紹控制寄存器(WWDGT_CTL),該寄存器的各位描述如圖所示。
可以看出,這里我們的WWDGT_CTL只有低八位有效,CNT[6:0]用來存儲看門狗的計(jì)數(shù)器值,隨時更新的,每個窗口看門狗計(jì)數(shù)周期(4096×2^ PSC)減 1。當(dāng)該計(jì)數(shù)器的值從 0X40 變?yōu)?0X3F 的時候,將產(chǎn)生看門狗復(fù)位。WDGTEN位則是看門狗的激活位,該位由軟件置 1,以啟動看門狗,并且一定要注意的是該位一旦設(shè)置,就只能在硬件復(fù)位后才能清零了。
窗口看門狗的第二個寄存器是配置寄存器(WWDGT_CFG),該寄存器的各位及其描述如圖所示。
該寄存器中的 EWIE是提前喚醒中斷,也就是在快要產(chǎn)生復(fù)位的前一段時間(CNT[6:0]=0X40) 來提醒我們,需要進(jìn)行喂狗了,否則將復(fù)位!因此,我們一般用該位來設(shè)置中斷,當(dāng)窗口看門狗的計(jì)數(shù)器值減到 0X40 的時候,如果該位設(shè)置,并開啟了中斷,則會產(chǎn)生中斷,我們可以在中斷里面向WWDGT_CTL重新寫入計(jì)數(shù)器的值,來達(dá)到喂狗的目的。注意這里在進(jìn)入中斷后, 必須在不大于 1 個窗口看門狗計(jì)數(shù)周期的時間(在 PCLK1 頻率為 60M 且PSC為 0 的條件下,該時間為68.2us)內(nèi)重新寫WWDGT_CTL,否則,看門狗將產(chǎn)生復(fù)位!
最后我們要介紹的是狀態(tài)寄存器(WWDGT_STAT,該寄存器用來記錄當(dāng)前是否有提前喚醒的標(biāo)志。該寄存器僅有位 0 有效,其他都是保留位。當(dāng)計(jì)數(shù)器值達(dá)到 40h 時,此位由硬件置 1。它必須通過軟件寫 0 來清除。對此位寫 1 無效。 即使中斷未被使能, 在計(jì)數(shù)器的值達(dá)到0X40的時候,此位也會被置1。
2.3 窗口看門狗具體代碼實(shí)現(xiàn)
啟用GD32 的窗口看門狗如下步驟。
1)使能 WWDGT時鐘
WWDGT不同于 FWDGT, FWDGT有自己獨(dú)立的 40Khz 時鐘,不存在使能問題。而 WWDGT使用的是 PCLK1 的時鐘,需要先使能時鐘。 方法是:
rcu_periph_clock_enable(RCU_WWDGT); // WWDGT時鐘使能
2)設(shè)置初始值、窗口值和分頻數(shù)
設(shè)置窗口值的函數(shù)是:
void wwdgt_config(uint16_t counter, uint16_t window, uint32_t prescaler)
3)開啟 WWDGT中斷并分組
開啟WWDGT中斷的函數(shù)為:
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
nvic_irq_enable(WWDGT_IRQn, 2U, 0U);
wwdgt_interrupt_enable (); //開啟窗口看門狗中斷
4)使能看門狗
這一步在庫函數(shù)里面是通過一個函數(shù)實(shí)現(xiàn)的:
void wwdgt_enable(void);
該函數(shù)使能窗口看門狗。
5)編寫中斷服務(wù)函數(shù)
在最后,還是要編寫窗口看門狗的中斷服務(wù)函數(shù),通過該函數(shù)來喂狗,喂狗要快,否則當(dāng)窗口看門狗計(jì)數(shù)器值減到 0X3F 的時候,就會引起軟復(fù)位了。在中斷服務(wù)函數(shù)里面也要將狀態(tài)寄存器的 EWIF 位清空。
/**
* @brief This function handles WWDG Handler.
* @param None
* @retval None
*/
void WWDGT_IRQHandler (void)
{
wwdgt_counter_update(0x7F);
wwdgt_flag_clear();
printf("WWDG");
}
【小貼士】當(dāng)然啦,最好不要在中斷服務(wù)程序中喂狗,標(biāo)準(zhǔn)的寫法是在中斷服務(wù)程序中做重要的操作,也就是復(fù)位前的操作,喂狗在主函數(shù)中進(jìn)行。
窗口配置如下:
/**
* @brief 看門狗初始化
* @param None
* @retval None
*/
void wwdog_configuration(void)
{
//窗口看門狗時鐘
rcu_periph_clock_enable(RCU_WWDGT);
//設(shè)置WWDG預(yù)分頻數(shù)值,則WWDG時鐘頻率=(PCK1(60M)/4096)/8
//窗口上邊界數(shù)值
wwdgt_config(0x7F, 0x5F, WWDGT_CFG_PSC_DIV8);
//使能窗口看門狗
wwdgt_enable();
//清除提前喚醒中斷標(biāo)志
wwdgt_flag_clear();
//開啟窗口看門狗中斷
wwdgt_interrupt_enable();
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
nvic_irq_enable(WWDGT_IRQn, 2U, 0U);
}
主函數(shù)如下:
/*
brief main function
param[in] none
param[out] none
retval none
*/
int main(void)
{
/* systick init*/
sysTick_init();
//usart init 115200 8-N-1
com_init(COM1, 115200, 0, 1);
/*窗口看門狗初始化*/
wwdog_configuration();
printf("Window watchdog");
while(1)
{
printf("https://www.bruceou.cn/");
delay_ms(800);
}
}
4 窗口看門狗實(shí)現(xiàn)現(xiàn)象
編譯無誤,打開串口,現(xiàn)象如下:

-
mcu
+關(guān)注
關(guān)注
147文章
19103瀏覽量
403044 -
看門狗
+關(guān)注
關(guān)注
10文章
611瀏覽量
73175 -
計(jì)數(shù)器
+關(guān)注
關(guān)注
32文章
2320瀏覽量
98504 -
keil
+關(guān)注
關(guān)注
69文章
1231瀏覽量
173106 -
GD32
+關(guān)注
關(guān)注
7文章
434瀏覽量
27590
發(fā)布評論請先 登錄
STM32中的獨(dú)立看門狗和窗口看門狗是什么
GD32開發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第12章 ADC
GD32開發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第16章 RTC
《GD32 MCU原理及固件庫開發(fā)指南》+讀后感
stm32看門狗時間計(jì)算 獨(dú)立看門狗和窗口看門狗的特性是什么
什么是stm32看門狗?獨(dú)立看門狗和窗口看門狗工作原理解析
STM32看門狗配置(獨(dú)立看門狗IWDG和窗口看門狗WWDG)
PIC24H系列中文參考手冊—第09章 看門狗定時器和節(jié)能模式
MCU獨(dú)立看門狗與窗口看門狗的區(qū)別
【GD32】GD32設(shè)置看門狗
STM32學(xué)習(xí)心得十六:獨(dú)立看門狗實(shí)驗(yàn)
STM32:獨(dú)立看門狗、窗口看門狗的配置
STM32中的獨(dú)立看門狗和窗口看門狗
STM32中的獨(dú)立看門狗和窗口看門狗
調(diào)試模式下如何調(diào)試看門狗?
GD32開發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第17章 看門狗
評論