AnsweredAssumed Answered

fsl_mcan driver dropping interrupts bug

Question asked by Tomas Vavra on Sep 16, 2019
Latest reply on Oct 21, 2019 by ZhangJennie

Hello, I think that there is a severe bug in fsl_mcan.c driver (SDK2.6.0). I am using LPC54618 dev kit.

 

Function MCAN_TransferHandleIRQ clears all interrupt flags insted of only the "solved ones". If there are simultanous interrupts pending, then only one gets processed and others are ignored.

 

Problematic part is MCAN_ClearStatusFlag(base, result);

void MCAN_TransferHandleIRQ(CAN_Type *base, mcan_handle_t *handle)
{
    /* Assertion. */
    assert(NULL != handle);

    status_t status = kStatus_MCAN_UnHandled;
    uint32_t result;

    /* Store Current MCAN Module Error and Status. */
    result = base->IR;

    do
    {
        /* Solve Rx FIFO, Tx interrupt. */
        if (result & kMCAN_TxTransmitCompleteFlag)
        {
            status = kStatus_MCAN_TxIdle;
            MCAN_TransferAbortSend(base, handle, handle->txbufferIdx);
        }
        else if (result & kMCAN_RxFifo0NewFlag)
        {
            MCAN_ReadRxFifo(base, 0U, handle->rxFifoFrameBuf);
            status = kStatus_MCAN_RxFifo0Idle;
            MCAN_TransferAbortReceiveFifo(base, 0U, handle);
        }
        else if (result & kMCAN_RxFifo0LostFlag)
        {
            status = kStatus_MCAN_RxFifo0Lost;
        }
        else if (result & kMCAN_RxFifo1NewFlag)
        {
            MCAN_ReadRxFifo(base, 1U, handle->rxFifoFrameBuf);
            status = kStatus_MCAN_RxFifo1Idle;
            MCAN_TransferAbortReceiveFifo(base, 1U, handle);
        }
        else if (result & kMCAN_RxFifo1LostFlag)
        {
            status = kStatus_MCAN_RxFifo0Lost;
        }
        else
        {
            ;
        }

        /* Clear resolved Rx FIFO, Tx Buffer IRQ. */
        MCAN_ClearStatusFlag(base, result);

        /* Calling Callback Function if has one. */
        if (handle->callback != NULL)
        {
            handle->callback(base, handle, status, result, handle->userData);
        }

        /* Reset return status */
        status = kStatus_MCAN_UnHandled;

        /* Store Current MCAN Module Error and Status. */
        result = base->IR;
    } while ((0U != MCAN_GetStatusFlag(base, 0xFFFFFFFFU)) ||
             (0U != (result & (kMCAN_ErrorWarningIntFlag | kMCAN_BusOffIntFlag | kMCAN_ErrorPassiveIntFlag))));
}

 

Following modified code works correctly.

 

void MCAN_TransferHandleIRQ(CAN_Type *base, mcan_handle_t *handle)
{
    /* Assertion. */
    assert(NULL != handle);

    enum _mcan_status status = kStatus_MCAN_UnHandled;
    uint32_t interruptReq;
    uint32_t interruptReqHandled;

    /* Store Current MCAN Module Error and Status. */
    interruptReq = base->IR;

    //assert(interruptReq != 0);

    do
    {
        interruptReqHandled = 0;

        /* Solve Rx FIFO, Tx interrupt. */
        if (interruptReq & kMCAN_TxTransmitCompleteFlag)
        {
            interruptReqHandled = kMCAN_TxTransmitCompleteFlag;
            status = kStatus_MCAN_TxIdle;
            MCAN_TransferAbortSend(base, handle, handle->txbufferIdx);
        }
        else if (interruptReq & kMCAN_RxFifo0NewFlag)
        {
            interruptReqHandled = kMCAN_RxFifo0NewFlag;
            MCAN_ReadRxFifo(base, 0U, handle->rxFifoFrameBuf);
            status = kStatus_MCAN_RxFifo0Idle;
            MCAN_TransferAbortReceiveFifo(base, 0U, handle);
        }
        else if (interruptReq & kMCAN_RxFifo0LostFlag)
        {
            interruptReqHandled = kMCAN_RxFifo0LostFlag;
            status = kStatus_MCAN_RxFifo0Lost;
        }
        else if (interruptReq & kMCAN_RxFifo1NewFlag)
        {
            interruptReqHandled = kMCAN_RxFifo1NewFlag;
            MCAN_ReadRxFifo(base, 1U, handle->rxFifoFrameBuf);
            status = kStatus_MCAN_RxFifo1Idle;
            MCAN_TransferAbortReceiveFifo(base, 1U, handle);
        }
        else if (interruptReq & kMCAN_RxFifo1LostFlag)
        {
            interruptReqHandled = kMCAN_RxFifo1LostFlag;
            status = kStatus_MCAN_RxFifo0Lost;
        }
        else
        {
            interruptReqHandled = interruptReq;
        }

        /* Clear resolved Rx FIFO, Tx Buffer IRQ. */
        MCAN_ClearStatusFlag(base, interruptReqHandled);

        /* Calling Callback Function if has one. */
        if (handle->callback != NULL)
        {
            handle->callback(base, handle, status, interruptReq, handle->userData);
        }

        /* Reset return status */
        status = kStatus_MCAN_UnHandled;

        /* Store Current MCAN Module Error and Status. */
        interruptReq = base->IR;
    } while ((0U != MCAN_GetStatusFlag(base, 0xFFFFFFFFU)) ||
             (0U != (interruptReq & (kMCAN_ErrorWarningIntFlag | kMCAN_BusOffIntFlag | kMCAN_ErrorPassiveIntFlag))));
}

Outcomes