feat(canfd): 修复CAN发送问题。实现CANFD发送完成中断处理和通道健康检查
- 添加CANFD发送完成中断处理函数,确保只有MTFNERR置位时才计数发送成功 - 新增通道健康检查功能,防止病态通道被持续重发的测试帧反复推回BUS_OFF - 重构CANFD配置结构体,添加TX中断配置项并修正GPIO映射设置 - 移除原有的软件发送队列机制,改为直接硬件发送模式 - 更新项目配置文件中的CANFD源文件路径命名 fix(canfd): 修复CANFD发送计数和错误处理逻辑 - 修正发送计数只在硬件MTFNERR确认后增加,而非请求进入邮箱时 - 改进错误日志输出,添加详细的错误类型和通道状态信息 - 优化总线恢复机制,通过收发器静默-唤醒协助硬件自动恢复 - 添加条件编译开关控制启动时自检和回环测试功能
This commit is contained in:
@@ -144,54 +144,48 @@ void TaskRunner::taskAdcProcess()
|
||||
void TaskRunner::taskCanRxPoll() { CanFd::poll(); }
|
||||
|
||||
/**
|
||||
* @brief 执行预留的 CAN 发送执行任务。
|
||||
* @brief 执行 CAN 周期发送任务:每 1ms 在每个使能通道上发送一帧 CANFD 测试帧。
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
* @note 当前阶段不做周期性发送调度;若后续需要显式验证某一路发送能力,可由调用方先 prepare,再直接调用 `CanFd::sendPrepared()`。
|
||||
* @note 帧格式:扩展帧 29-bit ID,CAN-FD,DLC=64,BRS 受 CONFIG_CAN_FD_BRS_ENABLE 控制。
|
||||
* 载荷布局:
|
||||
* [0] 固定标识 0xC0
|
||||
* [1] 通道号
|
||||
* [2..5] 发送序号(小端 uint32)
|
||||
* [6..7] 系统运行秒数低 16 位
|
||||
* [8..63] 填充 0xA0 + (index & 0x0F)
|
||||
* periodic=true:仅允许一个邮箱保持自动重发,不主动 abort 旧帧,
|
||||
* 跳过 TEC 保护以匹配诊断行为。
|
||||
*/
|
||||
void TaskRunner::taskCanTxSend()
|
||||
{
|
||||
/* 启动后每 100ms 轮流发送一路 CAN 通道的 CANFD+BRS 64 字节测试帧。
|
||||
* 三路通道时分复用:CH0→CH1→CH2→CH0→...,每 100ms 只发一路,
|
||||
* 避免多路同时发送导致总线仲裁冲突(当多路并接到同一总线时)。
|
||||
* 帧格式:扩展帧 29-bit ID,CANFD+BRS,DLC=64。
|
||||
* 载荷布局:
|
||||
* [0] 通道号 0/1/2
|
||||
* [1] 保留
|
||||
* [2..5] 发送序号(小端 uint32,每通道独立递增)
|
||||
* [6..9] 系统运行秒数 g_app_uptime_sec(小端 uint32)
|
||||
* [10..63] 递增填充,按通道偏移便于抓包区分 */
|
||||
static uint32_t seq[3] = {0U, 0U, 0U};
|
||||
static uint8_t round = 0U; /* 0=CH0, 1=CH1, 2=CH2, 轮流 */
|
||||
static uint32_t seq = 0U;
|
||||
|
||||
const uint8_t ch = round;
|
||||
round = (round + 1U) % 3U;
|
||||
for (uint8_t ch = 0U; ch < 3U; ++ch) {
|
||||
if (!CanFd::isChannelEnabled(ch)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 跳过已禁用的通道 */
|
||||
if (!CanFd::isChannelEnabled(ch)) {
|
||||
return;
|
||||
uint8_t data[64];
|
||||
data[0] = 0xC0U;
|
||||
data[1] = ch;
|
||||
const uint32_t s = seq;
|
||||
data[2] = static_cast<uint8_t>(s & 0xFFU);
|
||||
data[3] = static_cast<uint8_t>((s >> 8) & 0xFFU);
|
||||
data[4] = static_cast<uint8_t>((s >> 16) & 0xFFU);
|
||||
data[5] = static_cast<uint8_t>((s >> 24) & 0xFFU);
|
||||
data[6] = static_cast<uint8_t>(g_app_uptime_sec & 0xFFU);
|
||||
data[7] = static_cast<uint8_t>((g_app_uptime_sec >> 8) & 0xFFU);
|
||||
for (uint8_t i = 8U; i < 64U; ++i) {
|
||||
data[i] = static_cast<uint8_t>(0xA0U + (i & 0x0FU));
|
||||
}
|
||||
|
||||
const uint32_t extId = 0x18FF5000U | static_cast<uint32_t>(ch);
|
||||
if (CanFd::transmitFrame(ch, extId, data, sizeof(data), true)) {
|
||||
seq++;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t data[64];
|
||||
data[0] = ch;
|
||||
data[1] = 0U;
|
||||
const uint32_t s = seq[ch];
|
||||
data[2] = static_cast<uint8_t>(s & 0xFFU);
|
||||
data[3] = static_cast<uint8_t>((s >> 8) & 0xFFU);
|
||||
data[4] = static_cast<uint8_t>((s >> 16) & 0xFFU);
|
||||
data[5] = static_cast<uint8_t>((s >> 24) & 0xFFU);
|
||||
data[6] = static_cast<uint8_t>(g_app_uptime_sec & 0xFFU);
|
||||
data[7] = static_cast<uint8_t>((g_app_uptime_sec >> 8) & 0xFFU);
|
||||
data[8] = static_cast<uint8_t>((g_app_uptime_sec >> 16) & 0xFFU);
|
||||
data[9] = static_cast<uint8_t>((g_app_uptime_sec >> 24) & 0xFFU);
|
||||
for (uint8_t i = 10U; i < 64U; ++i) {
|
||||
data[i] = static_cast<uint8_t>(i + ch * 0x40U);
|
||||
}
|
||||
|
||||
const uint32_t extId = 0x1FFFFF00U | static_cast<uint32_t>(ch);
|
||||
CanFd::transmitFrame(ch, extId, data, 64U);
|
||||
seq[ch]++;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,18 +217,6 @@ void TaskRunner::taskCanRxParse()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行预留的 CAN 发送准备任务。
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
* @note 当前阶段三路 CANFD 仅要求底层收发能力可用,不做周期性业务状态广播。
|
||||
*/
|
||||
void TaskRunner::taskCanTxPrepare()
|
||||
{
|
||||
/* 当前阶段不做周期性业务状态广播。 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行状态灯维护任务。
|
||||
* @param[in] 无。
|
||||
|
||||
Reference in New Issue
Block a user