fix(BSP): SPI1 完成标志收回 GD5F 私有,HAL 回调改契约转调
推荐清单第 4a 步(结构债 S-2 剩余面里唯一带"静默失效"属性的那条)。 **问题不是风格**:HAL 的 SPI 完成/错误回调是**全局唯一符号**,整个工程只能有一份 实现,当前由 CH395F 代管并按 `hspi->Instance` 分发——于是 GD5F 的完成标志 `g_spi1_dma_done` 被 CH395F 跨模块裸 `extern` 直接写,**GD5F 出错时的"释放等待者" 寄居在别人的 .c 里**。谁哪天做"CH395F 清理",把那两个 `else if (SPI1)` 分支当无关 代码删掉:编译零报错,GD5F 的 DMA 等待在出错时只能干等 `GD5F_SPI_TIMEOUT` 兜底。 **改法(时序一字不动,只换所有权)**: · 标志收为 GD5F 文件内 `static volatile uint8_t s_spi1_dma_done`(6 处引用同步改名) · GD5F 导出 `gd5f_spi1_notify_done()` / `gd5f_spi1_notify_error()`,头文件里写明 "SPI1 分支必须转调这两个函数,否则本模块的 DMA 等待在出错时只能靠超时兜底" · CH395F 删除裸 `extern`、include `gd5f2gq5ue.h`、两个 SPI1 分支改为转调并就地注明 "勿删:少了这行 GD5F 的 DMA 出错只能靠超时退出" `HAL_SPI_AbortCpltCallback`(`HAL_SPI_DMAStop()` 会触发)本次**刻意不做**——它会改 变中止语义、需要真机专项,当前超时兜底可用(已在报告 §0.4 记为观察项)。 **体量代价**:`ch395f.o` −8 B、`gd5f2gq5ue.o` +24 B → `Code` 213,188 → **213,204 B (+16 B)**,RO/RW/ZI 全不变,`ER_IROM1` 231,768 → **231,784 B(22.1%)**。16 B 换 掉一个静默失效类,划算。 **真机 `@test` PASS**:无 `[ERR]`/Fault,复位原因 software;`[STACK] heap free=15800 min_ever=8464` 与改前**逐项相同**;各任务实测峰值 default 2152 / net 1116 / ftp 764 / ui 4052 / timesync 616 / adc 952 / iec104 540 / protect 624, **静态最坏链全部未变**(3024/1912/1456/4052/1264/1320/1456/872)→ 9/9 PASS。 ⚠ 记一条读数陷阱:测试脚本打印的 "boot to net init: OK = 7,907 ms" 是采集窗口 锚点造成的度量偏差,真机日志里 `boot: syslog init OK → net init: OK` 实测 ≈699 ms, 与改前一致,**不是性能回退**。 **数字联动**:`data/ram_report_20261022.md`、`data/stack_report_20261022.md` 重跑; `ram_baseline.py --update/--write`;`check_mem_numbers.py --write`(RAM 方案受管区 + 台账);`gen_memory_svg.py` 常量更新后重新生成 FLASH 与任务栈两张配图(逐文本按 字号与锚点复查越界 = 0;RAM 图无需变更);报告 §1.3/§5.1/§5.4、部署文档 §3.3 的 Flash 数字同步;§0.4/§9 的 S-2 口径改为"24 处手写已消 23 处,只剩 `net_socket.c:77`"。 门禁:`@build` 0 错 0 警告;`cubemx-survival --check`、`mem-numbers`、`mem-budget` (57.4% / 87.9%)、`task-table`、`doc-links --all --sections-strict`(146 文档 0 问题)、 `id-check --strict`(增量拦截通过、可判定 82.83%)全绿;字节卫生 BOM/CR/U+FFFD/尾 空格全清;未提交 UV4 抖动的 `.uvprojx`(本次未被改写)。未推送。
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
#include <stdio.h>
|
||||
#include "ch395f.h"
|
||||
#include "spi.h"
|
||||
#include "gd5f2gq5ue.h" /* SPI1 分支转调 gd5f_spi1_notify_*(HAL SPI 回调全局唯一,本文件代管分发) */
|
||||
#include "usart.h"
|
||||
|
||||
/*
|
||||
@@ -173,14 +174,11 @@ static int ch395f_spi_dma_transfer(uint16_t len) {
|
||||
* 入口参数:hspi - SPI句柄指针 SPI_HandleTypeDef*
|
||||
* 函数说明:由HAL SPI驱动在DMA TX+RX完成后调用
|
||||
*/
|
||||
/* SPI1 DMA完成标志(定义在gd5f2gq5ue.c中) */
|
||||
extern volatile uint8_t g_spi1_dma_done;
|
||||
|
||||
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
|
||||
if (hspi->Instance == SPI2) {
|
||||
s_spi2_dma_done = 1U;
|
||||
} else if (hspi->Instance == SPI1) {
|
||||
g_spi1_dma_done = 1U;
|
||||
gd5f_spi1_notify_done(); /* 归 GD5F 所有:本文件只代 HAL 分发,不碰它的标志 */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +191,7 @@ void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) {
|
||||
if (hspi->Instance == SPI2) {
|
||||
s_spi2_dma_done = 1U;
|
||||
} else if (hspi->Instance == SPI1) {
|
||||
g_spi1_dma_done = 1U;
|
||||
gd5f_spi1_notify_error(); /* 勿删:少了这行 GD5F 的 DMA 出错只能靠超时退出 */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,14 @@ static uint8_t s_bbt_best[GD5F_BBT_SIZE]; /* 最高版本位图缓存 */
|
||||
static const uint8_t s_bbt_magic[4] = { 'G', 'B', 'B', 'T' }; /* BBT 存储魔数 "GBBT" */
|
||||
|
||||
|
||||
/* DMA 完成标志(ch395f.c 中的 HAL_SPI_TxRxCpltCallback 会设置此标志) */
|
||||
volatile uint8_t g_spi1_dma_done;
|
||||
/* DMA 完成标志(本模块私有,2026-10-22 收编):
|
||||
* HAL 的 SPI 完成/错误回调是**全局唯一符号**(整个工程只能有一份实现),当前由
|
||||
* Drivers/BSP/CH395F/ch395f.c 实现并按 hspi->Instance 分发——SPI1 分支必须转调本
|
||||
* 模块导出的 gd5f_spi1_notify_done() / gd5f_spi1_notify_error(),不得反过来由
|
||||
* CH395F 直接写本模块的变量(原先是跨模块裸 extern,删掉那两行不会报错,只会让
|
||||
* 下面的 DMA 等待循环在出错时退化成干等 GD5F_SPI_TIMEOUT)。
|
||||
*/
|
||||
static volatile uint8_t s_spi1_dma_done;
|
||||
|
||||
/* DMA 阈值(字节数超过此值使用 DMA 传输):取值定义在头文件,理由如下——
|
||||
* 阈值以下走 CPU 轮询。存在把**栈上小缓冲**直接传进本驱动做收发的大小
|
||||
@@ -68,11 +74,11 @@ volatile uint8_t g_spi1_dma_done;
|
||||
* 入口参数:hspi - 触发回调的 SPI 句柄 SPI_HandleTypeDef*
|
||||
* 返回值:无
|
||||
* 限定条件:由 HAL DMA 中断调用
|
||||
* 函数说明:仅当 SPI1 传输完成时置位 g_spi1_dma_done 标志
|
||||
* 函数说明:仅当 SPI1 传输完成时置位 s_spi1_dma_done 标志
|
||||
*/
|
||||
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {
|
||||
if (hspi->Instance == SPI1) {
|
||||
g_spi1_dma_done = 1U;
|
||||
s_spi1_dma_done = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,10 +90,32 @@ void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {
|
||||
*/
|
||||
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {
|
||||
if (hspi->Instance == SPI1) {
|
||||
g_spi1_dma_done = 1U;
|
||||
s_spi1_dma_done = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:SPI1 DMA 完成通知(供实际注册 HAL 回调的一方转调)
|
||||
* 入口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:由 HAL SPI 回调(中断上下文)调用;只写一个标志,不阻塞
|
||||
* 函数说明:HAL 的 SPI 回调在整个工程里只能有一份实现,本模块不抢占 Error 回调
|
||||
* 的所有权,只导出这两个通知入口。**转调方不得省略本调用**——少了它,
|
||||
* 出错路径只能靠 GD5F_SPI_TIMEOUT 超时退出(能自保但会静默变慢)。
|
||||
*/
|
||||
void gd5f_spi1_notify_done(void) {
|
||||
s_spi1_dma_done = 1U;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:SPI1 DMA 错误通知(释放等待者;语义与 notify_done 相同)
|
||||
* 入口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:由 HAL SPI 错误回调(中断上下文)调用
|
||||
*/
|
||||
void gd5f_spi1_notify_error(void) {
|
||||
s_spi1_dma_done = 1U;
|
||||
}
|
||||
/* ======================== 私有函数声明 ======================== */
|
||||
|
||||
static int gd5f_page_program(uint32_t page_addr, uint16_t column,
|
||||
@@ -318,12 +346,12 @@ int32_t gd5f_read_from_cache(uint16_t column, uint8_t *p_buf,
|
||||
|
||||
if (use_dma != 0U) {
|
||||
uint32_t tick_start = HAL_GetTick();
|
||||
g_spi1_dma_done = 0U;
|
||||
s_spi1_dma_done = 0U;
|
||||
if (HAL_SPI_Receive_DMA(&hspi1, p_buf, (uint16_t)size) != HAL_OK) {
|
||||
GD5F_CS_HIGH();
|
||||
return GD5F_ERROR;
|
||||
}
|
||||
while (g_spi1_dma_done == 0U) {
|
||||
while (s_spi1_dma_done == 0U) {
|
||||
if ((HAL_GetTick() - tick_start) >= GD5F_SPI_TIMEOUT) {
|
||||
HAL_SPI_DMAStop(&hspi1);
|
||||
GD5F_CS_HIGH();
|
||||
@@ -399,13 +427,13 @@ int32_t gd5f_program_load(uint16_t column, const uint8_t *p_buf, size_t size) {
|
||||
|
||||
if (use_dma != 0U) {
|
||||
uint32_t tick_start = HAL_GetTick();
|
||||
g_spi1_dma_done = 0U;
|
||||
s_spi1_dma_done = 0U;
|
||||
if (HAL_SPI_Transmit_DMA(&hspi1, (uint8_t *)p_buf, (uint16_t)size)
|
||||
!= HAL_OK) {
|
||||
GD5F_CS_HIGH();
|
||||
return GD5F_ERROR;
|
||||
}
|
||||
while (g_spi1_dma_done == 0U) {
|
||||
while (s_spi1_dma_done == 0U) {
|
||||
if ((HAL_GetTick() - tick_start) >= GD5F_SPI_TIMEOUT) {
|
||||
HAL_SPI_DMAStop(&hspi1);
|
||||
GD5F_CS_HIGH();
|
||||
|
||||
@@ -324,6 +324,19 @@ void nand_ftl_wd_beat(void);
|
||||
*/
|
||||
void nand_ftl_wd_feed(void);
|
||||
|
||||
/*
|
||||
* 函数功能:SPI1 DMA 完成 / 错误通知(由实际注册 HAL SPI 回调的模块转调)
|
||||
* 入口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:中断上下文(HAL SPI 回调内),两者只写一个完成标志
|
||||
* 函数说明:HAL 的 SPI 完成/错误回调是全局唯一符号,本模块只实现 TxCplt/RxCplt
|
||||
* 两个(供自己的收发用),Error 回调的所有权留给回调的实际注册方
|
||||
* (当前 = Drivers/BSP/CH395F/ch395f.c,按 hspi->Instance 分发)。**SPI1
|
||||
* 分支必须转调这两个函数**,否则本模块的 DMA 等待在出错时只能靠超时
|
||||
* 兜底。2026-10-22:取代原先被 CH395F 跨模块裸 extern 直接写的全局变量。
|
||||
*/
|
||||
void gd5f_spi1_notify_done(void);
|
||||
void gd5f_spi1_notify_error(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<text x="186" y="72" text-anchor="end" dominant-baseline="central" class="label" fill="#333">defaultTask</text>
|
||||
<rect class="bar-seg" x="190" y="64" width="203.1" height="16" fill="#BBDEFB" rx="3"/>
|
||||
<rect x="190" y="64" width="120.0" height="16" fill="#2196F3" rx="3"/>
|
||||
<text x="190" y="91" dominant-baseline="central" class="legend-text" fill="#333">配置 5120B | 实测峰值 2164B | 最坏 3024B | 余量 2096B (40%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="190" y="91" dominant-baseline="central" class="legend-text" fill="#333">配置 5120B | 实测峰值 2152B | 最坏 3024B | 余量 2096B (40%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="186" y="112" text-anchor="end" dominant-baseline="central" class="label" fill="#333">netTask</text>
|
||||
<rect class="bar-seg" x="190" y="104" width="152.3" height="16" fill="#BBDEFB" rx="3"/>
|
||||
<rect x="190" y="104" width="75.9" height="16" fill="#2196F3" rx="3"/>
|
||||
@@ -21,7 +21,7 @@
|
||||
<text x="186" y="152" text-anchor="end" dominant-baseline="central" class="label" fill="#333">ftpTask</text>
|
||||
<rect class="bar-seg" x="190" y="144" width="162.5" height="16" fill="#BBDEFB" rx="3"/>
|
||||
<rect x="190" y="144" width="57.8" height="16" fill="#2196F3" rx="3"/>
|
||||
<text x="190" y="171" dominant-baseline="central" class="legend-text" fill="#333">配置 4096B | 实测峰值 756B | 最坏 1456B | 余量 2640B (64%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="190" y="171" dominant-baseline="central" class="legend-text" fill="#333">配置 4096B | 实测峰值 764B | 最坏 1456B | 余量 2640B (64%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="186" y="192" text-anchor="end" dominant-baseline="central" class="label" fill="#333">uiTask</text>
|
||||
<rect class="bar-seg" x="190" y="184" width="650.0" height="16" fill="#FFE0B2" rx="3"/>
|
||||
<rect x="190" y="184" width="160.8" height="16" fill="#FF9800" rx="3"/>
|
||||
@@ -41,11 +41,11 @@
|
||||
<text x="186" y="352" text-anchor="end" dominant-baseline="central" class="label" fill="#333">iec104Task</text>
|
||||
<rect class="bar-seg" x="190" y="344" width="101.6" height="16" fill="#BBDEFB" rx="3"/>
|
||||
<rect x="190" y="344" width="57.8" height="16" fill="#2196F3" rx="3"/>
|
||||
<text x="190" y="371" dominant-baseline="central" class="legend-text" fill="#333">配置 2560B | 实测峰值 544B | 最坏 1456B | 余量 1104B (43%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="190" y="371" dominant-baseline="central" class="legend-text" fill="#333">配置 2560B | 实测峰值 540B | 最坏 1456B | 余量 1104B (43%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="186" y="392" text-anchor="end" dominant-baseline="central" class="label" fill="#333">protectTask</text>
|
||||
<rect class="bar-seg" x="190" y="384" width="81.2" height="16" fill="#BBDEFB" rx="3"/>
|
||||
<rect x="190" y="384" width="34.6" height="16" fill="#2196F3" rx="3"/>
|
||||
<text x="190" y="411" dominant-baseline="central" class="legend-text" fill="#333">配置 2048B | 实测峰值 828B | 最坏 872B | 余量 1176B (57%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="190" y="411" dominant-baseline="central" class="legend-text" fill="#333">配置 2048B | 实测峰值 624B | 最坏 872B | 余量 1176B (57%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="186" y="434" text-anchor="end" dominant-baseline="central" class="label" fill="#333">idle</text>
|
||||
<rect class="bar-seg" x="190" y="428" width="20.3" height="12" fill="#90A4AE" rx="2"/>
|
||||
<text x="214.3125" y="434" dominant-baseline="central" class="legend-text" fill="#333">512B(未实测)</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
+16
-16
@@ -10,32 +10,32 @@
|
||||
<text x="410.0" y="24" text-anchor="middle" class="title">Flash (1MB) 使用布局 — 2026-10-22 @build</text>
|
||||
<rect class="bar-seg" x="60" y="50" width="150.5" height="40" fill="#2196F3" rx="2"/>
|
||||
<text x="135.2" y="70.0" text-anchor="middle" dominant-baseline="central" class="label" fill="#000">代码段 (Code) 208.2KB</text>
|
||||
<rect class="bar-seg" x="210.45082092285156" y="50" width="13.1" height="40" fill="#4CAF50" rx="2"/>
|
||||
<rect class="bar-seg" x="210.4621124267578" y="50" width="13.1" height="40" fill="#4CAF50" rx="2"/>
|
||||
<text x="227.6" y="70.0" text-anchor="start" dominant-baseline="central" class="legend-text" fill="#333">只读数据 (RO) 18.1KB</text>
|
||||
<rect class="bar-seg" x="223.56307983398438" y="50" width="575.6" height="40" fill="#E0E0E0" rx="2"/>
|
||||
<rect class="bar-seg" x="223.57437133789062" y="50" width="575.6" height="40" fill="#E0E0E0" rx="2"/>
|
||||
<text x="511.4" y="70.0" text-anchor="middle" dominant-baseline="central" class="label" fill="#000">Flash 空闲 796.5KB</text>
|
||||
<text x="60" y="108" class="label" fill="#333">已用: 227.5KB (22.2%) 空闲: 796.5KB (77.8%) ER_IROM1(Code+RO): 226.3KB (22.1%) 总量: 1MB (= ROM 合计口径)</text>
|
||||
<text x="60" y="124" class="label" fill="#555">Code + RO 分布(ER_IROM1 226.3KB,按 .map 对象归类)</text>
|
||||
<text x="60" y="108" class="label" fill="#333">已用: 227.5KB (22.2%) 空闲: 796.5KB (77.8%) ER_IROM1(Code+RO): 226.4KB (22.1%) 总量: 1MB (= ROM 合计口径)</text>
|
||||
<text x="60" y="124" class="label" fill="#555">Code + RO 分布(ER_IROM1 226.4KB,按 .map 对象归类)</text>
|
||||
<rect class="bar-seg" x="60" y="130" width="280.0" height="24" fill="#4CAF50" rx="2"/>
|
||||
<text x="200.0" y="142.0" text-anchor="middle" dominant-baseline="central" class="label" fill="#000">85.7KB</text>
|
||||
<rect class="bar-seg" x="340.0319284802044" y="130" width="182.0" height="24" fill="#2196F3" rx="2"/>
|
||||
<rect class="bar-seg" x="340.0125979360094" y="130" width="182.0" height="24" fill="#2196F3" rx="2"/>
|
||||
<text x="431.0" y="142.0" text-anchor="middle" dominant-baseline="central" class="label" fill="#000">55.7KB</text>
|
||||
<rect class="bar-seg" x="522.0593869731802" y="130" width="81.9" height="24" fill="#F44336" rx="2"/>
|
||||
<text x="563.0" y="142.0" text-anchor="middle" dominant-baseline="central" class="label" fill="#000">25.1KB</text>
|
||||
<rect class="bar-seg" x="603.9623243933589" y="130" width="57.1" height="24" fill="#607D8B" rx="2"/>
|
||||
<text x="632.5" y="142.0" text-anchor="middle" dominant-baseline="central" class="label" fill="#000">17.5KB</text>
|
||||
<rect class="bar-seg" x="661.0376756066412" y="130" width="34.8" height="24" fill="#FF9800" rx="2"/>
|
||||
<rect class="bar-seg" x="695.8620689655173" y="130" width="34.4" height="24" fill="#00BCD4" rx="2"/>
|
||||
<rect class="bar-seg" x="730.2234993614305" y="130" width="27.0" height="24" fill="#9C27B0" rx="2"/>
|
||||
<rect class="bar-seg" x="757.2605363984676" y="130" width="17.5" height="24" fill="#795548" rx="2"/>
|
||||
<rect class="bar-seg" x="774.7765006385698" y="130" width="1.5" height="24" fill="#B0BEC5" rx="2"/>
|
||||
<rect class="bar-seg" x="776.2707535121331" y="130" width="23.7" height="24" fill="#E0E0E0" rx="2"/>
|
||||
<rect class="bar-seg" x="522.027491112415" y="130" width="81.9" height="24" fill="#F44336" rx="2"/>
|
||||
<text x="563.0" y="142.0" text-anchor="middle" dominant-baseline="central" class="label" fill="#000">25.0KB</text>
|
||||
<rect class="bar-seg" x="603.8992337693714" y="130" width="57.1" height="24" fill="#607D8B" rx="2"/>
|
||||
<text x="632.4" y="142.0" text-anchor="middle" dominant-baseline="central" class="label" fill="#000">17.5KB</text>
|
||||
<rect class="bar-seg" x="660.9706450833535" y="130" width="34.9" height="24" fill="#FF9800" rx="2"/>
|
||||
<rect class="bar-seg" x="695.8692575846478" y="130" width="34.4" height="24" fill="#00BCD4" rx="2"/>
|
||||
<rect class="bar-seg" x="730.228316018362" y="130" width="27.0" height="24" fill="#9C27B0" rx="2"/>
|
||||
<rect class="bar-seg" x="757.2634866945087" y="130" width="17.5" height="24" fill="#795548" rx="2"/>
|
||||
<rect class="bar-seg" x="774.7782418113417" y="130" width="1.5" height="24" fill="#B0BEC5" rx="2"/>
|
||||
<rect class="bar-seg" x="776.2723915369482" y="130" width="23.7" height="24" fill="#E0E0E0" rx="2"/>
|
||||
<rect x="60" y="167" width="10" height="10" fill="#4CAF50" rx="2"/>
|
||||
<text x="74" y="176" class="legend-text" fill="#333">LVGL 库 85.7KB</text>
|
||||
<rect x="255" y="167" width="10" height="10" fill="#2196F3" rx="2"/>
|
||||
<text x="269" y="176" class="legend-text" fill="#333">应用代码/UI 55.7KB</text>
|
||||
<rect x="450" y="167" width="10" height="10" fill="#F44336" rx="2"/>
|
||||
<text x="464" y="176" class="legend-text" fill="#333">CH395F+FTP 25.1KB</text>
|
||||
<text x="464" y="176" class="legend-text" fill="#333">CH395F+FTP 25.0KB</text>
|
||||
<rect x="645" y="167" width="10" height="10" fill="#607D8B" rx="2"/>
|
||||
<text x="659" y="176" class="legend-text" fill="#333">HAL 驱动 17.5KB</text>
|
||||
<rect x="60" y="183" width="10" height="10" fill="#FF9800" rx="2"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
@@ -38,10 +38,10 @@
|
||||
<!-- MEM_SNAPSHOT:BEGIN generated by scripts/check_mem_numbers.py -->
|
||||
| 区域 | 用量 | 容量 | 占比 |
|
||||
|---|---|---|---|
|
||||
| ER_IROM1 | 231,768 B (226.34 KB) | 1,048,576 B (1024 KB) | 22.1% |
|
||||
| ER_IROM1 | 231,784 B (226.35 KB) | 1,048,576 B (1024 KB) | 22.1% |
|
||||
| RW_IRAM1 | 75,264 B (73.50 KB) | 131,072 B (128 KB) | 57.4% |
|
||||
| RW_CCM | 57,376 B (56.03 KB) | 65,280 B (64 KB) | 87.9% |
|
||||
| **Flash (ROM 合计)** | **232,952 B (227.5 KB)** | 1,048,576 B (1024 KB) | **22.2%** |
|
||||
| **Flash (ROM 合计)** | **232,968 B (227.5 KB)** | 1,048,576 B (1024 KB) | **22.2%** |
|
||||
<!-- MEM_SNAPSHOT:END -->
|
||||
|
||||
各区的容量与常量来源:
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<!-- MEM_BUDGET:BEGIN generated by scripts/ram_baseline.py -->
|
||||
| 区域 | 用量 | 容量 | 占比 | 门禁(≤92%) |
|
||||
|---|---|---|---|---|
|
||||
| ER_IROM1 (Flash) | 231,768 B | 1,048,576 B | 22.1% | 参考 |
|
||||
| ER_IROM1 (Flash) | 231,784 B | 1,048,576 B | 22.1% | 参考 |
|
||||
| RW_CCM | 57,376 B | 65,280 B | 87.9% | PASS |
|
||||
| UNINIT_CCM | 48 B | 256 B | 18.8% | 参考 |
|
||||
| RW_IRAM1 | 75,264 B | 131,072 B | 57.4% | PASS |
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
# STM32F4-Base RAM/Flash Usage Report
|
||||
|
||||
> Generated: 2026-10-22 12:06 Map: `STM32F407-Demo.map`
|
||||
> Generated: 2026-10-22 19:14 Map: `STM32F407-Demo.map`
|
||||
|
||||
## 1. Grand Totals (全局总量)
|
||||
|
||||
| Metric | Value |
|
||||
|---|---|
|
||||
| Code (inc. data) | 213,188 B (208.2 KB) |
|
||||
| Code (inc. data) | 213,204 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 RO (Code + RO)** | **231,784 B (226.4 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)** |
|
||||
| **Total ROM (Code + RO + RW init)** | **232,968 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% |
|
||||
| ER_IROM1 | 0x08000000 | 231,784 B (226.35 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% |
|
||||
@@ -140,7 +140,7 @@
|
||||
| 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 |
|
||||
| 7 | ch395f.o | 3,978 | 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 |
|
||||
@@ -150,7 +150,7 @@
|
||||
| 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 |
|
||||
| 17 | gd5f2gq5ue.o | 3,954 | 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 |
|
||||
@@ -204,7 +204,7 @@
|
||||
| 68 | vol_lock.o | 92 | 0 | 4 | 0 | 4 |
|
||||
| 69 | errno.o | 20 | 0 | 4 | 0 | 4 |
|
||||
| 70 | ui_page_net_cfg.o | 1,004 | 105 | 2 | 0 | 2 |
|
||||
| | **All .o files** | **213,188** | **18,580** | **1,184** | **131,504** | **132,688** |
|
||||
| | **All .o files** | **213,204** | **18,580** | **1,184** | **131,504** | **132,688** |
|
||||
|
||||
## 5. Flash (Code + RO Data) Top-30(按大小降序)
|
||||
|
||||
@@ -215,11 +215,11 @@
|
||||
| 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 |
|
||||
| 6 | ch395f.o | 3,978 | 603 | 4,581 |
|
||||
| 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 |
|
||||
| 10 | gd5f2gq5ue.o | 3,954 | 478 | 4,432 |
|
||||
| 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 |
|
||||
@@ -240,6 +240,6 @@
|
||||
| 28 | printfa.o | 2,312 | 0 | 2,312 |
|
||||
| 29 | stm32f4xx_hal_i2c.o | 2,294 | 0 | 2,294 |
|
||||
| 30 | lv_display.o | 2,284 | 0 | 2,284 |
|
||||
| | **All .o files** | **213,188** | **18,580** | **231,768** |
|
||||
| | **All .o files** | **213,204** | **18,580** | **231,784** |
|
||||
|
||||
> 自洽校验: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**
|
||||
> 自洽校验:per-file 213,204/18,580/1,184/131,504 vs Grand Totals 213,204/18,580/1,184/131,504(CodeΔ=+0 / ROΔ=+0 / RWΔ=+0 / ZIΔ=+0;精确一致(含 '('incl. Generated)'-'(incl. Padding)' 台账行))→ **PASS**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Stack budget report
|
||||
|
||||
- Source: `MDK-ARM\STM32F407-Demo\STM32F407-Demo.htm` (Keil static call graph)
|
||||
- Linker run: Thu Oct 22 10:36:17 2026
|
||||
- Linker run: Thu Oct 22 19:12:02 2026
|
||||
- Global maximum stack usage: **3024 B** (any call tree)
|
||||
- Runtime watermark: 8 task(s) from 串口采集日志 `.dsh\skills\serial-assistant\scripts\state\serial.log`
|
||||
|
||||
@@ -9,15 +9,15 @@ Rule: `margin = cfg - max(static_max_depth, runtime_peak)` must be >= max(1024 B
|
||||
|
||||
| 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 |
|
||||
| defaultTask | `StartDefaultTask` | 5120 | 3024 | 2152 | 3024 | 2096 | 40% | PASS |
|
||||
| netTask | `StartNetTask` | 3840 | 1912 | 1116 | 1912 | 1928 | 50% | PASS |
|
||||
| ftpTask | `StartFtpTask` | 4096 | 1456 | 756 | 1456 | 2640 | 64% | PASS |
|
||||
| ftpTask | `StartFtpTask` | 4096 | 1456 | 764 | 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 |
|
||||
| iec104Task | `iec104_serv_task` | 2560 | 1456 | 540 | 1456 | 1104 | 43% | PASS |
|
||||
| protectTask | `protect_task` | 2048 | 872 | 624 | 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.
|
||||
|
||||
|
||||
@@ -504,7 +504,7 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级
|
||||
|
||||
| 资源 | 已用 | 总量 | 利用率 | 余量 | 红线说明 |
|
||||
|---|---|---|---|---|---|
|
||||
| Flash(`ER_IROM1` = Code + RO) | 231,768 B(226.3 KB) | 1 MB | 22.1% | ≈804 KB | **充裕**:产品需求无 OTA / 双镜像预算,Flash 不是卡点;死代码裁剪簇已收口 → `docs/问题记录/项目审查与优化建议报告.md` §5.4 |
|
||||
| Flash(`ER_IROM1` = Code + RO) | 231,784 B(226.4 KB) | 1 MB | 22.1% | ≈804 KB | **充裕**:产品需求无 OTA / 双镜像预算,Flash 不是卡点;死代码裁剪簇已收口 → `docs/问题记录/项目审查与优化建议报告.md` §5.4 |
|
||||
| 主 SRAM1(静态区;FreeRTOS 堆已迁 CCM) | 75,264 B(73.5 KB) | 128 KB | 57.4% | 55,808 B | 已不紧张——2026-10-11 堆迁 CCM 与 2026-10-15 `LV_MEM_SIZE` 40→16 KB 两步的结果 |
|
||||
| CCM(`RW_CCM` 段) | 57,376 B(56.0 KB) | 65,280 B | **87.9%** | **7,904 B** | **当前真正的红线**:加任务 / 抬栈 / 加堆会先在这里撞墙;`mem-budget` 钩子在 92% 拦提交 |
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
| 内存 RAM | N-14 🟡(N-22) | FTL 单页写回缓存无空闲/掉电强制 flush(整页写与换页已 flush,`f_close` 经 `CTRL_SYNC` 已落盘) | 用户裁定 2026-10-22 暂不做;残余窗口只是"单条记录" |
|
||||
| Flash | **F-5 🟡 观察项**(N-28) | uvprojx 201 个 LVGL `.c` 里 **127 个空 TU**;增量构建 4~5 s、CI 不跑 `@build` | 有实测全量耗时痛点再做,用 `<IncludeInBuild>` |
|
||||
| 结构 | **S-1 ❌**(口径已按实测更正) | **不是"命名错位",是真实的 BSP→App 反向依赖**:`Drivers/BSP/NETCFG/{net_cfg,ftp_cfg}.c` include `App/cfg/cfg_file.h`(10 处调用点:`cfg_file_load/save/poll/register`),`Drivers/BSP/UI` 另有 3 个文件 include App 层头(`ui_page_runlog.c`、`ui_page_selftest.c`、`ui_w_records.h`);21 个 BSP 文件用 `dbg_log.h`(横切,待显式豁免) | **反转依赖**(约 7 文件 / 15 处)。⚠ 修正一条我先前写下的理由:这不是"运行时属主纪律被破"——UI 只投递 `net_cfg_save_request()`,写盘仍在 defaultTask,且 NETCFG 已有 `net_cfg_set_save_req_cb` / `net_cfg_request_apply` 的**回调注入**先例;也不是"测不了"——模拟器今天就在主机侧跑 `net_cfg_load → poll → save` 整条链(`../../simulator/README.md` 的验证链)。要修的只是**静态分层方向**(BSP 引用了 App 的头)+ 加一条「`Drivers/BSP/**` 不得 include `App/**`」的门禁;**目录搬迁暂缓**(远程 CI 仍不跑 `@build`,兜底未成立) |
|
||||
| 结构 | **S-2 大半已消**(24 处手写已消 22 处) | **该修的手写跨模块裸 `extern` 共 24 处,今天已消 22 处,只剩 2 处**:`ch395f.c:177`(CH395F 裸写 GD5F 的 `g_spi1_dma_done`,还在 `HAL_SPI_ErrorCallback` 的 SPI1 分支里**替 GD5F 释放等待者**——谁清理那两行「看着无关」的分支,编译零报错,GD5F 的 DMA 出错就退化成干等 `GD5F_SPI_TIMEOUT`)与 `net_socket.c:77`(`netMsgQueueHandle` 跨文件裸引)。已消的 22 处 = 2 处与 `Inc/spi.h` / `Inc/i2c.h` 重复(GD5F/SD2506)+ 19 处任务句柄与属性(`default_task.c:52-69` 的 18 行 + `adc_task.c:125`)+ 1 处 `main.c` 函数内的 `g_rcc_csr_latched`。**两类不算债要分清**:`stm32f4xx_it.c:241-256` 那 16 条是 CubeMX「External variables」生成块(删了会被重生成写回来);`:183/195/207/220` 那 4 条是手写在 `__asm` Handler 里引用汇编标签 `fault_entry_*`(ARMCC `__asm` 取不到 C 数据符号,**合法例外**)。上一版写的「25 处」把这两类混进来了,已更正 | 剩余两步:① `ch395f.c` 改为经 GD5F 导出的 `gd5f_spi1_notify_done()` / `notify_error()` 转调(标志收回 GD5F 内部)② `netMsgQueueHandle` 收进 net_socket 内部 + 提供投递 API |
|
||||
| 结构 | **S-2 只剩 1 处**(24 处手写已消 23) | 今天已消 23 处:2 处与 `Inc/spi.h`/`Inc/i2c.h` 重复(GD5F/SD2506)+ 19 处任务句柄与属性(新建 `App/task/task_handles.h`)+ 1 处 `main.c` 函数内 `g_rcc_csr_latched`(改由 `App/app/app_main.h` 声明)+ 1 处 `ch395f.c:177`(**改为契约转调**:GD5F 的完成标志收为文件内 `static`,导出 `gd5f_spi1_notify_done()` / `gd5f_spi1_notify_error()`,CH395F 那个"HAL 全局唯一回调"的 SPI1 分支只转调、不再直接写它的变量;`HAL_SPI_AbortCpltCallback` 仍无人实现 → 另列观察)。**只剩 `net_socket.c:77` 的 `netMsgQueueHandle`**。**两类不算债**:`stm32f4xx_it.c:241-256` 是 CubeMX「External variables」生成块(删了会被写回来);`:183/195/207/220` 是 `__asm` Handler 里的汇编标签引用(ARMCC `__asm` 取不到 C 数据符号,**合法例外**) | 剩下一步:`netMsgQueueHandle` 收进 net_socket 内部 + 提供投递 API |
|
||||
| 驱动规范 | S-5 ❌ | `bsp_err_t` 至今只出现在本报告里(无统一错误码/超时/重试约定) | 定义后进 `docs/代码规范/` |
|
||||
| 网络 | N-09 / PHY ❌(N-25) | `NET_MAX_SOCKETS` 仍为 8(与单连接复用语义不符);PHY 强制 100M 无自协商回退;PASV 每次新建监听 | 见 §4.2;随 N-25 一并处置 |
|
||||
| 存储 | N-15 🟡(N-25) | `nand_ftl.o` 静态 6,216 B——三块 2 KB 级页缓冲并存未合并 | 与 R-3 同批评估 |
|
||||
@@ -88,7 +88,7 @@ git ls-files -z | xargs -0 stat -c '%s'
|
||||
|
||||
| 名词 | 口径 |
|
||||
|---|---|
|
||||
| Flash 占用 | `Code + RO-data` = `ER_IROM1` = **231,768 B(22.1%)**;`ROM 合计` 再加 `RW` 初始化表 = 232,952 B(22.2%) |
|
||||
| Flash 占用 | `Code + RO-data` = `ER_IROM1` = **231,784 B(22.1%)**;`ROM 合计` 再加 `RW` 初始化表 = 232,968 B(22.2%) |
|
||||
| SRAM 占用 | `RW_IRAM1`(DMA 可达区)与 `RW_CCM`(仅 CPU)分开计,二者不可互换(规则 R2/R3) |
|
||||
| 最坏栈 | `max(armlink 静态调用图深度, 真机 [STACK] 高水位)`;判定线 `余量 ≥ max(1024 B ISR, 配置×30%)` |
|
||||
| 编译单元 | uvprojx 的 `<FilePath>` 计数(今日 **326 个 `.c`**,其中 LVGL 201);"自研 `.c`" 另按目录口径 114 个 |
|
||||
@@ -225,8 +225,8 @@ defaultTask 单属主;原子写经卷锁;旧档迁移已删除。**仍列为
|
||||
|
||||
| 指标 | 2026-10-22 | 2026-10-15 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `Code` | 213,188 B | 213,520 B | F-6 收口 −332 B |
|
||||
| `ER_IROM1`(Code+RO) | **231,768 B / 22.1%** | 232,280 B / 22.2% | 余 ≈804 KB |
|
||||
| `Code` | 213,204 B | 213,520 B | F-6 收口 −332 B;同日 SPI 回调归属纠正 +16 B |
|
||||
| `ER_IROM1`(Code+RO) | **231,784 B / 22.1%** | 232,280 B / 22.2% | 余 ≈804 KB |
|
||||
| `RW_IRAM1` | **75,264 B / 57.4%**(余 55,808) | 73,568 B / 56.1% | 增量来自 B5/B8 功能码 |
|
||||
| `RW_CCM` | **57,376 B / 87.9%**(余 7,904) | 57,376 B / 87.9% | **当前唯一红线** |
|
||||
| FreeRTOS 堆 | 56 KB(57,344 B)@CCM;实测 `free=15,800` / `min_ever=8,464` | 同 | 2026-10-22 真机 |
|
||||
@@ -266,7 +266,7 @@ defaultTask 单属主;原子写经卷锁;旧档迁移已删除。**仍列为
|
||||
| **F-6** 双精度软浮点 | ≈1 KB | **归因错**:全库 0 处 `%f`;剩余 `dadd/dmul/ddiv/depilogue/dfixul` 1,018 B 锁在 MicroLIB `printfa.o` 的 `_printf_core → _fp_digits`,只要用 `snprintf` 就删不掉。但**根因侧确有可修点**:`App/algo/prot_set.h` 两个 Q10 宏写成 `double` | ✅ **已落地 2026-10-22**:改单精度 → `@build` −332 B、5 个 helper(300 B)消失;数值逐位等价(穷举 42 个字面量 + int32 全域 ÷1024 往返 4.49×10⁶ 例零差异);真机 `@test` PASS |
|
||||
|
||||
**当前可回收 Flash = 0 B**(F-4/F-6 已定论,图片链同理不打补丁)。LVGL 仍占镜像 **37.8%**
|
||||
(87,706 / 231,768 B)——这是"用 LVGL 画单色菜单"的结构性代价,F-1/F-2/F-3 已省掉 64,576 B。
|
||||
(87,706 / 231,784 B)——这是"用 LVGL 画单色菜单"的结构性代价,F-1/F-2/F-3 已省掉 64,576 B。
|
||||
|
||||
### 5.5 内存治理长效机制(常开,不受暂缓影响)
|
||||
|
||||
@@ -374,7 +374,7 @@ W6 簇按 U4 → U1 → U3 → U2 的顺序执行完毕(U2 停在"够用即止
|
||||
| **D-1** | 外部资料与工程文档同仓同树 | ❌ 暂不处理 | 本文 §3.3、登记簿 N-29 |
|
||||
| D-2 ~ D-7 | 文档治理条目(链接/同源/编号/BOM 等) | ✅ 多数已制度化为钩子 | 本文 §3.2、`../文档规范.md` |
|
||||
| D-9 | 文档面残余观察 | 🟡 观察 | 本节即定义位 |
|
||||
| **S-1 / S-2** | 分层反向依赖 / 跨模块裸 `extern` | 🟡 半办(2026-10-22:S-2 的 24 处手写已消 22 处、剩 2 处;S-1 未动 = NETCFG+UI 反向 include) | 本文 §0.4、登记簿 C5 |
|
||||
| **S-1 / S-2** | 分层反向依赖 / 跨模块裸 `extern` | 🟡 半办(2026-10-22:24 处手写裸 extern 已消 23 处,只剩 `net_socket.c:77`;S-1 未动 = NETCFG+UI 反向 include) | 本文 §0.4、登记簿 C5 |
|
||||
| **S-4** | `app_cfg.h` 未接线占位开关 | ✅ **已闭环 2026-10-22**(4 个零消费点宏删除) | `App/app/app_cfg.h` 修改记录 v1.2;口径同步见 `../环境与部署/项目部署环境要求.md` §3.2/§3.5、`../产品需求/产品需求设计文档.md`、`../任务规划/排期详述.md` C5 |
|
||||
| **S-3** | `.ioc` 侧 USART1 配置 | ❌ 在策 | 登记簿 S-3 |
|
||||
| **S-5** | 统一 `bsp_err_t` 错误码约定 | ❌ 未做 | 本文 §0.4、`docs/代码规范/`(待建) |
|
||||
@@ -409,6 +409,27 @@ W6 簇按 U4 → U1 → U3 → U2 的顺序执行完毕(U2 停在"够用即止
|
||||
**改判的三条旧结论**:① §6 的 U1/U3/U4 原写「❌ 未建」,实际已落地(`ui_tokens.h` 69 行、`ui_page_registry.c` 描述符注册表、`ui-golden`+`font-charset` 两枚钩子);U2 只有 `ui_w_records` 一个组件;"27 页未落地"实为 7 页。② "新增一页 ≤30 行"目标**未达**(最省 40 行),如实记为未达项。③ §0.4 与登记簿已漂开 → 本版把待办清单降级为**快照 + 指向登记簿**,权威只留一处。
|
||||
**刻意保留的三层**(删了会出事):§9 **编号族登记处**——本文是 `id_registry.json` 里 `N-RPT`/`D-RPT`/`S-RPT`/`R-RPT`(游标 R-9)/`F-RPT`/`U-RPT`(游标 U5) 六族的属主登记处,且外部存在「报告 N-14」「报告 F-4/F-5/F-6」「报告 D-1」「报告 R-2/R-3」式紧邻引用与 `check_dangling`,删定义位即触发编号门禁;§1.2/§1.3 方法与口径(数字可重跑);文末**变更记录 + 已销项去处表**原样冻结保留(52 行)。被外部点名的锚点(`§0.3`/`§3.1`/`§4.1`/`§4.2`/`§4.3`/`§5.3`×9/`§5.4`/`§5.5`×4/`§6.2`/`§6.3`/`§6.5`)逐个保留,**68 处入站引用零改动**。
|
||||
**门禁**:`check_doc_links.py --all --sections-strict` → 146 文档 0 问题(章节引用 2,499、可判定 1,483);`check_ids.py --strict` 增量拦截通过、**存量债 650 → 641(−9)**、可判定比例 82.98% → **82.79%**(仍高于基线 82.6%,但缓冲从 0.38pp 缩到 0.19pp——删掉的那批引用 99% 是可判定的,属预期副作用);`mem-numbers` / `ram_baseline --gate` / `task-table` / `cubemx-survival` 全 0。字节卫生:BOM 无 / CR 0 / U+FFFD 0 / 无行尾空格 / LF 结尾。 |
|
||||
| **2026-10-22** | **S-2 第三步:SPI1 完成标志的回调归属拆清**(推荐清单第 4a 步) | 问题不是风格:HAL 的 SPI 完成/错误回调
|
||||
是**全局唯一符号**,全工程只能有一份实现,当前由 CH395F 代管并按 `hspi->Instance` 分发——于是 GD5F 的
|
||||
`g_spi1_dma_done` 被 CH395F 跨模块裸 `extern` 直接写,**GD5F 出错时的"释放等待者"寄居在别人的 .c 里**。
|
||||
谁哪天做"CH395F 清理",把那两个 `else if (SPI1)` 分支当无关代码删掉:**编译零报错**,GD5F 的 DMA 等待
|
||||
在出错时只能干等 `GD5F_SPI_TIMEOUT` 兜底。
|
||||
| | **改法(时序一字不动,只换所有权)**:标志收为 GD5F 文件内 `static s_spi1_dma_done`;GD5F 导出
|
||||
`gd5f_spi1_notify_done()` / `gd5f_spi1_notify_error()`(头文件里写明"SPI1 分支必须转调这两个函数");
|
||||
CH395F 删掉裸 `extern`、include `gd5f2gq5ue.h`、两个 SPI1 分支改为转调并就地注明"勿删"。
|
||||
`HAL_SPI_AbortCpltCallback`(`HAL_SPI_DMAStop()` 会触发)仍无人实现,**本次刻意不做**——它会改变中止
|
||||
语义,属真机专项,当前超时兜底可用。
|
||||
| | **体量代价**:`ch395f.o` −8 B、`gd5f2gq5ue.o` +24 B → `Code` 213,188 → **213,204 B(+16 B)**,
|
||||
RO/RW/ZI 全部不变,`ER_IROM1` 231,768 → **231,784 B(22.1%)**。16 B 换一个静默失效类,划算。
|
||||
数字联动一并做掉:`data/ram_report_20261022.md`、`data/stack_report_20261022.md` 重跑;`ram_baseline
|
||||
--update/--write`;`check_mem_numbers --write`;三张配图常量更新后重新生成(逐文本按字号与锚点复查
|
||||
越界 = **0**);本文 §1.3/§5.1/§5.4 与 `docs/环境与部署/项目部署环境要求.md` §3.3 的 Flash 数字同步。
|
||||
| | **真机验证 `@test` PASS**:无 `[ERR]`/Fault,复位原因 software;`[STACK] heap free=15800
|
||||
min_ever=8464`**与改前逐项相同**;各任务实测峰值 default 2152 / net 1116 / ftp 764 / ui 4052 /
|
||||
timesync 616 / adc 952 / iec104 540 / protect 624,**静态最坏链全部未变**(3024/1912/1456/4052/1264/
|
||||
1320/1456/872)→ 9/9 PASS。⚠ 记录一条读数陷阱:测试脚本打印的"boot to net init: OK = 7,907 ms"是
|
||||
采集窗口锚点造成的度量偏差,真机日志里 `boot: syslog init OK → net init: OK` 实测 ≈699 ms,与改
|
||||
前一致,**不是性能回退**。 |
|
||||
| **2026-10-22** | **S-2 第二步:19 处任务句柄裸 extern 收拢成引用契约**(推荐清单第 3 步) | 新建 `App/task/task_handles.h`——**只有声明、没有 `.c`**:头文件不需要双端注册,`../App/task` 本来就在 uvprojx 的 `<IncludePath>` 里,所以这一步零构建面。`default_task.c:52-69` 的 18 行 + `adc_task.c:125` 的 1 行局部 extern 全部删除改 include(栈水位表本体仍留在 `default_task.c`);同批把 `Src/main.c` 函数内的 `extern volatile uint32_t g_rcc_csr_latched;` 移进 `App/app/app_main.h`(该文件 `main.c` 本来就 include),
|
||||
USER CODE 区内只留「读 RCC_CSR → 写 RMVF 清除」两句、顺序约束的原注释保留。**价值**:原先每加一个任务都得记得往 `default_task.c` 再抄两行 extern,抄漏一行 = 读别人的栈(静默);现在只有一个改动点,且 CubeMX 若把句柄改名会在链接期报错而不是静默通过。**镜像逐项体积不变**(`Code=213,188 RO=18,580 RW=1,184 ZI=131,504`,`@build` 0 错 0 警告)证明行为中性。`check_cubemx_survival.py` 对这次有意的 USER CODE 区改动报「漂移」,已按其文档流程 `--write`重建基线(`.cubemx_survival_baseline.json` 仅 1 行变化),`--check` 复跑通过、易失清单 29 项全部到位;顺带把 §0.4 的 S-2 口径改成精确分类:**手写该修 24 处(已消 22)+ CubeMX 生成块 16 条(不算债)+ `__asm` 汇编标签 4 条(合法例外)**——上一版「25 处」混了这三类。 |
|
||||
| **2026-10-22** | **结构债 S-4 闭环 + S-2 第一步(用户批准「先只跑 1+2」)** | **S-4**:删除 `App/app/app_cfg.h` 里 4 个**零消费点**宏(`APP_NET_ENABLE`/`APP_ADC_ENABLE`/`APP_RS485_ENABLE`/`APP_SYS_TIME_SRC`),文件降格为「决策占位说明」——修改记录 v1.2 写明为什么删与将来怎么接回;并去掉 `app_main.c` 里只为它存在的 include。留「看着能裁剪、其实不生效」的宏比不留更糟:它不产生任何编译期效果,却让评审误信模块可裁剪;此前为了说明它,AGENTS 之外还得在 6 处文档各写一句「未接线占位,别当开关用」。同步改口径 **17 处**:`App/app/README.md`、`App/README.md`、根 `README.md`、`项目架构总览.md`、`项目部署环境要求.md`(§3.2 两行 + 配置表一行)、`产品需求设计文档.md`(B0 结论 + 配置表)、`基线与待确认.md`、`排期详述.md` C5、`登记簿.md` N-23 残余、`RAM使用分析与优化方案.md` 三处。
|
||||
|
||||
@@ -4,4 +4,4 @@ date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi
|
||||
2026-10-14 212296 18740 1112 154456 231036 22.0 98144 74.9 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=40960;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;default_task.o=2736;sys_log_mcu.o=1924
|
||||
2026-10-15 213540 18740 1136 131520 232280 22.2 75232 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736
|
||||
2026-10-20 213356 18580 1184 131480 231936 22.1 75240 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736
|
||||
2026-10-22 213188 18580 1184 131504 231768 22.1 75264 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736
|
||||
2026-10-22 213204 18580 1184 131504 231784 22.1 75264 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736
|
||||
|
||||
|
@@ -47,11 +47,11 @@ RAM2_CATEGORIES = [
|
||||
|
||||
# ── Flash breakdown (1MB = 1,048,576 B; 2026-10-22 @build) ──────────────────
|
||||
FLASH_TOTAL = 1048576
|
||||
FLASH_CODE = 213188
|
||||
FLASH_CODE = 213204
|
||||
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_IROM = FLASH_CODE + FLASH_RO # ER_IROM1 区用量 = 231,784 B(22.1%)
|
||||
FLASH_FREE = FLASH_TOTAL - FLASH_USED
|
||||
|
||||
FLASH_CATEGORIES = [
|
||||
@@ -61,14 +61,14 @@ FLASH_CATEGORIES = [
|
||||
("Flash 空闲", FLASH_FREE, "#E0E0E0"),
|
||||
]
|
||||
|
||||
# Flash Code+RO 分布(= ER_IROM1 231,768 B;2026-10-22 按 .map 对象表逐对象归类,
|
||||
# Flash Code+RO 分布(= ER_IROM1 231,784 B;2026-10-22 按 .map 对象表逐对象归类,
|
||||
# 口径同 data/ram_report_20261022.md;"其他"含链接器填充)
|
||||
FLASH_CODE_SUB = [
|
||||
("LVGL 库", 87706, "#4CAF50"),
|
||||
("应用代码/UI", 57011, "#2196F3"),
|
||||
("CH395F+FTP", 25652, "#F44336"),
|
||||
("CH395F+FTP", 25644, "#F44336"),
|
||||
("HAL 驱动", 17876, "#607D8B"),
|
||||
("dhara / FTL", 10907, "#FF9800"),
|
||||
("dhara / FTL", 10931, "#FF9800"),
|
||||
("FreeRTOS 内核", 10762, "#00BCD4"),
|
||||
("FatFS", 8468, "#9C27B0"),
|
||||
("C 库 (microlib)", 5486, "#795548"),
|
||||
@@ -81,15 +81,15 @@ FLASH_CODE_SUB = [
|
||||
# worst = max(静态最坏深度, 实测峰值); margin = cfg - worst
|
||||
# 9 行含 testTask(仅测试构建创建、无实测 → 取静态最坏链,峰位列填同值)
|
||||
TASK_STACKS = [
|
||||
("defaultTask", 5120, "Normal", 3024, 2164, 2096, 40, "PASS", "FatFS 挂载/探针 + 配置引擎 + syslog + LED"),
|
||||
("defaultTask", 5120, "Normal", 3024, 2152, 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 服务(大缓冲已静态化)"),
|
||||
("ftpTask", 4096, "Normal", 1456, 764, 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 保护判据 + 闭锁 + 定值校验和巡检"),
|
||||
("iec104Task", 2560, "Normal", 1456, 540, 1104, 43, "PASS", "IEC 60870-5-104 上行(2404)"),
|
||||
("protectTask", 2048, "Normal", 872, 624, 1176, 57, "PASS", "20 ms 保护判据 + 闭锁 + 定值校验和巡检"),
|
||||
]
|
||||
KERNEL_STACKS = [("idle", 512), ("timer", 1024)] # 128/256 words(未实测)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user