天天看點

關于AT91SAM3S4B 中看門狗分析

作者:盧老師,華清遠見嵌入式學院講師。

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時鐘子產品寄存器控制邏輯:

關于AT91SAM3S4B 中看門狗分析

圖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

更多相關嵌入式免費資料檢視華清遠見講師博文>>

繼續閱讀