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.

CAN Bus-Off recover

Hi

I set up a Can network with only 2 devices (TM4C1231D5P), based on the ti stellaris library and some custom code. 

It works fine, but if i short the CanHi and  CanLo line, we do this to test robustness, i get both devices into a bus-off state and i cannot recover from this.

It seems like both units sit in the bus-off state and wait for good frames. I try to recover by setting the CanEnable() but this does not help.

Is there a way to recover from this? 

Any help is appreciated.

  • Hello Dino,

    When the devices are in Bus Off State, what is the state of the CAN lines? Are they high?

    Regards
    Amit
  • Hello, I have been working on this for the past two days and have found how to make it work acceptably for our system. Here is a bit of code for our CAN ISR handler. Sorry that it's a bit long, but I thought it necessary to show what is being done.
    At first I thought that the CAN Status register being written with a BITERROR0 code would generate an interrupt for me to count to watch the bus-off recovery sequence in the CAN_STATUS_LEC_BIT0 handler, but I found that to not be the case. I then decided to use a local loop in the CAN_STATUS_BUS_OFF handler to watch the BITERROR0 code and found that the stated number of occurrences of 129 11 high bits required to allow re-connecting to the bus does not work either....

    I hope this helps, and I would like TI to comment on these findings please.

    Read on...


    in our CAN_ISR

    CANIntDisable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);

    //Find the cause of the interrupt, if it is a status interrupt then just acknowledge the interrupt by reading the status register.
    ulStatus = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE);

    if(ulStatus <= 32)
    {
    // This must have been a msgobject interrupt
    CANIntClear(CAN0_BASE, ulStatus);
    switch()
    {

    ... All our normal CAN Message objects here

    }

    }
    else // This must have been a status change, not a msgobject interrupt
    {
    g_ulCanStatus = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL);
    CANIntClear(CAN0_BASE, CAN_INT_INTID_STATUS);

    switch(g_ulCanStatus & CAN_STATUS_LEC_MASK)
    {


    ... other status handlers for the LEC


    case CAN_STATUS_LEC_BIT0:
    g_ulCanBit0ErrCounter++;

    //DEBUG_PRINT_STRING_RETURN("----> ERROR : CAN_STATUS_LEC_BIT0!");
    /* REMOVED- See bus-off handler below
    if(CAN_BusOffRecovery)
    {
    DEBUG_PRINT_STRING_NUMBER("BusOffRecvCounter: ", BusOffRecvCounter);
    g_ulCanStatus &= ~CAN_STATUS_BUS_OFF;
    if(BusOffRecvCounter > 0)
    {
    if((--BusOffRecvCounter) <= 0)
    {
    CAN_BusOffRecovery = false;
    bCAN_TxOK = true;
    }
    }
    }
    */
    CANErrorHandler();
    break;
    }


    ... other bit-wise status handlers



    // From the TI Tiva user's manual CAN device section,
    // The bus-off recovery sequence (see CAN Specification Rev. 2.0) cannot be shortened by setting
    // or clearing INIT. If the device goes bus-off, it sets INIT, stopping all bus activities. Once INIT
    // has been cleared by the CPU, the device then waits for 129 occurrences of Bus Idle (129 * 11
    // consecutive High bits) before resuming normal operations. At the end of the bus-off recovery
    // sequence, the Error Management Counters are reset.
    // During the waiting time after INIT is cleared, each time a sequence of 11 High bits has been
    // monitored, a BITERROR0 code is written to the CANSTS register (the LEC field = 0x5), enabling
    // the CPU to readily check whether the CAN bus is stuck Low or continuously disturbed, and to monitor
    // the proceeding of the bus-off recovery sequence.

    // From the Tivaware function CANIntClear() description in can.c
    // Because there is a write buffer in the Cortex-M processor, it may
    // take several clock cycles before the interrupt source is actually cleared.
    // Therefore, it is recommended that the interrupt source be cleared early in
    // the interrupt handler (as opposed to the very last action) to avoid
    // returning from the interrupt handler before the interrupt source is
    // actually cleared. Failure to do so may result in the interrupt handler
    // being immediately reentered (because the interrupt controller still sees
    // the interrupt source asserted).

    // CANIntClear is called at the entry of this status interrupt handler but it has been
    // observed that sometimes after a bus-off event the interrupt keeps being asserted again and again.
    // There is now a local loop in the bus-off handler that seems to stop the this re-assertion behavior.
    // It is not good to do it this way, as the processor is stuck here in the loop, but it does seem to work.
    // The BITERROR0 indication is tested during the execution of the loop. The events are counted.
    // If the count goes up to 129, then the loop is broken early. If not, the loop ends naturally.

    // An attempt was made to use the BITERROR0 code method of watching the progress of the bus-off
    // recovery sequence by watching for BITERROR0 interrupts, but that seemed to not work.
    // It was thought that when the CAN device saw the 11 High bits that an interrupt would be asserted
    // so the events could be counted. It seems to not work that way, so the local loop with the
    // BITERROR0 counter method was employed.

    // Testing has shown that the loop ends naturally before 129 BITERROR0 events, and the CAN device
    // does go back online and communicates normally. Even though there is a local loop here,
    // the short amount of time the processor is stuck here should not be a problem for the overall system.

    // Actual test result examples
    // ----> ERROR : CAN_STATUS_BUS_OFF!
    // BusOffRecvCounter: 21
    // i: 50000

    // ----> ERROR : CAN_STATUS_BUS_OFF!
    // BusOffRecvCounter: 81
    // i: 50000

    // ----> ERROR : CAN_STATUS_BUS_OFF!
    // BusOffRecvCounter: 89
    // i: 50000



    if(g_ulCanStatus & CAN_STATUS_BUS_OFF) //Controller is in bus-off condition.
    {
    g_ulCAN_BusOffCounter++;
    DEBUG_PRINT_STRING_RETURN("----> ERROR : CAN_STATUS_BUS_OFF!");
    for(i=0; i < 50000; i++) // 50000 chosen as a random guess...
    {
    ulStatus = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL);
    if(ulStatus & CAN_STATUS_LEC_BIT0)
    {
    if((++BusOffRecvCounter) >= 129)
    {
    break;
    }
    }
    }
    DEBUG_PRINT_STRING_NUMBER("BusOffRecvCounter: ", BusOffRecvCounter);
    DEBUG_PRINT_STRING_NUMBER("i: ", i);
    CANEnable(CAN0_BASE);

    /* REMOVED:
    if(CAN_BusOffRecovery == false)
    {
    CAN_BusOffRecovery = true;
    BusOffRecvCounter = 129;
    // Attempt to turn off all message TX
    HWREG(CAN0_BASE + CAN_O_IF1ARB2) = 0;
    HWREG(CAN0_BASE + CAN_O_IF1MCTL) = 0;
    HWREG(CAN0_BASE + CAN_O_TXRQ1) = 0;
    // re-enable the CAN peripheral, wait for the bus-off to wash out...
    CANEnable(CAN0_BASE);
    }
    */
    }
    else
    {
    BusOffRecvCounter = 0;
    }

    // Clear the status register
    g_ulCanStatus = 0;
    }

    CANIntEnable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);
    }