STM32 FDCAN 发送 DroneCAN 时如何排查 CRC mismatch?
结论
canard 负责生成和校验 DroneCAN 传输 CRC,但无法修复底层驱动发送的帧长度或数据错误。建议先检查驱动中的这一行:
txHeader.DataLength = frame->data_len;
STM32 HAL 的 FDCAN DataLength 通常要求使用 FDCAN_DLC_BYTES_n 这类编码值,而 frame->data_len 表示实际字节数。直接赋值可能导致硬件使用错误的 DLC 发帧,使接收端重组出的字节与发送端不同,最终出现 CRC mismatch。请根据所用 STM32 HAL 版本的定义,把实际长度映射为对应的 DLC 常量。
修正 FDCAN 的数据长度
经典 CAN 的负载长度最多为 8 字节。发送前可以检查长度,并将其转换为 HAL 使用的 DLC 编码:
static bool set_fdcan_data_length(FDCAN_TxHeaderTypeDef *header, uint8_t len)
{
switch (len) {
case 0: header->DataLength = FDCAN_DLC_BYTES_0; return true;
case 1: header->DataLength = FDCAN_DLC_BYTES_1; return true;
case 2: header->DataLength = FDCAN_DLC_BYTES_2; return true;
case 3: header->DataLength = FDCAN_DLC_BYTES_3; return true;
case 4: header->DataLength = FDCAN_DLC_BYTES_4; return true;
case 5: header->DataLength = FDCAN_DLC_BYTES_5; return true;
case 6: header->DataLength = FDCAN_DLC_BYTES_6; return true;
case 7: header->DataLength = FDCAN_DLC_BYTES_7; return true;
case 8: header->DataLength = FDCAN_DLC_BYTES_8; return true;
default: return false;
}
}
在发送代码中调用该函数。长度不在 0–8 范围内时,不要继续入队:
if (!set_fdcan_data_length(&txHeader, frame->data_len)) {
return -CANARD_STM32_ERROR_UNSUPPORTED_FRAME_FORMAT;
}
请查阅项目实际使用的 STM32 HAL 头文件,确认这些宏的名称和编码方式。frame->data_len 仍用于复制实际数据字节:
memcpy(data, frame->data, frame->data_len);
确认 CRC 错误对应哪条传输
代码中的 send_NodeStatus() 只发送 NodeStatus,而错误出现在接收端重组 DTID 1 传输时。仅凭这段代码和错误信息,无法确认报错对应的帧是否由这个函数发出,也无法确定具体哪一帧发生了变化。接收端已经打印出部分 YAML 内容,之后才抛错;这可能是因为它收到了并处理了其他消息,也可能是在重组多帧传输时发现校验不一致。
建议抓取 CAN 帧,并同时比对发送端和接收端的原始数据,至少核对:
- CAN ID、帧类型和 DLC;
- 每帧的实际数据字节;
- 多帧传输的顺序、transfer ID 和末帧标记;
- 接收端是否丢帧或过滤了部分帧。
从接收端实际收到的帧入手,可以判断差异来自发送驱动的长度或数据,还是接收、过滤或重组环节。也请确认总线速率与接收配置一致。错误中的 expected 和 got 表示传输 CRC 的校验结果,不是经典 CAN 帧自身的硬件 CRC 报错。
检查其他传输配置
如果修正 DLC 后问题仍然存在,再检查发送端与 Python 端使用的 DroneCAN 数据类型定义和相关传输配置是否一致。目前的信息不足以判断配置是否存在差异。可以先提供对应错误传输的发送帧和接收帧抓包,以及生成该传输的 C 代码,以便进一步定位首个不一致的字段或帧。
备注:内容仅供参考。
