diff --git a/Drivers/BSP/NET/net_socket.c b/Drivers/BSP/NET/net_socket.c index 07009d4d..7c060932 100644 --- a/Drivers/BSP/NET/net_socket.c +++ b/Drivers/BSP/NET/net_socket.c @@ -69,12 +69,34 @@ static uint16_t s_dynamic_port = 49152; /* 动态端口分配起始 static volatile uint32_t s_net_generation = 0; /* 网络代次号:网络重建完成时递增(服务据此重建监听) */ /* - * 消息队列(线程安全核心) + * 消息队列(线程安全核心,句柄由本模块私有持有) * 外部任务经 net_send/net_recv/net_close 等公开 API 投递请求 * netTask 调 net_process_messages() 串行处理所有 CH395F 操作 - * 由 CubeMX 在 MX_FREERTOS_Init()(osKernelInitialize 之后)中创建 + * 队列对象由 CubeMX 在 MX_FREERTOS_Init()(osKernelInitialize 之后)创建,创建后 + * 立刻经 net_msg_queue_adopt() 绑定到这里;绑定之前恒为 NULL,各处投递前的判空 + * 因此是真实防线而不是形式(绑定失败的后果是"请求被丢弃",不是崩溃)。 */ -extern osMessageQueueId_t netMsgQueueHandle; /* CubeMX 生成的消息队列句柄 */ +static osMessageQueueId_t s_net_msg_queue; + +/* + * 函数功能:绑定消息队列句柄(本模块是该句柄的唯一使用者) + * 入口参数:queue_id - 已创建的消息队列句柄 + * 返回值:0 = 绑定成功;-1 = 句柄为空或重复绑定(保留首次绑定,不覆盖) + * 限定条件:osKernelInitialize() 之后、netTask 启动之前,由 MX_FREERTOS_Init() 调用一次 + * 函数说明:见 net_socket.h 同名声明处的完整说明。重复绑定**不覆盖**是刻意的—— + * 真出现两处绑定时,说明有人新加了调用点,此时保留先绑的那个并把后来者 + * 拒掉,比静默换句柄(已入队的请求会留在旧队列里永不处理)更容易暴露。 + */ +int net_msg_queue_adopt(osMessageQueueId_t queue_id) { + if (queue_id == NULL) { + return -1; + } + if (s_net_msg_queue != NULL) { + return -1; + } + s_net_msg_queue = queue_id; + return 0; +} /* ================= 错误码存储(E-03 修复:按任务隔离,消除跨任务覆写竞态) ================= * @@ -582,7 +604,7 @@ void net_process_messages(void) { net_msg_t msg; /* 队列句柄未就绪(net_init 未完成):直接返回 */ - if (netMsgQueueHandle == NULL) { + if (s_net_msg_queue == NULL) { return; } @@ -599,7 +621,7 @@ void net_process_messages(void) { net_reconcile_tick(); /* 队列排空:超时 0 非阻塞取,每条处理一轮,直到本轮队列为空 */ - while (osMessageQueueGet(netMsgQueueHandle, &msg, NULL, 0) == osOK) { + while (osMessageQueueGet(s_net_msg_queue, &msg, NULL, 0) == osOK) { /* 默认处理完即发即时回执;RECV 挂起登记时置 0(回执推迟到 * net_pending_tick 完成检查,避免"登记成功"被误报为处理结果) */ int do_notify = 1; @@ -1120,7 +1142,7 @@ int net_listen(int sockfd) { } /* 消息队列未创建(网络层未初始化)→ 通用错误 */ - if (netMsgQueueHandle == NULL) { + if (s_net_msg_queue == NULL) { return NET_ERR_RETURN_1(NET_ERR); } @@ -1136,7 +1158,7 @@ int net_listen(int sockfd) { msg.result = -1; /* 入队:队列满时阻塞调用方直至有空位 */ - if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) { + if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) { /* 入队失败 → BUSY */ return NET_ERR_RETURN_1(NET_ERR_BUSY); } @@ -1284,7 +1306,7 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) { } /* 消息队列未创建(网络层未初始化)→ 通用错误 */ - if (netMsgQueueHandle == NULL) { + if (s_net_msg_queue == NULL) { return NET_ERR_RETURN_1(NET_ERR); } @@ -1304,7 +1326,7 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) { msg.result = -1; /* 入队:队列满时阻塞调用方直至有空位 */ - if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) { + if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) { /* 入队失败 → BUSY */ return NET_ERR_RETURN_1(NET_ERR_BUSY); } @@ -1445,7 +1467,7 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen) { } /* 消息队列未创建(网络层未初始化)→ 通用错误 */ - if (netMsgQueueHandle == NULL) { + if (s_net_msg_queue == NULL) { return NET_ERR_RETURN_1(NET_ERR); } @@ -1474,7 +1496,7 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen) { msg.result = -1; /* 入队:队列满时阻塞调用方直至有空位 */ - if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) { + if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) { /* 入队失败 → BUSY */ return NET_ERR_RETURN_1(NET_ERR_BUSY); } @@ -2011,9 +2033,9 @@ static int net_drop_conn_locked(net_sock_t *p_sock) { * 限定条件:1. 必须在【非 netTask】上下文中调用(应用/测试任务);若在 netTask 内调用会自己等自己 → 死锁 * (netTask 阻塞在 xTaskNotifyWait 而无人处理消息);netTask 内请直接用 net_send_locked() * 2. Socket 须处于 ESTABLISHED 状态 - * 3. net_init() + MX_FREERTOS_Init() 已执行,netMsgQueueHandle 已由 net_init 创建 + * 3. net_init() + MX_FREERTOS_Init() 已执行,消息队列已创建并绑定到本模块 * 函数说明:1. 所有 CH395F SPI 访问只允许在 netTask 内串行执行(见 TRAP-NET-14) - * 2. 本函数不直接触碰 SPI,而是把发送请求打包成 net_msg_t 投递到 netMsgQueueHandle + * 2. 本函数不直接触碰 SPI,而是把发送请求打包成 net_msg_t 投递到本模块的消息队列 * 3. netTask 的 net_process_messages() 取出并在 netTask 上下文调用 net_send_locked() 真正写 CH395F * 4. 调用方经 FreeRTOS TaskNotify 阻塞等待处理结果,对外呈现"同步发送"语义 * 5. 函数返回 = 本次发送已被 netTask 处理完毕(成功或失败) @@ -2031,7 +2053,7 @@ int net_send(int sockfd, const void *buf, int len, int flags) { } /* ---- 2. 运行环境检查:消息队列须已创建(网络层已初始化) ---- */ - if (netMsgQueueHandle == NULL) { + if (s_net_msg_queue == NULL) { /* 网络层未初始化 */ return NET_ERR_RETURN_1(NET_ERR); } @@ -2055,7 +2077,7 @@ int net_send(int sockfd, const void *buf, int len, int flags) { msg.result = -1; /* ---- 4. 入队:将消息投递给 netTask,osWaitForever 表示队列满时阻塞调用方 ---- */ - if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) { + if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) { /* 入队失败(队列异常等极端情况) */ return NET_ERR_RETURN_1(NET_ERR_BUSY); } @@ -2107,7 +2129,7 @@ int net_recv(int sockfd, void *buf, int len, int flags) { } /* 消息队列未创建(网络层未初始化)→ 通用错误 */ - if (netMsgQueueHandle == NULL) { + if (s_net_msg_queue == NULL) { return NET_ERR_RETURN_1(NET_ERR); } @@ -2129,7 +2151,7 @@ int net_recv(int sockfd, void *buf, int len, int flags) { msg.result = -1; /* 入队:队列满时阻塞调用方直至有空位 */ - if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) { + if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) { /* 入队失败 → BUSY */ return NET_ERR_RETURN_1(NET_ERR_BUSY); } @@ -2193,7 +2215,7 @@ int net_recv_to(int sockfd, void *buf, int len, uint32_t timeout_ms) { } /* ---- 2. 运行环境检查:消息队列须已创建(网络层已初始化) ---- */ - if (netMsgQueueHandle == NULL) { + if (s_net_msg_queue == NULL) { /* 网络层未初始化 */ return NET_ERR_RETURN_1(NET_ERR); } @@ -2225,7 +2247,7 @@ int net_recv_to(int sockfd, void *buf, int len, uint32_t timeout_ms) { msg.result = -1; /* ---- 5. 入队:将消息投递给 netTask,osWaitForever 表示队列满时阻塞调用方 ---- */ - if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) { + if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) { /* 入队失败(队列异常等极端情况) */ return NET_ERR_RETURN_1(NET_ERR_BUSY); } @@ -2278,7 +2300,7 @@ int net_close(int sockfd) { } /* 消息队列未创建(网络层未初始化)→ 通用错误 */ - if (netMsgQueueHandle == NULL) { + if (s_net_msg_queue == NULL) { return NET_ERR_RETURN_1(NET_ERR); } @@ -2294,7 +2316,7 @@ int net_close(int sockfd) { msg.result = -1; /* 入队:队列满时阻塞调用方直至有空位 */ - if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) { + if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) { /* 入队失败 → BUSY */ return NET_ERR_RETURN_1(NET_ERR_BUSY); } @@ -2336,7 +2358,7 @@ int net_drop_conn(int sockfd) { } /* 消息队列未创建(网络层未初始化)→ 通用错误 */ - if (netMsgQueueHandle == NULL) { + if (s_net_msg_queue == NULL) { return NET_ERR_RETURN_1(NET_ERR); } @@ -2352,7 +2374,7 @@ int net_drop_conn(int sockfd) { msg.result = -1; /* 入队:队列满时阻塞调用方直至有空位 */ - if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) { + if (osMessageQueuePut(s_net_msg_queue, &msg, 0, osWaitForever) != osOK) { /* 入队失败 → BUSY */ return NET_ERR_RETURN_1(NET_ERR_BUSY); } diff --git a/Drivers/BSP/NET/net_socket.h b/Drivers/BSP/NET/net_socket.h index 37d38960..37a2c086 100644 --- a/Drivers/BSP/NET/net_socket.h +++ b/Drivers/BSP/NET/net_socket.h @@ -24,6 +24,7 @@ extern "C" { #ifndef NET_NO_OS #include "FreeRTOS.h" #include "task.h" +#include "cmsis_os2.h" /* osMessageQueueId_t:net_msg_queue_adopt() 的参数类型 */ #endif /* NET_NO_OS */ #ifndef NET_NO_OS @@ -60,6 +61,23 @@ typedef struct { } net_msg_t; #endif /* NET_NO_OS */ +#ifndef NET_NO_OS +/* + * 函数功能:把消息队列句柄交给本模块持有(**句柄的唯一使用者是 net_socket.c**) + * 入口参数:queue_id - 已创建的消息队列句柄 + * 返回值:0 = 绑定成功;-1 = 句柄为空、或已绑定过(重复绑定保留首次句柄,不覆盖) + * 限定条件:必须在 osKernelInitialize() 之后、netTask 启动之前调用一次 + * 函数说明:队列对象本身仍由 CubeMX 在 MX_FREERTOS_Init() 里创建——创建点不能外移, + * 因为 osKernelInitialize() 之前任何创建类 API 都会杀死启动 + * (docs/架构设计/项目启动顺序管理.md)。外移创建点还会让重新生成把它抹掉。 + * 所以这里用"创建后立刻绑定":调用点见 Src/freertos.c 的 + * USER CODE BEGIN RTOS_QUEUES 区。此前本模块靠对本文件外全局变量的 + * 裸 extern 取用,谁改名或删掉创建语句都不会有提示。 + */ +int net_msg_queue_adopt(osMessageQueueId_t queue_id); +#endif /* NET_NO_OS */ + + /* * 网络初始化接口 */ diff --git a/Src/freertos.c b/Src/freertos.c index 79db3e66..8a6d89c8 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -329,6 +329,11 @@ void MX_FREERTOS_Init(void) { /* USER CODE BEGIN RTOS_QUEUES */ /* add queues, ... */ + /* 队列对象由上面生成的语句创建(创建点不可外移:osKernelInitialize() 之前的 + 创建类 API 会杀死启动)。这里立刻把句柄交给唯一使用者 net_socket,之后本模块 + 不再对外暴露这个全局变量;少了这一行,net_socket 的句柄恒为 NULL,所有 net_* + 请求会被判空丢弃(表现为网络全线静默不通)。 */ + (void)net_msg_queue_adopt(netMsgQueueHandle); /* USER CODE END RTOS_QUEUES */ /* Create the thread(s) */ diff --git a/docs/images/任务栈预算.svg b/docs/images/任务栈预算.svg index e30d1cf6..03d53e9e 100644 --- a/docs/images/任务栈预算.svg +++ b/docs/images/任务栈预算.svg @@ -21,7 +21,7 @@ ftpTask - 配置 4096B | 实测峰值 764B | 最坏 1456B | 余量 2640B (64%) PASS + 配置 4096B | 实测峰值 1404B | 最坏 1456B | 余量 2640B (64%) PASS uiTask @@ -33,7 +33,7 @@ timeSyncTask - 配置 2560B | 实测峰值 616B | 最坏 1264B | 余量 1296B (50%) PASS + 配置 2560B | 实测峰值 648B | 最坏 1264B | 余量 1296B (50%) PASS adcTask @@ -45,7 +45,7 @@ protectTask - 配置 2048B | 实测峰值 624B | 最坏 872B | 余量 1176B (57%) PASS + 配置 2048B | 实测峰值 828B | 最坏 872B | 余量 1176B (57%) PASS idle 512B(未实测) diff --git a/docs/images/内存布局_FLASH.svg b/docs/images/内存布局_FLASH.svg index f483f73b..cbf7e988 100644 --- a/docs/images/内存布局_FLASH.svg +++ b/docs/images/内存布局_FLASH.svg @@ -10,26 +10,26 @@ Flash (1MB) 使用布局 — 2026-10-22 @build 代码段 (Code) 208.2KB - + 只读数据 (RO) 18.1KB - + Flash 空闲 796.5KB 已用: 227.5KB (22.2%) 空闲: 796.5KB (77.8%) ER_IROM1(Code+RO): 226.4KB (22.1%) 总量: 1MB (= ROM 合计口径) Code + RO 分布(ER_IROM1 226.4KB,按 .map 对象归类) 85.7KB - + 55.7KB - - 25.0KB - + + 25.0KB + 17.5KB - - - - - - + + + + + + LVGL 库 85.7KB diff --git a/docs/内存管理/RAM使用分析与优化方案.md b/docs/内存管理/RAM使用分析与优化方案.md index 306952af..337f22fc 100644 --- a/docs/内存管理/RAM使用分析与优化方案.md +++ b/docs/内存管理/RAM使用分析与优化方案.md @@ -38,10 +38,10 @@ | 区域 | 用量 | 容量 | 占比 | |---|---|---|---| -| ER_IROM1 | 231,784 B (226.35 KB) | 1,048,576 B (1024 KB) | 22.1% | +| ER_IROM1 | 231,816 B (226.38 KB) | 1,048,576 B (1024 KB) | 22.1% | | RW_IRAM1 | 75,264 B (73.50 KB) | 131,072 B (128 KB) | 57.4% | | RW_CCM | 57,376 B (56.03 KB) | 65,280 B (64 KB) | 87.9% | -| **Flash (ROM 合计)** | **232,968 B (227.5 KB)** | 1,048,576 B (1024 KB) | **22.2%** | +| **Flash (ROM 合计)** | **233,004 B (227.5 KB)** | 1,048,576 B (1024 KB) | **22.2%** | 各区的容量与常量来源: diff --git a/docs/内存管理/RAM预算台账.md b/docs/内存管理/RAM预算台账.md index 47f9210a..ef2c17ce 100644 --- a/docs/内存管理/RAM预算台账.md +++ b/docs/内存管理/RAM预算台账.md @@ -15,14 +15,14 @@ | 区域 | 用量 | 容量 | 占比 | 门禁(≤92%) | |---|---|---|---|---| -| ER_IROM1 (Flash) | 231,784 B | 1,048,576 B | 22.1% | 参考 | +| ER_IROM1 (Flash) | 231,816 B | 1,048,576 B | 22.1% | 参考 | | RW_CCM | 57,376 B | 65,280 B | 87.9% | PASS | | UNINIT_CCM | 48 B | 256 B | 18.8% | 参考 | | RW_IRAM1 | 75,264 B | 131,072 B | 57.4% | PASS | | 子系统(静态 RW+ZI;除 RTOS 堆在 CCM 外均在 SRAM1) | 现值 | 配额 | 状态 | |---|---|---|---| -| 网络 | 13,690 B | 12 KB | ⚠ 超 1.4 KB | +| 网络 | 13,694 B | 12 KB | ⚠ 超 1.4 KB | | 存储 | 7,056 B | 12 KB | OK | | UI | 30,422 B | 16 KB | ⚠ 超 13.7 KB | | RTOS 堆 | 57,376 B | 56 KB | 堆=配额 | diff --git a/docs/内存管理/data/ram_report_20261022.md b/docs/内存管理/data/ram_report_20261022.md index bb26458e..5fd008e2 100644 --- a/docs/内存管理/data/ram_report_20261022.md +++ b/docs/内存管理/data/ram_report_20261022.md @@ -1,24 +1,24 @@ # STM32F4-Base RAM/Flash Usage Report -> Generated: 2026-10-22 19:14 Map: `STM32F407-Demo.map` +> Generated: 2026-10-22 19:56 Map: `STM32F407-Demo.map` ## 1. Grand Totals (全局总量) | Metric | Value | |---|---| -| Code (inc. data) | 213,204 B (208.2 KB) | +| Code (inc. data) | 213,236 B (208.2 KB) | | RO Data | 18,580 B (18.1 KB) | -| RW Data (initialized) | 1,184 B (1.16 KB) | -| ZI Data (zero-init) | 131,504 B (128.4 KB) | -| **Total RO (Code + RO)** | **231,784 B (226.4 KB)** | +| RW Data (initialized) | 1,188 B (1.16 KB) | +| ZI Data (zero-init) | 131,500 B (128.4 KB) | +| **Total RO (Code + RO)** | **231,816 B (226.4 KB)** | | **Total RW (RW + ZI) = SRAM used** | **132,688 B (129.58 KB)** | -| **Total ROM (Code + RO + RW init)** | **232,968 B (227.5 KB)** | +| **Total ROM (Code + RO + RW init)** | **233,004 B (227.5 KB)** | ## 2. 执行区水位 (Execution Regions) | Region | Base | Size | Max | Util% | |---|---|---|---|---| -| ER_IROM1 | 0x08000000 | 231,784 B (226.35 KB) | 1,048,576 B (1024 KB) | 22.1% | +| ER_IROM1 | 0x08000000 | 231,816 B (226.38 KB) | 1,048,576 B (1024 KB) | 22.1% | | RW_CCM | 0x10000000 | 57,376 B (56.03 KB) | 65,280 B (64 KB) | 87.9% | | UNINIT_CCM | 0x1000FF00 | 48 B (0.05 KB) | 256 B (0 KB) | 18.8% | | RW_IRAM1 | 0x20000000 | 75,264 B (73.50 KB) | 131,072 B (128 KB) | 57.4% | @@ -33,54 +33,54 @@ | 4 | 0x2000EDC8 | 6,408 | 6.26 | Zero | .bss | ui_port.o | | 5 | 0x2000667C | 6,200 | 6.05 | Zero | .bss | nand_ftl.o | | 6 | 0x20004E18 | 4,152 | 4.05 | Zero | .bss | ch395f.o | -| 7 | 0x20002054 | 4,096 | 4.00 | Zero | .bss | console_log.o | -| 8 | 0x20001274 | 3,552 | 3.47 | Zero | .bss | sys_log_mcu.o | -| 9 | 0x20003640 | 2,724 | 2.66 | Zero | .bss | default_task.o | +| 7 | 0x20002058 | 4,096 | 4.00 | Zero | .bss | console_log.o | +| 8 | 0x20001278 | 3,552 | 3.47 | Zero | .bss | sys_log_mcu.o | +| 9 | 0x20003644 | 2,724 | 2.66 | Zero | .bss | default_task.o | | 10 | 0x2000A524 | 1,720 | 1.68 | Zero | .bss | cmsis_os2.o | | 11 | 0x2000444C | 1,440 | 1.41 | Zero | .bss | sample_ring.o | | 12 | 0x20009F48 | 1,220 | 1.19 | Zero | .bss | tasks.o | -| 13 | 0x20000D74 | 1,104 | 1.08 | Zero | .bss | cfg_file_store_mcu.o | -| 14 | 0x20003054 | 1,064 | 1.04 | Zero | .bss | soe_store.o | +| 13 | 0x20000D78 | 1,104 | 1.08 | Zero | .bss | cfg_file_store_mcu.o | +| 14 | 0x20003058 | 1,064 | 1.04 | Zero | .bss | soe_store.o | | 15 | 0x20012200 | 1,024 | 1.00 | Zero | | startup_stm32f407xx.o | | 16 | 0x20005E50 | 800 | 0.78 | Zero | .bss | gd5f2gq5ue.o | | 17 | 0x200040E8 | 712 | 0.70 | Zero | .bss | iec104_serv.o | -| 18 | 0x20000AB4 | 704 | 0.69 | Zero | .bss | cfg_file.o | -| 19 | 0x200005CC | 560 | 0.55 | Zero | .bss | spi.o | -| 20 | 0x20000844 | 552 | 0.54 | Zero | .bss | usart.o | +| 18 | 0x20000AB8 | 704 | 0.69 | Zero | .bss | cfg_file.o | +| 19 | 0x200005D0 | 560 | 0.55 | Zero | .bss | spi.o | +| 20 | 0x20000848 | 552 | 0.54 | Zero | .bss | usart.o | | 21 | 0x20009CE0 | 552 | 0.54 | Zero | .bss | lftpd_io.o | | 22 | 0x2000ABDC | 492 | 0.48 | Zero | .bss | lv_init.o | | 23 | 0x20004C38 | 480 | 0.47 | Zero | .bss | freq.o | | 24 | 0x2000629C | 416 | 0.41 | Zero | .bss | net_socket.o | | 25 | 0x200064DC | 416 | 0.41 | Zero | .bss | net_pending.o | -| 26 | 0x200034C0 | 384 | 0.38 | Zero | .bss | task_prof.o | +| 26 | 0x200034C4 | 384 | 0.38 | Zero | .bss | task_prof.o | | 27 | 0x20004A8C | 320 | 0.31 | Zero | .bss | prot_set.o | | 28 | 0x2000A40C | 280 | 0.27 | Zero | .bss | timers.o | | 29 | 0x20006190 | 268 | 0.26 | Zero | .bss | rs485.o | -| 30 | 0x200011C4 | 176 | 0.17 | Zero | .bss | prot_set_store.o | -| 31 | 0x200004C4 | 168 | 0.16 | Zero | .bss | adc.o | -| 32 | 0x200002B0 | 160 | 0.16 | Data | .data | lftpd.o | +| 30 | 0x200011C8 | 176 | 0.17 | Zero | .bss | prot_set_store.o | +| 31 | 0x200004C8 | 168 | 0.16 | Zero | .bss | adc.o | +| 32 | 0x200002B4 | 160 | 0.16 | Data | .data | lftpd.o | | 33 | 0x200049EC | 160 | 0.16 | Zero | .bss | phasor.o | | 34 | 0x200106D0 | 152 | 0.15 | Zero | .bss | ui_menu_view.o | | 35 | 0x2000643C | 128 | 0.12 | Zero | .bss | net_listener.o | | 36 | 0x20004BCC | 108 | 0.11 | Zero | .bss | prot_elm.o | -| 37 | 0x2000056C | 84 | 0.08 | Zero | .bss | i2c.o | +| 37 | 0x20000570 | 84 | 0.08 | Zero | .bss | i2c.o | | 38 | 0x200043F8 | 84 | 0.08 | Zero | .bss | adc_input.o | -| 39 | 0x2000024C | 83 | 0.08 | Data | .data | ftp_cfg.o | -| 40 | 0x200007FC | 72 | 0.07 | Zero | .bss | tim.o | -| 41 | 0x20000A6C | 72 | 0.07 | Zero | .bss | stm32f4xx_hal_timebase_tim.o | -| 42 | 0x2000347C | 68 | 0.07 | Zero | .bss | task_watchdog.o | -| 43 | 0x20000480 | 65 | 0.06 | Zero | .bss | freertos.o | +| 39 | 0x20000250 | 83 | 0.08 | Data | .data | ftp_cfg.o | +| 40 | 0x20000800 | 72 | 0.07 | Zero | .bss | tim.o | +| 41 | 0x20000A70 | 72 | 0.07 | Zero | .bss | stm32f4xx_hal_timebase_tim.o | +| 42 | 0x20003480 | 68 | 0.07 | Zero | .bss | task_watchdog.o | +| 43 | 0x20000484 | 65 | 0.06 | Zero | .bss | freertos.o | | 44 | 0x20009F08 | 64 | 0.06 | Zero | .bss | queue.o | -| 45 | 0x20000354 | 60 | 0.06 | Data | .data | tasks.o | -| 46 | 0x2000040C | 60 | 0.06 | Data | .data | ui_page_selftest.o | +| 45 | 0x20000358 | 60 | 0.06 | Data | .data | tasks.o | +| 46 | 0x20000410 | 60 | 0.06 | Data | .data | ui_page_selftest.o | | 47 | 0x20010768 | 60 | 0.06 | Zero | .bss | ui_page_runlog.o | | 48 | 0x20000150 | 48 | 0.05 | Data | .data | adc_health.o | | 49 | 0x200043C8 | 48 | 0.05 | Zero | .bss | iec104_pts.o | | 50 | 0x20000000 | 44 | 0.04 | Data | .data | freertos.o | | 51 | 0x2000009C | 44 | 0.04 | Data | .data | task_watchdog.o | | 52 | 0x20000044 | 36 | 0.04 | Data | .data | sys_log_mcu.o | -| 53 | 0x20000228 | 36 | 0.04 | Data | .data | net_cfg.o | -| 54 | 0x20000448 | 32 | 0.03 | Data | .data | ui_standby.o | +| 53 | 0x2000022C | 36 | 0.04 | Data | .data | net_cfg.o | +| 54 | 0x2000044C | 32 | 0.03 | Data | .data | ui_standby.o | | 55 | 0x20006170 | 32 | 0.03 | Zero | .bss | tpafe5160.o | | 56 | 0x200064BC | 32 | 0.03 | Zero | .bss | net_events.o | | 57 | 0x20000128 | 28 | 0.03 | Data | .data | adc_input.o | @@ -88,47 +88,47 @@ | 59 | 0x200000E4 | 24 | 0.02 | Data | .data | adc_task.o | | 60 | 0x20000180 | 24 | 0.02 | Data | .data | prot_set.o | | 61 | 0x2000019C | 24 | 0.02 | Data | .data | freq.o | -| 62 | 0x200001FC | 24 | 0.02 | Data | .data | net_listener.o | +| 62 | 0x20000200 | 24 | 0.02 | Data | .data | net_listener.o | | 63 | 0x200043B0 | 24 | 0.02 | Zero | .bss | protect_task.o | | 64 | 0x20000030 | 20 | 0.02 | Data | .data | cfg_file.o | | 65 | 0x20000080 | 20 | 0.02 | Data | .data | soe_store.o | | 66 | 0x200001D0 | 20 | 0.02 | Data | .data | gd5f2gq5ue.o | -| 67 | 0x20000390 | 20 | 0.02 | Data | .data | timers.o | -| 68 | 0x20000468 | 20 | 0.02 | Data | .data | ui_net_sink.o | -| 69 | 0x200003D0 | 18 | 0.02 | Data | .data | ui_menu.o | +| 67 | 0x20000394 | 20 | 0.02 | Data | .data | timers.o | +| 68 | 0x2000046C | 20 | 0.02 | Data | .data | ui_net_sink.o | +| 69 | 0x200003D4 | 18 | 0.02 | Data | .data | ui_menu.o | | 70 | 0x200000FC | 16 | 0.02 | Data | .data | iec104_serv.o | | 71 | 0x20000118 | 16 | 0.02 | Data | .data | iec104_pts.o | -| 72 | 0x20000214 | 16 | 0.02 | Data | .data | net_events.o | -| 73 | 0x200002A0 | 16 | 0.02 | Data | .data | nand_ftl.o | -| 74 | 0x200003EC | 16 | 0.02 | Data | .data | ui_content_page.o | -| 75 | 0x200000D4 | 12 | 0.01 | Data | .data | default_task.o | -| 76 | 0x200001B4 | 12 | 0.01 | Data | .data | stm32f4xx_hal.o | -| 77 | 0x200001E4 | 12 | 0.01 | Data | .data | tpafe5160.o | -| 78 | 0x200001F0 | 12 | 0.01 | Data | .data | net_socket.o | -| 79 | 0x200003A8 | 12 | 0.01 | Data | .data | port.o | -| 80 | 0x200003C4 | 12 | 0.01 | Data | .data | ui_port.o | -| 81 | 0x200003FC | 12 | 0.01 | Data | .data | ui_page_password.o | -| 82 | 0x200005C0 | 12 | 0.01 | Zero | .bss | iwdg.o | +| 72 | 0x200001F0 | 16 | 0.02 | Data | .data | net_socket.o | +| 73 | 0x20000218 | 16 | 0.02 | Data | .data | net_events.o | +| 74 | 0x200002A4 | 16 | 0.02 | Data | .data | nand_ftl.o | +| 75 | 0x200003F0 | 16 | 0.02 | Data | .data | ui_content_page.o | +| 76 | 0x200000D4 | 12 | 0.01 | Data | .data | default_task.o | +| 77 | 0x200001B4 | 12 | 0.01 | Data | .data | stm32f4xx_hal.o | +| 78 | 0x200001E4 | 12 | 0.01 | Data | .data | tpafe5160.o | +| 79 | 0x200003AC | 12 | 0.01 | Data | .data | port.o | +| 80 | 0x200003C8 | 12 | 0.01 | Data | .data | ui_port.o | +| 81 | 0x20000400 | 12 | 0.01 | Data | .data | ui_page_password.o | +| 82 | 0x200005C4 | 12 | 0.01 | Zero | .bss | iwdg.o | | 83 | 0x200001C4 | 10 | 0.01 | Data | .data | ch395f.o | | 84 | 0x20000094 | 8 | 0.01 | Data | .data | sys_clock.o | | 85 | 0x200000C8 | 8 | 0.01 | Data | .data | task_prof.o | | 86 | 0x2000010C | 8 | 0.01 | Data | .data | protect_task.o | | 87 | 0x20000144 | 8 | 0.01 | Data | .data | sample_ring.o | -| 88 | 0x200003B4 | 8 | 0.01 | Data | .data | ff.o | -| 89 | 0x200003BC | 8 | 0.01 | Data | .data | ffsystem.o | -| 90 | 0x200003E4 | 8 | 0.01 | Data | .data | ui_menu_view.o | +| 88 | 0x200003B8 | 8 | 0.01 | Data | .data | ff.o | +| 89 | 0x200003C0 | 8 | 0.01 | Data | .data | ffsystem.o | +| 90 | 0x200003E8 | 8 | 0.01 | Data | .data | ui_menu_view.o | | 91 | 0x2000002C | 4 | 0.00 | Data | .data | app_main.o | | 92 | 0x200000D0 | 4 | 0.00 | Data | .data | vol_lock.o | | 93 | 0x200000E0 | 4 | 0.00 | Data | .data | net_task.o | | 94 | 0x200001C0 | 4 | 0.00 | Data | .data | system_stm32f4xx.o | -| 95 | 0x20000224 | 4 | 0.00 | Data | .data | net_pending.o | -| 96 | 0x20000350 | 4 | 0.00 | Data | .data | lftpd_io.o | -| 97 | 0x200003A4 | 4 | 0.00 | Data | .data | cmsis_os2.o | -| 98 | 0x2000047C | 4 | 0.00 | Data | .data | mc_w.l(errno.o) | +| 95 | 0x20000228 | 4 | 0.00 | Data | .data | net_pending.o | +| 96 | 0x20000354 | 4 | 0.00 | Data | .data | lftpd_io.o | +| 97 | 0x200003A8 | 4 | 0.00 | Data | .data | cmsis_os2.o | +| 98 | 0x20000480 | 4 | 0.00 | Data | .data | mc_w.l(errno.o) | | 99 | 0x2000014C | 2 | 0.00 | Data | .data | phasor.o | -| 100 | 0x20000408 | 2 | 0.00 | Data | .data | ui_page_net_cfg.o | +| 100 | 0x2000040C | 2 | 0.00 | Data | .data | ui_page_net_cfg.o | | 101 | 0x20000198 | 1 | 0.00 | Data | .data | prot_elm.o | -| | | **75,239** | **73.48** | | | **Total** | +| | | **75,243** | **73.48** | | | **Total** | ## 4. Image Component Sizes(RW + ZI > 0,按大小降序) @@ -158,7 +158,7 @@ | 22 | usart.o | 884 | 0 | 0 | 552 | 552 | | 23 | freq.o | 764 | 8 | 24 | 480 | 504 | | 24 | lv_init.o | 156 | 0 | 0 | 492 | 492 | -| 25 | net_socket.o | 4,916 | 443 | 12 | 416 | 428 | +| 25 | net_socket.o | 4,944 | 443 | 16 | 416 | 432 | | 26 | net_pending.o | 1,400 | 0 | 4 | 416 | 420 | | 27 | task_prof.o | 638 | 185 | 8 | 384 | 392 | | 28 | prot_set.o | 844 | 640 | 24 | 320 | 344 | @@ -171,7 +171,7 @@ | 35 | ui_menu_view.o | 2,034 | 16 | 8 | 152 | 160 | | 36 | net_listener.o | 948 | 207 | 24 | 128 | 152 | | 37 | adc_input.o | 592 | 27 | 28 | 84 | 112 | -| 38 | freertos.o | 712 | 592 | 44 | 65 | 109 | +| 38 | freertos.o | 716 | 592 | 44 | 65 | 109 | | 39 | prot_elm.o | 708 | 227 | 1 | 108 | 109 | | 40 | i2c.o | 168 | 0 | 0 | 84 | 84 | | 41 | ftp_cfg.o | 152 | 225 | 83 | 0 | 83 | @@ -187,8 +187,8 @@ | 51 | net_cfg.o | 832 | 103 | 36 | 0 | 36 | | 52 | protect_task.o | 840 | 68 | 8 | 24 | 32 | | 53 | ui_standby.o | 1,208 | 67 | 32 | 0 | 32 | -| 54 | (incl. Padding) | 284 | 96 | 16 | 9 | 25 | -| 55 | adc_task.o | 1,520 | 234 | 24 | 0 | 24 | +| 54 | adc_task.o | 1,520 | 234 | 24 | 0 | 24 | +| 55 | (incl. Padding) | 284 | 96 | 16 | 5 | 21 | | 56 | ui_menu.o | 760 | 137 | 18 | 0 | 18 | | 57 | ui_content_page.o | 1,664 | 81 | 16 | 0 | 16 | | 58 | iwdg.o | 28 | 0 | 0 | 12 | 12 | @@ -204,7 +204,7 @@ | 68 | vol_lock.o | 92 | 0 | 4 | 0 | 4 | | 69 | errno.o | 20 | 0 | 4 | 0 | 4 | | 70 | ui_page_net_cfg.o | 1,004 | 105 | 2 | 0 | 2 | -| | **All .o files** | **213,204** | **18,580** | **1,184** | **131,504** | **132,688** | +| | **All .o files** | **213,236** | **18,580** | **1,188** | **131,500** | **132,688** | ## 5. Flash (Code + RO Data) Top-30(按大小降序) @@ -213,7 +213,7 @@ | 1 | ff.o | 7,962 | 282 | 8,244 | | 2 | cfg_file.o | 5,970 | 810 | 6,780 | | 3 | lftpd.o | 6,108 | 509 | 6,617 | -| 4 | net_socket.o | 4,916 | 443 | 5,359 | +| 4 | net_socket.o | 4,944 | 443 | 5,387 | | 5 | lv_indev.o | 4,928 | 0 | 4,928 | | 6 | ch395f.o | 3,978 | 603 | 4,581 | | 7 | ui_font_cn_12.o | 0 | 4,545 | 4,545 | @@ -240,6 +240,6 @@ | 28 | printfa.o | 2,312 | 0 | 2,312 | | 29 | stm32f4xx_hal_i2c.o | 2,294 | 0 | 2,294 | | 30 | lv_display.o | 2,284 | 0 | 2,284 | -| | **All .o files** | **213,204** | **18,580** | **231,784** | +| | **All .o files** | **213,236** | **18,580** | **231,816** | -> 自洽校验:per-file 213,204/18,580/1,184/131,504 vs Grand Totals 213,204/18,580/1,184/131,504(CodeΔ=+0 / ROΔ=+0 / RWΔ=+0 / ZIΔ=+0;精确一致(含 '('incl. Generated)'-'(incl. Padding)' 台账行))→ **PASS** +> 自洽校验:per-file 213,236/18,580/1,188/131,500 vs Grand Totals 213,236/18,580/1,188/131,500(CodeΔ=+0 / ROΔ=+0 / RWΔ=+0 / ZIΔ=+0;精确一致(含 '('incl. Generated)'-'(incl. Padding)' 台账行))→ **PASS** diff --git a/docs/内存管理/data/stack_report_20261022.md b/docs/内存管理/data/stack_report_20261022.md index f688fb42..c2012bfa 100644 --- a/docs/内存管理/data/stack_report_20261022.md +++ b/docs/内存管理/data/stack_report_20261022.md @@ -1,7 +1,7 @@ # Stack budget report - Source: `MDK-ARM\STM32F407-Demo\STM32F407-Demo.htm` (Keil static call graph) -- Linker run: Thu Oct 22 19:12:02 2026 +- Linker run: Thu Oct 22 19:53:08 2026 - Global maximum stack usage: **3024 B** (any call tree) - Runtime watermark: 8 task(s) from 串口采集日志 `.dsh\skills\serial-assistant\scripts\state\serial.log` @@ -11,13 +11,13 @@ Rule: `margin = cfg - max(static_max_depth, runtime_peak)` must be >= max(1024 B |---|---|---|---|---|---|---|---|---| | defaultTask | `StartDefaultTask` | 5120 | 3024 | 2152 | 3024 | 2096 | 40% | PASS | | netTask | `StartNetTask` | 3840 | 1912 | 1116 | 1912 | 1928 | 50% | PASS | -| ftpTask | `StartFtpTask` | 4096 | 1456 | 764 | 1456 | 2640 | 64% | PASS | +| ftpTask | `StartFtpTask` | 4096 | 1456 | 1404 | 1456 | 2640 | 64% | PASS | | uiTask | `StartUiTask` | 16384 | 1336 | 4052 | 4052 | 12332 | 75% | PASS | | testTask | `start_test_task` | 8192 | 736 | - | 736 | 7456 | 91% | PASS | -| timeSyncTask | `time_sync_task` | 2560 | 1264 | 616 | 1264 | 1296 | 50% | PASS | +| timeSyncTask | `time_sync_task` | 2560 | 1264 | 648 | 1264 | 1296 | 50% | PASS | | adcTask | `adc_task_func` | 2560 | 1320 | 952 | 1320 | 1240 | 48% | PASS | | iec104Task | `iec104_serv_task` | 2560 | 1456 | 540 | 1456 | 1104 | 43% | PASS | -| protectTask | `protect_task` | 2048 | 872 | 624 | 872 | 1176 | 57% | PASS | +| protectTask | `protect_task` | 2048 | 872 | 828 | 872 | 1176 | 57% | PASS | `Static max` = armlink worst-case call-tree depth; `Runtime peak` = measured high-water mark (boot + whatever workload ran before the sample); `Worst` = max of the two, which is what the verdict is computed from. diff --git a/docs/环境与部署/项目部署环境要求.md b/docs/环境与部署/项目部署环境要求.md index 8f3a3cb9..602b2802 100644 --- a/docs/环境与部署/项目部署环境要求.md +++ b/docs/环境与部署/项目部署环境要求.md @@ -504,7 +504,7 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级 | 资源 | 已用 | 总量 | 利用率 | 余量 | 红线说明 | |---|---|---|---|---|---| -| Flash(`ER_IROM1` = Code + RO) | 231,784 B(226.4 KB) | 1 MB | 22.1% | ≈804 KB | **充裕**:产品需求无 OTA / 双镜像预算,Flash 不是卡点;死代码裁剪簇已收口 → `docs/问题记录/项目审查与优化建议报告.md` §5.4 | +| Flash(`ER_IROM1` = Code + RO) | 231,816 B(226.4 KB) | 1 MB | 22.1% | ≈804 KB | **充裕**:产品需求无 OTA / 双镜像预算,Flash 不是卡点;死代码裁剪簇已收口 → `docs/问题记录/项目审查与优化建议报告.md` §5.4 | | 主 SRAM1(静态区;FreeRTOS 堆已迁 CCM) | 75,264 B(73.5 KB) | 128 KB | 57.4% | 55,808 B | 已不紧张——2026-10-11 堆迁 CCM 与 2026-10-15 `LV_MEM_SIZE` 40→16 KB 两步的结果 | | CCM(`RW_CCM` 段) | 57,376 B(56.0 KB) | 65,280 B | **87.9%** | **7,904 B** | **当前真正的红线**:加任务 / 抬栈 / 加堆会先在这里撞墙;`mem-budget` 钩子在 92% 拦提交 | diff --git a/docs/问题记录/项目审查与优化建议报告.md b/docs/问题记录/项目审查与优化建议报告.md index 74456485..1e6bf7eb 100644 --- a/docs/问题记录/项目审查与优化建议报告.md +++ b/docs/问题记录/项目审查与优化建议报告.md @@ -49,7 +49,12 @@ | 内存 RAM | N-14 🟡(N-22) | FTL 单页写回缓存无空闲/掉电强制 flush(整页写与换页已 flush,`f_close` 经 `CTRL_SYNC` 已落盘) | 用户裁定 2026-10-22 暂不做;残余窗口只是"单条记录" | | Flash | **F-5 🟡 观察项**(N-28) | uvprojx 201 个 LVGL `.c` 里 **127 个空 TU**;增量构建 4~5 s、CI 不跑 `@build` | 有实测全量耗时痛点再做,用 `` | | 结构 | **S-1 已止住恶化**(2026-10-22 上门禁) | 不是"命名错位",是真实的 **BSP→App 反向 include**,精确口径 **8 个文件 9 处**(上一版写"7 文件 15 处"也不准,已按 `check_layer_deps.py` 判定重算):`cfg_file.h`×2(NETCFG)、`vol_lock.h`×1(lftpd_io)、`sys_log.h`×3(UI 两处 + `ui_w_records.h`);`console_log.h` / `sys_clock.h` / `sha256.h` 三个横切叶子头已**显式豁免**。**运行时的属主纪律本来就没破**(UI 只投递 `net_cfg_save_request()`,写盘在 defaultTask),要修的只是静态方向 | **门禁已落地**(`layer-deps` + `scripts/check_layer_deps.py`:存量 6 条基线只减不增、新增当场 FAIL,落地时做过故意违规自证)。剩下的才是反转:把 `cfg_file_*` 直接调用换成注入的 ops(NETCFG 已有 `net_cfg_set_save_req_cb` 先例);**目录搬迁仍暂缓**(远程 CI 不跑 `@build`,兜底未成立) | -| 结构 | **S-2 只剩 1 处**(24 处手写已消 23) | 今天已消 23 处:2 处与 `Inc/spi.h`/`Inc/i2c.h` 重复(GD5F/SD2506)+ 19 处任务句柄与属性(新建 `App/task/task_handles.h`)+ 1 处 `main.c` 函数内 `g_rcc_csr_latched`(改由 `App/app/app_main.h` 声明)+ 1 处 `ch395f.c:177`(**改为契约转调**:GD5F 的完成标志收为文件内 `static`,导出 `gd5f_spi1_notify_done()` / `gd5f_spi1_notify_error()`,CH395F 那个"HAL 全局唯一回调"的 SPI1 分支只转调、不再直接写它的变量;`HAL_SPI_AbortCpltCallback` 仍无人实现 → 另列观察)。**只剩 `net_socket.c:77` 的 `netMsgQueueHandle`**。**两类不算债**:`stm32f4xx_it.c:241-256` 是 CubeMX「External variables」生成块(删了会被写回来);`:183/195/207/220` 是 `__asm` Handler 里的汇编标签引用(ARMCC `__asm` 取不到 C 数据符号,**合法例外**) | 剩下一步:`netMsgQueueHandle` 收进 net_socket 内部 + 提供投递 API | +| ~~结构 S-2~~ ✅ **已闭环销项 2026-10-22** | 该修的 24 处手写跨模块裸 `extern` **全部消完**:2 处与 `Inc/spi.h`/`Inc/i2c.h` 重复 → 改 include;19 处任务句柄与属性 → `App/task/task_handles.h`;1 处 `main.c` 函数内 `g_rcc_csr_latched` → `App/app/app_main.h`; +`ch395f.c:177` 的 `g_spi1_dma_done` → 标志收回 GD5F 内部 `static`,改由 `gd5f_spi1_notify_done()` / `notify_error()` 契约转调;最后一处 `net_socket.c:77` 的 +`netMsgQueueHandle` → 句柄改为 net_socket 私有 `static s_net_msg_queue`,由 `Src/freertos.c` 的 `USER CODE BEGIN RTOS_QUEUES` 区在队列创建后立刻 +`net_msg_queue_adopt()` 绑定(创建点不能外移——`osKernelInitialize()` 之前的创建类 API 会杀死启动;**故意不新建第二个队列**:那会白占 CCM 里 8×`net_msg_t` +的堆空间,而 CCM 正是当前红线)。**两类从来不算债**:`stm32f4xx_it.c:241-256` 是 CubeMX「External variables」生成块;`:183/195/207/220` 是 `__asm` Handler +里的汇编标签引用(ARMCC `__asm` 取不到 C 数据符号)。 | 无(后续由 `layer-deps` 与 `cubemx-survival` 两条门禁守着不回退:新增 `net-msgq-adopt` 存活项) | | 驱动规范 | S-5 ❌ | `bsp_err_t` 至今只出现在本报告里(无统一错误码/超时/重试约定) | 定义后进 `docs/代码规范/` | | 网络 | N-09 / PHY ❌(N-25) | `NET_MAX_SOCKETS` 仍为 8(与单连接复用语义不符);PHY 强制 100M 无自协商回退;PASV 每次新建监听 | 见 §4.2;随 N-25 一并处置 | | 存储 | N-15 🟡(N-25) | `nand_ftl.o` 静态 6,216 B——三块 2 KB 级页缓冲并存未合并 | 与 R-3 同批评估 | @@ -88,7 +93,7 @@ git ls-files -z | xargs -0 stat -c '%s' | 名词 | 口径 | |---|---| -| Flash 占用 | `Code + RO-data` = `ER_IROM1` = **231,784 B(22.1%)**;`ROM 合计` 再加 `RW` 初始化表 = 232,968 B(22.2%) | +| Flash 占用 | `Code + RO-data` = `ER_IROM1` = **231,816 B(22.1%)**;`ROM 合计` 再加 `RW` 初始化表 = 233,004 B(22.2%) | | SRAM 占用 | `RW_IRAM1`(DMA 可达区)与 `RW_CCM`(仅 CPU)分开计,二者不可互换(规则 R2/R3) | | 最坏栈 | `max(armlink 静态调用图深度, 真机 [STACK] 高水位)`;判定线 `余量 ≥ max(1024 B ISR, 配置×30%)` | | 编译单元 | uvprojx 的 `` 计数(今日 **326 个 `.c`**,其中 LVGL 201);"自研 `.c`" 另按目录口径 114 个 | @@ -225,8 +230,8 @@ defaultTask 单属主;原子写经卷锁;旧档迁移已删除。**仍列为 | 指标 | 2026-10-22 | 2026-10-15 | 说明 | |---|---|---|---| -| `Code` | 213,204 B | 213,520 B | F-6 收口 −332 B;同日 SPI 回调归属纠正 +16 B | -| `ER_IROM1`(Code+RO) | **231,784 B / 22.1%** | 232,280 B / 22.2% | 余 ≈804 KB | +| `Code` | 213,236 B | 213,520 B | 当日累计:F-6 −332 B、SPI 回调归属 +16 B、消息队列收口 +32 B | +| `ER_IROM1`(Code+RO) | **231,816 B / 22.1%** | 232,280 B / 22.2% | 余 ≈804 KB | | `RW_IRAM1` | **75,264 B / 57.4%**(余 55,808) | 73,568 B / 56.1% | 增量来自 B5/B8 功能码 | | `RW_CCM` | **57,376 B / 87.9%**(余 7,904) | 57,376 B / 87.9% | **当前唯一红线** | | FreeRTOS 堆 | 56 KB(57,344 B)@CCM;实测 `free=15,800` / `min_ever=8,464` | 同 | 2026-10-22 真机 | @@ -266,7 +271,7 @@ defaultTask 单属主;原子写经卷锁;旧档迁移已删除。**仍列为 | **F-6** 双精度软浮点 | ≈1 KB | **归因错**:全库 0 处 `%f`;剩余 `dadd/dmul/ddiv/depilogue/dfixul` 1,018 B 锁在 MicroLIB `printfa.o` 的 `_printf_core → _fp_digits`,只要用 `snprintf` 就删不掉。但**根因侧确有可修点**:`App/algo/prot_set.h` 两个 Q10 宏写成 `double` | ✅ **已落地 2026-10-22**:改单精度 → `@build` −332 B、5 个 helper(300 B)消失;数值逐位等价(穷举 42 个字面量 + int32 全域 ÷1024 往返 4.49×10⁶ 例零差异);真机 `@test` PASS | **当前可回收 Flash = 0 B**(F-4/F-6 已定论,图片链同理不打补丁)。LVGL 仍占镜像 **37.8%** -(87,706 / 231,784 B)——这是"用 LVGL 画单色菜单"的结构性代价,F-1/F-2/F-3 已省掉 64,576 B。 +(87,706 / 231,816 B)——这是"用 LVGL 画单色菜单"的结构性代价,F-1/F-2/F-3 已省掉 64,576 B。 ### 5.5 内存治理长效机制(常开,不受暂缓影响) @@ -374,7 +379,8 @@ W6 簇按 U4 → U1 → U3 → U2 的顺序执行完毕(U2 停在"够用即止 | **D-1** | 外部资料与工程文档同仓同树 | ❌ 暂不处理 | 本文 §3.3、登记簿 N-29 | | D-2 ~ D-7 | 文档治理条目(链接/同源/编号/BOM 等) | ✅ 多数已制度化为钩子 | 本文 §3.2、`../文档规范.md` | | D-9 | 文档面残余观察 | 🟡 观察 | 本节即定义位 | -| **S-1 / S-2** | 分层反向依赖 / 跨模块裸 `extern` | 🟡 半办(2026-10-22:24 处手写裸 extern 已消 23 处,只剩 `net_socket.c:77`;反向 include 8 文件 9 处已上门禁、6 条基线待还) | 本文 §0.4、登记簿 C5 | +| **S-1** | 分层反向依赖(BSP include App 的头) | 🟡 已止住恶化(存量 6 条基线待还,新增被 `layer-deps` 拦) | 本文 §0.4、登记簿 C5 | +| **S-2** | 跨模块裸 `extern` | ✅ **已闭环 2026-10-22**(24 处手写全消;两类本就不算债见 §0.4) | 本文变更记录 2026-10-22 三行;契约见 `App/task/task_handles.h`、`gd5f_spi1_notify_*`、`net_msg_queue_adopt` | | **S-4** | `app_cfg.h` 未接线占位开关 | ✅ **已闭环 2026-10-22**(4 个零消费点宏删除) | `App/app/app_cfg.h` 修改记录 v1.2;口径同步见 `../环境与部署/项目部署环境要求.md` §3.2/§3.5、`../产品需求/产品需求设计文档.md`、`../任务规划/排期详述.md` C5 | | **S-3** | `.ioc` 侧 USART1 配置 | ❌ 在策 | 登记簿 S-3 | | **S-5** | 统一 `bsp_err_t` 错误码约定 | ❌ 未做 | 本文 §0.4、`docs/代码规范/`(待建) | @@ -409,6 +415,33 @@ W6 簇按 U4 → U1 → U3 → U2 的顺序执行完毕(U2 停在"够用即止 **改判的三条旧结论**:① §6 的 U1/U3/U4 原写「❌ 未建」,实际已落地(`ui_tokens.h` 69 行、`ui_page_registry.c` 描述符注册表、`ui-golden`+`font-charset` 两枚钩子);U2 只有 `ui_w_records` 一个组件;"27 页未落地"实为 7 页。② "新增一页 ≤30 行"目标**未达**(最省 40 行),如实记为未达项。③ §0.4 与登记簿已漂开 → 本版把待办清单降级为**快照 + 指向登记簿**,权威只留一处。 **刻意保留的三层**(删了会出事):§9 **编号族登记处**——本文是 `id_registry.json` 里 `N-RPT`/`D-RPT`/`S-RPT`/`R-RPT`(游标 R-9)/`F-RPT`/`U-RPT`(游标 U5) 六族的属主登记处,且外部存在「报告 N-14」「报告 F-4/F-5/F-6」「报告 D-1」「报告 R-2/R-3」式紧邻引用与 `check_dangling`,删定义位即触发编号门禁;§1.2/§1.3 方法与口径(数字可重跑);文末**变更记录 + 已销项去处表**原样冻结保留(52 行)。被外部点名的锚点(`§0.3`/`§3.1`/`§4.1`/`§4.2`/`§4.3`/`§5.3`×9/`§5.4`/`§5.5`×4/`§6.2`/`§6.3`/`§6.5`)逐个保留,**68 处入站引用零改动**。 **门禁**:`check_doc_links.py --all --sections-strict` → 146 文档 0 问题(章节引用 2,499、可判定 1,483);`check_ids.py --strict` 增量拦截通过、**存量债 650 → 641(−9)**、可判定比例 82.98% → **82.79%**(仍高于基线 82.6%,但缓冲从 0.38pp 缩到 0.19pp——删掉的那批引用 99% 是可判定的,属预期副作用);`mem-numbers` / `ram_baseline --gate` / `task-table` / `cubemx-survival` 全 0。字节卫生:BOM 无 / CR 0 / U+FFFD 0 / 无行尾空格 / LF 结尾。 | +| **2026-10-22** | **S-2 收尾:`netMsgQueueHandle` 收进 net_socket 内部——该族 24 处手写裸 extern 全部清零** | 最后一步。队列对象仍由 CubeMX 在 +`MX_FREERTOS_Init()` 创建(**创建点不可外移**:`osKernelInitialize()` 之前的任何创建类 API 会杀死启动, +docs/架构设计/项目启动顺序管理.md),改为创建后立刻在 `Src/freertos.c` 的 `USER CODE BEGIN RTOS_QUEUES` 区 +调用 `net_msg_queue_adopt(netMsgQueueHandle)` 把句柄交给本模块;net_socket 内改为 `static s_net_msg_queue` +(21 处引用改名),BSP 对该全局变量的裸 `extern` 消失,`netMsgQueueHandle` 现在只出现在生成文件自己的两处。 | +| | **两个刻意的设计决定**:① **不新建第二个队列**——那会白占 CCM 堆里 8 × `net_msg_t` 的空间,而 CCM 是当下 +87.9% 的红线;所以选"创建后绑定"而不是"自建队列 + 删 .ioc 里的队列"(后者还要 CubeMX 重生成,属 Ask-first)。 +② `adopt()` **拒绝重复绑定并保留首次句柄**——真出现两处绑定时,静默换句柄会让已入队的请求留在旧队列里永不处理, +拒掉第二个反而更容易暴露。绑定前的判空是真实防线:丢这一行的后果是"所有 net_* 请求被丢弃、网络全线静默不通", +不是崩溃。 | +| | **防回退**:`check_cubemx_survival.py` 新增存活项 `net-msgq-adopt`(region `RTOS_QUEUES`,must_contain +`net_msg_queue_adopt`),易失清单 **29 → 30 项全部到位**;基线已重建。 | +| | **体量**:`Code` 213,204 → **213,236 B(+32)**、`ER_IROM1` **231,816 B(22.1%)**;`RW +4 / ZI −4` → +`RW_IRAM1` 恒 **75,264 B(57.4%)**、`RW_CCM` 恒 **57,376 B(87.9%)**、`RW+ZI` 总量 132,688 B **不变**。 | +| | **验证**:`@build` 0 错 0 警告;`@test` PASS(624 ms 到 `net init: OK`、i104 已监听、无 `[ERR]`/Fault、 +`heap free=15800 min_ever=8464` 逐项不变——证明没有多占一个队列);**另做真机 FTP 控制通道往返**:220 → +`USER admin` 331 → `PASS admin` **230** → `PWD` 257 → `TYPE I` 200 → `QUIT` 221,每条命令都是一次过队列的 +net_recv/net_send → 绑定路径在真机走通;`.map` 里 `freertos.o(MX_FREERTOS_Init) refers to +net_socket.o(i.net_msg_queue_adopt)` 证明镜像确实含该行。 | +| | **顺带揪出一条测试工具漂移(未修,等定夺)**:`test/host/ftp_up_dl_test.py:123/126` 仍写死 +`USER anonymous` / `PASS test@test.com`,而设备自 N-19(2026-10-11)起按 `/config.ini [ftp]` 校验 +admin/admin(SHA-256 `pwd_hash`)→ 该脚本**必然登录失败**;它是手工工具、不在任何 pre-commit 钩子里,所以 +一直没人发现,而 `../测试说明/FTP_Test_Guide.md` 把它列为推荐入口。建议:加 `--user/--password` +(默认 admin/admin),并顺手把 `ftp_speed_test.py` 一起核。 | +| | 数字联动照做:两份 `data/` 快照重跑、`ram_baseline --update/--write`、`check_mem_numbers --write`、FLASH 与 +任务栈两张配图重算重生成(逐文本复查越界 = 0)、本文 §1.3/§5.1/§5.4 与部署文档 §3.3 同步;§0.4 的 S-2 行按 +「完成即销项」改写、§9 拆出 S-2 行标 ✅。 | | **2026-10-22** | **S-1 只做「防扩大」那一半:新增 `layer-deps` 分层方向门禁**(推荐清单第 5 步拆分执行,钩子 37 → **38**) | 上一轮的结论是「反转暂缓、门禁现在就该上」,这次照做。 为什么门禁比搬迁值钱:AGENTS 与分层图早就写着「六层单向依赖」,可从来没有机械检查——于是同一件事的记载从 2026-09 的 「NETCFG 一处」漂到今天的「8 文件 9 处」,全靠人读代码才发现。边界的静默腐蚀只能靠门禁止住。 | diff --git a/scripts/check_cubemx_survival.py b/scripts/check_cubemx_survival.py index 762e4850..fac30cd1 100644 --- a/scripts/check_cubemx_survival.py +++ b/scripts/check_cubemx_survival.py @@ -245,6 +245,16 @@ CHECKS = [ no_baseline=True, # 见下方说明:本文件每次 @build 后被 Keil 改写 hint="task_watchdog.c 须挂在 MDK 工程 App 组;CubeMX 重生成可能重建 .uvprojx。", ), + dict( + id="net-msgq-adopt", + kind="protected", + path="Src/freertos.c", + region="RTOS_QUEUES", + must_contain=["net_msg_queue_adopt"], + hint="消息队列句柄的唯一使用者是 net_socket,创建后必须在 USER CODE BEGIN RTOS_QUEUES 区" + "绑定给它(替代此前 BSP 对该全局变量的裸 extern)。丢了这一行,net_socket 的句柄" + "恒为 NULL → 所有 net_* 请求被判空丢弃,网络全线静默不通(无崩溃、无报错日志)。", + ), dict( id="reset-cause-latch", kind="protected", diff --git a/scripts/ram_baseline.tsv b/scripts/ram_baseline.tsv index 468008b2..44c05c1e 100644 --- a/scripts/ram_baseline.tsv +++ b/scripts/ram_baseline.tsv @@ -4,4 +4,4 @@ date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi 2026-10-14 212296 18740 1112 154456 231036 22.0 98144 74.9 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=40960;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;default_task.o=2736;sys_log_mcu.o=1924 2026-10-15 213540 18740 1136 131520 232280 22.2 75232 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736 2026-10-20 213356 18580 1184 131480 231936 22.1 75240 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736 -2026-10-22 213204 18580 1184 131504 231784 22.1 75264 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736 +2026-10-22 213236 18580 1188 131500 231816 22.1 75264 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736 diff --git a/tools/arch_diagram/gen_memory_svg.py b/tools/arch_diagram/gen_memory_svg.py index e8b8caca..8d6b3ff9 100644 --- a/tools/arch_diagram/gen_memory_svg.py +++ b/tools/arch_diagram/gen_memory_svg.py @@ -47,11 +47,11 @@ RAM2_CATEGORIES = [ # ── Flash breakdown (1MB = 1,048,576 B; 2026-10-22 @build) ────────────────── FLASH_TOTAL = 1048576 -FLASH_CODE = 213204 +FLASH_CODE = 213236 FLASH_RO = 18580 -FLASH_RW = 1184 +FLASH_RW = 1188 FLASH_USED = FLASH_CODE + FLASH_RO + FLASH_RW # ROM 合计(含 RW 初始化表) -FLASH_IROM = FLASH_CODE + FLASH_RO # ER_IROM1 区用量 = 231,784 B(22.1%) +FLASH_IROM = FLASH_CODE + FLASH_RO # ER_IROM1 区用量 = 231,816 B(22.1%) FLASH_FREE = FLASH_TOTAL - FLASH_USED FLASH_CATEGORIES = [ @@ -61,7 +61,7 @@ FLASH_CATEGORIES = [ ("Flash 空闲", FLASH_FREE, "#E0E0E0"), ] -# Flash Code+RO 分布(= ER_IROM1 231,784 B;2026-10-22 按 .map 对象表逐对象归类, +# Flash Code+RO 分布(= ER_IROM1 231,816 B;2026-10-22 按 .map 对象表逐对象归类, # 口径同 data/ram_report_20261022.md;"其他"含链接器填充) FLASH_CODE_SUB = [ ("LVGL 库", 87706, "#4CAF50"), @@ -73,7 +73,7 @@ FLASH_CODE_SUB = [ ("FatFS", 8468, "#9C27B0"), ("C 库 (microlib)", 5486, "#795548"), ("startup", 468, "#B0BEC5"), - ("其他 (长尾)", 7432, "#E0E0E0"), # remainder + ("其他 (长尾)", 7464, "#E0E0E0"), # remainder ] # ── Task stack budgets (2026-10-22 @build + 同日真机 [STACK] 实测; data/stack_report_20261022.md) ── @@ -83,13 +83,13 @@ FLASH_CODE_SUB = [ TASK_STACKS = [ ("defaultTask", 5120, "Normal", 3024, 2152, 2096, 40, "PASS", "FatFS 挂载/探针 + 配置引擎 + syslog + LED"), ("netTask", 3840, "Normal", 1912, 1116, 1928, 50, "PASS", "CH395F 轮询、消息处理"), - ("ftpTask", 4096, "Normal", 1456, 764, 2640, 64, "PASS", "lftpd FTP 服务(大缓冲已静态化)"), + ("ftpTask", 4096, "Normal", 1456, 1404, 2640, 64, "PASS", "lftpd FTP 服务(大缓冲已静态化)"), ("uiTask", 16384, "BelowNormal", 4052, 4052, 12332, 75, "PASS", "LVGL UI 主循环 + 远程显示推流"), ("testTask", 8192, "BelowNormal", 736, 736, 7456, 91, "PASS", "测试套件(产品构建不创建,取静态最坏链)"), - ("timeSyncTask", 2560, "Normal", 1264, 616, 1296, 50, "PASS", "TCP 时间同步(8888)"), + ("timeSyncTask", 2560, "Normal", 1264, 648, 1296, 50, "PASS", "TCP 时间同步(8888)"), ("adcTask", 2560, "AboveNormal", 1320, 952, 1240, 48, "PASS", "1 kHz 节拍消费者(L1 采集,纯取数)"), ("iec104Task", 2560, "Normal", 1456, 540, 1104, 43, "PASS", "IEC 60870-5-104 上行(2404)"), - ("protectTask", 2048, "Normal", 872, 624, 1176, 57, "PASS", "20 ms 保护判据 + 闭锁 + 定值校验和巡检"), + ("protectTask", 2048, "Normal", 872, 828, 1176, 57, "PASS", "20 ms 保护判据 + 闭锁 + 定值校验和巡检"), ] KERNEL_STACKS = [("idle", 512), ("timer", 1024)] # 128/256 words(未实测)