取值依据是实测水位,不是预估:菜单根框 5,368 B、开页-关页往返
5,448 B、最重页面峰值 6,568 B(占 16 KB 的 40%)、真机开机
used=3,192 B。注意 16,384 B 建池后 lv_mem_monitor 报的 total 是
15,020 B(TLSF 控制块与对齐元数据 ≈1,364 B),核算余量用后者。
两端 lv_conf.h 同步改值(lv-conf-sync 生效值比对 163 项 PASS),
Lib/lv_conf.h 的 UTF-8 BOM 已按原样补回(Edit 会静默剥掉)。
验证:
- @build 0 错 0 警;ZI 154,456 → 129,880,精确 −24,576 B
- SRAM1 98,144/74.9% → 73,568/56.1%(余 57,504 B);CCM 不变 87.9%
- 模拟器菜单回归 PASS(8 状态像素 + 池基线 5,368 B 未变);11 页
黄金参考逐字节 10/11 一致,往返池水位 5,448 B 分毫未变
- 唯一差异 netcfg_save 保存态:用 40 KB 旧池做 A/B 复测同样失败,
确认与本改动无关(属 506eccc 的 cfg_file 行为变化),未刷黄金
参考掩盖,留给该改动属主处置
- @test PASS:fw build Oct 15 2026 07:31:34,无 [ERR]/Fault,
开机 622 ms 到 net init: OK,menu build done: used=3192
- 本地 CI 全绿(L0 + L0.5,15 runner / 955 断言)
- 台账受管区与内存快照区已 --write 回填,mem-budget / mem-numbers
由红转绿
连带结论:R-2 后半待迁体量 54,146 → 29,570 B,瓶颈由 SRAM1 换到
CCM(只剩 7,904 B);解锁链第 ① 步完成,下一步只差缩堆 56→32 KB
(B5 是反向扩容,缩回前须重跑 stack_report.py + 上板 min_ever)。
文档同步 20 处:本报告按修复即销项删除 R-9 行,并改写 §0.2/§0.3/
§0.4/§5.1/§5.2/§5.3/§6.4 与变更记录、去处表;RAM使用分析 §2.6.2
新增实测水位表、阶段 1.1 标已执行;台账 §3 解锁链、登记簿 N-27、
任务规划 README W3 行与链路图;UI 四篇、产品需求、内存内容分配
策略、运行与自检记录、项目部署环境要求、测试开发标准流程、
simulator/README、ui-verify skill 常量。顺带订正三处与脚本不符的
旧值:池水位常量 4784/4864 → 5368/5448、FreeRTOS 堆 48 → 56 KB。
68 KiB
STM32F4-Base 项目审查与优化建议报告
| 项目 | 内容 |
|---|---|
| 审查日期 | 2026-09-18(初版) |
| 最近复核 | 2026-10-15(R-9 落地后重链接),基线 HEAD = 803f771(分支 v2-on-ui);固件基线 = MDK-ARM/STM32F407-Demo/STM32F407-Demo.map(0 Error / 0 Warning)。⚠ 该次构建含并行未提交改动(App/cfg/cfg_file.*、Drivers/BSP/SD2506/*)→ Code 212,344 比 2026-10-14 干净基线多 48 B;本报告只在内存/Flash 水位上追这次构建,其余结论仍属 2026-10-14 复核 |
| 销项状态 | 本报告采用修复即销项:已修复项的正文与表格行已删除,去处见文末已销项条目的记录去处;未闭环清单见 §0.2 / §0.4 |
| 审查范围 | 仓库全量(2,466 个受版本控制文件 / 79.3 MB);重点为自研代码 50,874 行(191 文件)与构建产物内存画像 |
| 审查方式 | 静态审查 + 链接图(.map)量化分析 + 构建脚本/门禁核对;未做上机动态验证(除特别标注外) |
| 目标 | 结构合理性、文档分布合理性、模块设计合理性、改进路线图、内存优化、UI 标准化 |
与既有文档的关系:本报告不重复
../任务规划/README.md(逐条缺陷台账 + 推进顺序唯一权威)与../内存管理/RAM使用分析与优化方案.md(内存专项方案),而是做体系层评审 + 量化补强 + 新增发现。编号口径:本报告自有编号
N-xx / D-x / S-x / R-x / F-x / U1~U5,⚠ 与登记簿同名不同义(报告 N-16 = 日志逐条开关,登记簿 N-16 = A2/A4 负向台架;报告 S-3 = 注册反向校验,登记簿 S-3 = USART1 TX-only 根治)→ 引用一律带文档名。未闭环项已于 2026-10-11 并轨进登记簿(新编N-19~N-29+ U 簇,出处列保留本报告编号);本报告编号本身不回改、不重排(../编号规范.md)。销项约定:问题修复后其分析正文与表格行从本报告删除,完整记录沉淀到对应模块文档。因此本报告只呈现未闭环问题,不随时间膨胀。
0. 执行摘要
0.1 六维评分(2026-10-14 复核)
| 维度 | 评分 | 一句话结论 | 仍开放的主要缺口 |
|---|---|---|---|
| 项目结构 | A− | 六层分层真实可执行、命名一致、门禁到位;反向依赖控制在 4 处 | NETCFG/UI 语义层错位(S-1)、4 处裸 extern(S-2)、rs485_task.c 仍在注册白名单里等 B2 |
| 文档分布 | A− | 工程文档 88 篇 / 31,416 行,docs/README.md 索引 + docs/文档规范.md + 三档一致性门禁全部落地,check_doc_links --all = 0 失效 |
D-1:docs/ 占仓库 71.8%、手册图片 36.3 MB、.git 已 235 MB(已决策暂不处理,登记观察) |
| 模块设计 | A− | 看门狗(IWDG + 心跳位图 + 4 个 Fault 现场 + .noinit)、就绪屏障、卷锁、FTP 鉴权、Error_Handler 自恢复、ADC 全链均已落地 |
N-12/N-13 dhara 移植两处缺陷(数据丢失风险)、N-16 日志逐条开关、驱动层无统一错误码约定(S-5)、RS485 无协议栈(随 B2 暂缓) |
| 内存使用 | B | 堆迁 CCM + 栈/堆三面观测常开 + mem-budget 92% 门禁;SRAM1 74.9% |
LVGL 池 + UI 两份缓冲 54,146 B 仍在 SRAM1,而 CCM 只剩 7,904 B → R-2 后半被堵死,须先 R-9(§5.3) |
| Flash 使用 | A− | F-1/F-2/F-3 落地省 64,576 B → 占用 22.0%(231,036 B) | F-4/F-5/F-6 ≈10 KB + 编译时长(§5.4) |
| UI 标准化 | B | golden 回归已建(simulator/tests/ 四脚本,含池水位门禁) |
无令牌层 / 无组件库 / 无页注册表(手写 case 仍在)、27 页未落地、golden 与字符集差集未挂门禁(§6) |
0.2 未闭环问题(Top 3,2026-10-14)
| # | 编号 | 问题 | 影响 | 现状 |
|---|---|---|---|---|
| 1 | N-12 / N-13(登记簿 N-21,W2) | dhara_nand_is_free() 只查页首 64 B(nand_ftl.c:152-179);dhara_nand_copy() 不处理 DHARA_NO_PAGE 哨兵(:204-216) |
映射恢复误判 → 数据丢失风险(低概率、后果重);哨兵页号被当真实页 → 未定义行为 | ❌ 两处原样;至今只能靠人工读代码发现(主机侧无 dhara 移植层测试) |
| 2 | R-2 剩余(登记簿 N-27,W3) | R-9 已落地(LV_MEM_SIZE 40→16 KB,2026-10-15)→ 待迁体量由 54,146 B 降到 29,570 B(池 16,384 + ui_port.o 6,420 + ui_net_sink.o 6,766),SRAM1 由 74.9% 降到 56.1% |
CCM 仍只剩 7,904 B(堆 56 KB 占掉)→ 29.5 KB 还是装不下,R-2 后半段只差"缩堆"一步 | 🟡 下一步 = 堆 56→32 KB(⚠ B5 是反向扩容,缩回前须重跑 stack_report.py + 上板 min_ever 复测)→ 解锁链 ../内存管理/RAM预算台账.md §3 |
| 3 | N-16(登记簿 N-24,W4) | 日志每条记录一次 f_open + f_write + f_close(sys_log_mcu.c:124-141) |
每条日志 2–4 次 NAND 页读写;UI 翻记录逐条 open/seek/close | ❌ 未办(仅 FIL static 化省 528 B 栈) |
⚠ 另有两条不在上表但需知晓:.git 已膨胀到 235 MB(D-1,§3.1,2026-10-11 决策"暂不处理、登记观察");rs485_task.c 仍不在两端构建清单里——这是 E-59 门禁下的刻意缺口(随 B2 暂缓),已登记在 check_registration.py 的 KNOWN_GAPS,不是漏注册。
0.3 两条主线建议
推进顺序的唯一权威是
../任务规划/README.md§2;本节只是体系评审视角的两条结构性建议,不另立顺序。
- 把内存从"卡死"变"富裕":R-9 已把 LVGL 池 40→16 KB(2026-10-15,SRAM1 由 74.9% 降到 56.1%);下一步缩堆腾出 CCM,把 LVGL 池与 UI 帧缓冲(现 ≈29.6 KB)搬进 CCM,作为后续功能的预算来源(§5.3)。
- 把 UI 从"每页手写"变"声明 + 原型库":令牌层 → 原型库 → 生成器补全注册 → golden 入门禁,使新增一页的成本从 8 处手工改动降到 1 处声明(§6)。
0.4 未闭环清单(2026-10-14 复核)
只列未办 / 半办项;已修项按「修复即销项」删除(去处见文末)。图例:❌ 未办 / 🟡 半办。 顺序权威在
../任务规划/README.md§2,本表为评审快照;登记簿编号在括号内。
| 类别 | 编号 | 未闭环内容 | 下一步 |
|---|---|---|---|
| 数据正确性 | N-12 / N-13 ❌(N-21,W2) | is_free 只查页首 64 B;copy 不处理 DHARA_NO_PAGE |
整页(或首/中/尾)扫描 + 返回 DHARA_E_UNSUPPORTED + 必须配主机侧移植层单测 |
| 内存 RAM | R-2 剩余 🟡(N-27,W3) | 待迁体量已由 54,146 B 降到 29,570 B(R-9 落地后);CCM 只剩 7,904 B | 只差缩堆 56→32 KB 腾 CCM,再迁(解锁链 → ../内存管理/RAM预算台账.md §3) |
| 内存 RAM | R-3 / R-4 / R-6 ❌(N-27,W3) | 页缓冲未合并 / UI 帧 4 副本 / 栈仍动态 | R-9 已落地销项(2026-10-15,SRAM1 74.9%→56.1%,见 §5.3);R-6 前置条件已满足。R-5 已判定不可行(§5.3) |
| 内存 RAM | N-14 🟡(N-22,W4) | 写回缓存无空闲/掉电强制 flush(整页写与换页已 flush) | 空闲 N ms 由 defaultTask flush |
| Flash | F-4 / F-5 / F-6 ❌(N-28,W4) | 剩余可评估 ≈10 KB(box_shadow 3,246 / draw_sw_img 2,960 / bin_decoder 1,972 / image_decoder 952 / triangle 930)+ 双精度 dadd 等 ≈1 KB;uvprojx 仍挂 201 个 LVGL .c(F-2 后均为空 TU,省的是编译时长) |
逐项实测再关;⚠ mask/mask_rect/grad 是文字与矩形绘制的必经路径,不可盲关 |
| 性能/资源 | N-09 / PHY / P3-x / rs485 DE ❌(N-25,W4) | PASV 每次新建监听;PHY 强制 100M 无自协商回退;NET_MAX_SOCKETS 8 与单连接语义不符;HAL_Delay(1) 阻塞 DE(DE 项随 B2 暂缓) |
见 §4.2 / §4.7 各行建议 |
| 结构 | S-1 / S-2 / S-4 ❌ | NETCFG/UI 语义层错位;4 处裸 extern;app_cfg.h 开关未接线未删 |
随登记簿 C5 处置;rs485_task.c 随 B2 一并出白名单 |
| 存储/日志 | N-15 🟡 / P2-10 ❌ | nand_ftl 三块 2 KB 页缓冲未合并(BBT 缓冲已收紧);容量轮转 f_unlink 与 UI 读并发未纳入卷锁 |
R-3 评估;卷锁覆盖面 → 登记簿 S-5 |
| 驱动规范 | S-5 ❌ | 无统一"错误码 + 超时 + 重试 + 自检上报"约定(GD5F_OK / 0 / bool 混用) |
定义 bsp_err_t + bsp_retry() 写入 docs/代码规范/ |
| 仓库 | D-1 ❌(N-29,W7) | 图片 36.3 MB 仍在仓;.git 已 235 MB |
降采样 / 拆 submodule / LFS 三选一 + 一次 git filter-repo 历史重写;已决策暂不处理、登记观察 |
| UI | U1 / U2 / U3 / U5 ❌(U 簇,W6) | 无令牌层、无组件库、无页注册表(手写 case 仍在);27 页未落地 |
按 §6.5 顺序,U4 的 golden 已可当 U1 的验收工具;本轮不排期 |
| UI | U4 残余 🟡(U 簇,W6) | golden 已建但未挂 pre-commit;字符集差集检查仍是约定 | 两个脚本入门禁 |
| 测试 | P1-10 🟡 / 覆盖率 ❌ | CH395F 套件收尾两步(构建实测链接 + @test 闭环);无覆盖率概念;主机侧对 dhara 移植层无测试 |
N-12/N-13 这类缺陷至今只能靠人工读代码发现 |
1. 审查方法与证据基线
1.1 数据源
| 数据 | 来源 | 可信度 |
|---|---|---|
| 内存/Flash 占用 | .map 的 component 表(237 个含码对象,列序 Code incData RO RW ZI Debug Name) |
高(构建产物,权威) |
| 总量 | map 尾部 Total RO / Total RW / Total ROM + Execution Region 表 |
高 |
| 依赖方向 | 逐文件 #include 扫描 + map 的 refers to 交叉表 |
高 |
| 构建注册 | MDK-ARM/STM32F407-Demo.uvprojx + simulator/CMakeLists.txt + git 文件清单三方对齐(已机械化:scripts/check_registration.py) |
高 |
| 文档链接 | scripts/check_doc_links.py --all(含 --sections-strict) |
高(门禁) |
1.2 复现命令(本报告所有数字可重跑)
# 1) 构建体量(三区水位 + Top-10 RW+ZI)
& '.venv\Scripts\python.exe' scripts/ram_report.py
& '.venv\Scripts\python.exe' scripts/ram_baseline.py --trend
# 2) MicroLIB C 堆真实大小(应为 0x200 = 512 B)
Select-String -Path 'MDK-ARM\STM32F407-Demo\STM32F407-Demo.map' -Pattern '__heap_base|__heap_limit|HEAP'
# 3) 三方文件注册对齐(uvprojx / CMakeLists / git)
& '.venv\Scripts\python.exe' scripts/check_registration.py --strict
# 4) 仓库体量:git ls-files -z | 逐个统计字节(必须用 -z,否则中文名会被控制台代码页破坏)
⚠️ 踩坑记录(供后续审查复用): ① map 组件表是 6 列数值(含
incData与Debug),按 5 列解析会得到 0 个对象; ②git ls-files输出经 PowerShell 管道会按控制台代码页破坏中文路径,导致"文件不存在"的假结论,必须用-z+ 字节流解码; ③ 终端渲染的中文乱码不等于文件损坏,判定损坏须统计EF BF BD字节数(本报告统计结果:0,全库无 U+FFFD)。
1.3 口径定义
| 术语 | 定义 |
|---|---|
| 自研代码 | App/、Drivers/BSP/(不含 Lib/、Middlewares/、HAL/CMSIS)、test/;不含 CubeMX 生成的 Src/、Inc/ |
| Flash 占用 | Code + RO-data = ER_IROM1 231,036 B(22.0% of 1 MB);ROM 再加 RW-data 初始化表 = 231,324 B |
| RAM 占用 | RW-data + ZI-data,跨两个区域 = SRAM1 RW_IRAM1 98,144 / 131,072(74.9%) + CCM RW_CCM 57,376 / 65,280(87.9%) + UNINIT_CCM 48 B(.noinit 崩溃现场保留区)。⚠ 原报告"CCM 不在 scatter 内计 0"的口径已不成立 |
| "死代码" | 该对象在镜像中有码,但其功能被工程配置(如 LV_COLOR_DEPTH 1)或调用点扫描(零调用者)证明不可达 |
内存数字的权威源:区域水位与子系统配额由
../内存管理/RAM预算台账.md(受管区,ram_baseline.py --write生成)持有,趋势在scripts/ram_baseline.tsv。本报告只在支撑结论处引用,不与之竞争事实源。
2. 项目结构合理性
2.1 规模与分布(2026-10-14 实测)
| 分类 | 文件 | 行数 | 说明 |
|---|---|---|---|
App/(自研应用) |
64 | 13,841 | 配置引擎、墙钟、日志、任务编排;App/algo/(L1~L3 + 测频 + 定值/SOE)14 文件 / 2,855 行 |
Drivers/BSP/(自研驱动/子系统) |
76 | 21,845 | NET 8,264、UI 6,073(含 ui_font_cn_12.c)、CH395F 2,641、GD5F 2,035、SD2506 835、NETCFG 766、TPAFE 680、RS485 310 |
test/(自研测试) |
51 | 15,188 | test/host/ 主机侧单测 33 文件 / 7,634 行 + test/board/ 板级套件 18 文件 / 7,554 行 |
| 自研合计 | 191 | 50,874 | 2026-09-18 基线为 108 / 24,353 |
CubeMX Src/+Inc/ |
26 | 5,528 | 受 USER CODE 标记保护 |
simulator/(自研部分,不含 SDL2 SDK) |
10 | 2,665 | PC SDL2 宿主 |
第三方 Lib/ |
958 | 529,983 | LVGL 9.3、FreeRTOS、FatFs、dhara、lftpd |
评价:自研体量与第三方体量比约 1:10.4(基线 1:20),仍属"薄自研 + 厚中间件"。这决定了结构审查的重点不在自研代码内部,而在"自研如何约束第三方"——§5.4 量化的 lv_conf.h 约束失守代价(64,576 B 死代码)已修,但两份 lv_conf.h 必须同一特性子集这条硬约束如今靠 lv-conf-sync 钩子守住,属"约束被机械化"的正例。
2.2 分层与依赖方向
实测自研层间的全部反向依赖(BSP → App)——2026-10-14 复核为 4 处:
| 位置 | 反向 include | 判定 |
|---|---|---|
Drivers/BSP/NETCFG/net_cfg.c:31 |
cfg_file.h |
可接受但需说明:NETCFG 实为"业务配置模块",放在 BSP 层是历史命名 |
Drivers/BSP/NETCFG/ftp_cfg.c:17 |
cfg_file.h |
同上(FTP 鉴权配置随 net_cfg 落在同一目录) |
Drivers/BSP/UI/ui_page_runlog.c:19 |
sys_log.h |
UI 读日志属正常消费者,但 sys_log 在 App 层 → 层次倒置 |
Drivers/BSP/UI/ui_page_selftest.c:19 |
sys_log.h |
同上 |
Lib/FatFs/ffsystem.c:19 |
sys_clock.h(App/util) |
中间件→应用;已在文件内注释声明为"④中间件层"有意为之 |
评价:良好。在 50k 行规模上把反向依赖控制在 4 处,说明分层不是墙上的图。但存在语义层错位:
Drivers/BSP/NETCFG/、Drivers/BSP/UI/名字是"板级支持包",内容是业务(网络/FTP 配置语义、菜单/页面/权限/内容页框架)。后果:sys_log(App)与net_cfg(BSP)互相引用,层次图自相矛盾。- 建议(S-1):把
NETCFG、UI在概念上重新定性为App/或新增Service/层,Drivers/BSP/只留下与引脚/芯片强绑定的ch395f、gd5f2gq5ue、sd2506、tpafe5160、rs485、dbg_*。迁移成本最低的做法:先改文档与分层图(零风险),目录迁移留到有 CI 兜底之后。
依赖方向裸引用(绕过头文件契约的 extern)实测 4 处——2026-10-14 复核:4 处全部仍在,S-2 未办:
| 位置 | 裸 extern |
|---|---|
Drivers/BSP/CH395F/ch395f.c:177 |
extern volatile uint8_t g_spi1_dma_done;(实为 GD5F 在 gd5f2gq5ue.c:50 定义的变量,跨模块反向且未进任何头文件) |
Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c:47 |
extern SPI_HandleTypeDef hspi1;(Inc/spi.h 已导出,局部重复) |
Drivers/BSP/NET/net_socket.c:77 |
extern osMessageQueueId_t netMsgQueueHandle; |
Drivers/BSP/SD2506/sd2506.c:20 |
extern I2C_HandleTypeDef hi2c1;(Inc/i2c.h 已导出,局部重复) |
建议(S-2):CubeMX 句柄类(hspi1/hi2c1)统一由 main.h 导出并 include,删除局部 extern;g_spi1_dma_done 应由 GD5F 模块自己定义并在头文件 extern 声明(当前跨模块裸 extern 是真正的耦合隐患);netMsgQueueHandle 改为 net_socket 内部持有 + 提供投递 API。
2.3 双构建清单漂移
把 git 文件清单 × uvprojx × simulator/CMakeLists 三方对齐后:
| 类别 | 文件 | 后果 |
|---|---|---|
| 两边都不注册 | 基线 5 个 → 现剩 1 个:App/task/rs485_task.c(E-59 门禁下的刻意缺口,随 B2 暂缓,已登记 KNOWN_GAPS) |
crc.c/ringbuf.c 已整体删除(全库无调用者)、lftpd_log.c 已删除并入 lftpd_auth.c、adc_task.c 已挂 uvprojx(仅 MCU,符合"任务层不入模拟器")——"写了不编译"的盲区已消 |
| 仅 simulator 注册 | cfg_file_store_sim.c、net_socket_sim.c、sim_port.c、sim_syslog.c、ui_net_sink_backend_sim.c |
正常(后端适配层模式) |
| uvprojx | 323 个 .c(含 201 个 LVGL) |
LVGL 全量编译 → 编译时长;F-2 落地后未用控件类 TU 均为空目标文件(见 §5.4 F-5) |
评价:AGENTS.md 的"新文件必须注册两处"铁律如今两端都有机械保障——正向由 new-source-file skill 约束,反向由 scripts/check_registration.py(pre-commit registration-check 钩子,2026-10-12)校验"存在但未注册",并反向查"注册了但文件不存在"的幽灵注册。残余只有一条刻意缺口:rs485_task.c 在 KNOWN_GAPS 里等 B2 立项,随该簇一并处置即可(清完后把 --strict 设为默认)。
2.4 目录组织与根目录卫生
| 观察 | 证据 | 判定 |
|---|---|---|
| 根目录散置工作文件 | ui_menu_tree.txt、ui_cn_chars.txt |
菜单树/字符集是生成器输入,放根目录合理且已在 docs/ 有权威说明 |
Lib/ 命名 |
Lib/ 下混放 lvgl/、lv_conf.h、FatFs/、dhara/ |
lv_conf.h 是工程配置不是库文件;建议移到 Config/lv_conf.h 并同步 include 路径(低风险;⚠ 须一并处理 simulator/lv_conf.h,两份必须同一特性子集) |
| 功能开关名存实亡 | App/app/app_cfg.h 的 APP_NET_ENABLE/APP_ADC_ENABLE/APP_RS485_ENABLE 全库零引用 |
开关不生效比没有开关更糟——评审者会误信"ADC 可裁剪"。文件头 v1.1 已如实标注"预留占位、不门控任何代码",但仍未接线也未删(S-4) |
2.5 结构结论
总体判断:结构合理,无需重构。要做的是三类低成本纠偏:S-1 层次定性、S-2 消裸 extern、S-4 让 app_cfg.h 开关真正生效或删除。
3. 文档分布合理性
3.1 体量画像(2026-10-14 实测,工作树)
| 对象 | 文件数 | 体积 | 占仓库 |
|---|---|---|---|
| 仓库受控文件总计 | 2,466 | 79.3 MB | 100% |
docs/ 合计 |
— | 56.9 MB | 71.8% |
└ docs/芯片手册/ 图片 |
703 张 | 36.3 MB | 45.8% |
.git 目录 |
— | 235.3 MB | — |
| 工程文档(Markdown,自研) | 88 篇 / 31,416 行 | — | — |
| 外部资料(Markdown,datasheet 转录) | 14 篇 / 58,244 行 | — | — |
关键失衡:工程文档与外部资料的行数比已从 1:4.2 改善到 1:1.9,但全部 Markdown 只有 5.4 MB,图片体量(36.3 MB)是它的 6.7 倍、占仓库近一半,git clone 的净耗时几乎全花在扫描手册图片上。⚠ .git 已达 235 MB(受控文件才 79.3 MB),说明历史里存过多版图片/产物——D-1 单靠拆仓或 LFS 不足以解决 clone 耗时,还需一次历史重写。
3.2 做得好的(应保留并显式制度化)
- 文档密度与可执行性:每篇都带"步骤 + 判据"(如 UI 制作流程有 P0→P4 Gate);测试说明按模块拆分并给出预期串口标记,可直接接
@test。 - 陷阱台账:
docs/问题记录/*_Trap_Records.md+docs/任务规划/(带状态与日期)——这是本工程最有价值的资产,多数嵌入式项目没有。 - 图与脚本同提交:
tools/arch_diagram/、tools/refgraph/生成器 + 产物入库,图可再生而非手绘。 - UI 设计资产链完整:原始参考图 → 说明 md → 代码,可追溯。
- 文档一致性已机械化:
doc-links(含--sections-strict)、task-table、mem-numbers、lv-conf-sync、cubemx-survival等只读钩子守住"文档说的 == 代码做的"。
3.3 问题清单
D-1(P1)外部资料与工程文档同仓同树
影响:clone 慢、备份慢、code review 时 diff 噪音大;docs/芯片手册/ 的 703 张图属于只读输入资料,与代码演进无关。
建议(三选一,按代价递增):
- 最省:把手册 JPG 降采样到长边 1,200 px(约 36 MB → 8 MB),一次性提交并在
../文档规范.md写入"入库图片上限 200 KB/张"; - 推荐:
docs/芯片手册/拆为独立仓库dtu-datasheets,用git submodule挂回原路径(现有全部链接不需改写); - 最正:Git LFS(需要托管端支持)。
⚠ 三项都不解决历史膨胀:
.git235 MB 需一次git filter-repo历史重写(破坏性操作,所有克隆需重取)。2026-10-11 已决策:暂不处理、登记观察(登记簿 N-29),推送/协作前重评——届时未推送提交更少、重写代价最低。
3.4 文档结论
内容质量高(A−)、分布形态差。D-1 处理后可到 A:工程量约 1 人日(不含拆仓与历史重写),收益是 clone 时间与"文档可信度"。
4. 功能模块设计评审
4.1 启动与任务框架
设计良好:
app_main_init顺序有因(墙钟优先,使后续日志带时间戳);- Event Flags 就绪屏障(
NET_READY/STORAGE_READY/FTP_READY/TIMESYNC_READY)取代魔法延时,是本项目最漂亮的设计之一; - 配置引擎属主收敛到 defaultTask 单任务,消除了跨任务竞态;
- 初始化失败路径已收口:
Error_Handler打 1 条自检日志 +NVIC_SystemReset()(不再__disable_irq(); while(1))。
问题:
| 编号 | 问题 | 影响/建议 |
|---|---|---|
| S-4 | App/app/app_cfg.h 三个 APP_*_ENABLE 零引用(文件头已标注"预留占位") |
开关要么生效要么删;产品定义(登记簿 B0)落定前至少别让评审者误信"可裁剪" |
4.2 网络子系统(CH395F + BSD 抽象层)
设计良好:
- 所有
net_*经netMsgQueue串行到 netTask 执行 → 单线程语义清晰; - 全部 CH395F 中断集中在
net_poll()内GET_GLOB_INT_STATUS排空(AGENTS 铁律,已落实); - 网络代次号机制使"改 IP 免重启"能重建各监听;
- 挂起 recv/send 模型(
net_pending.c/h)取代"强加 30 s 默认预算",recv 语义已主流化。
问题:
| 编号 | 问题 | 证据 | 建议 |
|---|---|---|---|
| N-09 | cmd_pasv 每次新建监听 lftpd_inet_listen(0)(随机端口) |
lftpd.c:472 |
在单连接 socket 上与 UI :7003、对时 :8888 争用同一物理 socket;建议限定监听资源池 + 显式"FTP 会话独占"策略,并在文档写明"一次只允许一个 TCP 服务活动" |
| — | PHY 强制 100M 全双工,忽略自协商 | App/task/net_task.c:110 无条件 ch395f_set_phy(CH395F_PHY_100M_FULL) |
与某些交换机会联不通;至少加"链路 up 失败 3 次后回退自协商" |
| P3-x | NET_MAX_SOCKETS 8(net_config.h:33)是软件表,与硬件单连接语义不符 |
文档已说明,但 API 层看不到限制 → 建议在 net_socket.c 断言"同时 LISTEN 数 ≤ N" |
4.3 存储子系统(GD5F2GQ5UE + dhara + FatFs)
设计良好:
- 分层正确:
gd5f2gq5ue(芯片)→nand_ftl(dhara map/journal + 页缓存)→ FatFs R0.14 → 应用; Lib/FatFs/ffsystem.c用真实osMutexNew实现FF_FS_REENTRANT=1的卷锁(多数移植是空实现)——这是本工程移植质量的一个亮点;get_fattime()接系统墙钟,使 FAT 时间戳有意义;- BBT 保留块池把坏块表存储区从 dhara 可见空间中排除,避免被 FTL 擦写;
- DMA 可达性三层防线(原 N-11 的处置,2026-10-11):编译期窗口断言(
gd5f2gq5ue.h:96-107负数组 typedef,DMA 白名单窗口与 CCM 永不得重叠 + 阈值契约)→ 启动期自检(nand_ftl.c:241-243三块静态页缓冲逐一过守卫)→ 运行时强制(gd5f_dma_buf_ok()不可达即回落轮询 +[ERR]);规则本身(R2 DMA 缓冲只允许 SRAM 静态、R3 堆/栈禁为 DMA 源/目的)已写进../内存管理/内存内容分配策略.md§4,并有 TC-GD5F-704/705 负路径用例实证。缓冲自身地址无法编译期断言(.bss地址链接期才定,AC5 取不到)——这条边界在头文件注释里写明,别再试图"加个_Static_assert"。
问题:
| 编号 | 问题 | 证据 | 影响/建议 |
|---|---|---|---|
| N-12 | dhara_nand_is_free() 只检查页首 64 B |
nand_ftl.c:152-179(仍 uint8_t buf[64]) |
dhara 依赖该判定做映射恢复;页首 64 B 全 FF 但后半页有数据时会误判为空闲 → 数据丢失风险(低概率但后果重)。建议整页扫描或至少首/中/尾三处采样 |
| N-13 | dhara_nand_copy() 未处理 DHARA_NO_PAGE 语义(dst 为哨兵值时仍执行"读+编程") |
nand_ftl.c:204-216(read→prog 直传) |
dhara map 在回收/擦除路径会用 DHARA_NO_PAGE 试探;当前实现会把它当作真实页号 → 未定义行为。建议:if (dst == DHARA_NO_PAGE) { dhara_set_error(err, DHARA_E_UNSUPPORTED); return -1; } |
| N-14 | 写回缓存 s_cache_buf/s_cache_dirty 无掉电保护策略:CTRL_SYNC 已实现但没有空闲时强制 flush |
nand_ftl.c:418 |
掉电窗口 = 最后一次未跨页的写。已改善:整页写立即 flush、换页时 flush、CTRL_SYNC 走 flush + dhara_map_sync;仍无空闲定时 flush → 建议 defaultTask 空闲 N ms flush |
| N-15 | 页缓冲重复:nand_ftl 3×2,048(s_page_buf/s_cache_buf/s_copy_buf) |
对象 ZI:nand_ftl 6,216 | 与 s_copy_buf 复用可省 2 KB(§5.3 R-3)。🟡 gd5f 的 s_bbt_page_buf 已由 2,048 B 收紧为 272 B |
| — | disk_ioctl GET_BLOCK_SIZE = 1 |
nand_ftl.c:442-444 |
FatFs 的擦除块提示失效(FAT32 对齐优化拿不到信息);建议返回 64 页(=1 物理块) |
4.4 配置引擎(App/cfg/cfg_file.c,1,343 行)
设计良好:描述符 + 段注册表、外科式(surgical)保存、模板生成、2 s 轮询(cfg_file_poll)响应 SYS_EVT_CFG_SAVE,属主单任务化。这是全项目设计最完整的一个模块。销毁用户文件的路径(超长/损坏)已补自检留痕(cfg load oversized / cfg load read fail → SYSLOG_SELFTEST),现场无调试器时可追溯。
问题:
| 编号 | 问题 | 建议 |
|---|---|---|
| — | 读失败仍静默回落工厂默认(:1071-1102),语义合理(不阻塞组网),但用户改了 IP 重启就丢,串口之外无提示 |
装置信息页给出"当前为出厂配置"标识(自检记录已有,UI 侧未接) |
4.5 日志子系统(App/log/sys_log_mcu.c)
设计良好:定长 64 B 记录(SYSLOG_REC_SIZE)、单写者(defaultTask)、RAM 队列 + syslog_drain、容量满时删除重建、/log 目录惰性创建(mkdir 失败保持未就绪 + 幂等重试 + 上报);/log/selftest.log + 开机自检锚点 + Fault 现场 .noinit 跨复位 → 现场故障从"不可知"变成"可回读"。控制台侧另有单写者队列(App/log/console_log.c,对象 ZI 4,120 B)把"多任务直接 printf 到 USART1"收敛为一条流;代价已量化进 AGENTS.md(每条日志约 90 B Flash + 216 B 栈,深调用链模块另以 #define DBG_LINE_BUF_MAX 128U 收紧)。
问题:
| 编号 | 问题 | 证据 | 建议 |
|---|---|---|---|
| N-16 | 每条记录一次 f_open + f_write + f_close,读侧同样每条 f_open/f_lseek/f_close |
sys_log_mcu.c:124-141(失败重建重试一次)、wdev.log 同模式 :486-489 |
写侧:常驻 FIL(仅 defaultTask 持有)+ 批量 flush;读侧:打开一次 + 缓存目录偏移(UI 已有 s_cache_valid/s_last_rec 雏形,可升级为页缓存)。🟡 唯一改善 = FIL 已 static 化(省 528 B 栈) |
| P2-10 | 容量轮转 f_unlink 与 UI 读并发 |
轮转只在写者、读者持版本号;卷锁覆盖面评估 → 登记簿 S-5 |
4.6 UI 子系统
见 §6 专题(同时是"标准化"章节)。此处仅记设计层结论:三层拆分(数据 ui_menu_tab / 视图 ui_menu_view / 控制器 ui_menu)+ 内容页描述符框架方向正确,但框架未收敛到"新页面零框架改动"(menu_content_page_for() 仍是手写 case,ui_menu.c:118-128),且 4 份 3,200 B 帧副本占 12.8 KB RAM(§5)。✅ 验证侧已到位:golden 回归已建(§6.1),UI 改动从此有逐像素/逐字节基线可依赖。
4.7 外设驱动
| 模块 | 评价 | 未闭环问题 |
|---|---|---|
sd2506(RTC) |
I2C 超时齐备,降级策略明确(RTC 故障→默认时基 + 自检上报),WRTC 解锁顺序按手册、负温度符号扩展已处理 | — |
tpafe5160(并行 ADC) |
BUSY 超时、EXTI 读取路径齐备;取数已收口为 tpafe5160_snapshot() 原子快照(帧序号只增不清 + FRSTDATA 自检) |
⚠ V0.1 硬件缺陷(登记簿 N-18,V0.2 改版项):8 路电气量被分给两片转换器 → 主板侧禁止跨转换器做相位/功率/功率因数运算;并行总线无批量采样框架,16 位端口读依赖 gpio.c 初值 |
rs485 |
结构简单 | DE 时序用 HAL_Delay(1) 阻塞 1 ms(在调用任务里,rs485.c);无帧校验、无接收环(crc.c/ringbuf.c 已删除 → 需从零重做);rs485_task.c 仍未注册,消费者被 E-50(包撕裂)/E-49(TX 超时拉 DE)挡住(随 B2 暂缓) |
ch395f |
事务包裹 begin/end、SPI 分频 8 为 PCB 约束(已文档化,勿动) |
静态 DMA 缓冲 2×2,052 B(obj ZI 4,162),必须留 SRAM1 |
驱动共性缺口:没有统一的"错误码 + 超时 + 重试 + 自检上报"约定,各模块自定返回码(GD5F_OK / 0 / bool 混用)。建议(S-5):定义 bsp_err_t 统一错误码 + bsp_retry() 辅助 + 所有失败必须走自检记录,作为驱动编写规范写入 docs/代码规范/。
4.8 测试体系
设计良好:test/board/test_config.h 的 TEST_SUITE_* 互斥(#error 保护)、CH395F 硬件层/NET 层 Phase 互斥、@test 一键闭环(烧录→wait-idle→标记校验)、模拟器 --cfgtest/--logtest、主机侧单测 15 个钩子(含 sha256 / ftp_auth / vol_lock / 采集算法族)。
⚠ 仍缺:覆盖率概念、主机侧对
dhara移植层的测试(N-12/N-13 这类缺陷至今只能靠人工读代码发现)。
问题:
| 编号 | 问题 | 建议 |
|---|---|---|
| P1-10 | CH395F 硬件测试套件静态 RAM 预算(L6406E 历史:HW 套 +8.7 KB、NET 层固件 +28 KB) |
基线已重建、测试缓冲已瘦身、RAM 侧因堆迁 CCM 大幅缓解;剩"套件构建实测链接确认 + @test 闭环"两步(登记簿唯一 P 类收尾项,W5) |
5. 内存优化(量化)
5.1 实测基线(2026-10-15 .map,R-9 落地后)
| 指标 | 数值 | 上限 | 占用 |
|---|---|---|---|
Code + RO-data(ER_IROM1) |
231,084 B | 1 MB Flash | 22.0% |
ROM(Code + RO + RW 初始化表) |
232,196 B | 1 MB | 22.1% |
SRAM1(0x20000000,128 KB) RW_IRAM1 |
73,568 B | 131,072 B | 56.1%(余 57,504 B) |
CCM(0x10000000,64 KB) RW_CCM |
57,376 B | 65,280 B | 87.9%(余 7,904 B) |
UNINIT_CCM(.noinit 崩溃现场) |
48 B | 256 B | 18.8% |
R-9 已落地(2026-10-15):
LV_MEM_SIZE40→16 KB → SRAM1 由 98,144 B / 74.9% 降到 73,568 B / 56.1%(−24,576 B,与池缩减量逐字节吻合)。SRAM1 首次从"最紧的一块"变成余 57.5 KB;当前瓶颈换到 CCM(87.9%,只剩 7,904 B)。
权威源:区域水位与子系统配额 →
../内存管理/RAM预算台账.md(受管区);趋势 →scripts/ram_baseline.tsv(ram_baseline.py --trend高亮 RW+ZI 增长 >1 KB 的对象)。本节只列支撑结论所需的数。
RW+ZI 主要对象(ram_baseline.tsv 末行 Top-10)
| 对象 / 符号 | 字节 | 所在区域 | 归属 | DMA 可达性 |
|---|---|---|---|---|
ucHeap(heap_4.o) |
57,376 | CCM(0x10000020) |
FreeRTOS 堆(configTOTAL_HEAP_SIZE 56 KB + 元数据) |
DMA 不可达——规则 R3「堆/栈禁为 DMA 源/目的」已写进 ../内存管理/内存内容分配策略.md §4,并由 gd5f_dma_buf_ok() 运行时强制 |
work_mem_int(lv_mem_core_builtin.o,= LV_MEM_SIZE 16*1024,R-9 后) |
16,384 | SRAM1 | LVGL 池(实测峰值 6,568 B = 40%) | 纯 CPU,可迁 CCM(R-2 未完成项) |
lftpd.o |
7,884 | SRAM1 | FTP(含鉴权) | 任意 |
ui_net_sink.o(g_tx + g_lcdmem_data + g_rx) |
6,766 | SRAM1 | UI 网络发送 | 可迁 CCM(CH395F 侧 memcpy 到自有 SRAM1 缓冲) |
ui_port.o(g_ui_fbuf + g_ui_draw_buf) |
6,420 | SRAM1 | UI 帧/绘制缓冲 | 可迁 CCM |
nand_ftl.o(3×2,048 页缓冲 + 控制块) |
6,216 | SRAM1 | 存储 | 必须 SRAM1(规则 R2/R3) |
ch395f.o(s_spi2_dma_tx/rx[2052]) |
4,162 | SRAM1 | 网络 | 必须 SRAM1 |
console_log.o(行环形缓冲) |
4,120 | SRAM1 | 日志 | 任意(TX 走 DMA → 实际必须 SRAM1) |
default_task.o |
2,736 | SRAM1 | 任务薄壳 | — |
sys_log_mcu.o |
1,924 | SRAM1 | 日志 | 任意 |
两个静态池(57,376 + 16,384 = 73,760 B)仍是 RAM 问题的核心,且分居两区:堆在 CCM(占 CCM 的 87.9%)、LVGL 池在 SRAM1(R-9 后只占 SRAM1 的 22%)。→ 下一步收益点仍是把 LVGL 池 + UI 两份缓冲搬进 CCM,但体量已由 54,146 B 降到 29,570 B(16,384 + 6,420 + 6,766),而 CCM 只剩 7,904 B → R-9 已做完,还差"缩堆"这一步(56→32 KB 可腾 24 KB → CCM 余 ≈31.9 KB ≥ 29,570 B;解锁链 → ../内存管理/RAM预算台账.md §3)。⚠ 迁移前必须过 DMA 可达性清单:区域放置与"堆/栈禁为 DMA 源/目的"的规则族(R1~R4)以 ../内存管理/内存内容分配策略.md §4 为准,本仓另有两条实证同族约束(ADC1 DMA 目的缓冲必须在 RW_IRAM1;CCM 上做 DMA 静默不落地)。
Flash 侧(Code+RO,按 .map 组件表对象名归类)
| 子系统 | Code+RO | 占镜像 |
|---|---|---|
| LVGL(核心/绘制/字体/缓存/图像) | 87,706 | 38.0% |
| 网络(NET + CH395F + NETCFG + lftpd) | 27,561 | 11.9% |
| 存储(FatFs + dhara + NAND + 卷锁) | 19,265 | 8.3% |
手写 UI 页面/框架(ui_*.o) |
18,507 | 8.0% |
| FreeRTOS + CMSIS-RTOS | 13,562 | 5.9% |
| HAL/CMSIS | 13,532 | 5.9% |
算法层 L1~L3(adc_input/phasor/sample_ring/prot_*) |
5,454 | 2.4% |
其余(App/ 应用与驱动自研、startup、C 库、填充) |
≈45,497 | ≈19.7% |
| 合计 | 231,084 | 100% |
归类按
.map组件表对象名前缀,合计与区域总量可差几十字节(链接器填充)。前 7 行逐字节与 2026-10-14 那次构建相同;并行未提交改动(cfg_file/sd2506)的 +48 B 落在"其余"。
要点:LVGL 的绝对量自 F-1/F-2/F-3 裁剪后未再增长(87,706 B),但仍是镜像最大单一子系统 → §5.4 的剩余裁剪(≈10 KB)与 F-5 的编译时长收益依旧成立。
5.2 结构性诊断(三条)
- 瓶颈已从 SRAM1 换到 CCM:R-9 落地后 SRAM1 只剩 56.1%(余 57,504 B),而 CCM 被堆占掉 87.9%(只剩 7,904 B),待迁的 LVGL 池 + UI 两份缓冲 = 29,570 B。
→ R-2 的剩余部分只差"缩堆"这一步(56→32 KB,
../内存管理/RAM使用分析与优化方案.md§2.2;⚠ 2026-10-12 B5 是反向扩容,缩回前必须重跑stack_report.py+ 上板min_ever复测);顺序不可颠倒(../内存管理/RAM预算台账.md§3)。 - 任务栈全部动态取自 FreeRTOS 堆:
osThreadAttr_t只设stack_size不设stack_mem(Src/freertos.c)→ 8 条产品任务栈合计 9,792 words = 39,168 B(另 testTask 2,048 words 仅测试构建)连同 idle/timer 栈、TCB、IPC 全部从堆里扣,留给动态分配的实际余量很紧(堆 56 KB 是 2026-10-12 B5 扩容后的值)。 → R-6(栈静态化)是把"池内碎片"变"可核算静态区"的正解,前置条件(观测常开 +stack_report.py每任务最坏链)已满足。 实时水位以串口[STACK]/ 自检打印为准,不在本文固化快照。 - MicroLIB 512 B C 堆是隐形地雷:任何新代码写一个
malloc都会中招。 →Heap_Size EQU 0x200未变、.map仍Removing startup_stm32f407xx.o(HEAP), (512 bytes);铁律已进 AGENTS.md(只用pvPortMalloc/vPortFree或收进平台后端),但没有机械化检查——check_coding_standard.py未含malloc(正则 → §5.5 第 5 条未落地。
5.3 RAM 优化路线(收益/风险/优先级)
| 编号 | 措施 | 收益 | 风险 | 优先级 | 状态 |
|---|---|---|---|---|---|
| R-2 | 启用 CCM 承载 LVGL 池与 UI 缓冲:对 work_mem_int 与 UI 帧/绘制缓冲加段属性(.sct 已有 RW_CCM) |
−29,570 B(R-9 后的待迁体量:16,384 + 6,420 + 6,766) | 中:必须确保这些缓冲不被任何 DMA 直接寻址。已核实 UI 发送路径 memcpy 进 CH395F 自有 SRAM1 DMA 缓冲,LVGL 为纯 CPU;NAND 路径(规则 R2/R3)绝对不可迁入 | P1(W3) | 🟡 只做一半:RW_CCM 只收 heap_4.o(57,376 B)→ SRAM1 已减 49 KB+。⚠ 前置条件只剩一步:R-9 已落地(2026-10-15),但 CCM 只剩 7,904 B,29.5 KB 仍装不下 → 需缩堆 56→32 KB |
| R-3 | 存储页缓冲合并:nand_ftl 三块 2 KB 中 s_page_buf(dhara scratch) 与 s_copy_buf 不可并发,可复用 |
−2 KB | 中:需严格审查 dhara 调用序列(copy 期间不会用 map scratch) | P2 | ❌ 未办(s_bbt_page_buf 已单独收紧为 272 B) |
| R-4 | UI 帧副本去重:同一 3,200 B 帧当前存 4 份(g_ui_draw_buf → g_ui_fbuf → g_lcdmem_data → g_tx)。让 ui_flush_cb 直接把 color_p 交给 sink、sink 发送时才拼帧头 |
−6.4 ~ −9.6 KB | 中:需要 sink 与 LVGL 刷新生命周期对齐(同任务,可控) | P1 | ❌ 未办(ui_port.o 6,420 + ui_net_sink.o 6,766 = 13,186 B,副本数未变) |
| R-6 | 任务栈改静态分配(stack_mem 指向各自 .bss 数组),从堆里释放 ≈39 KB |
堆可用 +39 KB(总量不变,但把"池内碎片"变成"可核算静态区") | 低-中:静态后溢出检测更难发现;先测水位再定尺寸 | P2 | ❌ 未办。⚠ 前置已满足:观测三面常开 + stack_report.py 已给出每任务最坏链 → 可直接按实测值定尺寸 |
✅ R-9 已落地并销项(2026-10-15):
LV_MEM_SIZE40→16 KB(两份lv_conf.h同步,lv-conf-sync生效值比对 163 项 PASS)。依据 = 池水位门禁实测(菜单基线 5,368 B / 开页-关页往返 5,448 B / 最重页面峰值 6,568 B = 池的 40%),≈2.5× 余量;PC 侧 11 页黄金参考逐字节比对 10/11 一致(唯一差异是netcfg_save保存态文本,A/B 复测证明与本次改动无关,属并行未提交的cfg_file改动)、往返池水位 5,448 B 分毫未变;@build0 错 0 警,ZI 精确 −24,576 B。真机复跑 ✅(2026-10-15@testPASS):menu build done: total=15020 free=11828 used=3192——菜单根框只占建池后 15,020 B 的 21%(TLSF 元数据 ≈1,364 B),全程无[ERR]/Fault。再往下试 8 KB 需先跑全量 UI 回归(PC + 真机),不在本条范围。
⚠️ R-2 与 R-4 不可叠加计算:R-4 省的是"副本份数",R-2 已把这四份缓冲整体搬到 CCM,因此 R-4 在 R-2 之后省的是 CCM 而非 SRAM1(CCM 侧 13,186 B → ≈6.8 KB,为后续 UI 扩展腾空间)。若只做 R-4 不做 R-2,则直接为 SRAM1 省 6.4 KB——两条路线对 RAM 总量等价,但顺序决定收益落在哪个区域。
R-5 已判定不可行(原建议
configMAX_PRIORITIES56→32 省 480 B):CMSIS-RTOS2 包装层freertos_os2.h:293有#if (configMAX_PRIORITIES != 56) #error——改小直接编译失败。为 480 B 去改第三方包装层不划算,本条关闭(登记簿 N-27 的评估清单已据此剔除 R-5)。
与 ../内存管理/RAM使用分析与优化方案.md 的关系:本表沿用其阶段划分(阶段 0 测量 / 阶段 1.1 池收缩 / 阶段 1.2 CCM / 阶段 2 堆收缩),本报告新增的是 ①R-4 帧副本去重(原文档未识别 4 份副本)②R-3 存储侧缓冲合并 ③DMA 可达性硬边界(原报告 N-11 提出,现已沉淀为 ../内存管理/内存内容分配策略.md §4 规则 R2/R3,属实施风险关键点)。
5.4 Flash 优化(未闭环:F-4 / F-5 / F-6)
F-1 / F-2 / F-3 已落地并销项(2026-10-11):两份
lv_conf.h对齐为同一特性子集 → 实测省 64,576 B,Flash 26.3% → 20.1%(现 22.0%,增量来自 B4/B5 功能代码)。完整记录见../内存管理/RAM使用分析与优化方案.md§2.6.4 与../UI设计/UI_设计架构.md§1.4 第 10 条。
| 编号 | 措施 | 可省 Flash | 依据 | 状态 |
|---|---|---|---|---|
| F-4 | 关闭未用的绘制子模块与 LV_USE_SNAPSHOT(MCU 端)/LV_USE_OBJ_PROPERTY/LV_USE_FLOAT 等 |
可评估部分 ≈10 KB | 对象实测:box_shadow 3,246 + draw_sw_img 2,960 + bin_decoder 1,972 + image_decoder 952 + triangle 930 ≈ 10.1 KB;工程无图片、无阴影、无变换 |
❌ 未办。⚠ 不可盲目关:mask 3,862 / mask_rect / grad 是文字与矩形绘制的必经路径 |
| F-5 | 从 uvprojx 中移除未使用的 LVGL 控件源文件(201 个 → 实际需要的子集) | 编译时长 −40% 左右 | 与 F-2 配合;lv_conf 关开关后文件仍参与编译,删文件才省编译时间 |
❌ 未办(uvprojx 现挂 323 个 .c,其中 LVGL 仍 201 个)。⚠ F-2 落地后这些 TU 现在编出来是空目标文件,删文件的收益更纯粹、风险更低 |
| F-6 | 双精度软浮点:dadd/dmul/ddiv/depilogue/dfixul(mf_w.l),来自 printf 的 %f/double 提升 |
−1 KB + 运行期性能 | 日志与 UI 全用定点;把 %f 改整数刻度 |
❌ 未办(新镜像仍链入 dadd.o) |
剩余可回收 ≈ 10–11 KB Flash(F-4 可评估部分 + F-6);F-5 省的是编译时长不是 Flash。
5.5 内存治理长效机制
已闭环(2026-10-12,登记簿 N-27 前半 / W1-0):① 超阈值即失败的
mem-budget钩子(ram_baseline.py --gate,92% 红线 + Top-10 RW+ZI 附表,无.map自适应跳过)② 趋势基线scripts/ram_baseline.tsv(--update/--trend)③../内存管理/RAM预算台账.md(子系统配额 + CCM 分配台账 + 超配额流程)。 阈值与配额的权威值现在只在那份台账里(本报告不再重复数值);mem-numbers钩子继续防"文档数字漂移"。已闭环(2026-10-11,登记簿 N-26):DMA 可达性清单与规则族——
../内存管理/内存内容分配策略.md§3「全板 DMA 使用方清点」+ §4 规则 R1~R4(含 R3 堆/栈禁为 DMA 源/目的),落地为编译期窗口断言 + 启动期自检 + 运行时守卫三层(见 §4.3)。原"独立清单文档 +_Static_assert"的建议形态已被这份更好的实现取代。
仍开放一条:
- 禁止新增 C 库
malloc:写进docs/代码规范/,并在check_coding_standard.py加正则检查(App/、Drivers/内出现malloc(即告警)。 → 🟡 前半已做、后半未做:AGENTS.md 已有铁律(含模拟器照不出来的原因);❌check_coding_standard.py未含malloc(正则 → 目前只靠人评审,属机械检查缺口。
6. UI 界面标准化实现方案
6.1 现状(框架已有,但未"闭环")
| 层 | 现状 | 评价 |
|---|---|---|
| 内容页 | ui_content_page.c 描述符表 s_defs[] 7 页(DEVICE_INFO/AC/DC/PASSWORD/NET_CFG/RUN_LOG/SELFTEST_LOG) |
❌ ui_menu_tab.h:28 42 节点(叶子 33 个),有内容页的叶子 6 个(PASSWORD 非叶子映射);menu_content_page_for()(ui_menu.c:118-128)仍是手写 case 1u/3u/4u/30u/39u/40u: |
| 设计令牌 | 无(每页自带 CP_SCREEN_W/H 160、CP_TITLE_Y 2、CP_PAGE_LINE_Y 143、CP_ROW_BUF_LEN 32 等布局常量) |
❌ 魔法数字分散在各页,Drivers/BSP/UI/ui_tokens.h 不存在(U1 未办) |
| golden 回归 | simulator/tests/ 四脚本:check_menu_rows.py(菜单 8 状态全像素)、check_content_pages.py(内容页黄金参考逐字节 + 文本断言 + LVGL 池水位门禁)、regen_ref_png.py、check_remo_sink.py |
🟡 有基线但未入门禁:两个脚本未挂 pre-commit / ui-verify |
6.2 新增一个页面要走多少步(当前)
ui_menu_tree.txt加节点 → 2. 重跑gen_menu.py→ 3. 新建ui_page_xxx.c→ 4. 在ui_content_page.c的枚举/s_defs[]注册 → 5. 在ui_menu.c:menu_content_page_for()手写case N:(下标硬编码,表序一变即错)→ 6. 注册到MDK-ARM/*.uvprojx→ 7. 注册到simulator/CMakeLists.txt→ 8. 新汉字跑font-regen。
8 步里 5 步是纯机械劳动且 2 处易错(步骤 5 的魔法下标、步骤 6/7 漏注册)。 步骤 6/7 如今有 registration-check 钩子兜底(存量走白名单),但新页面落在新目录而没把目录加进 uvprojx 的 <IncludePath> 时,报错落在消费者 TU 上(cannot open source input file),仍不等于"存在但未注册"的检查。
6.3 标准化目标:四层 + 一个闭环
graph LR
A[L0 设计令牌<br/>ui_tokens.h] --> B[L1 组件库<br/>ui_w_* 自绘控件]
B --> C[L2 页面原型<br/>list / detail / form / records]
C --> D[L3 页面实例<br/>ui_page_xxx.c 仅填数据]
D --> E[生成器 gen_page_registry.py]
E --> F[ui_page_registry.c<br/>菜单节点→页 映射]
F --> G[门禁: check_registration + golden]
L0 设计令牌(1 天,零行为变化) — 新建 Drivers/BSP/UI/ui_tokens.h:
/* 屏幕与骨架 */
#define UI_SCREEN_W 160
#define UI_SCREEN_H 160
#define UI_TITLE_Y 2
#define UI_TITLE_H 11
#define UI_PAGE_LINE_Y 143 /* 页脚分隔线 */
#define UI_ROW_PITCH 13 /* 行距(12px 字体 + 1) */
#define UI_ROW_H 12
#define UI_LIST_TOP 15
#define UI_SCROLLBAR_W 2
#define UI_PAD_X 3
#define UI_BUF_STRLEN 32 /* = CP_ROW_BUF_LEN,统一一处 */
/* 语义色(1bpp:只有黑白,但保留语义名以便换深度时平移) */
#define UI_COL_FG LV_COLOR_BLACK
#define UI_COL_BG LV_COLOR_WHITE
#define UI_COL_SEL_FG UI_COL_BG
#define UI_COL_SEL_BG UI_COL_FG
/* 样式:只用 const 描述符(动态 lv_style 会每次泄漏 88 B,见 ui_content_page.c) */
extern const lv_style_const_prop_t UI_STYLE_FLAT[];
要点:保留现有"只用 lv_style_const_prop_t 常量样式"的纪律(这是已被验证的必要约束:动态样式每个 88 B 泄漏);令牌化后所有页面自动获得统一观感,改一行即全局生效。
L1 组件库(3 天) — 把 ui_menu_view.c / ui_content_page.c 中重复的自绘逻辑抽成无状态组件(纯 lv_layer_t 绘制,不创建 LVGL 对象,保持零控件、零池压力):
| 组件 | 职责 | 从何处抽取 |
|---|---|---|
ui_w_title |
标题栏 + 分隔线 + 页码 | ui_content_page.c 通用绘制链 |
ui_w_list |
行列表 + 选中反白 + 滚动条 | ui_menu_view.c 行绘制 |
ui_w_kv |
"名称: 值" 两列(装置信息/实时数据) | ui_page_device_info.c、ui_page_ac.c |
ui_w_records |
定长记录分页浏览(含 s_cache_valid/s_last_rec 缓存范式) |
ui_page_runlog.c、ui_page_selftest.c(两文件结构几乎相同 → 直接合并) |
ui_w_form |
键值 + 光标 + 可编辑(含十进制/IP 输入约束) | ui_page_net_cfg.c |
ui_w_msgbox |
确认/错误提示("密码输入错误"等) | ui_page_password.c |
L2 页面原型(4 类,覆盖全部剩余页面):
| 原型 | 适用菜单 | 数据契约 |
|---|---|---|
detail(KV 只读) |
装置信息、交流量、直流量、遥信量 | kv_provider_t{ count(); get(i, name, val); } |
form(可编辑) |
整定/定值/控制字/软压板、遥测死区/系数、遥信类型/防抖/双点、装置维护、通讯参数、网口/SNTP | 直接绑定 cfg_file 描述符(复用配置引擎的段注册表,无需新数据结构) |
records(分页日志) |
SOE/事故/操作/保护告警/保护启动/遥控/自检/运行记录/运行报告 | record_provider_t{ count(); get(idx, ts, text); }(sys_log 已是这个形态) |
action(确认型) |
强制复归、清除记录、手动录波 | 提示 → 二次确认 → 执行 → 结果日志 |
口径:ui_menu_tab.h:28 UI_MENU_TAB_COUNT = 42(根 + 41 节点),叶子实为 33 个;已有内容页的叶子 6 个 → 待落地 27 页。四类原型的分布按 27 页重算即可。这意味着剩余页面工作量从"27 页 × 各自设计"降为"4 个原型 + 27 份数据绑定"。
L3 页面实例 — 目标形态(以"遥测死区"为例,全部新代码约 30 行):
static const ui_form_item_t s_items_deadzone[] = {
/* cfg 段/键, 显示名, 类型, 最小, 最大, 权限 */
{ "deadzone", "ia", "A 相死区", UI_T_UINT, 0, 1000, UI_PERM_MODIFY },
{ "deadzone", "ib", "B 相死区", UI_T_UINT, 0, 1000, UI_PERM_MODIFY },
{ "deadzone", "ic", "C 相死区", UI_T_UINT, 0, 1000, UI_PERM_MODIFY },
};
const ui_page_desc_t ui_page_deadzone = UI_FORM_PAGE("遥测死区", s_items_deadzone);
生成器补全(1.5 天,关键收益) — 扩展 ui_menu_tree.txt 支持页绑定注解,让 gen_menu.py 一并产出注册表,消灭步骤 4/5 的手工 switch:
遥测死区 #P @page=deadzone @arch=form
产物:ui_page_registry.c 含 node_index → (page_id, archetype, desc*) 常量表 + ui_page_registry_for(node);ui_menu.c 只需一次调用。生成器同时校验:@page 指向的描述符是否存在、是否有节点声明了页但无实例、是否有实例未被任何节点引用(编译期断言或生成期报错)。
闭环门禁(1 天)——未闭环 2 条:
- golden 回归入门禁:
simulator/tests/四脚本已建成,但未挂进 pre-commit /ui-verify。 - 字符集自动校验:构建前扫描所有
ui_*.c中的汉字,与ui_cn_chars.txt求差集,缺失即 FAIL(把font-regen从"记得跑"变成"漏跑就红")→ ❌ 未入门禁(font-regenskill 已把四步固化并写进 AGENTS.md,但仍是约定不是门禁)。
6.4 UI 侧的内存纪律(必须写进规范)
| 规则 | 依据 |
|---|---|
页面不得新增静态大缓冲;文本缓冲统一用 UI_BUF_STRLEN |
现有 s_ts/s_desc 已是范式 |
每页只用 lv_style_const_prop_t,禁止运行期 lv_style_init |
已验证动态样式每次泄漏 88 B |
优先自绘(lv_draw_* + lv_text_get_width),新控件需评审(会破坏 §5.4 F-2 已落地的裁剪,且须两端同步) |
LVGL 现占镜像 38.0%(87,706 / 231,036 B) |
| 帧缓冲任何改动必须遵守 R-4(副本数 ≤ 2) | 当前 4 副本 12.8 KB |
LVGL 池用量必须经 lv_mem_monitor / 池水位门禁实测后才允许扩大 |
16 KB(R-9 于 2026-10-15 由 40 KB 降下;实测峰值 6,568 B = 池的 40%,余 ≈9.8 KB) |
6.5 实施顺序(UI 专项,总计约 8 人日)
| 步骤 | 内容 | 交付判据 | 状态 |
|---|---|---|---|
| U1 | ui_tokens.h 令牌化(纯替换,不改行为) |
@build PASS + 模拟器截图与替换前逐像素一致 |
❌ 未办。🟡 验收条件如今可机械执行——golden 基线已建,"逐像素一致"从口头判据变成可跑断言 |
| U2 | ui_w_records(合并 runlog/selftest) |
两页行为不变,代码 −1 个文件 | ❌ 未办(两份结构几乎相同的代码仍在) |
| U3 | ui_w_form + ui_page_desc_t 原型化 + 生成器产注册表 |
手工 menu_content_page_for() 删除;新增一页只需"改树 + 加实例文件" |
❌ 未办(ui_page_registry.c / gen_page_registry.py 均不存在) |
| U4 | golden + 字符集检查 + 注册检查入 pre-commit | 三个新 hook 全绿 | 🟡 1/3 落地:golden 已建;❌ 字符集差集、❌ 注册检查未入门禁(注册检查钩子已存在,缺的是把它算作 UI 门禁的一环) |
| U5 | 用原型批量落剩余 27 页(每页 ≤30 行) | 菜单树全绿、无 CONTENT_PAGE_COUNT 哨兵命中 |
❌ 未动 |
本轮不排期(2026-10-11 已确认,登记簿 U 簇 / W6):等功能主线出结果后按产品需求启动;U4 残余(两脚本入门禁)可逢窗口顺带。
7. 统一改进路线图
顺序的唯一权威 =
../任务规划/README.md§2(W1 采集保护收尾 → W2 数据正确性 → W3 预算与内存 → W4 结构债 → W5 验证常态 → W6 UI 扩展 → W7 仓库决策;B2 RS-485 暂缓)。本节只保留"本报告条目 → 波次"的映射,不另立顺序。
| 波次 | 本报告条目 | 验收要点 |
|---|---|---|
| W2 数据正确性 | N-12 / N-13(登记簿 N-21) | 整页扫描 + DHARA_E_UNSUPPORTED + 主机侧 dhara 移植层单测(一并补覆盖率缺口) |
| W3 预算与内存 | R-9 → R-2 后半 → R-3/R-4/R-6 逐项评估 | 按 ../内存管理/RAM预算台账.md §3 解锁链走,每步前后跑 stack_report.py / ram_report.py |
| W4 结构债 | N-16、N-14、F-4/F-5/F-6、S-1/S-2/S-4/S-5;rs485_task.c 随 B2 出注册白名单 |
--strict 默认化;bsp_err_t 进规范 |
| W5 验证常态 | P1-10 收尾(构建实测链接 + @test 闭环) |
逢窗口顺手做 |
| W6 UI 扩展 | U4 残余 → U1 → U2/U3 → U5(27 页) | 新增一页 ≤30 行;本轮不排期 |
| W7 仓库决策 | D-1(登记簿 N-29) | 已决策暂不处理;推送/协作前重评 |
交付物清单(可直接排期)
| 交付物 | 类型 | 来源条目 | 状态 |
|---|---|---|---|
test/host/dhara/(移植层单测) |
主机侧单测 + pre-commit hook | N-12/N-13 | ❌ 未建——这是唯一能防住"同类缺陷再犯"的手段 |
Drivers/BSP/UI/ui_tokens.h |
令牌层 | U1 | ❌ 未建 |
Drivers/BSP/UI/ui_w_{list,kv,records,form,msgbox,title}.{c,h} |
组件库(需双端注册) | U2/U3 | ❌ 未建 |
tools/menu_gen/gen_menu.py 扩展 + ui_page_registry.c 生成 |
生成器 | U3 | ❌ 未建 |
check_coding_standard.py 加 malloc( 正则 |
门禁补强 | §5.5 第 5 条 | ❌ 未建 |
| 字符集差集检查 + golden 挂 pre-commit | 门禁补强 | U4 残余 | ❌ 未建 |
附录 A 关键证据索引
| 结论 | 证据(2026-10-14) |
|---|---|
| SRAM1 74.9%、余 32,928 B;CCM 87.9%、余 7,904 B | map Execution Region RW_IRAM1 Size: 0x00017f60, Max: 0x00020000 / RW_CCM Size: 0x0000e020, Max: 0x0000ff00;ram_baseline.tsv 末行 |
| MicroLIB C 堆 = 512 B | MDK-ARM/startup_stm32f407xx.s Heap_Size EQU 0x200;map Removing startup_stm32f407xx.o(HEAP), (512 bytes)(未被引用 → 整段移除) |
| 任务栈全部动态分配 | Src/freertos.c 的 osThreadAttr_t 无 .stack_mem;8 条产品任务栈合计 9,792 words(R-6 未办) |
| DMA 可达性三层防线(原 N-11 的处置) | 编译期窗口断言 gd5f2gq5ue.h:96-107(负数组 typedef)→ 启动期自检 nand_ftl.c:241-243 → 运行时守卫 gd5f_dma_buf_ok()(gd5f2gq5ue.c:121-139);规则族 R1~R4 → ../内存管理/内存内容分配策略.md §4;负路径用例 TC-GD5F-704/705 |
| CH395F memcpy 自有缓冲 | ch395f.c SPI2 DMA 收发缓冲(s_spi2_dma_tx/rx[2052])→ UI 缓冲仍可迁 CCM 的前提成立 |
| dhara 两处缺陷 | nand_ftl.c:152-179(uint8_t buf[64])/ :204-216(read→prog 直传,无哨兵判断) |
| 日志逐条开关 | sys_log_mcu.c:124-141(`FA_WRITE |
| 端口分配 | App/sync/time_sync.c TIME_SYNC_PORT 8888;Drivers/BSP/UI/ui_net_sink.h UI_NET_SINK_PORT 7003;FTP 21 |
| 菜单 42 节点 / 33 叶子 / 6 个有内容页 | ui_menu_tab.h:28 UI_MENU_TAB_COUNT 42;ui_content_page.c:84-92 s_defs[](7 页含 PASSWORD) |
| 手写映射 | ui_menu.c:118-128 menu_content_page_for()(case 1u/3u/4u/30u/39u/40u:) |
| 注册反向校验已机械化,仅剩一条刻意缺口 | scripts/check_registration.py(KNOWN_GAPS 只含 App/task/rs485_task.c,E-59/B2 刻意未接线)+ pre-commit registration-check;lftpd_log.c 已删除并入 lftpd_auth.c |
| 仓库体量 | 受控 2,466 文件 / 79.3 MB;docs/ 56.9 MB;docs/芯片手册/ 图片 703 张 / 36.3 MB;.git 235.3 MB |
附录 C 评审中确认"无需改动"的设计(避免后续误改)
| 项 | 结论 |
|---|---|
| CH395F SPI 分频 = 8 | PCB 约束,禁止"优化"(AGENTS 铁律,实测一致) |
| 就绪屏障用 Event Flags 而非魔法延时 | 正确,保留(就绪位必须 osFlagsNoClear) |
FatFs FF_FS_REENTRANT=1 + 真实互斥 |
正确,保留(多数移植偷工) |
| 配置引擎属主 = defaultTask | 正确,任何新代码不得跨任务触碰 |
UI 只用 lv_style_const_prop_t |
正确且必要,禁止"顺手改成动态样式" |
ffsystem.c 引用 sys_clock.h |
有意为之(中间件需要真实时间),保留但在分层图中显式标注 |
| UI 自绘而非 LVGL 控件 | 正确(1 bpp + 小 RAM),并是 Flash 裁剪的前提 |
configMAX_PRIORITIES = 56 |
不可下调:CMSIS-RTOS2 freertos_os2.h 硬性 #error 要求等于 56(原 R-5 建议因此关闭) |
两份 lv_conf.h 同一特性子集 |
必要(F-1/F-2/F-3 的前提),由 lv-conf-sync 钩子守 |
报告结束。
本报告按
../README.md的定位是体系层评审报告,不是待办池——待办与顺序一律以../任务规划/README.md为准;本报告只保留未闭环问题的发现 + 证据,修复即销项。
变更记录
| 日期 | 类型 | 说明 |
|---|---|---|
| 2026-09-18 | 初版 | 全量审查;基线 HEAD = 2d0ec35、.map 链接于 2026-09-16;产出 N-01..N-18 / D-1..D-7 / S-1..S-5 / R-1..R-9 / F-1..F-6 / U1..U5 编号体系 |
| 2026-10-11 | 实施 + 销项:F-1/F-2/F-3 | 两份 lv_conf.h 对齐同一特性子集 → 省 64,576 B;验证链(@build / ui-verify / @test)与对象级对照见 ../内存管理/RAM使用分析与优化方案.md §2.6.4 |
| 2026-10-15 | 登记簿同步销项 | 本报告的 N-03c / N-11 对应登记簿 N-20 / N-26 两行已按「完成即销项」从 ../任务规划/登记簿.md §5 删除(并清 ../任务规划/README.md §1/§2 与 排期详述.md §1 的引用,W4 链由 6 项减为 5 项、结构/健壮性计数 9→7)。删除前补齐去处记录:../子系统设计/看门狗设计说明.md §4.4 新增 Error_Handler 统一降级一节、../内存管理/内存内容分配策略.md §4 R2 补编译期窗口断言与启动期自检两层 + §8 落点索引两行。同批订正登记簿三处过时内容:N-23 残余去掉已删除的 lftpd_log.c、N-25 去掉已删除的 NET_RECV_TIMEOUT_MS、N-27 剔除不可行的 R-5 并把 CCM 余量改为实测 7,904 B、N-29 的 .git 由 149 MB 订正为实测 235.3 MB |
| 2026-10-15 | 执行本报告条目:R-9 落地并销项 | LV_MEM_SIZE 40→16 KB(Lib/lv_conf.h + simulator/lv_conf.h 同步,lv-conf-sync 生效值比对 PASS)。依据:池水位门禁实测菜单基线 5,368 B / 开页-关页往返 5,448 B / 最重页面峰值 6,568 B。验证:@build 0 错 0 警,ZI 精确 −24,576 B → SRAM1 98,144/74.9% → 73,568/56.1%(余 57,504 B),CCM 不变;PC 侧 11 页黄金参考逐字节 10/11 一致、往返池水位 5,448 B 未变(唯一差异 netcfg_save 经 40 KB A/B 复测确认与本次改动无关)。连带改写:§0.2 Top3 第 2 条、§0.3 主线一、§0.4 内存两行、§5.1 基线表(追 2026-10-15 .map)、§5.2 诊断 1(瓶颈由 SRAM1 换到 CCM)、§5.3(R-9 行删除、R-2 收益改 −29,570 B)、§6.4 池容量行;同步 ../内存管理/RAM使用分析与优化方案.md、../内存管理/RAM预算台账.md §3、../UI设计/UI_设计架构.md、../UI设计/UI_界面制作流程.md、../UI设计/LVGL模拟器部署与使用说明.md、simulator/README.md、../产品需求/产品需求设计文档.md。真机复跑 ✅:@test PASS(fw build: Oct 15 2026 07:31:34,无 [ERR]/Fault,开机 622 ms 到 net init: OK),menu build done: used=3192 = 建池后 15,020 B 的 21%。台账受管区与内存快照区已 --write 回填 → mem-budget / mem-numbers 两钩子转绿 |
| 2026-10-14 | 清理:删除已完成与过时内容 | ① 已修复项按销项删除(去处见下表):N-02(FTP 鉴权)、N-03c(Error_Handler 降级)、N-11(DMA 可达性三层防线 + 规则族 R1~R4)、S-3(注册反向校验)、P2-5/P2-6(SD2506 负温度与 WRTC)、P2-8(NET_RECV_TIMEOUT_MS 已删)、P2-9(mkdir 幂等重试)、§5.5 前三条(内存治理三件套)、交付物清单已建项。② 删除过时层:2026-09-16 / 2026-10-11 双列基线表与"复核期间未提交改动"口径说明、旧"组合结果预估"表、逐条"2026-10-11 复核"批注、历史变更记录行——内存数字改由 ../内存管理/RAM预算台账.md 与 scripts/ram_baseline.tsv 持有。③ 按 2026-10-14 .map 与代码重测全部保留结论的数字(含 lftpd_log.c 已删除并入 lftpd_auth.c,N-06 残余只剩 rs485_task.c 一条刻意缺口)。④ 修正三处错误:R-5(configMAX_PRIORITIES 56→32)判定不可行(CMSIS-RTOS2 #error);原 §7 把报告 S-5(驱动统一错误码)与登记簿 S-5(卷锁覆盖面)混为一谈;原 §5.5 第 4 条建议的 _Static_assert 形态在 AC5 上取不到链接期地址,已被"窗口断言 + 启动自检 + 运行时守卫"三层取代。⑤ 报告自有编号不回改、不重排(../编号规范.md) |
已销项条目的记录去处
删除前已逐条核对:以下去处文档/代码均含完整记录,删了不丢信息。
| 已销项条目 | 去处 |
|---|---|
| N-01(配置引擎 C 堆必失败) | ../子系统设计/配置文件设计说明.md §6.2 / §8 |
| N-02(FTP 无鉴权,登记簿 N-19) | ../子系统设计/网络配置说明.md §3.4([ftp] user/pwd_hash/write、恒定时间比较、5 败锁 60 s、出厂默认口令告警、明文嗅探边界)+ ../产品需求/产品需求设计文档.md §FTP 鉴权 + Drivers/BSP/NET/lftpd/lftpd_auth.c + 主机侧 test/host/sha256/、test/host/ftp_auth/ |
N-03a/N-03b/N-07/N-08(IWDG、configASSERT、两个钩子、4 个 Fault 现场) |
../子系统设计/看门狗设计说明.md(§4.4、§10.1/§10.2)+ AGENTS.md「平台约束」 |
N-03c(Error_Handler 死循环,登记簿 N-20,2026-10-15 已销项) |
../子系统设计/看门狗设计说明.md §4.4(统一降级:1 条自检 + NVIC_SystemReset()、三条实现约束含 __builtin_return_address 不可用的实证、内核前日志路径安全性、重生成存活三层)+ 实施代码 Src/main.c 的 USER CODE Error_Handler_Debug 区注释 + scripts/check_cubemx_survival.py 审计项 |
N-06 主体(crc.c/ringbuf.c/lftpd_log.c 删除、adc_task.c 注册)+ S-3(注册反向校验,登记簿 N-23) |
scripts/check_registration.py(KNOWN_GAPS 白名单 + --strict)+ ../代码规范/pre-commit使用说明.md(registration-check);lftpd_log.c 并入 Drivers/BSP/NET/lftpd/lftpd_auth.c |
| N-11(NAND 直 DMA 调用方缓冲 / CCM 迁移硬边界,登记簿 N-26,2026-10-15 已销项) | ../内存管理/内存内容分配策略.md §3(全板 DMA 使用方清点)+ §4 规则 R1~R4(R3 堆/栈禁为 DMA 源/目的,含"缓冲自身地址无法编译期断言"这条边界)+ §8 落点索引;代码三层 = gd5f2gq5ue.h:96-107 编译期窗口断言 → nand_ftl.c:241-243 启动期自检 → gd5f_dma_buf_ok() 运行时强制;负路径用例 TC-GD5F-704/705 |
| N-10(UI accept 门控) | ../UI设计/RemoDispBus协议与接收设计说明.md §3 + 看门狗设计说明 §11.4 |
| N-17(栈/堆水位观测)+ R-8(观测常开) | ../内存管理/RAM使用分析与优化方案.md + ../测试说明/实机测试实施指南.md([STACK] 水位 + stack_report.py + ram_report.py) |
| N-18(本报告口径:无 CI) | ../测试说明/测试开发标准流程.md §9 + ../CI/README.md |
| P2-5 / P2-6(SD2506 负温度解析、WRTC 解锁顺序) | Drivers/BSP/SD2506/sd2506.c(符号扩展 val | 0xF0;WRTC1→WRTC2/3 顺序按手册,上电即写禁止态) |
P2-8(net_recv 30 s 阻塞超时) |
Drivers/BSP/NET/net_config.h 头注(2026-10-13 recv 语义主流化:删除 NET_RECV_TIMEOUT_MS,预算由调用方显式给)+ ../网络/Net层阻塞模型架构设计.md |
P2-9(mkdir 失败不再重试) |
App/log/sys_log_mcu.c(s_fs_ready 幂等 + mkdir /log fail (%d), will retry + 上报自检) |
| P2-13 / P2-14 / P2-15 | AGENTS.md(test-suite-switch、keil-build、stlink-flash)+ ../测试说明/ST-LINK_CLI_复位使用说明.md |
| D-2 / D-3 / D-4 / D-5 / D-6 / D-7 | ../文档规范.md + ../代码规范/pre-commit使用说明.md;断链由 scripts/check_doc_links.py 门禁接管 |
| U4 主体(golden 回归) | simulator/tests/ 四脚本 + ../UI设计/UI_自动化测试流程.md(残余 = 挂门禁,见 §6.3) |
| R-1 / R-7 | ../子系统设计/看门狗设计说明.md + AGENTS.md 任务表(scripts/gen_task_table.py 生成区) |
| §5.5 前三条(92% 门禁 / 趋势基线 / 预算台账,登记簿 N-27 前半) | ../内存管理/RAM预算台账.md(阈值与配额的唯一权威)+ scripts/ram_baseline.py(--gate/--update/--trend/--write)+ ../代码规范/pre-commit使用说明.md(mem-budget) |
| F-1 / F-2 / F-3(LVGL 死代码裁剪) | ../内存管理/RAM使用分析与优化方案.md §2.6.4;../UI设计/UI_设计架构.md §1.4 第 10 条(两份 lv_conf.h 必须同一特性子集);../UI设计/UI_自动化测试流程.md 变更记录(池水位基线) |
R-9(LV_MEM_SIZE 40→16 KB,登记簿 N-27 的 W3 第一步,2026-10-15 已执行) |
取值依据与再降 8 KB 的前置写在 Lib/lv_conf.h 与 simulator/lv_conf.h 的池注释;实测水位 → ../内存管理/RAM使用分析与优化方案.md §2.6.2 与 §阶段 1.1(已执行);解锁链第 ① 步 ✅ → ../内存管理/RAM预算台账.md §3;池容量口径 → ../UI设计/UI_设计架构.md §1.2、../UI设计/UI_界面制作流程.md C4 |