//#############################################################################
// 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
//
Comments
Please log in or sign up to comment.