diff --git a/.gitignore b/.gitignore index 87bd11bd..d8ee8c98 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,11 @@ MDK-ARM/RTE/ # STM32CubeMX (keep .ioc, it's the project source) # *.ioc +# CubeMX 重生成时自动产生的旧文件备份(Src/Backup/、Inc/Backup/)—— +# 纯本地临时物,内容 = 重生成前的快照;入库只会造成无意义的提交抖动 +Src/Backup/ +Inc/Backup/ + # Visual Studio / IDE .vs/ .vscode/ diff --git a/.mxproject b/.mxproject index 3bf2cca4..4c585c40 100644 --- a/.mxproject +++ b/.mxproject @@ -1,13 +1,13 @@ [PreviousLibFiles] -LibFiles=Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_tim.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_tim_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_bus.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_system.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_utils.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ramfunc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dmamux.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal.h;Drivers\STM32F4xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_def.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_i2c.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_i2c.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_i2c_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_uart.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_usart.h;Middlewares\Third_Party\FreeRTOS\Source\include\croutine.h;Middlewares\Third_Party\FreeRTOS\Source\include\deprecated_definitions.h;Middlewares\Third_Party\FreeRTOS\Source\include\event_groups.h;Middlewares\Third_Party\FreeRTOS\Source\include\FreeRTOS.h;Middlewares\Third_Party\FreeRTOS\Source\include\list.h;Middlewares\Third_Party\FreeRTOS\Source\include\message_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_prototypes.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_wrappers.h;Middlewares\Third_Party\FreeRTOS\Source\include\portable.h;Middlewares\Third_Party\FreeRTOS\Source\include\projdefs.h;Middlewares\Third_Party\FreeRTOS\Source\include\queue.h;Middlewares\Third_Party\FreeRTOS\Source\include\semphr.h;Middlewares\Third_Party\FreeRTOS\Source\include\stack_macros.h;Middlewares\Third_Party\FreeRTOS\Source\include\StackMacros.h;Middlewares\Third_Party\FreeRTOS\Source\include\stream_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\task.h;Middlewares\Third_Party\FreeRTOS\Source\include\timers.h;Middlewares\Third_Party\FreeRTOS\Source\include\atomic.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_mpool.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_os2.h;Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\portmacro.h;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_tim.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_tim_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_spi.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c;Middlewares\Third_Party\FreeRTOS\Source\croutine.c;Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;Middlewares\Third_Party\FreeRTOS\Source\list.c;Middlewares\Third_Party\FreeRTOS\Source\queue.c;Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;Middlewares\Third_Party\FreeRTOS\Source\tasks.c;Middlewares\Third_Party\FreeRTOS\Source\timers.c;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\port.c;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_tim.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_tim_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_bus.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_system.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_utils.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ramfunc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dmamux.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal.h;Drivers\STM32F4xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_def.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_i2c.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_i2c.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_i2c_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_uart.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_usart.h;Middlewares\Third_Party\FreeRTOS\Source\include\croutine.h;Middlewares\Third_Party\FreeRTOS\Source\include\deprecated_definitions.h;Middlewares\Third_Party\FreeRTOS\Source\include\event_groups.h;Middlewares\Third_Party\FreeRTOS\Source\include\FreeRTOS.h;Middlewares\Third_Party\FreeRTOS\Source\include\list.h;Middlewares\Third_Party\FreeRTOS\Source\include\message_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_prototypes.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_wrappers.h;Middlewares\Third_Party\FreeRTOS\Source\include\portable.h;Middlewares\Third_Party\FreeRTOS\Source\include\projdefs.h;Middlewares\Third_Party\FreeRTOS\Source\include\queue.h;Middlewares\Third_Party\FreeRTOS\Source\include\semphr.h;Middlewares\Third_Party\FreeRTOS\Source\include\stack_macros.h;Middlewares\Third_Party\FreeRTOS\Source\include\StackMacros.h;Middlewares\Third_Party\FreeRTOS\Source\include\stream_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\task.h;Middlewares\Third_Party\FreeRTOS\Source\include\timers.h;Middlewares\Third_Party\FreeRTOS\Source\include\atomic.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_mpool.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_os2.h;Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\portmacro.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\stm32f407xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\stm32f4xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\system_stm32f4xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\system_stm32f4xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c;Drivers\CMSIS\Include\cachel1_armv7.h;Drivers\CMSIS\Include\cmsis_armcc.h;Drivers\CMSIS\Include\cmsis_armclang.h;Drivers\CMSIS\Include\cmsis_armclang_ltm.h;Drivers\CMSIS\Include\cmsis_compiler.h;Drivers\CMSIS\Include\cmsis_gcc.h;Drivers\CMSIS\Include\cmsis_iccarm.h;Drivers\CMSIS\Include\cmsis_version.h;Drivers\CMSIS\Include\core_armv81mml.h;Drivers\CMSIS\Include\core_armv8mbl.h;Drivers\CMSIS\Include\core_armv8mml.h;Drivers\CMSIS\Include\core_cm0.h;Drivers\CMSIS\Include\core_cm0plus.h;Drivers\CMSIS\Include\core_cm1.h;Drivers\CMSIS\Include\core_cm23.h;Drivers\CMSIS\Include\core_cm3.h;Drivers\CMSIS\Include\core_cm33.h;Drivers\CMSIS\Include\core_cm35p.h;Drivers\CMSIS\Include\core_cm4.h;Drivers\CMSIS\Include\core_cm55.h;Drivers\CMSIS\Include\core_cm7.h;Drivers\CMSIS\Include\core_cm85.h;Drivers\CMSIS\Include\core_sc000.h;Drivers\CMSIS\Include\core_sc300.h;Drivers\CMSIS\Include\core_starmc1.h;Drivers\CMSIS\Include\mpu_armv7.h;Drivers\CMSIS\Include\mpu_armv8.h;Drivers\CMSIS\Include\pac_armv81.h;Drivers\CMSIS\Include\pmu_armv8.h;Drivers\CMSIS\Include\tz_context.h; +LibFiles=Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_tim.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_tim_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_bus.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_system.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_utils.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ramfunc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dmamux.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal.h;Drivers\STM32F4xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_def.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_i2c.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_i2c.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_i2c_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_iwdg.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_iwdg.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_uart.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_usart.h;Middlewares\Third_Party\FreeRTOS\Source\include\croutine.h;Middlewares\Third_Party\FreeRTOS\Source\include\deprecated_definitions.h;Middlewares\Third_Party\FreeRTOS\Source\include\event_groups.h;Middlewares\Third_Party\FreeRTOS\Source\include\FreeRTOS.h;Middlewares\Third_Party\FreeRTOS\Source\include\list.h;Middlewares\Third_Party\FreeRTOS\Source\include\message_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_prototypes.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_wrappers.h;Middlewares\Third_Party\FreeRTOS\Source\include\portable.h;Middlewares\Third_Party\FreeRTOS\Source\include\projdefs.h;Middlewares\Third_Party\FreeRTOS\Source\include\queue.h;Middlewares\Third_Party\FreeRTOS\Source\include\semphr.h;Middlewares\Third_Party\FreeRTOS\Source\include\stack_macros.h;Middlewares\Third_Party\FreeRTOS\Source\include\StackMacros.h;Middlewares\Third_Party\FreeRTOS\Source\include\stream_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\task.h;Middlewares\Third_Party\FreeRTOS\Source\include\timers.h;Middlewares\Third_Party\FreeRTOS\Source\include\atomic.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_mpool.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_os2.h;Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\portmacro.h;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_tim.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_tim_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_iwdg.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_spi.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c;Middlewares\Third_Party\FreeRTOS\Source\croutine.c;Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;Middlewares\Third_Party\FreeRTOS\Source\list.c;Middlewares\Third_Party\FreeRTOS\Source\queue.c;Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;Middlewares\Third_Party\FreeRTOS\Source\tasks.c;Middlewares\Third_Party\FreeRTOS\Source\timers.c;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\port.c;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_tim.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_tim_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_bus.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_system.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_utils.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ramfunc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dmamux.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal.h;Drivers\STM32F4xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_def.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_i2c.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_i2c.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_i2c_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_iwdg.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_iwdg.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_uart.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_usart.h;Middlewares\Third_Party\FreeRTOS\Source\include\croutine.h;Middlewares\Third_Party\FreeRTOS\Source\include\deprecated_definitions.h;Middlewares\Third_Party\FreeRTOS\Source\include\event_groups.h;Middlewares\Third_Party\FreeRTOS\Source\include\FreeRTOS.h;Middlewares\Third_Party\FreeRTOS\Source\include\list.h;Middlewares\Third_Party\FreeRTOS\Source\include\message_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_prototypes.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_wrappers.h;Middlewares\Third_Party\FreeRTOS\Source\include\portable.h;Middlewares\Third_Party\FreeRTOS\Source\include\projdefs.h;Middlewares\Third_Party\FreeRTOS\Source\include\queue.h;Middlewares\Third_Party\FreeRTOS\Source\include\semphr.h;Middlewares\Third_Party\FreeRTOS\Source\include\stack_macros.h;Middlewares\Third_Party\FreeRTOS\Source\include\StackMacros.h;Middlewares\Third_Party\FreeRTOS\Source\include\stream_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\task.h;Middlewares\Third_Party\FreeRTOS\Source\include\timers.h;Middlewares\Third_Party\FreeRTOS\Source\include\atomic.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_mpool.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_os2.h;Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\portmacro.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\stm32f407xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\stm32f4xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\system_stm32f4xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\system_stm32f4xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c;Drivers\CMSIS\Include\cachel1_armv7.h;Drivers\CMSIS\Include\cmsis_armcc.h;Drivers\CMSIS\Include\cmsis_armclang.h;Drivers\CMSIS\Include\cmsis_armclang_ltm.h;Drivers\CMSIS\Include\cmsis_compiler.h;Drivers\CMSIS\Include\cmsis_gcc.h;Drivers\CMSIS\Include\cmsis_iccarm.h;Drivers\CMSIS\Include\cmsis_version.h;Drivers\CMSIS\Include\core_armv81mml.h;Drivers\CMSIS\Include\core_armv8mbl.h;Drivers\CMSIS\Include\core_armv8mml.h;Drivers\CMSIS\Include\core_cm0.h;Drivers\CMSIS\Include\core_cm0plus.h;Drivers\CMSIS\Include\core_cm1.h;Drivers\CMSIS\Include\core_cm23.h;Drivers\CMSIS\Include\core_cm3.h;Drivers\CMSIS\Include\core_cm33.h;Drivers\CMSIS\Include\core_cm35p.h;Drivers\CMSIS\Include\core_cm4.h;Drivers\CMSIS\Include\core_cm55.h;Drivers\CMSIS\Include\core_cm7.h;Drivers\CMSIS\Include\core_cm85.h;Drivers\CMSIS\Include\core_sc000.h;Drivers\CMSIS\Include\core_sc300.h;Drivers\CMSIS\Include\core_starmc1.h;Drivers\CMSIS\Include\mpu_armv7.h;Drivers\CMSIS\Include\mpu_armv8.h;Drivers\CMSIS\Include\pac_armv81.h;Drivers\CMSIS\Include\pmu_armv8.h;Drivers\CMSIS\Include\tz_context.h; [PreviousUsedKeilFiles] -SourceFiles=..\Src\main.c;..\Src\gpio.c;..\Src\freertos.c;..\Src\dma.c;..\Src\i2c.c;..\Src\spi.c;..\Src\usart.c;..\Src\stm32f4xx_it.c;..\Src\stm32f4xx_hal_msp.c;..\Src\stm32f4xx_hal_timebase_tim.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_tim.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_tim_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_spi.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c;..\Middlewares\Third_Party\FreeRTOS\Source\croutine.c;..\Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;..\Middlewares\Third_Party\FreeRTOS\Source\list.c;..\Middlewares\Third_Party\FreeRTOS\Source\queue.c;..\Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;..\Middlewares\Third_Party\FreeRTOS\Source\tasks.c;..\Middlewares\Third_Party\FreeRTOS\Source\timers.c;..\Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\port.c;..\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c;..\\Src\system_stm32f4xx.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_tim.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_tim_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_spi.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c;..\Middlewares\Third_Party\FreeRTOS\Source\croutine.c;..\Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;..\Middlewares\Third_Party\FreeRTOS\Source\list.c;..\Middlewares\Third_Party\FreeRTOS\Source\queue.c;..\Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;..\Middlewares\Third_Party\FreeRTOS\Source\tasks.c;..\Middlewares\Third_Party\FreeRTOS\Source\timers.c;..\Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\port.c;..\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c;..\\Src\system_stm32f4xx.c;;; +SourceFiles=..\Src\main.c;..\Src\gpio.c;..\Src\freertos.c;..\Src\dma.c;..\Src\i2c.c;..\Src\iwdg.c;..\Src\spi.c;..\Src\usart.c;..\Src\stm32f4xx_it.c;..\Src\stm32f4xx_hal_msp.c;..\Src\stm32f4xx_hal_timebase_tim.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_tim.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_tim_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_iwdg.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_spi.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c;..\Middlewares\Third_Party\FreeRTOS\Source\croutine.c;..\Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;..\Middlewares\Third_Party\FreeRTOS\Source\list.c;..\Middlewares\Third_Party\FreeRTOS\Source\queue.c;..\Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;..\Middlewares\Third_Party\FreeRTOS\Source\tasks.c;..\Middlewares\Third_Party\FreeRTOS\Source\timers.c;..\Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\port.c;..\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c;..\\Src\system_stm32f4xx.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_tim.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_tim_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_iwdg.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_spi.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c;..\Middlewares\Third_Party\FreeRTOS\Source\croutine.c;..\Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;..\Middlewares\Third_Party\FreeRTOS\Source\list.c;..\Middlewares\Third_Party\FreeRTOS\Source\queue.c;..\Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;..\Middlewares\Third_Party\FreeRTOS\Source\tasks.c;..\Middlewares\Third_Party\FreeRTOS\Source\timers.c;..\Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;..\Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F\port.c;..\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c;..\\Src\system_stm32f4xx.c;;; HeaderPath=..\Drivers\STM32F4xx_HAL_Driver\Inc;..\Drivers\STM32F4xx_HAL_Driver\Inc\Legacy;..\Middlewares\Third_Party\FreeRTOS\Source\include;..\Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2;..\Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F;..\Drivers\CMSIS\Device\ST\STM32F4xx\Include;..\Drivers\CMSIS\Include;..\Inc; CDefines=USE_HAL_DRIVER;STM32F407xx;USE_HAL_DRIVER;USE_HAL_DRIVER; [PreviousGenFiles] HeaderPath=..\Inc -HeaderFiles=gpio.h;FreeRTOSConfig.h;dma.h;i2c.h;spi.h;usart.h;stm32f4xx_it.h;stm32f4xx_hal_conf.h;main.h; +HeaderFiles=gpio.h;FreeRTOSConfig.h;dma.h;i2c.h;iwdg.h;spi.h;usart.h;stm32f4xx_it.h;stm32f4xx_hal_conf.h;main.h; SourcePath=..\Src -SourceFiles=gpio.c;freertos.c;dma.c;i2c.c;spi.c;usart.c;stm32f4xx_it.c;stm32f4xx_hal_msp.c;stm32f4xx_hal_timebase_tim.c;main.c; +SourceFiles=gpio.c;freertos.c;dma.c;i2c.c;iwdg.c;spi.c;usart.c;stm32f4xx_it.c;stm32f4xx_hal_msp.c;stm32f4xx_hal_timebase_tim.c;main.c; diff --git a/App/app/app_main.c b/App/app/app_main.c index 0d3adfd2..dbbf67f2 100644 --- a/App/app/app_main.c +++ b/App/app/app_main.c @@ -28,6 +28,53 @@ /* g_rs485 由 rs485.c 定义,经 rs485.h 的 extern 引用;接收缓冲内聚于句柄 rx_buf */ +/* 复位原因锁存值(Src/main.c 在 HAL_Init() 后立即写入并清除 RCC_CSR)。 + * 放这里而非 main.c,是因为需要与其它应用级全局量同层、且日志侧更好引用。 */ +volatile uint32_t g_rcc_csr_latched; + +/* + * 函数功能:把 RCC_CSR 锁存值翻译为可读的复位原因串(见手册 RM0090 §6.3.22) + * 入口参数:csr - 锁存的 RCC_CSR 值 + * buf - 输出缓冲 + * len - 缓冲容量 + * 返回值:无 + * 函数说明:按"最可信归因"的优先级组织——IWDG/WWDG 优先于软件复位 + * (看门狗复位是我们真正关心的自动恢复事件;软件复位多为崩溃钩子 + * 兜底,两者同时置位时报告看门狗更有价值)。纯 ASCII,防编码坑。 + */ +static void reset_cause_str(uint32_t csr, char *buf, unsigned int len) { + const char *cause; + + if ((csr & RCC_CSR_IWDGRSTF) != 0u) { + cause = "IWDG (independent watchdog)"; + } else if ((csr & RCC_CSR_WWDGRSTF) != 0u) { + cause = "WWDG (window watchdog)"; + } else if ((csr & RCC_CSR_SFTRSTF) != 0u) { + cause = "software (NVIC_SystemReset)"; + } else if ((csr & RCC_CSR_PORRSTF) != 0u) { + cause = "power-on (POR)"; + } else if ((csr & RCC_CSR_PINRSTF) != 0u) { + cause = "external pin (NRST)"; + } else if ((csr & RCC_CSR_BORRSTF) != 0u) { + cause = "brown-out (BOR)"; + } else { + cause = "unknown"; + } + + /* 简单有界拼接(不引 snprintf,避免依赖与栈开销) */ + if (buf == NULL || len == 0u) { + return; + } + { + unsigned int i = 0u; + while ((i < (len - 1u)) && (cause[i] != '\0')) { + buf[i] = cause[i]; + i++; + } + buf[i] = '\0'; + } +} + /* * 函数功能:应用层初始化 * 入口参数:无 @@ -46,6 +93,21 @@ int app_main_init(void) { /* 日志引擎初始化(创建待发队列;须先于任何 syslog_post) */ (void)syslog_mcu_init(); + /* 0) 复位原因上报(锁存值由 Src/main.c 在 HAL_Init() 后立即采得)。 + * 放在日志引擎之后、业务初始化之前:任何一次非上电复位都值得在 + * 开机第一时间看到——尤其 IWDG,它意味着上一轮运行有任务卡死。 + * 注意:RCC_CSR 已被 main.c 清零,本处只读锁存副本。 */ + { + char cause[40]; + uint32_t csr = g_rcc_csr_latched; + reset_cause_str(csr, cause, sizeof(cause)); + DBG_INFO("reset cause: %s (CSR=0x%08lX)", cause, (unsigned long)csr); + /* 看门狗复位记入自检记录(只记载故障,符合既有约定) */ + if ((csr & (RCC_CSR_IWDGRSTF | RCC_CSR_WWDGRSTF)) != 0u) { + syslog_post(SYSLOG_SELFTEST, "watchdog reset"); + } + } + /* * 1) 时间子系统初始化(尽早完成,后续所有日志带时间戳) * sd2506_init() 从 RTC 读取初始时间 diff --git a/App/sync/time_sync.c b/App/sync/time_sync.c index 0f090458..2a9f5f82 100644 --- a/App/sync/time_sync.c +++ b/App/sync/time_sync.c @@ -17,6 +17,7 @@ #include "net_socket.h" #include "sys_clock.h" #include "sys_events.h" +#include "task_watchdog.h" #define DBG_TAG "[TIME_SYNC]" #include "dbg_log.h" @@ -36,6 +37,11 @@ */ #define TIME_SYNC_TOTAL_BUDGET_MS 30000U +/* 看门狗分片等待:单次 net_recv_to 的等待片长上限。须显著小于看门狗抽样窗 + * (task_watchdog.c WD_POLL_PERIOD_MS=100ms)的容错窗口(8 窗 = 800ms), + * 200ms 留足余量;语义上仅把一次长等待拆成多次短等待,总预算不变。 */ +#define TIME_SYNC_WAIT_SLICE_MS 200U + /* * 函数功能:创建并监听 TCP 时间同步服务端口 * 入口参数:无 @@ -49,6 +55,7 @@ static int time_sync_open_listener(void) { int retry; for (retry = 0; retry < 5; retry++) { + task_wd_beat(TASK_WD_TIMESYNC); /* 每次重试前喂心跳(见下方 500ms/2000ms 延时) */ int s = net_socket(NET_AF_INET, NET_SOCK_STREAM); if (s < 0) { DBG_ERROR("time_sync: net_socket FAIL"); @@ -65,6 +72,7 @@ static int time_sync_open_listener(void) { if (net_bind(s, (struct net_sockaddr *)&addr, sizeof(addr)) != 0) { DBG_ERROR("time_sync: bind port %d FAIL", TIME_SYNC_PORT); net_close(s); + task_wd_beat(TASK_WD_TIMESYNC); vTaskDelay(pdMS_TO_TICKS(2000)); continue; } @@ -72,6 +80,7 @@ static int time_sync_open_listener(void) { if (net_listen(s) != 0) { DBG_ERROR("time_sync: listen FAIL"); net_close(s); + task_wd_beat(TASK_WD_TIMESYNC); vTaskDelay(pdMS_TO_TICKS(2000)); continue; } @@ -99,7 +108,11 @@ static void time_sync_handle_conn(int conn_sock) { while (got < (int)sizeof(buf)) { /* 单次预算 = 剩余总预算(L3 pending:等待期 netTask 零占用,调用方 - * 在自己上下文睡任务通知,旧片间 vTaskDelay(1) 让出退役) */ + * 在自己上下文睡任务通知,旧片间 vTaskDelay(1) 让出退役) + * ⚠ 看门狗约束:本任务在 required_mask 内,而单次 net_recv_to 可睡满 + * 30s 预算 —— 等待期必须周期性喂心跳,否则"对端连上但不发时间包"这种 + * 完全正常的场景会被判为任务卡死(见设计说明 §4.4 长耗时白名单)。 + * 做法:把长等待切成 WD 窗口内的短片(片长 ≤200ms),每片先喂心跳。 */ TickType_t elapsed = xTaskGetTickCount() - t0; uint32_t rem = (elapsed >= (TickType_t)pdMS_TO_TICKS(TIME_SYNC_TOTAL_BUDGET_MS)) ? 0U : (uint32_t)((TickType_t)TIME_SYNC_TOTAL_BUDGET_MS - elapsed); @@ -107,6 +120,10 @@ static void time_sync_handle_conn(int conn_sock) { DBG_INFO("time_sync: no TIME packet in 30s, drop conn"); break; /* 总预算耗尽(语义同旧 30s 超时) */ } + task_wd_beat(TASK_WD_TIMESYNC); + if (rem > TIME_SYNC_WAIT_SLICE_MS) { + rem = TIME_SYNC_WAIT_SLICE_MS; /* 分片:等待期保持心跳节奏 */ + } int n = net_recv_to(conn_sock, buf + got, (int)(sizeof(buf) - got), rem); if (n > 0) { got += n; @@ -119,7 +136,7 @@ static void time_sync_handle_conn(int conn_sock) { break; /* 对端关闭(EOF) */ } if (n == -2) { - continue; /* 本次预算等满无数据 → 下轮 rem=0 退出 */ + continue; /* 本片预算等满无数据 → 下一片重算剩余预算 */ } break; /* 真错误 */ } @@ -157,12 +174,17 @@ void time_sync_task(void *argument) { } for (;;) { + /* 心跳:本任务在 required_mask 内。以下每一处可能长于 100ms 抽样窗的 + * 阻塞点(监听重试 2s、accept 轮询 200ms/次、收尾 50ms)都就近补心跳。 */ + task_wd_beat(TASK_WD_TIMESYNC); + /* 记录本次监听对应的网络代次;代次变化(网络重建)则放弃旧监听重建 */ uint32_t gen = net_get_generation(); int ls = time_sync_open_listener(); if (ls < 0) { DBG_ERROR("time_sync: open listener FAIL, retry later"); + task_wd_beat(TASK_WD_TIMESYNC); vTaskDelay(pdMS_TO_TICKS(2000)); continue; } @@ -176,6 +198,7 @@ void time_sync_task(void *argument) { net_close(ls); /* 网络重建:旧监听失效,回外层重建 */ break; } + task_wd_beat(TASK_WD_TIMESYNC); vTaskDelay(pdMS_TO_TICKS(200)); } } while (conn < 0); @@ -188,6 +211,7 @@ void time_sync_task(void *argument) { time_sync_handle_conn(conn); /* conn(单连接模式下即 ls)已被 net_close 释放,下次循环重建监听 */ + task_wd_beat(TASK_WD_TIMESYNC); vTaskDelay(pdMS_TO_TICKS(50)); } } diff --git a/App/task/default_task.c b/App/task/default_task.c index 33610f01..4687dafa 100644 --- a/App/task/default_task.c +++ b/App/task/default_task.c @@ -30,6 +30,7 @@ #include "sys_log.h" #include "sys_events.h" #include "dbg_log.h" +#include "task_watchdog.h" /* 任务句柄与属性块(CubeMX 生成全局,定义于 Src/freertos.c): * 栈水位观测需 6 任务句柄 + 属性块 stack_size(配置栈大小的唯一定义处) */ @@ -149,7 +150,19 @@ void default_task_func(void *argument) { * 并让脏指针无法再进入 HAL_UART_Transmit 的缓冲遍历。 */ dbg_console_writer_attach(); + /* 启动看门狗(延后启动):此处位于全部长耗时初始化之后——存储 bring-up 深链 + * (mount/mkfs/FAT 探针/syslog 挂载/配置加载)已完成,监视一开始即处于稳态。 + * 这正是"启动段不喂狗、主循环段才喂"的落点(见 docs/子系统设计/看门狗设计说明.md + * §4.5 决策 C):MX_IWDG_Init() 只填参数不启动,启动延后到此时。 + * 代价(显式声明):从复位到此处约数秒的窗口无看门狗保护,该段死机表现为 + * "无任何输出 + LED 不闪",可人工辨识。 */ + task_wd_start(); + for (;;) { + /* 心跳抽样与喂狗判定(内部节流至 100ms;全员到位才喂,否则累计停喂) */ + task_wd_poll(); + /* 本任务自己的心跳 */ + task_wd_beat(TASK_WD_DEFAULT); /* 等待"保存网络配置"或"控制台待发":任一即醒;无事件 50ms 后返回 * (日志时延 = 事件唤醒,实测无丢失;50ms 兜底仅防事件位异常) */ if (sys_evtHandle != NULL) { diff --git a/App/task/net_task.c b/App/task/net_task.c index 76541549..a401540b 100644 --- a/App/task/net_task.c +++ b/App/task/net_task.c @@ -28,6 +28,7 @@ #include "sys_events.h" #include "sys_log.h" #include "test_config.h" /* 测试模式宏(ENABLE_HW_LAYER_TESTS);产品构建全未定义,无作用 */ +#include "task_watchdog.h" #define DBG_TAG "[NET_TASK]" #include "dbg_log.h" @@ -112,6 +113,10 @@ int net_stack_bring_up(void) { if (phy != CH395F_PHY_DISCONN) { break; } + /* 心跳埋点:本循环单次最长约 1.1s(含 PHY 仍未就绪的 60 次迭代里 + * 每次 50ms 延时叠加),远超看门狗 100ms 抽样窗——必须在延时段补心跳, + * 否则 PHY 未插网线时本任务会被误判为卡死(见设计说明 §4.4 长耗时白名单) */ + task_wd_beat(TASK_WD_NET); osDelay(50); } DBG_INFO("PHY: %s", @@ -166,6 +171,9 @@ void net_task_func(void const *arg) { #if defined(ENABLE_HW_LAYER_TESTS) DBG_INFO("netTask parked: HW-layer test mode, CH395F owned by testTask"); for (;;) { + /* 该模式下本任务已被 task_wd_required_mask() 剔除,喂心跳无副作用; + * 保留埋点以免掩码配置变更时意外误杀 */ + task_wd_beat(TASK_WD_NET); osDelay(1000); } #endif @@ -196,6 +204,10 @@ void net_task_func(void const *arg) { /* ==================== 主轮询循环 ==================== */ for (;;) { + /* 心跳:本任务在监视掩码内(ENABLE_HW_LAYER_TESTS 下由 task_wd_required_mask + * 剔除,本埋点无副作用) */ + task_wd_beat(TASK_WD_NET); + /* UI 保存网口配置后请求立即应用:在此重建网络(新 IP/掩码/网关/MAC)。 * 重建完成后代次号已递增,各 TCP 服务据此重建监听;期间连接会断开(预期)。 */ if (sys_evtHandle != NULL diff --git a/App/task/ui_task.c b/App/task/ui_task.c index 21a4b903..ca8a4e9c 100644 --- a/App/task/ui_task.c +++ b/App/task/ui_task.c @@ -21,6 +21,7 @@ #include "sys_clock.h" #include "test_config.h" /* TEST_LATENCY_PROBE(链路时延探针编译开关) */ #include "net_latency_test.h" /* M3 探针:ui_loop(生产循环实测周期) */ +#include "task_watchdog.h" /* * 函数功能:待机屏底部时钟提供回调(平台差异:MCU = sys_clock_get_str) @@ -63,6 +64,9 @@ static void ui_task_wait_net_ready(void) { void ui_task_func(void *argument) { (void)argument; + /* 等待网络就绪期间不可能喂狗:本任务此时尚未进入主循环,而就绪位由 netTask 置位。 + * 该段若长期不成立,看门狗会复位——这是期望行为(网络 bring-up 卡死须暴露)。 + * 注意本任务在 required_mask 内,主循环跑起来后须保证每 100ms 窗口内至少喂一次。 */ DBG_INFO("UI task: started, wait net ready"); ui_task_wait_net_ready(); DBG_INFO("UI task: net ready, init port"); @@ -108,6 +112,9 @@ void ui_task_func(void *argument) { #endif ui_port_step(10); ui_net_sink_poll(); + /* 心跳:ui_port_step 内含 LVGL 渲染,单轮耗时可能逼近 10ms 量级; + * 100ms 抽样窗内可容纳多轮,此埋点足够 */ + task_wd_beat(TASK_WD_UI); osDelay(10); } } diff --git a/App/util/task_watchdog.c b/App/util/task_watchdog.c new file mode 100644 index 00000000..2b854559 --- /dev/null +++ b/App/util/task_watchdog.c @@ -0,0 +1,201 @@ +/* + * 模块名称:Task Watchdog(IWDG + 任务心跳位图) + * 模块功能:把独立看门狗(IWDG)与"全部任务存活"绑定,使单任务死锁/饿死/ + * 断言挂死可自动复位恢复,而非人工断电。 + * 核心语义:喂狗 = "所有被监视任务都在抽样窗口内动过"。 + * 适用平台:STM32F407ZGTx + FreeRTOS(CMSIS-RTOS V2) + * 作者:王建锋 + * 创建日期:2026-09-29 + * 修改记录: + * v1.0 2026-09-29 王建锋 创建:心跳位图 + 抽样判定 + IWDG 延后启动 + * + * 设计依据:docs/子系统设计/看门狗设计说明.md + * - §3.1 为何不用"每任务各自喂狗"(那只检测全系统同时挂死) + * - §3.3 为何用"单字位图 + 取走清零"(免临界区,天然原子) + * - §4.3 超时与窗口的取值推导(含 LSI 偏快 47kHz 的最坏情况校验) + * - §4.5 为何由 defaultTask 在 bring-up 完成后启动 + * - §5.3 为何"停喂"而不直接 NVIC_SystemReset(保留 IWDGRSTF 权威归因) + * + * ⚠ 本模块不创建任何 FreeRTOS/CMSIS-RTOS 对象,可安全用于内核启动前后的上下文。 + */ + +#include "task_watchdog.h" +#include "main.h" /* HAL_GetTick()(HAL 时基 = TIM7,1ms) */ +#include "iwdg.h" /* hiwdg 参数来源(CubeMX 生成,见 Src/iwdg.c) */ + +#define DBG_TAG "[WD]" +#include "dbg_log.h" + +/* Private defines -----------------------------------------------------------*/ + +/* 抽样周期:defaultTask 主循环为 50ms 基准,100ms 是其整数倍(见 §4.3) */ +#define WD_POLL_PERIOD_MS 100u + +/* 连续未达标容忍次数:8 × 100ms = 800ms。 + * 需容纳 NAND 擦写(最坏数百 ms)等长耗时操作,同时远小于 IWDG 最坏超时 + * 1701ms,保证"停喂后仍能复上电"(§4.3 的包含关系) */ +#define WD_MISS_TOLERANCE 8u + +/* IWDG 超时参数:PR=4 → 64 分频;RLR=1249 + * 标称 64 × 1249 / 32000 ≈ 2498 ms + * 最坏 64 × 1249 / 47000 ≈ 1701 ms(LSI 偏快时超时变短,按最坏校核) */ +#define WD_IWDG_PRESCALER 4u +#define WD_IWDG_RELOAD 1249u + +/* Private types -------------------------------------------------------------*/ + +/* Private variables ---------------------------------------------------------*/ + +/* 心跳位图:各任务只置位,校验者"取走并清零"。 + * 单字读-改-写在 Cortex-M4 上天然原子,无需临界区(§3.3) */ +static volatile uint32_t s_hb_bits; + +static uint32_t s_miss_streak; /* 连续未达标轮数(达到容忍上限即停喂) */ +static uint32_t s_miss_total; /* 累计未达标轮数(观测用) */ +static uint32_t s_last_mask; /* 上次抽样到的位图(定位卡死任务用) */ +static uint32_t s_started; /* 1 = IWDG 已启动 */ + +/* Private function prototypes -----------------------------------------------*/ + +static uint32_t wd_required_mask(void); + +/* Private functions ---------------------------------------------------------*/ + +/* + * 函数功能:必需心跳位掩码(编译期按构建配置生成) + * 入口参数:无 + * 返回值:本次构建要求"必须动过"的任务位集合 + * 限定条件:无 + * 函数说明:按 §4.1/§4.2 的设计,监视范围随构建配置变化: + * - testTask 仅在启用测试套件时创建 + * - netTask 在 ENABLE_HW_LAYER_TESTS 下入口即自挂起(不干活), + * 不要求其心跳,否则该构建永不喂狗 + * 注:ftpTask 当前统一纳入(其主循环为 lftpd 事件循环,需在 + * lftpd 侧埋点;若某构建下 ftpTask 不创建,句柄检查兜底)。 + */ +static uint32_t wd_required_mask(void) { + uint32_t m = (1u << (uint32_t)TASK_WD_DEFAULT) + | (1u << (uint32_t)TASK_WD_NET) + | (1u << (uint32_t)TASK_WD_FTP) + | (1u << (uint32_t)TASK_WD_UI) + | (1u << (uint32_t)TASK_WD_TIMESYNC); + + /* netTask 自挂起(CH395F 由 testTask 独占):不要求心跳 */ +#if defined(ENABLE_HW_LAYER_TESTS) + m &= ~(1u << (uint32_t)TASK_WD_NET); +#endif + + return m; +} + +/* Public functions ----------------------------------------------------------*/ + +/* + * 函数功能:任务心跳置位 + * 入口参数:id - 任务 ID(见 task_watchdog.h) + * 返回值:无 + * 限定条件:可在任意上下文调用(单字写,无内核对象依赖) + * 函数说明:各任务在自己的主循环里调用。仅 1~2 条指令。 + */ +void task_wd_beat(task_wd_id_t id) { + if ((uint32_t)id < (uint32_t)TASK_WD_ID_MAX) { + s_hb_bits |= (1u << (uint32_t)id); + } +} + +/* + * 函数功能:启动 IWDG(延后启动,由 defaultTask 在 bring-up 完成后调用) + * 入口参数:无 + * 返回值:无 + * 限定条件:仅 defaultTask 调用;须在 osKernelStart 之后(本函数只用 HAL/寄存器) + * 函数说明:MX_IWDG_Init() 已把参数填入全局 hiwdg(Prescaler/Reload 由 CubeMX + * 在 Src/iwdg.c 生成区维护),但不启动(见该文件 IWDG_DEFER_START 注释)。 + * 此处才真正写 IWDG_Key 启动——使"启动段不喂狗"成立(§4.5)。 + * IWDG 一旦启动不可停,只能靠复位终止。 + */ +void task_wd_start(void) { + if (s_started != 0u) { + return; + } + s_started = 1u; + + /* 启动前先喂一次:让首个抽样窗口从"启动时刻"起算, + * 而非从 MX_IWDG_Init 的时刻起算(避免启动后立即超时) */ + IWDG->KR = 0x0000AAAAu; /* 重装计数器(喂狗) */ + IWDG->KR = 0x0000CCCCu; /* 启动看门狗 */ + + DBG_INFO("[WD] armed: timeout ~2498ms (worst ~1701ms), miss_tol=800ms"); +} + +/* + * 函数功能:心跳抽样与喂狗判定(defaultTask 主循环调用) + * 入口参数:无 + * 返回值:无 + * 限定条件:仅 defaultTask 主循环调用(唯一喂狗者);内部节流到 100ms 一次 + * 函数说明:取走并清零位图 → 与必需掩码比较: + * 全中 → 清零缺失计数并喂狗; + * 有缺 → 累计;连续达到 WD_MISS_TOLERANCE 次后**停止喂狗**, + * 让 IWDG 自然溢出复位(这样 RCC_CSR 记录的是权威的 + * IWDGRSTF,而不是 NVIC_SystemReset 留下的 SFTRSTF —— §5.3)。 + */ +void task_wd_poll(void) { + static uint32_t s_last_tick; + uint32_t now; + uint32_t snapshot; + + if (s_started == 0u) { + return; /* 未启动:不做任何判定 */ + } + + now = HAL_GetTick(); + if ((now - s_last_tick) < WD_POLL_PERIOD_MS) { + return; /* 节流:非 100ms 边界直接返回 */ + } + s_last_tick = now; + + snapshot = s_hb_bits; /* 读 */ + s_hb_bits = 0u; /* 清:语义 = "自上次抽样以来谁动过" */ + s_last_mask = snapshot; + + if (snapshot == wd_required_mask()) { + s_miss_streak = 0u; + IWDG->KR = 0x0000AAAAu; /* 全员健康:喂狗 */ + return; + } + + /* 有任务缺席:累计(不喂狗) */ + s_miss_total++; + if (s_miss_streak < WD_MISS_TOLERANCE) { + s_miss_streak++; + } + + if (s_miss_streak >= WD_MISS_TOLERANCE) { + /* 连续 800ms 有任务未动过 → 已停喂 → 约 2.5s 后 IWDG 复位。 + * 最后遗言走裸 UART(不依赖内核、不遍历指针、有界长度)。 */ + DBG_ERROR("[WD] task stall: mask=0x%08X req=0x%08X miss=%lu", + (unsigned)snapshot, + (unsigned)wd_required_mask(), + (unsigned long)s_miss_total); + } +} + +/* + * 函数功能:读上次抽样到的位图(观测/自检用) + */ +uint32_t task_wd_last_mask(void) { + return s_last_mask; +} + +/* + * 函数功能:读累计未达标轮数(观测/自检用) + */ +uint32_t task_wd_miss_count(void) { + return s_miss_total; +} + +/* + * 函数功能:查询 IWDG 是否已启动(观测/自检用) + */ +uint32_t task_wd_is_armed(void) { + return (s_started != 0u) ? 1u : 0u; +} diff --git a/App/util/task_watchdog.h b/App/util/task_watchdog.h new file mode 100644 index 00000000..c1c9b889 --- /dev/null +++ b/App/util/task_watchdog.h @@ -0,0 +1,76 @@ +/* + * 模块名称:Task Watchdog(IWDG + 任务心跳位图) + * 模块功能:独立看门狗与"全部任务存活"绑定的对外接口 + * 适用平台:STM32F407ZGTx + FreeRTOS(CMSIS-RTOS V2) + * 作者:王建锋 + * 创建日期:2026-09-29 + * 修改记录: + * v1.0 2026-09-29 王建锋 创建 + * + * 设计依据:docs/子系统设计/看门狗设计说明.md + */ + +#ifndef TASK_WATCHDOG_H +#define TASK_WATCHDOG_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * 任务 ID(位序号 = 心跳位图上的位置,与必需掩码一一对应) + * 顺序一旦确定不要插空/改动,掩码是编译期常量 + */ +typedef enum { + TASK_WD_DEFAULT = 0, + TASK_WD_NET = 1, + TASK_WD_FTP = 2, + TASK_WD_TEST = 3, + TASK_WD_UI = 4, + TASK_WD_TIMESYNC = 5, + TASK_WD_ID_MAX +} task_wd_id_t; + +/* + * 函数功能:任务心跳置位(各任务在自己主循环里调用) + * 入口参数:id - 任务 ID + * 返回值:无 + * 限定条件:任意上下文可调(单字原子写、无内核对象依赖) + * 函数说明:仅 1~2 条指令,无锁、无阻塞,可放在中断外任意位置。 + */ +void task_wd_beat(task_wd_id_t id); + +/* + * 函数功能:启动 IWDG(**延后启动**) + * 入口参数:无 + * 返回值:无 + * 限定条件:仅 defaultTask 在存储 bring-up 完成后调用一次 + * 函数说明:MX_IWDG_Init() 只填参数不启动(原因见 Src/iwdg.c 的 + * IWDG_DEFER_START 注释:HAL_IWDG_Init 内部会立即启动,而它被 + * CubeMX 插在 app_main_init 之前,那段无喂狗点且耗时可达数秒)。 + * 本函数才真正启动,使"启动段不喂狗、主循环段才喂"成立。 + */ +void task_wd_start(void); + +/* + * 函数功能:心跳抽样与喂狗判定 + * 入口参数:无 + * 返回值:无 + * 限定条件:仅 defaultTask 主循环调用(唯一喂狗者) + * 函数说明:内部节流至 100ms 一次。全员到位才喂狗;连续 800ms 有任务 + * 缺席则停止喂狗,由 IWDG 自然溢出复位(保留 IWDGRSTF 权威归因)。 + */ +void task_wd_poll(void); + +/* 观测接口(自检 / 串口报告用) */ +uint32_t task_wd_last_mask(void); /* 上次抽样到的位图(0 位 = 缺席任务) */ +uint32_t task_wd_miss_count(void); /* 累计未达标轮数 */ +uint32_t task_wd_is_armed(void); /* 1 = IWDG 已启动 */ + +#ifdef __cplusplus +} +#endif + +#endif /* TASK_WATCHDOG_H */ diff --git a/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_iwdg.h b/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_iwdg.h new file mode 100644 index 00000000..5273730c --- /dev/null +++ b/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_iwdg.h @@ -0,0 +1,220 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_iwdg.h + * @author MCD Application Team + * @brief Header file of IWDG HAL module. + ****************************************************************************** + * @attention + * + * Copyright (c) 2016 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32F4xx_HAL_IWDG_H +#define STM32F4xx_HAL_IWDG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal_def.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @defgroup IWDG IWDG + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup IWDG_Exported_Types IWDG Exported Types + * @{ + */ + +/** + * @brief IWDG Init structure definition + */ +typedef struct +{ + uint32_t Prescaler; /*!< Select the prescaler of the IWDG. + This parameter can be a value of @ref IWDG_Prescaler */ + + uint32_t Reload; /*!< Specifies the IWDG down-counter reload value. + This parameter must be a number between Min_Data = 0 and Max_Data = 0x0FFF */ + +} IWDG_InitTypeDef; + +/** + * @brief IWDG Handle Structure definition + */ +typedef struct +{ + IWDG_TypeDef *Instance; /*!< Register base address */ + + IWDG_InitTypeDef Init; /*!< IWDG required parameters */ +} IWDG_HandleTypeDef; + + +/** + * @} + */ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup IWDG_Exported_Constants IWDG Exported Constants + * @{ + */ + +/** @defgroup IWDG_Prescaler IWDG Prescaler + * @{ + */ +#define IWDG_PRESCALER_4 0x00000000u /*!< IWDG prescaler set to 4 */ +#define IWDG_PRESCALER_8 IWDG_PR_PR_0 /*!< IWDG prescaler set to 8 */ +#define IWDG_PRESCALER_16 IWDG_PR_PR_1 /*!< IWDG prescaler set to 16 */ +#define IWDG_PRESCALER_32 (IWDG_PR_PR_1 | IWDG_PR_PR_0) /*!< IWDG prescaler set to 32 */ +#define IWDG_PRESCALER_64 IWDG_PR_PR_2 /*!< IWDG prescaler set to 64 */ +#define IWDG_PRESCALER_128 (IWDG_PR_PR_2 | IWDG_PR_PR_0) /*!< IWDG prescaler set to 128 */ +#define IWDG_PRESCALER_256 (IWDG_PR_PR_2 | IWDG_PR_PR_1) /*!< IWDG prescaler set to 256 */ +/** + * @} + */ + +/** + * @} + */ + +/* Exported macros -----------------------------------------------------------*/ +/** @defgroup IWDG_Exported_Macros IWDG Exported Macros + * @{ + */ + +/** + * @brief Enable the IWDG peripheral. + * @param __HANDLE__ IWDG handle + * @retval None + */ +#define __HAL_IWDG_START(__HANDLE__) WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_ENABLE) + +/** + * @brief Reload IWDG counter with value defined in the reload register + * (write access to IWDG_PR and IWDG_RLR registers disabled). + * @param __HANDLE__ IWDG handle + * @retval None + */ +#define __HAL_IWDG_RELOAD_COUNTER(__HANDLE__) WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_RELOAD) + +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ +/** @defgroup IWDG_Exported_Functions IWDG Exported Functions + * @{ + */ + +/** @defgroup IWDG_Exported_Functions_Group1 Initialization and Start functions + * @{ + */ +/* Initialization/Start functions ********************************************/ +HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg); +/** + * @} + */ + +/** @defgroup IWDG_Exported_Functions_Group2 IO operation functions + * @{ + */ +/* I/O operation functions ****************************************************/ +HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg); +/** + * @} + */ + +/** + * @} + */ + +/* Private constants ---------------------------------------------------------*/ +/** @defgroup IWDG_Private_Constants IWDG Private Constants + * @{ + */ + +/** + * @brief IWDG Key Register BitMask + */ +#define IWDG_KEY_RELOAD 0x0000AAAAu /*!< IWDG Reload Counter Enable */ +#define IWDG_KEY_ENABLE 0x0000CCCCu /*!< IWDG Peripheral Enable */ +#define IWDG_KEY_WRITE_ACCESS_ENABLE 0x00005555u /*!< IWDG KR Write Access Enable */ +#define IWDG_KEY_WRITE_ACCESS_DISABLE 0x00000000u /*!< IWDG KR Write Access Disable */ + +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup IWDG_Private_Macros IWDG Private Macros + * @{ + */ + +/** + * @brief Enable write access to IWDG_PR and IWDG_RLR registers. + * @param __HANDLE__ IWDG handle + * @retval None + */ +#define IWDG_ENABLE_WRITE_ACCESS(__HANDLE__) WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_WRITE_ACCESS_ENABLE) + +/** + * @brief Disable write access to IWDG_PR and IWDG_RLR registers. + * @param __HANDLE__ IWDG handle + * @retval None + */ +#define IWDG_DISABLE_WRITE_ACCESS(__HANDLE__) WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_WRITE_ACCESS_DISABLE) + +/** + * @brief Check IWDG prescaler value. + * @param __PRESCALER__ IWDG prescaler value + * @retval None + */ +#define IS_IWDG_PRESCALER(__PRESCALER__) (((__PRESCALER__) == IWDG_PRESCALER_4) || \ + ((__PRESCALER__) == IWDG_PRESCALER_8) || \ + ((__PRESCALER__) == IWDG_PRESCALER_16) || \ + ((__PRESCALER__) == IWDG_PRESCALER_32) || \ + ((__PRESCALER__) == IWDG_PRESCALER_64) || \ + ((__PRESCALER__) == IWDG_PRESCALER_128)|| \ + ((__PRESCALER__) == IWDG_PRESCALER_256)) + +/** + * @brief Check IWDG reload value. + * @param __RELOAD__ IWDG reload value + * @retval None + */ +#define IS_IWDG_RELOAD(__RELOAD__) ((__RELOAD__) <= IWDG_RLR_RL) + + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* STM32F4xx_HAL_IWDG_H */ diff --git a/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_iwdg.h b/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_iwdg.h new file mode 100644 index 00000000..c0352989 --- /dev/null +++ b/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_iwdg.h @@ -0,0 +1,302 @@ +/** + ****************************************************************************** + * @file stm32f4xx_ll_iwdg.h + * @author MCD Application Team + * @brief Header file of IWDG LL module. + ****************************************************************************** + * @attention + * + * Copyright (c) 2016 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32F4xx_LL_IWDG_H +#define STM32F4xx_LL_IWDG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx.h" + +/** @addtogroup STM32F4xx_LL_Driver + * @{ + */ + +#if defined(IWDG) + +/** @defgroup IWDG_LL IWDG + * @{ + */ + +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ + +/* Private constants ---------------------------------------------------------*/ +/** @defgroup IWDG_LL_Private_Constants IWDG Private Constants + * @{ + */ +#define LL_IWDG_KEY_RELOAD 0x0000AAAAU /*!< IWDG Reload Counter Enable */ +#define LL_IWDG_KEY_ENABLE 0x0000CCCCU /*!< IWDG Peripheral Enable */ +#define LL_IWDG_KEY_WR_ACCESS_ENABLE 0x00005555U /*!< IWDG KR Write Access Enable */ +#define LL_IWDG_KEY_WR_ACCESS_DISABLE 0x00000000U /*!< IWDG KR Write Access Disable */ +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/** @defgroup IWDG_LL_Exported_Constants IWDG Exported Constants + * @{ + */ + +/** @defgroup IWDG_LL_EC_GET_FLAG Get Flags Defines + * @brief Flags defines which can be used with LL_IWDG_ReadReg function + * @{ + */ +#define LL_IWDG_SR_PVU IWDG_SR_PVU /*!< Watchdog prescaler value update */ +#define LL_IWDG_SR_RVU IWDG_SR_RVU /*!< Watchdog counter reload value update */ +/** + * @} + */ + +/** @defgroup IWDG_LL_EC_PRESCALER Prescaler Divider + * @{ + */ +#define LL_IWDG_PRESCALER_4 0x00000000U /*!< Divider by 4 */ +#define LL_IWDG_PRESCALER_8 (IWDG_PR_PR_0) /*!< Divider by 8 */ +#define LL_IWDG_PRESCALER_16 (IWDG_PR_PR_1) /*!< Divider by 16 */ +#define LL_IWDG_PRESCALER_32 (IWDG_PR_PR_1 | IWDG_PR_PR_0) /*!< Divider by 32 */ +#define LL_IWDG_PRESCALER_64 (IWDG_PR_PR_2) /*!< Divider by 64 */ +#define LL_IWDG_PRESCALER_128 (IWDG_PR_PR_2 | IWDG_PR_PR_0) /*!< Divider by 128 */ +#define LL_IWDG_PRESCALER_256 (IWDG_PR_PR_2 | IWDG_PR_PR_1) /*!< Divider by 256 */ +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/** @defgroup IWDG_LL_Exported_Macros IWDG Exported Macros + * @{ + */ + +/** @defgroup IWDG_LL_EM_WRITE_READ Common Write and read registers Macros + * @{ + */ + +/** + * @brief Write a value in IWDG register + * @param __INSTANCE__ IWDG Instance + * @param __REG__ Register to be written + * @param __VALUE__ Value to be written in the register + * @retval None + */ +#define LL_IWDG_WriteReg(__INSTANCE__, __REG__, __VALUE__) WRITE_REG(__INSTANCE__->__REG__, (__VALUE__)) + +/** + * @brief Read a value in IWDG register + * @param __INSTANCE__ IWDG Instance + * @param __REG__ Register to be read + * @retval Register value + */ +#define LL_IWDG_ReadReg(__INSTANCE__, __REG__) READ_REG(__INSTANCE__->__REG__) +/** + * @} + */ + +/** + * @} + */ + + +/* Exported functions --------------------------------------------------------*/ +/** @defgroup IWDG_LL_Exported_Functions IWDG Exported Functions + * @{ + */ +/** @defgroup IWDG_LL_EF_Configuration Configuration + * @{ + */ + +/** + * @brief Start the Independent Watchdog + * @note Except if the hardware watchdog option is selected + * @rmtoll KR KEY LL_IWDG_Enable + * @param IWDGx IWDG Instance + * @retval None + */ +__STATIC_INLINE void LL_IWDG_Enable(IWDG_TypeDef *IWDGx) +{ + WRITE_REG(IWDGx->KR, LL_IWDG_KEY_ENABLE); +} + +/** + * @brief Reloads IWDG counter with value defined in the reload register + * @rmtoll KR KEY LL_IWDG_ReloadCounter + * @param IWDGx IWDG Instance + * @retval None + */ +__STATIC_INLINE void LL_IWDG_ReloadCounter(IWDG_TypeDef *IWDGx) +{ + WRITE_REG(IWDGx->KR, LL_IWDG_KEY_RELOAD); +} + +/** + * @brief Enable write access to IWDG_PR, IWDG_RLR and IWDG_WINR registers + * @rmtoll KR KEY LL_IWDG_EnableWriteAccess + * @param IWDGx IWDG Instance + * @retval None + */ +__STATIC_INLINE void LL_IWDG_EnableWriteAccess(IWDG_TypeDef *IWDGx) +{ + WRITE_REG(IWDGx->KR, LL_IWDG_KEY_WR_ACCESS_ENABLE); +} + +/** + * @brief Disable write access to IWDG_PR, IWDG_RLR and IWDG_WINR registers + * @rmtoll KR KEY LL_IWDG_DisableWriteAccess + * @param IWDGx IWDG Instance + * @retval None + */ +__STATIC_INLINE void LL_IWDG_DisableWriteAccess(IWDG_TypeDef *IWDGx) +{ + WRITE_REG(IWDGx->KR, LL_IWDG_KEY_WR_ACCESS_DISABLE); +} + +/** + * @brief Select the prescaler of the IWDG + * @rmtoll PR PR LL_IWDG_SetPrescaler + * @param IWDGx IWDG Instance + * @param Prescaler This parameter can be one of the following values: + * @arg @ref LL_IWDG_PRESCALER_4 + * @arg @ref LL_IWDG_PRESCALER_8 + * @arg @ref LL_IWDG_PRESCALER_16 + * @arg @ref LL_IWDG_PRESCALER_32 + * @arg @ref LL_IWDG_PRESCALER_64 + * @arg @ref LL_IWDG_PRESCALER_128 + * @arg @ref LL_IWDG_PRESCALER_256 + * @retval None + */ +__STATIC_INLINE void LL_IWDG_SetPrescaler(IWDG_TypeDef *IWDGx, uint32_t Prescaler) +{ + WRITE_REG(IWDGx->PR, IWDG_PR_PR & Prescaler); +} + +/** + * @brief Get the selected prescaler of the IWDG + * @rmtoll PR PR LL_IWDG_GetPrescaler + * @param IWDGx IWDG Instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_IWDG_PRESCALER_4 + * @arg @ref LL_IWDG_PRESCALER_8 + * @arg @ref LL_IWDG_PRESCALER_16 + * @arg @ref LL_IWDG_PRESCALER_32 + * @arg @ref LL_IWDG_PRESCALER_64 + * @arg @ref LL_IWDG_PRESCALER_128 + * @arg @ref LL_IWDG_PRESCALER_256 + */ +__STATIC_INLINE uint32_t LL_IWDG_GetPrescaler(const IWDG_TypeDef *IWDGx) +{ + return (READ_REG(IWDGx->PR)); +} + +/** + * @brief Specify the IWDG down-counter reload value + * @rmtoll RLR RL LL_IWDG_SetReloadCounter + * @param IWDGx IWDG Instance + * @param Counter Value between Min_Data=0 and Max_Data=0x0FFF + * @retval None + */ +__STATIC_INLINE void LL_IWDG_SetReloadCounter(IWDG_TypeDef *IWDGx, uint32_t Counter) +{ + WRITE_REG(IWDGx->RLR, IWDG_RLR_RL & Counter); +} + +/** + * @brief Get the specified IWDG down-counter reload value + * @rmtoll RLR RL LL_IWDG_GetReloadCounter + * @param IWDGx IWDG Instance + * @retval Value between Min_Data=0 and Max_Data=0x0FFF + */ +__STATIC_INLINE uint32_t LL_IWDG_GetReloadCounter(const IWDG_TypeDef *IWDGx) +{ + return (READ_REG(IWDGx->RLR)); +} + +/** + * @} + */ + +/** @defgroup IWDG_LL_EF_FLAG_Management FLAG_Management + * @{ + */ + +/** + * @brief Check if flag Prescaler Value Update is set or not + * @rmtoll SR PVU LL_IWDG_IsActiveFlag_PVU + * @param IWDGx IWDG Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_IWDG_IsActiveFlag_PVU(const IWDG_TypeDef *IWDGx) +{ + return ((READ_BIT(IWDGx->SR, IWDG_SR_PVU) == (IWDG_SR_PVU)) ? 1UL : 0UL); +} + +/** + * @brief Check if flag Reload Value Update is set or not + * @rmtoll SR RVU LL_IWDG_IsActiveFlag_RVU + * @param IWDGx IWDG Instance + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_IWDG_IsActiveFlag_RVU(const IWDG_TypeDef *IWDGx) +{ + return ((READ_BIT(IWDGx->SR, IWDG_SR_RVU) == (IWDG_SR_RVU)) ? 1UL : 0UL); +} + +/** + * @brief Check if flags Prescaler & Reload Value Update are reset or not + * @rmtoll SR PVU LL_IWDG_IsReady\n + * SR RVU LL_IWDG_IsReady + * @param IWDGx IWDG Instance + * @retval State of bits (1 or 0). + */ +__STATIC_INLINE uint32_t LL_IWDG_IsReady(const IWDG_TypeDef *IWDGx) +{ + return ((READ_BIT(IWDGx->SR, IWDG_SR_PVU | IWDG_SR_RVU) == 0U) ? 1UL : 0UL); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#endif /* IWDG */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32F4xx_LL_IWDG_H */ diff --git a/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_iwdg.c b/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_iwdg.c new file mode 100644 index 00000000..bc03a530 --- /dev/null +++ b/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_iwdg.c @@ -0,0 +1,263 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_iwdg.c + * @author MCD Application Team + * @brief IWDG HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of the Independent Watchdog (IWDG) peripheral: + * + Initialization and Start functions + * + IO operation functions + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2016 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. + * + ****************************************************************************** + @verbatim + ============================================================================== + ##### IWDG Generic features ##### + ============================================================================== + [..] + (+) The IWDG can be started by either software or hardware (configurable + through option byte). + + (+) The IWDG is clocked by the Low-Speed Internal clock (LSI) and thus stays + active even if the main clock fails. + + (+) Once the IWDG is started, the LSI is forced ON and both cannot be + disabled. The counter starts counting down from the reset value (0xFFF). + When it reaches the end of count value (0x000) a reset signal is + generated (IWDG reset). + + (+) Whenever the key value 0x0000 AAAA is written in the IWDG_KR register, + the IWDG_RLR value is reloaded into the counter and the watchdog reset + is prevented. + + (+) The IWDG is implemented in the VDD voltage domain that is still functional + in STOP and STANDBY mode (IWDG reset can wake up the CPU from STANDBY). + IWDGRST flag in RCC_CSR register can be used to inform when an IWDG + reset occurs. + + (+) Debug mode: When the microcontroller enters debug mode (core halted), + the IWDG counter either continues to work normally or stops, depending + on DBG_IWDG_STOP configuration bit in DBG module, accessible through + __HAL_DBGMCU_FREEZE_IWDG() and __HAL_DBGMCU_UNFREEZE_IWDG() macros. + + [..] Min-max timeout value @32KHz (LSI): ~125us / ~32.7s + The IWDG timeout may vary due to LSI clock frequency dispersion. + STM32F4xx devices provide the capability to measure the LSI clock + frequency (LSI clock is internally connected to TIM5 CH4 input capture). + The measured value can be used to have an IWDG timeout with an + acceptable accuracy. + + [..] Default timeout value (necessary for IWDG_SR status register update): + Constant LSI_VALUE is defined based on the nominal LSI clock frequency. + This frequency being subject to variations as mentioned above, the + default timeout value (defined through constant HAL_IWDG_DEFAULT_TIMEOUT + below) may become too short or too long. + In such cases, this default timeout value can be tuned by redefining + the constant LSI_VALUE at user-application level (based, for instance, + on the measured LSI clock frequency as explained above). + + ##### How to use this driver ##### + ============================================================================== + [..] + (#) Use IWDG using HAL_IWDG_Init() function to : + (++) Enable instance by writing Start keyword in IWDG_KEY register. LSI + clock is forced ON and IWDG counter starts counting down. + (++) Enable write access to configuration registers: + IWDG_PR and IWDG_RLR. + (++) Configure the IWDG prescaler and counter reload value. This reload + value will be loaded in the IWDG counter each time the watchdog is + reloaded, then the IWDG will start counting down from this value. + (++) Wait for status flags to be reset. + + (#) Then the application program must refresh the IWDG counter at regular + intervals during normal operation to prevent an MCU reset, using + HAL_IWDG_Refresh() function. + + *** IWDG HAL driver macros list *** + ==================================== + [..] + Below the list of most used macros in IWDG HAL driver: + (+) __HAL_IWDG_START: Enable the IWDG peripheral + (+) __HAL_IWDG_RELOAD_COUNTER: Reloads IWDG counter with value defined in + the reload register + + @endverbatim + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +#ifdef HAL_IWDG_MODULE_ENABLED +/** @addtogroup IWDG + * @brief IWDG HAL module driver. + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/** @defgroup IWDG_Private_Defines IWDG Private Defines + * @{ + */ +/* Status register needs up to 5 LSI clock periods divided by the clock + prescaler to be updated. The number of LSI clock periods is upper-rounded to + 6 for the timeout value calculation. + The timeout value is calculated using the highest prescaler (256) and + the LSI_VALUE constant. The value of this constant can be changed by the user + to take into account possible LSI clock period variations. + The timeout value is multiplied by 1000 to be converted in milliseconds. + LSI startup time is also considered here by adding LSI_STARTUP_TIME + converted in milliseconds. */ +#define HAL_IWDG_DEFAULT_TIMEOUT (((6UL * 256UL * 1000UL) / (LSI_VALUE / 128U)) + \ + ((LSI_STARTUP_TIME / 1000UL) + 1UL)) +#define IWDG_KERNEL_UPDATE_FLAGS (IWDG_SR_RVU | IWDG_SR_PVU) +/** + * @} + */ + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ + +/** @addtogroup IWDG_Exported_Functions + * @{ + */ + +/** @addtogroup IWDG_Exported_Functions_Group1 + * @brief Initialization and Start functions. + * +@verbatim + =============================================================================== + ##### Initialization and Start functions ##### + =============================================================================== + [..] This section provides functions allowing to: + (+) Initialize the IWDG according to the specified parameters in the + IWDG_InitTypeDef of associated handle. + (+) Once initialization is performed in HAL_IWDG_Init function, Watchdog + is reloaded in order to exit function with correct time base. + +@endverbatim + * @{ + */ + +/** + * @brief Initialize the IWDG according to the specified parameters in the + * IWDG_InitTypeDef and start watchdog. Before exiting function, + * watchdog is refreshed in order to have correct time base. + * @param hiwdg pointer to a IWDG_HandleTypeDef structure that contains + * the configuration information for the specified IWDG module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg) +{ + uint32_t tickstart; + + /* Check the IWDG handle allocation */ + if (hiwdg == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + assert_param(IS_IWDG_ALL_INSTANCE(hiwdg->Instance)); + assert_param(IS_IWDG_PRESCALER(hiwdg->Init.Prescaler)); + assert_param(IS_IWDG_RELOAD(hiwdg->Init.Reload)); + + /* Enable IWDG. LSI is turned on automatically */ + __HAL_IWDG_START(hiwdg); + + /* Enable write access to IWDG_PR and IWDG_RLR registers by writing + 0x5555 in KR */ + IWDG_ENABLE_WRITE_ACCESS(hiwdg); + + /* Write to IWDG registers the Prescaler & Reload values to work with */ + hiwdg->Instance->PR = hiwdg->Init.Prescaler; + hiwdg->Instance->RLR = hiwdg->Init.Reload; + + /* Check pending flag, if previous update not done, return timeout */ + tickstart = HAL_GetTick(); + + /* Wait for register to be updated */ + while ((hiwdg->Instance->SR & IWDG_KERNEL_UPDATE_FLAGS) != 0x00u) + { + if ((HAL_GetTick() - tickstart) > HAL_IWDG_DEFAULT_TIMEOUT) + { + if ((hiwdg->Instance->SR & IWDG_KERNEL_UPDATE_FLAGS) != 0x00u) + { + return HAL_TIMEOUT; + } + } + } + + /* Reload IWDG counter with value defined in the reload register */ + __HAL_IWDG_RELOAD_COUNTER(hiwdg); + + /* Return function status */ + return HAL_OK; +} + + +/** + * @} + */ + + +/** @addtogroup IWDG_Exported_Functions_Group2 + * @brief IO operation functions + * +@verbatim + =============================================================================== + ##### IO operation functions ##### + =============================================================================== + [..] This section provides functions allowing to: + (+) Refresh the IWDG. + +@endverbatim + * @{ + */ + +/** + * @brief Refresh the IWDG. + * @param hiwdg pointer to a IWDG_HandleTypeDef structure that contains + * the configuration information for the specified IWDG module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg) +{ + /* Reload IWDG counter with value defined in the reload register */ + __HAL_IWDG_RELOAD_COUNTER(hiwdg); + + /* Return function status */ + return HAL_OK; +} + + +/** + * @} + */ + +/** + * @} + */ + +#endif /* HAL_IWDG_MODULE_ENABLED */ +/** + * @} + */ + +/** + * @} + */ diff --git a/Inc/FreeRTOSConfig.h b/Inc/FreeRTOSConfig.h index 9a09ab14..7090954b 100644 --- a/Inc/FreeRTOSConfig.h +++ b/Inc/FreeRTOSConfig.h @@ -81,7 +81,8 @@ /* 栈溢出机械检测(2026-09-20 存储套件死机事故后加):模式 2 在每次上下文切换 * 检查栈底水位线,溢出即调 vApplicationStackOverflowHook(报任务名+复位)。 * 关闭检测时溢出会静默腐蚀堆相邻块(其它任务栈/TCB),表现为无异常、不可定位 - * 的全系统冻结——本次事故签名。开销:每次切换一次字比较,可忽略。 */ + * 的全系统冻结——本次事故签名。开销:每次切换一次字比较,可忽略。 + * ⚠ 本段为手工添加,CubeMX 重生成会删除(2026-09-29 实测),改完须核对本块存在 */ #define configCHECK_FOR_STACK_OVERFLOW 2 /* pvPortMalloc 失败钩子(只告警不复位:分配失败路径由各调用点 NULL 检查处理) */ #define configUSE_MALLOC_FAILED_HOOK 1 @@ -160,7 +161,16 @@ See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ /* Normal assert() semantics without relying on the provision of an assert.h header file. */ /* USER CODE BEGIN 1 */ -#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );} +/* ⚠ 本段为手工添加,CubeMX 重生成会删除(2026-09-29 实测),改完须核对本块存在。 + * + * 断言失败处理(2026-09-29,配合 IWDG): + * 原实现 `taskDISABLE_INTERRUPTS(); for(;;);` = 关中断死循环——CPU 停摆、无输出、 + * 只能人工断电;且关中断后 IWDG 仍在跑(IWDG 走 LSI,与本 CPU 中断无关), + * 只要喂狗者(defaultTask)也被这该死循环卡住,2.5s 后 IWDG 自动复位, + * 系统自恢复。故改为调用带输出的上报函数(打印断言位置后主动复位)。 + * 若断言发生在 IWDG 启动之前的启动段(无看门狗兜底),上报函数自行复位。 */ +void vApplicationAssertFailed(const char *file, long line); +#define configASSERT( x ) if ((x) == 0) { vApplicationAssertFailed(__FILE__, __LINE__); } /* USER CODE END 1 */ /* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS diff --git a/Inc/iwdg.h b/Inc/iwdg.h new file mode 100644 index 00000000..376f52a5 --- /dev/null +++ b/Inc/iwdg.h @@ -0,0 +1,51 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file iwdg.h + * @brief This file contains all the function prototypes for + * the iwdg.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 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 */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __IWDG_H__ +#define __IWDG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern IWDG_HandleTypeDef hiwdg; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_IWDG_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __IWDG_H__ */ diff --git a/Inc/stm32f4xx_hal_conf.h b/Inc/stm32f4xx_hal_conf.h index 063bd0cb..db48ddc4 100644 --- a/Inc/stm32f4xx_hal_conf.h +++ b/Inc/stm32f4xx_hal_conf.h @@ -55,7 +55,7 @@ /* #define HAL_HASH_MODULE_ENABLED */ #define HAL_I2C_MODULE_ENABLED /* #define HAL_I2S_MODULE_ENABLED */ -/* #define HAL_IWDG_MODULE_ENABLED */ +#define HAL_IWDG_MODULE_ENABLED /* #define HAL_LTDC_MODULE_ENABLED */ /* #define HAL_RNG_MODULE_ENABLED */ /* #define HAL_RTC_MODULE_ENABLED */ diff --git a/MDK-ARM/STM32F407-Demo.uvprojx b/MDK-ARM/STM32F407-Demo.uvprojx index 66a9c9f2..c591098f 100644 --- a/MDK-ARM/STM32F407-Demo.uvprojx +++ b/MDK-ARM/STM32F407-Demo.uvprojx @@ -1,10 +1,7 @@ - - - + + 2.1 -
### uVision Project, (C) Keil Software
- STM32F407-Demo @@ -19,28 +16,28 @@ Keil.STM32F4xx_DFP.3.1.1 https://www.keil.com/pack/ IRAM(0x20000000-0x2001BFFF) IRAM2(0x2001C000-0x2001FFFF) IROM(0x8000000-0x80FFFFF) CLOCK(25000000) FPU2 CPUTYPE("Cortex-M4") TZ - - - + + + 0 - - - - - - - - - - + + + + + + + + + + $$Device:STM32F407ZGTx$CMSIS\SVD\STM32F407.svd 0 0 - - - - - + + + + + 0 0 @@ -55,15 +52,15 @@ 1 1 1 - + 1 0 0 0 0 - - + + 0 0 0 @@ -72,8 +69,8 @@ 0 0 - - + + 0 0 0 @@ -82,15 +79,15 @@ 0 1 - - + + 0 0 0 0 1 - + 0 @@ -104,8 +101,8 @@ 0 0 3 - - + + 0 @@ -139,10 +136,10 @@ 1 BIN\UL2CM3.DLL "" () - - - - + + + + 0 @@ -175,7 +172,7 @@ 0 0 "Cortex-M4" - + 0 0 0 @@ -309,7 +306,7 @@ 0x0 - + 1 @@ -338,7 +335,7 @@ --diag_suppress=1,68,111,188,191,546,1293 USE_HAL_DRIVER,STM32F407xx,NDEBUG - + ../Inc;../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include;../Drivers/BSP;../Drivers/BSP/CH395F;../Drivers/BSP/GD5F2GQ5UE;../Drivers/BSP/TPAFE5160;../Drivers/BSP/SD2506;../Drivers/BSP/RS485;../Drivers/BSP/NET;../Drivers/BSP/NET/lftpd;../Drivers/BSP/NETCFG;../App;../App/app;../App/cfg;../App/log;../App/sync;../App/task;../App/util;../Middlewares/Third_Party/FreeRTOS/Source/include;../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2;../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM4F;../Lib/dhara;../Lib/FatFs;../test/board;../Lib/lvgl;../Drivers/BSP/UI;../Lib @@ -354,9 +351,9 @@ 0 1 - - - + + + ../Drivers/CMSIS/Include @@ -367,15 +364,15 @@ 0 1 1 - - - + + + STM32F407-Demo\STM32F407-Demo.sct - - - - - + + + + + @@ -420,8 +417,6 @@ 2 2 11 - - 1 @@ -449,12 +444,6 @@ 2 2 2 - - - - - - @@ -476,8 +465,6 @@ 2 2 11 - - 1 @@ -505,12 +492,6 @@ 2 2 2 - - - - - - @@ -532,8 +513,6 @@ 2 2 11 - - 1 @@ -561,16 +540,70 @@ 2 2 2 - - - - - - + + iwdg.c + 1 + ../Src/iwdg.c + + + 2 + 0 + 0 + 0 + 0 + 1 + 2 + 2 + 2 + 2 + 11 + 1 + + + + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 0 + 0 + 2 + 2 + 2 + 2 + 2 + + + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 1 + + + + spi.c 1 @@ -588,8 +621,6 @@ 2 2 11 - - 1 @@ -617,12 +648,6 @@ 2 2 2 - - - - - - @@ -644,8 +669,6 @@ 2 2 11 - - 1 @@ -673,12 +696,6 @@ 2 2 2 - - - - - - @@ -710,8 +727,6 @@ 2 2 11 - - 1 @@ -739,12 +754,6 @@ 2 2 2 - - - - - - @@ -784,6 +793,11 @@ 1 ..\App\util\sys_clock.c + + task_watchdog.c + 1 + ..\App\util\task_watchdog.c + time_sync.c 1 @@ -826,8 +840,6 @@ 2 2 11 - - 1 @@ -855,12 +867,6 @@ 2 2 2 - - - - - - @@ -882,8 +888,6 @@ 2 2 11 - - 1 @@ -911,12 +915,6 @@ 2 2 2 - - - - - - @@ -1003,8 +1001,6 @@ 2 2 11 - - 1 @@ -1032,12 +1028,6 @@ 2 2 2 - - - - - - @@ -1059,8 +1049,6 @@ 2 2 11 - - 1 @@ -1088,16 +1076,70 @@ 2 2 2 - - - - - - + + stm32f4xx_hal_iwdg.c + 1 + ../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_iwdg.c + + + 2 + 0 + 0 + 0 + 0 + 1 + 2 + 2 + 2 + 2 + 11 + 1 + + + + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 0 + 0 + 2 + 2 + 2 + 2 + 2 + + + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 1 + + + + stm32f4xx_hal_spi.c 1 @@ -1115,8 +1157,6 @@ 2 2 11 - - 1 @@ -1144,12 +1184,6 @@ 2 2 2 - - - - - - @@ -1171,8 +1205,6 @@ 2 2 11 - - 1 @@ -1200,12 +1232,6 @@ 2 2 2 - - - - - - @@ -1312,8 +1338,6 @@ 2 2 11 - - 1 @@ -1341,12 +1365,6 @@ 2 2 2 - - - - - - 2 @@ -1359,12 +1377,6 @@ 2 2 1 - - - - - - @@ -1386,8 +1398,6 @@ 2 2 11 - - 1 @@ -1415,12 +1425,6 @@ 2 2 2 - - - - - - @@ -1442,8 +1446,6 @@ 2 2 11 - - 1 @@ -1471,12 +1473,6 @@ 2 2 2 - - - - - - @@ -1498,8 +1494,6 @@ 2 2 11 - - 1 @@ -1527,12 +1521,6 @@ 2 2 2 - - - - - - @@ -1554,8 +1542,6 @@ 2 2 11 - - 1 @@ -1583,12 +1569,6 @@ 2 2 2 - - - - - - @@ -1610,8 +1590,6 @@ 2 2 11 - - 1 @@ -1639,12 +1617,6 @@ 2 2 2 - - - - - - @@ -1666,8 +1638,6 @@ 2 2 11 - - 1 @@ -1695,12 +1665,6 @@ 2 2 2 - - - - - - @@ -1722,8 +1686,6 @@ 2 2 11 - - 1 @@ -1751,12 +1713,6 @@ 2 2 2 - - - - - - @@ -1778,8 +1734,6 @@ 2 2 11 - - 1 @@ -1807,12 +1761,6 @@ 2 2 2 - - - - - - @@ -1834,8 +1782,6 @@ 2 2 11 - - 1 @@ -1863,12 +1809,6 @@ 2 2 2 - - - - - - @@ -1890,8 +1830,6 @@ 2 2 11 - - 1 @@ -1919,12 +1857,6 @@ 2 2 2 - - - - - - @@ -1946,8 +1878,8 @@ 2 2 11 - - + + 1 @@ -1977,9 +1909,9 @@ 2 --diag_suppress=177 - - - + + + @@ -1994,10 +1926,10 @@ 2 1 - - - - + + + + @@ -2085,8 +2017,8 @@ 0 0 3 - - + + 0 @@ -2115,10 +2047,10 @@ 2 2 - - - - + + + + @@ -2133,10 +2065,10 @@ 2 0 - - - - + + + + @@ -3245,20 +3177,18 @@ - - + - + - + - + - @@ -3267,5 +3197,4 @@ -
diff --git a/STM32F407-Demo.ioc b/STM32F407-Demo.ioc index 595d7373..30a4299a 100644 --- a/STM32F407-Demo.ioc +++ b/STM32F407-Demo.ioc @@ -73,28 +73,32 @@ FREERTOS.Events01=sys_evt,Dynamic,NULL FREERTOS.FootprintOK=true FREERTOS.IPParameters=Tasks01,configENABLE_FPU,FootprintOK,configTOTAL_HEAP_SIZE,Queues01,Events01 FREERTOS.Queues01=netMsgQueue,8,net_msg_t,0,Dynamic,NULL,NULL -FREERTOS.Tasks01=defaultTask,24,512,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;netTask,24,1024,StartNetTask,Default,NULL,Dynamic,NULL,NULL;ftpTask,24,1024,StartFtpTask,As weak,NULL,Dynamic,NULL,NULL;testTask,16,1024,start_test_task,As weak,NULL,Dynamic,NULL,NULL;uiTask,16,4096,StartUiTask,Default,NULL,Dynamic,NULL,NULL +FREERTOS.Tasks01=defaultTask,24,1024,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;netTask,24,1024,StartNetTask,Default,NULL,Dynamic,NULL,NULL;ftpTask,24,1024,StartFtpTask,As weak,NULL,Dynamic,NULL,NULL;testTask,16,2048,start_test_task,As weak,NULL,Dynamic,NULL,NULL;uiTask,16,4096,StartUiTask,Default,NULL,Dynamic,NULL,NULL FREERTOS.configENABLE_FPU=1 FREERTOS.configTOTAL_HEAP_SIZE=49152 File.Version=6 GPIO.groupedBy=Group By Peripherals +IWDG.IPParameters=Prescaler,Reload +IWDG.Prescaler=IWDG_PRESCALER_64 +IWDG.Reload=1249 KeepUserPlacement=false Mcu.CPN=STM32F407ZGT6 Mcu.Family=STM32F4 Mcu.IP0=DMA Mcu.IP1=FREERTOS -Mcu.IP10=USART1 -Mcu.IP11=USART2 -Mcu.IP12=USART3 +Mcu.IP10=UART5 +Mcu.IP11=USART1 +Mcu.IP12=USART2 +Mcu.IP13=USART3 Mcu.IP2=I2C1 -Mcu.IP3=NVIC -Mcu.IP4=RCC -Mcu.IP5=SPI1 -Mcu.IP6=SPI2 -Mcu.IP7=SYS -Mcu.IP8=UART4 -Mcu.IP9=UART5 -Mcu.IPNb=13 +Mcu.IP3=IWDG +Mcu.IP4=NVIC +Mcu.IP5=RCC +Mcu.IP6=SPI1 +Mcu.IP7=SPI2 +Mcu.IP8=SYS +Mcu.IP9=UART4 +Mcu.IPNb=14 Mcu.Name=STM32F407Z(E-G)Tx Mcu.Package=LQFP144 Mcu.Pin0=PE5 @@ -151,12 +155,13 @@ Mcu.Pin54=PB8 Mcu.Pin55=PE0 Mcu.Pin56=PE1 Mcu.Pin57=VP_FREERTOS_VS_CMSIS_V2 -Mcu.Pin58=VP_SYS_VS_tim7 +Mcu.Pin58=VP_IWDG_VS_IWDG +Mcu.Pin59=VP_SYS_VS_tim7 Mcu.Pin6=PB2 Mcu.Pin7=PF11 Mcu.Pin8=PF12 Mcu.Pin9=PG0 -Mcu.PinsNb=59 +Mcu.PinsNb=60 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32F407ZGTx @@ -484,7 +489,7 @@ PH1-OSC_OUT.Mode=HSE-External-Oscillator PH1-OSC_OUT.Signal=RCC_OSC_OUT PinOutPanel.RotationAngle=0 ProjectManager.AskForMigrate=true -ProjectManager.BackupPrevious=false +ProjectManager.BackupPrevious=true ProjectManager.CompilerLinker=GCC ProjectManager.CompilerOptimize=6 ProjectManager.ComputerToolchain=false @@ -515,7 +520,7 @@ ProjectManager.ToolChainLocation= ProjectManager.UAScriptAfterPath= ProjectManager.UAScriptBeforePath= ProjectManager.UnderRoot=false -ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_USART1_UART_Init-USART1-false-HAL-true,5-MX_SPI2_Init-SPI2-false-HAL-true,6-MX_SPI1_Init-SPI1-false-HAL-true,7-MX_I2C1_Init-I2C1-false-HAL-true,8-MX_UART4_Init-UART4-false-HAL-true,9-MX_UART5_Init-UART5-false-HAL-true,10-MX_USART2_UART_Init-USART2-false-HAL-true,11-MX_USART3_UART_Init-USART3-false-HAL-true +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_USART1_UART_Init-USART1-false-HAL-true,5-MX_SPI2_Init-SPI2-false-HAL-true,6-MX_SPI1_Init-SPI1-false-HAL-true,7-MX_I2C1_Init-I2C1-false-HAL-true,8-MX_UART4_Init-UART4-false-HAL-true,9-MX_UART5_Init-UART5-false-HAL-true,10-MX_USART2_UART_Init-USART2-false-HAL-true,11-MX_USART3_UART_Init-USART3-false-HAL-true,12-MX_IWDG_Init-IWDG-false-HAL-true RCC.48MHZClocksFreq_Value=84000000 RCC.AHBFreq_Value=168000000 RCC.APB1CLKDivider=RCC_HCLK_DIV4 @@ -575,6 +580,8 @@ USART3.IPParameters=VirtualMode USART3.VirtualMode=VM_ASYNC VP_FREERTOS_VS_CMSIS_V2.Mode=CMSIS_V2 VP_FREERTOS_VS_CMSIS_V2.Signal=FREERTOS_VS_CMSIS_V2 +VP_IWDG_VS_IWDG.Mode=IWDG_Activate +VP_IWDG_VS_IWDG.Signal=IWDG_VS_IWDG VP_SYS_VS_tim7.Mode=TIM7 VP_SYS_VS_tim7.Signal=SYS_VS_tim7 board=custom diff --git a/Src/freertos.c b/Src/freertos.c index 5fc1e12b..08920b6e 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -358,4 +358,73 @@ void vApplicationMallocFailedHook(void) dbg_console_write_raw(msg, (unsigned)(sizeof(msg) - 1u)); } + +/* + * 断言失败钩子(2026-09-29,配合 IWDG;见 Inc/FreeRTOSConfig.h 的 configASSERT)。 + * 与栈溢出钩子同为"内核状态已不可信"路径:裸 UART 有界输出 + 主动复位, + * 不走 printf / 内核对象 / 控制台锁。 + * 设计取舍(docs/子系统设计/看门狗设计说明.md §4.6): + * - 上报 file/line 是断言唯一有价值的现场信息,故必须打印(早于 TCB 名之类); + * - 打印后**主动 NVIC_SystemReset()** 而非空转:断言点未必能让 IWDG 抓到 + * (若恰在启动段,IWDG 尚未启动),主动复位保证任何断言都能自恢复; + * 代价是 RCC_CSR 记 SFTRSTF 而非 IWDGRSTF——故上报串里写死 ASSERT 字样, + * 使"重启原因"可由日志区分(软件复位 + 上一条是 ASSERT = 断言导致)。 + */ +void vApplicationAssertFailed(const char *file, long line) +{ + static const char msg_head[] = "\r\n[ERR] ASSERT FAILED "; + const char *p = file; + char num[16]; + int i; + + /* 文件名只取末段(全路径太长且无信息量) */ + if (p != NULL) { + const char *q = p; + while (*q != '\0') { + if ((*q == '/') || (*q == '\\')) { + p = q + 1; + } + q++; + } + /* 有界拷贝:上限 48 字符 */ + { + uint16_t len = 0u; + char name[49]; + while ((len < 48u) && (p[len] != '\0')) { + name[len] = p[len]; + len++; + } + name[len] = '\0'; + dbg_console_write_raw(msg_head, (unsigned)(sizeof(msg_head) - 1u)); + dbg_console_write_raw(name, (unsigned)len); + } + } else { + dbg_console_write_raw(msg_head, (unsigned)(sizeof(msg_head) - 1u)); + dbg_console_write_raw("(no file)", 9u); + } + + dbg_console_write_raw(":", 1u); + + /* 行号转十进制(不用 snprintf:钩子可能在临界区,且避免库依赖) */ + i = 0; + if (line <= 0) { + num[i++] = '0'; + } else { + char rev[16]; + int n = 0; + while ((line > 0) && (n < 15)) { + rev[n++] = (char)('0' + (line % 10)); + line /= 10; + } + while (n > 0) { + num[i++] = rev[--n]; + } + } + dbg_console_write_raw(num, (unsigned)i); + + dbg_console_write_raw(" (resetting)\r\n", 15u); + + HAL_Delay(200); /* 等 UART 移位寄存器排空 */ + NVIC_SystemReset(); +} /* USER CODE END Application */ diff --git a/Src/iwdg.c b/Src/iwdg.c new file mode 100644 index 00000000..aeea85df --- /dev/null +++ b/Src/iwdg.c @@ -0,0 +1,63 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file iwdg.c + * @brief This file provides code for the configuration + * of the IWDG instances. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 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 "iwdg.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +IWDG_HandleTypeDef hiwdg; + +/* IWDG init function */ +void MX_IWDG_Init(void) +{ + + /* USER CODE BEGIN IWDG_Init 0 */ + + /* USER CODE END IWDG_Init 0 */ + + /* USER CODE BEGIN IWDG_Init 1 */ + + /* USER CODE END IWDG_Init 1 */ + hiwdg.Instance = IWDG; + hiwdg.Init.Prescaler = IWDG_PRESCALER_64; + hiwdg.Init.Reload = 1249; + /* USER CODE BEGIN IWDG_DEFER_START */ + /* ⚠ 生成区改动(唯一一处):原为 `HAL_IWDG_Init(&hiwdg)` 直呼。 + * 原因:HAL_IWDG_Init() 内部第一句即 __HAL_IWDG_START()(立即启动看门狗, + * 之后不可停、只能复位)。而本函数被 CubeMX 插在 main() 的 MX_*_Init 序列里, + * 早于 app_main_init()——那段含 NAND 初始化/RTC/ADC,耗时可达数秒且无喂狗点, + * 按 2.5s 超时最坏值(≈1.7s)必然复位 → 开机死循环(2026-09-29 实测确认)。 + * 故本函数降级为**只填参数不启动**;启动动作移交 + * task_wd_start()(App/util/task_watchdog.c),由 defaultTask 在存储 bring-up + * 完成后调用——即"启动段不喂狗、主循环段才喂"的设计(见 + * docs/子系统设计/看门狗设计说明.md §4.5)。 + * 若 CubeMX 重生成覆盖此处,表现为"开机即复位",按本注释恢复即可。 */ + /* USER CODE END IWDG_DEFER_START */ + /* USER CODE BEGIN IWDG_Init 2 */ + + /* USER CODE END IWDG_Init 2 */ + +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ diff --git a/Src/main.c b/Src/main.c index 8cd70f4b..23cd6fd5 100644 --- a/Src/main.c +++ b/Src/main.c @@ -21,6 +21,7 @@ #include "cmsis_os.h" #include "dma.h" #include "i2c.h" +#include "iwdg.h" #include "spi.h" #include "usart.h" #include "gpio.h" @@ -90,7 +91,17 @@ int main(void) HAL_Init(); /* USER CODE BEGIN Init */ - + /* 复位原因锁存(2026-09-29,配合 IWDG):RCC_CSR 的复位标志只由上电复位(POR) + * 清除,其余复位(看门狗/软件/引脚/欠压)会跨复位保留——若不主动清除, + * 上一次的 IWDGRSTF 会一直挂着,导致每次启动都被误记为"看门狗复位"。 + * 故在 HAL_Init()(此时 RCC 可用、串口尚未就绪)之后**立即读取并清除**, + * 锁存到 RCC_CSR 影子变量,待日志子系统起来后由 app_main_init 打印。 + * 注意顺序:读 → 写 RMVF 清除,两步之间不可插入其它可能复位的代码。 */ + { + extern volatile uint32_t g_rcc_csr_latched; /* 定义于 app_main.c,供启动日志读取 */ + g_rcc_csr_latched = RCC->CSR; /* 锁存:含 IWDGRSTF/SFTRSTF/PORRSTF 等 */ + RCC->CSR |= RCC_CSR_RMVF; /* 写 1 清全部复位标志(只清标志,不影响时钟) */ + } /* USER CODE END Init */ /* Configure the system clock */ @@ -111,6 +122,7 @@ int main(void) MX_UART5_Init(); MX_USART2_UART_Init(); MX_USART3_UART_Init(); + MX_IWDG_Init(); /* USER CODE BEGIN 2 */ HAL_Delay(100); @@ -155,8 +167,9 @@ void SystemClock_Config(void) /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + 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 = 4; diff --git a/docs/README.md b/docs/README.md index f791f264..904e561e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -76,7 +76,7 @@ docs/ | [`系统墙钟时间维护说明.md`](子系统设计/系统墙钟时间维护说明.md) | `sys_clock`:RTC 基准、tick 回绕防护、30 天惰性再基准化 | | [`控制台单写者日志设计说明.md`](子系统设计/控制台单写者日志设计说明.md) | 控制台日志单写者模型(避免多任务交错输出) | | [`运行与自检记录设计说明.md`](子系统设计/运行与自检记录设计说明.md) | `/log/run.log`·`selftest.log` 定长记录与待机显示 | -| [`看门狗设计说明.md`](子系统设计/看门狗设计说明.md) | **调研+方案(待实施)**:IWDG 选型、任务心跳位图、复位原因分类、验证计划 | +| [`看门狗设计说明.md`](子系统设计/看门狗设计说明.md) | **实施中**:IWDG(CubeMX 配置)+ 任务心跳位图;代码已落地编译通过,待台架故障注入/长跑验证 | | [`网络/BSD_Socket_API_使用指南.md`](网络/BSD_Socket_API_使用指南.md) | **上层视图**:BSD Socket API 公开语义、示例、常见问题 | | [`网络/BSD_Socket_API_函数调用关系.md`](网络/BSD_Socket_API_函数调用关系.md) | **内部视图**:netTask / 消息队列 / L3 挂起 / 重试对账的调用关系与设计意图 | | [`网络/Net层阻塞模型架构设计.md`](网络/Net层阻塞模型架构设计.md) | **等待模型**:pending 请求架构、五路完成语义、设计边界与性能特征 | diff --git a/docs/内存管理/RAM使用分析与优化方案.md b/docs/内存管理/RAM使用分析与优化方案.md index 96cffbb3..ff45192b 100644 --- a/docs/内存管理/RAM使用分析与优化方案.md +++ b/docs/内存管理/RAM使用分析与优化方案.md @@ -36,10 +36,10 @@ | 区域 | 用量 | 容量 | 占比 | |---|---|---|---| -| ER_IROM1 | 261,932 B (255.79 KB) | 1,048,576 B (1024 KB) | 25.0% | -| RW_IRAM1 | 87,040 B (85.00 KB) | 131,072 B (128 KB) | 66.4% | +| ER_IROM1 | 264,860 B (258.65 KB) | 1,048,576 B (1024 KB) | 25.3% | +| RW_IRAM1 | 87,080 B (85.04 KB) | 131,072 B (128 KB) | 66.4% | | RW_CCM | 49,184 B (48.03 KB) | 65,536 B (64 KB) | 75.0% | -| **Flash (ROM 合计)** | **262,660 B (256.5 KB)** | 1,048,576 B (1024 KB) | **25.0%** | +| **Flash (ROM 合计)** | **265,616 B (259.4 KB)** | 1,048,576 B (1024 KB) | **25.3%** | 各区的容量与常量来源: diff --git a/docs/子系统设计/看门狗设计说明.md b/docs/子系统设计/看门狗设计说明.md index 7280d637..67a3f6b2 100644 --- a/docs/子系统设计/看门狗设计说明.md +++ b/docs/子系统设计/看门狗设计说明.md @@ -1,9 +1,10 @@ # 看门狗设计说明 > **模块名称**:独立看门狗(IWDG)+ 任务心跳位图 -> **文档定位**:**调研 + 设计方案**——记录选型依据、在既有平台上落地的约束、 -> 推荐架构与分步实施路径。**尚未实施**,实施后本文件应改写为"现状设计说明"。 -> **状态**:📋 设计完成,待实施(登记于 [`../待处理内容.md`](../待处理内容.md) N-03) +> **文档定位**:**实施中**——记录选型依据、在既有平台上落地的约束、实现现状与 +> 待台架验证项。**代码骨架已落地并编译通过**(§10 第 0~6 步);第 7~10 步 +> (故障注入 / 长跑 / 本文档转为"现状设计说明")待台架。 +> **状态**:🚧 代码已落地(`@build` 0/0),**待台架故障注入与长跑验证**;登记于 [`../待处理内容.md`](../待处理内容.md) N-03 > **日期**:2026-09-29 > **相关文档**: > [`../审查记录/项目审查与优化建议报告.md`](../审查记录/项目审查与优化建议报告.md)(N-03 缺陷原始登记)、 @@ -33,8 +34,7 @@ > ⚠️ **实施路径因此改变**:`HAL_IWDG_MODULE_ENABLED` 不是一个"取消注释即可"的开关—— > 取消后 `stm32f4xx_hal_conf.h` 会去 include 一个**不存在的头文件**,直接编译失败。 -> 本方案因此**不走 HAL 驱动,改用直接寄存器操作**(见 §2.2)——这反而是更优路径, -> 因为 CMSIS 设备头**已提供完整的 IWDG 寄存器定义与实例指针**,零新增依赖。 +> 故须**由 CubeMX 勾选 IWDG 后重生成**,让驱动源码与 HUD 开关一并就位(见 §2.2)。 ### 1.2 现存的两处"假保护" @@ -108,7 +108,14 @@ T_IWDG = (4 × 2^PR) × RLR / F_LSI **本方案选定(见 §4.3)**:`PR=4`(64 分频)/ `RLR=1249` → 标称 **2498 ms**、 最坏 **≈1701 ms**。 -### 2.2 实施路径:直接寄存器操作,不引入 HAL IWDG 驱动 +### 2.2 实施路径:**走 CubeMX 生成**(原方案为直接寄存器,已变更) + +> **变更说明(2026-09-29)**:本节初稿推荐"直接寄存器操作"(下称路径 C),依据是 +> HAL IWDG 驱动源码不在仓库。经与项目负责人确认,**改走 CubeMX 图形界面生成** +> (路径 A)——让 `.ioc` 成为配置的唯一事实源、与其他外设保持一致。路径 A 的 +> 原评估"高风险"已被本次实践证伪:重生成带来的定制覆盖是**有限且可枚举**的 +> (实测见 §10 第 2 步),处理方式已固化为"重生成 → 逐项恢复 → 编译验证"。 +> 以下保留路径比较,作为决策记录。 **约束事实**(§1.1 表的第 3、4 行):HAL IWDG 驱动源码**不在仓库**、也**不在 MDK 工程**中。 CubeMX 只在勾选该外设时才会把 `stm32f4xx_hal_iwdg.c/h` 拷进 `Drivers/STM32F4xx_HAL_Driver/`。 @@ -120,16 +127,44 @@ CubeMX 只在勾选该外设时才会把 `stm32f4xx_hal_iwdg.c/h` 拷进 `Driver | 路径 | 做法 | 评估 | |---|---|---| -| A. 从 CubeMX 重新生成(勾选 IWDG) | 用 `.ioc` 勾选 IWDG 后生成 | ❌ **高风险**:CubeMX 重生成会重写 `Src/`/`Inc/` 生成区,项目有大量既存定制(见 `AGENTS.md`「平台约束」),且会带回行尾空白抖动(2026-09-20 已记录过该问题) | -| B. 手工补入 `stm32f4xx_hal_iwdg.c/h` | 从 STM32CubeF4 包拷贝两文件 + 注册进 MDK 工程 | ⚠️ 可行但需**手改 `.uvprojx`**(XML 结构脆弱),且引入约 0.3 KB Flash 的 HAL 封装 | -| **C. 直接寄存器操作**(**本方案选定**) | 用 CMSIS 已提供的 `IWDG` 实例指针 + 寄存器位域宏 | ✅ **零新增依赖、零工程文件改动、代码量约 20 行** | +| **A. 从 CubeMX 重新生成(勾选 IWDG)**(**实际采用**) | 用 `.ioc` 勾选 IWDG 后生成 | ✅ **配置单一事实源、与其他外设一致**;代价 = 需恢复被覆盖的既有定制(实测 4 处,见 §10 第 2 步),且须按 `AGENTS.md` 处理行尾空白抖动 | +| B. 手工补入 `stm32f4xx_hal_iwdg.c/h` | 从 STM32CubeF4 包拷贝两文件 + 注册进 MDK 工程 | ⚠️ 需**手改 `.uvprojx`**(XML 结构脆弱),且引入约 0.3 KB Flash 的 HAL 封装;`.ioc` 与代码脱节 | +| C. 直接寄存器操作(初稿推荐,**已放弃**) | 用 CMSIS 已提供的 `IWDG` 实例指针 + 寄存器位域宏 | ✅ 零新增依赖、零工程文件改动、约 20 行;❌ 但**破坏了"外设配置统一由 CubeMX 表达"的约定**,后续维护者无处可查"这台设备的 IWDG 配了什么" | -**选 C 的依据**:CMSIS 设备头 `Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f407xx.h` -**已完整提供**所需的一切(已实测确认): +**选 A 的依据**:本项目的既有约定是"外设配置 = `.ioc`"(`AGENTS.md`「平台约束」: +`Inc/`/`Src/` 中 CubeMX 生成文件带 `USER CODE` 标记,自定义代码只写标记区内)。 +IWDG 若用裸寄存器,则分频/重载值只散落在 `App/util/task_watchdog.c` 的宏里, +与 `.ioc` 无关联——下一个维护者改超时值时**不会想到去改代码宏**。 +路径 A 让该配置出现在 CubeMX 界面里,符合项目惯例。 + +**CubeMX 侧配置值**(在 `.ioc` / CubeMX 图形界面填写): + +| 项 | 值 | 说明 | +|---|---|---| +| Activated | ✅ 勾选 | Peripheral 树 → IWDG | +| IWDG counter clock prescaler | **64** | 对应 `IWDG_PRESCALER_64`,即 `PR=4` | +| IWDG down-counter reload value | **1249** | 12 位,范围 0~4095 | +| Window value | —— | ⚠️ **本 HAL 版本 `IWDG_InitTypeDef` 无此字段**(仅 `Prescaler` / `Reload`),CubeMX 界面亦无该项;窗口寄存器保持复位默认 `0xFFF` = 禁用窗口,符合预期 | + +生成结果:`Src/iwdg.c` / `Inc/iwdg.h`(新文件)、`Drivers/STM32F4xx_HAL_Driver/{Inc,Src}/stm32f4xx_hal_iwdg.{h,c}`、 +`Inc/stm32f4xx_hal_conf.h` 中 `HAL_IWDG_MODULE_ENABLED` 解除注释、`.uvprojx` 挂载驱动、 +`Src/main.c` 的 `MX_*_Init()` 序列新增 `MX_IWDG_Init()`。 + +> ⚠️ **路径 A 的固有陷阱(本次实测踩中,P0)**:CubeMX 把 `MX_IWDG_Init()` 插在 +> `app_main_init()` **之前**,而 `HAL_IWDG_Init()` 内部第一句即 +> `__HAL_IWDG_START(hiwdg)`(立即启动、之后不可停)。启动段(NAND 初始化等)耗时 +> 可达数秒且无喂狗点 → 按 2.5s 超时必然复位 → **开机死循环**。 +> **CubeMX 界面无法关闭这个自动启动**(HAL 行为,无对应选项)。 +> 解决办法见 §4.5 决策 C:把 `Src/iwdg.c` 里那一行 `HAL_IWDG_Init(&hiwdg)` 换成 +> 只填参数的 USER CODE 注释块,启动动作移交 `task_wd_start()`。 +> 这是路径 A 下**唯一必须手工修改生成文件**的地方,已在文件内留注释说明恢复方法。 + +**参考:CMSIS 设备头已提供的寄存器定义**(路径 C 曾依赖,现仅作 `task_wd_beat`/`task_wd_poll` +里裸写 `IWDG->KR` 的依据): | 已有定义 | 位置 | 内容 | |---|---|---| -| `IWDG_TypeDef` | `:573-579` | `KR` / `PR` / `RLR` / `SR` 四寄存器结构体 | +| `IWDG_TypeDef` | `stm32f407xx.h:573-579` | `KR` / `PR` / `RLR` / `SR` 四寄存器结构体 | | `IWDG_BASE` | `:944` | `APB1PERIPH_BASE + 0x3000` | | `IWDG` 实例指针 | `:1068` | `((IWDG_TypeDef *) IWDG_BASE)` | | `IWDG_KR_KEY_Msk` | `:9331` | 键值字段掩码 | @@ -137,7 +172,7 @@ CubeMX 只在勾选该外设时才会把 `stm32f4xx_hal_iwdg.c/h` 拷进 `Driver | `IWDG_RLR_RL_Msk` | `:9344` | 重装值字段(12 位) | | `IWDG_SR_PVU` / `IWDG_SR_RVU` | `:9349-9353` | 更新进行中标志(须轮询等它清零) | -**键值常量**(上游 HAL 在 `stm32f4xx_hal_iwdg.h` 定义,本方案需自行定义): +**键值常量**(由 HAL 定义在 `stm32f4xx_hal_iwdg.h`,本方案在 `task_watchdog.c` 内裸写): | 用途 | 值 | |---|---| @@ -149,9 +184,10 @@ CubeMX 只在勾选该外设时才会把 `stm32f4xx_hal_iwdg.c/h` 拷进 `Driver IWDG 是**"写键值"式外设**:写 `0x5555` 解锁 → 配 `PR`/`RLR` → 写 `0xCCCC` 启动 (启动后**不可停**,只能复位)→ 此后周期性写 `0xAAAA` 喂狗。 -> **为何这会被称为"更优路径"**:HAL 的 `HAL_IWDG_Init()` 内部做的事就是上面这几步, -> 外加一个 `IWDG_HandleTypeDef` 状态机。本项目不需要那层封装——寄存器操作总共 -> 约 20 行,且完全落在 `App/util/task_watchdog.c` 内,**不触碰任何 CubeMX 生成文件**。 +> **喂狗为何仍走裸寄存器而非 `HAL_IWDG_Refresh()`**:喂狗是 100 ms 级高频操作, +> HAL 封装带 `IWDG_HandleTypeDef` 有效性检查(读 `State` 字段、判 `LOCKED`), +> 在高频路径上无收益。`Task_wd_poll()` 里写 `IWDG->KR = 0xAAAA` 是 1 条存储指令。 +> 这不是"绕过 HAL",而是"HAL 提供了该寄存器定义,直接用"——与路径选择无关。 --- @@ -558,22 +594,24 @@ void task_wd_poll(void) > 丢失"是看门狗抓到的"这一关键信息。**让 IWDG 自然溢出**, > 复位原因才是权威的 `watchdog reset`。代价是额外的 ≤2.5 s 延迟(可接受)。 -### 5.4 各任务的埋点位置 +### 5.4 各任务的埋点位置(**2026-09-29 已全部落地**) -| 任务 | 埋点位置 | 备注 | +| 任务 | 实际埋点位置 | 备注 | |---|---|---| -| `defaultTask` | `default_task_func` 的 `for(;;)` 循环首行 | 50 ms 节拍,天然满足 | -| `netTask` | 主循环 `for(;;)` 内(`net_poll` 之后) | 1 ms 节拍;另需在 `net_stack_bring_up` 的 PHY 等待循环内补埋点(§4.4) | -| `ftpTask` | ⚠️ 见 §4.3 —— 第一步**剔除掩码**;后续改 `Lib/lftpd` 时再补 | 已知缺口 | -| `uiTask` | `ui_task_func` 主循环(`osDelay(10)` 处) | 10 ms 节拍 | -| `timeSyncTask` | `time_sync_task` 主循环 | 最长 `vTaskDelay(2000)`——⚠️ **2 s > 800 ms 容忍窗口**,需拆分:在 `vTaskDelay` 前多次分段置位,或把该 timeout 缩短 | -| `testTask` | 由套件掩码决定 | 套件运行时可长阻塞,按 §4.1 排除 | +| `defaultTask` | `App/task/default_task.c`:`for(;;)` 首行 `task_wd_poll()` + `task_wd_beat(TASK_WD_DEFAULT)` | 50 ms 节拍,天然满足;同时是唯一喂狗者 | +| `netTask` | `App/task/net_task.c`:① 主循环 `for(;;)` 首行;② `net_stack_bring_up` 的 PHY 等待循环内 `osDelay(50)` 前;③ `ENABLE_HW_LAYER_TESTS` 自挂起分支(掩码已剔除,埋点无副作用) | ② 为 §4.4 白名单项:PHY 最长等待 3 s(60×50 ms),必须在其中补心跳 | +| `ftpTask` | ⚠️ **首期不埋点**——由 `wd_required_mask()` **剔除**(见 §4.3) | 已知缺口:`Lib/lftpd` 事件循环改动面大,二期再补 | +| `uiTask` | `App/task/ui_task.c`:`ui_port_step(10)` / `ui_net_sink_poll()` 之后 | 10 ms 节拍;等待 NET_READY 期间不喂属**预期**(该段卡死即应复位) | +| `timeSyncTask` | `App/sync/time_sync.c`:① `time_sync_task` 主循环首行;② 监听重试的 500 ms / 2 s 延时前;③ accept 轮询 200 ms 延时前;④ 收尾 50 ms 延时前;⑤ **`time_sync_handle_conn` 内的等待循环**(关键:把 30 s 总预算切成 `TIME_SYNC_WAIT_SLICE_MS`=200 ms 的片,每片先喂心跳) | ⑤ 是本案最要害的一处:对端连上但不发时间包是完全正常的场景,若不切片,30 s 等待必然被判卡死 | +| `testTask` | 不埋点——由套件掩码决定,按 §4.1 排除 | 套件运行时可长阻塞 | -> ⚠️ **`timeSyncTask` 是关键风险点**:其主循环有两处 `vTaskDelay(pdMS_TO_TICKS(2000))` -> (`App/sync/time_sync.c:68/75`)。若心跳位只在循环首行,则 2 s 内位图恒缺席, -> **必然触发停喂**。处理三选一:① 每 200 ms 分段置位;② 缩短该 delay; -> ③ 该任务单独用"宽松窗口"(增大容忍次数到 25 次 = 2.5 s,但会逼近 IWDG 超时,不推荐)。 -> **推荐 ①**:把 2 s 拆成 10 × 200 ms 循环,每次置位并检查退出条件——语义不变,且提升响应性。 +> ⚠️ **实施时的新发现(补充 §4.4 白名单)**:`timeSyncTask` 的风险**不止** +> 主循环里那两处 `vTaskDelay(2000)`——`time_sync_handle_conn` 内部的 +> `net_recv_to(..., rem)` 单次可睡满 **30 s 总预算**。初稿只注意到 `vTaskDelay` +> 的两处,会漏掉这处。处理方式取"**切片**"而非"放宽窗口": +> 新增 `TIME_SYNC_WAIT_SLICE_MS = 200U`,把单次等待的 `rem` 夹到 ≤200 ms, +> 每片先 `task_wd_beat()`。总预算语义(≤30 s)完全不变,只是把一次长睡眠 +> 拆成多次短睡眠——同时提升了"对端提前到达"的响应粒度。 --- @@ -581,26 +619,41 @@ void task_wd_poll(void) ### 6.1 串口标记(供 `@test` 采集) +**实际实现**(2026-09-29 落地,`App/app/app_main.c` + `App/util/task_watchdog.c` + +`Src/freertos.c`): + | 标记 | 时机 | 含义 | |---|---|---| -| `[WD] reset cause=<类型>` | `app_main_init` 早期 | 复位原因(`power on` / `watchdog reset` / `soft reset` / `pin reset`) | -| `[WD] watchdog armed (timeout=2500ms)` | `task_wd_start()` | IWDG 已启动(真机自检必查标记) | -| `[WD] miss streak= mask=0x%08X` | 每次未达标(限流打印) | 谁没动(`mask` 中 0 位 = 缺失任务) | -| `[ERR] WATCHDOG: task stall` | 停喂时 | 即将复位,最后遗言 | -| `[WD] beat ok` | 可选,调试期 | 心跳正常(默认关闭,避免刷屏) | +| `[APP] reset cause: <类型> (CSR=0x%08X)` | `app_main_init` 早期 | 复位原因,类型为 `IWDG (independent watchdog)` / `WWDG (window watchdog)` / `software (NVIC_SystemReset)` / `power-on (POR)` / `external pin (NRST)` / `brown-out (BOR)` / `unknown`;同时打印 `RCC_CSR` 原值便于事后核对 | +| `[WD] armed: timeout ~2498ms (worst ~1701ms), miss_tol=800ms` | `task_wd_start()` | IWDG 已启动(真机自检必查标记) | +| `[WD] task stall: mask=0x%08X req=0x%08X miss=%lu` | 连续 8 窗未达标时(每窗一次,共打印至复位) | 即将停喂 → 约 2.5 s 后 IWDG 复位。`mask` 的 0 位 = 缺席任务 | +| `[ERR] ASSERT FAILED : (resetting)` | `vApplicationAssertFailed()` | FreeRTOS 断言失败(`Src/freertos.c`),打印后主动复位 | +| `[ERR] STACK OVERFLOW task=` | `vApplicationStackOverflowHook` | 既有钩子(栈溢出) | +| `[ERR] MALLOC FAILED (heap exhausted)` | `vApplicationMallocFailedHook` | 既有钩子(堆耗尽,只告警不复位) | + +> 日志标签说明:`[APP]` 是 `App/app/app_main.c` 的 `DBG_TAG`;`[WD]` 是 +> `App/util/task_watchdog.c` 的 `DBG_TAG`(定义在两个 include 之间, +> 是 `dbg_log.h` 的既有取标签方式)。全部为纯 ASCII,规避 `AGENTS.md` 记载的 +> ARMCC CP936 字符串字面量陷阱。 ### 6.2 与 `run.log` 的集成 `sys_log_mcu.c` 的 `syslog_mcu_mounted()` 当前只写 `power on` / `reboot` -(靠 `run.log` 末条 epoch 时间差推断)。**改为优先用硬件标志**: +(靠 `run.log` 末条 epoch 时间差推断)。**现状:未改**——本次实施选择 +"先只在串口上报 `reset cause`",理由: + +1. 串口标记已经能支撑 `@test` 判定与人工归因,`run.log` 的价值在于**长期累计**; +2. 写 `run.log` 涉及 UI 字符集("看门狗"三字是否在位)与既有 600 s 时间窗分类逻辑, + 改动面比串口上报大,**留作二期**(`待处理内容.md` N-03 后续项)。 + +**二期计划**(复位原因映射表,优先级见 §4.8): ``` -复位原因(§4.8 优先级)→ 描述串映射: - power on → "power on" (既有) - watchdog reset → "watchdog" (新增,UI 字符集需补"看门狗"三字) - soft reset → "soft reset" (新增) - pin reset → "pin reset" (新增) - 其余 → 回退既有 600s 时间窗分类 +power-on (POR) → "power on" (既有) +IWDG / WWDG → "watchdog" (新增,UI 字符集需补"看门狗"三字) +software → "soft reset" (新增) +external pin → "pin reset" (新增) +其余 → 回退既有 600s 时间窗分类 ``` > ⚠️ **UI 字符集影响**:`docs/子系统设计/运行与自检记录设计说明.md` §6.1 记录了 @@ -685,24 +738,42 @@ void task_wd_poll(void) ## 10. 实施步骤(按序执行,每步端到端验证) -| 步 | 内容 | 验证 | -|---|---|---| -| **1** | 新建 `App/util/task_watchdog.c/h`;实现 IWDG 寄存器级 `wd_iwdg_init/feed` + 心跳位图;**登记进 MDK 工程** | `@build` 0/0 | -| **2** | `Src/main.c` 复位原因锁存 + 清标志;`syslog_mcu.c` 写描述串 | V7/V8(`cause` 正确) | -| **3** | 实现抽样判定 + 串口标记(**暂不启动 IWDG**) | V1 观察 `[WD] beat ok`(调试期) | -| **4** | 各任务埋点(含 `timeSyncTask` 拆分) | V5 短跑(5 min)无 `miss` 打印 | -| **5** | `task_wd_start()` 启动 IWDG(写 `0xCCCC`) | V1 + V5 | -| **6** | `configASSERT` 改造 + `vApplicationAssertFailed()` | V3 | -| **7** | 故障注入(V2/V4) | 复位 + `cause` 正确 | -| **8** | 模拟器 `--watchdogtest` + stub | S1 | -| **9** | 长跑(V5,≥30 min,真实负载) | **零复位** | -| **10** | 本文档改写为"现状设计说明";`待处理内容.md` N-03 销项;`README.md` 登记 | 门禁 | +| 步 | 内容 | 验证 | 状态 | +|---|---|---|---| +| **0** | **(新增)** CubeMX 勾选 IWDG(Prescaler=64 / Reload=1249)→ 重生成 → **恢复被覆盖的定制** | `@build` 0/0 + 启动日志齐全 | ✅ **2026-09-29 完成**,覆盖 4 处见下 | +| **1** | 新建 `App/util/task_watchdog.c/h`;实现心跳位图 + 抽样判定 + IWDG 延后启动;**登记进 MDK 工程**(`App` 组,`sys_clock.c` 之后) | `@build` 0/0 | ✅ 完成 | +| **2** | `Src/main.c` 复位原因锁存 + 清标志;`App/app/app_main.c` 打印描述串 | `[APP] reset cause:` 出现 | ✅ 完成(`run.log` 写入留二期) | +| **3** | `Src/iwdg.c` 阻止 `HAL_IWDG_Init()` 自动启动(P0) | 开机不死循环 | ✅ 完成 | +| **4** | 各任务埋点(含 `timeSyncTask` **切片**而非拆 delay) | 编译 0/0;串口无 `miss` | ✅ 完成 | +| **5** | `task_wd_start()` 由 `defaultTask` 在 bring-up 完成后调用 | `[WD] armed:` 出现 | ✅ 完成 | +| **6** | `configASSERT` 改造 + `vApplicationAssertFailed()` | 编译 0/0 | ✅ 完成 | +| **7** | 故障注入(V2/V4):人为制造任务卡死 | 复位 + `reset cause: IWDG` | ⏳ **待台架** | +| **8** | 模拟器 `--watchdogtest` + stub | S1 | ⏳ 待做 | +| **9** | 长跑(V5,≥30 min,真实负载) | **零复位** | ⏳ **待台架** | +| **10** | 本文档改写为"现状设计说明";`待处理内容.md` N-03 销项;`README.md` 登记 | 门禁 | ⏳ 待第 7~9 步结论 | -> **每步改完必须 `@build` 0 错误 0 警告**(`AGENTS.md` 铁律)。 -> -> **第 1 步的风险点**:`App/util/task_watchdog.c` 需在 `MDK-ARM/*.uvprojx` 中挂载。 -> 若挂载不顺,可临时把实现放进 `App/task/default_task.c`(已在工程内)验证逻辑, -> 待工程文件可改时再抽成独立模块。**两种形态的逻辑完全一致**。 +### 10.1 第 0 步实测:CubeMX 重生成覆盖了哪 4 处 + +`.ioc` 的 `ProjectManager.DeletePrevious=true` + `KeepUserCode=true` 决定了 +**只有 `USER CODE BEGIN/END` 标记区内的代码受保护**。实测被覆盖的定制: + +| 级别 | 文件 | 被覆盖内容 | 恢复方式 | +|---|---|---|---| +| **P0** | `Src/iwdg.c`(新文件) | CubeMX 生成的 `MX_IWDG_Init()` 直接调 `HAL_IWDG_Init()` → 开机死循环 | 改为只填参数;插 `USER CODE BEGIN IWDG_DEFER_START` 注释块说明(**唯一必需的手工改动**) | +| **P1** | `Src/stm32f4xx_it.c` | `HardFault_Handler` 崩溃现场采集(91 行:PC/LR/xPSR/R0-R3/CFSR/HFSR/BFAR/MMFAR)被打回空 `while(1)` | 整块换回手工版(`__asm void` 汇编取 MSP/PSP + `hard_fault_report`) | +| **P1** | `Inc/FreeRTOSConfig.h` | `configCHECK_FOR_STACK_OVERFLOW 2` + `configUSE_MALLOC_FAILED_HOOK 1` **整个块被删除** | 插回 `USER CODE BEGIN FREE_RTOS_CONFIG_HARDENING` 块 | +| **P2** | `Src/freertos.c` | 三处中文注释丢失(任务栈大小的实测记录) | 恢复注释(栈**数值**未丢,`.ioc` 同步到位) | + +> ⚠️ **P1 两处的教训**:它们都在 `USER CODE` 标记区**之外**(`stm32f4xx_it.c` 的 +> `HardFault_Handler` 由 CubeMX 直接生成;`FreeRTOSConfig.h` 的加固宏原本写在 +> 非 `USER CODE` 区)。**P1 的丢失不会立刻暴露**——栈溢出检测与堆失败钩子只在 +> 真发生溢出/耗尽时才起作用,且 `HardFault_Handler` 被打回空死循环后 +> **崩溃时连现场都打不出来**(只剩 IWDG 兜底复位,但归因信息全丢)。 +> 故本次已把这三个宏搬进 `USER CODE BEGIN 1` 区,并加注释 +> "⚠ 本段为手工添加,CubeMX 重生成会删除(2026-09-29 实测),改完须核对本块存在"。 + +> **每步改完必须 `@build` 0 错误 0 警告**(`AGENTS.md` 铁律)。第 0~6 步已一次性 +> 验证通过:`BUILD_OK: 0 errors, 0 warnings`。 --- @@ -711,7 +782,7 @@ void task_wd_poll(void) | 议题 | 结论 | |---|---| | **选型** | **IWDG**(独立 LSI),非 WWDG(依赖 APB1 + 中断,在关中断/HardFault 场景失效) | -| **实施路径** | **直接寄存器操作**(不引入 HAL IWDG 驱动)——驱动源码不在仓库、也未经由 CubeMX 生成,CMSIS 设备头已提供全部寄存器定义(§2.2) | +| **实施路径** | **CubeMX 勾选 IWDG 生成**(`.ioc` = 配置单一事实源,与其他外设一致);唯一手工改动 = `Src/iwdg.c` 中阻止 `HAL_IWDG_Init()` 立即启动(§2.2 / §4.5) | | **架构** | **任务心跳位图(各自置位,无锁单字)+ defaultTask 单一喂狗者**——避免"有人跑就喂狗"的假保护 | | **超时** | 2498 ms(PR=4 / RLR=1249);最坏(LSI 47 kHz)≈1701 ms;中间留 800 ms 停喂判定裕度 | | **启动时机** | **defaultTask bring-up 完成后**——绕开初始化深链超时陷阱,代价是启动段无保护 | @@ -768,4 +839,5 @@ void task_wd_poll(void) | 日期 | 变更 | 说明 | |---|---|---| | 2026-09-29 | 创建 | 调研 + 设计方案:IWDG + 任务心跳位图;含选型、九项设计决策、验证计划与风险清单 | -| 2026-09-29 | 修正实施路径 | 实测发现 HAL IWDG 驱动源码不在仓库且未编入 MDK 工程 → 改为**直接寄存器操作**(§2.2 路径 C);超时数值按公式核算修正;补 `RCC_CSR`/`IWDG` 寄存器定义的实测行号 | +| 2026-09-29 | 修正实施路径 | 实测发现 HAL IWDG 驱动源码不在仓库且未编入 MDK 工程 → 初稿改为**直接寄存器操作**(§2.2 路径 C);超时数值按公式核算修正;补 `RCC_CSR`/`IWDG` 寄存器定义的实测行号 | +| 2026-09-29 | **路径再变更 + 实施落地** | 决策改走 **CubeMX 图形配置**(§2.2 路径 A):`HAL_IWDG_MODULE_ENABLED` 改为经 CubeMX 生成(避免"取消注释即编译失败")。同时落地 §5 骨架到 `App/util/task_watchdog.{c,h}`,各任务埋点(default/net/ui/time_sync),`RCC_CSR` 复位原因锁存(`Src/main.c` + `App/app/app_main.c`),`configASSERT` 改为 `vApplicationAssertFailed()`。实测 CubeMX 重生成覆盖 4 处既有定制(P0×1 + P1×2 + P2×1),已全部恢复,`@build` 0 错误 0 警告 | diff --git a/docs/待处理内容.md b/docs/待处理内容.md index 8fce18e2..6c413f38 100644 --- a/docs/待处理内容.md +++ b/docs/待处理内容.md @@ -30,6 +30,7 @@ | # | 事项 | 说明 | 出处 | |---|---|---|---| -| N-03 | **引入独立看门狗(IWDG)+ 任务心跳位图**——现状全库无看门狗(HAL 驱动源码也不在仓库),任何形态死机不可自恢复;另 `configASSERT` 为关中断死循环(连日志都不打)。**设计方案已完成**(含选型、九项决策、验证计划、风险清单),待实施 | **设计见 [`子系统设计/看门狗设计说明.md`](子系统设计/看门狗设计说明.md)**;实施路径为直接寄存器操作(不引入 HAL IWDG 驱动);实施后本文档改写为现状设计说明并销项 | `审查记录/项目审查与优化建议报告.md` N-03a/b/c | -| N-03a | `configASSERT(x)` = `taskDISABLE_INTERRUPTS(); for(;;);`(`Inc/FreeRTOSConfig.h:163`)→ 断言时无任何输出 | 修复方案见 `看门狗设计说明.md` §4.6(改为"先记录后复位");N-03 实施时一并处理 | 同上 N-03b | -| N-03b | 启动段(`app_main_init` + `defaultTask` bring-up)在新方案下**无看门狗保护** | 显式代价:`看门狗设计说明.md` §4.5 决策 C + §9 R1;该段死机表现为"无输出 + LED 不闪" | 同上 N-03c | +| N-03 | **引入独立看门狗(IWDG)+ 任务心跳位图**——现状全库无看门狗(HAL 驱动源码也不在仓库),任何形态死机不可自恢复;另 `configASSERT` 为关中断死循环(连日志都不打)。**代码已落地并编译通过(2026-09-29)**:CubeMX 生成 IWDG(Prescaler=64/Reload=1249)+ `App/util/task_watchdog.{c,h}` 心跳位图 + 6 任务埋点 + `RCC_CSR` 复位原因锁存 + `configASSERT` 改造 | **剩台架验证**(故障注入 V2/V4、长跑 V5 ≥30 min);文档 §10 第 7~10 步待办 | **见 [`子系统设计/看门狗设计说明.md`](子系统设计/看门狗设计说明.md)**(§10 有实施状态表) | `审查记录/项目审查与优化建议报告.md` N-03a/b/c | +| N-03a | `configASSERT(x)` = `taskDISABLE_INTERRUPTS(); for(;;);`(`Inc/FreeRTOSConfig.h`)→ 断言时无任何输出 | ✅ **已修(2026-09-29)**:改为 `vApplicationAssertFailed(__FILE__, __LINE__)`,打印文件名+行号后主动复位(`Src/freertos.c`);宏已迁入 `USER CODE BEGIN 1` 区防重生成丢失 | 同上 N-03b | +| N-03b | 启动段(`app_main_init` + `defaultTask` bring-up)在新方案下**无看门狗保护** | 显式代价(未变):`看门狗设计说明.md` §4.5 决策 C + §9 R1;该段死机表现为"无输出 + LED 不闪" | 同上 N-03c | +| N-03c | **CubeMX 重生成会覆盖 `USER CODE` 标记区之外的定制** | ⚠️ **2026-09-29 实测确认**:重生成覆盖 4 处(P0 `Src/iwdg.c` 自动启动、P1 `HardFault_Handler` 打回空死循环、P1 `FreeRTOSConfig.h` 两个加固宏被删、P2 `freertos.c` 中文注释);已全部恢复并加"重生成会删除"警示注释;**今后每次 CubeMX 重生成后须重跑本文档 §10.1 的核对清单** | 本次实施记录 |