CCM扩容FreeRTOS堆+DMA阈值1024防栈缓冲进CCM+HardFault现场报告与栈/内存钩子+修defaultTask栈溢出+LVGL绘制缓冲护栏+存储套件05/06与恢复模式

This commit is contained in:
2026-09-21 00:47:58 +08:00
parent 271adc38e1
commit 9230effced
9 changed files with 357 additions and 36 deletions
+61 -3
View File
@@ -25,6 +25,7 @@
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "test_config.h" /* 套件选择:STORAGE 套件下 defaultTask 让出存储所有权 */
#include <string.h>
#include "net_task.h"
#include "ch395f.h"
@@ -72,7 +73,10 @@ const osThreadAttr_t timeSyncTask_attributes = {
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.stack_size = 512 * 4,
.stack_size = 1024 * 4, /* 512→1024: 该任务扛 mount+mkfs+FAT探针+cfg加载+syslog写+
* 配置引擎(全深层 FatFS I/O),2KB 实测峰值溢出——开启
* configCHECK_FOR_STACK_OVERFLOW=2 后被钩子抓到(2026-09-21)。
* 此前静默溢出腐蚀堆相邻块。改 .ioc 前须同步此值防 CubeMX 覆盖 */
.priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for netTask */
@@ -93,7 +97,7 @@ const osThreadAttr_t ftpTask_attributes = {
osThreadId_t testTaskHandle;
const osThreadAttr_t testTask_attributes = {
.name = "testTask",
.stack_size = 1024 * 4,
.stack_size = 2048 * 4, /* 1024→2048: 存储套件 deep call chain + 局部缓冲,4KB 实测溢出(2026-09-20) */
.priority = (osPriority_t) osPriorityBelowNormal,
};
/* Definitions for uiTask */
@@ -117,7 +121,9 @@ const osEventFlagsAttr_t sys_evt_attributes = {
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
void ui_task_func(void *argument);
#if !defined(TEST_SUITE_STORAGE)
static void default_task_net_cfg_save_notify(void);
#endif
/* USER CODE END FunctionPrototypes */
void StartDefaultTask(void *argument);
@@ -225,7 +231,12 @@ void StartDefaultTask(void *argument)
* 防 FTL 瞬态抖动误触发);结构性错误 → 自动重格式化自愈。代价:卷被清空
* (/config.ini 丢失 → 配置引擎首启路径回落工厂默认并自动重建模板)——
* 仅当卷已不可用时触发,可用设备 > 一份配置文件。 */
static FATFS default_fatfs;
#if !defined(TEST_SUITE_STORAGE)
/* STORAGE 套件构建下 defaultTask 完全跳过存储 bring-up(挂载/配置/日志盘写),
* 卷由 testTask 的 storage_test_run 独占——测试含 nand_ftl_deinit 掉电模拟,
* 与任何后台文件写入并发都会互相踩坏 FTL/FatFs 状态(2026-09-20 台架实证:
* 双写并发导致 mkfs 半途冻结 + BBT 被误写) */
static FATFS default_fatfs;
FRESULT fr = f_mount(&default_fatfs, "", 1);
if (fr == FR_NO_FILESYSTEM) {
DBG_INFO("[FS] no FAT volume, formatting NAND...");
@@ -330,6 +341,10 @@ void StartDefaultTask(void *argument)
/* 注册"保存网络配置"请求通知:UI(uiTask)投递 → 置事件 → 本任务立即执行写盘
* (配置引擎属主 = 本任务;UI 保存不再直接触碰配置文件引擎,P1-3) */
net_cfg_set_save_req_cb(default_task_net_cfg_save_notify);
#else
/* STORAGE 套件构建:挂载/配置引擎/日志盘写全部跳过,存储由 testTask 独占 */
DBG_INFO("[FS] mount/cfg skipped (STORAGE suite owns storage)");
#endif
/* 配置 poll 周期计数(每 4 次循环 = 2s 轮询一次,与引擎文档/模拟器一致) */
uint32_t cfg_poll_cnt = 0u;
@@ -341,16 +356,22 @@ void StartDefaultTask(void *argument)
(void)osEventFlagsWait(sys_evtHandle, SYS_EVT_CFG_SAVE, osFlagsWaitAny, 500u);
}
/* 执行待处理保存(配置引擎属主:写盘 + 成功后立即应用);无请求 = 空操作 */
#if !defined(TEST_SUITE_STORAGE)
net_cfg_save_run();
#endif
/* 配置文件变更轮询(2s 周期;沉降去抖在引擎内) */
if ((cfg_poll_cnt++ & 3u) == 0u) {
#if !defined(TEST_SUITE_STORAGE)
cfg_file_poll();
#endif
}
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
HAL_GPIO_TogglePin(LED3_GPIO_Port, LED3_Pin);
#if !defined(TEST_SUITE_STORAGE)
/* 排空运行期日志(上电/重启分类与自检故障落盘) */
syslog_drain();
#endif
}
/* USER CODE END StartDefaultTask */
}
@@ -438,10 +459,47 @@ void StartUiTask(void *argument)
* "保存网络配置"请求通知(注册给 net_cfg 的保存交接):
* uiTask 投递保存请求 → 置 SYS_EVT_CFG_SAVE → defaultTask 循环立即唤醒执行写盘
*/
#if !defined(TEST_SUITE_STORAGE)
static void default_task_net_cfg_save_notify(void)
{
if (sys_evtHandle != NULL) {
(void)osEventFlagsSet(sys_evtHandle, SYS_EVT_CFG_SAVE);
}
}
#endif
/*
* 栈溢出钩子(configCHECK_FOR_STACK_OVERFLOW=2,2026-09-20 存储套件死机事故后加):
* 溢出 = 内核状态已不可信,禁止走 printf/内核对象,裸 UART 报任务名后复位。
*/
void vApplicationStackOverflowHook(void *xTask, signed char *pcTaskName)
{
static const char msg_head[] = "\r\n[ERR] STACK OVERFLOW task=";
(void)xTask;
HAL_UART_Transmit(&huart1, (const uint8_t *)msg_head,
(uint16_t)(sizeof(msg_head) - 1u), 0xFFFFu);
if (pcTaskName != NULL) {
uint16_t len = 0;
while (len < 32u && pcTaskName[len] != '\0') {
len++;
}
HAL_UART_Transmit(&huart1, (const uint8_t *)pcTaskName, len, 0xFFFFu);
}
HAL_UART_Transmit(&huart1, (const uint8_t *)"\r\n", 2u, 0xFFFFu);
HAL_Delay(200);
NVIC_SystemReset();
}
/*
* 堆分配失败钩子:只告警不复位(NULL 由各调用点自行处理并上报自检)。
* 同样走裸 UART——钩子可能在临界区内被调,printf/信号量不可用。
*/
void vApplicationMallocFailedHook(void)
{
static const char msg[] = "\r\n[ERR] MALLOC FAILED (heap exhausted)\r\n";
HAL_UART_Transmit(&huart1, (const uint8_t *)msg,
(uint16_t)(sizeof(msg) - 1u), 0xFFFFu);
}
/* USER CODE END Application */
+79 -9
View File
@@ -22,6 +22,7 @@
#include "stm32f4xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "usart.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@@ -95,17 +96,86 @@ void NMI_Handler(void)
/**
* @brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
/* USER CODE BEGIN HardFault_Handler */
/* 崩溃现场采集(本函数为手工改写,CubeMX 重生成会覆盖!):
* EXC_RETURN bit2 判断异常帧在 MSP 还是 PSP,取帧指针交给 C 报告函数。
* 空 while(1) 版会让死机在日志上完全静默(2026-09-20 存储套件死机排查实证) */
__asm void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
/* USER CODE END W1_HardFault_IRQn 0 */
}
extern hard_fault_report
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B hard_fault_report
}
/* USER CODE END HardFault_Handler */
/* USER CODE BEGIN HardFault_Report */
/*
* 函数功能:HardFault 现场报告(裸机上下文,不经内核/printf)
* 入口参数:frame - 异常栈帧 {R0,R1,R2,R3,R12,LR,PC,xPSR}
* 函数说明:直接 HAL_UART_Transmit 轮询输出 PC/LR/xPSR 与 CFSR/HFSR 故障
* 寄存器,供开机日志定位崩溃点(对照 .map 找符号);输出后复位。
*/
static void hard_fault_puts(const char *s)
{
uint16_t len = 0;
while (s[len] != '\0') {
len++;
}
HAL_UART_Transmit(&huart1, (const uint8_t *)s, len, 0xFFFFu);
}
static void hard_fault_puthex(uint32_t v)
{
static const char digits[] = "0123456789ABCDEF";
char out[9];
int i;
for (i = 0; i < 8; i++) {
out[i] = digits[(v >> (28 - i * 4)) & 0xFu];
}
out[8] = '\0';
hard_fault_puts(out);
}
void hard_fault_report(uint32_t *frame)
{
hard_fault_puts("\r\n[ERR] HARDFAULT PC=");
hard_fault_puthex(frame[6]);
hard_fault_puts(" LR=");
hard_fault_puthex(frame[5]);
hard_fault_puts(" xPSR=");
hard_fault_puthex(frame[7]);
hard_fault_puts(" R0=");
hard_fault_puthex(frame[0]);
hard_fault_puts(" R1=");
hard_fault_puthex(frame[1]);
hard_fault_puts(" R2=");
hard_fault_puthex(frame[2]);
hard_fault_puts(" R3=");
hard_fault_puthex(frame[3]);
hard_fault_puts(" CFSR=");
hard_fault_puthex(SCB->CFSR);
hard_fault_puts(" HFSR=");
hard_fault_puthex(SCB->HFSR);
/* BFAR/MMFAR 仅在对应 valid 位为 1 时有意义 */
if ((SCB->CFSR & (1UL << 15)) != 0U) {
hard_fault_puts(" BFAR=");
hard_fault_puthex(SCB->BFAR);
}
if ((SCB->CFSR & (1UL << 7)) != 0U) {
hard_fault_puts(" MMFAR=");
hard_fault_puthex(SCB->MMFAR);
}
HAL_Delay(200);
NVIC_SystemReset();
}
/* USER CODE END HardFault_Report */
/**
* @brief This function handles Memory management fault.