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.

TM4C1233H6PZI First Received CAN Message w/ All Zeros in Data Field

I am having an issue where the first CAN message received has the correct data field length, however the data bytes are all zeros. When I send the same CAN message a second time it works fine.

Here is my CAN initialization code:

/*--------------------------------------------------------------------
Function Name: can_init()
Purpose: This function will initialize the CAN Controller peripheral

Input(s): None
Output(s): None
----------------------------------------------------------------------*/
void can_init()
{
// ************************************************************************************************************
// Init CAN
SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0); // The GPIO port and pins have been set up for CAN.

GPIOPinTypeGPIOOutput( CANS_PORT, CANS_PIN );
GPIOPinWrite(CANS_PORT, CANS_PIN, 0 ); // S = LOW

IntMasterEnable(); // Enable processor interrupts.
GPIOPinConfigure(GPIO_PB4_CAN0RX); // Configure the GPIO pin muxing to select CAN0 functions for these pins.
GPIOPinConfigure(GPIO_PB5_CAN0TX);
GPIOPinTypeCAN(GPIO_PORTB_BASE, GPIO_PIN_4 | GPIO_PIN_5); // Enable the alternate function on the GPIO pins.

CANInit(CAN0_BASE); // Initialize the CAN controller
CANBitRateSet(CAN0_BASE, SysCtlClockGet(), 500000); // Set up the bit rate for the CAN bus.
CANIntEnable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS); // Enable interrupts on the CAN peripheral. Name of the handler is in the vector table of startup code.
IntEnable(INT_CAN0); // Enable the CAN interrupt on the processor (NVIC).
CANEnable(CAN0_BASE); // Enable the CAN for operation.
}

Has anyone encountered this issue?

Thanks,

Robert

  • Hi,

      I suppose this is the receiver node, correct? Some questions:

      - Are you getting errors when you say the data is all zeros? 

      - Can you run the stock TivaWare CAN example from C:\ti\TivaWare_C_Series-2.2.0.295\examples\peripherals\can\simple_rx.c? Are you seeing the same problem?

      - Can you use logic analyzer to see if the transmitter is sending zeros or not zeros data the first time?

      - Can you show your entire code? I can't tell if you are polling or using interrupt and how you are setting up the message objects.

      

  • Hi,

    Thanks for replying.

    Yes, that's correct this is the receive node.

    I am not getting any errors when the first message is received. I see no difference in the processing of interrupts between the first message (with all zeros in the data field) and all subsequent messages that are received properly. I am using a script based message transmitter called Docklight. I'm quick certain it is not sending zeros in the data field in the first message transmitted.

    I am not polling but strictly using interrupts for both transmitting and receiving CAN messages. Below is my ISR:

    -------------------------------------------------------------------------------------------------------------------------------------------

    void CAN0IntHandler(void)
    {
    int i;
    unsigned char curByte;
    uint32_t ui32Status;

    // Read the CAN interrupt status to find the cause of the interrupt
    // CAN_INT_STS_CAUSE register values
    // 0x0000 = No Interrupt Pending
    // 0x0001-0x0020 = Number of message object that caused the interrupt
    // 0x8000 = Status interrupt
    // all other numbers are reserved and have no meaning in this system
    ui32Status = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE);
    // If this was a status interrupt acknowledge it by reading the CAN controller status register.
    if(ui32Status == CAN_INT_INTID_STATUS)
    {
    // Read the controller status. This will return a field of status
    // error bits that can indicate various errors. Refer to the
    // API documentation for details about the error status bits.
    // The act of reading this status will clear the interrupt.
    ui32Status = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL);

    // Add ERROR flags to list of current errors.
    g_ui32ErrFlag |= ui32Status;

    CANMessageGet(CAN0_BASE, RXOBJECT, &g_sCAN0RxMessage, 0);
    }

    // Check if the cause is message object RXOBJECT, which we are using
    // for receiving messages.
    else if(ui32Status == RXOBJECT)
    {
    //
    // Getting to this point means that the RX interrupt occurred on
    // message object RXOBJECT, and the message reception is complete.
    // Clear the message object interrupt.
    //
    CANIntClear(CAN0_BASE, RXOBJECT);

    // Reuse the same message object that was used earlier to configure
    // the CAN for receiving messages. A buffer for storing the
    // received data must also be provided, so set the buffer pointer
    // within the message object.

    g_sCAN0RxMessage.pucMsgData = (uint8_t *) g_RxMessage.data;
    g_sCAN0RxMessage.ulMsgLen = sizeof(g_RxMessage.data);

    for(i = 0; i < g_sCAN0RxMessage.ulMsgLen; i++) {
    curByte = *(g_RxMessage.data + i);

    switch(rec_state) {
    case LOOKING_FOR_START:
    if(curByte == START_FLAG) {
    rec_state = LOOKING_FOR_ADDR;
    }
    break;

    case LOOKING_FOR_ADDR:
    if(curByte == getCanNodeAddress()) {
    rec_state = LOOKING_FOR_END;
    }
    else {
    rec_state = LOOKING_FOR_START;
    }
    break;

    case DUPLICATE_FLAG:
    if(curByte == 0x83) {
    receivePacket.buf[receivePacket.indx++] = 0x80;
    rec_state = LOOKING_FOR_END;
    }
    else if(curByte == 0x84) {
    receivePacket.buf[receivePacket.indx++] = 0x81;
    rec_state = LOOKING_FOR_END;
    }
    else if(curByte == DUP_FLAG) {
    receivePacket.buf[receivePacket.indx++] = 0x82;
    rec_state = LOOKING_FOR_END;
    }
    else {
    memset( &receivePacket, 0, sizeof(receivePacket) );
    rec_state = LOOKING_FOR_ADDR;
    }
    break;

    case LOOKING_FOR_END:
    if(curByte == END_FLAG) {
    receivePacket.Len = receivePacket.indx;
    receivePacket.indx = 0;
    commSource = MSG_SRC_CAN;
    receivePacket.flg = True;
    rec_state = LOOKING_FOR_START;
    }
    else if(curByte == DUP_FLAG) {
    rec_state = DUPLICATE_FLAG;
    }
    else if(curByte == START_FLAG) {
    rec_state = LOOKING_FOR_ADDR;
    }
    else {
    receivePacket.buf[receivePacket.indx++] = curByte;
    }
    break;

    default:
    break;
    }
    }

    // Read the message from the CAN. Message object RXOBJECT is used
    // (which is not the same thing as CAN ID). The interrupt clearing
    // flag is not set because this interrupt was already cleared in
    // the interrupt handler.
    //if ( g_bRXFlag == 0 ) {
    //int i = 0;
    CANMessageGet(CAN0_BASE, RXOBJECT, &g_sCAN0RxMessage, 0);
    //for(i = 0; i < g_sCAN0RxMessage.ui32MsgLen; i++)
    // g_RxMessage.data[i] = g_sCAN0RxMessage.pui8MsgData[i];
    // g_RxMessage.len = g_sCAN0RxMessage.ui32MsgLen;
    g_RxMessage.len = g_sCAN0RxMessage.ulMsgLen;
    if(g_sCAN0RxMessage.ulFlags & MSG_OBJ_REMOTE_FRAME)
    {
    g_RxMessage.rtr = 1;
    }
    else
    {
    g_RxMessage.rtr = 0;
    }
    g_RxMessage.cob_id = g_sCAN0RxMessage.ulMsgID;
    // g_RxMessage.recFlg = True;

    // Clear the message object interrupt.
    while(HWREG(CAN0_BASE + CAN_O_IF2CRQ) & CAN_IF1CRQ_BUSY) { }
    // Only change the interrupt pending state by setting only the CAN_IF1CMSK_CLRINTPND bit.
    HWREG(CAN0_BASE + CAN_O_IF2CMSK) |= CAN_IF1CMSK_CLRINTPND;
    // Send the clear pending interrupt command to the CAN controller.
    HWREG(CAN0_BASE + CAN_O_IF2CRQ) = RXOBJECT;
    // Wait to be sure that this interface is not busy.
    while(HWREG(CAN0_BASE + CAN_O_IF2CRQ) & CAN_IF1CRQ_BUSY) { }

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

    // Since a message was received, clear any error flags.
    // This is done because before the message is received it triggers
    // a Status Interrupt for RX complete. by clearing the flag here we
    // prevent unnecessary error handling from happeneing
    g_ui32ErrFlag = 0;
    }

    // Check if the cause is message object TXOBJECT, which we are using
    // for transmitting messages.
    else if(ui32Status == TXOBJECT)
    {
    // Getting to this point means that the TX interrupt occurred on
    // message object TXOBJECT, and the message reception is complete.
    // Clear the message object interrupt.
    HWREG(CAN0_BASE + CAN_O_IF1CMSK) = CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_ARB | CAN_IF1CMSK_CONTROL;
    HWREG(CAN0_BASE + CAN_O_IF1ARB1) = 0;
    HWREG(CAN0_BASE + CAN_O_IF1ARB2) = 0;
    HWREG(CAN0_BASE + CAN_O_IF1MCTL) = 0;
    HWREG(CAN0_BASE + CAN_O_IF1CRQ) = TXOBJECT; // Initiate programming the message object

    ROM_CANIntClear(CAN0_BASE, TXOBJECT);

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

    // Since a message was transmitted, clear any error flags.
    // This is done because before the message is transmitted it triggers
    // a Status Interrupt for TX complete. by clearing the flag here we
    // prevent unnecessary error handling from happeneing
    g_ui32ErrFlag = 0;

    if(txCanMessage_Len != txCanMessage_Indx) {
    if((txCanMessage_Len - txCanMessage_Indx) > 8) {
    can_write(0x3F0, 8, 0, &transmitPacket[txCanMessage_Indx] );
    txCanMessage_Indx += 8;
    }
    else { // less than or equal to 8 characters left to transmit - this will be the last transmit
    can_write(0x3F0, (txCanMessage_Len - txCanMessage_Indx) + 1, 0, &transmitPacket[txCanMessage_Indx] );
    txCanMessage_Len = txCanMessage_Indx;
    }
    }
    }
    // Otherwise, something unexpected caused the interrupt. This should never happen.
    else
    {
    // Spurious interrupt handling can go here.
    }
    }

    ----------------------------------------------------------------------------------------------------------------------------------------------

    I hope you are able to read this.

    Here is another section of code that starts the listener:

    void can_start_listening()
    {
    // Initialize a message object to be used for receiving CAN messages with
    // any CAN ID. In order to receive any CAN ID, the ID and mask must both
    // be set to 0, and the ID filter enabled.
    //
    // g_sCAN0RxMessage.ulMsgID = 0x3FF;
    // g_sCAN0RxMessage.ulMsgIDMask = 0x7FF;
    g_sCAN0RxMessage.ulMsgID = 0;
    g_sCAN0RxMessage.ulMsgIDMask = 0;
    g_sCAN0RxMessage.ulFlags = MSG_OBJ_RX_INT_ENABLE | MSG_OBJ_USE_ID_FILTER;
    g_sCAN0RxMessage.ulMsgLen = 8;

    //
    // Now load the message object into the CAN peripheral. Once loaded the
    // CAN will receive any message on the bus, and an interrupt will occur.
    // Use message object RXOBJECT for receiving messages (this is not the
    //same as the CAN ID which can be any value in this example).
    //
    CANMessageSet(CAN0_BASE, RXOBJECT, &g_sCAN0RxMessage, MSG_OBJ_TYPE_RX);
    }

    --------------------------------------------------------------------------------------------------------------------------------------------

    Thanks for your help on this issue.

    Robert

  • Hi Robert,

      I'm not too sure what went wrong but I feel you spend too much time in the ISR. You ISR code is quite long and you also try to read the CAN message directly in the ISR. What happens when another message is received to the same message object while you are in the middle of the ISR reading. This will become a message loss. I'm interested to find out if the TivaWare simple_rx.c example will have the same issue? Can you please confirm? I will also suggest you move the processing of the message to the outside of the ISR. Perhaps, the first experiment to do is to cut down majority of your ISR and let it just receive a message. Will it have all zeros data the first time? If you start simple and gradually add your code, it will be easier to narrow down the problem area. What happens if you slow down the bit rate. Will that make a difference?

  • Hi Charles,

    The latency time for the ISR is 40us. Without getting into the details of the application, a CAN message is received based upon a user input, which is quite infrequently. Also, most of the CAN messages are contained within a single packet. So the size of the ISR is not a concern for this particular application. 

    Having said that, I was able to determine the root cause of the issue. It was simply that I was performing my state machine too early in the ISR. Further down is where the actual read of the CAN registers occurs. Once I moved the state machine section down below the actual read, I was able to successfully read the CAN message the first time after boot up.

    Thanks for your input Charles! I will mark this issue as resolved.

    Robert