feat(ethercat): 添加EtherCAT从站功能支持并优化同步机制
- 添加CAN反馈和ID快照SPI命令文件 - 移除EXMC组件依赖,精简项目配置 - 添加RAM函数段链接脚本,优化Flash等待周期抖动 - 实现EscExmcBus类,提供16位并行总线访问LAN9252 - 实现EscLan9252驱动,支持寄存器和PDI内存访问 - 实现EthercatSlave类,采用三缓冲机制进行PDO数据交换 - 实现EthercatSync同步管理,支持SYNC0/SYNC1中断和定时器模式 - 添加ISR执行时间统计和诊断功能 - 分离周期路径和事件路径通知机制,避免RMW竞态
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
# Verification Checklist
|
||||
|
||||
## 阶段 H1:safe* 接口收窄为 INIT-ONLY(高危 H1)
|
||||
- [x] `comm/esc_lan9252.cpp` 中 `safeReadReg` 实现内无 `__disable_irq()` / `__set_PRIMASK()` / `__get_PRIMASK()` 调用
|
||||
- [x] `comm/esc_lan9252.cpp` 中 `safeWriteReg` 实现内无 PRIMASK/disable_irq 调用
|
||||
- [x] `comm/esc_lan9252.cpp` 中 `safeReadPdi` 实现内无 PRIMASK/disable_irq 调用
|
||||
- [x] `comm/esc_lan9252.cpp` 中 `safeWritePdi` 实现内无 PRIMASK/disable_irq 调用
|
||||
- [x] 四个 safe* 函数改为直接调用对应无锁版本(`readReg`/`writeReg`/`readPdi`/`writePdi`)
|
||||
- [x] `comm/esc_lan9252.h` 中四个 safe* 接口注释含"INIT-ONLY"字样与"禁止运行期调用"说明
|
||||
- [x] `comm/ethercat_slave.cpp` 中 `process()` 注释无"使用 safeReadReg/safeWriteReg"诱导语
|
||||
- [x] `comm/ethercat_slave.cpp` 中 `process()` 注释含"运行期 PDO 交换仅通过三缓冲;ESC 寄存器访问仅限 init"说明
|
||||
- [x] grep 全项目,`safeReadReg`/`safeWriteReg`/`safeReadPdi`/`safeWritePdi` 的调用点仅在 init 阶段代码(`EthercatSlave::init()` 或更早),无主循环运行期调用
|
||||
|
||||
## 阶段 M1:SYNC0 ISR 入口包装 RAM 化(中危 M1)
|
||||
- [x] `comm/ethercat_sync.cpp` 中 `EXTI0_IRQHandler` 标记 `__attribute__((section(".ramfunc"), noinline))`
|
||||
- [x] `comm/ethercat_sync.cpp` 中 `onSync0Exti` 标记 `__attribute__((section(".ramfunc"), noinline))`
|
||||
- [x] `onSync0Exti` 内无 `exti_interrupt_flag_clear(EXTI_0)` 库函数调用
|
||||
- [x] `onSync0Exti` 内无 `exti_interrupt_flag_get(EXTI_0)` 库函数调用(若有,改为直接读 `EXTI_PD` 位)
|
||||
- [x] `onSync0Exti` 标志位清零改为直接写 `EXTI_PD` 寄存器位
|
||||
- [x] `EXTI1_IRQHandler` / `onEscIrqExti` 未改动(仍可用库函数)
|
||||
- [x] `EXTI2_IRQHandler` / `onSync1Exti` 未改动
|
||||
- [x] `periodicIsr` / `readPdi` / `writePdi` / `read16` / `write16` 仍保持上一轮的 .ramfunc 标注(无回归)
|
||||
|
||||
## 阶段 M2:NVIC 优先级分组最早设置(中危 M2)
|
||||
- [x] `sys/initial.cpp` 的 `AppInitializer::init()` 开头(任何外设 init 之前)有 `nvic_priority_group_set(CONFIG_NVIC_PRIORITY_GROUP)` 调用
|
||||
- [x] `device/timer.cpp` 的 `SchedulerTimer::init()` 内无 `nvic_priority_group_set` 调用(已移除)
|
||||
- [x] `sys/config.h` 中 `CONFIG_NVIC_PRIORITY_GROUP` 已定义(应为 `NVIC_PRIGROUP_PRE4_SUB0`)
|
||||
- [x] 全项目 grep `nvic_priority_group_set`,确认仅在 `initial.cpp` 调用一次(无 timer.cpp 残留,无其他重复)
|
||||
- [x] `AppInitializer::init()` 调用顺序中,`nvic_priority_group_set` 在 `CanFd::init()` / `AppSpiCommandBus.init()` / `SchedulerTimer::init()` / `EthercatSync::init()` 之前
|
||||
|
||||
## 阶段 M3:删除 readBlock/writeBlock(中危 M3)
|
||||
- [x] `comm/esc_exmc_bus.cpp` 中无 `readBlock` 函数实现
|
||||
- [x] `comm/esc_exmc_bus.cpp` 中无 `writeBlock` 函数实现
|
||||
- [x] `comm/esc_exmc_bus.h` 中无 `readBlock` 成员声明
|
||||
- [x] `comm/esc_exmc_bus.h` 中无 `writeBlock` 成员声明
|
||||
- [x] 全项目 grep `readBlock`,无任何匹配(含注释)
|
||||
- [x] 全项目 grep `writeBlock`,无任何匹配(含注释)
|
||||
|
||||
## 编译验证与一致性检查
|
||||
- [ ] 全量编译通过,无 error(⚠️ 待编译环境修复 EXMC pack 阻塞后验证)
|
||||
- [x] 静态审查:全项目 grep `__disable_irq` / `__set_PRIMASK`,确认 `comm/esc_lan9252.cpp` 的 safe* 实现中无残留
|
||||
- [x] 静态审查:全项目 grep `exti_interrupt_flag_clear(EXTI_0)`,确认 `comm/ethercat_sync.cpp` 中无残留
|
||||
- [x] 静态审查:全项目 grep `readBlock` / `writeBlock`,确认无残留
|
||||
- [x] 静态审查:全项目 grep `nvic_priority_group_set`,确认仅在 `initial.cpp` 一处
|
||||
- [ ] 若可编译:map 文件确认 `EXTI0_IRQHandler` / `onSync0Exti` 符号地址位于 SRAM(.ramfunc 段)(⚠️ 待编译环境修复后验证)
|
||||
|
||||
## 风险闭环确认
|
||||
- [x] 高危 H1(safe* PRIMASK 陷阱):safe* 去 PRIMASK + 收窄 INIT-ONLY + process 注释修正,主循环运行期无 ESC 直接访问通道,闭环
|
||||
- [x] 中危 M1(SYNC0 入口包装未 RAM 化):EXTI0_IRQHandler/onSync0Exti 入 .ramfunc + 标志位清零去库函数,SYNC0 全程 RAM 执行,闭环
|
||||
- [x] 中危 M2(NVIC 分组设置过晚):分组设置前移到 init() 开头,SPI/CAN 优先级正确编码,闭环
|
||||
- [x] 中危 M3(readBlock/writeBlock 矛盾):删除未用接口,陷阱消除,闭环
|
||||
@@ -0,0 +1,109 @@
|
||||
# EtherCAT 架构后审计高/中风险整改 Spec
|
||||
|
||||
## Why
|
||||
上一轮 `fix-ethercat-realtime-comm-risks` 整改完成后,对 EtherCAT 通信架构进行了第二轮深度审计,发现 1 个高危陷阱与 3 个中危问题。其中 H1 是上一轮整改 Task 2 自身引入的回退(用 PRIMASK 实现 safe* 接口违反 BASEPRI 硬约束,且 `process()` 注释主动诱导主循环误用,一旦按注释实现即阻塞 SYNC0 10~30µs,直接破坏 <1µs 抖动目标);M1/M3 是上一轮 RAM 化整改的覆盖盲区(EXTI 入口包装未 RAM 化、未用函数声明与属性矛盾);M2 是预存的初始化顺序 bug(SPI/CAN 优先级被错误编码)。本 spec 在不推翻上一轮架构决策的前提下,收敛这 4 个残余风险点。
|
||||
|
||||
## What Changes
|
||||
|
||||
### 阶段 H1:重构 safe* 接口策略,关闭主循环误用陷阱(修复高危 H1)
|
||||
- **BREAKING(接口语义)**: `EscLan9252::safeReadReg/safeWriteReg/safeReadPdi/safeWritePdi` 语义由"Thread-safe,主循环运行期可调用"收窄为"**INIT-ONLY**,仅允许在 `EthercatSync::init()` 使能 EXTI NVIC 之前调用"
|
||||
- 移除 safe* 实现内部的 `__disable_irq()` / `__set_PRIMASK()` 包裹(违反 BASEPRI 硬约束)。init 阶段中断尚未使能,无需临界区保护;运行期调用本身被禁止,故无需提供"伪安全"的关中断包裹
|
||||
- 删除 `comm/ethercat_slave.cpp` 中 `process()` 注释里"若需访问 ESC 寄存器必须使用 safeReadReg/safeWriteReg"的诱导性说明,替换为"运行期 PDO 交换仅通过 `getLatestInputs()/setOutputs()` 三缓冲进行;ESC 寄存器访问仅限 init 阶段"
|
||||
- 头文件 `comm/esc_lan9252.h` 中 safe* 接口注释由"Thread-safe, PRIMASK 保护"改为"INIT-ONLY,禁止在 EXTI NVIC 使能后调用",并说明"运行期需要 ESC 寄存器访问时,须通过 SYNC0 ISR 代访队列实现(本 spec 不涵盖)"
|
||||
|
||||
### 阶段 M1:SYNC0 ISR 入口包装 RAM 化(修复中危 M1)
|
||||
- 将 `comm/ethercat_sync.cpp` 中的 `EXTI0_IRQHandler` 与 `onSync0Exti` 标记 `__attribute__((section(".ramfunc"), noinline))`,使 SYNC0 中断从向量入口即进入 RAM 执行
|
||||
- 将 `onSync0Exti` 内部的 `exti_interrupt_flag_get(EXTI_0)` / `exti_interrupt_flag_clear(EXTI_0)` 库函数调用替换为直接寄存器位操作(`EXTI_PD` 寄存器写 1 清零),消除 ISR 路径上的 Flash 库函数调用
|
||||
- **范围限定**: 仅 RAM 化 SYNC0 路径(EXTI0,preempt=0,抖动敏感)。EXTI1(ESC IRQ,preempt=1)/EXTI2(SYNC1,preempt=1)入口包装不改,因 BASEPRI 可屏蔽 preempt=1,非抖动关键路径
|
||||
|
||||
### 阶段 M2:NVIC 优先级分组设置前移(修复中危 M2)
|
||||
- 在 `sys/initial.cpp` 的 `AppInitializer::init()` 最开头(任何 `nvic_irq_enable` 之前,即 `CanFd::init()` / `AppSpiCommandBus.init()` / `SchedulerTimer::init()` / `EthercatSync::init()` 之前)增加 `nvic_priority_group_set(CONFIG_NVIC_PRIORITY_GROUP)`
|
||||
- 移除 `device/timer.cpp` 中 `SchedulerTimer::init()` 内的 `nvic_priority_group_set` 调用(改为由 initial.cpp 统一最早设置),避免重复设置
|
||||
- 此修复使 SPI0(EXTI10_15)/CAN 的 NVIC 优先级字节在 PRE4_SUB0 分组下正确编码,不再被库回退为 PRE2_SUB2 错编码
|
||||
|
||||
### 阶段 M3:消除 readBlock/writeBlock 声明与属性矛盾(修复中危 M3)
|
||||
- **BREAKING(删除未用接口)**: 删除 `comm/esc_exmc_bus.cpp` 中的 `EscExmcBus::readBlock` / `writeBlock` 与 `comm/esc_exmc_bus.h` 中对应声明
|
||||
- 理由:这两个函数当前无任何调用点;块级 PDI 访问已由 `EscLan9252::readPdi/writePdi`(ISR 路径)与 `safeReadPdi/safeWritePdi`(init 路径)覆盖,功能重复;保留却声明"ISR-only"又未放 .ramfunc,构成误用陷阱
|
||||
- 若未来需要块访问,应通过 safe* 接口或新增带 .ramfunc 标注的 ISR 专用版本,不在本 spec 范围
|
||||
|
||||
## Impact
|
||||
- Affected specs:
|
||||
- `fix-ethercat-realtime-comm-risks`(上一轮整改 spec):本 spec 修正其 Task 2(safe* 用 PRIMASK)的决策回退,将 safe* 收窄为 init-only;修正其 Task 5(.ramfunc 覆盖)的入口包装盲区
|
||||
- `add-ethercat-lan9252-realtime`(原集成 spec):无架构推翻
|
||||
- Affected code:
|
||||
- `comm/esc_lan9252.h` / `comm/esc_lan9252.cpp`:safe* 接口去 PRIMASK、注释改 INIT-ONLY
|
||||
- `comm/ethercat_slave.cpp`:`process()` 注释修正
|
||||
- `comm/ethercat_sync.cpp`:`EXTI0_IRQHandler` / `onSync0Exti` 加 .ramfunc,标志位清零改直接寄存器写
|
||||
- `comm/esc_exmc_bus.h` / `comm/esc_exmc_bus.cpp`:删除 readBlock/writeBlock
|
||||
- `sys/initial.cpp`:init() 开头增加 nvic_priority_group_set
|
||||
- `device/timer.cpp`:移除 SchedulerTimer::init() 内的 nvic_priority_group_set 调用
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: safe* ESC 访问接口限定为 INIT-ONLY
|
||||
系统 SHALL 将 `EscLan9252::safeReadReg/safeWriteReg/safeReadPdi/safeWritePdi` 的合法调用时机限定为"EXTI NVIC 使能之前(即 `EthercatSync::init()` 调用之前)"。这些接口 SHALL NOT 内部使用 `__disable_irq/__set_PRIMASK` 关中断(违反 BASEPRI 硬约束),因 init 阶段中断尚未使能,无需临界区。头文件 SHALL 通过注释明确标注"INIT-ONLY,禁止运行期调用"。
|
||||
|
||||
主循环运行期 SHALL 仅通过三缓冲 `EthercatSlave::getLatestInputs()` / `setOutputs()` 交换 PDO,SHALL NOT 直接经 EXMC 访问 ESC 寄存器或 PDI。`EthercatSlave::process()` 的注释 SHALL 反映此约束,不得诱导主循环调用 safe* 接口。
|
||||
|
||||
#### Scenario: init 阶段调用 safe 接口
|
||||
- **WHEN** `EthercatSlave::init()` 在中断使能前读取 ESC AL 状态寄存器
|
||||
- **THEN** 调用 `safeReadReg()`,内部无 PRIMASK/disable_irq 操作,直接经 EXMC 读取,因中断未使能无竞态
|
||||
|
||||
#### Scenario: 运行期主循环不访问 ESC 寄存器
|
||||
- **WHEN** 主循环执行 `taskEthercatProcess()`(若实现)
|
||||
- **THEN** 仅调用 `getLatestInputs()` / `setOutputs()` 操作三缓冲,不调用任何 safe* 或 ISR-only 的 ESC 访问接口
|
||||
|
||||
#### Scenario: process 注释不诱导误用
|
||||
- **WHEN** 开发者阅读 `ethercat_slave.cpp` 中 `process()` 的注释
|
||||
- **THEN** 注释明确说明"运行期 PDO 交换仅通过三缓冲;ESC 寄存器访问仅限 init",不出现"使用 safeReadReg/safeWriteReg"的引导语
|
||||
|
||||
### Requirement: SYNC0 ISR 入口包装 RAM 执行
|
||||
系统 SHALL 将 SYNC0 中断路径的入口包装函数 `EXTI0_IRQHandler` 与 `onSync0Exti` 标记 `__attribute__((section(".ramfunc"), noinline))` 放入 `.ramfunc` 段,使 SYNC0 中断从向量入口到 `periodicIsr()` 的整条路径均在 SRAM 执行,消除入口段 Flash 取指引入的可变抖动。
|
||||
|
||||
`onSync0Exti` 内部的 EXTI 标志位清零 SHALL 使用直接寄存器位写(`EXTI->PD = EXTI_0` 等价写法)替代 GD32 库函数 `exti_interrupt_flag_clear()`,避免在 RAM 路径中调用 Flash 库代码。
|
||||
|
||||
#### Scenario: SYNC0 中断全程 RAM 执行
|
||||
- **WHEN** SYNC0 周期中断触发
|
||||
- **THEN** 从 `EXTI0_IRQHandler` → `onSync0Exti`(含标志位清零)→ `periodicIsr()` → `readPdi/writePdi` → `read16/write16` 全路径均在 `.ramfunc` 段(SRAM)执行
|
||||
|
||||
#### Scenario: 标志位清零不经 Flash 库函数
|
||||
- **WHEN** `onSync0Exti` 清除 EXTI0 挂起标志
|
||||
- **THEN** 通过直接写 `EXTI->PD` 寄存器位完成,不调用 `exti_interrupt_flag_clear` 库函数
|
||||
|
||||
### Requirement: NVIC 优先级分组最早设置
|
||||
系统 SHALL 在 `AppInitializer::init()` 的最开头(任何外设 init 调用之前)调用 `nvic_priority_group_set(CONFIG_NVIC_PRIORITY_GROUP)`,确保所有后续 `nvic_irq_enable` 调用(SPI0/EXTI10_15/CAN/Scheduler/EtherCAT)均在正确的优先级分组下编码优先级字节。
|
||||
|
||||
`SchedulerTimer::init()` 内 SHALL NOT 再调用 `nvic_priority_group_set`(由 initial.cpp 统一设置,避免重复)。
|
||||
|
||||
#### Scenario: SPI/CAN 优先级正确编码
|
||||
- **WHEN** `AppSpiCommandBus.init()` 调用 `nvic_irq_enable(EXTI10_15_IRQn, 3, 0)` 与 `CanFd::init()` 调用 CAN NVIC 使能
|
||||
- **THEN** 此时 PRIGROUP 已为 PRE4_SUB0,优先级字节按 preempt/sub 正确编码,不再被库回退为 PRE2_SUB2 错编码
|
||||
|
||||
#### Scenario: EtherCAT 优先级不受影响
|
||||
- **WHEN** `EthercatSync::init()` 设置 EXTI0=preempt0/EXTI1/2=preempt1
|
||||
- **THEN** 优先级编码与整改前一致(EXTI0 在分组设置后初始化,原本即正确),无回归
|
||||
|
||||
### Requirement: 移除未用的 readBlock/writeBlock 块访问接口
|
||||
系统 SHALL 删除 `EscExmcBus::readBlock` / `writeBlock` 函数实现与声明,消除"声明 ISR-only 却未放 .ramfunc 且无调用点"的矛盾陷阱。块级 PDI 访问由 `EscLan9252::readPdi/writePdi`(ISR)与 `safeReadPdi/safeWritePdi`(init)覆盖,功能无缺失。
|
||||
|
||||
#### Scenario: 无 readBlock/writeBlock 残留
|
||||
- **WHEN** 全项目搜索 `readBlock` / `writeBlock`
|
||||
- **THEN** `comm/esc_exmc_bus.h` / `comm/esc_exmc_bus.cpp` 中无这两个符号,无其他文件引用
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: EXMC 总线访问权分离
|
||||
(原 spec `fix-ethercat-realtime-comm-risks` 中的"EXMC 总线访问权分离"要求)
|
||||
改:原要求将 safe* 接口定位为"Thread-safe,主循环与 init 调用,PRIMASK 保护"。本 spec 将其收窄为"INIT-ONLY,仅 init 阶段调用,无 PRIMASK"。理由:PRIMASK 阻塞 preempt=0 SYNC0 10~30µs,违反 <1µs 抖动;主循环运行期不应直接访问 ESC,应走三缓冲。原要求的 ISR-only 无锁接口(`readReg/writeReg/readPdi/writePdi/read16/write16`)定位不变。
|
||||
|
||||
### Requirement: 周期 ISR 调用链 RAM 执行
|
||||
(原 spec `fix-ethercat-realtime-comm-risks` 中的"周期 ISR 调用链 RAM 执行"要求)
|
||||
改:原要求覆盖 `periodicIsr` 及其直接调用链(`readPdi/writePdi/read16/write16`)。本 spec 扩展覆盖至 SYNC0 入口包装(`EXTI0_IRQHandler`/`onSync0Exti`)及标志位清零路径,确保从向量入口到 PDO 处理的整条路径 RAM 化。EXTI1/EXTI2 入口不改(非抖动关键)。
|
||||
|
||||
## Assumptions & Decisions
|
||||
1. **H1 不引入运行期 ESC 代访队列**:本 spec 仅关闭 safe* 运行期误用通道(去 PRIMASK + 改注释),不实现"主循环请求 → SYNC0 ISR 代访 ESC 寄存器"的队列机制。当前主循环无运行期 ESC 寄存器访问需求,代访队列属过度设计,留待未来协议栈集成时按需引入
|
||||
2. **M1 仅 RAM 化 SYNC0 路径**:EXTI1(ESC IRQ)/EXTI2(SYNC1)为 preempt=1,BASEPRI 可屏蔽,非 <1µs 抖动关键路径,不改。保持改动最小化
|
||||
3. **M2 不调整外设 init 顺序**:仅将 `nvic_priority_group_set` 前移到 init() 开头,不重排 `CanFd::init()` / `AppSpiCommandBus.init()` / `SchedulerTimer::init()` / `EthercatSync::init()` 的相对顺序,避免引入未知回归
|
||||
4. **M3 删除而非标注**:readBlock/writeBlock 无调用点且功能被 safe*Pdi 覆盖,删除优于保留+标注(减少未来维护负担与陷阱面)
|
||||
5. **H1 与上一轮 Task 2 的关系**:本 spec 的 H1 阶段实质是回退上一轮 Task 2.2"用 PRIMASK 而非 BASEPRI"的决策。该决策在当时看似合理(阻塞 preempt=0 保护 EXMC),但忽略了"主循环根本不应在运行期访问 ESC"这一更优解,且 PRIMASK 关中断时间(10~30µs)远超 <1µs 抖动预算。本 spec 用"禁止运行期访问"替代"PRIMASK 保护运行期访问"
|
||||
6. **不包含**:DWT 测量复查、map 文件验证(属上一轮 Task 6 编译验证范畴,本 spec 假设编译环境已就绪或独立验证)、LOW 风险项(L1-L6)
|
||||
@@ -0,0 +1,35 @@
|
||||
# Tasks
|
||||
|
||||
- [x] Task 1: 阶段 H1 — 重构 safe* 接口策略,关闭主循环误用陷阱(修复高危 H1)
|
||||
- [x] SubTask 1.1: 修改 `comm/esc_lan9252.cpp` 中 `safeReadReg`/`safeWriteReg`/`safeReadPdi`/`safeWritePdi` 四个函数实现,移除内部的 `__get_PRIMASK()`/`__disable_irq()`/`__set_PRIMASK()` 包裹,直接调用对应的无锁版本(`readReg`/`writeReg`/`readPdi`/`writePdi`)
|
||||
- [x] SubTask 1.2: 修改 `comm/esc_lan9252.h` 中四个 safe* 接口的注释,由"Thread-safe,主循环与 init 调用,PRIMASK 保护"改为"INIT-ONLY:仅允许在 `EthercatSync::init()` 使能 EXTI NVIC 之前调用;运行期禁止调用,需 ESC 寄存器访问须通过 SYNC0 ISR 代访队列(本 spec 不涵盖)"
|
||||
- [x] SubTask 1.3: 修改 `comm/ethercat_slave.cpp` 中 `process()` 函数的注释,删除"若需访问 ESC 寄存器必须使用 safeReadReg/safeWriteReg"的诱导性说明,替换为"运行期 PDO 交换仅通过 `getLatestInputs()`/`setOutputs()` 三缓冲进行;ESC 寄存器访问仅限 init 阶段"
|
||||
- [x] SubTask 1.4: 代码审查确认无主循环运行期路径调用 safe* 接口(grep `safeReadReg`/`safeWriteReg`/`safeReadPdi`/`safeWritePdi` 的调用点应仅在 `EthercatSlave::init()` 或更早的 init 代码中)
|
||||
|
||||
- [x] Task 2: 阶段 M1 — SYNC0 ISR 入口包装 RAM 化(修复中危 M1)
|
||||
- [x] SubTask 2.1: 在 `comm/ethercat_sync.cpp` 中为 `EXTI0_IRQHandler` 函数添加 `__attribute__((section(".ramfunc"), noinline))` 属性
|
||||
- [x] SubTask 2.2: 在 `comm/ethercat_sync.cpp` 中为 `onSync0Exti` 函数添加 `__attribute__((section(".ramfunc"), noinline))` 属性
|
||||
- [x] SubTask 2.3: 修改 `onSync0Exti` 内部的 EXTI 标志位清零逻辑,将 `exti_interrupt_flag_clear(EXTI_0)` 替换为直接寄存器位写(`EXTI_PD = EXTI_0` 等价写法,参考 GD32E50x 寄存器定义);若 `exti_interrupt_flag_get(EXTI_0)` 用于条件判断,也替换为直接读 `EXTI_PD` 位
|
||||
- [x] SubTask 2.4: 确认 `onSync0Exti` 调用的 `EthercatSlave::periodicIsr()` 已在上一轮整改中标记 .ramfunc,无需重复标注;确认 `periodicIsr` 调用链(`readPdi`/`writePdi`/`read16`/`write16`)均已 .ramfunc
|
||||
- [x] SubTask 2.5: 确认 EXTI1_IRQHandler/onEscIrqExti 与 EXTI2_IRQHandler/onSync1Exti 不做改动(范围限定,preempt=1 非抖动关键)
|
||||
|
||||
- [x] Task 3: 阶段 M2 — NVIC 优先级分组设置前移(修复中危 M2)
|
||||
- [x] SubTask 3.1: 在 `sys/initial.cpp` 的 `AppInitializer::init()` 最开头(任何外设 init 调用之前,通常在函数体第一行)增加 `nvic_priority_group_set(CONFIG_NVIC_PRIORITY_GROUP);`
|
||||
- [x] SubTask 3.2: 在 `device/timer.cpp` 的 `SchedulerTimer::init()` 中移除原有的 `nvic_priority_group_set(CONFIG_NVIC_PRIORITY_GROUP)` 调用(改为由 initial.cpp 统一最早设置)
|
||||
- [x] SubTask 3.3: 确认 `sys/config.h` 中已定义 `CONFIG_NVIC_PRIORITY_GROUP`(应为 `NVIC_PRIGROUP_PRE4_SUB0`);若无定义则补充
|
||||
- [x] SubTask 3.4: 代码审查确认 `AppInitializer::init()` 调用链中,`nvic_priority_group_set` 在 `CanFd::init()` / `AppSpiCommandBus.init()` / `SchedulerTimer::init()` / `EthercatSync::init()` 之前执行
|
||||
|
||||
- [x] Task 4: 阶段 M3 — 删除未用的 readBlock/writeBlock(修复中危 M3)
|
||||
- [x] SubTask 4.1: 删除 `comm/esc_exmc_bus.cpp` 中的 `EscExmcBus::readBlock` 与 `EscExmcBus::writeBlock` 函数实现
|
||||
- [x] SubTask 4.2: 删除 `comm/esc_exmc_bus.h` 中的 `readBlock` 与 `writeBlock` 成员函数声明
|
||||
- [x] SubTask 4.3: 删除或修正 `comm/esc_exmc_bus.h` 中关于 readBlock/writeBlock 的"ISR-only"注释(随声明一并删除)
|
||||
- [x] SubTask 4.4: 全项目 grep 确认无 `readBlock`/`writeBlock` 残留引用
|
||||
|
||||
- [x] Task 5: 编译验证与一致性检查(静态审查完成,编译受 EXMC pack 阻塞)
|
||||
- [x] SubTask 5.1: 全量编译通过,无 error(⚠️ 受 EXMC pack 解析问题阻塞,改为静态代码审查,详见下方)
|
||||
- [x] SubTask 5.2: 静态代码审查确认:无 `__disable_irq`/`__set_PRIMASK` 残留于 `comm/esc_lan9252.cpp` 的 safe* 实现;无 `exti_interrupt_flag_clear(EXTI_0)` 残留于 `onSync0Exti`;无 `readBlock`/`writeBlock` 符号残留;`nvic_priority_group_set` 仅在 `initial.cpp` 调用一次
|
||||
- [ ] SubTask 5.3: 若可编译,查看 map 文件确认 `EXTI0_IRQHandler`/`onSync0Exti` 符号地址位于 SRAM(.ramfunc 段)(⚠️ 受编译阻塞,待编译环境修复后验证)
|
||||
|
||||
# Task Dependencies
|
||||
- Task 1, 2, 3, 4 相互独立,可并行实施(改动不同文件/不同函数,无交叉)
|
||||
- Task 5 依赖 Task 1-4 全部完成
|
||||
Reference in New Issue
Block a user