- CubeMX 加 TIM6(PSC=83 / ARR=999 / ARR 预装载 / NVIC 抢占优先级 6) - Src/main.c 回调加 TIM6 分支触发 CONVST(USER CODE 区) - app_main.c 用 HAL_TIM_Base_Start_IT(&htim6) 替换单次触发 - adc_task.c 退化为纯消费者(1 ms 轮询仅作消费节奏) - @build 0 错 0 警;台架 @test 验收待做 - 同步 ADC采样节拍设计说明 / 继电保护复现规划 / AGENTS / TPAFE README
11 KiB
ADC 采样节拍设计说明(1 kHz 硬件定时器触发)
状态:已实现(2026-10-10)——TIM6 更新中断(1 kHz)触发已落地(
Src/main.c回调 +app_main.c启动 +adc_task.c退化为纯消费者),@build0 错 0 警;台架@test验收(§7)待做。 上位需求:docs/算法/继电保护功能复现规划.md§3.2 L1-1(周期 CONVST 重触发 1000 Hz, 与保护节拍同源)。驱动契约:Drivers/BSP/TPAFE5160/README.md。 背景:B1(2026-10-10)已把adc_task由空桩改为真实消费者,但采样节拍是 任务周期软触发(osDelayUntil)——CONVST 边沿 = 任务被调度到的时刻,抖动大、 且与 FreeRTOS tick 同源。本项把节拍源换成硬件定时器。
1. 目标与现状
| 项 | 改造前(B1 软触发) | 改造后(TIM6 硬件定时器,2026-10-10 已落地) |
|---|---|---|
| CONVST 边沿时刻 | 任务被调度时刻(抖动 = 调度延迟,可达数十 µs~ms) | TIM 更新事件 + ISR 入口延迟(亚 µs~数 µs) |
| 周期精度 | 依赖 FreeRTOS tick(TIM7) | 定时器硬件分频,晶振级 |
| 丢拍 | 任务被长时抢占会漏拍 | 硬件自动重载,不漏拍 |
| 等周波调频 | 需改 tick 周期(不可行) | 运行期写 ARR 即可(§8) |
判据(L1-1):周期 CONVST 重触发 1000 Hz;示波器见 U3 BUSY 连续脉冲;
tpafe5160_frame_seq() 持续递增(每秒 +1000)。
2. 方案选型
2.1 方案 A(推荐):TIM6 更新中断 → ISR 内脉冲 CONVST
- TIM6 配成 1 kHz 更新中断;ISR 内调
tpafe5160_start_conv_irq()(现成的 GPIO 脉冲)。 - 零引脚改动:PC9 保持
GPIO_Output,驱动与tpafe5160_init()首帧自检完全不动。 - BUSY(PC7)EXTI 读帧路径完全不动。
- 周期精度 = 定时器硬件(晶振级);CONVST 边沿抖动 = TIM6 ISR 入口延迟(见 §5)。
- 运行期改 ARR 即改变采样率 → 天然支持等周波调频。
2.2 方案 B(备选,暂不采用):TIM3_CH4/TIM8_CH4 硬件 PWM 直驱 PC9
- PC9 复用为定时器通道,硬件直接产生 CONVST 方波,零软件抖动。
- 代价:① 需把 PC9 由
GPIO_Output改为 AF(.ioc引脚改动); ② 驱动的TPAFE5160_CONVST_*宏(GPIO 写)全部失效 →tpafe5160_init()的 "确保 CONVST 低"与首帧自检(E-44)都要重写;③ 上电初值/空闲电平语义变化。 - 结论:收益(把抖动从"数 µs"降到"0")不足以抵消改动面与回归风险。 仅当 §5 实测抖动超过算法容限时再考虑。
下文只展开方案 A。
3. CubeMX 配置规格(照此配置)
前提:SYSCLK = 168 MHz / HCLK = 168 MHz / APB1 = 42 MHz(÷4)→ APB1 定时器时钟 = 84 MHz;
HAL 时基 = TIM7(已占用);TIM1TIM6、TIM8TIM14 当前全部空闲。
| 步骤 | 位置 | 值 | 说明 |
|---|---|---|---|
| 1 | Timers → TIM6 → Activated | ✅ 勾选 | 基础定时器,无输出引脚(不占用任何 IO) |
| 2 | Prescaler (PSC) | 83 | 84 MHz ÷ (83+1) = 1 MHz 计数时钟(1 µs 分辨率) |
| 3 | Counter Period (ARR) | 999 | 1 MHz ÷ (999+1) = 1.000 kHz(= 1000 µs 周期) |
| 4 | Counter Mode | Up | 向上计数 |
| 5 | auto-reload preload | Enable | 运行期写 ARR 在下一个更新事件生效,不产生毛刺(§8 等周波调频要用) |
| 6 | Clock Division | No Division | 与采样无关 |
| 7 | Trigger Event Selection | Reset(默认) | 不用 TRGO |
| 8 | NVIC Settings → TIM6 global interrupt | ✅ 勾选;Preemption Priority = 6 | 与 BUSY EXTI(EXTI9_5_IRQn = 6)同级:两者互不抢占,避免"读 RD 时序被 CONVST 脉冲打断"(§5);且 6 ≥ configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY(=5),将来 ISR 里发任务通知也安全 |
生成后:CubeMX 会新建 Src/tim.c + Inc/tim.h(含 htim6 与 MX_TIM6_Init())、
在 Src/stm32f4xx_it.c 生成 TIM6_IRQHandler()、在 Src/main.c 的 main() 里插入 MX_TIM6_Init()。
⚠ MX_TIM6_Init() 只做配置,不启动计数——启动由用户代码负责(§4 第 4 条)。
为何不用 TIM7 那种"1 MHz 计数 + ARR=999"以外的心跳:本配置与 HAL 时基 TIM7 的构造完全一致(同为 84 MHz / 1 MHz / 1000 计数),便于对照排查;PSC 取 83 使 ARR 与 "微秒"一一对应,等周波调频时可直接
ARR = 周期µs - 1。
4. 代码改造清单
约定:生成区不改(CubeMX 重生成会覆盖);所有手工代码落
USER CODE保护区(L2)。
4.1 Src/main.c(CubeMX 生成;改 USER CODE 区)
USER CODE BEGIN Includes增加#include "tpafe5160.h"。HAL_TIM_PeriodElapsedCallback()(注意:该回调被 TIM7 时基共用)增加 TIM6 分支:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM7) { HAL_IncTick(); } /* 既有:HAL 时基 */
/* USER CODE BEGIN Callback 0 / 1 —— 加在既有 TIM7 分支之后 */
if (htim->Instance == TIM6)
{
tpafe5160_start_conv_irq(); /* 1 kHz 采样节拍:ISR 内脉冲 CONVST(仅 GPIO 写,亚 µs) */
}
}
⚠ 不得破坏既有 HAL_IncTick() / task_wd_tick_probe() 两条 TIM7 分支。
4.2 Src/tim.c / Inc/tim.h / Src/stm32f4xx_it.c
- CubeMX 自动生成,勿手改(
TIM6_IRQHandler→HAL_TIM_IRQHandler(&htim6))。
4.3 App/app/app_main.c
- 增加
#include "tim.h"。 - 第 213 行的单次
tpafe5160_start_conv_irq();替换为启动周期触发:
/* 6) 启动 1 kHz 采样节拍(TIM6 更新中断 → ISR 内触发 CONVST) */
(void)HAL_TIM_Base_Start_IT(&htim6);
- ⚠ 必须在
tpafe5160_init()成功之后再启动 TIM6,否则 ISR 会在驱动自检 (首帧有效性探针,E-44)期间乱发 CONVST。
4.4 App/task/adc_task.c
- 删除主循环里的
tpafe5160_start_conv_irq();(触发已交给 TIM6)。 - 本任务退化为纯消费者:
tpafe5160_snapshot()+ 帧统计 + 10 s 心跳 + 看门狗心跳。 1 ms 节拍(osDelayUntil)保留,仅用于"消费节奏"。 - 更新文件头与函数注释(说明节拍由 TIM6 提供,本任务不再触发)。
- 看门狗不变:
TASK_WD_ADC心跳仍在循环内每拍调用。
4.5 文档同步(2026-10-10 已执行)
docs/算法/继电保护功能复现规划.md:§3.2 L1-1 由 🔶 改为 ✅(TIM6 硬件触发)、§1.2 采样软件行 + 变更记录同步。docs/待处理内容.md§4:TPAFE 自动扫描模式待确认项标注"已不影响"(TIM6 方案不依赖它)。AGENTS.md架构要点adcTask条 +app_main_init序列:改为"TIM6 硬件触发 + 纯消费者"。Drivers/BSP/TPAFE5160/README.md:周期重触发改为"由 TIM6 更新中断提供"。
5. 时序与优先级分析
单周期时序(1 kHz,周期 1000 µs):
t=0 TIM6 更新事件 → ISR → CONVST 脉冲(LOW→HIGH 上升沿)
t≈0+ε TPAFE5160 开始转换(BUSY 拉高)
t≈23 µs BUSY 拉低 → PC7 EXTI(优先级 6) → 读 8 通道(≈0.5 µs)→ seq++
t=1000 µs 下一个 TIM6 更新事件
- 读窗口与下一次 CONVST 相隔 ~977 µs(转换仅 ~23 µs),互不重叠。
- TIM6 与 BUSY EXTI 同级(6)→ 互不抢占:读 RD 时序(8 次 RD 翻转)不会被打断, 避免"读到一半被新转换刷新数据总线"。这是选 6 而非 5 的原因。
- 触发抖动:TIM6 是最高优先级之一(5 为 USART,7 为 SPI/DMA);被更高优先级 ISR (USART,~数 µs)挡住的概率与时长都有限 → 最坏抖动约数 µs,占 1000 µs 的 <0.5%。
- ISR 时长:
tpafe5160_start_conv_irq()只做两次HAL_GPIO_WritePin(寄存器写) → 亚 µs,不拖累其它中断。
6. 风险与注意事项
- 共用回调:
HAL_TIM_PeriodElapsedCallback同时服务 TIM7(HAL 时基)与 TIM6 → 分支必须并列、不得互相干扰;改动后必须确认开机日志时间戳正常(时基未坏)。 - 启动顺序:TIM6 必须在
tpafe5160_init()之后启动(§4.3)。 - 不新增任务/栈:本项零新任务、零新栈、零动态分配 → 不动
stack_report.py预算。 - CubeMX 生存:新增生成文件
Src/tim.c/Inc/tim.h;改后跑一次python scripts/check_cubemx_survival.py,若有新增生成文件被登记,按提示重建基线。 - Keil 工程:从 CubeMX 重生成工程(含 MDK-ARM)以把
tim.c纳入编译;随后@build必须 0 错 0 警。 mem-numbers:本项改 Flash/RAM 极小但非零 → 若check_mem_numbers.pyFAIL, 跑python scripts/check_mem_numbers.py --write刷新快照。- 消费端与生产端同频:TIM6(84 MHz 派生)与 FreeRTOS tick TIM7(同源)都恰好 1 kHz, 相位固定 → 消费端每拍恰好取到 1 帧。一旦进入等周波调频(采样率≠1 kHz), 1 ms 轮询会与生产端失配 → 消费端须改为"帧就绪事件驱动"(见 §8)。
7. 验收判据
| # | 判据 | 手段 |
|---|---|---|
| 1 | @build 0 错 0 警,且镜像无源文件新于 hex |
MDK-ARM/build.bat + find -newermt |
| 2 | PC9 CONVST 周期 = 1.000 kHz(±0.1%) |
示波器 / 逻辑分析仪 |
| 3 | PC7 BUSY 每周期一个脉冲,与 CONVST 相位固定 |
示波器双通道 |
| 4 | frame_seq() 每秒 +1000(每 10 s +10000),严格递增 |
@test 串口 [ADC_TASK] frames=... seq=... |
| 5 | frst_err=0、idle 基本为 0 |
同上 |
| 6 | 开机日志时间戳正常(TIM7 时基未坏) | 串口日志 |
| 7 | 无 HardFault / [ERR] / 看门狗复位 |
@test Forbidden 判定 |
8. 后续:等周波调频(不在本项范围)
参考系统按 20 点/周波采样:电网频率漂移时需让采样率跟随(50.0 Hz → 1000 Hz; 49.5 Hz → 990 Hz),以保持傅氏全波窗对齐一个工频周期。
- 本配置已为此预留:1 µs 分辨率 + ARR 预装载使能 → 运行期
__HAL_TIM_SET_AUTORELOAD(&htim6, 周期µs - 1)即可无毛刺改频。 - 需要配套:① 测频源(过零/DFT 相位);② 把当前采样率同步给保护算法(相量/定值); ③ 消费端改事件驱动(§6.7)——否则 1 ms 轮询在非 1 kHz 采样率下会丢帧。
9. 变更记录
| 日期 | 变更 | 说明 |
|---|---|---|
| 2026-10-10 | 建立本文档 | B1(ADC 采集链路)遗留项"精确 1 kHz 硬件定时器触发"的规划:方案选型(A/B)、CubeMX 配置规格、代码改造清单、时序与优先级分析、风险与验收判据、等周波调频预留 |
| 2026-10-10 | 实现(方案 A) | CubeMX 加 TIM6(PSC=83 / ARR=999 / ARR 预装载 / NVIC 抢占优先级 6);Src/main.c 回调加 TIM6 分支触发 CONVST;app_main.c 用 HAL_TIM_Base_Start_IT(&htim6) 启动节拍;adc_task.c 退化为纯消费者。@build 0 错 0 警;台架 @test 验收待做 |