feat(comm): 添加EtherCAT CAN桥接和PDO功能模块

添加了ethercat_can_bridge.h/cpp和ethercat_pdo.h/cpp四个文件,
扩展通信模块功能,支持CAN桥接和PDO相关操作。

fix(comm): 修复LAN9252 EXMC总线时序配置问题

将BUSLAT从1调整为4,确保满足数据手册要求的最小13ns间隔,
解决因时序余量不足导致的温漂偶发读错问题。

feat(comm): 配置ESC过程数据看门狗时间为1秒

修改ESC_REG_WD_TIME_PD寄存器值从默认100ms到1s,
防止主站调试周期触发SM2看门狗导致状态被拖回SAFEOP。
This commit is contained in:
cbb
2026-09-05 16:54:38 +08:00
parent 44d407390b
commit f9ef1b8da2
16 changed files with 2218 additions and 86 deletions
File diff suppressed because one or more lines are too long
+40
View File
@@ -17,6 +17,7 @@
#include "sys/task_runner.h"
#include "comm/ethercat_slave.h"
#include "comm/ethercat_sync.h"
#include "comm/ethercat_can_bridge.h"
#include "comm/esc_exmc_bus.h"
extern "C" {
@@ -233,6 +234,13 @@ void TaskRunner::taskCanRxParse()
s_runtime.last_rx_data,
s_runtime.last_rx_len);
#endif
/* 1.5.53:旁路投递给 EtherCAT PDO 桥。放在分发链末尾且**不消费**帧
* (不 return、不 continue),因此 OTA relay / 电机状态的取帧不受影响——
* 本队列只有 taskCanRxParse 一个消费者,新增第二个消费者会互相抢帧。 */
EthercatCanBridge::onCanFrame(s_runtime.last_rx_channel,
s_runtime.last_rx_id,
s_runtime.last_rx_data,
s_runtime.last_rx_len);
consumed++;
}
@@ -273,6 +281,33 @@ bool TaskRunner::copyAdcSample(Adc::Sample *out)
/* SSC 侧 AL 诊断快照(dc_app.c): [19:16]=AL 状态 [31:24]=AL 错误码 [15:0]=AL 事件寄存器 */
extern "C" uint32_t EcatDbg_ReadAlDiag(void);
/* SSC 侧 AL Event Mask(0x204) 守护(dc_app.c, 1.5.48):缺位自愈+WARN,返回实际值/0xFFFF=不适用 */
extern "C" uint32_t EcatDbg_GuardAleventMask(void);
/**
* @brief 1.5.48/1.5.49 AL Event Mask(0x204) 守护 + SM2 事件楔死自愈 + 1.5.52 邮箱
* SM 地址/长度失配自愈:250ms 周期。
* @note 实测"停止回 INIT 后重进 OP"概率性挂起(SAFEOP+0x001B, WKC=3/3 但
* bEcatFirstOutputsReceived 不置位,0x220 bit10 挂起 10s 无人处理)——
* PDI_Isr 通路楔死。守护在 SAFEOP 后 1s 内替 PDI_Isr 完成工作(置位
* 标志+应答事件),主站 12s OP 等待窗口内可自愈;WARN 携带全部内部旗标,
* 下次复现一行日志定位楔死路径(详见 dc_app.c 注释)。
* 1.5.52:周期 1s→250ms——新加的邮箱地址自愈(1.5.52 根治 SSC 侧
* u16EscAddrSendMbx 错位楔死,详见 dc_app.c)必须快过主站 SDO 超时
* (~700ms),否则自愈永远落在主站放弃之后,形同虚设。
*/
static void ethercatAleMaskGuard()
{
static uint32_t s_lastGuardMs = 0U;
if (!EthercatSync::isActive()) {
return;
}
const uint32_t nowMs = g_scheduler.tick_1ms;
if ((uint32_t)(nowMs - s_lastGuardMs) >= 250U) {
s_lastGuardMs = nowMs;
EcatDbg_GuardAleventMask();
}
}
/**
* @brief 1.5.32 ECAT 心跳:主循环存活证明 + ESC AL 状态/事件寄存器快照。
@@ -547,6 +582,11 @@ void TaskRunner::runPending()
* DC 模式下 PDO 交换由 SYNC0 ISR (Sync0_Isr) 完成,此处仅处理低优先级逻辑。 */
MainLoop();
/* 1.5.48:AL Event Mask(0x204) 守护——每圈入口执行,内部 1s 节流。
* 放 MainLoop 旁而非诊断任务:守护必须独立于诊断打印频率,
* OP 等待期(12s)内从站进 SAFEOP 后 1s 内即介入自愈。 */
ethercatAleMaskGuard();
const uint32_t pending = TaskManager::takePending();
if(pending == 0U) return;