文章目录
一、DSP CAN介绍
1.1 eCAN 介绍
支持最高1Mbps,拥有32个邮箱(MSGBOX)。
1 eCAN框图
2 CAN帧组成:起始位、仲裁段、控制位、数据段、CRC校验位、响应位和结束位
3 访问控制寄存器与状态寄存器的方式:采用影子寄存器操作
-
改变寄存器的值
-
访问寄存器的值
4 eCAN模式和CCS模式选择
区别:CCS模式是eCAN的阉割版,CCS模式只有16个邮箱可使用,部分功能限制,而eCAN有32个邮箱可使用。
通过设置CANMC.13bit (SCB)进行配置
5 波特率配置
公式:baud = SYSCLK / 2 / BRP / BT
其中:
BRP = BRP寄存器的值(CANBTCbit16-bit23) + 1
BT = (TSGG1 + 1) + (TSGE2 + 1) + 1
下图是官方给出的CAN波特率配置说明,SYSCLK = 150MHz
1.2、eCAN的配置说明
1.2.1 初始化eCAN(略)
1.2.2 配置发送邮箱
以邮箱1举例,CANxxx.1代表邮箱1在该寄存器的位置
配置步骤:
- CANTRS.1 = 0;
- CANME.1 = 0;
- 设置MSGID、DLC、DATA等等
- CANMD.1 = 0; //设置为发送邮箱
- 设CANME.1 = 1;
发送数据时注意:
- 发送前等待CANTRS.1清零,该位若发送成功由内部模块清零
- 下一次发送时
设置CANTRS.1 = 1,启动传输
设置CANTA.1 = 1,CPU清零该位 - 若要重写ID,先失能邮箱 CANME.1 = 0
1.2.3 配置接收邮箱
以邮箱3举例,CANxxx.3代表邮箱3在该寄存器的位置
配置步骤:
- CANME.3 = 0; 邮箱失能
- 设置MSGID,若设置接收掩码,MSGID.30(AME) = 1;
- 若AME = 1; 设置LAM(3)的值,0x…,1:任意,0:必须符合
- CANMD.3 = 1; //设置为接收邮箱
- 若要保护邮箱内的数据不被覆盖,设置CANOPC.3 = 1;
- CANME.3 = 1; 使能邮箱
接收数据时注意:
- 当接收到消息后,CANRMP.3置位
- 同时还要检查CANRML.3是否置位,若置位代表数据被覆盖
- 读取完成后,CANRMP.3 写1清零
二、程序及寄存器介绍
1. 配置eCAN功能
例程为DSP2833x_ECan.c初始化eCANA配置:void InitECana(void)
同时在代码后会根据代码顺序来逐一介绍寄存器
// InitECana - Initialize eCAN-A module
void InitECana(void)
{
struct ECAN_REGS ECanaShadow; //声明一个影子寄存器
volatile struct MBOX *eCANa_MBOX;
Uint8 i;
EALLOW;
SysCtrlRegs.PCLKCR0.bit.ECANAENCLK=1; // eCAN-A
GpioCtrlRegs.GPAPUD.bit.GPIO18 = 0; // Enable pull-up for GPIO18 (CANRXA)
GpioCtrlRegs.GPAPUD.bit.GPIO19 = 0; // Enable pull-up for GPIO19 (CANTXA)
GpioCtrlRegs.GPAQSEL2.bit.GPIO18 = 3; // Asynch qual for GPIO18 (CANRXA)
GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 3; // Configure GPIO18 for CANRXA operation
GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 3; // Configure GPIO19 for CANTXA operation
EDIS;
EALLOW; // EALLOW enables access to protected bits
// Step1:配置eCAN的TX和RX引脚功能
ECanaShadow.CANTIOC.all = ECanaRegs.CANTIOC.all;
ECanaShadow.CANTIOC.bit.TXFUNC = 1;
ECanaRegs.CANTIOC.all = ECanaShadow.CANTIOC.all;
ECanaShadow.CANRIOC.all = ECanaRegs.CANRIOC.all;
ECanaShadow.CANRIOC.bit.RXFUNC = 1;
ECanaRegs.CANRIOC.all = ECanaShadow.CANRIOC.all;
//Step2:配置CANMC寄存器
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.SCB = 1; //eCAN模式
ECanaShadow.CANMC.bit.ABO = 1; //总线自动恢复使能
ECanaShadow.CANMC.bit.DBO = 1; //数据发送/接收:低位优先
ECanaShadow.CANMC.bit.SUSP = 1; //CAN功能不受调试(断点等)影响
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
//初始化MSGCTRL寄存器
eCANa_MBOX= & ECanaMboxes.MBOX0;
for(i = 0; i < 32; i++)
{
eCANa_MBOX->MSGCTRL.all = 0;
eCANa_MBOX++;
}
//清除CANTA、CANRMP、CANGIFx寄存器
ECanaRegs.CANTRR.all = 0xFFFFFFFF; // Clear all TRRn bits
ECanaRegs.CANTA.all = 0xFFFFFFFF; // Clear all TAn bits
ECanaRegs.CANRMP.all = 0xFFFFFFFF; // Clear all RMPn bits
ECanaRegs.CANGIF0.all = 0xFFFFFFFF; // Clear all interrupt flag bits
ECanaRegs.CANGIF1.all = 0xFFFFFFFF;
//获取配置权限(配置CANBTC寄存器)
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.CCR = 1 ;
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
//CCR置位后,查询CANES.CCE置位,方可配置CANBTC
ECanaShadow.CANES.all = ECanaRegs.CANES.all;
do
{
ECanaShadow.CANES.all = ECanaRegs.CANES.all;
} while(ECanaShadow.CANES.bit.CCE != 1 );
ECanaShadow.CANBTC.all = 0;
#if (CPU_FRQ_150MHZ)
ECanaShadow.CANBTC.bit.BRPREG = 9;
ECanaShadow.CANBTC.bit.TSEG2REG = 1;
ECanaShadow.CANBTC.bit.TSEG1REG = 6;
#endif
#if (CPU_FRQ_100MHZ)
ECanaShadow.CANBTC.bit.BRPREG = 4;
ECanaShadow.CANBTC.bit.TSEG2REG = 1;
ECanaShadow.CANBTC.bit.TSEG1REG = 6;
#endif
ECanaShadow.CANBTC.bit.SAM = 1;
ECanaRegs.CANBTC.all = ECanaShadow.CANBTC.all;
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.CCR = 0 ;
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
ECanaShadow.CANES.all = ECanaRegs.CANES.all;
do
{
ECanaShadow.CANES.all = ECanaRegs.CANES.all;
} while(ECanaShadow.CANES.bit.CCE != 0 );// Wait for CCE bit to be cleared
//失能所有邮箱
ECanaRegs.CANME.all = 0; // Required before writing the MSGIDs
EDIS;
}
相关寄存器介绍:
Step 1 : CANTIOC 和 CANRIOC寄存器:为CAN发送和接收功能配置CANTX和CANRX引脚
Step 2 : 配置CANMC寄存器
Step3:初始化邮箱控制寄存器
该寄存器功能有:1.设置发送优先级,2.远程帧设置,3.数据长度设置
Step4:配置eCAN波特率(详细见1.1-5)
1.配置CANMC.CCR,同时等待CANES.CCE位置1
2.配置CANBTC寄存器
配置流程图如下:
CANMC.CCR:
CANBTC.BRP:
注:BRP寄存器赋值后会自动加一
2. 初始化接收\发送邮箱
以eCAN-A为例
2.1 数据帧结构体
// CAN消息ID位定义
struct CAN_MSGID_BITS
{
Uint32 msgID:29; // ID 0-28
Uint16 aam:1; // 自动应答位 29
Uint16 ame:1; // 屏蔽使能位 30
Uint16 ide:1; // 扩展帧 31
};
// CAN 数据结构
union CAN_MSGID_STRU
{
Uint32 all;
struct CAN_MSGID_BITS bit;
};
2.2 初始化发送邮箱
void InitTranMBOX(Uint16 MBOX_Num, Uint32 MSG_Id)
{
volatile struct ECAN_REGS ECanShadow;
volatile struct MBOX *ECanaMBOX;
Uint32 temp;
ECanaMBOX = &ECanaMboxes.MBOX0;
temp = (Uint32) 1 << MBOX_Num;
//失能邮箱
ECanShadow.CANME.all = ECanaRegs.CANME.all;
ECanShadow.CANME.all &= ~temp;
ECanaRegs.CANME.all = ECanShadow.CANME.all;
//邮箱方向:发送
ECanShadow.CANMD.all = ECanaRegs.CANMD.all;
ECanShadow.CANMD.all &= ~temp;
ECanaRegs.CANMD.all = ECanShadow.CANMD.all;
//配置邮箱信息
ECanaMBOX += MBOX_Num;
ECanaMBOX->MSGID.all = MSG_Id;
ECanaMBOX->MSGCTRL.bit.DLC = 8;
//使能邮箱
ECanShadow.CANME.all = ECanaRegs.CANME.all;
ECanShadow.CANME.all |= temp;
ECanaRegs.CANME.all = ECanShadow.CANME.all;
}
void InitCanTran(Uint32 id)
{
union CAN_MSGID_STRU msgId;
Uint16 i;
id &= 0x1fffffff;
msgId.bit.msgID = id; // ID标识位
msgId.bit.aam = 0; // 自动应答标志
msgId.bit.ame = 0; // 接收屏蔽使能,发送邮箱无效
msgId.bit.ide = 1; // 扩展帧标志
//开启3个发送邮箱,邮箱定义如下:
//MSG 0-15 :发送邮箱
//MSG 16-31 :接收邮箱
for(i = 0; i < 3; i++)
{
InitTranMBOX(15-i, msgId.all); // 初始化发送邮箱
}
}
相关寄存器介绍
CANMD 邮箱方向寄存器
CANME 邮箱使能寄存器
MSGID 邮箱ID寄存器
2.3 初始化接收邮箱
void InitRecMBOX(Uint16 MBOX_Num, Uint32 MSG_Id, Uint32 lam, Uint16 opc)
{
volatile struct ECAN_REGS ECanShadow;
volatile struct MBOX *ECanaMBOX;
volatile union CANLAM_REG *MBOX_LAM;
Uint32 temp;
ECanaMBOX = &ECanaMboxes.MBOX0;
MBOX_LAM = &ECanaLAMRegs.LAM0;
temp = (Uint32) 1 << MBOX_Num;
//失能邮箱
ECanShadow.CANME.all = ECanaRegs.CANME.all;
ECanShadow.CANME.all &= ~temp;
ECanaRegs.CANME.all = ECanShadow.CANME.all;
//设置方向:接收
ECanShadow.CANMD.all = ECanaRegs.CANMD.all;
ECanShadow.CANMD.all |= temp;
ECanaRegs.CANMD.all = ECanShadow.CANMD.all;
//设置邮箱覆盖保护
if(opc == 1) //禁止被覆盖
{
ECanShadow.CANOPC.all = ECanaRegs.CANOPC.all;
ECanShadow.CANOPC.all |= temp;
ECanaRegs.CANOPC.all = ECanShadow.CANOPC.all;
}
else //允许被覆盖
{
ECanShadow.CANOPC.all = ECanaRegs.CANOPC.all;
ECanShadow.CANOPC.all &= ~temp;
ECanaRegs.CANOPC.all = ECanShadow.CANOPC.all;
}
//配置邮箱信息
ECanaMBOX += MBOX_Num;
ECanaMBOX->MSGID.all = MSG_Id;
ECanaMBOX->MSGCTRL.bit.DLC = 8;
//使能邮箱
ECanShadow.CANME.all = ECanaRegs.CANME.all;
ECanShadow.CANME.all |= temp;
ECanaRegs.CANME.all = ECanShadow.CANME.all;
//设置邮箱掩码
MBOX_LAM += MBOX_Num;
MBOX_LAM->all = lam;
}
void InitCanRec(Uint32 id)
{
union CAN_MSGID_STRU msgId;
Uint32 lam;
Uint16 i;
id &= 0x1fffffff;
msgId.bit.msgID = id; // id
msgId.bit.ame = 1; // 接收屏蔽使能
msgId.bit.ide = 1; // 扩展帧标志
//~(7ul<<29) 高3位为0,其他位为1
lam = (~(7ul<<29)); //只接收扩展帧,不掩码
//开启3个接收邮箱,邮箱定义如下:
//MSG 0-15 :发送邮箱
//MSG 16-31 :接收邮箱
for(i = 0; i < 3-1; i++)
{
InitRecMBOX(31-i, msgId.all, lam, 1); //开启邮箱覆盖保护
}
InitRecMBOX(31-i, msgId.all, lam, 0); //不保护
}
相关寄存器介绍
LAM 接收掩码寄存器
CANOPC 覆盖保护寄存器
3. 发送/接收数据底层驱动
3.1 发送数据
Uint16 eCanSendData(Uint16 mbox_num, Uint16 len, Uint32 msgid, Uint32 *dataPi)
{
volatile struct ECAN_REGS ECanShadow;
volatile struct MBOX *ECanaMBOX;
Uint32 temp;
mbox_num &= 0x1f;
temp = 1ul << mbox_num;
ECanaMBOX = &ECanaMboxes.MBOX0;
// 检查上次发送是否完成,发送请求标志置位
if (ECanaRegs.CANTRS.all & temp)
{
return 1; // CAN邮箱忙
}
ECanaRegs.CANTA.all = temp; // 清空发送响应标志
ECanaMBOX += mbox_num;
msgid &= ~(0x7ul<<29); // 清除高三位
msgid |= ECanaMBOX->MSGID.all & (0x7ul << 29); // 不修改ID原始配置位
// 禁止对应邮箱
ECanShadow.CANME.all = ECanaRegs.CANME.all;
ECanShadow.CANME.all &= ~temp;
ECanaRegs.CANME.all = ECanShadow.CANME.all;
// 邮箱信息配置
ECanaMBOX->MSGID.all = msgid;
ECanaMBOX->MSGCTRL.bit.DLC = len;
ECanaMBOX->MDL.all = *dataPi++;
ECanaMBOX->MDH.all = *dataPi;
// 使能对应邮箱
ECanShadow.CANME.all = ECanaRegs.CANME.all;
ECanShadow.CANME.all |= temp;
ECanaRegs.CANME.all = ECanShadow.CANME.all;
// 使能发送
ECanaRegs.CANTRS.all = temp;
return (0);
}
3.2 接收数据
Uint16 eCanRecData(Uint16 mbox_num, Uint32 *dataPi)
{
volatile struct MBOX *ECanaMBOX;
Uint32 temp;
temp = 1ul << mbox_num;
mbox_num&= 0x1f;
ECanaMBOX = &ECanaMboxes.MBOX0;
ECanaMBOX += mbox_num;
if (ECanaRegs.CANRMP.all & temp) // 检查是否有接收消息挂起
{
*dataPi++ = ECanaMBOX->MSGID.all; // 读ID,读数据
*dataPi++ = ECanaMBOX->MDL.all;
*dataPi++ = ECanaMBOX->MDH.all;
*dataPi = ECanaMBOX->MSGCTRL.bit.DLC; // 读取接收数据长度
if (ECanaRegs.CANRML.all & temp) // 检查邮箱是否被覆盖过
{
ECanaRegs.CANRMP.all = temp; // 清除消息挂起寄存器
return (1); // 邮箱被覆盖,返回数据溢出
}
else
{
ECanaRegs.CANRMP.all = temp; // 清除消息挂起寄存器
return (2); // 接收成功
}
}
else
{
return (0); // 邮箱无数据
}
}
3.3 数据结构体定义
//32-bit high low 16 bit data
struct CAN_DATA_HL
{
Uint16 data_h;
Uint16 data_l;
};
// 32-bit data structure
union CAN_DATA_STRU
{
Uint32 all;
struct CAN_DATA_HL data;
};
// Email data structure
struct CAN_DATA_BUF
{
union CAN_MSGID_STRU msgid;
union CAN_DATA_STRU mdl;
union CAN_DATA_STRU mdh;
Uint32 len;
};
// Receive cache data structure
struct CAN_REC_BUF
{
Uint16 bufFull;
struct CAN_DATA_BUF buf[3];
};
4 发送和接收数据函数
4.1 发送数据
Uint16 DataTranforcan(Uint32 *dataPi, Uint16 len, Uint16 timeOut)
{
Uint16 rec, i;
Uint32 msgid;
static Uint16 timecount = 0;
msgid = *dataPi++;
for (i=0; i<3; i++)
{
rec = eCanSendData(15-i, len, msgid, dataPi);
if (0 == rec)
{
timecount = 0;
return (0); // 发送成功
}
}
if (++timecount >= timeOut)
{
timecount = 0;
return (1); // 发送超时
}
else
{
return (2); // 发送邮箱忙
}
}
4.2 接收数据
Uint16 DataRecforcan(struct CAN_REC_BUF *dataPi)
{
Uint16 i, rec;
dataPi->bufFull = 0;
for (i=0; i<3; i++)
{
rec = eCanRecData(31-i, (Uint32 *)(&(dataPi->buf[i])) );
if (0 != rec)
dataPi->bufFull |= 1<<i; // 接收缓存有效
}
if ( 0 == dataPi->bufFull ) // 未收数据
return (3); // 接收邮箱空,返回
if (1 == rec)
return (4);
else
return (0);
}
4.3 函数使用说明
4.3.1 发送数据
下面是步骤,不是完整代码
{
//1.定义发送数据
struct CAN_DATA_BUF senddatabuf;
Uint16 Status;
//2.配置ID、DLC、DATA等(略)
...
//3.发送数据,读取返回值
Status = DataTranforcan((Uint32*)(&senddatabuf), 4, 1000);
//4.根据返回状态Status作出处理事件
}
4.3.2 接收数据
下面是步骤,不是完整代码
//1.定义接收缓冲区
struct CAN_REC_BUF RecDataBuf;
Uint16 rec,i;
//2.接收数据
rec = DataRecforcan(&RecDataBuf);
//3.根据返回值处理数据
if ((0 == rec) || (4 == rec) )
{
for (i = 0; i < 3; i++)
{
if ( (RecDataBuf.bufFull & (1 << i) ) == (1 << i))
{
//处理函数自行定义
//处理函数的传入参数为:(struct CAN_REC_BUF*)(&RecDataBuf.buf[i]);
}
}
}
三、代码
总结
以上是dsp ecan功能的相关介绍,主要包括eCAN功能介绍,eCAN功能配置,发送接收邮箱配置,发送接收数据操作等,仅为个人学习记录(若侵权删)。