4. CAN报文过滤与接收中断处理
任务说明
在 S32G 的 FlexCAN 模块上配置接收滤波器(Rx FIFO 全局掩码 + 单个 ID 过滤),使 CAN 控制器只接收 ID 落在 [0x100, 0x1FF] 范围内的标准帧,并在接收中断回调中读取报文。本案例基于 S32 SDK 的 FlexCAN 驱动,使用 FlexCAN0,波特率 500 kbps。
环境与依赖
- S32 Design Studio + S32K3xx / S32G 系列 SDK(含
flexcan_driver、flexcan_hw_access、osif)。 - FlexCAN0 时钟已使能,CAN_H/CAN_L 已接总线(或回环测试)。
- 中断向量
FlexCAN0_0_IRQn已在启动文件中注册。
实现思路
FlexCAN 的接收过滤分两层:先由 Rx FIFO 全局掩码(RXFGMASK)决定哪些 ID 进入 FIFO,再由 FIFO 内的单个 ID 过滤表(RXFIR)做精确匹配。本案例用全局掩码把高 7 位固定为 0x1(即 ID 0x100~0x1FF),再在中断回调中读取 FIFO 报文。
关键完整代码
#include "flexcan_driver.h"
#include "flexcan_hw_access.h"
#include "osif.h"
#define INSTANCE 0U
#define RX_MB_IDX 1U
#define RX_FIFO_IDX 0U
#define ID_MIN 0x100U
#define ID_MAX 0x1FFU
static flexcan_driver_state_t g_flexcanState;
static flexcan_msgbuff_t g_rxMsg;
static volatile uint32_t g_rxCount = 0U;
/* 接收中断回调:从 Rx FIFO 读取报文 */
static void FlexCAN0_RxCallback(uint8_t instance,
flexcan_event_type_t eventType,
flexcan_msgbuff_t *msgBuff)
{
(void)instance;
if (eventType == FLEXCAN_EVENT_RX_COMPLETE) {
g_rxMsg = *msgBuff;
g_rxCount++;
/* 在此处理报文:g_rxMsg.data / g_rxMsg.msgId / g_rxMsg.dataLen */
}
}
/* 配置 Rx FIFO 全局掩码 + 单 ID 过滤,仅接收 0x100~0x1FF */
static void FlexCAN0_ConfigFilter(void)
{
/* 全局掩码:ID[10:4] 必须等于 0x1,即 0x100~0x1FF */
uint32_t mask = 0x7F0U; /* 高 7 位参与比较 */
FLEXCAN_SetRxFifoGlobalMask(INSTANCE, mask);
/* 单 ID 过滤表:匹配 0x100 */
flexcan_id_table_t idTable[1];
idTable[0].isRemoteFrame = false;
idTable[0].isExtendedFrame = false;
idTable[0].id = ID_MIN;
FLEXCAN_SetRxFifoFilter(INSTANCE, FLEXCAN_RX_FIFO_ID_FORMAT_A,
idTable, 1U);
}
void FlexCAN0_Init(void)
{
flexcan_user_config_t cfg;
FLEXCAN_DRV_GetDefaultConfig(&cfg);
cfg.fd_enable = false;
cfg.pe_clock = 40000000U; /* 外设时钟 40 MHz */
cfg.max_num_mb = 16U;
cfg.num_fifo_mb = 6U; /* 使用 6 个 FIFO 邮箱 */
cfg.is_rx_fifo_needed = true;
cfg.flexcanMode = FLEXCAN_NORMAL_MODE;
cfg.bitrate.bitrate = 500000U;
cfg.bitrate.samplePoint = 800U; /* 80% 采样点 */
FLEXCAN_DRV_Init(INSTANCE, &g_flexcanState, &cfg);
FlexCAN0_ConfigFilter();
/* 注册接收回调并启动接收 */
FLEXCAN_DRV_InstallEventCallback(INSTANCE, FlexCAN0_RxCallback, NULL);
FLEXCAN_DRV_ConfigRxFifo(INSTANCE, FLEXCAN_RX_FIFO_START,
&g_rxMsg);
FLEXCAN_DRV_StartRxFifo(INSTANCE);
}
int main(void)
{
FlexCAN0_Init();
for (;;) {
/* 主循环可做其他任务;报文在中断回调中处理 */
}
}
运行与验证
- 编译烧录后,用 CAN 分析仪向总线发送 ID 为
0x150的标准帧,观察g_rxCount递增、g_rxMsg.msgId为0x150。 - 发送 ID 为
0x050或0x300的帧,g_rxCount应保持不变,说明过滤生效。 - 若使用回环模式(
FLEXCAN_LOOPBACK_MODE),可在main中调用FLEXCAN_DRV_Send自发自收验证。
通过条件:仅 ID 在 [0x100, 0x1FF] 范围内的标准帧触发回调并更新 g_rxCount,范围外报文被硬件过滤丢弃。
常见问题
- 回调不触发:检查
FlexCAN0_0_IRQn是否使能、num_fifo_mb是否大于 0。 - 过滤不生效:确认
RXFGMASK与RXFIR的 ID 格式(标准/扩展)一致,扩展帧需改用FLEXCAN_RX_FIFO_ID_FORMAT_B。 - 波特率不匹配:
pe_clock必须与实际外设时钟一致,否则采样点偏移导致接收错误。