DSP中eCAN模块与上位机通信调试记录

问题

CAN模块相对与其他模块,寄存器配置较为复杂,官方历程不能实现期望的功能,网上搜到的程序并不全面,在不断的调试更改代码之后,实现了DSP与上位机之间的通信。

配置流程

寄存器初始化:首先需要对寄存器初始化,以满足CAN通信基本的寄存器要求。具体配置过程与官方实例基本相同,首先对GPIO口配置,复用CAN功能。然后通过CANTIOC及CANRIOC配置CAN的接收及发送功能,通过SCB位选择16邮箱或32邮箱模式,然后对邮箱初始化,然后相关的标志位置位,具体按照官方实例配置,需要注意的是波特率BTC寄存器的配置,波特率的计算公式为:

波特率=SysClock/[2*(BRP+1)*[(TSEGREG1+1)+(TSEGREG2+1)+1]],且要满足TSEG1REG1> TSEG1REG2

与SCI不同的是,如果波特率不对,CAN是接收不到或者发送不了数据的,而SCI波特率不对则是乱码,因此,如果在调试过程中出现收不到数据的情况,需要格外注意波特率的配置,笔者所用用的DSP为TMS320F28062,CPU最大主频为90MHz,晶振20MHz,起初笔者认为就是20MHz,与是按照=20MHz配置BTC寄存器,一直无法通信,一度的怀疑初始化程序有问题,后来按照90MHz配置,BRP=5,TSEGREG1=10,TSEGREG2=2,波特率为500K,功能就正常了。在配置BTC寄存器前,CCR位置位,以允许对BTC配置,然后等待CCE置位进行下一步配置,BTC配置完成后CCE需要清零,配置完成后需要确保所有邮箱处于屏蔽状态,因为只有在邮箱处于屏蔽状态才能对邮箱标识符进行配置。

邮箱配置:经过以上流程CAN模块配置完成,具备了CAN功能,然后进行邮箱配置,首先配置邮箱标识符寄存器MSGID,然后配置邮箱为发送或者接收,然后使能邮箱,接收邮箱还需要配置数据长度,数据长度最大为8。通过以上步骤CAN模块就具备了接收及发送功能。

发送及接收函数:发送及接收消息数据寄存器同为CANMDL及CANMDH,消息发送前需要先对CANMDL及CANMDH赋值,然后相应的CANTRS寄存器置位以启动发送,消息发送完成后CANTA置位,表明消息发送成功。在接受消息时,当接收到消息时CANRMP寄存器相应的位置位,然后读取消息数据寄存器同为CANMDL及CANMDH的值,读取完成后,接收到消息时CANRMP寄存器相应的位清零,以等待下一次接收数据。

总结:通过以上操作便可以实现CAN与上位机的通信,需要注意的是,以上配置流程只是为了进一步对CAN模块的理解,以便掌握CAN模块的使用,更复杂的应用仍然需要不断的尝试。

调试过程

邮箱0~3为发送邮箱,4~7为接收邮箱,DSP通过定时器中断发送数据给上位机,在主函数中接收上位机发送的数据。

硬件条件:

软件条件:

 接收结果:

 具体代码:

子函数

#include "DSP28x_Project.h"


            /*eCAN模块初始化,*/
void eCAN_Init()
{
    struct ECAN_REGS ECanaShadow;

                /*GPIO配置*/
    EALLOW;
    GpioCtrlRegs.GPAPUD.bit.GPIO30 = 0;
    GpioCtrlRegs.GPAPUD.bit.GPIO31 = 0;

    GpioCtrlRegs.GPAQSEL2.bit.GPIO30 = 3;

    GpioCtrlRegs.GPAMUX2.bit.GPIO30 = 1;
    GpioCtrlRegs.GPAMUX2.bit.GPIO31 = 1;
    EDIS;

                /*配置发送及接收功能*/
    EALLOW;
    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;


                /*eCAN增强模式*/
    ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
    ECanaShadow.CANMC.bit.SCB = 1;
    ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;

                /*邮箱初始化*/
    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;


            /*发送消息成功标志位初始化*/
    ECanaRegs.CANTA.all = 0xFFFFFFFF;

            /*接收消息挂起标志位初始化*/
    ECanaRegs.CANRMP.all = 0xffffffff;

                /*中断初始化*/
    ECanaRegs.CANGIF0.all = 0xFFFFFFFF;
    ECanaRegs.CANGIF1.all = 0xFFFFFFFF;

            /*CCR为1时允许对BTC配置*/
    ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
    ECanaShadow.CANMC.bit.CCR = 1 ;
    ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;

            /*CCE为1时进行下一步*/
    do
    {
      ECanaShadow.CANES.all = ECanaRegs.CANES.all;
    }
    while(ECanaShadow.CANES.bit.CCE != 1 );

    ECanaShadow.CANBTC.all = 0;


    /*              设置波特率
     * 波特率=SysClock/2/[(brp+1)/(tseg1+1+tseg2+1+1)]
     *     90MHz系统时钟波特率为90/2/6/15=0.5M=500k
     */

    ECanaShadow.CANBTC.bit.BRPREG = 5;
    ECanaShadow.CANBTC.bit.TSEG2REG = 2;
    ECanaShadow.CANBTC.bit.TSEG1REG = 10;

    ECanaRegs.CANBTC.all = ECanaShadow.CANBTC.all;

                    /*清除CCR位,对主控制器配置*/
    ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
    ECanaShadow.CANMC.bit.CCR = 0 ;
    ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;


                    /*CCE位清除表明eCAN模块配置完成*/
    do
    {
      ECanaShadow.CANES.all = ECanaRegs.CANES.all;
    }
    while(ECanaShadow.CANES.bit.CCE != 0 );

            /*MSGIDs配置前屏蔽邮箱,MSGIDs只能在邮箱屏蔽时配置*/
    ECanaRegs.CANME.all = 0;

    EDIS;
}

void eCAN_Config()
{

    ECanaMboxes.MBOX0.MSGID.all = 0x80000000;
    ECanaMboxes.MBOX1.MSGID.all = 0x80000001;
    ECanaMboxes.MBOX2.MSGID.all = 0x80000002;
    ECanaMboxes.MBOX3.MSGID.all = 0x80000003;

    ECanaMboxes.MBOX4.MSGID.all = 0x80000004;
    ECanaMboxes.MBOX5.MSGID.all = 0x80000005;
    ECanaMboxes.MBOX6.MSGID.all = 0x80000006;
    ECanaMboxes.MBOX7.MSGID.all = 0x80000007;

    ECanaRegs.CANMD.all = 0x000000f0;           //0~3发送邮箱,4~7接收邮箱
    ECanaRegs.CANME.all = 0x000000ff;           //使能0~7号邮箱

    ECanaMboxes.MBOX0.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX1.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX2.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX3.MSGCTRL.bit.DLC = 8;
}

void eCAN_Send()
{
    ECanaMboxes.MBOX0.MDL.all = 0x01000000;
    ECanaMboxes.MBOX0.MDH.all = 0x00000000;

    ECanaMboxes.MBOX1.MDL.all = 0x02000000;
    ECanaMboxes.MBOX1.MDH.all = 0x00000000;

    ECanaMboxes.MBOX2.MDL.all = 0x03000000;
    ECanaMboxes.MBOX2.MDH.all = 0x00000000;

    ECanaMboxes.MBOX3.MDL.all = 0x04000000;
    ECanaMboxes.MBOX3.MDH.all = 0x00000000;

    ECanaRegs.CANTRS.all = 0x0000000f;
    while(ECanaRegs.CANTA.all != 0x0000000f) {}
    ECanaRegs.CANTA.all = 0x0000000f;
}


int Rec_msg[] = {0,0,0,0,0,0,0,0};

void eCAN_Rec()
{
    struct ECAN_REGS ECanaShadow;

    ECanaShadow.CANRMP.all = ECanaRegs.CANRMP.all;

    if(ECanaShadow.CANRMP.bit.RMP4 == 1)     //RMP置位表明邮箱中包含一个接收到的消息,
    {
        Rec_msg[0] = ECanaMboxes.MBOX4.MDL.byte.BYTE0;
        Rec_msg[1] = ECanaMboxes.MBOX4.MDL.byte.BYTE1;
        Rec_msg[2] = ECanaMboxes.MBOX4.MDL.byte.BYTE2;
        Rec_msg[3] = ECanaMboxes.MBOX4.MDL.byte.BYTE3;
        Rec_msg[4] = ECanaMboxes.MBOX4.MDH.byte.BYTE4;
        Rec_msg[5] = ECanaMboxes.MBOX4.MDH.byte.BYTE5;
        Rec_msg[6] = ECanaMboxes.MBOX4.MDH.byte.BYTE6;
        Rec_msg[7] = ECanaMboxes.MBOX4.MDH.byte.BYTE7;
    }
    ECanaShadow.CANRMP.bit.RMP4 = 0;        //接收消息读完清零,等待下一次接收消息
    ECanaRegs.CANRMP.all = ECanaShadow.CANRMP.all;
}

 主函数:

#include "DSP28x_Project.h"
#include "eCAN.h"

void interrupt Timer1_isr();
void main(void)
{
    InitSysCtrl();                  //系统初始化
    DINT;                           //关闭中断
    InitPieCtrl();                  //初始化中断
    IER = 0x0000;                   //关闭中断使能
    IFR = 0x0000;                   //清空中断标志
    InitPieVectTable();             //初始化PIE中断向量表

    eCAN_Init();
    eCAN_Config();

    EALLOW;
    PieVectTable.TINT1 = &Timer1_isr;
    EDIS;

    InitCpuTimers();
    ConfigCpuTimer(&CpuTimer1, 20, 10000000);// (定时时间~s)

    CpuTimer1Regs.TCR.all = 0x4001;
    StartCpuTimer1();

    IER |= M_INT13;

    EINT;
    ERTM;


    for(;;)
    {
        eCAN_Rec();
    }
}

void interrupt Timer1_isr()
{
    eCAN_Send();
}

  • 6
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值