MM32F0140学习笔记——窗口看门狗(WWDG)

cathy的头像
cathy 发布于:周一, 05/30/2022 - 10:27 ,关键词:

1、WWDG简介

窗口看门狗(WWDG)是喂狗时间有上下限范围的看门狗,主要用于检测由外部干扰和不可预测的逻辑条件导致程序跑飞了所引起的软件问题,根据程序正常执行的时间设置刷新看门狗的一个时间窗口,保证不会提前刷新看门狗或滞后刷新看门狗,可以用于检测出程序是否按照正常的路径运行或者是非正常的跳过某些程序段的情况。

复位

当WWDG计数器的值大于设定的上限窗口值时喂狗,将产生复位;当计数器的值从下限固定值0x40变成0x3F时,低于窗口看门狗的下限,也会产生复位。

计数器时钟

WWDG计数器时钟由CK计时器时钟经过预分频器分频得到,预分频器的时基由配置寄存器(WWDG_CFGR)的WDGTB位配置,如图1所示,CK计时器时钟=PCLK1/4096,可将CK计时器时钟进行2分频/4分频/8分频/不分频。

“图1.WWDG计数器时钟配置"
图1.WWDG计数器时钟配置

计数器

WWDG的计数器是一个递减计数器,每4096x2WDGTB个PCLK1周期减1,WDGTB的值如图1所示。控制寄存器(WWDG_CR)的T位用于存储看门狗的7位计数器值,如图2所示,计数器所有位置1时为最大值0x7F,其下限固定值为0x40,当计数器值从0x40下降到0x3F时,产生看门狗复位。WWDG的喂狗操作必须在计数器值小于窗口寄存器值时操作,只有该情况下喂狗不会产生复位。

“图2.WWDG计数器位"
图2.WWDG计数器位

窗口值

如图3所示,WWDG的上限窗口值由配置寄存器(WWDG_CFGR)的W位控制,为保证窗口的价值,上限窗口值必须大于0x40且小于等于0x7F。

“图3.WWDG上限窗口值"
图3.WWDG上限窗口值

提前唤醒中断

利用提前唤醒中断(EWI) 可以避免复位并且重载计数器。操作配置寄存器(WWDG_CFGR)中的EWI位开启中断,当计数器递减到0x40时,产生提前唤醒中断,可以在中断处理函数中向控制寄存器(WWDG_CR)重载计数器的值来达到喂狗的目的,从而防止复位。

2、实验

本实验配置WWDG计数器时钟的预分频系数为8分频,配置重载计数器窗口的上限值为0x7F,时钟初始化后,串口打印"wwdg_basic example.",初始化WWDG后使能提前唤醒中断(EWI),在中断处理函数中判断是否已经重装载计数器到指定次数,若未达到则重装载一次WWDG计数器,并记录重装载次数,达到指定次数则不再重装载计数器。

初始化WWDG后进入死循环,每经过一段延时,串口打印一个".",表示CPU仍在工作,直到WWDG复位,串口再次打印"wwdg_basic example."。

启用WWDG外设时钟 enable_clock()

实验使用WWDG,串口打印输出结果,串口使用引脚属于GPIOA组,因此需要启用WWDG、UART1及GPIOA的外设时钟。

void enable_clock()
{
    /* Enable WWDG clock. */
    RCC->APB1ENR |= RCC_APB1_PERIPH_WWDG;
    /* Enable GPIOA clock. */
    RCC->AHB1ENR |= RCC_AHB1_PERIPH_GPIOA;
    /* Enable UART1 clock. */
    RCC->APB2ENR |= RCC_APB2_PERIPH_UART1;
}

配置引脚 pin_init()

由于实验现象通过串口显示,故配置UART的TX(PA9)与RX(PA10)引脚。

void pin_init()
{
    /* PA9 - UART_TX. */
    GPIOA->CRH &= ~GPIO_CRH_MODE9_MASK;
    GPIOA->CRH &= ~GPIO_CRH_CNF9_MASK;
    GPIOA->CRH |= GPIO_CRH_MODE9(GPIO_Speed_50MHz);
    GPIOA->CRH |= GPIO_CRH_CNF9(GPIO_PinMode_AF_PushPull);
    GPIOA->AFRH &= ~GPIO_AFRH_AFR_MASK;
    GPIOA->AFRH |= (GPIO_AF_1 << GPIO_CRH_MODE9_SHIFT);

    /* PA10 - UART_RX. */
    GPIOA->CRH &= ~GPIO_CRH_MODE10_MASK;
    GPIOA->CRH &= ~GPIO_CRH_CNF10_MASK;
    GPIOA->CRH |= GPIO_CRH_CNF10(GPIO_PinMode_In_Floating);
    GPIOA->AFRH |= (GPIO_AF_1 << GPIO_CRH_MODE10_SHIFT);
}

UART初始化 uart_init()

初始化UART,配置时钟频率、波特率、数据长度、停止位、传输模式及是否使用校验。

void uart_init()
{
    /* Clear the corresponding bit to be used. */
    UART1->CCR &= ~( UART_CCR_PEN_MASK | UART_CCR_PSEL_MASK | UART_CCR_SPB0_MASK | UART_CCR_SPB1_MASK | UART_CCR_CHAR_MASK );
    UART1->GCR &= ~( UART_GCR_AUTOFLOWEN_MASK | UART_GCR_RXEN_MASK | UART_GCR_TXEN_MASK );
    /* WordLength. */
    UART1->CCR |= UART_CCR_CHAR_MASK;
    /* XferMode. */
    UART1->GCR |= (UART_XferMode_RxTx << UART_GCR_RXEN_SHIFT);
    /* Setup baudrate, BOARD_DEBUG_UART_FREQ = 48000000u, BOARD_DEBUG_UART_BAUDRATE = 9600u. */
    UART1->BRR = (BOARD_DEBUG_UART_FREQ / BOARD_DEBUG_UART_BAUDRATE) / 16u;
    UART1->FRA = (BOARD_DEBUG_UART_FREQ / BOARD_DEBUG_UART_BAUDRATE) % 16u;
    /* Enable UART1. */
    UART1->GCR |= UART_GCR_UARTEN_MASK;
}

WWDG初始化 wwdg_init()

操作配置寄存器(WWDG_CFGR)的WDGPB位配置预分频系数为8分频,W位配置重载计数器窗口的上限值为0x7F,EWI位置1使能提前唤醒中断,操作控制寄存器(WWDG_CR)的WDGA位置1,启动看门狗。

void wwdg_init()
{
    WWDG->CFGR = WWDG_CFGR_WDGTB(WWDG_Prescaler_8) | WWDG_CFGR_W(WWDG_UPPER_LIMIT);  /* WWDG_UPPER_LIMIT = 0x7F, WWDG_Prescaler_8 = 3u. */
    NVIC_EnableIRQ(WWDG_IWDG_IRQn);
    WWDG->CFGR |= WWDG_CFGR_EWI_MASK;
    WWDG->CR |=  WWDG_CR_WDGA_MASK;
}

中断服务程序 WWDG_IWDG_IRQHandler()

中断服务程序中判断是否已经重装载计数器到指定次数,若未达到则重装载一次WWDG计数器,并记录重装载次数,若达到则不再重装载计数器。向状态寄存器(WWDG_SR)的EWIF位写0,清除提前唤醒中断标志。

void WWDG_IWDG_IRQHandler(void)
{
    uint32_t status = WWDG->SR;
    if ( 0 != (WWDG_SR_EWIF_MASK & status) )
    {
        WWDG->SR &= ~WWDG_SR_EWIF_MASK;;
    }

    /* Stop reload WWDG counter aftert reload WWDG counter BOARD_WWDG_RELOAD_TIMES times. */
    if (100u > reload_times)    /* uint32_t reload_times = 0u. */
    {
        reload_times++;
        WWDG->CR = (WWDG->CR & ~WWDG_CR_T_MASK) | WWDG_CR_T(WWDG_RELOAD_VALUE);  /* WWDG_RELOAD_VALUE = 0x7f. */
    }
}

延时 soft_delay()

本实验设置初始化后进入while循环,循环中隔一段延时进行一次串口打印,表示当前CPU仍在工作,故编写软件延时。

void soft_delay(uint32_t delay)
{
    for(uint32_t i = 0u; i < delay; i++)
    {
        for(uint32_t j = 0u; j < 10000u; j++)
        {
            __NOP();
        }
    }
}

main()函数

main()函数结合上述操作,串口打印"wwdg_basic example.",初始化WWDG并使能提前唤醒中断后进入死循环,循环中每经过一段延时串口将打印一个 “.” ,表示CPU仍在工作,直到WWDG复位,实验现象如图4所示。

void main()
{
    enable_clock();
    pin_init();
    uart_init();
    printf("\r\nwwdg_basic example.\r\n");
    wwdg_init();
    while (1)
    {
        printf(".");
        soft_delay(100u);
    }
}

“图4.实验现象"
图4.实验现象

来源:灵动MM32MCU
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 233