FDCAN
CubeMX配置解析
这里的配置以STM32G474CET6
为例

Classic mode
:普通CAN
FD mode without BitRate Switching
:FDCAN,没有波特率转换
FD mode with BitRate Switching
:FDCAN,带有波特率转换,数据段使用更高波特率
注意选用FD mode with BitRate Switching
后还可以通过txheader
去选定是否开启BitRateSwithcing
,以及是 采用CAN
的帧格式还是 FDCAN
帧格式
也就是说这个帧格式选择是决定 是否允许拥有FDCAN
的特殊格式和能否开启BitRateSwitching
,至于发送的帧实际是否用,取决于txheader
从这一段HAL_FDCAN_Init
初始化代码中可以看出,只有FD mode with BitRate Switching
才会去初始化数据段的传输参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
HAL_StatusTypeDef HAL_FDCAN_Init(FDCAN_HandleTypeDef *hfdcan)
{
uint32_t tickstart;
/* Check FDCAN handle */
//...
/* Check function parameters */
//...
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));
}
//....
//...
}
|
1. Classic Mode(传统模式)
- 本质:完全兼容传统 CAN 2.0B 协议,不启用 FDCAN 的扩展功能
- 数据长度:最大 8 字节(DLC=0~8)
- 波特率:全程使用标称波特率(Nominal Bit Rate),无速率切换
- 帧结构:与传统 CAN 帧一致,仅包含仲裁段、控制段、数据段(≤8 字节)、CRC 段等
- 核心作用:用于对接仅支持传统 CAN 协议的设备(如老旧传感器、执行器),确保兼容性
2. FD mode with BitRate Switching(带波特率切换的 FD 模式)
- 本质:启用 FDCAN 的核心扩展功能,支持高速长数据传输,且数据段使用更高波特率
- 数据长度:最大 64 字节(DLC=0
15,其中 DLC=915 对应 32~64 字节)
- 波特率:
- 仲裁段(Arbitration Phase):使用标称波特率(与传统模式一致,确保仲裁兼容性)
- 数据段(Data Phase):使用更高的数据波特率(Data Bit Rate)(可配置为标称波特率的 2~8 倍,如 8Mbps)
3. FD mode without BitRate Switching(不带波特率切换的 FD 模式)
- 本质:启用 FDCAN 的长数据功能,但不切换波特率,全程使用标称波特率
- 数据长度:最大 64 字节(与带切换的 FD 模式一致)
- 波特率:仲裁段和数据段均使用标称波特率,无速率提升
- 帧结构:包含 FD 帧标志(FDF),但无波特率切换标志(BRS=0)
- 核心作用:用于需要长数据传输(>8 字节)但总线上存在不支持高速数据段的设备场景,或因硬件限制(如线缆质量差)无法使用高速率的场景
Mode
一般使用Normal mode

- Normal mode(正常模式)
- Restricted operation(受限操作模式)
- Bus Monitoring mode(总线监听模式)
- Internal LoopBack mode(内部回环模式)
- External LoopBack mode(外部回环模式)
Auto-Retransmission & Transmit-Pause & Protocol-Exception

Auto-Retransmission
:自动重传,如果发送的帧没有收到应答,出现错误,就不断重新发送,在总线负载较高的时候一定要关掉,会严重拉低控制频率
Transmit-Pause
:一种临时停止 FDCAN 发送功能的机制,用于在特定场景下主动暂停数据发送,避免干扰总线或等待特定条件,可以通过软件主动触发,调用HAL
库函数
Protocol-Exception
:检测到异常情况(帧格式错误等),会去触发异常处理机制(例如异常处理中断)
Data & Nominal
此处提一下,Data Sync Jump Width
(数据段同步跳转宽度)是针对数据波特率(Data Bit Rate) 配置的关键时序参数
Data(数据波特率相关)
“Data” 特指 FDCAN 在FD 模式(Flexible Data Rate Mode) 下,帧的数据段(Data Phase) 所使用的传输速率,即数据波特率(Data Bit Rate)
Nominal(标称波特率相关)
“Nominal” 特指 FDCAN 帧在仲裁段(Arbitration Phase)、控制段(Control Phase)、CRC 段(CRC Phase) 和ACK 段(Acknowledgment Phase) 中使用的传输速率,即标称波特率(Nominal Bit Rate)
Filter and Std-Filters-Nbr&Ext-Filters-Nbr
Std Filters Nbr(标准帧过滤器数量) 和Ext Filters Nbr(扩展帧过滤器数量) 是配置 FDCAN(Flexible Data Rate CAN)接收过滤功能的核心参数。它们分别用于定义标准帧(11 位 ID) 和扩展帧(29 位 ID) 的硬件过滤器数量,直接影响 FDCAN 控制器能接收的帧类型和数量
- Std Filters Nbr:配置标准帧(11 位 ID) 的过滤器数量。每个过滤器可匹配一个或多个标准 ID,或通过掩码模式匹配 ID 范围
- Ext Filters Nbr:配置扩展帧(29 位 ID) 的过滤器数量。每个过滤器可匹配一个或多个扩展 ID,或通过掩码模式匹配 ID 范围
过滤器类型
FDCAN 支持多种过滤模式,不同模式对过滤器数量的需求不同:
- 掩码模式(Mask Mode):
通过 ID 和掩码匹配 ID 范围。例如,1 个标准过滤器可匹配 0x100~0x1FF 范围内的所有 ID(掩码 = 0x100,ID=0x1FF)
- 双 ID 模式(Dual ID Mode):
匹配两个特定 ID。例如,1 个扩展过滤器可同时匹配 0x12345678 和 0x87654321
- 范围模式(Range Mode):
匹配 ID 在两个值之间的所有帧。例如,1 个标准过滤器可匹配 0x000~0x0FF 范围内的 ID
配置示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// 配置4个扩展过滤器,每个匹配1个特定ID(双ID模式)
FDCAN_FilterTypeDef sFilterConfig;
sFilterConfig.IdType = FDCAN_EXTENDED_ID;
sFilterConfig.FilterType = FDCAN_FILTER_DUAL;
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXBUFFER;
// 过滤器0匹配ID=0x01
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterID1 = 0x01;
sFilterConfig.FilterID2 = 0x01;
sFilterConfig.RxBufferIndex = 0;
HAL_FDCAN_ConfigFilter(&hfdcan2, &sFilterConfig);
// 过滤器1匹配ID=0x02
sFilterConfig.FilterIndex = 1;
sFilterConfig.FilterID1 = 0x02;
sFilterConfig.FilterID2 = 0x02;
sFilterConfig.RxBufferIndex = 1;
HAL_FDCAN_ConfigFilter(&hfdcan2, &sFilterConfig);
// 依此类推配置过滤器2和3
|
关于Txheader
的配置
1
2
3
4
5
6
7
8
9
10
11
|
FDCAN_TxHeaderTypeDef Txheader_gimbal ;
Txheader_gimbal.DataLength = 0x08 ;//数据长度
Txheader_gimbal.Identifier = 0x1FF ;//标识符
Txheader_gimbal.TxFrameType = FDCAN_DATA_FRAME ;
Txheader_gimbal.IdType = FDCAN_STANDARD_ID ;
Txheader_gimbal.ErrorStateIndicator=FDCAN_ESI_ACTIVE;//开启错误状态指示
Txheader_gimbal.BitRateSwitch=FDCAN_BRS_OFF;
Txheader_gimbal.FDFormat=FDCAN_CLASSIC_CAN;//传统的CAN模式
//Txheader_gimbal.FDFormat=FDCAN_FD_CAN;//FDCAN模式
Txheader_gimbal.TxEventFifoControl = FDCAN_NO_TX_EVENTS;//无发送事件
Txheader_gimbal.MessageMarker = 0;
|
时间片
不做解析,硬件方面计算出来拿来用即可
使用代码
FilterInit-and-FDCANStart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
void FDCAN_IntFilterAndStart(FDCAN_HandleTypeDef *hfdcan) {
//--------FDCAN1 Filter and Start--------//
FDCAN_FilterTypeDef sFilterConfig;
sFilterConfig.IdType = FDCAN_STANDARD_ID;
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = FDCAN_FILTER_MASK;
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
sFilterConfig.FilterID1 = 0x00;//0x500;
sFilterConfig.FilterID2 = 0x00;//0x780;
if (HAL_FDCAN_ConfigFilter(hfdcan, &sFilterConfig) != HAL_OK)
{
FDCAN_ErrorHandler();
}
if (HAL_FDCAN_ConfigGlobalFilter(hfdcan, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
{
FDCAN_ErrorHandler();
}
if (HAL_FDCAN_Start(hfdcan) != HAL_OK)
{
FDCAN_ErrorHandler();
}
if (HAL_FDCAN_ActivateNotification(hfdcan, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
{
FDCAN_ErrorHandler();
}
if (HAL_FDCAN_ActivateNotification(hfdcan, FDCAN_IT_BUS_OFF, 0) != HAL_OK)
{
FDCAN_ErrorHandler();
}
}
|
解析一下
1
|
if (HAL_FDCAN_ConfigGlobalFilter(hfdcan, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
|
HAL_FDCAN_ConfigGlobalFilter
用于定义未被任何特定过滤器匹配的帧的处理规则,参数含义如下:
- 第 2 个参数(
FDCAN_REJECT
):未匹配的标准帧被 “拒绝”(不接收);
- 第 3 个参数(
FDCAN_REJECT
):未匹配的扩展帧被 “拒绝”(不接收);
- 第 4 个参数(
FDCAN_FILTER_REMOTE
):未匹配的标准远程帧被 “拒绝”;
- 第 5 个参数(
FDCAN_FILTER_REMOTE
):未匹配的扩展远程帧被 “拒绝”。
结合前面的过滤器配置(所有标准帧都被第 0 号过滤器匹配),这里的全局规则实际效果是:
- 所有标准帧被第 0 号过滤器接收(存入 FIFO0);
- 扩展帧、远程帧(无论标准还是扩展)因未被匹配,全部被拒绝。
数据发送
如果需要兼容CAN
,将FDFormat
修改为FDCAN_CLASSIC_CAN
即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
void FDCAN_InitTxHander(FDCAN_TxHeaderTypeDef* pheader, uint32_t id, uint32_t dlc,uint32_t baudrateswitch,uint32_t can_type){
pheader->Identifier = id;
if(id>=0x800) {
pheader->IdType = FDCAN_EXTENDED_ID;
}
else {
pheader->IdType = FDCAN_STANDARD_ID;
}
pheader->TxFrameType = FDCAN_DATA_FRAME;
pheader->DataLength = dlc;
pheader->ErrorStateIndicator = FDCAN_ESI_ACTIVE;//开启错误状态指示
pheader->BitRateSwitch = baudrateswitch;
pheader->FDFormat = can_type;
pheader->TxEventFifoControl = FDCAN_NO_TX_EVENTS;
pheader->MessageMarker = 0;
}
void FDCAN_SendMessageWithBaudSwitch(FDCAN_HandleTypeDef *hfdcan,uint8_t* pdata,uint32_t dlc,uint32_t id)
{
FDCAN_TxHeaderTypeDef txhead;
FDCAN_InitTxHander(&txhead,id,dlc,FDCAN_BRS_ON,FDCAN_FD_CAN);
HAL_FDCAN_AddMessageToTxFifoQ(hfdcan, &txhead, pdata);
}
void FDCAN_SendMessageWithOutBaudSwitch(FDCAN_HandleTypeDef *hfdcan,uint8_t* pdata,uint32_t dlc,uint32_t id)
{
FDCAN_TxHeaderTypeDef txhead;
FDCAN_InitTxHander(&txhead,id,dlc,FDCAN_BRS_OFF,FDCAN_CLASSIC_CAN);
HAL_FDCAN_AddMessageToTxFifoQ(hfdcan, &txhead, pdata);
if(HAL_FDCAN_AddMessageToTxFifoQ(hfdcan, &txhead, pdata)!=HAL_OK) {
FDCAN_ErrorHandler();
}
}
|
数据接收
1
2
3
4
5
6
7
8
9
10
11
12
13
|
uint8_t RxData[64];
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{
if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE)!=RESET)//判断是否是新消息中断
{
if(hfdcan->Instance == FDCAN1) //Slave Arm
{
HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader, RxData);
//...
}
}
}
|
CAN
Cube配置

模式设置(Mode)

- Normal mode(正常模式):正常发送和接收帧,用于实际总线通信
- Loopback mode(回环模式):发送的帧会被自身接收,无需外部总线,用于调试
- Silent mode(静默模式):只能接收帧,不能发送,用于监听总线
- Silent Loopback mode(静默回环模式):结合静默和回环,仅内部测试
波特率
$$波特率 = APB时钟频率 / [ Prescaler × (1 + TimeSeg1 + TimeSeg2) ]$$

CAN 的波特率由位时间(Bit Time) 决定,位时间 = 1 / 波特率(如 1Mbps 对应位时间 1μs)。位时间由 3 部分组成:
- Prescaler(预分频器):将 APB 时钟(如 APB1=36MHz)分频为时间量子(TQ),公式:
TQ = 1/(APB时钟频率 / Prescaler)
- Sync Jump Width (SJW):同步跳转宽度,用于补偿节点间时钟偏差,取值 1~4TQ(通常设为 1 或 2)
- Time Seg1:包含传播段(PropSeg)和相位段 1(PS1),取值 4~16TQ(用于补偿总线延迟)
- Time Seg2:相位段 2(PS2),取值 2~8TQ(用于同步补偿)
Basic-Parameters
Time Triggered Communication(时间触发通信)
Automatic Bus-Off Management(自动总线关闭管理)
当节点因错误计数超限进入 “总线关闭” 状态(无法发送和接收帧)时,是否需要软件手动恢复,还是控制器自动恢复
Automatic WakeUP mode(自动唤醒模式) 是一种针对低功耗场景的功能,用于让 CAN 控制器在休眠(低功耗)状态下,通过检测总线上的有效活动(如特定 CAN 帧)自动恢复到正常工作状态,无需软件手动触发唤醒
Automatic Retransmission(自动重传)
Receive FIFO Locked Mode(接收 FIFO 锁定模式)
当接收 FIFO(CAN 通常有 2 个接收 FIFO,FIFO0 和 FIFO1)存储的帧数量达到最大深度(如 3 个或 6 个,依芯片型号而定)时,新接收的帧是否覆盖旧的帧
Transmit FIFO Priority(发送 FIFO 优先级)
当发送 FIFO(CAN 通常有 1 个发送 FIFO,可存储多个待发送帧)中有多个帧等待发送时,帧的发送顺序规则
使用代码
FilterInit-and-FDCANStart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
void CAN_Config(void)
{
CAN_FilterTypeDef sFilterConfig;
/* Configure the CAN Filter */
sFilterConfig.FilterBank = 0; // 过滤器编号,使用一个CAN,则可选0-13;使用两个CAN可选0-27
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 过滤器模式,掩码模式或列表模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 过滤器位宽
sFilterConfig.FilterIdHigh = 0x0000; // 过滤器验证码ID高16位,0-0xFFFF
sFilterConfig.FilterIdLow = 0x0000; // 过滤器验证码ID低16位,0-0xFFFF
sFilterConfig.FilterMaskIdHigh = 0x0000; // 过滤器掩码ID高16位,0-0xFFFF
sFilterConfig.FilterMaskIdLow = 0x0000; // 过滤器掩码ID低16位,0-0xFFFF
sFilterConfig.FilterFIFOAssignment = CAN_FilterFIFO0; // FIFOx,0或1
sFilterConfig.FilterActivation = ENABLE; // 使能过滤器
sFilterConfig.SlaveStartFilterBank = 14; // 从过滤器编号,0-27,对于单CAN实例该参数没有意义
if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
/* Filter configuration Error */
}
/* Start the CAN peripheral */
if (HAL_CAN_Start(&hcan1) != HAL_OK)
{
/* Start Error */
}
/* Activate CAN RX notification */
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
/* Notification Error */
}
}
|
发送
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
uint8_t CAN_Send_Msg(uint16_t output , uint8_t len)
{
uint8_t message[8];
uint32_t TxMailbox;
CAN_TxHeaderTypeDef CAN_TxHeader;
// 设置发送参数
CAN_TxHeader.StdId = 0x200; // 标准标识符(12bit)
//CAN_TxHeader.ExtId = 0x00; // 扩展标识符(29bit)
CAN_TxHeader.IDE = CAN_ID_STD; // 使用标准帧
CAN_TxHeader.RTR = CAN_RTR_DATA; // 数据帧
CAN_TxHeader.DLC = 0x08; // 发送长度
CAN_TxHeader.TransmitGlobalTime = DISABLE;//关闭can的时间触发通信模式
// 装载数据
memset(message, 0, sizeof(message));
message[0] = (output >> 8) & 0xFF;
message[1] = output & 0xFF;
// 发送CAN消息
if(HAL_CAN_AddTxMessage(&hcan1, &CAN_TxHeader, message, &TxMailbox) != HAL_OK)
{
return 0;
}
return 1;
}
|
接收
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{// 收到CAN数据会触发接收中断,进入该回调函数
uint8_t RxData[8];
CAN_RxHeaderTypeDef CAN_RxHeader;
if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_RxHeader, RxData) != HAL_OK)
{
while(1) {};
}
if(hcan==&hcan1) // 只处理CAN1
{
// 处理CAN1接收到的数据
switch (CAN_RxHeader.StdId) // 标准标识符
{
case 0x201:
// 处理ID为0x201的消息
test_motor.motor_raw_angle = (RxData[0] << 8) | RxData[1];
test_motor.motor_angle = (float)test_motor.motor_raw_angle/8191.f*360.f;
test_motor.motor_speed = (RxData[2] << 8) | RxData[3];
test_motor.motor_current = (RxData[4] << 8) | RxData[5];
test_motor.temp = RxData[6];
break;
default:
break;
}
}
}
|