diff --git a/Drivers/BSP/NET/lftpd/lftpd.c b/Drivers/BSP/NET/lftpd/lftpd.c index d3719416..32e8d446 100644 --- a/Drivers/BSP/NET/lftpd/lftpd.c +++ b/Drivers/BSP/NET/lftpd/lftpd.c @@ -368,7 +368,8 @@ static int cmd_list(lftpd_client_t *client, const char *arg) send_simple_response(client->socket, 150, STATUS_150); int data_sock = lftpd_inet_accept_timeout(client->data_socket, 5000); if (data_sock < 0) { - lftpd_log_error("%s accept failed, sk=%d", __func__, client->data_socket); + lftpd_log_peer("%s data accept failed (peer gone?), sk=%d", + __func__, client->data_socket); send_simple_response(client->socket, 425, STATUS_425); lftpd_inet_close(client->data_socket); client->data_socket = -1; @@ -400,7 +401,8 @@ static int cmd_nlst(lftpd_client_t *client, const char *arg) send_simple_response(client->socket, 150, STATUS_150); int data_sock = lftpd_inet_accept_timeout(client->data_socket, 5000); if (data_sock < 0) { - lftpd_log_error("%s accept failed, sk=%d", __func__, client->data_socket); + lftpd_log_peer("%s data accept failed (peer gone?), sk=%d", + __func__, client->data_socket); send_simple_response(client->socket, 425, STATUS_425); lftpd_inet_close(client->data_socket); client->data_socket = -1; @@ -526,7 +528,8 @@ static int cmd_retr(lftpd_client_t *client, const char *arg) send_simple_response(client->socket, 150, STATUS_150); int data_sock = lftpd_inet_accept_timeout(client->data_socket, 5000); if (data_sock < 0) { - lftpd_log_error("%s accept failed, sk=%d", __func__, client->data_socket); + lftpd_log_peer("%s data accept failed (peer gone?), sk=%d", + __func__, client->data_socket); send_simple_response(client->socket, 425, STATUS_425); lftpd_inet_close(client->data_socket); client->data_socket = -1; @@ -593,7 +596,8 @@ static int cmd_stor(lftpd_client_t *client, const char *arg) send_simple_response(client->socket, 150, STATUS_150); int data_sock = lftpd_inet_accept_timeout(client->data_socket, 5000); if (data_sock < 0) { - lftpd_log_error("%s accept failed, sk=%d", __func__, client->data_socket); + lftpd_log_peer("%s data accept failed (peer gone?), sk=%d", + __func__, client->data_socket); send_simple_response(client->socket, 425, STATUS_425); lftpd_inet_close(client->data_socket); client->data_socket = -1; @@ -658,7 +662,7 @@ static int handle_control_channel(lftpd_client_t *client) { int err = send_simple_response(client->socket, 220, STATUS_220); if (err != 0) { - lftpd_log_error("error sending welcome message"); + lftpd_log_peer("peer gone before welcome acked"); goto cleanup; } @@ -668,7 +672,9 @@ static int handle_control_channel(lftpd_client_t *client) int line_len = lftpd_inet_read_line(client->socket, read_buffer, sizeof(read_buffer)); if (line_len != 0) { - lftpd_log_error("error reading next command"); + /* 绝大多数是客户端正常收尾(关窗口 / QUIT 前先断了 TCP); + * 真读错也由返回值区分得出来,留 ret=%d 便于排障 */ + lftpd_log_peer("control channel closed by peer (ret=%d)", line_len); goto cleanup; } @@ -786,7 +792,7 @@ int lftpd_start(const char *directory, int port, lftpd_t *lftpd) int client_socket = lftpd_inet_accept(lftpd->server_socket); if (client_socket < 0) { - lftpd_log_error("error accepting client socket"); + lftpd_log_peer("listener rebuilt (reason logged by accept layer)"); lftpd_inet_close(lftpd->server_socket); lftpd->server_socket = -1; /* 监听器已不可用(网络重建):下轮重建 */ continue; diff --git a/Drivers/BSP/NET/lftpd/lftpd_inet.c b/Drivers/BSP/NET/lftpd/lftpd_inet.c index 7a073ad0..e14a269d 100644 --- a/Drivers/BSP/NET/lftpd/lftpd_inet.c +++ b/Drivers/BSP/NET/lftpd/lftpd_inet.c @@ -88,7 +88,8 @@ int lftpd_inet_accept(int socket) return s; } if (net_get_generation() != gen) { - DBG_ERROR("network re-init: abort accept, relisten"); + /* 运维改 IP 的正常后果,不是缺陷 → info(级别划分见存储架构说明 §10.3) */ + DBG_INFO("network re-init: abort accept, relisten"); return -1; } lftpd_task_wd_beat(); /* 看门狗:自旋轮次喂心跳(无限等待,可能长时间无客户端) */ @@ -110,6 +111,8 @@ int lftpd_inet_accept_timeout(int socket, int timeout_ms) * 认"监听器在服役(LISTENING)或待重建且 RX 有残留(closed-with-data 救回窗)", * 与 :7003 的 N-32 P1 同型修复 */ if (net_listener_armed(socket) == 0) { + /* **故意留 error**:控制连接还活着、我方数据监听却已不在服役 → + * 这是本侧异常,不是对端行为 */ DBG_ERROR("data listener disarmed, accept aborted"); return -1; } @@ -118,7 +121,8 @@ int lftpd_inet_accept_timeout(int socket, int timeout_ms) elapsed += 100; } - DBG_ERROR("accept timeout (%dms)", timeout_ms); + /* 客户端连上控制通道却没来建数据连接(中止/被防火墙拦)= 对端行为 → info */ + DBG_INFO("accept timeout (%dms) - peer never opened data channel", timeout_ms); return -1; } diff --git a/Drivers/BSP/NET/lftpd/private/lftpd_log.h b/Drivers/BSP/NET/lftpd/private/lftpd_log.h index 07572a96..30d6bf3e 100644 --- a/Drivers/BSP/NET/lftpd/private/lftpd_log.h +++ b/Drivers/BSP/NET/lftpd/private/lftpd_log.h @@ -4,4 +4,19 @@ #define lftpd_log_error(format, ...) DBG_ERROR("[FTP] " format, ##__VA_ARGS__) #define lftpd_log_info(format, ...) DBG_INFO("[FTP] " format, ##__VA_ARGS__) +/* + * 对端行为级别(既不是缺陷,也不该长得像缺陷)—— + * 控制连接被对端关闭 / 客户端连上就走 / PASV 之后不来数据连接 / 网络重建导致 + * 监听重建,这些都是**外部输入决定的正常收尾**。它们原先记 error 级,代价实测: + * ① 本仓 @test 的 Forbidden 标记含 `[ERR]`(它同时是四个 Fault 崩溃日志的前缀), + * 于是"FileZilla 关了个窗口"就能把一次启动测试判 FAIL;② 任何人对着 21 端口 + * 连一下就走,就能无限制造固件级 ERROR 日志(日志面 + 门禁面都能被外部驱动)。 + * 所以这一类降为 info,并单独起一个名字,让"谁是真故障"在读代码时就一目了然。 + * 完整划分表 → docs/架构设计/STM32F4-Base存储架构说明.md §10.3。 + * + * ⚠ **传输未完成不在这一级**:`DOWNLOAD/UPLOAD FAILED` 仍记 error——对端中途退出 + * 确实让一次传输没走完,那是数据完整性事件,值得留痕。 + */ +#define lftpd_log_peer(format, ...) DBG_INFO("[FTP] " format, ##__VA_ARGS__) + #define lftpd_log_debug(format, ...) diff --git a/docs/images/内存布局_FLASH.svg b/docs/images/内存布局_FLASH.svg index cbf7e988..cb1afc26 100644 --- a/docs/images/内存布局_FLASH.svg +++ b/docs/images/内存布局_FLASH.svg @@ -9,33 +9,33 @@ 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 - + 代码段 (Code) 208.3KB + + 只读数据 (RO) 18.2KB + + Flash 空闲 796.4KB +已用: 227.6KB (22.2%) 空闲: 796.4KB (77.8%) ER_IROM1(Code+RO): 226.5KB (22.1%) 总量: 1MB (= ROM 合计口径) +Code + RO 分布(ER_IROM1 226.5KB,按 .map 对象归类) + + 85.7KB + + 55.7KB + + 25.1KB + 17.5KB - - - - - - + + + + + + LVGL 库 85.7KB 应用代码/UI 55.7KB - CH395F+FTP 25.0KB + CH395F+FTP 25.1KB HAL 驱动 17.5KB diff --git a/docs/内存管理/RAM使用分析与优化方案.md b/docs/内存管理/RAM使用分析与优化方案.md index 337f22fc..9d829319 100644 --- a/docs/内存管理/RAM使用分析与优化方案.md +++ b/docs/内存管理/RAM使用分析与优化方案.md @@ -38,10 +38,10 @@ | 区域 | 用量 | 容量 | 占比 | |---|---|---|---| -| ER_IROM1 | 231,816 B (226.38 KB) | 1,048,576 B (1024 KB) | 22.1% | +| ER_IROM1 | 231,916 B (226.48 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 合计)** | **233,004 B (227.5 KB)** | 1,048,576 B (1024 KB) | **22.2%** | +| **Flash (ROM 合计)** | **233,104 B (227.6 KB)** | 1,048,576 B (1024 KB) | **22.2%** | 各区的容量与常量来源: diff --git a/docs/内存管理/RAM预算台账.md b/docs/内存管理/RAM预算台账.md index ef2c17ce..95aef43c 100644 --- a/docs/内存管理/RAM预算台账.md +++ b/docs/内存管理/RAM预算台账.md @@ -15,7 +15,7 @@ | 区域 | 用量 | 容量 | 占比 | 门禁(≤92%) | |---|---|---|---|---| -| ER_IROM1 (Flash) | 231,816 B | 1,048,576 B | 22.1% | 参考 | +| ER_IROM1 (Flash) | 231,916 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 | diff --git a/docs/内存管理/data/ram_report_20261022.md b/docs/内存管理/data/ram_report_20261022.md index 5fd008e2..d8df039c 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:56 Map: `STM32F407-Demo.map` +> Generated: 2026-10-22 22:26 Map: `STM32F407-Demo.map` ## 1. Grand Totals (全局总量) | Metric | Value | |---|---| -| Code (inc. data) | 213,236 B (208.2 KB) | -| RO Data | 18,580 B (18.1 KB) | +| Code (inc. data) | 213,264 B (208.3 KB) | +| RO Data | 18,652 B (18.2 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 RO (Code + RO)** | **231,916 B (226.5 KB)** | | **Total RW (RW + ZI) = SRAM used** | **132,688 B (129.58 KB)** | -| **Total ROM (Code + RO + RW init)** | **233,004 B (227.5 KB)** | +| **Total ROM (Code + RO + RW init)** | **233,104 B (227.6 KB)** | ## 2. 执行区水位 (Execution Regions) | Region | Base | Size | Max | Util% | |---|---|---|---|---| -| ER_IROM1 | 0x08000000 | 231,816 B (226.38 KB) | 1,048,576 B (1024 KB) | 22.1% | +| ER_IROM1 | 0x08000000 | 231,916 B (226.48 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% | @@ -136,7 +136,7 @@ |---|---|---|---|---|---|---| | 1 | heap_4.o | 512 | 69 | 32 | 57,344 | 57,376 | | 2 | lv_mem_core_builtin.o | 410 | 0 | 0 | 16,384 | 16,384 | -| 3 | lftpd.o | 6,108 | 509 | 160 | 7,724 | 7,884 | +| 3 | lftpd.o | 6,180 | 509 | 160 | 7,724 | 7,884 | | 4 | ui_net_sink.o | 1,126 | 67 | 20 | 6,746 | 6,766 | | 5 | ui_port.o | 418 | 0 | 12 | 6,408 | 6,420 | | 6 | nand_ftl.o | 2,352 | 175 | 16 | 6,200 | 6,216 | @@ -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,236** | **18,580** | **1,188** | **131,500** | **132,688** | +| | **All .o files** | **213,264** | **18,652** | **1,188** | **131,500** | **132,688** | ## 5. Flash (Code + RO Data) Top-30(按大小降序) @@ -212,7 +212,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 | +| 3 | lftpd.o | 6,180 | 509 | 6,689 | | 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 | @@ -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,236** | **18,580** | **231,816** | +| | **All .o files** | **213,264** | **18,652** | **231,916** | -> 自洽校验: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** +> 自洽校验:per-file 213,264/18,652/1,188/131,500 vs Grand Totals 213,264/18,652/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 c2012bfa..eb6dc567 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:53:08 2026 +- Linker run: Thu Oct 22 22:25:25 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,12 +11,12 @@ 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 | 1404 | 1456 | 2640 | 64% | PASS | +| ftpTask | `StartFtpTask` | 4096 | 1456 | 740 | 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 | 648 | 1264 | 1296 | 50% | PASS | +| timeSyncTask | `time_sync_task` | 2560 | 1264 | 616 | 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 | +| iec104Task | `iec104_serv_task` | 2560 | 1456 | 580 | 1456 | 1104 | 43% | 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/架构设计/STM32F4-Base存储架构说明.md b/docs/架构设计/STM32F4-Base存储架构说明.md index 09137307..3cb5a955 100644 --- a/docs/架构设计/STM32F4-Base存储架构说明.md +++ b/docs/架构设计/STM32F4-Base存储架构说明.md @@ -593,3 +593,31 @@ FTP 根目录 = 卷根,lftpd 是卷的网络文件入口(`Drivers/BSP/NET/lf - **STOR/DELE 写门** — `[ftp] write=0` 时写命令一律 `550` 拒,卷对 FTP 侧只读(`/log`、`/config.ini` 仍可下载不可改写)。 - **全局失败锁定** — 连续 5 次鉴权失败 → 锁定 60 s(跨会话全局、易失、重启清零);纯 lftpd 层状态,不触存储。 - **默认口令告警锚点** — 出厂 `pwd_hash` 在用期间每次启动打 INFO `[FTP] using factory default password`。 + +### 10.3 FTP 日志级别划分:对端行为 vs 固件故障(2026-10-22) + +lftpd 原先把全部异常路径一律按 error 级打(串口上带 `[ERR]`),其中**九处其实由外部输入决 +定**:客户端关窗口、连上就走、PASV 之后不建数据连接、运维改 IP 触发监听重建。代价实测两条: + +1. `@test` 的 Forbidden 标记含 `[ERR]`(它同时是四个 Fault 崩溃日志的前缀)——"FileZilla 关了 + 个窗口"就能把一次启动测试判 FAIL。实测就是这样踩到的:抓自检台账基线那次 FTP 会话结束后, + 设备打 `[ERR] [FTP] error reading next command`,本次 `@test` 直接 FAIL。 +2. 任何对 21 端口"连一下就断开"的外部行为,都能**无限制造固件级 ERROR 日志**——日志面与门禁 + 面都可被外部输入驱动,这在工业现场是过不了审的。 + +| 级别 | 串口形态 | 覆盖的事件 | 判据 | +|---|---|---|---| +| error(`lftpd_log_error` / `DBG_ERROR`) | `[ERR] …` | 建 socket / bind / listen 失败、取端口失败、写通道失败、文件打开失败(读/写/重复打开)、`DOWNLOAD FAILED` / `UPLOAD FAILED`(传输未完成)、`data listener disarmed`(控制连接还活着而我方数据监听已不在服役) | 本侧缺陷,或**数据完整性事件** | +| peer(`lftpd_log_peer` → info 级) | 普通 INFO 行 | 控制通道被对端关闭(原 `error reading next command`)、发送 220 之前对端已走、`listener rebuilt`(网络重建,原因由 accept 层自己记)、四处 `data accept failed`(PASV 后没来数据连接)、`accept timeout` | **对端决定的正常收尾** | + +- **新增专门的 `lftpd_log_peer()` 而不是就地改成 `DBG_INFO`**:让"谁才算真故障"在读代码时 + 一目了然,也防止后来者顺手把对端行为又升回 error。 +- **"传输未完成"仍留 error**:对端中途退出确实让一次 STOR/RETR 没走完,那是需要留痕的完整性 + 事件(`../问题记录/CH395F_Trap_Records.md` 的中止家族就靠这些锚点定位)。 +- **边界(实测划清)**:客户端**干净收尾**(发 `QUIT`,或 FIN 半关)现在整条链路上没有任何 `[ERR]`; + 但用 **RST 硬拆**(`SO_LINGER` 清零、进程被杀、网线拔了)仍会留一条 `[ERR][NET] sockN TIMEOUT`—— + 那是 net 层的套接字超时锚点,网络自愈架构的判据要读它,**不在本次降级范围**。所以"采集窗口内 + 不要跑 FTP"这条规避口径仍然有效,只是不再因为一次正常下载而中弹。 +- 排障信息量不减:peer 级照旧打印,且比原来更准(带 `ret=` / `sk=` / `timeout(ms)`,措辞从 + "error reading next command"改成"control channel closed by peer"——原先那句把正常收尾 + 写成了故障,误导过排查方向。 diff --git a/docs/测试说明/自动化测试流程.md b/docs/测试说明/自动化测试流程.md index fb6b2e01..8739548a 100644 --- a/docs/测试说明/自动化测试流程.md +++ b/docs/测试说明/自动化测试流程.md @@ -68,10 +68,12 @@ | 既没有 `device_ip` 也没有 `--selftest-log` | 要求判定却没有数据源 | **FAIL**(同上,不再 WARN 放行) | | 基线最后一条在台账里找不到 | 512 条环已覆盖基线(更新量 ≥ 环容),无法证明 | **FAIL**(不拿"看不到"当"没有") | -- ⚠ **采集窗口内不要跑 FTP**:设备会把每条 FTP 命令打到串口,客户端退出时还会多打一行 - `[ERR] [FTP] error reading next command` —— 默认 Forbidden 含 `[ERR]`,于是**任何**人边跑 `@test` - 边用 FileZilla 传文件,都会让本次莫名 FAIL(本次改造实测踩到:抓基线原先排在采集武装之后, - 开机耗时被自己的 FTP 会话拉到 ~8 s 并命中 `[ERR]`)。基线抓取因此固定在 open/clear **之前**。 +- ⚠ **采集窗口内仍不要跑 FTP**:每条 FTP 命令都会打到串口上(日志变长、开机耗时指标被污染—— + 实测抓基线排在采集武装之后时,`net init: OK` 从 612 ms 被拉到 7997 ms)。基线抓取因此固定在 + `open/clear` **之前**。(原先更要命的是客户端退出会打 `[ERR] [FTP] error reading next command` + → 直接命中 Forbidden 里的 `[ERR]`;该措辞与级别已在 2026-10-22 归入"对端行为"级,见 + `../架构设计/STM32F4-Base存储架构说明.md` §10.3。注意:RST 硬拆仍会留一条 `[ERR][NET] sockN` + `TIMEOUT`——那是网络自愈架构要读的套接字超时锚点,不在降级范围内。 - `--selftest-scope all` = 保留旧的累计口径(任一记录即 FAIL),用于**审计**或第一次建基线。 - 给了 `--selftest-log`(本地副本)就没有基线可比 → 自动降级为累计口径并打印一行说明。 - 抓基线同样要 FTP 凭据:`--ftp-user` / `--ftp-pass`(config `ftp_user` / `ftp_pass`,默认出厂 diff --git a/docs/环境与部署/项目部署环境要求.md b/docs/环境与部署/项目部署环境要求.md index 602b2802..c649bc88 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,816 B(226.4 KB) | 1 MB | 22.1% | ≈804 KB | **充裕**:产品需求无 OTA / 双镜像预算,Flash 不是卡点;死代码裁剪簇已收口 → `docs/问题记录/项目审查与优化建议报告.md` §5.4 | +| Flash(`ER_IROM1` = Code + RO) | 231,916 B(226.5 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 1e6bf7eb..26fa8a1e 100644 --- a/docs/问题记录/项目审查与优化建议报告.md +++ b/docs/问题记录/项目审查与优化建议报告.md @@ -93,7 +93,7 @@ git ls-files -z | xargs -0 stat -c '%s' | 名词 | 口径 | |---|---| -| Flash 占用 | `Code + RO-data` = `ER_IROM1` = **231,816 B(22.1%)**;`ROM 合计` 再加 `RW` 初始化表 = 233,004 B(22.2%) | +| Flash 占用 | `Code + RO-data` = `ER_IROM1` = **231,916 B(22.1%)**;`ROM 合计` 再加 `RW` 初始化表 = 233,104 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 个 | @@ -230,8 +230,8 @@ defaultTask 单属主;原子写经卷锁;旧档迁移已删除。**仍列为 | 指标 | 2026-10-22 | 2026-10-15 | 说明 | |---|---|---|---| -| `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 | +| `Code` | 213,264 B | 213,520 B | 当日累计:F-6 −332 B、SPI 回调归属 +16 B、消息队列收口 +32 B、FTP 日志级别改造 +28 B(RO 另 +72 B) | +| `ER_IROM1`(Code+RO) | **231,916 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 真机 | @@ -271,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,816 B)——这是"用 LVGL 画单色菜单"的结构性代价,F-1/F-2/F-3 已省掉 64,576 B。 +(87,706 / 231,916 B)——这是"用 LVGL 画单色菜单"的结构性代价,F-1/F-2/F-3 已省掉 64,576 B。 ### 5.5 内存治理长效机制(常开,不受暂缓影响) diff --git a/scripts/ram_baseline.tsv b/scripts/ram_baseline.tsv index 44c05c1e..3e73537e 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 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 +2026-10-22 213264 18652 1188 131500 231916 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 8d6b3ff9..5b4cb294 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 = 213236 -FLASH_RO = 18580 +FLASH_CODE = 213264 +FLASH_RO = 18652 FLASH_RW = 1188 FLASH_USED = FLASH_CODE + FLASH_RO + FLASH_RW # ROM 合计(含 RW 初始化表) -FLASH_IROM = FLASH_CODE + FLASH_RO # ER_IROM1 区用量 = 231,816 B(22.1%) +FLASH_IROM = FLASH_CODE + FLASH_RO # ER_IROM1 区用量 = 231,916 B(22.1%) FLASH_FREE = FLASH_TOTAL - FLASH_USED FLASH_CATEGORIES = [ @@ -61,12 +61,12 @@ FLASH_CATEGORIES = [ ("Flash 空闲", FLASH_FREE, "#E0E0E0"), ] -# Flash Code+RO 分布(= ER_IROM1 231,816 B;2026-10-22 按 .map 对象表逐对象归类, +# Flash Code+RO 分布(= ER_IROM1 231,916 B;2026-10-22 按 .map 对象表逐对象归类, # 口径同 data/ram_report_20261022.md;"其他"含链接器填充) FLASH_CODE_SUB = [ ("LVGL 库", 87706, "#4CAF50"), ("应用代码/UI", 57011, "#2196F3"), - ("CH395F+FTP", 25644, "#F44336"), + ("CH395F+FTP", 25744, "#F44336"), ("HAL 驱动", 17876, "#607D8B"), ("dhara / FTL", 10931, "#FF9800"), ("FreeRTOS 内核", 10762, "#00BCD4"),