Tool/software:
Hi TI Experts,
I have a project using MCAN for TX and RX communication. The CAN configuration uses the standard CAN protocol with an extended frame ID and a baud rate of 500K.
I would like to receive data using the RX buffer in interrupt mode. However, when I send a frame with the corresponding ID from PCAN-View to the F280039C, I do not receive any RX data. Additionally, I have set up a breakpoint in debug mode for the RX interrupt, but the interrupt is not being triggered.
Below is my code. Could you please help me check why the RX is not working?
//#############################################################################
//
// FILE: mcan_ex7_classic_transmit_modified.c
//
// TITLE: MCAN Classic Frames Transmission with GPIO-Controlled Modes
// and Enhanced Rx Buffer Support
//
// DESCRIPTION:
// This example extends the MCAN classic frame transmission to include GPIO
// button inputs and enhanced Rx Buffer functionality. It supports:
// - Multiple lighting/motor modes controlled by GPIO buttons
// - Reception of CAN messages into dedicated Rx Buffers
// - Bus-off detection and recovery
// - Periodic message transmission with life counter
//
// Hardware Required:
// - A C2000 board with CAN transceiver
// - GPIO20, GPIO21, GPIO13, GPIO40, GPIO0, GPIO1 connected to buttons
//
// External Connections:
// - MCANRXA and MCANTXA to a CAN transceiver
//
// Watch Variables:
// - txMsg: CAN message being transmitted
// - lightMode: Current mode (0-6)
// - hpcLevel: Motor level in Mode 6
// - rxMsg: Received messages in buffers
//
//#############################################################################
#include "driverlib.h"
#include "device.h"
#include "inc/stw_types.h"
#include "inc/stw_dataTypes.h"
#include <string.h>
#define SYS_CLK_HZ 20000000 // 20MHz系统时钟
// 消息RAM配置 - 使用Rx Buffer
#define MCAN_EXT_ID_FILTER_NUM (4U) // 四个扩展ID过滤器
#define MCAN_RX_BUFF_NUM (4U) // Rx Buffer元素数量
#define MCAN_RX_BUFF_ELEM_SIZE (MCAN_ELEM_SIZE_64BYTES)
#define MCAN_TX_BUFF_NUM (1U) // TX buffer数量
// 计算Message RAM各段起始地址 (word addresses)
#define MCAN_EXT_ID_FILT_START_ADDR (0x0U)
#define MCAN_RX_BUFF_START_ADDR (MCAN_EXT_ID_FILT_START_ADDR + \
(MCAN_EXT_ID_FILTER_NUM * MCANSS_EXT_ID_FILTER_SIZE_WORDS))
#define MCAN_TX_BUFF_START_ADDR (MCAN_RX_BUFF_START_ADDR + \
(MCAN_getMsgObjSize(MCAN_RX_BUFF_ELEM_SIZE) * MCAN_RX_BUFF_NUM))
// GPIO按钮定义
#define KEY_MODE1_PIN 20 // GPIO20: Mode 1
#define KEY_MODE2_PIN 21 // GPIO21: Mode 2
#define KEY_MODE3_PIN 13 // GPIO13: Mode 3
#define KEY_MODE4_PIN 40 // GPIO40: Mode 4
#define KEY_MODE5_PIN 0 // GPIO0: Mode 5
#define KEY_MODE6_PIN 1 // GPIO1: Mode 6
#define DEVICE_DELAY_MS(x) SysCtl_delay(((((long double)(x)) / (1000.0L / \
(long double)((SYS_CLK_HZ * 48) / (2 * 4 * 1)))) - 9.0L) / 5.0L)
// 全局变量
volatile unsigned long tsInterruptCntr = 0;
volatile unsigned long error = 0;
MCAN_TxBufElement txMsg;
MCAN_RxBufElement rxMsg[MCAN_RX_BUFF_NUM]; // Rx Buffer存储
volatile uint32_t isrIntr0Flag = 1U;
volatile uint32_t isrIntr1Flag = 1U;
volatile uint32_t txCompleteFlag = 0;
volatile uint32_t rxDataReady = 0;
volatile uint32_t busOffFlag = 0;
volatile uint8_t lightMode = 0;
volatile uint8_t hpcLevel = 0;
volatile uint32_t errorCount = 0;
volatile uint8_t lifeCounter = 0;
// 添加Rx状态变量
volatile MCAN_RxNewDataStatus newDataStatus;
// 按键相关变量
uint32_t keyPressCounter = 0; // 按键按下计数器
uint8_t lastMode = 0; // 释放按键后保留的上一个模式
volatile uint8_t motor_init = 0;
volatile uint8_t motor_init_cnt = 0;
volatile uint8_t motor_init_finish = 0;
volatile uint32_t hpc_timer = 0;
volatile uint32_t hpc_timer2 = 0;
volatile uint8_t hpc_active = 0;
volatile uint8_t step_phase = 0; // 0:待初始化 1:需推至step4 2:需推至step0 3:保持step0
// 接收消息ID数组
const uint32_t RX_MSG_IDS[MCAN_RX_BUFF_NUM] = {
0x001FFF23, // Buffer 0
0x001FFF24, // Buffer 1
0x001FFF25, // Buffer 2
0x001FFF26 // Buffer 3
};
// 函数原型声明
static void MCANConfig(void);
void checkKeyPress(void);
void UpdateTxMessage(void);
__interrupt void MCAN_TX_ISR(void);
__interrupt void MCAN_RX_ISR(void);
static void MCAN_IntrConfig(void);
void ProcessReceivedData(uint32_t bufIndex);
void CheckBusOffAndRecover(void);
void InitRxBuffers(void);
void InitGPIO(void);
void main()
{
// 初始化设备时钟和外设
Device_init();
// 初始化GPIO
Device_initGPIO();
InitGPIO();
// 初始化Rx Buffer
InitRxBuffers();
// 配置MCAN模块
SysCtl_setMCANClk(SYSCTL_MCANCLK_DIV_3);
MCAN_IntrConfig();
MCANConfig();
// 主循环
while(1)
{
CheckBusOffAndRecover(); // 总线状态监控
checkKeyPress(); // 检查按键输入
UpdateTxMessage(); // 更新发送数据
// 中断模式发送处理
if(!MCAN_getTxBufReqPend(MCANA_DRIVER_BASE))
{
MCAN_writeMsgRam(MCANA_DRIVER_BASE, MCAN_MEM_TYPE_BUF, 0, &txMsg);
MCAN_txBufAddReq(MCANA_DRIVER_BASE, 0U);
// 等待中断触发(带超时)
uint32_t timeout = 5000; // 5ms超时
while(!txCompleteFlag && timeout--);
txCompleteFlag = 0;
}
DEVICE_DELAY_US(49000); // 50ms周期
lifeCounter = (lifeCounter < 255) ? (lifeCounter + 1) : 0;
}
}
// GPIO初始化
void InitGPIO(void)
{
int i = 0;
// 配置CAN引脚
GPIO_setPinConfig(DEVICE_GPIO_CFG_MCANRXA);
GPIO_setPinConfig(DEVICE_GPIO_CFG_MCANTXA);
// 配置模式选择按钮
const uint16_t keyPins[] = {
KEY_MODE1_PIN, KEY_MODE2_PIN, KEY_MODE3_PIN,
KEY_MODE4_PIN, KEY_MODE5_PIN, KEY_MODE6_PIN
};
for( i = 0; i < 6; i++)
{
GPIO_setPadConfig(keyPins[i], GPIO_PIN_TYPE_STD | GPIO_PIN_TYPE_PULLUP);
GPIO_setDirectionMode(keyPins[i], GPIO_DIR_MODE_IN);
GPIO_setQualificationMode(keyPins[i], GPIO_QUAL_SYNC);
GPIO_setControllerCore(keyPins[i], GPIO_CORE_CPU1);
}
}
// Rx Buffer初始化
void InitRxBuffers(void)
{
int i = 0;
for( i = 0; i < MCAN_RX_BUFF_NUM; i++)
{
rxMsg[i].id = 0U;
rxMsg[i].rtr = 0U;
rxMsg[i].xtd = 1U; // 扩展帧
rxMsg[i].esi = 0U;
rxMsg[i].rxts = 0U;
rxMsg[i].dlc = 0U;
rxMsg[i].brs = 0U;
rxMsg[i].fdf = 0U;
rxMsg[i].fidx = 0U;
rxMsg[i].anmf = 0U;
memset(rxMsg[i].data, 0, 64);
}
}
// 总线关闭检测与恢复
void CheckBusOffAndRecover(void)
{
static uint8_t retryCount = 0;
MCAN_ProtocolStatus status;
MCAN_getProtocolStatus(MCANA_DRIVER_BASE, &status);
if(status.busOffStatus)
{
busOffFlag = 1;
retryCount++;
// 进入初始化模式
MCAN_setOpMode(MCANA_DRIVER_BASE, MCAN_OPERATION_MODE_SW_INIT);
// 重置错误计数器
HW_WR_REG32(MCANA_DRIVER_BASE + MCAN_ECR, 0x0);
// 硬件级恢复
if(retryCount > 3)
{
SysCtl_resetDevice(); // 超过重试次数则硬件复位
}
else
{
// 重新初始化
MCANConfig();
MCAN_IntrConfig();
MCAN_setOpMode(MCANA_DRIVER_BASE, MCAN_OPERATION_MODE_NORMAL);
}
}
else
{
busOffFlag = 0;
retryCount = 0;
}
}
// MCAN配置
static void MCANConfig(void)
{
MCAN_InitParams initParams = {0};
initParams.fdMode = 0; // 经典CAN模式
initParams.brsEnable = 0; // 禁用比特率切换
initParams.darEnable = 1; // 启用自动重传
// 500kbps位定时配置
MCAN_BitTimingParams bitTiming = {
.nomRatePrescalar = 3,
.nomTimeSeg1 = 9,
.nomTimeSeg2 = 8,
.nomSynchJumpWidth = 8
};
// 消息RAM配置
MCAN_MsgRAMConfigParams ramConfig = {0};
ramConfig.flesa = MCAN_EXT_ID_FILT_START_ADDR;
ramConfig.lse = MCAN_EXT_ID_FILTER_NUM;
ramConfig.rxBufStartAddr = MCAN_RX_BUFF_START_ADDR;
//ramConfig.rxBufNum = MCAN_RX_BUFF_NUM;
ramConfig.rxBufElemSize = MCAN_RX_BUFF_ELEM_SIZE;
ramConfig.txStartAddr = MCAN_TX_BUFF_START_ADDR;
ramConfig.txBufNum = MCAN_TX_BUFF_NUM;
ramConfig.txBufElemSize = MCAN_ELEM_SIZE_8BYTES;
// 进入初始化模式
while(!MCAN_isMemInitDone(MCANA_DRIVER_BASE));
MCAN_setOpMode(MCANA_DRIVER_BASE, MCAN_OPERATION_MODE_SW_INIT);
while(MCAN_getOpMode(MCANA_DRIVER_BASE) != MCAN_OPERATION_MODE_SW_INIT);
// 初始化MCAN模块
MCAN_init(MCANA_DRIVER_BASE, &initParams);
MCAN_setBitTime(MCANA_DRIVER_BASE, &bitTiming);
MCAN_msgRAMConfig(MCANA_DRIVER_BASE, &ramConfig);
// 配置扩展ID过滤器 - 使用循环和ID数组
uint16_t i = 0;
MCAN_ExtMsgIDFilterElement ef;
for( i = 0; i < MCAN_EXT_ID_FILTER_NUM; i++)
{
memset(&ef, 0, sizeof(ef));
ef.efec = 0x7; // 存储到Rx Buffer (efec=0x7)
ef.efid2 = i; // 指定Buffer索引 (低6位有效)
ef.efid1 = RX_MSG_IDS[i]; // 使用数组中的ID
MCAN_addExtMsgIDFilter(MCANA_DRIVER_BASE, i, &ef);
}
// 返回正常模式
MCAN_setOpMode(MCANA_DRIVER_BASE, MCAN_OPERATION_MODE_NORMAL);
while(MCAN_getOpMode(MCANA_DRIVER_BASE) != MCAN_OPERATION_MODE_NORMAL);
}
// 检查按键输入
void checkKeyPress(void)
{
int i = 0;
static uint8_t prevKeyState = 0; // 上一个按键状态
uint8_t currentKeyState = 0;
const uint16_t keyPins[] = {
KEY_MODE1_PIN, KEY_MODE2_PIN, KEY_MODE3_PIN,
KEY_MODE4_PIN, KEY_MODE5_PIN, KEY_MODE6_PIN
};
// 读取当前按键状态(低电平有效)
for( i = 0; i < 6; i++)
{
if(GPIO_readPin(keyPins[i]) == 0)
{
currentKeyState |= (1 << i);
}
}
// 检查按键状态是否变化
if(currentKeyState != prevKeyState)
{
// 检测到按键按下
if(currentKeyState != 0)
{
keyPressCounter = 0; // 新按下时重置计数器
}
// 检测到按键释放
else if(prevKeyState != 0)
{
// 按键释放时保留上一个模式
lastMode = lightMode;
}
prevKeyState = currentKeyState;
}
// 按键被按住
if(currentKeyState != 0)
{
keyPressCounter++;
if(keyPressCounter >= 5) // 1s = 20 * 50ms
{
// 根据按键组合切换模式
if(currentKeyState == (1 << 0)) lightMode = 1; // Mode 1
else if(currentKeyState == (1 << 1)) lightMode = 2; // Mode 2
else if(currentKeyState == (1 << 2)) lightMode = 3; // Mode 3
else if(currentKeyState == (1 << 3)) lightMode = 4; // Mode 4
else if(currentKeyState == (1 << 4)) lightMode = 5; // Mode 5
else if(currentKeyState == (1 << 5)) // Mode 6
{
lightMode = 6;
// 重置状态变量
motor_init = 1;
motor_init_cnt = 0;
motor_init_finish = 0;
step_phase = 0;
hpcLevel = 0;
}
keyPressCounter = 0; // 模式切换后重置计数器
}
}
else
{
// 无按键按下,保留上一个模式
lightMode = lastMode;
}
}
// 中断配置
static void MCAN_IntrConfig(void)
{
Interrupt_initModule();
Interrupt_initVectorTable();
Interrupt_register(INT_MCANA_0, &MCAN_TX_ISR);
Interrupt_register(INT_MCANA_1, &MCAN_RX_ISR);
Interrupt_enable(INT_MCANA_0);
Interrupt_enable(INT_MCANA_1);
Interrupt_enableGlobal();
// 启用TC和DRX中断
MCAN_enableIntr(MCANA_DRIVER_BASE, MCAN_IR_TC_MASK | MCAN_IR_DRX_MASK, 1U);
MCAN_selectIntrLine(MCANA_DRIVER_BASE, MCAN_IR_TC_MASK, MCAN_INTR_LINE_NUM_0);
MCAN_selectIntrLine(MCANA_DRIVER_BASE, MCAN_IR_DRX_MASK, MCAN_INTR_LINE_NUM_1);
MCAN_enableIntrLine(MCANA_DRIVER_BASE, MCAN_INTR_LINE_NUM_0, 1U);
MCAN_enableIntrLine(MCANA_DRIVER_BASE, MCAN_INTR_LINE_NUM_1, 1U);
}
// 发送中断服务程序
__interrupt void MCAN_TX_ISR(void)
{
uint32_t status = MCAN_getIntrStatus(MCANA_DRIVER_BASE);
MCAN_clearIntrStatus(MCANA_DRIVER_BASE, status);
MCAN_clearInterrupt(MCANA_DRIVER_BASE, 0x1U);
if(status & MCAN_IR_TC_MASK)
txCompleteFlag = 1;
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}
// 接收中断服务程序 - 修复了清除新数据标志的问题
__interrupt void MCAN_RX_ISR(void)
{
uint8_t i = 0;
uint32_t status = MCAN_getIntrStatus(MCANA_DRIVER_BASE);
MCAN_clearIntrStatus(MCANA_DRIVER_BASE, status);
MCAN_clearInterrupt(MCANA_DRIVER_BASE, 0x2U);
if(status & MCAN_IR_DRX_MASK) // Rx Buffer新数据中断
{
// 获取新数据状态
MCAN_getNewDataStatus(MCANA_DRIVER_BASE, &newDataStatus);
// 创建一个掩码用于清除所有检测到的标志
uint32_t clearMask = 0;
// 检查每个Buffer元素是否有新数据
for( i = 0; i < MCAN_RX_BUFF_NUM; i++)
{
if(newDataStatus.statusLow & (1UL << i))
{
// 从Rx Buffer读取数据
MCAN_readMsgRam(MCANA_DRIVER_BASE, MCAN_MEM_TYPE_BUF, i, 0, &rxMsg[i]);
// 处理接收到的数据
ProcessReceivedData(i);
// 添加到清除掩码
clearMask |= (1UL << i);
}
}
// 清除所有检测到的新数据标志
if(clearMask != 0)
{
MCAN_clearNewDataStatus(MCANA_DRIVER_BASE, clearMask);
}
}
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}
// 处理接收数据
void ProcessReceivedData(uint32_t bufIndex)
{
// 根据Buffer索引处理数据
switch(bufIndex)
{
case 0: // ID 0x001FFF23
// 示例: 更新HPC等级
// hpcLevel = rxMsg[bufIndex].data[0] & 0x0F;
lightMode = 1;
break;
case 1: // ID 0x001FFF24
// 示例: 更新灯光模式
// lightMode = rxMsg[bufIndex].data[1];
lightMode = 2;
break;
case 2: // ID 0x001FFF25
// 处理ID 0x001FFF25的数据
lightMode = 3;
break;
case 3: // ID 0x001FFF26
// 处理ID 0x001FFF26的数据
break;
}
rxDataReady = 1; // 设置数据就绪标志
}
// 更新发送消息
void UpdateTxMessage(void)
{
// 清空数据字节
memset(txMsg.data, 0, sizeof(txMsg.data));
// 设置固定消息属性
txMsg.id = 0x0CFE41FD; // 扩展ID
txMsg.rtr = 0U;
txMsg.xtd = 1U; // 扩展标识符
txMsg.esi = 0U;
txMsg.dlc = 8U; // 8字节数据长度
txMsg.brs = 0U;
txMsg.fdf = 0U;
txMsg.efc = 1U;
txMsg.mm = 0xAAU;
// 根据当前模式更新数据
switch(lightMode)
{
case 1: // 模式1: 近光灯
txMsg.data[0] = 0x04;
break;
case 2: // 模式2: 远光灯
txMsg.data[0] = 0x01;
break;
case 3: // 模式3: 位置灯
txMsg.data[0] = 0x50;
break;
case 4: // 模式4: 日间行车灯
txMsg.data[1] = 0x01 | (0x01 << 2);
break;
case 5: // 模式5: 转向灯
txMsg.data[3] = 0x01 | (0x01 << 2);
break;
case 6: // 模式6: 电机控制
if(motor_init == 1) // 初始化阶段
{
txMsg.data[5] = 1;
motor_init_cnt++;
if(motor_init_cnt >= 20) // 初始化完成(20*50ms=1秒)
{
motor_init = 0;
motor_init_finish = 1;
step_phase = 1;
}
}
else
{
txMsg.data[5] = 0;
}
if(motor_init_finish)
{
switch(step_phase)
{
case 1: // 推至step4
hpcLevel = 4;
hpc_timer2++;
if(hpc_timer2 >= 40) // 2秒
step_phase = 2;
break;
case 2: // 推至step0
hpcLevel = 0;
step_phase = 3;
break;
case 3: // 保持step0
hpcLevel = 0;
break;
}
}
txMsg.data[4] = hpcLevel;
break;
default: // 无模式
break;
}
txMsg.data[7] = lifeCounter; // 生命周期计数器
}
Best regards,
Allen
