chg-stn-motherboard-ti-mcu/Core/Source/ivec_mcal_mcan.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;
}