feat(ethercat): LAN9252 bring-up完成,EEPROM烧录改主站侧并增强DC/AL可观测性

- 新增ESC硬件复位序列(1.5.25):PB10驱动LAN9252 RST#,拉低30ms+释放后300ms轮询HBI就绪,
  满足tpurstd/trstia时序;此前RST#仅靠R44上拉自然释放
- 修正EXMC 16-bit地址左移(1.5.27):HBI DATA偏移0x20000/0x30000→0x40000/0x60000;
  ADDSET 2→4 HCLK;片选更名NE1→NE0(LQFP100仅Region0)
- 按LAN9252手册/AN1907修正EEPROM镜像(1.5.28):word1高字节0x00→0xCC(SYNC0/1 Map+Output,
  否则SYNC0留LATCH态DC过程数据死)、word2=5000(脉宽50µs)、尾部补真实0xFF;
  gen_eeprom.py按ETG.1000.6重写;DCU_ESI.xml PDI 0x05→0x8D、RxPdo/TxPdo互换改4×64bit对齐
- 删除GD32侧EEPROM烧录路径(1.5.29):移除EscEeprom/esc_eeprom、eeprom_image.h及主循环
  烧录块,ESI镜像改由主站ecat_flash_eeprom.py经ESC 0x0500刷写(162字全校验通过);
  HBI互斥补屏蔽EXTI2(SYNC1),防Sync1_Isr两步事务打断主循环HBI访问致错址
- DC SYNC0通路可观测(1.5.30/31):EthercatSync新增sync0/sync1/escirq三个volatile计数器,
  task_runner 5s按增量打印速率;SSC OD新增只读0x2000 SYNC Diag,主站SDO轮询网页显示
- AL通路诊断(1.5.32):ECAT_Main/SetALStatus打印主站AL请求与写回状态+错误码,
  task_runner新增5s [ECAT][HB]心跳(仅同步ISR激活时);dc_app.c导出EcatDbg_ReadAlDiag
- 删除死代码EthercatSlave::periodicIsr三缓冲PDO桥,PDO交换由SSC完成(4×64bit=32B);
  EthercatSlave::init()恢复调用并以isBusReady()(BYTE_TEST)门控
- CANFD修复同通道突发只发3帧:transmitFrame新增allow_abort区分突发/软件队列路径,
  邮箱满落入软件TX队列(深度13)由TX完成中断drainTxQueueIsr回灌;BRS重新启用(0→1)
- motor_state新增CONFIG帧缓存(0x00000101, DLC 24)记录目标值回报,条目44B→76B、每页5→3
- SPI 0xA2诊断扩展action 20~24(ECAT_NRST拉低/拉高/浮空/回读);新增ESP32 EN自检打印
- 版本号更新至1.5.32
This commit is contained in:
cbb
2026-09-01 03:07:48 +08:00
parent a2d0b28b3d
commit cfe7725b26
32 changed files with 22382 additions and 1349 deletions
+23 -10
View File
@@ -52,7 +52,7 @@ constexpr uint16_t CONFIG_MOTOR_OFFLINE_MS = 3000U;
/** @brief CAN-FD BRS 使能(canfd.cpp #if)。
* 关闭 BRS: 数据段用仲裁段同速率,牢牢性更高。
* 电机 BOOT 无法正确接收 BRS 高速段→nonce(16B FD+BRS)被拒绝→握手失败。 */
#define CONFIG_CAN_FD_BRS_ENABLE 0U
#define CONFIG_CAN_FD_BRS_ENABLE 1U
/** @brief 启动时总线探测帧;正常固件关。 */
#define CONFIG_CAN_STARTUP_BUS_TEST_ENABLE 0
/** @brief 启动时内部回环自检;正常固件关。 */
@@ -115,7 +115,7 @@ constexpr bool CONFIG_CAN_CH2_ENABLE = true;
* ============================================================ */
constexpr uint32_t APP_FW_VERSION_MAJOR = 1U;
constexpr uint32_t APP_FW_VERSION_MINOR = 5U;
constexpr uint32_t APP_FW_VERSION_PATCH = 15U; /* 1.5.15:EXMC 通断测试新增 MODE0/MODE1 strap 驱动测试(action 0x0A-0x0D, PB8/PB9) */
constexpr uint32_t APP_FW_VERSION_PATCH = 32U; /* 1.5.32:AL 通路诊断打印(排查主站连接后 AL 卡 INIT)——ECAT_Main 收到主站 AL 控制请求打 [ECAT][AL] evt/req、SetALStatus 写回打 [ECAT][AL] -> 状态+错误码、task_runner 5s 心跳 [ECAT][HB] al/code/evt(仅同步 ISR 激活时,心跳停=主循环卡死);dc_app.c 导出 EcatDbg_ReadAlDiag(0x0130+0x0220 快照)。1.5.31:DC 通路观测同步到网页——SSC OD 新增只读记录 0x2000 SYNC Diag(sub1=sync0/sub2=sync1/sub3=escirq/sub4=uptime 秒,UINT32),APPL_InputMapping 每 PDO 周期从 EthercatSync 拉取快照(ethercat_sync.cpp 导出 EcatDbg_Get* extern C);配套 tools/ecat:/api/sync_diag 经 SDO 读 0x2000 并以主站时间戳算 sync0 速率,ecat.html 运行期 2s 轮询显示,串口 5s 低频打印保留为旁证。1.5.30:DC SYNC0 通路可观测性——EthercatSync 增加 s_sync0Count/s_sync1Count/s_escIrqCount 三个 volatile 计数器(ISR 内自增,SYNC0 路径实测仅 LDR/ADDS/STR 三条指令,仍在 .ramfunc);task_runner 新增 ethercatSyncCounterPrint(),5s 诊断按增量打印 sync0 速率(主站设 1ms 周期时应 ≈1000/s),无脉冲时静默。配套 tools/ecat 支持分布时钟:ecat_tool.py send/monitor 新增 --dc-cycle-us/--dc-shift-us(0=free-run 默认),enter_op() 在 config_map 后、进 SAFEOP 前调 config_dc()+dc_sync();ecat_server.py /api/op/start 接受 dc_cycle_us/dc_shift_us;ecat.html 加 DC SYNC0 周期下拉。此前工具从不调用 config_dc,PDO 恒为 free-run,SYNC0 引脚无脉冲、Sync0_Isr 从未触发,1.5.28 配的 word1=0xCC/word2=5000 一直未被实测覆盖。1.5.29:删除 GD32 侧 EEPROM 烧录路径(EscEeprom/esc_eeprom.h/.cpp、eeprom_image.h 及 task_runner 主循环烧录块)——ESI 镜像改由 EtherCAT 主站侧刷写(tools/ecat/ecat_flash_eeprom.py 经 ESC 0x0500 EEPROM 接口,2026-08-31 实测 162 字全校验通过),固件不再负责烧录;gen_eeprom.py 生成器保留。HBI 复查修复:maskEnter/Exit 补屏蔽 EXTI2(SYNC1)——Sync1_Isr 的 PDO_InputMapping→HW_EscWriteIsr 两步事务(preempt=1)可打断主循环 HW_EscRead/Write 致错址;通断测试模式进入/退出改经 maskEnter/Exit 屏蔽三类 EXTI,防测试期 ISR 访问 GPIO 态总线读垃圾。1.5.28:对照 LAN9252 数据手册/AN1907/官方 EVB XML 修正——EEPROM word1 高字节 0x00→0xCC(Sync/Latch 0151h:SYNC0/1 Map+Output、推挽低有效配 EXTI 下降沿;原 0x00 时 SYNC0 引脚留在 LATCH 输入态,DC 模式过程数据死);word2 0→5000(Sync 脉宽 0982h,x10ns=50us,0=确认模式不可用);eeprom_image.h 尾部补真实 0xFF 字节(原注释行致 C 零填充,烧写全阵列);EXMC ADDSET 2→4 HCLK(DS 表9-4 trdrd/twrwr/twrrd≥13ns);XML ConfigData 扩到 14B 并加 CycleTimeSync1。1.5.27:LAN9252 使用修正——EXMC 16-bit 地址左移 1 位(HBI DATA 偏移 0x20000/0x30000→0x40000/0x60000);gen_eeprom.py 按 ETG.1000.6 重写(CRC-8/word7、身份字 word8-15、CoE=0x0004、分类区 byte128);DCU_ESI.xml ConfigData PDI 0x05→0x8D、RxPdo/TxPdo 互换并改 4×64bit 对齐 dc_app.c;HBI 两步事务互斥守卫(主循环 mask EXTI0/1 + PDI/Sync1 ISR 屏蔽 EXTI0);删除死代码 EthercatSlave::periodicIsr 三缓冲;20s HBI 诊断在同步 ISR 激活后自动停跑 */
constexpr uint32_t APP_FW_VERSION_BUILD = 0U;
@@ -178,7 +178,8 @@ constexpr uint8_t CONFIG_CANFD_ID_SNAPSHOT_MAX = 16U;
/** @brief 快照条目最大数据字节数(CAN FD DLC 上限)。 */
constexpr uint8_t CONFIG_CANFD_ID_SNAPSHOT_DATA_MAX = 64U;
/** @brief ESP32 硬件复位控制端口(PC9 接 ESP32 EN/RESET)。 */
/** @brief ESP32 硬件复位控制端口(PC9 接 ESP32 EN/RESET,对应原理图 WLESS_EN)。
* @note 复位后 PC9 浮空,ESP_CHIP_EN 会被 C41/U11 拉低;BOOT 也必须主动拉高。 */
constexpr uint32_t CONFIG_ESP32_RESET_PORT = GPIOC;
/** @brief ESP32 硬件复位控制引脚。 */
constexpr uint32_t CONFIG_ESP32_RESET_PIN = GPIO_PIN_9;
@@ -296,11 +297,9 @@ constexpr uint32_t CONFIG_IRQ_PREEMPT_SPI_USART = 3U;
/* ============================================================
* EtherCAT LAN9252 配置(开关见顶部 CONFIG_MAIN_LOOP_WFI / ETHERCAT_SYNC_MODE)
* ============================================================ */
constexpr uint32_t CONFIG_ETHERCAT_ISR_MAX_US_THRESHOLD = 5U;
constexpr uint32_t CONFIG_ESC_PDI_INPUT_OFFSET = 0x1000U;
constexpr uint32_t CONFIG_ESC_PDI_OUTPUT_OFFSET = 0x1200U;
/** @brief 默认 PDO 缓冲大小(字节),应用/ISR 三缓冲共用。 */
constexpr size_t CONFIG_ETHERCAT_PDO_SIZE = 32U;
/* 1.5.27:CONFIG_ETHERCAT_ISR_MAX_US_THRESHOLD / CONFIG_ESC_PDI_INPUT_OFFSET /
* CONFIG_ESC_PDI_OUTPUT_OFFSET / CONFIG_ETHERCAT_PDO_SIZE 随死代码 EthercatSlave::
* periodicIsr 三缓冲一并删除;PDO 交换由 SSC(dc_app.c APPL_*, 4×64bit=32B) 完成。 */
/* ---------- EXMC 引脚配置(GD32E508 EXMC 标准映射) ---------- */
constexpr uint32_t CONFIG_ESC_EXMC_BASE_ADDR = 0x60000000U;
@@ -337,6 +336,17 @@ constexpr IRQn_Type CONFIG_ESC_SYNC1_IRQn = EXTI2_IRQn;
constexpr uint32_t CONFIG_ESC_SYNC1_EXTI_SOURCE_PORT = GPIO_PORT_SOURCE_GPIOB;
constexpr uint32_t CONFIG_ESC_SYNC1_EXTI_SOURCE_PIN = GPIO_PIN_SOURCE_2;
/* ---------- ESC 硬件复位(PB10 → LAN9252 Pin11 RST#,SCH 第1页 Pin47) ---------- */
/** @note 2026-08-22(1.5.25) 前固件从未初始化 PB10,RST# 仅靠 R44 10k 上拉自然释放,
* 不满足 LAN9252 手册 18.6.3 tpurstd(电源稳定→RST#释放)≥25ms、trstia(低脉宽)≥200µs。
* 由 EscLan9252::hardwareReset() 执行受控复位序列;释放后保持推挽输出高,
* GD32 自身复位期间引脚回浮空,由 R44 上拉维持高,不会误复位 ESC。 */
constexpr uint32_t CONFIG_ESC_NRST_PORT = GPIOB;
constexpr uint32_t CONFIG_ESC_NRST_PIN = GPIO_PIN_10;
constexpr uint32_t CONFIG_ESC_NRST_ASSERT_MS = 30U; /* 低脉宽,同时覆盖 tpurstd 25ms 与 trstia 200µs */
constexpr uint32_t CONFIG_ESC_HBI_POLL_TIMEOUT_MS = 300U; /* RST# 释放后等待 ESC 启动/EEPROM 加载 */
constexpr uint32_t CONFIG_ESC_HBI_POLL_STEP_MS = 5U;
/* ---------- EXMC 数据/控制线引脚(GD32E508 标准映射) ---------- */
constexpr uint32_t CONFIG_EXMC_D0_PORT = GPIOD; constexpr uint32_t CONFIG_EXMC_D0_PIN = GPIO_PIN_14;
constexpr uint32_t CONFIG_EXMC_D1_PORT = GPIOD; constexpr uint32_t CONFIG_EXMC_D1_PIN = GPIO_PIN_15;
@@ -357,10 +367,13 @@ constexpr uint32_t CONFIG_EXMC_D15_PORT = GPIOD; constexpr uint32_t CONFIG_EXMC
constexpr uint32_t CONFIG_EXMC_A16_PORT = GPIOD; constexpr uint32_t CONFIG_EXMC_A16_PIN = GPIO_PIN_11;
/* A17 (PD12) 用于 HBI Indexed Mode 访问 HBI_DATA_0 寄存器,已将 LAN9252 A2 (Pin 29) 接到 PD12。
* 注意 LAN9252 引脚顺序:Pin25=A1, Pin26=A3, Pin27=A4, Pin28=CS, Pin29=A2。
* A2 是 IDX/DATA 选择位,必须接到 PD12 才能访问 DATA 寄存器,EEPROM 烧录功能可用。 */
* A2 是 IDX/DATA 选择位,必须接到 PD12 才能访问 DATA 寄存器,EEPROM 烧录功能可用。
* 注意 EXMC 16-bit 模式地址左移 1 位(用户手册 p869):A16(PD11)=CPU 偏移 0x20000、
* A17(PD12)=CPU 偏移 0x40000,HBI_DATA_0 访问偏移见 esc_lan9252.cpp。 */
constexpr uint32_t CONFIG_EXMC_A17_PORT = GPIOD; constexpr uint32_t CONFIG_EXMC_A17_PIN = GPIO_PIN_12;
constexpr uint32_t CONFIG_EXMC_NOE_PORT = GPIOD; constexpr uint32_t CONFIG_EXMC_NOE_PIN = GPIO_PIN_4;
constexpr uint32_t CONFIG_EXMC_NWE_PORT = GPIOD; constexpr uint32_t CONFIG_EXMC_NWE_PIN = GPIO_PIN_5;
constexpr uint32_t CONFIG_EXMC_NE1_PORT = GPIOD; constexpr uint32_t CONFIG_EXMC_NE1_PIN = GPIO_PIN_7;
/* LQFP100 只有 NE0(PD7) 一个 NOR/SRAM 片选,归 Region0(0x60000000);命名沿用硬件真值 NE0。 */
constexpr uint32_t CONFIG_EXMC_NE0_PORT = GPIOD; constexpr uint32_t CONFIG_EXMC_NE0_PIN = GPIO_PIN_7;
#endif /* SYS_CONFIG_H */
+9 -1
View File
@@ -116,6 +116,9 @@ void AppInitializer::init()
gpio_bit_set(CONFIG_ESP32_RESET_PORT, CONFIG_ESP32_RESET_PIN);
gpio_init(CONFIG_ESP32_RESET_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, CONFIG_ESP32_RESET_PIN);
mark(kEsp32Hold);
/* ESP32 EN 自检:日志里能直接看出是上电即拉高,还是被外部钳住 */
APP_LOGI("[APP] ESP32_EN PC9=%d (1=released)\r\n",
(int)gpio_input_bit_get(CONFIG_ESP32_RESET_PORT, CONFIG_ESP32_RESET_PIN));
Usart0::configurePins();
Usart0::init();
@@ -144,8 +147,13 @@ void AppInitializer::init()
mark(kScheduler);
/* ---- EtherCAT: EXMC 总线探活 → SSC 协议栈初始化 → SYNC0/IRQ 中断使能 ----
* 1.5.27:改经 EthercatSlave::init()(内部调用 EscLan9252::init 并记录
* chipId/AL 状态诊断,此前该函数无调用点、s_escReady 恒为 false)。
* 门控用 EscLan9252::isBusReady()(BYTE_TEST 通过)而非 isEscReady():
* 冷启动时 AL=INIT,SSC 必须照常启动并等待主站配置。
* EEPROM 校验/烧录延迟到主循环执行,避免阻塞 init(烧录需 ~20s)。 */
if (EscLan9252::init()) {
EthercatSlave::init();
if (EscLan9252::isBusReady()) {
const uint16_t sscResult = MainInit();
if (sscResult == 0U) {
mark(kEthercat);
+81 -69
View File
@@ -16,9 +16,8 @@
#include "sys/task_manager.h"
#include "sys/task_runner.h"
#include "comm/ethercat_slave.h"
#include "comm/esc_eeprom.h"
#include "comm/ethercat_sync.h"
#include "comm/esc_exmc_bus.h"
#include "comm/ssc/port/eeprom_image.h"
extern "C" {
void MainLoop(void);
@@ -272,6 +271,68 @@ bool TaskRunner::copyAdcSample(Adc::Sample *out)
return true;
}
/* SSC 侧 AL 诊断快照(dc_app.c): [19:16]=AL 状态 [31:24]=AL 错误码 [15:0]=AL 事件寄存器 */
extern "C" uint32_t EcatDbg_ReadAlDiag(void);
/**
* @brief 1.5.32 ECAT 心跳:主循环存活证明 + ESC AL 状态/事件寄存器快照。
* @note 仅在同步 ISR 激活(SSC 在跑)时打印。心跳停 = 主循环卡死;
* al=0x1 且 evt bit0 长期置位 = SSC 没处理 AL 请求;
* al 与主站读到的不一致 = ESC 写回路径问题。
*/
static void ethercatAlHeartbeat()
{
if (!EthercatSync::isActive()) {
return;
}
const uint32_t alDiag = EcatDbg_ReadAlDiag();
printf("[ECAT][HB] al=0x%lX code=0x%02lX evt=0x%04lX (uptime=%lus)\r\n",
(unsigned long)((alDiag >> 16) & 0x0FU),
(unsigned long)((alDiag >> 24) & 0xFFU),
(unsigned long)(alDiag & 0xFFFFU),
(unsigned long)g_app_uptime_sec);
}
/**
* @brief 打印 EtherCAT 同步中断计数与速率(DC 通路验证)。
* @note 主站启用 DC(SYNC0 周期 T)后,sync0 速率应稳定 ≈ 1e6/T_us 次/秒;
* free-run 模式下 SYNC0 引脚无脉冲,三个计数器恒为 0(本函数不打印)。
* 仅在有增量时输出,避免未接主站时刷屏。
*/
static void ethercatSyncCounterPrint()
{
static uint32_t s_prevSync0 = 0U;
static uint32_t s_prevSync1 = 0U;
static uint32_t s_prevEscIrq = 0U;
static uint32_t s_prevSec = 0U;
const uint32_t sync0 = EthercatSync::getSync0Count();
const uint32_t sync1 = EthercatSync::getSync1Count();
const uint32_t escIrq = EthercatSync::getEscIrqCount();
const uint32_t d0 = sync0 - s_prevSync0; /* 无符号回绕自然成立 */
const uint32_t d1 = sync1 - s_prevSync1;
const uint32_t di = escIrq - s_prevEscIrq;
const uint32_t now = g_app_uptime_sec;
const uint32_t elapsed = (now > s_prevSec) ? (now - s_prevSec) : 1U;
s_prevSync0 = sync0;
s_prevSync1 = sync1;
s_prevEscIrq = escIrq;
s_prevSec = now;
if (d0 == 0U && d1 == 0U && di == 0U) {
return; /* 未接主站或 free-run:无脉冲,静默 */
}
printf("[ECAT][SYNC] sync0=%lu(+%lu, %lu/s) sync1=%lu(+%lu) escirq=%lu(+%lu) dt=%lus\r\n",
(unsigned long)sync0, (unsigned long)d0, (unsigned long)(d0 / elapsed),
(unsigned long)sync1, (unsigned long)d1,
(unsigned long)escIrq, (unsigned long)di,
(unsigned long)elapsed);
}
/**
* @brief 5s 诊断任务:默认仅状态变化/错误增量;可选全量 UART 摘要。
* @note CONFIG_UART_TEMP_PERIODIC_PRINT=1 时打印 ADC/CAN/ECAT 全量行(调试用)。
@@ -326,19 +387,16 @@ void TaskRunner::taskDiagnosticPrint()
#endif
if (EthercatSlave::isEscReady()) {
uint32_t maxCyc = 0U, avgCyc = 0U, cnt = 0U;
EthercatSlave::getIsrStats(&maxCyc, &avgCyc, &cnt);
/* 180MHz: cycles / 180 = µs;用 *1000/180 获得亚微秒精度避免浮点 */
const uint32_t maxUs_x1000 = maxCyc * 1000U / 180U;
const uint32_t avgUs_x1000 = avgCyc * 1000U / 180U;
printf("[ECAT] periodicIsr cnt=%lu max=%lu.%03luus avg=%lu.%03luus\r\n",
(unsigned long)cnt,
(unsigned long)(maxUs_x1000 / 1000U), (unsigned long)(maxUs_x1000 % 1000U),
(unsigned long)(avgUs_x1000 / 1000U), (unsigned long)(avgUs_x1000 % 1000U));
/* 1.5.27:periodicIsr 已删除(死代码,无调用点),PDO 交换由 SSC
* Sync0_Isr → ECAT_Application → dc_app.c APPL_* 完成。 */
printf("[ECAT] ESC ready (chip id=0x%08lX), PDO via SSC Sync0_Isr\r\n",
(unsigned long)EthercatSlave::getChipId());
} else {
printf("[ECAT] ESC not detected (chip id=0x%08lX), EtherCAT disabled\r\n",
(unsigned long)EthercatSlave::getChipId());
}
ethercatSyncCounterPrint();
ethercatAlHeartbeat();
}
#else
/* ---- 默认静默路径:仅错误增量 / 状态变化,无 uptime 心跳 ---- */
@@ -351,7 +409,6 @@ void TaskRunner::taskDiagnosticPrint()
static uint8_t s_prev_adc_valid = 0xFFU; /* 0xFF=尚未采样 */
static bool s_prev_esc_ready = false;
static bool s_esc_ready_inited = false;
static uint32_t s_prev_ecat_max_cyc = 0U;
const uint32_t rx_drop = diag->rx_drop_count;
const uint32_t rx_full = diag->rx_fifo_full_count;
@@ -403,39 +460,14 @@ void TaskRunner::taskDiagnosticPrint()
(unsigned long)g_app_uptime_sec);
s_prev_esc_ready = esc_ready;
}
if (esc_ready) {
uint32_t maxCyc = 0U, avgCyc = 0U, cnt = 0U;
EthercatSlave::getIsrStats(&maxCyc, &avgCyc, &cnt);
/* 阈值单位 µs → CPU 周期(180 MHz) */
const uint32_t threshCyc = CONFIG_ETHERCAT_ISR_MAX_US_THRESHOLD * 180U;
if (maxCyc > threshCyc && maxCyc > s_prev_ecat_max_cyc) {
const uint32_t maxUs_x1000 = maxCyc * 1000U / 180U;
printf("[ECAT] ISR max over threshold: max=%lu.%03luus thr=%luus cnt=%lu (uptime=%lus)\r\n",
(unsigned long)(maxUs_x1000 / 1000U),
(unsigned long)(maxUs_x1000 % 1000U),
(unsigned long)CONFIG_ETHERCAT_ISR_MAX_US_THRESHOLD,
(unsigned long)cnt,
(unsigned long)g_app_uptime_sec);
s_prev_ecat_max_cyc = maxCyc;
}
}
/* 1.5.27:periodicIsr ISR 统计随死代码一并删除 */
/* DC SYNC0 通路验证:仅在有脉冲增量时打印(未接主站时静默)。 */
ethercatSyncCounterPrint();
ethercatAlHeartbeat();
}
#endif
}
/**
* @brief 执行 EtherCAT 周期/事件处理(非实时应用层 PDO 映射)。
* @param[in] 无。
* @param[out] 无。
* @retval 无返回值。
* @note 由周期 ISR(EXTI0 SYNC0)或 ESC 事件 ISR(EXTI1 IRQ)置位 TASK_ETHERCAT_PROCESS。
*/
void TaskRunner::taskEthercatProcess()
{
EthercatSlave::process();
}
/**
* @brief 初始化任务执行器运行时上下文。
* @param[in] 无。
@@ -468,41 +500,21 @@ void TaskRunner::runPending()
{
Watchdog::feed();
/* === HBI 周期诊断:每 20 秒重新跑一次 EXMC/HBI 探活,方便热插拔/焊接后观察 === */
/* === HBI 周期诊断:每 20 秒重新跑一次 EXMC/HBI 探活,方便热插拔/焊接后观察 ===
* 1.5.27:EtherCAT 同步 ISR 激活后停止(diagDump 会把 EXMC 引脚切成 GPIO,
* 拆毁运行中的总线;诊断的 bit-bang 也与 HBI 事务互斥冲突)。 */
static uint32_t s_lastDiagSec = 0xFFFFFFFFU;
if (g_app_uptime_sec >= s_lastDiagSec + 20U || s_lastDiagSec == 0xFFFFFFFFU) {
if (!EthercatSync::isActive()
&& (g_app_uptime_sec >= s_lastDiagSec + 20U || s_lastDiagSec == 0xFFFFFFFFU)) {
s_lastDiagSec = g_app_uptime_sec;
printf("[ECAT][DIAG] === 20s periodic HBI probe (uptime=%lus) ===\r\n",
(unsigned long)g_app_uptime_sec);
EscExmcBus::diagDump();
}
/* 延迟 EEPROM 烧录:init 不阻塞,主循环第一轮执行一次。
* 校验编译期镜像与 AT24C32 内容,不匹配则全量烧录(~20s,期间看门狗正常喂)。 */
static bool s_eepromDone = false;
if (!s_eepromDone) {
s_eepromDone = true;
if (EscEeprom::init()) {
if (EscEeprom::verifyEsi(ESI_EEPROM_IMAGE, ESI_EEPROM_SIZE)) {
printf("[ECAT][EEPROM] content OK, skip burn\r\n");
} else {
printf("[ECAT][EEPROM] content mismatch, burning ESI (%u bytes)...\r\n",
(unsigned)ESI_EEPROM_SIZE);
if (EscEeprom::writeEsi(ESI_EEPROM_IMAGE, ESI_EEPROM_SIZE)) {
if (EscEeprom::verifyEsi(ESI_EEPROM_IMAGE, ESI_EEPROM_SIZE)) {
EscEeprom::reload();
printf("[ECAT][EEPROM] burn+verify OK, reload issued\r\n");
} else {
printf("[ECAT][EEPROM] post-burn verify FAIL\r\n");
}
} else {
printf("[ECAT][EEPROM] burn FAIL\r\n");
}
}
} else {
printf("[ECAT][EEPROM] init FAIL (PDI control not acquired)\r\n");
}
}
/* 延迟 EEPROM 烧录已删除(1.5.29):ESI 镜像改由 EtherCAT 主站侧刷写
* (tools/ecat/ecat_flash_eeprom.py 经 ESC 0x0500 EEPROM 接口),
* 固件不再承担烧录/校验职责。 */
/* poll() 含按铃超时看门狗(cancelRing),必须每轮无条件执行。
* 主动推送已随 2026-08 请求驱动改造移除,此处仅需消费请求响应的按铃。 */
-2
View File
@@ -52,8 +52,6 @@ private:
static void taskHeartbeat();
/** @brief 诊断打印任务。 */
static void taskDiagnosticPrint();
/** @brief EtherCAT 周期/事件处理(非实时应用层 PDO 映射)。 */
static void taskEthercatProcess();
};
#endif /* SYS_TASK_RUNNER_H */