From f4b9bd57d5f003943f4fbbf3498858b252da3a36 Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Thu, 22 Oct 2026 12:09:54 +0800 Subject: [PATCH] =?UTF-8?q?docs(=E9=83=A8=E7=BD=B2):=20=E5=88=A0=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=A0=88=E5=89=AF=E6=9C=AC=E8=A1=A8=E6=94=B9=E6=8C=87?= =?UTF-8?q?=E9=92=88=EF=BC=9B=E7=BA=A0=20CCM/FPU=20=E4=BA=8B=E5=AE=9E?= =?UTF-8?q?=E5=B9=B6=E5=88=B7=E6=96=B0=E9=85=8D=E5=9B=BE=E5=9F=BA=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 范围:AGENTS.md 一处指针、部署环境要求 §2.2/§3.1/§3.3、RAM 方案 6 处现状 数字、内存配图生成器 + 3 张 SVG、两份报告脚本的行尾与路径修正、新增两份 .map/.htm 数据快照。未改任何 .c/.h(仍跑 @build 复核:0 错误 0 警告)。 部署环境要求.md - §3.3 删"任务栈预算"副本表、改为指针:该表已缺 adcTask/iec104Task/ protectTask,defaultTask/timeSyncTask 两值停在旧数,注释却写"由 gen_task_table.py 同源"——该钩子的校验面只有 README.md / AGENTS.md 两处受管块,抄出来的副本没有门禁、改栈后必漂。指针指向 Src/freertos.c + 两份受管表 + RAM 方案 §2.3/§0.6,并留一条"别再抄"的成因说明。 - §2.2 链接布局补 `RW_CCM 0x10000000`(scatter 给 0x0000FF00 = 65,280 B, 2026-10-11 起承载 FreeRTOS 堆;另有 256 B UNINIT_CCM 尾区),写明 CCM 不可 DMA。原文"SRAM3/CCM 故意未映射"与 STM32F407-Demo.sct 直接矛盾。 - §3.1 MCU 行更正为**单精度 FPU(VFPv4-SP,无硬件双精度)、无 TrustZone** (原写"双精度 FPU / TrustZone"是芯片事实错误,也正是报告 F-6 双精度软 浮点被长期误判的土壤);SRAM 行改为"两块都在用,仅 SRAM3 未映射"。 - §3.3 资源预算表补 CCM 行,并把"主 SRAM 125,104 B / 95.4% / 极度紧张" 更正为 75,264 B / 57.4%(余 55,808 B);红线改标在 CCM(余 7,904 B)。 - 变更记录补 2026-10-22 行(含上一提交里的资源表刷新那一笔)。 AGENTS.md:任务表注里 "RAM使用分析与优化方案.md §1.4" 是**指错小节**——§1.4 确实 存在(该文档 §4「方案」下的阶段 1 子项,讲 lftpd 大局部缓冲静态化),但栈余量 台账在 §2.3(任务栈配置与实测峰值)与 §0.6(静态最坏链与判定),故改指这两处 再加 内存内容分配策略.md §6。根因是该文档里 §1(背景)与 §4 下的 1.1~1.5 同号 撞面,人和 doc-links(自引用放过)都会看错——本会话我上一轮就被它带错过一次。 配图与数据(draw-diagram 流程:改生成器顶部数据 → 重跑 → 逐文本核越界) - 新增 data/ram_report_20261022.md、data/stack_report_20261022.md;后者 运行时水位取自 2026-10-22 真机 [STACK] 心跳(8 任务高水位 + heap free=15,800 / min_ever=8,464),静态侧来自同日 .htm(全局最深链 3,024 B)。 - gen_memory_svg.py:三组图数据从 2026-09-21 / 10-10 快照换成 2026-10-22 实测;任务栈 6 → 9 行,堆总量 48KB → 56KB,判定 6/6 → 9/9 PASS,新增 AboveNormal 配色;Flash 子条改为"窄段不压字 + 下方四列图例";任务栈 画布 440 → 620 高。CCM 段总量按 scatter 用 65,280 B(与台账同口径)。 - 三张 SVG 重生成;用"CJK≈1.0em / 其余≈0.58em + 锚点"逐文本估算边界, 修掉 5 处文字越界/压字(生成器内置 ElementTree 自检亦通过)。 - ram_report.py / stack_report.py 两处工具性修正:write_text 未指定 newline 参数 → Windows 下把 data/ 快照写成 CRLF(与 .gitattributes 及既有快照 不符);stack_report 的 relative_to 在传相对 -i 时抛 ValueError,且会把 本机绝对路径写进入库快照 → 统一走 resolve+relative_to 的相对路径回退。 RAM 方案:6 处"当前状态"随 .map/[STACK] 更正——RW_IRAM1 89,168 → 75,264、 RW_CCM 49,184 → 57,376、FreeRTOS 堆 48KB → 56KB(两处)、CCM 余量 ~16KB → 7,904 B、min_ever 4,848 → 8,464 B、6 任务全过 → 9/9 PASS;S-1 历史句保留。 门禁:pre-commit 对全部改动文件 Passed(doc-links --sections-strict、 task-table、mem-numbers、mem-budget、id-check 增量拦截);字节卫生自查 BOM / CR / U+FFFD / 行尾空格全清。已提交本地,未推送。 --- AGENTS.md | 2 +- docs/images/任务栈预算.svg | 85 ++++--- docs/images/内存布局_FLASH.svg | 71 +++--- docs/images/内存布局_RAM.svg | 71 +++--- docs/内存管理/RAM使用分析与优化方案.md | 12 +- docs/内存管理/data/ram_report_20261022.md | 245 ++++++++++++++++++++ docs/内存管理/data/stack_report_20261022.md | 100 ++++++++ docs/环境与部署/项目部署环境要求.md | 39 ++-- scripts/ram_report.py | 4 +- scripts/stack_report.py | 15 +- tools/arch_diagram/gen_memory_svg.py | 153 +++++++----- 11 files changed, 606 insertions(+), 191 deletions(-) create mode 100644 docs/内存管理/data/ram_report_20261022.md create mode 100644 docs/内存管理/data/stack_report_20261022.md diff --git a/AGENTS.md b/AGENTS.md index a2963b12..6e9146b2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -63,7 +63,7 @@ | protectTask | 512 | Normal | -(实际值以 `Src/freertos.c` 为准,本表由 `scripts/gen_task_table.py` 生成、`task-table` 钩子校验;testTask 仅在启用测试套件时创建。FreeRTOS 堆已迁 CCM,任务栈不占 SRAM;**每次抬栈的实测最坏链与余量台账** → `docs/内存管理/RAM使用分析与优化方案.md` §1.4 与 `docs/内存管理/内存内容分配策略.md` §6) +(实际值以 `Src/freertos.c` 为准,本表由 `scripts/gen_task_table.py` 生成、`task-table` 钩子校验;testTask 仅在启用测试套件时创建。FreeRTOS 堆已迁 CCM,任务栈不占 SRAM;**每次抬栈的实测最坏链与余量台账** → `docs/内存管理/RAM使用分析与优化方案.md` §2.3(任务栈配置与实测峰值)与 §0.6(静态最坏链与判定)、`docs/内存管理/内存内容分配策略.md` §6(容量台账)) ## 铁律:源码编辑与编码 diff --git a/docs/images/任务栈预算.svg b/docs/images/任务栈预算.svg index 1dee4bb5..023bfc38 100644 --- a/docs/images/任务栈预算.svg +++ b/docs/images/任务栈预算.svg @@ -1,4 +1,4 @@ - + -FreeRTOS 任务栈预算(48KB 堆,2026-09-21 已迁 CCM) -数据: 2026-10-10 @build + 开机/空闲实测(data/stack_report_20261010.md);最坏 = max(静态最坏链, 实测峰值) +FreeRTOS 任务栈预算(9 任务;栈全部从 56KB FreeRTOS 堆分配,堆位于 CCM) +数据: 2026-10-22 @build + 同日真机 [STACK] 水位(data/stack_report_20261022.md);最坏 = max(静态最坏链, 实测峰值);判定线 = 余量 ≥ max(1024B ISR, 配置×30%) 浅色条 = 分配栈 深色条 = 最坏占用(max(静态最坏, 实测峰值)) 下方文字 = 实测余量/判定 defaultTask - - - 配置 4096B | 实测峰值 2152B | 最坏 2776B | 余量 1320B (32%) PASS + + + 配置 5120B | 实测峰值 2164B | 最坏 3024B | 余量 2096B (40%) PASS netTask - - 配置 3840B | 实测峰值 920B | 最坏 1872B | 余量 1968B (51%) PASS + + 配置 3840B | 实测峰值 1116B | 最坏 1912B | 余量 1928B (50%) PASS ftpTask - - 配置 4096B | 实测峰值 740B | 最坏 1216B | 余量 2880B (70%) PASS - testTask - - - 配置 8192B | 实测峰值 496B | 最坏 496B | 余量 7696B (93%) PASS - uiTask - - - 配置 16384B | 实测峰值 4016B | 最坏 4016B | 余量 12368B (75%) PASS + + 配置 4096B | 实测峰值 756B | 最坏 1456B | 余量 2640B (64%) PASS + uiTask + + + 配置 16384B | 实测峰值 4052B | 最坏 4052B | 余量 12332B (75%) PASS + testTask + + + 配置 8192B | 实测峰值 736B | 最坏 736B | 余量 7456B (91%) PASS timeSyncTask - - - 配置 2048B | 实测峰值 616B | 最坏 1024B | 余量 1024B (50%) PASS - idle - - 512B(未实测) - timer - - 1024B(未实测) -堆总量: 49152B (48KB, RW_CCM) 任务栈合计: 38656B (37.8KB) + 内核栈 1536B -实测: free=8784B / min_ever=4848B(2026-09-21,含 FTP 负载) 判定: 6/6 PASS(余量 ≥ max(1024B, 配置×30%)) - - Normal 优先级 - - BelowNormal 优先级 - - 内核任务栈 (idle/timer) + + + 配置 2560B | 实测峰值 616B | 最坏 1264B | 余量 1296B (50%) PASS + adcTask + + + 配置 2560B | 实测峰值 952B | 最坏 1320B | 余量 1240B (48%) PASS + iec104Task + + + 配置 2560B | 实测峰值 544B | 最坏 1456B | 余量 1104B (43%) PASS + protectTask + + + 配置 2048B | 实测峰值 828B | 最坏 872B | 余量 1176B (57%) PASS + idle + + 512B(未实测) + timer + + 1024B(未实测) +堆总量: 57344B(configTOTAL_HEAP_SIZE=56KB,位于 RW_CCM) 任务栈合计: 47360B(含 testTask 8192B) +产品构建 8 任务栈 = 39168B + 内核栈 1536B 实测: free=15800B / min_ever=8464B(2026-10-22) +判定: 9/9 PASS(testTask 无实测,取静态最坏链) + + Normal 优先级 + + BelowNormal 优先级 + + AboveNormal 优先级(adcTask) + + 内核栈 idle/timer diff --git a/docs/images/内存布局_FLASH.svg b/docs/images/内存布局_FLASH.svg index 07e91eb9..91b2ac34 100644 --- a/docs/images/内存布局_FLASH.svg +++ b/docs/images/内存布局_FLASH.svg @@ -7,32 +7,47 @@ .bar-seg { stroke:#fff; stroke-width:0.5; } -Flash (1MB) 使用布局 — 2026-09-21 @build - - 代码段 (Code) 229.5KB - - 只读数据 (RO) 13.5KB - - Flash 空闲 780.4KB -已用: 243.6KB (23.8%) 空闲: 780.4KB (76.2%) 总量: 1024KB -代码段明细 (229.5KB) - - LVGL 库 95.7KB - - 应用代码/UI 33.3KB - - FatFS 8.0KB - - dhara / FTL 4.9KB - - HAL 驱动 - 15.6KB - - FreeRTOS 内核 9.9KB - - CH395F 网络 2.7KB - - C 库 (microlib) 4.1KB - - 其他 (长尾) 55.3KB +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.3KB (22.1%) 总量: 1MB (= ROM 合计口径) +Code + RO 分布(ER_IROM1 226.3KB,按 .map 对象归类) + + 85.7KB + + 55.7KB + + 25.1KB + + 17.5KB + + + + + + + + LVGL 库 85.7KB + + 应用代码/UI 55.7KB + + CH395F+FTP 25.1KB + + HAL 驱动 17.5KB + + dhara / FTL 10.7KB + + FreeRTOS 内核 10.5KB + + FatFS 8.3KB + + C 库 (microlib) 5.4KB + + startup 0.5KB + + 其他 (长尾) 7.3KB diff --git a/docs/images/内存布局_RAM.svg b/docs/images/内存布局_RAM.svg index a6a98cb3..ee20aeab 100644 --- a/docs/images/内存布局_RAM.svg +++ b/docs/images/内存布局_RAM.svg @@ -7,50 +7,51 @@ .bar-seg { stroke:#fff; stroke-width:0.5; } -SRAM (192KB) 使用布局 — 2026-09-21 @build +SRAM (192KB) 使用布局 — 2026-10-22 @build 主 SRAM RW_IRAM1 @0x20000000(128KB,DMA 可达) - - LVGL - - UI - - - - - - - - - free -已用: 82048B (62.6%) 空闲: 49024B (37.4%) 总量: 128KB -CCM RW_CCM @0x10000000(64KB,仅 CPU 可达,DMA 不可达) - - heap - - free -已用: 49184B (75.0%) 空闲: 16352B (25.0%) 总量: 64KB + + LVGL 池 16KB + + UI + + lftpd + + + + + + other + + free +已用: 75264B (57.4%) 空闲: 55808B (42.6%) 总量: 128KB +CCM RW_CCM @0x10000000(段 65,280 B;仅 CPU 可达、DMA 不可达 → R2/R3) + + FreeRTOS 堆 + + free +已用: 57376B (87.9%) 空闲: 7904B (12.1%) 总量: 63.75KB(+256 B UNINIT_CCM 尾区)——CCM 是当前全局卡点 - 主SRAM LVGL: 40.5KB (31.6%) + 主SRAM LVGL 池 16KB: 16.5KB (12.9%) 主SRAM UI: 13.2KB (10.3%) - - 主SRAM FTL/BBT: 8.6KB (6.7%) - - 主SRAM lftpd: 5.2KB (4.1%) - - 主SRAM CMSIS: 4.9KB (3.8%) - - 主SRAM NET: 4.3KB (3.4%) + + 主SRAM lftpd: 8.2KB (6.4%) + + 主SRAM FTL/BBT: 6.9KB (5.4%) + + 主SRAM NET/CH395F: 5.1KB (4.0%) + + 主SRAM CMSIS-RTOS: 1.7KB (1.3%) - 主SRAM HAL: 1.2KB (1.0%) + 主SRAM HAL: 0.1KB (0.1%) 主SRAM C stack: 1.0KB (0.8%) - 主SRAM other: 1.1KB (0.9%) + 主SRAM other: 20.8KB (16.2%) - 主SRAM free: 47.9KB (37.4%) + 主SRAM free: 54.5KB (42.6%) - CCM heap: 48.0KB (75.0%) + CCM FreeRTOS 堆: 56.0KB (87.9%) - CCM free: 16.0KB (25.0%) + CCM free: 7.7KB (12.1%) diff --git a/docs/内存管理/RAM使用分析与优化方案.md b/docs/内存管理/RAM使用分析与优化方案.md index a03776be..0e7bc568 100644 --- a/docs/内存管理/RAM使用分析与优化方案.md +++ b/docs/内存管理/RAM使用分析与优化方案.md @@ -18,7 +18,7 @@ - F407 另有 **64KB CCM RAM**:**已于 2026-09-21 启用**并把 FreeRTOS 堆迁入(§1.2) - 起步时没有任何运行时测量手段:不知道每个任务实际用了多少栈,改栈全靠拍脑袋 -当前状态(**以 §2.1 受管快照为准**,由 `.map` 自动生成):RW_IRAM1 **89,168 / 131,072 B(68.0%)**、RW_CCM **49,184 / 65,280 B(75.3%)**。✅ **任务栈:2026-10-10 削链后 `defaultTask` 实测峰值 2152B/4096(余 47%)、静态最坏链 2776B(余 32%)**,6 任务全过 `stack_report.py` 判据(曾于 2026-10-04 升至 3664B/4096 ≈ 10%,登记为 S-1,现已销项),详见 §2.3 与"2026-10-10 复测"小节。 +当前状态(**以 §2.1 受管快照为准**,由 `.map` 自动生成;2026-10-22 `@build`):RW_IRAM1 **75,264 / 131,072 B(57.4%)**、RW_CCM **57,376 / 65,280 B(87.9%)**。✅ **任务栈:`stack_report.py` 9/9 PASS**(2026-10-22 静态最坏链 + 同日真机 `[STACK]` 水位,`defaultTask` 最坏 3024B/5120(余 40%)、`protectTask` 872B/2048(余 57%),见 `data/stack_report_20261022.md`);**卡点已从 SRAM1 移到 CCM**(余 7,904 B)。历史:`defaultTask` 曾于 2026-10-04 达 3664B/4096 ≈10%,登记为 S-1,2026-10-10 削链后销项(详见"2026-10-10 复测"小节)。 本方案三个目标: @@ -121,7 +121,7 @@ | idle(内核) | `configMINIMAL_STACK_SIZE=128` | 0.5KB | 空闲 | 未观测(未取句柄) | | timer(内核) | `configTIMER_TASK_STACK_DEPTH=256` | 1KB | 软定时器 | 未观测 | -> 任务栈全部从 FreeRTOS 堆(48KB,2026-09-21 已迁 CCM)分配。**"配置栈"列以 `Src/freertos.c` 为唯一来源;实测峰值/余量判定以 §0.6 的 `stack_report` 基线为准**(本表数值同步自该基线)。 +> 任务栈全部从 FreeRTOS 堆(56KB = `configTOTAL_HEAP_SIZE` 57,344 B;2026-09-21 迁 CCM、2026-10-12 扩容)分配。**"配置栈"列以 `Src/freertos.c` 为唯一来源;实测峰值/余量判定以 §0.6 的 `stack_report` 基线为准**(本表数值同步自该基线)。 ### 2.4 动态分配点与隐患 @@ -135,12 +135,12 @@ |---|---|---| | ① LVGL 内存池 40KB 对 1bpp 小屏菜单过大 | 40KB → **16KB ✅ 2026-10-15** | 高(目标 8~16KB;**开机实测 UI 仅用 ~3KB**,见 §2.6.2) | | ② 任务栈"往大了给",无实测依据 | 38,912 B(38 KB 现值,§2.6.1) | 高(§0.6 已有实测:uiTask 3.8/16KB、netTask 0.6/4KB → 阶段 1.3 缩减) | -| ③ 64KB CCM 曾完全未利用,缓冲挤在主 SRAM | — | ✅ 2026-09-21 已启用(堆迁入 CCM),CCM 余量 ~16KB | +| ③ 64KB CCM 曾完全未利用,缓冲挤在主 SRAM | — | ✅ 2026-09-21 已启用(堆迁入 CCM);2026-10-22 CCM 余量 7,904 B(**全局卡点**)| 量化补充(来源:2026-09-11 审计快照,口径与方法见 §8.4): -- 两池(FreeRTOS 48KB + LVGL 40KB)曾占主 SRAM 的 **68%**,是当时"SRAM 几乎耗尽(95.4%,余 5.8KB)"的直接原因;**堆迁 CCM 后该结构性压力已解除**(现 RW_IRAM1 66.4%,见 §2.1) -- heap_4 **不合并相邻空闲块** → 长期运行需盯碎片,`min_ever`(现 4,848 B)是硬指标而非 `free` +- 两池(FreeRTOS 48KB + LVGL 40KB)曾占主 SRAM 的 **68%**,是当时"SRAM 几乎耗尽(95.4%,余 5.8KB)"的直接原因;**堆迁 CCM 后该结构性压力已解除**(2026-10-22 RW_IRAM1 57.4%,见 §2.1) +- heap_4 **不合并相邻空闲块** → 长期运行需盯碎片,`min_ever`(2026-10-22 实测 8,464 B,56KB 池)是硬指标而非 `free` - 未映射资源:SRAM3 64KB(scatter 未映射;clone 芯片可能无此区);CCM 已用 - 曾经的三条中风险项:新任务无处安置(已缓解)、堆碎片(仍存)、栈溢出检测缺失 → **已于阶段 0 开启 `configCHECK_FOR_STACK_OVERFLOW=2` 并实测抓到过溢出**(§0.1) @@ -148,7 +148,7 @@ ### 2.6 堆 / LVGL 池 / C 库 / Flash 明细 -#### 2.6.1 FreeRTOS 堆(48 KB;2026-09-21 已迁 CCM `RW_CCM`) +#### 2.6.1 FreeRTOS 堆(56 KB;2026-09-21 已迁 CCM `RW_CCM`) `configTOTAL_HEAP_SIZE = 49,152`(heap_4)。内部构成: diff --git a/docs/内存管理/data/ram_report_20261022.md b/docs/内存管理/data/ram_report_20261022.md new file mode 100644 index 00000000..cd7243f4 --- /dev/null +++ b/docs/内存管理/data/ram_report_20261022.md @@ -0,0 +1,245 @@ +# STM32F4-Base RAM/Flash Usage Report + +> Generated: 2026-10-22 12:06 Map: `STM32F407-Demo.map` + +## 1. Grand Totals (全局总量) + +| Metric | Value | +|---|---| +| Code (inc. data) | 213,188 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,768 B (226.3 KB)** | +| **Total RW (RW + ZI) = SRAM used** | **132,688 B (129.58 KB)** | +| **Total ROM (Code + RO + RW init)** | **232,952 B (227.5 KB)** | + +## 2. 执行区水位 (Execution Regions) + +| Region | Base | Size | Max | Util% | +|---|---|---|---|---| +| ER_IROM1 | 0x08000000 | 231,768 B (226.34 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% | + +## 3. RW_IRAM1 逐符号明细(ZI + RW,按大小降序) + +| # | Address | Size (B) | Size (KB) | Type | Section | Object | +|---|---|---|---|---|---|---| +| 1 | 0x2000ADC8 | 16,384 | 16.00 | Zero | .bss | lv_mem_core_builtin.o | +| 2 | 0x20007EB4 | 7,724 | 7.54 | Zero | .bss | lftpd.o | +| 3 | 0x200107A4 | 6,746 | 6.59 | Zero | .bss | ui_net_sink.o | +| 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 | +| 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 | +| 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 | +| 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 | +| 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 | +| 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 | +| 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 | +| 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 | +| 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 | +| 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 | +| 58 | 0x20000068 | 24 | 0.02 | Data | .data | console_log.o | +| 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 | +| 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 | +| 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 | +| 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 | +| 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) | +| 99 | 0x2000014C | 2 | 0.00 | Data | .data | phasor.o | +| 100 | 0x20000408 | 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** | + +## 4. Image Component Sizes(RW + ZI > 0,按大小降序) + +| # | Object | Code | RO | RW | ZI | RW+ZI | +|---|---|---|---|---|---|---| +| 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 | +| 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 | +| 7 | ch395f.o | 3,986 | 603 | 10 | 4,152 | 4,162 | +| 8 | console_log.o | 980 | 55 | 24 | 4,096 | 4,120 | +| 9 | sys_log_mcu.o | 3,074 | 83 | 36 | 3,552 | 3,588 | +| 10 | default_task.o | 2,332 | 280 | 12 | 2,724 | 2,736 | +| 11 | cmsis_os2.o | 1,496 | 0 | 4 | 1,720 | 1,724 | +| 12 | sample_ring.o | 292 | 0 | 8 | 1,440 | 1,448 | +| 13 | tasks.o | 4,342 | 0 | 60 | 1,220 | 1,280 | +| 14 | cfg_file_store_mcu.o | 380 | 24 | 0 | 1,104 | 1,104 | +| 15 | soe_store.o | 816 | 28 | 20 | 1,064 | 1,084 | +| 16 | startup_stm32f407xx.o | 36 | 392 | 0 | 1,024 | 1,024 | +| 17 | gd5f2gq5ue.o | 3,930 | 478 | 20 | 800 | 820 | +| 18 | iec104_serv.o | 1,188 | 16 | 16 | 712 | 728 | +| 19 | cfg_file.o | 5,970 | 810 | 20 | 704 | 724 | +| 20 | spi.o | 584 | 0 | 0 | 560 | 560 | +| 21 | lftpd_io.o | 1,198 | 0 | 4 | 552 | 556 | +| 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 | +| 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 | +| 29 | timers.o | 1,232 | 0 | 20 | 280 | 300 | +| 30 | rs485.o | 120 | 0 | 0 | 268 | 268 | +| 31 | prot_set_store.o | 236 | 74 | 0 | 176 | 176 | +| 32 | adc.o | 580 | 0 | 0 | 168 | 168 | +| 33 | phasor.o | 420 | 258 | 2 | 160 | 162 | +| 34 | task_watchdog.o | 1,110 | 137 | 44 | 116 | 160 | +| 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 | +| 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 | +| 42 | stm32f4xx_hal_timebase_tim.o | 152 | 0 | 0 | 72 | 72 | +| 43 | tim.o | 168 | 0 | 0 | 72 | 72 | +| 44 | iec104_pts.o | 1,082 | 132 | 16 | 48 | 64 | +| 45 | queue.o | 2,840 | 0 | 0 | 64 | 64 | +| 46 | ui_page_runlog.o | 28 | 105 | 0 | 60 | 60 | +| 47 | ui_page_selftest.o | 28 | 109 | 60 | 0 | 60 | +| 48 | adc_health.o | 432 | 0 | 48 | 0 | 48 | +| 49 | net_events.o | 1,994 | 809 | 16 | 32 | 48 | +| 50 | tpafe5160.o | 808 | 67 | 12 | 32 | 44 | +| 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 | +| 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 | +| 59 | port.o | 762 | 73 | 12 | 0 | 12 | +| 60 | stm32f4xx_hal.o | 116 | 0 | 12 | 0 | 12 | +| 61 | ui_page_password.o | 686 | 175 | 12 | 0 | 12 | +| 62 | ff.o | 7,962 | 282 | 8 | 0 | 8 | +| 63 | ffsystem.o | 204 | 20 | 8 | 0 | 8 | +| 64 | sys_clock.o | 1,788 | 286 | 8 | 0 | 8 | +| 65 | app_main.o | 2,272 | 65 | 4 | 0 | 4 | +| 66 | net_task.o | 1,460 | 72 | 4 | 0 | 4 | +| 67 | system_stm32f4xx.o | 16 | 24 | 4 | 0 | 4 | +| 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,188** | **18,580** | **1,184** | **131,504** | **132,688** | + +## 5. Flash (Code + RO Data) Top-30(按大小降序) + +| # | Object | Code | RO Data | Code+RO | +|---|---|---|---|---| +| 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 | +| 5 | lv_indev.o | 4,928 | 0 | 4,928 | +| 6 | ch395f.o | 3,986 | 603 | 4,589 | +| 7 | ui_font_cn_12.o | 0 | 4,545 | 4,545 | +| 8 | lv_obj_pos.o | 4,526 | 16 | 4,542 | +| 9 | lv_refr.o | 4,486 | 0 | 4,486 | +| 10 | gd5f2gq5ue.o | 3,930 | 478 | 4,408 | +| 11 | tasks.o | 4,342 | 0 | 4,342 | +| 12 | lv_obj_scroll.o | 4,126 | 0 | 4,126 | +| 13 | lv_obj_style.o | 4,106 | 0 | 4,106 | +| 14 | lv_draw_sw_mask.o | 3,862 | 0 | 3,862 | +| 15 | stm32f4xx_hal_spi.o | 3,586 | 0 | 3,586 | +| 16 | lv_draw_sw_box_shadow.o | 3,246 | 0 | 3,246 | +| 17 | sys_log_mcu.o | 3,074 | 83 | 3,157 | +| 18 | lv_indev_scroll.o | 3,068 | 0 | 3,068 | +| 19 | lv_obj.o | 2,982 | 43 | 3,025 | +| 20 | lv_draw_sw_img.o | 2,960 | 0 | 2,960 | +| 21 | queue.o | 2,840 | 0 | 2,840 | +| 22 | journal.o | 2,834 | 0 | 2,834 | +| 23 | iec104_link.o | 2,824 | 0 | 2,824 | +| 24 | net_events.o | 1,994 | 809 | 2,803 | +| 25 | default_task.o | 2,332 | 280 | 2,612 | +| 26 | nand_ftl.o | 2,352 | 175 | 2,527 | +| 27 | app_main.o | 2,272 | 65 | 2,337 | +| 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,188** | **18,580** | **231,768** | + +> 自洽校验:per-file 213,188/18,580/1,184/131,504 vs Grand Totals 213,188/18,580/1,184/131,504(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 new file mode 100644 index 00000000..0acd4d45 --- /dev/null +++ b/docs/内存管理/data/stack_report_20261022.md @@ -0,0 +1,100 @@ +# Stack budget report + +- Source: `MDK-ARM\STM32F407-Demo\STM32F407-Demo.htm` (Keil static call graph) +- Linker run: Thu Oct 22 10:36:17 2026 +- Global maximum stack usage: **3024 B** (any call tree) +- Runtime watermark: 8 task(s) from 串口采集日志 `.dsh\skills\serial-assistant\scripts\state\serial.log` + +Rule: `margin = cfg - max(static_max_depth, runtime_peak)` must be >= max(1024 B ISR, 30% of cfg). + +| Task | Entry | Cfg (B) | Static max (B) | Runtime peak (B) | Worst (B) | Margin (B) | Margin % | Verdict | +|---|---|---|---|---|---|---|---|---| +| defaultTask | `StartDefaultTask` | 5120 | 3024 | 2164 | 3024 | 2096 | 40% | PASS | +| netTask | `StartNetTask` | 3840 | 1912 | 1116 | 1912 | 1928 | 50% | PASS | +| ftpTask | `StartFtpTask` | 4096 | 1456 | 756 | 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 | +| adcTask | `adc_task_func` | 2560 | 1320 | 952 | 1320 | 1240 | 48% | PASS | +| iec104Task | `iec104_serv_task` | 2560 | 1456 | 544 | 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. + +Runtime heap: free=15800 B, min_ever=8464 B + +## Worst call chain per task + +### defaultTask: 3024 B (own frame 0 B) + +``` +StartDefaultTask -> default_task_func -> storage_bring_up -> net_cfg_load -> cfg_file_load -> s_write_template -> s_write_doc -> cfg_store_write_atomic -> f_rename -> sync_fs -> disk_ioctl -> ftl_flush_cache -> dhara_map_write -> prepare_write -> auto_gc -> dhara_map_gc -> try_recover -> raw_gc -> trace_path -> dhara_journal_read_meta -> dhara_nand_read -> gd5f_read_from_cache -> dbg_console_write_line -> con_append -> dbg_console_drain -> MX_USART1_UART_Init -> HAL_UART_Init -> HAL_UART_MspInit -> Error_Handler -> dbg_console_write_line (Cycle) +``` + +### netTask: 1912 B (own frame 0 B) + +``` +StartNetTask -> net_task_func -> net_process_messages -> net_listener_tick -> net_relisten_locked -> ch395f_read_recv_buf -> ch395f_spi_dma_transfer -> ch395f_spi_fault_set -> dbg_console_write_line -> con_append -> dbg_console_drain -> MX_USART1_UART_Init -> HAL_UART_Init -> HAL_UART_MspInit -> Error_Handler -> dbg_console_write_line (Cycle) +``` + +### ftpTask: 1456 B (own frame 24 B) + +``` +StartFtpTask -> lftpd_start -> lftpd_inet_listen -> net_bind -> ch395f_open_socket -> ch395f_poll_cmd_status -> ch395f_get_cmd_status -> ch395f_write_cmd -> ch395f_spi_fault_set -> dbg_console_write_line -> con_append -> dbg_console_drain -> MX_USART1_UART_Init -> HAL_UART_Init -> HAL_UART_MspInit -> Error_Handler -> dbg_console_write_line (Cycle) +``` + +### uiTask: 1336 B (own frame 0 B) + +``` +StartUiTask -> ui_task_func -> ui_menu_init -> ui_menu_view_init -> lv_obj_create -> lv_obj_class_init_obj -> lv_theme_apply -> lv_obj_remove_style_all -> lv_obj_remove_style -> lv_obj_refresh_style -> refresh_children_style -> refresh_children_style (Cycle) +``` + +### testTask: 736 B (own frame 224 B) + +``` +start_test_task -> dbg_console_write_line -> con_append -> dbg_console_drain -> MX_USART1_UART_Init -> HAL_UART_Init -> HAL_UART_MspInit -> Error_Handler -> dbg_console_write_line (Cycle) +``` + +### timeSyncTask: 1264 B (own frame 152 B) + +``` +time_sync_task -> time_sync_open_listener -> net_bind -> ch395f_open_socket -> ch395f_poll_cmd_status -> ch395f_get_cmd_status -> ch395f_write_cmd -> ch395f_spi_fault_set -> dbg_console_write_line -> con_append -> dbg_console_drain -> MX_USART1_UART_Init -> HAL_UART_Init -> HAL_UART_MspInit -> Error_Handler -> dbg_console_write_line (Cycle) +``` + +### adcTask: 1320 B (own frame 312 B) + +``` +adc_task_func -> adc_health_report -> syslog_post -> dbg_console_write_line -> con_append -> dbg_console_drain -> MX_USART1_UART_Init -> HAL_UART_Init -> HAL_UART_MspInit -> Error_Handler -> dbg_console_write_line (Cycle) +``` + +### iec104Task: 1456 B (own frame 160 B) + +``` +iec104_serv_task -> s_serv_poll -> s_service_link -> s_drop_conn -> s_bind_listen -> net_bind -> ch395f_open_socket -> ch395f_poll_cmd_status -> ch395f_get_cmd_status -> ch395f_write_cmd -> ch395f_spi_fault_set -> dbg_console_write_line -> con_append -> dbg_console_drain -> MX_USART1_UART_Init -> HAL_UART_Init -> HAL_UART_MspInit -> Error_Handler -> dbg_console_write_line (Cycle) +``` + +### protectTask: 872 B (own frame 160 B) + +``` +protect_task -> s_log_active_edge -> dbg_console_write_line -> con_append -> dbg_console_drain -> MX_USART1_UART_Init -> HAL_UART_Init -> HAL_UART_MspInit -> Error_Handler -> dbg_console_write_line (Cycle) +``` + +## Frame-size ranking (own frame, top 15) + +| Bytes | Function | +|---|---| +| 624 | `lv_draw_sw_arc` | +| 400 | `draw_line_skew` | +| 352 | `lv_draw_sw_triangle` | +| 352 | `net_stack_bring_up` | +| 328 | `lv_obj_redraw` | +| 328 | `view_frame_draw_cb` | +| 324 | `s_transform` | +| 320 | `wd_stall_evidence` | +| 312 | `adc_task_func` | +| 312 | `nc_draw_cb` | +| 304 | `lv_draw_label_iterate_characters` | +| 304 | `lv_draw_sw_box_shadow` | +| 304 | `soe_store_drain` | +| 304 | `sys_clock_init` | +| 296 | `net_relisten_locked` | diff --git a/docs/环境与部署/项目部署环境要求.md b/docs/环境与部署/项目部署环境要求.md index bd565260..1e74a79f 100644 --- a/docs/环境与部署/项目部署环境要求.md +++ b/docs/环境与部署/项目部署环境要求.md @@ -117,8 +117,12 @@ Graphviz / Cppcheck 的安装位置差异一律用 `DTU_*` 环境变量表达( - 链接器使用**手动 scatter 文件** `MDK-ARM/STM32F407-Demo/STM32F407-Demo.sct`(在仓库,`.uvprojx` 已启用 `useFile=1`): - `ER_IROM1` 0x08000000,1 MB(代码 + 只读数据) - - `RW_IRAM1` 0x20000000,**128 KB**(SRAM1 112K + SRAM2 16K 连续;SRAM3/CCM 故意未映射——克隆芯片可能无 SRAM3) -- Keil `Options for Target → Target` 页显示的片上内存来自 `.uvprojx` 的 `` 行(IRAM 112 KB / IRAM2 16 KB / IROM 1 MB,同样在仓库)+ Device Pack + - `RW_IRAM1` 0x20000000,**128 KB**(SRAM1 112K + SRAM2 16K 连续,**DMA 可达区**:存储/网络/串口 DMA + 缓冲只能放这里;克隆芯片可能无 SRAM3,换料必须重测) + - `RW_CCM` 0x10000000,**64 KB 减 256 B 尾**(2026-10-11 起启用,承载 FreeRTOS 堆与 `.noinit` 崩溃现场; + **CCM 不可被 DMA 寻址**——规则 R2/R3 见 `docs/内存管理/内存内容分配策略.md` §4,并有编译期窗口断言 + + 启动期自检 + 运行时守卫三层强制) +- Keil `Options for Target → Target` 页显示的片上内存来自 `.uvprojx` 的 `` 行(IRAM 112 KB / IRAM2 16 KB / IROM 1 MB,同样在仓库)+ Device Pack(**GUI 那几格不含 CCM 段,别据此判断"CCM 没用"**) - ⚠ 新机器**不要在 GUI 里重填 RAM 区**,也**勿改 Target 页**(会回写共享的 `.uvprojx` 影响他人);确需调整内存布局(如日后启用 SRAM3/CCM)时修改 `.sct` 并提交 ### 2.3 PC 侧编译环境(模拟器 + 主机侧单元测试,必需) @@ -476,10 +480,10 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级 | 项 | 值 | 说明 | |---|---|---| -| MCU | STM32F407ZGTx | Cortex-M4(双精度 FPU / TrustZone),LQFP144 | +| MCU | STM32F407ZGTx | Cortex-M4,**单精度** FPU(VFPv4-SP,**无硬件双精度**,`double` 走软件模拟;无 TrustZone),LQFP144 | | 主频 | 168 MHz | HSE 8 MHz → PLL M=4 / N=168 / P=2(`Inc/stm32f4xx_hal_conf.h`) | | Flash | 1 MB(0x08000000) | 片内 | -| SRAM | 192 KB(128 KB 主 + 64 KB CCM) | 当前仅用主 SRAM 128 KB;SRAM3/CCM 未映射(§3.3) | +| SRAM | 192 KB(128 KB 主 + 64 KB CCM) | **两块都在用**:主 SRAM1 128 KB(DMA 可达)+ CCM(FreeRTOS 堆);SRAM3 仍未映射 → §3.3 | | RTOS | FreeRTOS V10.3.1(CMSIS-RTOS V2) | HAL 时基 TIM7,tick = 1 ms;NVIC 4 位抢占,外设中断优先级 ≥5 | ### 3.2 外设硬件要求(引脚级) @@ -505,22 +509,18 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级 | CCM(`RW_CCM` 段) | 57,376 B(56.0 KB) | 65,280 B | **87.9%** | **7,904 B** | **当前真正的红线**:加任务 / 抬栈 / 加堆会先在这里撞墙;`mem-budget` 钩子在 92% 拦提交 | - LVGL 内存池 16 KB(静态占用,2026-10-15 由 40 KB 收缩);FreeRTOS 堆 56 KB(CCM) -- 任务栈预算(words,1 word = 4 B): +- **任务栈配置不在本文重复**:唯一事实源是 `Src/freertos.c`(`.ioc` 的 `FREERTOS.Tasks01`), + 受管表只有两份——根 `README.md` 与 `AGENTS.md` 里由 `scripts/gen_task_table.py --write` 生成的 + `TASK_TABLE` 块,由 `task-table` 钩子校验;每任务的静态最坏链、实测峰值与余量台账在 + `docs/内存管理/RAM使用分析与优化方案.md` §2.3(配置与实测峰值)与 §0.6(静态最坏链与判定)。 +- ⚠ **不要再在本文抄一份任务表**:`task-table` 钩子的校验面只有上面那两份受管块,抄出来的副本 + 没有门禁、改栈后必然漂(2026-10-22 删除本文历史副本时,它已缺 `adcTask` / `iec104Task` / + `protectTask` 三个任务,`defaultTask`/`timeSyncTask` 两值也停在旧数)。 -| 任务 | 栈大小 | 优先级 | -|---|---|---| -| defaultTask | 1024 | Normal | -| netTask | 960 | Normal | -| ftpTask | 1024 | Normal | -| testTask | 2048 | BelowNormal | -| uiTask | 4096 | BelowNormal | -| timeSyncTask | 512 | Normal | - -> 上表由 `scripts/gen_task_table.py` 同源(唯一来源 `Src/freertos.c` / `.ioc` 的 `FREERTOS.Tasks01`); -> 2026-10-10 栈整改**未改任何栈值**,靠削调用链达标(详见 `docs/内存管理/RAM使用分析与优化方案.md`)。 - -> 挖潜方向(未实施):SRAM3 64 KB / CCM 64 KB 未映射——详见 `docs/内存管理/`。 -> 部署侧含义:**不要做任何需要额外 RAM 的固件定制**,新增功能先过内存预算。 +> 挖潜方向:**SRAM3 64 KB 仍未映射**;CCM 64 KB **已启用**(2026-10-11 起承载 FreeRTOS 堆,见上表 +> `RW_CCM` 行),配额与台账 → `docs/内存管理/RAM预算台账.md`。 +> 部署侧含义:**新增需要额外 RAM 的固件定制前必须先过内存预算**——余量集中在 SRAM1,CCM 只剩 +> 7,904 B,加任务 / 抬栈 / 加堆会先在 CCM 撞墙。 ### 3.4 下载与调试 @@ -649,6 +649,7 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级 | 日期 | 变更 | |---|---| +| 2026-10-22 | **§3.2 / §3.3 与 §2.2 内存事实纠偏**:① §3.3 资源预算表由 2026-09-11 快照刷新为 2026-10-22 实测——Flash 231,768 B / 22.1%,主 SRAM1 由"125,104 B / 95.4% / 极度紧张"更正为 **75,264 B / 57.4%(余 55,808 B)**,并**补上 CCM 行**(57,376 B / 87.9%,余 7,904 B)——当前红线在 CCM 而非 SRAM1;② 删除 §3.3 的任务栈副本表(无门禁、已缺 `adcTask`/`iec104Task`/`protectTask`),改指针到 `README.md`/`AGENTS.md` 受管表与 `RAM使用分析与优化方案.md` §2.3/§0.6;③ §2.2 链接布局补 `RW_CCM 0x10000000` 段(2026-10-11 已启用、**不可 DMA**),§3.1 MCU 行更正为**单精度 FPU、无 TrustZone**(原写"双精度 FPU / TrustZone"是芯片事实错误,也正是报告 F-6 双精度软浮点被长期误判的土壤) | | 2026-10-12 | **远程 CI 文档迁出本目录**:`CI配置指南.md` 与 `Gitea_Runner部署指南.md` 合并为 **`docs/CI/远程CI完整指南.md`**(入口 `docs/CI/README.md`),本文三处引用改指新路径与新章节号(§4.1.3 机器级变量、§7 相关文档登记)。原因:远程 CI 只涉及本机一台 runner,不应与"任何机器都要过"的部署核对清单混在一起 | | 2026-10-10 | **删除旧档 NCFG 迁移**(升级/迁移口径变更):旧固件遗留的 `/cfg/netcfg.bin` 不再"首启自动迁移"——旧档若存在则被忽略(不读、不删、不迁移),配置直接回落工厂默认(`/config.ini` `[network]` 段模板)。`net_cfg_legacy.c/h` 与 `cfg_store_legacy_path()` 已移除;携带旧档的设备升级后需经 UI 或 FTP 重新配置网口。§五 现场部署 IP 行同步 | | 2026-10-02 | **模拟器构建修复**(配置引擎重构遗留):`simulator/CMakeLists.txt` 的配置文件引擎引用同步到迁移后位置——包含目录 `App/`→`App/cfg/`(`cfg_file.h`/`cfg_file_store.h`)、源文件 `App/cfg_file.c`→`App/cfg/cfg_file.c`、包含目录 `test/`→`test/board/`(`test_config.h`/`net_latency_test.h`);全量 include 离线核查无其他断链,模拟器全量构建恢复(`--cfgtest` 四场景 PASS,rc=0)。§2.12 验证链 ⑤ 行同步更新 | diff --git a/scripts/ram_report.py b/scripts/ram_report.py index 73dde519..c068a1ef 100644 --- a/scripts/ram_report.py +++ b/scripts/ram_report.py @@ -365,7 +365,9 @@ def main(): if args.output: pathlib.Path(args.output).parent.mkdir(parents=True, exist_ok=True) - pathlib.Path(args.output).write_text(report, encoding="utf-8") + # newline="\n":Windows 下 write_text 默认把 \n 翻成 \r\n,会跟 .gitattributes + # (* text=auto eol=lf)与 data/ 目录既有快照的行尾不一致(2026-10-22 实测)。 + pathlib.Path(args.output).write_text(report, encoding="utf-8", newline="\n") print(f"OK: Report written to {args.output}", file=sys.stderr) else: print(report) diff --git a/scripts/stack_report.py b/scripts/stack_report.py index 55fe3343..cd315e7d 100644 --- a/scripts/stack_report.py +++ b/scripts/stack_report.py @@ -176,12 +176,20 @@ def main(): add = out.append add('# Stack budget report') add('') - add(f'- Source: `{html_path.relative_to(REPO_ROOT)}` (Keil static call graph)') + # 显示用相对路径:传相对 -i 时 relative_to 会抛 ValueError(2026-10-22 实测踩到), + # 且绝不把本机绝对路径写进入库的 data/ 快照。 + def _disp(pth): + try: + return pathlib.Path(pth).resolve().relative_to(REPO_ROOT) + except (ValueError, OSError): + return pathlib.Path(pth).name + + add(f'- Source: `{_disp(html_path)}` (Keil static call graph)') if meta["updated"]: add(f'- Linker run: {meta["updated"]}') add(f'- Global maximum stack usage: **{meta["max_stack"]} B** (any call tree)') if runtime: - add(f'- Runtime watermark: {len(runtime)} task(s) from `{args.serial}`') + add(f'- Runtime watermark: {len(runtime)} task(s) from 串口采集日志 `{_disp(args.serial)}`') add('') add('Rule: `margin = cfg - max(static_max_depth, runtime_peak)` must be ' f'>= max({args.isr_margin} B ISR, {args.min_free_pct}% of cfg).') @@ -252,7 +260,8 @@ def main(): report = '\n'.join(out) if args.output: - pathlib.Path(args.output).write_text(report, encoding='utf-8') + # newline="\n":避免 Windows 换行翻译污染 data/ 快照的 LF 行尾(与 .gitattributes 一致)。 + pathlib.Path(args.output).write_text(report, encoding='utf-8', newline='\n') print(f'written: {args.output}') else: print(report) diff --git a/tools/arch_diagram/gen_memory_svg.py b/tools/arch_diagram/gen_memory_svg.py index 58e36690..f5e1a41f 100644 --- a/tools/arch_diagram/gen_memory_svg.py +++ b/tools/arch_diagram/gen_memory_svg.py @@ -17,39 +17,41 @@ import sys # Diagram data # --------------------------------------------------------------------------- -# ── RAM breakdown (2026-09-21 @build, map Grand Totals; data/ram_report_20260921.md) ── +# ── RAM breakdown (2026-10-22 @build, map Grand Totals; data/ram_report_20261022.md) ── # Region 1: main SRAM RW_IRAM1 @0x20000000 (128KB = 131,072 B, DMA-reachable) SRAM1_TOTAL = 131072 -SRAM1_USED = 82048 +SRAM1_USED = 75264 SRAM1_FREE = SRAM1_TOTAL - SRAM1_USED -# Region 2: CCM RW_CCM @0x10000000 (64KB = 65,536 B, CPU only, DMA NOT reachable) -CCM_TOTAL = 65536 -CCM_USED = 49184 +# Region 2: CCM RW_CCM @0x10000000 —— scatter 给的是 0x0000FF00 = 65,280 B(CPU only, +# DMA 不可达);另有 0x1000FF00 起 256 B 的 UNINIT_CCM 尾区(.noinit 崩溃现场用 48 B) +CCM_TOTAL = 65280 +CCM_USED = 57376 CCM_FREE = CCM_TOTAL - CCM_USED RAM1_CATEGORIES = [ - ("LVGL", 41460, "#4CAF50"), - ("UI", 13532, "#FF9800"), - ("FTL/BBT", 8812, "#9C27B0"), - ("lftpd", 5324, "#8BC34A"), - ("CMSIS", 5016, "#00BCD4"), - ("NET", 4445, "#F44336"), - ("HAL", 1280, "#607D8B"), + ("LVGL 池 16KB", 16876, "#4CAF50"), + ("UI", 13546, "#FF9800"), + ("lftpd", 8440, "#8BC34A"), + ("FTL/BBT", 7036, "#9C27B0"), + ("NET/CH395F", 5250, "#F44336"), + ("CMSIS-RTOS", 1724, "#00BCD4"), + ("HAL", 84, "#607D8B"), ("C stack", 1024, "#795548"), - ("other", 1155, "#9E9E9E"), - ("free", SRAM1_FREE, "#E0E0E0"), + ("other", 21284, "#9E9E9E"), + ("free", SRAM1_FREE, "#E0E0E0"), ] RAM2_CATEGORIES = [ - ("heap", 49184, "#2196F3"), - ("free", CCM_FREE, "#E0E0E0"), + ("FreeRTOS 堆", CCM_USED, "#2196F3"), + ("free", CCM_FREE, "#E0E0E0"), ] -# ── Flash breakdown (1MB = 1,048,576 B; 2026-09-21 @build) ────────────────── +# ── Flash breakdown (1MB = 1,048,576 B; 2026-10-22 @build) ────────────────── FLASH_TOTAL = 1048576 -FLASH_CODE = 234976 -FLASH_RO = 13824 -FLASH_RW = 632 -FLASH_USED = FLASH_CODE + FLASH_RO + FLASH_RW +FLASH_CODE = 213188 +FLASH_RO = 18580 +FLASH_RW = 1184 +FLASH_USED = FLASH_CODE + FLASH_RO + FLASH_RW # ROM 合计(含 RW 初始化表) +FLASH_IROM = FLASH_CODE + FLASH_RO # ER_IROM1 区用量 = 231,768 B(22.1%) FLASH_FREE = FLASH_TOTAL - FLASH_USED FLASH_CATEGORIES = [ @@ -59,37 +61,42 @@ FLASH_CATEGORIES = [ ("Flash 空闲", FLASH_FREE, "#E0E0E0"), ] -# Flash code sub-breakdown (2026-09-21; top items from data/ram_report_20260921.md, -# long-tail .o objects below the report's top-44 threshold are counted in "其他") +# Flash Code+RO 分布(= ER_IROM1 231,768 B;2026-10-22 按 .map 对象表逐对象归类, +# 口径同 data/ram_report_20261022.md;"其他"含链接器填充) FLASH_CODE_SUB = [ - ("LVGL 库", 98000, "#4CAF50"), - ("应用代码/UI", 34110, "#2196F3"), - ("FatFS", 8146, "#9C27B0"), - ("dhara / FTL", 4982, "#FF9800"), - ("HAL 驱动", 16000, "#607D8B"), - ("FreeRTOS 内核", 10132, "#00BCD4"), - ("CH395F 网络", 2738, "#F44336"), - ("C 库 (microlib)", 4230, "#795548"), - ("其他 (长尾)", 56638, "#E0E0E0"), # remainder + ("LVGL 库", 87706, "#4CAF50"), + ("应用代码/UI", 57011, "#2196F3"), + ("CH395F+FTP", 25652, "#F44336"), + ("HAL 驱动", 17876, "#607D8B"), + ("dhara / FTL", 10907, "#FF9800"), + ("FreeRTOS 内核", 10762, "#00BCD4"), + ("FatFS", 8468, "#9C27B0"), + ("C 库 (microlib)", 5486, "#795548"), + ("startup", 468, "#B0BEC5"), + ("其他 (长尾)", 7432, "#E0E0E0"), # remainder ] -# ── Task stack budgets (2026-10-10 @build + 开机/空闲实测; data/stack_report_20261010.md) ── +# ── Task stack budgets (2026-10-22 @build + 同日真机 [STACK] 实测; data/stack_report_20261022.md) ── # (name, cfg, prio, worst, peak_used, margin, margin_pct, verdict, desc) # worst = max(静态最坏深度, 实测峰值); margin = cfg - worst +# 9 行含 testTask(仅测试构建创建、无实测 → 取静态最坏链,峰位列填同值) TASK_STACKS = [ - ("defaultTask", 4096, "Normal", 2776, 2152, 1320, 32, "PASS", "FatFS 挂载/探针 + 配置引擎 + syslog + 栈探针"), - ("netTask", 3840, "Normal", 1872, 920, 1968, 51, "PASS", "CH395F 轮询、消息处理"), - ("ftpTask", 4096, "Normal", 1216, 740, 2880, 70, "PASS", "lftpd FTP 服务(大缓冲已静态化)"), - ("testTask", 8192, "BelowNormal", 496, 496, 7696, 93, "PASS", "测试套件(产品构建不创建,取静态最坏链)"), - ("uiTask", 16384, "BelowNormal", 4016, 4016, 12368, 75, "PASS", "LVGL UI 主循环"), - ("timeSyncTask", 2048, "Normal", 1024, 616, 1024, 50, "PASS", "TCP 时间同步(余量正好卡在 ISR 底线)"), + ("defaultTask", 5120, "Normal", 3024, 2164, 2096, 40, "PASS", "FatFS 挂载/探针 + 配置引擎 + syslog + LED"), + ("netTask", 3840, "Normal", 1912, 1116, 1928, 50, "PASS", "CH395F 轮询、消息处理"), + ("ftpTask", 4096, "Normal", 1456, 756, 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)"), + ("adcTask", 2560, "AboveNormal", 1320, 952, 1240, 48, "PASS", "1 kHz 节拍消费者(L1 采集,纯取数)"), + ("iec104Task", 2560, "Normal", 1456, 544, 1104, 43, "PASS", "IEC 60870-5-104 上行(2404)"), + ("protectTask", 2048, "Normal", 872, 828, 1176, 57, "PASS", "20 ms 保护判据 + 闭锁 + 定值校验和巡检"), ] -KERNEL_STACKS = [("idle", 512), ("timer", 1024)] # 128/256 words +KERNEL_STACKS = [("idle", 512), ("timer", 1024)] # 128/256 words(未实测) -HEAP_TOTAL = 49152 # configTOTAL_HEAP_SIZE(位于 RW_CCM) -HEAP_FREE = 8784 # 2026-09-21 实测(含 FTP 负载) -HEAP_MIN_EVER = 4848 -TOTAL_STACKS = sum(t[1] for t in TASK_STACKS) # 38,656 +HEAP_TOTAL = 57344 # configTOTAL_HEAP_SIZE 56 KB(位于 RW_CCM;段实占 57,376 B 含元数据) +HEAP_FREE = 15800 # 2026-10-22 真机 [STACK](启动 + 网络/FTP/104 就绪后) +HEAP_MIN_EVER = 8464 +TOTAL_STACKS = sum(t[1] for t in TASK_STACKS) # 47,360(含 testTask;产品构建 8 任务 = 39,168) # --------------------------------------------------------------------------- # SVG helpers @@ -171,7 +178,7 @@ def gen_ram_svg(): SCALE = (W - 80) / SRAM1_TOTAL # 128KB 占满宽;CCM (64KB) 占半宽 svg = svg_header(W, H) - svg += f'SRAM (192KB) 使用布局 — 2026-09-21 @build\n' + svg += f'SRAM (192KB) 使用布局 — 2026-10-22 @build\n' # Region 1: 主 SRAM y1 = 50 @@ -191,7 +198,7 @@ def gen_ram_svg(): # Region 2: CCM y2 = y1 + BAR_H + 50 - svg += f'CCM RW_CCM @0x10000000(64KB,仅 CPU 可达,DMA 不可达)\n' + svg += f'CCM RW_CCM @0x10000000(段 65,280 B;仅 CPU 可达、DMA 不可达 → R2/R3)\n' x = BAR_X for label, size, color in RAM2_CATEGORIES: w = size * SCALE @@ -203,7 +210,7 @@ def gen_ram_svg(): svg += f'' svg += f'已用: {CCM_USED}B ({CCM_USED/CCM_TOTAL*100:.1f}%)' svg += f' 空闲: {CCM_FREE}B ({CCM_FREE/CCM_TOTAL*100:.1f}%)' - svg += f' 总量: 64KB\n' + svg += f' 总量: 63.75KB(+256 B UNINIT_CCM 尾区)——CCM 是当前全局卡点\n' # Legend(主 SRAM 两列 + CCM 两行) ly = y2 + BAR_H + 40 @@ -239,7 +246,7 @@ def gen_flash_svg(): SCALE = (W - 80) / FLASH_TOTAL svg = svg_header(W, H) - svg += f'Flash (1MB) 使用布局 — 2026-09-21 @build\n' + svg += f'Flash (1MB) 使用布局 — 2026-10-22 @build\n' x = BAR_X for label, size, color in FLASH_CATEGORIES: @@ -255,29 +262,39 @@ def gen_flash_svg(): svg += f'' svg += f'已用: {FLASH_USED/1024:.1f}KB ({FLASH_USED/FLASH_TOTAL*100:.1f}%)' svg += f' 空闲: {FLASH_FREE/1024:.1f}KB ({FLASH_FREE/FLASH_TOTAL*100:.1f}%)' - svg += f' 总量: 1024KB\n' + svg += f' ER_IROM1(Code+RO): {FLASH_IROM/1024:.1f}KB ({FLASH_IROM/FLASH_TOTAL*100:.1f}%)' + svg += f' 总量: 1MB (= ROM 合计口径)' + svg += f'\n' # Code sub-breakdown mini bar Y2 = 130 - svg += f'代码段明细 ({FLASH_CODE/1024:.1f}KB)\n' - SCALE2 = (W - 80) / FLASH_CODE + svg += f'Code + RO 分布(ER_IROM1 {FLASH_IROM/1024:.1f}KB,按 .map 对象归类)\n' + SCALE2 = (W - 80) / FLASH_IROM x2 = BAR_X for label, size, color in FLASH_CODE_SUB: w = size * SCALE2 if w < 1: continue - inside = f"{label} {size/1024:.1f}KB" if w > 50 else "" - outside = "" if w > 50 else f"{label} {size/1024:.1f}KB" - svg += _draw_bar_segment(x2, Y2, w, 24, color, inside, outside) + # 窄段(多数桶 < 40px)不放内嵌文字,统一列到下方图例,避免互相压字 + inside = f"{size/1024:.1f}KB" if w > 40 else "" + svg += _draw_bar_segment(x2, Y2, w, 24, color, inside, "") x2 += w + # 图例:四列三行(10 个桶) + for i, (label, size, color) in enumerate(FLASH_CODE_SUB): + col, row = i % 4, i // 4 + lx = 60 + col * 195 + ly = 176 + row * 16 + svg += f' \n' + svg += f' {label} {size/1024:.1f}KB\n' + svg += svg_footer() return svg def gen_taskstack_svg(): """任务栈预算.svg — 每任务:分配栈条 + 最坏占用叠加条 + 实测余量/判定。""" - W, H = 880, 440 + W, H = 880, 620 # 9 个任务 + 2 内核栈 + 堆汇总,行高 40 需要 ~600 高 BAR_X = 190 MAX_STACK = 16384 SCALE = (W - BAR_X - 40) / MAX_STACK @@ -286,16 +303,19 @@ def gen_taskstack_svg(): BAR_H = 16 svg = svg_header(W, H) - svg += f'FreeRTOS 任务栈预算(48KB 堆,2026-09-21 已迁 CCM)\n' - svg += f'数据: 2026-10-10 @build + 开机/空闲实测(data/stack_report_20261010.md);最坏 = max(静态最坏链, 实测峰值)\n' + svg += f'FreeRTOS 任务栈预算(9 任务;栈全部从 56KB FreeRTOS 堆分配,堆位于 CCM)\n' + svg += f'数据: 2026-10-22 @build + 同日真机 [STACK] 水位(data/stack_report_20261022.md);最坏 = max(静态最坏链, 实测峰值);判定线 = 余量 ≥ max(1024B ISR, 配置×30%)\n' svg += f'浅色条 = 分配栈 深色条 = 最坏占用(max(静态最坏, 实测峰值)) 下方文字 = 实测余量/判定\n' y = Y_START for name, cfg, prio, worst, peak, margin, pct, verdict, desc in TASK_STACKS: w = cfg * SCALE wc = worst * SCALE - dark = "#2196F3" if prio == "Normal" else "#FF9800" - light = "#BBDEFB" if prio == "Normal" else "#FFE0B2" + # 三档优先级配色:Normal 蓝 / BelowNormal 琥珀 / AboveNormal 绿(adcTask) + dark = {"Normal": "#2196F3", "BelowNormal": "#FF9800", + "AboveNormal": "#4CAF50"}[prio] + light = {"Normal": "#BBDEFB", "BelowNormal": "#FFE0B2", + "AboveNormal": "#C8E6C9"}[prio] vc = "#2E7D32" if verdict == "PASS" else "#C62828" # 任务名(左侧) @@ -321,18 +341,25 @@ def gen_taskstack_svg(): # 堆汇总(实测值) y += 8 svg += f'' - svg += f'堆总量: {HEAP_TOTAL}B (48KB, RW_CCM) 任务栈合计: {TOTAL_STACKS}B ({TOTAL_STACKS/1024:.1f}KB) + 内核栈 {512+1024}B\n' + svg += f'堆总量: {HEAP_TOTAL}B(configTOTAL_HEAP_SIZE=56KB,位于 RW_CCM)' + svg += f' 任务栈合计: {TOTAL_STACKS}B(含 testTask 8192B)\n' y += 16 svg += f'' - svg += f'实测: free={HEAP_FREE}B / min_ever={HEAP_MIN_EVER}B(2026-09-21,含 FTP 负载) 判定: 6/6 PASS(余量 ≥ max(1024B, 配置×30%))\n' + svg += f'产品构建 8 任务栈 = 39168B + 内核栈 {512+1024}B' + svg += f' 实测: free={HEAP_FREE}B / min_ever={HEAP_MIN_EVER}B(2026-10-22)\n' + y += 16 + svg += f'' + svg += '判定: 9/9 PASS(testTask 无实测,取静态最坏链)\n' y += 24 # 颜色图例 svg += f' \n' svg += f' Normal 优先级\n' svg += f' \n' svg += f' BelowNormal 优先级\n' - svg += f' \n' - svg += f' 内核任务栈 (idle/timer)\n' + svg += f' \n' + svg += f' AboveNormal 优先级(adcTask)\n' + svg += f' \n' + svg += f' 内核栈 idle/timer\n' svg += svg_footer() return svg