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.

TMS320F28379D: CAN configuration with register

Part Number: TMS320F28379D
Other Parts Discussed in Thread: C2000WARE, TMDSCNCD28379D

Hi,

I need to use CAN to communicate with other product.

I start with the example "can_loopback_cpu01" to analyze registers settings. In this example, we use 2 functions, " CANMessageSet" and " CANMessageGet".

For more flexibility, I don't want to use these functions; but writing directly in the registers.

I've tried to convert the code, but it doesn't works.
I can see signals on the oscilloscope for Tx and Rx, but "NewDat" bit on a receipt is always '0'.

I've configured all the registers (CAN_IF1CMD, CAN_IF2CMD, CAN_IF1MSK, CAN_IF2MSK, CAN_IF1ARB, CAN_IF2ARB, CAN_IF1MCTL and CAN_IF2MCTL)  to have the same settings than the original program.

//###########################################################################
//
// FILE:   can_loopback.c
//
// TITLE:  Example to demonstrate basic CAN setup and use.
//
//! \addtogroup cpu01_example_list
//! <h1>CAN External Loopback Using Driverlib (can_loopback)</h1>
//!
//! This example, using driverlib, shows the basic setup of CAN in order to 
//! transmit and receive messages on the CAN bus.  The CAN peripheral is 
//! configured to transmit messages with a specific CAN ID.  A message is then 
//! transmitted once per second, using a simple delay loop for timing.  The 
//! message that is sent is a 4 byte message that contains an incrementing 
//! pattern.
//!
//! This example sets up the CAN controller in External Loopback test mode.
//! Data transmitted is visible on the CAN0TX pin and can be received with
//! an appropriate mailbox configuration.
//!
//! \b Watch \b Variables \n
//!  - g_ulMsgCount - A counter for the number of successful messages received
//!  - g_bErrFlag   - Indicates the data received didn't match the 
//!                   transmitted data
//!
//
//###########################################################################
// $TI Release: F2837xD Support Library v3.05.00.00 $
// $Release Date: Thu Oct 18 15:48:42 CDT 2018 $
// $Copyright:
// Copyright (C) 2013-2018 Texas Instruments Incorporated - http://www.ti.com/
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions 
// are met:
// 
//   Redistributions of source code must retain the above copyright 
//   notice, this list of conditions and the following disclaimer.
// 
//   Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the 
//   documentation and/or other materials provided with the   
//   distribution.
// 
//   Neither the name of Texas Instruments Incorporated nor the names of
//   its contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//###########################################################################

//
// Included Files
//
#include "F28x_Project.h"
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_can.h"
#include "driverlib/can.h"

//
// Globals
//
volatile unsigned long g_ulMsgCount = 0; // A counter that keeps track of the
                                         // number of times the transmit was
                                         // successful.
volatile unsigned long g_bErrFlag = 0;   // A flag to indicate that some
                                         // transmission error occurred.

//
// Main
//
int
main(void)
{
    tCANMsgObject sTXCANMessage;
    tCANMsgObject sRXCANMessage;
    unsigned int ucTXMsgData[2], ucRXMsgData[2];

    uint32_t ui32CmdMaskReg;
    uint32_t ui32MaskReg;
    uint32_t ui32ArbReg;
    uint32_t ui32MsgCtrl;

    int16_t iMsg;

    //
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the F2837xD_SysCtrl.c file.
    //
    InitSysCtrl();

    //
    // Step 2. Initialize GPIO:
    // This example function is found in the F2837xD_Gpio.c file and
    // illustrates how to set the GPIO to its default state.
    //
    InitGpio();
    /*GPIO_SetupPinMux(30, GPIO_MUX_CPU1, 1);  //GPIO30 - CANRXA
    GPIO_SetupPinMux(31, GPIO_MUX_CPU1, 1);  //GPIO31 - CANTXA
    GPIO_SetupPinOptions(30, GPIO_INPUT, GPIO_ASYNC);
    GPIO_SetupPinOptions(31, GPIO_OUTPUT, GPIO_PUSHPULL);*/
    /*GPIO_SetupPinMux(21, GPIO_MUX_CPU1, 3);  //GPIO30 - CANRXA
    GPIO_SetupPinMux(20, GPIO_MUX_CPU1, 3);  //GPIO31 - CANTXA
    GPIO_SetupPinOptions(21, GPIO_INPUT, GPIO_ASYNC);
    GPIO_SetupPinOptions(20, GPIO_OUTPUT, GPIO_PUSHPULL);*/
    EALLOW;
    GpioCtrlRegs.GPAPUD.bit.GPIO20 = 0;   // Enable pullup on GPIO20
    GpioCtrlRegs.GPAPUD.bit.GPIO21 = 0;   // Enable pullup on GPIO21
    GpioCtrlRegs.GPAMUX2.bit.GPIO20 = 3;  // GPIO20 = CANTXB
    GpioCtrlRegs.GPAMUX2.bit.GPIO21 = 3;  // GPIO21 = CANRXB
    GpioCtrlRegs.GPAQSEL2.bit.GPIO21 = 3; // asynch input
    EDIS;

    //
    // Initialize the CAN controller
    //
    //CANInit(CANB_BASE);

    //
    // Place CAN controller in init state, regardless of previous state.  This
    // will put controller in idle, and allow the message object RAM to be
    // programmed.
    //
    CanbRegs.CAN_CTL.bit.Init = 1; // CAN module ignores bus activity

    EALLOW;
    CanbRegs.CAN_CTL.bit.SWR = 1;  // Module is forced to reset state. This bit will get cleared automatically one clock cycle after execution of software reset.
    EDIS;

    CanbRegs.CAN_CTL.bit.CCE = 1;  // The CPU has write access to the configuration registers (when Init bit is set).

    //
    // Setup CAN to be clocked off the M3/Master subsystem clock
    //
    //CANClkSourceSelect(CANB_BASE, 0);

    EALLOW;
    // Configure the eCAN timing
    // CANB Bit-Clock Source Select Bit:
    ClkCfgRegs.CLKSRCCTL2.bit.CANBBCLKSEL = 0;      // 00 = PERx.SYSCLK (default on reset)
    EDIS;

    //
    // Set up the bit rate for the CAN bus.  This function sets up the CAN
    // bus timing for a nominal configuration.  You can achieve more control
    // over the CAN bus timing by using the function CANBitTimingSet() instead
    // of this one, if needed.
    // In this example, the CAN bus is set to 500 kHz.  In the function below,
    // the call to SysCtlClockGet() is used to determine the clock rate that
    // is used for clocking the CAN peripheral.  This can be replaced with a
    // fixed value if you know the value of the system clock, saving the extra
    // function call.  For some parts, the CAN peripheral is clocked by a fixed
    // 8 MHz regardless of the system clock in which case the call to
    // SysCtlClockGet() should be replaced with 8000000.  Consult the data
    // sheet for more information about CAN peripheral clocking.
    //

//    CANBitRateSet(CANB_BASE, 200000000, 125000);

    CanbRegs.CAN_BTR.bit.BRPE = 1; // Baud Rate Prescaler Extension - Valid programmed values are 0 to 15.
    CanbRegs.CAN_BTR.bit.BRP = 58; // Baud Rate Prescaler - Value by which the CAN_CLK frequency is divided for generating the bit time quanta. The bit time is built up from a multiple of this quanta.
    // ////////////////////////////////////////////// Maximum : 64 (6 bits)
    // Prescaler calculation : BRPE - BRP bits : XXXX XXXXXX = 0001 100011 = 0110 0011 = 99    Scaled_Clock (tq) = SYSCLK / PRESCAL = 200Mhz / (Prescale + 1) = 2Mhz

    CanbRegs.CAN_BTR.bit.TSEG1 = 6;
    CanbRegs.CAN_BTR.bit.TSEG2 = 4;
    CanbRegs.CAN_BTR.bit.SJW = 3;

    //
    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
    //
    DINT;

    //
    // Initialize the PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the F2837xD_PieCtrl.c file.
    //
    InitPieCtrl();

    //
    // Disable CPU interrupts and clear all CPU interrupt flags:
    //
    IER = 0x0000;
    IFR = 0x0000;

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in F2837xD_DefaultIsr.c.
    // This function is found in F2837xD_PieVect.c.
    //
    InitPieVectTable();

    //
    // Enable test mode and select external loopback
    //
    HWREG(CANB_BASE + CAN_O_CTL) |= CAN_CTL_TEST;
    HWREG(CANB_BASE + CAN_O_TEST) = CAN_TEST_EXL;

    //
    // Enable the CAN for operation.
    //
    CanbRegs.CAN_CTL.bit.Init = 0; // Enable CAN - CAN module processes messages normally


    //
    // Initialize the message object that will be used for sending CAN
    // messages.  The message will be 4 bytes that will contain an incrementing
    // value.  Initially it will be set to 0.
    //
/*        sTXCANMessage.ui32MsgID = 1;                      // CAN message ID - use 1
    sTXCANMessage.ui32MsgIDMask = 0;                  // no mask needed for TX
    sTXCANMessage.ui32Flags = MSG_OBJ_TX_INT_ENABLE;  // enable interrupt on TX
    sTXCANMessage.ui32MsgLen = sizeof(ucTXMsgData);   // size of message is 4
    sTXCANMessage.pucMsgData = ucTXMsgData;           // ptr to message content
*/

    CanbRegs.CAN_IF1ARB.bit.ID = 0x0040000;             // CAN message ID - use 1
    CanbRegs.CAN_IF1ARB.bit.Dir = 1;                    // Direction = transmit. On TxRqst, the respective message object is transmitted as a data frame.
    CanbRegs.CAN_IF1ARB.bit.MsgVal = 1;                 // The mailbox is enabled.
    CanbRegs.CAN_IF1ARB.bit.Xtd =  0;                   // The 11-bit ("standard") Identifier is used for this message object.

    CanbRegs.CAN_IF1MCTL.bit.UMask = 0;                 // Mask ignored
    CanbRegs.CAN_IF1MCTL.bit.DLC = 2;                   // size of message is 2
    CanbRegs.CAN_IF1MCTL.bit.TxIE = 1;                  // IntPnd will be triggered after the successful transmission of a frame.
    CanbRegs.CAN_IF1MCTL.bit.EoB = 1;                   // The message object is a single message object or the last message object in a FIFO Buffer Block.

    CanbRegs.CAN_IF1MSK.all = 0x20000000;               // The corresponding bit in the identifier of the message object is not used for acceptance filtering
 
    
    //
    // Initialize the message object that will be used for receiving CAN
    // messages.
    //
/*    sRXCANMessage.ui32MsgID = 1;                      // CAN message ID - use 1
    sRXCANMessage.ui32MsgIDMask = 0;                  // no mask needed for TX
    sRXCANMessage.ui32Flags = MSG_OBJ_NO_FLAGS;
    sRXCANMessage.ui32MsgLen = sizeof(ucRXMsgData);   // size of message is 4
    sRXCANMessage.pucMsgData = ucRXMsgData;           // ptr to message content
*/
    CanbRegs.CAN_IF2ARB.bit.ID = 0x0040000;             // CAN message ID - use 1
    CanbRegs.CAN_IF2ARB.bit.Dir = 0;                    // Direction = receive
    CanbRegs.CAN_IF2ARB.bit.MsgVal = 1;                 // The mailbox is enabled.
    CanbRegs.CAN_IF2ARB.bit.Xtd =  0;                   // The 11-bit ("standard") Identifier is used for this message object.

    CanbRegs.CAN_IF2MCTL.bit.UMask = 0;                 // Mask ignored
    CanbRegs.CAN_IF2MCTL.bit.TxIE = 0;                  // IntPnd will not be triggered after the successful transmission of a frame.
    CanbRegs.CAN_IF2MCTL.bit.RxIE = 0;                  // IntPnd will not be triggered after the successful reception of a frame.
    CanbRegs.CAN_IF2MCTL.bit.RmtEn = 0;                 // At the reception of a remote frame, TxRqst is not changed.
    CanbRegs.CAN_IF2MCTL.bit.EoB = 1;                   // The message object is a single message object or the last message object in a FIFO Buffer Block.
    CanbRegs.CAN_IF2MCTL.bit.IntPnd = 0;                // This message object is not the source of an interrupt.
    CanbRegs.CAN_IF2MCTL.bit.DLC = 2;                   // Size of message is 2

    CanbRegs.CAN_IF2MSK.all = 0xB19E0C8C;               // The corresponding bit in the identifier of the message object is not used for acceptance filtering

    //
    // Setup send and receive buffers
    //
    ucTXMsgData[0] = 0x01;
    ucTXMsgData[1] = 0x02;
    *(unsigned long *)ucRXMsgData = 0;

    //
    // Setup the message object being used to receive messages
    //
    //CANMessageSet(CANB_BASE, 2, &sRXCANMessage, MSG_OBJ_TYPE_RX);

    while(CanbRegs.CAN_IF2CMD.bit.Busy)                 // 1 Transfer between IF2 Register Set and Message RAM is in progress.
    {
    }
    CanbRegs.CAN_IF2CMD.bit.DIR = 0;                    // Direction = Read: Transfer direction is from the message object addressed by Message Number (Bits [7:0]) to the IF1/IF2 Register
    CanbRegs.CAN_IF2DATA.bit.Data_0 = *ucRXMsgData;      // ptr to message content

    CanbRegs.CAN_IF2CMD.bit.MSG_NUM = 2;                // Transfer the message object

    //
    // Enter loop to send messages.  A new message will be sent once per
    // second.  The 4 bytes of message content will be treated as an unsigned
    // long and incremented by one each time.
    //
    while(1)
    {
        //
        // Send the CAN message using object number 1 (not the same thing as
        // CAN ID, which is also 1 in this example).  This function will cause
        // the message to be transmitted right away.
        //
        //CANMessageSet(CANB_BASE, 1, &sTXCANMessage, MSG_OBJ_TYPE_TX);

        while(CanbRegs.CAN_IF1CMD.bit.Busy)                 // 1 Transfer between IF1 Register Set and Message RAM is in progress.
        {
        }
        CanbRegs.CAN_IF1CMD.bit.DIR = 1;                    // Transfer direction is from the IF1 Register set to the message object
        CanbRegs.CAN_IF1DATA.bit.Data_0 = ucTXMsgData[0];      // ptr to message content
        CanbRegs.CAN_IF1DATA.bit.Data_1 = ucTXMsgData[1];      // ptr to message content

        CanbRegs.CAN_IF1MCTL.bit.TxRqst = 1;                // The transmission of this message object is requested and is not yet done.

        CanbRegs.CAN_IF1CMD.bit.Arb = 1;                    // The Arbitration bits (Identifier + Dir + Xtd + MsgVal) will be transferred
        CanbRegs.CAN_IF1CMD.bit.Control = 1;                // The message control bits will be transferred
        CanbRegs.CAN_IF1CMD.bit.DATA_A = 1;                 // The Data Bytes 0-3 will be transferred
        CanbRegs.CAN_IF1CMD.bit.DATA_B = 1;                 // The Data Bytes 0-3 will be transferred

        CanbRegs.CAN_IF1CMD.bit.MSG_NUM = 1;                // Transfer the message object

        CanbRegs.CAN_IF1DATA.bit.Data_0 = ucTXMsgData[0];      // ptr to message content
        CanbRegs.CAN_IF1DATA.bit.Data_1 = ucTXMsgData[1];      // ptr to message content

        CanbRegs.CAN_IF1MCTL.bit.TxRqst = 1;                // The transmission of this message object is requested and is not yet done.


        //
        // Now wait 1 second before continuing
        //
        DELAY_US(10*1000);





        //
        // Get the receive message
        //
        //CANMessageGet(CANB_BASE, 2, &sRXCANMessage, true);

        CanbRegs.CAN_IF2CMD.bit.TxRqst = 1;             // Clears NewDat bit in the message object.

        CanbRegs.CAN_IF2CMD.bit.MSG_NUM = 2;            // Transfer the message object

        while (CanbRegs.CAN_IF2CMD.bit.Busy)            // Transfer between IF1/IF2 Register Set and Message RAM is in progress.
        {
        }

        if (CanbRegs.CAN_IF2MCTL.bit.NewDat == 1)       // The message handler or the CPU has written new data into the data portion of this message object.
        {
            CanbRegs.CAN_IF2CMD.bit.TxRqst = 1;         // Clears NewDat bit in the message object.

            CanbRegs.CAN_IF2CMD.bit.MSG_NUM = 2;        // Transfer the message object
            while(CanbRegs.CAN_IF2CMD.bit.Busy)         // 1 Transfer between IF1/IF2 Register Set and Message RAM is in progress.
            {
            }
        }

        //
        // Ensure the received data matches the transmitted data
        //
        if((ucTXMsgData[0] != ucRXMsgData[0]) ||
           (ucTXMsgData[1] != ucRXMsgData[1]))
        {
            g_bErrFlag++;
            //asm(" ESTOP0");
        }
        else
        {
            //
            // Increment message received counter
            //
            g_ulMsgCount++;
        }

        // Increment the value in the transmitted message data.
        //
        //
        ucTXMsgData[0] += 0x01;
        ucTXMsgData[1] += 0x02;

        //
        // Reset data if exceeds a byte
        //
        if(ucTXMsgData[0] > 0xFF)
        {
            ucTXMsgData[0] = 0;
        }
        if(ucTXMsgData[1] > 0xFF)
        {
            ucTXMsgData[1] = 0;
        }

    }
}

//
// End of file
//

Where're the mistakes?

Thank you.

Regards

  • Dear Sir, Madam, 

    It will be very challenging for us to debug the issue you running into in this manner.  It is best to look at this using a CAN bus analyzer.  Do you have one available that you can use?  If so, please start with the original code establish a base line with the analyzer and then make your modifications in a controlled way, verifying each modification incrementally.  

    I suggest you also study this application note in detail:  https://www.ti.com/lit/an/sprace5/sprace5.pdf?ts=1593024835627 

    Cheers!

    Krishna 

  • Debugging your code is not something we can support on the forum. Have you single-stepped through your code and looked at the bits/registers in the CCS watch window ?

  • Hi Krishna and Hareesh,

    No I don't have a CAN bus analyser.

    This is how I've proceed to develop the program :

    1. I've executed the example "can_loopback_cpu01", and look at the important registers. This is what I get : 

    CAN_IF1CMD 0x00B30001 CAN_IF2CMD 0x00040002
    CAN_IF1MSK 0x20000000 CAN_IF2MSK 0xB19E0C8C
    CAN_IF1ARB 0xA0040000 CAN_IF2ARB 0x80040000
    CAN_IF1MCTL 0x00000982 CAN_IF2MCTL 0x00008082

    2. I've configured registers by myself to have same settings than above.

    3. I had a look in can.c to see " CANMessageSet" and " CANMessageGet" are composed. I've tried to replace these functions with my own lines.

    4. When I execute my program, CAN_IF1_DATA register values are changing, but I have no value on CAN_IF2_DATA register

    I think my issue is not very complicated because there's not too much lines in my program, it's just a conversion of the initial program.

    That's why I asked you because it's the first time I use CAN on this MCU, and I think I've used the good way to proceed.

    Regards

  • Florian,

                    Kindly answer the following questions in order to help you better: 

    Are you attempting a loopback test or are you attempting communication with an external node? I presume it is the former, but wanted to confirm. 

    If you are only doing a loopback within the same node, have you tried the supplied example in C2000ware “as is”? i.e. the supplied Driverlib code? If you tried the example, what is the outcome? 

    Are you running the testcase in your own hardware or are you running it in LaunchPad/ControlCARD? 

    Have you looked at the Debug tips provided in my Application report http://www.ti.com/lit/sprace5

  • Florian,

                    It appears you are using an older version of C2000ware. Please download the latest version at https://www.ti.com/tool/download/C2000WARE 

    Your bit-rate calculation appears to be incorrect. Please look at SPRACE5 for a correct example. 

    Note: Neither of the above two points have anything to do with your problem. I merely wanted to bring them to your attention. 

    Can you please clarify the objective of the statement below:

    CanbRegs.CAN_IF2MSK.all = 0xB19E0C8C;

    Did you really intend to setup the mask? Can you try the example without the mask?

  • Hi Hareesh,

    1. I'm trying to do a loopback test, like the example "can_loopback_cpu01"

    2. I'm not sure I understood, but first I've tried "can_loopback_cpu01" without modification. Program and loopback worked.

    3. I'm running the program on a ControlCARD, TMDSCNCD28379D

    4. I havent' look your document yet, I will do soon.

    Regards

  • Hareesh,

    I'm using C2000Ware_3_01_00_00 version of C2000ware.

    For the bit-rate, I need 125kbits/s. I used "CAN Bit Timing Calculator.xls" to define register values.


    CanbRegs.CAN_IF2MSK.all = 0xB19E0C8C;

    I've define this value for this register because when I've executed the example "can_loopback_cpu01" the first time, it was the value I found in CCS watch window.

    I've did the test without the mask, the issue is the same.

    Regards,

  • Hi Hareesh,

    I've looked your document, but it didn't helped me.

    Any ideas to help me?

    Regards

  • Hi,

    To be more specific, I've replaced "CANMessageSet" with :

    while(CanbRegs.CAN_IF1CMD.bit.Busy)                 // 1 Transfer between IF1 Register Set and Message RAM is in progress.
            {
            }
            CanbRegs.CAN_IF1CMD.bit.DIR = 1;                    // Transfer direction is from the IF1 Register set to the message object
            CanbRegs.CAN_IF1DATA.bit.Data_0 = ucTXMsgData[0];      // ptr to message content
            CanbRegs.CAN_IF1DATA.bit.Data_1 = ucTXMsgData[1];      // ptr to message content
    
            CanbRegs.CAN_IF1MCTL.bit.TxRqst = 1;                // The transmission of this message object is requested and is not yet done.
    
            CanbRegs.CAN_IF1CMD.bit.Arb = 1;                    // The Arbitration bits (Identifier + Dir + Xtd + MsgVal) will be transferred
            CanbRegs.CAN_IF1CMD.bit.Control = 1;                // The message control bits will be transferred
            CanbRegs.CAN_IF1CMD.bit.DATA_A = 1;                 // The Data Bytes 0-3 will be transferred
            CanbRegs.CAN_IF1CMD.bit.DATA_B = 1;                 // The Data Bytes 0-3 will be transferred
    
            CanbRegs.CAN_IF1CMD.bit.MSG_NUM = 1;                // Transfer the message object
    

    and " CANMessageGet" with :

    CanbRegs.CAN_IF2CMD.bit.TxRqst = 1;             // Clears NewDat bit in the message object.
    
    CanbRegs.CAN_IF2CMD.bit.MSG_NUM = 2;            // Transfer the message object
    
    while (CanbRegs.CAN_IF2CMD.bit.Busy)            // Transfer between IF1/IF2 Register Set and Message RAM is in progress.
    {
    }
    
    if (CanbRegs.CAN_IF2MCTL.bit.NewDat == 1)       // The message handler or the CPU has written new data into the data portion of this message object.
    {
        CanbRegs.CAN_IF2CMD.bit.TxRqst = 1;         // Clears NewDat bit in the message object.
    
        CanbRegs.CAN_IF2CMD.bit.MSG_NUM = 2;        // Transfer the message object
        while(CanbRegs.CAN_IF2CMD.bit.Busy)         // 1 Transfer between IF1/IF2 Register Set and Message RAM is in progress.
        {
        }
    }

    Where're mistakes?

    Thank you

  • Hareesh,

    I've modified the original software to use registers. I've followed line by line functions "CANMessageSet" and "CANMessageGet" to have exactly the same value in the registers.

    But I don't know why, I cannot get the message :; can you just have a look where I'm wrong? The program should do exactly the same thing than  "can_loopback_cpu01" :

    //
    // Included Files
    //
    #include "F28x_Project.h"
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_types.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_can.h"
    #include "driverlib/can.h"
    
    //
    // Globals
    //
    volatile unsigned long g_ulMsgCount = 0; // A counter that keeps track of the
                                             // number of times the transmit was
                                             // successful.
    volatile unsigned long g_bErrFlag = 0;   // A flag to indicate that some
                                             // transmission error occurred.
    
    //
    // Main
    //
    int
    main(void)
    {
        tCANMsgObject sTXCANMessage;
        tCANMsgObject sRXCANMessage;
        unsigned int ucTXMsgData[2], ucRXMsgData[2];
    
        int16_t iMsg;
    
        //
        // Step 1. Initialize System Control:
        // PLL, WatchDog, enable Peripheral Clocks
        // This example function is found in the F2837xD_SysCtrl.c file.
        //
        InitSysCtrl();
    
        //
        // Step 2. Initialize GPIO:
        // This example function is found in the F2837xD_Gpio.c file and
        // illustrates how to set the GPIO to its default state.
        //
        InitGpio();
        EALLOW;
        GpioCtrlRegs.GPAPUD.bit.GPIO20 = 0;   // Enable pullup on GPIO20
        GpioCtrlRegs.GPAPUD.bit.GPIO21 = 0;   // Enable pullup on GPIO21
        GpioCtrlRegs.GPAMUX2.bit.GPIO20 = 3;  // GPIO20 = CANTXB
        GpioCtrlRegs.GPAMUX2.bit.GPIO21 = 3;  // GPIO21 = CANRXB
        GpioCtrlRegs.GPAQSEL2.bit.GPIO21 = 3; // asynch input
        EDIS;
    
        //
        // Initialize the CAN controller
        //
        //CANInit(CANB_BASE);
    
        //
        // Place CAN controller in init state, regardless of previous state.  This
        // will put controller in idle, and allow the message object RAM to be
        // programmed.
        //
        CanbRegs.CAN_CTL.bit.Init = 1; // CAN module ignores bus activity
    
        EALLOW;
        CanbRegs.CAN_CTL.bit.SWR = 1;  // Module is forced to reset state. This bit will get cleared automatically one clock cycle after execution of software reset.
        EDIS;
    
        CanbRegs.CAN_CTL.bit.CCE = 1;  // The CPU has write access to the configuration registers (when Init bit is set).
    
        //
        // Setup CAN to be clocked off the M3/Master subsystem clock
        //
        //CANClkSourceSelect(CANB_BASE, 0);
    
        EALLOW;
        // Configure the eCAN timing
        // CANB Bit-Clock Source Select Bit:
        ClkCfgRegs.CLKSRCCTL2.bit.CANBBCLKSEL = 0;      // 00 = PERx.SYSCLK (default on reset)
        EDIS;
    
    
        //CanbRegs.CAN_BTR.bit.BRPE = 1; // Baud Rate Prescaler ExtensionValid programmed values are 0 to 15.
        //CanbRegs.CAN_BTR.bit.BRP = 35; // Baud Rate Prescaler - Value by which the CAN_CLK frequency is divided for generating the bit time quanta. The bit time is built up from a multiple of this quanta.
        // Prescaler calculation : BRPE - BRP bits : XXXX XXXXXX = 0001 100011 = 0110 0011 = 99    Scaled_Clock (tq) = SYSCLK / PRESCAL = 200Mhz / (Prescale + 1) = 2Mhz
    
        CanbRegs.CAN_BTR.bit.BRPE = 1; // Baud Rate Prescaler Extension - Valid programmed values are 0 to 15.
        CanbRegs.CAN_BTR.bit.BRP = 58; // Baud Rate Prescaler - Value by which the CAN_CLK frequency is divided for generating the bit time quanta. The bit time is built up from a multiple of this quanta.
        // ////////////////////////////////////////////// Maximum : 64 (6 bits)
        // Prescaler calculation : BRPE - BRP bits : XXXX XXXXXX = 0001 100011 = 0110 0011 = 99    Scaled_Clock (tq) = SYSCLK / PRESCAL = 200Mhz / (Prescale + 1) = 2Mhz
    
        CanbRegs.CAN_BTR.bit.TSEG1 = 6;
        CanbRegs.CAN_BTR.bit.TSEG2 = 4;
        CanbRegs.CAN_BTR.bit.SJW = 3;
    
        //
        // Step 3. Clear all interrupts and initialize PIE vector table:
        // Disable CPU interrupts
        //
        DINT;
    
        //
        // Initialize the PIE control registers to their default state.
        // The default state is all PIE interrupts disabled and flags
        // are cleared.
        // This function is found in the F2837xD_PieCtrl.c file.
        //
        InitPieCtrl();
    
        //
        // Disable CPU interrupts and clear all CPU interrupt flags:
        //
        IER = 0x0000;
        IFR = 0x0000;
    
        //
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        // This will populate the entire table, even if the interrupt
        // is not used in this example.  This is useful for debug purposes.
        // The shell ISR routines are found in F2837xD_DefaultIsr.c.
        // This function is found in F2837xD_PieVect.c.
        //
        InitPieVectTable();
    
        //
        // Enable test mode and select external loopback
        //
        HWREG(CANB_BASE + CAN_O_CTL) |= CAN_CTL_TEST;
        HWREG(CANB_BASE + CAN_O_TEST) = CAN_TEST_EXL;
    
        //
        // Enable the CAN for operation.
        //
        CanbRegs.CAN_CTL.bit.Init = 0; // Enable CAN - CAN module processes messages normally
    
        //
        // Initialize the message object that will be used for sending CAN
        // messages.  The message will be 4 bytes that will contain an incrementing
        // value.  Initially it will be set to 0.
        //
    /*    sTXCANMessage.ui32MsgID = 1;                      // CAN message ID - use 1
        sTXCANMessage.ui32MsgIDMask = 0;                  // no mask needed for TX
        sTXCANMessage.ui32Flags = MSG_OBJ_TX_INT_ENABLE;  // enable interrupt on TX
        sTXCANMessage.ui32MsgLen = sizeof(ucTXMsgData);   // size of message is 4
        sTXCANMessage.pucMsgData = ucTXMsgData;           // ptr to message content
    
        //
        // Initialize the message object that will be used for receiving CAN
        // messages.
        //
        sRXCANMessage.ui32MsgID = 1;                      // CAN message ID - use 1
        sRXCANMessage.ui32MsgIDMask = 0;                  // no mask needed for TX
        sRXCANMessage.ui32Flags = MSG_OBJ_NO_FLAGS;
        sRXCANMessage.ui32MsgLen = sizeof(ucRXMsgData);   // size of message is 4
        sRXCANMessage.pucMsgData = ucRXMsgData;           // ptr to message content
    */
    
        //
        // Setup send and receive buffers
        //
        ucTXMsgData[0] = 0x01;
        ucTXMsgData[1] = 0x02;
        *(unsigned long *)ucRXMsgData = 0;
    
        //
        // Setup the message object being used to receive messages
        //
        //CANMessageSet(CANB_BASE, 2, &sRXCANMessage, MSG_OBJ_TYPE_RX);
    
    
        while(CanbRegs.CAN_IF1CMD.bit.Busy)                 // 1 Transfer between IF2 Register Set and Message RAM is in progress.
        {
        }
    
        CanbRegs.CAN_IF1CMD.bit.DIR = 1;                    // Direction = Write : Transfer direction is from the IF1/IF2 Register set to the message object addressed by Message Number (Bits [7:0])
        CanbRegs.CAN_IF1CMD.bit.Control = 1;                // The message control bits will be transferred
        CanbRegs.CAN_IF1CMD.bit.DATA_A = 1;                 // The Data Bytes 0-3 will be transferred
        CanbRegs.CAN_IF1CMD.bit.DATA_B = 1;                 // The Data Bytes 0-3 will be transferred
    
        CanbRegs.CAN_IF1CMD.bit.Arb = 1;                    // The Arbitration bits (Identifier + Dir + Xtd + MsgVal) will be transferred
    
        CanbRegs.CAN_IF1ARB.all = 0x80040000;
        CanbRegs.CAN_IF1MCTL.all = 0x00000082;
    
        CanbRegs.CAN_IF1CMD.bit.MSG_NUM = 2;                // Transfer the message object
    
    
        //
        // Enter loop to send messages.  A new message will be sent once per
        // second.  The 4 bytes of message content will be treated as an unsigned
        // long and incremented by one each time.
        //
        while(1)
        {
            //
            // Send the CAN message using object number 1 (not the same thing as
            // CAN ID, which is also 1 in this example).  This function will cause
            // the message to be transmitted right away.
            //
            //CANMessageSet(CANB_BASE, 1, &sTXCANMessage, MSG_OBJ_TYPE_TX);
    
            while(CanbRegs.CAN_IF1CMD.bit.Busy)                 // 1 Transfer between IF1 Register Set and Message RAM is in progress.
            {
            }
    
            CanbRegs.CAN_IF1CMD.bit.DIR = 1;                    // Direction = Write : Transfer direction is from the IF1/IF2 Register set to the message object addressed by Message Number (Bits [7:0])
            CanbRegs.CAN_IF1CMD.bit.Control = 1;                // The message control bits will be transferred
            CanbRegs.CAN_IF1CMD.bit.DATA_A = 1;                 // The Data Bytes 0-3 will be transferred
            CanbRegs.CAN_IF1CMD.bit.DATA_B = 1;                 // The Data Bytes 0-3 will be transferred
    
            CanbRegs.CAN_IF1MCTL.bit.TxRqst = 1;                // The transmission of this message object is requested and is not yet done.
            CanbRegs.CAN_IF1ARB.bit.Dir = 1;
    
            CanbRegs.CAN_IF1MCTL.bit.TxIE = 1;
    
            CanbRegs.CAN_IF1CMD.bit.Arb = 1;                    // The Arbitration bits (Identifier + Dir + Xtd + MsgVal) will be transferred
    
            CanbRegs.CAN_IF1ARB.bit.MsgVal = 1;
            CanbRegs.CAN_IF1ARB.bit.ID = 0x4000;
    
            CanbRegs.CAN_IF1MCTL.bit.DLC = 2;
            CanbRegs.CAN_IF1MCTL.bit.EoB = 1;
    
            CanbRegs.CAN_IF1DATA.bit.Data_0 = ucTXMsgData[0];   // ptr to message content
            CanbRegs.CAN_IF1DATA.bit.Data_1 = ucTXMsgData[1];   // ptr to message content
    
            CanbRegs.CAN_IF1CMD.bit.MSG_NUM = 1;                // Transfer the message object
    
    
            //
            // Now wait 1 second before continuing
            //
            DELAY_US(1000*1000);
    
    
            //
            // Get the receive message
            //
            //CANMessageGet(CANB_BASE, 2, &sRXCANMessage, true);
    
    
            CanbRegs.CAN_IF2CMD.bit.DATA_A = 1;             // The Data Bytes 0-3 will be transferred from the IF1/IF2 Register set to the message object addressed by the Message Number (Bits [7:0]).
            CanbRegs.CAN_IF2CMD.bit.DATA_B = 1;             // The Data Bytes 4-7 will be transferred from the IF1/IF2 Register set to the message object addressed by the Message Number (Bits [7:0]).
            CanbRegs.CAN_IF2CMD.bit.Control = 1;            // The message control bits will be transferred from the message object addressed by message number (Bits [7:0]) to the IF1 register set.
            CanbRegs.CAN_IF2CMD.bit.Mask = 0;               // Mask bits will not be changed
            CanbRegs.CAN_IF2CMD.bit.Arb = 1;                // The Arbitration bits (Identifier + Dir + Xtd + MsgVal) will be transferred from the IF1/IF2 Register set to the message object addressed by Message Number (Bits [7:0]
    
            CanbRegs.CAN_IF2CMD.bit.TxRqst = 1;
            CanbRegs.CAN_IF2CMD.bit.ClrIntPnd = 1;
    
            HWREGH(0x4A000 + 0x120 + 2) =  0x7F0000 >> 16;
    
            CanbRegs.CAN_IF2CMD.bit.MSG_NUM = 2;            // Transfer the message object
    
            while(CanbRegs.CAN_IF2CMD.bit.Busy)         // 1 Transfer between IF1/IF2 Register Set and Message RAM is in progress.
            {
            }
    
            //// Here is the problem, I don't receive NewValue....
    
    
            //
            // Ensure the received data matches the transmitted data
            //
            if((ucTXMsgData[0] != ucRXMsgData[0]) || (ucTXMsgData[1] != ucRXMsgData[1]))
            {
                g_bErrFlag++;
                //asm(" ESTOP0");
            }
            else
            {
                //
                // Increment message received counter
                //
                g_ulMsgCount++;
            }
    
            // Increment the value in the transmitted message data.
            //
            //
            ucTXMsgData[0] += 0x01;
            ucTXMsgData[1] += 0x02;
    
            //
            // Reset data if exceeds a byte
            //
            if(ucTXMsgData[0] > 0xFF)
            {
                ucTXMsgData[0] = 0;
            }
            if(ucTXMsgData[1] > 0xFF)
            {
                ucTXMsgData[1] = 0;
            }
    
        }
    }
    
    //
    // End of file
    //
    

    Regards

  • Florian,

        I have been unable to spend time looking into your code. Will do so shortly. In the interim, have you looked at the bit-field example provided as part of C2000ware? C:\ti\c2000\C2000Ware_3_02_00_00\device_support\f2837xd\examples\cpu1\can_loopback_bitfields\cpu01

  • You mentioned the supplied example in C2000ware worked "as is". You also captured the registers' contents after successful execution. Did you try single stepping through your code to check if the writes are going through? Did you check the register contents with your code with that of the supplied C2000ware example?

  • Hi Hareesh,

    Thank you for the example, it wasn't available with C2000Ware_3_01_00_00. It's exactly what I needed.

    But I want to know one last thing concerning the operation of the DCAN : I want to write a function to disable a message object ; does my code will just modify the bit "MsgVal" or the other bits too?

    void DisableMessageObjectID(uint32_t objID)
    {
    
        // Use Shadow variable for IF1CMD. IF1CMD should be written to in single 32-bit write.
        union CAN_IF1CMD_REG CAN_IF1CMD_SHADOW;
    
        // Wait for busy bit to clear.
        while(CanbRegs.CAN_IF1CMD.bit.Busy)
        {
        }
    
        // Set the  Arb bit so that they get transferred to the Message object.
        CAN_IF1CMD_SHADOW.bit.Arb = 1;
    
    
        // Disable the Mailbox
        CanbRegs.CAN_IF1ARB.bit.MsgVal = 0;
    
    
        // Transfer data to message object RAM
        CAN_IF1CMD_SHADOW.bit.MSG_NUM = objID;
        CanbRegs.CAN_IF1CMD.all = CAN_IF1CMD_SHADOW.all;
    }

    Thank you

  • You should be able to disable with MsgVal alone.

  • Hi Hareesh,

    The function above doesn't works every time ; in my software I can disable MsgVal one Message box 1 (MSG_OBJ_TYPE_TRANSMIT) but not on message Box n 20 (MSG_OBJ_TYPE_RECEIVE).

    Do you know why?

    Regards

  • The mailbox number should not have a bearing on how the function works.

    Can you check the value of the DIR & MSG_NUM bits in IF1CMD register before executing CanbRegs.CAN_IF1CMD.all = CAN_IF1CMD_SHADOW.all; ?

  • Hareesh Janakiraman said:

    The mailbox number should not have a bearing on how the function works.

    Yes I'm agree with you.

    Hareesh Janakiraman said:

    Can you check the value of the DIR & MSG_NUM bits in IF1CMD register before executing CanbRegs.CAN_IF1CMD.all = CAN_IF1CMD_SHADOW.all; ?

    When I execute DisableMessageObjectID(1) : 

    CAN_IF1CMD.bit.DIR = 1
    CAN_IF1CMD.bit.MSG_NUM = 20

    CAN_IF1CMD_SHADOW.bit.MSG_NUM = 32
    CAN_IF1CMD_SHADOW.bit.Arb = 0

    When I execute DisableMessageObjectID(20) : 

    CAN_IF1CMD.bit.DIR = 0
    CAN_IF1CMD.bit.MSG_NUM = 1

    CAN_IF1CMD_SHADOW.bit.MSG_NUM = 63
    CAN_IF1CMD_SHADOW.bit.Arb = 0

    It seems that DisableMessageObjectID(1) doesn't works either.

    Regards

  • If I want to disable mailbox or change the identifier in the middle of my software, does I need to :

    CanbRegs.CAN_CTL.bit.Init = 1;                                  // CAN module ignores bus activity
    CanbRegs.CAN_CTL.bit.CCE = 1;                               // The CPU has write access to the configuration registers (when Init bit is set).

    // Disable Mailbox, change identifier and enable Mailbox

    CanbRegs.CAN_CTL.bit.Init = 0;                                  // Enable CAN - CAN module processes messages normally

    CanbRegs.CAN_CTL.bit.Init = 1;                                  // CAN module ignores bus activity
    CanbRegs.CAN_CTL.bit.CCE = 1;                               // The CPU has write access to the configuration registers (when Init bit is set).
    
    // Disable Mailbox, change identifier and enable Mailbox
    
    CanbRegs.CAN_CTL.bit.Init = 0;                                  // Enable CAN - CAN module processes messages normally

    Normally not but I just want to be sure.

    Regards,

  • Hareesh,

    In order to work around the previous problem, I use the SetupMessageObject () function each time.
    It works when sending the 1st frame, I communicate with a device (sending data with IF1_registers, receiving correct answers on IF2_registers).

    On the other hand, during my second sending, I do not receive anything, registers IF2-DATA and IF2_DATB remain frozen with the values received during the 1st sending. CanbRegs.CAN_IF2MCTL.bit.NewDat = 0.

    Is there a bit or other to reset after the 1st reception?

    Thank you.

  • In your void DisableMessageObjectID(uint32_t objID) function, you are not setting the DIR bit at all. You must set this for the transfer to happen.

     

    Your values are incorrect below. Are these value before or after you execute the function? 

    When I execute DisableMessageObjectID(1) : 

    CAN_IF1CMD.bit.DIR = 1

    CAN_IF1CMD.bit.MSG_NUM = 20 (why is this 20, instead of 1?) 

    CAN_IF1CMD_SHADOW.bit.MSG_NUM = 32 (why is this 32, instead of 1?)

    CAN_IF1CMD_SHADOW.bit.Arb = 0 (why is this 0, instead of 1?) 

    When I execute DisableMessageObjectID(20) : (all values below are incorrect) 

    CAN_IF1CMD.bit.DIR = 0

    CAN_IF1CMD.bit.MSG_NUM = 1 

    CAN_IF1CMD_SHADOW.bit.MSG_NUM = 63

    CAN_IF1CMD_SHADOW.bit.Arb = 0 

    It appears your function is not getting executed correctly. You need to debug that first. 

    Is there a bit or other to reset after the 1st reception?

    Please refer to the C2000ware examples that show multiple reception.

  • Hareesh,

    Hareesh Janakiraman said:

    In your void DisableMessageObjectID(uint32_t objID) function, you are not setting the DIR bit at all. You must set this for the transfer to happen.

    Ok, I will modify my code to set DIR.

    Hareesh Janakiraman said:

    Your values are incorrect below. Are these value before or after you execute the function? 

    Of course I know these values are incorrect, it's very strange. I put a breakpoint just before executing 

    CanbRegs.CAN_IF1CMD.all = CAN_IF1CMD_SHADOW.all;

    Hareesh Janakiraman said:

    Please refer to the C2000ware examples that show multiple reception.

    It's not two receptions at the same time, it's 2 receptions (with differents ID, message object number) one after the other. 
    It's not the same operation than can_loopback_bitfields?
    Which example do I need to use?

    Regards,

  • Hi Hareesh,

    I just want to understand why you told me to use another example to use two mailbox? I cannot use C:\ti\c2000\C2000Ware_3_02_00_00\device_support\f2837xd\examples\cpu1\can_loopback_bitfields\cpu01?

    electrocc said:

    On the other hand, during my second sending, I do not receive anything, registers IF2-DATA and IF2_DATB remain frozen with the values received during the 1st sending. CanbRegs.CAN_IF2MCTL.bit.NewDat = 0.

    Regards,

  • By “multiple reception”, I was referring to back-to-back reception. In other words, one frame following another forever. Not sure what you mean by “It's not two receptions at the same time,”. I presume you are using the example in C:\ti\c2000\C2000Ware_3_02_00_00\device_support\f2837xd\examples\cpu1\can_loopback_bitfields\cpu01, correct?

  • Hi Hareesh,

    Forget "two receptions at the same time"

    Yes, I used example C:\ti\c2000\C2000Ware_3_02_00_00\device_support\f2837xd\examples\cpu1\can_loopback_bitfields\cpu01

    During the first step of my software, I send a message with Message Object 1 (configured for transmit) and I read Message Object 20 (configured for receipt).
    I received the good information on IF2_DATA and IF2_DATB, so it works.

    But during the second step of my software, I send a message with Message Object 1 (I changed only the Identifier) and I read Message Object 20 (I changed Identifier too).
    I can read good data for Message Object 1 with IF1_DATA and IF1_DATB (and all the configuration registers), but for the receipt (IF2_DATA and IF2_DATB), values are not updated, I can read values from the first step of my program.

    Is it clear for you?

    Regards,

  • Yes, I believe I understand your issue.

    Step 1:

    You transmit from Mailbox1 and receive it in Mailbox 20. The received data as read through IF2DATA & IF2DATB correctly reflects the transmitted data.

    Step 2:

    You change the MSGID of both mailboxes and initiate transmission again. However, this time IF2DATA & IF2DATB still reflect the previous data, not the currently transmitted data.

    Is this correct? 

    Could you please try the attached program? I modified the example to mimic the above condition. (I only use Mailboxes 1 & 2)

    //###########################################################################
    //
    // FILE:   can_loopback_bitfields.c
    //
    // TITLE:  Example to demonstrate basic CAN setup and use.
    //
    //! \addtogroup cpu01_example_list
    //! <h1>CAN External Loopback Using Bitfields (can_loopback_bitfields)</h1>
    //!
    //! IMPORTANT: CAN Bitfield headers require compiler v16.6.0.STS and newer!
    //!
    //! This example, using bitfield headers, shows the basic setup of CAN in
    //! order to transmit and receive messages on the CAN bus.  The CAN
    //! peripheral is configured to transmit messages with a specific CAN ID.
    //! A message is then transmitted once per second, using a simple delay
    //! loop for timing.  The message that is sent is a 4 byte message that
    //! contains an incrementing pattern.
    //!
    //! This example sets up the CAN controller in External Loopback test mode.
    //! Data transmitted is visible on the CAN0TX pin and can be received with
    //! an appropriate mailbox configuration.
    //!
    //
    //###########################################################################
    // $TI Release: F2837xD Support Library v3.10.00.00 $
    // $Release Date: Tue May 26 17:13:46 IST 2020 $
    // $Copyright:
    // Copyright (C) 2013-2020 Texas Instruments Incorporated - http://www.ti.com/
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //###########################################################################
    
    //
    // Included Files
    //
    #include "F28x_Project.h"
    
    //
    // Defines
    //
    #define CAN_MSG_ID              0x111 // This example only supports standard ID
    #define CAN_TX_MSG_OBJ          1
    #define CAN_RX_MSG_OBJ          2
    #define CAN_MAX_BIT_DIVISOR     (13)   // The maximum CAN bit timing divisor
    #define CAN_MIN_BIT_DIVISOR     (5)    // The minimum CAN bit timing divisor
    #define CAN_MAX_PRE_DIVISOR     (1024) // The maximum CAN pre-divisor
    #define CAN_MIN_PRE_DIVISOR     (1)    // The minimum CAN pre-divisor
    #define CAN_BTR_BRP_M           (0x3F)
    #define CAN_BTR_BRPE_M          (0xF0000)
    #define CAN_MSG_ID_SHIFT        18U
    
    
    //
    // Globals
    //
    unsigned char ucTXMsgData[4] = {0x1, 0x2, 0x3, 0x4}; // TX Data
    unsigned char ucRXMsgData[4] = {0, 0, 0, 0};         // RX Data
    uint32_t messageSize = sizeof(ucTXMsgData);          // Message Size (DLC)
    volatile unsigned long msgCount = 0; // A counter that keeps track of the
                                         // number of times the transmit was
                                         // successful.
    volatile unsigned long errFlag = 0;  // A flag to indicate that some
                                         // transmission error occurred.
    
    static const uint16_t canBitValues[] =
    {
        0x1100, // TSEG2 2, TSEG1 2, SJW 1, Divide 5
        0x1200, // TSEG2 2, TSEG1 3, SJW 1, Divide 6
        0x2240, // TSEG2 3, TSEG1 3, SJW 2, Divide 7
        0x2340, // TSEG2 3, TSEG1 4, SJW 2, Divide 8
        0x3340, // TSEG2 4, TSEG1 4, SJW 2, Divide 9
        0x3440, // TSEG2 4, TSEG1 5, SJW 2, Divide 10
        0x3540, // TSEG2 4, TSEG1 6, SJW 2, Divide 11
        0x3640, // TSEG2 4, TSEG1 7, SJW 2, Divide 12
        0x3740  // TSEG2 4, TSEG1 8, SJW 2, Divide 13
    };
    
    typedef enum
    {
            //! Transmit message object.
            MSG_OBJ_TYPE_TRANSMIT,
    
            //! Receive message object.
            MSG_OBJ_TYPE_RECEIVE
    }
    msgObjType;
    
    //
    // Function Prototypes
    //
    uint32_t setCANBitRate(uint32_t sourceClock, uint32_t bitRate);
    void  setupMessageObject(uint32_t objID, uint32_t msgID, msgObjType msgType);
    void sendCANMessage(uint32_t objID);
    bool getCANMessage(uint32_t objID);
    void TXRXloop(void);
    //
    // Main
    //
    int
    main(void)
    {
        //
        // Initialize System Control:
        // PLL, WatchDog, enable Peripheral Clocks
        // This example function is found in the F2837xD_SysCtrl.c file.
        //
        InitSysCtrl();
    
        //
        // Initialize GPIO:
        // This example function is found in the F2837xD_Gpio.c file and
        // illustrates how to set the GPIO to its default state.
        //
        InitGpio();
        GPIO_SetupPinMux(30, GPIO_MUX_CPU1, 1);  //GPIO30 - CANRXA
        GPIO_SetupPinMux(31, GPIO_MUX_CPU1, 1);  //GPIO31 - CANTXA
        GPIO_SetupPinOptions(30, GPIO_INPUT, GPIO_ASYNC);
        GPIO_SetupPinOptions(31, GPIO_OUTPUT, GPIO_PUSHPULL);
    
        // Modified configuration for the VBD
    
        /*GPIO_SetupPinMux(70, GPIO_MUX_CPU1, 2);  //GPIO70 - CANRXA
        GPIO_SetupPinMux(71, GPIO_MUX_CPU1, 2);  //GPIO71 - CANTXA
        GPIO_SetupPinOptions(70, GPIO_INPUT, GPIO_ASYNC);
        GPIO_SetupPinOptions(71, GPIO_OUTPUT, GPIO_PUSHPULL);*/
    
        //
        // Initialize the CAN-A controller
        //
        InitCAN();
    
        //
        // Setup CAN to be clocked off the SYSCLKOUT
        //
        ClkCfgRegs.CLKSRCCTL2.bit.CANABCLKSEL = 0;
    
        //
        // Set up the bit rate for the CAN bus.  This function sets up the CAN
        // bus timing for a nominal configuration.
        // In this example, the CAN bus is set to 500 kHz.
        //
        // Consult the data sheet for more information about
        // CAN peripheral clocking.
        //
        uint32_t status = setCANBitRate(200000000, 500000);
    
        //
        // If values requested are too small or too large, catch error
        //
        if(status == 0)
        {
            errFlag++;
            ESTOP0;         // Stop here and handle error
        }
    
        //
        // Step 3. Clear all interrupts and initialize PIE vector table:
        // Disable CPU interrupts
        //
        DINT;
    
        //
        // Initialize the PIE control registers to their default state.
        // The default state is all PIE interrupts disabled and flags
        // are cleared.
        // This function is found in the F2837xD_PieCtrl.c file.
        //
        InitPieCtrl();
    
        //
        // Disable CPU interrupts and clear all CPU interrupt flags:
        //
        IER = 0x0000;
        IFR = 0x0000;
    
        //
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        // This will populate the entire table, even if the interrupt
        // is not used in this example.  This is useful for debug purposes.
        // The shell ISR routines are found in F2837xD_DefaultIsr.c.
        // This function is found in F2837xD_PieVect.c.
        //
        InitPieVectTable();
    
        //
        // Enable test mode and select external loopback
        //
        CanaRegs.CAN_CTL.bit.Test = 1;
        CanaRegs.CAN_TEST.bit.EXL = 1;
    
        //
        // Initialize the message object that will be used for sending CAN
        // messages.
        //
        setupMessageObject(CAN_TX_MSG_OBJ, CAN_MSG_ID, MSG_OBJ_TYPE_TRANSMIT);
    
        //
        // Initialize the message object that will be used for receiving CAN
        // messages.
        //
        setupMessageObject(CAN_RX_MSG_OBJ, CAN_MSG_ID, MSG_OBJ_TYPE_RECEIVE);
    
        //
        // Enable the CAN for operation.
        //
        CanaRegs.CAN_CTL.bit.Init = 0;
    
         TXRXLOOP();
    
        setupMessageObject(CAN_TX_MSG_OBJ, 0x222, MSG_OBJ_TYPE_TRANSMIT);
        setupMessageObject(CAN_RX_MSG_OBJ, 0x222, MSG_OBJ_TYPE_RECEIVE);
         TXRXLOOP();
    
        for(;;){}
    }
    
    void TXRXLOOP()
    {
        //
        // Send the CAN message using object number 1 (not the same thing as
        // CAN ID, which is also 1 in this example).  This function will cause
        // the message to be transmitted right away.
        //
        sendCANMessage(CAN_TX_MSG_OBJ);
    
        //
        // Now wait 1 second before continuing
        //
        DELAY_US(1000*1000);
    
        //
        // Get the receive message
        //
        getCANMessage(CAN_RX_MSG_OBJ);
    
        //
        // Ensure the received data matches the transmitted data
        //
        if((ucTXMsgData[0] != ucRXMsgData[0]) ||
           (ucTXMsgData[1] != ucRXMsgData[1]) ||
           (ucTXMsgData[2] != ucRXMsgData[2]) ||
           (ucTXMsgData[3] != ucRXMsgData[3]))
        {
            errFlag++;
            asm(" ESTOP0");
        }
        else
        {
            //
            // Increment successful message count
            //
            msgCount++;
        }
            
    
        //
        // Increment the value in the transmitted message data.
        //
        ucTXMsgData[0] += 0x1;
        ucTXMsgData[1] += 0x1;
        ucTXMsgData[2] += 0x1;
        ucTXMsgData[3] += 0x1;
    
    
    }
    
    //
    // setCANBitRate - Set the CAN bit rate based on device clock (Hz)
    //                 and desired bit rate (Hz)
    //
    uint32_t setCANBitRate(uint32_t sourceClock, uint32_t bitRate)
    {
        uint32_t desiredRatio;
        uint32_t canBits;
        uint32_t preDivide;
        uint32_t regValue;
        uint16_t canControlValue;
    
        //
        // Calculate the desired clock rate.
        //
        desiredRatio = sourceClock / bitRate;
    
        //
        // Make sure that the Desired Ratio is not too large.  This enforces the
        // requirement that the bit rate is larger than requested.
        //
        if((sourceClock / desiredRatio) > bitRate)
        {
            desiredRatio += 1;
        }
    
        //
        // Check all possible values to find a matching value.
        //
        while(desiredRatio <= CAN_MAX_PRE_DIVISOR * CAN_MAX_BIT_DIVISOR)
        {
            //
            // Loop through all possible CAN bit divisors.
            //
            for(canBits = CAN_MAX_BIT_DIVISOR;
                canBits >= CAN_MIN_BIT_DIVISOR;
                canBits--)
            {
                //
                // For a given CAN bit divisor save the pre divisor.
                //
                preDivide = desiredRatio / canBits;
    
                //
                // If the calculated divisors match the desired clock ratio then
                // return these bit rate and set the CAN bit timing.
                //
                if((preDivide * canBits) == desiredRatio)
                {
                    //
                    // Start building the bit timing value by adding the bit timing
                    // in time quanta.
                    //
                    regValue = canBitValues[canBits - CAN_MIN_BIT_DIVISOR];
    
                    //
                    // To set the bit timing register, the controller must be
                    // placed
                    // in init mode (if not already), and also configuration change
                    // bit enabled.  The state of the register should be saved
                    // so it can be restored.
                    //
                    canControlValue = CanaRegs.CAN_CTL.all;
                    CanaRegs.CAN_CTL.bit.Init = 1;
                    CanaRegs.CAN_CTL.bit.CCE = 1;
    
                    //
                    // Now add in the pre-scalar on the bit rate.
                    //
                    regValue |= ((preDivide - 1) & CAN_BTR_BRP_M) |
                                (((preDivide - 1) << 10) & CAN_BTR_BRPE_M);
    
                    //
                    // Set the clock bits in the and the bits of the
                    // pre-scalar.
                    //
                    CanaRegs.CAN_BTR.all = regValue;
    
                    //
                    // Restore the saved CAN Control register.
                    //
                    CanaRegs.CAN_CTL.all = canControlValue;
    
                    //
                    // Return the computed bit rate.
                    //
                    return(sourceClock / ( preDivide * canBits));
                }
            }
    
            //
            // Move the divisor up one and look again.  Only in rare cases are
            // more than 2 loops required to find the value.
            //
            desiredRatio++;
        }
        return 0;
    }
    
    //
    // setupMessageObject - Setup message object as Transmit or Receive
    //
    void setupMessageObject(uint32_t objID, uint32_t msgID, msgObjType msgType)
    {
        //
        // Use Shadow variable for IF1CMD. IF1CMD should be written to in
        // single 32-bit write.
        //
        union CAN_IF1CMD_REG CAN_IF1CMD_SHADOW;
        
        //
        // Wait for busy bit to clear.
        //
        while(CanaRegs.CAN_IF1CMD.bit.Busy)
        {
        }
    
        //
        // Clear and Write out the registers to program the message object.
        //
        CAN_IF1CMD_SHADOW.all = 0;    
        CanaRegs.CAN_IF1MSK.all = 0;
        CanaRegs.CAN_IF1ARB.all = 0;
        CanaRegs.CAN_IF1MCTL.all = 0;
    
        //
        // Set the Control, Mask, and Arb bit so that they get transferred to the
        // Message object.
        //
        CAN_IF1CMD_SHADOW.bit.Control = 1;
        CAN_IF1CMD_SHADOW.bit.Arb = 1;
        CAN_IF1CMD_SHADOW.bit.Mask = 1;
        CAN_IF1CMD_SHADOW.bit.DIR = 1;
    
        //
        // Set direction to transmit
        //
        if(msgType == MSG_OBJ_TYPE_TRANSMIT)
        {
            CanaRegs.CAN_IF1ARB.bit.Dir = 1;
        }
    
        //
        // Set Message ID (this example assumes 11 bit ID mask)
        //
        CanaRegs.CAN_IF1ARB.bit.ID = msgID ;
        CanaRegs.CAN_IF1ARB.bit.MsgVal = 1;
    
        //
        // Set the data length since this is set for all transfers.  This is
        // also a single transfer and not a FIFO transfer so set EOB bit.
        //
        CanaRegs.CAN_IF1MCTL.bit.DLC = messageSize;
        CanaRegs.CAN_IF1MCTL.bit.EoB = 1;
    
        //
        // Transfer data to message object RAM
        //
        CAN_IF1CMD_SHADOW.bit.MSG_NUM = objID;
        CanaRegs.CAN_IF1CMD.all = CAN_IF1CMD_SHADOW.all;
    }
    
    //
    // sendCANMessage - Transmit data from the specified message object
    //
    void sendCANMessage(uint32_t objID)
    {
        //
        // Use Shadow variable for IF1CMD. IF1CMD should be written to in
        // single 32-bit write.
        //
        union CAN_IF1CMD_REG CAN_IF1CMD_SHADOW;
        
        //
        // Wait for busy bit to clear.
        //
        while(CanaRegs.CAN_IF1CMD.bit.Busy)
        {
        }
    
        //
        // Write data to transfer into DATA-A and DATA-B interface registers
        //
        uint16_t index;
        for(index = 0; index < messageSize; index++)
        {
            switch(index)
            {
                case 0:
                    CanaRegs.CAN_IF1DATA.bit.Data_0 = ucTXMsgData[index];
                    break;
                case 1:
                    CanaRegs.CAN_IF1DATA.bit.Data_1 = ucTXMsgData[index];
                    break;
                case 2:
                    CanaRegs.CAN_IF1DATA.bit.Data_2 = ucTXMsgData[index];
                    break;
                case 3:
                    CanaRegs.CAN_IF1DATA.bit.Data_3 = ucTXMsgData[index];
                    break;
                case 4:
                    CanaRegs.CAN_IF1DATB.bit.Data_4 = ucTXMsgData[index];
                    break;
                case 5:
                    CanaRegs.CAN_IF1DATB.bit.Data_5 = ucTXMsgData[index];
                    break;
                case 6:
                    CanaRegs.CAN_IF1DATB.bit.Data_6 = ucTXMsgData[index];
                    break;
                case 7:
                    CanaRegs.CAN_IF1DATB.bit.Data_7 = ucTXMsgData[index];
                    break;
            }
        }
    
        //
        // Set Direction to write and set DATA-A/DATA-B to be transfered to
        // message object
        //
        CAN_IF1CMD_SHADOW.all = 0;
        CAN_IF1CMD_SHADOW.bit.DIR = 1;
        CAN_IF1CMD_SHADOW.bit.DATA_A = 1;
        CAN_IF1CMD_SHADOW.bit.DATA_B = 1;
    
        //
        // Set Tx Request Bit
        //
        CAN_IF1CMD_SHADOW.bit.TXRQST = 1;
    
        //
        // Transfer the message object to the message object specified by
        // objID.
        //
        CAN_IF1CMD_SHADOW.bit.MSG_NUM = objID;
        CanaRegs.CAN_IF1CMD.all = CAN_IF1CMD_SHADOW.all;
    }
    
    //
    // getCANMessage - Check the message object for new data.
    //                 If new data, data written into array and return true.
    //                 If no new data, return false.
    //
    bool getCANMessage(uint32_t objID)
    {
        bool status;
        
        //
        // Use Shadow variable for IF2CMD. IF2CMD should be written to in
        // single 32-bit write.
        //
        union CAN_IF2CMD_REG CAN_IF2CMD_SHADOW;
    
        //
        // Set the Message Data A, Data B, and control values to be read
        // on request for data from the message object.
        //
        CAN_IF2CMD_SHADOW.all = 0;
        CAN_IF2CMD_SHADOW.bit.Control = 1;
        CAN_IF2CMD_SHADOW.bit.DATA_A = 1;
        CAN_IF2CMD_SHADOW.bit.DATA_B = 1;
    
        //
        // Transfer the message object to the message object IF register.
        //
        CAN_IF2CMD_SHADOW.bit.MSG_NUM = objID;
        CanaRegs.CAN_IF2CMD.all = CAN_IF2CMD_SHADOW.all;
    
        //
        // Wait for busy bit to clear.
        //
        while(CanaRegs.CAN_IF2CMD.bit.Busy)
        {
        }
    
        //
        // See if there is new data available.
        //
        if(CanaRegs.CAN_IF2MCTL.bit.NewDat == 1)
        {
            //
            // Read out the data from the CAN registers.
            //
            uint16_t index;
            for(index = 0; index < messageSize; index++)
            {
                switch(index)
                {
                    case 0:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATA.bit.Data_0;
                    break;
                    case 1:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATA.bit.Data_1;
                    break;
                    case 2:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATA.bit.Data_2;
                    break;
                    case 3:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATA.bit.Data_3;
                    break;
                    case 4:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATB.bit.Data_4;
                    break;
                    case 5:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATB.bit.Data_5;
                    break;
                    case 6:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATB.bit.Data_6;
                    break;
                    case 7:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATB.bit.Data_7;
                    break;
                }
            }
    
            //
            // Populate Shadow Variable
            //
            CAN_IF2CMD_SHADOW.all = CanaRegs.CAN_IF2CMD.all;
    
            //
            // Clear New Data Flag
            //
            CAN_IF2CMD_SHADOW.bit.TxRqst = 1;
    
            //
            // Transfer the message object to the message object IF register.
            //
            CAN_IF2CMD_SHADOW.bit.MSG_NUM = objID;
            CanaRegs.CAN_IF2CMD.all = CAN_IF2CMD_SHADOW.all;
    
            status = true;
        }
        else
        {
            status = false;
        }
    
        return(status);
    }
    
    //
    // End of file
    //
    

  • Hi Hareesh,

    Hareesh Janakiraman said:

    Yes, I believe I understand your issue.

    Step 1:

    You transmit from Mailbox1 and receive it in Mailbox 20. The received data as read through IF2DATA & IF2DATB correctly reflects the transmitted data.

    Step 2:

    You change the MSGID of both mailboxes and initiate transmission again. However, this time IF2DATA & IF2DATB still reflect the previous data, not the currently transmitted data.

    Is this correct? 

    Yes, it's exactly the issue I had.

    I can try the program, but only Monday. 

    We keep in touch.

    Thank you.

    Regards,

  • Hi Hareesh,

    I tried your program, but we don't know if the identifier is changed, that's right?

    Normally, before changing the ID, bit MsgVal must be reset. With the function setupMessageObject(), we never reset MsgVal, you're agree?

    So maybe in your software, the 2 functions TXRXLOOP(); send the message at the same ID, CAN_MSG_ID (=0x111)
    The message Object ID doesn't change to 0x222 perhaps?

    Regards,



  • Hareesh,

    I think I need to use the function DisableMessageObject()) before using setupMessageObject(), you're agree?
    I've modified this one to have DIR = 1, as you recommanded me :

    void DisableMessageObject(uint32_t objID)
    {
    
        // Use Shadow variable for IF1CMD. IF1CMD should be written to in single 32-bit write.
        union CAN_IF1CMD_REG CAN_IF1CMD_SHADOW;
    
        // Wait for busy bit to clear.
        while(CanbRegs.CAN_IF1CMD.bit.Busy)
        {
        }
    
        // Set the  Arb bit so that they get transferred to the Message object.
        CAN_IF1CMD_SHADOW.bit.Arb = 1;
        CAN_IF1CMD_SHADOW.bit.DIR = 1;
    
        // Disable the Mailbox
        CanbRegs.CAN_IF1ARB.bit.MsgVal = 0;
    
    
        // Transfer data to message object RAM
        CAN_IF1CMD_SHADOW.bit.MSG_NUM = objID;
    
        CanbRegs.CAN_IF1CMD.all = CAN_IF1CMD_SHADOW.all;
    
    
    }

    But it doesn't change anything. Do you have any idea to help me to solve my issue?

    Thank you.

    Regards.

  • It does appear the MSGID is not changing. I am looking into why. 

  • Hi Hareesh,

    Ok, I'm waiting for your reply.

    Regards,

  • There was a mistake in the code in terms of updating the MSGID. It has been fixed. Please try the attached. I am able to see the data correctly. First time, MSGID ix 0x111. 2nd time is 0x222. The databytes are correctly incremented the 2nd time. Before running this code, please make sure to modify the GPIO configuration to reflect your hardware. My board uses GPIO70 & 71. I dont know what your board uses.

    //###########################################################################
    //
    // FILE:   can_loopback_bitfields.c
    //
    // TITLE:  Example to demonstrate basic CAN setup and use.
    //
    //! \addtogroup cpu01_example_list
    //! <h1>CAN External Loopback Using Bitfields (can_loopback_bitfields)</h1>
    //!
    //! IMPORTANT: CAN Bitfield headers require compiler v16.6.0.STS and newer!
    //!
    //! This example, using bitfield headers, shows the basic setup of CAN in
    //! order to transmit and receive messages on the CAN bus.  The CAN
    //! peripheral is configured to transmit messages with a specific CAN ID.
    //! A message is then transmitted once per second, using a simple delay
    //! loop for timing.  The message that is sent is a 4 byte message that
    //! contains an incrementing pattern.
    //!
    //! This example sets up the CAN controller in External Loopback test mode.
    //! Data transmitted is visible on the CAN0TX pin and can be received with
    //! an appropriate mailbox configuration.
    //!
    //
    //###########################################################################
    // $TI Release: F2837xD Support Library v3.10.00.00 $
    // $Release Date: Tue May 26 17:13:46 IST 2020 $
    // $Copyright:
    // Copyright (C) 2013-2020 Texas Instruments Incorporated - http://www.ti.com/
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //###########################################################################
    
    //
    // Included Files
    //
    #include "F28x_Project.h"
    
    //
    // Defines
    //
    #define CAN_MSG_ID              0x111 // This example only supports standard ID
    #define CAN_TX_MSG_OBJ          1
    #define CAN_RX_MSG_OBJ          2
    #define CAN_MAX_BIT_DIVISOR     (13)   // The maximum CAN bit timing divisor
    #define CAN_MIN_BIT_DIVISOR     (5)    // The minimum CAN bit timing divisor
    #define CAN_MAX_PRE_DIVISOR     (1024) // The maximum CAN pre-divisor
    #define CAN_MIN_PRE_DIVISOR     (1)    // The minimum CAN pre-divisor
    #define CAN_BTR_BRP_M           (0x3F)
    #define CAN_BTR_BRPE_M          (0xF0000)
    #define CAN_MSG_ID_SHIFT        18U
    
    
    //
    // Globals
    //
    unsigned char ucTXMsgData[4] = {0x1, 0x2, 0x3, 0x4}; // TX Data
    unsigned char ucRXMsgData[4] = {0, 0, 0, 0};         // RX Data
    uint32_t messageSize = sizeof(ucTXMsgData);          // Message Size (DLC)
    volatile unsigned long msgCount = 0; // A counter that keeps track of the
                                         // number of times the transmit was
                                         // successful.
    volatile unsigned long errFlag = 0;  // A flag to indicate that some
                                         // transmission error occurred.
    
    static const uint16_t canBitValues[] =
    {
        0x1100, // TSEG2 2, TSEG1 2, SJW 1, Divide 5
        0x1200, // TSEG2 2, TSEG1 3, SJW 1, Divide 6
        0x2240, // TSEG2 3, TSEG1 3, SJW 2, Divide 7
        0x2340, // TSEG2 3, TSEG1 4, SJW 2, Divide 8
        0x3340, // TSEG2 4, TSEG1 4, SJW 2, Divide 9
        0x3440, // TSEG2 4, TSEG1 5, SJW 2, Divide 10
        0x3540, // TSEG2 4, TSEG1 6, SJW 2, Divide 11
        0x3640, // TSEG2 4, TSEG1 7, SJW 2, Divide 12
        0x3740  // TSEG2 4, TSEG1 8, SJW 2, Divide 13
    };
    
    typedef enum
    {
            //! Transmit message object.
            MSG_OBJ_TYPE_TRANSMIT,
    
            //! Receive message object.
            MSG_OBJ_TYPE_RECEIVE
    }
    msgObjType;
    
    //
    // Function Prototypes
    //
    uint32_t setCANBitRate(uint32_t sourceClock, uint32_t bitRate);
    void  setupMessageObject(uint32_t objID, uint32_t msgID, msgObjType msgType);
    void sendCANMessage(uint32_t objID);
    bool getCANMessage(uint32_t objID);
    void DisableMessageObject(uint32_t objID);
    void TXRXloop(void);
    //
    // Main
    //
    int
    main(void)
    {
        //
        // Initialize System Control:
        // PLL, WatchDog, enable Peripheral Clocks
        // This example function is found in the F2837xD_SysCtrl.c file.
        //
        InitSysCtrl();
    
        //
        // Initialize GPIO:
        // This example function is found in the F2837xD_Gpio.c file and
        // illustrates how to set the GPIO to its default state.
        //
        InitGpio();
        /*GPIO_SetupPinMux(30, GPIO_MUX_CPU1, 1);  //GPIO30 - CANRXA
        GPIO_SetupPinMux(31, GPIO_MUX_CPU1, 1);  //GPIO31 - CANTXA
        GPIO_SetupPinOptions(30, GPIO_INPUT, GPIO_ASYNC);
        GPIO_SetupPinOptions(31, GPIO_OUTPUT, GPIO_PUSHPULL);*/
    
        // Modified configuration for the VDB
    
        GPIO_SetupPinMux(70, GPIO_MUX_CPU1, 5);  //GPIO70 - CANRXA
        GPIO_SetupPinMux(71, GPIO_MUX_CPU1, 5);  //GPIO71 - CANTXA
        GPIO_SetupPinOptions(70, GPIO_INPUT, GPIO_ASYNC);
        GPIO_SetupPinOptions(71, GPIO_OUTPUT, GPIO_PUSHPULL);
    
        //
        // Initialize the CAN-A controller
        //
        InitCAN();
    
        //
        // Setup CAN to be clocked off the SYSCLKOUT
        //
        ClkCfgRegs.CLKSRCCTL2.bit.CANABCLKSEL = 0;
    
        //
        // Set up the bit rate for the CAN bus.  This function sets up the CAN
        // bus timing for a nominal configuration.
        // In this example, the CAN bus is set to 500 kHz.
        //
        // Consult the data sheet for more information about
        // CAN peripheral clocking.
        //
        uint32_t status = setCANBitRate(200000000, 500000);
    
        //
        // If values requested are too small or too large, catch error
        //
        if(status == 0)
        {
            errFlag++;
            ESTOP0;         // Stop here and handle error
        }
    
        //
        // Step 3. Clear all interrupts and initialize PIE vector table:
        // Disable CPU interrupts
        //
        DINT;
    
        //
        // Initialize the PIE control registers to their default state.
        // The default state is all PIE interrupts disabled and flags
        // are cleared.
        // This function is found in the F2837xD_PieCtrl.c file.
        //
        InitPieCtrl();
    
        //
        // Disable CPU interrupts and clear all CPU interrupt flags:
        //
        IER = 0x0000;
        IFR = 0x0000;
    
        //
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        // This will populate the entire table, even if the interrupt
        // is not used in this example.  This is useful for debug purposes.
        // The shell ISR routines are found in F2837xD_DefaultIsr.c.
        // This function is found in F2837xD_PieVect.c.
        //
        InitPieVectTable();
    
        //
        // Enable test mode and select external loopback
        //
        CanaRegs.CAN_CTL.bit.Test = 1;
        CanaRegs.CAN_TEST.bit.EXL = 1;
    
        //
        // Initialize the message object that will be used for sending CAN
        // messages.
        //
        setupMessageObject(CAN_TX_MSG_OBJ, CAN_MSG_ID, MSG_OBJ_TYPE_TRANSMIT);
    
        //
        // Initialize the message object that will be used for receiving CAN
        // messages.
        //
        setupMessageObject(CAN_RX_MSG_OBJ, CAN_MSG_ID, MSG_OBJ_TYPE_RECEIVE);
    
        //
        // Enable the CAN for operation.
        //
        CanaRegs.CAN_CTL.bit.Init = 0;
    
        TXRXLOOP();
    
        DisableMessageObject(CAN_TX_MSG_OBJ);
        DisableMessageObject(CAN_RX_MSG_OBJ);
    
        setupMessageObject(CAN_TX_MSG_OBJ, 0x222, MSG_OBJ_TYPE_TRANSMIT);
        setupMessageObject(CAN_RX_MSG_OBJ, 0x222, MSG_OBJ_TYPE_RECEIVE);
    
        TXRXLOOP();
    
        for(;;){}
    }
    
     TXRXLOOP(void)
    {
        //
        // Send the CAN message using object number 1 (not the same thing as
        // CAN ID, which is also 1 in this example).  This function will cause
        // the message to be transmitted right away.
        //
        sendCANMessage(CAN_TX_MSG_OBJ);
    
        //
        // Now wait 1 second before continuing
        //
        DELAY_US(1000*1000);
    
        //
        // Get the receive message
        //
        getCANMessage(CAN_RX_MSG_OBJ);
    
        //
        // Ensure the received data matches the transmitted data
        //
        if((ucTXMsgData[0] != ucRXMsgData[0]) ||
           (ucTXMsgData[1] != ucRXMsgData[1]) ||
           (ucTXMsgData[2] != ucRXMsgData[2]) ||
           (ucTXMsgData[3] != ucRXMsgData[3]))
        {
            errFlag++;
            asm(" ESTOP0");
        }
        else
        {
            //
            // Increment successful message count
            //
            msgCount++;
        }
            
    
        //
        // Increment the value in the transmitted message data.
        //
        ucTXMsgData[0] += 0x1;
        ucTXMsgData[1] += 0x1;
        ucTXMsgData[2] += 0x1;
        ucTXMsgData[3] += 0x1;
    
    
    }
    
    //
    // setCANBitRate - Set the CAN bit rate based on device clock (Hz)
    //                 and desired bit rate (Hz)
    //
    uint32_t setCANBitRate(uint32_t sourceClock, uint32_t bitRate)
    {
        uint32_t desiredRatio;
        uint32_t canBits;
        uint32_t preDivide;
        uint32_t regValue;
        uint16_t canControlValue;
    
        //
        // Calculate the desired clock rate.
        //
        desiredRatio = sourceClock / bitRate;
    
        //
        // Make sure that the Desired Ratio is not too large.  This enforces the
        // requirement that the bit rate is larger than requested.
        //
        if((sourceClock / desiredRatio) > bitRate)
        {
            desiredRatio += 1;
        }
    
        //
        // Check all possible values to find a matching value.
        //
        while(desiredRatio <= CAN_MAX_PRE_DIVISOR * CAN_MAX_BIT_DIVISOR)
        {
            //
            // Loop through all possible CAN bit divisors.
            //
            for(canBits = CAN_MAX_BIT_DIVISOR;
                canBits >= CAN_MIN_BIT_DIVISOR;
                canBits--)
            {
                //
                // For a given CAN bit divisor save the pre divisor.
                //
                preDivide = desiredRatio / canBits;
    
                //
                // If the calculated divisors match the desired clock ratio then
                // return these bit rate and set the CAN bit timing.
                //
                if((preDivide * canBits) == desiredRatio)
                {
                    //
                    // Start building the bit timing value by adding the bit timing
                    // in time quanta.
                    //
                    regValue = canBitValues[canBits - CAN_MIN_BIT_DIVISOR];
    
                    //
                    // To set the bit timing register, the controller must be
                    // placed
                    // in init mode (if not already), and also configuration change
                    // bit enabled.  The state of the register should be saved
                    // so it can be restored.
                    //
                    canControlValue = CanaRegs.CAN_CTL.all;
                    CanaRegs.CAN_CTL.bit.Init = 1;
                    CanaRegs.CAN_CTL.bit.CCE = 1;
    
                    //
                    // Now add in the pre-scalar on the bit rate.
                    //
                    regValue |= ((preDivide - 1) & CAN_BTR_BRP_M) |
                                (((preDivide - 1) << 10) & CAN_BTR_BRPE_M);
    
                    //
                    // Set the clock bits in the and the bits of the
                    // pre-scalar.
                    //
                    CanaRegs.CAN_BTR.all = regValue;
    
                    //
                    // Restore the saved CAN Control register.
                    //
                    CanaRegs.CAN_CTL.all = canControlValue;
    
                    //
                    // Return the computed bit rate.
                    //
                    return(sourceClock / ( preDivide * canBits));
                }
            }
    
            //
            // Move the divisor up one and look again.  Only in rare cases are
            // more than 2 loops required to find the value.
            //
            desiredRatio++;
        }
        return 0;
    }
    
    //
    // setupMessageObject - Setup message object as Transmit or Receive
    //
    void setupMessageObject(uint32_t objID, uint32_t msgID, msgObjType msgType)
    {
        //
        // Use Shadow variable for IF1CMD. IF1CMD should be written to in
        // single 32-bit write.
        //
        union CAN_IF1CMD_REG CAN_IF1CMD_SHADOW;
        
        //
        // Wait for busy bit to clear.
        //
        while(CanaRegs.CAN_IF1CMD.bit.Busy)
        {
        }
    
        //
        // Clear and Write out the registers to program the message object.
        //
        CAN_IF1CMD_SHADOW.all = 0;    
        CanaRegs.CAN_IF1MSK.all = 0;
        CanaRegs.CAN_IF1ARB.all = 0;
        CanaRegs.CAN_IF1MCTL.all = 0;
    
        //
        // Set the Control, Mask, and Arb bit so that they get transferred to the
        // Message object.
        //
        CAN_IF1CMD_SHADOW.bit.Control = 1;
        CAN_IF1CMD_SHADOW.bit.Arb = 1;
        CAN_IF1CMD_SHADOW.bit.Mask = 1;
        CAN_IF1CMD_SHADOW.bit.DIR = 1;
    
        //
        // Set direction to transmit
        //
        if(msgType == MSG_OBJ_TYPE_TRANSMIT)
        {
            CanaRegs.CAN_IF1ARB.bit.Dir = 1;
        }
    
        //
        // Set Message ID (this example assumes 11 bit ID mask)
        //
        CanaRegs.CAN_IF1ARB.bit.ID = (msgID << CAN_MSG_ID_SHIFT) ;
        CanaRegs.CAN_IF1ARB.bit.MsgVal = 1;
    
        //
        // Set the data length since this is set for all transfers.  This is
        // also a single transfer and not a FIFO transfer so set EOB bit.
        //
        CanaRegs.CAN_IF1MCTL.bit.DLC = messageSize;
        CanaRegs.CAN_IF1MCTL.bit.EoB = 1;
    
        //
        // Transfer data to message object RAM
        //
        CAN_IF1CMD_SHADOW.bit.MSG_NUM = objID;
        CanaRegs.CAN_IF1CMD.all = CAN_IF1CMD_SHADOW.all;
    }
    
    //
    // sendCANMessage - Transmit data from the specified message object
    //
    void sendCANMessage(uint32_t objID)
    {
        //
        // Use Shadow variable for IF1CMD. IF1CMD should be written to in
        // single 32-bit write.
        //
        union CAN_IF1CMD_REG CAN_IF1CMD_SHADOW;
        
        //
        // Wait for busy bit to clear.
        //
        while(CanaRegs.CAN_IF1CMD.bit.Busy)
        {
        }
    
        //
        // Write data to transfer into DATA-A and DATA-B interface registers
        //
        uint16_t index;
        for(index = 0; index < messageSize; index++)
        {
            switch(index)
            {
                case 0:
                    CanaRegs.CAN_IF1DATA.bit.Data_0 = ucTXMsgData[index];
                    break;
                case 1:
                    CanaRegs.CAN_IF1DATA.bit.Data_1 = ucTXMsgData[index];
                    break;
                case 2:
                    CanaRegs.CAN_IF1DATA.bit.Data_2 = ucTXMsgData[index];
                    break;
                case 3:
                    CanaRegs.CAN_IF1DATA.bit.Data_3 = ucTXMsgData[index];
                    break;
                case 4:
                    CanaRegs.CAN_IF1DATB.bit.Data_4 = ucTXMsgData[index];
                    break;
                case 5:
                    CanaRegs.CAN_IF1DATB.bit.Data_5 = ucTXMsgData[index];
                    break;
                case 6:
                    CanaRegs.CAN_IF1DATB.bit.Data_6 = ucTXMsgData[index];
                    break;
                case 7:
                    CanaRegs.CAN_IF1DATB.bit.Data_7 = ucTXMsgData[index];
                    break;
            }
        }
    
        //
        // Set Direction to write and set DATA-A/DATA-B to be transfered to
        // message object
        //
        CAN_IF1CMD_SHADOW.all = 0;
        CAN_IF1CMD_SHADOW.bit.DIR = 1;
        CAN_IF1CMD_SHADOW.bit.DATA_A = 1;
        CAN_IF1CMD_SHADOW.bit.DATA_B = 1;
    
        //
        // Set Tx Request Bit
        //
        CAN_IF1CMD_SHADOW.bit.TXRQST = 1;
    
        //
        // Transfer the message object to the message object specified by
        // objID.
        //
        CAN_IF1CMD_SHADOW.bit.MSG_NUM = objID;
        CanaRegs.CAN_IF1CMD.all = CAN_IF1CMD_SHADOW.all;
    }
    
    //
    // getCANMessage - Check the message object for new data.
    //                 If new data, data written into array and return true.
    //                 If no new data, return false.
    //
    bool getCANMessage(uint32_t objID)
    {
        bool status;
        
        //
        // Use Shadow variable for IF2CMD. IF2CMD should be written to in
        // single 32-bit write.
        //
        union CAN_IF2CMD_REG CAN_IF2CMD_SHADOW;
    
        //
        // Set the Message Data A, Data B, and control values to be read
        // on request for data from the message object.
        //
        CAN_IF2CMD_SHADOW.all = 0;
        CAN_IF2CMD_SHADOW.bit.Control = 1;
        CAN_IF2CMD_SHADOW.bit.DATA_A = 1;
        CAN_IF2CMD_SHADOW.bit.DATA_B = 1;
    
        //
        // Transfer the message object to the message object IF register.
        //
        CAN_IF2CMD_SHADOW.bit.MSG_NUM = objID;
        CanaRegs.CAN_IF2CMD.all = CAN_IF2CMD_SHADOW.all;
    
        //
        // Wait for busy bit to clear.
        //
        while(CanaRegs.CAN_IF2CMD.bit.Busy)
        {
        }
    
        //
        // See if there is new data available.
        //
        if(CanaRegs.CAN_IF2MCTL.bit.NewDat == 1)
        {
            //
            // Read out the data from the CAN registers.
            //
            uint16_t index;
            for(index = 0; index < messageSize; index++)
            {
                switch(index)
                {
                    case 0:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATA.bit.Data_0;
                    break;
                    case 1:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATA.bit.Data_1;
                    break;
                    case 2:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATA.bit.Data_2;
                    break;
                    case 3:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATA.bit.Data_3;
                    break;
                    case 4:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATB.bit.Data_4;
                    break;
                    case 5:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATB.bit.Data_5;
                    break;
                    case 6:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATB.bit.Data_6;
                    break;
                    case 7:
                        ucRXMsgData[index] = CanaRegs.CAN_IF2DATB.bit.Data_7;
                    break;
                }
            }
    
            //
            // Populate Shadow Variable
            //
            CAN_IF2CMD_SHADOW.all = CanaRegs.CAN_IF2CMD.all;
    
            //
            // Clear New Data Flag
            //
            CAN_IF2CMD_SHADOW.bit.TxRqst = 1;
    
            //
            // Transfer the message object to the message object IF register.
            //
            CAN_IF2CMD_SHADOW.bit.MSG_NUM = objID;
            CanaRegs.CAN_IF2CMD.all = CAN_IF2CMD_SHADOW.all;
    
            status = true;
        }
        else
        {
            status = false;
        }
    
        return(status);
    }
    
    void DisableMessageObject(uint32_t objID)
    {
        EALLOW;
        // Use Shadow variable for IF1CMD. IF1CMD should be written to in single 32-bit write.
        union CAN_IF1CMD_REG CAN_IF1CMD_SHADOW;
        // Wait for busy bit to clear.
        while(CanaRegs.CAN_IF1CMD.bit.Busy)
        {
        }
        CAN_IF1CMD_SHADOW.all = 0;
        // Set the  Arb bit so that they get transferred to the Message object.
        CAN_IF1CMD_SHADOW.bit.Arb = 1;
        CAN_IF1CMD_SHADOW.bit.DIR = 1;
        // Disable the Mailbox
        CanaRegs.CAN_IF1ARB.bit.MsgVal = 0;
        // Transfer data to message object RAM
        CAN_IF1CMD_SHADOW.bit.MSG_NUM = objID;
        CanaRegs.CAN_IF1CMD.all = CAN_IF1CMD_SHADOW.all;
    }
    
    //
    // End of file
    //
    

  • Any update? Did the code work for you?

  • Hi Hareesh,

    Yes, it's works for me.
    Thank you very much.

    Regards