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.

TMS320F28388D: CAN communication example

Part Number: TMS320F28386D
Other Parts Discussed in Thread: C2000WARE

Hello everyone, 

I have to test  CAN_A  and CAN_B  in TMS320F28386D in a custom board provided of CAN transceiver, what is the appropriate TI example to do it?

The idea is to transmit with CAN_A and receive in CAN_B or viceversa in the same board.

Thank you.

  • C:\ti\c2000\C2000Ware_5_02_00_00\driverlib\f2837xd\examples\cpu1\can\can_ex3_external_transmit

  • Correction:

    Please refer to the example with the following path - C:\ti\c2000\C2000Ware_5_02_00_00\driverlib\f2838x\examples\c28x\can\can_ex5_transmit_receive

    Thanks.

  • Hello,

    I saw the example "can_ex5_transmit_receive", it can be setted to transmit or receive to dialogue with an external board, but I have to transmit and also receive with the same board, how can I edit the code in order to do it? 

    I have to enable a second interrupt also for CAN_B?

    Thanks.

  • OK, so you want to transmit and receive using the same device i.e. use CAN-A for transmission and CAN-B for reception. We don't have an example like that but you can easily modify the example for this. Here is how you do it: 

    Make a copy of this example and replace all instances of CANA to CANB (note that this example is currently written only for CANA, for both transmit and receive configurations). It is extremely important you configure the GPIO pins correctly for CANB. Please refer to www.ti.com/lit/SPRACE5 for more information.

    I have to enable a second interrupt also for CAN_B?

    Both CANA and CANB are completely independent modules, with their own interrupt lines. Each module has 2 interrupts. Whether to use polling or interrupt is completely up to you,

  • Hello,

    as per your advice, the code is the following:

    //#############################################################################
    //
    // FILE:   can_ex5_transmit_receive.c
    //
    // TITLE:   CAN Configuration for Transmit and Receive.
    //
    //! \addtogroup driver_example_list
    //! <h1> CAN Transmit and Receive Configurations </h1>
    //!
    //! This example shows the basic setup of CAN in order to transmit or receive
    //! messages on the CAN bus with a specific Message ID. The CAN Controller is
    //! configured according to the selection of the define.
    //!
    //! When the TRANSMIT define is selected, the CAN Controller acts as a
    //! Transmitter and sends data to the second CAN Controller connected
    //! externally.If TRANMSIT is not defined the CAN Controller acts as a Receiver
    //! and waits for message to be transmitted by the External CAN Controller.
    //! Refer to [Programming Examples and Debug Strategies for
    //! the DCAN Module](www.ti.com/lit/SPRACE5) for useful information about
    //! this example
    //!
    //! \note CAN modules on the device need to be connected to via CAN
    //!       transceivers.
    //!
    //! \b Hardware \b Required \n
    //!  - A C2000 board with CAN transceiver.
    //!
    //! \b External \b Connections \n
    //!  - ControlCARD CANA is on DEVICE_GPIO_PIN_CANTXA (CANTXA)
    //!  - and DEVICE_GPIO_PIN_CANRXA (CANRXA)
    //!
    //! \b Watch \b Variables \b Transmit \Configuration \n
    //!  - MSGCOUNT   - Adjust to set the number of messages
    //!  - txMsgCount - A counter for the number of messages sent
    //!  - txMsgData  - An array with the data being sent
    //!  - errorFlag  - A flag that indicates an error has occurred
    //!  - rxMsgCount - Has the initial value as No. of Messages to be received
    //!                 and decrements with each message.
    //!
    //
    //#############################################################################
    
    //
    // Included Files
    //
    #include "driverlib.h"
    #include "device.h"
    
    //
    // Comment to Make the CAN Controller work as a Receiver.
    //
    
    //
    // Defines
    //
    //TRANSMIT
    #define TX_MSG_OBJ_ID    1
    //RECEIVE
    #define RX_MSG_OBJ_ID    1
    
    #define MSG_DATA_LENGTH  4
    #define MSGCOUNT        10
    
    //
    // Globals
    //
    //TRANSMIT
    volatile uint32_t txMsgCount = 0;
    uint32_t txMsgSuccessful  = 1;
    uint16_t txMsgData[4];
    //RECEIVE
    volatile uint32_t rxMsgCount = MSGCOUNT;
    uint16_t rxMsgData[4];
    
    volatile unsigned long i;
    volatile uint32_t errorFlag = 0;
    
    
    //
    // Function Prototypes
    //
    __interrupt void canaISR(void);
    __interrupt void canbISR(void);
    
    //
    // Main
    //
    void main(void)
    {
        //
        // Initialize device clock and peripherals
        //
        Device_init();
    
        //
        // Initialize GPIO and configure GPIO pins for CANTX/CANRX
        // on module A.
        //
        Device_initGPIO();
        GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA);
        GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXA);
        GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXB);
        GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXB);
    
        //
        // Allocated shared peripheral to C28x
        //
        SysCtl_allocateSharedPeripheral(SYSCTL_PALLOCATE_CAN_A,0x0U);
        SysCtl_allocateSharedPeripheral(SYSCTL_PALLOCATE_CAN_B,0x0U);
    
        //
        // Initialize the CAN controllers
        //
        CAN_initModule(CANA_BASE);
        CAN_initModule(CANB_BASE);
    
        //
        // Set up the CAN bus bit rate to 500kHz for each module
        // Refer to the Driver Library User Guide for information on how to set
        // tighter timing control. Additionally, consult the device data sheet
        // for more information about the CAN module clocking.
        //
        CAN_setBitRate(CANA_BASE, DEVICE_SYSCLK_FREQ, 500000, 20);
        CAN_setBitRate(CANB_BASE, DEVICE_SYSCLK_FREQ, 500000, 20);
    
        //
        // Enable interrupts on the CAN A and CAN B peripheral.
        //
        CAN_enableInterrupt(CANA_BASE, CAN_INT_IE0 | CAN_INT_ERROR |
                            CAN_INT_STATUS);
        CAN_enableInterrupt(CANB_BASE, CAN_INT_IE0 | CAN_INT_ERROR |
                            CAN_INT_STATUS);
    
        //
        // Initialize PIE and clear PIE registers. Disables CPU interrupts.
        //
        Interrupt_initModule();
    
        //
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        //
        Interrupt_initVectorTable();
    
        //
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        //
        EINT;
        ERTM;
    
        //
        // Interrupts that are used in this example are re-mapped to
        // ISR functions found within this file.
        // This registers the interrupt handler in PIE vector table.
        //
        Interrupt_register(INT_CANA0,&canaISR);
        Interrupt_register(INT_CANB0,&canbISR);
    
        //
        // Enable the CAN-A interrupt signal
        //
        Interrupt_enable(INT_CANA0);
    
        CAN_enableGlobalInterrupt(CANA_BASE, CAN_GLOBAL_INT_CANINT0);
    
        // Enable the CAN-B interrupt signal
        //
        Interrupt_enable(INT_CANB0);
    
        CAN_enableGlobalInterrupt(CANB_BASE, CAN_GLOBAL_INT_CANINT0);
    
    //TRANSMIT
        //
        // Initialize the transmit message object used for sending CAN messages.
        // Message Object Parameters:
        //      CAN Module: A
        //      Message Object ID Number: 1
        //      Message Identifier: 0x15555555
        //      Message Frame: Extended
        //      Message Type: Transmit
        //      Message ID Mask: 0x0
        //      Message Object Flags: None
        //      Message Data Length: 4 Bytes
        //
        CAN_setupMessageObject(CANA_BASE, TX_MSG_OBJ_ID, 0x15555555,
                               CAN_MSG_FRAME_EXT, CAN_MSG_OBJ_TYPE_TX, 0,
                               CAN_MSG_OBJ_TX_INT_ENABLE, MSG_DATA_LENGTH);
        //
        // Initialize the transmit message object data buffer to be sent
        //
        txMsgData[0] = 0x12;
        txMsgData[1] = 0x34;
        txMsgData[2] = 0x56;
        txMsgData[3] = 0x78;
    
        //
        // Start CAN module A operations
        //
        CAN_startModule(CANA_BASE);
    
        //
        // Transmit messages from CAN-A.
        //
        for(i = 0; i < MSGCOUNT; i++)
        {
            //
            // Check the error flag to see if errors occurred
            //
            if(errorFlag)
            {
                asm("   ESTOP0");
            }
    
            //
            // Transmit the message.
            //
            CAN_sendMessage(CANA_BASE, TX_MSG_OBJ_ID, MSG_DATA_LENGTH,
                            txMsgData);
    
            //
            // Delay 0.25 second before continuing
            //
            DEVICE_DELAY_US(250000);
    
            //while(txMsgSuccessful);
            //
            // Increment the value in the transmitted message data.
            //
            txMsgData[0] += 0x01;
            txMsgData[1] += 0x01;
            txMsgData[2] += 0x01;
            txMsgData[3] += 0x01;
    
            //
            // Reset data if exceeds a byte
            //
            if(txMsgData[0] > 0xFF)
            {
                txMsgData[0] = 0;
            }
            if(txMsgData[1] > 0xFF)
            {
                txMsgData[1] = 0;
            }
            if(txMsgData[2] > 0xFF)
            {
                txMsgData[2] = 0;
            }
            if(txMsgData[3] > 0xFF)
            {
                txMsgData[3] = 0;
            }
    
            //
            // Update the flag for next message.
            //
            txMsgSuccessful  = 1;
        }
    
    //RECEIVE
        // Initialize the receive message object used for receiving CAN messages.
        // Message Object Parameters:
        //      CAN Module: A
        //      Message Object ID Number: 1
        //      Message Identifier: 0x15555555
        //      Message Frame: Extended
        //      Message Type: Receive
        //      Message ID Mask: 0x0
        //      Message Object Flags: Receive Interrupt
        //      Message Data Length: 4 Bytes (Note that DLC field is a "don't care"
        //      for a Receive mailbox
        //
        CAN_setupMessageObject(CANB_BASE, RX_MSG_OBJ_ID, 0x15555555,
                               CAN_MSG_FRAME_EXT, CAN_MSG_OBJ_TYPE_RX, 0,
                               CAN_MSG_OBJ_RX_INT_ENABLE, MSG_DATA_LENGTH);
    
        //
        // Loop to keep receiving data from another CAN Controller.
        //
        while(rxMsgCount)
        {
        }
    
        //
        // Stop application after completion.
        //
        asm("   ESTOP0");
    }
    
    __interrupt void
    canaISR(void)
    {
        uint32_t status;
    
        //
        // Read the CAN-B interrupt status to find the cause of the interrupt
        //
        status = CAN_getInterruptCause(CANA_BASE);
    
        //
        // If the cause is a controller status interrupt, then get the status
        //
        if(status == CAN_INT_INT0ID_STATUS)
        {
            //
            // Read the controller status.  This will return a field of status
            // error bits that can indicate various errors.  Error processing
            // is not done in this example for simplicity.  Refer to the
            // API documentation for details about the error status bits.
            // The act of reading this status will clear the interrupt.
            //
            status = CAN_getStatus(CANA_BASE);
    
            //
            // Check to see if an error occurred.
            //
    //TRANSMIT
            if(((status  & ~(CAN_STATUS_TXOK)) != CAN_STATUS_LEC_MSK) &&
               ((status  & ~(CAN_STATUS_TXOK)) != CAN_STATUS_LEC_NONE))
    
            {
                //
                // Set a flag to indicate some errors may have occurred.
                //
                errorFlag = 1;
            }
        }
        else if(status == TX_MSG_OBJ_ID)
        {
            //
            // Getting to this point means that the TX interrupt occurred on
            // message object 1, and the message TX is complete.  Clear the
            // message object interrupt.
            //
            CAN_clearInterruptStatus(CANA_BASE, TX_MSG_OBJ_ID);
    
            //
            // Increment a counter to keep track of how many messages have been
            // transmitted. In a real application this could be used to set flags to
            // indicate when a message is transmitted.
            //
            txMsgCount++;
    
            //
            // Since the message was transmitted, clear any error flags.
            //
            errorFlag = 0;
    
            //
            // Clear the message transmitted successful Flag.
            //
            txMsgSuccessful  = 0;
        }
        //
        // If something unexpected caused the interrupt, this would handle it.
        //
        else
        {
            //
            // Spurious interrupt handling can go here.
            //
        }
    
        //
        // Clear the global interrupt flag for the CAN interrupt line
        //
        CAN_clearGlobalInterruptStatus(CANA_BASE, CAN_GLOBAL_INT_CANINT0);
    
        //
        // Acknowledge this interrupt located in group 9
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
    }
    
    
    //
    // CAN B ISR - The interrupt service routine called when a CAN interrupt is
    //             triggered on CAN module B.
    //
    __interrupt void
    canbISR(void)
    {
        uint32_t status;
    
        //
        // Read the CAN-B interrupt status to find the cause of the interrupt
        //
        status = CAN_getInterruptCause(CANB_BASE);
    
        //
        // If the cause is a controller status interrupt, then get the status
        //
        if(status == CAN_INT_INT0ID_STATUS)
        {
            //
            // Read the controller status.  This will return a field of status
            // error bits that can indicate various errors.  Error processing
            // is not done in this example for simplicity.  Refer to the
            // API documentation for details about the error status bits.
            // The act of reading this status will clear the interrupt.
            //
            status = CAN_getStatus(CANB_BASE);
    
            //
            // Check to see if an error occurred.
            //
    //RECEIVE
            if(((status  & ~(CAN_STATUS_RXOK)) != CAN_STATUS_LEC_MSK) &&
               ((status  & ~(CAN_STATUS_RXOK)) != CAN_STATUS_LEC_NONE))
    
            {
                //
                // Set a flag to indicate some errors may have occurred.
                //
                errorFlag = 1;
            }
        }
        else if(status == RX_MSG_OBJ_ID)
        {
            //
            // Get the received message
            //
            CAN_readMessage(CANB_BASE, RX_MSG_OBJ_ID, rxMsgData);
    
            //
            // Getting to this point means that the RX interrupt occurred on
            // message object 1, and the message RX is complete.  Clear the
            // message object interrupt.
            //
            CAN_clearInterruptStatus(CANB_BASE, RX_MSG_OBJ_ID);
    
            //
            // Decrement the counter after a message has been received.
            //
            rxMsgCount--;
    
            //
            // Since the message was received, clear any error flags.
            //
            errorFlag = 0;
        }
    
        //
        // If something unexpected caused the interrupt, this would handle it.
        //
        else
        {
            //
            // Spurious interrupt handling can go here.
            //
        }
    
        //
        // Clear the global interrupt flag for the CAN interrupt line
        //
        CAN_clearGlobalInterruptStatus(CANB_BASE, CAN_GLOBAL_INT_CANINT0);
    
        //
        // Acknowledge this interrupt located in group 9
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
    }
    
    //
    // End of File
    //
    

    The transmission seems ok(in debug I see txMsgData to increment) but rxMsgData values are always 0 and rxMsgCount does not decrement.

    I connected in the same board, for the transceivers:

    • CANL_A to CANL_B
    • CANH_A to CANH_B
    • GND_CANA to GND_CANB

    I setted an other interrupt on CANB to receive.

    I edited the GPIO pins for the CANB for my custom board (file device.h):

    // CANA
    //
    #define DEVICE_GPIO_PIN_CANTXA      37U  // GPIO number for CANTXA
    #define DEVICE_GPIO_PIN_CANRXA      36U  // GPIO number for CANRXA
    // CANB
    //
    #define DEVICE_GPIO_PIN_CANTXB      16U  // GPIO number for CANTXA
    #define DEVICE_GPIO_PIN_CANRXB      17U  // GPIO number for CANRXA
    
    //
    // CAN External Loopback
    #define DEVICE_GPIO_CFG_CANRXA      GPIO_36_CANA_RX  // "pinConfig" for CANA RX
    #define DEVICE_GPIO_CFG_CANTXA      GPIO_37_CANA_TX  // "pinConfig" for CANA TX
    #define DEVICE_GPIO_CFG_CANRXB      GPIO_17_CANB_RX  // "pinConfig" for CANB RX
    #define DEVICE_GPIO_CFG_CANTXB      GPIO_16_CANB_TX  // "pinConfig" for CANB TX

    The approach is it correct? What else have I to edit?

  • Did you look at the debug tips in SPRACE5? 

  • I haven’t heard from you in a while. I presume your issue is resolved.

  • Hello,

    Sorry for the response delay.

    I have read the document (SPRACE5), I think that all the points are respected (I'm using the example code with the correct GPIOs and added the canbISR part taking inspiration from canaISR). For the hardware, I added the 120ohm resistor at either ends of connections.

    This is the scope of CANL and CANH:

     

    From this scope, I don't understand if the message is correct (the ID It doesn't seem correct).

    As I said, from debug rxMsgData values are always 0 and rxMsgCount does not decrement, so something is not working.

    These are the setup of the modules A and B:

    // CAN Module: A
    // Message Object ID Number: 1
    // Message Identifier: 0x15555555
    // Message Frame: Extended
    // Message Type: Transmit
    // Message ID Mask: 0x0
    // Message Object Flags: None
    // Message Data Length: 4 Bytes
    
    // CAN Module: B
    // Message Object ID Number: 1
    // Message Identifier: 0x15555555
    // Message Frame: Extended
    // Message Type: Receive
    // Message ID Mask: 0x0
    // Message Object Flags: Receive Interrupt
    // Message Data Length: 4 Bytes (Note that DLC field is a "don't care"
    // for a Receive mailbox
    
    
        //
        txMsgData[0] = 0x12;
        txMsgData[1] = 0x34;
        txMsgData[2] = 0x56;
        txMsgData[3] = 0x78;

  • Your waveform does look like a valid CAN frame. If your scope is capable of triggering on CAN frames, that makes things easy for you because you can see your data decoded on the scope screen itself. As recommended in SPRACE5, I suggest not using interrupts initially. Just transmit a single frame and probe the CANRX pin of the receiving module. Once you ensure data reaches the CANRX pin, you can read the data using the IFx registers. The debug tips in SPRACE5 should finitely help if you carefully evaluate every tip and ensure compliance.