You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32G473CET6 CAN总线多设备响应异常问题排查求助

问题分析:STM32G473 CAN总线多设备查询响应异常

我基于STM32G473CET6开发CAN总线项目,STM32负责发送消息、处理接收消息并响应。例如发送10170001查询设备01的IO状态,设备会返回8条包含IO状态、设备状态、PWM值等的响应消息。但总线上存在多台设备时,发送10170002查询设备02,会出现部分响应是设备01的旧回复(比如8条里有2条),直到第三次查询才能得到设备02的正确IO状态。怀疑是STM32的溢出或缓冲问题,但FIFO状态监测正常,终端电阻配置也正确。

已完成的排查工作

  • 总线两端终端电阻配置正确
  • 已实现FIFO状态监测机制
  • 使用分析仪追踪总线上的消息
  • 两台设备均出现相同问题,排除硬件故障
  • CAN总线速率为500kbps,即使发送少量测试消息仍会出现该问题

相关代码

/* main can line fifo0 callback */
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{
    FDCAN_RxHeaderTypeDef bufRxHdrCan;
    uint8_t payloadCan[8];

    if ((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != RESET)
    {
        if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0,&bufRxHdrCan,payloadCan) == HAL_OK)
        {
            dbgPrintf("Can1 new message in RxFifo0\n");
            dbgPrintf("RxHeader.Identifier: %x\n", bufRxHdrCan.Identifier);
            dbgPrintf("RxHeader.DataLength: %x\n", bufRxHdrCan.DataLength);

            CanMessage canMsg;

            memcpy(canMsg.data,payloadCan,bufRxHdrCan.DataLength);

            canMsg.id  = bufRxHdrCan.Identifier;
            canMsg.len = bufRxHdrCan.DataLength;

            ParsedID id = canMessageParseId(canMsg.id);

            dbgTrace("ParsedID.pgn       : %d\n", id.pgn);
            dbgTrace("ParsedID.sourceAddr: %d\n", id.sourceAddr);
            dbgTrace("ParsedID.targetAddr: %d\n", id.targetAddr);

            if((id.targetAddr == gAppSettings.devAddress) ||  (id.targetAddr == BROADCAST_ADDRESS))
            {
                gSysMsg sysMsg;

                sysMsg.dataDesc.msgId = canMsg.id;
                sysMsg.dataDesc.msgSrc = SRC_CANA;
                sysMsg.dataLen = canMsg.len;

                memcpy(sysMsg.dataBuffer,payloadCan,sysMsg.dataLen);

                gRingBufPush(&sysMsgRingBuf,(void*)(&sysMsg));
            }

            return;
        }
        dbgPrintf("ERROR: Fifo0Callback HAL_FDCAN_GetRxMessage\n");
        Error_Handler(1);   // id 1
    }
}

/* can message send */
bool canMessageSend(CanLine cLine,CanMessage *pCanMsg)
{
    FDCAN_HandleTypeDef *phfdcan = phfdcanMain;

    FDCAN_TxHeaderTypeDef TxHeader;

    TxHeader.Identifier = pCanMsg->id;
    TxHeader.DataLength = pCanMsg->len;

    TxHeader.IdType = FDCAN_EXTENDED_ID;

    if(TxHeader.DataLength > 0)
    {
        TxHeader.TxFrameType = FDCAN_DATA_FRAME;
    }
    else
    {
        TxHeader.TxFrameType = FDCAN_REMOTE_FRAME;
    }

    TxHeader.ErrorStateIndicator = FDCAN_ESI_PASSIVE;
    TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
    TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
    TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
    TxHeader.MessageMarker = 0;

    dbgTrace("canMessageSend\n");
    dbgTrace("id = %d\n", pCanMsg->id);
    dbgTrace("len = %d\n",pCanMsg->len);

    while (HAL_FDCAN_GetTxFifoFreeLevel(phfdcan) == 0);
    if (HAL_FDCAN_AddMessageToTxFifoQ(phfdcan,&TxHeader,pCanMsg->data)!= HAL_OK)
    {
        dbgPrintf("ERROR:HAL_FDCAN_AddMessageToTxFifoQ-MIO\n");
        return false;
    }

    return true;
}

可能的原因分析

  1. 环形缓冲区未清空
    切换查询目标设备时,sysMsgRingBuf环形缓冲区中可能残留上一次查询设备01的响应消息。如果后续处理逻辑未先清空缓冲区,会将旧消息与新消息混合返回,导致异常。需检查查询新设备前是否有清空缓冲区的操作。

  2. 响应消息与请求无关联
    当前代码仅通过targetAddr判断是否接收消息,但未将响应与对应的查询请求关联。若设备01的响应延迟到达,会被误当作设备02的响应处理。需给每个查询请求添加唯一标识(如序列号),响应消息携带对应标识,处理时仅匹配当前查询的序列号。

  3. CAN过滤器配置不严谨
    即使FIFO状态正常,若CAN过滤器未正确过滤非目标设备的消息,可能导致设备接收其他设备的旧响应。检查FDCAN过滤器配置,确保仅接收目标地址匹配的消息,或在接收后严格校验sourceAddr是否为当前查询的设备地址。

  4. 局部变量生命周期问题
    回调函数中定义的sysMsg是局部变量,调用gRingBufPush时传入的是局部变量指针。若环形缓冲区存储的是指针而非复制完整数据,回调返回后局部变量被销毁,后续访问会出现数据错误。需确认gRingBufPush是否复制整个sysMsg数据,而非存储指针。

  5. 消息处理时序问题
    设备02的响应可能被延迟处理,而旧的设备01消息仍在处理队列中。检查消息处理线程的优先级和调度逻辑,确保新查询请求发出后,立即暂停处理旧响应消息,优先处理新设备的响应。

内容的提问来源于stack exchange,提问作者MKT12

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 19:04:52