天天看点

关于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

更多相关嵌入式免费资料查看华清远见讲师博文>>

继续阅读