Files
DCU_APP/.trae/specs/fix-ecat-pdo-and-runtime-issues/tasks.md
T
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

69 lines
8.2 KiB
Markdown

# Tasks
- [x] Task 1: 阶段 S1 — 分离输入/输出 PDO 的 PDI 偏移(修复严重 S1)
- [x] SubTask 1.1: 在 `sys/config.h` 的 EtherCAT 配置区新增 `CONFIG_ESC_PDI_INPUT_OFFSET` 与 `CONFIG_ESC_PDI_OUTPUT_OFFSET` 两个 `constexpr` 或 `#define` 常量(默认占位值 `0x1000U` / `0x1200U`,注释说明需与主站 ESI 匹配)
- [x] SubTask 1.2: 修改 `comm/ethercat_slave.cpp::periodicIsr()` 中 `EscLan9252::readPdi()` 调用,将 offset 参数由 `0x0000U` 改为 `CONFIG_ESC_PDI_INPUT_OFFSET`
- [x] SubTask 1.3: 修改 `comm/ethercat_slave.cpp::periodicIsr()` 中 `EscLan9252::writePdi()` 调用,将 offset 参数由 `0x0000U` 改为 `CONFIG_ESC_PDI_OUTPUT_OFFSET`
- [x] SubTask 1.4: 修改 `comm/esc_lan9252.h` 中 `readPdi`/`writePdi`/`initOnlyReadPdi`/`initOnlyWritePdi`(M6 重命名后)的接口注释,说明 offset 参数语义为"SyncManager 内存区相对偏移,输入/输出必须分离"
- [x] Task 2: 阶段 S2 — 实现 `process()` 框架级 PDO 桥接(修复严重 S2)
- [x] SubTask 2.1: 在 `comm/ethercat_slave.h` 的 `EthercatSlave` 类中新增 `static PdoBuffer s_appInputs` 与 `static PdoBuffer s_appOutputs` 私有静态成员声明
- [x] SubTask 2.2: 在 `comm/ethercat_slave.h` 的 `EthercatSlave` 类 public 区新增 `getApplicationInputs()`(返回 `const PdoBuffer*`)与 `setApplicationOutputs(const PdoBuffer*)` 两个公共静态接口声明
- [x] SubTask 2.3: 在 `comm/ethercat_slave.cpp` 中定义 `s_appInputs` / `s_appOutputs` 静态成员(初始化为空 PdoBuffer)
- [x] SubTask 2.4: 实现 `process()`:先调用 `getLatestInputs()`,若返回非空则拷贝到 `s_appInputs`;然后调用 `setOutputs(&s_appOutputs)` 推入输出三缓冲(保留原 TODO 注释说明应用对象字典映射待后续 spec)
- [x] SubTask 2.5: 实现 `getApplicationInputs()`:返回 `&s_appInputs`
- [x] SubTask 2.6: 实现 `setApplicationOutputs(const PdoBuffer *outputs)`:非空检查后拷贝 `*outputs` 到 `s_appOutputs`
- [x] Task 3: 阶段 S3 — ESC 就绪状态守卫增强(修复严重 S3,仅守卫)
- [x] SubTask 3.1: 在 `comm/ethercat_slave.h` 新增 `static uint8_t s_alState` 私有静态成员声明,与 `static uint8_t getAlState()` 公共接口声明;新增 AL 状态码常量(可选:定义为 `constexpr` 或 `#define`,如 `AL_STATE_INIT=0x01`、`AL_STATE_PREOP=0x02`、`AL_STATE_SAFEOP=0x04`、`AL_STATE_OP=0x08`)
- [x] SubTask 3.2: 在 `comm/ethercat_slave.cpp` 定义 `s_alState` 静态成员(初始化 0)
- [x] SubTask 3.3: 修改 `EthercatSlave::init()`:在读取芯片 ID 后,若 ID 匹配则进一步读取 AL 状态寄存器(0x0130)并保存到 `s_alState`(注意:M6 重命名后用 `initOnlyReadReg` 而非 `safeReadReg`)
- [x] SubTask 3.4: 修改 `isEscReady()` 内联实现:返回 `(s_chipId == 0x87654321U) && (s_alState >= AL_STATE_SAFEOP)`(注:AL 状态寄存器低 4 位为状态码,SAFEOP=0x04,OP=0x08,故 `>= 0x04` 兼容 SAFEOP 与 OP)
- [x] SubTask 3.5: 修改 `EthercatSlave::init()` 的诊断打印:ID 匹配但 AL < SAFEOP 时打印"ESC detected but AL state=0x%02X < SAFEOP, SYNC0 will not fire, full ESC config requires SSC integration";ID 匹配且 AL ≥ SAFEOP 时打印现有"ESC ready, AL state=0x%04X"
- [x] SubTask 3.6: 实现 `getAlState()` 返回 `s_alState`
- [x] SubTask 3.7: 在 `comm/esc_lan9252.cpp::EscLan9252::init()` 现有 TODO 注释处扩展为完整 TODO 块,列出:SyncManager 初始化(SM0/1/2/3 配置寄存器)、FMMU 配置、AL Control 写入(OP 状态请求)、SYNC0 生成寄存器(0x0981-0x0982 周期、0x0983 脉冲长度等),并说明需 SSC 或等价协议栈代码
- [x] Task 4: 阶段 M4 — TIMER0 降级模式保留 ESC IRQ handler(修复中危 M4)
- [x] SubTask 4.1: 修改 `comm/ethercat_sync.cpp` 的 `extern "C"` 中断入口包装区:`#else`(TIMER0 降级)分支在 `TIMER0_IRQHandler` 定义之后,补充 `EXTI1_IRQHandler` 与 `EXTI2_IRQHandler` 的定义(与 `#if` 分支一致,调用 `onEscIrqExti`/`onSync1Exti`)
- [x] SubTask 4.2: 修改 `EthercatSync::init()` 的 `#else`(TIMER0 降级)分支:在 TIMER0 配置之前或之后,补充 EXTI1(ESC IRQ)与 EXTI2(SYNC1)的 `gpio_exti_source_select`/`exti_init`/`exti_interrupt_enable`/`exti_interrupt_flag_clear`/`nvic_irq_enable` 配置(代码与 `#if` 分支的 EXTI1/EXTI2 配置段相同)
- [x] SubTask 4.3: 确认 `onEscIrqExti` 与 `onSync1Exti` 实现无需改动(降级模式下行为一致)
- [x] Task 5: 阶段 M5 — 输出三缓冲写入索引改为 `(readIdx+2)%3`(修复中危 M5)
- [x] SubTask 5.1: 修改 `comm/ethercat_slave.cpp::setOutputs()`:`write_idx` 由 `(s_outputReadIdx + 1U) % 3U` 改为 `(s_outputReadIdx + 2U) % 3U`
- [x] SubTask 5.2: 修改 `setOutputs()` 实现内注释:删除"无需临界区"表述,改为"2 周期宽限下拷贝竞态窗口消除,前提是主循环处理时间 < 2 × 周期时间"
- [x] SubTask 5.3: 修改 `comm/ethercat_slave.h` 中 `s_outputs` 成员的注释:说明 `setOutputs()` 写入 `(readIdx+2)%3`,与 ISR 当前读取位置隔 2 个缓冲,提供 2 周期宽限
- [x] Task 6: 阶段 M6 — `safe*` 接口重命名为 `initOnly*`(修复中危 M6)
- [x] SubTask 6.1: 修改 `comm/esc_lan9252.h`:`safeReadReg`/`safeWriteReg`/`safeReadPdi`/`safeWritePdi` 四个成员函数声明重命名为 `initOnlyReadReg`/`initOnlyWriteReg`/`initOnlyReadPdi`/`initOnlyWritePdi`,注释中移除"safe"字样,统一为"INIT-ONLY"
- [x] SubTask 6.2: 修改 `comm/esc_lan9252.cpp`:四个函数定义同步重命名
- [x] SubTask 6.3: 修改 `comm/ethercat_slave.cpp::EthercatSlave::init()` 中调用 `safeReadReg(0x0130U)` 的代码,改为 `initOnlyReadReg(0x0130U)`(注:此调用点在 Task 3 S3 实现中可能已重命名,需协调)
- [x] SubTask 6.4: 修改 `comm/esc_lan9252.cpp::readChipId()` 中调用 `safeReadReg` 的代码,改为 `initOnlyReadReg`
- [x] SubTask 6.5: 全项目 grep `safeReadReg`/`safeWriteReg`/`safeReadPdi`/`safeWritePdi`,确认无任何残留(含声明、定义、调用、注释)
- [x] Task 7: 阶段 M7 — `s_periodicSeq` 加宽为 `uint16_t`(修复中危 M7)
- [x] SubTask 7.1: 修改 `comm/ethercat_slave.h`:`s_periodicSeq` 类型由 `volatile uint8_t` 改为 `volatile uint16_t`;`s_processedSeq` 类型由 `uint8_t` 改为 `uint16_t`
- [x] SubTask 7.2: 修改 `comm/ethercat_slave.cpp` 中两个静态成员定义的类型,与头文件一致
- [x] SubTask 7.3: 确认 `hasPendingPeriodic()` 与 `markPeriodicProcessed()` 实现无需改动(比较与赋值操作对 `uint16_t` 同样适用)
- [x] SubTask 7.4: 确认诊断打印中无 `s_periodicSeq` 直接格式化输出(若有,确认 `%u`/`%lu` 格式符适配 `uint16_t`)
- [x] Task 8: 编译验证与一致性检查
- [x] SubTask 8.1: 静态代码审查确认:全项目无 `safeReadReg`/`safeWriteReg`/`safeReadPdi`/`safeWritePdi` 残留;`periodicIsr()` 中 `readPdi`/`writePdi` 使用不同 offset;`setOutputs()` 使用 `(readIdx+2)%3`;`s_periodicSeq` 为 `uint16_t`;降级模式下 `EXTI1_IRQHandler`/`EXTI2_IRQHandler` 已定义
- [x] SubTask 8.2: 静态代码审查确认:`process()` 内部调用 `getLatestInputs()` 与 `setOutputs()`;`getApplicationInputs()`/`setApplicationOutputs()` 已实现;`isEscReady()` 含 AL 状态守卫
- [ ] SubTask 8.3: 若可编译:全量编译通过,无 error(⚠️ 受 EXMC pack 解析问题阻塞,改为静态代码审查,详见下方验证)
- [ ] SubTask 8.4: 若可编译:map 文件确认新增静态成员 `s_appInputs`/`s_appOutputs`/`s_alState` 已分配(⚠️ 待编译环境修复后验证)
# Task Dependencies
- Task 1(S1 PDO 偏移)、Task 5(M5 输出索引)、Task 7(M7 序列号加宽)相互独立,可并行实施(改动 `ethercat_slave.cpp`/`config.h` 不同代码段,无交叉)
- Task 6(M6 重命名)应早于 Task 3(S3 AL 状态守卫),因 S3 SubTask 3.3 调用 `initOnlyReadReg`,需先完成重命名
- Task 2(S2 process 桥接)与 Task 3(S3 AL 守卫)均修改 `ethercat_slave.h`/`.cpp`,建议串行实施避免冲突
- Task 4(M4 降级模式)独立,改动 `ethercat_sync.cpp`,可与其他任务并行
- Task 8(编译验证)依赖 Task 1-7 全部完成
# 推荐执行顺序
1. Task 6(M6 重命名)— 先改名,避免后续任务调用旧名
2. Task 1(S1 PDO 偏移)+ Task 5(M5 索引)+ Task 7(M7 加宽)— 并行,改动不同代码段
3. Task 4(M4 降级模式)— 独立文件,可并行
4. Task 2(S2 process 桥接)
5. Task 3(S3 AL 守卫)— 依赖 M6 重命名完成
6. Task 8(编译验证)