From 03721aafc4bf11e560f69d101b8e09ea3361240e Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Tue, 27 Oct 2026 20:55:04 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=96=B0=E5=A2=9E=20ADC=20=E9=87=87?= =?UTF-8?q?=E6=A0=B7=E9=99=B7=E9=98=B1=E5=8F=B0=E8=B4=A6=EF=BC=88TRAP-ADC-?= =?UTF-8?q?01/02=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 把 2026-10-27 排查出的两个 ADC 采样陷阱沉淀成正式台账,按 docs/编号规范.md 的 TRAP-ADC- 编号,属主文档 docs/问题记录/ADC_Trap_Records.md。 TRAP-ADC-01:ADC 使能后闲置数秒才挂 DMA,导致 DMA 乒乓缓冲整体 +2 格相位旋转(槽 i 装的是 rank ((i+1) mod 9)+1)。全程无任何 编译或运行错误,只是数据整体错位两格,表象与「映射表写错」完全 一致,历史上据此误判过三轮。 条目重点记了那条判读陷阱:adcr[CH_i] == adcb[i] 成立不能证明通道 映射正确——它只证明拷贝循环是恒等映射,缓冲整体旋转时拷贝照样 恒等。判映射只能靠按通道号索引的独立真值(无 DMA 单通道读)。 附 9 行同开机对照证据表、5 种固件形态的 A/B 对照、修复方式、 回归判据与未证部分(微架构为何恰好丢 2 拍仍未证)。 TRAP-ADC-02:RTOS 运行期校准被 TIM3 TRGO 打断,adc1_calibrate() 返回 0xFFFF 超时哨兵。记了指纹判读要点(truth=65535 且 min 大于 max 是哨兵,不是满量程)与修法(校准期间屏蔽 EXTEN)。 关联登记三处: - docs/README.md 7.3 问题记录表新增一行 - 设计文档 4.5 节加反向链接到 TRAP-ADC-01(代码 -> 设计 -> 台账) - scripts/id_registry.json 的 TRAP 族 cursor_note 补 ADC 域 01~02 纯文档改动,不涉构建。 --- docs/README.md | 1 + docs/子系统设计/ADC采样节拍设计说明.md | 1 + docs/问题记录/ADC_Trap_Records.md | 145 +++++++++++++++++++++++++ scripts/id_registry.json | 2 +- 4 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 docs/问题记录/ADC_Trap_Records.md diff --git a/docs/README.md b/docs/README.md index 66a354da..93c23c58 100644 --- a/docs/README.md +++ b/docs/README.md @@ -195,6 +195,7 @@ docs/ | [`CH395F_Trap_Records.md`](问题记录/CH395F_Trap_Records.md) | CH395F 以太网控制器陷阱台账 | | [`GD5F2GQ5UE_Trap_Records.md`](问题记录/GD5F2GQ5UE_Trap_Records.md) | GD5F2GQ5UE SPI NAND 陷阱台账 | | [`SD2506_Trap_Records.md`](问题记录/SD2506_Trap_Records.md) | SD2506 RTC 陷阱台账 | +| [`ADC_Trap_Records.md`](问题记录/ADC_Trap_Records.md) | ADC1 采样链路陷阱台账(DMA 乒乓缓冲 +2 格相位旋转、RTOS 期校准被节拍打断;2026-10-27) | | [`采集与数据处理短板评测.md`](问题记录/采集与数据处理短板评测.md) | 对照参考项目评测采集/遥测/录波/开入开出的完成度与缺口,给出补齐顺序(2026-10-23) | --- diff --git a/docs/子系统设计/ADC采样节拍设计说明.md b/docs/子系统设计/ADC采样节拍设计说明.md index c1f12abc..bd3ffd77 100644 --- a/docs/子系统设计/ADC采样节拍设计说明.md +++ b/docs/子系统设计/ADC采样节拍设计说明.md @@ -243,6 +243,7 @@ DMA 从序列中途开始搬时,缓冲整体旋转,拷贝照样是恒等的 ⚠ **顺序不可调换**:`adc1_disable()` 必须严格早于 `adc_input_init()`;若 ADC 在挂 DMA 时仍处于使能态, 旋转会重新出现。改动被删时会由审计项 `adc1-calibration-impl` 的基线漂移拦下 (它整段守护 `Src/adc.c` 的 `USER CODE BEGIN 1`)。 +踩坑经过、判读陷阱与回归判据另见 `docs/问题记录/ADC_Trap_Records.md` 的 `TRAP-ADC-01`。 --- ## 5. TPAFE 侧:CONVST 脉冲与 BUSY 读帧 diff --git a/docs/问题记录/ADC_Trap_Records.md b/docs/问题记录/ADC_Trap_Records.md new file mode 100644 index 00000000..a73f8702 --- /dev/null +++ b/docs/问题记录/ADC_Trap_Records.md @@ -0,0 +1,145 @@ +# ADC 采样陷阱记录(TRAP-ADC 系列) + +ADC1 采样链路(TIM3 1 kHz 节拍 → ADC1 九通道扫描 → DMA2_Stream4 乒乓搬运 → `adc_input` +语义映射)的实证陷阱:现象、判读陷阱、定案根因、修复与回归判据。**动 ADC 采样、通道映射或 +诊断代码之前先读本文。** + +> 编号口径:按 `docs/编号规范.md` 采用 `TRAP-ADC-`,本域自 01 起连续。编号不复用、不重排。 +> 状态图例:✅ 已修复定案 · ⏳ 待修。 +> 设计侧口径(采样节拍、寄存器配置、铁律)不在本文,见 +> `docs/子系统设计/ADC采样节拍设计说明.md`;本文只记「踩过的坑」与「怎么判断踩到了」。 + +## 索引 + +| 编号 | 标题 | 状态 | 一句话结论 | +|---|---|---|---| +| TRAP-ADC-01 | ADC 使能后闲置数秒才挂 DMA | ✅ | 乒乓缓冲整体 +2 格旋转;挂 DMA 那一瞬 ADON 必须为 0 | +| TRAP-ADC-02 | RTOS 运行期校准被 TIM3 TRGO 打断 | ✅ | `adc1_calibrate()` 返回 0xFFFF 超时哨兵,诊断读数全 65535 | + +--- + +## TRAP-ADC-01 · ADC 使能后闲置数秒才挂 DMA → 乒乓缓冲 +2 格相位旋转 + +- **状态**:✅ 已修复定案(2026-10-27,提交 `1166ab1c`) +- **发现时间**:2026-10-27(台架,同开机对照实验) + +**现象**:把 `AIN2`(`UB` / PC4 / CH14)的端子接地,`UB` 却读出 **784 码**(浮空量级), +而本该浮空的 `IB` 读出 **0**。九路读数整体"错开两位":接哪一路,0 就出现在**往前数两路** +的位置上。 + +表象与"映射表写错"或"注入点标签不对"**完全一致**,历史上据此误判过三轮——两次接地实验 +(认为 AIN3→IC=0、AIN10→UB=0)都被读成"映射错了两个槽位",实际夹子位置也在动 +(`U5.B7` 与 `U5.A8` 在连接器上斜向相邻、间距不到 3 mm),两个因素叠加,谁也说不清。 + +**判读陷阱(这条比根因更贵)**: + +> `adcr[CH_i] == adcb[i]` 成立**不能**证明通道映射正确。 + +它只证明 `stm32_take()` 的拷贝循环是**恒等映射**(`s_stm32_raw[k_stm32_rank_ch[i]] = src[i]`)。 +DMA 从序列中途开始搬运时,整个缓冲一起旋转,拷贝照样"恒等"——**旋转后的缓冲被原样复制, +看起来完美自洽**。我当时正是拿这个恒等性(11:18 那次 6/6 精确相等)宣布"DMA 从来没有错过", +结论完全错误。 + +判通道映射只有两条路: +1. **按通道号索引的独立真值**——关掉 DMA 与扫描,逐路软件触发、直接读 `DR`; +2. 先按本节修法消除旋转,再做任何比对。 + +从 `adc:` 的**语义标签**反推永远不算证据:标签一错,整条推断链跟着跑偏。 + +**根因(定案)**:触发条件是「**ADC 被使能之后闲置了数秒才挂 DMA**」。 + +`MX_ADC1_Init()` 在 `main()` 里就调用(使能 ADC),而挂 DMA 在 `app_main_init()` 步骤 4b, +两者之间隔着 **GD5F 全片 BBT 扫描(数秒)**。ADC 在这段时间里处于 `ADON=1` 的空转态; +等 DMA 挂上去时,搬运起点已经不在序列的 rank 1 上。 + +台架进一步收窄为:**挂 DMA 的那一瞬间 `CR2.ADON` 必须为 0**——不需要整个闲置期都为 0, +只要使能与搬运之间不留可观测间隔,旋转就不出现。 + +**证据(同一次开机内对照,9/9 完美置换)**:先用无 DMA 单通道方式逐路取真值,再与 DMA 路径 +的同一批输入按通道号对照: + +| 槽(rank) | 通道 | DMA 值 | 实际装的是 | 真值 | 差 | +|---|---|---|---|---|---| +| 1 | CH0 | 850 | CH2 | 850 | 0 | +| 2 | CH1 | 932 | CH3 | 931 | 1 | +| 3 | CH2 | 853 | CH4 | 852 | 1 | +| 4 | CH3 | 819 | CH5 | 817 | 2 | +| 5 | CH4 | 946 | CH6 | 945 | 1 | +| 6 | CH5 | 954 | CH7 | 953 | 1 | +| 7 | CH6 | 0 | CH14 | 0 | 0 | +| 8 | CH7 | 690 | CH0 | 691 | 1 | +| 9 | CH14 | 790 | CH1 | 785 | 5 | + +即**槽 `i` 装的是 rank `((i+1) mod 9)+1`,整个缓冲从 rank 3 开始搬,固定错开 2 格**。 +差值全在 5 码以内(两种读法的噪声),不是随机抖动。 + +**A/B 对照(硬件完全不动,只换固件)**: + +| 固件形态 | 开机次数 | `UB` 读数 | 结论 | +|---|---|---|---| +| 干净固件 | 7/7 | 783~786 | 旋转存在 | +| 挂 DMA 前重初始化 ADC | 5/5 | 0 | 旋转消失 | +| 同一次开机内重新挂 DMA | 1/1 | 0 | 旋转消失 | +| 修复后(`MX_ADC1_Init()` 末尾关闭) | 4/4 | 0 | 旋转消失 | +| 修复后(步骤 4b-pre 调 `adc1_disable()`) | 3/3 | 0 | 旋转消失 | + +⚠ **跨开机对照无效**:输入浮空时读数会随环境漂移,7 次和 5 次看着都"稳定",但两组之间 +不可比。必须同一次开机内、硬件不动,才能下结论。 + +**修复**:`app_main_init()` 步骤 **4b-pre** 调 `adc1_disable()`(实现见 `Src/adc.c` 的 +`USER CODE BEGIN 1`),把 ADC 关掉;使能动作交给 `HAL_ADC_Start_DMA()` 内部完成——它自己 +`__HAL_ADC_ENABLE` + 等 Tstab(约 20 µs),然后紧接着开 `CR2.DMA` 并启流。 + +⚠ **顺序不可调换**:`adc1_disable()` 必须严格早于 `adc_input_init()`。若 ADC 在挂 DMA 时 +仍处于使能态,旋转会重新出现。该顺序已写进 +`docs/子系统设计/ADC采样节拍设计说明.md` 的设计铁律第 8 条,并由 CubeMX 存活审计项 +`adc1-calibration-impl`(整段守护 `USER CODE BEGIN 1`)的基线漂移兜底。 + +**回归判据**: +1. 把 `AIN2`(`UB`)端子接地后开机,`adc:` 行 `UB` 必须为 **0**(不是 700~800); +2. 九路按 rank 序无错位——接地哪一路,`0` 就出现在**该路**上,不往前偏两格; +3. 同开机对照(DMA 值 vs 无 DMA 单通道真值)逐路差值 ≤5 码。 + +**未证部分**:微架构层面**为什么恰好丢 2 拍**仍未证出(`ADON=1` 空转态下内部状态机如何 +预推进两格)。工程结论已足够:使能与搬运不该有可观测间隔。不要为了"解释清楚"去猜, +更不要据此改动 ADC 配置。 + +**教训**: +1. **恒等性 ≠ 正确性**:拷贝循环恒等只能证明"没抄错",证明不了"源头没偏"。 +2. **同开机对照是唯一有效方法论**:跨开机比浮空读数会把漂移当成差异。 +3. **判映射只认按通道号索引的真值**,不认语义标签反推。 +4. **"不报错的错"最贵**:这一条全程没有任何编译/运行错误,只是数据整体错位两格。 + +--- + +## TRAP-ADC-02 · RTOS 运行期校准被 TIM3 TRGO 打断 → 返回 0xFFFF + +- **状态**:✅ 已定性(探针代码已删,本条作为以后再写校准/诊断代码的证词保留) +- **发现时间**:2026-10-27(TRAP-ADC-01 的同开机对照探针) + +**现象**:诊断探针在 RTOS 上下文里逐路取真值,**从第二路起**每次都是 +`truth=65535 min=65535 max=0`——看起来像"这一路输入是满量程",实际是校准失败。 + +**根因**:`adc1_calibrate()` 置 `CR2.CAL` 后轮询等它由硬件清零,超时上限 10 ms。但 TIM3 +的 1 kHz 节拍(TRGO 触发 ADC1 常规转换)此时**已经在跑**,一次 TRGO 就启动常规转换、 +打断 CAL 序列,CAL 位永远等不到清零 → 函数返回 `0xFFFF` 超时哨兵,调用方把它当成了 +转换结果。固定发生在第二个被探通道,是因为第一路探完时 TIM3 还没启动。 + +**修复(若再写探针)**:校准前后屏蔽外部触发—— +`CLEAR_BIT(ADC1->CR2, ADC_CR2_EXTEN)` → 校准 → 恢复 `EXTEN`。 + +**判读要点**:`truth` 恰好等于 `0xFFFF`(65535)且 `min=65535 / max=0`(最小值大于最大值) +是超时哨兵的**指纹**,不是满量程读数。看到这个组合先怀疑校准失败,不要怀疑输入。 + +**教训**:任何在 RTOS 运行期调用的 ADC 校准,都必须先断开外部触发;校准是独占操作, +不能与常规采样节拍并发。 + +--- + +## 相关文档 + +- 设计侧口径、寄存器配置、9 行证据表的原始记录与复现方法: + `docs/子系统设计/ADC采样节拍设计说明.md` §4.5(设计铁律第 8 条)。 +- 通道映射与引脚对应:`docs/硬件平台/ADC通道映射说明.md`。 +- 前端拓扑(③ 段变比 = 1:1,非分压):`docs/硬件平台/V0.0_网表详细分析报告.md` §4.7。 +- 零点/线性/映射的现场验证步骤与判据:`docs/测试说明/ADC前端注入验证流程.md`。 diff --git a/scripts/id_registry.json b/scripts/id_registry.json index 5ca9a004..ba08816a 100644 --- a/scripts/id_registry.json +++ b/scripts/id_registry.json @@ -520,7 +520,7 @@ 2 ], "check_dangling": true, - "cursor_note": "分模块各自递增:NET 01~21(属主 docs/问题记录/CH395F_Trap_Records.md)、GD5F 01~07(GD5F2GQ5UE_Trap_Records.md)、RTC 01(SD2506_Trap_Records.md)。批 4(2026-10-21)已把空格形 `Trap NN` 与中文形 `陷阱 N` 统一成 `TRAP--`,数字不变、只补模块码(§7.1)。**已知盲区(登记而非静默放过)**:docs/硬件平台/V0.0_网表详细分析报告.md(5 处)与 V0.1_网表详细分析报告.md(1 处)里的 `Trap05` 语义确指 `TRAP-NET-05`(CH395F 与 RTL8305 自动协商不兼容)已于批 7 统一为 TRAP-NET-05(6 处,改名工具已解除对本目录的排除);本目录**仍不在门禁扫描语料内**:粗测有约 4200 处 R/C/D/J/X/U/T 位号,位号类型识别做完前纳入会让 --strict 天天为位号拦提交,那等于把闸门变成噪音源。", + "cursor_note": "分模块各自递增:NET 01~21(属主 docs/问题记录/CH395F_Trap_Records.md)、GD5F 01~07(GD5F2GQ5UE_Trap_Records.md)、RTC 01(SD2506_Trap_Records.md)。批 4(2026-10-21)已把空格形 `Trap NN` 与中文形 `陷阱 N` 统一成 `TRAP--`,数字不变、只补模块码(§7.1)。**已知盲区(登记而非静默放过)**:docs/硬件平台/V0.0_网表详细分析报告.md(5 处)与 V0.1_网表详细分析报告.md(1 处)里的 `Trap05` 语义确指 `TRAP-NET-05`(CH395F 与 RTL8305 自动协商不兼容)已于批 7 统一为 TRAP-NET-05(6 处,改名工具已解除对本目录的排除);本目录**仍不在门禁扫描语料内**:粗测有约 4200 处 R/C/D/J/X/U/T 位号,位号类型识别做完前纳入会让 --strict 天天为位号拦提交,那等于把闸门变成噪音源。ADC 域 01~02(属主 docs/问题记录/ADC_Trap_Records.md,2026-10-27 新增:DMA 乒乓缓冲 +2 格相位旋转、RTOS 期校准被节拍打断)。", "adjacent_cues": [ "Trap", "trap",