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)
{
assert(NULL != handle);
status_t status = kStatus_MCAN_UnHandled;
uint32_t result;
result = base->IR;
do
{
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
{
;
}
MCAN_ClearStatusFlag(base, result);
if (handle->callback != NULL)
{
handle->callback(base, handle, status, result, handle->userData);
}
status = kStatus_MCAN_UnHandled;
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)
{
assert(NULL != handle);
enum _mcan_status status = kStatus_MCAN_UnHandled;
uint32_t interruptReq;
uint32_t interruptReqHandled;
interruptReq = base->IR;
do
{
interruptReqHandled = 0;
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;
}
MCAN_ClearStatusFlag(base, interruptReqHandled);
if (handle->callback != NULL)
{
handle->callback(base, handle, status, interruptReq, handle->userData);
}
status = kStatus_MCAN_UnHandled;
interruptReq = base->IR;
} while ((0U != MCAN_GetStatusFlag(base, 0xFFFFFFFFU)) ||
(0U != (interruptReq & (kMCAN_ErrorWarningIntFlag | kMCAN_BusOffIntFlag | kMCAN_ErrorPassiveIntFlag))));
}