本文主要是介绍【STM32H7教程】第91章 STM32H7的FDCAN总线基础知识和HAL库API,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980
第91章 STM32H7的FDCAN总线基础知识和HAL库API
本章节为大家讲解FDCAN的基础知识和对应的HAL库API。CAN FD中的FD含义就是flexible data,灵活数据通信,且波特率可以和仲裁阶段波特率不同
目录
91.1 初学者重要提示
91.2 FDCAN基础知识
91.2.1 CAN FD协议介绍
91.2.2 CAN FD特性
91.2.3 CAN FD格式
91.2.4 CAN FD相比CAN2.0的提升
91.3 FDCAN总线的HAL库用法
91.3.1 FDCAN总线结构体FDCAN_GlobalTypeDef
91.3.2 FDCAN总线时间触发结构体TTCAN_TypeDef
91.3.3 FDCAN总线初始化结构体FDCAN_InitTypeDef
91.3.4 FDCAN总线消息RAM地址FDCAN_MsgRamAddressTypeDef
91.3.5 FDCAN总线过滤结构体FDCAN_FilterTypeDef
91.3.6 FDCAN总线消息发送结构体FDCAN_TxHeaderTypeDef
91.3.7 FDCAN总线消息接收结构体FDCAN_RxHeaderTypeDef
91.3.8 FDCAN总线句柄结构体FDCAN_HandleTypeDef
91.4 FD CAN总线源文件stm32h7xx_hal_fdcan.c
91.4.1 函数HAL_FDCAN_Init
91.4.2 函数HAL_FDCAN_DeInit
91.4.3 函数HAL_FDCAN_ConfigFilter
91.4.4 函数HAL_FDCAN_ConfigFifoWatermark
91.4.5 函数HAL_FDCAN_ActivateNotification
91.4.6 函数HAL_FDCAN_Start
91.4.7 函数HAL_FDCAN_AddMessageToTxFifoQ
91.4.8 函数HAL_FDCAN_GetRxMessage
91.5 总结
91.1 初学者重要提示
- FDCAN基础知识点可以看第90章,已经进行了详细说明
- 特别推荐瑞萨的CAN入门中英文手册,做的非常好:地址链接
91.2 FDCAN基础知识
FDCAN的基础知识在本教程的第90章进行了非常详细的说明。我们这里将本章用到的几个知识点再做个说明,详情推荐看第90章。
91.2.1 CAN FD协议介绍
STM32H7的CAN FD符合ISO 11898-12015标准。STM32器件上的FDCAN的功能如下所示:
(1)符合CAN协议2.0版A,B和ISO 11898-1:2015,-4。
(2)可访问的10 KB RAM内存,最多可分配2560个字。
(3)改进了接收过滤。
(4)两个可配置的接收FIFO。
(5)多达64个专用接收缓冲区。
(6)接收高优先级消息时的单独信令。
(7)多达32个专用发送缓冲区。
(8)可配置的发送FIFO和发送队列。
(9)可配置的发送事件FIFO。
(10)时钟校准单元。
(11)收发器延迟补偿。
下图说明了FDCAN框图。
通过这个框图要了解到以下信息:
(1)CANFD1和CANFD2共用一个RAM空间。
(2)每个CANFD都有自己的内核。
(3)CAN内核实现协议控制和收发移位寄存器。
(4)Tx handler控制消息从CAN消息RAM到CAN内核。
(5)Rx handler控制CAN内核到CAN消息RAM。
91.2.2 CAN FD特性
(1)兼容经典CAN,可以遵循ISO 11898-1做数据收发。
(2)提升错误检测,支持高达CRC 21位的校验和。
(3)消息优先级。
(4)保证延迟时间。
(5)配置灵活性。
(6)具有时间同步的组播接收。
(7)系统范围内的数据一致性,每条消息最多64个字节。
(8)多主机。
(9)错误检测和信号。
(10)区分节点的临时错误和永久性故障以及自动关闭缺陷节点。
91.2.3 CAN FD格式
第一个仲裁阶段(The first arbitration phase)是一条消息,其中包含:
(1)帧开始(SOF)。
(2)ID号和其他位,指示消息的目的(提供或请求数据),以及速度和格式配置(CAN或CAN-FD)。
数据传输阶段(The data transmission phase)包括:
(1)数据长度代码(DLC),指示消息包含多少数据字节。
(2)用户希望发送的数据。
(3)检查循环冗余序列(CRC)。
(4)显性位。
第二个仲裁阶段(The second arbitration phase)包含:
(1)总线上其他节点发送的确认(ACK)的接收器(如果至少有一个接收器成功收到消息)
(2)帧尾(EOF),在IFS期间不传输任何消息:目标是将当前帧与下一帧分开。
注意:对于29bit标识符帧,当添加18bit标识到第1个仲裁阶段的IDE bit之后与标准CAN FD是类似的。
91.2.4 CAN FD相比CAN2.0的提升
CAN-FD的开发可以满足需要更高带宽的通信网络需求。每帧最多具有64个字节的CAN-FD以及将比特率提高到最大的可能性,使数据阶段要快8倍,在第二个仲裁阶段要恢复到正常的比特率。通过以下方式确保数据传输的完整性:
(1)17级多项式对最大16字节的有效载荷进行CRC。
(2)21级多项式对16到64字节之间的有效载荷进行校验。
标准帧和CAN FD的区别:
标识符后,CAN 2.0和CAN-FD具有不同的作用:
(1)CAN 2.0发送RTR位以精确确定帧类型:数据帧(RTR为主要)或远程帧(RTR)是隐性的)。
(2)由于CAN-FD仅支持数据帧,因此始终发送占优势的RRS(保留)。
IDE位保持在相同位置,并以相同的动作来区分基本格式(11位标识符)。请注意,在扩展格式的情况下,IDE位以显性或隐性方式传输(29位标识符)。
与CAN 2.0相比,在CAN-FD帧中,在控制字段中添加了三个新位:
(1)扩展数据长度(EDL)位:隐性表示帧为CAN-FD,否则该位为显性(称为R0)在CAN 2.0帧中。
(2)比特率切换(BRS):指示是否启用两个比特率(例如,当数据阶段位以不同的比特率传输到仲裁阶段)。
(3)错误状态指示器(ESI):指示节点处于错误活动模式还是错误被动模式。
控制字段的最后一部分是数据长度代码(DLC),它具有相同的位置和相同的长度(4位),用于CAN 2.0和CAN-FD。 DLC功能在CAN-FD和CAN 2.0中相同,但CAN-FD有很小变化(下表中的详细信息)。 CAN-FD扩展帧允许单个消息中发送64个数据字节,而CAN 2.0有效负载数据最多可以发送8个字节。
通过增加有效载荷数据的数据字段来改善网络带宽,因为需要更少的包处理。 同时,通过为CRC添加更多位来增强消息完整性:
(1)如果有效载荷数据最多为16个字节,则CRC以17位编码。
(2)如果有效载荷数据大于20(16)个字节,则CRC以21位编码。
另外,为了确保CAN-FD帧的鲁棒性,填充位机制支持CRC字段。下表总结了CAN-FD和CAN 2.0之间的主要区别。 提供的主要功能与CAN 2.0相比,CAN FD的改进之处在于数据有效负载的增加和速度的提高由CAN-FD中可用的BRS,EDL和ESI位来确保。
91.3 FDCAN总线的HAL库用法
91.3.1 FDCAN总线结构体FDCAN_GlobalTypeDef
FD CAN总线相关的寄存器是通过HAL库中的结构体FDCAN_GlobalTypeDef定义,在stm32h743xx.h中可以找到这个类型定义:
typedef struct
{__IO uint32_t CREL; __IO uint32_t ENDN; __IO uint32_t RESERVED1; __IO uint32_t DBTP; __IO uint32_t TEST; __IO uint32_t RWD; __IO uint32_t CCCR; __IO uint32_t NBTP; __IO uint32_t TSCC; __IO uint32_t TSCV; __IO uint32_t TOCC; __IO uint32_t TOCV; __IO uint32_t RESERVED2[4];__IO uint32_t ECR; __IO uint32_t PSR; __IO uint32_t TDCR; __IO uint32_t RESERVED3; __IO uint32_t IR; __IO uint32_t IE; __IO uint32_t ILS; __IO uint32_t ILE; __IO uint32_t RESERVED4[8];__IO uint32_t GFC; __IO uint32_t SIDFC; __IO uint32_t XIDFC; __IO uint32_t RESERVED5; __IO uint32_t XIDAM; __IO uint32_t HPMS; __IO uint32_t NDAT1; __IO uint32_t NDAT2; __IO uint32_t RXF0C; __IO uint32_t RXF0S; __IO uint32_t RXF0A; __IO uint32_t RXBC; __IO uint32_t RXF1C; __IO uint32_t RXF1S; __IO uint32_t RXF1A; __IO uint32_t RXESC; __IO uint32_t TXBC; __IO uint32_t TXFQS; __IO uint32_t TXESC; __IO uint32_t TXBRP; __IO uint32_t TXBAR; __IO uint32_t TXBCR; __IO uint32_t TXBTO; __IO uint32_t TXBCF; __IO uint32_t TXBTIE; __IO uint32_t TXBCIE; __IO uint32_t RESERVED6[2]; __IO uint32_t TXEFC; __IO uint32_t TXEFS; __IO uint32_t TXEFA; __IO uint32_t RESERVED7;
} FDCAN_GlobalTypeDef;
这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
下面我们看下FDCAN的定义,在stm32h743xx.h文件。
#define PERIPH_BASE (0x40000000UL)
#define D2_APB1PERIPH_BASE PERIPH_BASE#define FDCAN1_BASE (D2_APB1PERIPH_BASE + 0xA000UL)
#define FDCAN2_BASE (D2_APB1PERIPH_BASE + 0xA400UL)
#define FDCAN_CCU_BASE (D2_APB1PERIPH_BASE + 0xA800UL)#define FDCAN1 ((FDCAN_GlobalTypeDef *) FDCAN1_BASE) <----- 展开这个宏,(FDCAN_GlobalTypeDef *)0x4000A000
#define FDCAN2 ((FDCAN_GlobalTypeDef *) FDCAN2_BASE)
#define FDCAN_CCU ((FDCAN_ClockCalibrationUnit_TypeDef *) FDCAN_CCU_BASE)
我们访问FDCAN1的CCCR寄存器可以采用这种形式:FDCAN1->CCCR = 0。
91.3.2 FDCAN总线时间触发结构体TTCAN_TypeDef
FDCAN总线时间触发相关的寄存器是通过HAL库中的结构体TTCAN_TypeDef定义,在stm32h743xx.h中可以找到这个类型定义:
typedef struct
{__IO uint32_t TTTMC; /*!< TT Trigger Memory Configuration register, Address offset: 0x100 */__IO uint32_t TTRMC; /*!< TT Reference Message Configuration register, Address offset: 0x104 */__IO uint32_t TTOCF; /*!< TT Operation Configuration register, Address offset: 0x108 */__IO uint32_t TTMLM; /*!< TT Matrix Limits register, Address offset: 0x10C */__IO uint32_t TURCF; /*!< TUR Configuration register, Address offset: 0x110 */__IO uint32_t TTOCN; /*!< TT Operation Control register, Address offset: 0x114 */__IO uint32_t TTGTP; /*!< TT Global Time Preset register, Address offset: 0x118 */__IO uint32_t TTTMK; /*!< TT Time Mark register, Address offset: 0x11C */__IO uint32_t TTIR; /*!< TT Interrupt register, Address offset: 0x120 */__IO uint32_t TTIE; /*!< TT Interrupt Enable register, Address offset: 0x124 */__IO uint32_t TTILS; /*!< TT Interrupt Line Select register, Address offset: 0x128 */__IO uint32_t TTOST; /*!< TT Operation Status register, Address offset: 0x12C */__IO uint32_t TURNA; /*!< TT TUR Numerator Actual register, Address offset: 0x130 */__IO uint32_t TTLGT; /*!< TT Local and Global Time register, Address offset: 0x134 */__IO uint32_t TTCTC; /*!< TT Cycle Time and Count register, Address offset: 0x138 */__IO uint32_t TTCPT; /*!< TT Capture Time register, Address offset: 0x13C */__IO uint32_t TTCSM; /*!< TT Cycle Sync Mark register, Address offset: 0x140 */__IO uint32_t RESERVED1[111]; /*!< Reserved, 0x144 - 0x2FC */__IO uint32_t TTTS; /*!< TT Trigger Select register, Address offset: 0x300 */
} TTCAN_TypeDef;
91.3.3 FDCAN总线初始化结构体FDCAN_InitTypeDef
下面是FDCAN总线的初始化结构体:
typedef struct
{uint32_t FrameFormat; /*!< Specifies the FDCAN frame format.This parameter can be a value of @ref FDCAN_frame_format */uint32_t Mode; /*!< Specifies the FDCAN mode.This parameter can be a value of @ref FDCAN_operating_mode */FunctionalState AutoRetransmission; /*!< Enable or disable the automatic retransmission mode.This parameter can be set to ENABLE or DISABLE */FunctionalState TransmitPause; /*!< Enable or disable the Transmit Pause feature.This parameter can be set to ENABLE or DISABLE */FunctionalState ProtocolException; /*!< Enable or disable the Protocol Exception Handling.This parameter can be set to ENABLE or DISABLE */uint32_t NominalPrescaler; /*!< Specifies the value by which the oscillator frequency isdivided for generating the nominal bit time quanta.This parameter must be a number between 1 and 512 */uint32_t NominalSyncJumpWidth; /*!< Specifies the maximum number of time quanta the FDCANhardware is allowed to lengthen or shorten a bit to performresynchronization.This parameter must be a number between 1 and 128 */uint32_t NominalTimeSeg1; /*!< Specifies the number of time quanta in Bit Segment 1.This parameter must be a number between 2 and 256 */uint32_t NominalTimeSeg2; /*!< Specifies the number of time quanta in Bit Segment 2.This parameter must be a number between 2 and 128 */uint32_t DataPrescaler; /*!< Specifies the value by which the oscillator frequency isdivided for generating the data bit time quanta.This parameter must be a number between 1 and 32 */uint32_t DataSyncJumpWidth; /*!< Specifies the maximum number of time quanta the FDCANhardware is allowed to lengthen or shorten a data bit toperform resynchronization.This parameter must be a number between 1 and 16 */uint32_t DataTimeSeg1; /*!< Specifies the number of time quanta in Data Bit Segment 1.This parameter must be a number between 1 and 32 */uint32_t DataTimeSeg2; /*!< Specifies the number of time quanta in Data Bit Segment 2.This parameter must be a number between 1 and 16 */uint32_t MessageRAMOffset; /*!< Specifies the message RAM start address.This parameter must be a number between 0 and 2560 */uint32_t StdFiltersNbr; /*!< Specifies the number of standard Message ID filters.This parameter must be a number between 0 and 128 */uint32_t ExtFiltersNbr; /*!< Specifies the number of extended Message ID filters.This parameter must be a number between 0 and 64 */uint32_t RxFifo0ElmtsNbr; /*!< Specifies the number of Rx FIFO0 Elements.This parameter must be a number between 0 and 64 */uint32_t RxFifo0ElmtSize; /*!< Specifies the Data Field Size in an Rx FIFO 0 element.This parameter can be a value of @ref FDCAN_data_field_size */uint32_t RxFifo1ElmtsNbr; /*!< Specifies the number of Rx FIFO 1 Elements.This parameter must be a number between 0 and 64 */uint32_t RxFifo1ElmtSize; /*!< Specifies the Data Field Size in an Rx FIFO 1 element.This parameter can be a value of @ref FDCAN_data_field_size */uint32_t RxBuffersNbr; /*!< Specifies the number of Dedicated Rx Buffer elements.This parameter must be a number between 0 and 64 */uint32_t RxBufferSize; /*!< Specifies the Data Field Size in an Rx Buffer element.This parameter can be a value of @ref FDCAN_data_field_size */uint32_t TxEventsNbr; /*!< Specifies the number of Tx Event FIFO elements.This parameter must be a number between 0 and 32 */uint32_t TxBuffersNbr; /*!< Specifies the number of Dedicated Tx Buffers.This parameter must be a number between 0 and 32 */uint32_t TxFifoQueueElmtsNbr; /*!< Specifies the number of Tx Buffers used for Tx FIFO/Queue.This parameter must be a number between 0 and 32 */uint32_t TxFifoQueueMode; /*!< Tx FIFO/Queue Mode selection.This parameter can be a value of @ref FDCAN_txFifoQueue_Mode */uint32_t TxElmtSize; /*!< Specifies the Data Field Size in a Tx Element.This parameter can be a value of @ref FDCAN_data_field_size */} FDCAN_InitTypeDef;
下面将结构体成员逐一做个说明:
- FrameFormat
用于设置CAN帧格式。
#define FDCAN_FRAME_CLASSIC ((uint32_t)0x00000000U) /* 经典CAN模式 */
#define FDCAN_FRAME_FD_NO_BRS ((uint32_t)FDCAN_CCCR_FDOE) /* FD CAN不带可变波特率 */
#define FDCAN_FRAME_FD_BRS ((uint32_t)(FDCAN_CCCR_FDOE | FDCAN_CCCR_BRSE)) /* FD CAN带可变波特率 */
- Mode
用于设置CAN操作模式。
#define FDCAN_MODE_NORMAL ((uint32_t)0x00000000U) /*!< 正常模式 */
#define FDCAN_MODE_RESTRICTED_OPERATION ((uint32_t)0x00000001U) /*!< 有限制的操作模式 */
#define FDCAN_MODE_BUS_MONITORING ((uint32_t)0x00000002U) /*!< 总线监测模式 */
#define FDCAN_MODE_INTERNAL_LOOPBACK ((uint32_t)0x00000003U) /*!< 内部环回模式 */
#define FDCAN_MODE_EXTERNAL_LOOPBACK ((uint32_t)0x00000004U) /*!< 外部环回模式 */
- AutoRetransmission
使能自动重传模式。
使能ENABLE或者禁止DISABLE。
- TransmitPause
使能或者禁止传输暂停特性。ENABLE使能或者DISABLE禁止。
- ProtocolException
使能或者禁止协议异常管理。ENABLE表示使能,DISABLE表示禁止。
- NominalPrescaler
用于CAN FD仲裁阶段分频设置,产生标称位时间量,参数范围1-512。
- NominalSyncJumpWidth
设置FD CAN仲裁阶段最大支持的时间量来加长或者缩短一个bit来实现再同步,参数范围1-128。
- NominalTimeSeg1
设置仲裁阶段Bit Segment 1的时间量,范围2 – 256。
- NominalTimeSeg2
设置仲裁阶段Bit Segment 2的时间量,范围2 – 128。
- DataPrescaler
用于CAN FD数据阶段分频设置,范围1-32。
- DataSyncJumpWidth
设置FD CAN数据阶段最大支持的时间量来加长或者缩短一个bit来实现数据再同步,参数范围1-16。
- DataTimeSeg1
设置数据阶段Data Bit Segment 1的时间量,范围1 – 32。
- DataTimeSeg2
设置数据阶段Data Bit Segment 2的时间量,范围1 – 16。
- MessageRAMOffset
设置消息RAM起始地址,范围0到2560。
- StdFiltersNbr
标准ID过滤个数,范围0到128。
- ExtFiltersNbr
扩展ID过滤个数,范围0到64。
- RxFifo0ElmtsNbr
RX FIFO0元素个数,范围0到64。
- RxFifo0ElmtSize
RX FIFO0每个元素中数据大小,支持参数如下:
#define FDCAN_DATA_BYTES_8 ((uint32_t)0x00000004U) /*!< 8 bytes data field */
#define FDCAN_DATA_BYTES_12 ((uint32_t)0x00000005U) /*!< 12 bytes data field */
#define FDCAN_DATA_BYTES_16 ((uint32_t)0x00000006U) /*!< 16 bytes data field */
#define FDCAN_DATA_BYTES_20 ((uint32_t)0x00000007U) /*!< 20 bytes data field */
#define FDCAN_DATA_BYTES_24 ((uint32_t)0x00000008U) /*!< 24 bytes data field */
#define FDCAN_DATA_BYTES_32 ((uint32_t)0x0000000AU) /*!< 32 bytes data field */
#define FDCAN_DATA_BYTES_48 ((uint32_t)0x0000000EU) /*!< 48 bytes data field */
#define FDCAN_DATA_BYTES_64 ((uint32_t)0x00000012U) /*!< 64 bytes data field */
- RxFifo1ElmtsNbr
RX FIFO1个数,范围0到64。
- RxFifo1ElmtSize
RX FIFO1每个元素中数据大小,支持参数如下:
#define FDCAN_DATA_BYTES_8 ((uint32_t)0x00000004U) /*!< 8 bytes data field */
#define FDCAN_DATA_BYTES_12 ((uint32_t)0x00000005U) /*!< 12 bytes data field */
#define FDCAN_DATA_BYTES_16 ((uint32_t)0x00000006U) /*!< 16 bytes data field */
#define FDCAN_DATA_BYTES_20 ((uint32_t)0x00000007U) /*!< 20 bytes data field */
#define FDCAN_DATA_BYTES_24 ((uint32_t)0x00000008U) /*!< 24 bytes data field */
#define FDCAN_DATA_BYTES_32 ((uint32_t)0x0000000AU) /*!< 32 bytes data field */
#define FDCAN_DATA_BYTES_48 ((uint32_t)0x0000000EU) /*!< 48 bytes data field */
#define FDCAN_DATA_BYTES_64 ((uint32_t)0x00000012U) /*!< 64 bytes data field */
- RxBuffersNbr
设置Rx Buffer元素个数,范围0 - 64:
- RxBuffersSize
设置Rx Buffer元素中每个数据大小,范围0 - 64:
#define FDCAN_DATA_BYTES_8 ((uint32_t)0x00000004U) /*!< 8 bytes data field */
#define FDCAN_DATA_BYTES_12 ((uint32_t)0x00000005U) /*!< 12 bytes data field */
#define FDCAN_DATA_BYTES_16 ((uint32_t)0x00000006U) /*!< 16 bytes data field */
#define FDCAN_DATA_BYTES_20 ((uint32_t)0x00000007U) /*!< 20 bytes data field */
#define FDCAN_DATA_BYTES_24 ((uint32_t)0x00000008U) /*!< 24 bytes data field */
#define FDCAN_DATA_BYTES_32 ((uint32_t)0x0000000AU) /*!< 32 bytes data field */
#define FDCAN_DATA_BYTES_48 ((uint32_t)0x0000000EU) /*!< 48 bytes data field */
#define FDCAN_DATA_BYTES_64 ((uint32_t)0x00000012U) /*!< 64 bytes data field */
- TxEventsNbr
Tx Event FIFO元素个数,范围0到32。
- TxBuffersNbr
设置专用的Tx Buffer元素个数,范围0到32。
- TxFifoQueueElmtsNbr
设置用于Tx FIFO/Queue的Tx Buffers个数。范围0到32。
- TxFifoQueueMode
设置FIFO模式或者QUEUE队列模式。
#define FDCAN_TX_FIFO_OPERATION ((uint32_t)0x00000000U) /*!< FIFO mode */
#define FDCAN_TX_QUEUE_OPERATION ((uint32_t)FDCAN_TXBC_TFQM) /*!< Queue mode */
- TxElmtSize
设置Tx Element中的数据域大小。支持参数如下:
#define FDCAN_DATA_BYTES_8 ((uint32_t)0x00000004U) /*!< 8 bytes data field */
#define FDCAN_DATA_BYTES_12 ((uint32_t)0x00000005U) /*!< 12 bytes data field */
#define FDCAN_DATA_BYTES_16 ((uint32_t)0x00000006U) /*!< 16 bytes data field */
#define FDCAN_DATA_BYTES_20 ((uint32_t)0x00000007U) /*!< 20 bytes data field */
#define FDCAN_DATA_BYTES_24 ((uint32_t)0x00000008U) /*!< 24 bytes data field */
#define FDCAN_DATA_BYTES_32 ((uint32_t)0x0000000AU) /*!< 32 bytes data field */
#define FDCAN_DATA_BYTES_48 ((uint32_t)0x0000000EU) /*!< 48 bytes data field */
#define FDCAN_DATA_BYTES_64 ((uint32_t)0x00000012U) /*!< 64 bytes data field */
91.3.4 FDCAN总线消息RAM地址FDCAN_MsgRamAddressTypeDef
下面是消息RAM结构体:
typedef struct
{uint32_t StandardFilterSA; /*!< Specifies the Standard Filter List Start Address.This parameter must be a 32-bit word address */uint32_t ExtendedFilterSA; /*!< Specifies the Extended Filter List Start Address.This parameter must be a 32-bit word address */uint32_t RxFIFO0SA; /*!< Specifies the Rx FIFO 0 Start Address.This parameter must be a 32-bit word address */uint32_t RxFIFO1SA; /*!< Specifies the Rx FIFO 1 Start Address.This parameter must be a 32-bit word address */uint32_t RxBufferSA; /*!< Specifies the Rx Buffer Start Address.This parameter must be a 32-bit word address */uint32_t TxEventFIFOSA; /*!< Specifies the Tx Event FIFO Start Address.This parameter must be a 32-bit word address */uint32_t TxBufferSA; /*!< Specifies the Tx Buffers Start Address.This parameter must be a 32-bit word address */uint32_t TxFIFOQSA; /*!< Specifies the Tx FIFO/Queue Start Address.This parameter must be a 32-bit word address */uint32_t TTMemorySA; /*!< Specifies the Trigger Memory Start Address.This parameter must be a 32-bit word address */uint32_t EndAddress; /*!< Specifies the End Address of the allocated RAM.This parameter must be a 32-bit word address */} FDCAN_MsgRamAddressTypeDef;
下面将结构体成员逐一做个说明:
- StandardFilterSA
设置标准过滤器起始地址,必须是32bit地址。
- ExtendedFilterSA
设置扩展过滤器起始地址,必须是32bit地址。
- RxFIFO0SA
设置RX FIFO 0起始地址,必须是32bit地址。
- RxFIFO1SA
设置RX FIFO 1起始地址,必须是32bit地址。
- RxBufferSA
设置RX Buffer起始地址,必须是32bit地址。
- TxEventFIFOSA
设置Tx Event FIFO起始地址,必须是32bit地址。
- TTMemorySA
设置触发内存起始地址,必须是32bit地址。
- EndAddress
设置申请RAM空间的结束地址,必须是32bit地址。
91.3.5 FDCAN总线过滤结构体FDCAN_FilterTypeDef
下面是过滤结构体:
typedef struct
{uint32_t IdType; /*!< Specifies the identifier type.This parameter can be a value of @ref FDCAN_id_type */uint32_t FilterIndex; /*!< Specifies the filter which will be initialized.This parameter must be a number between:- 0 and 127, if IdType is FDCAN_STANDARD_ID- 0 and 63, if IdType is FDCAN_EXTENDED_ID */uint32_t FilterType; /*!< Specifies the filter type.This parameter can be a value of @ref FDCAN_filter_type.The value FDCAN_EXT_FILTER_RANGE_NO_EIDM is permittedonly when IdType is FDCAN_EXTENDED_ID.This parameter is ignored if FilterConfig is set toFDCAN_FILTER_TO_RXBUFFER */uint32_t FilterConfig; /*!< Specifies the filter configuration.This parameter can be a value of @ref FDCAN_filter_config */uint32_t FilterID1; /*!< Specifies the filter identification 1.This parameter must be a number between:- 0 and 0x7FF, if IdType is FDCAN_STANDARD_ID- 0 and 0x1FFFFFFF, if IdType is FDCAN_EXTENDED_ID */uint32_t FilterID2; /*!< Specifies the filter identification 2.This parameter is ignored if FilterConfig is set toFDCAN_FILTER_TO_RXBUFFER.This parameter must be a number between:- 0 and 0x7FF, if IdType is FDCAN_STANDARD_ID- 0 and 0x1FFFFFFF, if IdType is FDCAN_EXTENDED_ID */uint32_t RxBufferIndex; /*!< Contains the index of the Rx buffer in which thematching message will be stored.This parameter must be a number between 0 and 63.This parameter is ignored if FilterConfig is differentfrom FDCAN_FILTER_TO_RXBUFFER */uint32_t IsCalibrationMsg; /*!< Specifies whether the filter is configured forcalibration messages.This parameter is ignored if FilterConfig is differentfrom FDCAN_FILTER_TO_RXBUFFER.This parameter can be:- 0 : ordinary message- 1 : calibration message */} FDCAN_FilterTypeDef;
- IdType
用于设置标准ID和扩展ID。
#define FDCAN_STANDARD_ID ((uint32_t)0x00000000U) /*!< 标准ID */
#define FDCAN_EXTENDED_ID ((uint32_t)0x40000000U) /*!< 扩展ID */
- FilterIndex
用于过滤索引,如果是标准ID,范围0到127。如果是扩展ID,范围0到64。
- FilterType
用于设置过滤类型。如果成员FilterConfig设置为FDCAN_FILTER_TO_RXBUFFER,本参数将不起作用。
#define FDCAN_FILTER_RANGE ((uint32_t)0x00000000U) /*!< 范围过滤从FilterID1 到 FilterID2 */
#define FDCAN_FILTER_DUAL ((uint32_t)0x00000001U) /*!< 专用ID过滤,FilterID1 或者FilterID2 *//*!< 精度屏蔽过滤,FilterID1 = filter, FilterID2 = mask */
#define FDCAN_FILTER_MASK ((uint32_t)0x00000002U) /*!< 仅ID扩展模式支持此参数,范围从FilterID1 到 FilterID2, EIDM mask not applied */
#define FDCAN_FILTER_RANGE_NO_EIDM ((uint32_t)0x00000003U)
- FilterConfig
用于设置过滤类型。
#define FDCAN_FILTER_DISABLE ((uint32_t)0x00000000U) 禁止过滤
#define FDCAN_FILTER_TO_RXFIFO0 ((uint32_t)0x00000001U) 如果过滤匹配,将数据保存到Rx FIFO 0
#define FDCAN_FILTER_TO_RXFIFO1 ((uint32_t)0x00000002U) 如果过滤匹配,将数据保存到Rx FIFO 1
#define FDCAN_FILTER_REJECT ((uint32_t)0x00000003U) 如果过滤匹配,拒绝此ID
#define FDCAN_FILTER_HP ((uint32_t)0x00000004U) 如果过滤匹配,设置高优先级
#define FDCAN_FILTER_TO_RXFIFO0_HP ((uint32_t)0x00000005U) 如果过滤匹配,设置高优先级并保存到FIFO 0
#define FDCAN_FILTER_TO_RXFIFO1_HP ((uint32_t)0x00000006U) 如果过滤匹配,设置高优先级并保存到FIFO 1
#define FDCAN_FILTER_TO_RXBUFFER ((uint32_t)0x00000007U) 如果过滤匹配,保存到Rx Buffer,并忽略FilterType
配置
- FilterID1
用于设置过滤ID1。如果ID类型是FDCAN_STANDARD_ID,范围0到0x7FF。如果ID类型是FDCAN_EXTENDED_ID,范围是0 到0x1FFFFFFF。
- FilterID2
用于设置过滤ID2。如果FilterConfig设置为FDCAN_FILTER_TO_RXBUFFER,此参数不起作用。如果ID类型是FDCAN_STANDARD_ID,范围0到0x7FF。如果ID类型是FDCAN_EXTENDED_ID,范围是0 到0x1FFFFFFF。
- RxBufferIndex
匹配消息存储到Rx buffer中的索引。参数范围0到63。如果FilterConfig设置为FDCAN_FILTER_TO_RXBUFFER,此参数不起作用。
- IsCalibrationMsg
用于设置是否配置校准消息。如果FilterConfig设置为FDCAN_FILTER_TO_RXBUFFER,此参数不起作用。
0 : 表示正常消息。
1 : 标志校准消息。
91.3.6 FDCAN总线消息发送结构体FDCAN_TxHeaderTypeDef
下面是CAN FD发送消息结构体:
typedef struct
{uint32_t Identifier; /*!< Specifies the identifier.This parameter must be a number between:- 0 and 0x7FF, if IdType is FDCAN_STANDARD_ID- 0 and 0x1FFFFFFF, if IdType is FDCAN_EXTENDED_ID */uint32_t IdType; /*!< Specifies the identifier type for the message that will betransmitted.This parameter can be a value of @ref FDCAN_id_type */uint32_t TxFrameType; /*!< Specifies the frame type of the message that will be transmitted.This parameter can be a value of @ref FDCAN_frame_type */uint32_t DataLength; /*!< Specifies the length of the frame that will be transmitted.This parameter can be a value of @ref FDCAN_data_length_code */uint32_t ErrorStateIndicator; /*!< Specifies the error state indicator.This parameter can be a value of @ref FDCAN_error_state_indicator */uint32_t BitRateSwitch; /*!< Specifies whether the Tx frame will be transmitted with or withoutbit rate switching.This parameter can be a value of @ref FDCAN_bit_rate_switching */uint32_t FDFormat; /*!< Specifies whether the Tx frame will be transmitted in classic orFD format.This parameter can be a value of @ref FDCAN_format */uint32_t TxEventFifoControl; /*!< Specifies the event FIFO control.This parameter can be a value of @ref FDCAN_EFC */uint32_t MessageMarker; /*!< Specifies the message marker to be copied into Tx Event FIFOelement for identification of Tx message status.This parameter must be a number between 0 and 0xFF */} FDCAN_TxHeaderTypeDef;
- Identifier
用于设置ID,如果IdType是标准FDCAN_STANDARD_ID,范围0到0x7FF,如果IdType是FDCAN_EXTENDED_ID扩展ID,范围0到0x1FFFFFFF。
- IdType
用于设置标准ID或者扩展ID。
#define FDCAN_STANDARD_ID ((uint32_t)0x00000000U) /*!< 标准ID */
#define FDCAN_EXTENDED_ID ((uint32_t)0x40000000U) /*!< 扩展ID */
- TxFrameType
用于设置帧类型,数据帧或遥控帧。
#define FDCAN_DATA_FRAME ((uint32_t)0x00000000U) /*!< 数据帧 */
#define FDCAN_REMOTE_FRAME ((uint32_t)0x20000000U) /*!< 遥控帧 */
- DataLength
用于设置数据长度。
#define FDCAN_DLC_BYTES_0 ((uint32_t)0x00000000U) /*!< 0 bytes data field */
#define FDCAN_DLC_BYTES_1 ((uint32_t)0x00010000U) /*!< 1 bytes data field */
#define FDCAN_DLC_BYTES_2 ((uint32_t)0x00020000U) /*!< 2 bytes data field */
#define FDCAN_DLC_BYTES_3 ((uint32_t)0x00030000U) /*!< 3 bytes data field */
#define FDCAN_DLC_BYTES_4 ((uint32_t)0x00040000U) /*!< 4 bytes data field */
#define FDCAN_DLC_BYTES_5 ((uint32_t)0x00050000U) /*!< 5 bytes data field */
#define FDCAN_DLC_BYTES_6 ((uint32_t)0x00060000U) /*!< 6 bytes data field */
#define FDCAN_DLC_BYTES_7 ((uint32_t)0x00070000U) /*!< 7 bytes data field */
#define FDCAN_DLC_BYTES_8 ((uint32_t)0x00080000U) /*!< 8 bytes data field */
#define FDCAN_DLC_BYTES_12 ((uint32_t)0x00090000U) /*!< 12 bytes data field */
#define FDCAN_DLC_BYTES_16 ((uint32_t)0x000A0000U) /*!< 16 bytes data field */
#define FDCAN_DLC_BYTES_20 ((uint32_t)0x000B0000U) /*!< 20 bytes data field */
#define FDCAN_DLC_BYTES_24 ((uint32_t)0x000C0000U) /*!< 24 bytes data field */
#define FDCAN_DLC_BYTES_32 ((uint32_t)0x000D0000U) /*!< 32 bytes data field */
#define FDCAN_DLC_BYTES_48 ((uint32_t)0x000E0000U) /*!< 48 bytes data field */
#define FDCAN_DLC_BYTES_64 ((uint32_t)0x000F0000U) /*!< 64 bytes data field */
- ErrorStateIndicator
用于设置错误状态指示:
#define FDCAN_ESI_ACTIVE ((uint32_t)0x00000000U) /*!< 传输节点 error active */
#define FDCAN_ESI_PASSIVE ((uint32_t)0x80000000U) /*!< 传输节点error passive */
- BitRateSwitch
用于设置发送是否波特率可变。
#define FDCAN_BRS_OFF ((uint32_t)0x00000000U) /*!< FDCAN帧发送/接收不带波特率可变 */
#define FDCAN_BRS_ON ((uint32_t)0x00100000U) /*!< FDCAN帧发送/接收带波特率可变 */
- FDFormat
用于设置发送帧是经典格式还是CANFD格式。
#define FDCAN_CLASSIC_CAN ((uint32_t)0x00000000U) /*!< 帧发送/接收使用经典CAN */
#define FDCAN_FD_CAN ((uint32_t)0x00200000U) /*!< 帧发送/接收使用FDCAN格式 */
- TxEventFifoControl
用于设置发送事件FIFO控制。
#define FDCAN_NO_TX_EVENTS ((uint32_t)0x00000000U) /*!< 不存储 Tx events */
#define FDCAN_STORE_TX_EVENTS ((uint32_t)0x00800000U) /*!< 存储Tx events */
- MessageMarker
用于设置复制到TX EVENT FIFO的消息Maker,来识别消息状态,范围0到0xFF。
91.3.7 FDCAN总线消息接收结构体FDCAN_RxHeaderTypeDef
下面是CAN FD接收消息结构体:
typedef struct
{uint32_t Identifier; /*!< Specifies the identifier.This parameter must be a number between:- 0 and 0x7FF, if IdType is FDCAN_STANDARD_ID- 0 and 0x1FFFFFFF, if IdType is FDCAN_EXTENDED_ID */uint32_t IdType; /*!< Specifies the identifier type of the received message.This parameter can be a value of @ref FDCAN_id_type */uint32_t RxFrameType; /*!< Specifies the the received message frame type.This parameter can be a value of @ref FDCAN_frame_type */uint32_t DataLength; /*!< Specifies the received frame length.This parameter can be a value of @ref FDCAN_data_length_code */uint32_t ErrorStateIndicator; /*!< Specifies the error state indicator.This parameter can be a value of @ref FDCAN_error_state_indicator */uint32_t BitRateSwitch; /*!< Specifies whether the Rx frame is received with or without bitrate switching.This parameter can be a value of @ref FDCAN_bit_rate_switching */uint32_t FDFormat; /*!< Specifies whether the Rx frame is received in classic or FDformat.This parameter can be a value of @ref FDCAN_format */uint32_t RxTimestamp; /*!< Specifies the timestamp counter value captured on start of framereception.This parameter must be a number between 0 and 0xFFFF */uint32_t FilterIndex; /*!< Specifies the index of matching Rx acceptance filter element.This parameter must be a number between:- 0 and 127, if IdType is FDCAN_STANDARD_ID- 0 and 63, if IdType is FDCAN_EXTENDED_ID */uint32_t IsFilterMatchingFrame; /*!< Specifies whether the accepted frame did not match any Rx filter.Acceptance of non-matching frames may be enabled viaHAL_FDCAN_ConfigGlobalFilter().This parameter can be 0 or 1 */} FDCAN_RxHeaderTypeDef;
- Identifier
用于设置ID,如果IdType是标准FDCAN_STANDARD_ID,范围0到0x7FF,如果IdType是FDCAN_EXTENDED_ID扩展ID,范围0到0x1FFFFFFF。
- IdType
用于设置标志ID或者扩展ID。
#define FDCAN_STANDARD_ID ((uint32_t)0x00000000U) /*!< 标准ID */
#define FDCAN_EXTENDED_ID ((uint32_t)0x40000000U) /*!< 扩展ID */
- RxFrameType
用于设置接收帧类型,数据帧或遥控帧
#define FDCAN_DATA_FRAME ((uint32_t)0x00000000U) /*!< 数据帧 */
#define FDCAN_REMOTE_FRAME ((uint32_t)0x20000000U) /*!< 遥控帧 */
- DataLength
用于设置数据长度。
#define FDCAN_DLC_BYTES_0 ((uint32_t)0x00000000U) /*!< 0 bytes data field */
#define FDCAN_DLC_BYTES_1 ((uint32_t)0x00010000U) /*!< 1 bytes data field */
#define FDCAN_DLC_BYTES_2 ((uint32_t)0x00020000U) /*!< 2 bytes data field */
#define FDCAN_DLC_BYTES_3 ((uint32_t)0x00030000U) /*!< 3 bytes data field */
#define FDCAN_DLC_BYTES_4 ((uint32_t)0x00040000U) /*!< 4 bytes data field */
#define FDCAN_DLC_BYTES_5 ((uint32_t)0x00050000U) /*!< 5 bytes data field */
#define FDCAN_DLC_BYTES_6 ((uint32_t)0x00060000U) /*!< 6 bytes data field */
#define FDCAN_DLC_BYTES_7 ((uint32_t)0x00070000U) /*!< 7 bytes data field */
#define FDCAN_DLC_BYTES_8 ((uint32_t)0x00080000U) /*!< 8 bytes data field */
#define FDCAN_DLC_BYTES_12 ((uint32_t)0x00090000U) /*!< 12 bytes data field */
#define FDCAN_DLC_BYTES_16 ((uint32_t)0x000A0000U) /*!< 16 bytes data field */
#define FDCAN_DLC_BYTES_20 ((uint32_t)0x000B0000U) /*!< 20 bytes data field */
#define FDCAN_DLC_BYTES_24 ((uint32_t)0x000C0000U) /*!< 24 bytes data field */
#define FDCAN_DLC_BYTES_32 ((uint32_t)0x000D0000U) /*!< 32 bytes data field */
#define FDCAN_DLC_BYTES_48 ((uint32_t)0x000E0000U) /*!< 48 bytes data field */
#define FDCAN_DLC_BYTES_64 ((uint32_t)0x000F0000U) /*!< 64 bytes data field */
- ErrorStateIndicator
用于设置错误状态指示:
#define FDCAN_ESI_ACTIVE ((uint32_t)0x00000000U) /*!< 传输节点error active */
#define FDCAN_ESI_PASSIVE ((uint32_t)0x80000000U) /*!< 传输节点error passive */
- BitRateSwitch
用于设置接收是否带波特率切换
#define FDCAN_BRS_OFF ((uint32_t)0x00000000U) /*!< FDCAN 帧发送/接收不支持波特率可变*/
#define FDCAN_BRS_ON ((uint32_t)0x00100000U) /*!< FDCAN 帧发送/接收支持波特率可变 */
- FDFormat
用于设置接收帧是经典格式还是CANFD格式
#define FDCAN_CLASSIC_CAN ((uint32_t)0x00000000U) /*!< 经典帧 */
#define FDCAN_FD_CAN ((uint32_t)0x00200000U) /*!< FDCAN帧 */
- RxTimestamp
用于设置帧接收时间戳,范围0到0xFFFF。
- FilterIndex
用于设置接收过滤索引。如果是标准ID,范围0到127,如果是扩展ID,范围0到63。
- IsFilterMatchingFrame
用于设置是否接收非匹配帧,通过函数HAL_FDCAN_ConfigGlobalFilter()可以使能。
0:表示不接受。
1:表示接收。
91.3.8 FDCAN总线句柄结构体FDCAN_HandleTypeDef
下面是CANFD句柄结构体:
#if USE_HAL_FDCAN_REGISTER_CALLBACKS == 1
typedef struct __FDCAN_HandleTypeDef
#else
typedef struct
#endif /* USE_HAL_FDCAN_REGISTER_CALLBACKS */
{FDCAN_GlobalTypeDef *Instance; /*!< Register base address */TTCAN_TypeDef *ttcan; /*!< TT register base address */FDCAN_InitTypeDef Init; /*!< FDCAN required parameters */FDCAN_MsgRamAddressTypeDef msgRam; /*!< FDCAN Message RAM blocks */uint32_t LatestTxFifoQRequest; /*!< FDCAN Tx buffer indexof latest Tx FIFO/Queue request */__IO HAL_FDCAN_StateTypeDef State; /*!< FDCAN communication state */HAL_LockTypeDef Lock; /*!< FDCAN locking object */__IO uint32_t ErrorCode; /*!< FDCAN Error code */#if USE_HAL_FDCAN_REGISTER_CALLBACKS == 1void (* ClockCalibrationCallback)(struct __FDCAN_HandleTypeDef *hfdcan, uint32_t ClkCalibrationITs); /*!< FDCAN Clock Calibration callback */void (* TxEventFifoCallback)(struct __FDCAN_HandleTypeDef *hfdcan, uint32_t TxEventFifoITs); /*!< FDCAN Tx Event Fifo callback */void (* RxFifo0Callback)(struct __FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs); /*!< FDCAN Rx Fifo 0 callback */void (* RxFifo1Callback)(struct __FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo1ITs); /*!< FDCAN Rx Fifo 1 callback */void (* TxFifoEmptyCallback)(struct __FDCAN_HandleTypeDef *hfdcan); /*!< FDCAN Tx Fifo Empty callback */void (* TxBufferCompleteCallback)(struct __FDCAN_HandleTypeDef *hfdcan, uint32_t BufferIndexes); /*!< FDCAN Tx Buffer complete callback */void (* TxBufferAbortCallback)(struct __FDCAN_HandleTypeDef *hfdcan, uint32_t BufferIndexes); /*!< FDCAN Tx Buffer abort callback */void (* RxBufferNewMessageCallback)(struct __FDCAN_HandleTypeDef *hfdcan); /*!< FDCAN Rx Buffer New Message callback */void (* HighPriorityMessageCallback)(struct __FDCAN_HandleTypeDef *hfdcan); /*!< FDCAN High priority message callback */void (* TimestampWraparoundCallback)(struct __FDCAN_HandleTypeDef *hfdcan); /*!< FDCAN Timestamp wraparound callback */void (* TimeoutOccurredCallback)(struct __FDCAN_HandleTypeDef *hfdcan); /*!< FDCAN Timeout occurred callback */void (* ErrorCallback)(struct __FDCAN_HandleTypeDef *hfdcan); /*!< FDCAN Error callback */void (* ErrorStatusCallback)(struct __FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs); /*!< FDCAN Error status callback */void (* TT_ScheduleSyncCallback)(struct __FDCAN_HandleTypeDef *hfdcan, uint32_t TTSchedSyncITs); /*!< FDCAN T Schedule Synchronization callback */void (* TT_TimeMarkCallback)(struct __FDCAN_HandleTypeDef *hfdcan, uint32_t TTTimeMarkITs); /*!< FDCAN TT Time Mark callback */void (* TT_StopWatchCallback)(struct __FDCAN_HandleTypeDef *hfdcan, uint32_t SWTime, uint32_t SWCycleCount); /*!< FDCAN TT Stop Watch callback */void (* TT_GlobalTimeCallback)(struct __FDCAN_HandleTypeDef *hfdcan, uint32_t TTGlobTimeITs); /*!< FDCAN TT Global Time callback */void (* MspInitCallback)(struct __FDCAN_HandleTypeDef *hfdcan); /*!< FDCAN Msp Init callback */void (* MspDeInitCallback)(struct __FDCAN_HandleTypeDef *hfdcan); /*!< FDCAN Msp DeInit callback */
#endif /* USE_HAL_FDCAN_REGISTER_CALLBACKS */} FDCAN_HandleTypeDef;
注意事项:
条件编译USE_HAL_FDCAN_REGISTER_CALLBACKS用来设置使用自定义回调还是使用默认回调,此定义一般放在stm32h7xx_hal_conf.h文件里面设置:
#define USE_HAL_FDCAN_REGISTER_CALLBACKS 1
函数HAL_FDCAN_RegisterCallback注册回调,取消注册使用函数HAL_FDCAN_UnRegisterCallback。
这里重点介绍下面几个参数,其它参数主要是HAL库内部使用和自定义回调函数。
- FDCAN_GlobalTypeDef *Instance
这个参数是寄存器的例化,方便操作寄存器。
- TTCAN_TypeDef *ttcan
TT CAN时间触发寄存器基地址。
- FDCAN_InitTypeDef Init
FDCAN相关的初始化参数。
- FDCAN_MsgRamAddressTypeDef msgRam
消息RAM地址。
- uint32_t LatestTxFifoQRequest
Tx buffer索引最后一个Tx FIFO/Queue参数。
- __IO HAL_FDCAN_StateTypeDef State
HAL_LockTypeDef Lock
__IO uint32_t ErrorCode
程序内部使用的状态参数。
- 剩下的都是回调函数
91.4 FD CAN总线源文件stm32h7xx_hal_fdcan.c
此文件涉及到的函数较多,这里把几个常用的函数做个说明:
91.4.1 函数HAL_FDCAN_Init
函数原型:
HAL_StatusTypeDef HAL_FDCAN_Init(FDCAN_HandleTypeDef *hfdcan)
{uint32_t tickstart;HAL_StatusTypeDef status;const uint32_t CvtEltSize[] = {0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7};/* 检测FDCAN句柄是否有效 */if (hfdcan == NULL){return HAL_ERROR;}/* 检查FDCAN例化 */if (hfdcan->Instance == FDCAN1){hfdcan->ttcan = (TTCAN_TypeDef *)((uint32_t)hfdcan->Instance + 0x100U);}/* 检查函数参数 */assert_param(IS_FDCAN_ALL_INSTANCE(hfdcan->Instance));assert_param(IS_FDCAN_FRAME_FORMAT(hfdcan->Init.FrameFormat));assert_param(IS_FDCAN_MODE(hfdcan->Init.Mode));assert_param(IS_FUNCTIONAL_STATE(hfdcan->Init.AutoRetransmission));assert_param(IS_FUNCTIONAL_STATE(hfdcan->Init.TransmitPause));assert_param(IS_FUNCTIONAL_STATE(hfdcan->Init.ProtocolException));assert_param(IS_FDCAN_NOMINAL_PRESCALER(hfdcan->Init.NominalPrescaler));assert_param(IS_FDCAN_NOMINAL_SJW(hfdcan->Init.NominalSyncJumpWidth));assert_param(IS_FDCAN_NOMINAL_TSEG1(hfdcan->Init.NominalTimeSeg1));assert_param(IS_FDCAN_NOMINAL_TSEG2(hfdcan->Init.NominalTimeSeg2));if (hfdcan->Init.FrameFormat == FDCAN_FRAME_FD_BRS){assert_param(IS_FDCAN_DATA_PRESCALER(hfdcan->Init.DataPrescaler));assert_param(IS_FDCAN_DATA_SJW(hfdcan->Init.DataSyncJumpWidth));assert_param(IS_FDCAN_DATA_TSEG1(hfdcan->Init.DataTimeSeg1));assert_param(IS_FDCAN_DATA_TSEG2(hfdcan->Init.DataTimeSeg2));}assert_param(IS_FDCAN_MAX_VALUE(hfdcan->Init.StdFiltersNbr, 128U));assert_param(IS_FDCAN_MAX_VALUE(hfdcan->Init.ExtFiltersNbr, 64U));assert_param(IS_FDCAN_MAX_VALUE(hfdcan->Init.RxFifo0ElmtsNbr, 64U));if (hfdcan->Init.RxFifo0ElmtsNbr > 0U){assert_param(IS_FDCAN_DATA_SIZE(hfdcan->Init.RxFifo0ElmtSize));}assert_param(IS_FDCAN_MAX_VALUE(hfdcan->Init.RxFifo1ElmtsNbr, 64U));if (hfdcan->Init.RxFifo1ElmtsNbr > 0U){assert_param(IS_FDCAN_DATA_SIZE(hfdcan->Init.RxFifo1ElmtSize));}assert_param(IS_FDCAN_MAX_VALUE(hfdcan->Init.RxBuffersNbr, 64U));if (hfdcan->Init.RxBuffersNbr > 0U){assert_param(IS_FDCAN_DATA_SIZE(hfdcan->Init.RxBufferSize));}assert_param(IS_FDCAN_MAX_VALUE(hfdcan->Init.TxEventsNbr, 32U));assert_param(IS_FDCAN_MAX_VALUE((hfdcan->Init.TxBuffersNbr + hfdcan->Init.TxFifoQueueElmtsNbr), 32U));if (hfdcan->Init.TxFifoQueueElmtsNbr > 0U){assert_param(IS_FDCAN_TX_FIFO_QUEUE_MODE(hfdcan->Init.TxFifoQueueMode));}if ((hfdcan->Init.TxBuffersNbr + hfdcan->Init.TxFifoQueueElmtsNbr) > 0U){assert_param(IS_FDCAN_DATA_SIZE(hfdcan->Init.TxElmtSize));}#if USE_HAL_FDCAN_REGISTER_CALLBACKS == 1if (hfdcan->State == HAL_FDCAN_STATE_RESET){/* 解锁*/hfdcan->Lock = HAL_UNLOCKED;/* 复位设置默认回调 */hfdcan->ClockCalibrationCallback = HAL_FDCAN_ClockCalibrationCallback; /* Legacy weak ClockCalibrationCallback */hfdcan->TxEventFifoCallback = HAL_FDCAN_TxEventFifoCallback; /* Legacy weak TxEventFifoCallback */hfdcan->RxFifo0Callback = HAL_FDCAN_RxFifo0Callback; /* Legacy weak RxFifo0Callback */hfdcan->RxFifo1Callback = HAL_FDCAN_RxFifo1Callback; /* Legacy weak RxFifo1Callback */hfdcan->TxFifoEmptyCallback = HAL_FDCAN_TxFifoEmptyCallback; /* Legacy weak TxFifoEmptyCallback */hfdcan->TxBufferCompleteCallback = HAL_FDCAN_TxBufferCompleteCallback; /* Legacy weak TxBufferCompleteCallback */hfdcan->TxBufferAbortCallback = HAL_FDCAN_TxBufferAbortCallback; /* Legacy weak TxBufferAbortCallback */hfdcan->RxBufferNewMessageCallback = HAL_FDCAN_RxBufferNewMessageCallback; /* Legacy weak RxBufferNewMessageCallback */hfdcan->HighPriorityMessageCallback = HAL_FDCAN_HighPriorityMessageCallback; /* Legacy weak HighPriorityMessageCallback */hfdcan->TimestampWraparoundCallback = HAL_FDCAN_TimestampWraparoundCallback; /* Legacy weak TimestampWraparoundCallback */hfdcan->TimeoutOccurredCallback = HAL_FDCAN_TimeoutOccurredCallback; /* Legacy weak TimeoutOccurredCallback */hfdcan->ErrorCallback = HAL_FDCAN_ErrorCallback; /* Legacy weak ErrorCallback */hfdcan->ErrorStatusCallback = HAL_FDCAN_ErrorStatusCallback; /* Legacy weak ErrorStatusCallback */hfdcan->TT_ScheduleSyncCallback = HAL_FDCAN_TT_ScheduleSyncCallback; /* Legacy weak TT_ScheduleSyncCallback */hfdcan->TT_TimeMarkCallback = HAL_FDCAN_TT_TimeMarkCallback; /* Legacy weak TT_TimeMarkCallback */hfdcan->TT_StopWatchCallback = HAL_FDCAN_TT_StopWatchCallback; /* Legacy weak TT_StopWatchCallback */hfdcan->TT_GlobalTimeCallback = HAL_FDCAN_TT_GlobalTimeCallback; /* Legacy weak TT_GlobalTimeCallback */if (hfdcan->MspInitCallback == NULL){hfdcan->MspInitCallback = HAL_FDCAN_MspInit; /* Legacy weak MspInit */}/* 初始化CLOCK和NVIC */hfdcan->MspInitCallback(hfdcan);}
#elseif (hfdcan->State == HAL_FDCAN_STATE_RESET){/* 解锁 */hfdcan->Lock = HAL_UNLOCKED;/* 初始化底层硬件 */HAL_FDCAN_MspInit(hfdcan);}
#endif /* USE_HAL_FDCAN_REGISTER_CALLBACKS *//* 退出Sleep */CLEAR_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_CSR);/* 获取时钟 */tickstart = HAL_GetTick();/* 等待Sleep模式确认 */while ((hfdcan->Instance->CCCR & FDCAN_CCCR_CSA) == FDCAN_CCCR_CSA){if ((HAL_GetTick() - tickstart) > FDCAN_TIMEOUT_VALUE){/* 更新错误码 */hfdcan->ErrorCode |= HAL_FDCAN_ERROR_TIMEOUT;/* 改变FDCAN状态 */hfdcan->State = HAL_FDCAN_STATE_ERROR;return HAL_ERROR;}}/* 请求初始化 */SET_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_INIT);/* 获取时钟 */tickstart = HAL_GetTick();/* 等待CCCR寄存器的INIT位 */while ((hfdcan->Instance->CCCR & FDCAN_CCCR_INIT) == 0U){/* 检查溢出时间 */if ((HAL_GetTick() - tickstart) > FDCAN_TIMEOUT_VALUE){/* 更新错误码 */hfdcan->ErrorCode |= HAL_FDCAN_ERROR_TIMEOUT;/* 设置FDCAN状态 */hfdcan->State = HAL_FDCAN_STATE_ERROR;return HAL_ERROR;}}/* 使能配置修改 */SET_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_CCE);/* 设置是否自动重传 */if (hfdcan->Init.AutoRetransmission == ENABLE){CLEAR_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_DAR);}else{SET_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_DAR);}/* 设置传输暂停特性 */if (hfdcan->Init.TransmitPause == ENABLE){SET_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_TXP);}else{CLEAR_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_TXP);}/* 设置协议异常处理 */if (hfdcan->Init.ProtocolException == ENABLE){CLEAR_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_PXHD);}else{SET_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_PXHD);}/* 设置FDCAN帧格式 */MODIFY_REG(hfdcan->Instance->CCCR, FDCAN_FRAME_FD_BRS, hfdcan->Init.FrameFormat);/* 复位FDCAN操作模式 */CLEAR_BIT(hfdcan->Instance->CCCR, (FDCAN_CCCR_TEST | FDCAN_CCCR_MON | FDCAN_CCCR_ASM));CLEAR_BIT(hfdcan->Instance->TEST, FDCAN_TEST_LBCK);/* 设置FDCAN操作模式:| Normal | Restricted | Bus | Internal | External| | Operation | Monitoring | LoopBack | LoopBackCCCR.TEST | 0 | 0 | 0 | 1 | 1CCCR.MON | 0 | 0 | 1 | 1 | 0TEST.LBCK | 0 | 0 | 0 | 1 | 1CCCR.ASM | 0 | 1 | 0 | 0 | 0*/if (hfdcan->Init.Mode == FDCAN_MODE_RESTRICTED_OPERATION){/* 使能限制操作模式 */SET_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_ASM);}else if (hfdcan->Init.Mode != FDCAN_MODE_NORMAL){if (hfdcan->Init.Mode != FDCAN_MODE_BUS_MONITORING){/* TEST寄存器写访问使能 */SET_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_TEST);/* 使能回环模式 */SET_BIT(hfdcan->Instance->TEST, FDCAN_TEST_LBCK);if (hfdcan->Init.Mode == FDCAN_MODE_INTERNAL_LOOPBACK){SET_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_MON);}}else{/* 使能检测模式 */SET_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_MON);}}else{/* Nothing to do: normal mode */}/* 设置nominal bit timing 寄存器 */hfdcan->Instance->NBTP = ((((uint32_t)hfdcan->Init.NominalSyncJumpWidth - 1U) << FDCAN_NBTP_NSJW_Pos) | \(((uint32_t)hfdcan->Init.NominalTimeSeg1 - 1U) << FDCAN_NBTP_NTSEG1_Pos) | \(((uint32_t)hfdcan->Init.NominalTimeSeg2 - 1U) << FDCAN_NBTP_NTSEG2_Pos) | \(((uint32_t)hfdcan->Init.NominalPrescaler - 1U) << FDCAN_NBTP_NBRP_Pos));/* 如果使能BRS(BitRate Switching可变波特率),设置data bit timing 寄存器*/if (hfdcan->Init.FrameFormat == FDCAN_FRAME_FD_BRS){hfdcan->Instance->DBTP = ((((uint32_t)hfdcan->Init.DataSyncJumpWidth - 1U) << FDCAN_DBTP_DSJW_Pos) | \(((uint32_t)hfdcan->Init.DataTimeSeg1 - 1U) << FDCAN_DBTP_DTSEG1_Pos) | \(((uint32_t)hfdcan->Init.DataTimeSeg2 - 1U) << FDCAN_DBTP_DTSEG2_Pos) | \(((uint32_t)hfdcan->Init.DataPrescaler - 1U) << FDCAN_DBTP_DBRP_Pos));}if (hfdcan->Init.TxFifoQueueElmtsNbr > 0U){/* 设置Tx FIFO 或 Tx Queue 操作模式 */SET_BIT(hfdcan->Instance->TXBC, hfdcan->Init.TxFifoQueueMode);}/* 配置Tx element 大小 */if ((hfdcan->Init.TxBuffersNbr + hfdcan->Init.TxFifoQueueElmtsNbr) > 0U){MODIFY_REG(hfdcan->Instance->TXESC, FDCAN_TXESC_TBDS, CvtEltSize[hfdcan->Init.TxElmtSize]);}/* 配置Rx FIFO 0 大小 */if (hfdcan->Init.RxFifo0ElmtsNbr > 0U){MODIFY_REG(hfdcan->Instance->RXESC, FDCAN_RXESC_F0DS, (CvtEltSize[hfdcan->Init.RxFifo0ElmtSize] << FDCAN_RXESC_F0DS_Pos));}/* 配置Rx FIFO 1大小 */if (hfdcan->Init.RxFifo1ElmtsNbr > 0U){MODIFY_REG(hfdcan->Instance->RXESC, FDCAN_RXESC_F1DS, (CvtEltSize[hfdcan->Init.RxFifo1ElmtSize] << FDCAN_RXESC_F1DS_Pos));}/* 配置 Rx buffer element 大小 */if (hfdcan->Init.RxBuffersNbr > 0U){MODIFY_REG(hfdcan->Instance->RXESC, FDCAN_RXESC_RBDS, (CvtEltSize[hfdcan->Init.RxBufferSize] << FDCAN_RXESC_RBDS_Pos));}/* 默认是的事件触发模式,如果使用时间触发模式,用户需要在HAL_FDCAN_Init
后调用HAL_FDCAN_TT_ConfigOperation */if (hfdcan->Instance == FDCAN1){CLEAR_BIT(hfdcan->ttcan->TTOCF, FDCAN_TTOCF_OM);}/* 初始化Tx FIFO/Queue */hfdcan->LatestTxFifoQRequest = 0U;/* 初始化错误码 */hfdcan->ErrorCode = HAL_FDCAN_ERROR_NONE;/* 初始化FDCAN状态 */hfdcan->State = HAL_FDCAN_STATE_READY;/* 计算每个RAM块地址 */status = FDCAN_CalcultateRamBlockAddresses(hfdcan);/* 返回函数状态 */return status;
}
函数描述:
此函数用于初始化FDCAN。
函数参数:
- 第1个参数是FDCAN_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
- 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
注意事项:
- 函数HAL_FDCAN_MspInit用于初始化FDCAN的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
- 如果形参hfdcan的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量FDCAN_HandleTypeDef FdCANHandle。
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_FDCAN_STATE_RESET = 0x00U。
解决办法有三
方法1:用户自己初始化FDCAN和涉及到的GPIO等。
方法2:定义FDCAN_HandleTypeDef FdCANHandle为全局变量。
方法3:下面的方法
if(HAL_FDCAN_DeInit(&FdCANHandle) != HAL_OK)
{Error_Handler();
}
if(HAL_FDCAN_Init(&FdCANHandle) != HAL_OK)
{Error_Handler();
}
使用举例:
FDCAN_HandleTypeDef hfdcan1;/*
*********************************************************************************************************
* 函 数 名: bsp_InitCan1
* 功能说明: 初始CAN1
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitCan1(void)
{ /* 位时间特性配置Bit time parameter | Nominal | Data---------------------------|--------------|----------------fdcan_ker_ck | 20 MHz | 20 MHzTime_quantum (tq) | 50 ns | 50 nsSynchronization_segment | 1 tq | 1 tqPropagation_segment | 23 tq | 1 tqPhase_segment_1 | 8 tq | 4 tqPhase_segment_2 | 8 tq | 4 tqSynchronization_Jump_width | 8 tq | 4 tqBit_length | 40 tq = 2us | 10 tq = 0.5usBit_rate | 0.5 MBit/s | 2 MBit/s*/hfdcan1.Instance = FDCAN1; /* 配置FDCAN1 */ hfdcan1.Init.FrameFormat = FDCAN_FRAME_FD_BRS; /* 配置使用FDCAN可变波特率 */ hfdcan1.Init.Mode = FDCAN_MODE_NORMAL; /* 配置使用正常模式 */ hfdcan1.Init.AutoRetransmission = ENABLE; /*使能自动重发 */ hfdcan1.Init.TransmitPause = DISABLE; /* 配置禁止传输暂停特性 */hfdcan1.Init.ProtocolException = ENABLE; /* 协议异常处理使能 *//* 配置仲裁阶段波特率 CAN时钟20MHz时,仲裁阶段的波特率就是CAN FD Freq / (Sync_Seg + Pro_Seg + Phase_Seg1 + Phase_Seg2) = 20MHz / (1+0x1F + 8) = 0.5Mbps 其中Sync_Seg是固定值 = 1 , Pro_Seg + Phase_Seg1 = NominalTimeSeg1, Phase_Seg2 = NominalTimeSeg2*/
/* CAN时钟分配设置,一般设置为1即可,全部由PLL配置好,tq = NominalPrescaler x (1/ fdcan_ker_ck) */hfdcan1.Init.NominalPrescaler = 0x01; /* 用于动态调节 Phase_Seg1和 Phase_Seg1,所以不可以比Phase_Seg1和 Phase_Seg1大 */hfdcan1.Init.NominalSyncJumpWidth = 0x08; /* 特别注意这里的Seg1,这里是两个参数之和,对应位时间特性图的 Pro_Seg + Phase_Seg1 */hfdcan1.Init.NominalTimeSeg1 = 0x1F; /* 对应位时间特性图的 Phase_Seg2 */hfdcan1.Init.NominalTimeSeg2 = 0x08; /* 配置数据阶段波特率 CAN时钟20MHz时,数据阶段的波特率就是CAN FD Freq / (Sync_Seg + Pro_Seg + Phase_Seg1 + Phase_Seg2) = 20MHz / (1+5+ 4) = 2Mbps其中Sync_Seg是固定值 = 1 , Pro_Seg + Phase_Seg1 = DataTimeSeg1, Phase_Seg2 = DataTimeSeg2*/
/* CAN时钟分配设置,一般设置为1即可,全部由PLL配置好,tq = NominalPrescaler x (1/ fdcan_ker_ck),
范围1-32 */hfdcan1.Init.DataPrescaler = 0x01; /* 用于动态调节 Phase_Seg1和 Phase_Seg1,所以不可以比Phase_Seg1和 Phase_Seg1大,范围1-16 */hfdcan1.Init.DataSyncJumpWidth = 0x04; /* 特别注意这里的Seg1,这里是两个参数之和,对应位时间特性图的 Pro_Seg + Phase_Seg1,范围 */hfdcan1.Init.DataTimeSeg1 = 0x05; /* 对应位时间特性图的 Phase_Seg2 */ hfdcan1.Init.DataTimeSeg2 = 0x04; hfdcan1.Init.MessageRAMOffset = 0; /* CAN1和CAN2共享2560个字, 这里CAN1分配前1280字 */hfdcan1.Init.StdFiltersNbr = 1; /* 设置标准ID过滤器个数,范围0-128 */ hfdcan1.Init.ExtFiltersNbr = 0; /* 设置扩展ID过滤器个数,范围0-64 */ hfdcan1.Init.RxFifo0ElmtsNbr = 2; /* 设置Rx FIFO0的元素个数,范围0-64 */ /* 设置Rx FIFO0中每个元素大小,支持8,12,16,20,24,32,48或者64字节 */
hfdcan1.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8; hfdcan1.Init.RxFifo1ElmtsNbr = 0; /* 设置Rx FIFO1的元素个数,范围0-64 *//* 设置Rx FIFO1中每个元素大小,支持8,12,16,20,24,32,48或者64字节 */ hfdcan1.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_8; hfdcan1.Init.RxBuffersNbr = 0; /* 设置Rx Buffer个数,范围0-64 *//* 设置Rx Buffer中每个元素大小,支持8,12,16,20,24,32,48或者64字节 */
hfdcan1.Init.RxBufferSize = 0; hfdcan1.Init.TxEventsNbr = 0; /* 设置Tx Event FIFO中元素个数,范围0-32 */ hfdcan1.Init.TxBuffersNbr = 0; /* 设置Tx Buffer中元素个数,范围0-32 */hfdcan1.Init.TxFifoQueueElmtsNbr = 2; /* 设置用于Tx FIFO/Queue的Tx Buffers个数。范围0到32 */hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; /* 设置FIFO模式或者QUEUE队列模式 *//* 设置Tx Element中的数据域大小,支持8,12,16,20,24,32,48或者64字节 */hfdcan1.Init.TxElmtSize = FDCAN_DATA_BYTES_8; HAL_FDCAN_Init(&hfdcan1);//省略未写}
91.4.2 函数HAL_FDCAN_DeInit
函数原型:
HAL_StatusTypeDef HAL_FDCAN_DeInit(FDCAN_HandleTypeDef *hfdcan)
{/* 检测句柄 */if (hfdcan == NULL){return HAL_ERROR;}/* 检查函数形参 */assert_param(IS_FDCAN_ALL_INSTANCE(hfdcan->Instance));/* 停止FDCAN */(void)HAL_FDCAN_Stop(hfdcan);/* 禁止中断 */CLEAR_BIT(hfdcan->Instance->ILE, (FDCAN_INTERRUPT_LINE0 | FDCAN_INTERRUPT_LINE1));#if USE_HAL_FDCAN_REGISTER_CALLBACKS == 1if (hfdcan->MspDeInitCallback == NULL){hfdcan->MspDeInitCallback = HAL_FDCAN_MspDeInit; /* Legacy weak MspDeInit */}/* 复位底层硬件,如时钟,NVIC等 */hfdcan->MspDeInitCallback(hfdcan);
#else/* 复位底层硬件,如时钟,NVIC等 */HAL_FDCAN_MspDeInit(hfdcan);
#endif /* 复位错误码 */hfdcan->ErrorCode = HAL_FDCAN_ERROR_NONE;/* 设置FDCAN状态 */hfdcan->State = HAL_FDCAN_STATE_RESET;/* 返回HAL_OK */return HAL_OK;
}
函数描述:
用于复位FDCAN。
函数参数:
- 第1个参数是FDCAN_HandleTypeDef类型结构体指针变量。
- 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
91.4.3 函数HAL_FDCAN_ConfigFilter
函数原型:
HAL_StatusTypeDef HAL_FDCAN_ConfigFilter(FDCAN_HandleTypeDef *hfdcan, FDCAN_FilterTypeDef *sFilterConfig)
{uint32_t FilterElementW1;uint32_t FilterElementW2;uint32_t *FilterAddress;HAL_FDCAN_StateTypeDef state = hfdcan->State;if ((state == HAL_FDCAN_STATE_READY) || (state == HAL_FDCAN_STATE_BUSY)){/* 检测函数参数 */assert_param(IS_FDCAN_ID_TYPE(sFilterConfig->IdType));assert_param(IS_FDCAN_FILTER_CFG(sFilterConfig->FilterConfig));if (sFilterConfig->FilterConfig == FDCAN_FILTER_TO_RXBUFFER){assert_param(IS_FDCAN_MAX_VALUE(sFilterConfig->RxBufferIndex, 63U));assert_param(IS_FDCAN_MAX_VALUE(sFilterConfig->IsCalibrationMsg, 1U));}/* 标准ID */if (sFilterConfig->IdType == FDCAN_STANDARD_ID){/* 检测函数形参 */assert_param(IS_FDCAN_MAX_VALUE(sFilterConfig->FilterIndex, (hfdcan->Init.StdFiltersNbr - 1U)));assert_param(IS_FDCAN_MAX_VALUE(sFilterConfig->FilterID1, 0x7FFU));if (sFilterConfig->FilterConfig != FDCAN_FILTER_TO_RXBUFFER){assert_param(IS_FDCAN_MAX_VALUE(sFilterConfig->FilterID2, 0x7FFU));assert_param(IS_FDCAN_STD_FILTER_TYPE(sFilterConfig->FilterType));}/* 构建过滤元素 */if (sFilterConfig->FilterConfig == FDCAN_FILTER_TO_RXBUFFER){FilterElementW1 = ((FDCAN_FILTER_TO_RXBUFFER << 27U) |(sFilterConfig->FilterID1 << 16U) |(sFilterConfig->IsCalibrationMsg << 8U) |sFilterConfig->RxBufferIndex);}else{FilterElementW1 = ((sFilterConfig->FilterType << 30U) |(sFilterConfig->FilterConfig << 27U) |(sFilterConfig->FilterID1 << 16U) |sFilterConfig->FilterID2);}/* 计算过滤地址 */FilterAddress = (uint32_t *)(hfdcan->msgRam.StandardFilterSA + (sFilterConfig->FilterIndex * 4U));/* 将过滤元素写到消息RAM中 */*FilterAddress = FilterElementW1;
}
/* 扩展ID */else {/* 检测函数参数 */assert_param(IS_FDCAN_MAX_VALUE(sFilterConfig->FilterIndex, (hfdcan->Init.ExtFiltersNbr - 1U)));assert_param(IS_FDCAN_MAX_VALUE(sFilterConfig->FilterID1, 0x1FFFFFFFU));if (sFilterConfig->FilterConfig != FDCAN_FILTER_TO_RXBUFFER){assert_param(IS_FDCAN_MAX_VALUE(sFilterConfig->FilterID2, 0x1FFFFFFFU));assert_param(IS_FDCAN_EXT_FILTER_TYPE(sFilterConfig->FilterType));}/* 构建第1个word的过滤元素 */FilterElementW1 = ((sFilterConfig->FilterConfig << 29U) | sFilterConfig->FilterID1);/* 构建第2个word的过滤元素 */if (sFilterConfig->FilterConfig == FDCAN_FILTER_TO_RXBUFFER){FilterElementW2 = sFilterConfig->RxBufferIndex;}else{FilterElementW2 = ((sFilterConfig->FilterType << 30U) | sFilterConfig->FilterID2);}/* 计算过滤地址 */FilterAddress = (uint32_t *)(hfdcan->msgRam.ExtendedFilterSA + (sFilterConfig->FilterIndex * 4U * 2U));/* 写过滤元素到消息RAM */*FilterAddress = FilterElementW1;FilterAddress++;*FilterAddress = FilterElementW2;}return HAL_OK;}else{/* 更新错误码e */hfdcan->ErrorCode |= HAL_FDCAN_ERROR_NOT_INITIALIZED;return HAL_ERROR;}
}
函数描述:
此函数主要用于设置FDCAN过滤。
函数参数:
- 第1个参数是FDCAN_HandleTypeDef类型结构体指针变量。
- 第2个参数是FDCAN_FilterTypeDef类型结构体变量,主要用于过滤参数配置。
- 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
使用举例:
FDCAN_HandleTypeDef hfdcan1;/*
*********************************************************************************************************
* 函 数 名: bsp_InitCan1
* 功能说明: 初始CAN1
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitCan1(void)
{ /* 配置过滤器, 过滤器主要用于接收,这里采样屏蔽位模式。FilterID1 = filterFilterID2 = maskFilterID2的mask每个bit含义0: 不关心,该位不用于比较;1: 必须匹配,接收到的ID必须与滤波器对应的ID位相一致。举例说明:FilterID1 = 0x111FilterID2 = 0x7FF 表示仅接收ID为0x111的FDCAN帧。*/sFilterConfig1.IdType = FDCAN_STANDARD_ID; /* 设置标准ID或者扩展ID *//* 用于过滤索引,如果是标准ID,范围0到127。如果是扩展ID,范围0到64 */
sFilterConfig1.FilterIndex = 0; sFilterConfig1.FilterType = FDCAN_FILTER_MASK; /* 过滤器采样屏蔽位模式 */sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; /* 如果过滤匹配,将数据保存到Rx FIFO 0 */sFilterConfig1.FilterID1 = 0x111; /* 屏蔽位模式下,FilterID1是消息ID */sFilterConfig1.FilterID2 = 0x7FF; /* 屏蔽位模式下,FilterID2是消息屏蔽位 */HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1); /* 配置过滤器 */}
91.4.4 函数HAL_FDCAN_ConfigFifoWatermark
函数原型:
HAL_StatusTypeDef HAL_FDCAN_ConfigFifoWatermark(FDCAN_HandleTypeDef *hfdcan, uint32_t FIFO, uint32_t Watermark)
{/* 检测参数 */assert_param(IS_FDCAN_FIFO_WATERMARK(FIFO));if (FIFO == FDCAN_CFG_TX_EVENT_FIFO){assert_param(IS_FDCAN_MAX_VALUE(Watermark, 32U));}else /* (FIFO == FDCAN_CFG_RX_FIFO0) || (FIFO == FDCAN_CFG_RX_FIFO1) */{assert_param(IS_FDCAN_MAX_VALUE(Watermark, 64U));}if (hfdcan->State == HAL_FDCAN_STATE_READY){/* 设置发送事件FIFO */if (FIFO == FDCAN_CFG_TX_EVENT_FIFO){MODIFY_REG(hfdcan->Instance->TXEFC, FDCAN_TXEFC_EFWM, (Watermark << FDCAN_TXEFC_EFWM_Pos));
}
/* 设置接收FIFO0 */else if (FIFO == FDCAN_CFG_RX_FIFO0){MODIFY_REG(hfdcan->Instance->RXF0C, FDCAN_RXF0C_F0WM, (Watermark << FDCAN_RXF0C_F0WM_Pos));
}
/* 设置接收FIFO1 */else {MODIFY_REG(hfdcan->Instance->RXF1C, FDCAN_RXF1C_F1WM, (Watermark << FDCAN_RXF1C_F1WM_Pos));}/* 返回状态 */return HAL_OK;}else{/* 更新错误码 */hfdcan->ErrorCode |= HAL_FDCAN_ERROR_NOT_READY;return HAL_ERROR;}
}
函数描述:
此函数主要用于配置FIFO Watermark
函数参数:
- 第1个参数是FDCAN_HandleTypeDef类型结构体指针变量。
- 第2个参数是FDCAN FIFO Watermark
#define FDCAN_CFG_TX_EVENT_FIFO ((uint32_t)0x00000000U) /*!< Tx event FIFO */
#define FDCAN_CFG_RX_FIFO0 ((uint32_t)0x00000001U) /*!< Rx FIFO0 */
#define FDCAN_CFG_RX_FIFO1 ((uint32_t)0x00000002U) /*!< Rx FIFO1 */
- 第3个参数FIFO Watermark 中断位置,如果是FDCAN_CFG_TX_EVENT_FIFO,范围0到32,如果是FDCAN_CFG_RX_FIFO0 或FDCAN_CFG_RX_FIFO1,范围0到64。
- 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
使用举例:
FDCAN_HandleTypeDef hfdcan1;/* 设置Rx FIFO0的wartermark为1 */
HAL_FDCAN_ConfigFifoWatermark(&hfdcan1, FDCAN_CFG_RX_FIFO0, 1);
91.4.5 函数HAL_FDCAN_ActivateNotification
函数原型:
HAL_StatusTypeDef HAL_FDCAN_ActivateNotification(FDCAN_HandleTypeDef *hfdcan, uint32_t ActiveITs, uint32_t BufferIndexes)
{HAL_FDCAN_StateTypeDef state = hfdcan->State;/* 检测函数形参 */assert_param(IS_FDCAN_IT(ActiveITs));if ((state == HAL_FDCAN_STATE_READY) || (state == HAL_FDCAN_STATE_BUSY)){/* 使能中断行 */if ((ActiveITs & hfdcan->Instance->ILS) == 0U){/* 使能中断行0 */SET_BIT(hfdcan->Instance->ILE, FDCAN_INTERRUPT_LINE0);}else if ((ActiveITs & hfdcan->Instance->ILS) == ActiveITs){/* 使能中断行1 */SET_BIT(hfdcan->Instance->ILE, FDCAN_INTERRUPT_LINE1);}else{/* 使能中断行0和中断行1 */hfdcan->Instance->ILE = (FDCAN_INTERRUPT_LINE0 | FDCAN_INTERRUPT_LINE1);}if ((ActiveITs & FDCAN_IT_TX_COMPLETE) != 0U){/* 使能Tx Buffer Transmission 中断 */SET_BIT(hfdcan->Instance->TXBTIE, BufferIndexes);}if ((ActiveITs & FDCAN_IT_TX_ABORT_COMPLETE) != 0U){/* 使能 Tx Buffer Cancellation Finished 中断 */SET_BIT(hfdcan->Instance->TXBCIE, BufferIndexes);}/* 使能选择的中断 */__HAL_FDCAN_ENABLE_IT(hfdcan, ActiveITs);/* 返回函数状态 */return HAL_OK;}else{/* 更新错误码 */hfdcan->ErrorCode |= HAL_FDCAN_ERROR_NOT_INITIALIZED;return HAL_ERROR;}
}
函数描述:
此函数主要用于使能中断。
函数参数:
- 第1个参数是FDCAN_HandleTypeDef类型结构体指针变量。
- 第2个参数用于设置要使能的中断,支持的参数如下:
#define FDCAN_IT_TX_COMPLETE FDCAN_IE_TCE /*!< Transmission Completed
#define FDCAN_IT_TX_ABORT_COMPLETE FDCAN_IE_TCFE /*!< Transmission Cancellation Finished */
#define FDCAN_IT_TX_FIFO_EMPTY FDCAN_IE_TFEE /*!< Tx FIFO Empty #define FDCAN_IT_RX_HIGH_PRIORITY_MSG FDCAN_IE_HPME /*!< High priority message received */
#define FDCAN_IT_RX_BUFFER_NEW_MESSAGE FDCAN_IE_DRXE /*!< At least one received message stored into a Rx Buffer #define FDCAN_IT_TIMESTAMP_WRAPAROUND FDCAN_IE_TSWE /*!< Timestamp counter wrapped around */
#define FDCAN_IT_TIMEOUT_OCCURRED FDCAN_IE_TOOE /*!< Timeout reached */#define FDCAN_IT_CALIB_STATE_CHANGED (FDCANCCU_IE_CSCE << 30) /*!< Clock calibration state changed */
#define FDCAN_IT_CALIB_WATCHDOG_EVENT (FDCANCCU_IE_CWEE << 30) /*!< Clock calibration watchdog event occurred #define FDCAN_IT_TX_EVT_FIFO_ELT_LOST FDCAN_IE_TEFLE /*!< Tx Event FIFO element lost */
#define FDCAN_IT_TX_EVT_FIFO_FULL FDCAN_IE_TEFFE /*!< Tx Event FIFO full */
#define FDCAN_IT_TX_EVT_FIFO_WATERMARK FDCAN_IE_TEFWE /*!< Tx Event FIFO fill level reached watermark */
#define FDCAN_IT_TX_EVT_FIFO_NEW_DATA FDCAN_IE_TEFNE /*!< Tx Handler wrote Tx Event FIFO element */#define FDCAN_IT_RX_FIFO0_MESSAGE_LOST FDCAN_IE_RF0LE /*!< Rx FIFO 0 message lost */
#define FDCAN_IT_RX_FIFO0_FULL FDCAN_IE_RF0FE /*!< Rx FIFO 0 full */
#define FDCAN_IT_RX_FIFO0_WATERMARK FDCAN_IE_RF0WE /*!< Rx FIFO 0 fill level reached watermark */
#define FDCAN_IT_RX_FIFO0_NEW_MESSAGE FDCAN_IE_RF0NE /*!< New message written to Rx FIFO 0 */#define FDCAN_IT_RX_FIFO1_MESSAGE_LOST FDCAN_IE_RF1LE /*!< Rx FIFO 1 message lost */
#define FDCAN_IT_RX_FIFO1_FULL FDCAN_IE_RF1FE /*!< Rx FIFO 1 full */
#define FDCAN_IT_RX_FIFO1_WATERMARK FDCAN_IE_RF1WE /*!< Rx FIFO 1 fill level reached watermark */
#define FDCAN_IT_RX_FIFO1_NEW_MESSAGE FDCAN_IE_RF1NE /*!< New message written to Rx FIFO 1 */#define FDCAN_IT_RAM_ACCESS_FAILURE FDCAN_IE_MRAFE /*!< Message RAM access failure occurred
#define FDCAN_IT_ERROR_LOGGING_OVERFLOW FDCAN_IE_ELOE /*!< Overflow of FDCAN Error Logging Counter occurred
#define FDCAN_IT_RAM_WATCHDOG FDCAN_IE_WDIE /*!< Message RAM Watchdog event due to missing READY
#define FDCAN_IT_ARB_PROTOCOL_ERROR FDCAN_IE_PEAE /*!< Protocol error in arbitration phase detected
#define FDCAN_IT_DATA_PROTOCOL_ERROR FDCAN_IE_PEDE /*!< Protocol error in data phase detected
#define FDCAN_IT_RESERVED_ADDRESS_ACCESS FDCAN_IE_ARAE /*!< Access to reserved address occurred #define FDCAN_IT_ERROR_PASSIVE FDCAN_IE_EPE /*!< Error_Passive status changed */
#define FDCAN_IT_ERROR_WARNING FDCAN_IE_EWE /*!< Error_Warning status changed */
#define FDCAN_IT_BUS_OFF FDCAN_IE_BOE /*!< Bus_Off status changed */
- 第3个参数是Tx Buffer Indexes,可以如下参数的任意组合:
#define FDCAN_TX_BUFFER0 ((uint32_t)0x00000001U) /*!< Add message to Tx Buffer 0 */
#define FDCAN_TX_BUFFER1 ((uint32_t)0x00000002U) /*!< Add message to Tx Buffer 1 */
#define FDCAN_TX_BUFFER2 ((uint32_t)0x00000004U) /*!< Add message to Tx Buffer 2 */
#define FDCAN_TX_BUFFER3 ((uint32_t)0x00000008U) /*!< Add message to Tx Buffer 3 */
#define FDCAN_TX_BUFFER4 ((uint32_t)0x00000010U) /*!< Add message to Tx Buffer 4 */
#define FDCAN_TX_BUFFER5 ((uint32_t)0x00000020U) /*!< Add message to Tx Buffer 5 */
#define FDCAN_TX_BUFFER6 ((uint32_t)0x00000040U) /*!< Add message to Tx Buffer 6 */
#define FDCAN_TX_BUFFER7 ((uint32_t)0x00000080U) /*!< Add message to Tx Buffer 7 */
#define FDCAN_TX_BUFFER8 ((uint32_t)0x00000100U) /*!< Add message to Tx Buffer 8 */
#define FDCAN_TX_BUFFER9 ((uint32_t)0x00000200U) /*!< Add message to Tx Buffer 9 */
#define FDCAN_TX_BUFFER10 ((uint32_t)0x00000400U) /*!< Add message to Tx Buffer 10 */
#define FDCAN_TX_BUFFER11 ((uint32_t)0x00000800U) /*!< Add message to Tx Buffer 11 */
#define FDCAN_TX_BUFFER12 ((uint32_t)0x00001000U) /*!< Add message to Tx Buffer 12 */
#define FDCAN_TX_BUFFER13 ((uint32_t)0x00002000U) /*!< Add message to Tx Buffer 13 */
#define FDCAN_TX_BUFFER14 ((uint32_t)0x00004000U) /*!< Add message to Tx Buffer 14 */
#define FDCAN_TX_BUFFER15 ((uint32_t)0x00008000U) /*!< Add message to Tx Buffer 15 */
#define FDCAN_TX_BUFFER16 ((uint32_t)0x00010000U) /*!< Add message to Tx Buffer 16 */
#define FDCAN_TX_BUFFER17 ((uint32_t)0x00020000U) /*!< Add message to Tx Buffer 17 */
#define FDCAN_TX_BUFFER18 ((uint32_t)0x00040000U) /*!< Add message to Tx Buffer 18 */
#define FDCAN_TX_BUFFER19 ((uint32_t)0x00080000U) /*!< Add message to Tx Buffer 19 */
#define FDCAN_TX_BUFFER20 ((uint32_t)0x00100000U) /*!< Add message to Tx Buffer 20 */
#define FDCAN_TX_BUFFER21 ((uint32_t)0x00200000U) /*!< Add message to Tx Buffer 21 */
#define FDCAN_TX_BUFFER22 ((uint32_t)0x00400000U) /*!< Add message to Tx Buffer 22 */
#define FDCAN_TX_BUFFER23 ((uint32_t)0x00800000U) /*!< Add message to Tx Buffer 23 */
#define FDCAN_TX_BUFFER24 ((uint32_t)0x01000000U) /*!< Add message to Tx Buffer 24 */
#define FDCAN_TX_BUFFER25 ((uint32_t)0x02000000U) /*!< Add message to Tx Buffer 25 */
#define FDCAN_TX_BUFFER26 ((uint32_t)0x04000000U) /*!< Add message to Tx Buffer 26 */
#define FDCAN_TX_BUFFER27 ((uint32_t)0x08000000U) /*!< Add message to Tx Buffer 27 */
#define FDCAN_TX_BUFFER28 ((uint32_t)0x10000000U) /*!< Add message to Tx Buffer 28 */
#define FDCAN_TX_BUFFER29 ((uint32_t)0x20000000U) /*!< Add message to Tx Buffer 29 */
#define FDCAN_TX_BUFFER30 ((uint32_t)0x40000000U) /*!< Add message to Tx Buffer 30 */
#define FDCAN_TX_BUFFER31 ((uint32_t)0x80000000U) /*!< Add message to Tx Buffer 31 */
如果第2个参数不包括FDCAN_IT_TX_COMPLETE或FDCAN_IT_TX_ABORT_COMPLETE,此参数将被忽略。
- 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
使用举例:
FDCAN_HandleTypeDef hfdcan1;/* 激活RX FIFO0的watermark通知中断,位开启Tx Buffer中断*/
HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_WATERMARK, 0);
91.4.6 函数HAL_FDCAN_Start
函数原型:
HAL_StatusTypeDef HAL_FDCAN_Start(FDCAN_HandleTypeDef *hfdcan)
{if (hfdcan->State == HAL_FDCAN_STATE_READY){/* 设置FDCAN外设状态 */hfdcan->State = HAL_FDCAN_STATE_BUSY;/* 请求离开初始化状态 */CLEAR_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_INIT);/* 设置错误码 */hfdcan->ErrorCode = HAL_FDCAN_ERROR_NONE;return HAL_OK;}else{hfdcan->ErrorCode |= HAL_FDCAN_ERROR_NOT_READY;return HAL_ERROR;}
}
函数描述:
此函数主要用于启动FDCAN。
函数参数:
- 第1个参数是FDCAN_HandleTypeDef类型结构体指针变量。
- 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
使用举例:
/**
* @brief Writes block(s) to a specified address in an SD card, in DMA mode.
* @param pData: Pointer to the buffer that will contain the data to transmit
* @param WriteAddr: Address from where data is to be written
* @param NumOfBlocks: Number of SD blocks to write
* @retval SD status
*/
uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
{if( HAL_SD_WriteBlocks_DMA(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks) == HAL_OK){return MSD_OK;}else{return MSD_ERROR;}
}
91.4.7 函数HAL_FDCAN_AddMessageToTxFifoQ
函数原型:
HAL_StatusTypeDef HAL_FDCAN_AddMessageToTxFifoQ(FDCAN_HandleTypeDef *hfdcan, FDCAN_TxHeaderTypeDef *pTxHeader, uint8_t *pTxData)
{uint32_t PutIndex;/* 检查函数形参 */assert_param(IS_FDCAN_ID_TYPE(pTxHeader->IdType));if (pTxHeader->IdType == FDCAN_STANDARD_ID){assert_param(IS_FDCAN_MAX_VALUE(pTxHeader->Identifier, 0x7FFU));}else /* pTxHeader->IdType == FDCAN_EXTENDED_ID */{assert_param(IS_FDCAN_MAX_VALUE(pTxHeader->Identifier, 0x1FFFFFFFU));}assert_param(IS_FDCAN_FRAME_TYPE(pTxHeader->TxFrameType));assert_param(IS_FDCAN_DLC(pTxHeader->DataLength));assert_param(IS_FDCAN_ESI(pTxHeader->ErrorStateIndicator));assert_param(IS_FDCAN_BRS(pTxHeader->BitRateSwitch));assert_param(IS_FDCAN_FDF(pTxHeader->FDFormat));assert_param(IS_FDCAN_EFC(pTxHeader->TxEventFifoControl));assert_param(IS_FDCAN_MAX_VALUE(pTxHeader->MessageMarker, 0xFFU));if (hfdcan->State == HAL_FDCAN_STATE_BUSY){/* 检测Tx FIFO/Queue 是否在RAM中分配到空间 */if ((hfdcan->Instance->TXBC & FDCAN_TXBC_TFQS) == 0U){/* 更新错误码 */hfdcan->ErrorCode |= HAL_FDCAN_ERROR_PARAM;return HAL_ERROR;}/* 检查Tx FIFO/Queue 是否满 */if ((hfdcan->Instance->TXFQS & FDCAN_TXFQS_TFQF) != 0U){/* 更新错误码 */hfdcan->ErrorCode |= HAL_FDCAN_ERROR_FIFO_FULL;return HAL_ERROR;}else{/* 获取Tx FIFO PutIndex */PutIndex = ((hfdcan->Instance->TXFQS & FDCAN_TXFQS_TFQPI) >> FDCAN_TXFQS_TFQPI_Pos);/* 添加消息到Tx FIFO/Queue */FDCAN_CopyMessageToRAM(hfdcan, pTxHeader, pTxData, PutIndex);/* 激活相应的传输请求 */hfdcan->Instance->TXBAR = ((uint32_t)1 << PutIndex);/* 存储最近的Tx FIFO/Queue Request Buffer Index */hfdcan->LatestTxFifoQRequest = ((uint32_t)1 << PutIndex);}/* 返回错误状态 */return HAL_OK;}else{/* 更新错误码 */hfdcan->ErrorCode |= HAL_FDCAN_ERROR_NOT_STARTED;return HAL_ERROR;}
}
函数描述:
此函数用于添加消息到Tx FIFO/Queue并激活相应的传输请求。
函数参数:
- 第1个参数是FDCAN_HandleTypeDef类型结构体指针变量。
- 第2个参数是FDCAN_TxHeaderTypeDef类型结构体变量,用于消息发送。
- 第3个参数是要发送的数据地址。程序里面会将数据复制到发送缓冲区。
- 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
使用举例:
/*
*********************************************************************************************************
* 函 数 名: can1_SendPacket
* 功能说明: 发送一包数据
* 形 参:_DataBuf 数据缓冲区
* _Len 数据长度, 支持8,12,16,20,24,32,48或者64字节
* 返 回 值: 无
*********************************************************************************************************
*/
void can1_SendPacket(uint8_t *_DataBuf, uint8_t _Len)
{ FDCAN_TxHeaderTypeDef TxHeader = {0};/* 配置发送参数 */TxHeader.Identifier = 0x222; /* 设置接收帧消息的ID */TxHeader.IdType = FDCAN_STANDARD_ID; /* 标准ID */TxHeader.TxFrameType = FDCAN_DATA_FRAME; /* 数据帧 */TxHeader.DataLength = (uint32_t)_Len << 16; /* 发送数据长度 */TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE; /* 设置错误状态指示 */TxHeader.BitRateSwitch = FDCAN_BRS_ON; /* 开启可变波特率 */TxHeader.FDFormat = FDCAN_FD_CAN; /* FDCAN格式 */TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;/* 用于发送事件FIFO控制, 不存储 */TxHeader.MessageMarker = 0; /* 用于复制到TX EVENT FIFO的消息Maker来识别消息状态,范围0到0xFF *//* 添加数据到TX FIFO */HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, _DataBuf);
}
91.4.8 函数HAL_FDCAN_GetRxMessage
函数原型:
HAL_StatusTypeDef HAL_FDCAN_GetRxMessage(FDCAN_HandleTypeDef *hfdcan, uint32_t RxLocation, FDCAN_RxHeaderTypeDef *pRxHeader, uint8_t *pRxData)
{uint32_t *RxAddress;uint8_t *pData;uint32_t ByteCounter;uint32_t GetIndex = 0;HAL_FDCAN_StateTypeDef state = hfdcan->State;if (state == HAL_FDCAN_STATE_BUSY){if (RxLocation == FDCAN_RX_FIFO0) /* Rx element分配到 Rx FIFO 0 */{/* 检查Rx FIFO 0 分配了RAM空间 */if ((hfdcan->Instance->RXF0C & FDCAN_RXF0C_F0S) == 0U){/* 更新错误码*/hfdcan->ErrorCode |= HAL_FDCAN_ERROR_PARAM;return HAL_ERROR;}/* 检查Rx FIFO 0 非空 */if ((hfdcan->Instance->RXF0S & FDCAN_RXF0S_F0FL) == 0U){/* 更新错误码*/hfdcan->ErrorCode |= HAL_FDCAN_ERROR_FIFO_EMPTY;return HAL_ERROR;}else{/* 检查Rx FIFO 0 满且开了覆盖模式 */if(((hfdcan->Instance->RXF0S & FDCAN_RXF0S_F0F) >> FDCAN_RXF0S_F0F_Pos) == 1U){if(((hfdcan->Instance->RXF0C & FDCAN_RXF0C_F0OM) >> FDCAN_RXF0C_F0OM_Pos) == FDCAN_RX_FIFO_OVERWRITE){/* 开启了覆盖模式,丢弃第1个数据 */GetIndex = 1U;}}/* 计算Rx FIFO 0 element 索引 */GetIndex += ((hfdcan->Instance->RXF0S & FDCAN_RXF0S_F0GI) >> FDCAN_RXF0S_F0GI_Pos);/* 计算 Rx FIFO 0 element 地址 */RxAddress = (uint32_t *)(hfdcan->msgRam.RxFIFO0SA + (GetIndex * hfdcan->Init.RxFifo0ElmtSize * 4U));}}else if (RxLocation == FDCAN_RX_FIFO1) /* Rx element is assigned to the Rx FIFO 1 */{/* 检查Rx FIFO 1 分配了RAM空间 */if ((hfdcan->Instance->RXF1C & FDCAN_RXF1C_F1S) == 0U){/* 更新错误码 */hfdcan->ErrorCode |= HAL_FDCAN_ERROR_PARAM;return HAL_ERROR;}/* 检查 Rx FIFO 0 非空 */if ((hfdcan->Instance->RXF1S & FDCAN_RXF1S_F1FL) == 0U){/* 更新错误码 */hfdcan->ErrorCode |= HAL_FDCAN_ERROR_FIFO_EMPTY;return HAL_ERROR;}else{/* 检查Rx FIFO 1 满且开了覆盖模式 */if(((hfdcan->Instance->RXF1S & FDCAN_RXF1S_F1F) >> FDCAN_RXF1S_F1F_Pos) == 1U){if(((hfdcan->Instance->RXF1C & FDCAN_RXF1C_F1OM) >> FDCAN_RXF1C_F1OM_Pos) == FDCAN_RX_FIFO_OVERWRITE){/* 开启了覆盖模式,丢弃第1个数据 */GetIndex = 1U;}}/* 计算 Rx FIFO 1 element 索引 */GetIndex += ((hfdcan->Instance->RXF1S & FDCAN_RXF1S_F1GI) >> FDCAN_RXF1S_F1GI_Pos);/* 计算 Rx FIFO 1 element 地址 */RxAddress = (uint32_t *)(hfdcan->msgRam.RxFIFO1SA + (GetIndex * hfdcan->Init.RxFifo1ElmtSize * 4U));}}else /* Rx element 分配了专用 Rx buffer */{/* 检查选择的buffer分配了RAM空间 */if (RxLocation >= hfdcan->Init.RxBuffersNbr){/* 更新错误码 */hfdcan->ErrorCode |= HAL_FDCAN_ERROR_PARAM;return HAL_ERROR;}else{/* 计算Rx buffer 地址 */RxAddress = (uint32_t *)(hfdcan->msgRam.RxBufferSA + (RxLocation * hfdcan->Init.RxBufferSize * 4U));}}/* 接收IdType */pRxHeader->IdType = *RxAddress & FDCAN_ELEMENT_MASK_XTD;/* 接收Identifier */if (pRxHeader->IdType == FDCAN_STANDARD_ID) /* Standard ID element */{pRxHeader->Identifier = ((*RxAddress & FDCAN_ELEMENT_MASK_STDID) >> 18);}else /* Extended ID element */{pRxHeader->Identifier = (*RxAddress & FDCAN_ELEMENT_MASK_EXTID);}/* 接收RxFrameType */pRxHeader->RxFrameType = (*RxAddress & FDCAN_ELEMENT_MASK_RTR);/* 接收ErrorStateIndicator */pRxHeader->ErrorStateIndicator = (*RxAddress & FDCAN_ELEMENT_MASK_ESI);/* Increment RxAddress pointer to second word of Rx FIFO element */RxAddress++;/* 接收RxTimestamp */pRxHeader->RxTimestamp = (*RxAddress & FDCAN_ELEMENT_MASK_TS);/* 接收DataLength */pRxHeader->DataLength = (*RxAddress & FDCAN_ELEMENT_MASK_DLC);/* 接收BitRateSwitch */pRxHeader->BitRateSwitch = (*RxAddress & FDCAN_ELEMENT_MASK_BRS);/* 接收FDFormat */pRxHeader->FDFormat = (*RxAddress & FDCAN_ELEMENT_MASK_FDF);/* 接收FilterIndex */pRxHeader->FilterIndex = ((*RxAddress & FDCAN_ELEMENT_MASK_FIDX) >> 24);/* 接收NonMatchingFrame */pRxHeader->IsFilterMatchingFrame = ((*RxAddress & FDCAN_ELEMENT_MASK_ANMF) >> 31);/* 增加地址,指向Rx FIFO element的payload */RxAddress++;/* 接收 Rx payload */pData = (uint8_t *)RxAddress;for (ByteCounter = 0; ByteCounter < DLCtoBytes[pRxHeader->DataLength >> 16]; ByteCounter++){pRxData[ByteCounter] = pData[ByteCounter];}if (RxLocation == FDCAN_RX_FIFO0) /* Rx element is assigned to the Rx FIFO 0 */{/* 确认Rx FIFO 0先进的数据已经读出 */hfdcan->Instance->RXF0A = GetIndex;}else if (RxLocation == FDCAN_RX_FIFO1) /* Rx element is assigned to the Rx FIFO 1 */{/* 确认Rx FIFO 1先进的数据已经读出 */hfdcan->Instance->RXF1A = GetIndex;}else /* Rx element is assigned to a dedicated Rx buffer */{/* 清除当前Rx buffer的新数据标志 */if (RxLocation < FDCAN_RX_BUFFER32){hfdcan->Instance->NDAT1 = ((uint32_t)1 << RxLocation);}else /* FDCAN_RX_BUFFER32 <= RxLocation <= FDCAN_RX_BUFFER63 */{hfdcan->Instance->NDAT2 = ((uint32_t)1 << (RxLocation & 0x1FU));}}/* 返回状态 */return HAL_OK;}else{/* 更新错误码 */hfdcan->ErrorCode |= HAL_FDCAN_ERROR_NOT_STARTED;return HAL_ERROR;}
}
函数描述:
此函数主要用于获取接收到的数据。
函数参数:
- 第1个参数是FDCAN_HandleTypeDef类型结构体指针变量。
- 第2个参数是读取位置,支持如下几种参数:
#define FDCAN_RX_FIFO0 ((uint32_t)0x00000040U) /*!< Get received message from Rx FIFO 0 */
#define FDCAN_RX_FIFO1 ((uint32_t)0x00000041U) /*!< Get received message from Rx FIFO 1 */
#define FDCAN_RX_BUFFER0 ((uint32_t)0x00000000U) /*!< Get received message from Rx Buffer 0 */
#define FDCAN_RX_BUFFER1 ((uint32_t)0x00000001U) /*!< Get received message from Rx Buffer 1 */
#define FDCAN_RX_BUFFER2 ((uint32_t)0x00000002U) /*!< Get received message from Rx Buffer 2 */
#define FDCAN_RX_BUFFER3 ((uint32_t)0x00000003U) /*!< Get received message from Rx Buffer 3 */
#define FDCAN_RX_BUFFER4 ((uint32_t)0x00000004U) /*!< Get received message from Rx Buffer 4 */
#define FDCAN_RX_BUFFER5 ((uint32_t)0x00000005U) /*!< Get received message from Rx Buffer 5 */
#define FDCAN_RX_BUFFER6 ((uint32_t)0x00000006U) /*!< Get received message from Rx Buffer 6 */
#define FDCAN_RX_BUFFER7 ((uint32_t)0x00000007U) /*!< Get received message from Rx Buffer 7 */
#define FDCAN_RX_BUFFER8 ((uint32_t)0x00000008U) /*!< Get received message from Rx Buffer 8 */
#define FDCAN_RX_BUFFER9 ((uint32_t)0x00000009U) /*!< Get received message from Rx Buffer 9 */
#define FDCAN_RX_BUFFER10 ((uint32_t)0x0000000AU) /*!< Get received message from Rx Buffer 10 */
#define FDCAN_RX_BUFFER11 ((uint32_t)0x0000000BU) /*!< Get received message from Rx Buffer 11 */
#define FDCAN_RX_BUFFER12 ((uint32_t)0x0000000CU) /*!< Get received message from Rx Buffer 12 */
#define FDCAN_RX_BUFFER13 ((uint32_t)0x0000000DU) /*!< Get received message from Rx Buffer 13 */
#define FDCAN_RX_BUFFER14 ((uint32_t)0x0000000EU) /*!< Get received message from Rx Buffer 14 */
#define FDCAN_RX_BUFFER15 ((uint32_t)0x0000000FU) /*!< Get received message from Rx Buffer 15 */
#define FDCAN_RX_BUFFER16 ((uint32_t)0x00000010U) /*!< Get received message from Rx Buffer 16 */
#define FDCAN_RX_BUFFER17 ((uint32_t)0x00000011U) /*!< Get received message from Rx Buffer 17 */
#define FDCAN_RX_BUFFER18 ((uint32_t)0x00000012U) /*!< Get received message from Rx Buffer 18 */
#define FDCAN_RX_BUFFER19 ((uint32_t)0x00000013U) /*!< Get received message from Rx Buffer 19 */
#define FDCAN_RX_BUFFER20 ((uint32_t)0x00000014U) /*!< Get received message from Rx Buffer 20 */
#define FDCAN_RX_BUFFER21 ((uint32_t)0x00000015U) /*!< Get received message from Rx Buffer 21 */
#define FDCAN_RX_BUFFER22 ((uint32_t)0x00000016U) /*!< Get received message from Rx Buffer 22 */
#define FDCAN_RX_BUFFER23 ((uint32_t)0x00000017U) /*!< Get received message from Rx Buffer 23 */
#define FDCAN_RX_BUFFER24 ((uint32_t)0x00000018U) /*!< Get received message from Rx Buffer 24 */
#define FDCAN_RX_BUFFER25 ((uint32_t)0x00000019U) /*!< Get received message from Rx Buffer 25 */
#define FDCAN_RX_BUFFER26 ((uint32_t)0x0000001AU) /*!< Get received message from Rx Buffer 26 */
#define FDCAN_RX_BUFFER27 ((uint32_t)0x0000001BU) /*!< Get received message from Rx Buffer 27 */
#define FDCAN_RX_BUFFER28 ((uint32_t)0x0000001CU) /*!< Get received message from Rx Buffer 28 */
#define FDCAN_RX_BUFFER29 ((uint32_t)0x0000001DU) /*!< Get received message from Rx Buffer 29 */
#define FDCAN_RX_BUFFER30 ((uint32_t)0x0000001EU) /*!< Get received message from Rx Buffer 30 */
#define FDCAN_RX_BUFFER31 ((uint32_t)0x0000001FU) /*!< Get received message from Rx Buffer 31 */
#define FDCAN_RX_BUFFER32 ((uint32_t)0x00000020U) /*!< Get received message from Rx Buffer 32 */
#define FDCAN_RX_BUFFER33 ((uint32_t)0x00000021U) /*!< Get received message from Rx Buffer 33 */
#define FDCAN_RX_BUFFER34 ((uint32_t)0x00000022U) /*!< Get received message from Rx Buffer 34 */
#define FDCAN_RX_BUFFER35 ((uint32_t)0x00000023U) /*!< Get received message from Rx Buffer 35 */
#define FDCAN_RX_BUFFER36 ((uint32_t)0x00000024U) /*!< Get received message from Rx Buffer 36 */
#define FDCAN_RX_BUFFER37 ((uint32_t)0x00000025U) /*!< Get received message from Rx Buffer 37 */
#define FDCAN_RX_BUFFER38 ((uint32_t)0x00000026U) /*!< Get received message from Rx Buffer 38 */
#define FDCAN_RX_BUFFER39 ((uint32_t)0x00000027U) /*!< Get received message from Rx Buffer 39 */
#define FDCAN_RX_BUFFER40 ((uint32_t)0x00000028U) /*!< Get received message from Rx Buffer 40 */
#define FDCAN_RX_BUFFER41 ((uint32_t)0x00000029U) /*!< Get received message from Rx Buffer 41 */
#define FDCAN_RX_BUFFER42 ((uint32_t)0x0000002AU) /*!< Get received message from Rx Buffer 42 */
#define FDCAN_RX_BUFFER43 ((uint32_t)0x0000002BU) /*!< Get received message from Rx Buffer 43 */
#define FDCAN_RX_BUFFER44 ((uint32_t)0x0000002CU) /*!< Get received message from Rx Buffer 44 */
#define FDCAN_RX_BUFFER45 ((uint32_t)0x0000002DU) /*!< Get received message from Rx Buffer 45 */
#define FDCAN_RX_BUFFER46 ((uint32_t)0x0000002EU) /*!< Get received message from Rx Buffer 46 */
#define FDCAN_RX_BUFFER47 ((uint32_t)0x0000002FU) /*!< Get received message from Rx Buffer 47 */
#define FDCAN_RX_BUFFER48 ((uint32_t)0x00000030U) /*!< Get received message from Rx Buffer 48 */
#define FDCAN_RX_BUFFER49 ((uint32_t)0x00000031U) /*!< Get received message from Rx Buffer 49 */
#define FDCAN_RX_BUFFER50 ((uint32_t)0x00000032U) /*!< Get received message from Rx Buffer 50 */
#define FDCAN_RX_BUFFER51 ((uint32_t)0x00000033U) /*!< Get received message from Rx Buffer 51 */
#define FDCAN_RX_BUFFER52 ((uint32_t)0x00000034U) /*!< Get received message from Rx Buffer 52 */
#define FDCAN_RX_BUFFER53 ((uint32_t)0x00000035U) /*!< Get received message from Rx Buffer 53 */
#define FDCAN_RX_BUFFER54 ((uint32_t)0x00000036U) /*!< Get received message from Rx Buffer 54 */
#define FDCAN_RX_BUFFER55 ((uint32_t)0x00000037U) /*!< Get received message from Rx Buffer 55 */
#define FDCAN_RX_BUFFER56 ((uint32_t)0x00000038U) /*!< Get received message from Rx Buffer 56 */
#define FDCAN_RX_BUFFER57 ((uint32_t)0x00000039U) /*!< Get received message from Rx Buffer 57 */
#define FDCAN_RX_BUFFER58 ((uint32_t)0x0000003AU) /*!< Get received message from Rx Buffer 58 */
#define FDCAN_RX_BUFFER59 ((uint32_t)0x0000003BU) /*!< Get received message from Rx Buffer 59 */
#define FDCAN_RX_BUFFER60 ((uint32_t)0x0000003CU) /*!< Get received message from Rx Buffer 60 */
#define FDCAN_RX_BUFFER61 ((uint32_t)0x0000003DU) /*!< Get received message from Rx Buffer 61 */
#define FDCAN_RX_BUFFER62 ((uint32_t)0x0000003EU) /*!< Get received message from Rx Buffer 62 */
#define FDCAN_RX_BUFFER63 ((uint32_t)0x0000003FU) /*!< Get received message from Rx Buffer 63 */
- 第3个参数是FDCAN_RxHeaderTypeDef类型结构体变量,主要用于消息接收。
- 第4个参数是数据接收缓冲地址。
- 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
使用举例:
/*
*********************************************************************************************************
* 函 数 名: HAL_FDCAN_RxFifo0Callback
* 功能说明: CAN中断服务程序-回调函数
* 形 参: hfdcan
* 返 回 值: 无
*********************************************************************************************************
*/
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{if (hfdcan == &hfdcan1){if ((RxFifo0ITs & FDCAN_IT_RX_FIFO0_WATERMARK) != RESET){/* 从RX FIFO0读取数据 */HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &g_Can1RxHeader, g_Can1RxData);/* 激活Rx FIFO0 watermark notification */HAL_FDCAN_ActivateNotification(hfdcan, FDCAN_IT_RX_FIFO0_WATERMARK, 0);if (g_Can1RxHeader.Identifier == 0x111 && g_Can1RxHeader.IdType == FDCAN_STANDARD_ID){bsp_PutMsg(MSG_CAN1_RX, 0); /* 发消息收到数据包,结果在g_Can1RxHeader, g_Can1RxData */}}}
}
91.5 总结
本章节就为大家讲解这么多,更多FDCAN知识可以看本教程的第90章。
这篇关于【STM32H7教程】第91章 STM32H7的FDCAN总线基础知识和HAL库API的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!