From 96855f6b6b9def47169fd9eaef58d0a5f7b33a56 Mon Sep 17 00:00:00 2001
From: Wanderingss <1624155937@qq.com>
Date: Mon, 21 Sep 2026 05:10:01 +0800
Subject: [PATCH] =?UTF-8?q?=E5=86=85=E5=AD=98=E5=B8=83=E5=B1=80=E5=9B=BE?=
=?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=88=B009-21=E6=9C=80=E6=96=B0=EF=BC=9A?=
=?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=A0=88=E9=A2=84=E7=AE=97=E5=90=AB=E5=AE=9E?=
=?UTF-8?q?=E6=B5=8B=E5=B3=B0=E5=80=BC=E4=B8=8E=E5=88=A4=E5=AE=9A=EF=BC=8C?=
=?UTF-8?q?RAM=E5=8F=8C=E5=8C=BA/Flash=E5=B8=83=E5=B1=80=E5=90=8C=E6=AD=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/images/任务栈预算.svg | 68 +++++---
docs/images/内存布局_FLASH.svg | 53 +++---
docs/images/内存布局_RAM.svg | 89 +++++-----
tools/arch_diagram/gen_memory_svg.py | 250 ++++++++++++++++-----------
4 files changed, 266 insertions(+), 194 deletions(-)
diff --git a/docs/images/任务栈预算.svg b/docs/images/任务栈预算.svg
index 06d27e35..ed02c6e0 100644
--- a/docs/images/任务栈预算.svg
+++ b/docs/images/任务栈预算.svg
@@ -1,4 +1,4 @@
-
diff --git a/docs/images/内存布局_RAM.svg b/docs/images/内存布局_RAM.svg
index fbd8dfaa..a6a98cb3 100644
--- a/docs/images/内存布局_RAM.svg
+++ b/docs/images/内存布局_RAM.svg
@@ -1,4 +1,4 @@
-
+
-SRAM (128KB) 使用布局
-
- FreeRTOS 堆 (48KB heap_4)
-
- LVGL 内存池 (40KB)
-
- UI 帧缓冲
- (~13KB)
-
- FTL / 存储
- (~11KB)
-
- 网络 /
- CH395F
- (~7KB)
-
- 内核 / CMSIS (~3KB)
-
- HAL 驱动 (~1.4KB)
-
- 其他静态 (~0.5KB)
-
-
- FreeRTOS 堆 (48KB heap_4): 48.0KB (37.5%)
-
- LVGL 内存池 (40KB): 40.0KB (31.2%)
-
- UI 帧缓冲 (~13KB): 12.8KB (10.0%)
-
- FTL / 存储 (~11KB): 12.1KB (9.5%)
-
- 网络 / CH395F (~7KB): 6.9KB (5.4%)
-
- 内核 / CMSIS (~3KB): 3.0KB (2.3%)
-
- HAL 驱动 (~1.4KB): 1.4KB (1.1%)
-
- 其他静态 (~0.5KB): 0.5KB (0.4%)
-
- SRAM 空闲: 5.8KB (4.6%)
-已用: 122.2KB (95.4%) 空闲: 5.8KB (4.6%) 总量: 128KB
+SRAM (192KB) 使用布局 — 2026-09-21 @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
+
+ 主SRAM LVGL: 40.5KB (31.6%)
+
+ 主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 HAL: 1.2KB (1.0%)
+
+ 主SRAM C stack: 1.0KB (0.8%)
+
+ 主SRAM other: 1.1KB (0.9%)
+
+ 主SRAM free: 47.9KB (37.4%)
+
+ CCM heap: 48.0KB (75.0%)
+
+ CCM free: 16.0KB (25.0%)
diff --git a/tools/arch_diagram/gen_memory_svg.py b/tools/arch_diagram/gen_memory_svg.py
index 5d9623d4..db0bcb49 100644
--- a/tools/arch_diagram/gen_memory_svg.py
+++ b/tools/arch_diagram/gen_memory_svg.py
@@ -17,28 +17,38 @@ import sys
# Diagram data
# ---------------------------------------------------------------------------
-# ── RAM breakdown (128KB = 131,072 B) ────────────────────────────────────────
-SRAM_TOTAL = 131072
-SRAM_USED = 125104
-SRAM_FREE = SRAM_TOTAL - SRAM_USED
+# ── RAM breakdown (2026-09-21 @build, map Grand Totals; data/ram_report_20260921.md) ──
+# Region 1: main SRAM RW_IRAM1 @0x20000000 (128KB = 131,072 B, DMA-reachable)
+SRAM1_TOTAL = 131072
+SRAM1_USED = 82048
+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
+CCM_FREE = CCM_TOTAL - CCM_USED
-RAM_CATEGORIES = [
- ("FreeRTOS 堆\n(48KB heap_4)", 49152, "#2196F3"),
- ("LVGL 内存池\n(40KB)", 40960, "#4CAF50"),
- ("UI 帧缓冲\n(~13KB)", 13158, "#FF9800"),
- ("FTL / 存储\n(~11KB)", 12416, "#9C27B0"),
- ("网络 / CH395F\n(~7KB)", 7110, "#F44336"),
- ("内核 / CMSIS\n(~3KB)", 3024, "#00BCD4"),
- ("HAL 驱动\n(~1.4KB)", 1400, "#607D8B"),
- ("其他静态\n(~0.5KB)", 498, "#795548"),
- ("SRAM 空闲", SRAM_FREE, "#E0E0E0"),
+RAM1_CATEGORIES = [
+ ("LVGL", 41460, "#4CAF50"),
+ ("UI", 13532, "#FF9800"),
+ ("FTL/BBT", 8812, "#9C27B0"),
+ ("lftpd", 5324, "#8BC34A"),
+ ("CMSIS", 5016, "#00BCD4"),
+ ("NET", 4445, "#F44336"),
+ ("HAL", 1280, "#607D8B"),
+ ("C stack", 1024, "#795548"),
+ ("other", 1155, "#9E9E9E"),
+ ("free", SRAM1_FREE, "#E0E0E0"),
+]
+RAM2_CATEGORIES = [
+ ("heap", 49184, "#2196F3"),
+ ("free", CCM_FREE, "#E0E0E0"),
]
-# ── Flash breakdown (1MB = 1,048,576 B) ─────────────────────────────────────
+# ── Flash breakdown (1MB = 1,048,576 B; 2026-09-21 @build) ──────────────────
FLASH_TOTAL = 1048576
-FLASH_CODE = 219976
-FLASH_RO = 11496
-FLASH_RW = 528
+FLASH_CODE = 234976
+FLASH_RO = 13824
+FLASH_RW = 632
FLASH_USED = FLASH_CODE + FLASH_RO + FLASH_RW
FLASH_FREE = FLASH_TOTAL - FLASH_USED
@@ -49,30 +59,37 @@ FLASH_CATEGORIES = [
("Flash 空闲", FLASH_FREE, "#E0E0E0"),
]
-# Flash code sub-breakdown (top categories from map analysis)
+# 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_SUB = [
- ("LVGL 库", 69364, "#4CAF50"),
- ("应用代码/UI", 42540, "#2196F3"),
+ ("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"),
- ("FatFS + dhara", 11540, "#9C27B0"),
- ("CH395F 网络", 8776, "#F44336"),
- ("HAL 驱动", 9400, "#607D8B"),
- ("FreeRTOS", 4240, "#00BCD4"),
- ("其他", 69886, "#E0E0E0"), # remainder
+ ("其他 (长尾)", 56638, "#E0E0E0"), # remainder
]
-# ── Task stack budgets ─────────────────────────────────────────────────────
+# ── Task stack budgets (2026-09-21 @build + FTP 128KB 实测; data/stack_report_20260921.md) ──
+# (name, cfg, prio, worst, peak_used, margin, margin_pct, verdict, desc)
+# worst = max(静态最坏深度, 实测峰值); margin = cfg - worst
TASK_STACKS = [
- ("defaultTask", 2048, "Normal", "FatFS 挂载、LED"),
- ("netTask", 4096, "Normal", "CH395F 轮询、消息处理"),
- ("ftpTask", 4096, "Normal", "lftpd FTP 服务"),
- ("testTask", 4096, "BelowNormal", "测试套件"),
- ("uiTask", 16384, "BelowNormal", "LVGL UI 主循环"),
- ("timeSyncTask", 2048, "Normal", "TCP 时间同步"),
+ ("defaultTask", 4096, "Normal", 2776, 2136, 1320, 32, "PASS", "FatFS 挂载/探针 + 配置引擎 + syslog + 栈探针"),
+ ("netTask", 4096, "Normal", 588, 588, 3508, 85, "PASS", "CH395F 轮询、消息处理"),
+ ("ftpTask", 4096, "Normal", 1184, 1184, 2912, 71, "PASS", "lftpd FTP 服务(大缓冲已静态化)"),
+ ("testTask", 8192, "BelowNormal", 348, 348, 7844, 95, "PASS", "测试套件(产品构建空转)"),
+ ("uiTask", 16384, "BelowNormal", 3824, 3824, 12560, 76, "PASS", "LVGL UI 主循环"),
+ ("timeSyncTask", 2048, "Normal", 420, 420, 1628, 79, "PASS", "TCP 时间同步"),
]
+KERNEL_STACKS = [("idle", 512), ("timer", 1024)] # 128/256 words
-HEAP_FREE = 49152 - (2048+4096+4096+4096+16384+2048+512+1024+80*8+448+24)
-# = 49152 - 35304 = 13848 (approximate; stacks+TCBs+queue+eventgroup)
+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,912
# ---------------------------------------------------------------------------
# SVG helpers
@@ -148,44 +165,69 @@ def _draw_bar_segment(x, y, w, h, fill, label_inside, label_outside="",
# ---------------------------------------------------------------------------
def gen_ram_svg():
- """内存布局_RAM.svg — horizontal stacked bar with legend."""
- W, H = 820, 320
- BAR_X, BAR_Y, BAR_H = 60, 50, 50
- SCALE = (W - 80) / SRAM_TOTAL
+ """内存布局_RAM.svg — 两条堆叠条:主 SRAM(DMA 可达)+ CCM(仅 CPU)。"""
+ W, H = 820, 360
+ BAR_X, BAR_H = 60, 44
+ SCALE = (W - 80) / SRAM1_TOTAL # 128KB 占满宽;CCM (64KB) 占半宽
svg = svg_header(W, H)
- svg += f'SRAM (128KB) 使用布局\n'
+ svg += f'SRAM (192KB) 使用布局 — 2026-09-21 @build\n'
+ # Region 1: 主 SRAM
+ y1 = 50
+ svg += f'主 SRAM RW_IRAM1 @0x20000000(128KB,DMA 可达)\n'
x = BAR_X
- for label, size, color in RAM_CATEGORIES:
+ for label, size, color in RAM1_CATEGORIES:
w = size * SCALE
if w < 1:
continue
- inside = label.replace("\n", " ") if w > 30 else ""
- outside = "" if w > 30 else label.replace("\n", " ")
- svg += _draw_bar_segment(x, BAR_Y, w, BAR_H, color, inside, outside)
+ inside = label if w > _text_width(label) + 10 else ""
+ svg += _draw_bar_segment(x, y1, w, BAR_H, color, inside, "")
x += w
-
- # Legend
- lx, ly = 60, 130
- for label, size, color in RAM_CATEGORIES:
- pct = size / SRAM_TOTAL * 100
- kb = size / 1024
- display = label.replace("\n", " ")
- svg += f' \n'
- svg += f' '
- svg += f'{display}: {kb:.1f}KB ({pct:.1f}%)\n'
- ly += 16
- if ly > H - 20:
- lx += 260
- ly = 130
-
- # Summary text
- svg += f''
- svg += f'已用: {SRAM_USED/1024:.1f}KB ({SRAM_USED/SRAM_TOTAL*100:.1f}%)'
- svg += f' 空闲: {SRAM_FREE/1024:.1f}KB ({SRAM_FREE/SRAM_TOTAL*100:.1f}%)'
+ svg += f''
+ svg += f'已用: {SRAM1_USED}B ({SRAM1_USED/SRAM1_TOTAL*100:.1f}%)'
+ svg += f' 空闲: {SRAM1_FREE}B ({SRAM1_FREE/SRAM1_TOTAL*100:.1f}%)'
svg += f' 总量: 128KB\n'
+ # Region 2: CCM
+ y2 = y1 + BAR_H + 50
+ svg += f'CCM RW_CCM @0x10000000(64KB,仅 CPU 可达,DMA 不可达)\n'
+ x = BAR_X
+ for label, size, color in RAM2_CATEGORIES:
+ w = size * SCALE
+ if w < 1:
+ continue
+ inside = label if w > _text_width(label) + 10 else ""
+ svg += _draw_bar_segment(x, y2, w, BAR_H, color, inside, "")
+ x += w
+ 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'
+
+ # Legend(主 SRAM 两列 + CCM 两行)
+ ly = y2 + BAR_H + 40
+ lx = 60
+ half = (len(RAM1_CATEGORIES) + 1) // 2
+ for i, (label, size, color) in enumerate(RAM1_CATEGORIES):
+ pct = size / SRAM1_TOTAL * 100
+ kb = size / 1024
+ if i >= half:
+ lx2 = 420
+ else:
+ lx2 = 60
+ yy = 226 + (i % half) * 16
+ svg += f' \n'
+ svg += f' '
+ svg += f'主SRAM {label}: {kb:.1f}KB ({pct:.1f}%)\n'
+ for i, (label, size, color) in enumerate(RAM2_CATEGORIES):
+ pct = size / CCM_TOTAL * 100
+ kb = size / 1024
+ yy = 322 + i * 16
+ svg += f' \n'
+ svg += f' '
+ svg += f'CCM {label}: {kb:.1f}KB ({pct:.1f}%)\n'
+
svg += svg_footer()
return svg
@@ -197,7 +239,7 @@ def gen_flash_svg():
SCALE = (W - 80) / FLASH_TOTAL
svg = svg_header(W, H)
- svg += f'Flash (1MB) 使用布局\n'
+ svg += f'Flash (1MB) 使用布局 — 2026-09-21 @build\n'
x = BAR_X
for label, size, color in FLASH_CATEGORIES:
@@ -234,57 +276,63 @@ def gen_flash_svg():
def gen_taskstack_svg():
- """任务栈预算.svg — horizontal bars for each task's stack allocation."""
- W, H = 740, 340
- BAR_X = 180
+ """任务栈预算.svg — 每任务:分配栈条 + 最坏占用叠加条 + 实测余量/判定。"""
+ W, H = 880, 440
+ BAR_X = 190
MAX_STACK = 16384
SCALE = (W - BAR_X - 40) / MAX_STACK
- ROW_H = 30
- Y_START = 60
+ Y_START = 64
+ ROW_PITCH = 40
+ BAR_H = 16
svg = svg_header(W, H)
- svg += f'FreeRTOS 任务栈分配 (48KB 堆池)\n'
-
- # Header
- svg += f'分配栈大小 (Bytes)\n'
+ svg += f'FreeRTOS 任务栈预算(48KB 堆,2026-09-21 已迁 CCM)\n'
+ svg += f'数据: 2026-09-21 @build + FTP 128KB 实测(data/stack_report_20260921.md)\n'
+ svg += f'浅色条 = 分配栈 深色条 = 最坏占用(max(静态最坏, 实测峰值)) 下方文字 = 实测余量/判定\n'
y = Y_START
- for name, stack, prio, desc in TASK_STACKS:
- w = stack * SCALE
- color = "#2196F3" if "Normal" in prio else "#FF9800"
+ 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"
+ vc = "#2E7D32" if verdict == "PASS" else "#C62828"
- # Task name label
- svg += f' {name}\n'
+ # 任务名(左侧)
+ svg += f' {name}\n'
+ # 分配栈条(浅色)+ 最坏占用叠加条(深色)
+ svg += f' \n'
+ svg += f' \n'
+ # 数据行
+ svg += f' '
+ svg += f'配置 {cfg}B | 实测峰值 {peak}B | 最坏 {worst}B | 余量 {margin}B ({pct}%) '
+ svg += f'{verdict}\n'
+ y += ROW_PITCH
- # Bar
- svg += f' \n'
-
- # Size inside bar
- if w > 60:
- svg += f' {stack}B ({stack/1024:.1f}KB)\n'
- else:
- svg += f' {stack}B\n'
-
- y += ROW_H + 4
-
- # FreeRTOS heap summary
- total_stacks = sum(s for _, s, _, _ in TASK_STACKS) + 512 + 1024 # app + idle + timer
+ # 内核任务(静态小栈,未取句柄实测)
y += 4
- svg += f''
- svg += f'堆总量: 49,152B (48KB) '
- svg += f'任务栈合计: ~{total_stacks}B ({total_stacks/1024:.1f}KB) '
- svg += f'空闲: ~{HEAP_FREE}B ({HEAP_FREE/1024:.1f}KB)\n'
+ for name, stack in KERNEL_STACKS:
+ w = max(stack * SCALE, 2)
+ svg += f' {name}\n'
+ svg += f' \n'
+ svg += f' {stack}B(未实测)\n'
+ y += 22
- # Color legend
- y += 18
+ # 堆汇总(实测值)
+ y += 8
+ svg += f''
+ svg += f'堆总量: {HEAP_TOTAL}B (48KB, RW_CCM) 任务栈合计: {TOTAL_STACKS}B ({TOTAL_STACKS/1024:.1f}KB) + 内核栈 {512+1024}B\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'
+ 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 += svg_footer()
return svg