MCU:H743野火挑战者 其他文章: STM32H743 FDCAN通信 接收中断如何实现 如何计算并设置CAN外设的波特率(基于STM32H7和HAL库)
前言
H743具备两个接收FIFO,分别是FIFO 0和FIFO 1,功能相同;H743提供的是FDCAN,FDCAN扩展帧允许单个消息中发送64个数据字节,而CAN 2.0有效负载数据最多可以发送8个字节。
当FDCAN接收到报文,经过过滤器过滤后,会将报文存储到FIFO或RX buffer中(可选,本文仅分析进入FIFO)。对于标准帧,H7提供了128个过滤器;对于扩展帧,H7提供了64个过滤器,每个过滤器都有一个自己的编号。各个过滤器处于并联关系,即只要通过一个过滤器就可以进入FIFO。那进入FIFO后,H7是如何保存这些报文,又是如何读取这些报文,并辨析报文对应何内容?这是本文想要探索的问题。
RAM过滤区
FDCAN外设可以配置两套验收滤波器:一套用于标准标识符,一种是扩展标识符,用于存储或拒绝接收到的消息。针对标准帧有128个元素,扩展帧则有64个元素。而滤波器的元素保存的是滤波器的基本设定,比如过滤的模式、ID等信息。 滤波器相当于审核的大门,这个大门可以设定在某个接收区域,比如FIFO 0或FIFO 1或RX buffer。如下图的代码, 则将标准滤波器0号安排给RXFIFO0守大门。 每个接收区域都可能不止一个滤波器,一般会从编号比较小的开始审核,如果通过了,就不再进行后面的审核。
接收区
下图是FDCAN外设对应消息RAM。图上显示FIFO0区域最多64个元素。在FDCAN中,消息的接收和发送意味着在RAM级别存储“元素”。 这个“元素”仅包含标识符,DLC,控制位(ESI,XTD,RTR,BRS,FDF),数据字段和特定的发送/接收位字段进行控制。就是一些信息+数据段。 一个FIFO元素,包含前面2个字(32位)的标识符内容,还有后面部分真正的数据段。 介绍部分标识符: XTD:标准帧还是扩展帧; RTR:数据帧还是扩展帧; ID:标准帧的话11位ID,扩展帧的话29位ID; FIDX:过滤器索引,代表这条报文是经过了哪条过滤器审核才进来的。加入一个过滤器只通过一个ID,那么我们就可以通过读取这个过滤器索引得知这个报文属于哪个ID。虽然说读索引效率比读ID效率高那么一丢丢,但是直接读ID不香吗? 每个元素的数据段都是可以设置的,最多64字节。前面两个固定2个字,后面数据x个字,x主要取决于接收的数据到底有多长。如果数据8个字节,则每个元素为数据分配2个字,再加上前面2个字,一共就是4个字,对应下表第一行。下表详细介绍了必要的“元素”大小,具体取决于数据字段范围。 而FIFO 0 包含64个这样的元素,理论上是可以同时保存64个报文。收到的报文通过滤波器后就会被整合成一个元素,放在FIFO 0这片区域。如果Rx FIFO已满(即传入超过64个报文且不读取),则可以根据两种不同模式来处理新到达的元素:
(1)阻塞模式:这是Rx FIFO的默认操作模式,没有其他元素写入RxFIFO,直到至少一个元素已被读出。 (2)覆盖模式:Rx FIFO中接受的新元素将覆盖Rx FIFO中最旧(最先接收的数据)的元素并且FIFO的put和get索引加1。
所以只要报文接收的速度没那么快,滤波器设置严格一点,读的勤快一点,FIFO还是没那么容易溢出的,毕竟有64个。
要从Rx FIFO读取元素,CPU必须执行以下步骤: (1)读取寄存器FDCAN_RXF0S(FDCAN 接收 FIFO 0 状态寄存器)以了解FIFO 0的状态。 位24 F0F:0代表接收FIFO 0已满;1代表接收FIFO 0未满; 位21:16 F0PI 接收 FIFO 0 写入索引指针,范围为 0 到 63,即新的报文放在哪个位置; 位13: 8 F0GI 接收 FIFO 0 读取索引指针,范围为 0 到 63,即读取下一个报文从哪里开始读起; 位 6: 0 F0FL 接收 FIFO 0 中存储的元素数,范围为 0 到 64,即装了多少个未读的元素了。
(2)按照以下公式计算RAM中最旧的元素的地址: Oldest element address = CAN_message_RAM_base_address + FDCAN_RXF0C.F0SA (start address) + FDCAN_RXF0S.F0GI (get Index) x Rx FIFO_element_size. 解释:CAN 消息RAM起始地址+FIFO的起始地址+读取索引指针*元素大小
(3)从计算出的地址中读取元素。
CPU从Rx FIFO读取一个元素或一系列元素后,它必须确认读取。确认后,FDCAN可以将相应的Rx FIFO缓冲区重新用于新元素。为了确认一个或多个元素,则CPU必须将从Rx FIFO读取的最后一个元素的缓冲区索引写入FDCAN_RXF0A(FDCAN 接收 FIFO 0 确认寄存器)。结果,FDCAN更新了FIFO填充级别和get索引。
这个寄存器位5:0为F0AI:主机从接收 FIFO 0 读取消息或消息序列后,必须将从接收 FIFO 0 读取的最后一个元素的 缓冲区索引写入 F0AI 中。此操作会将接收 FIFO 0 获取索引 RXF0S[F0GI] 设为 F0AI + 1,并会更新 FIFO 0 填充级别 RXF0S[F0FL]。通俗点讲,这个寄存器的值会传给上面那个状态寄存器,包括新的获取索引和填充级别。比如读完第4个元素,那获取索引应该是5。
看了这么多,觉得很复杂的朋友不用慌。上述过程HAL库已经整合成了一个函数。需要的时候引用就好,至于获取索引,填充级别之类的,函数内部已经设置好了。 虽说FIFO 0有64个元素,但不是默认就是使用64个的。需要自己设定使用多少个,多于设定值那就叫满溢。 下面还可以设置每个元素的数据段多少字节,还有FIFO 1的一些参数。这个在STM32 CubeMX就可以设置,生成的工程自带这些代码。
通过这篇文章,我们可以了解到FIFO是如何把通过滤波器的报文保存下来的,又是如何读取的。FIFO 1和RX BUFFER是同样的道理。在报文传递速度低的情况下, 只要函数内部保证读取的速度,其实就能保证FIFO不溢出。如果存在溢出,那么就得考虑滤波器的设置和满溢中断函数了。
参考 STM32之CAN—接收管理分析 STM32H7的CAN FD教程笔记
|