BMS通信CAN底层配置

CAN底层配置

什么是CAN通信?

 一种局域网通信方式
 时间触发通信
 中断使能和清除
 CAN-FD帧
 过滤器
 工作模式:睡眠模式、初始化模式、正常工作模式
 波特率: BaudRate
 中断:发送中断、FIFO0中断、FIFO1中断、错误和状态改变中断。

总结:一种无主从关系的总线型通信方式。通过硬件实现仲裁和检错。

配置要素(需要配置哪些东西)?

* CAN的APB时钟配置
* GPIO口配置
* CAN参数配置\过滤器配置
can_gpio_config
/*GPIO配置*/
void can_gpio_config(void)
{
    /* enable CAN clock */
    rcu_periph_clock_enable(RCU_CAN0);
    rcu_periph_clock_enable(RCU_GPIOD);
    rcu_periph_clock_enable(RCU_AF);

    /* configure CAN0 GPIO */
    gpio_init(GPIOD, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);

    gpio_pin_remap_config(GPIO_CAN0_FULL_REMAP, ENABLE);
}
can_config
    void can_config(void)
    {
        can_parameter_struct can_parameter;
        can_filter_parameter_struct can_filter;

        can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
        /* initialize CAN register */
        can_deinit(CAN0);

        /* initialize CAN parameters */
        can_parameter.time_triggered = DISABLE;
        can_parameter.auto_bus_off_recovery = DISABLE;
        can_parameter.auto_wake_up = DISABLE;
        can_parameter.auto_retrans = DISABLE;
        can_parameter.rec_fifo_overwrite = DISABLE;
        can_parameter.trans_fifo_order = DISABLE;
        can_parameter.working_mode = CAN_NORMAL_MODE;
        /* configure CAN0 baud rate 1MBps, sample point at 80% */
        can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
        can_parameter.time_segment_1 = CAN_BT_BS1_7TQ;
        can_parameter.time_segment_2 = CAN_BT_BS2_2TQ;
        can_parameter.prescaler = 9U;
        /* initialize CAN */
        can_init(CAN0, &can_parameter);

        /* initialize filter */
        /* configure filter mode */
        can_filter.filter_mode = CAN_FILTERMODE_MASK;
        can_filter.filter_bits = CAN_FILTERBITS_32BIT;
        /* configure filter ID */
        can_filter.filter_list_high = 0x0000U;
        can_filter.filter_list_low = 0x0000U;
        /* configure filter mask */
        can_filter.filter_mask_high = 0x0000U;
        can_filter.filter_mask_low = 0x0000U;
        /* select receiver fifo */
        can_filter.filter_fifo_number = CAN_FIFO0;
        can_filter.filter_number = 0U;
        can_filter.filter_enable = ENABLE;
        can_filter_init(CAN0, &can_filter);
    #if defined(GD32E51X_HD)
        /* configure CAN0 NVIC */
        nvic_irq_enable(USBD_LP_CAN0_RX0_IRQn, 0U, 0U);
    #else
        /* configure CAN0 NVIC */
        nvic_irq_enable(CAN0_RX0_IRQn, 0U, 0U);
    #endif /* GD32E51X_HD */

        /* enable can receive FIFO0 not empty interrupt */
        can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0);
    }

如何进行接受与发送?

* can_message_transmit
* can_transmit_states
* can_message_receive

* 发送状态切换:empty -> pending -> scheduled(超过1个邮箱需要发送) -> transmit -> empty
* 发送流程:
    1. 选择一个空闲发送邮箱
    2. 配置4个发送寄存器(CAN_TMIx,CAN_TMPx,CAN_TMDATA0x和CAN_TMDATA1x)
    3. 将 CAN_TMIx 寄存器的 TEN 置 1
    4. 检测发送状态和错误信息。典型情况是检测到 MTF 和 MTFNERR 置 1,说明数据被成功发送。

* 数据接收步骤
    1. 查看FIFO中帧的数量
    2. 通过 CAN_RFIFOMIx , CAN_RFIFOMPx , CAN_RFIFOMDATA0x 和 CAN_RFIFOMDATA1x 读取数据。
    3. :将寄存器 CAN_RFIFOx 的 RFD 置 1 释放邮箱,并且等待其由硬件自动清 0。

* 2个深度为3的接收FIFO
  28个标识符过滤器
  14个独立标识符过滤器

使用中断方式接收

  1. 中断使能
    // configure CAN0 NVIC
    nvic_irq_enable(CAN1_RX0_IRQn,1,2);

    // enable can receive FIFO0 not empty interrupt
    can_interrupt_enable(CAN1, CAN_INT_RFNE0);
  1. 中断处理函数编写
    void CAN1_RX0_IRQHandler(void)
    {
        /* check the receive message */
        can_message_receive(CAN1, CAN_FIFO0, &receive_message);
        CAN1_Receice_Analysis(&receive_message);
    }

===============================================================================================

问题记录

  • 理论知识获取:
    FDCAN配置与普通CAN的区别?
    STM32配置FDCAN过程

    1. 设置FDCAN时钟为:LL_RCC_FDCAN_CLKSOURCE_HSE
    2. GPIO初始化
  • 调试工具
    CAN通信必须外部配备两个120Ω的终端电阻,才可向外通信。调试内部通信可使用回环模式。
    状态寄存器、 接收FIFO0寄存器、 接收FIFO1寄存器、 错误寄存器、 接收FIFO邮箱标识符寄存器、接收FIFO邮箱data0寄存器(调试注意)

  • 宏的打开与关闭:由于项目属于国产替代化项目,存在多处的宏开关。

  • 配置到一半时发现芯片为GD32E513,而FDCAN支持的芯片为GD32E518X系列(影响:开始看的FDCAN都无效)

调试过程发现无通信数据发出!!!!

可能原因:
原因1:底层配置不对。断点查看发送数据是否到CAN端口
原因2:硬件连接问题。示波器查看GPIO出口数据(示波器查看GPIO口无任何数据发出)
* 事后分析:观察到CAN1寄存器中值已经放入TMDATA0,但是GPIO无电平变化。应着重思考CAN0的数据到GPIO处的问题,例如复用时钟是否开启。GPIO配置是否正常(根据手册看GPIOB寄存器)。
问题发现点:发现CAN1的ERR寄存器报故障0x05问题。在示波器上看到未上电时为低,上电后出现先高一下,然后常低的问题,打断点分析电平变化的位置,最终找到了Debug.c处重新配置了GPIO。
底层配置不对
通过寄存器观察到:错误寄存器报0x05(位显性错误)
配置结束后(开启复用时钟后),发现err不报故障发送寄存器有数据,但端口无数据,CAN分析仪无数据接收。
img

can_init返回值不对(0x08015564)
且有些断点无法达到(keil的BUG),让我一度怀疑是条件编译原因导致!!。

发送问题解决后出现:无法接收数据,回环模式下接收FIFO都不能接到数据
配置为回环模式发现
img
img
配置回环后
img

问题定位:看到文章中的回环模式发送规则,寻找寄存器可收到GPIO口未发出问题点。
去查看Datasheet的引脚复用,发现PB12与PB13为CAN1寄存器。而配置的时钟等都是CAN0。
(原意想确认PB12与13是否支持CAN功能)

根因分析:1. 上拉输入、推挽输出、上拉输出等的外部GPIO电平显示为什么?
            2. 其他数据初始化时配置了PB13引脚,导致被持续拉低
从CAN0配置到CAN1后,回环模式下,接收寄存器无法收到发送寄存器值,但发送寄存器正常,且CAN_TX抓到通信数据。
1.过滤器配置导致
2.接收中断服务函数未写
3.接收函数不对

4.如果未配置过滤器或者过滤器未使能则不接受任何数据
GD芯片逆天大坑出现!!!
:使用CAN1时,必须开启CAN0时钟.
由于CAN0与CAN1共用过滤器,且CAN1过滤器默认15.

电池发送过程中偶发性上报BMS内部故障

该故障发生条件:BMS通过CAN上传错误标志,软件解析后变量转换进行上报
现象:使用真电池基本上1~2个小时出现一次,是否有变稳定这个还不清除。
思路:这种长时间偶发性问题,感觉是通信干扰导致。其他人给的意见是软件内部赋值可能错误导致。

解决方法:1.通过示波器抓取CAN接收器解析后数据,对比与MCU进入端口是否一致。
            经验:示波器打到500ms进行抓取,示波器存在失真现象,导致波形对比不正确形成误判。
            ![img](https://img2024.cnblogs.com/blog/3649801/202508/3649801-20250821163857087-1109856101.png)

            通过置起GPIO口减小分辨率,示波器调整为触发抓取故障时刻。
        
        措施:软件增加变量通过Modbus显示。
            1. 置起故障时的GPIO标志
            2,保存故障时刻的CAN解析帧
            3. 保存故障时刻的CAN错误计数器值
  • 原因:通过抓取电池包发送数据帧以及CAN通信数据处理数据帧对比发现。
    img
    数据存在规律性赋值错误问题。
    首先可以排查硬件、物理层、干扰等因素,问题主要出现在逻辑层。主要原因为:出现问题的数据帧不是错误数据,而是规律性的半帧赋值。
    半帧赋值:当访问过程中FIFO正好接收到外部数据。

  • 解决方案:
    由于轮询方式调用can_message_receive,出现FiFO为空状态下依旧访问的问题,导致错误赋值。

    解决代码:
    if (can_receive_message_length_get(CAN1, CAN_FIFO0) == 0){
    return STATUS_TRUE;
    }

    读取前访问FIFO数据量,如果为空则直接退出,避免出现错误访问。

posted on 2025-07-15 17:21  Yanron  阅读(98)  评论(0)    收藏  举报

导航