feat(ethercat): 添加LAN9252睡眠挂起机制防止HBI访问冲突
添加了s_pmSuspended状态标志来管理LAN9252的电源管理模式,在芯片进入D1-D3 睡眠状态时阻止HBI访问以避免唤醒问题。同步修改了ethercat_sync中断处理程序, 在睡眠挂起期间跳过HBI相关操作确保芯片能够正常维持睡眠状态。 fix(spi): 提升SPI CS EXTI抢占优先级避免帧丢失 将SPI CS EXTI中断优先级从1提升至0,使其能够抢占PDI/SYNC1等关键中断,确 保SPI帧释放处理能够在微秒级完成,避免因延时导致的ESP32 CS间隔超时和帧 丢失问题。 feat(ssc): 实现OP输入新鲜度不变量监控机制 添加了输入映射序列号监控机制,当PDI路径中断时能够检测到输入数据冻结并 自动触发强制刷新,解决结构洞问题导致的输入数据停止更新现象。 chore(pdo): 更新PDO输入字节注释说明布局变更历史
This commit is contained in:
@@ -0,0 +1,313 @@
|
||||
---
|
||||
feature: tiered-pdo-mapping
|
||||
status: designed
|
||||
updated: 2026-09-12
|
||||
branch: master (DCU_APP) + main (tools/ecat) — 无 worktree,沿用工作树
|
||||
commits: <pending delivery>
|
||||
---
|
||||
|
||||
# Tiered PDO Mapping(按电机数分档收缩 SM3)
|
||||
|
||||
## Report
|
||||
|
||||
(交付后填写)
|
||||
|
||||
---
|
||||
|
||||
## [S1] Problem
|
||||
|
||||
输入 PDO SM3 恒为 **600B**,与本拍实际密排电机数无关:
|
||||
|
||||
- 3 电机时仍占用 600B SM 与 ~984B 过程数据帧,100Mbps 上单帧线路时钟地板约 **81µs**。
|
||||
- 从站稀疏写(1.6.22)只省 PRAM 搬运,**不减线长**。
|
||||
- 用户场景:电机数长期固定(常见 3 台),偶发插拔;希望档内无感、跨档自动重映射,且重映射 **<500ms**、不 NRST、不撞 1s 过程数据看门狗。
|
||||
|
||||
现链路硬约束:
|
||||
|
||||
1. SSC `PREOP→SAFEOP` 调 `APPL_GenerateMapping` 得 `nPdInputSize`,`CheckSmSettings` 要求 **ESC SM3.Length == nPdInputSize**(`ecatslv.c:509`)。
|
||||
2. SOEM `Ibytes` 来自 CoE PDO 映射位数,**不是**从站运行时 tier;主站不改写 SM/FMMU/`Ibytes` 则线帧不变。
|
||||
3. 完整 `do_op_start`(重枚举 + 250×4ms 喂帧 + 最长数秒等 OP)无法满足 <500ms。
|
||||
4. `decode_input` 密排魔数 `@35=0xA5` 已可区分布局,但 **段3@544 / 段5@584 写死**,短 SM 下会读越界/错位。
|
||||
|
||||
---
|
||||
|
||||
## [S2] Design
|
||||
|
||||
### S2.1 容量档与线格式
|
||||
|
||||
唯一真源(从站头 + 主站常量,数值必须一致):
|
||||
|
||||
```
|
||||
ECAT_PDO_IN_MAX = 600
|
||||
ECAT_PDO_IN_PREFIX = 40 // 段1 32B + 段2 头 8B,槽区起点 MOTW_OFF_SLOTS=40
|
||||
ECAT_PDO_IN_XRX = 40 // 段3 长快照
|
||||
ECAT_PDO_IN_DIAG = 16 // 段5 诊断(实际用 12B,对齐到 8)
|
||||
ECAT_MOT_SLOT_SIZE = 56
|
||||
|
||||
in_bytes(cap) = 40 + cap*56 + 40 + 16 = 96 + 56*cap
|
||||
```
|
||||
|
||||
| 档 | count 范围 | cap | in_bytes | 线过程数据 out+in | 约线路时钟* |
|
||||
|----|------------|-----|----------|-------------------|-------------|
|
||||
| A | 0–3 | 3 | **264** | 384+264=648 | ~52µs |
|
||||
| B | 4–6 | 6 | **432** | 384+432=816 | ~65µs |
|
||||
| C | 7–9 | 9 | **600** | 384+600=984 | ~81µs(现状)|
|
||||
|
||||
\*仅 eth 过程数据字节的 100Mbps 线时钟粗算,不含头/IFG 的完整帧模型见 `ECAT_BEAT_TAIL_REPORT`。
|
||||
|
||||
**布局语义(密排,魔数 `@35=0xA5` 不变):**
|
||||
|
||||
```
|
||||
[0..31] 段1 桥状态(与现网一致)
|
||||
[32..39] 段2 头:count/active/boot/magic/gseq
|
||||
[40 .. 40+n*56) 密排槽,n = count ≤ cap
|
||||
[40+cap*56 .. +40) 段3 xrx
|
||||
[+40 .. +16) 段5 诊断(load/torn/seq/overfull/reltimeout/reject)
|
||||
```
|
||||
|
||||
- **档内**(count 在同一 cap 槽位预算内变化):只更新 `count` 与槽内容,**不改 SM、不 PREOP**。
|
||||
- **跨档**:走 S2.3 轻量重映射;两端同时切到目标 `in_bytes`。
|
||||
- 非密排(magic≠0xA5 或 ilen≥640 旧布局)路径保持原样,本特性不碰。
|
||||
|
||||
主站由 `Ibytes` 反推 cap(与 tier 一一对应):
|
||||
|
||||
```
|
||||
cap = (Ibytes - 96) / 56 // 264→3, 432→6, 600→9
|
||||
xrx_off = 40 + cap*56
|
||||
diag_off = xrx_off + 40
|
||||
```
|
||||
|
||||
禁止再写死 544/584。
|
||||
|
||||
### S2.2 从站契约(DCU_APP,目标版本 **1.6.34**)
|
||||
|
||||
1. **SII/EEPROM 不改**:`gen_eeprom.py` 仍 `PD_IN_SIZE=600`,冷启动 SM3 默认 600,与旧主站兼容。
|
||||
2. **`APPL_GenerateMapping`**(`dc_app.c`,`PREOP→SAFEOP` 时调用):
|
||||
- 读 ESC 当前 SM3 `Length`(`GetSyncMan(PROCESS_DATA_IN)`)。
|
||||
- 若 `Length` ∈ {264, 432, 600} → `*pInputSize = Length`(从站跟随主站)。
|
||||
- 否则 → `*pInputSize = ECAT_PDO_IN_MAX`(600,保底)。
|
||||
- `*pOutputSize` 仍 384,不变。
|
||||
3. **`APPL_InputMapping`**:`memcpy(pInputData, …, nPdInputSize)`,不再写死 600。
|
||||
4. **密排填充 / 稀疏写 / 差分写**(`ethercat_can_bridge.cpp` + diff/sparse 开关路径):
|
||||
- 段3/段5 物理偏移改为 `40 + cap*56` 起,其中 `cap = (nPdInputSize - 96) / 56`(在 Safe/OP 内 `nPdInputSize` 已被 GenerateMapping 更新)。
|
||||
- 稀疏写范围同步:段A=`0 .. 40+count*56`,段B=`xrx_off .. nPdInputSize`。
|
||||
- `count > cap` 时本拍只打包前 `cap` 个(并保持现有“撑满回退整包”仅在 cap=9 时语义不变);正常调度不应出现,出现时记诊断。
|
||||
5. **对象字典 0x6000**:仍按 600B 定义(SDO 可读全镜像);过程数据长度以 SM/`nPdInputSize` 为准。不引入多 TxPDO 映射子索引(v1 范围外)。
|
||||
6. **版本**:`config.h` patch → **34**,注释写明 tiered SM3 跟随主站。
|
||||
|
||||
**从站不主动改 SM 长度**,避免与主站写顺序竞态。
|
||||
|
||||
### S2.3 主站契约(tools/ecat / `ecat_native.c`)
|
||||
|
||||
#### 常量与状态
|
||||
|
||||
```
|
||||
tier_in_bytes[] = {264, 432, 600} // cap 3/6/9
|
||||
g_tier_cap // 当前会话生效 cap,默认 9
|
||||
g_tier_seen_count / g_tier_since // 滞回:观察到的新档 count 与起始时刻
|
||||
g_tier_last_remap / g_tier_remaps // 诊断
|
||||
```
|
||||
|
||||
`count` 取密排头 `g_head.wcount`(或 `inp[32]`),**不用** `active`(离线电机仍占槽报最后一轮,属于“槽预算”)。
|
||||
|
||||
#### 首次进 OP
|
||||
|
||||
- `do_op_start` 仍走完整 `config_init` + `config_map`(CoE 得 Ibytes=600)→ **首拍恒 Tier C**。
|
||||
- 首拍 decode 得到 `count` 后进入滞回观察;不与 SAFEOP→OP 竞态。
|
||||
|
||||
#### 跨档轻量重映射 `do_tier_remap(target_cap)`
|
||||
|
||||
前置:`g_bus_open && g_op && 循环已 loop_stop(调用方持 g_bus_lock)`。
|
||||
|
||||
```
|
||||
1. 记录 DC 形态 (dc_cycle_us, dc_shift_us) —— 与 wedge 恢复同源
|
||||
2. OP → PREOP|ACK(不 INIT、不 config_init 重枚举)
|
||||
- statecheck PREOP ≤400ms;失败则回退完整 do_op_start 一次
|
||||
3. 写 0x0420 = 10000(1s WD,与 do_op_start 同款)
|
||||
4. 改写 SM3:
|
||||
- ec_slave[1].SM[3].SMlength = htoes(target_in_bytes) // StartAddr 仍 0x1880,flags 不动(3-buffer)
|
||||
- ecx_FPWR / ec_FPWRw 写 ESC SM3 寄存器(与 config_map 写 SM 同基址)
|
||||
5. 改写输入 FMMU 逻辑长度(仅输入 FMMU,LogStart 不变,LogLength = target_in_bytes)
|
||||
6. 同步 SOEM 进程数据尺寸:
|
||||
- ec_slave[1].Ibytes / Ibits = target_in_bytes / *8
|
||||
- ec_group[0].Ibytes 调整,保证 send/receive_processdata 帧长 = O+new_I
|
||||
- g_expected_wkc 重算(inputsWKC 对短映射通常仍 1,需实读确认)
|
||||
7. PREOP → SAFEOP|ACK(≤400ms)—— 此时从站 GenerateMapping 读回新 SM3 长度
|
||||
8. 短喂帧:1ms 节拍 pump ~150 次(≈150ms,≪1s WD),再请求 OP
|
||||
9. OP|ACK,继续 pump 直到 AL=OP,总预算 ≤400ms;失败一次则完整 do_op_start
|
||||
10. g_tier_cap = target_cap;g_rxb_layout 保持 dense(3);清空槽表按 do_op_start 会话语义
|
||||
(可选:保留 g_slots,避免 remap 窗口 UI 闪空——v1 与 do_op_start 一致选择清空+重建)
|
||||
```
|
||||
|
||||
**目标耗时:** PREOP/SAFEOP/OP 状态检查各一次成功路径通常 10–50ms,加 150ms 喂帧,合计 **远低于 500ms**;全失败回退完整路径仍可恢复(不保证 <500ms,记日志)。
|
||||
|
||||
**禁止:** NRST、`ec_close`、改邮箱 SM、改输出 SM2 长度。
|
||||
|
||||
#### 滞回与触发点
|
||||
|
||||
- 仅在 **循环运行且 OP** 时评估;放在 `wedge_worker` 100ms 节拍(或 pdo_worker 每 N 拍采样后置标志,由 wedge 线程统一处理——**不得在 pdo_worker 内 loop_stop 自己**)。
|
||||
- 规则:
|
||||
- `need_cap = cap_for_count(count)`
|
||||
- 若 `need_cap == g_tier_cap` → 清观察状态
|
||||
- 若 `need_cap != g_tier_cap`:
|
||||
- 首次记下 `g_tier_seen_count` 与 `g_tier_since`
|
||||
- **同一 need_cap 连续 ≥500ms** 才执行 remap
|
||||
- 期间 count 又回到原档 → 清观察
|
||||
- `pm/hold` 置位期间不 remap(与楔死看门狗一致)。
|
||||
- remap 进行中 `g_tier_busy`:wedge 楔死恢复、`/api/motor/start`、SDO 独占路由互斥(复用 `g_bus_lock`)。
|
||||
|
||||
#### `decode_input` 密排分支
|
||||
|
||||
- 魔数判定不变。
|
||||
- `cap = (ilen - 96) / 56`,非法(不能整除或 cap∉{3,6,9})时:按 cap=9 且 `off+size>ilen` 则 break 的现有保护,**不崩溃**;记 layout 异常。
|
||||
- 段3/段5 偏移用 `xrx_off/diag_off`,替换 `XRX_DENSE_OFF_*` / `DIAG_OFF_*_WIN` 常量中的 544/584(常量改为宏函数或运行时变量)。
|
||||
|
||||
#### API / 观测
|
||||
|
||||
- `/api/motor/state` 或 busKv 增加:`tier_cap`、`tier_in_bytes`、`tier_remaps`、`tier_since`(可选)。
|
||||
- `/api/pdo/tier`:`{"cap":3|6|9}` 手动钉档(立即 remap,不走 500ms 滞回);`{"auto":true}` 恢复自动。v1 至少实现手动钉档读写。
|
||||
- `/api/open` 启动日志:`输入 %dB` 打印真实 `Ibytes`(remap 后),去掉写死「600B」文案。
|
||||
|
||||
#### 楔死恢复 / start / sdo
|
||||
|
||||
- `wedge_worker`、`/api/motor/state` 快路径、`/api/motor/start`:重拉 `do_op_start` 后 **重置 `g_tier_cap=9`**,再允许滞回把档缩回去(简单、可预期)。
|
||||
- `/api/sdo` 仍 `loop_stop` 不恢复——tier 状态在下次 start 时回到 9,可接受。
|
||||
|
||||
### S2.4 前端 / 文档(次要)
|
||||
|
||||
- `lab/spi_test.html`:bus 总线卡展示 `tier in_bytes`(若 API 提供);layout=dense 分支的段5 注释改为“偏移随 cap”。
|
||||
- `lab/pdo_layout.html`:统计卡从「600 B SM3」改为「264/432/600 分档」;**不阻塞固件交付**,可同 PR 或 follow-up。
|
||||
- 注释清理:避免再写“线速两布局同为 600B”这类在 tier 生效后错误的句子。
|
||||
|
||||
### S2.5 错误与回退
|
||||
|
||||
| 情况 | 行为 |
|
||||
|------|------|
|
||||
| SM3 改写 FPWR 失败 | abort remap,保持旧 Ibytes,日志 WARN;下一滞回窗重试 |
|
||||
| SAFEOP 失败(SSC 拒 SM) | 读 ALstatuscode;完整 `do_op_start`(回到 600)并记 `tier_remap_fail` |
|
||||
| OP 失败 | 同上 |
|
||||
| count 突然 > cap(从站 bug/撕裂) | decode 已有越界 break;从站侧 count>cap 截断;**不**立即 remap,等滞回 |
|
||||
| 首拍 Ibytes 仍 600 且 count=3 | 正常进入滞回,500ms 后缩到 264 |
|
||||
| 主站新、从站旧(GenerateMapping 恒 600) | 主站写 SM=264 后 SSC CheckSm 失败 → 回退 600,功能与今日等价 |
|
||||
| 从站新、主站旧 | SM 仍被旧主站写 600,从站跟随 600,与今日等价 |
|
||||
|
||||
### S2.6 不做(Out of Scope 见 S3)但需预留
|
||||
|
||||
- 输出 SM2 分档
|
||||
- 多 TxPDO 赋值(0x1C13 子索引选映射)
|
||||
- EEPROM/ESI 为每档发一份 SII
|
||||
- 改 1-buffer 换更大窗口
|
||||
|
||||
### S2.7 文件级改动清单(Implement 对照表)
|
||||
|
||||
> 行号以 2026-09-12 工作树为准,实现时以符号为准、行号仅作导航。
|
||||
|
||||
#### A. 从站 DCU_APP
|
||||
|
||||
| # | 文件 | 改什么 |
|
||||
|---|------|--------|
|
||||
| A1 | `GD32E508_DCU_APP/comm/ethercat_pdo_size.h` | 新增分档纯宏(C/C++ 共用):`ECAT_PDO_IN_TIERS {264,432,600}`、`ECAT_PDO_TIER_CAPS {3,6,9}`、`ECAT_PDO_IN_PREFIX=40`、`ECAT_PDO_IN_XRX=40`、`ECAT_PDO_IN_DIAG=16`、`ECAT_PDO_IN_BYTES_FOR_CAP(cap)=(96+56*(cap))`、`ECAT_PDO_CAP_FOR_IN_BYTES(ib)`。静态断言:三档均 ≤600 且 `%8==0`,cap=9 时等于现行 `ECAT_PDO_IN_BYTES`。`ECAT_PDO_IN_BYTES` 保留为 **max=600**(数组/EEPROM 上限),语义注释改为「上限,运行期可小于」。 |
|
||||
| A2 | `GD32E508_DCU_APP/comm/ethercat_can_bridge.h` | 段3/段5 **枚举保持 cap=9 数值**(544/584…)作默认/静态断言基准;新增运行时偏移接口:`uint16_t ecatMotXrxOff(uint8_t cap)` / `ecatMotDiagOff(uint8_t cap)` / `ecatPdoInBytesForCap(uint8_t cap)`(inline 或声明+cpp)。`static_assert` 改为只约束 cap=9 与 max 的首尾相接。注释标明:短档时段3/段5 前移,主站必须按 Ibytes 解。 |
|
||||
| A3 | `GD32E508_DCU_APP/comm/ethercat_can_bridge.cpp` `buildInput` @286–333 | 段3 填充:`ECAT_XRX_OFF_*` → `xrx = ecatMotXrxOff(cap)` 相对写。`memset(in,0,kEcatPdoInBytes)` 可改为只清 `in_bytes`(或仍清 600,多清无害但稀疏/diff 会多比——**建议只清 in_bytes**)。`cap` 来源见 A5。段1/段2 偏移不变(0–39 + slots)。 |
|
||||
| A4 | `GD32E508_DCU_APP/comm/ethercat_can_bridge.cpp` `fillMotorRound` @119+ | 逻辑不变;若 `count > cap` 截断到 cap(防越界写到段3)。影子区仍按 max 分配。 |
|
||||
| A5 | `GD32E508_DCU_APP/comm/ssc/port/dc_app.c` `APPL_GenerateMapping` @355–360 | 读 `GetSyncMan(PROCESS_DATA_IN)`(channel=3)`Length`;∈{264,432,600} 则 `*pInputSize=Length`,否则 600。随后调用新增 `EcatPdo_OnPdoInBytes(*pInputSize)`(或写 `EthercatPdo` 静态),通知填充层当前 in_bytes/cap。输出仍 384。 |
|
||||
| A6 | `GD32E508_DCU_APP/comm/ssc/port/dc_app.c` `APPL_InputMapping` @408–453 | `EcatPdo_WriteInputs` 之后:`memcpy(pInputData, …, nPdInputSize)`(替换写死 `ECAT_PDO_IN_BYTES`)。 |
|
||||
| A7 | `GD32E508_DCU_APP/comm/ethercat_pdo.h` / `.cpp` | 新增静态 `s_inBytes`/`s_cap`(默认 600/9)+ `OnPdoInBytes(uint16)`。`fillDiagTail` @114–155:`ECAT_DIAG_OFF_*` → `diag=ecatMotDiagOff(cap)` 相对。`sparseEscWritePlan` @166–194:`ECAT_XRX_OFF_CH`/`kPdoInBytes` → 运行时 `xrx`/`in_bytes`;「撑满」条件改为 `headEnd >= xrx`。`escSeg2WriteLen` @199–216、diff 三区 @258–279:同改。影子数组 `s_escSh2/s_escSh3` **保持按 600 上限分配**,只比较/写 `in_bytes` 内长度。 |
|
||||
| A8 | `GD32E508_DCU_APP/sys/config.h` @152 | `APP_FW_VERSION_PATCH` 33→**34**,追加 1.6.34 注释:SM3 分档跟随主站(GenerateMapping 读回 SM3.Length)。 |
|
||||
| A9 | `GD32E508_DCU_APP/comm/ssc/port/gen_eeprom.py` | **不改** PD_IN_SIZE=600(v1 不刷 EEPROM)。可在文件头加一行注释:「运行期主站可把 SM3 改为 264/432,SII 仍 600」。 |
|
||||
| A10 | `ethercat_diff_stats.cpp` | 若 `kInBytes` 宏绑死 600:改为读 `EthercatPdo::inBytes()` 或仍按 max 快照——**差分仪表在短档下勿拿 600 去比 in_bytes 内容**;实现时优先 `observe` 用当前 in_bytes。 |
|
||||
|
||||
#### B. 主站 tools/ecat
|
||||
|
||||
| # | 文件 | 改什么 |
|
||||
|---|------|--------|
|
||||
| B1 | `ecat_native.c` 顶部常量 @70–133 | 新增:`TIER_IN_BYTES[]`、`tier_cap_for_count(n)`、`tier_in_bytes(cap)`、`dense_xrx_off(ilen)`、`dense_diag_off(ilen)`(`cap=(ilen-96)/56`)。**保留** `XRX_DENSE_OFF_*`/`DIAG_OFF_*_WIN` 仅作文档/默认 cap=9;decode 路径改走函数。 |
|
||||
| B2 | `ecat_native.c` 状态 @190–226 附近 | 新增:`g_tier_cap`(默认9)、`g_tier_auto`(默认1)、`g_tier_busy`、`g_tier_need_cap`、`g_tier_since`、`g_tier_remaps`、`g_tier_remap_fail`。 |
|
||||
| B3 | `ecat_native.c` `decode_input` @450–530 | 密排分支:`xch/xda/diag` 用 `dense_*_off(ilen)`。若 `(ilen-96)%56!=0` 或 cap∉{3,6,9}:仍按魔数密排处理但 `off+size>ilen` 则 break(已有),并置 layout 异常标志。段5 读取位置同步改(@559–560 现用 `DIAG_OFF_LOAD_WIN`)。 |
|
||||
| B4 | `ecat_native.c` 新函数 `do_tier_remap(int target_cap, …)` | 放在 `do_op_start`/`do_op_stop` 附近。实现 S2.3 十步;内部用 `ecx_FPWR`/`ec_FPWRw`:SM3 长度字 @ ESC `0x081A`(`ECT_REG_SM0+3*8+2`),整段 SM 重写可抄 `ethercatconfig.c` `ecx_map_sm` 的 FPWR 模式;输入 FMMU:读当前 FMMU 表,只改输入那条的 `LogLength=target_in`,FPWR 回去;`ec_slave[1].Ibytes=Ibits/8`、`ec_group[0].Ibytes` 收缩/回扩;`g_expected_wkc` 重算。成功:`g_tier_cap=target`;失败:`do_op_start` 回落并 `g_tier_cap=9`。 |
|
||||
| B5 | `ecat_native.c` `wedge_worker` @3057–3100 | 在 `need` 楔死分支**之前**增加 tier 滞回评估(仅当 `g_loop_running && g_op && !g_tier_busy && !pm_hold && g_tier_auto`):用最新 `g_head.wcount`;同一 `need_cap≠g_tier_cap` 持续 ≥0.5s → `loop_stop` + `do_tier_remap` + `loop_start`。楔死恢复成功路径:`g_tier_cap=9`、清观察。 |
|
||||
| B6 | `ecat_native.c` `do_op_start` 成功出口 @1178–1207 | `g_tier_cap=9`、清滞回观察。日志 `输入 %dB` 已打真实 Ibytes(@1180)——确认 remap 后再 start 也正确。 |
|
||||
| B7 | `ecat_native.c` `/api/motor/start` @1987–2046 | 成功 `loop_start` 后同样 `g_tier_cap=9`(若走的是未 remap 的 do_op_start)。日志去掉写死「输入 600B」文案 @2039。 |
|
||||
| B8 | `ecat_native.c` `/api/motor/state` @2365–2403 | 快路径楔死恢复成功后 `g_tier_cap=9`。`build_state_json` 增加 `tier_cap`/`tier_in_bytes`/`tier_remaps`(函数体搜 `build_state_json`)。 |
|
||||
| B9 | `ecat_native.c` 新路由 `/api/pdo/tier` | GET:返回 `{ok, auto, tier_cap, tier_in_bytes, remaps, last_ms}`。POST body `{"cap":3\|6\|9}` 或 `{"auto":false\|true}`:钉档时持 `g_bus_lock`、`loop_stop`、`do_tier_remap`、`loop_start`;`auto` 只改标志。 |
|
||||
| B10 | `ecat_native.c` `pdo_worker` @848–852 | 无需改 Ibytes 来源(已读 `ec_slave[1].Ibytes`)。**禁止**在此 remap。可选:每 N 拍把 `g_head.wcount` 时间戳写给 wedge(直接读 `g_head` 已无锁跨线程——与现状一致,保持)。 |
|
||||
| B11 | `build_new.bat` / 工程 | 无新源文件则不用改;若 `do_tier_remap` 拆到新 `.c` 再加入 bat。 |
|
||||
|
||||
#### C. 前端 tools/ESP32(不阻塞固件)
|
||||
|
||||
| # | 文件 | 改什么 |
|
||||
|---|------|--------|
|
||||
| C1 | `lab/spi_test.html` | 总线/KV 区:若 API 返回 `tier_in_bytes` 则显示「SM3 264/432/600 · 档」。dense 段5 注释 @1198 改为「偏移随 cap」。CSS/JS 引用若外置需 `?v=`(本页自包含则内联即可)。 |
|
||||
| C2 | `lab/pdo_layout.html` | 统计卡 @243–244、图例 @819/@841、说明 @264:由「600 B SM3」改为分档说明;图可标三档长度。 |
|
||||
| C3 | `ECAT_BEAT_TAIL_REPORT.html` 等历史报告 | **不改**(已归档结论);避免改写历史数字。 |
|
||||
|
||||
#### D. 明确不改
|
||||
|
||||
- `ESP32_COMM/**`
|
||||
- `gen_eeprom.py` 的 PD_IN_SIZE、`DCU_ESI.xml`
|
||||
- `soem-src/**`(只调用,不改库;FMMU/SM 用现成 FPWR)
|
||||
- 输出 SM2、邮箱 SM0/1
|
||||
|
||||
#### E. 实现顺序(文件依赖)
|
||||
|
||||
```
|
||||
A1 → A2 → A5/A6(GenerateMapping+InputMapping)
|
||||
→ A3/A4/A7(填充与稀疏/差分,依赖 A5 通知 in_bytes)
|
||||
→ A8 版本
|
||||
B1 → B3 decode → B4 remap → B5/B6/B7 滞回与重置 → B8/B9 API
|
||||
C1/C2 可后置
|
||||
```
|
||||
|
||||
双端可并行:A 与 B 仅共享数值表;联调以 V3–V8 为准。
|
||||
|
||||
---
|
||||
|
||||
## [S3] Out of Scope
|
||||
|
||||
- ESP32_COMM 固件(不解析 EtherCAT PDO)
|
||||
- 输出 PDO 384B 收缩
|
||||
- 刷 EEPROM / 冷启动依赖的 SII 多映射
|
||||
- 电机 10+ 节点
|
||||
- 用 tier 直接调 PDO 周期(0.25ms 等)
|
||||
- 提交/合并(用户明确不自动 commit)
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] T1: A1+A2+A5+A6 从站长度宏 + GenerateMapping 跟随 SM3 + InputMapping 按 nPdInputSize —— acceptance: 静态断言 264/432/600;主站手写 SM3=264 后 PREOP→SAFEOP 不报 0x001A/INVALIDSMINCFG;`nPdInputSize` 变 264 (covers: S2.2 S2.7-A)
|
||||
- [ ] T2: A3+A4+A7 从站密排/稀疏/差分偏移 cap 相对 —— acceptance: 264B SM 下段3/段5 不越界,主站能读 load/torn;count≤3 稀疏写两段正确 (covers: S2.2 S2.7-A; depends: T1)
|
||||
- [ ] T3: A8 版本 1.6.34 —— acceptance: PATCH=34 + 注释 (covers: S2.2; depends: T1)
|
||||
- [ ] T4: B1+B3 主站 decode cap 相对 —— acceptance: ilen=264+magic 槽/段3/段5 正确;ilen=600 回归一致 (covers: S2.1 S2.3 S2.7-B)
|
||||
- [ ] T5: B4 do_tier_remap + Ibytes/FMMU/group —— acceptance: 600→264→600 各一次 AL=OP、wkc 正、成功路径日志 <500ms (covers: S2.3; depends: T4)
|
||||
- [ ] T6: B5+B6+B7 滞回 + start/wedge 重置 —— acceptance: 稳定 3 电机 0.5–1.0s 进 264;4 电机进 432;楔死后回 9 再缩回 (covers: S2.3; depends: T5)
|
||||
- [ ] T7: B8+B9 `/api/pdo/tier` 与 state 字段 —— acceptance: POST cap 立即 remap;GET 含 tier_* (covers: S2.3; depends: T5)
|
||||
- [ ] T8: V1–V10 双端编译+台架 —— acceptance: cbuild/build_native 通过;见 Verification (covers: S2.2 S2.3; depends: T1–T7)
|
||||
- [ ] T9: C1+C2 前端分档展示 —— acceptance: 页面显示当前档;不阻塞 T8 (covers: S2.4; depends: T7)
|
||||
|
||||
---
|
||||
|
||||
## Verification(交付证据)
|
||||
|
||||
| 步骤 | 命令/操作 | 期望 |
|
||||
|------|-----------|------|
|
||||
| V1 | DCU cbuild(既有 Release+GD32E508VE) | 0 error |
|
||||
| V2 | `build_new.bat` / VS2022 cl 原生主站 | 产出 `ecat_native.new.exe` |
|
||||
| V3 | 冷启动 600 进 OP(3 电机) | 与今日一致,layout=dense |
|
||||
| V4 | 等待 ≥1s | 自动 remap 到 264,日志含耗时 |
|
||||
| V5 | `/api/motor/state` + spi_test | Ibytes/tier=264,count=3,wkc 稳定 |
|
||||
| V6 | rx 线时(粗) | 过程数据字节 648 vs 984,rx 段应下降(允许 ±15µs 噪声) |
|
||||
| V7 | 手动 `/api/pdo/tier` cap=9 | 回到 600 |
|
||||
| V8 | 拔/加第 4 台(或模拟 count) | 滞回后 432 |
|
||||
| V9 | 旧从站 + 新主站 | SAFEOP 失败路径回 600,总线仍可用 |
|
||||
| V10 | 楔死/PM hold | hold 中不 remap;恢复后 tier 策略符合 S2.3 |
|
||||
|
||||
---
|
||||
|
||||
## Journey log(设计期)
|
||||
|
||||
1. 线时收益来自 **SM3 变短**,稀疏写不够——与 1.6.22/1.6.25 结论一致。
|
||||
2. SSC 长度双源校验 ⇒ 必须主从同数;v1 选「主站写 SM,从站 GenerateMapping 读回」,避免 EEPROM 与多 PDO 映射。
|
||||
3. 首拍恒 600 是为了兼容 config_map/CoE,用 500ms 滞回消化一次 remap,比改 CoE 映射表风险低。
|
||||
4. 重映射不能走完整 `do_op_start`(重枚举+长喂帧)——独立轻量路径 + 失败回退完整路径。
|
||||
5. 段3/段5 偏移写死是主站解码的隐雷;Ibytes 分支(ilen<600→slim)会把 264 误判成瘦身布局——必须先用魔数 0xA5 拦下,再按 cap 排偏移。
|
||||
Reference in New Issue
Block a user