STM32 CAN接收FIFO细节

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):
    • 通过软件设置RFOM=1,FIFO中的消息将被释放。
    • 每次释放一个消息,FMP位会相应减少,表示FIFO中待处理的消息数减少。

CAN的接收FIFO寄存器

在这里插入图片描述

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

RFOM0

  1. RFOM0位描述

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

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

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

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

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

FOVR0

  1. FOVR0位描述

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

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

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

FULL0

  1. FULL0位描述

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

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

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

FMP0

  1. FMP0[1:0]位描述

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

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

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

接收报文

  1. FIFO的邮箱深度:

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

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

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

    • 当FIFO接收到一个新报文时,FIFO的管理硬件会更新FMP(FIFO消息挂起)位,并且如果CAN中断使能寄存器(CAN_IER)中的FMPIE位被设置,将会产生一个接收中断请求。这允许软件通过中断服务例程来处理接收到的数据。
    • 如果FIFO已满(即存储了3个报文),CAN接收FIFO寄存器(CAN_RFxR)的FULL位会被置1。如果CAN_IER寄存器的FFIE位被设置,将会产生一个“FIFO满”中断请求。
    • 当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. 参数检查

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

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

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

    • 将读取到的消息挂起位的值转换为uint8_t类型,并作为函数的返回值返回。
    • 返回值表示了接收FIFO中待处理的消息数量。
### STM32H745 CAN FD 配置与示例 STM32H745 微控制器支持 CAN FD 功能,其配置方式与其他系列(如 G4 和 H7)相似,但在具体参数设置上可能有所不同。以下是基于 HAL 库的 STM32H745 的 CAN FD 初始化和使用的示例。 #### 初始配置 为了启用 CAN FD 功能,需要初始化 `hcan` 结构体并配置相关参数。以下是一个典型的初始化过程: ```c #include "stm32h7xx_hal.h" #include "stm32h7xx_hal_can.h" void MX_CAN_Init(void) { hcan.Instance = FDCAN1; // 配置仲裁阶段位定时器 hcan.Init.Prescaler = 8; // 波特率分频器 hcan.Init.SyncJumpWidth = 2; // 同步跳转宽度 hcan.Init.TimeSeg1 = 15; // 时间段 1 (TSEG1) hcan.Init.TimeSeg2 = 6; // 时间段 2 (TSEG2) hcan.Init.Mode = CAN_MODE_NORMAL; // 正常模式 hcan.Init.AutoBusOff = DISABLE; // 自动关闭总线禁用 hcan.Init.AutoWakeUp = ENABLE; // 自动唤醒使能 hcan.Init.AutoRetransmission = ENABLE; // 自动重传使能 // 数据阶段位定时器 hcan.Init.DataPrescaler = 2; // 数据波特率分频器 hcan.Init.DataSyncJumpWidth = 2; // 数据同步跳转宽度 hcan.Init.DataTimeSeg1 = 13; // 数据时间段 1 (DTSEG1) hcan.Init.DataTimeSeg2 = 3; // 数据时间段 2 (DTSEG2) if (HAL_OK != HAL_CAN_Init(&hcan)) { Error_Handler(); // 错误处理函数 } } ``` 上述代码中定义了 CAN FD 的两个主要部分:**仲裁阶段**和**数据阶段**的位定时器配置[^2]。这些参数决定了通信速率以及信号采样点的位置。 #### 发送消息 发送一条标准帧的消息可以通过如下方法完成: ```c static void CAN_SendMessage(uint32_t StdId, uint8_t *pData, uint8_t DLC) { CAN_TxHeaderTypeDef TxHeader; uint32_t Mailbox; TxHeader.StdId = StdId; // 标准ID TxHeader.ExtId = 0; // 扩展ID未使用 TxHeader.IDE = CAN_ID_STD; // 使用标准ID TxHeader.RTR = CAN_RTR_DATA; // 数据帧而非远程帧 TxHeader.DLC = DLC; // 数据长度码 if (HAL_OK == HAL_CAN_AddTxMessage(&hcan, &TxHeader, pData, &Mailbox)) { /* 消息成功加入队列 */ } else { /* 处理错误情况 */ } } // 调用示例 uint8_t data[] = {0x01, 0x02, 0x03, 0x04}; CAN_SendMessage(0x123, data, sizeof(data)); ``` 此代码片段展示了如何通过指定的标准 ID (`StdId`) 将一组数据发送到 CAN 总线上[^1]。 #### 接收消息 接收来自 CAN 总线的数据可以按照以下方式进行: ```c static void CAN_ReceiveMessage(CAN_HandleTypeDef* hcan, uint8_t* RxData) { CAN_RxHeaderTypeDef RxHeader; if (HAL_OK == HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData)) { /* 成功接收到消息 */ } else { /* 处理错误情况 */ } } // 调用示例 uint8_t received_data[8]; CAN_ReceiveMessage(&hcan, received_data); ``` 以上实现了从 FIFO 缓冲区读取接收到的信息,并将其存储至目标数组中。 --- ###
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YRr YRr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值