Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

The STM32F10xxx has two built-in watchdogs for increased security, time accuracy and flexibility in use. Two watchdog devices (independent watchdog and window watchdog) are used to detect and resolve faults caused by software bugs; When the counter reaches a specified timeout value, an interrupt (window-type watchdog only) is triggered or a system reset is generated.

The independent watchdog (IWDG) is powered by a dedicated low speed clock (LSI), which remains effective even if the master clock fails. The window watchdog, driven by a clock derived from the APB1 clock divider, detects abnormally late or premature application action through a configurable time window.

IWDG is best used in situations where a watchdog is required to work independently of the main program and with low time precision. WWDG is best suited for applications that require a watchdog to function in a precise timing window.

The watchdog is mainly used to monitor the running status of the system, so as to avoid the code running away after the system is disturbed, resulting in system chaos. The use of watchdog is also relatively simple. The following is the use of independent watchdog and window watchdog respectively.

Independent watchdog

// Initialize the independent watchdog
//prer: 0~7(only lower 3 bits are valid!)
// Divide factor =4*2^prer.
// RLR: reloaded register value: 11 bits lower valid.
// Time calculation (approximate):Tout=((4*2^prer)* RLR)/40 (ms)
void IWDG_Init(u8 prer,u16 rlr)
{
	// 1. Disable register write protection write 0x5555
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
	// 2. Set the independent watchdog pre-dividing frequency coefficient
	IWDG_SetPrescaler(prer);
	// 3. Set the independent watchdog reloading value
	IWDG_SetReload(rlr);;
	// 4, overload count value feed dog write 0xAAAA
	IWDG_ReloadCounter();
	// 5, start watchdog write 0xCCCC
	IWDG_Enable();
}
void IWDG_Feed(void)
{
	IWDG_ReloadCounter();
}
Copy the code

The initialization of the independent watchdog is very simple, basically setting the feeding time of the dog. And feed the dog as the program runs.

int main(void)
{
    u8 key = 0;
    delay_init();       // Delay function initialization
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    LED_Init();
    KEY_Init();
    IWDG_Init(4.625);	// Overflow time is 1s (4*2^4)*625/40=1000ms

    LED0 = 1;
    LED1 = 1;
    delay_ms(500);
    LED0 = 0;
    LED1 = 0;

    while(1)
    {
        key = KEY_Sacn(1);
        if( key == WKUP_PRES)
        {
            IWDG_Feed();
        }
        delay_ms(10); }}Copy the code

Here, a button is used to simulate feeding the dog. When the button is pressed once, the dog is fed once. If the button is not pressed after the dog has been fed, the independent watchdog will reset the system.

Window guard dog

u8 WWDG_CNT = 0x7f;
void WWDG_NVIC_Init(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

// Initialize the window watchdog
//tr :T[6:0], counter value
//wr :W[6:0], window value
// fPREr: frequency division coefficient (WDGTB). Only the lowest 2 bits are valid
//Fwwdg=PCLK1/(4096*2^fprer)
void WWDG_Init(u8 tr, u8 wr, u32 fprer)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // The clock is enabled
    WWDG_CNT = tr & WWDG_CNT;
    WWDG_SetPrescaler(fprer);			// Set the predivision value
    WWDG_SetWindowValue(wr);			// Set the window value to be independent of the interval between feeding the dog
    WWDG_Enable(WWDG_CNT);			// Enable the watchdog and set the count
    WWDG_ClearFlag();				// Clear the early wake interrupt
    WWDG_NVIC_Init();				// Set the interrupt priority
    WWDG_EnableIT();				// Open window watchdog interrupt
}
void WWDG_Set_Counter(u8 cnt)
{
    WWDG_Enable(cnt);				// Enable the watchdog and set the count
}
void WWDG_IRQHandler(void)
{
    WWDG_SetCounter(WWDG_CNT);		       / / feed the dog
    WWDG_ClearFlag();				// Clear the early wake interruptLED0=! LED0; }Copy the code

Because the window watchdog feeding time is very short, it is difficult to determine when to feed the dog in the process of running the program, so the dog feeding is implemented by using interrupt. When the dog needs to be fed, interrupt is directly triggered and the dog is fed in the interrupt. Every time the dog is fed, the LED is reversed. The execution of the interrupt function can be seen by observing the flicker of the LED.

int main(void)
{
    u8 key = 0;
    delay_init();       // Delay function initialization
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    LED_Init();
    KEY_Init();
    //IWDG_Init(4, 625); // Overflow time is 1s (4*2^4)*625/40=1000ms

    LED0 = 1;
    LED1 = 1;
    delay_ms(500);
    LED0 = 0;
    LED1 = 0;
	
    Wr can be set to any value between 0x40-- 0x7f
    // 4096*2^3*64/36000000 = 58.25ms (64 = 0x7f low 6 bits)
    WWDG_Init(0x7f.0x7f, WWDG_Prescaler_8); // count = 7f, window register = 5f, frequency = 8
	
    // 4096*2^3*31/36000000 =28.22ms (31 = 0x4f low 6 bits)
    //WWDG_Init(0x5f, 0x5f, WWDG_Prescaler_8);
	
   // 4096*2^3*15/36000000 =13.65ms (15 = 0x4f low 6 bits)
    //WWDG_Init(0x4f, 0x5f, WWDG_Prescaler_8);	
	
    // 4096*2^3*1/36000000 =910us (1 = 0x41 low 6 bits value) The minimum window value is 0x40
    //WWDG_Init(0x41, 0x5f, WWDG_Prescaler_8);
    while(1) {}}Copy the code

In the main function by setting different overflow time to observe the LED flashing frequency.