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.

TM4C123GH6PM: CAN using FIFO

Hi, I want to use the can with FIFO buffer but I don´t know how to handle it.I took this example from the tiva user´s guide and I can´t completly understand how the read the data, in the last line uses CANMessageGet pointing to MsgObjectRx, shouldn´t it pass a buffer to the object´s data member of the MsgObjectRx.Also is there another example that i can use?

tCANBitClkParms CANBitClk;
tCANMsgObject sMsgObjectRx;
tCANMsgObject sMsgObjectTx;
uint8_t pui8BufferIn[8];
uint8_t pui8BufferOut[8];
//
// Enable the CAN0 module.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);
//
// Wait for the CAN0 module to be ready.
//
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_CAN0)){}
//
// Enable the CAN1 module.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN1);
//
// Wait for the CAN1 module to be ready.
//
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_CAN1)){}
//
// Reset the state of all the message objects and the state of the CAN
// module to a known state.
//
CANInit(CAN0_BASE);
CANInit(CAN1_BASE);
//
// Configure the controller for 1 Mbit operation.
//
CANSetBitTiming(CAN1_BASE, &CANBitClk);
//
// Take the CAN0 device out of INIT state.
//
CANEnable(CAN0_BASE);
CANEnable(CAN1_BASE);
//
// Configure a receive object.
//
sMsgObjectRx.ulMsgID = (0x400);
sMsgObjectRx.ulMsgIDMask = 0x7f8;
sMsgObjectRx.ulFlags = MSG_OBJ_USE_ID_FILTER | MSG_OBJ_FIFO;
//
// The first three message objects have the MSG_OBJ_FIFO set to indicate
// that they are part of a FIFO.
//
CANMessageSet(CAN0_BASE, 1, &sMsgObjectRx, MSG_OBJ_TYPE_RX);
CANMessageSet(CAN0_BASE, 2, &sMsgObjectRx, MSG_OBJ_TYPE_RX);
CANMessageSet(CAN0_BASE, 3, &sMsgObjectRx, MSG_OBJ_TYPE_RX);
//
// Last message object does not have the MSG_OBJ_FIFO set to indicate that
// this is the last message.
//
sMsgObjectRx.ulFlags = MSG_OBJ_USE_ID_FILTER;
CANMessageSet(CAN0_BASE, 4, &sMsgObjectRx, MSG_OBJ_TYPE_RX);
//
// Configure and start transmit of message object.
//
sMsgObjectTx.ulMsgID = 0x400;
sMsgObjectTx.ulFlags = 0;
sMsgObjectTx.ulMsgLen = 8;
sMsgObjectTx.pucMsgData = pui8BufferOut;
CANMessageSet(CAN0_BASE, 2, &sMsgObjectTx, MSG_OBJ_TYPE_TX);
//
// Wait for new data to become available.
//
while((CANStatusGet(CAN1_BASE, CAN_STS_NEWDAT) & 1) == 0){
//
// Read the message out of the message object.
//

CANMessageGet(CAN1_BASE, 1, &sMsgObjectRx, true);
}
//

  • First, let me point out, as stated in the datasheet, when using FIFO mode the order of received messages is not guaranteed. If this is important, then I suggest instead you use a single message buffer and a high priority interrupt to read the message buffer into a software FIFO.

  • To read the message objects from a FIFO buffer you should follow the flow chart given on page 1059 of the datasheet

  • I´m aware about the order of the received messages and its not a problem for my project, but my doubt its about where the data is stored after the CANMessageGet function beacuse in the example the sMsgObjectTx.pucMsgData its not set, like it is for transmit "sMsgObjectTx.pucMsgData = pui8BufferOut;" so its the explample missing that step?

  • Sorry, I just looked at that example in section 6.4 of the Driver Library User's Guide. There are several issues with that example. I need to take some time to correct it and then I will post a better example. To be more specific, the function CANMessageGet() will only read the data received in one of the message objects. When using FIFO mode, you must cycle through the message objects that are part of the FIFO and read each one that has new data in it. The example code clearly does not do that.

  • Yes, among other problems, this example is missing the assignment of the input buffer to the receive CAN message object structure. It needs a line like:

        sMsgObjectRx.pui8MsgData = pui8BufferIn;
    

  • Ok, I will work some code too, let me know if  you get to fix it !

    thanks for your help.

    Regards

  • Here is the interrupt routine that I wrote and tested which reads the values out of a 4 message buffer FIFO. The routine reads from the CAN message mailboxes and stores the data into a circular buffer.

    // Circular buffer for receive CAN frames
    #define BUFFER_SIZE 1024
    volatile uint64_t    g_pui64Array[BUFFER_SIZE];
    volatile bool        g_bErrFlag;
    volatile bool        g_bTxFlag;
    volatile bool        g_bRXFlag;
    volatile uint32_t    g_ui32MsgCount;
    volatile uint32_t    g_ui32RxMsgCount;
    volatile uint32_t    g_ui32ArrayHead;
    static   uint32_t    g_ui32ArrayTail;
    
    void CAN0IntHandler(void)
    {
        uint32_t ui32Status, i;
        tCANMsgObject sMsgObjectRx;
    
        GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_7, GPIO_PIN_7);
    
        //
        // Read the CAN interrupt status to find the cause of the interrupt
        //
        ui32Status = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE);
    
        //
        // If the cause is a controller status interrupt, then get the status
        //
        if(ui32Status == CAN_INT_INTID_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.  If the
            // CAN peripheral is not connected to a CAN bus with other CAN devices
            // present, then errors will occur and will be indicated in the
            // controller status.
            //
            ui32Status = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL);
            //
            // Set a flag to indicate some errors may have occurred.
            //
            g_bErrFlag = 1;
        }
    
        //
        // Check if the cause is a receive message object
        //
        else if((ui32Status > 0) & (ui32Status < 5))
        {
            for(i = ui32Status; i < 5; i++)
            {
                //
                // Getting to this point means that the RX interrupt occurred.
                // Read the message, clear the interrupt
                sMsgObjectRx.ui32Flags = MSG_OBJ_NO_FLAGS;
                sMsgObjectRx.pui8MsgData = (void *)&(g_pui64Array[g_ui32ArrayHead]);
                CANMessageGet(CAN0_BASE, i, &sMsgObjectRx, true);
                if((sMsgObjectRx.ui32Flags & MSG_OBJ_NEW_DATA) == MSG_OBJ_NEW_DATA)
                {
                    // Increment head of circular buffer
                    g_ui32ArrayHead++;
                    g_ui32ArrayHead = g_ui32ArrayHead % BUFFER_SIZE;
                    //
                    // 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.
                    //
                    g_ui32RxMsgCount++;
                }
                else
                {
                    break;
                }
            }
        }
        //
        // Otherwise, something unexpected caused the interrupt.  This should
        // never happen.
        //
        else
        {
            //
            // Spurious interrupt handling can go here.
            //
        }
    }