Refactor and clean up codebase

- Removed unused constants and type aliases in app_spi_command_defs.h and temp_sensor.h.
- Simplified ISpiCommandHandler destructor to default.
- Eliminated redundant methods and comments in temp_sensor and usart0 files.
- Consolidated writeU32Le function to app_spi_command_defs.h for reuse.
- Updated comments for clarity and accuracy in task_manager.h and task_runner.cpp.
- Removed hardfault.h as it contained no declarations.
- Cleaned up CANFD and watchdog implementations by removing dead code and unnecessary comments.
- Updated version numbers in config.h to reflect recent changes.
- Enhanced error handling and diagnostics in hardfault handling.
This commit is contained in:
cbb
2026-07-15 02:49:37 +08:00
parent a52d94687b
commit 76da7a3dd6
37 changed files with 1401 additions and 1955 deletions
+153 -251
View File
@@ -12,6 +12,12 @@
#include <cstring>
namespace {
/* 纯软件延时循环(不依赖 SysTick,可在任何中断状态下使用) */
static inline void spinDelay(uint32_t loops) {
for (volatile uint32_t d = 0; d < loops; ++d) { }
}
struct CanChannelConfig {
uint32_t canPeriph;
rcu_periph_enum canRcu;
@@ -91,7 +97,7 @@ static CanSelfTestResult runSelfTestFrame(uint8_t channelIndex, uint32_t extId,
result.mailbox = can_message_transmit(canPeriph, &tx_msg);
result.txReq = (result.mailbox != CAN_NOMAILBOX);
for (volatile uint32_t dly = 0; dly < 40000U; ++dly) { }
spinDelay(40000U);
if (result.txReq) {
result.txState = static_cast<uint8_t>(can_transmit_states(canPeriph, result.mailbox));
@@ -117,21 +123,21 @@ static void hardResetCan(uint32_t canPeriph, rcu_periph_enum canRcu)
{
/* 1. 触发 SWRST 软件复位 */
CAN_CTL(canPeriph) |= CAN_CTL_SWRST;
for (volatile uint32_t d = 0; d < 100000U; ++d) {}
spinDelay(100000U);
/* 2. 确认 SWRST 已被硬件自动清零;若未清零则强制写 0 并等待 */
if (CAN_CTL(canPeriph) & CAN_CTL_SWRST) {
CAN_CTL(canPeriph) &= ~CAN_CTL_SWRST;
for (volatile uint32_t d = 0; d < 50000U; ++d) {}
spinDelay(50000U);
}
/* 3. 关 RCU 时钟,等待外设域完全放电 */
rcu_periph_clock_disable(canRcu);
for (volatile uint32_t d = 0; d < 200000U; ++d) {} /* ~1.1ms @180MHz */
spinDelay(200000U); /* ~1.1ms @180MHz */
/* 4. 重新开时钟,等待外设域上电稳定 */
rcu_periph_clock_enable(canRcu);
for (volatile uint32_t d = 0; d < 200000U; ++d) {} /* ~1.1ms @180MHz */
spinDelay(200000U); /* ~1.1ms @180MHz */
/* 5. can_deinit() 走标准固件库复位流程 */
can_deinit(canPeriph);
@@ -303,123 +309,110 @@ bool CanFd::initFdMode(uint32_t canPeriph)
#endif
}
/**
* @brief 初始化三路 CANFD 控制器、过滤器、中断与软件队列。
* @param[in] 无。
* @param[out] 无。
* @retval 无返回值。
* @note 初始化后默认将三路 TCAN1057A 收发器置为 Normal,并使能 FIFO0 的非空/满/overfull 中断统计。
*/
void CanFd::init()
/** @brief 打印 SYS/APB1 时钟与目标波特率。 */
void CanFd::printClockInfo()
{
s_diag = {};
s_nextConsumeChannel = 0U;
s_mode = Mode::kModeAllPass;
for (size_t i = 0; i < kChannelCount; ++i) {
s_channelStats[i] = {};
s_feedback[i] = {};
}
s_feedbackSeq = 0U;
initGpio();
printf("[CAN-CLOCK] SYS=%luHz APB1=%luHz nominal=1Mbps data=2Mbps\r\n",
static_cast<unsigned long>(SystemCoreClock),
static_cast<unsigned long>(rcu_clock_freq_get(CK_APB1)));
}
for(size_t i = 0; i < kChannelCount; ++i) {
const auto &ch = kChannels[i];
if (!kChannelEnabled[i]) {
printf("[CAN] CH%u DISABLED, skip init\r\n", static_cast<unsigned>(i));
continue;
}
rcu_periph_clock_enable(ch.canRcu);
gpio_bit_reset(ch.slpPort, ch.slpPin); /* STB=0 -> Normal */
const uint8_t rxLevelBefore = (gpio_input_bit_get(ch.rxPort, ch.rxPin) != RESET) ? 1U : 0U;
const uint8_t stbLevel = (gpio_output_bit_get(ch.slpPort, ch.slpPin) != RESET) ? 1U : 0U;
/** @brief 单通道硬件初始化(hardResetCan+重试+退出init mode+中断使能+RX队列清零)。 */
void CanFd::initChannelHardware(uint8_t i)
{
const auto &ch = kChannels[i];
if (!kChannelEnabled[i]) {
printf("[CAN] CH%u DISABLED, skip init\r\n", static_cast<unsigned>(i));
return;
}
rcu_periph_clock_enable(ch.canRcu);
gpio_bit_reset(ch.slpPort, ch.slpPin); /* STB=0 -> Normal */
const uint8_t rxLevelBefore = (gpio_input_bit_get(ch.rxPort, ch.rxPin) != RESET) ? 1U : 0U;
const uint8_t stbLevel = (gpio_output_bit_get(ch.slpPort, ch.slpPin) != RESET) ? 1U : 0U;
/* 强制复位 + 重试机制:使用 hardResetCan 完整电源周期解决 CAN1 卡死问题 */
bool nominalOk = false;
bool fdOk = false;
for (uint8_t retry = 0U; retry < 5U; ++retry) {
hardResetCan(ch.canPeriph, ch.canRcu);
/* 强制复位 + 重试机制:使用 hardResetCan 完整电源周期解决 CAN1 卡死问题 */
bool nominalOk = false;
bool fdOk = false;
for (uint8_t retry = 0U; retry < 5U; ++retry) {
hardResetCan(ch.canPeriph, ch.canRcu);
nominalOk = initNominalTiming(ch.canPeriph);
fdOk = initFdMode(ch.canPeriph);
if (nominalOk && fdOk) {
break; /* 初始化成功,无需重试 */
}
/* can_init 失败后外设可能卡在 init mode,先强制退出让下次重试从干净状态开始 */
CAN_CTL(ch.canPeriph) &= ~CAN_CTL_IWMOD;
for (volatile uint32_t d = 0; d < 50000U; ++d) {
if ((CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) == 0U) break;
}
printf("[CAN-WARN] CH%u init failed (nom=%u fd=%u STAT=0x%08lX), retry %u/5\r\n",
static_cast<unsigned>(i),
nominalOk ? 1U : 0U, fdOk ? 1U : 0U,
static_cast<unsigned long>(CAN_STAT(ch.canPeriph)),
static_cast<unsigned>(retry + 1U));
nominalOk = initNominalTiming(ch.canPeriph);
fdOk = initFdMode(ch.canPeriph);
if (nominalOk && fdOk) {
break; /* 初始化成功,无需重试 */
}
/* 滤波器配置延迟到循环结束后统一执行:
* CAN1 的 hardResetCan 含 SWRST,会清零 CAN0/CAN1 共享滤波器寄存器,
* 若在循环内配 CAN0 filter 后再做 CAN1 hardReset,CAN0 filter 会被破坏。 */
/* 退出 init mode,确保进入 NORMAL 工作模式 */
/* can_init 失败后外设可能卡在 init mode,先强制退出让下次重试从干净状态开始 */
CAN_CTL(ch.canPeriph) &= ~CAN_CTL_IWMOD;
uint32_t exitWait = 0U;
for (; exitWait < 200000U; ++exitWait) {
if ((CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) == 0U) {
break;
}
for (volatile uint32_t d = 0; d < 50000U; ++d) {
if ((CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) == 0U) break;
}
/* 兜底:若仍然卡在 init mode,做一次额外的 SWRST + 强制退出 */
if (CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) {
CAN_CTL(ch.canPeriph) |= CAN_CTL_SWRST;
for (volatile uint32_t d = 0; d < 50000U; ++d) {}
CAN_CTL(ch.canPeriph) &= ~(CAN_CTL_SWRST | CAN_CTL_IWMOD);
for (volatile uint32_t d = 0; d < 200000U; ++d) {
if ((CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) == 0U) break;
}
printf("[CAN-WARN] CH%u needed extra SWRST to exit init mode (STAT=0x%08lX)\r\n",
static_cast<unsigned>(i),
static_cast<unsigned long>(CAN_STAT(ch.canPeriph)));
}
const uint32_t statAfterExit = CAN_STAT(ch.canPeriph);
const uint32_t errAfterExit = CAN_ERR(ch.canPeriph);
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;
printf("[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",
printf("[CAN-WARN] CH%u init failed (nom=%u fd=%u STAT=0x%08lX), retry %u/5\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_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);
nvic_irq_enable(ch.txIrq, CONFIG_IRQ_PREEMPT_CAN, static_cast<uint8_t>(i));
nvic_irq_enable(ch.rx0Irq, CONFIG_IRQ_PREEMPT_CAN, static_cast<uint8_t>(i));
s_rxQueues[i].head = 0U;
s_rxQueues[i].tail = 0U;
s_rxQueues[i].count = 0U;
nominalOk ? 1U : 0U, fdOk ? 1U : 0U,
static_cast<unsigned long>(CAN_STAT(ch.canPeriph)),
static_cast<unsigned>(retry + 1U));
}
s_nextConsumeChannel = 0U;
/* 滤波器配置延迟到循环结束后统一执行:
* CAN1 的 hardResetCan 含 SWRST,会清零 CAN0/CAN1 共享滤波器寄存器,
* 若在循环内配 CAN0 filter 后再做 CAN1 hardReset,CAN0 filter 会被破坏。 */
/* 退出 init mode,确保进入 NORMAL 工作模式 */
CAN_CTL(ch.canPeriph) &= ~CAN_CTL_IWMOD;
uint32_t exitWait = 0U;
for (; exitWait < 200000U; ++exitWait) {
if ((CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) == 0U) {
break;
}
}
/* 兜底:若仍然卡在 init mode,做一次额外的 SWRST + 强制退出 */
if (CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) {
CAN_CTL(ch.canPeriph) |= CAN_CTL_SWRST;
spinDelay(50000U);
CAN_CTL(ch.canPeriph) &= ~(CAN_CTL_SWRST | CAN_CTL_IWMOD);
for (volatile uint32_t d = 0; d < 200000U; ++d) {
if ((CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) == 0U) break;
}
printf("[CAN-WARN] CH%u needed extra SWRST to exit init mode (STAT=0x%08lX)\r\n",
static_cast<unsigned>(i),
static_cast<unsigned long>(CAN_STAT(ch.canPeriph)));
}
const uint32_t statAfterExit = CAN_STAT(ch.canPeriph);
const uint32_t errAfterExit = CAN_ERR(ch.canPeriph);
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;
printf("[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_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);
nvic_irq_enable(ch.txIrq, CONFIG_IRQ_PREEMPT_CAN, static_cast<uint8_t>(i));
nvic_irq_enable(ch.rx0Irq, CONFIG_IRQ_PREEMPT_CAN, static_cast<uint8_t>(i));
s_rxQueues[i].head = 0U;
s_rxQueues[i].tail = 0U;
s_rxQueues[i].count = 0U;
}
/** @brief 统一配置三路滤波器(HBC1F + per-channel filter)。 */
void CanFd::configureAllFilters()
{
/* ===== 统一配置滤波器(必须在所有 hardResetCan 完成之后) =====
* CAN1 hardResetCan 的 SWRST 会清零 CAN0/CAN1 共享滤波器寄存器域。
* 若在循环内先配 CAN0 filter、后做 CAN1 hardReset,CAN0 的 filter 0 会被
@@ -433,7 +426,11 @@ void CanFd::init()
printf("[CAN] filters configured post-init: HBC1F=%lu FW=0x%08lX\r\n",
static_cast<unsigned long>((CAN_FCTL(CAN0) >> 8) & 0x3FU),
static_cast<unsigned long>(CAN_FW(CAN0)));
}
/** @brief 打印初始化结果汇总(BT/DBT/滤波器状态)。 */
void CanFd::printInitResult()
{
/* ===== 初始化结果汇总 ===== */
printf("=== CAN INIT RESULT ===\r\n");
for (size_t i = 0; i < kChannelCount; ++i) {
@@ -462,7 +459,11 @@ void CanFd::init()
static_cast<unsigned long>(fw2),
static_cast<unsigned long>((fw2 >> 2) & 1U));
}
}
/** @brief 打印初始化后错误计数器快照(TEC/REC/BOFF/EPV/EW)。 */
void CanFd::printErrorState()
{
/* ===== 初始化后错误计数器快照(不发帧,避免启动时累积 TEC)===== */
printf("=== CAN INIT ERR STATE ===\r\n");
for (size_t i = 0; i < kChannelCount; ++i) {
@@ -479,7 +480,11 @@ void CanFd::init()
(err & CAN_ERR_PERR) ? 1U : 0U, /* EPV bit1 */
(err & CAN_ERR_WERR) ? 1U : 0U); /* EWARN bit0 */
}
}
/** @brief 物理总线自测(受 CONFIG_CAN_STARTUP_BUS_TEST_ENABLE 控制)。 */
void CanFd::runSelfTest()
{
/* ===== Self-test (NORMAL mode, 发到物理总线测 ACK) ===== */
#if (CONFIG_CAN_STARTUP_BUS_TEST_ENABLE != 0)
printf("=== CAN SELF-TEST (normal mode) ===\r\n");
@@ -514,8 +519,11 @@ void CanFd::init()
#else
printf("=== CAN SELF-TEST SKIPPED (CONFIG_CAN_STARTUP_BUS_TEST_ENABLE=0) ===\r\n");
#endif
}
/** @brief 内部回环测试(受 CONFIG_CAN_STARTUP_LOOPBACK_TEST_ENABLE 控制)。 */
void CanFd::runLoopbackTest()
{
/* ===== Loopback 回环测试 (内部 TX→RX,不走物理总线) ===== */
#if (CONFIG_CAN_STARTUP_LOOPBACK_TEST_ENABLE != 0)
printf("=== CAN LOOPBACK (internal) ===\r\n");
@@ -658,7 +666,11 @@ void CanFd::init()
#else
printf("=== CAN LOOPBACK SKIPPED (CONFIG_CAN_STARTUP_LOOPBACK_TEST_ENABLE=0) ===\r\n");
#endif
}
/** @brief 全寄存器快照转储(CTL/STAT/BT/DBT/ERR/INTEN/FCTL/FW/RFL0)。 */
void CanFd::dumpRegisters()
{
/* ===== 初始化后全寄存器快照:诊断 CAN0/CAN1 不收帧 ===== */
printf("=== POST-INIT FULL REG DUMP ===\r\n");
for (size_t i = 0; i < kChannelCount; ++i) {
@@ -702,6 +714,40 @@ void CanFd::init()
printf("===============================\r\n");
}
/**
* @brief 初始化三路 CANFD 控制器、过滤器、中断与软件队列。
* @param[in] 无。
* @param[out] 无。
* @retval 无返回值。
* @note 初始化后默认将三路 TCAN1057A 收发器置为 Normal,并使能 FIFO0 的非空/满/overfull 中断统计。
*/
void CanFd::init()
{
s_diag = {};
s_nextConsumeChannel = 0U;
s_mode = Mode::kModeAllPass;
for (size_t i = 0; i < kChannelCount; ++i) {
s_channelStats[i] = {};
s_feedback[i] = {};
}
s_feedbackSeq = 0U;
initGpio();
printClockInfo();
for (uint8_t i = 0; i < kChannelCount; ++i) {
initChannelHardware(i);
}
s_nextConsumeChannel = 0U;
configureAllFilters();
printInitResult();
printErrorState();
runSelfTest();
runLoopbackTest();
dumpRegisters();
}
/**
* @brief 切换 CANFD 接收过滤模式。
* @param[in] mode 目标过滤模式。
@@ -725,18 +771,6 @@ CanFd::Mode CanFd::mode()
return s_mode;
}
/**
* @brief 执行兼容保留的 CAN 轮询入口。
* @param[in] 无。
* @param[out] 无。
* @retval 无返回值。
* @note 当前三路接收均由 RX0 中断驱动,该函数仅保留旧调用兼容性。
*/
void CanFd::poll()
{
/* 兼容保留:三通道接收已由 RX0 中断驱动 */
}
/**
* @brief 查询三路 CAN 通道是否存在待消费接收报文。
* @param[in] 无。
@@ -963,34 +997,6 @@ const CanFd::Diag *CanFd::diag()
return &s_diag;
}
/**
* @brief 将三路 TCAN1057A 收发器置为 Normal 模式。
* @param[in] 无。
* @param[out] 无。
* @retval 无返回值。
* @note 对所有通道统一将 SLP/STB 控制脚拉低。
*/
void CanFd::setNormalMode()
{
for(size_t i = 0; i < kChannelCount; ++i) {
gpio_bit_reset(kChannels[i].slpPort, kChannels[i].slpPin);
}
}
/**
* @brief 将三路 TCAN1057A 收发器置为 Silent 模式。
* @param[in] 无。
* @param[out] 无。
* @retval 无返回值。
* @note 对所有通道统一将 SLP/STB 控制脚拉高。
*/
void CanFd::setSilentMode()
{
for(size_t i = 0; i < kChannelCount; ++i) {
gpio_bit_set(kChannels[i].slpPort, kChannels[i].slpPin);
}
}
/**
* @brief 透传式发送:按接收帧的原格式(标准/扩展、CAN-FD/经典、BRS/ESI、DLC)原样转发到目标 CAN 通道。
* @param[in] canPeriph 目标 CAN 外设实例。
@@ -1184,18 +1190,6 @@ void CanFd::handleRxInterrupt(uint8_t channelIndex)
}
}
/**
* @brief CAN0 兼容中断处理入口。
* @param[in] 无。
* @param[out] 无。
* @retval 无返回值。
* @note 兼容保留入口,内部统一转调 `handleRxInterrupt(0U)`。
*/
void CanFd::onRx0Interrupt()
{
handleRxInterrupt(0U);
}
/**
* @brief 处理指定通道的发送完成中断。
* @param[in] channelIndex 目标 CAN 通道索引(0/1/2)。
@@ -1334,98 +1328,6 @@ void CanFd::refreshFeedbackSnapshot()
}
}
/**
* @brief 运行时 BUS_OFF / 严重错误被动状态软件恢复。
* @note 由 1Hz 心跳任务调用。若某通道持续 2 秒以上处于 BUS_OFF 或 TEC>96,
* 通过收发器静默-唤醒切换让总线获得 128×11 个连续隐性位,协助硬件
* auto_bus_off_recovery 退出 BUS_OFF。本函数不执行 CAN 控制器 hardReset,
* 避免破坏 CAN0/CAN1 共享的 filter 配置;若切换后仍不健康,说明物理层
* 问题未消除,需要排查终端电阻/ACK/波特率/接线。
*/
void CanFd::recoverBusOffIfNeeded()
{
static uint32_t s_unhealthySinceSeq[kChannelCount] = {0U, 0U, 0U};
static bool s_recoveryInProgress[kChannelCount] = {false, false, false};
for (size_t i = 0; i < kChannelCount; ++i) {
if (!kChannelEnabled[i]) {
continue;
}
const auto &ch = kChannels[i];
const uint32_t errReg = CAN_ERR(ch.canPeriph);
const bool busOff = (errReg & CAN_ERR_BOERR) != 0U;
const uint32_t tec = (errReg >> 16) & 0xFFU;
const bool healthy = !busOff && (tec <= 96U);
if (healthy) {
if (s_unhealthySinceSeq[i] != 0U) {
printf("[CAN-RECOVER] CH%u healthy again (TEC=%lu) seq=%lu\r\n",
static_cast<unsigned>(i),
static_cast<unsigned long>(tec),
static_cast<unsigned long>(s_feedbackSeq));
s_unhealthySinceSeq[i] = 0U;
}
s_recoveryInProgress[i] = false;
continue;
}
if (s_unhealthySinceSeq[i] == 0U) {
s_unhealthySinceSeq[i] = s_feedbackSeq;
}
/* 仅在连续 2 秒不健康后才干预,避免对短暂波动过度反应 */
const uint32_t elapsed = s_feedbackSeq - s_unhealthySinceSeq[i];
if (elapsed < 2U) {
continue;
}
if (s_recoveryInProgress[i]) {
/* 上一轮恢复后仍在下一周期观察到不健康:物理层问题未解决,不要刷屏 */
static uint32_t s_lastStillBadPrintSeq[kChannelCount] = {0U, 0U, 0U};
if ((s_feedbackSeq - s_lastStillBadPrintSeq[i]) >= 10U) {
printf("[CAN-RECOVER] CH%u still unhealthy after toggle (TEC=%lu bus_off=%u) seq=%lu; check physical layer\r\n",
static_cast<unsigned>(i),
static_cast<unsigned long>(tec),
busOff ? 1U : 0U,
static_cast<unsigned long>(s_feedbackSeq));
s_lastStillBadPrintSeq[i] = s_feedbackSeq;
}
s_recoveryInProgress[i] = false; /* 允许下一轮再次尝试 */
continue;
}
printf("[CAN-RECOVER] CH%u attempting recovery (TEC=%lu bus_off=%u elapsed=%lus)\r\n",
static_cast<unsigned>(i),
static_cast<unsigned long>(tec),
busOff ? 1U : 0U,
static_cast<unsigned long>(elapsed));
/* 步骤:让收发器进入 standby 再切回 normal,强制总线出现连续隐性位,
* 帮助硬件 ABOR 完成 128×11 个连续隐性位的恢复序列。 */
gpio_bit_set(ch.slpPort, ch.slpPin);
SysTickTimer::delayMs(20U);
gpio_bit_reset(ch.slpPort, ch.slpPin);
SysTickTimer::delayMs(10U);
const uint32_t errAfterToggle = CAN_ERR(ch.canPeriph);
const bool stillBad = ((errAfterToggle & CAN_ERR_BOERR) != 0U) ||
(((errAfterToggle >> 16) & 0xFFU) > 96U);
if (stillBad) {
printf("[CAN-RECOVER] CH%u toggle done but still unhealthy (TEC=%lu bus_off=%u); need physical-layer fix\r\n",
static_cast<unsigned>(i),
static_cast<unsigned long>((errAfterToggle >> 16) & 0xFFU),
((errAfterToggle & CAN_ERR_BOERR) != 0U) ? 1U : 0U);
} else {
printf("[CAN-RECOVER] CH%u recovered by transceiver toggle\r\n",
static_cast<unsigned>(i));
}
s_recoveryInProgress[i] = true;
}
}
/**
* @brief 拷贝指定通道的最新反馈快照。
* @param[in] channelIndex 目标 CAN 通道号(0/1/2)。