# Verification Checklist ## 阶段 A:周期任务标志脱离 TaskManager(严重风险 #1) - [x] `comm/ethercat_slave.h` 中声明 `s_periodicSeq` / `s_processedSeq` 静态成员 - [x] `comm/ethercat_slave.h` 中声明 `hasPendingPeriodic()` / `markPeriodicProcessed()` 公有接口 - [x] `comm/ethercat_slave.cpp` 的 `periodicIsr()` 末尾无 `TaskManager::set(1UL << TASK_ETHERCAT_PROCESS)`,改为 `s_periodicSeq++` - [x] `hasPendingPeriodic()` 返回 `s_periodicSeq != s_processedSeq` - [x] `markPeriodicProcessed()` 执行 `s_processedSeq = s_periodicSeq` - [x] `sys/task_runner.cpp` 的 `runPending()` 中增加 `hasPendingPeriodic()` 检查分支,受 `#if CONFIG_ETHERCAT_ENABLE` 保护 - [x] `comm/ethercat_sync.cpp` 的 `onEscIrqExti()` 仍调用 `TaskManager::set(1UL << TASK_ETHERCAT_PROCESS)`,未改动 - [x] `comm/ethercat_slave.h` 头注释说明周期路径与事件路径的标志分离机制 - [x] 确认 `task_flags` 不再被 preempt=0 的 periodicIsr 触碰 ## 阶段 B:EXMC 总线访问权分离(严重风险 #2) - [x] `comm/esc_lan9252.h` 声明 `safeReadReg` / `safeWriteReg` / `safeReadPdi` / `safeWritePdi` 四个 safe 接口 - [x] `comm/esc_lan9252.cpp` 实现 safe 接口,内部用 `__disable_irq/__set_PRIMASK` 包裹(非 BASEPRI) - [x] `comm/esc_lan9252.h` 注释标注 `readReg/writeReg/readPdi/writePdi` 为 "ISR-only,preempt=0 调用,无锁" - [x] `comm/esc_lan9252.h` 注释标注 `safeReadReg/safeWriteReg/safeReadPdi/safeWritePdi` 为 "Thread-safe,主循环/init 调用,PRIMASK 保护" - [x] `comm/esc_exmc_bus.h` 注释标注 `read16/write16/readBlock/writeBlock` 调用约束 - [x] `comm/ethercat_slave.cpp` 的 `init()` 中 EXMC 访问改用 safe 接口 - [x] `comm/ethercat_slave.cpp` 的 `process()` 若有 EXMC 访问,使用 safe 接口 - [x] `comm/ethercat_slave.cpp` 的 `periodicIsr()` 仍调用无锁 `readPdi/writePdi` - [x] 代码审查确认无主循环路径误调用 ISR-only 接口 ## 阶段 C:PDO 三缓冲替换双缓冲(严重风险 #3 与 #4) - [x] `comm/ethercat_slave.h` 中 `s_inputs` / `s_outputs` 数组大小改为 3 - [x] `comm/ethercat_slave.h` 成员名改为 `s_inputWriteIdx` / `s_outputReadIdx`(无原 `s_inputReadIndex` / `s_outputWriteIndex` 残留) - [x] `comm/ethercat_slave.cpp` 的 `init()` 初始化 `s_inputWriteIdx = 0` / `s_outputReadIdx = 0` - [x] `comm/ethercat_slave.cpp` 的 `periodicIsr()` 使用模 3 轮转写入 `s_inputs[s_inputWriteIdx]` 后递增 - [x] `comm/ethercat_slave.cpp` 的 `periodicIsr()` 使用模 3 轮转读取 `s_outputs[s_outputReadIdx]` 后递增 - [x] `comm/ethercat_slave.cpp` 的 `getLatestInputs()` 返回 `&s_inputs[(s_inputWriteIdx + 2) % 3]` - [x] `comm/ethercat_slave.cpp` 的 `setOutputs()` 写入 `s_outputs[(s_outputReadIdx + 1) % 3]`,无临界区 - [x] 全项目搜索确认无残留的 `^1U` XOR 翻转逻辑(原双缓冲) - [x] `comm/ethercat_slave.h` 头注释更新为三缓冲说明,标注容忍度"主循环处理 < 2 × 周期时间" ## 阶段 D:periodicIsr 执行时间测量(高风险 #5) - [x] `comm/ethercat_slave.h` 声明 `s_isrMaxCycles` / `s_isrAvgCycles` / `s_isrCount` 诊断成员 - [x] `comm/ethercat_slave.cpp` 的 `periodicIsr()` 入口/出口读取 `DWT->CYCCNT` 计算差值 - [x] `periodicIsr()` 更新 max(原子比较)与 avg 统计 - [x] `sys/initial.cpp` 或 `comm/esc_lan9252.cpp::init()` 中使能 DWT(DEMCR + CYCCNT) - [x] `sys/task_runner.cpp` 的 `taskDiagnosticPrint()` 增加 `periodicIsr max=Xus avg=Yus` 输出(受 `#if CONFIG_ETHERCAT_ENABLE` 保护) - [x] `sys/config.h` 增加 `CONFIG_ETHERCAT_ISR_MAX_US_THRESHOLD 5U` 宏 - [x] spec.md 或代码注释记录 >5µs 的评估流程与 ≤5µs 的接受说明 ## 阶段 E:.ramfunc 段落地与调用链 RAM 化(高风险 #6) - [x] 定位到项目链接脚本文件(`.sct` 或 RTE 配置) - [x] 链接脚本中新增 `.ramfunc` 输出段,VMA 在 SRAM,LMA 在 Flash - [x] 启动代码中确认/增加 `.ramfunc` 段从 Flash 到 RAM 的拷贝逻辑 - [x] `comm/ethercat_slave.cpp` 的 `periodicIsr()` 标记 `__attribute__((section(".ramfunc"), noinline))` - [x] `comm/esc_lan9252.cpp` 的 `readPdi()` / `writePdi()` 标记 `__attribute__((section(".ramfunc"), noinline))` - [x] `comm/esc_exmc_bus.cpp` 的 `read16()` / `write16()` 标记 `__attribute__((section(".ramfunc"), noinline))` - [x] `readBlock()` / `writeBlock()` 不标记(非 ISR 调用链) - [ ] map 文件确认 `.ramfunc` 段 VMA 在 SRAM 区域、LMA 在 Flash 区域 - [ ] map 文件确认 `periodicIsr` / `readPdi` / `writePdi` / `read16` / `write16` 符号地址在 SRAM ## 编译验证与回退 - [ ] `CONFIG_ETHERCAT_ENABLE=1` 时全量编译通过,无 error - [ ] `CONFIG_ETHERCAT_ENABLE=1` 时无新增 warning(特别检查 `.ramfunc` 相关链接警告) - [ ] map 文件确认 `s_inputs[3]` / `s_outputs[3]` / `s_periodicSeq` 在 SRAM - [ ] `CONFIG_ETHERCAT_ENABLE` 恢复为 0 - [ ] `CONFIG_ETHERCAT_ENABLE=0` 时全量编译仍通过 - [ ] `CONFIG_ETHERCAT_ENABLE=0` 时功能与改造前等价(ADC/CAN/SPI 正常) ## 严重风险闭环确认 - [x] 严重风险 #1(task_flags 丢失更新):periodicIsr 不再触碰 task_flags,闭环 - [x] 严重风险 #2(EXMC 总线争用):主循环访问走 safe 接口(PRIMASK),ISR 走无锁,闭环 - [x] 严重风险 #3(PDO 双缓冲竞态):三缓冲容忍跨周期,闭环 - [x] 严重风险 #4(setOutputs 拷贝竞态):三缓冲隔离,无需锁,闭环 - [x] 高风险 #5(ISR 慢速 EXMC 循环):DWT 测量 + 评估阈值,闭环 - [x] 高风险 #6(.ramfunc 未落地):链接脚本 + 启动拷贝 + 调用链 RAM 化,闭环