docs(AGENTS): 入口重构——补宏观概况与边界块,瘦身51KB→25.8KB,子域知识入skills
- AGENTS.md 51,067→25,828 B(−50%):审计→迁移→删除,逐节 diff 零信息损失 - 按调研(agents.md 官方/aihero/airflow)补「项目概况」:一句话定位、 数据主线、顶层目录地图、分层边界;平台约束 17 条分 5 组 - 新增「边界(Ask first / Never)」:git commit/push 须明确指示首次入库 - 串口助手、LVGL 模拟器两节移入 serial-assistant / 新建 lvgl-simulator skill (开关语义按 main.c 实锤);LVGL 两条实证坑移入 ui-verify skill - 9 条入口独有细节迁移至对应设计文档(存储/看门狗/启动顺序/文档规范/ pre-commit 使用说明/keil-build skill);@test 细节指向自动化测试流程 - 新增 docs/AGENTS编写指南.md:六原则/模板/反模式/维护纪律 + 本仓案例 - 修正 3 处对 AGENTS 串口节的过时引用;docs/README.md 登记新文档
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
# AGENTS 编写指南——一份好的 AGENTS.md 应该怎么写
|
||||
|
||||
> **定位**:回答"AGENTS.md 该写什么、不该写什么、怎么维护"。适用于本仓库 `AGENTS.md` 与任何采用 [AGENTS.md 开放格式](https://agents.md/) 的项目。
|
||||
> **依据**:官方规范 + 两篇实践指南 + 一个标杆范例 + 本仓库实测(51 KB → 25 KB 瘦身与重构,见 §8)。
|
||||
> **关联**:文档体系通用约定 → [`文档规范.md`](文档规范.md);人类索引 → [`README.md`](README.md)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 定位:它是谁的什么
|
||||
|
||||
| 文件 | 读者 | 内容 |
|
||||
|---|---|---|
|
||||
| `README.md` | 人类贡献者 | 项目介绍、快速上手、贡献指南 |
|
||||
| `AGENTS.md` | **AI 编码代理** | 构建/测试命令、约定、约束、坑——那些"放 README 会碍事、但 agent 每次都需要"的上下文 |
|
||||
|
||||
[官方定义](https://agents.md/):*"Think of it as a README for agents"*、*"anything you'd tell a new teammate belongs here"*。它没有必填字段、纯 Markdown,但**位置即命运**——它坐在每次请求的上下文最前面,写什么就得为什么付费(§3 P3)。
|
||||
|
||||
## 2. 一句话定位(写之前先回答)
|
||||
|
||||
文件第一行必须让 agent 回答"**这是什么东西、给谁用、跑在哪**"。[aihero 指南](https://www.aihero.dev/a-complete-guide-to-agents-md)的说法:这句话是**锚定后续每个决策的角色提示**——"嵌入式固件"与"Next.js 网站"会让 agent 对同一个"加个日志"请求做出完全不同的权衡。没有这句话,后面所有规则都失去解释框架。
|
||||
|
||||
反例:直接以"编码规范"开头——agent 知道规矩,不知道为什么有这些规矩。
|
||||
|
||||
## 3. 六条核心原则
|
||||
|
||||
| # | 原则 | 为什么 | 反例信号 |
|
||||
|---|---|---|---|
|
||||
| P1 | **一句话定位打头**(§2) | 所有规则的锚点 | 文件从规范讲起,产品是什么要翻三节才拼出来 |
|
||||
| P2 | **宏观先行**:概况 → 目录地图 → 架构边界 → 再是操作规则 | [airflow 范例](https://github.com/apache/airflow/blob/main/AGENTS.md)把 Repository Structure 与 Architecture Boundaries 放在编码规范之前;agent 先知道"代码怎么摆、边界在哪"才不会把算法塞进任务文件 | 规则堆完才出现"架构要点",或根本没有宏观视图 |
|
||||
| P3 | **指令预算**:模型只能稳定遵循约 150~200 条指令,且**每个 token 每次请求都加载**([Humanlayer](https://www.humanlayer.dev/blog/writing-a-good-claude-md) / aihero) | 膨胀不是"浪费",是**稀释**——不相关的指令会实际降低执行质量 | 文件 >30 KB;同一主题超过 5 条规则 |
|
||||
| P4 | **渐进披露**:入口只留面包屑,细节进 `docs/` 与 skills;大仓用嵌套 AGENTS.md(就近生效,[官方推荐](https://agents.md/)) | 用到才加载 = 零常驻成本。本仓库把串口助手、模拟器整节移进 skill 后入口各减数 KB 而能力无损 | 入口里出现完整命令表/参数表/FAQ |
|
||||
| P5 | **描述能力,不写易漂移路径**(aihero):目录地图只到**顶层稳定边界**,细节让 agent 自己 `ls` | 深层路径随重构漂移,agent 会**拒绝相信眼前的真实代码**去服从过期地图 | 入口罗列到三级以下的文件清单 |
|
||||
| P6 | **每条 = 禁令/事实 + 一句为什么 + 指针**(本仓库实测) | "为什么"让 agent 能外推到未列举的场景;只有禁令会催生新坑的新禁令(回 P3 雪球) | 只有"禁止 X"没有半句原因;或大段叙事讲踩坑史 |
|
||||
|
||||
## 4. 推荐结构(模板)
|
||||
|
||||
综合[官方常用节](https://agents.md/)(Project overview / Build & test / Code style / Testing / Security)与 airflow 实践:
|
||||
|
||||
```
|
||||
# 项目名
|
||||
一句话定位(P1)+ 平台/工具链一行 + 最高频命令一行(如"改完必须 build")
|
||||
|
||||
## 项目概况 产品现状一句话(含最大缺口)· 数据/调用主线(能力级,P5)
|
||||
· 顶层目录地图(目录|职责|可改性 三列)· 分层边界
|
||||
## 架构要点 运行时视图(任务/线程/启动顺序),机器生成表用标记包裹(§5)
|
||||
## 操作规则 编辑铁律 · 构建与测试命令(含退出码判读)· 提交门禁
|
||||
## 领域约束 平台/硬件/协议陷阱——每条带为什么(P6),按主题分组
|
||||
## 索引 按主题查哪份文档(表格;子域知识入口=skills)
|
||||
```
|
||||
|
||||
要点:**构建/测试命令必须给全**(官方:agent 会自动执行文中列出的检查命令并在完成前修复失败);**边界用"必须/禁止"级措辞**——airflow 的 `Never` / `Ask first` 两栏清单是范例。
|
||||
|
||||
## 5. 机器可读契约(本仓库经验)
|
||||
|
||||
入口文件里凡是被脚本/钩子消费的部分,用**显式标记**声明契约,人改脚本改都撞不上:
|
||||
|
||||
- 生成表用锚点包裹:`<!-- TASK_TABLE:BEGIN generated by scripts/gen_task_table.py -->`,由 `--check` 钩子校验与代码一致(同类:`MEM_SNAPSHOT:BEGIN/END`)→ `代码规范/pre-commit使用说明.md`
|
||||
- **段名是跨文档引用键**:其它文档以「AGENTS.md 平台约束」这类**段名**做引用,改名 = 静默断链。重构时段名保持稳定,删节可以、改名要全库 grep 引用
|
||||
- 入口自身纳入 `doc-links` 类门禁:文中路径全部可验证存在
|
||||
|
||||
## 6. 不该进入口的内容(反模式清单)
|
||||
|
||||
| 反模式 | 为什么坏 | 去处 |
|
||||
|---|---|---|
|
||||
| **规则雪球**(每次 agent 犯错加一条) | [aihero](https://www.aihero.dev/a-complete-guide-to-agents-md):数月后成 ball of mud,互相矛盾、无人通读 | 同类规则合并成一条带"为什么"的总则 |
|
||||
| **自动生成全量 dump**(`/init` 一把梭) | 生成器追求"面面俱到"而非克制,等于开局就把预算花光 | 生成后必须人工按 P3 裁剪 |
|
||||
| **历史叙事**(日期、commit 号、踩坑过程) | 决策依据进 changelog/问题记录;入口只留结论 | `docs/问题记录/`、文档变更记录 |
|
||||
| **从 docs 抄全表**(引脚表、命令表、FAQ) | 双写必漂移,违反单一事实源 | 一行指针(本仓库「完成即销项」约定) |
|
||||
| **个人偏好**(某人的缩进口味) | 每次请求全员付费 | 个人级 agent 配置 / editorconfig |
|
||||
| **过期路径与旧工具名** | 比没有更糟——agent 会服从它 | 定期瘦身(§7) |
|
||||
|
||||
## 7. 维护纪律
|
||||
|
||||
1. **单一事实源**:同一事实只在一处详述,其余位置用链接指向(本仓库 `docs/文档规范.md` 同此要求)。
|
||||
2. **瘦身方法论**(本仓库实测,先审计后动刀):全量条目普查 → 逐条核对去处(docs/skills 是否已完整承接)→ 缺口先迁移 → 再删除 → 跑链接/一致性门禁。**禁止**没核对去处就删。
|
||||
3. **skills 是披露层**:子域工作流(构建工具、串口、模拟器…)整段进 skill,入口索引行留名——目录常驻、全文用到才加载。
|
||||
4. **改完跑门禁**:链接存在性、生成表一致性、表格格式、编码(本仓库 `check_doc_links.py --all` + `pre-commit`)。
|
||||
5. **体量红线**:入口超过 ~30 KB 就触发瘦身流程(P3);新增一节前先问"这条是否**每次**都需要在场"。
|
||||
|
||||
## 8. 本仓库案例:51 KB → 25 KB
|
||||
|
||||
| 步骤 | 动作 | 结果 |
|
||||
|---|---|---|
|
||||
| 1 普查 | 脚本统计各节行数/字节数,49 个主题逐条核对 docs 承接情况 | 48/49 主题文档已有完整承接,9 条入口独有 → 先迁移 |
|
||||
| 2 迁移 | 叙事史/日期/commit 号回写各设计文档;串口、模拟器两节移入 skills | 零信息损失(逐节 diff 验证) |
|
||||
| 3 删除 | 入口重写:禁令 + 一句为什么 + 指针 | 51,067 → 21,795 B(−57%) |
|
||||
| 4 重构 | 按 P1/P2 补一句话定位 + 项目概况(数据主线/目录地图/分层边界),平台约束 17 条分 5 组 | 25,306 B,段名与机器标记全保留,门禁全绿 |
|
||||
|
||||
**教训**:瘦身最大的风险不是删错,而是**删了唯一副本**——所以"先核对去处"必须先于任何删除;第二大风险是**改段名断引用**——跨文档按段名引用在 Markdown 链接检查里不可见。
|
||||
|
||||
## 9. 质量自查清单
|
||||
|
||||
- [ ] 第一行能否让新 agent 说出"这是什么、跑在哪、用什么工具链"?
|
||||
- [ ] 前五节之内能否回答"代码怎么摆、哪些目录不能碰"?
|
||||
- [ ] 每条规则是否带"为什么"(或本身自明)?
|
||||
- [ ] 有没有任何一条在 docs/skills 已有更全版本?(有 → 删,留指针)
|
||||
- [ ] 构建/测试命令是否可直接复制执行、含退出码判读?
|
||||
- [ ] 生成表/锚点标记是否完好?段名是否未改(或已全库同步引用)?
|
||||
- [ ] 文件多大?>30 KB 触发瘦身。
|
||||
- [ ] 最近一次 agent 犯错,是"缺规则"还是"规则太多没执行"?(后者 → 删规则而不是加规则)
|
||||
|
||||
## 10. 参考资料
|
||||
|
||||
| 来源 | 要点 |
|
||||
|---|---|
|
||||
| [agents.md 官方规范](https://agents.md/) | 定位/常用节/嵌套文件/60k+ 项目案例(openai/codex、apache/airflow 等) |
|
||||
| [A Complete Guide To AGENTS.md](https://www.aihero.dev/a-complete-guide-to-agents-md)(Matt Pocock) | 指令预算、渐进披露、能力>路径、反雪球、skills 披露层 |
|
||||
| [Writing a good CLAUDE.md](https://www.humanlayer.dev/blog/writing-a-good-claude-md)(Humanlayer) | "instruction budget"概念出处:前沿模型约 150~200 条指令 |
|
||||
| [apache/airflow AGENTS.md](https://github.com/apache/airflow/blob/main/AGENTS.md) | 标杆结构:Repository Structure / Architecture Boundaries / Ask first–Never / References |
|
||||
@@ -20,6 +20,7 @@ docs/
|
||||
├── 测试说明/ 测试流程、模块测试指南、工具说明
|
||||
├── 代码规范/ 编码规范与静态检查门禁
|
||||
├── 文档规范.md 本文档体系的规范(命名/链接/门禁/结构)
|
||||
├── AGENTS编写指南.md 如何写好 AGENTS.md(入口文件的取舍、结构与维护纪律)
|
||||
├── 内存管理/ RAM 预算、分配策略与优化调研
|
||||
├── 问题记录/ 模块陷阱台账、专项审计与项目评审报告
|
||||
├── 环境与部署/ 环境搭建与部署核对清单
|
||||
@@ -168,6 +169,7 @@ docs/
|
||||
| 文档 | 内容 |
|
||||
|---|---|
|
||||
| [`文档规范.md`](文档规范.md) | **文档体系强制约定**:目录/命名(无空格)、编码换行、链接形态(互链用根相对、图片用目录相对)、`[计划]` 标记、门禁三档、结构要素与常见错误速查 |
|
||||
| [`AGENTS编写指南.md`](AGENTS编写指南.md) | **如何写好 AGENTS.md**(agent 入口文件):定位与一句话锚点、六条核心原则(指令预算/渐进披露/能力>路径)、推荐结构模板、机器可读契约、反模式清单、瘦身方法论 + 本仓库 51KB→25KB 实测案例与外部标杆调研(agents.md 官方 / airflow / aihero) |
|
||||
|
||||
### 7.2 内存管理(**新增任务/缓冲/栈前必读**)
|
||||
|
||||
@@ -266,6 +268,7 @@ docs/
|
||||
|
||||
| 日期 | 变更 | 说明 |
|
||||
|---|---|---|
|
||||
| 2026-10-11 | 新增文档 | 新建 [`AGENTS编写指南.md`](AGENTS编写指南.md)(好的 AGENTS.md 怎么写:六原则/模板/反模式/维护纪律 + 本仓库瘦身重构案例与外部标杆调研);本索引 §1 目录树与 §7.1b 登记;同日 `AGENTS.md` 按该指南完成宏观重构(补项目概况/目录地图、平台约束分组) |
|
||||
| 2026-10-10 | 新增子系统设计 | 新建 `docs/子系统设计/ADC采样节拍设计说明.md`(ADC 采集链路 1 kHz 硬件定时器触发的 CubeMX 配置规格与代码改造清单,B1 遗留项规划);本索引 §5.1 补登记 |
|
||||
| 2026-10-10 | 新增算法专题 | 新建 `docs/算法/继电保护功能复现规划.md`(保护链路复现总规划);本索引 §1 目录树补 `算法/`、§5 拆为 5.1 功能子系统 / 5.2 算法专题并登记 `算法/` 两篇文档 |
|
||||
| 2026-10-05 | 新增产品需求文档 | 新建 `docs/产品需求/产品需求设计文档.md`(面向产品的需求基线);本索引新增 §3 产品需求、§2 推荐阅读顺序置顶、§1 目录树补 `产品需求/`;后续章节号顺延(架构设计 §4 … 变更记录 §12) |
|
||||
|
||||
@@ -314,11 +314,11 @@ cppcheck 是开源 C/C++ 静态分析工具,**不运行代码**,通过语法
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|---|
|
||||
| **触发条件** | commit message 标题超 100 字符 / 含 body-is-missing 警告 |
|
||||
| **触发条件** | commit message 标题超 100 字符 / **正文单行超 80 字符** / 其他格式规则 |
|
||||
| **处理方式** | **阻止提交**(commit-msg 阶段) |
|
||||
| **当前规则** | 宽松:不强制 Conventional Commits,兼容中文标题 |
|
||||
| **典型报错** | `T1 Title exceeds max length (159>100)` |
|
||||
| **修复方式** | 精简 commit message 标题到 100 字符以内,或拆分为多行(标题+空行+body) |
|
||||
| **当前规则** | 宽松:不强制 Conventional Commits,兼容中文标题。配置源是仓库根 `.gitlint`(**不是** hook args):`ignore=body-is-missing`(**不强制写正文**)+ `[title-max-length] line-length=100`;正文行宽走 gitlint 默认 **80**(未关) |
|
||||
| **典型报错** | `T1 Title exceeds max length (159>100)`、`B4 Line too long (87>80)` |
|
||||
| **修复方式** | 标题压到 100 字符内(中文长标题极易超限);长说明一律用**短标题 + `git commit -F <文件>` 多行正文**,正文每行 ≤80 字符。消息文件必须 **UTF-8 无 BOM**——用 `-F 文件` 而非 `-m "…"`,防终端代码页转码破坏中文 |
|
||||
|
||||
### 2.15 lv-conf-sync — 两份 `lv_conf.h` 特性子集一致性(2026-10-11 加)
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ HAL 并发语义(本仓库实现实测,`stm32f4xx_hal_uart.c:1135`):轮
|
||||
| # | 约束 | 出处 |
|
||||
|---|------|------|
|
||||
| K1 | 内核启动前禁止创建/使用任何 FreeRTOS/CMSIS-RTOS 对象 | AGENTS.md 平台约束(2026-09-20 启动失败实证根因)→ 本模块内核前纯 BSS/寄存器机制 |
|
||||
| K2 | 禁止 `malloc/calloc/realloc`(C 堆仅 512B) | AGENTS.md P0-1 → 全部状态静态 BSS |
|
||||
| K2 | 禁止 `malloc/calloc/realloc`(C 堆仅 512B) | AGENTS.md 平台约束(禁 C 库堆分配条)→ 全部状态静态 BSS |
|
||||
| K3 | HAL 生成文件(`Src/`、`Inc/`)不含应用代码 | 2026-09-25 迁移动机 → 实现位于 `App/log/` |
|
||||
| K4 | 生产者阻塞时间有界 | 最多 `DBG_CON_WAIT_MS`(200ms),日志不得阻塞业务 |
|
||||
| K5 | RAM 预算紧张,新增静态内存必须核算 | §8 |
|
||||
|
||||
@@ -518,6 +518,20 @@ python scripts/check_cubemx_survival.py --write # 确认改动无误后重建
|
||||
|
||||
> **工作流**:每次 CubeMX 重生成后**立刻**跑一次该脚本——它直接列出"被覆盖了哪几处 + 修复提示",比事后靠故障现象反推快得多。
|
||||
|
||||
### 10.4 ARMCC `__asm` 的三条语法约束(2026-09-29 踩坑)
|
||||
|
||||
> **出处**:自 `AGENTS.md`「ARMCC 内联汇编语法」条目迁入(AGENTS.md 瘦身,不再当事实存放地)。4 个 Fault Handler 是手工 `__asm`(§10.2 的 L2 条);ARMCC 的内联汇编只有一种合法形态,以下三种写法全部实测踩坑:
|
||||
|
||||
| # | 尝试写法 | ARMCC 实际报错 | 根因 |
|
||||
|---|---|---|---|
|
||||
| ① | `__asm volatile ("MRS %0, lr" : "=r" (x))` | `#18: expected a ")"` | 这是 **GCC 内联汇编语法**,ARMCC 不支持 |
|
||||
| ② | `__asm { MRS x, lr }`(块内联) | `#20: identifier "lr" is undefined` | 块内联把寄存器名当 **C 标识符**解析 |
|
||||
| ③ | `__asm` 块内 `ADR r1, xxx_tag` 取 C 侧字符串/表格 | `A1516E: Bad symbol 'xxx_tag'` | `__asm` 块里**取不到 C 的数据符号**;去掉 `static` 也无效——汇编器只认自己作用域内的符号 |
|
||||
|
||||
**结论 / 可用写法**:整个函数写成 `__asm void f(void) { ... }`;要传"字符串/表格"这类 C 侧数据,就让 `__asm` 只取**寄存器参数**然后 `B` 到一个普通 C 函数、由 C 侧补上——所以 4 个 Fault 的故障名必须由 C 侧 per-fault 入口 `fault_entry_{hard,mem,bus,usage}` 带上,`__asm` 里不取 C 变量。
|
||||
|
||||
**覆盖 CubeMX 生成的同名函数**(对 §10.2 那条的补充):用 `#define f f_Gen`(**写在生成实体之前**)把生成实体改名,链接器会把未被引用的 `f_Gen` 自动移除(`.map` 可见 `Removing ... (N bytes)`)——**零代码开销且不删生成区任何一行**。
|
||||
|
||||
---
|
||||
|
||||
## 11. 任务级饥饿的诊断方法与实测基线(Task #32 沉淀,2026-10-10)
|
||||
@@ -663,3 +677,4 @@ enter/exit 段还能读出"此刻仍在段内已多久"——**永久阻塞的
|
||||
| 2026-10-10 | **adcTask 纳入监视(B1):必需掩码 `0x37`→`0x77`** | B1(ADC 采集链路)落地时新增 `adcTask`(`App/task/adc_task.c`:1 ms 采样节拍触发 CONVST + 消费 `tpafe5160_snapshot()`)并纳入 IWDG 监视:`task_wd_id_t` 新增 `TASK_WD_ADC = 6`;`wd_required_mask()` 产品 `0x37`→`0x77`、`ENABLE_HW_LAYER_TESTS` `0x35`→`0x75`(adcTask **不依赖任何就绪屏障** → 任何构建都置位)。adcTask 主循环每 1 ms `task_wd_beat(TASK_WD_ADC)`;**不做 NAND I/O → 不登记 FTL 心跳路由**(无需 `task_wd_bind()`)。主机侧单测 `beat_all()` 与掩码断言(`tc_003`/`tc_005`/`tc_011` 的 `0x37`→`0x77`)同步,39 断言全绿。任务由 `Src/freertos.c` 的 `USER CODE` 区手工创建(同 timeSyncTask,不在 `.ioc` 里),栈 512 words、优先级 Normal,`stack_report.py` 实测最坏链 504 B(余 1544 B / 75%)。见 `docs/算法/继电保护功能复现规划.md` §7 |
|
||||
| 2026-10-10 | **B1 `@test` 实机闭环:adcTask 掩码真机验证** | 台架闭环(`.dsh/skills/serial-boot-test/scripts/run_boot_test.py`)确认 `adcTask` 纳入掩码后**无 adc 相关误复位**:`[STACK] adc peak_used=496/2048 free_min=1552 (75%)`、`frames/seq` 每 10 s 严格 +10000(=1000 Hz)、`idle=0`/`frst_err=0`、全片回读 `No difference found`。启动早期两次 `MISS start snap=0x67 req=0x77` 仅缺 bit4(`timeSync` 未启动,属正常就绪窗;adc 的 bit6 自始置位),掩码随后收敛、全程无复位。同轮另修 `dbg_console_writer_ready()` 门控(adcTask 周期日志在写者注册前抑制,见 `控制台单写者日志设计说明.md`) |
|
||||
| 2026-10-10 | **新增 §11:任务级饥饿的诊断方法与实测基线** | 承接 Task #32(`task stall: mask=0x67 req=0x77`,缺 `TASK_WD_UI`)结案后的沉淀——原分析文档 `docs/问题记录/UI任务看门狗停摆分析.md` 按"完成即销项"删除,可复用部分并入本文:**§11.1** 三条易误读的判读口径(启动期 `MISS start 0x67` 良性、`miss=` 是累计不是连续、`reset cause` 不能区分 IWDG 与台架);**§11.2** 诊断四步(先看掩码缺几位 → 量化占空比 → 用计数速率反证空转 → 用 `[PROF]` 指认占用者;本例否掉"CPU 饱和",实测 10%~13%);**§11.3** 三条结构性脆弱点(uiTask 唯一 BelowNormal/心跳依赖 netTask 往返/自定截止期不可恢复)与两个顺带修掉的**正确性**缺陷(无新帧仍压环 ≈3% 频率失配、失败拍静默沿用旧值);**§11.4** `[PROF]`/`[PROF2]` 全字段语义 + v2.8 基线(含 `netp=0` 是真实值、`adcm` 峰值来自心跳日志、`uip` 地板 = LVGL 帧周期)与三机理判读口诀;**§11.5** 三条教训(门控须留低频兜底、门控会消灭暴露路径、事件驱动要核对节拍源与消费者创建时刻);**§11.6** 明确不做的四条及理由。§9.1 的 R7 行改指本文 §11.3 |
|
||||
| 2026-10-11 | **新增 §10.4:ARMCC `__asm` 的三条语法约束** | AGENTS.md 瘦身:「ARMCC 内联汇编语法」条目的完整细节(GCC 语法报 `#18`、块内联把寄存器名当 C 标识符报 `#20`、`__asm` 取不到 C 数据符号 `A1516E`、可用写法 = 整函数 `__asm void f(void)` + `B` 到 C 入口、`#define f f_Gen` 让位机理)迁入本文,AGENTS.md 只留一行禁令与指针 |
|
||||
|
||||
+4
-2
@@ -57,8 +57,10 @@
|
||||
| 文件尾 | 必须以单个换行结束(`end-of-file-fixer`) |
|
||||
| 乱码 | 禁止出现 `U+FFFD`(替换字符,字节序列 `EF BF BD`) |
|
||||
|
||||
> ⚠️ **本仓库 BOM 铁律**(见 `AGENTS.md`):C 源码中 `Drivers/BSP/UI/*`、`App/task/ui_task.c`、`App/cfg/cfg_file.c`、`Lib/lv_conf.h` 等**带 BOM**,被工具改写后 BOM 会静默丢失 → ARMCC 改按 CP936 解码 → 中文字面量编译失败。
|
||||
> **文档(`.md`)不受此限**,一律用无 BOM UTF-8。但用脚本批量改写文档时,仍须**按原样回写换行符**(本仓库 `core.autocrlf=true` 且无 `.gitattributes`,工作区换行混杂),否则会产生整文件行尾漂移的巨型 diff。
|
||||
> ⚠️ **本仓库 BOM 铁律**(见 `AGENTS.md`「铁律:源码编辑与编码」):C 源码中 `Drivers/BSP/UI/*`、`App/task/ui_task.c`、`App/cfg/cfg_file.c`、`Lib/lv_conf.h` 等**带 BOM**,被工具改写后 BOM 会静默丢失 → ARMCC 改按 CP936 解码 → 中文字面量编译失败。
|
||||
> **文档(`.md`)不受此限**,一律用无 BOM UTF-8。
|
||||
>
|
||||
> **行尾策略(2026-10-09 起写死进 `.gitattributes`,本节是权威口径)**:`* text=auto eol=lf`(仓库 blob 与工作区统一 LF)+ `*.bat`/`*.cmd` 强制 CRLF(cmd.exe 对 LF-only 的 goto/标签不可靠)+ PNG/TTF/DLL/LIB 等显式 `binary` + `*.jpg` 走 LFS 且 `-text`(该条必须排在 `*` 之后才能覆盖)。**不要再依赖 `core.autocrlf`,也不要把工作区文件"改回 CRLF"**——CubeMX 重生成写的就是 LF;此前每次重生成后 40+ 个第三方文件在 `git status` 里显示"已修改",根因就是行尾由每台机器各自的 autocrlf 决定。用脚本批量改写文档时仍须**按原样回写换行符**,否则会产生整文件行尾漂移的巨型 diff。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -565,7 +565,7 @@ if (nand_ftl_format() == 0) {
|
||||
7. **单写者规则** — 存储由 **defaultTask 独占**:挂载 / `f_mkfs` / 卷健康探针 / `net_cfg_load` / syslog 落盘 / 配置引擎全收敛于它。netTask / uiTask **不得**直接触碰配置引擎或 FatFS。启用存储测试套件(`TEST_SUITE_STORAGE`)时存储所有权整体移交 testTask,defaultTask 必须**完全跳过**存储 bring-up(`App/task/default_task.c` 中 `#if !defined(TEST_SUITE_STORAGE)` 包裹,2026-09-25 自 `Src/freertos.c` 迁出)——否则后台文件写与测试的 `nand_ftl_deinit` 掉电模拟并发,互相踩坏 FTL/FatFs 状态(实测:mkfs 半途冻结 + BBT 被误写)。
|
||||
8. **内存布局与 DMA/CCM 约束** — FreeRTOS 堆(含全部任务栈)已迁至 **CCM `0x10000000`**(64KB,直连 M4 零等待),但 **DMA1/DMA2 物理不可达 CCM**。GD5F 驱动 `GD5F_DMA_THRESHOLD = 1024`:栈上的小缓冲(dhara meta 读 132B、`dhara_nand_is_free` 64B)一律走 **CPU 轮询**、绝不经 DMA;页级大块(2048)才走 DMA 且源/目的**全部是文件作用域静态缓冲**(落 SRAM)。新增任何 DMA 收发缓冲必须①文件作用域静态②大小≥阈值③确认落 SRAM。违反任一条 = 静默数据损坏(CCM 首轮扩容实验实证)。换料注意:克隆片可能缺 SRAM3(CCM),必须重测。
|
||||
9. **LVGL 绘制缓冲越界护栏** — LVGL 9.3.0 对 I1(1bpp) 整帧渲染会在其算出的 `stride*h`(160×160/8=3200) 之后**多写 1 个字节**,紧邻 `g_ui_draw_buf` 之后的 `.bss`(如 `ui_menu_view` 的 `s_frame_box`)指针最低字节被打成 `0xFF` → 野指针 → HardFault(`PC=lv_obj_get_scroll_y`)。`ui_port.c` 的 `g_ui_draw_buf` 已预留 `UI_DRAW_BUF_GUARD=32` 字节护栏吸收该越界写(逻辑尺寸仍按 `UI_FB_SIZE` 上报,渲染数学不变)。**勿删护栏、勿把缓冲缩到与邻接 `.bss` 紧邻**。Lib/LVGL 为第三方不改。
|
||||
10. **FatFs 严格 8.3 短名** — 详见 AGENTS。补充:含冒号 `:` 的名字被 FatFs 先解析为**盘符前缀** → `f_open` 返回 `FR_INVALID_DRIVE`(11) 而非 `FR_INVALID_NAME`(6);两者都属合法拒绝(测试用例须同时接受)。
|
||||
11. **FA_OPEN_APPEND 陷阱 / 短写** — 详见 AGENTS。追加写必须 `FA_WRITE | FA_OPEN_APPEND`;`f_write` 簇分配失败返回 `FR_OK`+短写(无错误码),判失败必须校验写回字节数。
|
||||
10. **FatFs 严格 8.3 短名** — 本移植 `Lib/FatFs/ffconf.h` 为 `FF_USE_LFN=0`,**只支持严格 8.3 短名**:主名 ≤8 字符、扩展 ≤3 字符、**不得以点开头**(2026-09-20 台架实证,`.fschk` 无限重格式化事故根因)。`.fschk` 会被 `ff.c` 的 `create_short` 把「点之后」当扩展域解析而超限 → `f_open` 恒返 `FR_INVALID_NAME`(6);这是**纯 RAM 里的名字判定,不碰盘**。`ff.c` `create_short` 全部拒绝点的地方已加 DEBUG 打印:`[ERR][FATFS] SFN reject (原因) seg='名字片段' bad_ch=坏字符`——非法名字调用看开机日志即可定位。自愈类逻辑**严禁**把名字/参数类错误码(`FR_INVALID_NAME` 等)归入"卷损坏"触发集(整卷重格式化不可逆)。补充:含冒号 `:` 的名字被 FatFs 先解析为**盘符前缀** → `f_open` 返回 `FR_INVALID_DRIVE`(11) 而非 `FR_INVALID_NAME`(6);两者都属合法拒绝(测试用例须同时接受)。
|
||||
11. **FA_OPEN_APPEND 陷阱 / 短写** — `FA_OPEN_APPEND`(0x30) = `FA_OPEN_ALWAYS|FA_SEEKEND`,**不含 `FA_WRITE`(0x02)**——不带写位打开的文件 `f_write` 恒返回 `FR_DENIED`(7)(这是当年 `/log` 写失败的真根因);追加写必须写 `FA_WRITE | FA_OPEN_APPEND`(2026-09-20 台架实测,`Lib/FatFs` 移植版)。该移植的 `f_write` 在簇分配失败时返回 `FR_OK` + 短写(**没有错误码**)→ 判失败必须校验写回的字节数。标志位为**旧式编号**:`FA_READ`=0x01 / `FA_WRITE`=0x02 / `FA_CREATE_NEW`=0x04 / `FA_CREATE_ALWAYS`=0x08 / `FA_OPEN_ALWAYS`=0x10 / `FA_OPEN_APPEND`=0x30 / `FA_SEEKEND`=0x20(`ff.c` 内部定义),与上游 FatFs R0.14 不同,**勿照抄上游代码示例**。
|
||||
12. **崩溃可观测性(勿屏蔽)** — 已开启 `configCHECK_FOR_STACK_OVERFLOW=2` + `configUSE_MALLOC_FAILED_HOOK` + HardFault 现场报告(`Src/stm32f4xx_it.c`:裸 UART 打印 PC/LR/xPSR + CFSR/HFSR/BFAR/MMFAR 后复位,对照 `.map` 定位符号)。defaultTask **1024** words、testTask **2048** words 是**实测下限,勿降**。开机日志出现 `[ERR] STACK OVERFLOW task=` / `[ERR] HARDFAULT ...` / `MALLOC FAILED` 是精确定位线索,禁止屏蔽或降级。
|
||||
13. **BBT 恢复模式** — 运行期坏块会随 TC-STO-03 注入累积;当介质被**误标脏**(如 DMA 误打 CCM 栈导致随机块被写坏并持久化)时,打开 `test/board/storage_test.h` 的 `ENABLE_STORAGE_RECOVERY_TESTS` 编译**恢复构建**,testTask 会执行 `gd5f2gq5ue_bbt_rebuild()`(出厂扫描清除运行期误标)+ `nand_ftl_format()` 清账后复位。恢复后容量回到基线(即扣除 BBT 保留池后的正常容量,非出厂裸容量)。
|
||||
|
||||
+23
-1
@@ -237,6 +237,28 @@ if (sys_evtHandle != NULL) {
|
||||
|
||||
---
|
||||
|
||||
## 7. 总结
|
||||
## 7. 内核启动前(`osKernelStart` 之前)的编码模式
|
||||
|
||||
> 本节是根目录 `AGENTS.md`「平台约束」中这条铁律的完整细节迁入处(2026-10-11,AGENTS.md 瘦身,不再当事实存放地)。
|
||||
|
||||
**禁令:`osKernelStart` 之前禁止调用任何 FreeRTOS / CMSIS-RTOS 创建类 API**——`osMessageQueueNew` / `osMessageQueuePut` / `osMutexNew` / `osSemaphoreNew` 等在内核启动前调用会**直接杀死启动**。
|
||||
|
||||
**2026-09-20 启动失败实证根因**:`syslog_mcu_init` 在内核启动前调用 `osMessageQueueNew`——这就是 09/19~09/20 "每次必死" 的代码层根因(修复提交 `82411cf`)。机理(见 `App/log/sys_log_mcu.c` 中 `syslog_mcu_init` 的函数注释):`app_main_init()` 运行在 `osKernelInitialize()` **之前**(`Src/main.c` 顺序 = `app_main_init` → `osKernelInitialize` → `MX_FREERTOS_Init` → `osKernelStart`),创建类 API 会在这一窗口提前拉起内核,其后的任务创建落在未完成初始化的内核状态上执行 → 启动失败。
|
||||
|
||||
**内核启动前代码的标准模式三件套**(现成参照:`App/log/sys_log_mcu.c`):
|
||||
|
||||
1. **纯寄存器 / HAL 轮询操作**:启动段初始化只走不依赖内核的裸驱动路径;
|
||||
2. **无锁静态缓冲**:内核前产生的日志先暂存到 `s_preboot[8]`(`SYSLOG_QUEUE_MAX = 8`,纯 BSS 数组,不碰任何内核对象;RTOS 前单生产者、后单消费者,故免锁)。投递点 `syslog_post` 按内核状态(`osKernelGetState()`)自动分流:内核未运行 → 写 `s_preboot`;已运行 → 走真队列;
|
||||
3. **内核启动后惰性创建真队列**:真队列推迟到**任务上下文首次使用时**才创建——见 `syslog_drain`(仅 defaultTask 调用,调度器已在运行,`s_queue == NULL` 时才 `osMessageQueueNew`)。
|
||||
|
||||
**推论**:凡在内核启动前执行的初始化函数里,**不得创建任何 CMSIS 对象**。落地效果:`syslog_mcu_init` 现为"内核启动前安全空操作"(直接 `return 0`),真实初始化全部后移到运行期。
|
||||
|
||||
> **与 §3.3 的边界(勿混读)**:§3.3 说"CMSIS-RTOS v2 允许在 `osKernelInitialize()` 之后、`osKernelStart()` 之前创建内核对象"——那是 **CubeMX 生成器**在 `MX_FREERTOS_Init` 里创建事件组 / 任务的专用窗口;**手写代码**(尤其 `app_main_init` 这条早于 `osKernelInitialize` 的链)不享受该窗口,一律按本节禁令执行。
|
||||
|
||||
**配套判读**:违反本禁令的后果是启动段死机(无输出 + LED 不闪,此时没有任务、没有看门狗保护),定位方法见 §6 第 8 条「启动段(`osKernelStart` 之前)死机的判读法」——开机日志的最后一行 = 卡住的那一步。
|
||||
|
||||
---
|
||||
|
||||
## 8. 总结
|
||||
|
||||
**不要靠"等多少毫秒"来赌依赖就绪,而要靠"对方声明自己就绪了"来驱动启动**——Event Flags 把隐式的时间耦合变成显式的事件依赖,启动顺序自然清晰、健壮、易扩展。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Python 串口助手(serial_tool)使用指南
|
||||
|
||||
> **定位**:面向使用者的操作手册——命令怎么敲、输出怎么看、常见场景怎么组合、出问题怎么排查。
|
||||
> **关联文档**:设计决策与实现细节见 `串口助手设计说明.md`;@test 自动化闭环见 `自动化测试流程.md`;`AGENTS.md`「串口调试」节有一页速查。
|
||||
> **关联文档**:设计决策与实现细节见 `串口助手设计说明.md`;@test 自动化闭环见 `自动化测试流程.md`;`serial-assistant` skill 有一页速查(用到自动加载,AGENTS.md 不再重复收录)。
|
||||
> **版本**:v1.1(与 `.dsh/skills/serial-assistant/scripts/serial_tool.py` 当前实现一致,2026-09-15)
|
||||
|
||||
## 1. 它是什么(60 秒版)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
> **版本**:v1.1(需求 + 设计 + 实施记录)
|
||||
> **日期**:2026-09-15
|
||||
> **状态**:**已实施**(S1–S6 完成;本机验收 A1–A5/A8 通过,A6/A7 正路径待 CH340 硬件接入后补验)
|
||||
> **关联文档**:`串口助手使用指南.md`(命令用法/工作流/排障) · `自动化测试流程.md` · `AGENTS.md`(串口调试/自动化测试节) · `.serialtest/config.json`(端口单一配置源,2026-10-10 由 `.opencode/serial_config.json` 迁入)
|
||||
> **关联文档**:`串口助手使用指南.md`(命令用法/工作流/排障) · `自动化测试流程.md` · `serial-assistant` skill(命令速查/陷阱) · `.serialtest/config.json`(端口单一配置源,2026-10-10 由 `.opencode/serial_config.json` 迁入)
|
||||
> **取代**:`serial-mcp-server_串口调试.md`(实施时删除,工具历史并入本文 §12)
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
Reference in New Issue
Block a user