Part Number: LAUNCHXL-F28379D
Tool/software: Code Composer Studio
I have been trying to get an interrupt based message system working on two of the Delfino LaunchpadXL's. I was able to get bidirectional code without interrupts working with multiple messages but it required me to add delay after each message is sent or received. When adding interrupt functionality, the messages get through at first but then, after 3-10 messages (it changes each time), the code gets stuck with each board waiting for an ACK from the other, I end up with LEC =111. I'm most interested in Rx interrupts so I've disable Tx ones for now.
I'm guessing this is some timing issues but I haven't been able to find online specifications for timing, the standards I'm using dictate using 500kbps and 5 messages. The example code is used for the ISR with some modifications. Code for one of the boards is below, the other is very similar but obviously has the Tx and Rx msg definitions switched.
#include "driverlib.h"
#include "device.h"
#define MSG_DATA_LENGTH 8
#define RX_MSG_OBJ_ID100 1 // Use mailbox 1
#define RX_MSG_OBJ_ID101 2 // Use mailbox 2
#define RX_MSG_OBJ_ID102 3 // Use mailbox 3
#define TX_MSG_OBJ_ID108 4 // Use mailbox 4
#define TX_MSG_OBJ_ID109 5 // Use mailbox 5
#define V2C_ID100 0x100
#define V2C_ID101 0x101
#define V2C_ID102 0x102
#define C2V_ID108 0x108
#define C2V_ID109 0x109
volatile uint32_t txMsgCount = 0;
volatile uint32_t rx100, rx101, rx102;
volatile uint32_t errorFlag = 0;
uint32_t glblStatus;
//each rx and tx msg gets its own variable
uint16_t rxMsgData100[8],rxMsgData101[8],rxMsgData102[8];
uint16_t txMsgData108[8],txMsgData109[8];
int sent108 = 0;
int sent109 = 0;
__interrupt void canbISR(void); // Receive interrupt for CAN-B.
// Main
//
void main(void)
{
// Initialize device clock and peripherals
Device_init();
// Configure GPIO pins for CANTX/CANRX
Device_initGPIO();
GPIO_setPinConfig(GPIO_12_CANTXB);
GPIO_setPinConfig(GPIO_17_CANRXB);
// Initialize the CAN controller
CAN_initModule(CANB_BASE);
// Set up the CAN bus bit rate to 500kHz for each module
CAN_setBitRate(CANB_BASE, DEVICE_SYSCLK_FREQ, 500000, 16);
// Enable interrupts on the CAN B peripheral.
// Enables Int.line0, Error & Status Change interrupts
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, &canbISR);
// Enable the CAN-B interrupt signal
Interrupt_enable(INT_CANB0);
// Set GLBINT0_EN bit in CAN_GLB_INT_EN register
CAN_enableGlobalInterrupt(CANB_BASE, CAN_GLOBAL_INT_CANINT0);
// Initialize the receive and transmit messages object V2C and C2V.
// Message Object Parameters:
// CAN Module: B --all
// Message Object ID Number: 1,2,3,4,5
// Message Identifier: 0x100,0x101,0x102,0x108,0x109
// Message Frame: Standard --all
// Message Type: Receive 3x, transmit 2x
// Message ID Mask: 0x0
// Message Object Flags: receive interrupts, idk about transmit ones yet
// Message Data Length: just keep everything at 8 bytes
//
CAN_setupMessageObject(CANB_BASE, RX_MSG_OBJ_ID100, V2C_ID100,
CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_RX, 0,
CAN_MSG_OBJ_RX_INT_ENABLE, MSG_DATA_LENGTH);
CAN_setupMessageObject(CANB_BASE, RX_MSG_OBJ_ID101, V2C_ID101,
CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_RX, 0,
CAN_MSG_OBJ_RX_INT_ENABLE, MSG_DATA_LENGTH);
CAN_setupMessageObject(CANB_BASE, RX_MSG_OBJ_ID102, V2C_ID102,
CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_RX, 0,
CAN_MSG_OBJ_RX_INT_ENABLE, MSG_DATA_LENGTH);
CAN_setupMessageObject(CANB_BASE, TX_MSG_OBJ_ID108, C2V_ID108,
CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_TX, 0,
CAN_MSG_OBJ_NO_FLAGS, MSG_DATA_LENGTH);
CAN_setupMessageObject(CANB_BASE, TX_MSG_OBJ_ID109, C2V_ID109,
CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_TX, 0,
CAN_MSG_OBJ_NO_FLAGS, MSG_DATA_LENGTH);
txMsgData108[0] = 0x01;
txMsgData108[1] = 0x23;
txMsgData108[2] = 0x45;
txMsgData108[3] = 0x67;
txMsgData108[4] = 0x89;
txMsgData108[5] = 0xAB;
txMsgData108[6] = 0xCD;
txMsgData108[7] = 0xEF;
txMsgData109[0] = 0x01;
txMsgData109[1] = 0x23;
txMsgData109[2] = 0x45;
txMsgData109[3] = 0x67;
txMsgData109[4] = 0x89;
txMsgData109[5] = 0xAB;
txMsgData109[6] = 0xCD;
txMsgData109[7] = 0xEF;
// Start CAN module B operations
CAN_startModule(CANB_BASE);
// Start msg exchange
while(1)
{
// Delay in us before continuing, hopefully allows enough time for rx interrupt,
//lower id anyways, this may not be necessary
DEVICE_DELAY_US(1000);
CAN_sendMessage(CANB_BASE, TX_MSG_OBJ_ID108, MSG_DATA_LENGTH, txMsgData108);
while(((HWREGH(CANB_BASE + CAN_O_ES) & CAN_ES_TXOK)) != CAN_ES_TXOK)
{
CAN_sendMessage(CANB_BASE, TX_MSG_OBJ_ID108, MSG_DATA_LENGTH, txMsgData108);
}
sent108++;
DEVICE_DELAY_US(1000);
CAN_sendMessage(CANB_BASE, TX_MSG_OBJ_ID109, MSG_DATA_LENGTH, txMsgData109);
while(((HWREGH(CANB_BASE + CAN_O_ES) & CAN_ES_TXOK)) != CAN_ES_TXOK)
{
CAN_sendMessage(CANB_BASE, TX_MSG_OBJ_ID109, MSG_DATA_LENGTH, txMsgData109);
}
sent109++;
DEVICE_DELAY_US(1000);
}
}
__interrupt void
canbISR(void)
{
uint32_t status;
// Read the CAN-B interrupt status (in the CAN_INT register) to find the
// cause of the interrupt
status = CAN_getInterruptCause(CANB_BASE);
// If the cause is a controller status interrupt, then get the status.
// During first iteration of every ISR execution, status = 0x8000,
// which simply means CAN_ES != 0x07.
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); // Return CAN_ES value.
// Now status = 0x00000010, indicating RxOK.
// Check to see if an error occurred.
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;
glblStatus = status;
}
}
else if((status == TX_MSG_OBJ_ID108) ||(status == TX_MSG_OBJ_ID109))
{
//
// 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, status); //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 CAN-B receive message object 1. Will be skipped
// in the first iteration of every ISR execution
else if(status == RX_MSG_OBJ_ID100)
{
while(!(((HWREGH(CANB_BASE + CAN_O_ES) & CAN_ES_RXOK)) == CAN_ES_RXOK))
{}
// Get the received message
CAN_readMessage(CANB_BASE, RX_MSG_OBJ_ID100, rxMsgData100);
DEVICE_DELAY_US(1000);
// 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_ID100);
// 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.
rx100++;
// Since the message was received, clear any error flags.
errorFlag = 0;
}
else if((status == RX_MSG_OBJ_ID101))
{
while(!(((HWREGH(CANB_BASE + CAN_O_ES) & CAN_ES_RXOK)) == CAN_ES_RXOK))
{}
// Get the received message
CAN_readMessage(CANB_BASE, RX_MSG_OBJ_ID101, rxMsgData101);
DEVICE_DELAY_US(1000);
// 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_ID101);
// 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.
rx101++;
// Since the message was received, clear any error flags.
errorFlag = 0;
}
else if(status == RX_MSG_OBJ_ID102)
{
while(!(((HWREGH(CANB_BASE + CAN_O_ES) & CAN_ES_RXOK)) == CAN_ES_RXOK))
{}
// Get the received message
CAN_readMessage(CANB_BASE, RX_MSG_OBJ_ID102, rxMsgData102);
DEVICE_DELAY_US(1000);
// 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_ID102);
// 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.
rx102++;
// 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);
}