N Lopez
Created May 14, 2021

Onboard CAN TI C2000 LaunchPad XL

This project activates the onboard CAN Controller and Transceiver to allow for fault tolerant communication in a lab environment.

Intermediate1 hour20
Onboard CAN TI C2000 LaunchPad XL

Things used in this project

Hardware components

Texas Instruments TI C2000 LaunchPad XL
×2
BeagleBone Black
BeagleBoard.org BeagleBone Black
×1

Software apps and online services

Code Composer Studio
Texas Instruments Code Composer Studio

Story

Read more

Custom parts and enclosures

Compiled Report

CAN Tech Ref

Onboard CAN Communications CCS Project

Code

Onboard CAN Communications

C/C++
//#############################################################################
// FILE MODIFIED FOR USE WITH UIUC SE423 MECHATRONICS CLASS
// Original comments left in place for better understanding.

// FILE:   can_ex2_loopback_interrupts.c
//
// TITLE:   CAN External Loopback with Interrupts Example
//
//! \addtogroup driver_example_list
//! <h1> CAN External Loopback with Interrupts </h1>
//!
//! This example 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.  A CAN interrupt
//! handler is used to confirm message transmission and count the number of
//! messages that have been sent.
//!
//! This example sets up the CAN controller in External Loopback test mode.
//! Data transmitted is visible on the CANTXA pin and is received internally
//! back to the CAN Core. CAN-B module is not involved.
//!
//! Note: "External" loopback does not mean the loopback is done externally.
//! The loopback is done internally, but the transmitted data can be seen
//! externally on the CANTX pin.
//!
//! \b External \b Connections \n
//!  - None. (Transmitting node generates its own ACK)
//!
//! \b Watch \b Variables \n
//!  - txMsgCount - A counter for the number of messages sent
//!  - rxMsgCount - A counter for the number of messages received
//!  - txMsgData - An array with the data being sent
//!  - rxMsgData - An array with the data that was received
//!  - errorFlag - A flag that indicates an error has occurred
//!
//
//#############################################################################
// $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 "driverlib.h"
#include "device.h"

//
// Defines
//
// New device configuratin definitions to use onboard transceiver. 
// I don't think the first set of defines are required as they are not used.
// The second defines are used to set the PinMux on the GPIO pins.
#define DEVICE_GPIO_PIN_CANTXB 12U
#define DEVICE_GPIO_PIN_CANRXB 17U

#define DEVICE_GPIO_CFG_CANRXB_OB GPIO_17_CANRXB
#define DEVICE_GPIO_CFG_CANTXB_OB GPIO_12_CANTXB


// MSG_OBJ_ID values define which "mailbox" is used for the below message setups.
// Note that these are *not* the CAN Message IDs, those are taken care of separately.
#define MSG_DATA_LENGTH    4
#define TX_MSG_OBJ_ID      1
#define RX_MSG_OBJ_ID      2
#define TX2_MSG_OBJ_ID     3

//
// Globals
//
volatile uint32_t txMsgCount = 0;
volatile uint32_t rxMsgCount = 0;
volatile uint32_t errorFlag = 0;

// Received and Transmitted data goes into these arrays
uint16_t txMsgData[MSG_DATA_LENGTH];
uint16_t rxMsgData[MSG_DATA_LENGTH];
uint16_t tx2MsgData[MSG_DATA_LENGTH];

//
// Function Prototypes
//
__interrupt void canISR(void);

//
// Main
//
void main(void)
{
    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Initialize GPIO and configure GPIO pins for CANTX/CANRX
    //
    Device_initGPIO();
    
    // Set the PinConfig with our new definitions
    GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXB_OB);
    GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXB_OB);

    //
    // Initialize the CAN controller
    //
    // Puts the module in Initialization mode, Disables the parity function
    // Initializes the MBX RAM, Initiates a S/W reset of the module
    // Seeks write-access to configuration registers.
    //
    
    // Initialize with CANB_BASE anywhere CANA_BASE is seen
    CAN_initModule(CANB_BASE);

    //
    // Set up the CAN bus bit rate to 500 kbps
    // 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.
    //
    
    // The bitrate here is 500kbps. Note that if the predefined symbol for the F28379D isn't set then this will run at half speed.
    CAN_setBitRate(CANB_BASE, DEVICE_SYSCLK_FREQ, 500000, 20);

    //
    // Enable interrupts on the CAN peripheral.
    // Enables Interrupt line 0, Error & Status Change interrupts in CAN_CTL
    // register.
    //
    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_CANB0, &canISR);

    //
    // Enable the CAN interrupt signal
    //
    Interrupt_enable(INT_CANB0);
    CAN_enableGlobalInterrupt(CANB_BASE, CAN_GLOBAL_INT_CANINT0);

    //
    // Enable CAN test mode with external loopback
    //
//    CAN_enableTestMode(CANB_BASE, CAN_TEST_EXL);


    // Setup Mailboxes
    /*
    Setup(CAN Controller, Mailbox Number, CAN Message ID, Type of CAN message,
            Transmit or Receive, CAN Message ID mask (0 for exact match, 0x3FF for catch-all),
            Enable Specific Interrupt, Length of message)

    CAN Controller: CANA_BASE, CANB_BASE
    Mailbox Number: 1-32
    CAN Message ID: Standard(0x1 - 0x3FF)
    Type of CAN message: CAN_MSG_FRAME_STD, CAN_MSG_FRAME_EXT
    Interrupt options: CAN_MSG_OBJ_TX_INT_ENABLE, CAN_MSG_OBJ_RX_INT_ENABLE, CAN_MSG_OBJ_NO_FLAGS
    */

    //
    // Initialize the transmit message object used for sending CAN messages.
    // Message Object Parameters:
    //      Message Object ID Number: 1
    //      Message Identifier: 0x1
    //      Message Frame: Standard
    //      Message Type: Transmit
    //      Message ID Mask: 0x0
    //      Message Object Flags: Transmit Interrupt
    //      Message Data Length: 4 Bytes
    //

    // Master Transmit 0x1, Rx 0x2
    // Slave Transmit 0x2, Rx 0x1

    CAN_setupMessageObject(CANB_BASE, TX_MSG_OBJ_ID, 0x2, CAN_MSG_FRAME_STD,
                           CAN_MSG_OBJ_TYPE_TX, 0, CAN_MSG_OBJ_TX_INT_ENABLE,
                           MSG_DATA_LENGTH);

    //
    // Initialize the receive message object used for receiving CAN messages.
    // Message Object Parameters:
    //      Message Object ID Number: 2
    //      Message Identifier: 0x1
    //      Message Frame: Standard
    //      Message Type: Receive
    //      Message ID Mask: 0x0
    //      Message Object Flags: Receive Interrupt
    //      Message Data Length: 4 Bytes
    //
    CAN_setupMessageObject(CANB_BASE, RX_MSG_OBJ_ID, 0x1, CAN_MSG_FRAME_STD,
                           CAN_MSG_OBJ_TYPE_RX, 0, CAN_MSG_OBJ_RX_INT_ENABLE,
                           MSG_DATA_LENGTH);

    CAN_setupMessageObject(CANB_BASE, TX2_MSG_OBJ_ID, 0x3, CAN_MSG_FRAME_STD,
                           CAN_MSG_OBJ_TYPE_TX, 0, CAN_MSG_OBJ_NO_FLAGS,
                           MSG_DATA_LENGTH);

    //
    // Initialize the transmit message object data buffer to be sent
    //
    // Master
//    txMsgData[0] = 0x12;
//    txMsgData[1] = 0x34;
//    txMsgData[2] = 0x56;
//    txMsgData[3] = 0x78;

    //
    // Start CAN module operations
    //
    CAN_startModule(CANB_BASE);

    //
    // Loop Forever - A new message will be sent once per second.
    //
    for(;;)
    {
        //
        // Check the error flag to see if errors occurred
        //
        if(errorFlag)
        {
            Example_Fail = 1;
            asm("   ESTOP0");
        }

        //
        // Verify that the number of transmitted messages equal the number of
        // messages received before sending a new message
        //
//        if(txMsgCount == rxMsgCount)
//        {
        
        // To send a message you simply call the below function. 
        // This can happen inside CPUtimer functions without issue
        CAN_sendMessage(CANB_BASE, TX_MSG_OBJ_ID, MSG_DATA_LENGTH,
                        txMsgData);

        // Slave
        CAN_sendMessage(CANB_BASE, TX2_MSG_OBJ_ID, MSG_DATA_LENGTH,
                        tx2MsgData);


        Example_PassCount++;
//        }
//        else
//        {
//            errorFlag = 1;
//        }

        //
        // Delay 1 second before continuing
        //
        
        // If the build does not have the predefined symbol, this will take 2 seconds instead of 1.
        DEVICE_DELAY_US(1000000);

        //
        // Increment the value in the transmitted message data.
        //

        // Master
//        txMsgData[0] += 0x01;
//        txMsgData[1] += 0x01;
//        txMsgData[2] += 0x01;
//        txMsgData[3] += 0x01;


        // Slave
        txMsgData[0] = rxMsgData[0];
        txMsgData[1] = rxMsgData[1];
        txMsgData[2] = rxMsgData[2];
        txMsgData[3] = rxMsgData[3];


        //
        // 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;
        }
    }
}

//
// CAN ISR - The interrupt service routine called when a CAN interrupt is
//           triggered.  It checks for the cause of the interrupt, and
//           maintains a count of all messages that have been transmitted.
//

// CAN Interrupt unmodified from example EXCEPT CANA_BASE replaced with CANB_BASE
__interrupt void
canISR(void)
{
    uint32_t status;

    //
    // Read the CAN 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.
        //
        if(((status  & ~(CAN_STATUS_TXOK | CAN_STATUS_RXOK)) != 7) &&
           ((status  & ~(CAN_STATUS_TXOK | CAN_STATUS_RXOK)) != 0))
        {
            //
            // Set a flag to indicate some errors may have occurred.
            //
            errorFlag = 1;
        }
    }

    //
    // Check if the cause is the transmit message object 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(CANB_BASE, TX_MSG_OBJ_ID);

        //
        // Increment a counter to keep track of how many messages have been
        // sent.  In a real application this could be used to set flags to
        // indicate when a message is sent.
        //
        txMsgCount++;

        //
        // Since the message was sent, clear any error flags.
        //
        errorFlag = 0;
    }

    //
    // Check if the cause is the receive message object 2
    //
    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 2, and the message RX is complete.  Clear the
        // message object interrupt.
        //
        CAN_clearInterruptStatus(CANB_BASE, RX_MSG_OBJ_ID);

        //
        // Increment a counter to keep track of how many messages have been
        // received. In a real application this could be used to set flags to
        // indicate when a message is 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
//

Credits

N Lopez
2 projects • 1 follower
Contact

Comments

Please log in or sign up to comment.