跳到主要内容

配置

启动参数

启动参数 (Startup Parameters) 是主站在 ESM 状态转换前后自动写入从站的 SDO/寄存器序列, 符合 ETG.1500 PO->SO Init 命令规范. 适用于厂商特定初始化序列 (如配置 PDO 映射、设置工作模式、写入电机参数等), 用户态无需手写状态机, SDK 在 SetStateSequence 期间按 transition+priority 顺序自动应用.

AddStartupParameter()

int AddStartupParameter(uint16_t master_index, uint16_t slave_index,
const ec_startup_param_t* param);

为指定从站追加一条启动参数, 参数会缓存到从站槽位, 状态转换时按 priority 顺序应用.

参数:

  • master_index (uint16_t) — 主站索引
  • slave_index (uint16_t) — 从站索引 (1-based)
  • param (const ec_startup_param_t*) — 启动参数描述

返回值:

  • int — 0=成功, 非 0=失败 (从站不存在 / 槽位已满 / 参数非法)

相关结构:

#pragma pack(push, 1)
typedef struct {
uint16_t index; /* SDO 索引 */
uint8_t sub_index; /* SDO 子索引 */
uint8_t data[256]; /* 参数数据 (EC_STARTUP_PARAM_MAX_DATA) */
uint16_t data_len; /* 数据长度 (字节) */
uint8_t transition; /* 转换标识 (EC_TRANS_*) */
uint8_t timing; /* 执行时机 (EC_TIMING_*) */
uint16_t priority; /* 执行优先级 (数值越小越先执行) */
uint8_t complete_access; /* 完整访问 (CA=1 写入整个索引) */
uint8_t is_register_write; /* 1=寄存器写入, 0=SDO 写入 */
} ec_startup_param_t;
#pragma pack(pop)
  • transition: EC_TRANS_IP=0 (Init->PreOp), EC_TRANS_PS=1 (PreOp->SafeOp), EC_TRANS_SO=2 (SafeOp->OP), EC_TRANS_OS=3, EC_TRANS_SP=4, EC_TRANS_PI=5
  • timing: EC_TIMING_BEFORE=0 (转换前执行), EC_TIMING_AFTER=1 (转换后执行)
  • 单从站最多 EC_MAX_STARTUP_PARAMS=128
调用时机

必须在 SetStateSequence/SetStateWithStartup 之前添加完毕. 已经进入 OP 后再添加的条目本周期不会生效, 需重新跑状态转换.

示例:

/* PreOp 之前写入电机操作模式 = 8 (CSP, CiA402) */
ec_startup_param_t p = {0};
p.index = 0x6060;
p.sub_index = 0x00;
p.data[0] = 8;
p.data_len = 1;
p.transition = EC_TRANS_PS; /* PreOp -> SafeOp */
p.timing = EC_TIMING_BEFORE;
p.priority = 100;
p.complete_access = 0;
p.is_register_write = 0;

if (dll.AddStartupParameter(master, 1, &p) != 0)
printf("启动参数追加失败\n");

ApplyStartupParameters()

int ApplyStartupParameters(uint16_t master_index, uint16_t slave_index,
uint8_t transition, uint8_t timing);

立即对指定从站应用匹配 (transition + timing) 的启动参数, 用于手动驱动场景 (跳过 SetStateSequence 自动管线时).

参数:

  • master_index (uint16_t) — 主站索引
  • slave_index (uint16_t) — 从站索引 (1-based)
  • transition (uint8_t) — 状态转换标识 (EC_TRANS_*)
  • timing (uint8_t) — 执行时机 (EC_TIMING_BEFORE / EC_TIMING_AFTER)

返回值:

  • int — 已成功应用的参数数量, 负数表示失败
自动管线

绝大多数应用走 SetStateSequence 即可, 框架自动在每次转换前后调用本函数. 只有需要在自定义状态机里精确控制时机时才手动调用.

示例:

/* 手动: PreOp -> SafeOp 之前应用 EC_TRANS_PS / BEFORE 段 */
int n = dll.ApplyStartupParameters(master, 1, EC_TRANS_PS, EC_TIMING_BEFORE);
printf("从站1 应用了 %d 条启动参数\n", n);

ApplyStartupParametersAll()

int ApplyStartupParametersAll(uint16_t master_index, uint8_t transition, uint8_t timing);

对全部从站批量应用匹配 (transition + timing) 的启动参数, 等价于循环 ApplyStartupParameters.

参数:

  • master_index (uint16_t) — 主站索引
  • transition (uint8_t) — 状态转换标识 (EC_TRANS_*)
  • timing (uint8_t) — 执行时机 (EC_TIMING_BEFORE / EC_TIMING_AFTER)

返回值:

  • int — 已成功应用的参数总数, 负数表示失败

示例:

/* 进 OP 之前对所有从站应用 PS/BEFORE 段 */
dll.ApplyStartupParametersAll(master, EC_TRANS_PS, EC_TIMING_BEFORE);
dll.SetStateWithTimeout(master, EC_STATE_SAFE_OP, 5000);
dll.ApplyStartupParametersAll(master, EC_TRANS_PS, EC_TIMING_AFTER);

相关辅助

  • ClearStartupParameters(mi, si)int — 清除指定从站的全部启动参数
  • GetStartupParameterCount(mi, si)int — 查询指定从站当前缓存的启动参数数量
  • AddStartupParameterBatch(mi, si, params, count)int — 一次性批量追加 (避免循环单条调用开销)

JSON 配置加载

LoadConfigJson()

int LoadConfigJson(uint16_t master_index, const char* json_str);

从 JSON 字符串加载配置(含从站启动参数)。返回加载的参数数量。

AutoConfigureSM()

int AutoConfigureSM(uint16_t master_index, uint16_t slave_index);

根据启动参数自动计算 SM2/SM3。slave_index=0 时处理所有从站。

一步初始化

详见 初始化 - EcInit

日志控制

void SetPDOLogging(BOOL enable);
void SetMailboxLogging(BOOL enable);
void SetDebugLogging(BOOL enable);

日志类别:

typedef enum {
LOG_CATEGORY_ERROR = 0,
LOG_CATEGORY_WARNING = 1,
LOG_CATEGORY_MESSAGE = 2,
LOG_CATEGORY_MAILBOX = 3,
LOG_CATEGORY_PDO = 4,
LOG_CATEGORY_DEBUG = 5
} log_category_t;

互斥锁保护

void SetMutexProtection(uint16_t master_index, BOOL enable);
BOOL GetMutexProtection(uint16_t master_index);

互斥锁保护开关。控制 PDO 读写时是否自动加锁确保线程安全。

  • 启用(默认) — 框架自动加锁保证线程安全
  • 禁用 — 关闭自动互斥锁,由用户自行管理线程安全,减少锁竞争开销
注意

禁用互斥锁保护后,用户需要自行确保 PDO 数据的线程安全。适用于对延迟有极致要求且能自行管理并发的场景。

IOmap 锁定

void LockIOmap(uint16_t master_index);
void UnlockIOmap(uint16_t master_index);

手动锁定/解锁 IOmap,用于多轴批量原子写入。当 SetMutexProtection(mi, FALSE) 时,需要手动调用此函数保证 PDO 数据的原子性。

三种线程安全模式对比:

模式设置延迟适用场景
自动互斥锁SetMutexProtection(mi, TRUE)(默认)~200ns通用场景,无需关心线程安全
手动锁SetMutexProtection(mi, FALSE) + LockIOmap/UnlockIOmap多轴插补,需要批量原子写入
无锁SetMutexProtection(mi, FALSE),不调用 Lock0单线程写入,保证无竞争
多轴插补场景

多轴联动插补时,多个从站的目标位置必须在同一 PDO 周期内同时生效。使用手动 IOmap 锁可以保证一批写入操作在一次 PDO 帧中原子提交。

示例(多轴插补批量写入):

// 关闭自动互斥锁
SetMutexProtection(mi, FALSE);

// PDO 回调中批量写入
void pdo_callback(uint16_t mi) {
LockIOmap(mi);

// 所有写入在同一把锁内完成,保证原子性
WriteSlaveOutput(mi, 1, target_pos1_data, 4);
WriteSlaveOutput(mi, 2, target_pos2_data, 4);
WriteSlaveOutput(mi, 3, target_pos3_data, 4);

UnlockIOmap(mi);
}

PDO 周期配置

LoopCycle

uint32_t config_get_loop_cycle(uint16_t master);
void config_set_loop_cycle(uint16_t master, uint32_t cycle_ns);

PDO 交换周期时间,单位:纳秒(ns)

主站 RT 线程(WDK 内核定时器驱动)以此周期执行 PDO 帧的发送和接收。该值决定了主站与从站之间过程数据的刷新频率 -- 值越小,数据刷新越快,但对系统实时性要求也越高。WDK 驱动最低支持 31.25μs。

推荐值

Windows 系统建议不低于 125,000ns(125us)。WDK 驱动完全支持 31.25us,更小的值在 Windows 上没有意义,应用层无法做到更高频的写入。

示例:

config_set_loop_cycle(mi, 1000000);  /* 1ms     = 1,000,000ns */
config_set_loop_cycle(mi, 500000); /* 500us = 500,000ns */
config_set_loop_cycle(mi, 250000); /* 250us = 250,000ns */
config_set_loop_cycle(mi, 125000); /* 125us = 125,000ns(Windows 推荐最小值) */
DC 漂移补偿

DC 漂移补偿自动完成,无需额外配置。

邮箱通信与 PDO 周期

邮箱报文(SDO 读写、FoE 文件传输、紧急消息等)自动附带在 PDO 周期中,不占用额外帧

邮箱响应延迟: 约 2-3 个 PDO 周期。如 LoopCycle=1ms,SDO 读取约需 2-3ms。

通信配置属性

以下配置通过 master/config.h 中的内联函数读写,底层通过 ec_State 结构体指针直接访问字段。

头文件

使用这些函数需要包含 master/config.h,该头文件已被 ethercat.h 自动包含。

类别函数 (Get/Set)类型读写默认值说明
PDO 周期config_get/set_loop_cycle(master)uint32_t读写1000000PDO 交换周期(纳秒)
帧优先级config_get/set_frame_high_priority(master)BOOL读写FALSE帧 OS 级优先级(Linux: SO_PRIORITY, Windows: 线程优先级)
PDO 优化config_get/set_overlapping_groups(master)BOOL读写FALSEFMMU 逻辑地址重叠模式(TI ESC),仅 INIT/PREOP 设置
config_get/set_packed_mode(master)BOOL读写FALSEbit 紧密 PDO 映射(Beckhoff EL1008/EL2008),仅 INIT/PREOP 设置
帧重复config_get/set_frame_repeat_count(master)uint8_t读写1每周期 PDO 帧重复次数(1=禁用, 2-3=ETG.1500 5.4.3)
丢帧检测config_get/set_pdo_frame_loss_threshold(master)uint16_t读写3连续丢帧阈值,达到时触发 PDOFrameLoss 回调
自适应超时config_get/set_adaptive_timeout(master)BOOL读写FALSE根据网络 RTT 动态调整 PDO 超时值
状态超时config_get/set_timeout_init_to_preop(master)uint32_t读写3000INIT->PREOP 超时(毫秒, ETG.1020)
config_get/set_timeout_preop_to_safeop(master)uint32_t读写10000PREOP->SAFEOP 超时(毫秒)
config_get/set_timeout_safeop_to_op(master)uint32_t读写5000SAFEOP->OP 超时(毫秒)
看门狗config_get/set_pd_watchdog_ms(master)uint16_t读写0过程数据看门狗超时(毫秒, 0=从站默认, ETG.1000.4)
config_get/set_pdi_watchdog_ms(master)uint16_t读写0PDI 看门狗超时(毫秒, 0=从站默认)
VLANconfig_get/set_vlan_id(master)uint16_t读写0VLAN ID(0=禁用, 1-4095, IEEE 802.1Q),仅 WDK 模式
config_get/set_vlan_priority(master)uint8_t读写0VLAN 优先级 PCP(0-7, 7 最高),需先设置 VlanId
UDPSetUdpMode(master, enable) / GetUdpMode(master)BOOL读写FALSEUDP 帧传输模式(ETG.1500 5.3.7)
IsUdpAvailable(master)BOOL只读-UDP 帧传输是否可用

帧优先级

BOOL config_get_frame_high_priority(uint16_t master);
void config_set_frame_high_priority(uint16_t master, BOOL enabled);

OS 层面的帧发送优先级提升。不插入 VLAN 标签,与 VLAN 功能独立。

PDO 优化

/* Overlapping Groups (TI ESC 重叠模式) */
BOOL config_get_overlapping_groups(uint16_t master);
void config_set_overlapping_groups(uint16_t master, BOOL enabled);

/* Packed PDO 映射 (bit-level IO 模块) */
BOOL config_get_packed_mode(uint16_t master);
void config_set_packed_mode(uint16_t master, BOOL enabled);
注意

Overlapping Groups 和 Packed Mode 仅在 INIT 或 PRE_OP 状态下设置,SafeOp/OP 状态下修改无效。

帧重复 (ETG.1500 5.4.3)

uint8_t config_get_frame_repeat_count(uint16_t master);
void config_set_frame_repeat_count(uint16_t master, uint8_t count);

每个 PDO 周期发送相同帧的次数。count=1 禁用(默认),count=2-3 启用。需要从站支持帧重复(通过 SetSlaveSupportsFrameRepeat 标记)。

PDO 丢帧阈值

uint16_t config_get_pdo_frame_loss_threshold(uint16_t master);
void config_set_pdo_frame_loss_threshold(uint16_t master, uint16_t threshold);

连续丢帧数达到此阈值时触发 PDOFrameLoss 回调。默认值为 3。

自适应超时

BOOL config_get_adaptive_timeout(uint16_t master);
void config_set_adaptive_timeout(uint16_t master, BOOL enabled);

启用后根据网络往返时间(RTT)动态调整 PDO 超时值,适用于网络延迟波动较大的场景。

状态转换超时 (ETG.1020)

/* INIT -> PREOP (默认 3000ms) */
uint32_t config_get_timeout_init_to_preop(uint16_t master);
void config_set_timeout_init_to_preop(uint16_t master, uint32_t timeout_ms);

/* PREOP -> SAFEOP (默认 10000ms) */
uint32_t config_get_timeout_preop_to_safeop(uint16_t master);
void config_set_timeout_preop_to_safeop(uint16_t master, uint32_t timeout_ms);

/* SAFEOP -> OP (默认 5000ms) */
uint32_t config_get_timeout_safeop_to_op(uint16_t master);
void config_set_timeout_safeop_to_op(uint16_t master, uint32_t timeout_ms);

状态转换超时控制。在 SetStateSequenceSetStateWithTimeout 前设置,用于调整等待从站响应的最大时间。

过程数据看门狗 (ETG.1000.4)

/* 过程数据看门狗 (默认 0=从站默认值) */
uint16_t config_get_pd_watchdog_ms(uint16_t master);
void config_set_pd_watchdog_ms(uint16_t master, uint16_t timeout_ms);

/* PDI 看门狗 (默认 0=从站默认值) */
uint16_t config_get_pdi_watchdog_ms(uint16_t master);
void config_set_pdi_watchdog_ms(uint16_t master, uint16_t timeout_ms);

全局看门狗超时配置。设置为 0 时使用从站 EEPROM 中的默认值。与从站级看门狗 SetSlaveWatchdog 独立。

UDP 帧传输 (ETG.1500 5.3.7)

BOOL SetUdpMode(uint16_t master_index, BOOL enable);
BOOL GetUdpMode(uint16_t master_index);
BOOL IsUdpAvailable(uint16_t master_index);

启用 UDP 帧传输模式。IsUdpAvailable 检查当前环境是否支持 UDP 传输。

VLAN 配置 (IEEE 802.1Q)

uint16_t config_get_vlan_id(uint16_t master);
void config_set_vlan_id(uint16_t master, uint16_t vlan_id);

uint8_t config_get_vlan_priority(uint16_t master);
void config_set_vlan_priority(uint16_t master, uint8_t priority);
警告

大部分标准 EtherCAT 从站(Beckhoff EK/EL 系列等)不支持 VLAN 帧。启用 VLAN 会导致帧头从 14 扩展到 18 字节,不兼容的从站直接丢弃帧(WKC=0)。仅在确认所有从站支持 802.1Q 时才启用。

  • 仅 WDK 驱动模式下生效
  • 需要在 SetNetwork 之前设置 VlanId
  • VlanPriority 需要 VlanId 为非零值才能生效

配置示例

dll_t dll;
LOAD_DLL(&dll, "Darra.Core.dll");

uint16_t mi = dll.Initialize();

/* 设置状态转换超时 */
config_set_timeout_init_to_preop(mi, 5000);
config_set_timeout_preop_to_safeop(mi, 15000);
config_set_timeout_safeop_to_op(mi, 8000);

/* 启用帧优先级 */
config_set_frame_high_priority(mi, TRUE);

/* 设置帧重复 (需要从站支持) */
config_set_frame_repeat_count(mi, 2);

/* 设置过程数据看门狗 100ms */
config_set_pd_watchdog_ms(mi, 100);

/* 启用自适应超时 */
config_set_adaptive_timeout(mi, TRUE);

/* 设置丢帧检测阈值 */
config_set_pdo_frame_loss_threshold(mi, 5);

dll.SetNetwork(mi, adapter, "");
dll.SetStateSequence(mi, EC_STATE_OPERATIONAL, 15000);

扫描配置

ScanRevisionMatch

uint32_t config_get_scan_revision_match(uint16_t master);
void config_set_scan_revision_match(uint16_t master, uint32_t mode);

扫描从站时的版本匹配策略。控制 Build 过程中扫描到的从站与 DENI 配置中从站的版本号匹配严格程度。

  • 0 Exact — 精确匹配 VendorID + ProductID + RevisionID
  • 1 CompatibleHigher — 兼容匹配: 扫描到的 RevisionID >= 配置的 RevisionID
  • 2 IgnoreRevision — 忽略 RevisionID,仅匹配 VendorID + ProductID(默认)

DC 配置

DriftCompensation

BOOL config_get_drift_compensation(uint16_t master);
void config_set_drift_compensation(uint16_t master, BOOL enabled);

DC 漂移补偿开关。启用后主站周期性检测 DC 系统时间偏差并写入补偿值 (0x0920)。默认关闭。

超时配置最佳实践

EtherCAT 通信涉及的多种超时字段彼此独立, 对网络异常的检测灵敏度和恢复时延有直接影响. 下表汇总常用字段、典型默认值与推荐范围, 实际部署时按照网络长度 / 干扰水平 / 实时性优先级三维平衡选取.

关键字段速查:

字段单位默认推荐范围影响
loop_cyclens1,000,000 (1ms)125,000 ~ 4,000,000 (125us ~ 4ms)PDO 周期, 决定刷新率与 CPU 负载
timeout_init_to_preopms30003000 ~ 10000INIT->PREOP 等待时间 (慢从站 / EEPROM 加载)
timeout_preop_to_safeopms1000010000 ~ 30000PREOP->SAFEOP 等待时间 (含 SM/FMMU/PDO 映射, 大网络可加大)
timeout_safeop_to_opms50005000 ~ 15000SAFEOP->OP 等待时间
pd_watchdog_msms0 (从站默认 ≈100)loop_cycle × 10 ~ 100从站丢失主站连接后回退 SafeOp 的时间
pdi_watchdog_msms0 (从站默认)0 ~ 200从站本地固件停止访问 ESC 的检测窗口

何时调大 / 调小

调大 适用场景:

  • 长电缆 / 跨机柜 / 跨车间 -- 物理传输延迟大, 偶发 RTT 抖动需缓冲
  • 高 EMI / 焊接 / 大功率变频器附近 -- 噪声造成偶发丢帧, 重试空间需放宽
  • 跨 VLAN / TSN 复合网络 -- 经过交换机会引入排队抖动
  • 大网络 (>50 从站) -- timeout_preop_to_safeop 必须放大, 否则 SafeOp 转换失败
  • 慢从站 (FoE 大文件下载 / EEPROM 写入) -- 邮箱 / Init->PreOp 都要拉长

调小 适用场景:

  • 快速故障检测优先 -- 工业紧急停车场景, 看门狗调到 5×loop_cycle, 50ms 内检测到丢帧
  • 桌面短电缆 / 实验室 -- RTT 极低, 看门狗可下探到 20~50ms
  • RT 严苛 (≤ 250µs 周期) -- 整体时序紧凑, 任何超时都要短

默认 / 实验室 / 工业 / 高 EMI 四档示例

/* (1) SDK 默认 — 适合标准短电缆 + 桌面 ~ 普通车间 */
config_set_loop_cycle(mi, 1000000); /* 1ms */
config_set_timeout_preop_to_safeop(mi, 10000);
config_set_pd_watchdog_ms(mi, 0); /* 从站默认 (~100ms) */

/* (2) 实验室高速 — 短线 + 严苛 RT */
config_set_loop_cycle(mi, 250000); /* 250us */
config_set_timeout_preop_to_safeop(mi, 5000);
config_set_pd_watchdog_ms(mi, 20); /* 极快检测 */

/* (3) 工业典型 — 长电缆 + 大网络 */
config_set_loop_cycle(mi, 1000000);
config_set_timeout_preop_to_safeop(mi, 20000); /* 大网络放宽 */
config_set_pd_watchdog_ms(mi, 200);

/* (4) 高 EMI / 焊接现场 — 容忍偶发丢帧 */
config_set_loop_cycle(mi, 2000000); /* 2ms */
config_set_timeout_preop_to_safeop(mi, 30000);
config_set_pd_watchdog_ms(mi, 500);
config_set_adaptive_timeout(mi, TRUE); /* 自适应吸收抖动 */
副作用
  • 超时太大 -- 真实故障也要等到超时才上报, 应用层告警 / 安全停机延迟变长
  • 超时太小 -- 偶发抖动被误判成故障, 频繁触发 PDOFrameLoss / StateChange 噪声告警
  • 看门狗 < loop_cycle × 数倍 -- 正常运行也会触发, 从站反复回退 SafeOp
  • 调整后建议跑 24h 通讯压力测试再上线
配合自适应超时

启用 config_set_adaptive_timeout(mi, TRUE) 后, SDK 自动按真实 RTT 计算 PDO 单帧超时, 无需手动收紧 loop_cycle. 上面的 watchdog / state transition 字段仍需按场景配置.