Based on STM32HAL library (window 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. Window Watchdog (WWDG)

Definition of window watchdog
The window watchdog is the same as the independent watchdog. It is also a decrement counter that continuously counts down. If the dog is not fed when it reaches a fixed value of 0x3F, a reset is generated. This value is called the lower limit of the window, which is a fixed value. ,unable to be changed.

The reason why the window watchdog is called a window is because its dog feeding time is within a range with upper and lower limits (the counter decreases to a certain value ~ the counter decreases to 0x3F). The dog can be fed only within this range. You can pass Set the relevant registers and set the upper limit time (but the lower limit is fixed 0x3F).


1), the initial value of the counter
2), is the upper window we set (W[6:0] value)
3), is the lower window value (0x3F)
The value of the window watchdog counter can only be fed when the value of the window watchdog counter is between 2 and 3 (between the upper window and the lower window).

Window watchdog interrupt:

And the window watchdog can also enable interrupts. If the early wake-up interrupt is enabled and there is a problem with the system and the dog feeding function does not take effect, then when the counter decreases from 0x40 (0x3f + 1), the interrupt will be entered first. It will be reset later, and you can also feed the dog in the interrupt.

A. The first calculation method:

Learn from the picture above
Watchdog timeout: Twwdg = Tpclk1 x 4096 x 2^wdgtb x (T[5:0] + 1) ms;
When PCLK1 = 42MHZ, there are minimum and maximum timeout times when WDGTB takes different values;
When WDGTB=0, the down counter has 7 bits T[6:0]. When bit 6 becomes 0, a reset will occur. In fact, the effective counting bit is T[5:0], and T6 must be set first. is 1. If T[5:0]=0, the down counter decrements again and a reset occurs, then the time of decrement by one is equal to the counter period=1/CNT_CK = Tpclk1 * 4096 * (2 ^WDGTB) = 1/ 42 * 4096 *2^ 0 = 97.52us, this is the shortest timeout time.

If T[5:0] is all filled with 1, that is, 63, when it is reduced to 0X40 and becomes 0X3F, the time required is the maximum timeout time = 97.52 *(2^6) = 6.241ms.

B. The second calculation method:

Watchdog timeout: Twwdg = (4096 * window value) / PCLK1,
When PCLK1 = 42MHZ, there are minimum and maximum timeout times when WDGTB takes different values;
The maximum value of the counter is 127, and the lower limit of the window is 63.
Minimum timeout: window upper limit value is 64, window value is 1
Maximum timeout: window upper limit value is 127, window value is 64
When WDGTB=0, the frequency division coefficient is 1, (STM32Cube MX can directly configure the frequency division coefficient)
Minimum timeout time = 1/CNT_CK = (( 4096 * frequency division coefficient ) / PCLK1) * window value = 1/42 * 4096 * 1 = 97.52us;
Maximum timeout time = 1/CNT_CK = (( 4096 * frequency division coefficient ) / PCLK1) * window value = 1/42 * 4096 * 64 = 97.52 * 64 = 6.241ms.

When we configure WWDG as follows:
1), configure the frequency division coefficient to 8,
2), the upper limit of the window is 90,
3). The lower limit value of the window is 63=(0x3F),
4), the counter value is 127,
5), the window value is 27, (90 + (63 + 1) – 127 = 154 – 127 = 27)
6), PCLK1 = 42MHz,
Window time = ((4096 frequency division coefficient)/PCLK1) * 27 = ((4096 * 8) / 42MHz) * 27 = 21.065 ms
The earliest dog feeding time = ((4096 frequency division coefficient)/PCLK1) * (127 – 90) = ((4096 * 8) / 42MHz) * 37 = 28.867 ms
Latest dog feeding time = ((4096*frequency division coefficient)/PCLK1) * (127 – 63) = ((4096 * 8) / 42MHz) * 64 = 49.932 ms

2.6. Generate code

3. Encoding

1. usart.c

/* 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 "wwdg.h"
uint32_t timeCount_10ms = 0;
uint32_t timeCount_20ms = 0;
uint8_t times = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim->Instance == TIM1) { //Task count 1ms
timeCount_10ms + + ;
timeCount_20ms + + ;
if(timeCount_10ms==10) {
timeCount_10ms = 0;
printf("time + 10ms\
");
\t\t\t
//It is learned that it is not possible to feed the dog early or late. The dog must be fed between the upper window and the lower window.
//Earliest dog feeding time = ((4096 frequency division coefficient)/PCLK1) * (127 - 90) = ((4096 * 8) / 42MHz) * 37 = 28.867 ms
//The latest dog feeding time = ((4096*frequency division coefficient)/PCLK1) * (127 - 63) = ((4096 * 8) / 42MHz) * 64 = 49.932 ms
times + + ;
if (times == 3) {
printf("Feeding the dog successfully \
");
HAL_WWDG_Refresh( & amp;hwwdg); //Feed the dog
} else if (times == 5) {
times = 0;
printf("Timeout to feed the dog!!! \
");
}
\t\t\t
}
}
}

/* USER CODE END 1 */

3. wwdg.c file
API corresponding to HAL library

HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg); //Watchdog initialization
HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg); //Feed the dog
HAL_WWDG_IRQHandler(WWDG_HandleTypeDef *hwwdg); //Watchdog interrupt processing function

//Function: Determine whether the interrupt is normal and enter the interrupt callback function
__weak HAL_WWDG_EarlyWakeupCallback(hwwdg); //Watchdog interrupt callback function
/* USER CODE BEGIN Header */
/**
  *************************************************** ******************************
  * @file wwdg.c
  * @brief This file provides code for the configuration
  * of the WWDG 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 "wwdg.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

WWDG_HandleTypeDef hwwdg;

/* WWDG init function */
void MX_WWDG_Init(void)
{

  /* USER CODE BEGIN WWDG_Init 0 */

  /* USER CODE END WWDG_Init 0 */

  /* USER CODE BEGIN WWDG_Init 1 */

  /* USER CODE END WWDG_Init 1 */
  hwwdg.Instance = WWDG;
  hwwdg.Init.Prescaler = WWDG_PRESCALER_8;
  hwwdg.Init.Window = 95;
  hwwdg.Init.Counter = 127;
  hwwdg.Init.EWIMode = WWDG_EWI_ENABLE;
  if (HAL_WWDG_Init( & amp;hwwdg) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN WWDG_Init 2 */
  
  /* USER CODE END WWDG_Init 2 */

}

void HAL_WWDG_MspInit(WWDG_HandleTypeDef* wwdgHandle)
{

  if(wwdgHandle->Instance==WWDG)
  {
  /* USER CODE BEGIN WWDG_MspInit 0 */

  /* USER CODE END WWDG_MspInit 0 */
    /* WWDG clock enable */
    __HAL_RCC_WWDG_CLK_ENABLE();

    /* WWDG interrupt Init */
    HAL_NVIC_SetPriority(WWDG_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(WWDG_IRQn);
  /* USER CODE BEGIN WWDG_MspInit 1 */

  /* USER CODE END WWDG_MspInit 1 */
  }
}

/* USER CODE BEGIN 1 */
#include "stdio.h"

void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hwwdg);
  printf("callback timeout to feed the dog\r\
");
}
/* USER CODE END 1 */

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 "tim.h"
#include "usart.h"
#include "wwdg.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_WWDG_Init();
  /* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT( & amp;htim1);
printf("heihei wwdg \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_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_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.