TMS320x280x_2801x Piccolo eCAN 开发笔记(代码基于F28069)

TMS320x280x_2801x Piccolo eCAN 开发笔记(主要基于F28069)

eCAN特性:

  • 与CAN 协议,版本2.0B 完全兼容
  • 支持高达1Mbps 的数据速率
  • 拥有32 个邮箱,每个邮箱都可配置为以下四种消息对象:
    (1)发送消息对象 --------》 只能传输消息
    (2)接收消息对象 --------》 只能接收消息
    (3)远程请求消息对象 ---------》用于发送远程请求帧,并等待接收另一个节点返回的相应数据帧
    (4)自动应答消息对象 ---------》此模式下当邮箱接收到相应的请求帧后,便会自动发送应答的数据帧
    (说明:通过第1,2点的对象,加自己写代码处理数据,也能实现后两者的功能。STM32的CAN模块就只有第1,2点的对象。第3,4点的对象的好处是可以减轻CPU处理消息的负担。)

eCAN结构:

在这里插入图片描述

  • eCAN 模块的架构,如图所示,是由一个CAN协议内核(CPK) 和一个消息控制器组成。
  • 根据CAN 协议,CPK 的两个功能的是解码在CAN 总线上接收到的所有消息,并把这些消息转移到接收缓冲器。CPK 的另一个功能是根据CAN 协议传输CAN 总线上的消息。
  • CAN 控制器的消息控制器是负责确定CPK 接收到的任何信息是否必须被保留以便用于CPU 使用还是被丢弃。在初始化阶段,CPU 指定消息控制器应用所使用的所有消息标识符。根据消息的优先级,消息控制器还负责发送下一条消息传输到CPK。

eCAN模式

  • SCC模式
    SCC 模式是eCAN 的一种精简功能模式。在这种模式下,只有16 个邮箱(0 到15)可用。不提供时 间戳功能,并且可用的接受屏蔽数量也被减少。缺省情况下,这种模式被选中。通过SCB 位
    (CANMC.13),SCC 模式或功能齐全的eCAN 模式被选择。
  • eCAN模式
    此模式下可以使用32个邮箱,并且每个邮箱都配有一个标识符屏蔽器,非常强大方便。本次实验实验eCAN模式。

控制和状态寄存器的32 位访问

需要注意,eCAN模块的控制和状态寄存器只允许32 位访问。
这些寄存器的16 位访问可能会破坏该寄存器的内容或返回错误数据。

这时可以自己定义一个影子寄存器来进行配置,影子寄存器没有位访问限制,配置好影子寄存器后,在给控制和状态寄存器赋值即可。
例如:

//写操作
ECanaShadow.CANTIOC.all = ECanaRegs.CANTIOC.all; // 执行一个32 位读取以复制整个寄存器内容到它的影子寄存器中
ECanaShadow.CANTIOC.bit.TXFUNC = 1; // 修改影子寄存器中所需要的一个或多个位
ECanaRegs.CANTIOC.all = ECanaShadow.CANTIOC.all; // 执行一个32 位写入以复制修改后的影子寄存器内容到原始寄存器中。

//读操作
// 首先复制整个CANTA 寄存器到它的影子寄存器(使用32 位读取),然后检查相关位,重复此操作,直到该条件得到满足。
do
{
ECanaShadow.CANTA.all = ECanaRegs.CANTA.all;
} while(ECanaShadow.CANTA.bit.TA25 == 0); 

消息邮箱

消息邮箱是RAM 区域,这些区域就是消息被接收后或被传输前CAN 信息实际存储的地方。
CPU 可将消息邮箱中不被用来存储消息的RAM 区用作普通内存。
每个邮箱包含:

  • 消息标识符
    – 29 位扩展标识符
    – 11 位标准标识符
  • 标识符扩展位,IDE (MSGID.31)
  • 接受屏蔽使能位,AME (MSGID.30)
  • 自动应答模式位,AAM (MSGID.29)
  • 发送优先级,TPL (MSGCTRL.12-8)
  • 远程传输请求位,RTR (MSGCTRL.4)
  • 数据长度代码,DLC (MSGCTRL.3-0)
  • 多达8 字节的数据区字段

邮箱消息对象的配置如下
在这里插入图片描述
我这里只使用第1,第2种对象。

发送邮箱:
  • CPU 将要发送的数据存储在一个配置为发送邮箱的邮箱中。在把数据和标识符写入到RAM 中后,如果相应的TRS[n] 位已设置,假如通过设置相应的CANME.n 位邮箱被启用的话,则消息被发送。
    如果不止一个邮箱被设为发送邮箱,并且不止一个TRS[n] 位被置位,则消息从具有最高优先级的邮箱按照优先级下降的次序依次发送。
  • 在SCC 兼容模式下,邮箱传输的优先级取决于邮箱号。最高的邮箱号(=15) 包含最高优先级。
    在eCAN 模式下,邮箱传输的优先级取决于消息控制器字段(MSGCTRL) 寄存器中的TPL 字段的设置。具有最高TPL 值的邮箱首先被发送。只有当在两个邮箱的TPL 值相同时,更高号码的邮箱首先发送。
  • 如果一个传输由于仲裁丢失或错误而失败,则消息将重新尝试传输。在重新传输前,CAN 模块检查是否有另外一个传输被请求,然后传输优先级最高的邮箱。
接收邮箱:
  • 每个进入消息的标识符与保存在使用适当屏蔽的接收邮箱内的标识符相比较。当两者匹配时,接收到的标注符,控制位和数据字节将被写进匹配的RAM 位置。同时,相应的接收消息等待位,RMPn 被设置,如果被启用则产生一个接收中断。如果未检测到匹配,则消息不存储。
    当消息接收后,消息控制器从邮箱编号最高的邮箱开始搜索一个匹配的标识符。
  • 在SCC 兼容模式下的eCAN 的邮箱15 具有最高接收优先级;在eCAN 模式下,eCAN 的邮箱31 具有最高接收优先级。
  • 在读取数据后,CPU 必须将RMP[n] (RMP.31-0) 复位。如果这个邮箱又接收到第二个消息,且接受消息等待位已经被设定,相应的消息丢失位(RML[n] (RML.31-0)) 被设置。这种情况下,如果写覆盖保护位OPC[n] (OPC.31-0) 被清除,则存储的消息被新消息写覆盖;否则,检查下一个邮箱。如果一个邮箱被设置为一个接收邮箱并且发送请求位(RTR) 被设置,则邮箱可以发送一个远程帧。一旦一个远程帧被发送,则邮箱的TRS 位被CAN 模块清除。

CAN 模块运行在正常配置中

  • 如果CAN 模块被用于正常配置下(即,非自检测模式),则网络中至少要有两个CAN 模块,且比特率设置相同。另外一个CAN 模块不必设置为真正接收来自发送节点的消息。但是,它应被设置为相同的比特率。这是因为,一个CAN 发送模块期望CAN 网络中至少一个节点确认已发送消息的正确接收。按照CAN 协议技术规范,任何接收到信息的CAN 节点将确认(除非取认机理被明确关闭),不管是否被设置为存储接收的消息。在C28x DSP 中确认机制中是不可被关闭的。
  • 在自测模式(STM) 下,不需要另外一个节点。在该模式下,一个传输节点产生自己的确认信号。唯一的要求就是节点必须配置任一有效的比特率。也就是说,位时序寄存器不应该包含一个不被CAN 协议所允许的值。
  • 不能通过将CANTX 和CANRX 引脚连接在一起实现直接外部数字回路(使用SCI/SPI/McBSP 模块是可能的)。在自检测模式(STM) 下,可实现内部回路。

eCAN模块配置

  • gpio 配置及CAN时钟使能:

GPIO31口配置用于CANTX 引脚,GPIO30口配置CANRX 引脚。开启CAN时钟。

	EALLOW;
    GpioCtrlRegs.GPAPUD.bit.GPIO30 = 0;     // Enable pull-up for GPIO30 (CANRXA)
    GpioCtrlRegs.GPAPUD.bit.GPIO31 = 0;     // Enable pull-up for GPIO31 (CANTXA)
    GpioCtrlRegs.GPAQSEL2.bit.GPIO30 = 3;   // Asynch qual for GPIO30 (CANRXA)
    GpioCtrlRegs.GPAMUX2.bit.GPIO30 = 1;    // Configure GPIO18 for CANRXA operation
    GpioCtrlRegs.GPAMUX2.bit.GPIO31 = 1;    // Configure GPIO19 for CANTXA operation
    
    SysCtrlRegs.PCLKCR0.bit.ECANAENCLK =1;  //CAN时钟使能
    
    ECanaShadow.CANTIOC.all=ECanaRegs.CANTIOC.all;
    ECanaShadow.CANTIOC.bit.TXFUNC=1; //CANTX 引脚被用于CAN 传输功能
    ECanaRegs.CANTIOC.all=ECanaShadow.CANTIOC.all;

    ECanaShadow.CANRIOC.all=ECanaRegs.CANRIOC.all;
    ECanaShadow.CANRIOC.bit.RXFUNC=1; //CANTX 引脚被用于CAN 接收功能。
    ECanaRegs.CANRIOC.all=ECanaShadow.CANRIOC.all;
    EDIS;
CAN 模块进入初始化模式
  • 必须进入初始化模式,才能更改全局接受屏蔽寄存器(CANGAM)和两个本地接受屏蔽寄存器[LAM(0) 和LAM(3)]。CAN 模块也必须在初始化模式中设定。
  • 编辑CCR (CANMC.12)=1 设定初始化模式。只有在CCE(CANES.4)=1 时,才可以进行初始化。
  • 进入初始化模式后,如果CANBTC 寄存器被编程为0 值,或保留为初始值,CAN 模块无法离开初始化模式,当清除CCR 位时,CCE (CANES.4) 位仍为1。
CAN 位时序配置及eCAN模块配置
  • IPT(信息处理时间)对应位读取处理所需的时间。IPT 对应TQ 的两个单位。
  • 确定位段值时必须满足以下的位定时规则:
    TSEG1(最小)≥TSEG2
    IPT≤TSEG1≤16TQ
    IPT≤TSEG2≤8TQ
    IPT = 3/BRP(由此产生IPT 必须四舍五入到下一个整数值)
    1T Q≤ SJW 的最小值[4 TQ,TSEG2](SJW = 同步跳转宽度)
    为了使用三次采样模式,必须选定BRP≥5
    在这里插入图片描述
  • CAN 比特率计算:
    比特率乃按每秒比特计算,如下:
    在这里插入图片描述
    在这里,位时间是每比特时间定额(TQ)数量。SYSCLKOUT 是CAN 模块系统的时钟频率,与CPU 的时钟频率一样。BRP = BRPreg+1 的值。
    位时间定义如下:
    Bit-time = (TSEG1reg + 1) + (TSEG2reg + 1) + 1
    在上述方程式中,TESG1reg和TSEG2reg表示实际写入到CANBTC寄存器中相应字段的值。当CAN 模块访问TSEG1reg,TSEG2reg,SJWreg以及BRPreg的这些参数时,它们会自动增加1。
    SJW:主要是TSEG1和TSEG2每次延长或缩短的尺度。不理解也无所谓,只要在1Tq到4个Tq之间取值即可。
配置步骤如下
  • 1,设置CCR=1进入初始化模式,需要判断是否进入了初始化模式(CCE=1)。
  • 2,使用适当的时序值对CANBTC 寄存器进行配置。配置出需要的比特率。
  • 3,(eCAN模式无需理会此步)对于SCC 模式,现在对接受屏蔽寄存器编程。例如:写入LAM(3)=0x3C0000
  • 4,对主控制寄存器(CANMC) 进行如下编程:
    (a) 清除CCR (CANMC.12) = 0 //CCR=0,设定退出初始化模式
    (b) 清除PDR (CANMC.11) = 0
    © 清除DBO (CANMC.10) = 0
    (d) 清除WUBA (CANMC.9)= 0
    (e) 清除CDR (CANMC.8) = 0
    (f) 清除ABO (CANMC.7) = 0
    (g) 清除STM (CANMC.6) = 0 //1-自测模式; 0-正常模式 (建议先进行自测模式验证)
    (h) 清除SRES (CANMC.5) = 0
    (i) 清除MBNR (CANMC.4-0) = 0
    (j)置位SCB=1; //选择eCAN模式
    5,将MSGCTRLn 寄存器的所有位初始化为零。
    6,等待退出初始化模式成功(CCE=0)。
    这就完成了基本功能的设置。
    注意:brq,sjw,tseg1,tseg2的值需要根据你所需的比特率来选取填入。
	struct ECAN_REGS ECanaShadow;	//需要在前面定义影子寄存器

/*****************CAN进入初始化模式*****************/
	EALLOW;
     ECanaShadow.CANMC.all =ECanaRegs.CANMC.all;
     ECanaShadow.CANMC.bit.CCR=1; //CCR=1,设定进入初始化模式
     ECanaRegs.CANMC.all =ECanaShadow.CANMC.all;

     do
     {
        ECanaShadow.CANES.all =ECanaRegs.CANES.all;
     }while(ECanaShadow.CANES.bit.CCE==0); //等待CCE置1,进入初始化模式成功
/*****************位时序配置*****************/
    ECanaShadow.CANBTC.all =ECanaRegs.CANBTC.all;
    ECanaShadow.CANBTC.all =0;
    ECanaShadow.CANBTC.bit.BRPREG =brq;
    ECanaShadow.CANBTC.bit.SJWREG =sjw;
    ECanaShadow.CANBTC.bit.TSEG1REG =tseg1;
    ECanaShadow.CANBTC.bit.TSEG2REG =tseg2;
    if(brq>3) ECanaShadow.CANBTC.bit.SAM=1; //1-CAN 模块三次取样后进行取多数决定。只有当比特率预分频值大于4 时(BRP>4) 选择三重采样样本模式。
                                            //0-在采样点上CAN 模块只能采样一次。
    ECanaRegs.CANBTC.all =ECanaShadow.CANBTC.all;
    
/*****************eCAN配置*****************/
    ECanaShadow.CANMC.all =ECanaRegs.CANMC.all;
    ECanaShadow.CANMC.bit.SCB=1; //选择eCAN模式
    ECanaShadow.CANMC.bit.CCR=0; //CCR=0,设定退出初始化模式
    ECanaShadow.CANMC.bit.PDR=0;
    ECanaShadow.CANMC.bit.DBO=0;
    ECanaShadow.CANMC.bit.WUBA=0;
    ECanaShadow.CANMC.bit.CDR=0;
    ECanaShadow.CANMC.bit.ABO=0;
    ECanaShadow.CANMC.bit.STM=1; //1-自测模式; 0-正常模式
    ECanaShadow.CANMC.bit.SRES=0;
    ECanaShadow.CANMC.bit.MBNR=0;
    ECanaRegs.CANMC.all =ECanaShadow.CANMC.all;
    /* Initialize all bits of 'Message Control Register' 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;

        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;
        
    do
    {
         ECanaShadow.CANES.all = ECanaRegs.CANES.all;
    } while(ECanaShadow.CANES.bit.CCE != 0 );  //等待CCE置0,退出初始化模式成功

    ECanaRegs.CANMIM.all=0x00000000; //禁用所有邮箱中断
    ECanaRegs.CANGIM.all=0x00000000; //禁用所有全局中断
    EDIS;
配置发送邮箱及配置接收邮箱

为了传输一个消息,必须执行以下步骤(本例中以邮箱1 为例):

  1. 将CANTRS 寄存器中适当位清零:
    清除CANTRS.1=0 (向TRS 写入0 无效;相反设置TRR.1 并等待直到TRS.1 清除。)
  2. 通过清除邮箱使能(CANME)寄存器的相应位来禁用邮箱。
    清除CANME.filter1=0
  3. 加载邮箱的消息标识符(MSGID)寄存器。对于正常的发送邮箱(MSGID.30=0 和MSGID.29=0),清除AME(MSGID.30)和AAM(MSGID.29) 位。在操作过程中,该寄存器通常不会被修改。只有在邮箱被禁用时,才能把它修改。例如:
    (a) 写入MSGID(1)=0x15AC0000
    (b) 消息控制字段寄存器(MSGCTRL.3:0) DLC 字段写入数据的长度。RTR 标志通常都会被清除(MSGCTRL.4=0)。
    © 通过清除CANMD 寄存器的相应位来设置邮箱方向。
    (d) 清除CANMD.1=0
  4. 通过设置CANME 寄存器的相应位设置邮箱启用
    设置CANME.1=1
    这将邮箱1 配置为传输模式。
/*****************发送邮箱 1 配置*****************/
    ECanaShadow.CANTRR.all = ECanaRegs.CANTRR.all;
    ECanaShadow.CANTRR.bit.TRR1 =1; //清除CANTRS.1
    ECanaRegs.CANTRR.all = ECanaShadow.CANTRR.all;
    do{
        ECanaShadow.CANTRS.all = ECanaRegs.CANTRS.all;
    }while(ECanaShadow.CANTRS.bit.TRS1 == 1); //等待TRS.1清除

    ECanaShadow.CANME.all = ECanaRegs.CANME.all;
    ECanaShadow.CANME.bit.ME1=0;  //禁用邮箱1
    ECanaRegs.CANME.all = ECanaShadow.CANME.all;

    ECanaMboxes.MBOX1.MSGID.all=0x1f500006;//设置标识符ID
    ECanaMboxes.MBOX1.MSGID.bit.IDE =1;  //IDE=1,扩展帧
    ECanaMboxes.MBOX1.MSGCTRL.all=0;
    ECanaMboxes.MBOX1.MSGCTRL.bit.DLC=8;  //DLC=8,8个数据

    ECanaShadow.CANMD.all = ECanaRegs.CANMD.all;
    ECanaShadow.CANMD.bit.MD1 =0;  //1号邮箱被配置为一个发送邮箱。
    ECanaRegs.CANMD.all = ECanaShadow.CANMD.all;

    ECanaShadow.CANME.all = ECanaRegs.CANME.all;
    ECanaShadow.CANME.bit.ME1 =1;  //1号邮箱使能
    ECanaRegs.CANME.all = ECanaShadow.CANME.all;

为了配置接收邮箱,必须执行以下步骤(本例中以邮箱3 为例):

  1. 清除邮箱使能(CANME)寄存器的相应位来禁用邮箱。
    清除CANME.3=0
  2. 将所选的标识符写入相应的MSGID 寄存器。标识符扩展位必须被配置为适合预计的标识符。如果使用接受屏蔽,接受屏蔽使能(AME)位必须被设定(MSGID.30=1)。例如:
    写入MSGID(3) = 0x4f780000
  3. AME 位如果设置为1,必须设定相应的接受屏蔽。
    写入LAM(3) = 0x03c0000。
  4. 通过设置邮箱方向寄存器(CANMD.3=1) 的相应标志,将邮箱配置为一个接收邮箱。确保此操作不会影响该寄存器中的其它位。
  5. 如果邮箱中的数据受到保护,现在需要对写覆盖保护控制寄存器(CANOPC)进行编程。如果没有消息必须被丢弃,这种保护是非常有用的。如果设置了OPC,该软件必须确保一个额外的邮箱(缓冲邮箱)被配置用来存储“溢出”的消息。否则,消息可能会在没有任何通知的情况下丢失。
    写入OPC.3=1
  6. 通过设置邮箱中的使能寄存器(CANME)相应的标志来启用邮箱。这必须通过读取CANME,并写回(CANME|=0x0008) 的方法来完成以确保没有其他标志被意外更改。

对象现在被配置为接收模式。该对象的任何传入消息都将自动处理。

/*****************接收邮箱 31 配置*****************/
    //当AMI=1 时:接收邮箱的IDE 位是“无关”。接收邮箱的IDE 位被已传输消息的IDE 位写覆盖。
    ECanaShadow.CANME.all = ECanaRegs.CANME.all;
    ECanaShadow.CANME.bit.ME31=0;  //禁用邮箱31
    ECanaRegs.CANME.all = ECanaShadow.CANME.all;

    ECanaMboxes.MBOX31.MSGID.all=0x1f500006;  //设置ID
    ECanaMboxes.MBOX31.MSGID.bit.AME =1; //AME:使用相应的接受屏蔽。
    ECanaMboxes.MBOX31.MSGID.bit.AAM =0; //AAM:自动应答模式位, 0-正常传输模式;1-自动应答模式。

    ECanaLAMRegs.LAM31.all=0xe00ffff0;//1-针对接受到的标识符的相应位,接受一个0 或1(无关)。0-接收到的标识符位值必须与MSGID 寄存器的相应标识符位相匹配。
    ECanaLAMRegs.LAM31.bit.LAMI =1;   //LAMI:1-可以接收标准和扩展帧

    ECanaShadow.CANMD.all = ECanaRegs.CANMD.all;
    ECanaShadow.CANMD.bit.MD31 =1;    //31号邮箱被配置为一个接收邮箱。
    ECanaRegs.CANMD.all = ECanaShadow.CANMD.all;

    ECanaShadow.CANOPC.all = ECanaRegs.CANOPC.all;
    ECanaShadow.CANOPC.bit.OPC31 =1;    //0-旧消息就会被新消息写覆盖。1-则不会写覆盖
    ECanaRegs.CANOPC.all = ECanaShadow.CANOPC.all;

    ECanaShadow.CANME.all = ECanaRegs.CANME.all;
    ECanaShadow.CANME.bit.ME31 =1;  //31号邮箱使能
    ECanaRegs.CANME.all = ECanaShadow.CANME.all;
中断处理配置

为了配置中断处理,邮箱中断优先级寄存器(CANMIL),邮箱中断屏蔽寄存器(CANMIM),和全局中断屏蔽
寄存器(CANGIM) 都需要进行配置。配置步骤如下所述:

  1. 写入CANMIL 寄存器。这定义了将一个成功传输置为中断线路0 还是1。例如, CANMIL =
    0xFFFFFFFF 设置所有邮箱中断为1 级。
  2. 配置邮箱中断屏蔽寄存器(CANMIM) 来屏蔽掉不会引起中断的邮箱。该寄存器可以设置为0xFFFFFFFF,这将启动所有邮箱中断。未使用的邮箱无论如何不会引起任何中断。
  3. 现在配置CANGIM 寄存器。标志AAIM,WDIM,WUIM,BOIM,EPIM,和WLIM (GIM.14-9) 应一直被设置(启用这些中断)。此外,GIL (GIM.2) 位可被设置为具有邮箱中断级别之外的全局中断。I1EN(GIM.1) 和I0EN (GIM.0) 标志都应被设置以启动两条中断线路。标志RMLIM (GIM.11) 也可以根据CPU 的负载设置。
    这种配置将所有邮箱中断放置在线路1 上,将所有系统中断放置在线路0。因此,CPU 可以处理所有具有高优先级的系统中断(一直为重要中断),和具有较低优先级的邮箱中断(在其他线路上)。所有具有高优先级的消息也可以定向到中断线路0 。

下面我们来配置一下接收中断:

/*****************配置接收中断*****************/
    
    EALLOW;
    ECanaRegs.CANMIM.all=0x00000000; //禁用所有邮箱中断
    ECanaRegs.CANMIL.all=0xffffffff;    //所有邮箱中断产生在中断线路1 上。

    /*****************配置31号邮箱接收中断*****************/
    ECanaRegs.CANMIM.bit.MIM31 =1; //启用31号邮箱中断
    ECanaRegs.CANGIM.bit.I1EN =1;  //启用ECAN1INT 中断线路。
    PieVectTable.ECAN1INTA = &ecan1Isr_dasen;   //自定义中断函数
    
    EDIS;
    //开启CPU 第9组中断并使能第9组中断的第6 个小中断,即CAN1INTA
    IER |=M_INT9;
    PieCtrlRegs.PIEIER9.bit.INTx6=1;
    //使能总中断
    EINT;
    ERTM;*/

自定义的中断处理函数如下:

/*
 * eCAN自定义中断处理函数
 */
__interrupt void ecan1Isr_dasen(void)
{
    Uint8 numb;
    Uint16 IDE,RTR,len;
    Uint32 ID;
    Uint32 getflag_bit;
    char* msg_debug;
    volatile struct MBOX *Mailbox;

  
    if(ECanaRegs.CANGIF1.bit.GMIF1)	//判断是否触发邮箱成功发送或接收中断
    {

        numb=ECanaRegs.CANGIF1.bit.MIV1 ;	//获取接收到消息的邮箱号n
        getflag_bit=1;
        getflag_bit <<= numb;
        if(ECanaRegs.CANRMP.all & getflag_bit)	//判断邮箱n的接收消息等待寄存器CANRMP的RMPn=1,如果RMPn=1,代表接收到数据。
        {
            Mailbox = &ECanaMboxes.MBOX0+numb;	//获取接收到数据的邮箱n的地址指针
            IDE =(Mailbox->MSGID.bit.IDE);	//获取数据的标识符类型,IDE=1为扩展标识符,IDE=0为标志标识符
            RTR = (Mailbox->MSGCTRL.bit.RTR);	//RTR=1为远程帧,RTR=0为数据帧
            len =Mailbox->MSGCTRL.bit.DLC ;	//获取接收到的数据长度
            if(IDE)
            {
            	//扩展标识符
                ID=Mailbox->MSGID.all & 0x1fffffff;
                sprintf(NUMCHAR,"id:0X%04X%04X\r\n", (Uint16)(ID>>16),(Uint16)ID);
            }
            else
            {
            	//标志标识符
                ID=Mailbox->MSGID.bit.STDMSGID;
                sprintf(NUMCHAR,"id:%x\r\n", (Uint16)ID);

            }
            UARTa_SendString(NUMCHAR);//打印标识符

			//下面主要是把接收到的数据打印出来
                sprintf(NUMCHAR,"ide:%d\r\n", IDE);
                UARTa_SendString(NUMCHAR);

                sprintf(NUMCHAR,"rtr:%d\r\n", RTR);
                UARTa_SendString(NUMCHAR);

                sprintf(NUMCHAR,"len:%d\r\n", len);
                UARTa_SendString(NUMCHAR);

                sprintf(NUMCHAR,"rxbuf[0]:%c\r\n", Mailbox->MDL.byte.BYTE0);
                UARTa_SendString(NUMCHAR);

                sprintf(NUMCHAR,"rxbuf[1]:%c\r\n", Mailbox->MDL.byte.BYTE1);
                UARTa_SendString(NUMCHAR);

                sprintf(NUMCHAR,"rxbuf[2]:%c\r\n", Mailbox->MDL.byte.BYTE2);
                UARTa_SendString(NUMCHAR);

                sprintf(NUMCHAR,"rxbuf[3]:%c\r\n", Mailbox->MDL.byte.BYTE3);
                UARTa_SendString(NUMCHAR);

                sprintf(NUMCHAR,"rxbuf[4]:%c\r\n", Mailbox->MDH.byte.BYTE4);
                UARTa_SendString(NUMCHAR);

                sprintf(NUMCHAR,"rxbuf[5]:%c\r\n", Mailbox->MDH.byte.BYTE5);
                UARTa_SendString(NUMCHAR);

                sprintf(NUMCHAR,"rxbuf[6]:%c\r\n", Mailbox->MDH.byte.BYTE6);
                UARTa_SendString(NUMCHAR);

                sprintf(NUMCHAR,"rxbuf[7]:%c\r\n", Mailbox->MDH.byte.BYTE7);
                UARTa_SendString(NUMCHAR);

                
                ECanaRegs.CANRMP.all |= getflag_bit;  /* 清楚对应的RMPn位,给其置1就可以清除 */
                while(ECanaRegs.CANRMP.all & getflag_bit);	//判断是否已经清除
                sprintf(NUMCHAR,"clear RMP%d=0. \r\n", numb);
                UARTa_SendString(NUMCHAR);	//打印清除成功的消息
        }
        else
        {
        //出错了
            sprintf(NUMCHAR,"error number : %d.\r\n\0",numb);
            UARTa_SendString(NUMCHAR);
            ECanaRegs.CANRMP.all=0xffffffff;
        }

        while(ECanaRegs.CANGIF1.bit.GMIF1==1);	//判断中断标志是否清除,RMPn清除后,GMIF1便会跟着被清除
        msg_debug="clear GMIF1=0. \r\n\0";
        UARTa_SendString(msg_debug);//打印清除成功的消息
    }

    //ECanaRegs.CANGIF1.all=0;

    EALLOW;
    PieCtrlRegs.PIEACK.bit.ACK9=1;//清除中断9的响应位
    EDIS;
}
传输一个消息

为了开始一个传输(在这个例子中,对于邮箱:

  1. 将消息数据写入邮箱数据字段。
    (a) 由于在配置时,DBO (MC.10) 设置为零,MSGCTRL(1) 设置为2,数据存储在CANMDL(1) 2 个最有效字节中。
    (b) 写入CANMDL(1) = xxxx0000h
  2. 在发送请求寄存器中设定相应的标志(CANTRS.1=1) 来启动的消息传输。现在CAN 模块处理CAN 消息的完整传输。
  3. 等待,直到相应邮箱的发送确认标志被设置(TA.1=1)。成功传输后,CAN 模块设置此标志。
  4. 传输成功或中止传输后,模块将TRS 标志复位为0 (TRS.1=0)。
  5. 为了下一个传输(从同一邮箱)发送确认必须清除。
    (a) 设置TA.1=1
    (b) 等到TA 读取为0
  6. 要在同一邮箱发送另一条消息,邮箱RAM 中的数据必须更新。设置TRS.1 标志来启动下一个传输。写入邮箱RAM 中的可以是半字(16 位)或整字(32 位),但模块总是从偶数边界返回32 位。CPU 必须接受所有32 位或其中的一部分。

下面我们来编写代码,发送一个消息,看看能不能被中断接收到。

			struct ECAN_REGS ECanaShadow;
			//设置将要发送的数据,使用刚配置好的邮箱1
			ECanaMboxes.MBOX1.MDH.byte.BYTE7='1';
            ECanaMboxes.MBOX1.MDH.byte.BYTE6='2';
            ECanaMboxes.MBOX1.MDH.byte.BYTE5='3';
            ECanaMboxes.MBOX1.MDH.byte.BYTE4='4';
            ECanaMboxes.MBOX1.MDL.byte.BYTE3='D;
            ECanaMboxes.MBOX1.MDL.byte.BYTE2='C;
            ECanaMboxes.MBOX1.MDL.byte.BYTE1='B;
            ECanaMboxes.MBOX1.MDL.byte.BYTE0=‘A’;

            ECanaShadow.CANTRS.all =ECanaRegs.CANTRS.all;
            ECanaShadow.CANTRS.bit.TRS1 =1;  //启动发送
            ECanaRegs.CANTRS.all =ECanaShadow.CANTRS.all;
            do
            {
                ECanaShadow.CANTA.all = ECanaRegs.CANTA.all;
            } while((ECanaShadow.CANTA.bit.TA1) == 0 );   // 等待发送成功

            ECanaShadow.CANTA.all=0;
            ECanaShadow.CANTA.bit.TA1 =1;   //给其置1,清除TA标志位,为下次发送做准备
            ECanaRegs.CANTA.all = ECanaShadow.CANTA.all;

ok,到这步设置已经完成。

总结

  • 把代码烧录到芯片TMS320F28069后,由于设置为自测模式,无需接线,运行起来后就可以用串口助手打印出你发送的数据了。
  • 在实验中,我发现F28069的eCAN工作在自测模式下时,接收邮箱似乎不把接收到消息的标识符存储进去,只接收了数据。打印出来的标识符依旧是我设置接收邮箱时输入的标识符。对于接收邮箱的标识符和屏蔽器,我修改了几个不同的值,都出现这个问题。但是工作在正常模式下,接收确是正确的。对这个问题存有疑问。
  • 注意,上面的串口函数,需要各位自己编写,我这里不列举出来。里面涉及很多寄存器,限于篇幅没有细讲。各位可以到TI官网去下载相应的参考手册,阅读里面的寄存器用法。我也是刚学CAN通讯一个星期多的新手,写得有误之处请多多包涵。谢谢。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木龠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值