MCU:H743野火挑战者 其他文章: STM32H743 FDCAN通信 接收中断如何实现 如何计算并设置CAN外设的波特率(基于STM32H7和HAL库) STM32H743 FDCAN FIFO接收管理分析(HAL库)
前言
在CAN专属的消息RAM中,存在32个TX缓冲区,32个TX事件FIFO。每个里面都存在1个元素,一共有64个元素,对应64个报文。
TX缓冲区
每一个TX缓冲区可以配置一个ID,即对应一个报文。缓冲区内不仅仅只有报文的内容,还有报文的类型、ID等相关信息,官方定义这样一个整体叫element,叫元素。下面是每个元素都有什么内容。 (1) 位 ESI:当检测到错误时是否将发送错误标志。 (2) 位 XTD:决定接受 ID 的位数是 11 位还是 29 位。1 表示 29 位扩展格式的 ID,0 表示 11 位标准格式的 ID。 (3) 位 RTR:遥控帧标识符。用于向远端节点请求数据。 (4) ID[28:0]:用来存放 ID。ID 的位数由 XTD 位决定。若 ID 是 11 位的,则存放在 ID[28:18]位中。 (5)MM:信息识别标志,发送数据时,会被拷贝到发送事件 FIFO 中。 (6) EFC:是否使用事件 FIFO 的功能。 (7) 位 ANMF:决定 FDCAN 是否接收不匹配的数据帧。 (8) FIDX[6:0]:验收筛选器的编号; (9) FDF:决定数据帧的格式。可选择标准帧格式(该位为 0)和 FDCAN 帧格式(该位为 1)。 (10) BRS:主要用 FDCAN 的 FFM 模式。传输数据阶段是否进行位时序切换。 (11) DLC:数据长度码,CAN 一般可接受 8 个字节,而 FDCAN 能够接受 12/16/20/24/32/48/64个字节。 (12) DBn:数据段,FDCAN 最大支持 64 个字节数据,可通过配置寄存器 RXESC 进行修改。
总结起来,就是一系列的标志位+数据段。在这部分TX缓存区又可以分为3钟类型,专门发送缓存区、发送FIFO、发送队列。千万不要混淆TX缓冲区和专门发送缓存区,他们是包含的关系。TX缓存区包括专门发送缓存区。
1.专门发送缓存区
专用发送缓冲区可完全在 CPU 的控制下发送消息。每个专用发送缓冲区都配置了特定的消 息 ID。如果多个发送缓冲区配置为使用同一消息 ID,则会先发送缓冲区编号最小的发送缓存区中的消息。发送分两步,一步是装数据,第二步请求发送。如果数据部分已更新,则会通过添加请求的 TXBAR[ARn] 位请求发送。请求的消息在内部会与发送 FIFO 或发送队列中的消息进行仲裁,在外部会与 CAN 总线上的消息进行仲裁, 并会根据其消息 ID 发送出去。所以消息仲裁不仅要与外部CAN总线上的消息进行仲裁,还需要与内部其他两种类型消息进行仲裁。 HAL是通过上述两个函数进行消息的传入和发出,最后一个参数一共有32个buffer。所以装入哪个buffer,发出哪个buffer是需要靠代码实现的,这是最灵活的。
2.发送FIFO
发送 FIFO 中存储的消息是先 从【获取索引】 TXFQS[TFGI] (某个寄存器标志位)引用的消息开始发送的。每次发送后,获取索引会循环递增,直至发送 FIFO 为空。如下图所示,先发【获取索引】对应的元素。发送 FIFO 可按消息写入发送 FIFO 的顺序发送来自不同发送缓冲区但消息 ID 相同的消息。前面专门发送缓存区,是按照缓冲区编号顺序一个个发,从小发到到,是不管ID的。而发送FIFO发送的时候,是允许把不同缓存区的相同ID的消息发出。 如果要存入新元素,那就存入【放入索引】对应的位置,然后【放入索引】就会递增,指向新的空白位置。如果【放入索引】到达了【获取索引】的位置,那证明发送FIFO已经满了。HAL库是通过下列这条函数存入发送FIFO的。 如果有一条消息添加到发送 FIFO,则会通过向与发送 FIFO 【放入索引】引用的发送缓冲区相关的 TXBAR 位写入“1”来请求发送消息。
如果有多条 (n) 消息添加到发送 FIFO,则会写入以【放入索引】开始的 n 个连续发送缓冲区中。 随后会通过 TXBAR 请求发送。【放入索引】随后会循环递增 n。请求的发送缓冲区数不应超过 发送 FIFO 空闲级别指示的空闲发送缓冲区数。
3.发送队列
送队列中存储的消息是先从消息 ID 最小(优先级最高)的消息开始发送的。如果多个队列缓冲区配置为使用同一消息 ID,则会先发送缓冲区编号最小的队列缓冲区。看对这里大家可以明白,3种发送类型区域其实就是发送的优先级不一样。
4.三者区别
特点 | 专用发送缓存区 | 发送FIFO | 发送队列 |
---|
配置的部分 | 可以配置32个缓存区 | 只有一个发送FIFO配置 | 只有一个发送队列可以配置 | 每部分的元素 | 每个缓存区最多一个元素 | 每部分可以包含0-32个元素 | 每部分可以包含0-32个元素 | 优先级 | ID小的优先 | 按照存入的先后顺序发 | ID小的优先 | 相同ID的优先级 | buffer编号小的优先 | 无关 | 无关 | 在RAM的位置 | 用户自己挑选 | 自动管理 | 自动管理(索引自动递增) | 待发元素管理 | 用户使能发送 | 自动使能 | 自动使能 |
5.灵活的传输配置
在下列这种情况下,消息 RAM 中的发送缓冲区部分会被划分为一组专用发送缓冲区和一个发送 FIFO。 发送优先次序:
- 扫描专用发送缓冲区和发送 FIFO 缓冲区的【获取索引】对应的ID。
- 专用TX缓存区优先级最高的是ID3对应的消息,TX FIFO消息级最高的是【获取索引】对应ID4的消息,两者对比,ID3比较小,先发ID3对应的消息。
- 然后继续扫描,ID8和ID4比较,ID4比较小,先发ID4,【获取索引】指向ID2。
- 继续扫描,专用缓存区最小的ID8和ID2比较,先发ID2.
- 以此重复扫描。
- 如果相同ID的话,那就先存入这里的先发。
在下列这种情况下,消息 RAM 中的发送缓冲区会被划分为一组专用发送缓冲区和一个发送队列。 发送优先级:扫描所有激活了发送请求的发送缓存区,优先级直接看ID,ID最小的先发。如果相同ID,先激活请求的先发。前面表格写着队列的请求是自动激活的,所以相当于先存入的先发。 他们具体的数量配置需要在CAN初始化中设置,代码如下。
发送管理单位
上一部分是发送报文存放的地方,就是类似于快递中心存放快递的大仓库,发送管理单位就是负责这些快递如何发送的办公室,大家一起商量用什么方式发。就是下图CAN子系统箭头所指的地方。 发送管理单元会把报文转发给CAN内核,然后CAN内核就会对外发送信息。CAN发送的数据段为8-16个字节。FDCAN 主要有三种模式可以选择,分别是标准的 CAN 协议,即 Classic CAN,要求数据段长度小于 8字节;还有 FDCAN 模式,又可以分为 FFM 和 LFM。第一种要求用较高的比特率传输数据段的内容,对应图 CAN 发送配置 的最后一种配置;第二种是传输的数据段长度超过了 8个字节,对应了第三、第五的配置。
发送报文头部结构体
前面讲过一个元素除了包含报文数据段,还包含很多标志。HAL专门定义了一个发送报文头部结构体去定义这些标志。
- Identifier:本成员存储的是报文的 11 位标准标识符,范围是 0-0x7FF。或者是报文的 29 位扩展标识符,范围是
0-0x1FFFFFFF。ExtId 与 StdId 这两个成员根据下面的 IDE 位配置,只有一个是有效的。 - IdType:本成员存储的是扩展标志 IDE 位,当它的值为宏 FDCAN_STANDARD_ID 时表示本报文是标准帧,使用 StdId 成员存储报文 ID;当它的值为宏 FDCAN_EXTENDED_ID 时表示本报文是扩展帧,使用 ExtId 成员存储报文 ID。
- TxFrameType:发送报文的类型可选数据帧或者遥控帧。 DataLength:数据帧数据段的长度。
- ErrorStateIndicator:错误状态标识符。处于主动错误状态(FDCAN_ESI_ACTIVE)的节点,当检测到错误时将发送错 误标志;处于被动错误状态(FDCAN_ESI_PASSIVE)的节点不能发送主动错误标志。
- BitRateSwitch:本成员存储的是数据段的位时序切换功能。主要用于 FDCAN 的 FFM 模式。
- FDFormat:本成员存储的就是数据帧的数据格式。可以选择标准的 CAN 协议和 FDCAN 模式。
- TxEventFifoControl:本成员用于配置是否使用发送事件 FIFO,发送事件 FIFO 主要用来存放一些消息的标志。
- MessageMarker:本成员用来定义个消息的标志。假如使能发送事件 FIFO 的功能,则该值会被拷贝到发送事件FIFO 中。
FDCAN发送步骤
首先把发送数据的头部信息定义好,然后利用HAL_FDCAN_AddMessageToTxBuffer把消息存入BUFFER0。目前这个状态消息仅仅只是存进缓存区,并没有发送。 接着利用HAL_FDCAN_EnableTxBufferRequest函数使能发送BUFFER0的消息。我们具体看看函数内部怎么完成发送操作的。函数内容将缓存区编号赋值给TXBAR。 TXBAR是FDCAN的一个寄存器,全称FDCAN 发送缓冲区添加请求寄存器,专门负责添加请求的。类似在说:我准备好了,可以出发。 寄存区一共32位,对应32个发送缓存区。每个发送缓冲区都有自己的添加请求位。写入“1”会将相应的添加请求位置 1 ;写入“0”没有影响。这样,主机通过对 TXBAR 进行一次写操作便可为多个发送缓冲区设置发送请求。多个发送缓存区设置的话想,用或操作就行,如下图所示。 前面有讲到,FIFO和队列的发起请求是自动完成,无需函数操作。完成这两步之后,剩下的就是硬件自己的事了,不需要我们去控制。
接下来看一下HAL有关于发送的另一个函数,函数内部判断了TXBRP(就是上面那个寄存器)对应位是否等于0。如果等于0,根据上面寄存器说明,没有添加请求。如果等于1,则是添加了请求。所以这个函数的目的就是检测某个缓存器有没有添加发送请求。
参考资料 《H74X3 参考手册》
|