/** ****************************************************************************** * @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" static volatile bool b_MCAN_InitFlag = 0; /*!< CAN initialization flag */ static volatile bool b_ServiceInt=true; static volatile uint32_t u32InterruptLine1Status; static char u8ErrorInterruptStatus[50]; static volatile DL_MCAN_RxFIFOStatus rxFS; static DL_MCAN_RxBufElement TempRxMsg; static uint32_t id; extern uint16_t idx; uint32_t IntrStatus; static volatile uint8_t u8_MCAN_StatusFlag = IVEC_MCAL_STATUS_ERROR; uint8_t g_CanData[8]; volatile DL_MCAN_ProtocolStatus HeaderStat; #define MCAN_FILTER_SIZE 4u extern uint16_t g_u16CanSpeed; /*REQUIRED MCAN CONFIGS*/ /*=======================================================================================PRIVATE_MEMBERS======================================================================================*/ static const DL_MCAN_ClockConfig gMCAN0ClockConf = { .clockSel = DL_MCAN_FCLK_HFCLK,////DL_MCAN_FCLK_SYSPLLCLK1,DL_MCAN_FCLK_HFCLK, .divider = DL_MCAN_FCLK_DIV_1, }; static const DL_MCAN_InitParams gMCAN0InitParams= { /* Initialize MCAN Init parameters. */ .fdMode = false, .brsEnable = false, .txpEnable = false, .efbi = false, .pxhddisable = false, .darEnable = false, .wkupReqEnable = false, .autoWkupEnable = false, .emulationEnable = true, .tdcEnable = true, .wdcPreload = 255, /* Transmitter Delay Compensation parameters. */ .tdcConfig.tdcf = 10, .tdcConfig.tdco = 6, }; static DL_MCAN_ConfigParams gMCAN0ConfigParams={ /* 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, // .filterConfig.rrfs = true, // .filterConfig.rrfe = true, // .filterConfig.anfe = 1, // .filterConfig.anfs = 1, }; static DL_MCAN_MsgRAMConfigParams gMCAN0MsgRAMConfigParams ={ /* Standard ID Filter List Start Address. */ .flssa = 5 , /* List Size: Standard ID. */ .lss = MCAN_FILTER_SIZE, /* Extended ID Filter List Start Address. */ .flesa = 48 , /* List Size: Extended ID. */ .lse = 1 , /* Tx Buffers Start Address. */ .txStartAddr = 10 , /* Number of Dedicated Transmit Buffers. */ .txBufNum = 10 , .txFIFOSize = 10, /* Tx Buffer Element Size. */ .txBufMode = 0, .txBufElemSize = DL_MCAN_ELEM_SIZE_8BYTES, /* Tx Event FIFO Start Address. */ .txEventFIFOStartAddr = 640 , /* Event FIFO Size. */ .txEventFIFOSize = 10 , /* Level for Tx Event FIFO watermark interrupt. */ .txEventFIFOWaterMark = 0, /* Rx FIFO0 Start Address. */ .rxFIFO0startAddr = 170 , /* Number of Rx FIFO elements. */ .rxFIFO0size = 10 , /* Rx FIFO0 Watermark. */ .rxFIFO0waterMark = 0, .rxFIFO0OpMode = 0, /* Rx FIFO1 Start Address. */ .rxFIFO1startAddr = 190 , /* Number of Rx FIFO elements. */ .rxFIFO1size = 10 , /* Level for Rx FIFO 1 watermark interrupt. */ .rxFIFO1waterMark = 10, /* FIFO blocking mode. */ .rxFIFO1OpMode = 0, /* Rx Buffer Start Address. */ .rxBufStartAddr = 208 , /* 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 const DL_MCAN_StdMsgIDFilterElement gMCAN0StdFiltelem = { // .sfec = 0x1, // Store in Rx FIFO 0 if filter matches // .sft = 0x11, // Disable filter, receive all IDs // .sfid1 = 0, // These values won't be used because filtering is disabled // .sfid2 = 0, // These values won't be used because filtering is disabled //}; // //// Static filter element definition to disable filtering //static const DL_MCAN_ExtMsgIDFilterElement gMCAN0ExtFilterElem = { // .efid1 = 0, // These values won't be used because filtering is disabled // .efec = 0x0, // Disable filter element (0b000) // .efid2 = 0xffffffff, // These values won't be used because filtering is disabled // .eft = 0x3, // Set to 0b11 for disabling filtering (no specific filter applied) //}; static DL_MCAN_BitTimingParams gMCAN0BitTimes_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 gMCAN0BitTimes_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, }; //static const DL_MCAN_BitTimingParams gMCAN0BitTimes_125 = { // /* Arbitration Baud Rate Pre-scaler. */ // .nomRatePrescalar = 0, // /* Arbitration Time segment before sample point. */ // .nomTimeSeg1 = 138, // /* Arbitration Time segment after sample point. */ // .nomTimeSeg2 = 19, // /* Arbitration (Re)Synchronization Jump Width Range. */ // .nomSynchJumpWidth = 19, // /* 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 gMCAN0BitTimes_150 = { /* Arbitration Baud Rate Pre-scaler. */ .nomRatePrescalar = 0, /* Arbitration Time segment before sample point. */ .nomTimeSeg1 = 138, /* Arbitration Time segment after sample point. */ .nomTimeSeg2 = 19, /* Arbitration (Re)Synchronization Jump Width Range. */ .nomSynchJumpWidth = 19, /* Data Baud Rate Pre-scaler. */ .dataRatePrescalar = 0, /* Data Time segment before sample point. */ .dataTimeSeg1 = 19, /* Data Time segment after sample point. */ .dataTimeSeg2 = 2, /* Data (Re)Synchronization Jump Width. */ .dataSynchJumpWidth = 2, }; static const DL_MCAN_BitTimingParams gMCAN0BitTimes_1000 = { /* Arbitration Baud Rate Pre-scaler. */ .nomRatePrescalar = 0, /* Arbitration Time segment before sample point. */ .nomTimeSeg1 = 19, /* Arbitration Time segment after sample point. */ .nomTimeSeg2 = 2, /* Arbitration (Re)Synchronization Jump Width Range. */ .nomSynchJumpWidth = 2, /* Data Baud Rate Pre-scaler. */ .dataRatePrescalar = 0, /* Data Time segment before sample point. */ .dataTimeSeg1 = 19, /* Data Time segment after sample point. */ .dataTimeSeg2 = 2, /* Data (Re)Synchronization Jump Width. */ .dataSynchJumpWidth = 2, }; /*____________________________________________________________________________________________________________________________________________________________________________________________*/ /*============================================================================================================================================================================================= PRIVATE_DECLARATIONS ==============================================================================================================================================================================================*/ /** * @brief Static Function to store RX data in a static buffer * @retval void */ //static void _prv_vGetRxMsg(DL_MCAN_RxBufElement *rxMsg,uint8_t *RxData,int DLC) //{ // for (int i =0 ; i < DLC ; i++) // { // RxData[i] = rxMsg->data[i]; // } // //} static void _prv_vGetRxMsg(DL_MCAN_RxBufElement *rxMsg,uint8_t *RxData,int DLC) { id = ((rxMsg->id & (uint32_t) 0x1FFC0000) >> (uint32_t) 18); switch (id) { case 0x5: *RxData = rxMsg->data[0]; idx = (rxMsg->data[0] + 1) % 256; break; default: /* Don't do anything */ break; } } /** * @brief Private Function working as an Error Handler in IRQ * @retval void */ static void ErrorHandler() { switch(DL_MCAN_getIntrStatus(CANFD0)) { case MCAN_IR_PED_MASK: strcpy(u8ErrorInterruptStatus, "Protocol Error in Data Phase!"); __asm("nop"); break; case MCAN_IR_PEA_MASK: strcpy(u8ErrorInterruptStatus, "Protocol Error in Arbitration Phase!"); __asm("nop"); break; case MCAN_IR_BO_MASK: strcpy(u8ErrorInterruptStatus, "CAN BUS OFF!"); DL_MCAN_reset(CANFD0); __asm("nop"); break; case MCAN_IR_EW_MASK: strcpy(u8ErrorInterruptStatus, "Warning Status Interrupt generated!"); __asm("nop"); break; case MCAN_IR_EP_MASK: strcpy(u8ErrorInterruptStatus, "Error Passive Interrupt generated!"); __asm("nop"); break; case MCAN_IR_ELO_MASK: strcpy(u8ErrorInterruptStatus, "Error Logging Overflow!"); __asm("nop"); break; case MCAN_IR_BEU_MASK: strcpy(u8ErrorInterruptStatus, "Bit Error Uncorrected!"); __asm("nop"); break; case MCAN_IR_TOO_MASK: strcpy(u8ErrorInterruptStatus, "Timeout Occured!"); __asm("nop"); break; default: break; } } /** * @brief Default Interrupt Handler for MCAN * */ //void CANFD0_IRQHandler(void) //{ // ErrorHandler(); // // switch (DL_MCAN_getPendingInterrupt(CANFD0)) { // case DL_MCAN_IIDX_LINE1: // /* Check MCAN interrupts fired during TX/RX of CAN package */ // u32InterruptLine1Status |= DL_MCAN_getIntrStatus(CANFD0); // DL_MCAN_clearIntrStatus(CANFD0, u32InterruptLine1Status,DL_MCAN_INTR_SRC_MCAN_LINE_1); // b_ServiceInt = true; // break; // default: // break; // } //} void CANFD0_IRQHandler(void) { IntrStatus = DL_MCAN_getIntrStatus(CANFD0); DL_MCAN_getProtocolStatus(CANFD0, &HeaderStat); if(HeaderStat.busOffStatus==1) { DL_MCAN_setOpMode(CANFD0, DL_MCAN_OPERATION_MODE_NORMAL); } if (HeaderStat.lastErrCode) { if (HeaderStat.lastErrCode != 3){ int status = -1; //printf("Attempting recovery...\n"); status = xECU_CanReInit(CANFD0 , g_u16CanSpeed); if(status == 0) { //printf("done\n"); } } // else //printf("tx ack err...\n"); } if (IntrStatus & DL_MCAN_INTERRUPT_TC){ __asm("nop"); DL_MCAN_clearIntrStatus(CANFD0, IntrStatus,DL_MCAN_INTR_SRC_MCAN_LINE_1); b_ServiceInt = true; u8_MCAN_StatusFlag = IVEC_MCAL_STATUS_SUCCESS; __asm("nop"); } if(IntrStatus & DL_MCAN_INTERRUPT_RF0N) { b_ServiceInt = false; rxFS.fillLvl = 0; rxFS.num = DL_MCAN_RX_FIFO_NUM_0; int status = -1; while ((rxFS.fillLvl) == 0) { DL_MCAN_getRxFIFOStatus(CANFD0, &rxFS); } if (rxFS.fillLvl > 0) { // There are messages to process while (rxFS.fillLvl > 0) { // Read and process messages... // (Assuming you have logic to read from the FIFO) DL_MCAN_readMsgRam(CANFD0, DL_MCAN_MEM_TYPE_FIFO, 0, rxFS.num, &TempRxMsg); // Acknowledge the message DL_MCAN_writeRxFIFOAck(CANFD0, rxFS.num, rxFS.getIdx); // Update the FIFO status again after reading DL_MCAN_getRxFIFOStatus(CANFD0, &rxFS); } } xCanIdType_t idType = ERROR; uint64_t idx = 0; idx = TempRxMsg.id; if(TempRxMsg.xtd == 0) { idx = ((TempRxMsg.id & (uint32_t) 0x1FFC0000) >> (uint32_t) 18); } if(idx) { for(uint8_t inx = 0; inx <= 7; inx++) { g_CanData[inx] = TempRxMsg.data[inx]; } mcu_FDCAN_RxFifo_Callback(idx, &g_CanData[0], TempRxMsg.dlc); } b_ServiceInt = true; DL_MCAN_getIntrStatus(CANFD0); DL_MCAN_clearIntrStatus(CANFD0, IntrStatus,DL_MCAN_INTR_SRC_MCAN_LINE_1); } //ErrorHandler(); } /*============================================================================================================================================================================================= API ==============================================================================================================================================================================================*/ /** * @brief Function to initialize MCAN Peripheral * @note Interrupts are enabled in this function itself * @param MCAN Pointer to the register overlay for the peripheral * @param BAUD Param to set Baud rate of MCAN * @retval IVEC_McalStatus_e */ IVEC_McalStatus_e xMCAL_MCANInit(MCAN_Regs* MCAN, xCAN_baud_t BAUD) { // DL_GPIO_initPeripheralOutputFunction(IOMUX_PINCM59, IOMUX_PINCM59_PF_CANFD0_CANTX); //ok // DL_GPIO_initPeripheralInputFunction(IOMUX_PINCM60, IOMUX_PINCM60_PF_CANFD0_CANRX); assert(MCAN == CANFD0); assert(BAUD == BAUD_500 || BAUD == BAUD_250); assert(b_MCAN_InitFlag == 0); DL_MCAN_RevisionId revid_MCAN0; DL_MCAN_enableModuleClock(MCAN); DL_MCAN_setClockConfig(MCAN, (DL_MCAN_ClockConfig *) &gMCAN0ClockConf); /* Get MCANSS Revision ID. */ DL_MCAN_getRevisionId(MCAN, &revid_MCAN0); /* Wait for Memory initialization to be completed. */ while(false == DL_MCAN_isMemInitDone(MCAN)); /* Put MCAN in SW initialization mode. */ DL_MCAN_setOpMode(MCAN, DL_MCAN_OPERATION_MODE_SW_INIT); /* Wait till MCAN is not initialized. */ while (DL_MCAN_OPERATION_MODE_SW_INIT != DL_MCAN_getOpMode(MCAN)); /* Initialize MCAN module. */ DL_MCAN_init(MCAN, (DL_MCAN_InitParams *) &gMCAN0InitParams); /* Configure MCAN module. */ DL_MCAN_config(MCAN, (DL_MCAN_ConfigParams*) &gMCAN0ConfigParams); /* Configure Bit timings. */ if(BAUD==BAUD_500) { DL_MCAN_setBitTime(MCAN, (DL_MCAN_BitTimingParams*) &gMCAN0BitTimes_500); } else if(BAUD==BAUD_250) { DL_MCAN_setBitTime(MCAN, (DL_MCAN_BitTimingParams*) &gMCAN0BitTimes_250); } else if(BAUD==BAUD_1000) { DL_MCAN_setBitTime(MCAN, (DL_MCAN_BitTimingParams*) &gMCAN0BitTimes_1000); } else if(BAUD==BAUD_150) { DL_MCAN_setBitTime(MCAN, (DL_MCAN_BitTimingParams*) &gMCAN0BitTimes_150); } // else if(BAUD==BAUD_125) // { // DL_MCAN_setBitTime(MCAN, (DL_MCAN_BitTimingParams*) &gMCAN0BitTimes_125); // } else { DL_MCAN_setBitTime(MCAN, (DL_MCAN_BitTimingParams*) &gMCAN0BitTimes_500); } /* Configure Message RAM Sections */ DL_MCAN_msgRAMConfig(MCAN, (DL_MCAN_MsgRAMConfigParams*) &gMCAN0MsgRAMConfigParams); // /* Configure Standard ID filter element */ // DL_MCAN_addStdMsgIDFilter(MCAN, 0U, (DL_MCAN_StdMsgIDFilterElement *) &gMCAN0StdFiltelem); // // DL_MCAN_addExtMsgIDFilter(MCAN, 0U, (DL_MCAN_StdMsgIDFilterElement *) &gMCAN0ExtFilterElem); /* Set Extended ID Mask. */ DL_MCAN_setExtIDAndMask(MCAN, (0x1FFFFFFFU) ); /* Take MCAN out of the SW initialization mode */ DL_MCAN_setOpMode(MCAN, DL_MCAN_OPERATION_MODE_NORMAL); while (DL_MCAN_OPERATION_MODE_NORMAL != DL_MCAN_getOpMode(MCAN)); /* Enable MCAN mopdule Interrupts */ DL_MCAN_enableIntr(MCAN, (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_TC | \ DL_MCAN_INTERRUPT_TOO), 1U); DL_MCAN_selectIntrLine(MCAN, DL_MCAN_INTR_MASK_ALL, DL_MCAN_INTR_LINE_NUM_1); DL_MCAN_enableIntrLine(MCAN, DL_MCAN_INTR_LINE_NUM_1, 1U); /* Enable MSPM0 MCAN interrupt */ DL_MCAN_clearInterruptStatus(MCAN,(DL_MCAN_MSP_INTERRUPT_LINE1)); DL_MCAN_enableInterrupt(MCAN,(DL_MCAN_MSP_INTERRUPT_LINE1)); NVIC_EnableIRQ(CANFD0_INT_IRQn); b_MCAN_InitFlag = 1; return IVEC_MCAL_STATUS_SUCCESS; } /** * @brief Function to De-Initialize MCAN peripheral * @param MCAN Pointer to the register overlay for the peripheral * @retval IVEC MCAL status */ IVEC_McalStatus_e xMCAL_MCANDeInit(MCAN_Regs* MCAN) { assert(MCAN == CANFD0); assert(b_MCAN_InitFlag != 0); // Ensure the module was initialized before deinitializing. /* Disable MSPM0 MCAN interrupt */ NVIC_DisableIRQ(CANFD0_INT_IRQn); DL_MCAN_disableInterrupt(MCAN, DL_MCAN_MSP_INTERRUPT_LINE1); /* Put MCAN in SW initialization mode to stop it */ DL_MCAN_setOpMode(MCAN, DL_MCAN_OPERATION_MODE_SW_INIT); /* Wait till MCAN is in SW initialization mode */ while (DL_MCAN_OPERATION_MODE_SW_INIT != DL_MCAN_getOpMode(MCAN)); /* Disable the MCAN clock */ DL_MCAN_disableModuleClock(MCAN); /* Clear initialization flag */ b_MCAN_InitFlag = 0; return IVEC_MCAL_STATUS_SUCCESS; } /** * @brief Function to Transmit CAN message * @param MCAN Pointer to the register overlay for the peripheral * @param TxMsg Message Object. * @param TxData Array of Data to be transmitted * @param BufNum Tx Buffer Number * @param Bytes Number of bytes to be transmitted * @retval IVEC_McalStatus_e */ IVEC_McalStatus_e xMCAL_MCANTx(MCAN_Regs *MCAN, DL_MCAN_TxBufElement *TxMsg ,uint16_t *TxData, uint32_t BufNum, int Bytes) { assert(MCAN == CANFD0); assert(b_MCAN_InitFlag != 0); for(int i=0;idata[i] = TxData[i]; } uint32_t txPendingStatus; //Check if the Tx Buffer is available (no pending request) txPendingStatus = DL_MCAN_getTxBufReqPend(MCAN); //Check if the specified buffer (BufNum) is available if ((txPendingStatus & (1 << BufNum)) == 0) { DL_MCAN_writeMsgRam(MCAN, DL_MCAN_MEM_TYPE_BUF, BufNum , TxMsg); DL_MCAN_TXBufAddReq(MCAN, BufNum); } else { //printf("tx pending\n"); //return IVEC_MCAL_STATUS_BUSY; } return IVEC_MCAL_STATUS_SUCCESS; } /** * @brief Function to Receive CAN message * @param MCAN Pointer to the register overlay for the peripheral * @param RxMsg Message Object. * @param FifoNum Fifo Number to be used * @param RxData Array where received data is to be stored * @param DLC length of received data * @retval IVEC_McalStatus_e */ IVEC_McalStatus_e xMCAL_MCANRx(MCAN_Regs *MCAN, DL_MCAN_RxBufElement *RxMsg ,uint32_t FifoNum,uint8_t *RxData,int DLC) { assert(MCAN == CANFD0); assert(b_MCAN_InitFlag != 0); while (false == b_ServiceInt) { __WFE();//__asm("nop"); } b_ServiceInt = false; rxFS.fillLvl = 0; if ((u32InterruptLine1Status & MCAN_IR_RF0N_MASK) == MCAN_IR_RF0N_MASK) { rxFS.num = DL_MCAN_RX_FIFO_NUM_0; while ((rxFS.fillLvl) == 0) { DL_MCAN_getRxFIFOStatus(MCAN, &rxFS); } DL_MCAN_readMsgRam(MCAN, DL_MCAN_MEM_TYPE_FIFO, FifoNum, rxFS.num, RxMsg); DL_MCAN_writeRxFIFOAck(MCAN, rxFS.num, rxFS.getIdx); _prv_vGetRxMsg(RxMsg,RxData,DLC); u32InterruptLine1Status &= ~(MCAN_IR_RF0N_MASK); } return IVEC_MCAL_STATUS_SUCCESS; } /** * @brief Function to check current Error Status of MCAN peripheral * @param ErrorStatus Pointer to array where current status will be stored * @retval IVEC_McalStatus_e */ IVEC_McalStatus_e xMCAL_getMCAN_ErrorStatus(char *ErrorStatus) { assert(b_MCAN_InitFlag != 0); strcpy(ErrorStatus,u8ErrorInterruptStatus); return IVEC_MCAL_STATUS_SUCCESS; } /** * @brief Function to check Interrupt Line1 Status of MCAN peripheral * @param Interrupt_Status Pointer to variable where current status will be stored * @retval IVEC_McalStatus_e */ IVEC_McalStatus_e xMCAL_getMCAN_InterruptLine1Status(uint32_t *Interrupt_Status) { assert(b_MCAN_InitFlag != 0); *Interrupt_Status=u32InterruptLine1Status; return IVEC_MCAL_STATUS_SUCCESS; } /*____________________________________________________________________________________________________________________________________________________________________________________________*/