作者:盧老師,華清遠見嵌入式學院講師。
WDT看門狗基本原理
看門狗,又叫Watchdog Timer,是一個定時器電路,一般有一個輸入,叫喂狗(kicking the dog or service the dog),一個輸出到MCU的RST端。MCU正常工作的時候,每隔一段時間輸出一個信号到喂狗端,給WDT清零,如果超過規定的時間不喂狗(一般在程式跑飛時),WDT定時超過預先設定值,就會給出一個複位信号到MCU,使MCU重新開始工作。看門狗的作用就是防止程式發生死循環,或者叫程式跑飛。
在SAM3S系統中,用于看門狗的遞減計數器是12位,可以計數的最大周期為16s(慢速時鐘,32.768Khz),其加載的值為慢速時鐘的128分頻。
圖7-56給出WDT時鐘子產品寄存器控制邏輯:
圖7-56 WDT時鐘子產品寄存器
SAM3S4B複位後,WDV的值為0xfff,允許外部複位,預設情況下,看門狗是處于運作狀态,如果使用者沒有使能看門狗,就需要禁止看門狗,否則需要定時“喂狗”。
看門狗模式寄存器WDT_MR隻能寫一次,之後,複位後重新加載定時器。
在正常情況下,使用者定期向WDT_CR的WDRSTT位置1,重載看門狗定時器。WDRSTT置位後,計數器從WDT_MR重新加載,并重新啟動。慢速時鐘128分頻器也被複位及重新啟動。WDT_CR是寫保護寄存器,若預設值不正确,對WDT_CR的操作無效,如果發生計數器益處,且WDR_MR的WDRSTEN為1,産生“wdt_fault”,WDT_SR的WDUNF置位。
為防止軟體死鎖,在0和WDD之間重新加載看門狗,WDD在看門狗模式下WDT_MR中定義。
如果試圖在WDV和WDD之間重新開機看門狗定時器,将會導緻看門狗錯誤,即使看門狗被禁止。這将導緻WDT_SR中的WDERR位被修改,wdt_fault生效。若WDD不小于WDV的值時,上述功能是無效的,看門狗定時器允許在0和WDV之間重新啟動,不産生錯誤,晶片預設的複位狀态時WDV=WDD。
如果WDFIFN=1,WDRSTEN=0,則WDUNF(看門狗溢出)和WDERR(看門狗錯誤)置位,觸發中斷;如果WDFIFN=1,WDRSTEN=1,則觸發wdt_fault,複位,WDERR,WDUNF被清零。
如果複位已經産生,讀WDT_SR寄存器,狀态複位,中斷被清楚,此時wdt_fault無效,執行WDT_MR寫操作,将重新加載計數器,是CPU複位。
在調試和空閑狀态,WDT_MR中的WDIDLEHLT和WDDBGHLT置位,看門狗計數器停止運作。
表7-18控制寄存器
偏移 | 寄存器功能 | 名稱 | 權限 | 複位值 |
0x00 | 控制寄存器 | WDT_CR | 隻寫 | - |
0x04 | 模式寄存器 | WDT_MR | 隻讀一次 | 0x3FFF_2FFF |
0x08 | 狀态寄存器 | WDT_SR | 隻讀 | 0x0000_0000 |
WDT看門狗軟體設計與分析
定義看門的結構體
typedefstruct {
WoReg WDT_CR;
RwReg WDT_MR;
RoReg WDT_SR;
} Wdt;
擷取看門狗的定時時間程式:
uint32_t wdt_get_timeout_value(uint32_t ul_us, uint32_t ul_sclk)
{
uint32_t max, min;
//3000*1000 屬于3.9 ~16000*1000之間//min = 128 * 1000000 / ul_sclk;//3000*1000
min = WDT_SLCK_DIV * 1000000 / ul_sclk;
max = min * WDT_MAX_VALUE;//max = min * 4095;
if ((ul_us< min) || (ul_us> max)) {
return WDT_INVALID_ARGUMENT;
}
return WDT_MR_WDV(ul_us / min);//ul_us/min=768=256*3;
}
看門狗初始化程式:
voidwdt_init(Wdt *p_wdt, uint32_t ul_mode, uint16_t us_counter,
uint16_t us_delta)
{
p_wdt->WDT_MR=ul_mode| WDT_MR_WDV(us_counter) | WDT_MR_WDD(us_delta);
// ul_mode|0x300|(0x300<<16);
printf("p_wdt->WDT_MR= %x\r",p_wdt->WDT_MR);
}
喂狗程式:
voidwdt_restart(Wdt *p_wdt)
{
p_wdt->WDT_CR = WDT_KEY_PASSWORD | WDT_CR_WDRSTT;// 0x5a000000 |1
}
擷取看門狗寄存器狀态程式:
uint32_t wdt_get_status(Wdt *p_wdt)
{
returnp_wdt->WDT_SR;
}
擷取看門狗定時器溢出時間程式:
uint32_t wdt_get_us_timeout_period(Wdt *p_wdt, uint32_t ul_sclk)
{
return WDT_MR_WDV(p_wdt->WDT_MR) * WDT_SLCK_DIV / ul_sclk * 1000000;
}
看門狗中斷處理函數:
voidWDT_Handler(void)
{
gpio_set_pin_high(LED2_GPIO);//關閉LED2
gpio_set_pin_low(LED1_GPIO);//打開LED1;
puts("Enter watchdog interrupt.\r");
wdt_get_status(WDT);//擷取WDT狀态寄存器
wdt_restart(WDT);//看門狗複位
puts("The watchdog timer was restarted.\r");
}
在主程式中,初始化序列槽,列印相關資訊,初始化看門狗3S為溢出,産生中斷的時間,初始化按鍵BUTTON2,LED燈。
int main(void)
{
Uart *p_uart=(Uart *)0x400e0600;//序列槽位址定義
uint32_t wdt_mode, timeout_value;
sysclk_init();
//此處不能禁止看門狗,因為WDT->WDT_MR隻能進行一次寫操作,禁止操作意味着寫進去的數值為0,此後寫入的資料溢出時無效
pio_configure_group(PINS_UART0_PIO,PINS_UART0,PINS_UART0_FLAGS);
configure_console(); //序列槽配置
SysTick_Config(sysclk_get_cpu_hz() / 1000);//系統systick,1ms中斷
timeout_value = wdt_get_timeout_value(WDT_PERIOD * 1000,
BOARD_FREQ_SLCK_XTAL);//看門狗溢出時間為3S=0X300
if (timeout_value == WDT_INVALID_ARGUMENT) {
while (1) {//中斷中的處理
}
}
wdt_mode = WDT_MR_WDFIEN |
WDT_MR_WDRPROC |
WDT_MR_WDDBGHLT |
WDT_MR_WDIDLEHLT;
wdt_init(WDT, wdt_mode, timeout_value, timeout_value);//初始化看門狗
printf("timeout_period=%d",(int)wdt_get_us_timeout_period(WDT, BOARD_FREQ_SLCK_XTAL));
NVIC_DisableIRQ(WDT_IRQn);
NVIC_ClearPendingIRQ(WDT_IRQn);
NVIC_SetPriority(WDT_IRQn, 0);
NVIC_EnableIRQ(WDT_IRQn);
//配置LED燈,
gpio_configure_pin(LED1_GPIO, LED0_FLAGS);
gpio_configure_pin(LED2_GPIO, LED1_FLAGS);
gpio_set_pin_high(LED1_GPIO);
pmc_enable_periph_clk(ID_PIOA);
//按鍵2配置
gpio_configure_pin(BUTTON_2, BUTTON_INPUT);//add by luyj 2013.6.8
while(1)
{
if (g_b_systick_event == true) {
g_b_systick_event = false;
if ((g_ul_ms_ticks% WDT_RESTART_PERIOD)==0) {
printf("2s"); // 2s列印一次,提示該喂狗了,此時按鍵喂狗,
}
}
if (pio_get(PIOA, PIO_TYPE_PIO_INPUT, PIO_PA0) == 0)
{
mdelay(100);
if (pio_get(PIOA, PIO_TYPE_PIO_INPUT, PIO_PA0) == 0)
{
printf("PUSH BUTTON 2!\r");
wdt_restart(WDT);//喂狗,
gpio_set_pin_low(LED2_GPIO); //LED2亮
gpio_set_pin_high(LED1_GPIO);//LED1滅
}
}
}
}
将程式下載下傳入傳感闆,運作程式,看門狗中斷時,LED1被點亮,LED2被關閉,認為看門狗溢出,同時如果調試序列槽打開(115200,無校驗,資料位8bit,停止位1bit),可以看到列印資訊。
喂狗可以通過按鍵操作,按下K2,表示喂狗,當喂狗時,LED1被關閉,LED2被點亮,在3秒内及時喂狗,則不觸發看門狗中斷,LED1将處于關閉狀态。
文章來源:華清遠見嵌入式學院,原文位址:http://www.embedu.org/Column/Column782.htm
更多相關嵌入式免費資料檢視華清遠見講師博文>>