HC11425 发表于 2021-11-22 17:42

HC32F460 CAN通信问题刨析与解决


大家好!非常感谢使用华大MCU,在调试HC32F460遇到的问题作一些笔记和个人理解,希望能帮助大家!谢谢。
近来在配合客户做BMS管理,需要使用到CAN功能,CAN功能比较频繁的收发多包数据,大概1秒收发15包数据。
1、客户遇到的问题,在进行CAN收发过程,发现数据只能发送或者接收。
2、压力测试情况下直接造成数据阻塞,CAN无法工作。
3、在进行超过8Bit数据情况下,进行分包发送或者接收也会出现频繁出现数据阻塞。
A、按照客户遇到以上问题进行CAN分析。使用CAN总线分析仪进行压力测试。并且复现以上问题。
B、首先我们看华大官方例程can_rx_tx_irq,其实直接使用官方例程即可,波特率修改如下,用户手册有计算波特率说明
static void CanInitConfig(uint16_t CAN_Baud_Rate)
{
    stc_can_init_config_t stcCanInitCfg;
    stc_can_filter_t astcFilters = \
    {
      {0x00000000ul, 0x1FFFFFFFul, CanFilterSel1, CanAllFrames}
    };

    //<< Enable can peripheral clock and buffer(ram)
    PWC_RamOpMdConfig(HighSpeedMd);
    PWC_RamPwrdownCmd(PWC_RAMPWRDOWN_CAN, Enable);
    PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_CAN, Enable);

    //<< CAN GPIO config
    PORT_SetFunc(PortB, Pin06, Func_Can1_Rx, Disable);
    PORT_SetFunc(PortB, Pin07, Func_Can1_Tx, Disable);
    PORT_ResetBits(PortD, Pin15);
    PORT_OE(PortD, Pin15, Enable);
               
               
                PORT_SetBits(PortB, Pin13);
    PORT_OE(PortB, Pin13, Enable);

    MEM_ZERO_STRUCT(stcCanInitCfg);
    //<< Can bit time config
//    stcCanInitCfg.stcCanBt.PRESC = 4u-1u;//波特率,主要修改这个地方即可
                switch(CAN_Baud_Rate)
                {
                        case 500://500K
                                stcCanInitCfg.stcCanBt.PRESC = 2u-1u;
                        break;
                        case 250://250K
                                stcCanInitCfg.stcCanBt.PRESC = 4u-1u;
                        break;
                        case 125://125K
                                stcCanInitCfg.stcCanBt.PRESC = 8u-1u;
                        break;
                        case 100://100K
                                stcCanInitCfg.stcCanBt.PRESC = 10u-1u;
                        break;
                        default:
                                stcCanInitCfg.stcCanBt.PRESC = 2u-1u;
                        break;                                                                       
                }
    stcCanInitCfg.stcCanBt.SEG_1 = 5u-2u;
    stcCanInitCfg.stcCanBt.SEG_2 = 3u-1u;               
    stcCanInitCfg.stcCanBt.SJW   = 3u-1u;
    stcCanInitCfg.stcWarningLimit.CanErrorWarningLimitVal = 10u;
    stcCanInitCfg.stcWarningLimit.CanWarningLimitVal = 16u-1u;

    stcCanInitCfg.enCanRxBufAll= CanRxNormal;
    stcCanInitCfg.enCanRxBufMode = CanRxBufNotStored;//新CAN消息 不做存储
    stcCanInitCfg.enCanSAck      = CanSelfAckDisable;//CanSelfAckEnable;// 有应答响应
    stcCanInitCfg.enCanSTBMode   = CanSTBFifoMode;//

    stcCanInitCfg.pstcFilter   = astcFilters;
    stcCanInitCfg.u8FilterCount= CAN_FILTERS_COUNT;

    CAN_Init(&stcCanInitCfg);
}
C、按照以上配置,直接使用官方开发板进行数据收发是没有问题的。但问题不是出在CAN配置上面。
D、咱们再看看CAN中断节点枚举,这些是CAN中断标记位枚举节点,引起节点中断有很多原因,比如收发数据中断,错误帧、超时、干扰中断等等。
   并不是说只打开某个中断节点,MCU就只会产生某个中断,因为的中断寄存器是硬件置位,需要软件进行清零。所有需要在中断回调里面进行中断枚举清零。
   我是全部中断节点都在回调函数里面进行标记位清零。经过测试没有发现上面提到的问题。
typedef enum
{
    //<<Can Tx or Tx Irq **
    CanTxBufFullIrq**          = 0x00000001,   ///<
    CanRxIrq**               = 0x00008000,   ///< Receive interrupt flag
    CanRxOverIrq**             = 0x00004000,   ///< RB overrun interrupt flag
    CanRxBufFullIrq**          = 0x00002000,   ///< RB full interrupt flag
    CanRxBufAlmostFullIrq**    = 0x00001000,   ///< RB almost full interrupt flag
    CanTxPrimaryIrq**          = 0x00000800,   ///< Transmission primary interrupt flag
    CanTxSecondaryIrq**      = 0x00000400,   ///< Transmission secondary interrupt flag
    CanErrorIrq**            = 0x00000200,   ///< Error interrupt flag
    CanAbortIrq**            = 0x00000100,   ///< Abort interrupt flag

    //<< Can Error Irq **
    CanErrorWarningIrq**       = 0x00800000,   ///< Error warning limit reached flag
    CanErrorPassivenodeIrq**   = 0x00400000,   ///< Error passive mode active flag
    CanErrorPassiveIrq**       = 0x00100000,   ///< Error passive interrupt flag
    CanArbiLostIrq**         = 0x00040000,   ///< Arbitration lost interrupt flag
    CanBusErrorIrq**         = 0x00010000,   ///< Bus error interrupt flag
}en_can_irq_flag_type_t;
static void CAN_RxIrqCallBack(void)
{
    if(true == CAN_Irq**Get(CanRxIrq**))
    {
      CAN_Irq**Clr(CanRxIrq**);
      CAN_IrqCmd(CanRxIrqEn, Disable);

      CAN_Receive(&stcRxFrame);

      u8RxFlag = true;
    }

    if(true == CAN_Irq**Get(CanTxPrimaryIrq**))
    {
      CAN_Irq**Clr(CanTxPrimaryIrq**);

      CAN_IrqCmd(CanRxIrqEn, Enable);
    }
                //总线忙碌中断
                if(true == CAN_Irq**Get(CanBusErrorIrq**))
    {
      CAN_Irq**Clr(CanBusErrorIrq**);

    }
                //仲裁失败中断
                if(true == CAN_Irq**Get(CanArbiLostIrq**))
    {
      CAN_Irq**Clr(CanArbiLostIrq**);

    }
}
实则是需要及时清除CAN产生的错误节点,需要及时清理标记位。
E、经过进行全部节点进行清除,压力测试CAN数据收发,没有复现以上问题。

如有其他问题,请联系:131 6807 9092(微信同号) 华大代理商 喻生








七毛钱 发表于 2021-12-1 17:25

非常感谢分享

chenqianqian 发表于 2021-12-1 20:29

感谢分享经验

caigang13 发表于 2021-12-3 08:12

讲解详细,非常实用。

onlycook 发表于 2021-12-14 16:38

这个不错,可以借鉴
页: [1]
查看完整版本: HC32F460 CAN通信问题刨析与解决