本文记录和总结了我初步学习英飞凌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,输入工程名,并选择芯片型号即可:
工程创建好后,可以在工程目录下看到Cpu0_Main.c和Cpu1_Main.c两个文件,分别包含了两个核心的main函数,其中core0是主核心。
关于硬件调试器可以使用英飞凌官方的miniwiggler,约1000RMB,觉得贵的话国内有一家乾勤科技自制的miniwiggler,300多块,使用起来也挺稳定的。连接好调试器和开发板后,点击调试会先编译再启动调试,界面如下,在①处可以执行单步运行等操作,②处可以选择想要运行的cpu,右上角的③处可以切换编辑界面和调试界面。
如果使用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
另外还有网上找到的第三方开发的TC264的资料,芯片型号不同的话替换一下iLLD库即可,应用程序程序都是通用的,包括上面的官方例程也是一样。下载链接:
基于上面这些资料的基础,我们来看以下点亮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报文的发送闪烁:
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);
}
结果如下:
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电平。
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);
}
结果如下:
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);
}
结果如下:
6.Loop-Back Mode
补充一个小知识点,该系列单片机CAN节点可以设置为Loop-Back Mode,用于调试,当节点设置为Loop-Back模式时,节点将挂在内部CAN总线上,不与外部总线相连,同时挂在内部总线上的CAN node即可互相发送报文,以便于外部硬件环境不满足的时候进行调试。