3. CAN驱动配置

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;
}

验证方法

  1. 硬件连接:将TC275的CAN0_TX(P20.8)和CAN0_RX(P20.9)通过CAN收发器连接至USB-CAN分析工具,两端需正确接入120Ω终端电阻。
  2. 发送验证:运行程序后,在CAN分析工具中设置500kbps波特率,应能捕获到ID=0x100、DLC=8、数据为01 02 03 04 05 06 07 08的周期报文。
  3. 接收验证:使用CAN分析工具发送ID=0x200、DLC=8的任意数据帧,程序应进入接收中断。可在CanDriver_RxCallback()中设置断点,观察g_rxData数组内容与发送数据一致。
  4. 过滤验证:发送ID=0x201或其他非0x200的报文,程序不应触发接收中断,确认硬件过滤生效。

通过判定标准

  • CAN分析工具能稳定捕获到周期发送的0x100报文,无CRC错误或位填充错误。
  • 发送0x200报文时,程序能可靠进入接收中断,且数据内容与发送端完全一致。
  • 发送非过滤ID报文时,接收中断不触发,验证过滤功能正常。

常见问题

  • 总线无报文:检查波特率配置是否匹配(500k),确认收发器供电和终端电阻连接。
  • 接收中断不触发:确认中断优先级配置与IFX_INTERRUPT宏中的优先级一致,检查过滤配置的acceptanceMask是否正确。
  • 发送失败:确认总线空闲且无其他节点占用,检查TX引脚映射是否正确。