3. CAN驱动配置
任务目标
在Bootloader工程中完成CAN驱动的基础配置,使MCU能够通过CAN总线与上位机建立通信链路。本案例聚焦于CAN控制器初始化、报文收发缓冲配置以及最简收发验证,为后续Bootloader的UDS诊断和刷写协议奠定通信基础。
环境依赖
- MCU:Infineon AURIX TC275(或同系列TriCore架构MCU)
- 开发环境:AURIX Development Studio 或 HighTec + iLLD库
- 硬件:CAN收发器(如TJA1051)、USB-CAN分析工具(如PCAN、CANoe)
- 依赖文件:
IfxCan_Can.h、IfxCan_PinMap.h(iLLD库自带)
核心实现
以下代码完成CAN模块初始化、报文发送与接收中断配置。采用TC275的CAN0模块,Node0作为通信节点,波特率500kbps,使用标准帧ID(0x100用于发送,0x200用于接收)。
// can_driver.c - CAN驱动最小实现
#include "IfxCan_Can.h"
#include "IfxCan_PinMap.h"
#define CAN_TX_ID 0x100
#define CAN_RX_ID 0x200
#define CAN_MESSAGE_SIZE 8
static IfxCan_Can g_canModule;
static IfxCan_Can_Node g_canNode;
static IfxCan_Can_NodeConfig g_nodeConfig;
static IfxCan_Can_Filter g_rxFilter;
static uint8 g_rxData[CAN_MESSAGE_SIZE];
// 发送消息句柄
static IfxCan_Can_MsgObj g_txMsgObj;
static IfxCan_Can_MsgObj g_rxMsgObj;
// CAN引脚配置(TC275: CAN0_NODE0_TX = P20.8, RX = P20.9)
static const IfxCan_Pins canPins = {
.rxPin = &IfxCan_CAN0_RXD00_P20_9_IN,
.txPin = &IfxCan_CAN0_TXD00_P20_8_OUT,
.pins = IfxCan_Pins_2
};
void CanDriver_Init(void)
{
// 1. 初始化CAN模块时钟
IfxCan_Can_initModule(&g_canModule, &MODULE_CAN0);
// 2. 配置节点
IfxCan_Can_NodeConfig_init(&g_nodeConfig);
g_nodeConfig.baudRate = IfxCan_Can_getBaudrateConfig(500000);
g_nodeConfig.nodeId = IfxCan_NodeId_0;
g_nodeConfig.pins = &canPins;
g_nodeConfig.txConfig.txEnabled = TRUE;
g_nodeConfig.rxConfig.rxEnabled = TRUE;
g_nodeConfig.rxConfig.rxInterruptEnabled = TRUE;
g_nodeConfig.rxConfig.rxInterruptPriority = 10;
IfxCan_Can_initNode(&g_canNode, &g_canModule, &g_nodeConfig);
// 3. 配置发送消息对象(标准帧,ID=0x100)
IfxCan_Can_MsgObjConfig txMsgConfig;
IfxCan_Can_MsgObjConfig_init(&txMsgConfig);
txMsgConfig.msgObjId = IfxCan_MsgObjId_0;
txMsgConfig.messageId = CAN_TX_ID;
txMsgConfig.frameType = IfxCan_FrameType_standard;
txMsgConfig.msgObjType = IfxCan_MsgObjType_transmit;
IfxCan_Can_initMsgObj(&g_canNode, &g_txMsgObj, &txMsgConfig);
// 4. 配置接收消息对象(标准帧,ID=0x200,带过滤)
IfxCan_Can_MsgObjConfig rxMsgConfig;
IfxCan_Can_MsgObjConfig_init(&rxMsgConfig);
rxMsgConfig.msgObjId = IfxCan_MsgObjId_1;
rxMsgConfig.messageId = CAN_RX_ID;
rxMsgConfig.frameType = IfxCan_FrameType_standard;
rxMsgConfig.msgObjType = IfxCan_MsgObjType_receive;
IfxCan_Can_initMsgObj(&g_canNode, &g_rxMsgObj, &rxMsgConfig);
// 5. 配置硬件过滤(仅接收ID=0x200的报文)
IfxCan_Can_FilterConfig filterConfig;
IfxCan_Can_FilterConfig_init(&filterConfig);
filterConfig.elementConfig.messageId = CAN_RX_ID;
filterConfig.elementConfig.acceptanceMask = 0x7FF; // 标准帧11位ID全匹配
filterConfig.msgObjId = IfxCan_MsgObjId_1;
IfxCan_Can_initFilter(&g_canNode, &g_rxFilter, &filterConfig);
// 6. 使能接收中断
IfxCan_Can_enableNodeInterrupts(&g_canNode, IfxCan_Interrupt_receiveIndication);
}
// 发送CAN报文
boolean CanDriver_SendMessage(uint8* data, uint8 length)
{
IfxCan_Can_MsgObjConfig txConfig;
IfxCan_Can_MsgObjConfig_init(&txConfig);
IfxCan_Can_MsgObj_send(&g_txMsgObj, data, length, &txConfig);
return TRUE;
}
// 接收中断回调(由iLLD中断框架调用)
void CanDriver_RxCallback(void)
{
IfxCan_Can_MsgObj_getData(&g_rxMsgObj, g_rxData, CAN_MESSAGE_SIZE);
// 在此处添加Bootloader协议解析入口
// 例如:Bootloader_ProcessCanMessage(g_rxData, CAN_MESSAGE_SIZE);
}
// 获取接收数据指针
uint8* CanDriver_GetRxData(void)
{
return g_rxData;
}
中断服务函数注册
在TC275中,CAN接收中断需要注册到中断向量表。在Isr.c中添加以下代码:
// Isr.c - 中断注册
IFX_INTERRUPT(Can0_Node0_Isr, 0, 10); // 优先级10,与初始化配置一致
void Can0_Node0_Isr(void)
{
IfxCan_Can_Node_deinitInterrupt(&g_canNode);
CanDriver_RxCallback();
IfxCan_Can_Node_clearInterrupt(&g_canNode, IfxCan_Interrupt_receiveIndication);
IfxCan_Can_Node_enableInterrupt(&g_canNode, IfxCan_Interrupt_receiveIndication);
}
主函数调用示例
// main.c 片段
int main(void)
{
// 初始化MCU时钟等(省略)
CanDriver_Init();
uint8 testData[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
while(1)
{
// 每100ms发送一次测试报文
CanDriver_SendMessage(testData, 8);
waitTime(IfxStm_getTicksFromMilliseconds(100));
}
return 0;
}
验证方法
- 硬件连接:将TC275的CAN0_TX(P20.8)和CAN0_RX(P20.9)通过CAN收发器连接至USB-CAN分析工具,两端需正确接入120Ω终端电阻。
- 发送验证:运行程序后,在CAN分析工具中设置500kbps波特率,应能捕获到ID=0x100、DLC=8、数据为
01 02 03 04 05 06 07 08的周期报文。 - 接收验证:使用CAN分析工具发送ID=0x200、DLC=8的任意数据帧,程序应进入接收中断。可在
CanDriver_RxCallback()中设置断点,观察g_rxData数组内容与发送数据一致。 - 过滤验证:发送ID=0x201或其他非0x200的报文,程序不应触发接收中断,确认硬件过滤生效。
通过判定标准
- CAN分析工具能稳定捕获到周期发送的0x100报文,无CRC错误或位填充错误。
- 发送0x200报文时,程序能可靠进入接收中断,且数据内容与发送端完全一致。
- 发送非过滤ID报文时,接收中断不触发,验证过滤功能正常。
常见问题
- 总线无报文:检查波特率配置是否匹配(500k),确认收发器供电和终端电阻连接。
- 接收中断不触发:确认中断优先级配置与
IFX_INTERRUPT宏中的优先级一致,检查过滤配置的acceptanceMask是否正确。 - 发送失败:确认总线空闲且无其他节点占用,检查TX引脚映射是否正确。