9.1.FWDG 簡介
本章我們主要分析獨立看門狗(FWDG)的功能框圖和它的應用。獨立看門狗用通俗一點的話來解釋就是一個12位的遞減計數器,當計數器的值從某個值一直減到0的時候,系統就會產生一個復位信號,即FWDGTRSTF。如果在計數沒減到0之前,刷新了計數器的值的話,那么就不會產生復位信號,這個動作就是我們經常說的喂狗。看門狗功能由 VDD 電壓域供電,在停止模式和待機模式下仍能工作。獨立看門狗定時器有獨立的時鐘源(IRC40K) 。 即使主時鐘失效, FWDGT依然 能保持正常工作狀態, 適用于需要獨立環境且對計時精度要求不高的場合。
9.2.GD32 FWDG 外設原理簡介
因篇幅有限,本文無法詳細介紹GD32所有系列FWDG外設接口,下面以GD32F30x為列,著重介紹下GD32F30x的FWDG外設簡介和結構框圖,后介紹下各個系列的差異。
GD32 FWDG 主要特性
? 自由運行的12位向下計數器;
? 如果看門狗定時器被使能,那么當向下計數器的值達到0時產生系統復位;
? 獨立時鐘源,獨立看門狗定時器在主時鐘故障(例如待機和深度睡眠模式下)時仍能工作;
? 獨立看門狗定時器硬件控制位,可以用來控制是否在上電時自動啟動獨立看門狗定時器;
? 可以配置獨立看門狗定時器在調試模式下選擇停止還是繼續工作。
FWDG 功能結構框圖

FWDG時鐘:如FWDG框圖的①所示, FWDG的時鐘由獨立的RC振蕩器IRC40K提供,即使主時鐘發生故障它仍然有效,非常獨立。IRC的頻率根據溫度和工作場合會有一定的漂移,我們一般取40KHZ,所以FWDG的定時時間并不一定非常精確,只適用于對時間精度要求相對較低的場合。
計數器時鐘:如FWDG框圖的②所示, 遞減計數器的時鐘由IRC40K經過一個8位的預分頻器得到,我們可以操作預分頻器寄存器FWDG_PSC來設置分頻因子,分頻因子可以是:[4,8,16,32,64,128,256]。
計數器:如圖 0-28 FWDG框圖的③所示, FWDG的計數器是一個12位的遞減計數器,最大值為0XFFF,當計數器減到0時,會產生一個復位信號: FWDGTRSTF,讓程序重新啟動運行,如果在計數器減到0之前刷新了計數器的值的話,就不會產生復位信號,重新刷新計數器值的這個動作我們俗稱喂狗。
重裝載寄存器:如FWDG框圖的④所示, 重裝載寄存器是一個12位的寄存器,里面裝著要刷新到計數器的值,這個值的大小決定著FWDG的溢出時間。超時時間Tout = (42^prv) / 40 rlv (s) ,prv是預分頻器寄存器的值,rlv是重裝載寄存器的值。
控制寄存器:如FWDG框圖的⑤所示, 控制寄存器FWDG_CTL可以說是獨立看門狗的一個控制寄存器,主要有三種控制方式,往這個寄存器寫入下面三個不同的值有不同的效果。具體如下表控制寄存器取值枚舉

狀態寄存器:如FWDG框圖的⑥所示, 狀態寄存器STAT只有位0:PUD和位1:RUD有效,這兩位只能由硬件操作,軟件操作不了。RUD:看門狗計數器重裝載值更新,硬件置1表示重裝載值的更新正在進行中,更新完畢之后由硬件清0。PUD: 看門狗預分頻值更新,硬件置‘1‘指示預分頻值的更新正在進行中,當更新完成后,由硬件清0。所以只有當RUD/PUD等于0的時候才可以更新重裝載寄存器/預分頻寄存器。
注意:
如果在選項字節中打開了“硬件看門狗定時器”功能,那么在上電的時候看門狗定時器就被自動打開。為了避免系統復位,軟件應該在計數器達到0x000之前重裝載計數器;
如果DBG控制寄存器0(DBG_CTL0) 中的FWDGT_HOLD位被清0,即使Cortex?-M4內核停止(調試模式下) 獨立看門狗定時器依然工作。如果FWDGT_HOLD位置1,獨立看門狗定時器將在調試模式下停止工作。
各系列 FWDG 功能差異
F4xx系例FWDG時鐘為32K,因此要注意FWDG的定時時間。
9.3.硬件連接說明
FWDG屬于單片機內部資源,不需要外部電路,需要一個外部的按鍵和LED,通過按鍵來喂狗,喂狗成功LED亮,喂狗失敗,程序重啟,LED滅一次。
9.4.軟件配置說明
本小節講解FWDG_Example例程中FWDG模塊的實驗講解,主要包括FWDG配置函數、FWDG喂狗函數、主函數介紹以及運行結果。
FWDG 配置函數
外設時鐘配置
外設時鐘配置如代碼清單FWDG例程時鐘配置所示,在GD32全系列MCU中需打開GPIOA(LED)的時鐘,另外,在GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F3X0 || GD32E230中需要打開IRC40K,GD32F4XX中需要打開IRC32K。
void rcu_config(void) { #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E230 rcu_periph_clock_enable(RCU_GPIOA); #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F3X0 || GD32E230 /* enable IRC40K */ rcu_osci_on(RCU_IRC40K); /* wait till IRC40K is ready */ while(SUCCESS != rcu_osci_stab_wait(RCU_IRC40K)){ } #elif GD32F4XX /* enable IRC32K */ rcu_osci_on(RCU_IRC32K); /* wait till IRC32K is ready */ while(SUCCESS != rcu_osci_stab_wait(RCU_IRC32K)){ } #endif #endif }
GPIO(LED)引腳配置
GPIO引腳配置如代碼清單FWDG例程GPIO(LED)引腳配置所示,GD32F10X、GD32F30X、GD32F20X、GD32E10X系列GPIO配置相同, PA3、PA4作為LED引腳配置為推挽輸出模式;GD32F1X0、GD32F4XX、GD32F3X0、GD32E23X系列GPIO配置基本相同。配置完成后將PA3 和PA4拉低。
void gpio_led_config(void) { #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3); gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E230 gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3); gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3); gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4); gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4); #endif GPIO_BC(GPIOA) = GPIO_PIN_3; GPIO_BC(GPIOA) = GPIO_PIN_4; }
按鍵初始化配置
按鍵初始化配置如代碼清單按鍵初始化配置所示。本例程中默認使用PA0下降沿進入中斷,GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X系列配置基本相同,GD32F1X0 || GD32F3X0系列配置類似。GD32E230中斷分組只有搶占優先級沒有子優先級。
void key_init(void) { #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X rcu_periph_clock_enable(RCU_AF); gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_0); /* enable and set key EXTI interrupt to the lowest priority */ nvic_irq_enable(EXTI0_IRQn, 2U, 0U); /* connect key EXTI line to key GPIO pin */ gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOA, GPIO_PIN_SOURCE_0); /* configure key EXTI line */ exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_FALLING); exti_interrupt_flag_clear(EXTI_0); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E230 #if defined GD32F1X0 || GD32F3X0 rcu_periph_clock_enable(RCU_CFGCMP); /* configure button pin as input */ gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE,GPIO_PIN_0); /* enable and set key EXTI interrupt to the lowest priority */ nvic_irq_enable(EXTI0_1_IRQn, 2U, 0U); #elif defined GD32E230 rcu_periph_clock_enable(RCU_CFGCMP); /* configure button pin as input */ gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE,GPIO_PIN_0); /* enable and set key EXTI interrupt to the lowest priority */ nvic_irq_enable(EXTI0_1_IRQn, 2U); #elif defined GD32F4XX rcu_periph_clock_enable(RCU_SYSCFG); /* configure button pin as input */ gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE,GPIO_PIN_0); /* enable and set key EXTI interrupt to the lowest priority */ nvic_irq_enable(EXTI0_IRQn, 2U, 0U); #endif /* connect key EXTI line to key GPIO pin */ syscfg_exti_line_config(EXTI_SOURCE_GPIOA, EXTI_SOURCE_PIN0); /* configure key EXTI line */ exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_FALLING); exti_interrupt_flag_clear(EXTI_0); #endif }
FWDG 配置函數
FWDG配置函數如代碼清單FWDG配置配置所示。當時鐘為40K時,溢出時間Tout =prv/40 rlv (s),prv可以是[4,8,16,32,64,128,256];rlv的取值范圍為0~0XFFF。如果我們需要設置1s的超時溢出, prv 可以取 FWDGT_PSC_DIV64 , rlv 取 625 ,即調用 : fwdgt_config(625,FWDGT_PSC_DIV64)。Tout=64/40625=1s。GD32F4XX系列IRC為32K則定時時間1.25s。
void FWDGT_init(void) { /* confiure FWDGT counter clock: 40KHz(IRC40K) / 64 = 0.625 KHz GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F3X0 || GD32E23X*/ /* confiure FWDGT counter clock: 32KHz(IRC32K) / 64 = 0.5 KHz GD32F4XX*/ fwdgt_config(625, FWDGT_PSC_DIV64); /* after 1.x seconds to generate a reset */ fwdgt_enable(); }
中斷喂狗
中斷喂狗函數如代碼清單中斷喂狗所示。當進進入PA0外部中斷時執行喂狗函數。
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F4XX void EXTI0_IRQHandler(void) { /* make sure whether the tamper key EXTI Line is interrupted */ if(RESET != exti_interrupt_flag_get(EXTI_0)){ /* reload FWDGT counter */ fwdgt_counter_reload(); } /* clear the interrupt flag bit */ exti_interrupt_flag_clear(EXTI_0); } #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E230 void EXTI0_1_IRQHandler(void) { /* make sure whether the tamper key EXTI Line is interrupted */ if(RESET != exti_interrupt_flag_get(EXTI_0)){ /* reload FWDGT counter */ fwdgt_counter_reload(); } /* clear the interrupt flag bit */ exti_interrupt_flag_clear(EXTI_0); } #endif
主函數說明
主函數如代碼清單FWDG例程主函數所示,主函數中我們初始化好LED和按鍵相關的配置,設置FWDG 1s 超時溢出之后,進入while死循環,通過按鍵來喂狗,如果喂狗成功,則LED2(PA4)點亮,如果喂狗失敗的話,系統重啟,程序重新執行,當執行到rcu_flag_get函數的時候,則會檢測到是FWDG復位,然后讓LED1(PA3)亮。如果喂狗一直失敗的話,則會一直產生系統復位,加上前面延時的效果,則會看到LED1(PA3)一直閃爍。
int main(void) { /* peripheral clock enable */ rcu_config(); /* config systick */ systick_config(); /* GPIO config */ gpio_led_config(); key_init(); delay_1ms(500); FWDGT_init(); /* check if the system has resumed from FWDGT reset */ if(RESET != rcu_flag_get(RCU_FLAG_FWDGTRST)){ /* turn on LED1 */ GPIO_BOP(GPIOA) = GPIO_PIN_3; /* clear the FWDGT reset flag */ rcu_all_reset_flag_clear(); while(1); } else{ /* turn on LED2 */ GPIO_BOP(GPIOA) = GPIO_PIN_4; } while(1) { } }
運行結果
把編譯好的程序下載到開發板,在1s的時間內通過按鍵來不斷的喂狗,如果喂狗失敗,LED1閃爍。如果一直喂狗成功,則LED2常亮。
9.5.FWDG 使用注意事項
(1) FWDG在Debug仿真時,請將DBG控制寄存器0(DBG_CTL0) 中的FWDGT_HOLD位置1,來關閉FWDG功能。
(2) 沒有開啟軟件看門狗時,程序自動復位,可能在選項字節里開啟了硬件看門狗。
(3) 同時使用FWDG、Standby或Deep-sleep模式時,無法喂狗:在reload命令后,硬件清除reload信號之前,進入Deepsleep或者standby模式,會導致后續reload命令無法正常響應。軟件保證在reload命令和進入Deepsleep/standby mode的命令中間有3個LXTAL clock(100us)以上的時間間隔。
(4) 由于環境溫度影響,獨立看門狗定時器超時周期會有些許波動,可以通過校準IRC40K使獨立看門狗定時器超時更加精確。
-
單片機
+關注
關注
6067文章
44969瀏覽量
649751 -
mcu
+關注
關注
146文章
17953瀏覽量
364912 -
看門狗
+關注
關注
10文章
582瀏覽量
71749 -
GD32
+關注
關注
7文章
420瀏覽量
25428
發布評論請先 登錄
GD32 MCU 入門教程】GD32 MCU 常見外設介紹(12)FMC 模塊介紹

GD32 MCU移植
《GD32 MCU原理及固件庫開發指南》+讀后感
兆易創新GD32 MCU選型手冊,適用于GD32全系列MCU
【GD32 MCU 入門教程】一、GD32 MCU 開發環境搭建(1)使用Keil開發GD32

【GD32 MCU 入門教程】一、GD32 MCU 開發環境搭建(2)使用 IAR 開發 GD32

【GD32 MCU 入門教程】一、GD32 MCU 開發環境搭建(3)使用 Embedded Builder 開發 GD32

【GD32 MCU 入門教程】二、GD32 MCU 燒錄說明(1)ISP 燒錄

【GD32 MCU 入門教程】GD32 MCU 常見外設介紹(14)RTC 模塊介紹

【GD32 MCU入門教程】GD32 MCU GPIO 結構與使用注意事項

評論