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.

Issue with CANMessageGet

Hello all, I am working with a CAN application, in this app we have a transmit layer requirement where if a message with a specific message ID is repeated, the CAN app must retransmit the last command.  In this application only two different message IDs will be received by the device.  I have set up two CAN objects for the two message IDs, and a third object for transmitting a message.  Please see attached code for details.  Also I am using a Microchip CAN bus analyzer to send data to the target.


The code seems to work correctly for the most part, but I am seeing one problem that has me stumped; the very  first block of data retrieved with CANMessageGet from CAN objects 1 and 2 reads 0x00 for all 8 bytes, even though the analyzer is sending the correct data.  The second retrieved block is correct for both CAN objects, and from that point on all is well. 


What makes it stranger is that the message ID is retrieved correctly from both CAN objects from the beginning, only the first retrieval of sCANMessageRXx.pui8MsgData from each CAN objects 1 and 2 returns all 8 message data bytes as 0x00, even though the transmitted data is different.

Could you please take a look at the code and help me find what may be causing that first message data read of CAN objects 1 and 2 to return 0x00?  This is my first work with uC's in about 14 years, so there may be rookie mistakes afoot.  Thank you for all your help.

*****************************************************************************************************

#define TARGET_IS_TM4C123_RA1  //Preprocessor define for TM4C1230E6PMI

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_can.h"
#include "inc/hw_ints.h"
#include "driverlib/can.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "inc/uartstdio.h"
#include "inc/pin_map.h"
#include "driverlib/eeprom.h"
#include "inc/tm4c1230e6pm.h"  //Defines for TM4C1230E6PM uC

volatile unsigned long g_ulMsgRXCount = 0;  //RX interrupt counter

volatile unsigned long g_ulMsgTXCount = 0;  //RTX interrupt counter

volatile unsigned long g_bRXFlag = 0;  //CAN Message received flag

volatile unsigned long g_bTXFlag = 0;  //CAN Message TX flag

volatile unsigned long g_bErrFlag = 0;  //Reception error flag

unsigned char ucMsgData1[8];
unsigned char ucMsgData2[8];
unsigned char ucMsgDataTX[8];  //Data field for TX data

uint32_t RMUSN = 0;  //Device serial number 
uint32_t pulData[1];  //EEPROM array for serial number

tCANMsgObject sCANMessageRX1;  // Msg object for CAN RX object 1

tCANMsgObject sCANMessageRX2;  // Msg object for CAN RX object 2

tCANMsgObject sCANMessageTX;  // Msg object for CAN TX object


//*****************************************************************************
//
// This function sets up UART0 to be used for a console to display information
// as the example is running.
//
//*****************************************************************************
void
InitConsole(void)
{
    
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);  //Enable GPIOA

    GPIOPinConfigure(GPIO_PA0_U0RX);  //Pin mux
    GPIOPinConfigure(GPIO_PA1_U0TX);

    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); //Alt UART function

    //
    // Initialize the UART for console I/O.
    //
    UARTStdioInit(0);  //Initialize UART
}

//*****************************************************************************
//
// This function writes the device code to the EEPROM.  The EEPROM is
// mass erased, then the sensor code is written.  This function should only be 
// run when the sensor code is set at manufacture time.
//
//*****************************************************************************
void
WriteSenCode(void)
{
    pulData[0] = 10712;  //Enter RMUIII sensor code into eeprom variable(0x29D8)
    SysCtlPeripheralEnable(SYSCTL_PERIPH_EEPROM0); //enable eeprom peripheral
    EEPROMInit();  //initialize eeprom
    EEPROMMassErase(); //mass erase eeprom at sensor code program time
    EEPROMProgram (pulData, 0x0, sizeof(pulData)); //enter sensor code into eeprom
    
}

//*****************************************************************************
//
// This function reads the device code from the EEPROM.  This function
// should only be run a single time at power up or unit reset.
//
//*****************************************************************************
void
ReadSenCode(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_EEPROM0); //enable eeprom peripheral
    EEPROMInit();  //initialize eeprom
    EEPROMRead (pulData, 0x0, sizeof(pulData)); //enter sensor code into eeprom
    RMUSN = pulData[0]; //enter recalled sensor code into variable
    
}

//*****************************************************************************
//
// This function flashes the RMUIII PCB LEDs.  Each LED is flashed in sequence
// every time a CAN packet is accepted.  LEDs are:
//
// LED1: PC4 (pin 16)
// LED2: PC5 (pin 15)
// MEAS: PC6 (pin 14)
//
// LEDs are powered directly off GPIO pins, logic high = LED on
//
//*****************************************************************************

void
FlashLEDs(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    SysCtlDelay(1);

    //
    // Configure LED pins as outputs.
    //
    GPIOPinTypeGPIOOutput(GPIO_PORTC_BASE, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6);

    //
    // Turn LEDs on and off in sequence, LEDs on with small delay.
    //
    GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_4, GPIO_PIN_4);
    SysCtlDelay(200000);   
    GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_4, 0);  
    
    GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_5, GPIO_PIN_5);
    SysCtlDelay(200000);   
    GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_5, 0); 
    
    GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_6, GPIO_PIN_6);
    SysCtlDelay(200000);   
    GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_6, 0); 
    
}

//*****************************************************************************
//
// This function initializes the CAN RX peripheral.  All of the CAN objects are
// set up once at the beginning of the main function.  The CAN objects are set
// up prior to enabling interrupts or the CAN peripheral.
//
//*****************************************************************************
void
InitCANRxTX(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); //Enable port E for CAN

    GPIOPinConfigure(GPIO_PE4_CAN0RX); //Pin mux for CAN functions
    GPIOPinConfigure(GPIO_PE5_CAN0TX);

    // Enable the alternate function on the GPIO pins.
    GPIOPinTypeCAN(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0); //Enable CAN peripheral

    CANInit(CAN0_BASE); //Initialize CAN controller

    //Set CAN bus rate to 20kbps for use with Microchip CAN bus analyzer 
    //(this is its slowest rate)
    CANBitRateSet(CAN0_BASE, SysCtlClockGet(), 20000);   
    
    // Enable interrupts on the CAN peripheral.  
    CANIntEnable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);
    
    //
    // Initialize message object 1 to be used for receiving CAN messages with
    // packet type 0x04 and the device code.  
    //

    sCANMessageRX1.ui32MsgID = (0x04000000 + RMUSN);
    sCANMessageRX1.ui32MsgIDMask = ((0x1F000000 + RMUSN) - 0x01);   // Mask to filter all non device IDs
    sCANMessageRX1.ui32Flags = MSG_OBJ_RX_INT_ENABLE | MSG_OBJ_USE_ID_FILTER;    // enable interrupt on RX
    sCANMessageRX1.ui32MsgLen = 8;       // allow up to 8 bytes
    //
    // Now load the message object into the CAN peripheral.  
    CANMessageSet(CAN0_BASE, 1, &sCANMessageRX1, MSG_OBJ_TYPE_RX);
    
    //
    // Initialize message object 2 to be used for receiving CAN messages with
    // packet type 0x05 and the device sensor code.
    //
 
    sCANMessageRX2.ui32MsgID = (0x05000000 + RMUSN);
    sCANMessageRX2.ui32MsgIDMask = ((0x1F000000 + RMUSN) - 0x01);   // Mask to filter all non device IDs
    sCANMessageRX2.ui32Flags = MSG_OBJ_RX_INT_ENABLE | MSG_OBJ_USE_ID_FILTER;    // enable interrupt on RX
    sCANMessageRX2.ui32MsgLen = 8;       // allow up to 8 bytes
    //
    // Now load the message object into the CAN peripheral. Will reuse other setup info from CAN obj 1.    
    CANMessageSet(CAN0_BASE, 2, &sCANMessageRX2, MSG_OBJ_TYPE_RX);
    
    // Initialize message object 3 to be used for transmitting CAN messages.
    //
  
    sCANMessageTX.ui32MsgID = RMUSN;                    // Device s/n
    sCANMessageTX.ui32MsgIDMask = 0;                    // no mask needed for TX
    sCANMessageTX.ui32Flags = MSG_OBJ_TX_INT_ENABLE;    // enable interrupt on RX
    sCANMessageTX.ui32MsgLen = 8;                       // allow up to 8 bytes
    sCANMessageTX.pui8MsgData = ucMsgDataTX;            // ptr to TX message content 

    IntEnable(INT_CAN0); //Enable CAN interrupt 

    CANEnable(CAN0_BASE); //Enable CAN for operation 
    
}

//*****************************************************************************
//
// This function is the interrupt handler for the CAN peripheral.  It checks
// for the cause of the interrupt, and maintains a count of all messages that
// have been received.
//
//*****************************************************************************
void
CANIntHandler(void)
{
    unsigned long ulStatus;

    ulStatus = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE); //Read CAN int status

    //
    // If the cause is a controller status interrupt, then get the status
    //
    if(ulStatus == CAN_INT_INTID_STATUS)
    {

        ulStatus = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL); //Read cont status

        g_bErrFlag = 1; //Set error flag
    }

    else if(ulStatus == 1)  //If msg object is 1, message received CAN obj 1
    {
 
        CANIntClear(CAN0_BASE, 1); //Clear msg object interrupt

        g_ulMsgRXCount++;  //Increment msg RX counter

        g_bRXFlag = 1; //Set flag to indicate received message is pending

        g_bErrFlag = 0; //Clear any error flags
    }

    else if(ulStatus == 2)  //If msg object is 1, message received CAN obj 2
    {
 
        CANIntClear(CAN0_BASE, 2); //Clear msg object interrupt

        g_ulMsgRXCount++;  //Increment msg RX counter

        g_bRXFlag = 2; //Set flag to indicate received message is pending

        g_bErrFlag = 0; //Clear any error flags
    }

    else if(ulStatus == 3)  //If msg object is 3, message TX successful
    {
 
        CANIntClear(CAN0_BASE, 3); //Clear msg object interrupt

        g_ulMsgTXCount++;  //Increment msg TX counter

        g_bTXFlag = 1; //Set flag to indicate message TX completed

        g_bErrFlag = 0; //Clear any error flags
    }
    
    else
    {
        //
        // Spurious interrupt handling can go here.
        //
    }
}

//*****************************************************************************
//
// Configure the CAN and enter a loop to receive CAN messages.
//
//*****************************************************************************
int
main(void)
{
    unsigned long CANPacketTypeLastRX = 0;      //Last packet type received
    
    SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);

    ReadSenCode();  //Read sensor code from EEPROM
    
    InitConsole();   //Initialize RS232 debug console
    
    InitCANRxTX();   // Initialize CAN for RX mode
    
    for(;;)  //Loop to process received messages
    {
        
        unsigned int uIdx;

//*****************************************************************************
//
// This is the discrimination section for the TX Layer.  g_bRXFlag is initially
// set by the interrupt handler.  This directs which action to take.  If the
// g_bRXFlag value = CANPacketTypeLastRX, the function will retransmit the last
// message.  If not, a new task will be initiated.  The last function that is
// done for this CAN object is to clear g_bRXFlag.  The loop then continues and
// waits for the next g_bRXFlag to be set by the handler.
//
//*****************************************************************************        
        
        if(g_bRXFlag==1) //If flag is set, RX int occurred and msg is received
        
        {
          
          if(g_bRXFlag == CANPacketTypeLastRX)
            {
             UARTprintf("RX CAN msg object 1 0x04, retransmit\n");//Same packet
             //as before, retransmit
            }
          
            else
            {
              CANMessageGet(CAN0_BASE, 1, &sCANMessageRX1, 0); //Read msg from CAN obj1
              sCANMessageRX1.pui8MsgData = ucMsgData1;  

              UARTprintf("Object 1 Msg ID=0x%08X data=0x",
                         sCANMessageRX1.ui32MsgID);
            
              for(uIdx = 0; uIdx < sCANMessageRX1.ui32MsgLen; uIdx++)
              {
                  UARTprintf("%02X ", ucMsgData1[uIdx]);
              }
            
              UARTprintf("total count=%u\n", g_ulMsgRXCount);
              
              CANPacketTypeLastRX = 1; //Set last packet to this one (0x04) 
              
              FlashLEDs();    //Flash LEDs 
            }
          
          g_bRXFlag = 0;  // Clear RX flag
          
        }
        
        if(g_bRXFlag==2) //If flag is set, RX int occurred and msg is received
        
        {
          
          if(g_bRXFlag == CANPacketTypeLastRX)
            {
             UARTprintf("RX CAN msg object 2 0x05, retransmit\n");//Same packet
             //as before, retransmit
            }
          else
          {
            CANMessageGet(CAN0_BASE, 2, &sCANMessageRX2, 0); //Read msg from CAN obj2            
            sCANMessageRX2.pui8MsgData = ucMsgData2;  //
              
            UARTprintf("Object 2 Msg ID=0x%08X data=0x",
                         sCANMessageRX2.ui32MsgID);
            
              for(uIdx = 0; uIdx < sCANMessageRX2.ui32MsgLen; uIdx++)
              {
                  UARTprintf("%02X ", ucMsgData2[uIdx]);
              }
            
              UARTprintf("total count=%u\n", g_ulMsgRXCount);
              
            CANPacketTypeLastRX = 2;  //Set last packet to this one (0x05) 
            
            FlashLEDs();    //Flash LEDs 
          }
          
         g_bRXFlag = 0;  // Clear RX flag
          
        }
        
        
    }

    return(0); //Return if no errors
}

  • Surprised this code didn't vector into the fault handler.    While you (properly) enable Port_E you perform Pinconfigs() & Pintypes() upon peripheral CAN0 - prior to enabling it!  [edit 14:15] although upon 2nd look perhaps those "Pin" functs. are more targeting GPIO...

    void
    InitCANRxTX(void)
    {
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); //Enable port E for CAN

        GPIOPinConfigure(GPIO_PE4_CAN0RX); //Pin mux for CAN functions
        GPIOPinConfigure(GPIO_PE5_CAN0TX);

        // Enable the alternate function on the GPIO pins.
        GPIOPinTypeCAN(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);

        SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0); //Enable CAN peripheral

    }

    When any peripheral fails to behave during the initial transaction - we most always think of bad or incomplete initialization.  One work-around may be to call the SysCtlPeripheralReset() function for CAN0 - prior to its use/access.

    Your 20K CAN bit rate would prove no challenge for Danica - cannot that "non-ARM" vestage tester press down harder?

  • Thank you for your response.  I structured the enable sequence in InitCANRxTx exactly as it is sequenced in the Tiva code example simple_rx.  I have not run into any other issues starting things up this way.

    I also tried working with SysCtlPeripheralReset, but that locked the code up depending on where it was entered.  The strange thing is that CAN seems to be working correctly with the first two packets, only the data field is all set to 0x00.  CAN is parsing through the ID correctly and the input filter is working, only the data field isn't coming through.  No frames appear to be lost.

    Another thing I tried was to sprinkle a few SysCtl delays after the peripheral and CAN enables, that did not help either.

    Actually this project will be using a data rate of 10k, as the communications don't need to be fast and the devices will be connected with very long lengths of twisted pair.  I have it set to 20k as that is as slow as the Microchip CAN bus analyzer will go.


    Thanks again for your help!

  • CANMessageGet(CAN0_BASE, 1, &sCANMessageRX1, 0); //Read msg from CAN obj1
     sCANMessageRX1.pui8MsgData = ucMsgData1;

    Aren't these lines reversed? You are initializing the pointer to the buffer that will receive the data after you have already received it.

    Robert

  • Hello Robert, thank you for your response.  This was indeed the problem, the buffer was not initialized until after the first frame was received.  All frames after that worked fine.  It works great now.  Thanks so much for your help!!

  • Glad I could help.

    Robert