Based on STM32HAL library (independent watchdog)-brief description

Table of Contents

Overview

1. Development environment

2. STM32CubeMx configuration

3. Encoding

4. Operation results

5. Summary


Overview

A mature and reliable project is inseparable from the “watchdog” option. Every program written by people will have bugs (or the chip peripherals are interfered by the outside world, causing the faulty program to get stuck or run away). . In order to prevent the product from becoming a brick, it is necessary to introduce a watchdog, which can effectively solve the problem of program runaway (ensuring that the program can run normally in most situations).

Explanation from Baidu Encyclopedia (Watchdog)
The Watchdog Timer (WDT, Watch Dog Timer) is an integral part of the microcontroller. It is actually a counter. Generally, the watchdog is given a number. The watchdog starts counting after the program starts running. If the program runs normally, the CPU should issue an instruction after a while to reset the watchdog to zero and restart counting. If the watchdog increases to the set value, it is considered that the program is not working properly and the entire system is forced to reset.

STM32’s built-in watchdog-(For details, please refer to the-STM32F4xx Chinese Reference Manual.pdf document)

STM32 has two built-in watchdogs, providing higher security, time accuracy and flexibility of use. Two watchdog devices (independent watchdog, window watchdog) can be used to detect and resolve failures caused by software errors. When the counter reaches a given timeout value, an interrupt is triggered (window watchdog only) or a system reset is generated.

1). The independent watchdog (IWDG) is driven by a dedicated low-speed clock (LSI) (32kHz), and it is still effective even if the main clock fails. The independent watchdog is suitable for applications where the watchdog is required to work completely independently outside the main program and has low time accuracy requirements.
2) The window watchdog is driven by a clock (42MHz) obtained by dividing the APB1 clock (84MHz). Detect unusually late or premature application operations through configurable time windows. Window watchdogs are best suited for programs that require the watchdog to function within a precisely timed window.

?

1. Development environment

1. Hardware platform
STM32F401CEU6
Internal Flash: 512Kbytes, SARM: 96 Kbytes

?

2. STM32CubeMx configuration

2.1. System clock configuration

?

2.2. Download debugging configuration

?

2.3. TIM configuration (1ms interrupt)

?

?

2.4, usart1 configuration

?

?

2.5. Independent watchdog (IWDG)

?

?

A) IWDG clock prescaler coefficient divided by 32
B) Counter reload value 4095 RLR

The clock frequency LSI=32KHz, one watchdog clock cycle is the minimum timeout time. (M4 core)
Maximum timeout time = (maximum value of IWDG_RLR register) x watchdog clock period
Exceed (overflow) time calculation: unit is ms

Tout=((4×2^PRER) ×RLR)/LSI clock frequency
Obtained from the formula: Tout=(4×2^3)×4095/32=4095ms

PRER values corresponding to different prescaler coefficients:

Detailed explanation:
Tout is the watchdog overflow time (unit: ms); prer is the watchdog clock prescaler value (IWDG_PR value), ranging from 0 to 7; rlr is the watchdog reload value (IWDG_RLR value);
We set the prer value to 6 (6 represents 256 frequency division, and the macro definition identifier IWDG_PRESCALER_256 can be used in the HAL library), and the rlr value is 4095, then we can get Tout=256×4095/32=32760ms. In this way, the watchdog overflow time is 32760ms. As long as you write 0XAAAA to IWDG_KR once within 32.76 seconds, it will not cause the watchdog to reset (of course, writing multiple times is also possible). What needs to be reminded here is that the watchdog clock is not accurate to 32Khz, so when feeding the dog, it is best not to be too late, otherwise, the watchdog reset may occur.

2.6. Generate code

?

?

3. Encoding

1. usart.c file

/* USER CODE BEGIN Header */
/**
  *************************************************** ******************************
  * @file usart.c
  * @brief This file provides code for the configuration
  * of the USART instances.
  *************************************************** ******************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  *************************************************** ****************************
  */
/* USER CODE END Header */
/* Includes ----------------------------------------------- ------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

UART_HandleTypeDef huart1;

/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init( & amp;huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9 ------> USART1_TX
    PA10 ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PA9 ------> USART1_TX
    PA10 ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

    /* USART1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
#include "stdio.h"
#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
  * @brief Retargets the C library printf function to the USART.
  * @param None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
  HAL_UART_Transmit( & amp;huart1, (uint8_t *) & amp;ch, 1, 0xFFFF);
 
  return ch;
}
 
int fgetc(FILE * f)
{
  uint8_t ch = 0;
  HAL_UART_Receive( & amp;huart1, (uint8_t *) & amp;ch, 1, 0xffff);
  return ch;
}

/* USER CODE END 1 */

2. tim.c file (this example uses “timer” simulation tasks to execute program logic code)

/* USER CODE BEGIN Header */
/**
  *************************************************** ******************************
  * @file tim.c
  * @brief This file provides code for the configuration
  * of the TIM instances.
  *************************************************** ******************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  *************************************************** ******************************
  */
/* USER CODE END Header */
/* Includes ----------------------------------------------- ------------------*/
#include "tim.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

TIM_HandleTypeDef htim1;

/* TIM1 init function */
void MX_TIM1_Init(void)
{

  /* USER CODE BEGIN TIM1_Init 0 */

  /* USER CODE END TIM1_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM1_Init 1 */

  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 84-1;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 1000-1;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init( & amp;htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource( & amp;htim1, & amp;sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization( & amp;htim1, & amp;sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */

  /* USER CODE END TIM1_Init 2 */

}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspInit 0 */

  /* USER CODE END TIM1_MspInit 0 */
    /* TIM1 clock enable */
    __HAL_RCC_TIM1_CLK_ENABLE();

    /* TIM1 interrupt Init */
    HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
  /* USER CODE BEGIN TIM1_MspInit 1 */

  /* USER CODE END TIM1_MspInit 1 */
  }
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspDeInit 0 */

  /* USER CODE END TIM1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM1_CLK_DISABLE();

    /* TIM1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM1_UP_TIM10_IRQn);
  /* USER CODE BEGIN TIM1_MspDeInit 1 */

  /* USER CODE END TIM1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
#include "stdio.h"
#include "iwdg.h"
uint32_t timeCount_500ms = 0;
uint32_t timeCount_1000ms = 0;
uint8_t times_refresh = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim->Instance == TIM1){ //Task count 1ms
timeCount_500ms + + ;
timeCount_1000ms + + ;
if(timeCount_500ms==500){
timeCount_500ms = 0;
printf("time + 500ms\
");
}
if(timeCount_1000ms==1000){
timeCount_1000ms = 0;
printf("time + 1s\
");
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); //LED flip - flashing indicates successful dog feeding
times_refresh + + ;
if (times_refresh < 2) {
HAL_IWDG_Refresh( & amp;hiwdg); //Feed the dog
printf("Feed the dog successfully!!!\
");
} else if (times_refresh == 5){
times_refresh = 0;
printf("Timeout to feed the dog!!! \
");
}
}
}
}

/* USER CODE END 1 */

3. The iwdg.c file can be used by default.
Just pay attention to the following APIs of the HAL library independent window dog:

HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg); //Watchdog initialization

HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg); //Feed the dog

4. main.c file

/* USER CODE BEGIN Header */
/**
  *************************************************** ****************************
  * @file: main.c
  * @brief: Main program body
  *************************************************** ****************************
  *@attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  *************************************************** ****************************
  */
/* USER CODE END Header */
/* Includes ----------------------------------------------- ------------------*/
#include "main.h"
#include "iwdg.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes -------------------------------------------------- ----------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

/* Private typedef ----------------------------------------------- -------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define -------------------------------------------------- ---------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro ----------------------------------------------- ---------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables -------------------------------------------------- -----------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes --------------------------------------------- --*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/*Private user code------------------------------------------------ ----------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration------------------------------------------------- ----------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_TIM1_Init();
  MX_IWDG_Init();
  /* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT( & amp;htim1);
printf("heihei iwdg \r\
");
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig( & amp;RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig( & amp;RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
  * @brief Reports the name of the source file and the source line number
  * where the assert_param error has occurred.
  * @param file: pointer to the source file name
  * @param line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\
", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

4. Operation results

5. Summary

Okay, the introduction is over. With it, you no longer have to worry about the program running away. I hope it will be helpful to you. Thank you for visiting! Thanks for reading.