STM32 CAN接收FIFO细节

简介

  • CAN外设一共有2个接收FIFO,每个FIFO中有3个邮箱,即最多可以缓存6个接收到的报文。
  • FIFO状态

    1. EMPTY: 初始状态,表示FIFO为空,没有挂起的消息(FMP=0x00),且没有发生溢出(FOVR=0)。
    2. PENDING_1: 当接收到一个有效的CAN消息时,FIFO状态转变为PENDING_1。这时,FIFO中有一个待处理的消息(FMP=0x01),仍然没有溢出(FOVR=0)。
    3. PENDING_2: 如果在PENDING_1状态时收到另一个有效消息,则FIFO状态转变为PENDING_2。这时,FIFO中有两个待处理的消息(FMP=0x10),仍然没有溢出。
    4. PENDING_3: 类似地,如果在PENDING_2状态时收到第三个有效消息,FIFO状态变为PENDING_3,此时FIFO已满(FMP=0x11),但尚未发生溢出。
    5. OVERRUN: 如果FIFO已满(即处于PENDING_3状态),此时如果收到另一个有效消息,会发生溢出。在这种情况下,最早接收的消息会被新消息替代,并且FIFO的状态变为OVERRUN,其中FMP=0x11表示FIFO已满,FOVR=1表示发生了溢出。
    6. 处理溢出: 在OVERRUN状态,如果再次收到有效消息,FIFO维持OVERRUN状态,FOVR位继续保持为1,表示FIFO仍然处于溢出状态。软件应尽快读取FIFO以处理溢出情况。
    7. 释放邮箱(Release Mailbox):
    8. 通过软件设置RFOM=1,FIFO中的消息将被释放。
    9. 每次释放一个消息,FMP位会相应减少,表示FIFO中待处理的消息数减少。

    CAN的接收FIFO寄存器

    位数 作用描述
    位31:6 保留位,硬件强制为0
    位5 RFOM0: 释放接收FIFO 0输出邮箱 软件通过对该位置1来释放接收FIFO的输出邮箱。如果接收FIFO为空,那么对该位置1没有任何效果,即只有当FIFO中有报文时对该位置1才有意义。如果FIFO中有2个以上的报文,由于FIFO的特点,软件为了访问第2个报文,就需要释放输出邮箱才行。 当输出邮箱被释放时,硬件对该位清0。
    位4 FOVR0: FIFO 0 溢出 当FIFO 0已满,又收到新的报文且报文符合过滤条件,硬件对该位置1。 该位由软件清0。
    位3 FULL0: FIFO 0 满 当有3个报文被存入FIFO 0时,硬件对该位置1。 该位由软件清0。
    位2 保留位,硬件强制其值为0
    位1:0 FMP0[1:0]: FIFO 0 报文数目 FIFO 0报文数目这2位反映了当前接收FIFO 0中存放的报文数目。 每当1个新的报文被存入接收FIFO 0,硬件就对FMP0加1。 每当软件对RFOM0位写1来释放输出邮箱,FMP0就被减1,直到其为0。

    RFOM0

    1. RFOM0位描述

    2. RFOM0位用于释放接收FIFO 0的输出邮箱。
    3. 该位由软件操作,通过将其设置为1来实现释放FIFO 0的输出邮箱的功能。
    4. 软件通过对该位置1来释放接收FIFO的输出邮箱

    5. 软件可以通过将RFOM0位设置为1来触发释放FIFO 0的输出邮箱的操作。
    6. 如果接收FIFO为空,那么对该位置1没有任何效果

    7. 如果FIFO 0中没有待处理的报文,即FIFO为空,软件将RFOM0位置1不会产生任何效果。
    8. 这意味着只有在FIFO中存在待处理的报文时,才能成功地释放FIFO的输出邮箱。
    9. 如果FIFO中有2个以上的报文,由于FIFO的特点,软件为了访问第2个报文,就需要释放输出邮箱才行

    10. 在FIFO 0中,通常只有一个输出邮箱可以用于访问FIFO中的报文。
    11. 如果FIFO中有2个以上的报文,为了访问第2个报文,软件需要先释放输出邮箱,以便将第2个报文移至输出位置。
    12. 当输出邮箱被释放时,硬件对该位清0

    13. 当FIFO的输出邮箱被成功释放时,硬件会自动将RFOM0位清0,以便下一次软件操作。

    FOVR0

    1. FOVR0位描述

    2. FOVR0位用于指示FIFO 0是否发生了溢出。
    3. 当FIFO 0已满,并且接收到新的报文且该报文符合过滤条件时,硬件会将FOVR0位置1。
    4. 当FIFO 0已满,又收到新的报文且报文符合过滤条件,硬件对该位置1

    5. 如果FIFO 0已经存满了3个报文,而又收到了一个新的报文,并且该报文符合FIFO 0的过滤条件,硬件会将FOVR0位置1。
    6. 这表示FIFO 0发生了溢出,即新的报文无法被存储到FIFO 0中。
    7. 该位由软件清0

    8. FOVR0位的清零操作由软件执行。
    9. 一旦软件检测到FIFO 0发生了溢出并且已经处理了溢出情况后,软件会将FOVR0位手动清零。

    FULL0

    1. FULL0位描述

    2. FULL0位用于指示FIFO 0是否已满。
    3. 当FIFO 0中存放了3个报文时,硬件会将FULL0位置1。
    4. 当有3个报文被存入FIFO 0时,硬件对该位置1

    5. 当FIFO 0中存放的报文数量达到3个时,硬件会将FULL0位设置为1。
    6. 这表示FIFO 0已经达到了存储容量的上限,不能再容纳更多的报文。
    7. 该位由软件清0

    8. FULL0位的清零操作由软件执行。
    9. 一旦软件检测到FIFO 0已满的情况并且已经处理了相应的报文,软件会手动将FULL0位清零。

    FMP0

    1. FMP0[1:0]位描述

    2. FMP0[1:0]是FIFO 0报文数目位,由两个位组成,用于反映当前接收FIFO 0中存放的报文数目。
    3. 每当1个新的报文被存入接收FIFO 0,硬件就对FMP0加1

    4. 每当CAN控制器接收到一个新的报文并存入FIFO 0时,硬件会自动将FMP0加1。
    5. 这表示FIFO 0中存放的报文数目增加了,以反映新接收到的报文。
    6. 每当软件对RFOM0位写1来释放输出邮箱,FMP0就被减1,直到其为0

    7. 软件通过将RFOM0位设置为1来释放FIFO 0的输出邮箱,以便访问FIFO中的下一个消息。
    8. 每次释放输出邮箱时,软件会将FMP0减1。
    9. 当FIFO 0的输出邮箱释放完毕,即FIFO 0为空时,FMP0将减至0。

    接收报文

    1. FIFO的邮箱深度:

    2. 接收到的CAN报文被存储在一个具有3级邮箱深度的FIFO中。这意味着FIFO可以存储最多3个报文。
    3. FIFO的管理完全由硬件完成,这样可以减轻CPU的处理负担,简化软件逻辑,并确保数据的一致性。
    4. 报文的读取:

    5. 应用程序读取FIFO中的报文时,只能按照报文到达的顺序(先到先得)读取。
    6. 当应用程序从FIFO中读取一个报文后,FIFO会自动将下一个报文移动到输出位置。
    7. 报文的有效性:

    8. 报文在接收过程中如果没有出现任何错误,并且通过了标识符过滤,就被认为是有效的报文。
    9. 接收中断条件:

    10. 当FIFO接收到一个新报文时,FIFO的管理硬件会更新FMP(FIFO消息挂起)位,并且如果CAN中断使能寄存器(CAN_IER)中的FMPIE位被设置,将会产生一个接收中断请求。这允许软件通过中断服务例程来处理接收到的数据。
    11. 如果FIFO已满(即存储了3个报文),CAN接收FIFO寄存器(CAN_RFxR)的FULL位会被置1。如果CAN_IER寄存器的FFIE位被设置,将会产生一个“FIFO满”中断请求。
    12. 当FIFO发生溢出(即有新报文到达但FIFO已满)时,FOVR(FIFO溢出)位被置1。如果CAN_IER寄存器的FOVIE位被设置,将会产生一个“FIFO溢出”中断请求。

    主要函数接口

    CAN_Receive

    /**
      * @brief  Receives a correct CAN frame.
      * @param  CANx: where x can be 1 or 2 to select the CAN peripheral.
      * @param  FIFONumber: Receive FIFO number, CAN_FIFO0 or CAN_FIFO1.
      * @param  RxMessage: pointer to a structure receive frame which contains CAN Id,
      *         CAN DLC, CAN data and FMI number.
      * @retval None
      */
    void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage);
    

    CAN_Receive 函数的作用可以归纳如下:

    1. 从指定的CAN控制器的接收FIFO中读取接收到的CAN消息。
    2. 将读取到的消息的各个字段(如标识符、数据、数据长度等)提取出来,并存储到提供的 CanRxMsg 结构体中。
    3. 根据接收到的消息的类型(标准帧或扩展帧),正确提取相应的标识符,并存储到结构体的相应字段中。
    4. 将消息的远程传输请求位、数据长度码和过滤器索引等信息提取出来,并存储到结构体的相应字段中。
    5. 将消息的数据部分按字节提取出来,并存储到结构体的数据数组中。
    6. 释放相应的接收FIFO的输出邮箱,以便下一次读取。

    CAN_MessagePending

    /**
      * @brief  Returns the number of pending received messages.
      * @param  CANx: where x can be 1 or 2 to select the CAN peripheral.
      * @param  FIFONumber: Receive FIFO number, CAN_FIFO0 or CAN_FIFO1.
      * @retval NbMessage : which is the number of pending message.
      */
    uint8_t CAN_MessagePending(CAN_TypeDef* CANx, uint8_t FIFONumber);
    
    1. 参数检查

    2. 首先对传入的CAN控制器和FIFO编号进行有效性检查,确保它们满足CAN控制器的要求。
    3. 检查消息挂起情况

    4. 根据传入的FIFO编号,检查相应的接收FIFO中是否有消息挂起等待处理。
    5. 读取消息挂起位

    6. 通过位掩码操作,从相应的寄存器(RF0R或RF1R)中读取消息挂起位的值。
    7. 返回消息挂起数量

    8. 将读取到的消息挂起位的值转换为uint8_t类型,并作为函数的返回值返回。
    9. 返回值表示了接收FIFO中待处理的消息数量。

    作者:YRr YRr

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32 CAN接收FIFO细节

    发表回复