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.

TMS320F28379D: CAN bus action during error when transmitting/receive data

Part Number: TMS320F28379D
Other Parts Discussed in Thread: C2000WARE

Hello 

I am currently looking at the driverlib example code can_ex3_external_transmit, (\C2000Ware_4_01_00_00\driverlib\f2837xd\examples\cpu1\can)

where CAN-A is used to transmit and CAN-B receives the data

This is the ISR function

//
// CAN B ISR - The interrupt service routine is called when an interrupt is
//             triggered on CAN module B. It will be executed twice for every
//             frame received.
//             First time for status-change; second time for Mailbox receive.
//
__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;
        }
    }
    //
    // 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_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 1, 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);
}

Based on the above, I created this ISR skeleton for my application, where we check if any frame is received, transmitted or if there are any errors .

#define CTRL_BRD_CAN                        CANA_BASE
#define CTRL_BRD_CAN_INT                    INT_CANA0
#define CTRL_BRD_CAN_TX_MSG_OBJ_ID_1        1
#define CTRL_BRD_CAN_TX_MSG_OBJ_ID_1_LEN    1
#define CTRL_BRD_CAN_RX_MSG_OBJ_ID_1        1
#define CTRL_BRD_CAN_RX_MSG_OBJ_ID_1_LEN    2
#define CTRL_BRD_CAN_MSG_ID                 0x01

__interrupt void INT_CAN_CTRL_ISR(void)
{
    uint32_t status;
    //
    // Read the interrupt cause
    //
    status = CAN_getInterruptCause(CTRL_BRD_CAN);
    if (status == CAN_INT_INT0ID_STATUS)
    {
        status = CAN_getStatus(CTRL_BRD_CAN);  // Return CAN_ES value.
        //
        // 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;
            // 
            // TODO: Do error handling in here
            ;
        }
    }
    //
    // Check if the cause is the CAN receive message object 1. Will be skipped
    // in the first iteration of every ISR execution
    //
    else if(status == CTRL_BRD_CAN_RX_MSG_OBJ_ID_1)
    {
        //TODO: Do something
        //
        //Clear the RX message object interrupt.
        //
        CAN_clearInterruptStatus(CTRL_BRD_CAN, CTRL_BRD_CAN_RX_MSG_OBJ_ID_1);
    }
    //
    // Check if the cause is the transmit message object 1
    //
    else if (status == CTRL_BRD_CAN_TX_MSG_OBJ_ID_1)
    {
        //TODO: Do something
        //
        //Clear the TX message object interrupt.
        //
        CAN_clearInterruptStatus(CTRL_BRD_CAN, CTRL_BRD_CAN_TX_MSG_OBJ_ID_1);
    }
    //
    // Clear the global interrupt flag for the CAN interrupt line
    //
    CAN_clearGlobalInterruptStatus(CTRL_BRD_CAN, CAN_GLOBAL_INT_CANINT0);

    //
    // Acknowledge this interrupt located in group 9
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}

My question here is , if an error does occur (read from CAN_ES),

  1. Does the can bus automatically re-transmit the data again, or do we have to do it manually? Does this have anything to do with the CAN_enableRetry() function?
  2. In the event of an error, could you suggest any corrective actions that we can take to get the bus back to an error free state?
  • Does the can bus automatically re-transmit the data again, or do we have to do it manually? Does this have anything to do with the CAN_enableRetry() function?

    During transmission, if an error is detected by any node on the bus, it destroys the ongoing transmission by transmitting an error frame. This error frame intentionally violates the bit-stuffing rule. Other nodes on the bus either detect the original error themselves or detect the error frame transmitted by the node that detected the error and in turn transmit their own error frames. So what you see on the bus is a superposition of error frames transmitted by every node on the bus. Now, coming to your question, when the transmission of an on-going frame is destroyed due to an error, the transmitting node will automatically retransmit the frame. This happens without any code intervention. This is a CAN protocol requirement.

    In the event of an error, could you suggest any corrective actions that we can take to get the bus back to an error free state?

    In a properly designed/configured network, communication errors should be rare. Common reasons for errors are

    1. Loose oscillator tolerance
    2. Improper sampling-point selection
    3. Mismatched bit-rates between nodes. This can happen, among other things, due to loose oscillator tolerance
    4. Electrical noise. If the noise is transient, the bus should recover on its own once the disturbances vanish. That is how the protocol is designed. 

    Bus-off is a severe error condition. You should investigate the root-cause of the errors (leading to bus-off) during communication.

  • Thanks for such a detailed reply, Will let you know if we have any further questions