feat(ethercat): 1.6.40 起板探针改 BYTE_TEST 放行, 根治 warm jump 后 EtherCAT 降级

This commit is contained in:
cbb
2026-09-16 01:54:25 +08:00
parent 7d9d9c70a1
commit 63af85e7be
4 changed files with 142 additions and 35 deletions
+45 -25
View File
@@ -407,7 +407,7 @@ uint8_t EscLan9252::pmDrive(uint8_t op)
bool EscLan9252::init()
{
s_busReady = false; /* 1.5.27:s_busReady 语义 = init 完整成功(EXMC+探针+BYTE_TEST) */
s_busReady = false; /* 1.6.40:s_busReady = EXMC+BYTE_TEST 往返通过(IDX 残值不挡) */
s_coreReady = false; /* 1.5.39:s_coreReady 语义 = EEPROM 加载完成、EtherCAT 核心使能 */
/* 使能 DWT 周期计数器,供 hw_gd32exmc/SSC 执行时间测量 */
@@ -426,36 +426,56 @@ bool EscLan9252::init()
return false;
}
/* HBI 存活探针(数据手册 9.5.4.2):先直接读 HBI_IDX_0(offset 0,不写任何东西),
* 其复位默认值 = 0x1234。RST# 释放后 ESC 需完成内部启动与 EEPROM 加载,
* 故按手册建议轮询(此前为单次读,复位后立即读可能仍在启动中)。
* 若超时仍 != 0x1234(通常是 0x0000/0xFFFF 或上次写入的回显),
* 说明 LAN9252 完全没有驱动总线——CS 未拉低、CHIP_MODE strap 非 00(三端口=SPI only)
* 或芯片未出复位/未上电,而不是 EEPROM 问题(HBI 在 EEPROM 空白时也工作)。 */
uint16_t idx0 = EscExmcBus::read16(HBI_IDX0_OFFSET);
for (uint32_t waited = 0U;
idx0 != 0x1234U && waited < CONFIG_ESC_HBI_POLL_TIMEOUT_MS;
waited += CONFIG_ESC_HBI_POLL_STEP_MS) {
SysTickTimer::delayMs(CONFIG_ESC_HBI_POLL_STEP_MS);
/* 1.6.40: 放行判据换到能兜住的那侧——BYTE_TEST 完整往返(索引写+数据低/高
* 字读)才证明 HBI 通路通;HBI_IDX_0 只证明「芯片刚出过复位」(复位默认值
* 0x1234,DS 9.5.4.2),证明不了通路。warm jump(BOOT 刷完直跳)时 BOOT 的
* bootEcatDeinit 最后一条 HBI 写把索引寄存器留在 0x0054(IRQ_CFG),而跳转前
* 那发硬复位已被证明会把 warm jump 打死(BOOT 1.1.0.18 已短路)——于是这条
* 「读复位默认值」的探针对 warm 路径必然假阴性;cold 路径芯片自带 POR 天然
* 0x1234,与那发复位有没有落地无关——这正是「reset 能起、刷完起不来」的根因。
* BYTE_TEST 每次访问前都会重写索引,与复位态无关。
* 结构:BYTE_TEST 为唯一放行门;不过才补一发 RST# 再探一轮(此刻 SSC 尚未
* MainInit,二次复位零代价;s_resetDone 只保护运行期重复 init,不挡 init 内
* 重试)。两轮 BYTE_TEST 仍不通 = 总线物理不通,维持降级。
* warm 残值(如 0x0054)跳过 0x1234 轮询,避免无意义 300ms 等待 + 二次复位。 */
uint16_t idx0 = 0U;
uint32_t byteTest = 0U;
for (uint8_t attempt = 0U; attempt < 2U; ++attempt) {
if (attempt > 0U) {
printf("[ECAT][ESC] probe#%u fail (idx0=0x%04X byte_test=0x%08lX), 补发 RST# 重探\r\n",
(unsigned)attempt, (unsigned)idx0, (unsigned long)byteTest);
hardwareReset();
}
idx0 = EscExmcBus::read16(HBI_IDX0_OFFSET);
/* 仅在「像复位中/未驱动」时轮询 0x1234;warm 残值(非 0/0xFFFF/0x1234)说明
* 芯片活着且带着上次索引,直接测 BYTE_TEST,不空等。 */
const bool idxLooksIdle = (idx0 == 0x0000U) || (idx0 == 0xFFFFU);
if (idxLooksIdle || idx0 == 0x1234U) {
for (uint32_t waited = 0U;
idx0 != 0x1234U && waited < CONFIG_ESC_HBI_POLL_TIMEOUT_MS;
waited += CONFIG_ESC_HBI_POLL_STEP_MS) {
SysTickTimer::delayMs(CONFIG_ESC_HBI_POLL_STEP_MS);
idx0 = EscExmcBus::read16(HBI_IDX0_OFFSET);
}
}
byteTest = readReg32(LAN9252_REG_BYTE_TEST);
if (byteTest == LAN9252_BYTE_TEST_VALUE) {
break;
}
}
if (idx0 != 0x1234U) {
printf("[ECAT][ESC] init: FAIL, HBI_IDX_0=0x%04X (expect 0x1234) -> LAN not driving bus\r\n",
(unsigned)idx0);
if (byteTest != LAN9252_BYTE_TEST_VALUE) {
printf("[ECAT][ESC] init: FAIL, BYTE_TEST=0x%08lX (expect 0x87654321), idx0=0x%04X -> LAN not driving bus\r\n",
(unsigned long)byteTest, (unsigned)idx0);
printf("[ECAT][ESC] hint: check CS(PD7) pulse, CHIP_MODE0/1 straps=00, RST#/power\r\n");
return false;
}
/* 再读 BYTE_TEST(0x064)确认接口完全就绪,默认 0x87654321(小端)。
* 该值只有 HBI_DATA_0 偏移正确(EXMC 16-bit 地址左移 1 位)才可能读到。 */
const uint32_t byteTest = readReg32(LAN9252_REG_BYTE_TEST);
if (byteTest != LAN9252_BYTE_TEST_VALUE) {
printf("[ECAT][ESC] init: FAIL, BYTE_TEST=0x%08lX (expect 0x87654321)\r\n",
(unsigned long)byteTest);
printf("[ECAT][ESC] hint: IDX probe passed but DATA access failed -> check HBI_DATA_0 offsets (0x40000/0x60000)\r\n");
return false;
if (idx0 != 0x1234U) {
printf("[ECAT][ESC] init: WARN idx0=0x%04X != 0x1234, BYTE_TEST ok -> 复位态未知但通路可用,放行\r\n",
(unsigned)idx0);
}
printf("[ECAT][ESC] init: OK, HBI alive (IDX=0x1234, BYTE_TEST=0x87654321)\r\n");
printf("[ECAT][ESC] init: OK, HBI alive (idx0=0x%04X, BYTE_TEST=0x87654321)\r\n",
(unsigned)idx0);
s_busReady = true;
/* 等待 PDI 就绪、EtherCAT 核心可交互(1.5.37 新增,1.5.39 改经 CSR 间接端口读——