Author Topic: Potential CAN error handling problem  (Read 2896 times)

Offline AlexS

  • Newbie
  • *
  • Posts: 46
    • View Profile
Potential CAN error handling problem
« on: October 14, 2021, 11:40:28 AM »
Hi Mark,

While diagnosing a hard fault triggered by CAN operation, I noticed something which doesn't look right. Essentially 'ptrMessageBuffer' ends up pointing to a region of memory which is not in the FlexCAN peripheral (0x4002 4180)


Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: Potential CAN error handling problem
« Reply #1 on: October 14, 2021, 01:05:29 PM »
Hi

Yes, the address is just pas the end of the CAN message buffer and I am pretty sure that what happened is that the error loop was traversed more than once, but the message pointer left after the end of the memory the fist time.

In the following I have added a pointer to the start of the message buffers and set ptrMessageBuffer back to this each time that it goes around the error loop. This should allow multiple queued errors to be handled.

Thanks for the report!

Regards

Mark

Code: [Select]
static void fnCAN_error(int iChannel)
{
    unsigned char can_error_int_message[HEADER_LENGTH];
    KINETIS_CAN_CONTROL *ptrCAN_control;
    KINETIS_CAN_BUF *ptrMessageBuffer;
    KINETIS_CAN_BUF *ptrMessageBufferStart;
    volatile unsigned long ulError;                                      // read the error status register, clearing error bits

    can_error_int_message[MSG_DESTINATION_NODE] = INTERNAL_ROUTE;
    can_error_int_message[MSG_SOURCE_NODE]      = INTERNAL_ROUTE;
    can_error_int_message[MSG_DESTINATION_TASK] = CAN_ERROR_TASK;
    can_error_int_message[MSG_SOURCE_TASK]      = INTERRUPT_EVENT;

    switch (iChannel) {
    case 0:
        ptrCAN_control = (KINETIS_CAN_CONTROL *)CAN0_BASE_ADD;
        ptrMessageBufferStart = MBUFF0_ADD_0;
        break;
    #if NUMBER_OF_CAN_INTERFACES > 1
    case 1:
        ptrCAN_control = (KINETIS_CAN_CONTROL *)CAN1_BASE_ADD;
        ptrMessageBufferStart = MBUFF0_ADD_1;
        break;
    #endif
    #if NUMBER_OF_CAN_INTERFACES > 2
    case 2:
        ptrCAN_control = (KINETIS_CAN_CONTROL *)CAN2_BASE_ADD;
        ptrMessageBufferStart = MBUFF0_ADD_2;
        break;
    #endif
    }

    while (((ulError = ptrCAN_control->CAN_ESR1) & (BIT1ERROR | BIT0ERROR | CAN_CRC_ERR | CAN_ACK_ERR | CAN_FRM_ERR | CAN_STF_ERR)) != 0) { // read the error status register, clearing error bits
    #if defined _WINDOWS
        ptrCAN_control->CAN_ESR1 &= ~(BIT1ERROR | BIT0ERROR | CAN_CRC_ERR | CAN_ACK_ERR | CAN_FRM_ERR | CAN_STF_ERR);
    #endif
        ptrMessageBuffer = ptrMessageBufferStart;
        if ((ulError & CAN_ACK_ERR) != 0) {                              // a transmission received no ack
            CANQUE *ptrCanQue = can_queue[iChannel];                     // we need to search for buffers which are transmitting
            int i = NUMBER_CAN_MESSAGE_BUFFERS;
            can_error_int_message[MSG_INTERRUPT_EVENT] = 0;
            while (i-- != 0) {
                if ((ptrCanQue->ucMode & CAN_TX_BUF_ACTIVE) != 0) {      // this buffer is presently transmitting a message
                    if (++(ptrCanQue->ucErrors) >= MAX_TX_CAN_TRIES) {   // we allow a few attempts before quitting (it also filters counting normal active buffers)
                        ptrMessageBuffer->ulCode_Len_TimeStamp = ((ptrMessageBuffer->ulCode_Len_TimeStamp & ~CAN_CODE_FIELD) | MB_TX_INACTIVE); // stop transmission
                        can_error_int_message[MSG_DESTINATION_TASK] = ptrCanQue->TaskToWake;
                        if ((ptrCanQue->ucMode & CAN_TX_BUF_REMOTE) != 0) {
                            can_error_int_message[MSG_INTERRUPT_EVENT] = CAN_TX_REMOTE_ERROR;
                            ptrCanQue->ucMode = (CAN_TX_BUF | CAN_RX_BUF_FULL | CAN_TX_BUF_REMOTE); // mark that it is an errored transmission buffer
                        }
                        else {
                            can_error_int_message[MSG_INTERRUPT_EVENT] = CAN_TX_ERROR;
                            ptrCanQue->ucMode = (CAN_TX_BUF | CAN_RX_BUF_FULL); // mark that it is an errored transmission buffer
                        }
                        break;
                    }
                }
                ptrCanQue++;
                ptrMessageBuffer++;
            }
        }
        else {
            ptrMessageBuffer->ulCode_Len_TimeStamp = (MB_TX_INACTIVE | (ptrMessageBuffer->ulCode_Len_TimeStamp & CAN_KEEP_CONTENTS)); // free the buffer
            can_error_int_message[MSG_INTERRUPT_EVENT] = CAN_OTHER_ERROR;
        }
        ptrCAN_control->CAN_ESR1 = ERRINT;                               // clear the error interrupt
    #if defined _WINDOWS
        ptrCAN_control->CAN_ESR1 &= ~(ERRINT);
    #endif
        if (can_error_int_message[MSG_INTERRUPT_EVENT] != 0) {
            uDisable_Interrupt();                                        // ensure interrupts remain blocked when putting message to queue
                fnWrite(INTERNAL_ROUTE, can_error_int_message, HEADER_LENGTH); // inform the handling task of event
            uEnable_Interrupt();
        }
    }
}

Offline AlexS

  • Newbie
  • *
  • Posts: 46
    • View Profile
Re: Potential CAN error handling problem
« Reply #2 on: October 18, 2021, 10:11:54 AM »
Thanks for the quick reply Mark! Will get it tested today.