项目场景:
通过TMS320F28069与北京伟恩斯技术有限公司的VSMD136_025T步进电机驱动控制器实现CAN通信,控制电机的转速、使能、细分、加速、减速等控制与读写。
CAN通信介绍
-
通过两条通信线(双绞线)产生的电压差传输数据,一个CAN网络里的所有节点都挂在这两条通信线上,使用差分信号半双工通信。
-
CAN 使用称为 CANH / CANL 的通信线路执行传输和接收。没有电位差的信号称为隐性(Recessive)信号,其逻辑值为1。具有电位差的信号称为显性(Dominant)信号,其逻辑值0。如果通信总线上发生显性和隐性(Recessive)冲突,则显性(Dominant)优先。总线空闲时保持隐性。
-
CAN的数据定义了有5种帧类型:
帧 | 帧用途 |
---|---|
数据帧 | 由于节点向外传输数据 |
遥控帧 | 用于向远端节点请求数据 |
错误帧 | 用于向远端节点通知检验错误,请求重新发送上一个数据 |
过载帧 | 用于通知远端节点 |
帧间隔 | 用于将数据帧和遥控帧与前面的帧分离开来 |
TMS320F28069之CAN通信:
- 如下图是由一个 CAN协议内核 (CPK) 和一个消息控制器组成,根据 CAN 协议,CPK 的两个功能的是解码在 CAN 总线上接收到的所有消息,并把这些消息转移到接收缓冲器。CPK 的另一个功能是根据 CAN 协议传输 CAN 总线上的消息。CAN 控制器的消息控制器是负责确定 CPK 接收到的任何信息是否必须被保留以便用于CPU 使用还是被丢弃。在初始化阶段,CPU 指定消息控制器应用所使用的所有消息标识符。根据消息的优先级,消息控制器还负责发送下一条消息传输到 CPK。
- 一条消息由 11 或 29 位标识符、一个控制字段,以及多达 8 个数据字节组成。当一条消息必须传输时, 消息控制器把该消息传输到 CPK 的发送缓冲区, 以便在下次总线空闲状态时开始
传输该消息。 当必须传输多个消息时, 已做好传输准备的、 具有最高优先级的消息将由消息控制器传输到CPK 中。 如果两个邮箱具有相同的优先级, 那么具有较高的号码的邮箱优先传输。 - 邮箱布局:各个邮箱都由以下四个 32 位寄存器组成:MSGID(存储 ID)、MSGCTRL (定义字节, 传输优先级和远程帧的数目)、 CANMDL ( 4 字节数据)、CANMDH ( 4 字节数据)。结构如下:
发送邮箱
CPU 将要发送的数据存储在一个配置为发送邮箱的邮箱中。 在把数据和标识符写入到 RAM 中后, 如果相应的 TRS[n] 位已设置, 假如通过设置相应的 CANME.n 位邮箱被启用的话, 则消息被发送。如果不止一个邮箱被设为发送邮箱, 并且不止一个 TRS[n] 位被置位, 则消息从具有最高优先级的邮箱按照优先级下降的次序依次发送。
接收邮箱
每个进入消息的标识符与保存在使用适当屏蔽的接收邮箱内的标识符相比较。 当两者匹配时, 接收到的标注符, 控制位和数据字节将被写进匹配的 RAM 位置。同时,相应的接收消息等待位,RMP[n] ( RMP.31-0 ) ) 被设置, 如果被启用则产生一个接收中断。 如果未检测到匹配, 则消息不存储。当消息接收后, 消息控制器从邮箱编号最高的邮箱开始搜索一个匹配的标识符。 在 SCC 兼容模式下的,eCAN 的邮箱 15 具有最高接收优先级; 在 eCAN 模式下, eCAN 的邮箱 31 具有最高接收优先级。
程序:
unsigned char pump_tx_len;
unsigned long pump_msgid; //接收存储信息
unsigned char pump_rcvBuf[128]; //接受数据缓存
unsigned char pump_rcvLen; //接收数据长度
p_pumpcomm_callback pumpCommFunc //接收数据 回调函数
void InitECana(void) // Initialize eCAN-A module
{
struct ECAN_REGS ECanaShadow;
EALLOW; // EALLOW enables access to protected bits
/* Configure eCAN RX and TX pins for CAN operation using eCAN regs*/
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;
/* Configure eCAN for HECC mode - (reqd to access mailboxes 16 thru 31) */
// HECC mode also enables time-stamping feature
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.SCB = 1;
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
/* Initialize all bits of 'Message Control Register' to zero */
// Some bits of MSGCTRL register come up in an unknown state. For proper operation,
// all bits (including reserved bits) of MSGCTRL must be initialized to zero
ECanaMboxes.MBOX0.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX1.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX2.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX3.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX4.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX5.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX6.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX7.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX8.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX9.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX10.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX11.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX12.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX13.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX14.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX15.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX16.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX17.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX18.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX19.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX20.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX21.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX22.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX23.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX24.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX25.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX26.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX27.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX28.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX29.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX30.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX31.MSGCTRL.all = 0x00000000;
// TAn, RMPn, GIFn bits are all zero upon reset and are cleared again
// as a matter of precaution.
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;
/* Configure bit timing parameters for eCANA*/
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.CCR = 1 ; // Set CCR = 1
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
// Wait until the CPU has been granted permission to change the configuration registers
do
{
ECanaShadow.CANES.all = ECanaRegs.CANES.all;
} while(ECanaShadow.CANES.bit.CCE != 1 ); // Wait for CCE bit to be set..
ECanaShadow.CANBTC.all = 0;
/* The following block is for 80 MHz SYSCLKOUT. (40 MHz CAN module clock Bit rate = 100 Kbps
See Note at end of file. */
ECanaShadow.CANBTC.bit.BRPREG = 29;
ECanaShadow.CANBTC.bit.TSEG2REG = 2;
ECanaShadow.CANBTC.bit.TSEG1REG = 10;
ECanaShadow.CANBTC.bit.SAM = 1;
ECanaRegs.CANBTC.all = ECanaShadow.CANBTC.all;
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.CCR = 0 ; // Set CCR = 0
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
// Wait until the CPU no longer has permission to change the configuration registers
do
{
ECanaShadow.CANES.all = ECanaRegs.CANES.all;
} while(ECanaShadow.CANES.bit.CCE != 0 ); // Wait for CCE bit to be cleared..
/* Disable all Mailboxes */
ECanaRegs.CANME.all = 0; // Required before writing the MSGIDs
EDIS;
}
void xd_halCAN_init(void)
{
struct ECAN_REGS ECanaShadow;
InitECanGpio();
MessageReceivedCount = 0;
ErrorCount = 0;
PassCount = 0;
InitECana(); // Initialize eCAN-A module CANMC
EALLOW;
ECanaShadow.CANGAM.all = ECanaRegs.CANGAM.all;
ECanaShadow.CANGAM.bit.AMI = 0; // Standard and extended frames can be received.接收标识符位必须与MSGID寄存器一致
ECanaRegs.CANGAM.all = ECanaShadow.CANGAM.all;
EDIS;
EALLOW;
ECanaMboxes.MBOX1.MSGID.bit.IDE = 1;
ECanaMboxes.MBOX1.MSGID.bit.AAM =0;
ECanaMboxes.MBOX1.MSGID.bit.AME =0;
ECanaMboxes.MBOX30.MSGID.bit.IDE =1;
ECanaMboxes.MBOX30.MSGID.bit.AAM =0;
ECanaMboxes.MBOX30.MSGID.bit.AME =0;
ECanaMboxes.MBOX1.MSGCTRL.bit.RTR = 0; //无远程帧
ECanaMboxes.MBOX30.MSGCTRL.bit.RTR = 0;
ECanaMboxes.MBOX29.MSGCTRL.bit.RTR = 0;
ECanaMboxes.MBOX28.MSGCTRL.bit.RTR = 0;
ECanaMboxes.MBOX27.MSGCTRL.bit.RTR = 0;
ECanaMboxes.MBOX26.MSGCTRL.bit.RTR = 0;
EDIS;
EALLOW;
ECanaShadow.CANMD.all = ECanaRegs.CANMD.all;
ECanaShadow.CANMD.all = 0xFFFF0000;
ECanaRegs.CANMD.all = ECanaShadow.CANMD.all;
ECanaShadow.CANME.all = ECanaRegs.CANME.all;
ECanaShadow.CANME.all = 0xFFFFFFFF;
ECanaRegs.CANME.all = ECanaShadow.CANME.all;
// Configure the eCAN for self test mode
// Enable the enhanced features of the eCAN.
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.STM = 0; // Configure CAN for self-test mode
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
EDIS;
//中断配置
EALLOW;
ECanaShadow.CANMIM.all = ECanaRegs.CANMIM.all;
ECanaShadow.CANMIM.all = 0xFFFF0000;
ECanaRegs.CANMIM.all = ECanaShadow.CANMIM.all;
ECanaShadow.CANMIL.all = ECanaRegs.CANMIL.all;
ECanaShadow.CANMIL.all = 0; //level0
ECanaRegs.CANMIL.all = ECanaShadow.CANMIL.all;
ECanaShadow.CANGIM.all = ECanaRegs.CANGIM.all;
ECanaShadow.CANGIM.bit.I0EN = 1; //can0init
ECanaRegs.CANGIM.all = ECanaShadow.CANGIM.all;
EDIS;
EALLOW;
PieVectTable.ECAN0INTA = &xd_halCAN_RxFifoIsr;
PieCtrlRegs.PIEIER9.bit.INTx5 = 1; // PIE Group 9, Ecan1 CAN-A
IER |= M_INT9;
EDIS;
}
//发送数据,发送数据的邮箱ID在初始化中设置完成,接收邮箱ID也在此处更改,
void xd_Pump_can_Send_Data(unsigned int e_id ,unsigned char* data, unsigned char size)
{
unsigned int i =0;
pump_tx_len =size;
ECanaRegs.CANME.all = 0; //此处必须打开
ECanaMboxes.MBOX30.MSGID.all = e_id ; //此处根据需要更改为接收信号的ID号。
ECanaRegs.CANME.all = 0xFFFFFFFF; //此处必须关闭
ECanaMboxes.MBOX1.MSGCTRL.bit.DLC = size;
switch(pump_tx_len)
{
case 8:
ECanaMboxes.MBOX1.MDH.byte.BYTE7 = data[7];
case 7:
ECanaMboxes.MBOX1.MDH.byte.BYTE6 = data[6];
case 6:
ECanaMboxes.MBOX1.MDH.byte.BYTE5 = data[5];
case 5:
ECanaMboxes.MBOX1.MDH.byte.BYTE4 = data[4];
case 4:
ECanaMboxes.MBOX1.MDL.byte.BYTE3 = data[3];
case 3:
ECanaMboxes.MBOX1.MDL.byte.BYTE2 = data[2];
case 2:
ECanaMboxes.MBOX1.MDL.byte.BYTE1 = data[1];
case 1:
ECanaMboxes.MBOX1.MDL.byte.BYTE0 = data[0];
break;
default:break;
}
ECanaRegs.CANTRS.all = 0x00000002; // Set TRS for all transmit mailboxes
while(ECanaRegs.CANTA.all != 0x00000002)//;// Wait for all TAn bits to be set..
{
if(i>5000)
{
break;
}
++i;
}
ECanaRegs.CANTA.all = 0x00000002; // Clear all TAn
ECanaRegs.CANRMP.bit.RMP30 = 0 ;
}
__interrupt void xd_halCAN_RxFifoIsr(void) // ECAN-A
{
// g_halCanCfg.RcvTimeout.timeoutEnable = XD_TRUE;
if(ECanaRegs.CANRMP.bit.RMP30 == 1)
{
pump_msgid = 0;
pump_rcvLen = 0;
pump_rcvBuf[7] = 0;
pump_rcvBuf[6] = 0;
pump_rcvBuf[5] = 0;
pump_rcvBuf[4] = 0;
pump_rcvBuf[3] = 0;
pump_rcvBuf[2] = 0;
pump_rcvBuf[1] = 0;
pump_rcvBuf[0] = 0;
pump_msgid = (ECanaMboxes.MBOX30.MSGID.all & 0x1FFFFFFF);
pump_rcvLen = ECanaMboxes.MBOX30.MSGCTRL.bit.DLC;
switch(pump_rcvLen)
{
case 0x08:
pump_rcvBuf[7] = ECanaMboxes.MBOX30.MDH.byte.BYTE7;
case 0x07:
pump_rcvBuf[6] = ECanaMboxes.MBOX30.MDH.byte.BYTE6;
case 0x06:
pump_rcvBuf[5] = ECanaMboxes.MBOX30.MDH.byte.BYTE5;
case 0x05:
pump_rcvBuf[4] = ECanaMboxes.MBOX30.MDH.byte.BYTE4;
case 0x04:
pump_rcvBuf[3] = ECanaMboxes.MBOX30.MDL.byte.BYTE3;
case 0x03:
pump_rcvBuf[2] = ECanaMboxes.MBOX30.MDL.byte.BYTE2;
case 0x02:
pump_rcvBuf[1] = ECanaMboxes.MBOX30.MDL.byte.BYTE1;
case 0x01:
pump_rcvBuf[0] = ECanaMboxes.MBOX30.MDL.byte.BYTE0;
}
}
if(pumpCommFunc)
{
pumpCommFunc(pump_msgid,pump_rcvBuf,pump_rcvLen); //回调函数返回数据
}
ECanaRegs.CANRMP.bit.RMP30 = 1;
ECanaMboxes.MBOX30.MDL.all &= 0x00000000;
PieCtrlRegs.PIEACK.all |= M_INT9; // Issue PIE ACK
}
注意事项:
- 波特率计算,CAN位时序如下:
波特率计算公式如上,其中BRP=BRPreg+1 (CANBTC.23-16)。
Bit-time = (TSEG1reg + 1) + (TSEG2reg + 1) + 1
2.程序当中,要修改邮箱ID号(MSGID),必须将ECanaRegs.CANME.all=0,修改完ID后,ECanaRegs.CANME.all=0xFFFFFFFF。
3.数据帧由7个段(Field)构成,分别为帧起始,仲裁段,控制段,数据段,CRC段,ACK段和帧结束。遥控帧由6个段构成,即数据帧的7个段去除数据段。
当发送数据为0x0008019E, 00 ,02。其中ID号为0x0008019E,数据为0x00、0x02,长度为2。使用示波器测试CAN帧数据,示波器电源不接地线,表笔高接CANH,夹子接CANL,发示波器观察时序如下:
- CAN协议结构帧中连续出现5个高电平时,需插入一个低电平,如表中红色0。
- 高电平为显性,逻辑为0,低电平为隐形,逻辑为1。
- 由于未接其他CAN设备,后面CRC、ACK段、帧结束段没有。