DSP F28335:CAN配置[DSP CAN]


一、DSP CAN介绍

1.1 eCAN 介绍

支持最高1Mbps,拥有32个邮箱(MSGBOX)。

1 eCAN框图

eCAN框图

2 CAN帧组成:起始位、仲裁段、控制位、数据段、CRC校验位、响应位和结束位

CAN帧信息

3 访问控制寄存器与状态寄存器的方式:采用影子寄存器操作

  1. 改变寄存器的值
    改变寄存器的值

  2. 访问寄存器的值
    访问寄存器的值

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
官方文档BUAD配置举例

1.2、eCAN的配置说明

1.2.1 初始化eCAN(略)

1.2.2 配置发送邮箱

以邮箱1举例,CANxxx.1代表邮箱1在该寄存器的位置

配置步骤:

  1. CANTRS.1 = 0;
  2. CANME.1 = 0;
  3. 设置MSGID、DLC、DATA等等
  4. CANMD.1 = 0; //设置为发送邮箱
  5. 设CANME.1 = 1;

发送数据时注意:

  1. 发送前等待CANTRS.1清零,该位若发送成功由内部模块清零
  2. 下一次发送时
    设置CANTRS.1 = 1,启动传输
    设置CANTA.1 = 1,CPU清零该位
  3. 若要重写ID,先失能邮箱 CANME.1 = 0

1.2.3 配置接收邮箱

以邮箱3举例,CANxxx.3代表邮箱3在该寄存器的位置

配置步骤:

  1. CANME.3 = 0; 邮箱失能
  2. 设置MSGID,若设置接收掩码,MSGID.30(AME) = 1;
  3. 若AME = 1; 设置LAM(3)的值,0x…,1:任意,0:必须符合
  4. CANMD.3 = 1; //设置为接收邮箱
  5. 若要保护邮箱内的数据不被覆盖,设置CANOPC.3 = 1;
  6. CANME.3 = 1; 使能邮箱

接收数据时注意:

  1. 当接收到消息后,CANRMP.3置位
  2. 同时还要检查CANRML.3是否置位,若置位代表数据被覆盖
  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引脚

CANTIOC
CANRIOC

Step 2 : 配置CANMC寄存器

CANMC

Step3:初始化邮箱控制寄存器
该寄存器功能有:1.设置发送优先级,2.远程帧设置,3.数据长度设置

MSGCTRL

Step4:配置eCAN波特率(详细见1.1-5)
1.配置CANMC.CCR,同时等待CANES.CCE位置1
2.配置CANBTC寄存器
配置流程图如下:

初始化参数
CANMC.CCR:
CCR
CANBTC.BRP:
注:BRP寄存器赋值后会自动加一
BPR
TSEG
SAM

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 邮箱方向寄存器

CANMD

CANME 邮箱使能寄存器

CANME

MSGID 邮箱ID寄存器

MSGID

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 接收掩码寄存器

LAM

CANOPC 覆盖保护寄存器

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]);
			}	
		}
	}

三、代码

将上述代码整理后,如下链接查看
can.c
can.h


总结

以上是dsp ecan功能的相关介绍,主要包括eCAN功能介绍,eCAN功能配置,发送接收邮箱配置,发送接收数据操作等,仅为个人学习记录(若侵权删)。

  • 33
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值