实现独立看门狗:CubeMX 配置 IWDG + 任务心跳位图,恢复三处被覆盖定制
经 CubeMX 图形界面启用 IWDG(Prescaler=64 / Reload=1249,标称 2498ms /
最坏 1701ms),并落地心跳位图判定、各任务埋点、RCC_CSR 复位原因上报与
configASSERT 改造。重生成覆盖的既有定制已全部恢复。
P0(开机死循环):HAL_IWDG_Init() 内部立即启动看门狗,而 CubeMX 把
MX_IWDG_Init() 插在 app_main_init() 之前——该段 NAND/RTC/ADC 初始化耗时
数秒无喂狗点,按 2.5s 超时必然复位。改 Src/iwdg.c 为只填参数不启动,
启动移交 task_wd_start(),由 defaultTask 在存储 bring-up 完成后调用。
恢复的三处定制(重生成覆盖):
- Src/stm32f4xx_it.c:HardFault_Handler 崩溃现场采集被打回空 while(1)
- Inc/FreeRTOSConfig.h:栈溢出检测与堆失败钩子两个宏被整块删除
- Src/freertos.c:三处任务栈实测记录中文注释丢失(数值未丢)
新增:
- App/util/task_watchdog.{c,h}:心跳位图 + 抽样判定 + IWDG 延后启动
- time_sync.c 长等待切片:net_recv_to 单次可睡满 30s 预算,切成 200ms 片
- Src/main.c 复位原因锁存(读后即清 RMVF,防残留误判)
埋点:defaultTask(唯一喂狗者)/ netTask(含 PHY 等待循环)/ uiTask /
timeSyncTask。ftpTask 首期剔除掩码,待二期改 lftpd。
门禁:build 0 错误 0 警告;pre-commit 10 钩子全通过;Flash +2956B / RAM +40B。
This commit is contained in:
@@ -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 */
|
||||
|
||||
+63
@@ -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 */
|
||||
+15
-2
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user