跳到主要内容

DC 同步 (从站级)

从站级 DC(分布式时钟)属性和配置。主站级 DC 配置详见 DC 配置

推荐使用主站级方法

大多数场景建议使用 ConfigureDCAll() 一次性配置所有 DC 从站。 从站级方法适用于需要对个别从站设置不同参数的场景。两者都默认自动计算偏移。

只读属性

类别函数返回类型说明
DC 状态GetSlaveHasDC(mi, si)BOOLESC 硬件是否支持 DC
DC 状态slave_has_esi_dc_sync(mi, si)BOOLESI 是否声明此从站使用 DC 同步
DC 状态GetSlaveDCActive(mi, si)uint16_tDC 激活状态 (0=禁用, 非0=已激活)
DC 时间GetSlaveDCCycle0(mi, si)int32_t当前 SYNC0 周期 (纳秒)
DC 时间GetSlaveDCCycle1(mi, si)int32_t当前 SYNC1 周期 (纳秒)
DC 时间GetSlaveDCShift(mi, si)int32_t当前相位偏移 (纳秒)
DC 时间GetSlavePropagationDelay(mi, si)int32_t帧从主站到达此从站的传播延迟 (纳秒)
DC 拓扑GetSlaveDCNext(mi, si) / GetSlaveDCPrevious(mi, si)uint16_tDC 链表下一个 / 上一个从站索引
DC 拓扑GetSlaveDCParentPort(mi, si)int32_tDC 父端口号
DC 接收时间GetSlaveDCReceiveTimeA/B/C/D(mi, si)int32_t各端口接收时间 (纳秒)
HasDC vs HasEsiDcSync

GetSlaveHasDC 仅反映 ESC 硬件 bit, 不代表应用层一定使用 DC。部分从站 ESC 报 DC capable 但 ESI 未声明 DC OpMode, 此时应跑 FreeRun / SM-Sync, 强行启用 DC 会让从站拒绝进入 OP。

启用 DC 前的稳妥写法:

if (dll.GetSlaveHasDC(master, 1) && dll.slave_has_esi_dc_sync(master, 1)) {
dll.SetSyncBySlaveIndex(master, 1, 1000000, 0, 0);
}

配置方法

SetSyncBySlaveIndex()

void SetSyncBySlaveIndex(uint16_t master_index, uint16_t slave_index,
uint32_t sync0_ns, uint32_t sync1_ns, int32_t shift_ns);

配置单个从站的 DC 同步参数。所有参数单位纳秒sync0_ns=0 禁用 DC,sync1_ns=0 仅 SYNC0,shift_ns=0 不设置偏移。

示例:

/* SYNC0 = 1ms, 无 SYNC1, 无偏移 */
dll.SetSyncBySlaveIndex(master, 1, 1000000, 0, 0);

/* SYNC0 + SYNC1, 偏移 500us */
dll.SetSyncBySlaveIndex(master, 1, 1000000, 2000000, 500000);

/* 禁用 DC */
dll.SetSyncBySlaveIndex(master, 1, 0, 0, 0);

SetDcSyncMode()

typedef enum {
DC_FREE_RUN = 0, /* 自由运行: 不使用 DC */
DC_SM_SYNCHRON = 1, /* SM 事件同步 */
DC_SYNCHRON = 2, /* DC SYNC0 同步 */
DC_SYNCHRON_01 = 3 /* DC SYNC0 + SYNC1 */
} dc_sync_mode_t;

BOOL SetDcSyncMode(uint16_t master_index, uint16_t slave_index, uint8_t sync_type);
uint8_t GetDcSyncMode(uint16_t master_index, uint16_t slave_index);
BOOL dc_configure_with_mode(uint16_t master_index, uint16_t slave_index,
dc_sync_mode_t mode,
uint32_t sync0_ns, uint32_t sync1_ns,
int32_t shift_ns);

SetDcSyncMode() 设置/读取从站 SyncManager 同步类型。dc_configure_with_mode() 按同步模式一次性完成从站 DC 配置(SYNC0/SYNC1 信号 + SyncManager 同步类型),DC 同步模式按 ETG.1020 §22 / ESI AssignActivate 分四档。

示例:

/* 仅 SYNC0, 周期 1ms */
dll.dc_configure_with_mode(master, 1, DC_SYNCHRON, 1000000, 0, 0);

/* SYNC0 + SYNC1, 偏移 500us */
dll.dc_configure_with_mode(master, 1, DC_SYNCHRON_01, 1000000, 2000000, 500000);

DisableDC()

/* 通过 SetSyncBySlaveIndex 把 sync0_ns 置 0 即可 */
dll.SetSyncBySlaveIndex(master, 1, 0, 0, 0);

同步窗口诊断

GetSlaveSyncWindowStatus()

BOOL GetSlaveSyncWindowStatus(uint16_t master_index, uint16_t slave_index,
int* diff_ns, int* max_diff_ns, int* min_diff_ns,
BOOL* in_sync, uint32_t* out_of_sync_count);

获取从站 DC 同步窗口的详细状态。不支持 DC 或读取失败时返回 FALSE。输出参数: 当前/最大/最小时间差、是否在同步窗口内、累计失同步次数。

便捷查询

如果只需要 in_sync 或当前差值,可通过 GetSlaveLinkQuality / IsAllSlavesInSync 等便捷接口;GetSlaveSyncWindowStatus() 适合需要完整统计信息的场景。

ResetSlaveSyncWindowStats()

void ResetSlaveSyncWindowStats(uint16_t master_index, uint16_t slave_index);
int GetMaxSyncDifference(uint16_t master_index);
BOOL IsAllSlavesInSync(uint16_t master_index);

ResetSlaveSyncWindowStats() 重置此从站的同步窗口统计。GetMaxSyncDifference() / IsAllSlavesInSync() 是全局便捷查询。

完整示例

#define DYNAMIC_LOAD
#include "ethercat.h"
#include <stdio.h>

int main(void) {
dll_t dll;
LOAD_DLL(&dll, "Darra.Core.dll");

uint16_t master = dll.Initialize();
dll.SetNetwork(master, "\\Device\\NPF_{GUID}", "");
dll.SetStateSequence(master, EC_STATE_OPERATIONAL, 10000);
dll.Start(master);

if (dll.GetSlaveHasDC(master, 1)) {
/* 配置从站1: SYNC0 = 1ms */
dll.SetSyncBySlaveIndex(master, 1, 1000000, 0, 0);

printf("DC 激活: %d\n", dll.GetSlaveDCActive(master, 1));
printf("SYNC0 周期: %d ns\n", dll.GetSlaveDCCycle0(master, 1));
printf("相位偏移: %d ns\n", dll.GetSlaveDCShift(master, 1));
printf("传播延迟: %d ns\n", dll.GetSlavePropagationDelay(master, 1));

/* 同步窗口诊断 */
int diff, max_d, min_d;
BOOL sync;
uint32_t oos;
if (dll.GetSlaveSyncWindowStatus(master, 1, &diff, &max_d, &min_d, &sync, &oos)) {
printf("同步差: %d ns, 同步=%s, 失步=%u\n",
diff, sync ? "是" : "否", oos);
}

if (dll.IsAllSlavesInSync(master))
printf("所有从站已同步\n");

/* 禁用 DC */
dll.SetSyncBySlaveIndex(master, 1, 0, 0, 0);
}

dll.Stop(master);
dll.Dispose(master);
UNLOAD_DLL(&dll);
return 0;
}