From 36a3c3449c367878664df5b410a1896a9103f787 Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Thu, 22 Oct 2026 19:09:20 +0800 Subject: [PATCH] =?UTF-8?q?refactor(task):=2019=20=E5=A4=84=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=8F=A5=E6=9F=84=E8=A3=B8=20extern=20=E6=94=B6?= =?UTF-8?q?=E6=8B=A2=E4=B8=BA=20task=5Fhandles.h=20=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E5=A5=91=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 推荐清单第 3 步(结构债 S-2 剩余面),用户批准"按你推荐做"。 新建 `App/task/task_handles.h`——**只有声明、没有 `.c`**:头文件不需要双端注册, 且 `../App/task` 本来就在 uvprojx 的 `` 里,所以这一步零构建面。 - `App/task/default_task.c:52-69` 的 18 行局部 extern(9 个句柄 + 9 个 attributes) 删除,改 include;栈水位观测用的任务清单表本体仍留在该文件 - `App/task/adc_task.c:125` 的 1 行同法收口 - `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-data=18,580 RW-data=1,184 ZI-data=131,504`,`@build` 0 错 0 警告 → 行为中性。 `check_cubemx_survival.py` 对这次有意的 USER CODE 区改动报"漂移",已按其文档流程 `--write` 重建基线(`.cubemx_survival_baseline.json` 仅 1 个指纹变化;顺手把该脚本 写文件带来的 CRLF 归一回 LF,符合 `* text=auto eol=lf`),`--check` 复跑通过、易失 清单 29 项全部到位。 报告 §0.4/§9 的 S-2 口径同时改成**精确分类**:该修的手写跨模块裸 extern **24 处, 今天已消 22 处,只剩 2 处**(`ch395f.c:177` 的 `g_spi1_dma_done` 与 `net_socket.c:77` 的 `netMsgQueueHandle`);`stm32f4xx_it.c:241-256` 那 16 条是 CubeMX「External variables」生成块(删了会被重生成写回来,**不算债**),`:183/195/207/220` 那 4 条 是手写在 `__asm` Handler 里引用汇编标签(ARMCC `__asm` 取不到 C 数据符号, **合法例外**)。上一版写的"25 处"把这三类混在一起了,一并更正。另更正 §0.4 的 S-1 一格:不是"运行时属主纪律被破"(UI 只投递 `net_cfg_save_request()`,写盘在 defaultTask),也不是"进不了主机侧单测"(模拟器已跑整条链),要修的只是静态分层 方向。 门禁:`@build` 0/0;`cubemx-survival --check` 通过;`check_doc_links.py --all --sections-strict` 146 文档 0 问题;`check_ids.py --strict` 增量拦截通过、可判定 82.83%;`mem-numbers` 0。字节卫生:新增头文件与各改动文件 BOM 无 / CR 0 / U+FFFD 0。未推送。 --- .cubemx_survival_baseline.json | 2 +- App/app/app_main.h | 8 ++++ App/task/adc_task.c | 3 +- App/task/default_task.c | 22 +--------- App/task/task_handles.h | 55 +++++++++++++++++++++++++ Src/main.c | 3 +- docs/问题记录/项目审查与优化建议报告.md | 8 ++-- 7 files changed, 72 insertions(+), 29 deletions(-) create mode 100644 App/task/task_handles.h diff --git a/.cubemx_survival_baseline.json b/.cubemx_survival_baseline.json index ae4e16f9..23d9efbb 100644 --- a/.cubemx_survival_baseline.json +++ b/.cubemx_survival_baseline.json @@ -14,7 +14,7 @@ "malloc-failed-hook-impl": "fcd7250e5cd6403b", "stack-overflow-hook-helper": "cacd9fd028be9b5b", "watchdog-module": "663f05caf22cf7d0", - "reset-cause-latch": "52fc71acbb0f1aed", + "reset-cause-latch": "983927d587cb9f48", "iwdg-hal-driver": "4b902875a84554e9", "hal-iwdg-enabled": "1a8ed6cff34f7ba6", "ioc-keepusercode": "b5bea41b6c623f7c", diff --git a/App/app/app_main.h b/App/app/app_main.h index 83b952b4..380097a6 100644 --- a/App/app/app_main.h +++ b/App/app/app_main.h @@ -17,6 +17,14 @@ extern "C" { #include +/* + * 复位原因锁存影子(定义于 app_main.c)。Src/main.c 在 HAL_Init() 之后、串口/日志 + * 尚未就绪时读 RCC->CSR 并清标志,这里提供引用契约——原先写成 main.c 函数内的局部 + * extern(跨文件裸 extern,改名/删除都不会有提示)。读→清两步的顺序约束见 main.c + * 该段注释,不可调换。 + */ +extern volatile uint32_t g_rcc_csr_latched; + int app_main_init(void); void app_main_run(void); diff --git a/App/task/adc_task.c b/App/task/adc_task.c index 6917bc65..672701bd 100644 --- a/App/task/adc_task.c +++ b/App/task/adc_task.c @@ -88,6 +88,7 @@ #include "adc_task.h" #include "cmsis_os.h" +#include "task_handles.h" /* adcTaskHandle(原为本文件局部 extern) */ #include "adc_input.h" /* L1 采集层:adc_input_poll()/adc_input_raw()(按语义取数) */ #include "sample_ring.h" /* L2 输入:sample_ring_push_frame()(采样环缓冲) */ #include "phasor.h" /* L2 相量层:phasor_run()/phasor_get()(全周傅氏) */ @@ -121,8 +122,6 @@ static uint32_t s_frames_skip; static uint32_t s_health_prev; static uint32_t s_health_logged; -/* adcTask 的内核句柄,定义在 Src/freertos.c(引用方式同 App/task/default_task.c) */ -extern osThreadId_t adcTaskHandle; /* 消费者就绪门:由 adcTask 自己在进入等待前置 1;单写者 = 本任务,ISR 只读。 * ⚠ 为什么必须有这道门:TIM3 在 app_main_init()(Src/main.c:140)里就 diff --git a/App/task/default_task.c b/App/task/default_task.c index 30666218..f5e9920f 100644 --- a/App/task/default_task.c +++ b/App/task/default_task.c @@ -46,27 +46,7 @@ #include "task_watchdog.h" #include "task_prof.h" /* 各任务最坏耗时上报 */ #include "vol_lock.h" - -/* 任务句柄与属性块(CubeMX 生成全局,定义于 Src/freertos.c): - * 栈水位观测需各任务句柄 + 属性块 stack_size(配置栈大小的唯一定义处) */ -extern osThreadId_t defaultTaskHandle; -extern const osThreadAttr_t defaultTask_attributes; -extern osThreadId_t netTaskHandle; -extern const osThreadAttr_t netTask_attributes; -extern osThreadId_t ftpTaskHandle; -extern const osThreadAttr_t ftpTask_attributes; -extern osThreadId_t testTaskHandle; -extern const osThreadAttr_t testTask_attributes; -extern osThreadId_t uiTaskHandle; -extern const osThreadAttr_t uiTask_attributes; -extern osThreadId_t timeSyncTaskHandle; -extern const osThreadAttr_t timeSyncTask_attributes; -extern osThreadId_t adcTaskHandle; -extern const osThreadAttr_t adcTask_attributes; -extern osThreadId_t iec104TaskHandle; -extern const osThreadAttr_t iec104Task_attributes; -extern osThreadId_t protectTaskHandle; -extern const osThreadAttr_t protectTask_attributes; +#include "task_handles.h" /* 任务句柄与属性块的引用契约(定义处仍是 Src/freertos.c) */ /* Private defines -----------------------------------------------------------*/ /* 栈水位观测节奏:首次报告须晚于 bring-up 深链(mount/mkfs/探针/cfg/syslog), diff --git a/App/task/task_handles.h b/App/task/task_handles.h new file mode 100644 index 00000000..f73609ad --- /dev/null +++ b/App/task/task_handles.h @@ -0,0 +1,55 @@ +/* + * 模块名称:Task Handles(内核任务句柄与属性块的集中声明) + * 模块功能:把散落在各 .c 里的跨文件裸 extern 收拢成一份有名字的契约,供栈水位观测、 + * 看门狗位图、按句柄取剩余栈等消费方引用 + * 适用平台:STM32F407ZGTx + * 作者:王建锋 + * 创建日期:2026-10-22 + * 修改记录: + * v1.0 2026-10-22 王建锋 从 App/task/default_task.c 的 18 行局部 extern 收拢而来。 + * 唯一定义处仍是 Src/freertos.c(CubeMX 生成的任务表),本文件 + * 只是引用契约:新增/改名任务必须同步这里,否则报错落在链接期 + * 而不是静默——这是有意的(原先每加一个任务就往 default_task.c + * 再抄两行 extern,抄漏一行就是读别人的栈)。 + */ + +#ifndef TASK_HANDLES_H +#define TASK_HANDLES_H + +#include "cmsis_os.h" /* osThreadId_t / osThreadAttr_t */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * 以下符号全部定义于 Src/freertos.c(CubeMX 任务表,只写 USER CODE 区,不可外移)。 + * p_attr->stack_size 是「配置栈大小」的唯一起点;实测最坏链与余量台账见 + * docs/内存管理/RAM使用分析与优化方案.md 的 2.3 与 4.0.6 小节(此处不重复数字)。 + * testTask 仅在启用板级测试套件时创建,未创建时句柄为 NULL(消费方须判空)。 + */ +extern osThreadId_t defaultTaskHandle; +extern osThreadId_t netTaskHandle; +extern osThreadId_t ftpTaskHandle; +extern osThreadId_t testTaskHandle; +extern osThreadId_t uiTaskHandle; +extern osThreadId_t timeSyncTaskHandle; +extern osThreadId_t adcTaskHandle; +extern osThreadId_t iec104TaskHandle; +extern osThreadId_t protectTaskHandle; + +extern const osThreadAttr_t defaultTask_attributes; +extern const osThreadAttr_t netTask_attributes; +extern const osThreadAttr_t ftpTask_attributes; +extern const osThreadAttr_t testTask_attributes; +extern const osThreadAttr_t uiTask_attributes; +extern const osThreadAttr_t timeSyncTask_attributes; +extern const osThreadAttr_t adcTask_attributes; +extern const osThreadAttr_t iec104Task_attributes; +extern const osThreadAttr_t protectTask_attributes; + +#ifdef __cplusplus +} +#endif + +#endif /* TASK_HANDLES_H */ diff --git a/Src/main.c b/Src/main.c index abbf7072..4e9ea681 100644 --- a/Src/main.c +++ b/Src/main.c @@ -111,8 +111,7 @@ int main(void) * 故在 HAL_Init()(此时 RCC 可用、串口尚未就绪)之后**立即读取并清除**, * 锁存到 RCC_CSR 影子变量,待日志子系统起来后由 app_main_init 打印。 * 注意顺序:读 → 写 RMVF 清除,两步之间不可插入其它可能复位的代码。 */ - { - extern volatile uint32_t g_rcc_csr_latched; /* 定义于 app_main.c,供启动日志读取 */ + { /* 符号声明见 App/app/app_main.h */ g_rcc_csr_latched = RCC->CSR; /* 锁存:含 IWDGRSTF/SFTRSTF/PORRSTF 等 */ RCC->CSR |= RCC_CSR_RMVF; /* 写 1 清全部复位标志(只清标志,不影响时钟) */ } diff --git a/docs/问题记录/项目审查与优化建议报告.md b/docs/问题记录/项目审查与优化建议报告.md index 57f6e5f7..dd5d47a6 100644 --- a/docs/问题记录/项目审查与优化建议报告.md +++ b/docs/问题记录/项目审查与优化建议报告.md @@ -48,8 +48,8 @@ | 内存 RAM | R-2 剩余 / R-3 / R-4 / R-6 ⏸(N-27) | 待迁体量 29,570 B,而 CCM 只剩 7,904 B → 搬迁已无空间收益 | 暂缓;重开条件 §5.3 | | 内存 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` | 有实测全量耗时痛点再做,用 `` | -| 结构 | **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 处;NETCFG 去掉 `cfg_file.h` 后还能进主机侧单测)+ 加一条「`Drivers/BSP/**` 不得 include `App/**`」的门禁;**目录搬迁暂缓**(远程 CI 仍不跑 `@build`,兜底未成立) | -| 结构 | **S-2 ❌**(实测 **25 处**,旧写「4 处」低估) | 原 4 处全部仍在,其中 `ch395f.c:177` 最危险:CH395F 裸写 GD5F 的 `g_spi1_dma_done`,并在 `HAL_SPI_ErrorCallback` 的 SPI1 分支里**替 GD5F 释放等待者**——谁清理那两行「看着无关」的分支,编译零报错,GD5F 的 DMA 出错就退化成干等 `GD5F_SPI_TIMEOUT`;`HAL_SPI_AbortCpltCallback`(`HAL_SPI_DMAStop` 会触发)无人实现。新增实测面:`App/task/default_task.c:52-69` 18 行任务句柄/属性 extern(看门狗用的任务清单表)、`adc_task.c:125`、`Src/main.c:115`、`Src/stm32f4xx_it.c` 2 处;其中 `fault_entry_hard` 属 ARMCC `__asm` **合法例外** | 四步:① ~~删冗余 extern~~ ✅ 已做 2 处(2026-10-22)② SPI 完成/错误/中止回调**归属拆清**(GD5F 导出 `gd5f_spi1_notify_*`,CH395F 只转发)③ 建 `App/task/task_registry.h` 集中消掉 19 行 ④ `netMsgQueueHandle` 收口 | +| 结构 | **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-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 同批评估 | @@ -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-1 = NETCFG+UI 共 7 文件 15 处;S-2 = 25 处,含 1 处合法例外) | 本文 §0.4、登记簿 C5 | +| **S-1 / S-2** | 分层反向依赖 / 跨模块裸 `extern` | 🟡 半办(2026-10-22:S-2 的 24 处手写已消 22 处、剩 2 处;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,8 @@ 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 第二步:19 处任务句柄裸 extern 收拢成引用契约**(推荐清单第 3 步) | 新建 `App/task/task_handles.h`——**只有声明、没有 `.c`**:头文件不需要双端注册,`../App/task` 本来就在 uvprojx 的 `` 里,所以这一步零构建面。`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` 三处。 | | **顺带纠出另一个不存在的宏**:`RAM使用分析与优化方案.md` 把 `APP_CCM_ENABLE` 写成「加在 `App/app/app_cfg.h`」,实际从来没有落地(全库仅该文档提及)——已就地标注「未实现,重开本簇时一起落地」,避免下一个读者以为 CCM 有回退开关。 | | **S-2 第一步(实测纠偏)**:删掉 `gd5f2gq5ue.c:47`、`sd2506.c:20` 两处与 `Inc/spi.h`/`Inc/i2c.h` 重复的 `extern`,GD5F 改 `#include "spi.h"`(沿用 `ch395f.c:22` 的既有做法)。**镜像逐字节不变**:`Code=213,188 RO=18,580 RW=1,184 ZI=131,504` 与改动前完全相同,`@build` 0 错 0 警告 → 证明这两步是行为中性的。同时把 §0.4/§9 的旧口径换成实测值:**S-2 不是 4 处而是 25 处**(`App/task/default_task.c:52-69` 一次就有 18 行;`stm32f4xx_it.c` 的 `fault_entry_hard` 属 ARMCC `__asm` 合法例外,不该「修」),**S-1 不是语义错位而是真实反向依赖**(NETCFG include `App/cfg/cfg_file.h` 10 处 + UI 3 个文件)。**这两个旧数字是我 v3.0 重写时沿用未测,一并认错。** SPI 回调归属这条隐患(CH395F 替 GD5F 释放错误路径)目前只在本文 §0.4 留了痕,**尚未进登记簿**——要不要立项等你定。 |