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:
@@ -149,6 +149,16 @@ extern volatile UINT32 g_dbg_appCyc;
|
||||
/* [DIFF-STATS] 差分写统计窗口值(comm/ethercat_diff_stats.cpp),out[0..10] 对应 sub13..23 */
|
||||
void EcatDiffStats_GetWindow(UINT32 *out);
|
||||
|
||||
/* 1.6.33:OP 输入新鲜度 — APPL_InputMapping 每次成功刷新就自增 */
|
||||
static volatile UINT32 s_inMapSeq = 0U;
|
||||
static UINT32 s_inMapSeqSeen = 0U;
|
||||
static UINT32 s_inStaleBaseCyc = 0U;
|
||||
static UINT32 s_opFreshRescues = 0U;
|
||||
#include <stdint.h>
|
||||
/* DFP 的 SystemCoreClock 是 uint32_t(=unsigned int);SSC 的 UINT32 是 unsigned long,
|
||||
* 不能用 UINT32 重复声明。 */
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
/* 过程数据收发模块 (comm/ethercat_pdo.cpp 的 extern "C" shim, 1.5.54)。
|
||||
* 1.5.53 时这里直接调 EcatCan_* 转发桥;1.5.54 把"一个 EtherCAT 周期怎么收发"
|
||||
* 收拢进 EthercatPdo 类,本文件退回纯 SSC 移植层:只留对象字典 + 三行转发。 */
|
||||
@@ -437,6 +447,9 @@ void APPL_InputMapping(UINT16 *pInputData)
|
||||
* SDO 读 0x6000 时看到与过程数据一致的内容。 */
|
||||
EcatPdo_WriteInputs((UINT8 *)&s_inputObj.u64Data[0]);
|
||||
memcpy(pInputData, &s_inputObj.u64Data[0], ECAT_PDO_IN_BYTES);
|
||||
/* 1.6.33:OP 输入新鲜度不变量的活性计数。每次真正走到输入映射就自增,
|
||||
* 供 EcatDbg_OpInputFreshness 判断 PDI 路径是否还活着。 */
|
||||
++s_inMapSeq;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
@@ -632,3 +645,81 @@ UINT32 EcatDbg_GuardAleventMask(void)
|
||||
}
|
||||
return actual;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
* OP 输入新鲜度不变量 — 1.6.33
|
||||
*
|
||||
* 结构洞(用户实锤:1ms 也复现,复位 GD32 APP 才好):
|
||||
* SM-Synchron 稳态下 MainLoop 的 free-run 分支被
|
||||
* (!bEscIntEnabled || !bEcatFirstOutputsReceived) && !bDcSyncActive
|
||||
* 整段跳过,输入 PDO **只**由 PDI_Isr 的 PDO_InputMapping 刷新。
|
||||
* PDI 通路一停(门控/掩码/EXTI),ESC 仍答 WKC、AL 仍 OP,主站读到的是
|
||||
* 冻住的旧缓冲 —— 网页绿灯+高 Hz、CPU/CAN 全像没解析。既有 1.5.60 只救
|
||||
* "门关着",救不了"门开着但 EXTI 不来"。
|
||||
*
|
||||
* 根治:把「OP ⇒ 输入必须在 T ms 内被重写」做成不变量。
|
||||
* - 正常路径:PDI_Isr 每拍自增 s_inMapSeq
|
||||
* - 异常路径:seq 停涨超过阈值 → 主循环强制 PDO_InputMapping
|
||||
* (屏中断防双写)+ 重开门/应答 SM2,主站侧 gseq/rx 立刻恢复前进
|
||||
* 不依赖主站重拉、不依赖人工复位。MainLoop 若本身死锁则本函数也停 ——
|
||||
* 那是另一类故障(心跳会停),不在本不变量覆盖范围。
|
||||
*---------------------------------------------------------------------------*/
|
||||
void EcatDbg_OpInputFreshness(void)
|
||||
{
|
||||
const UINT8 al = (UINT8)(nAlStatus & 0x0FU);
|
||||
const UINT32 now = EcatDbg_Dwt();
|
||||
const UINT32 seq = s_inMapSeq;
|
||||
|
||||
if (al != 8U || nPdInputSize == 0U) {
|
||||
s_inMapSeqSeen = seq;
|
||||
s_inStaleBaseCyc = now;
|
||||
return;
|
||||
}
|
||||
if (seq != s_inMapSeqSeen) {
|
||||
s_inMapSeqSeen = seq;
|
||||
s_inStaleBaseCyc = now;
|
||||
return;
|
||||
}
|
||||
|
||||
/* seq 未推进:等满阈值再介入,避开两拍之间的正常空隙。
|
||||
* 5ms @1ms 周期 = 连丢 ≥5 拍;@4ms 周期 = 连丢 1~2 拍,仍足够判死。 */
|
||||
{
|
||||
const UINT32 thresh = (SystemCoreClock / 1000U) * 5U;
|
||||
if ((UINT32)(now - s_inStaleBaseCyc) < thresh) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* 强制刷新:先重开门/首输出标志(门关着时 PDI 永远不会回来),
|
||||
* 再在关中断窗口内做一次输入映射 —— 此路径极低频,关中断可接受。 */
|
||||
{
|
||||
UINT16 dummy = 0U;
|
||||
const UINT16 evt = HW_GetALEventRegister();
|
||||
if (!bEscIntEnabled) {
|
||||
bEscIntEnabled = TRUE;
|
||||
}
|
||||
if (!bEcatFirstOutputsReceived) {
|
||||
bEcatFirstOutputsReceived = TRUE;
|
||||
HW_EscReadWord(dummy, nEscAddrOutputData);
|
||||
HW_EscReadWord(dummy, (UINT16)(nEscAddrOutputData + nPdOutputSize - 2U));
|
||||
}
|
||||
__asm volatile ("cpsid i" ::: "memory");
|
||||
PDO_InputMapping();
|
||||
__asm volatile ("cpsie i" ::: "memory");
|
||||
++s_opFreshRescues;
|
||||
s_inMapSeqSeen = s_inMapSeq;
|
||||
s_inStaleBaseCyc = EcatDbg_Dwt();
|
||||
printf("[ECAT][FRESH] WARN: OP input frozen (seq=%lu) evt=0x%04X "
|
||||
"(gate=%u first=%u dc=%u) -> forced PDO_InputMapping #%lu\r\n",
|
||||
(unsigned long)seq, (unsigned)evt,
|
||||
(unsigned)(bEscIntEnabled ? 1U : 0U),
|
||||
(unsigned)(bEcatFirstOutputsReceived ? 1U : 0U),
|
||||
(unsigned)(bDcSyncActive ? 1U : 0U),
|
||||
(unsigned long)s_opFreshRescues);
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 EcatDbg_OpFreshRescues(void)
|
||||
{
|
||||
return s_opFreshRescues;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,10 @@ void APPL_InputMapping(UINT16 *pInputData);
|
||||
void APPL_OutputMapping(UINT16 *pOutputData);
|
||||
void APPL_Application(void);
|
||||
|
||||
/* 1.6.33:OP 输入新鲜度不变量(task_runner 每圈调用;内部廉价,仅冻结时强制重写) */
|
||||
void EcatDbg_OpInputFreshness(void);
|
||||
UINT32 EcatDbg_OpFreshRescues(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -173,7 +173,7 @@ volatile UINT32 g_dbg_pdiCyc = 0; /* sub5: PDI_Isr 全函数累计周期 */
|
||||
volatile UINT32 g_dbg_outCyc = 0; /* sub6: PDO_OutputMapping(输出探针/全量读) */
|
||||
volatile UINT32 g_dbg_freerunCyc = 0; /* sub7: MainLoop free-run 分支(SM 同步下恒 0) */
|
||||
volatile UINT32 g_dbg_pdiCnt = 0; /* sub8: PDI_Isr 触发次数(=每周期 1 次) */
|
||||
volatile UINT32 g_dbg_inCyc = 0; /* sub9: PDO_InputMapping 全程(APPL+640B 写) */
|
||||
volatile UINT32 g_dbg_inCyc = 0; /* sub9: PDO_InputMapping 全程(APPL+过程数据写) */
|
||||
volatile UINT32 g_dbg_inWriteCyc = 0; /* sub10: 其中 HW_EscWriteIsr 640B 过程数据写 */
|
||||
volatile UINT32 g_dbg_alCyc = 0; /* sub11: PDI_Isr 内 AL 事件读×2+超限应答 */
|
||||
volatile UINT32 g_dbg_appCyc = 0; /* sub12: ECAT_Application(桥 processOutput) */
|
||||
@@ -200,7 +200,7 @@ BOOL bInitFinished = FALSE; /** < \brief indicates if the initialization is fini
|
||||
*////////////////////////////////////////////////////////////////////////////////////////
|
||||
void PDO_InputMapping(void)
|
||||
{
|
||||
/*ECAT_DBG(1.6.0 剖分:输入映射全程 + 640B 写细分)*/
|
||||
/*ECAT_DBG(1.6.0 剖分:输入映射全程 + 过程数据写细分)*/
|
||||
/* 1.6.22 稀疏写:APPL 仍整填 aPdInputData(对齐 SDO 0x6000),但 HW_EscWriteIsr
|
||||
* 只写密排有效段+段3/5,跳过空槽区 —— 省的是 PRAM 字节时间,不是 RAM 拷贝。
|
||||
* 1.6.25 差分写:在稀疏之上再跳过「与影子一致且 3-buffer 冲刷完成」的段。 */
|
||||
|
||||
Reference in New Issue
Block a user