This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DRV8301-69M-KIT: CANBUS/Serial communication

Part Number: DRV8301-69M-KIT
Other Parts Discussed in Thread: CONTROLSUITE, MOTORWARE

Hi,

I would like to set the speed and Iq value via CANbus or any other serial comms.

Also, receive information such as bus voltage, current and motor speed. 

How can I do this? Where should I start from?

Many thanks. Regards

Noble.

  • I did some work on providing a speed reference using CAN communication.  Actually on the same exact hardware as you - DRV 8301 and F28069M. TI has a can.h file but no .c file available, I wrote my own. Additionally if you want the can to interface with the hardware abstraction layer, it's necessary to alter a few more files as well (this can effect how other projects compile).

    First off, regardless of implementation, in the GPIO initialization in hal.c (HAL_setupGpios), the following code needs to be changed/added:

    // CAN
    GPIO_setMode(obj->gpioHandle,GPIO_Number_30,GPIO_30_Mode_CANRXA);

    GPIO_setMode(obj->gpioHandle,GPIO_Number_31,GPIO_31_Mode_CANTXA);

    Note that LED 2 (I think) will no longer light up as a result of this config.

    Secondly, also regardless of implementation, you're going to need to enable the clock to the CAN peripheral (the normal hal function disables it):

    In HAL_setupPeripheralClks:

    Change CLK_disableEcanaClock(obj->clkHandle); to CLK_enableEcanaClock(obj->clkHandle);

    Lastly, assuming you'll want to use code composer to compile, you'll need to add the can.c file you create to the .PROJECT file as a link.

    The rest of this is for if you want to interface it with the HAL like I did. Some of this code could probably be altered to be more streamlined/efficient; I threw it together rather quickly.

    Some things you'll need to change include adding a HAL function for receiving a certain message (I have one for receiving an RPM command; you'll probably want two for receiving speed/Iq). You should be able to easily send the bus voltage, current, and motor speed with the transmit functions here provided you set the message IDs and data lengths correctly and use the right mailbox. You'll want to change the bit timing config as well, and which mailboxes you want to use for data receiving/sending (this code uses first 16 for sending, last 16 for receiving). I did not do anything with the local acceptance masks or the time stamp registers; the code has handles for them though, so you can write can functions/hal functions to use them if you want.

    can.c:

    Changes you'll need: Change the CANBTC registers to their correct values for your baud rate.

    /*
    
    * can.c
    
    *
    
    *  Created on: March 21, 2017
    
    *      Author: Adam Manders
    
    */
    
    #include "sw/drivers/can/src/32b/f28x/f2806x/can.h"
    #define NELEMS(x) (sizeof(x)/sizeof((x)[0]))
    //! \brief Define to allow protected register writes (legacy)
    //!
    #define  EALLOW asm(" EALLOW")
    
    //! \brief Define to allow protected register writes
    //!
    #define  ENABLE_PROTECTED_REGISTER_WRITE_MODE  asm(" EALLOW")
    
    //! \brief Define to disable protected register writes (legacy)
    //!
    #define  EDIS   asm(" EDIS")
    
    //! \brief Define to disable protected register writes
    //!
    #define  DISABLE_PROTECTED_REGISTER_WRITE_MODE asm(" EDIS")
    
    
    //STATIC VARIABLES NEEDED TO FORCE COMPILER TO ACCESS CORRECT DATA
    //(For transmit/recieve and setting up mailboxes)
    static int dls[32];
    static int ids[32];
    static uint32_t datal;
    static uint32_t datah;
    static volatile uint32_t *datalocl;
    static volatile uint32_t *dataloch;
    static int n;
    static int dsize;
    static int loops;
    
    
    //------------------------
    //INITIALIZATION FUNCTIONS
    //------------------------
    //Set up pointers to correct memory addresses
    
    ECAN_REG_Handle CAN_InitECanReg(void *pMemory, const size_t numBytes) //Init ECAN REGS
    {
    
      ECAN_REG_Handle canHandle;
    
      //Check to make sure size is correct
      if(numBytes < sizeof(ECAN_REGS))
        return((ECAN_REG_Handle)NULL);
    
      canHandle = (ECAN_REG_Handle)pMemory;
      
      return canHandle;
    }
    
    ECAN_MBOX_Handle CAN_InitECanMbox(void *pMemory, const size_t numBytes)
    {
      ECAN_MBOX_Handle canHandle;
    
      //Check to make sure size is correct
      if(numBytes < sizeof(ECAN_MBOXES))
        return((ECAN_MBOX_Handle)NULL);
    
      canHandle = (ECAN_MBOX_Handle)pMemory;
      
      return canHandle;
    }
    
    ECAN_LAM_Handle CAN_InitECanLAM(void *pMemory, const size_t numBytes)
    {
      ECAN_LAM_Handle canHandle;
    
      //Check to make sure size is correct
      if(numBytes < sizeof(LAM_REGS))
        return((ECAN_LAM_Handle)NULL);
    
      canHandle = (ECAN_LAM_Handle)pMemory;
      
      return canHandle;
    }
    
    ECAN_MOTO_Handle CAN_InitECanMOTO(void *pMemory, const size_t numBytes)
    {
      ECAN_MOTO_Handle canHandle;
    
      //Check to make sure size is correct
      if(numBytes < sizeof(MOTO_REGS))
        return((ECAN_MOTO_Handle)NULL);
    
      canHandle = (ECAN_MOTO_Handle)pMemory;
      
      return canHandle;
    }
    
    
    ECAN_MOTS_Handle CAN_InitECanMOTS(void *pMemory, const size_t numBytes)
    {
      ECAN_MOTS_Handle canHandle;
    
      //Check to make sure size is correct
      if(numBytes < sizeof(MOTS_REGS))
        return((ECAN_MOTS_Handle)NULL);
    
      canHandle = (ECAN_MOTS_Handle)pMemory;
      
      return canHandle;
    }
    
    //SETUP ID ARRAYS
    //ASSUMES ID AND DL ARE 32 IN LENGTH!
    void CAN_SetIDS(int *id, int *dl)
    {
    	int i = 0;
    	for(i = 0; i < 32; i++)
    	{
    		dls[i] = dl[i];
    		ids[i] = id[i];
    	}
    }
    
    
    //-------------------------------
    //CAN BUS SETUP (BAUD RATE, ETC)
    //-------------------------------
    
    
    void CAN_initCTRL(volatile ECAN_REG_Handle handle)
    {
      
      volatile ECAN_REGS *regs = (ECAN_REGS *)handle;
      
    
    /* Only 32 bit writes allowed to ECan Control/Status; use shadow to alter single bits
    and then copy shadow over */
    
      ECAN_REGS shadow = (ECAN_REGS)*regs;
      
      //disable mailboxes until mailboxes get setup
      shadow.CANME.all = 0;
    
      
      //to allow all 32 mailboxes to be used
      shadow.CANMC.bit.SCB = 1;
      //Set data byte order
      shadow.CANMC.bit.DBO = 0;
    
      //these bits should be initialized to zero;
      //clear by writing a 1 as a precaution
      shadow.CANTA.all = 0xFFFFFFFF; //transmit acknowledge
      shadow.CANRMP.all = 0xFFFFFFFF; //recieved msg pending
      shadow.CANGIF0.all = 0xFFFFFFFF;//interrupt flag regs
      shadow.CANGIF1.all = 0xFFFFFFFF;
      
      
      //Allow protected register writes
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
      
      //write what we have sofar
      //set TX and RX func bits to 1 in RIOC and TIOC registers
      regs->CANRIOC.all = 0x8;
      regs->CANTIOC.all = 0x8;
      //write CANMC, CANME registers
      regs->CANME.all = shadow.CANME.all;
      regs->CANMC.all = shadow.CANMC.all;
      //write CANTA, CANRMP, CANFIG0, CANGIF1 registers
      regs->CANTA.all = shadow.CANTA.all;
      regs->CANRMP.all = shadow.CANRMP.all;
      regs->CANGIF0.all = shadow.CANGIF0.all;
      regs->CANGIF1.all = shadow.CANGIF1.all;
    
      //set up CANBTC field for shadow; currently set up same as Digiflow
      //4 TQ After Samp, 5 TQ Before Samp, 2 TQ RJS, baud rate = 1 MBaud
      //9 TQ per BIT
    
      //inital clear
      shadow.CANBTC.all = 0;
      //baud rate prescaler
      shadow.CANBTC.bit.BRPREG = 2; //TQ = 2/SYSCLKOUT*(BRPREG+1)
      //sync jump width register
      shadow.CANBTC.bit.SJWREG = 1; //SJW = SJWREG + 1
      //TSEG 1
      shadow.CANBTC.bit.TSEG1REG = 7; //PROP SEG + PHASE SEG 1 = TSEG1REG + 1
      //TSEG 2
      shadow.CANBTC.bit.TSEG2REG = 5; //PHASE SEG 2 = TSEG2REG + 1
      //Samp point setting
      shadow.CANBTC.bit.SAM = 1;
      
      //request configuration write
      shadow.CANMC.bit.CCR = 1;
      regs->CANMC.all = shadow.CANMC.all;
      
      //wait for permission
      do {
        shadow.CANES.all = regs->CANES.all;
      } while(shadow.CANES.bit.CCE != 1);
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      //write CANBTC
      do {
    	  regs->CANBTC.all = shadow.CANBTC.all;
      } while(shadow.CANBTC.all != regs->CANBTC.all);
      
      //remove permission to change config
      shadow.CANMC.bit.CCR = 0;
      ((ECAN_REGS) *regs).CANMC.all = shadow.CANMC.all;
    
      //wait for permission to be removed
      do {
        shadow.CANES.all = ((ECAN_REGS) *regs).CANES.all;
      } while(shadow.CANES.bit.CCE != 0);
      
    
      //Disable protected register writes
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
    }
    
    //-------------------------------------
    //MAILBOX SETUP (TRANSMIT, RECIEVE, IDS)
    //-------------------------------------
    
    //arrays should all have size of 32
    //ids contains msg ids; dls contains data lengths
    
    void CAN_setupMail(volatile ECAN_REG_Handle reghandle, volatile ECAN_MBOX_Handle boxhandle)
    {
      ECAN_REGS *regs = (ECAN_REGS *)reghandle;
      ECAN_MBOXES *mbox = (ECAN_MBOXES *)boxhandle;
    
      //clear data registers of mailboxes
      mbox->MBOX0.MDL.all = 0x00000000;
      mbox->MBOX1.MDL.all = 0x00000000;
      mbox->MBOX2.MDL.all = 0x00000000;
      mbox->MBOX3.MDL.all = 0x00000000;
      mbox->MBOX4.MDL.all = 0x00000000;
      mbox->MBOX5.MDL.all = 0x00000000;
      mbox->MBOX6.MDL.all = 0x00000000;
      mbox->MBOX7.MDL.all = 0x00000000;
      mbox->MBOX8.MDL.all = 0x00000000;
      mbox->MBOX9.MDL.all = 0x00000000;
      mbox->MBOX10.MDL.all = 0x00000000;
      mbox->MBOX11.MDL.all = 0x00000000;
      mbox->MBOX12.MDL.all = 0x00000000;
      mbox->MBOX13.MDL.all = 0x00000000;
      mbox->MBOX14.MDL.all = 0x00000000;
      mbox->MBOX15.MDL.all = 0x00000000;
      mbox->MBOX16.MDL.all = 0x00000000;
      mbox->MBOX17.MDL.all = 0x00000000;
      mbox->MBOX18.MDL.all = 0x00000000;
      mbox->MBOX19.MDL.all = 0x00000000;
      mbox->MBOX20.MDL.all = 0x00000000;
      mbox->MBOX21.MDL.all = 0x00000000;
      mbox->MBOX22.MDL.all = 0x00000000;
      mbox->MBOX23.MDL.all = 0x00000000;
      mbox->MBOX24.MDL.all = 0x00000000;
      mbox->MBOX25.MDL.all = 0x00000000;
      mbox->MBOX26.MDL.all = 0x00000000;
      mbox->MBOX27.MDL.all = 0x00000000;
      mbox->MBOX28.MDL.all = 0x00000000;
      mbox->MBOX29.MDL.all = 0x00000000;
      mbox->MBOX30.MDL.all = 0x00000000;
      mbox->MBOX31.MDL.all = 0x00000000;
      mbox->MBOX0.MDH.all = 0x00000000;
      mbox->MBOX1.MDH.all = 0x00000000;
      mbox->MBOX2.MDH.all = 0x00000000;
      mbox->MBOX3.MDH.all = 0x00000000;
      mbox->MBOX4.MDH.all = 0x00000000;
      mbox->MBOX5.MDH.all = 0x00000000;
      mbox->MBOX6.MDH.all = 0x00000000;
      mbox->MBOX7.MDH.all = 0x00000000;
      mbox->MBOX8.MDH.all = 0x00000000;
      mbox->MBOX9.MDH.all = 0x00000000;
      mbox->MBOX10.MDH.all = 0x00000000;
      mbox->MBOX11.MDH.all = 0x00000000;
      mbox->MBOX12.MDH.all = 0x00000000;
      mbox->MBOX13.MDH.all = 0x00000000;
      mbox->MBOX14.MDH.all = 0x00000000;
      mbox->MBOX15.MDH.all = 0x00000000;
      mbox->MBOX16.MDH.all = 0x00000000;
      mbox->MBOX17.MDH.all = 0x00000000;
      mbox->MBOX18.MDH.all = 0x00000000;
      mbox->MBOX19.MDH.all = 0x00000000;
      mbox->MBOX20.MDH.all = 0x00000000;
      mbox->MBOX21.MDH.all = 0x00000000;
      mbox->MBOX22.MDH.all = 0x00000000;
      mbox->MBOX23.MDH.all = 0x00000000;
      mbox->MBOX24.MDH.all = 0x00000000;
      mbox->MBOX25.MDH.all = 0x00000000;
      mbox->MBOX26.MDH.all = 0x00000000;
      mbox->MBOX27.MDH.all = 0x00000000;
      mbox->MBOX28.MDH.all = 0x00000000;
      mbox->MBOX29.MDH.all = 0x00000000;
      mbox->MBOX30.MDH.all = 0x00000000;
      mbox->MBOX31.MDH.all = 0x00000000;
    
    
      //initialize MSG CTRL registers to 0
      mbox->MBOX0.MSGCTRL.all = 0x00000000;
      mbox->MBOX1.MSGCTRL.all = 0x00000000;
      mbox->MBOX2.MSGCTRL.all = 0x00000000;
      mbox->MBOX3.MSGCTRL.all = 0x00000000;
      mbox->MBOX4.MSGCTRL.all = 0x00000000;
      mbox->MBOX5.MSGCTRL.all = 0x00000000;
      mbox->MBOX6.MSGCTRL.all = 0x00000000;
      mbox->MBOX7.MSGCTRL.all = 0x00000000;
      mbox->MBOX8.MSGCTRL.all = 0x00000000;
      mbox->MBOX9.MSGCTRL.all = 0x00000000;
      mbox->MBOX10.MSGCTRL.all = 0x00000000;
      mbox->MBOX11.MSGCTRL.all = 0x00000000;
      mbox->MBOX12.MSGCTRL.all = 0x00000000;
      mbox->MBOX13.MSGCTRL.all = 0x00000000;
      mbox->MBOX14.MSGCTRL.all = 0x00000000;
      mbox->MBOX15.MSGCTRL.all = 0x00000000;
      mbox->MBOX16.MSGCTRL.all = 0x00000000;
      mbox->MBOX17.MSGCTRL.all = 0x00000000;
      mbox->MBOX18.MSGCTRL.all = 0x00000000;
      mbox->MBOX19.MSGCTRL.all = 0x00000000;
      mbox->MBOX20.MSGCTRL.all = 0x00000000;
      mbox->MBOX21.MSGCTRL.all = 0x00000000;
      mbox->MBOX22.MSGCTRL.all = 0x00000000;
      mbox->MBOX23.MSGCTRL.all = 0x00000000;
      mbox->MBOX24.MSGCTRL.all = 0x00000000;
      mbox->MBOX25.MSGCTRL.all = 0x00000000;
      mbox->MBOX26.MSGCTRL.all = 0x00000000;
      mbox->MBOX27.MSGCTRL.all = 0x00000000;
      mbox->MBOX28.MSGCTRL.all = 0x00000000;
      mbox->MBOX29.MSGCTRL.all = 0x00000000;
      mbox->MBOX30.MSGCTRL.all = 0x00000000;
      mbox->MBOX31.MSGCTRL.all = 0x00000000;
    
      //Set IDS for mesg buffers
    
      //First Clear all
      mbox->MBOX0.MSGID.all = 0x00000000;
      mbox->MBOX1.MSGID.all = 0x00000000;
      mbox->MBOX2.MSGID.all = 0x00000000;
      mbox->MBOX3.MSGID.all = 0x00000000;
      mbox->MBOX4.MSGID.all = 0x00000000;
      mbox->MBOX5.MSGID.all = 0x00000000;
      mbox->MBOX6.MSGID.all = 0x00000000;
      mbox->MBOX7.MSGID.all = 0x00000000;
      mbox->MBOX8.MSGID.all = 0x00000000;
      mbox->MBOX9.MSGID.all = 0x00000000;
      mbox->MBOX10.MSGID.all = 0x00000000;
      mbox->MBOX11.MSGID.all = 0x00000000;
      mbox->MBOX12.MSGID.all = 0x00000000;
      mbox->MBOX13.MSGID.all = 0x00000000;
      mbox->MBOX14.MSGID.all = 0x00000000;
      mbox->MBOX15.MSGID.all = 0x00000000;
      mbox->MBOX16.MSGID.all = 0x00000000;
      mbox->MBOX17.MSGID.all = 0x00000000;
      mbox->MBOX18.MSGID.all = 0x00000000;
      mbox->MBOX19.MSGID.all = 0x00000000;
      mbox->MBOX20.MSGID.all = 0x00000000;
      mbox->MBOX21.MSGID.all = 0x00000000;
      mbox->MBOX22.MSGID.all = 0x00000000;
      mbox->MBOX23.MSGID.all = 0x00000000;
      mbox->MBOX24.MSGID.all = 0x00000000;
      mbox->MBOX25.MSGID.all = 0x00000000;
      mbox->MBOX26.MSGID.all = 0x00000000;
      mbox->MBOX27.MSGID.all = 0x00000000;
      mbox->MBOX28.MSGID.all = 0x00000000;
      mbox->MBOX29.MSGID.all = 0x00000000;
      mbox->MBOX30.MSGID.all = 0x00000000;
      mbox->MBOX31.MSGID.all = 0x00000000;
    
      //Set standard IDS
      mbox->MBOX0.MSGID.bit.STDMSGID = ids[0];
      mbox->MBOX1.MSGID.bit.STDMSGID = ids[1];
      mbox->MBOX2.MSGID.bit.STDMSGID = ids[2];
      mbox->MBOX3.MSGID.bit.STDMSGID = ids[3];
      mbox->MBOX4.MSGID.bit.STDMSGID = ids[4];
      mbox->MBOX5.MSGID.bit.STDMSGID = ids[5];
      mbox->MBOX6.MSGID.bit.STDMSGID = ids[6];
      mbox->MBOX7.MSGID.bit.STDMSGID = ids[7];
      mbox->MBOX8.MSGID.bit.STDMSGID = ids[8];
      mbox->MBOX9.MSGID.bit.STDMSGID = ids[9];
      mbox->MBOX10.MSGID.bit.STDMSGID = ids[10];
      mbox->MBOX11.MSGID.bit.STDMSGID = ids[11];
      mbox->MBOX12.MSGID.bit.STDMSGID = ids[12];
      mbox->MBOX13.MSGID.bit.STDMSGID = ids[13];
      mbox->MBOX14.MSGID.bit.STDMSGID = ids[14];
      mbox->MBOX15.MSGID.bit.STDMSGID = ids[15];
      mbox->MBOX16.MSGID.bit.STDMSGID = ids[16];
      mbox->MBOX17.MSGID.bit.STDMSGID = ids[17];
      mbox->MBOX18.MSGID.bit.STDMSGID = ids[18];
      mbox->MBOX19.MSGID.bit.STDMSGID = ids[19];
      mbox->MBOX20.MSGID.bit.STDMSGID = ids[20];
      mbox->MBOX21.MSGID.bit.STDMSGID = ids[21];
      mbox->MBOX22.MSGID.bit.STDMSGID = ids[22];
      mbox->MBOX23.MSGID.bit.STDMSGID = ids[23];
      mbox->MBOX24.MSGID.bit.STDMSGID = ids[24];
      mbox->MBOX25.MSGID.bit.STDMSGID = ids[25];
      mbox->MBOX26.MSGID.bit.STDMSGID = ids[26];
      mbox->MBOX27.MSGID.bit.STDMSGID = ids[27];
      mbox->MBOX28.MSGID.bit.STDMSGID = ids[28];
      mbox->MBOX29.MSGID.bit.STDMSGID = ids[29];
      mbox->MBOX30.MSGID.bit.STDMSGID = ids[30];
      mbox->MBOX31.MSGID.bit.STDMSGID = ids[31];
    
      //Standard ID -> IDE = 0
      mbox->MBOX0.MSGID.bit.IDE = 0;
      mbox->MBOX1.MSGID.bit.IDE = 0;
      mbox->MBOX2.MSGID.bit.IDE = 0;
      mbox->MBOX3.MSGID.bit.IDE = 0;
      mbox->MBOX4.MSGID.bit.IDE = 0;
      mbox->MBOX5.MSGID.bit.IDE = 0;
      mbox->MBOX6.MSGID.bit.IDE = 0;
      mbox->MBOX7.MSGID.bit.IDE = 0;
      mbox->MBOX8.MSGID.bit.IDE = 0;
      mbox->MBOX9.MSGID.bit.IDE = 0;
      mbox->MBOX10.MSGID.bit.IDE = 0;
      mbox->MBOX11.MSGID.bit.IDE = 0;
      mbox->MBOX12.MSGID.bit.IDE = 0;
      mbox->MBOX13.MSGID.bit.IDE = 0;
      mbox->MBOX14.MSGID.bit.IDE = 0;
      mbox->MBOX15.MSGID.bit.IDE = 0;
      mbox->MBOX16.MSGID.bit.IDE = 0;
      mbox->MBOX17.MSGID.bit.IDE = 0;
      mbox->MBOX18.MSGID.bit.IDE = 0;
      mbox->MBOX19.MSGID.bit.IDE = 0;
      mbox->MBOX20.MSGID.bit.IDE = 0;
      mbox->MBOX21.MSGID.bit.IDE = 0;
      mbox->MBOX22.MSGID.bit.IDE = 0;
      mbox->MBOX23.MSGID.bit.IDE = 0;
      mbox->MBOX24.MSGID.bit.IDE = 0;
      mbox->MBOX25.MSGID.bit.IDE = 0;
      mbox->MBOX26.MSGID.bit.IDE = 0;
      mbox->MBOX27.MSGID.bit.IDE = 0;
      mbox->MBOX28.MSGID.bit.IDE = 0;
      mbox->MBOX29.MSGID.bit.IDE = 0;
      mbox->MBOX30.MSGID.bit.IDE = 0;
      mbox->MBOX31.MSGID.bit.IDE = 0;
    
      //Set MSG Data byte lengths
      mbox->MBOX0.MSGCTRL.bit.DLC = dls[0];
      mbox->MBOX1.MSGCTRL.bit.DLC = dls[1];
      mbox->MBOX2.MSGCTRL.bit.DLC = dls[2];
      mbox->MBOX3.MSGCTRL.bit.DLC = dls[3];
      mbox->MBOX4.MSGCTRL.bit.DLC = dls[4];
      mbox->MBOX5.MSGCTRL.bit.DLC = dls[5];
      mbox->MBOX6.MSGCTRL.bit.DLC = dls[6];
      mbox->MBOX7.MSGCTRL.bit.DLC = dls[7];
      mbox->MBOX8.MSGCTRL.bit.DLC = dls[8];
      mbox->MBOX9.MSGCTRL.bit.DLC = dls[9];
      mbox->MBOX10.MSGCTRL.bit.DLC = dls[10];
      mbox->MBOX11.MSGCTRL.bit.DLC = dls[11];
      mbox->MBOX12.MSGCTRL.bit.DLC = dls[12];
      mbox->MBOX13.MSGCTRL.bit.DLC = dls[13];
      mbox->MBOX14.MSGCTRL.bit.DLC = dls[14];
      mbox->MBOX15.MSGCTRL.bit.DLC = dls[15];
      mbox->MBOX16.MSGCTRL.bit.DLC = dls[16];
      mbox->MBOX17.MSGCTRL.bit.DLC = dls[17];
      mbox->MBOX18.MSGCTRL.bit.DLC = dls[18];
      mbox->MBOX19.MSGCTRL.bit.DLC = dls[19];
      mbox->MBOX20.MSGCTRL.bit.DLC = dls[20];
      mbox->MBOX21.MSGCTRL.bit.DLC = dls[21];
      mbox->MBOX22.MSGCTRL.bit.DLC = dls[22];
      mbox->MBOX23.MSGCTRL.bit.DLC = dls[23];
      mbox->MBOX24.MSGCTRL.bit.DLC = dls[24];
      mbox->MBOX25.MSGCTRL.bit.DLC = dls[25];
      mbox->MBOX26.MSGCTRL.bit.DLC = dls[26];
      mbox->MBOX27.MSGCTRL.bit.DLC = dls[27];
      mbox->MBOX28.MSGCTRL.bit.DLC = dls[28];
      mbox->MBOX29.MSGCTRL.bit.DLC = dls[29];
      mbox->MBOX30.MSGCTRL.bit.DLC = dls[30];
      mbox->MBOX31.MSGCTRL.bit.DLC = dls[31];
      
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      //don't use global acceptance mask
      regs->CANGAM.all = 0;
    
      //First 16 transmit, second 16 receive
      regs->CANMD.all = 0xFFFF0000;
    
      //Enable mailboxes
      regs->CANME.all = 0xFFFFFFFF;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
    }
    
    //------------------------------------
    //RECIEVE FUNCTIONS
    //------------------------------------
    //Return true if there is any message recieved that has not been read
    bool CAN_checkMail(volatile ECAN_REG_Handle handle)
    {
    	ECAN_REGS *regs = (ECAN_REGS *)handle;
    	if (regs->CANRMP.all == 0) return false;
    	else return true;
    }
    //Return true if there is a message at mailbox n and also read message
    //Return false if no message
    bool CAN_getMail(volatile ECAN_REG_Handle reghandle, volatile ECAN_MBOX_Handle boxhandle, volatile int j, volatile uint32_t *data1, volatile uint32_t *data2)
    {
    	//Get Handles
    	volatile ECAN_REGS *regs = (ECAN_REGS *)reghandle;
    	volatile ECAN_MBOXES *mbox = (ECAN_MBOXES *)boxhandle;
    
    
    	//Set statics
    	n = j;
    	datalocl = data1;
    	dataloch = data2;
    	loops = 0;
        dsize = dls[n];
    	//Check to ensure mailbox n has a message to recieve
    	//Return false if it does not
    	if((((uint32_t)((uint32_t)(0b1) << n) & regs->CANRMP.all) >> n) == 0)
    	{
    		return false;
    	}
    	else
    	{
    		//Loop as long as this mailbox has a msg
    		while((((uint32_t)((uint32_t)(0b1) << n) & regs->CANRMP.all) >> n) == 1)
    		{
    			//Write a 1 to RMP of mailbox n to clear the bit
    			regs->CANRMP.all = (uint32_t)((uint32_t)0b1 << n);
    			//Increment loops; if loops > 1, an error occured
    			//Loops > 1 means RMP was set back to 1 while reading data
    			//AKA, second message was recieved while reading first message
    			loops++;
    
    			//Read Mbox data
    			switch (n)
    			{
    			case 16:
    				datal = mbox->MBOX16.MDL.all;
    				datah = mbox->MBOX16.MDH.all;
    				break;
    			case 17:
    				datal = mbox->MBOX17.MDL.all;
    				datah = mbox->MBOX17.MDH.all;
    				break;
    			case 18:
    				datal = mbox->MBOX18.MDL.all;
    				datah = mbox->MBOX18.MDH.all;
    				break;
    			case 19:
    				datal = mbox->MBOX19.MDL.all;
    				datah = mbox->MBOX19.MDH.all;
    				break;
    			case 20:
    				datal = mbox->MBOX20.MDL.all;
    				datah = mbox->MBOX20.MDH.all;
    				break;
    			case 21:
    				datal = mbox->MBOX21.MDL.all;
    				datah = mbox->MBOX21.MDH.all;
    				break;
    			case 22:
    				datal = mbox->MBOX22.MDL.all;
    				datah = mbox->MBOX22.MDH.all;
    				break;
    			case 23:
    				datal = mbox->MBOX23.MDL.all;
    				datah = mbox->MBOX23.MDH.all;
    				break;
    			case 24:
    				datal = mbox->MBOX24.MDL.all;
    				datah = mbox->MBOX24.MDH.all;
    				break;
    			case 25:
    				datal = mbox->MBOX25.MDL.all;
    				datah = mbox->MBOX25.MDH.all;
    				break;
    			case 26:
    				datal = mbox->MBOX26.MDL.all;
    				datah = mbox->MBOX26.MDH.all;
    				break;
    			case 27:
    				datal = mbox->MBOX27.MDL.all;
    				datah = mbox->MBOX27.MDH.all;
    				break;
    			case 28:
    				datal = mbox->MBOX28.MDL.all;
    				datah = mbox->MBOX28.MDH.all;
    				break;
    			case 29:
    				datal = mbox->MBOX29.MDL.all;
    				datah = mbox->MBOX29.MDH.all;
    				break;
    			case 30:
    				datal = mbox->MBOX30.MDL.all;
    				datah = mbox->MBOX30.MDH.all;
    				break;
    			case 31:
    				datal = mbox->MBOX31.MDL.all;
    				datah = mbox->MBOX31.MDH.all;
    				break;
    			}
    
    			//Remove indeterminant data bytes (limit data to size of dsize)
    			if(dsize < 5)
    			{
    				datah = 0;
    				datal = datal & (0xFFFFFFFF >> (32-dsize*8));
    			}
    			else
    			{
    				datah = datah & (0xFFFFFFFF >> (32-(dsize-4)*8));
    			}
    		}
    		*datalocl = datal;
    		*dataloch = datah;
    		//ERROR procedure
    		if(loops > 1) return false;
    
    		//If data retrieval successful return true
    		return true;
    	}
    }
    
    //----------------------------------
    //TRANSMIT FUNCTIONS
    //----------------------------------
    int CAN_sendMSG(volatile ECAN_REG_Handle reghandle, volatile ECAN_MBOX_Handle boxhandle, volatile int j, volatile uint32_t data1, volatile uint32_t data2)
    {
    	//get Register structures from handles
    	volatile ECAN_REGS *regs = (ECAN_REGS *)reghandle;
    	volatile ECAN_MBOXES *mbox = (ECAN_MBOXES *)boxhandle;
    
    	//Set statics
    	n = j;
    	datal = data1;
    	datah = data2;
    
    
    	//Set MDL and MDH of correct mailbox
    	switch (n)
    	{
    	case 0:
    		mbox->MBOX0.MDL.all = datal;
    		mbox->MBOX0.MDH.all = datah;
    		break;
    	case 1:
    		mbox->MBOX1.MDL.all = datal;
    		mbox->MBOX1.MDH.all = datah;
    		break;
    	case 2:
    		mbox->MBOX2.MDL.all = datal;
    		mbox->MBOX2.MDH.all = datah;
    		break;
    	case 3:
    		mbox->MBOX3.MDL.all = datal;
    		mbox->MBOX3.MDH.all = datah;
    		break;
    	case 4:
    		mbox->MBOX4.MDL.all = datal;
    		mbox->MBOX4.MDH.all = datah;
    		break;
    	case 5:
    		mbox->MBOX5.MDL.all = datal;
    		mbox->MBOX5.MDH.all = datah;
    		break;
    	case 6:
    		mbox->MBOX6.MDL.all = datal;
    		mbox->MBOX6.MDH.all = datah;
    		break;
    	case 7:
    		mbox->MBOX7.MDL.all = datal;
    		mbox->MBOX7.MDH.all = datah;
    		break;
    	case 8:
    		mbox->MBOX8.MDL.all = datal;
    		mbox->MBOX8.MDH.all = datah;
    		break;
    	case 9:
    		mbox->MBOX9.MDL.all = datal;
    		mbox->MBOX9.MDH.all = datah;
    		break;
    	case 10:
    		mbox->MBOX10.MDL.all = datal;
    		mbox->MBOX10.MDH.all = datah;
    		break;
    	case 11:
    		mbox->MBOX11.MDL.all = datal;
    		mbox->MBOX11.MDH.all = datah;
    		break;
    	case 12:
    		mbox->MBOX12.MDL.all = datal;
    		mbox->MBOX12.MDH.all = datah;
    		break;
    	case 13:
    		mbox->MBOX13.MDL.all = datal;
    		mbox->MBOX13.MDH.all = datah;
    		break;
    	case 14:
    		mbox->MBOX14.MDL.all = datal;
    		mbox->MBOX14.MDH.all = datah;
    		break;
    	case 15:
    		mbox->MBOX15.MDL.all = datal;
    		mbox->MBOX15.MDH.all = datah;
    		break;
    	}
    	//Set correct transmit request register
    	regs->CANTRS.all = 0b1 << n;
    
    	//Wait for transmit acknowledge
    	while(!(regs->CANTA.all >> n));
    
    	//Clear transmit acknowledge
    	regs->CANTA.all = (uint32_t)(0b1 << n);
    
    	//Wait for the clear to work
    	while(regs->CANTA.all >> n);
    
    	return 0;
    
    }
    

    Alterations to can.h:

    At the top, defines for the ECANA base addresses:

    // Define eCAN Base Address
    #define ECANA_REG_BASE_ADDR (0x6000)
    #define ECANA_LAM_BASE_ADDR (0x6040)
    #define ECANA_MOTS_BASE_ADDR (0x6080)
    #define ECANA_MOTO_BASE_ADDR (0x60C0)
    #define ECANA_MBOX_BASE_ADDR (0x6100)

    At the bottom, after all the structs are declared:

    typedef volatile struct _ECAN_REGS_ *ECAN_REG_Handle;
    typedef volatile struct _ECAN_MBOXES_ *ECAN_MBOX_Handle;
    typedef volatile struct _LAM_REGS_ *ECAN_LAM_Handle;
    typedef volatile struct _MOTO_REGS_ *ECAN_MOTO_Handle;
    typedef volatile struct _MOTS_REGS_ *ECAN_MOTS_Handle;
    
    extern ECAN_REG_Handle CAN_InitECanReg(void *pMemory, const size_t numBytes);
    extern ECAN_MBOX_Handle CAN_InitECanMbox(void *pMemory, const size_t numBytes);
    extern ECAN_LAM_Handle CAN_InitECanLAM(void *pMemory, const size_t numBytes);
    extern ECAN_MOTO_Handle CAN_InitECanMOTO(void *pMemory, const size_t numBytes);
    extern ECAN_MOTS_Handle CAN_InitECanMOTS(void *pMemory, const size_t numBytes);
    extern void CAN_SetIDS(int *id, int *dl);
    
    extern void CAN_initCTRL(volatile ECAN_REG_Handle handle);
    
    extern void CAN_setupMail(volatile ECAN_REG_Handle reghandle, volatile ECAN_MBOX_Handle boxhandle);
    
    //Check for any and all messages
    extern bool CAN_checkMail(volatile ECAN_REG_Handle handle);
    //Get message at mailbox n
    extern bool CAN_getMail(volatile ECAN_REG_Handle reghandle, volatile ECAN_MBOX_Handle boxhandle, volatile int n, volatile uint32_t *datal, volatile uint32_t *datah);
    //Send message from mailbox n
    extern int CAN_sendMSG(volatile ECAN_REG_Handle reghandle, volatile ECAN_MBOX_Handle boxhandle, volatile int n, volatile uint32_t datal, volatile uint32_t datah);

    More files need to be altered to setup these handles for the ECAN registers:

    In hal_obj.h add these handles to the object definition:

      volatile ECAN_REG_Handle canRegHandle;   //Can BUS Handles
      volatile ECAN_MBOX_Handle canMboxHandle;
      volatile ECAN_MOTS_Handle canMotsHandle;
      volatile ECAN_MOTO_Handle canMotoHandle;
      volatile ECAN_LAM_Handle canLamHandle;

    In hal.h, add these function declarations:

    //CAN FUNCTION DECLARATIONS
    extern void HAL_setupCAN(HAL_Handle handle);
    extern bool HAL_checkCAN(HAL_Handle handle);
    extern void HAL_sendCAN(HAL_Handle handle, int i, uint32_t datal, uint32_t datah);

    In hal.c, define these functions: (also, I defined static arrays at the top of hal.c containing message ids and data lengths)

    //call for setup
    void HAL_setupCAN(volatile HAL_Handle handle)
    {
    	volatile HAL_Obj *obj = (HAL_Obj *)handle;
    	CAN_initCTRL(obj->canRegHandle);
    	CAN_SetIDS(CANIDS, CANDLS);
    	CAN_setupMail(obj->canRegHandle, obj->canMboxHandle);
    	return;
    }
    
    //call to check for message
    bool HAL_checkCAN(volatile HAL_Handle handle)
    {
    	volatile HAL_Obj *obj = (HAL_Obj *)handle;
    	return CAN_checkMail(obj->canRegHandle);
    }
    
    //transmit msg
    void HAL_sendCAN(volatile HAL_Handle handle, int i, uint32_t datal, uint32_t datah)
    {
    	CAN_sendMSG(handle->canRegHandle, handle->canMboxHandle, i, datal, datah);
    }

    You aren't done yet. More alterations need to be made to hal.c:

    In the HAL_init function, add:

      // initialize CAN interface
      obj->canRegHandle = CAN_InitECanReg((void *)ECANA_REG_BASE_ADDR,sizeof(ECAN_REGS));
      obj->canMboxHandle = CAN_InitECanMbox((void *)ECANA_MBOX_BASE_ADDR,sizeof(ECAN_MBOXES));
      obj->canLamHandle = CAN_InitECanLAM((void *)ECANA_LAM_BASE_ADDR,sizeof(LAM_REGS));
      obj->canMotoHandle = CAN_InitECanMOTO((void *)ECANA_MOTO_BASE_ADDR,sizeof(MOTO_REGS));
      obj->canMotsHandle = CAN_InitECanMOTS((void *)ECANA_MOTS_BASE_ADDR,sizeof(MOTS_REGS));

    In your main code you're going to want to call HAL_setupCAN sometime after HAL_init. After you should be able to just use the HAL functions added for the CAN interface to use it.

    I believe that's about it. For reference I used the ECANA technical reference pdf available somewhere on TI's website (http://www.ti.com/lit/ug/sprueu0/sprueu0.pdf

  • In addition to the above, you may investigate the ControlSUITE CAN examples and try porting them into the project you are working on.

    Also, Motorware 18 has an example on how to bring SCI functionality into a Motorware project; while you are not looking for SCI, following that guide may give you some insight into which files you'll need to include, and which functions you'll need to create, in order to bring CAN into a project. For that guide, please check C:\ti\motorware\motorware_1_01_00_18\docs\tutorials\motorware_hal_tutorial.pdf

    Sean
  • Hey Adam,

    Thanks a million indeed. Very generous and comprehensive.

    I am now trying the "motorware_hal_tutorial" to enable controlling the motor speed with the onboard pot. 

    Once I get it working,  my next step will be to use your code and enable speed control via canbus.

    Fun days ahead!!

    Noble

  • Hello Sean,
    Thanks a lot.
    As suggested I am going through the tutorial to get bit more experienced before diving into the CANbus.
    Noble
  • Hi Adam, Thanks.

    Where do you defined ECAN_MBOXES, CANIDS, CANDLS and ...?

    Andrew.
  • Hello Adam,

    did you not Change in can.h? 

    struct MOTO_REGS {
    .....
    };

    into

    typedef struct _MOTS_REGS_
    {
    ....
    } MOTO_REGS ;

    Andrew.

  • The ECAN_MBOXES and such were defined in my altered can.h file.

    CANIDS and CANDLS were defined in hal.c for me and then passed to the can.c in the HAL_setupCAN.

  • Yes, I actually did make that change (and similar changes to the LAM, MBOX, MOTS, etc. structs) in can.h. Forgot to mention it.
  • Nice work!

    I declared the mailbox registers as an array, this saves you a lot of switches and you can initialize them in a loop;

    // Declaration
    #pragma DATA_SECTION(EcanaMboxesArray, "ECanaMboxesFile");
    volatile struct MBOX EcanaMboxesArray[32];

    // Usage (initialization)
    for (i = 0; i < 32; i++)
    {
    EcanaMboxesArray[i].MSGCTRL.all = 0;
    EcanaMboxesArray[i].MSGID.all = 0; /* Additional - Initialize identifiers */
    EcanaMboxesArray[i].MDH.all = 0; /* Additional - Clear data */
    EcanaMboxesArray[i].MDL.all = 0; /* Additional - Clear data */
    }

    You get the picture.

    Best regards,

    Rob.
  • Hello All.
    After Easter, there was little time to add the ECAN in MotorWare 18.
    lab01_ECanBack2Back - ControlSuite.
    lab09a_ECanBack2Back_API - single reading/writing .
    lab09a_ECanCmd - burst reading/writing with FIFO.
    I plan to add CANOpen and UAVCAN.

    This is the first draft of my API.
    github.com/.../MotorWare_eCAN

    Andrew
    PS.
    Write if you find errors or extensions.

    Interrupt processing will be later.

  • Hello All,
    Help me with the Problem "Answering a Remote Request".
    i set MailBox0 MD = 0,
    id = 80, IDE = 0, AME = 0, AAM = 1.
    MDL = 0x5A5A5A5A, MDH = MDL = 0x5A5A5A5A.
    I do not receive an answer.

    Thank you.

    Andrew.

  • Hello everybody,

    I added an interrupt and fixed an error with masks.

    Andrew.

    github.com/.../MotorWare_eCAN

    PS:
    "Answering a Remote Request" I do it later if necessary. :)