打印
[STM32H7]

STM32H7 FDCAN兼容普通CAN使用 基于CubeMX配置

[复制链接]
1068|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
1.说明
STM32大多数型号均使用的是bxCAN这个IP核,该IP核工作非常稳定,以至于从STM32F1系列到STM32F7系列均使用此IP核。下列两张图分别为STM32F1C8Tx系列和STM32F767IITx的CAN配置界面。可以看到配置界面的选项完全相同。

bxCAN的配置例程非常多,应用广泛。FDCAN是2011年博世发布的改进版CAN,FDCAN的性能固然强悍,但是在实际项目中若是多个板之间通信的情况,难免需要让FDCAN兼容CAN通信。本文皆在介绍如何通过CubeMX配置FDCAN使之兼容CAN使用,并讨论和实践FIFO深度参数的实际作用。




使用特权

评论回复
沙发
突然下起雨|  楼主 | 2023-12-20 16:28 | 只看该作者
2.CubeMX配置FDCAN

首先,设置帧格式为传统模式,模式设置为正常模式;然后,设置“2”处的4个参数,这4个参数与bxCAN中4个决定波特率和采样位置的参数意义相同,具体计算下文介绍;最后设置接收FIFO和发送FIFO,该部分介绍同样在下文展开介绍。

使用特权

评论回复
板凳
突然下起雨|  楼主 | 2023-12-20 16:29 | 只看该作者
3.四个时间相关参数配置具体计算



此图是CAN的位时序图,其中SyncSeg部分的时间长度即Nominal Sync Jump Width,Bit segment 1即Nominal Time Seg1,Bit segment 2 即Nominal Time Seg2,而这三个参数的单位是时钟个数,故实际的时间长度即为时钟数乘以每个时钟的时间长度。

每个时钟的时间长度由进入CAN外设的时钟和Nominal Prescaler分频器共同决定。

例如本例中,四个参数分别为10,1,15,8,怎么来的呢?首先已知条件是输入CAN外设的时钟是120MHZ,想要的波特率是500KHZ即0.5MHZ。首先分频 120MHZ/10=12MHZ,然后每个周期的时钟数为1+15+8=24,最后算出波特率为12MHZ/12=0.5MHZ=500KHZ。

到这里想必屏幕前的你也有个疑惑,为啥是1,15,8三个值,别的行不?当然可以,不过要注意这三个值之间的关系决定着采样点的位置。由上图显而易见,BS1+SyncSeg大BS2小时,采样点后移,BS1+SyncSeg小BS2大时,采样点前移。采样点不宜太前或太后,一碗水端平即可
.

使用特权

评论回复
地板
突然下起雨|  楼主 | 2023-12-20 16:30 | 只看该作者
4.FIFO如何设置

使用特权

评论回复
5
突然下起雨|  楼主 | 2023-12-20 16:30 | 只看该作者
首先从整个CAN宏观来看FIFO在消息RAM中,该消息RAM总共有10KB,此RAM为CAN的专用RAM,和系统SRAM没有关系。此RAM已经划分好了每个区域的用途和大小,如下图。

使用特权

评论回复
6
突然下起雨|  楼主 | 2023-12-20 16:30 | 只看该作者
由此图可见接收FIFO的每个单元的深度均为64,无论帧长为多少,深度都是64,只不过在用作普通CAN时只用了前8个单元。每个FIFO总共有这样的单元64个,接收部分总共有这样的两个FIFO。即FIFO全压满时可以暂存128条信息,这非常利于批量处理信息。发送部分的FIFO与发送同理,只是空间小一些。当然,消息RAM是FDCAN1和FDCAN2公用的,在实际使用中如果两个FDCAN都是用了,分配FIFO时要注意。

在初期学习时发现大多数参考资料和历程均只用了1个FIFO单元,之后仔细看了数据手册才发现这些资源是不用白不用哦。

使用特权

评论回复
7
突然下起雨|  楼主 | 2023-12-20 16:31 | 只看该作者
5.发送、接收及准备工作代码实现
5.1准备工作
基本参数的初始化CubeMX已经自动生成了,我们需要在基本初始化后紧随其后添加准备工作,即接收FIFO设置和过滤器设置,代码如下。这部分直接插入在void MX_FDCAN1_Init(void)函数的用户代码段2即可。

使用特权

评论回复
8
突然下起雨|  楼主 | 2023-12-20 16:31 | 只看该作者
这段代码中的过滤器设置尤为重要,此处使用的是掩码模式,掩码模式和IP地址中的子网掩码原理一样,掩码为1的位必须与指定值相同才可通过,此代码中掩码为全0意味着将接收所有主机发来的信息。

使用特权

评论回复
9
突然下起雨|  楼主 | 2023-12-20 16:31 | 只看该作者
  /* USER CODE BEGIN FDCAN1_Init 2 */
    //配置RX滤波器   
    FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID
    FDCAN1_RXFilter.FilterIndex=0;                                  //滤波器索引                  
    FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    FDCAN1_RXFilter.FilterID1=0x0000;                               //32位ID
    FDCAN1_RXFilter.FilterID2=0x0000;                               //如果FDCAN配置为传统模式的话,这里是32位掩码
    if(HAL_FDCAN_ConfigFilter(&hfdcan1,&FDCAN1_RXFilter)!=HAL_OK) //滤波器初始化
                {
                        Error_Handler();
                }
    HAL_FDCAN_Start(&hfdcan1);                               //开启FDCAN
    HAL_FDCAN_ActivateNotification(&hfdcan1,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);
  /* USER CODE END FDCAN1_Init 2 */

使用特权

评论回复
10
突然下起雨|  楼主 | 2023-12-20 16:31 | 只看该作者
5.2发送
发送功能首先设置ID号,该ID号将被CAN总线上的其他主机的过滤器过滤。其次,设置帧类型和帧长度。帧长度设置时尤其要注意,不能直接敲数字上去,要用宏定义,比如8字节长度帧用宏定义FDCAN_DLC_BYTES_8 。

使用特权

评论回复
11
突然下起雨|  楼主 | 2023-12-20 16:31 | 只看该作者
其次该发送函数的套路不同UART\SPI\I2C等,没有区分软件轮询方式、中断方式和DMA方式,而是一个添加信息到FIFO的函数。该函数的功能是,添加当前信息到发送FIFO中,并给FDCAN发送一个发送数据请求。该函数是非阻塞的,不会等着数据发送完毕,所以在批量发送数据时需要注意发送FIFO单元使用数目和每次批量传输数量以及传输时间间隔之间的关系,避免FIFO溢出丢失数据。

使用特权

评论回复
12
突然下起雨|  楼主 | 2023-12-20 16:31 | 只看该作者
uint8_t FDCAN1_Send_Msg(uint8_t* msg,uint32_t len)
{       
    fdcan1_TxHeader.Identifier=0x12;                           //32位ID
    fdcan1_TxHeader.IdType=FDCAN_STANDARD_ID;                  //标准ID
    fdcan1_TxHeader.TxFrameType=FDCAN_DATA_FRAME;              //数据帧
    fdcan1_TxHeader.DataLength=len;                            //数据长度
    fdcan1_TxHeader.ErrorStateIndicator=FDCAN_ESI_ACTIVE;            
    fdcan1_TxHeader.BitRateSwitch=FDCAN_BRS_OFF;               //关闭速率切换
    fdcan1_TxHeader.FDFormat=FDCAN_CLASSIC_CAN;                //传统的CAN模式
    fdcan1_TxHeader.TxEventFifoControl=FDCAN_NO_TX_EVENTS;     //无发送事件
    fdcan1_TxHeader.MessageMarker=0;                           
   
    if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1,&fdcan1_TxHeader,msg)!=HAL_OK) return 1;//发送
    return 0;       
}

使用特权

评论回复
13
突然下起雨|  楼主 | 2023-12-20 16:31 | 只看该作者
5.3接收
接收也是同理,不是等着数据来,而是去FIFO里面看一圈,有数据就带回来,没有就不管了,所以此函数的返回值在实际使用时是非常重要的,如果FIFO 空了则会返回0,如果没有空返回会大于0,此时应当继续读取。同时,此函数还需要带回来每条信息对应的主机号(ID号)。

使用特权

评论回复
14
突然下起雨|  楼主 | 2023-12-20 16:32 | 只看该作者
详细代码如下。

uint8_t FDCAN1_Receive_Msg(uint8_t *buf, uint16_t *Identifier)
{       
    if(HAL_FDCAN_GetRxMessage(&hfdcan1,FDCAN_RX_FIFO0,&fdcan1_RxHeader,buf)!=HAL_OK)return 0;//接收数据
        *Identifier = fdcan1_RxHeader.Identifier;
        return fdcan1_RxHeader.DataLength>>16;       
}

使用特权

评论回复
15
突然下起雨|  楼主 | 2023-12-20 16:32 | 只看该作者
6.调试
CAN总线协议属于链路层协议,在使用时必须有完好可以使用的物理层做支持,但是在调试时,不确定物理层是否正常工作时,可以先调试链路层的设置是否正确。此时需要用到回环模式。STM32H7的FDCAN有内部回环和外部回环两种,常用的是内部回环模式。内部回环模式将完全断开与CAN相连接的IO,并置Tx引脚为1。而外部回环模式可以用于物理层测试,此时需要有另一台可以在正常模式下工作的主机,使用外部回环模式会将数据在内部直接接收的同时从CAN的Tx引脚发送出去,若另一台主机此时正确接收了消息,则证明测试主机的物理层的发送功能完好。

使用特权

评论回复
16
突然下起雨|  楼主 | 2023-12-20 16:32 | 只看该作者

使用特权

评论回复
17
突然下起雨|  楼主 | 2023-12-20 16:32 | 只看该作者
7.实践
上述代码少写入左边的小板子,右边是原子哥的阿波罗开发板(核心板为STM32F429IGT6),使用原子哥的板子发送信息,左边的小板子接收到后返回相同的信息。对比原子哥开发板屏幕上的发送和接收信息即可验证功能。

使用特权

评论回复
18
突然下起雨|  楼主 | 2023-12-20 16:32 | 只看该作者

使用特权

评论回复
19
突然下起雨|  楼主 | 2023-12-20 16:32 | 只看该作者
其次,进一步验证FIFO的作用,这里使用限制轮询和回复消息间隔的方法来验证,验证左边的小板子必须隔500ms才能接受一条消息,并回复一条消息。这样,用原子哥的板子连续发送多条,若在此后每隔500ms,回复一条,且没有遗漏,则说明FIFO起到了作用。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

38

主题

284

帖子

1

粉丝