Files
cbb b171767023 feat(ethercat): 添加EtherCAT从站功能支持并优化同步机制
- 添加CAN反馈和ID快照SPI命令文件
- 移除EXMC组件依赖,精简项目配置
- 添加RAM函数段链接脚本,优化Flash等待周期抖动
- 实现EscExmcBus类,提供16位并行总线访问LAN9252
- 实现EscLan9252驱动,支持寄存器和PDI内存访问
- 实现EthercatSlave类,采用三缓冲机制进行PDO数据交换
- 实现EthercatSync同步管理,支持SYNC0/SYNC1中断和定时器模式
- 添加ISR执行时间统计和诊断功能
- 分离周期路径和事件路径通知机制,避免RMW竞态
2026-06-29 01:51:02 +08:00

5.4 KiB
Raw Permalink Blame History

Verification Checklist

阶段 A:周期任务标志脱离 TaskManager(严重风险 #1)

  • comm/ethercat_slave.h 中声明 s_periodicSeq / s_processedSeq 静态成员
  • comm/ethercat_slave.h 中声明 hasPendingPeriodic() / markPeriodicProcessed() 公有接口
  • comm/ethercat_slave.cpp 的 periodicIsr() 末尾无 TaskManager::set(1UL << TASK_ETHERCAT_PROCESS),改为 s_periodicSeq++
  • hasPendingPeriodic() 返回 s_periodicSeq != s_processedSeq
  • markPeriodicProcessed() 执行 s_processedSeq = s_periodicSeq
  • sys/task_runner.cpp 的 runPending() 中增加 hasPendingPeriodic() 检查分支,受 #if CONFIG_ETHERCAT_ENABLE 保护
  • comm/ethercat_sync.cpp 的 onEscIrqExti() 仍调用 TaskManager::set(1UL << TASK_ETHERCAT_PROCESS),未改动
  • comm/ethercat_slave.h 头注释说明周期路径与事件路径的标志分离机制
  • 确认 task_flags 不再被 preempt=0 的 periodicIsr 触碰

阶段 B:EXMC 总线访问权分离(严重风险 #2)

  • comm/esc_lan9252.h 声明 safeReadReg / safeWriteReg / safeReadPdi / safeWritePdi 四个 safe 接口
  • comm/esc_lan9252.cpp 实现 safe 接口,内部用 __disable_irq/__set_PRIMASK 包裹(非 BASEPRI)
  • comm/esc_lan9252.h 注释标注 readReg/writeReg/readPdi/writePdi 为 "ISR-only,preempt=0 调用,无锁"
  • comm/esc_lan9252.h 注释标注 safeReadReg/safeWriteReg/safeReadPdi/safeWritePdi 为 "Thread-safe,主循环/init 调用,PRIMASK 保护"
  • comm/esc_exmc_bus.h 注释标注 read16/write16/readBlock/writeBlock 调用约束
  • comm/ethercat_slave.cpp 的 init() 中 EXMC 访问改用 safe 接口
  • comm/ethercat_slave.cpp 的 process() 若有 EXMC 访问,使用 safe 接口
  • comm/ethercat_slave.cpp 的 periodicIsr() 仍调用无锁 readPdi/writePdi
  • 代码审查确认无主循环路径误调用 ISR-only 接口

阶段 C:PDO 三缓冲替换双缓冲(严重风险 #3 与 #4)

  • comm/ethercat_slave.h 中 s_inputs / s_outputs 数组大小改为 3
  • comm/ethercat_slave.h 成员名改为 s_inputWriteIdx / s_outputReadIdx(无原 s_inputReadIndex / s_outputWriteIndex 残留)
  • comm/ethercat_slave.cpp 的 init() 初始化 s_inputWriteIdx = 0 / s_outputReadIdx = 0
  • comm/ethercat_slave.cpp 的 periodicIsr() 使用模 3 轮转写入 s_inputs[s_inputWriteIdx] 后递增
  • comm/ethercat_slave.cpp 的 periodicIsr() 使用模 3 轮转读取 s_outputs[s_outputReadIdx] 后递增
  • comm/ethercat_slave.cpp 的 getLatestInputs() 返回 &s_inputs[(s_inputWriteIdx + 2) % 3]
  • comm/ethercat_slave.cpp 的 setOutputs() 写入 s_outputs[(s_outputReadIdx + 1) % 3],无临界区
  • 全项目搜索确认无残留的 ^1U XOR 翻转逻辑(原双缓冲)
  • comm/ethercat_slave.h 头注释更新为三缓冲说明,标注容忍度"主循环处理 < 2 × 周期时间"

阶段 D:periodicIsr 执行时间测量(高风险 #5)

  • comm/ethercat_slave.h 声明 s_isrMaxCycles / s_isrAvgCycles / s_isrCount 诊断成员
  • comm/ethercat_slave.cpp 的 periodicIsr() 入口/出口读取 DWT->CYCCNT 计算差值
  • periodicIsr() 更新 max(原子比较)与 avg 统计
  • sys/initial.cpp 或 comm/esc_lan9252.cpp::init() 中使能 DWT(DEMCR + CYCCNT)
  • sys/task_runner.cpp 的 taskDiagnosticPrint() 增加 periodicIsr max=Xus avg=Yus 输出(受 #if CONFIG_ETHERCAT_ENABLE 保护)
  • sys/config.h 增加 CONFIG_ETHERCAT_ISR_MAX_US_THRESHOLD 5U 宏
  • spec.md 或代码注释记录 >5µs 的评估流程与 ≤5µs 的接受说明

阶段 E:.ramfunc 段落地与调用链 RAM 化(高风险 #6)

  • 定位到项目链接脚本文件(.sct 或 RTE 配置)
  • 链接脚本中新增 .ramfunc 输出段,VMA 在 SRAM,LMA 在 Flash
  • 启动代码中确认/增加 .ramfunc 段从 Flash 到 RAM 的拷贝逻辑
  • comm/ethercat_slave.cpp 的 periodicIsr() 标记 __attribute__((section(".ramfunc"), noinline))
  • comm/esc_lan9252.cpp 的 readPdi() / writePdi() 标记 __attribute__((section(".ramfunc"), noinline))
  • comm/esc_exmc_bus.cpp 的 read16() / write16() 标记 __attribute__((section(".ramfunc"), noinline))
  • 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 正常)

严重风险闭环确认

  • 严重风险 #1(task_flags 丢失更新):periodicIsr 不再触碰 task_flags,闭环
  • 严重风险 #2(EXMC 总线争用):主循环访问走 safe 接口(PRIMASK),ISR 走无锁,闭环
  • 严重风险 #3(PDO 双缓冲竞态):三缓冲容忍跨周期,闭环
  • 严重风险 #4(setOutputs 拷贝竞态):三缓冲隔离,无需锁,闭环
  • 高风险 #5(ISR 慢速 EXMC 循环):DWT 测量 + 评估阈值,闭环
  • 高风险 #6(.ramfunc 未落地):链接脚本 + 启动拷贝 + 调用链 RAM 化,闭环