文章目录
-
- [SOEM 源码修改总结](#SOEM 源码修改总结)
-
- [修改一:CoE PDO 读取后更新 SMlength](#修改一:CoE PDO 读取后更新 SMlength)
- [修改二:PO2SOconfig 钩子位置移动](#修改二:PO2SOconfig 钩子位置移动)
- 函数调用链中的位置
SOEM 源码修改总结
为了让 EL5101 和 EC-DO64 正常运行,对 SOEM 源码做了2 处功能修改 ,均在src/ec_config.c的ecx_map_coe_soe() 函数中。
修改一:CoE PDO 读取后更新 SMlength
保证正常从站(EL5101)的 SM 缓冲区大小跟随 PDO 切换同步更新;
位置:src/ec_config.c:534-535
修改前:
c
if (!rval) /* CA not available or not succeeded */
{
rval = ecx_readPDOmap(context, slave, &Osize, &Isize);
}
EC_PRINT(" CoE Osize:%u Isize:%u\n", Osize, Isize); // ← 只打印,不更新 SM
}
if ((!Isize && !Osize) && (...) ) /* has SoE */
{
rval = ecx_readIDNmap(context, slave, &Osize, &Isize);
context->slavelist[slave].SM[2].SMlength = htoes((uint16)((Osize + 7) / 8)); // ← SoE 有这行
context->slavelist[slave].SM[3].SMlength = htoes((uint16)((Isize + 7) / 8)); // ← SoE 有这行
}
context->slavelist[slave].Obits = (uint16)Osize;
context->slavelist[slave].Ibits = (uint16)Isize;
修改后:
c
if (!rval)
{
rval = ecx_readPDOmap(context, slave, &Osize, &Isize);
}
context->slavelist[slave].SM[2].SMlength = htoes((uint16)((Osize + 7) / 8)); // ← 新增
context->slavelist[slave].SM[3].SMlength = htoes((uint16)((Isize + 7) / 8)); // ← 新增
EC_PRINT(" CoE Osize:%u Isize:%u\n", Osize, Isize);
}
原因 :SoE 分支(第 545-546 行)一直有 SMlength 更新逻辑,但 CoE 分支缺少。ecx_readPDOmap()通过 SDO 读回 PDO 位宽后仅设置了 Obits/Ibits,SMlength 仍保留ecx_config_init()时从 SII EEPROM 读取的默认值。EL5101 默认 SM2=3 bytes / SM3=5 bytes,切换 PDO 后变为 6 bytes / 10 bytes,SMlength 不更新则后续ecx_map_sm() 写入 ESC 硬件的是错误值。
原理:
bash
ecx_readPDOmap() 通过 SDO 读:
0x1C12:01 → PDO 索引 → 计算 bit 总和 → Osize
0x1C13:01 → PDO 索引 → 计算 bit 总和 → Isize
SoE 分支有: SM[2].SMlength = (Osize+7)/8 ← AMS/SoE 从站
CoE 分支无: SM[2].SMlength = ??? ← EL5101/EL3052 等 CoE 从站
缺失导致 ecx_map_sm() 用错误长度写 SM 寄存器 → ESC 拒绝。
修改二:PO2SOconfig 钩子位置移动
保证异常从站(EC-DO64)的钩子修正在所有自动检测完成后成为最终值。
位置:src/ec_config.c:551-558(从 518-522 行移来)
修改前:
c
static int ecx_map_coe_soe(ecx_contextt *context, uint16 slave, ...)
{
ecx_statecheck(context, slave, EC_STATE_PRE_OP, ...);
if (context->ENI) { ... }
/* execute slave configuration hook Pre-Op to Safe-OP */
if (context->slavelist[slave].PO2SOconfig) // ← 钩子在 CoE 读之前
{
context->slavelist[slave].PO2SOconfig(context, slave);
}
/* Find IO mapping in slave */
if (mbx_proto & ECT_MBXPROT_COE) {
ecx_readPDOmap(context, slave, &Osize, &Isize); // ← CoE 读会覆盖钩子的修正!
...
}
...
context->slavelist[slave].Obits = (uint16)Osize; // ← 覆盖!
context->slavelist[slave].Ibits = (uint16)Isize; // ← 覆盖!
return 1;
}
修改后:
c
static int ecx_map_coe_soe(ecx_contextt *context, uint16 slave, ...)
{
ecx_statecheck(context, slave, EC_STATE_PRE_OP, ...);
if (context->ENI) { ... }
/* Find IO mapping in slave */
if (mbx_proto & ECT_MBXPROT_COE) {
ecx_readPDOmap(context, slave, &Osize, &Isize);
...
}
...
context->slavelist[slave].Obits = (uint16)Osize;
context->slavelist[slave].Ibits = (uint16)Isize;
/* execute slave configuration hook Pre-Op to Safe-OP.
* Called AFTER CoE/SoE/SII PDO reads, allowing the hook to
* override automatically-discovered SM types, sizes, and lengths
* for slaves with non-standard or incorrect firmware. */
if (context->slavelist[slave].PO2SOconfig) // ← 钩子移到 CoE 读之后
{
context->slavelist[slave].PO2SOconfig(context, slave);
}
return 1;
}
原因 :EC-DO64 从站固件的 SM2/SM3 类型定义与标准相反。原始代码中 PO2SOconfig 钩子在 CoE PDO 读取之前 执行,钩子设置的修正值(SMtype、Obits、Ibits、SMlength)会被后续ecx_readPDOmap()和Obits/Ibits 赋值覆盖,导致修正不生效。
原理:
bash
EC-DO64 SII 读取值: SM[2].SMtype=4(Inputs), SM[3].SMtype=3(Outputs)
CoE PDO 读回值: Osize=0, Isize=64 ← 因为 SM 类型反了
修改前:
钩子修正: SMtype[2]=3, Obits=64 ✓
CoE 读: Osize=0 ← 读回 0
Obits=0 ← 覆盖! 钩子白改了
SM[2].SMlength = (0+7)/8 = 0 ← SM2 被禁用!
修改后:
CoE 读: Osize=0 ← 先读完
Obits=0 ← 先赋值
钩子修正: SMtype[2]=3, SM[2].SMlength=8, Obits=64 ← 最终裁定!
→ ecx_map_sm 写入正确的 SM 硬件值
函数调用链中的位置
bash
ecx_config_map_group()
└─ ecx_config_find_mappings()
├─ ecx_map_coe_soe(slave) ← ★ 两处修改都在此函数内
│ ├─ ecx_readPDOmap() → Osize, Isize
│ ├─ ★ SM[2/3].SMlength 更新 (修改一)
│ ├─ Obits = Osize, Ibits = Isize
│ └─ ★ PO2SOconfig 钩子 (修改二, 移到这里)
├─ ecx_map_sii(slave) → SII 兜底 (若 Obits/Ibits=0)
└─ ecx_map_sm(slave) → 写 SM 寄存器到 ESC 硬件
两处修改缺一不可:修改一保证正常从站(EL5101)的 SM 缓冲区大小跟随 PDO 切换同步更新;修改二保证异常从站(EC-DO64)的钩子修正在所有自动检测完成后成为最终值。