60 lines
7.8 KiB
Markdown
60 lines
7.8 KiB
Markdown
# Tasks
|
|||
|
|
|
||
|
|
- [x] Task 1: 阶段 A — EtherCAT 周期任务标志脱离 TaskManager(修复严重风险 #1)
|
||
|
|
- [x] SubTask 1.1: 在 `comm/ethercat_slave.h` 中声明 `static volatile uint8_t s_periodicSeq` 与 `static uint8_t s_processedSeq` 私有静态成员,并增加 `static bool hasPendingPeriodic()` / `static void markPeriodicProcessed()` 公有接口
|
||
|
|
- [x] SubTask 1.2: 在 `comm/ethercat_slave.cpp` 的 `periodicIsr()` 末尾移除 `TaskManager::set(1UL << TASK_ETHERCAT_PROCESS)`,改为 `s_periodicSeq++`(uint8 自然回绕,原子单字节写)
|
||
|
|
- [x] SubTask 1.3: 实现 `hasPendingPeriodic()` 返回 `s_periodicSeq != s_processedSeq`,`markPeriodicProcessed()` 执行 `s_processedSeq = s_periodicSeq`
|
||
|
|
- [x] SubTask 1.4: 在 `sys/task_runner.cpp` 的 `runPending()` 开头(TaskManager::takePending 之前或之后)增加:`if (EthercatSlave::hasPendingPeriodic()) { EthercatSlave::markPeriodicProcessed(); taskEthercatProcess(); }`,该分支用 `#if CONFIG_ETHERCAT_ENABLE` 保护
|
||
|
|
- [x] SubTask 1.5: 确认 ESC IRQ 路径(`comm/ethercat_sync.cpp::onEscIrqExti()`)仍调用 `TaskManager::set(1UL << TASK_ETHERCAT_PROCESS)`,BASEPRI 保护该路径,无改动
|
||
|
|
- [x] SubTask 1.6: 在 `comm/ethercat_slave.h` 头注释中说明"周期路径用 s_periodicSeq,事件路径用 TASK_ETHERCAT_PROCESS,两者独立"
|
||
|
|
|
||
|
|
- [x] Task 2: 阶段 B — EXMC 总线访问权分离(修复严重风险 #2)
|
||
|
|
- [x] SubTask 2.1: 在 `comm/esc_lan9252.h` 中声明 `static uint16_t safeReadReg(uint16_t addr)` / `static void safeWriteReg(uint16_t addr, uint16_t val)` / `static void safeReadPdi(uint16_t offset, uint8_t *buf, size_t len)` / `static void safeWritePdi(uint16_t offset, const uint8_t *buf, size_t len)` 公有接口
|
||
|
|
- [x] SubTask 2.2: 在 `comm/esc_lan9252.cpp` 实现 safe 接口,内部用 `__disable_irq()` / `__set_PRIMASK()` 包裹(注意:这里用 PRIMASK 而非 BASEPRI,因为要阻塞 preempt=0 的 SYNC0),调用对应的无锁版本后恢复
|
||
|
|
- [x] SubTask 2.3: 在 `comm/esc_lan9252.h` / `comm/esc_exmc_bus.h` 头文件注释中明确标注:`readReg/writeReg/readPdi/writePdi/read16/write16/readBlock/writeBlock` 为 "ISR-only,仅供 preempt=0 调用,无锁";`safeReadReg/safeWriteReg/safeReadPdi/safeWritePdi` 为 "Thread-safe,主循环与 init 调用,PRIMASK 保护"
|
||
|
|
- [x] SubTask 2.4: 审查 `comm/ethercat_slave.cpp` 的 `init()` 与 `process()`,所有 EXMC 访问改用 safe 接口(init 阶段虽中断未使能但保持一致性;process 若有 EXMC 访问必须用 safe)
|
||
|
|
- [x] SubTask 2.5: 在 `comm/ethercat_slave.cpp` 的 `periodicIsr()` 中确认仍调用无锁的 `readPdi/writePdi`(因 ISR 为 preempt=0,天然原子)
|
||
|
|
- [x] SubTask 2.6: 代码审查确认无主循环路径误调用 ISR-only 接口
|
||
|
|
|
||
|
|
- [x] Task 3: 阶段 C — PDO 三缓冲替换双缓冲(修复严重风险 #3 与 #4)
|
||
|
|
- [x] SubTask 3.1: 在 `comm/ethercat_slave.h` 中将 `s_inputs[2]` / `s_outputs[2]` 改为 `s_inputs[3]` / `s_outputs[3]`,成员名改为 `s_inputWriteIdx` / `s_outputReadIdx`(替换原 `s_inputReadIndex` / `s_outputWriteIndex`),类型 `volatile uint8_t`
|
||
|
|
- [x] SubTask 3.2: 在 `comm/ethercat_slave.h` 头注释中更新双缓冲说明为三缓冲说明,描述模 3 轮转规则
|
||
|
|
- [x] SubTask 3.3: 在 `comm/ethercat_slave.cpp` 的 `init()` 中初始化 `s_inputWriteIdx = 0` / `s_outputReadIdx = 0`
|
||
|
|
- [x] SubTask 3.4: 重写 `periodicIsr()` 的缓冲管理:写入 `s_inputs[s_inputWriteIdx]` → 递增 `s_inputWriteIdx = (s_inputWriteIdx + 1) % 3`;读取 `s_outputs[s_outputReadIdx]` → 递增 `s_outputReadIdx = (s_outputReadIdx + 1) % 3`
|
||
|
|
- [x] SubTask 3.5: 重写 `getLatestInputs()` 返回 `&s_inputs[(s_inputWriteIdx + 2) % 3]`(最新完成且与 ISR 当前写入隔一个)
|
||
|
|
- [x] SubTask 3.6: 重写 `setOutputs()` 写入 `s_outputs[(s_outputReadIdx + 1) % 3]`(与 ISR 当前读取隔一个),无需临界区
|
||
|
|
- [x] SubTask 3.7: 移除原 XOR 翻转逻辑(`^1U`),确认无残留引用
|
||
|
|
- [x] SubTask 3.8: 在 `comm/ethercat_slave.h` 注释中明确"三缓冲容忍主循环跨 1 个周期,主循环处理必须 < 2 × 周期时间"
|
||
|
|
|
||
|
|
- [x] Task 4: 阶段 D — periodicIsr 执行时间测量与评估(修复高风险 #5)
|
||
|
|
- [x] SubTask 4.1: 在 `comm/ethercat_slave.h` 增加 `static volatile uint32_t s_isrMaxCycles` / `static volatile uint32_t s_isrAvgCycles` / `static volatile uint32_t s_isrCount` 诊断成员
|
||
|
|
- [x] SubTask 4.2: 在 `comm/ethercat_slave.cpp` 的 `periodicIsr()` 入口读 `DWT->CYCCNT` 存局部变量,出口再读,差值更新 max(原子比较)与 avg(滑动平均或累加)
|
||
|
|
- [x] SubTask 4.3: 在 `sys/initial.cpp` 或 `comm/esc_lan9252.cpp::init()` 中使能 DWT:`CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;`
|
||
|
|
- [x] SubTask 4.4: 在 `sys/task_runner.cpp` 的 `taskDiagnosticPrint()` 中增加 EtherCAT ISR 执行时间输出(受 `#if CONFIG_ETHERCAT_ENABLE` 保护),格式 `periodicIsr max=Xus avg=Yus`(cycles / 180 转 µs)
|
||
|
|
- [x] SubTask 4.5: 在 `sys/config.h` 增加 `CONFIG_ETHERCAT_ISR_MAX_US_THRESHOLD 5U` 宏,作为评估阈值
|
||
|
|
- [x] SubTask 4.6: 在 spec.md 与代码注释中记录:若实测 > 5µs 需评估减小 `CONFIG_ETHERCAT_PDO_SIZE` 或优化 EXMC 时序;若 ≤ 5µs 则接受现状并在注释中说明"preempt=0 阻塞窗口 ≤ 5µs,CAN/SPI 需容忍"
|
||
|
|
|
||
|
|
- [x] Task 5: 阶段 E — .ramfunc 段落地与调用链 RAM 化(修复高风险 #6)
|
||
|
|
- [x] SubTask 5.1: 定位项目链接脚本文件(查找 `*.sct` 或 RTE 配置中的 linker script)
|
||
|
|
- [x] SubTask 5.2: 在链接脚本中新增 `.ramfunc` 输出段,执行区(VMA)位于 SRAM,加载区(LMA)位于 Flash(参考 `.data` 段的 scatter 语法)
|
||
|
|
- [x] SubTask 5.3: 确认启动代码(`startup_gd32e50x_cl.s` 或 `system_gd32e50x.c`)是否自动拷贝 `.ramfunc` 段;若否,增加拷贝逻辑(类似 `.data` 拷贝循环)
|
||
|
|
- [x] SubTask 5.4: 在 `comm/ethercat_slave.cpp` 的 `periodicIsr()` 已有 `__attribute__((section(".ramfunc")))` 基础上增加 `noinline` 属性
|
||
|
|
- [x] SubTask 5.5: 在 `comm/esc_lan9252.cpp` 的 `readPdi()` / `writePdi()` 增加 `__attribute__((section(".ramfunc"), noinline))`
|
||
|
|
- [x] SubTask 5.6: 在 `comm/esc_exmc_bus.cpp` 的 `read16()` / `write16()` 增加 `__attribute__((section(".ramfunc"), noinline))`(注意:`readBlock/writeBlock` 不在 ISR 调用链,不标记)
|
||
|
|
- [ ] SubTask 5.7: 编译后查看 map 文件,确认 `.ramfunc` 段的 VMA 在 SRAM 区域、LMA 在 Flash 区域
|
||
|
|
- [x] SubTask 5.8: 若 DWT 测量(阶段 D)显示 Flash 执行已满足 <1µs 抖动,可在 spec 中记录降级方案(仅 periodicIsr 本体 RAM 化),但默认按完整 RAM 化实施
|
||
|
|
|
||
|
|
- [ ] Task 6: 编译验证与回退(⚠️ 受阻于预存 EXMC 组件解析问题)
|
||
|
|
- [ ] SubTask 6.1: 临时将 `sys/config.h` 中 `CONFIG_ETHERCAT_ENABLE` 改为 1,全量编译通过,无 error
|
||
|
|
- [ ] SubTask 6.2: 检查无新增 warning(特别注意 `.ramfunc` 段未定义或未拷贝的链接警告)
|
||
|
|
- [ ] SubTask 6.3: 查看 map 文件确认 `.ramfunc` 段在 SRAM、`s_inputs[3]`/`s_outputs[3]` 在 SRAM、`s_periodicSeq` 在 SRAM
|
||
|
|
- [x] SubTask 6.4: 编译验证完成后将 `CONFIG_ETHERCAT_ENABLE` 恢复为 0
|
||
|
|
- [ ] SubTask 6.5: 确认 `CONFIG_ETHERCAT_ENABLE=0` 时全量编译仍通过,功能与改造前等价
|
||
|
|
- [ ] SubTask 6.6: ⚠️ 阻塞项:`GD32E508_DCU_APP.cproject.yml` 第 68 行无条件引用 `Device:GD32E50x_StdPeripherals:EXMC` 组件,但已安装的 GD32E50x_DFP pack(1.9.0/1.3.2)pdsc 未注册 EXMC 组件,导致 csolution 组件解析失败,ENABLE=0 与 ENABLE=1 均无法构建。EXMC 驱动源文件(`gd32e50x_exmc.h/.c`)实际存在于 pack 中。需单独修复 cproject.yml(改为直接引用源文件)或更新 pack 后重新执行本任务
|
||
|
|
|
||
|
|
# Task Dependencies
|
||
|
|
- Task 1, 2, 3 相互独立,可并行实施(均集中在 `comm/` 目录,但修改不同函数与成员)
|
||
|
|
- Task 4 依赖 Task 1(periodicIsr 改造完成才能测量)
|
||
|
|
- Task 5 依赖 Task 1, 2, 3(调用链 RAM 化需在接口稳定后)
|
||
|
|
- Task 6 依赖 Task 1-5 全部完成
|