fix(esc_lan9252): 修复LAN9252 HBI访问模型和IRQ输出使能问题

- 修正HBI访问模型:将ESC核心CSR(0x0000-0x0FFF)改为通过ECAT_CSR_CMD/DATA
  间接端口访问,解决此前直接寻址导致核心寄存器恒读0/写丢弃的问题

- 新增csrRead/csrWrite/pramRead/pramWrite接口,正确实现LAN9252访问端口操作

- 添加PDI就绪检测:等待DL_STATUS bit0置位确认EEPROM加载完成和EtherCAT核心使能

- 实现IRQ引脚输出使能:配置IRQ_CFG和INT_EN寄存器,使EtherCAT事件能到达PB1,
  解决PDI_Isr未触发导致SAFEOP->OP无限挂起的问题

- 为ESC_EXMC硬件诊断添加CONFIG_ESC_EXMC_DIAG门控,默认关闭避免影响正常运行

- 修正system_gd32e50x.c中HXTAL故障诊断的寄存器偏移和位设置错
This commit is contained in:
cbb
2026-09-02 02:38:35 +08:00
parent cfe7725b26
commit 44d407390b
29 changed files with 1178 additions and 292 deletions
+47 -40
View File
@@ -399,19 +399,24 @@ void CanFd::initChannelHardware(uint8_t i)
const uint8_t rxLevelAfter = (gpio_input_bit_get(ch.rxPort, ch.rxPin) != RESET) ? 1U : 0U;
const uint32_t tecAfterExit = (errAfterExit >> 16) & 0xFFU;
const uint32_t recAfterExit = (errAfterExit >> 24) & 0xFFU;
CAN_LOGI("[CAN-DIAG] CH%u init_nom=%u init_fd=%u exit_ok=%u wait=%lu rx_before=%u rx_after=%u stb=%u STAT=0x%08lX ERR=0x%08lX TEC=%lu REC=%lu\r\n",
static_cast<unsigned>(i),
nominalOk ? 1U : 0U,
fdOk ? 1U : 0U,
((statAfterExit & CAN_STAT_IWS) == 0U) ? 1U : 0U,
static_cast<unsigned long>(exitWait),
static_cast<unsigned>(rxLevelBefore),
static_cast<unsigned>(rxLevelAfter),
static_cast<unsigned>(stbLevel),
static_cast<unsigned long>(statAfterExit),
static_cast<unsigned long>(errAfterExit),
static_cast<unsigned long>(tecAfterExit),
static_cast<unsigned long>(recAfterExit));
/* 正常上电静默:只在本端控制器初始化失败(can_init/can_fd_init 失败或卡 init mode)
* 时打印一行诊断。TEC/REC 属总线侧状态,未接从站时浮空噪声会累积,不作为打印条件。 */
const bool exitedInitMode = ((statAfterExit & CAN_STAT_IWS) == 0U);
if (!nominalOk || !fdOk || !exitedInitMode) {
LOG_ERR("[CAN-DIAG] CH%u init_nom=%u init_fd=%u exit_ok=%u wait=%lu rx_before=%u rx_after=%u stb=%u STAT=0x%08lX ERR=0x%08lX TEC=%lu REC=%lu\r\n",
static_cast<unsigned>(i),
nominalOk ? 1U : 0U,
fdOk ? 1U : 0U,
exitedInitMode ? 1U : 0U,
static_cast<unsigned long>(exitWait),
static_cast<unsigned>(rxLevelBefore),
static_cast<unsigned>(rxLevelAfter),
static_cast<unsigned>(stbLevel),
static_cast<unsigned long>(statAfterExit),
static_cast<unsigned long>(errAfterExit),
static_cast<unsigned long>(tecAfterExit),
static_cast<unsigned long>(recAfterExit));
}
CAN_TSTAT(ch.canPeriph) = CAN_TSTAT_MTF0 | CAN_TSTAT_MTF1 | CAN_TSTAT_MTF2;
can_interrupt_enable(ch.canPeriph, CAN_INT_TME | CAN_INT_RFNE0 | CAN_INT_RFF0 | CAN_INT_RFO0);
@@ -782,13 +787,16 @@ void CanFd::init()
}
/**
* @brief L0 轻量自检:无总线发帧,仅校验使能通道硬件与收发器状态。
* @brief L0 轻量自检:无总线发帧,仅校验使能通道控制器自身状态(GD32 侧故障)。
* @note 1.5.35:不再检查 BUS_OFF/TEC/REC——未接从站的通道 RX 浮空噪声会累积 REC,
* 「没接设备」不等于错误;总线侧健康由 0xC1 反馈帧运行期上报。
*/
bool CanFd::selfTestL0()
bool CanFd::selfTestL0(uint8_t *fault_code, uint8_t *fault_channel)
{
constexpr uint32_t kTecRecLimit = 16U;
bool anyEnabled = false;
bool allOk = true;
uint8_t firstCode = kSelfTestOk;
uint8_t firstCh = 0U;
for (uint8_t i = 0U; i < static_cast<uint8_t>(kChannelCount); ++i) {
if (!kChannelEnabled[i]) {
@@ -796,38 +804,37 @@ bool CanFd::selfTestL0()
}
anyEnabled = true;
const auto &ch = kChannels[i];
uint8_t code = kSelfTestOk;
if (!s_channelHwOk[i]) {
allOk = false;
continue;
code = kSelfTestHwInit;
} else if ((CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) != 0U) {
/* 仍停在初始化模式 */
code = kSelfTestStuckInit;
} else if (gpio_output_bit_get(ch.slpPort, ch.slpPin) != RESET) {
/* STB=0 为 Normal;输出寄存器回读确认配置生效 */
code = kSelfTestStbLevel;
}
/* 仍停在初始化模式 */
if ((CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) != 0U) {
if (code != kSelfTestOk) {
allOk = false;
continue;
}
/* STB=0 为 Normal;高电平视为仍待机 */
if (gpio_output_bit_get(ch.slpPort, ch.slpPin) != RESET) {
allOk = false;
continue;
}
const uint32_t errReg = CAN_ERR(ch.canPeriph);
if ((errReg & CAN_ERR_BOERR) != 0U) {
allOk = false;
continue;
}
const uint32_t tec = (errReg >> 16) & 0xFFU;
const uint32_t rec = (errReg >> 24) & 0xFFU;
if (tec > kTecRecLimit || rec > kTecRecLimit) {
allOk = false;
continue;
if (firstCode == kSelfTestOk) {
firstCode = code;
firstCh = i;
}
LOG_ERR("[CAN] L0 selftest CH%u FAIL code=%u (STAT=0x%08lX ERR=0x%08lX)\r\n",
static_cast<unsigned>(i), static_cast<unsigned>(code),
static_cast<unsigned long>(CAN_STAT(ch.canPeriph)),
static_cast<unsigned long>(CAN_ERR(ch.canPeriph)));
}
}
if (fault_code != nullptr) {
*fault_code = firstCode;
}
if (fault_channel != nullptr) {
*fault_channel = firstCh;
}
return anyEnabled && allOk;
}