713 lines
29 KiB
C
713 lines
29 KiB
C
|
|
/**
|
|
******************************************************************************
|
|
* @file ivec_mcal_mcan.c
|
|
* @brief This file provides APIs for MCAN peripheral.
|
|
* @date 15-feb-2024
|
|
* @Author Vecmocon Technology
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include <../Core/Include/ivec_mcal_mcan.h>
|
|
|
|
#include "string.h"
|
|
/* MCAN Protocol Status Header */
|
|
volatile DL_MCAN_ProtocolStatus g_xHeaderStat;
|
|
|
|
/* MCAN Interrupt Line 1 Status */
|
|
volatile uint32_t g_u32InterruptLine1Status;
|
|
|
|
__attribute__((weak)) void vMCU_FDCANRxFifoCallback(uint32_t u32Identifier, uint8_t *pu8data, uint16_t u16DataLength)
|
|
{
|
|
|
|
}
|
|
|
|
/*=======================================================================================PRIVATE_MEMBERS======================================================================================*/
|
|
|
|
static const DL_MCAN_ClockConfig __gprv_xClockConf = {
|
|
.clockSel = DL_MCAN_FCLK_HFCLK,////DL_MCAN_FCLK_SYSPLLCLK1,DL_MCAN_FCLK_HFCLK,
|
|
.divider = DL_MCAN_FCLK_DIV_1,
|
|
};
|
|
|
|
static DL_MCAN_InitParams __gprv_xInitParams= {
|
|
|
|
/* Initialize MCAN Init parameters. */
|
|
.fdMode = false,
|
|
.brsEnable = false,
|
|
.txpEnable = false,
|
|
.efbi = false,
|
|
.pxhddisable = false,
|
|
.darEnable = true,
|
|
.wkupReqEnable = true,
|
|
.autoWkupEnable = true,
|
|
.emulationEnable = true,
|
|
.tdcEnable = true,
|
|
.wdcPreload = 255,
|
|
|
|
/* Transmitter Delay Compensation parameters. */
|
|
.tdcConfig.tdcf = 10,
|
|
.tdcConfig.tdco = 6,
|
|
};
|
|
|
|
static DL_MCAN_ConfigParams __gprv_xConfigParams={
|
|
/* Initialize MCAN Config parameters. */
|
|
.monEnable = false,
|
|
.asmEnable = false,
|
|
.tsPrescalar = 15,
|
|
.tsSelect = 0,
|
|
.timeoutSelect = DL_MCAN_TIMEOUT_SELECT_CONT,
|
|
.timeoutPreload = 65535,
|
|
.timeoutCntEnable = false,
|
|
.filterConfig.rrfs = false,
|
|
.filterConfig.rrfe = false,
|
|
.filterConfig.anfe = 0,
|
|
.filterConfig.anfs = 0,
|
|
};
|
|
static DL_MCAN_MsgRAMConfigParams __gprv_xMsgRAMConfigParams = {
|
|
|
|
/* Standard ID Filter List Start Address. */
|
|
.flssa = 0x0,
|
|
/* List Size: Standard ID. */
|
|
.lss = 10,
|
|
/* Extended ID Filter List Start Address. */
|
|
.flesa = 10 ,
|
|
/* List Size: Extended ID. */
|
|
.lse = 10 ,
|
|
/* Tx Buffers Start Address. */
|
|
.txStartAddr = 40 + 80+20 ,
|
|
/* Number of Dedicated Transmit Buffers. */
|
|
.txBufNum = 0 ,
|
|
.txFIFOSize = 3,
|
|
/* Tx Buffer Element Size. */
|
|
.txBufMode = 0,
|
|
.txBufElemSize = DL_MCAN_ELEM_SIZE_8BYTES,
|
|
/* Tx Event FIFO Start Address. */
|
|
.txEventFIFOStartAddr = 0 ,
|
|
/* Event FIFO Size. */
|
|
.txEventFIFOSize = 0 ,
|
|
/* Level for Tx Event FIFO watermark interrupt. */
|
|
.txEventFIFOWaterMark = 0,
|
|
/* Rx FIFO0 Start Address. */
|
|
.rxFIFO0startAddr = 40 + 80 + 36+20 +40,
|
|
/* Number of Rx FIFO elements. */
|
|
.rxFIFO0size = 3 ,
|
|
/* Rx FIFO0 Watermark. */
|
|
.rxFIFO0waterMark = 0,
|
|
.rxFIFO0OpMode = 0,
|
|
/* Rx FIFO1 Start Address. */
|
|
.rxFIFO1startAddr = 40 + 80 + 36 + 36+80 ,
|
|
/* Number of Rx FIFO elements. */
|
|
.rxFIFO1size = 3 ,
|
|
/* Level for Rx FIFO 1 watermark interrupt. */
|
|
.rxFIFO1waterMark = 0,
|
|
/* FIFO blocking mode. */
|
|
.rxFIFO1OpMode = 0,
|
|
/* Rx Buffer Start Address. */
|
|
.rxBufStartAddr = 0 ,
|
|
/* Rx Buffer Element Size. */
|
|
.rxBufElemSize = DL_MCAN_ELEM_SIZE_8BYTES,
|
|
/* Rx FIFO0 Element Size. */
|
|
.rxFIFO0ElemSize = DL_MCAN_ELEM_SIZE_8BYTES,
|
|
/* Rx FIFO1 Element Size. */
|
|
.rxFIFO1ElemSize = DL_MCAN_ELEM_SIZE_8BYTES,
|
|
};
|
|
|
|
static DL_MCAN_BitTimingParams __gprv_xBitTimes_500 = {
|
|
/* Arbitration Baud Rate Pre-scaler. */
|
|
.nomRatePrescalar = 0,
|
|
/* Arbitration Time segment before sample point. */
|
|
.nomTimeSeg1 = 41,
|
|
/* Arbitration Time segment after sample point. */
|
|
.nomTimeSeg2 = 4,
|
|
/* Arbitration (Re)Synchronization Jump Width Range. */
|
|
.nomSynchJumpWidth = 4,
|
|
/* Data Baud Rate Pre-scaler. */
|
|
.dataRatePrescalar = 0,
|
|
/* Data Time segment before sample point. */
|
|
.dataTimeSeg1 = 0,
|
|
/* Data Time segment after sample point. */
|
|
.dataTimeSeg2 = 0,
|
|
/* Data (Re)Synchronization Jump Width. */
|
|
.dataSynchJumpWidth = 0,
|
|
};
|
|
|
|
static const DL_MCAN_BitTimingParams __gprv_xBitTimes_250 = {
|
|
/* Arbitration Baud Rate Pre-scaler. */
|
|
.nomRatePrescalar = 0,
|
|
/* Arbitration Time segment before sample point. */
|
|
.nomTimeSeg1 = 82,
|
|
/* Arbitration Time segment after sample point. */
|
|
.nomTimeSeg2 = 11,
|
|
/* Arbitration (Re)Synchronization Jump Width Range. */
|
|
.nomSynchJumpWidth = 11,
|
|
/* Data Baud Rate Pre-scaler. */
|
|
.dataRatePrescalar = 0,
|
|
/* Data Time segment before sample point. */
|
|
.dataTimeSeg1 = 0,
|
|
/* Data Time segment after sample point. */
|
|
.dataTimeSeg2 = 0,
|
|
/* Data (Re)Synchronization Jump Width. */
|
|
.dataSynchJumpWidth = 0,
|
|
};
|
|
/*____________________________________________________________________________________________________________________________________________________________________________________________*/
|
|
|
|
|
|
/*=============================================================================================================================================================================================
|
|
PRIVATE_DECLARATIONS
|
|
==============================================================================================================================================================================================*/
|
|
/**
|
|
* @brief Processes CAN interrupt events.
|
|
*
|
|
* Handles CAN RX FIFO events, reads messages from the RX FIFO, and invokes a callback
|
|
* for each received message. It also processes error conditions and manages the interrupt status.
|
|
*
|
|
* @param[in] u32InterruptStatus The interrupt status indicating which event triggered the interrupt.
|
|
*
|
|
* @details
|
|
* - If the interrupt is related to RX FIFO events (RF0F, RF0N, RF1F, RF1N):
|
|
* - Retrieves the FIFO status and reads messages from the corresponding RX FIFO.
|
|
* - Acknowledges the read message and processes the message ID and data payload.
|
|
* - Calls `vMCAL_CanReceiveFifoCallback` with the received message.
|
|
* - If the interrupt is related to errors (e.g., timeout, bus off, protocol errors):
|
|
* - The interrupt status is saved for further processing (currently no action is taken for errors).
|
|
*/
|
|
|
|
|
|
static void __prv_McalCanInterruptProcess(uint32_t u32InterruptStatus)
|
|
{
|
|
volatile uint32_t l_u32CanInterrupt = 0;
|
|
l_u32CanInterrupt = u32InterruptStatus;
|
|
uint32_t u32IntrStatus = u32InterruptStatus;
|
|
if (u32IntrStatus & (DL_MCAN_INTERRUPT_RF1F | DL_MCAN_INTERRUPT_RF0N | DL_MCAN_INTERRUPT_RF0F | DL_MCAN_INTERRUPT_RF1N)) {
|
|
|
|
volatile DL_MCAN_RxFIFOStatus l_xRxFIFOStatus = {0};
|
|
|
|
if (u32IntrStatus & (DL_MCAN_INTERRUPT_RF0F | DL_MCAN_INTERRUPT_RF0N))
|
|
l_xRxFIFOStatus.num = DL_MCAN_RX_FIFO_NUM_0;
|
|
else
|
|
l_xRxFIFOStatus.num = DL_MCAN_RX_FIFO_NUM_1;
|
|
DL_MCAN_getRxFIFOStatus(CANFD0, &l_xRxFIFOStatus);
|
|
|
|
while ((l_xRxFIFOStatus.fillLvl) != 0)
|
|
{
|
|
volatile DL_MCAN_RxBufElement l_xTempRxMsg;
|
|
|
|
DL_MCAN_readMsgRam(CANFD0, DL_MCAN_MEM_TYPE_FIFO, 0, l_xRxFIFOStatus.num, &l_xTempRxMsg);
|
|
DL_MCAN_writeRxFIFOAck(CANFD0, l_xRxFIFOStatus.num, l_xRxFIFOStatus.getIdx);
|
|
|
|
if (!l_xTempRxMsg.xtd)
|
|
l_xTempRxMsg.id = (uint32_t)(l_xTempRxMsg.id >> 18);
|
|
|
|
/* Extract data payload */
|
|
uint8_t au8DataArr[8] = {0};
|
|
for (int i = 0; i < 8; i++) {
|
|
au8DataArr[i] = l_xTempRxMsg.data[i] & 0xFF;
|
|
}
|
|
|
|
vMCAL_CanReceiveFifoCallback(l_xTempRxMsg.id, &au8DataArr[0], l_xTempRxMsg.dlc);
|
|
DL_MCAN_getRxFIFOStatus(CANFD0, &l_xRxFIFOStatus);
|
|
}
|
|
}
|
|
if(u32IntrStatus & (DL_MCAN_INTR_SRC_MSG_RAM_ACCESS_FAILURE|DL_MCAN_INTR_SRC_TIMEOUT|DL_MCAN_INTR_SRC_ERR_LOG_OVRFLW|DL_MCAN_INTR_SRC_ERR_PASSIVE|DL_MCAN_INTR_SRC_ERR_PASSIVE|DL_MCAN_INTR_SRC_WARNING_STATUS|DL_MCAN_INTR_SRC_BUS_OFF_STATUS|DL_MCAN_INTR_SRC_WATCHDOG|DL_MCAN_INTR_SRC_PROTOCOL_ERR_ARB|DL_MCAN_INTR_SRC_PROTOCOL_ERR_DATA|DL_MCAN_INTR_SRC_RES_ADDR_ACCESS) ) {
|
|
l_u32CanInterrupt = u32InterruptStatus;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Default Interrupt Handler for MCAN
|
|
*
|
|
*/
|
|
|
|
void CANFD0_IRQHandler(void)
|
|
{
|
|
/* Get the pending interrupt source */
|
|
switch (DL_MCAN_getPendingInterrupt(CANFD0))
|
|
{
|
|
case DL_MCAN_IIDX_LINE1:
|
|
{
|
|
/* Get interrupt status for Line 1 */
|
|
uint32_t l_u32IntrStatus = DL_MCAN_getIntrStatus(CANFD0);
|
|
/* Process the interrupt */
|
|
__prv_McalCanInterruptProcess(l_u32IntrStatus );
|
|
|
|
/* Clear the interrupt status for Line 1 */
|
|
DL_MCAN_clearIntrStatus(MCAN0_INST, l_u32IntrStatus, DL_MCAN_INTR_SRC_MCAN_LINE_1);
|
|
break;
|
|
}
|
|
case DL_MCAN_IIDX_LINE0:
|
|
{
|
|
/* Get interrupt status for Line 0 */
|
|
uint32_t l_u32IntrStatus = DL_MCAN_getIntrStatus(CANFD0);
|
|
|
|
/* Process the interrupt */
|
|
__prv_McalCanInterruptProcess(l_u32IntrStatus );
|
|
|
|
/* Clear the interrupt status for Line 0 */
|
|
DL_MCAN_clearIntrStatus(MCAN0_INST, l_u32IntrStatus, DL_MCAN_INTR_SRC_MCAN_LINE_0);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
/* Get interrupt status for external timestamp */
|
|
uint32_t l_u32IntrStatus = DL_MCAN_getIntrStatus(CANFD0);
|
|
|
|
/* Clear the interrupt status for external timestamp */
|
|
DL_MCAN_clearIntrStatus(MCAN0_INST, l_u32IntrStatus, DL_MCAN_INTR_SRC_MCAN_EXT_TS);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*=============================================================================================================================================================================================
|
|
API
|
|
==============================================================================================================================================================================================*/
|
|
|
|
/**
|
|
* @brief Initializes the MCAN module with specified configurations.
|
|
*
|
|
* This function configures the MCAN module with the following:
|
|
* - Enables the module clock and sets the clock configuration.
|
|
* - Initializes the MCAN in software initialization mode and waits for completion.
|
|
* - Configures bit timings and message RAM.
|
|
* - Sets up the filter configurations for both extended and standard IDs based on the provided filter values and masks.
|
|
* - Enables necessary interrupts for CAN operation and sets interrupt priorities.
|
|
*
|
|
* @param[in] pxCanHandle Pointer to the CAN handle structure containing the configuration parameters.
|
|
*
|
|
* @return IVEC_MCAL_STATUS_SUCCESS if the initialization is successful, or an error status if failed.
|
|
*
|
|
* @details
|
|
* The function performs the following steps:
|
|
* 1. Validates the CAN instance and speed.
|
|
* 2. Initializes the MCAN module by enabling the module clock, configuring the clock, and setting the operation mode to software initialization.
|
|
* 3. Waits for memory initialization to complete, then sets the MCAN operation mode to normal.
|
|
* 4. Configures the MCAN module parameters, including bit timings and message RAM.
|
|
* 5. Sets up CAN filters for extended and standard IDs based on the provided filter and mask values.
|
|
* 6. Enables CAN interrupts and configures interrupt lines for CAN events.
|
|
* 7. Clears and enables interrupts in the NVIC for the CAN module.
|
|
*/
|
|
|
|
IVEC_McalCommonErr_e xMCAL_MCANInit(IVEC_McalCanHandle_s* pxCanHandle)
|
|
{
|
|
|
|
if((pxCanHandle->pMCAN != CANFD0) && (pxCanHandle->u16Speed == IVEC_MCAL_CAN_BR_500 || pxCanHandle->u16Speed == IVEC_MCAL_CAN_BR_250))
|
|
{
|
|
return commonMCAL_INVALID_PARAM;
|
|
}
|
|
if(pxCanHandle->__u8Init == 1)
|
|
{
|
|
return commonMCAL_INVALID_PARAM;
|
|
}
|
|
|
|
/* Enable power to the MCAN module */
|
|
DL_MCAN_enablePower(pxCanHandle->pMCAN);
|
|
delay_cycles(POWER_STARTUP_DELAY);
|
|
|
|
/* Configure GPIO for CAN TX and RX */
|
|
DL_GPIO_initPeripheralOutputFunction(GPIO_MCAN0_IOMUX_CAN_TX, GPIO_MCAN0_IOMUX_CAN_TX_FUNC);
|
|
DL_GPIO_initPeripheralInputFunction(GPIO_MCAN0_IOMUX_CAN_RX, GPIO_MCAN0_IOMUX_CAN_RX_FUNC);
|
|
|
|
|
|
DL_MCAN_RevisionId xRevid;
|
|
|
|
DL_MCAN_enableModuleClock(pxCanHandle->pMCAN);
|
|
|
|
DL_MCAN_setClockConfig(pxCanHandle->pMCAN, (DL_MCAN_ClockConfig *) &__gprv_xClockConf);
|
|
|
|
/* Get MCANSS Revision ID. */
|
|
DL_MCAN_getRevisionId(pxCanHandle->pMCAN, &xRevid);
|
|
|
|
/* Wait for Memory initialization to be completed. */
|
|
while (false == DL_MCAN_isMemInitDone(pxCanHandle->pMCAN));
|
|
|
|
/* Put MCAN in SW initialization mode. */
|
|
|
|
DL_MCAN_setOpMode(pxCanHandle->pMCAN, DL_MCAN_OPERATION_MODE_SW_INIT);
|
|
|
|
/* Wait till MCAN is not initialized. */
|
|
while (DL_MCAN_OPERATION_MODE_SW_INIT != DL_MCAN_getOpMode(pxCanHandle->pMCAN));
|
|
|
|
/* Initialize MCAN module. */
|
|
DL_MCAN_init(pxCanHandle->pMCAN, (DL_MCAN_InitParams*)&__gprv_xInitParams);
|
|
__gprv_xConfigParams.filterConfig.anfe = 0;
|
|
__gprv_xConfigParams.filterConfig.anfs = 0;
|
|
|
|
for (int u32Index = 0; u32Index <= pxCanHandle->i32MaskCount; u32Index++) {
|
|
if ((pxCanHandle->u32FilterValues[u32Index] > 0x7FF) || (pxCanHandle->u32MaskValues[u32Index] > 0x7FF)) {
|
|
__gprv_xConfigParams.filterConfig.anfe = 3;
|
|
}
|
|
else
|
|
{
|
|
__gprv_xConfigParams.filterConfig.anfs = 3;
|
|
}
|
|
}
|
|
/* Configure MCAN module. */
|
|
DL_MCAN_config(pxCanHandle->pMCAN, (DL_MCAN_ConfigParams*)&__gprv_xConfigParams);
|
|
|
|
/* Configure Bit timings. */
|
|
if (pxCanHandle->u16Speed == IVEC_MCAL_CAN_BR_500)
|
|
{
|
|
|
|
DL_MCAN_setBitTime(pxCanHandle->pMCAN, (DL_MCAN_BitTimingParams*)&__gprv_xBitTimes_500);
|
|
}
|
|
else if (pxCanHandle->u16Speed == IVEC_MCAL_CAN_BR_250)
|
|
{
|
|
DL_MCAN_setBitTime(pxCanHandle->pMCAN, (DL_MCAN_BitTimingParams*)&__gprv_xBitTimes_250);
|
|
}
|
|
else
|
|
{
|
|
DL_MCAN_setBitTime(pxCanHandle->pMCAN, (DL_MCAN_BitTimingParams*)&__gprv_xBitTimes_250);
|
|
}
|
|
|
|
/* Configure Message RAM Sections */
|
|
DL_MCAN_msgRAMConfig(pxCanHandle->pMCAN, (DL_MCAN_MsgRAMConfigParams*)&__gprv_xMsgRAMConfigParams);
|
|
|
|
uint8_t l_u8ExtendedFilterCount = 0;
|
|
uint8_t l_u8StandardFilterCount = 0;
|
|
|
|
for (int u32Index = 0; u32Index <= pxCanHandle->i32MaskCount; u32Index++) {
|
|
if ((pxCanHandle->u32FilterValues[u32Index] > 0x7FF) || (pxCanHandle->u32MaskValues[u32Index] > 0x7FF)) {
|
|
// Extended ID filter
|
|
DL_MCAN_ExtMsgIDFilterElement extFilterElement;
|
|
extFilterElement.efid1 = pxCanHandle->u32FilterValues[u32Index];
|
|
extFilterElement.efid2 = pxCanHandle->u32MaskValues[u32Index];
|
|
extFilterElement.efec = 001;
|
|
extFilterElement.eft = 2;
|
|
DL_MCAN_addExtMsgIDFilter(pxCanHandle->pMCAN, l_u8ExtendedFilterCount, (DL_MCAN_StdMsgIDFilterElement*)&extFilterElement);
|
|
l_u8ExtendedFilterCount++;
|
|
|
|
}
|
|
else {
|
|
// Standard ID filter
|
|
DL_MCAN_StdMsgIDFilterElement stdFilterElement;
|
|
stdFilterElement.sfid1 = pxCanHandle->u32FilterValues[u32Index];
|
|
stdFilterElement.sfid2 = pxCanHandle->u32MaskValues[u32Index];
|
|
stdFilterElement.sfec = 001;
|
|
stdFilterElement.sft = 2;
|
|
DL_MCAN_addStdMsgIDFilter(pxCanHandle->pMCAN, l_u8StandardFilterCount, (DL_MCAN_StdMsgIDFilterElement*)&stdFilterElement);
|
|
l_u8StandardFilterCount++;
|
|
|
|
}
|
|
}
|
|
DL_MCAN_setExtIDAndMask(pxCanHandle->pMCAN, (0x1FFFFFFFU));
|
|
|
|
/* Take MCAN out of the SW initialization mode */
|
|
DL_MCAN_setOpMode(pxCanHandle->pMCAN, DL_MCAN_OPERATION_MODE_NORMAL);
|
|
|
|
while (DL_MCAN_OPERATION_MODE_NORMAL != DL_MCAN_getOpMode(pxCanHandle->pMCAN));
|
|
|
|
/* Enable MCAN mopdule Interrupts */
|
|
DL_MCAN_enableIntr(pxCanHandle->pMCAN, (MCAN_IR_RF0N_MASK | \
|
|
MCAN_IR_RF0F_MASK | \
|
|
MCAN_IR_RF1N_MASK | \
|
|
MCAN_IR_RF1F_MASK | \
|
|
MCAN_IR_TSW_MASK | \
|
|
MCAN_IR_MRAF_MASK | \
|
|
MCAN_IR_TOO_MASK | \
|
|
MCAN_IR_DRX_MASK | \
|
|
MCAN_IR_BEU_MASK | \
|
|
MCAN_IR_ELO_MASK | \
|
|
MCAN_IR_EP_MASK | \
|
|
MCAN_IR_EW_MASK | \
|
|
MCAN_IR_BO_MASK | \
|
|
MCAN_IR_WDI_MASK | \
|
|
MCAN_IR_ARA_MASK), 1);
|
|
|
|
|
|
DL_MCAN_selectIntrLine(pxCanHandle->pMCAN, DL_MCAN_INTR_MASK_ALL, DL_MCAN_INTR_LINE_NUM_0);
|
|
DL_MCAN_enableIntrLine(pxCanHandle->pMCAN, DL_MCAN_INTR_LINE_NUM_0, 1U);
|
|
|
|
/* Enable MSPM0 MCAN interrupt */
|
|
DL_MCAN_clearInterruptStatus(pxCanHandle->pMCAN, (DL_MCAN_MSP_INTERRUPT_LINE0));
|
|
DL_MCAN_enableInterrupt(pxCanHandle->pMCAN, (DL_MCAN_MSP_INTERRUPT_LINE0));
|
|
|
|
NVIC_SetPriority(CANFD0_INT_IRQn, 1);
|
|
NVIC_ClearPendingIRQ(CANFD0_INT_IRQn);
|
|
NVIC_EnableIRQ(CANFD0_INT_IRQn);
|
|
pxCanHandle->__u8Init = 1;
|
|
|
|
return commonMCAL_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Function to De-Initialize MCAN peripheral
|
|
* @param MCAN Pointer to the register overlay for the peripheral
|
|
* @retval IVEC MCAL status
|
|
*/
|
|
|
|
IVEC_McalCommonErr_e xMCAL_MCANDeInit(IVEC_McalCanHandle_s* pxCanHandle)
|
|
{
|
|
/* Assert that the MCAN module pointer is valid */
|
|
if((pxCanHandle->pMCAN != CANFD0) && (pxCanHandle->u16Speed == IVEC_MCAL_CAN_BR_500 || pxCanHandle->u16Speed == IVEC_MCAL_CAN_BR_250))
|
|
{
|
|
return commonMCAL_INVALID_PARAM;
|
|
}
|
|
if(pxCanHandle->__u8Init == 0) /* Ensure the module was initialized before deinitializing. */
|
|
{
|
|
return commonMCAL_INVALID_PARAM;
|
|
}
|
|
|
|
/* Reset the CAN module to initialization mode */
|
|
DL_MCAN_setOpMode(pxCanHandle->pMCAN, DL_MCAN_OPERATION_MODE_SW_INIT);
|
|
|
|
/* Wait until the operation mode is set to initialization mode */
|
|
while (DL_MCAN_OPERATION_MODE_SW_INIT != DL_MCAN_getOpMode(pxCanHandle->pMCAN));
|
|
|
|
/* Disable the CAN interrupt */
|
|
NVIC_DisableIRQ(CANFD0_INT_IRQn);
|
|
|
|
/* Disable interrupts on CAN module */
|
|
DL_MCAN_enableIntr(pxCanHandle->pMCAN, (DL_MCAN_INTERRUPT_BEU | \
|
|
DL_MCAN_INTERRUPT_BO | \
|
|
DL_MCAN_INTERRUPT_ELO | \
|
|
DL_MCAN_INTERRUPT_EP | \
|
|
DL_MCAN_INTERRUPT_EW | \
|
|
DL_MCAN_INTERRUPT_PEA | \
|
|
DL_MCAN_INTERRUPT_PED | \
|
|
DL_MCAN_INTERRUPT_RF0N | \
|
|
DL_MCAN_INTERRUPT_RF1N | \
|
|
DL_MCAN_INTERRUPT_TC | \
|
|
DL_MCAN_INTERRUPT_TOO), false);
|
|
|
|
|
|
/* Disable interrupt lines */
|
|
DL_MCAN_enableIntrLine(pxCanHandle->pMCAN, DL_MCAN_INTR_LINE_NUM_0, false);
|
|
DL_MCAN_enableIntrLine(pxCanHandle->pMCAN, DL_MCAN_INTR_LINE_NUM_1, false);
|
|
|
|
/* Clear interrupt statuses for lines 0 and 1 */
|
|
DL_MCAN_clearInterruptStatus(pxCanHandle->pMCAN, DL_MCAN_MSP_INTERRUPT_LINE0);
|
|
DL_MCAN_disableInterrupt(pxCanHandle->pMCAN, DL_MCAN_MSP_INTERRUPT_LINE0);
|
|
|
|
DL_MCAN_clearInterruptStatus(pxCanHandle->pMCAN, DL_MCAN_MSP_INTERRUPT_LINE1);
|
|
DL_MCAN_disableInterrupt(pxCanHandle->pMCAN, DL_MCAN_MSP_INTERRUPT_LINE1);
|
|
|
|
/* Set the operation mode back to normal */
|
|
DL_MCAN_setOpMode(pxCanHandle->pMCAN, DL_MCAN_OPERATION_MODE_NORMAL);
|
|
|
|
/* Reset the initialization flag */
|
|
pxCanHandle->__u8Init = 0;
|
|
|
|
/* Disable the CAN module's GPIO peripheral function */
|
|
DL_GPIO_initPeripheralOutputFunction(IOMUX_PINCM59, 0);
|
|
DL_GPIO_initPeripheralInputFunction(IOMUX_PINCM60, 0);
|
|
|
|
/* Disable the module clock and power */
|
|
DL_MCAN_disableModuleClock(pxCanHandle->pMCAN);
|
|
DL_MCAN_disablePower(pxCanHandle->pMCAN);
|
|
|
|
/* Wait for power down to complete */
|
|
delay_cycles(16);
|
|
return commonMCAL_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Deinitializes the MCAN module and disables associated resources.
|
|
*
|
|
* This function performs the necessary steps to safely deinitialize the MCAN module, including:
|
|
* - Resetting the MCAN to initialization mode.
|
|
* - Disabling CAN interrupts and interrupt lines.
|
|
* - Clearing interrupt statuses.
|
|
* - Setting the MCAN operation mode back to normal.
|
|
* - Disabling the CAN module clock and powering down the module.
|
|
* - Disabling the GPIO peripheral functions for CAN.
|
|
*
|
|
* @param[in] pxCanHandle Pointer to the CAN handle structure containing the configuration parameters.
|
|
*
|
|
* @return IVEC_MCAL_STATUS_SUCCESS if the deinitialization is successful, or an error status if failed.
|
|
*
|
|
* @details
|
|
* The function performs the following steps:
|
|
* 1. Validates the CAN module pointer and checks if the module was initialized.
|
|
* 2. Resets the CAN module to the software initialization mode and waits for completion.
|
|
* 3. Disables interrupts for the CAN module and the interrupt lines associated with CAN events.
|
|
* 4. Clears interrupt statuses for both interrupt lines and disables the interrupts in the NVIC.
|
|
* 5. Sets the CAN operation mode back to normal.
|
|
* 6. Resets the initialization flag and disables the GPIO peripheral functions for CAN pins.
|
|
* 7. Disables the CAN module's clock and power, waiting for the power down process to complete.
|
|
*/
|
|
|
|
IVEC_McalCommonErr_e xMCAL_MCANTx(IVEC_McalCanHandle_s* pxCanHandle, uint32_t u32Id,
|
|
uint16_t* pu16TxData, uint32_t u32BufNum,
|
|
uint32_t u32Bytes)
|
|
{
|
|
/* Ensure that the MCAN instance is CANFD0 */
|
|
if(pxCanHandle->pMCAN != CANFD0)
|
|
{
|
|
return IVEC_MCAL_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
/* Ensure that the MCAN is initialized */
|
|
if(pxCanHandle->__u8Init == 0)
|
|
{
|
|
return IVEC_MCAL_STATUS_FALSE;
|
|
}
|
|
|
|
|
|
/* Validate the byte size */
|
|
if (u32Bytes > 8)
|
|
{
|
|
return IVEC_MCAL_STATUS_FALSE;
|
|
}
|
|
|
|
DL_MCAN_TxBufElement txMsg = {0};
|
|
|
|
/* Set the message type (standard or extended ID) */
|
|
if (u32Id > 0x7FF)
|
|
{
|
|
txMsg.xtd = 1; /* Extended ID */
|
|
txMsg.id = u32Id; /* Set the extended ID */
|
|
}
|
|
else
|
|
{
|
|
txMsg.xtd = 0; /* Standard ID */
|
|
txMsg.id = ((uint32_t)(u32Id)) << 18U; /* Adjust for standard ID format */
|
|
}
|
|
|
|
/* Copy the data bytes to the message */
|
|
for (uint32_t u32Index = 0; u32Index < u32Bytes; u32Index++)
|
|
{
|
|
txMsg.data[u32Index] = pu16TxData[u32Index];
|
|
}
|
|
txMsg.dlc = u32Bytes; /* Set the Data Length Code (DLC) */
|
|
|
|
__asm("nop"); /* No operation for synchronization */
|
|
|
|
volatile DL_MCAN_TxFIFOStatus l_xTxFifoStatus = { 0 }; // Structure variable prefixed with 's' for structure type and 'x' for typedef suffix
|
|
|
|
DL_MCAN_getTxFIFOQueStatus(pxCanHandle->pMCAN, &l_xTxFifoStatus); // Get the FIFO status
|
|
// __disable_irq();
|
|
if (l_xTxFifoStatus.freeLvl) // Check if there is space in the FIFO
|
|
{
|
|
DL_MCAN_writeMsgRam(pxCanHandle->pMCAN, DL_MCAN_MEM_TYPE_FIFO, u32BufNum, &txMsg); // Function and variable name updated
|
|
|
|
if (DL_MCAN_TXBufAddReq(pxCanHandle->pMCAN, l_xTxFifoStatus.putIdx) == IVEC_MCAL_STATUS_ERROR) // Function return type 'x'
|
|
{
|
|
return IVEC_MCAL_STATUS_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* If no space in FIFO, return busy */
|
|
return IVEC_MCAL_STATUS_BUSY;
|
|
}
|
|
|
|
DL_MCAN_getTxFIFOQueStatus(pxCanHandle->pMCAN, &l_xTxFifoStatus);
|
|
volatile uint32_t l_i32TransmitTimeout = i32MCAL_getTicks();
|
|
volatile uint8_t l_u8StatusFlag = IVEC_MCAL_STATUS_BUSY;
|
|
|
|
while (1)
|
|
{
|
|
|
|
if (l_u8StatusFlag == IVEC_MCAL_STATUS_SUCCESS)
|
|
{
|
|
return l_u8StatusFlag;
|
|
}
|
|
else if ((i32MCAL_getTicks() - l_i32TransmitTimeout) > 2)
|
|
{
|
|
return IVEC_MCAL_STATUS_TIMEOUT;
|
|
}
|
|
l_u8StatusFlag = (DL_MCAN_getTxBufTransmissionStatus(pxCanHandle->pMCAN) == 0x01) ? \
|
|
IVEC_MCAL_STATUS_SUCCESS : IVEC_MCAL_STATUS_ERROR;
|
|
}
|
|
|
|
|
|
// __enable_irq();
|
|
return IVEC_MCAL_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Receives a message from the CAN bus.
|
|
*
|
|
* Retrieves the received CAN message, including the message ID and data.
|
|
* Handles bus-off recovery and copies the received data into the provided buffer.
|
|
*
|
|
* @param[in] pxCanHandle Pointer to the CAN handle.
|
|
* @param[out] pu32ID Pointer to store the received message ID.
|
|
* @param[out] pu8RxData Pointer to the buffer to store the received message data.
|
|
* @param[in] iDLC The Data Length Code (DLC), specifying the number of bytes in the data field.
|
|
*
|
|
* @return IVEC_MCAL_STATUS_SUCCESS on successful reception.
|
|
*/
|
|
|
|
IVEC_McalCommonErr_e xMCAL_MCANRx(IVEC_McalCanHandle_s* pxCanHandle, uint32_t *pu32ID, uint8_t *pu8RxData, int iDLC)
|
|
{
|
|
/* Assert that the CAN module is CANFD0 and that the MCAL initialization flag is set */
|
|
if((pxCanHandle->pMCAN != CANFD0) && (pxCanHandle->u16Speed == IVEC_MCAL_CAN_BR_500 || pxCanHandle->u16Speed == IVEC_MCAL_CAN_BR_250))
|
|
{
|
|
return commonMCAL_INVALID_PARAM;
|
|
}
|
|
if(pxCanHandle->__u8Init == 0)
|
|
{
|
|
return commonMCAL_INVALID_PARAM;
|
|
}
|
|
|
|
return commonMCAL_FAIL;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Retrieves the error status of the MCAN module.
|
|
*
|
|
* Copies the current error interrupt status and protocol status into a buffer and returns
|
|
* an appropriate status based on error conditions.
|
|
*
|
|
* @param[in] pxCanHandle Pointer to the CAN handle.
|
|
* @param[out] pcErrorStatus Buffer to store the error status string.
|
|
*
|
|
* @return IVEC_MCAL_STATUS_SUCCESS if no errors, IVEC_MCAL_STATUS_ERROR if errors are detected.
|
|
*/
|
|
|
|
|
|
IVEC_McalCommonErr_e xMCAL_MCANGetErrorStatus(IVEC_McalCanHandle_s* pxCanHandle, char *pcErrorStatus)
|
|
{
|
|
/* Assert that the MCAN initialization flag is set */
|
|
if(pxCanHandle->__u8Init == 0)
|
|
{
|
|
return commonMCAL_INVALID_PARAM;
|
|
}
|
|
|
|
/* Retrieve the current protocol status of the MCAN module */
|
|
DL_MCAN_getProtocolStatus(pxCanHandle->pMCAN, &g_xHeaderStat);
|
|
|
|
/* Declare and initialize the error counter status structure */
|
|
volatile DL_MCAN_ErrCntStatus l_xCounter = {0};
|
|
DL_MCAN_getErrCounters(CANFD0, &l_xCounter);
|
|
|
|
/* Return the status based on various error conditions */
|
|
if((g_xHeaderStat.lastErrCode == DL_MCAN_ERR_CODE_ACK_ERROR) || (g_xHeaderStat.busOffStatus))
|
|
DL_MCAN_setOpMode(CANFD0, DL_MCAN_OPERATION_MODE_NORMAL);
|
|
return commonMCAL_SUCCESS;
|
|
/*
|
|
return ( (g_xHeaderStat.lastErrCode == DL_MCAN_ERR_CODE_ACK_ERROR) || \
|
|
(g_xHeaderStat.busOffStatus) ) ? commonMCAL_FAIL : commonMCAL_SUCCESS;
|
|
*/
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Retrieves the status of interrupt line 1 for the MCAN module.
|
|
*
|
|
* Copies the current interrupt status for line 1 into the provided status buffer.
|
|
*
|
|
* @param[in] pxCanHandle Pointer to the CAN handle.
|
|
* @param[out] pu32InterruptStatus Pointer to store the interrupt status.
|
|
*
|
|
* @return IVEC_MCAL_STATUS_SUCCESS if successful.
|
|
*/
|
|
|
|
IVEC_McalCommonErr_e xMCAL_MCANGetInterruptLine1Status(IVEC_McalCanHandle_s* pxCanHandle, uint32_t *pu32InterruptStatus)
|
|
{
|
|
// Ensure CAN module is initialized (optional assertion, can be uncommented as needed)
|
|
if(pxCanHandle->__u8Init == 0)
|
|
{
|
|
return commonMCAL_INVALID_PARAM;
|
|
}
|
|
|
|
*pu32InterruptStatus = g_u32InterruptLine1Status;
|
|
|
|
return commonMCAL_SUCCESS;
|
|
}
|
|
|