项目场景:
学习CAN总线相关知识是每个汽电行业从业者的必修课之一,使用英飞凌TC397芯片作为MCU进行通讯中,首先进行CAN收发和解析实验,在自己的调试和学习中出现了一些问题,在此记录,望各位兄台少走弯路:
- 此Demo初期是用英飞凌示例程序中的两节点通过环回模式通讯,当发送和接收到数据后点亮LED
具体可参考:MCMCAN_1_KIT_TC397_TFT - 第二部分为了实现CAN收发功能,并在中断中解析报文,参考weifengdq的MCMCAN例程
- 当我将大佬代码放到自己的板子上运行的时候出现了问题…
问题描述
*英飞凌MCMCAN模块和上位机无法通讯*
通过 AURIX Development Studio(当然HighTec也可以)打印关键的IR寄存器:
可以看到BO位置1,总线关闭状态,说明CAN总线发生了错误。
继续查看ECR寄存器确定错误类型:
由寄存器说明可知,TEC和CEL置位,说明CAN发送出现主动错误。说明链路没有问题,是程序和板子本身的问题。
具体寄存器的详细描述我摘下来芯片手册,可以看一下
-
IR0
-
ERC0
原因分析:
问题分析如下:
1.数据链路的问题 CAN节点–CAN线–CAN卡–上位机(通过寄存器排除)
2.板载的CAN控制器问题(环回模式正常排除)
3.最后就是代码问题了,请看下面
CAN初始化部分
void initCAN0(void)
{
/*******CAN module configuration and initialization*******/
IfxCan_Can_initModuleConfig(&g_mcmcan.canConfig, &MODULE_CAN0);
IfxCan_Can_initModule(&g_mcmcan.canModule, &g_mcmcan.canConfig);
/*******CAN00 node configuration and initialization*******/
IfxCan_Can_initNodeConfig(&g_mcmcan.canNodeConfig, &g_mcmcan.canModule);
g_mcmcan.canNodeConfig.nodeId = IfxCan_NodeId_0;
g_mcmcan.canNodeConfig.clockSource = IfxCan_ClockSource_both;
g_mcmcan.canNodeConfig.frame.type = IfxCan_FrameType_transmitAndReceive;
g_mcmcan.canNodeConfig.frame.mode = IfxCan_FrameMode_standard; //Classic CAN
g_mcmcan.canNodeConfig.txConfig.txMode = IfxCan_TxMode_dedicatedBuffers;
g_mcmcan.canNodeConfig.txConfig.dedicatedTxBuffersNumber = 255;
g_mcmcan.canNodeConfig.txConfig.txBufferDataFieldSize = IfxCan_DataFieldSize_8;
g_mcmcan.canNodeConfig.rxConfig.rxMode = IfxCan_RxMode_dedicatedBuffers;
g_mcmcan.canNodeConfig.rxConfig.rxBufferDataFieldSize = IfxCan_DataFieldSize_8;
g_mcmcan.canNodeConfig.filterConfig.extendedListSize = 255; //Extended Frame
g_mcmcan.canNodeConfig.filterConfig.messageIdLength = IfxCan_MessageIdLength_extended;
g_mcmcan.canNodeConfig.baudRate.baudrate = 500000; //500KBaud
//transmit interrupt
g_mcmcan.canNodeConfig.interruptConfig.transmissionCompletedEnabled = TRUE;
g_mcmcan.canNodeConfig.interruptConfig.traco.priority = ISR_PRIORITY_CAN_TX;
g_mcmcan.canNodeConfig.interruptConfig.traco.interruptLine = IfxCan_InterruptLine_0;
g_mcmcan.canNodeConfig.interruptConfig.traco.typeOfService = IfxSrc_Tos_cpu0;
//receive interrupt
g_mcmcan.canNodeConfig.interruptConfig.messageStoredToDedicatedRxBufferEnabled = TRUE;
g_mcmcan.canNodeConfig.interruptConfig.reint.priority = ISR_PRIORITY_CAN_RX;
g_mcmcan.canNodeConfig.interruptConfig.reint.interruptLine = IfxCan_InterruptLine_1;
g_mcmcan.canNodeConfig.interruptConfig.reint.typeOfService = IfxSrc_Tos_cpu0;
//binding pin
IFX_CONST IfxCan_Can_Pins Can00_pins =
{
&IfxCan_TXD00_P20_8_OUT, IfxPort_OutputMode_pushPull, // CAN00_TX
&IfxCan_RXD00B_P20_7_IN, IfxPort_InputMode_pullUp, // CAN00_RX
IfxPort_PadDriver_cmosAutomotiveSpeed4
};
g_mcmcan.canNodeConfig.pins = &can00_pins;
IfxCan_Can_initNode(&g_mcmcan.can00Node, &g_mcmcan.canNodeConfig);
/*******CAN filter configuration and initialization*******/
g_mcmcan.canFilter.number = 0;
g_mcmcan.canFilter.elementConfiguration = IfxCan_FilterElementConfiguration_storeInRxBuffer;
g_mcmcan.canFilter.id1 = CAN_MESSAGE_RX_ID1;
g_mcmcan.canFilter.rxBufferOffset = IfxCan_RxBufferId_0;
IfxCan_Can_setExtendedFilter(&g_mcmcan.can02Node, &g_mcmcan.canFilter);
g_mcmcan.canFilter.number = 1;
g_mcmcan.canFilter.elementConfiguration = IfxCan_FilterElementConfiguration_storeInRxBuffer;
g_mcmcan.canFilter.id1 = CAN_MESSAGE_RX_ID2;
g_mcmcan.canFilter.rxBufferOffset = IfxCan_RxBufferId_0;
IfxCan_Can_setExtendedFilter(&g_mcmcan.can02Node, &g_mcmcan.canFilter);
g_mcmcan.canFilter.number = 2;
g_mcmcan.canFilter.elementConfiguration = IfxCan_FilterElementConfiguration_storeInRxBuffer;
g_mcmcan.canFilter.id1 = CAN_MESSAGE_RX_ID3;
g_mcmcan.canFilter.rxBufferOffset = IfxCan_RxBufferId_0;
IfxCan_Can_setExtendedFilter(&g_mcmcan.can02Node, &g_mcmcan.canFilter);
}
发送函数部分
void initMsg(void)
{
IfxCan_Can_initMessage(&g_mcmcan.txMsg);
g_mcmcan.txMsg.messageId = CAN_MESSAGE_TX_ID0;
g_mcmcan.txMsg.bufferNumber = 0;
g_mcmcan.txMsg.dataLengthCode = IfxCan_DataLengthCode_8;//8 bytes
g_mcmcan.txMsg.frameMode = IfxCan_FrameMode_standard; //Classic CAN
g_mcmcan.txMsg.messageIdLength=IfxCan_MessageIdLength_extended; //Extended Frame
g_mcmcan.txData[0] = g_mcmcan.rxData[0];
g_mcmcan.txData[1] = g_mcmcan.rxData[1];
while(IfxCan_Status_notSentBusy ==
IfxCan_Can_sendMessage(&g_mcmcan.can02Node, &g_mcmcan.txMsg, &g_mcmcan.txData[0]) )
{
}
}
看起来一切正常,环回模式中用的CAN0,CAN1实现收发,怎么把环回打开就不能用了,我百思不得其解。继续阅读芯片手册,改代码,求助大佬,翻论坛,无果。
直到我打开了在文件夹里尘封已久的TC397 demo板手册…
解决方案:
在Demo板3.10节MultiCAN中写道:
On the board is one CAN transceiver (CAN FD capable) connected to the CAN module 0 node 0 (P20.7 and P20.8)
on TC3X7. Optional the CAN transceiver can be connected to CAN module 0 node 2 (P10.2 and P10.3). To do this
remove resistor R269, R270 and assemble R257, R258 with 0R Resistor. For location of this resistors please see the
Top Layer assembling Figure 7-5.
Note: If the board is assembled with TC397 and TLF35584QVVS2 (3,3V version) then the SDMMC module is
connected directly to the SD card. In this case P20.7 and P20.8 are used by the SDMMC and the
transceiver is connected to P10.2 and P10.3.
The transceiver is connected to an IDC10 plug. For the pinout of IDC10 plug see Figure 6-4. You can use a IDC
female connector with crimpconnector, flat cable and SUB-D 9 plug with crimpconnector to have a 1:1 adapter
to SUB-D 9.
大概意思就是:在打板时将SD卡的SDMMC 使用 P20.7 和 P20.8 而CAN收发器连接到 P10.2 和 P10.3,因此要使用CAN2节点和P10.2 和,P10.3口。
太坑爹了!!!
知道问题后修改代码(CPU0全部代码附上):
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "Ifx_Types.h"
#include "IfxCan_Can.h"
#include "IfxCan.h"
#include "IfxCpu_Irq.h"
#include "IfxPort.h"
#include "Bsp.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"
#include "IfxStm.h"
#include "IfxAsclin_Asc.h"
//CPU同步
IFX_ALIGN(4) IfxCpu_syncEvent g_cpuSyncEvent = 0;
/******************************************LED define***********************************************************************/
#define LED0 &MODULE_P13,0
#define LED1 &MODULE_P13,1
#define LED2 &MODULE_P13,2
#define LED3 &MODULE_P13,3
/******************************************CAN define*************************************************************************/
#define MODULE_CAN0_RAM 0xF0200000
#define NODE0_RAM_OFFSET 0x0
#define CAN_MESSAGE_TX_ID0 (uint32)0xC6
#define CAN_MESSAGE_RX_ID1 (uint32)0xb4
#define CAN_MESSAGE_RX_ID2 (uint32)0x8C
#define CAN_MESSAGE_RX_ID3 (uint32)0x1A3
#define ISR_PRIORITY_CAN_TX 2 /* Define the CAN TX interrupt priority */
#define ISR_PRIORITY_CAN_RX 1 /* Define the CAN RX interrupt priority */
#define MAXIMUM_CAN_DATA_PAYLOAD 2 /* Define maximum classical CAN payload in 4-byte words */
#define WAIT_TIME 1000
typedef struct
{
IfxCan_Can_Config canConfig; /* CAN module configuration structure */
IfxCan_Can canModule; /* CAN module handle */
IfxCan_Can_Node can02Node; /* CAN source node handle data structure */
IfxCan_Can_NodeConfig canNodeConfig; /* CAN node configuration structure */
IfxCan_Filter canFilter; /* CAN filter configuration structure */
IfxCan_Message txMsg; /* Transmitted CAN message structure */
IfxCan_Message rxMsg; /* Received CAN message structure */
uint32 txData[MAXIMUM_CAN_DATA_PAYLOAD]; /* Transmitted CAN data array */
uint32 rxData[MAXIMUM_CAN_DATA_PAYLOAD]; /* Received CAN data array */
} McmcanType;
McmcanType g_mcmcan;
/********************************************CAN Implement*************************************************************************************/
void initMsg(void);
IFX_INTERRUPT(canIsrTxHandler, 0, ISR_PRIORITY_CAN_TX);
void canIsrTxHandler(void)
{
IfxCan_Node_clearInterruptFlag(g_mcmcan.can02Node.node, IfxCan_Interrupt_transmissionCompleted);
IfxPort_togglePin(LED0);
}
IFX_INTERRUPT(canIsrRxHandler, 0, ISR_PRIORITY_CAN_RX);
void canIsrRxHandler(void)
{
/* Clear the "Message stored to Dedicated RX Buffer" interrupt flag */
IfxCan_Node_clearInterruptFlag(g_mcmcan.can02Node.node, IfxCan_Interrupt_messageStoredToDedicatedRxBuffer);
/* Clear the "New Data" flag; as long as the "New Data" flag is set, the respective Rx buffer is
* locked against updates from received matching frames.
*/
IfxCan_Node_clearRxBufferNewDataFlag(g_mcmcan.can02Node.node, g_mcmcan.canFilter.rxBufferOffset);
/* Read the received CAN message */
IfxCan_Can_readMessage(&g_mcmcan.can02Node, &g_mcmcan.rxMsg, g_mcmcan.rxData);
/* Check if the received data matches with the transmitted one */
if(g_mcmcan.rxMsg.messageId == CAN_MESSAGE_RX_ID1)
{
IfxPort_setPinState(LED1, IfxPort_State_low); //LED ON
uint8 Checksum = (g_mcmcan.rxData[1] >>24) & 0xFF;
uint8 WheelSpeed_FR = (g_mcmcan.rxData[1] >> 16) & 0xFF;
uint8 WheelSpeed_FL = (g_mcmcan.rxData[1] >> 8) & 0xFF;
uint8 ABS_VehicleSpeed = g_mcmcan.rxData[1] & 0xFF;
uint8 LiveConter = (g_mcmcan.rxData[0]>>24) & 0xFF ;
uint8 ABS_DrivingDirection = (g_mcmcan.rxData[0] >> 16) & 0xFF;
uint32 speedKmPerHour = ABS_VehicleSpeed;
float speedMps = (float)speedKmPerHour * 1000.0 / 3600.0;
printf("*********************************************************\n");
printf("ABS_VehicleSpeed: %.2f m/s\n", speedMps);
printf("WheelSpeed_FL: %u kmh\n", WheelSpeed_FL);
printf("WheelSpeed_FR: %u kmh\n", WheelSpeed_FR);
switch(ABS_DrivingDirection)
{
case 0 : printf("front\n");
break;
case 1 : printf("back\n");
break;
case 2 : printf("left\n");
break;
case 3 : printf("right\n");
break;
}
printf("Checksum: %u\n", Checksum);
printf("LiveConter: %u\n", LiveConter);
printf("*********************************************************\n");
}
else
{
IfxPort_setPinState(LED1, IfxPort_State_high); //LED OFF
}
if(g_mcmcan.rxMsg.messageId == CAN_MESSAGE_RX_ID2)
{
initMsg();
}
else
{
IfxPort_setPinState(LED2, IfxPort_State_high);
}
if(g_mcmcan.rxMsg.messageId == CAN_MESSAGE_RX_ID3)
{
IfxPort_setPinState(LED3, IfxPort_State_low);
}
else
{
IfxPort_setPinState(LED3, IfxPort_State_high);
}
}
void initCAN0(void)
{
/*******CAN module configuration and initialization*******/
IfxCan_Can_initModuleConfig(&g_mcmcan.canConfig, &MODULE_CAN0);
IfxCan_Can_initModule(&g_mcmcan.canModule, &g_mcmcan.canConfig);
/*******CAN00 node configuration and initialization*******/
IfxCan_Can_initNodeConfig(&g_mcmcan.canNodeConfig, &g_mcmcan.canModule);
g_mcmcan.canNodeConfig.nodeId = IfxCan_NodeId_2;
g_mcmcan.canNodeConfig.clockSource = IfxCan_ClockSource_both;
g_mcmcan.canNodeConfig.frame.type = IfxCan_FrameType_transmitAndReceive;
g_mcmcan.canNodeConfig.frame.mode = IfxCan_FrameMode_standard; //Classic CAN
g_mcmcan.canNodeConfig.txConfig.txMode = IfxCan_TxMode_dedicatedBuffers;
g_mcmcan.canNodeConfig.txConfig.dedicatedTxBuffersNumber = 255;
g_mcmcan.canNodeConfig.txConfig.txBufferDataFieldSize = IfxCan_DataFieldSize_8;
g_mcmcan.canNodeConfig.rxConfig.rxMode = IfxCan_RxMode_dedicatedBuffers;
g_mcmcan.canNodeConfig.rxConfig.rxBufferDataFieldSize = IfxCan_DataFieldSize_8;
g_mcmcan.canNodeConfig.filterConfig.extendedListSize = 255; //Extended Frame
g_mcmcan.canNodeConfig.filterConfig.messageIdLength = IfxCan_MessageIdLength_extended;
g_mcmcan.canNodeConfig.messageRAM.extendedFilterListStartAddress = 0x100; //Extended Frame
g_mcmcan.canNodeConfig.messageRAM.rxBuffersStartAddress = 0x200;
g_mcmcan.canNodeConfig.messageRAM.txBuffersStartAddress = 0x400;
g_mcmcan.canNodeConfig.messageRAM.baseAddress = MODULE_CAN0_RAM + NODE0_RAM_OFFSET;
g_mcmcan.canNodeConfig.baudRate.baudrate = 500000; //500KBaud
//transmit interrupt
g_mcmcan.canNodeConfig.interruptConfig.transmissionCompletedEnabled = TRUE;
g_mcmcan.canNodeConfig.interruptConfig.traco.priority = ISR_PRIORITY_CAN_TX;
g_mcmcan.canNodeConfig.interruptConfig.traco.interruptLine = IfxCan_InterruptLine_0;
g_mcmcan.canNodeConfig.interruptConfig.traco.typeOfService = IfxSrc_Tos_cpu0;
//receive interrupt
g_mcmcan.canNodeConfig.interruptConfig.messageStoredToDedicatedRxBufferEnabled = TRUE;
g_mcmcan.canNodeConfig.interruptConfig.reint.priority = ISR_PRIORITY_CAN_RX;
g_mcmcan.canNodeConfig.interruptConfig.reint.interruptLine = IfxCan_InterruptLine_1;
g_mcmcan.canNodeConfig.interruptConfig.reint.typeOfService = IfxSrc_Tos_cpu0;
//binding pin
IFX_CONST IfxCan_Can_Pins can02_pins = {
&IfxCan_TXD02_P10_3_OUT, IfxPort_OutputMode_pushPull,
&IfxCan_RXD02E_P10_2_IN, IfxPort_InputMode_pullUp,
IfxPort_PadDriver_cmosAutomotiveSpeed4
};
g_mcmcan.canNodeConfig.pins = &can02_pins;
IfxCan_Can_initNode(&g_mcmcan.can02Node, &g_mcmcan.canNodeConfig);
/*******CAN filter configuration and initialization*******/
g_mcmcan.canFilter.number = 0;
g_mcmcan.canFilter.elementConfiguration = IfxCan_FilterElementConfiguration_storeInRxBuffer;
g_mcmcan.canFilter.id1 = CAN_MESSAGE_RX_ID1;
g_mcmcan.canFilter.rxBufferOffset = IfxCan_RxBufferId_0;
IfxCan_Can_setExtendedFilter(&g_mcmcan.can02Node, &g_mcmcan.canFilter);
g_mcmcan.canFilter.number = 1;
g_mcmcan.canFilter.elementConfiguration = IfxCan_FilterElementConfiguration_storeInRxBuffer;
g_mcmcan.canFilter.id1 = CAN_MESSAGE_RX_ID2;
g_mcmcan.canFilter.rxBufferOffset = IfxCan_RxBufferId_0;
IfxCan_Can_setExtendedFilter(&g_mcmcan.can02Node, &g_mcmcan.canFilter);
g_mcmcan.canFilter.number = 2;
g_mcmcan.canFilter.elementConfiguration = IfxCan_FilterElementConfiguration_storeInRxBuffer;
g_mcmcan.canFilter.id1 = CAN_MESSAGE_RX_ID3;
g_mcmcan.canFilter.rxBufferOffset = IfxCan_RxBufferId_0;
IfxCan_Can_setExtendedFilter(&g_mcmcan.can02Node, &g_mcmcan.canFilter);
}
void initLED(void)
{
IfxPort_setPinMode(LED0, IfxPort_Mode_outputPushPullGeneral); /* Initialize LED port pin */
IfxPort_setPinMode(LED1, IfxPort_Mode_outputPushPullGeneral);
IfxPort_setPinMode(LED2, IfxPort_Mode_outputPushPullGeneral);
IfxPort_setPinMode(LED3, IfxPort_Mode_outputPushPullGeneral);
IfxPort_setPinState(LED0, IfxPort_State_high); /* Turn off LED (LED is low-level active) */
IfxPort_setPinState(LED1, IfxPort_State_high);
IfxPort_setPinState(LED2, IfxPort_State_high);
IfxPort_setPinState(LED3, IfxPort_State_high);
}
void initMsg(void)
{
IfxCan_Can_initMessage(&g_mcmcan.txMsg);
g_mcmcan.txMsg.messageId = CAN_MESSAGE_TX_ID0;
g_mcmcan.txMsg.bufferNumber = 0;
g_mcmcan.txMsg.dataLengthCode = IfxCan_DataLengthCode_8;//8 bytes
g_mcmcan.txMsg.frameMode = IfxCan_FrameMode_standard; //Classic CAN
g_mcmcan.txMsg.messageIdLength=IfxCan_MessageIdLength_extended; //Extended Frame
g_mcmcan.txData[0] = g_mcmcan.rxData[0];
g_mcmcan.txData[1] = g_mcmcan.rxData[1];
while(IfxCan_Status_notSentBusy ==
IfxCan_Can_sendMessage(&g_mcmcan.can02Node, &g_mcmcan.txMsg, &g_mcmcan.txData[0]) )
{
}
}
void core0_main(void)
{
IfxCpu_enableInterrupts();
IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
IfxCpu_emitEvent(&g_cpuSyncEvent);
IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
initLED();
initCAN0();
while(1)
{
waitTime(IfxStm_getTicksFromMilliseconds(BSP_DEFAULT_TIMER, WAIT_TIME));
}
}
代码编译运行正常,接上CAN卡发送数据
配置ID为0xb4的帧做报文解析,ID为0x8c直接转发,ID为0x1a3点灯
可以看到五帧报文全部发送成功!
AURIX Development Studio 模拟串口print如下:
到此为止,MCMCAN收发并解析问题解决,我也顺利完成了师父交给我的学习任务,加油汽电人!