本文记录和总结了我初步学习英飞凌TC265这款单片机的过程,主要有以下内容:
1.如何新建一个工程并使用英飞凌的iLLD底层驱动库;
2.点亮一个LED灯(Ports的使用);
3.发送CAN(FD)报文;
4.用中断接收CAN(FD)报文;
5.如何使用CAN网关模式。
整套例程的代码我传上来了,需要的可以下载:

1.新建工程

英飞凌针对Tricore系列单片机推出了一款免费的软件——AURIX™ Development Studio,集成了iLLD库,内置Tasking compiler和Tasking Debugger,但这两个模块只能用于非商业用途,可供学习和试用。可以从下面的链接下载,但需要注册一个账号:
https://www.infineon.com/cms/en/product/promopages/aurix-development-studio/?redirId=119357 安装完成后,新建工程的步骤十分简单,打开软件时要先选择一个工作目录,然后点 File→New→New AURIX Project,输入工程名,并选择芯片型号即可:
深入学习单片机RTOS双架构双系统 双核单片机怎么用_引脚
工程创建好后,可以在工程目录下看到Cpu0_Main.c和Cpu1_Main.c两个文件,分别包含了两个核心的main函数,其中core0是主核心。
深入学习单片机RTOS双架构双系统 双核单片机怎么用_引脚_02
关于硬件调试器可以使用英飞凌官方的miniwiggler,约1000RMB,觉得贵的话国内有一家乾勤科技自制的miniwiggler,300多块,使用起来也挺稳定的。连接好调试器和开发板后,点击调试会先编译再启动调试,界面如下,在①处可以执行单步运行等操作,②处可以选择想要运行的cpu,右上角的③处可以切换编辑界面和调试界面。
深入学习单片机RTOS双架构双系统 双核单片机怎么用_can_03
如果使用Tasking,新建工程时先新建一个空工程,然后把iLLD库放到Tasking工程文件夹下,在Tasking工程中右键选择Refresh或update等操作更新工程后即可看到iLLD文件夹,然后选择工程设置,在include path中将iLLD库中的所有文件夹的路径添加进去,之后就可以在程序中直接包含iLLD库的头文件了。
Tasking自带PinMap,可以直接配置引脚功能,很方便。

2.点亮一个LED灯

先放一些参考资料。英飞凌官方提供了iLLD库的使用例程,包括了各种外设,还有多款芯片的iLLD库,见下面的Git链接:
https://github.com/Infineon/AURIX_code_examples 下面的额链接是官方培训资料,左侧是和例程配套的说明文档,右侧有iLLD库使用手册的下载链接:
https://www.infineon.com/cms/en/product/promopages/aurix-expert-training/?redirId=118978
深入学习单片机RTOS双架构双系统 双核单片机怎么用_单片机_04
另外还有网上找到的第三方开发的TC264的资料,芯片型号不同的话替换一下iLLD库即可,应用程序程序都是通用的,包括上面的官方例程也是一样。下载链接:

深入学习单片机RTOS双架构双系统 双核单片机怎么用_深入学习单片机RTOS双架构双系统_05
基于上面这些资料的基础,我们来看以下点亮LED灯的程序。
首先在AURIX Development Studio中新建一个工程,包含以下两个头文件:

#include "SysSe/Bsp/Bsp.h"  //包含延时函数
#include "Port/Io/IfxPort_Io.h"  //Ports控制API

main函数如下,先初始化延时函数和引脚电平,然后在main主循环中每隔1秒翻转一次引脚电平,实现LED灯的闪烁。使用的时候修改一下引脚编号即可。需要注意英飞凌官方的一些例程貌似把 initTime() 这个函数给忘记了,会导致延时函数不能用,使用官方例程的时候注意一下。

#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "SysSe/Bsp/Bsp.h"
#include "Port/Io/IfxPort_Io.h"
IfxCpu_syncEvent g_cpuSyncEvent = 0;
int core0_main(void)
{
    IfxCpu_enableInterrupts();
    
    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
    
    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);

    initTime();	//初始化延时函数
    IfxPort_setPinMode(&MODULE_P14, 9, IfxPort_Mode_outputPushPullGeneral);	//初始化引脚状态
    
    while(1)
    {
        IfxPort_togglePin(&MODULE_P14, 9);	//翻转引脚电平
        wait(TimeConst_1s);	//延时1S
    }
    return (1);
}

3.发送CAN(FD)报文

3.1发送传统CAN报文并触发发送中断

#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "SysSe/Bsp/Bsp.h"
#include "Port/Io/IfxPort_Io.h"
#include "Multican/Can/IfxMultican_Can.h"	//包含CAN控制API

IfxCpu_syncEvent g_cpuSyncEvent = 0;

//定义CAN模块、节点、MessageObject:
// CAN handle
IfxMultican_Can can;
// Nodes handles
IfxMultican_Can_Node canSrcNode;
// Message Object handles
IfxMultican_Can_MsgObj canSrcMsgObj;

//定义中断等级和中断函数,报文发送完成后进入中断,翻转LED电平
#define ISR_PRIORITY_CAN_TX         2                           /* Define the CAN TX interrupt priority              */
#define TX_INTERRUPT_SRC_ID         IfxMultican_SrcId_0         /* Transmit interrupt service request ID             */
IFX_INTERRUPT(canIsrTxHandler, 0, ISR_PRIORITY_CAN_TX);
void canIsrTxHandler(void)
{
    IfxPort_togglePin(&MODULE_P14, 9);
}
//CAN初始化函数:
void CanApp_init(void)
{
    // create configuration
    IfxMultican_Can_Config canConfig;
    IfxMultican_Can_initModuleConfig(&canConfig, &MODULE_CAN);
    // initialize interrupt priority
    canConfig.nodePointer[TX_INTERRUPT_SRC_ID].priority = ISR_PRIORITY_CAN_TX;
    // initialize module
    IfxMultican_Can_initModule(&can, &canConfig);

    // create CAN node config
    IfxMultican_Can_NodeConfig canNodeConfig;
    IfxMultican_Can_Node_initConfig(&canNodeConfig, &can);
    canNodeConfig.baudrate = 500000; // 1 MBaud
    canNodeConfig.nodeId = IfxMultican_NodeId_0;
    canNodeConfig.rxPin = &IfxMultican_RXD0A_P02_1_IN;
    canNodeConfig.txPin = &IfxMultican_TXD0_P02_0_OUT;
    IfxMultican_Can_Node_init(&canSrcNode, &canNodeConfig);

    // create message object config
    IfxMultican_Can_MsgObjConfig canMsgObjConfig;
    IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &canSrcNode);
    // assigned message object:
    canMsgObjConfig.msgObjId = 0;
    canMsgObjConfig.frame = IfxMultican_Frame_transmit;
    canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_8;
    canMsgObjConfig.control.extendedFrame = FALSE;
    canMsgObjConfig.txInterrupt.enabled = TRUE;
    canMsgObjConfig.txInterrupt.srcId = TX_INTERRUPT_SRC_ID;

    // initialize receive message object
    IfxMultican_Can_MsgObj_init(&canSrcMsgObj, &canMsgObjConfig);
}
//CAN发送函数
void CAN_SendSingle(uint32 id, uint32 high, uint32 low)
{
    // Initialise the message strcture
    IfxMultican_Message txMsg;
    IfxMultican_Message_init(&txMsg, id, low, high, IfxMultican_DataLengthCode_8);

    // Transmit Data
    while( IfxMultican_Can_MsgObj_sendMessage(&canSrcMsgObj, &txMsg) == IfxMultican_Status_notSentBusy );

}
//主函数
int core0_main(void)
{
    IfxCpu_enableInterrupts();
    
    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
    
    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);

    initTime();
    IfxPort_setPinMode(&MODULE_P14, 9, IfxPort_Mode_outputPushPullGeneral);

	//初始化CAN_STB引脚(我的开发板上CAN收发器的STB引脚是软件控制的所以需要程序拉低,如果是硬件拉低则不需要)
    IfxPort_setPinMode(&MODULE_P11, 11, IfxPort_Mode_outputPushPullGeneral);
    //IfxPort_setPinMode(&MODULE_P02, 8, IfxPort_Mode_outputPushPullGeneral);

    CanApp_init();
    while(1)
    {
        CAN_SendSingle(0x200,(uint32)0x01020304, (uint32)0x01020304);
        wait(TimeConst_1s);
    }
    return (1);
}

结果如下,同时LED灯随着CAN报文的发送闪烁:

深入学习单片机RTOS双架构双系统 双核单片机怎么用_单片机_06

3.2发送CAN FD报文

代码中定义了两个CANFD MO,其中MO1没有开启 fastBitRate ,即相对于传统CAN报文来说,只是增加了数据场的长度,而没有增加数据场的速率,MO2开启了fastBitRate,即增加了数据场的长度又增加了发送速率。同时将MO1定义为扩展帧用于测试。

#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "SysSe/Bsp/Bsp.h"
#include "Port/Io/IfxPort_Io.h"
#include "Multican/Can/IfxMultican_Can.h"

IfxCpu_syncEvent g_cpuSyncEvent = 0;

// CAN handle
IfxMultican_Can can;
// Nodes handles
IfxMultican_Can_Node canSrcNode;
// Message Object handles
IfxMultican_Can_MsgObj canSrcMsgObj;
IfxMultican_Can_MsgObj canfdSrcMsgObj1;	//定义CANFD MO
IfxMultican_Can_MsgObj canfdSrcMsgObj2;

#define ISR_PRIORITY_CAN_TX         2                           /* Define the CAN TX interrupt priority              */
#define TX_INTERRUPT_SRC_ID         IfxMultican_SrcId_0         /* Transmit interrupt service request ID             */
IFX_INTERRUPT(canIsrTxHandler, 0, ISR_PRIORITY_CAN_TX);
void canIsrTxHandler(void)
{
    IfxPort_togglePin(&MODULE_P14, 9);
}

//CANFD报文因为数据场过长,需要占用其它MO的寄存器来存储数据,详细的内容请查询参考手册中有关topMsgObj和bottomMsgObj的介绍。
#define SRC_EXTENDED_MO_OFFSET      64                          /* Offset where the src extended MOs are located     */

void CanApp_init(void)
{
    // create configuration
    IfxMultican_Can_Config canConfig;
    IfxMultican_Can_initModuleConfig(&canConfig, &MODULE_CAN);
    // initialize interrupt priority
    canConfig.nodePointer[TX_INTERRUPT_SRC_ID].priority = ISR_PRIORITY_CAN_TX;
    // initialize module
    IfxMultican_Can_initModule(&can, &canConfig);

    // create CAN node config
    IfxMultican_Can_NodeConfig canNodeConfig;
    IfxMultican_Can_Node_initConfig(&canNodeConfig, &can);
    canNodeConfig.baudrate = 500000; // 1 MBaud
    canNodeConfig.nodeId = IfxMultican_NodeId_0;
    canNodeConfig.rxPin = &IfxMultican_RXD0A_P02_1_IN;
    canNodeConfig.txPin = &IfxMultican_TXD0_P02_0_OUT;
    //CAN FD configuration
    canNodeConfig.flexibleDataRate               = TRUE;
    canNodeConfig.fdConfig.nominalBaudrate       = 500000;
    canNodeConfig.fdConfig.nominalSynchJumpWidth = 2000;
    canNodeConfig.fdConfig.nominalSamplePoint    = 8000;
    canNodeConfig.fdConfig.fastBaudrate          = 2000000;
    canNodeConfig.fdConfig.fastSynchJumpWidth    = 2000;
    canNodeConfig.fdConfig.fastSamplePoint       = 8000;
    IfxMultican_Can_Node_init(&canSrcNode, &canNodeConfig);

    // create message object config
    IfxMultican_Can_MsgObjConfig canMsgObjConfig;
    IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &canSrcNode);
    // assigned message object:
    canMsgObjConfig.msgObjId = 0;
    canMsgObjConfig.frame = IfxMultican_Frame_transmit;
    canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_8;
    canMsgObjConfig.control.extendedFrame = FALSE;
    canMsgObjConfig.txInterrupt.enabled = TRUE;
    canMsgObjConfig.txInterrupt.srcId = TX_INTERRUPT_SRC_ID;

    // initialize receive message object
    IfxMultican_Can_MsgObj_init(&canSrcMsgObj, &canMsgObjConfig);

    // assigned CAN FD message object:

    IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &canSrcNode);
    canMsgObjConfig.msgObjId = 1;
    canMsgObjConfig.frame = IfxMultican_Frame_transmit;
    canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_32;
    canMsgObjConfig.control.extendedFrame = TRUE;
    canMsgObjConfig.txInterrupt.enabled = FALSE;

    canMsgObjConfig.control.fastBitRate = FALSE;// low speed CANFD frame
    canMsgObjConfig.control.topMsgObjId = SRC_EXTENDED_MO_OFFSET;
    canMsgObjConfig.control.bottomMsgObjId = canMsgObjConfig.control.topMsgObjId + 1;

    IfxMultican_Can_MsgObj_init(&canfdSrcMsgObj1, &canMsgObjConfig);

    IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &canSrcNode);
    canMsgObjConfig.msgObjId = 2;
    canMsgObjConfig.frame = IfxMultican_Frame_transmit;
    canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_64;
    canMsgObjConfig.control.extendedFrame = FALSE;

    canMsgObjConfig.control.fastBitRate = TRUE;// high speed CANFD frame
    canMsgObjConfig.control.topMsgObjId = SRC_EXTENDED_MO_OFFSET + 2;
    canMsgObjConfig.control.bottomMsgObjId = canMsgObjConfig.control.topMsgObjId + 1;

    IfxMultican_Can_MsgObj_init(&canfdSrcMsgObj2, &canMsgObjConfig);
}

void CAN_SendSingle(uint32 id, uint32 high, uint32 low)
{
    // Initialise the message strcture
    IfxMultican_Message txMsg;
    IfxMultican_Message_init(&txMsg, id, low, high, IfxMultican_DataLengthCode_8);

    // Transmit Data
    while( IfxMultican_Can_MsgObj_sendMessage(&canSrcMsgObj, &txMsg) == IfxMultican_Status_notSentBusy );

}
//发送数据场速率不变的CANFD报文
void CANFD_SendLowSpeedFrame(uint32 id)
{
  uint8 txData[64] = {0};
    IfxMultican_Message txMsg;

  for(uint8 i = 0; i < 64; i++)
    txData[i] = 0xCC;

  IfxMultican_Message_longFrameInit(&txMsg,
                                    id,
                                    IfxMultican_DataLengthCode_32,
                                    FALSE);

  /* Send the CAN message with the previously defined TX message content */
  while(IfxMultican_Status_notSentBusy ==
        IfxMultican_Can_MsgObj_sendLongFrame(&canfdSrcMsgObj1,
                                             &txMsg,
                                             (uint32*)&txData));
  {
  }
}
//发送数据场数据改变的CANFD报文
void CANFD_SendHighSpeedFrame(uint32 id)
{
  uint8 txData[64] = {0};
    IfxMultican_Message txMsg;

  for(uint8 i = 0; i < 64; i++)
    txData[i] = 0xCC;

  IfxMultican_Message_longFrameInit(&txMsg,
                                    id,
                                    IfxMultican_DataLengthCode_64,
                                    TRUE);//Enable fast bitrate

  /* Send the CAN message with the previously defined TX message content */
  while(IfxMultican_Status_notSentBusy ==
        IfxMultican_Can_MsgObj_sendLongFrame(&canfdSrcMsgObj2,
                                             &txMsg,
                                             (uint32*)&txData));
  {
  }
}

int core0_main(void)
{
    IfxCpu_enableInterrupts();
    
    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
    
    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);

    initTime();
    IfxPort_setPinMode(&MODULE_P14, 9, IfxPort_Mode_outputPushPullGeneral);

    IfxPort_setPinMode(&MODULE_P11, 11, IfxPort_Mode_outputPushPullGeneral);
    IfxPort_setPinMode(&MODULE_P02, 8, IfxPort_Mode_outputPushPullGeneral);

    CanApp_init();
    while(1)
    {
        CAN_SendSingle(0x200,(uint32)0x01020304, (uint32)0x01020304);
        wait(TimeConst_1s);
        CANFD_SendLowSpeedFrame(0x18FEEEEE);
        wait(TimeConst_1s);
        CANFD_SendHighSpeedFrame(0x300);
        wait(TimeConst_1s);
    }
    return (1);
}

结果如下:

深入学习单片机RTOS双架构双系统 双核单片机怎么用_深入学习单片机RTOS双架构双系统_07

4.接收CAN报文

4.1接收传统CAN报文

代码中接收ID=0x100的报文,触发中断并把数据场的内容赋给ID=0x200的报文发送出来(没有转换大小端)。添加中断的时候有以下几点,不能遗漏:
1.声明中断;
2.定义中断函数;
3.CAN模块初始化中定义中断等级;
4.CAN MO初始化中开启中断并定义中断源。

#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "SysSe/Bsp/Bsp.h"
#include "Port/Io/IfxPort_Io.h"
#include "Multican/Can/IfxMultican_Can.h"

IfxCpu_syncEvent g_cpuSyncEvent = 0;

// CAN handle
IfxMultican_Can can;
// Nodes handles
IfxMultican_Can_Node canSrcNode;
// Message Object handles
IfxMultican_Can_MsgObj canSrcMsgObj;
IfxMultican_Can_MsgObj canRcvMsgObj;
void CAN_SendSingle(uint32 id, uint32 high, uint32 low);
#define ISR_PRIORITY_CAN_RX         1                           /* Define the CAN RX interrupt priority              */
#define ISR_PRIORITY_CAN_TX         2                           /* Define the CAN TX interrupt priority              */
#define TX_INTERRUPT_SRC_ID         IfxMultican_SrcId_0         /* Transmit interrupt service request ID             */
#define RX_INTERRUPT_SRC_ID         IfxMultican_SrcId_1         /* Receive interrupt service request ID              */
IFX_INTERRUPT(canIsrTxHandler, 0, ISR_PRIORITY_CAN_TX);//声明中断
IFX_INTERRUPT(canIsrRxHandler, 0, ISR_PRIORITY_CAN_RX);
void canIsrTxHandler(void)
{
    IfxPort_togglePin(&MODULE_P14, 9);
}
void canIsrRxHandler(void)//定义中断函数
{
    IfxMultican_Status readStatus;

    IfxMultican_Message rxMsg;

    /* Read the received CAN message and store the status of the operation */
    readStatus = IfxMultican_Can_MsgObj_readMessage(&canRcvMsgObj, &rxMsg);

    /* If no new data has been received, report an error */
    if( !( readStatus & IfxMultican_Status_newData ) )
    {
        while(1)
        {
        }
    }

    /* If new data has been received but with one message lost, report an error */
    if( readStatus == IfxMultican_Status_newDataButOneLost )
    {
        while(1)
        {
        }
    }

    CAN_SendSingle(0x200, rxMsg.data[0], rxMsg.data[1]);

}

void CanApp_init(void)
{
    // create configuration
    IfxMultican_Can_Config canConfig;
    IfxMultican_Can_initModuleConfig(&canConfig, &MODULE_CAN);
    // initialize interrupt priority
    canConfig.nodePointer[TX_INTERRUPT_SRC_ID].priority = ISR_PRIORITY_CAN_TX;
    canConfig.nodePointer[RX_INTERRUPT_SRC_ID].priority = ISR_PRIORITY_CAN_RX;//定义中断等级
    // initialize module
    IfxMultican_Can_initModule(&can, &canConfig);

    // create CAN node config
    IfxMultican_Can_NodeConfig canNodeConfig;
    IfxMultican_Can_Node_initConfig(&canNodeConfig, &can);
    canNodeConfig.baudrate = 500000; // 1 MBaud
    canNodeConfig.nodeId = IfxMultican_NodeId_0;
    canNodeConfig.rxPin = &IfxMultican_RXD0A_P02_1_IN;
    canNodeConfig.txPin = &IfxMultican_TXD0_P02_0_OUT;
    IfxMultican_Can_Node_init(&canSrcNode, &canNodeConfig);

    // create message object config
    IfxMultican_Can_MsgObjConfig canMsgObjConfig;
    IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &canSrcNode);
    // assigned message object:
    canMsgObjConfig.msgObjId = 0;
    canMsgObjConfig.frame = IfxMultican_Frame_transmit;
    canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_8;
    canMsgObjConfig.control.extendedFrame = FALSE;
    canMsgObjConfig.txInterrupt.enabled = TRUE;
    canMsgObjConfig.txInterrupt.srcId = TX_INTERRUPT_SRC_ID;

    // initialize receive message object
    IfxMultican_Can_MsgObj_init(&canSrcMsgObj, &canMsgObjConfig);

    IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &canSrcNode);
    canMsgObjConfig.msgObjId = 1;
    canMsgObjConfig.messageId = 0x100;
    canMsgObjConfig.acceptanceMask = 0x7FFFFFFFUL;
    canMsgObjConfig.frame = IfxMultican_Frame_receive;
    canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_8;
    canMsgObjConfig.rxInterrupt.enabled = TRUE;//使能接收中断
    canMsgObjConfig.rxInterrupt.srcId = RX_INTERRUPT_SRC_ID;//定义中断源

    // initialize message object
    IfxMultican_Can_MsgObj_init(&canRcvMsgObj, &canMsgObjConfig);
}

void CAN_SendSingle(uint32 id, uint32 high, uint32 low)
{
    // Initialise the message strcture
    IfxMultican_Message txMsg;
    IfxMultican_Message_init(&txMsg, id, low, high, IfxMultican_DataLengthCode_8);

    // Transmit Data
    while( IfxMultican_Can_MsgObj_sendMessage(&canSrcMsgObj, &txMsg) == IfxMultican_Status_notSentBusy );

}

int core0_main(void)
{
    IfxCpu_enableInterrupts();
    
    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
    
    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);

    initTime();
    IfxPort_setPinMode(&MODULE_P14, 9, IfxPort_Mode_outputPushPullGeneral);

    IfxPort_setPinMode(&MODULE_P11, 11, IfxPort_Mode_outputPushPullGeneral);

    CanApp_init();
    while(1)
    {
    }
    return (1);
}

结果如下,当收到0x100报文时触发中断并发送0x200报文,0x200报文发送成功后触发中断翻转LED电平。

深入学习单片机RTOS双架构双系统 双核单片机怎么用_单片机_08

4.2接收CANFD报文

与上面的接收CAN报文类似,接收CANFD报文特殊之处就在于数据场长度较长,需先定义一个buffer,用于存储数据。

#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "SysSe/Bsp/Bsp.h"
#include "Port/Io/IfxPort_Io.h"
#include "Multican/Can/IfxMultican_Can.h"

IfxCpu_syncEvent g_cpuSyncEvent = 0;

// CAN handle
IfxMultican_Can can;
// Nodes handles
IfxMultican_Can_Node canSrcNode;
// Message Object handles
IfxMultican_Can_MsgObj canSrcMsgObj;
IfxMultican_Can_MsgObj canRcvMsgObj;
void CAN_SendSingle(uint32 id, uint32 high, uint32 low);
#define ISR_PRIORITY_CAN_RX         1                           /* Define the CAN RX interrupt priority              */
#define ISR_PRIORITY_CAN_TX         2                           /* Define the CAN TX interrupt priority              */
#define TX_INTERRUPT_SRC_ID         IfxMultican_SrcId_0         /* Transmit interrupt service request ID             */
#define RX_INTERRUPT_SRC_ID         IfxMultican_SrcId_1         /* Receive interrupt service request ID              */
#define SRC_EXTENDED_MO_OFFSET      64                          /* Offset where the src extended MOs are located     */

IFX_INTERRUPT(canIsrTxHandler, 0, ISR_PRIORITY_CAN_TX);
IFX_INTERRUPT(canIsrRxHandler, 0, ISR_PRIORITY_CAN_RX);
void canIsrTxHandler(void)
{
    IfxPort_togglePin(&MODULE_P14, 9);
}
void canIsrRxHandler(void)
{
    IfxMultican_Status readStatus;

    IfxMultican_Message rxMsg;

    uint8 rxData[64] = {0};
    /* Read the received long frame CAN message and store the status of the operation */
    readStatus = IfxMultican_MsgObj_readLongFrame(canRcvMsgObj.node->mcan,
                                                  canRcvMsgObj.msgObjId,
                                                  &rxMsg,
                                                  (uint32*)&rxData);
    /* If no new data has been received, report an error */
    if( !( readStatus & IfxMultican_Status_newData ) )
    {
        while(1)
        {
        }
    }

    /* If new data has been received but with one message lost, report an error */
    if( readStatus == IfxMultican_Status_newDataButOneLost )
    {
        while(1)
        {
        }
    }

    CAN_SendSingle(0x200, rxData[0], rxData[4]);

}

void CanApp_init(void)
{
    // create configuration
    IfxMultican_Can_Config canConfig;
    IfxMultican_Can_initModuleConfig(&canConfig, &MODULE_CAN);
    // initialize interrupt priority
    canConfig.nodePointer[TX_INTERRUPT_SRC_ID].priority = ISR_PRIORITY_CAN_TX;
    canConfig.nodePointer[RX_INTERRUPT_SRC_ID].priority = ISR_PRIORITY_CAN_RX;
    // initialize module
    IfxMultican_Can_initModule(&can, &canConfig);

    // create CAN node config
    IfxMultican_Can_NodeConfig canNodeConfig;
    IfxMultican_Can_Node_initConfig(&canNodeConfig, &can);
    canNodeConfig.baudrate = 500000; // 1 MBaud
    canNodeConfig.nodeId = IfxMultican_NodeId_0;
    canNodeConfig.rxPin = &IfxMultican_RXD0A_P02_1_IN;
    canNodeConfig.txPin = &IfxMultican_TXD0_P02_0_OUT;

    canNodeConfig.flexibleDataRate               = TRUE;

    canNodeConfig.fdConfig.nominalBaudrate       = 500000;
    canNodeConfig.fdConfig.nominalSynchJumpWidth = 2000;
    canNodeConfig.fdConfig.nominalSamplePoint    = 8000;
    canNodeConfig.fdConfig.fastBaudrate          = 2000000;
    canNodeConfig.fdConfig.fastSynchJumpWidth    = 2000;
    canNodeConfig.fdConfig.fastSamplePoint       = 8000;
    IfxMultican_Can_Node_init(&canSrcNode, &canNodeConfig);

    // create message object config
    IfxMultican_Can_MsgObjConfig canMsgObjConfig;
    IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &canSrcNode);
    // assigned message object:
    canMsgObjConfig.msgObjId = 0;
    canMsgObjConfig.frame = IfxMultican_Frame_transmit;
    canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_8;
    canMsgObjConfig.control.extendedFrame = FALSE;
    canMsgObjConfig.txInterrupt.enabled = TRUE;
    canMsgObjConfig.txInterrupt.srcId = TX_INTERRUPT_SRC_ID;

    // initialize receive message object
    IfxMultican_Can_MsgObj_init(&canSrcMsgObj, &canMsgObjConfig);

    IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &canSrcNode);
    canMsgObjConfig.msgObjId = 1;
    canMsgObjConfig.messageId = 0x101;
    canMsgObjConfig.acceptanceMask = 0x7FFFFFFFUL;
    canMsgObjConfig.frame = IfxMultican_Frame_receive;
    canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_64;
    canMsgObjConfig.rxInterrupt.enabled = TRUE;
    canMsgObjConfig.rxInterrupt.srcId = RX_INTERRUPT_SRC_ID;

    canMsgObjConfig.control.fastBitRate = TRUE;// high speed CANFD frame
    canMsgObjConfig.control.topMsgObjId = SRC_EXTENDED_MO_OFFSET;
    canMsgObjConfig.control.bottomMsgObjId = canMsgObjConfig.control.topMsgObjId + 1;

    // initialize message object
    IfxMultican_Can_MsgObj_init(&canRcvMsgObj, &canMsgObjConfig);
}

void CAN_SendSingle(uint32 id, uint32 high, uint32 low)
{
    // Initialise the message strcture
    IfxMultican_Message txMsg;
    IfxMultican_Message_init(&txMsg, id, low, high, IfxMultican_DataLengthCode_8);

    // Transmit Data
    while( IfxMultican_Can_MsgObj_sendMessage(&canSrcMsgObj, &txMsg) == IfxMultican_Status_notSentBusy );

}

int core0_main(void)
{
    IfxCpu_enableInterrupts();
    
    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
    
    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);

    initTime();
    IfxPort_setPinMode(&MODULE_P14, 9, IfxPort_Mode_outputPushPullGeneral);

    IfxPort_setPinMode(&MODULE_P11, 11, IfxPort_Mode_outputPushPullGeneral);

    CanApp_init();
    while(1)
    {
    }
    return (1);
}

结果如下:

深入学习单片机RTOS双架构双系统 双核单片机怎么用_单片机_09

5.网关模式的使用

网关模式可以把接收到的报文直接转发出去,不需要占用CPU进行处理。但要注意的是网关模式只支持8字节的传统CAN帧,不能直接转发CANFD 的长于8字节的数据。如果转发CANFD帧则只能转发ID、DLC和数据场前8字节。

需要注意的一点是MO网关模式需要用到从节点(Slave MO)做FIFO,并且能指定FIFO的数量(msgObjCount),firstSlaveObjId 变量指向的slave MO即为FIFO起始MO,从该MO开始之后的msgObjCount个MO都不应再作为他用,也不能作为其他网关节点的slave MO,否则会导致程序运行不稳定。

下面的代码演示了网关模式转发CAN和CANFD帧,定义了两个CANFD node,CAN1上的MO1用来接收ID=0x101的CANFD帧并转发到CAN2,转发后ID=0x600,CAN1上的MO3用来接收ID=0x102的传统CAN帧并将完全一致的帧转发到CAN2:

#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "SysSe/Bsp/Bsp.h"
#include "Port/Io/IfxPort_Io.h"
#include "Multican/Can/IfxMultican_Can.h"

IfxCpu_syncEvent g_cpuSyncEvent = 0;

// CAN handle
IfxMultican_Can can;
// Nodes handles
IfxMultican_Can_Node canSrcNode;
IfxMultican_Can_Node canDesNode;
// Message Object handles
IfxMultican_Can_MsgObj canSrcMsgObj;
IfxMultican_Can_MsgObj canRcvMsgObj;
IfxMultican_Can_MsgObj canDesMsgObj;
IfxMultican_Can_MsgObj canRcvMsgObj2;
IfxMultican_Can_MsgObj canDesMsgObj2;
#define SRC_EXTENDED_MO_OFFSET      64                          /* Offset where the src extended MOs are located     */

void CanApp_init(void)
{
    // create configuration
    IfxMultican_Can_Config canConfig;
    IfxMultican_Can_initModuleConfig(&canConfig, &MODULE_CAN);
    // initialize interrupt priority
    // initialize module
    IfxMultican_Can_initModule(&can, &canConfig);

    // create CAN node config
    IfxMultican_Can_NodeConfig canNodeConfig;
    IfxMultican_Can_Node_initConfig(&canNodeConfig, &can);
    canNodeConfig.baudrate = 500000; // 1 MBaud
    canNodeConfig.nodeId = IfxMultican_NodeId_0;
    canNodeConfig.rxPin = &IfxMultican_RXD0A_P02_1_IN;
    canNodeConfig.txPin = &IfxMultican_TXD0_P02_0_OUT;

    canNodeConfig.flexibleDataRate               = TRUE;

    canNodeConfig.fdConfig.nominalBaudrate       = 500000;
    canNodeConfig.fdConfig.nominalSynchJumpWidth = 2000;
    canNodeConfig.fdConfig.nominalSamplePoint    = 8000;
    canNodeConfig.fdConfig.fastBaudrate          = 2000000;
    canNodeConfig.fdConfig.fastSynchJumpWidth    = 2000;
    canNodeConfig.fdConfig.fastSamplePoint       = 8000;
    IfxMultican_Can_Node_init(&canSrcNode, &canNodeConfig);

    //CAN node1 configuration
    canNodeConfig.nodeId = IfxMultican_NodeId_1;
    canNodeConfig.rxPin = &IfxMultican_RXD1D_P00_1_IN;
    canNodeConfig.txPin = &IfxMultican_TXD1_P00_0_OUT;
    IfxMultican_Can_Node_init(&canDesNode, &canNodeConfig);

    // create message object config
    IfxMultican_Can_MsgObjConfig canMsgObjConfig;

    IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &canSrcNode);
    canMsgObjConfig.msgObjId = 1;
    canMsgObjConfig.messageId = 0x101;
    canMsgObjConfig.acceptanceMask = 0x7FFFFFFFUL;
    canMsgObjConfig.frame = IfxMultican_Frame_receive;
    canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_64;
    canMsgObjConfig.control.fastBitRate = TRUE;// high speed CANFD frame
    canMsgObjConfig.control.topMsgObjId = SRC_EXTENDED_MO_OFFSET;
    canMsgObjConfig.control.bottomMsgObjId = canMsgObjConfig.control.topMsgObjId + 1;
    //Gateway configuration
    canMsgObjConfig.msgObjCount = 2;
    canMsgObjConfig.firstSlaveObjId = (IfxMultican_MsgObjId)10;
    canMsgObjConfig.gatewayTransfers = TRUE;	
    在此处定义转发报文时copy CAN帧的那些内容
    canMsgObjConfig.gatewayConfig.copyDataLengthCode = FALSE;
    canMsgObjConfig.gatewayConfig.copyData = TRUE;
    canMsgObjConfig.gatewayConfig.copyId = FALSE;
    canMsgObjConfig.gatewayConfig.enableTransmit = TRUE;
    canMsgObjConfig.gatewayConfig.gatewayDstObjId = (IfxMultican_MsgObjId)10;
    // initialize message object
    IfxMultican_Can_MsgObj_init(&canRcvMsgObj, &canMsgObjConfig);


    IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &canDesNode);

    canMsgObjConfig.msgObjId = 2;
    canMsgObjConfig.msgObjCount = 2;
    canMsgObjConfig.messageId = 0x600;
    canMsgObjConfig.acceptanceMask = 0x7FFFFFFFUL;
    canMsgObjConfig.frame = IfxMultican_Frame_transmit;
    canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_8;
    canMsgObjConfig.rxInterrupt.enabled = FALSE;
    canMsgObjConfig.txInterrupt.enabled = FALSE;
    canMsgObjConfig.firstSlaveObjId = (IfxMultican_MsgObjId)10;
    canMsgObjConfig.control.fastBitRate = TRUE;// high speed CANFD frame
    canMsgObjConfig.control.topMsgObjId = SRC_EXTENDED_MO_OFFSET+2;
    canMsgObjConfig.control.bottomMsgObjId = canMsgObjConfig.control.topMsgObjId + 1;
    // initialize message object
    IfxMultican_Can_MsgObj_init(&canDesMsgObj, &canMsgObjConfig);

    IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &canSrcNode);
    canMsgObjConfig.msgObjId = 3;
    canMsgObjConfig.messageId = 0x102;
    canMsgObjConfig.acceptanceMask = 0x7FFFFFFFUL;
    canMsgObjConfig.frame = IfxMultican_Frame_receive;
    canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_8;

    //Gateway configuration
    canMsgObjConfig.msgObjCount = 2;
    canMsgObjConfig.firstSlaveObjId = (IfxMultican_MsgObjId)12;
    canMsgObjConfig.gatewayTransfers = TRUE;
    canMsgObjConfig.gatewayConfig.copyDataLengthCode = TRUE;
    canMsgObjConfig.gatewayConfig.copyData = TRUE;
    canMsgObjConfig.gatewayConfig.copyId = TRUE;
    canMsgObjConfig.gatewayConfig.enableTransmit = TRUE;
    canMsgObjConfig.gatewayConfig.gatewayDstObjId = (IfxMultican_MsgObjId)12;
    // initialize message object
    IfxMultican_Can_MsgObj_init(&canRcvMsgObj2, &canMsgObjConfig);


    IfxMultican_Can_MsgObj_initConfig(&canMsgObjConfig, &canDesNode);

    canMsgObjConfig.msgObjId = 4;
    canMsgObjConfig.msgObjCount = 2;
    canMsgObjConfig.messageId = 0x602;
    canMsgObjConfig.acceptanceMask = 0x7FFFFFFFUL;
    canMsgObjConfig.frame = IfxMultican_Frame_transmit;
    canMsgObjConfig.control.messageLen = IfxMultican_DataLengthCode_8;
    canMsgObjConfig.firstSlaveObjId = (IfxMultican_MsgObjId)12;
    // initialize message object
    IfxMultican_Can_MsgObj_init(&canDesMsgObj2, &canMsgObjConfig);

}

void CAN_SendSingle(uint32 id, uint32 high, uint32 low)
{
    // Initialise the message strcture
    IfxMultican_Message txMsg;
    IfxMultican_Message_init(&txMsg, id, low, high, IfxMultican_DataLengthCode_8);

    // Transmit Data
    while( IfxMultican_Can_MsgObj_sendMessage(&canSrcMsgObj, &txMsg) == IfxMultican_Status_notSentBusy );

}

int core0_main(void)
{
    IfxCpu_enableInterrupts();

    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());

    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);

    initTime();
    IfxPort_setPinMode(&MODULE_P14, 9, IfxPort_Mode_outputPushPullGeneral);

    IfxPort_setPinMode(&MODULE_P11, 11, IfxPort_Mode_outputPushPullGeneral);
    IfxPort_setPinMode(&MODULE_P02, 8, IfxPort_Mode_outputPushPullGeneral);

    CanApp_init();
    while(1)
    {
    }
    return (1);
}

结果如下:

深入学习单片机RTOS双架构双系统 双核单片机怎么用_单片机_10

6.Loop-Back Mode

补充一个小知识点,该系列单片机CAN节点可以设置为Loop-Back Mode,用于调试,当节点设置为Loop-Back模式时,节点将挂在内部CAN总线上,不与外部总线相连,同时挂在内部总线上的CAN node即可互相发送报文,以便于外部硬件环境不满足的时候进行调试。

深入学习单片机RTOS双架构双系统 双核单片机怎么用_深入学习单片机RTOS双架构双系统_11