feat(canfd): 添加CANFD硬件自检功能并优化初始化时序
- 新增s_channelHwOk数组跟踪各通道硬件初始化状态 - 修改CANFD初始化流程,在GPIO上电后延时200ms再进入Normal模式 - 实现selfTestL0()轻量自检函数,检查硬件初始化、退出init模式、收发器状态等 - 更新CANFD初始化逻辑,只有自检通过才标记为成功 refactor(spi): 调整SPI DMA和EXTI配置顺序避免通信失步 - 将armSpiDmasForNextCs()调用移至configureExti()之前 - 添加注释说明DMA预装和EXTI开启的时序要求 - 避免OTA跳转后ESP32立即发送HELLO导致的SPI从机失步问题 fix(app_spi): 修复HELLO_ACK响应中credit初始化问题 - 在HELLO_ACK构建前将g_localCredit设置为1 - 与requestEsp32Read()保持一致避免TX占用时credit=0的问题 - 防止主机因remoteCredit=0而拒绝发送PING帧 refactor(initial): 重构应用初始化流程添加模块状态跟踪 - 引入ModuleBit枚举和掩码机制跟踪各模块初始化状态 - 实现mark()和report()方法统一管理模块启动结果 - 按NVIC→SysTick→ESP32_EN→USART0→AppSpi→ADC→CANFD→OTA→TaskManager→Scheduler→EtherCAT→Watchdog顺序启动 - 将CANFD模块成功条件改为selfTestL0()通过才标记成功
This commit is contained in:
@@ -163,6 +163,7 @@ CanFd::ChannelStats CanFd::s_channelStats[3]{};
|
||||
CanFd::ChannelFeedback CanFd::s_feedback[3]{};
|
||||
uint32_t CanFd::s_feedbackSeq = 0U;
|
||||
CanFd::IdSnapshotTable CanFd::s_idSnapshot[3]{};
|
||||
bool CanFd::s_channelHwOk[3]{};
|
||||
|
||||
/**
|
||||
* @brief 查询指定通道是否已使能。
|
||||
@@ -212,6 +213,8 @@ void CanFd::initGpio()
|
||||
gpio_init(ch.rxPort, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, ch.rxPin);
|
||||
gpio_init(ch.txPort, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, ch.txPin);
|
||||
gpio_init(ch.slpPort, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, ch.slpPin);
|
||||
/* 上电先 STB=1(待机),延时后再进入 Normal */
|
||||
gpio_bit_set(ch.slpPort, ch.slpPin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,9 +329,10 @@ 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));
|
||||
s_channelHwOk[i] = false;
|
||||
return;
|
||||
}
|
||||
s_channelHwOk[i] = false;
|
||||
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;
|
||||
@@ -412,6 +416,9 @@ void CanFd::initChannelHardware(uint8_t i)
|
||||
s_rxQueues[i].head = 0U;
|
||||
s_rxQueues[i].tail = 0U;
|
||||
s_rxQueues[i].count = 0U;
|
||||
|
||||
const bool exitOk = ((CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) == 0U);
|
||||
s_channelHwOk[i] = (nominalOk && fdOk && exitOk);
|
||||
}
|
||||
|
||||
/** @brief 统一配置三路滤波器(HBC1F + per-channel filter)。 */
|
||||
@@ -724,7 +731,7 @@ void CanFd::dumpRegisters()
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
* @note 初始化后默认将三路 TCAN1057A 收发器置为 Normal,并使能 FIFO0 的非空/满/overfull 中断统计。
|
||||
* @note 初始化收发器 GPIO 后延时进入 Normal,并启用 FIFO0 中断统计。
|
||||
*/
|
||||
void CanFd::init()
|
||||
{
|
||||
@@ -734,6 +741,7 @@ void CanFd::init()
|
||||
for (size_t i = 0; i < kChannelCount; ++i) {
|
||||
s_channelStats[i] = {};
|
||||
s_feedback[i] = {};
|
||||
s_channelHwOk[i] = false;
|
||||
}
|
||||
s_feedbackSeq = 0U;
|
||||
|
||||
@@ -742,6 +750,10 @@ void CanFd::init()
|
||||
printClockInfo();
|
||||
#endif
|
||||
|
||||
/* 收发器待机保持后,延时再进入 Normal */
|
||||
constexpr uint32_t kCanPowerOnDeferMs = 200U;
|
||||
SysTickTimer::delayMs(kCanPowerOnDeferMs);
|
||||
|
||||
for (uint8_t i = 0; i < kChannelCount; ++i) {
|
||||
initChannelHardware(i);
|
||||
}
|
||||
@@ -761,6 +773,56 @@ void CanFd::init()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief L0 轻量自检:无总线发帧,仅校验使能通道硬件与收发器状态。
|
||||
*/
|
||||
bool CanFd::selfTestL0()
|
||||
{
|
||||
constexpr uint32_t kTecRecLimit = 16U;
|
||||
bool anyEnabled = false;
|
||||
bool allOk = true;
|
||||
|
||||
for (uint8_t i = 0U; i < static_cast<uint8_t>(kChannelCount); ++i) {
|
||||
if (!kChannelEnabled[i]) {
|
||||
continue;
|
||||
}
|
||||
anyEnabled = true;
|
||||
const auto &ch = kChannels[i];
|
||||
|
||||
if (!s_channelHwOk[i]) {
|
||||
allOk = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 仍停在初始化模式 */
|
||||
if ((CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) != 0U) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return anyEnabled && allOk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 切换 CANFD 接收过滤模式。
|
||||
* @param[in] mode 目标过滤模式。
|
||||
|
||||
Reference in New Issue
Block a user