基于DSP28335的CAN通信(附代码)

目录

  • 问题描述
  • 配置步骤
  • 初始化
  • 配置引脚和邮箱
  • 中断配置
  • 注意事项
  • 移植代码时输入输出引脚的改变
  • 波特率选择
  • Bit Rate计算
  • CAN模块代码
  • CAN初始化
  • CAN接受中断
  • 问题描述

    在学DSP28335的时候由于寄存器数量多且配置复杂,网上各路大神给出的代码基本上都不太能跑的通(可能是我移植的时候有些寄存器没配置好),所以在看了好几遍官方数据手册并且自己动手写了一遍代码之后,将一些容易错的地方记录了下来,文末也附上了一份代码,希望能对大家有所帮助,也欢迎各位一起谈论。

    配置步骤

    初始化

    初始化主要是配置BRPREG和BT,这里需要注意的是CCR和CCE这两个位的读和写,具体流程图参考官方数据手册中给出的初始化流程,这里我也截图放在下面了。
    CAN模块初始化流程

    配置引脚和邮箱

    这一步就是根据需求配置发送接收引脚和输入输出邮箱,比较简单。

    中断配置

    中断的配置算是有些复杂的,下面结合官方数据手册中的中断结构图进行说明。
    CAN中断结构图
    以接收中断为例进行说明。当接收到消息后RMP会被硬件置位,此时想要把成功接收的信息传达给中断线需要经过三个开关。第一个开关是CANMIM[x],这个位是中断使能位,如果被置位就说明RMP被置位后就会引起中断;第二个开关是CANMIL[x],这个位用来选择将前一个开关带来的接收成功的消息送到中断线0还是中断线1,因为CAN模块有两根中断线,所以要这第二个开关进行一个选择,与此同时对应中断标志位GMIF会被置位;最后一个开关是CANGIM,是用来选择是否将中断线接到CPU上去(这个说法不准确,但是可以先这样理解)。总之仔细看看这张图大概就能知道中断应该怎么配了。
    同时在接收中断函数中,中断标志位的清除是通过向CANRMP对应位写1实现的,而无法通过GIFx.GMFx位实现。

    注意事项

    移植代码时输入输出引脚的改变

    TI官方例程中将GPIO16、GPIO17分别配置成了ECanb的发送和接收引脚,进行代码移植时要注意自己开发板CAN模块的引脚是否与例程一致,不一致则要进行修改。

    波特率选择

    不同CAN通信设备的带宽是不一样的,要根据实际需求配置CAN总线的波特率,并且必须保证各个结点的波特率一致。

    Bit Rate计算

    上面说到了要根据实际需求配置CAN总线的波特率,那么应该怎么算呢,官方数据手册是这样给的:
    Bit Rate计算公式
    Bit-time计算公式

    CAN模块代码

    CAN初始化

    void ECAN_Init(void)
    {
        struct ECAN_REGS ECanbShadow;
    
        //配置引脚
        EALLOW;
        GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 2;
        GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 2;
        GpioCtrlRegs.GPAPUD.bit.GPIO16  = 0;
        GpioCtrlRegs.GPAPUD.bit.GPIO17  = 0;
        GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3;
        EDIS;
    
        //配置引脚用于CAN
        EALLOW;
        ECanbShadow.CANTIOC.all = ECanbRegs.CANTIOC.all;
        ECanbShadow.CANTIOC.bit.TXFUNC = 1;
        ECanbRegs.CANTIOC.all = ECanbShadow.CANTIOC.all;
    
        ECanbShadow.CANRIOC.all = ECanbRegs.CANRIOC.all;
        ECanbShadow.CANRIOC.bit.RXFUNC = 1;
        ECanbRegs.CANRIOC.all = ECanbShadow.CANRIOC.all;
        EDIS;
    
        ECanbRegs.CANME.all = 0;
    
        //接收邮箱
        ECanbMboxes.MBOX0.MSGID.all  = 0x9555AAA0;
        ECanbMboxes.MBOX1.MSGID.all  = 0x9555AAA1;
        ECanbMboxes.MBOX2.MSGID.all  = 0x9555AAA2;
        ECanbMboxes.MBOX3.MSGID.all  = 0x9555AAA3;
        ECanbMboxes.MBOX4.MSGID.all  = 0x9555AAA4;
        ECanbMboxes.MBOX5.MSGID.all  = 0x9555AAA5;
    
        //发送邮箱
        ECanbMboxes.MBOX16.MSGID.all = 0x9555AAB0;
        ECanbMboxes.MBOX17.MSGID.all = 0x9555AAB1;
        ECanbMboxes.MBOX18.MSGID.all = 0x9555AAB2;
        ECanbMboxes.MBOX19.MSGID.all = 0x9555AAB3;
    
        EALLOW;
        ECanbShadow.CANMD.all = ECanbRegs.CANMD.all;
        ECanbShadow.CANMD.bit.MD0  = 1;  //Rx
        ECanbShadow.CANMD.bit.MD1  = 1;  //Rx
        ECanbShadow.CANMD.bit.MD2  = 1;  //Rx
        ECanbShadow.CANMD.bit.MD3  = 1;  //Rx
        ECanbShadow.CANMD.bit.MD4  = 1;  //Rx
        ECanbShadow.CANMD.bit.MD5  = 1;  //Rx
    
        ECanbShadow.CANMD.bit.MD16 = 0;  //Tx
        ECanbShadow.CANMD.bit.MD17 = 0;  //Tx
        ECanbShadow.CANMD.bit.MD18 = 0;  //Tx
        ECanbShadow.CANMD.bit.MD19 = 0;  //Tx
        ECanbRegs.CANMD.all = ECanbShadow.CANMD.all;
    
        ECanbShadow.CANME.all = ECanbRegs.CANME.all;
        ECanbShadow.CANME.bit.ME0  = 1;
        ECanbShadow.CANME.bit.ME1  = 1;
        ECanbShadow.CANME.bit.ME2  = 1;
        ECanbShadow.CANME.bit.ME3  = 1;
        ECanbShadow.CANME.bit.ME4  = 1;
        ECanbShadow.CANME.bit.ME5  = 1;
        ECanbShadow.CANME.bit.ME16 = 1;
        ECanbShadow.CANME.bit.ME17 = 1;
        ECanbShadow.CANME.bit.ME18 = 1;
        ECanbShadow.CANME.bit.ME19 = 1;
        ECanbRegs.CANME.all = ECanbShadow.CANME.all;
        EDIS;
    
        ECanbMboxes.MBOX0.MSGCTRL.bit.DLC  = 8;
        ECanbMboxes.MBOX1.MSGCTRL.bit.DLC  = 8;
        ECanbMboxes.MBOX2.MSGCTRL.bit.DLC  = 8;
        ECanbMboxes.MBOX3.MSGCTRL.bit.DLC  = 8;
        ECanbMboxes.MBOX4.MSGCTRL.bit.DLC  = 8;
        ECanbMboxes.MBOX5.MSGCTRL.bit.DLC  = 8;
        ECanbMboxes.MBOX16.MSGCTRL.bit.DLC = 8;
        ECanbMboxes.MBOX17.MSGCTRL.bit.DLC = 8;
        ECanbMboxes.MBOX18.MSGCTRL.bit.DLC = 8;
        ECanbMboxes.MBOX19.MSGCTRL.bit.DLC = 8;
    
        ECanbMboxes.MBOX16.MSGCTRL.bit.RTR  = 0;
        ECanbMboxes.MBOX17.MSGCTRL.bit.RTR  = 0;
        ECanbMboxes.MBOX18.MSGCTRL.bit.RTR  = 0;
        ECanbMboxes.MBOX19.MSGCTRL.bit.RTR  = 0;
    
    
        EALLOW;
        ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;
        ECanbShadow.CANMC.bit.CCR = 1;
        ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;
        EDIS;
        do
        {
            ECanbShadow.CANES.all = ECanbRegs.CANES.all;
        }while(ECanbShadow.CANES.bit.CCE != 1 );
    
        EALLOW;
        ECanbShadow.CANBTC.all = ECanbRegs.CANBTC.all;
        ECanbShadow.CANBTC.bit.BRPREG = 9;
        ECanbShadow.CANBTC.bit.TSEG2REG = 2 ;
        ECanbShadow.CANBTC.bit.TSEG1REG = 10;  // Bit time = 15
        ECanbShadow.CANBTC.bit.SAM = 1;
        ECanbRegs.CANBTC.all = ECanbShadow.CANBTC.all;
    
        ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;
        ECanbShadow.CANMC.bit.CCR = 0;
        ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;
        EDIS;
        do
        {
          ECanbShadow.CANES.all = ECanbRegs.CANES.all;
        } while(ECanbShadow.CANES.bit.CCE != 0 );
    
        ECanbRegs.CANTA.all = 0xFFFFFFFF;  //清除所有TA位
    
        EALLOW;
        ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;
        ECanbShadow.CANMC.bit.STM = 0;    
        ECanbShadow.CANMC.bit.SCB = 1;    // eCAN mode (reqd to access 32 mailboxes)
        ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;
        EDIS;
    
        EALLOW;
        ECanbRegs.CANGIM.all = 0;
        ECanbRegs.CANMIM.all = 0x003F;  //使能上面的接收邮箱(0-5号邮箱)中断
        ECanbRegs.CANMIL.all = 0;
    
        ECanbShadow.CANGIM.all = ECanbRegs.CANGIM.all;
        ECanbShadow.CANGIM.bit.I0EN = 1;  //选择中断线0
        ECanbRegs.CANGIM.all = ECanbShadow.CANGIM.all;
    
        PieCtrlRegs.PIECTRL.bit.ENPIE=1;
        PieCtrlRegs.PIEIER9.bit.INTx7=1;  //9.7
        PieVectTable.ECAN0INTB = &ISRECanRx;
        IER|=M_INT9;
        EINT;
        EDIS;
    }
    

    CAN接受中断

    interrupt void ISRECanbRx(void)
    {
    
        PieCtrlRegs.PIEACK.bit.ACK9 = 1;
    
        struct ECAN_REGS ECanbShadow;
        Uint16 group;
        Uint32 high;  //用于存储接收邮箱的内容
        Uint32 low;   //用于存储接收邮箱的内容
        volatile struct MBOX* Mailbox;
        group = (ECanbRegs.CANGIF0.all)&0x3F;   //判断是哪个接收邮箱触发的中断
        Mailbox = &ECanbMboxes.MBOX0 + group;   //取触发中断邮箱的地址
        switch(group)  //我这里是把0-5号邮箱配置成了接收邮箱,所以下面case的取值是0-5
        {
        case 0:
            low     = Mailbox->MDL.all    //低32位
            high    = Mailbox->MDH.all    //高32位
            break;
        case 1:
            //跟上面是一样的,把邮箱里的数取出来
            break;
        case 2:
    
            break;
        case 3:
    
            break;
        case 4:
    
            break;
        case 5:
    
            break;
        default:
            break;
        }
        ECanbRegs.CANRMP.all = 0x0000003F;   //清除GIF0.GMIF位,即中断标志位
    }
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » 基于DSP28335的CAN通信(附代码)

    发表评论