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.

[AM335x] DCAN BusOff workaround

Hi,

Possibly a new issue with DCAN module on AM335x. The problem is with usage of the auto Bus-Off recovery feature of the DCAN module. In tests related to error recovery I have found out that if Bus-Off will happen with the next code the DCAN module will be not able to receive and send messages anymore. Proposed workaround below, but feedback wanted from the StarterWare team if this is an accurate solution?

Thanks.

/Magnus

Code and following workaround:

/**< Base address of DCAN module memory mapped registers */
#define DCAN_1_REG_BASE                     (0x481D0000)
 
/* CAN interrupts related defines */
#define SYS_INT_DCAN1_INT0                  (55)
#define SYS_INT_DCAN1_INT1                  (56)
#define SYS_INT_DCAN1_PARITY                (57)
 
 
/**< Clock frequency of CAN controller */
#define DCAN_IN_CLK                         (25000000u)
/**< Bit rate used for CAN communication */
#define DCAN_BIT_RATE                       (1000000u)
/**< Auto Bus-Off Recovery time */
#define DCAN_ABO_TIME                       (DCAN_IN_CLK / 100)
/**< Number of CAN message objects in DCAN RAM */
#define CAN_NUM_OF_MSG_OBJS                 (64)
/**< CAN Identifier used for object masking during acceptance filtering */
#define DCAN_ID_MASK                        (0x0u)
 
/**< CAN objects mapping inside the driver */
#define DCAN_RX_MSG_OBJS_START              (1)
#define DCAN_NUM_OF_RX_MSG_OBJS             (16)
#define DCAN_RX_MSG_OBJS_END                (DCAN_RX_MSG_OBJS_START + DCAN_NUM_OF_RX_MSG_OBJS)
 
#define DCAN_TX_MSG_OBJS_START              (DCAN_RX_MSG_OBJS_END)
#define DCAN_NUM_OF_TX_MSG_OBJS             (16)
#define DCAN_TX_MSG_OBJS_END                (DCAN_TX_MSG_OBJS_START + DCAN_NUM_OF_TX_MSG_OBJS)
 
 
static void CAN_ISR(void)
{
    do
    {
        unsigned int errVal;
 
        /* Check the status of DCAN Status and error register */
        errVal = DCANErrAndStatusRegInfoGet(DCAN_1_REG_BASE);
        /* CAN Bus-Off event occurred */
        if(0 != (errVal & DCAN_MOD_IN_BUS_OFF_STATE))
        {
            BusOffCount++;
        }
        /* CAN in error passive state */
        if(0 != (errVal & DCAN_CORE_IN_ERR_PASSIVE))
        {
            ErrorPassiveCount++;
        }
        /* Error warning limit reached */
        if(0 != (errVal & DCAN_ERR_WARN_STATE_RCHD))
        {
            ErrorWarningCount++;
        }
        /* Error during RX or TX */
        if((DCAN_LST_ERRCODE_NO_ERR != (errVal & DCAN_ES_LEC)) &&
                (DCAN_NO_EVENT_ON_CAN_BUS != (errVal & DCAN_ES_LEC)))
        {
            BusErrorCount++;
        }
 
        /* Receive service */
        if(0 != (errVal & DCAN_RXD_MSG_SUCCESSFULLY))
        {
            ReadRxObjects();
        }
 
        /* Transmit service */
        if(0 != (errVal & DCAN_TXD_MSG_SUCCESSFULLY))
        {
            SendNextTxObject();
        }
    } while(DCAN_NO_INT_PENDING != DCANIntRegStatusGet(DCAN_1_REG_BASE,
            DCAN_INT_LINE0_STAT));
}
 
 
static int DCAN_INIT_HW(void)
{
    unsigned int index = CAN_NUM_OF_MSG_OBJS;
 
    /* Reset the DCAN module */
    DCANReset(DCAN_1_REG_BASE);
 
    /* Enter the Initialization mode of CAN controller */
    DCANInitModeSet(DCAN_1_REG_BASE);
 
    /* Enable the write access to the DCAN configuration registers */
    DCANConfigRegWriteAccessControl(DCAN_1_REG_BASE, DCAN_CONF_REG_WR_ACCESS_ENABLE);
 
    /* Configure the bit timing values for CAN communication */
    CANSetBitTiming(DCAN_1_REG_BASE, DCAN_IN_CLK, DCAN_BIT_RATE);
 
    /*
    ** This feature will automatically get the CAN bus to bus-on
    ** state once the error counters are below the error warning
    ** limit.
    */
    DCANAutoBusOnTimeValSet(DCAN_1_REG_BASE, DCAN_ABO_TIME);
    DCANAutoBusOnControl(DCAN_1_REG_BASE, DCAN_AUTO_BUS_ON_ENABLE);
 
    /* Disable the write access to the DCAN configuration registers */
    DCANConfigRegWriteAccessControl(DCAN_1_REG_BASE, DCAN_CONF_REG_WR_ACCESS_DISABLE);
 
    while(index--)
    {
        /* Clear the MsgVal bit of DCAN_IFARB register */
        DCANMsgObjInvalidate(DCAN_1_REG_BASE, DCAN_IF2_REG);
 
        /* Set the Arb bit of DCAN_IFCMD register */
        DCANCommandRegSet(DCAN_1_REG_BASE, (DCAN_ACCESS_ARB_BITS | DCAN_MSG_WRITE),
                index, DCAN_IF2_REG);
    }
 
    /* Configure receive objects */
    CAN_ConfigRxObj();
    /* Configure transmit objects */
    CAN_ConfigTxObj();
 
    /* Register the DCAN Interrupt handler for interrupt line 0 */
    IntRegister(SYS_INT_DCAN1_INT0, &CAN_ISR);
 
    /* Assign priority to the interrupt */
    IntPrioritySet(SYS_INT_DCAN1_INT0, 0, AINTC_HOSTINT_ROUTE_IRQ);
 
    /* Enable the system interrupts in AINTC */
    IntSystemEnable(SYS_INT_DCAN1_INT0);
 
    /* Enable error and status change interrupts */
    DCANIntEnable(DCAN_1_REG_BASE, DCAN_ERROR_INT | DCAN_STATUS_CHANGE_INT);
 
    /* Enable the interrupt line 0 of DCAN module */
    DCANIntLineEnable(DCAN_1_REG_BASE, DCAN_INT_LINE0);
    /* Start the CAN controller */
    DCANNormalModeSet(DCAN_1_REG_BASE);
 
    return 0;
}

Proposed workaround:

static void CAN_ISR(void)
{
...
...
        /* CAN Bus-Off event occurred */
        if(0 != (errVal & DCAN_MOD_IN_BUS_OFF_STATE))
        {
            BusOffCount++;
            /* Restart the CAN controller */
            DCANNormalModeSet(DCAN_1_REG_BASE);
        }
...
...   
}
 
static int DCAN_INIT_HW(void)
{
...
...
    /*
    ** This feature will automatically get the CAN bus to bus-on
    ** state once the error counters are below the error warning
    ** limit.
    */
    /* DCANAutoBusOnTimeValSet(DCAN_1_REG_BASE, DCAN_ABO_TIME);
    DCANAutoBusOnControl(DCAN_1_REG_BASE, DCAN_AUTO_BUS_ON_ENABLE); */
...
...
}

 

  • Hi,

    Thanks for the suggestion. We shall look into this solution. However we have not encountered the bus off condition and currently Auto bus on feature is enabled in the code which means the CAN controller will get itself to bus on state after the error counters go below the error warning limit.

    Currently i am out of office. Will look into this once i am back.

  • Hi,

    Both the ways are correct i.e. using the Auto bus on feature as well as reset the Init bit on bus off condition.

    The description given in TRM is as follows:

    Auto-Bus-On
    By default, after the DCAN has entered Bus-Off state, the CPU can start a Bus-Off-Recovery sequence by
    resetting the Init bit. If this is not done, the module will stay in Bus-Off state.
    The DCAN provides an automatic Auto-Bus-On feature which is enabled by bit ABO in the CAN control
    register. If set, the DCAN will automatically start the Bus-Off-Recovery sequence. The sequence can be
    delayed by a user-defined number of L3_SLOW_GCLK cycles which can be defined in the Auto-Bus-On
    Time register (DCAN ABOTR).
    NOTE: If the DCAN goes to Bus-Off state due to a massive occurrence of CAN bus errors, it stops
    all bus activities and automatically sets the Init bit. Once the Init bit has been reset by the
    CPU or due to the Auto-Bus-On feature, the device will wait for 129 occurrences of bus Idle
    (equal to 129 * 11 consecutive recessive bits) before resuming normal operation. At the end
    of the Bus-Off recovery sequence, the error counters will be reset.

    Can you please let me know how are you creating the bus off error condition?

    Regards,

    Jeethan