//***************************************************************************** // (C) Automotive Lighting Reutlingen GmbH // Tuebinger Strasse 123, 72762 Reutlingen, Germany // // Automotive Lighting Reutlingen GmbH owns all the rights to this work. // This work shall not be copied, reproduced, used, modified, transferred // or its information shall not be disclosed without the prior written // authorization of Automotive Lighting Reutlingen GmbH. //***************************************************************************** //----------------------------------------------------------------------------- /// \file Can.c /// /// \brief Can functions APIs implementation. /// /// \descr /// //----------------------------------------------------------------------------- //============================================================================= // Includes //============================================================================= #include #include #include #include #include #define CAN_MAC_DECL_FCT #include #undef CAN_MAC_DECL_FCT #define CAN_MAC_DECL_MAP #include #undef CAN_MAC_DECL_MAP //============================================================================= // Preprocessor definitions //============================================================================= #define TX_FIFO_ELEMENTCOUNT 32 //============================================================================= // Private Variables //============================================================================= typedef volatile stc_CANFD_CH_t* cy_pstc_canfd_type_t; // Look - up table for all enabled CAN FD channels and their internal context // TODO: this needs to be adapted to the used channels static cy_pstc_canfd_type_t ChannelsConfig[] = { // PRQA S 303 3 // correct cast - mapping register address to structure CY_CANFD1_1_TYPE, // CAN_1_1 : PRIVATE CAN CY_CANFD1_3_TYPE, // CAN_1_3 : SAT CAN // CY_CANFD0_0_TYPE, // CAN_0_0 : BODY CAN }; static uint32 can_rx_set_start = 0U; // active receive map set start index static uint32 can_tx_set_start = 0U; // active transmit map set start index static uint32 can_wait_timeout_error = 0U; // DLC-Word conversion static const uint8 dataBufferSizeInWord[] = { 2u, // 8 bytes 3u, // 12 bytes 4u, // 16 bytes 5u, // 20 bytes 6u, // 24 bytes 8u, // 32 bytes 12u, // 48 bytes 16u // 64 bytes }; #define CAN_WAIT_TIMEOUT 0xFFFUL; //============================================================================= // Private variables declaration //============================================================================= //============================================================================= // Private functions declaration //============================================================================= static void CddMlcCan_PinConfiguration(uint8 channel); static void CddMlcCan_Enable(uint8 channel); static void CddMlcCan_Init_Clock(void); static void CddMlcCan_Init_RxRulesAndTxRxBuffers(void); static void CddMlcCan_Init_Bus(void); static inline uint32 CddMlcCan_TxHandleToIndex(can_handle_type tx_handle); static uint32* CddMlcCan_CalcTxBufAdrs(cy_pstc_canfd_type_t pstcCanFD, uint8 u8MsgBuf); static uint32* CddMlcCan_CalcRxFifoAdrs(cy_pstc_canfd_type_t pstcCanFD, uint8 u8FifoNumber, uint32 u32GetIndex); static void CddMlcCan_ExtractMsgFromRXBuffer(cy_stc_canfd_rx_buffer_t *pstcRxBufferAddr, cy_stc_canfd_msg_t *pstcCanFDmsg); static uint32* CddMlcCan_CalcRxBufAdrs(cy_pstc_canfd_type_t pstcCanFD, uint8 u8MsgBuf); static void CddMlcCan_GetMsgramOffset(cy_pstc_canfd_type_t pstcCanFD, cy_stc_canfd_msgram_config_t *pstcMsgramConfig); static void CddMlcCan_ConfigureBufferDataSize(uint32 channel); static void CddMlcCan_ProcessRxFIFOData(cy_stc_canfd_msg_t stcCanFDmsg, uint32 fifoFilter); static void CddMlcCan_TxChnConfig(uint32 channel, uint32 noObRxBuffersChn, uint8 txMsgCountChn); static void CddMlcCan_InitMsgRam(uint32 channel, cy_stc_canfd_msgram_config_t stcMsgramConfigChn); static void CddMlcCan_ConfigureRxFifos(uint32 channel, uint8 noOfFifo0ElChn, uint32 extIdCntChn, uint8 noOfFifo1ElChn); static void CddMlcCan_ConfigureSIDFiler(uint32 channel, cy_stc_canfd_msgram_config_t stcMsgramConfigChn, uint32 stdIdCntChn); static void CddMlcCan_ConfigureEXTIDFiler(uint32 channel, uint32 startAddr, uint32 extIdCntChn); static void CddMlcCan_GetMsgRxFifo(void); static void CddMlcCan_GetMsgRxBuff(void); static uint32 CddMlcCan_SearchRxMessageCallbackIndex(uint32 identifier); //============================================================================= // Public functions definition //============================================================================= //----------------------------------------------------------------------------- /// \brief Rx callback for CAN0 used in CddMlcCan_Cfg.h /// /// \descr Take the received message and put it into the CAN transport protocol stack /// /// \param rx_handle - the message handle /// \param *data - the received data /// \param dlc - the length of the received data /// /// \return void //----------------------------------------------------------------------------- // PRQA S 3408 1 // It is actually being declared using macros void CddMlcCan_RxBptCallback(can_handle_type rx_handle, const uint8* data, uint8 dlc) { (void)rx_handle; (void)data; (void)dlc; } //----------------------------------------------------------------------------- /// \brief CddMlcCan_Init /// /// \descr This function initializes the Can module using the maps from /// CddMlcCan_Cfg.h This function does not use the configuration structure /// given as parameter. /// \param *ConfigPtr configuration structure pointer (not used) /// /// \return void //----------------------------------------------------------------------------- void CddMlcCan_Init(const can_config_type* ConfigPtr) { uint8 channel; uint8 ActiveChannel = CAN_CHANNEL_PRIVATE; uint32 ulCanWaitTimeout = CAN_WAIT_TIMEOUT uint8 UsedBuses = 1U; if (ConfigPtr != NULL) { // no configuration given, use default sets can_tx_set_start = ConfigPtr->tx_map_set; can_rx_set_start = ConfigPtr->rx_map_set; ActiveChannel = ConfigPtr->ActiveChannels; UsedBuses = ConfigPtr->UsedBuses; } // Configure the CAN HW pins if(UsedBuses < CAN_MAX_CHANNELS) { if(ActiveChannel == CAN_CHANNEL_PRIVATE) { CddMlcCan_PinConfiguration(CAN_CHANNEL_PRIVATE); } else { CddMlcCan_PinConfiguration(CAN_CHANNEL_SATELLITE); } } else { CddMlcCan_PinConfiguration(CAN_CHANNEL_PRIVATE); CddMlcCan_PinConfiguration(CAN_CHANNEL_SATELLITE); } // Prepare initialization of all channels // Set CCCR.INIT to 1 and wait until it will be updated for (channel = 0U; channel < CAN_MAX_CHANNELS; channel++) { ChannelsConfig[channel]->M_TTCAN.unCCCR.u32Register = 0x1U; // TODO: create a safety exit condition while((ChannelsConfig[channel]->M_TTCAN.unCCCR.stcField.u1INIT != 1U) && (ulCanWaitTimeout > 0U)) { ulCanWaitTimeout--; } if(ulCanWaitTimeout == 0U) { can_wait_timeout_error++; } // Cancel protection by setting CCE ChannelsConfig[channel]->M_TTCAN.unCCCR.u32Register = 0x3U; } // Initialize the clock of the configured channels CddMlcCan_Init_Clock(); // Initialize Rx Filters, Rx Buffers, Rx FIFOs and Tx Buffers // Info: All these are done in one single function in order to avoid using global variables for MRAM writing CddMlcCan_Init_RxRulesAndTxRxBuffers(); // Initialize the Can Bus CddMlcCan_Init_Bus(); // Enable the CAN channel if(UsedBuses < CAN_MAX_CHANNELS) { if(ActiveChannel == CAN_CHANNEL_PRIVATE) { CddMlcCan_Enable(CAN_CHANNEL_PRIVATE); } else { CddMlcCan_Enable(CAN_CHANNEL_SATELLITE); } } else { CddMlcCan_Enable(CAN_CHANNEL_PRIVATE); CddMlcCan_Enable(CAN_CHANNEL_SATELLITE); } } //----------------------------------------------------------------------------- /// \brief CddMlcCan_PinConfiguration /// /// \descr This function configure the IO pin for CAN. /// \param channel - the channel to be configured /// /// \return void //----------------------------------------------------------------------------- static void CddMlcCan_PinConfiguration(uint8 channel) { #define PCLK_MLC_CAN_1_1_CLOCK (11U) //Peripheral Clock Assignments #define PCLK_MLC_CAN_1_3_CLOCK (13U) //Peripheral Clock Assignments #define PCLK_MLC_DIV_8 (22U) if(CAN_CHANNEL_PRIVATE == channel) { // Configure CAN Peripheral clock PERI->unCLOCK_CTL[PCLK_MLC_CAN_1_1_CLOCK].stcField.u2TYPE_SEL = (uint32)0; // PRQA S 303 ++ // correct cast - mapping register address to structure PERI->unCLOCK_CTL[PCLK_MLC_CAN_1_1_CLOCK].stcField.u8DIV_SEL = PCLK_MLC_DIV_8; PERI->unDIV_8_CTL[PCLK_MLC_DIV_8].stcField.u8INT8_DIV = 1U; //80MHz /(1+1) = 40MHz for CAN_1_1 and CAN_1_3 Blocks PERI->unDIV_CMD.stcField.u1ENABLE = 1U; PERI->unDIV_CMD.stcField.u2PA_TYPE_SEL = 3U; PERI->unDIV_CMD.stcField.u8PA_DIV_SEL = 0xFFU; PERI->unDIV_CMD.stcField.u2TYPE_SEL = (uint32)0; PERI->unDIV_CMD.stcField.u8DIV_SEL = PCLK_MLC_DIV_8; (void)PERI->unDIV_CMD; // dummy read to handle buffered writes /****************************************************************/ /********************* PRIVATE_CAN Pin Config **************************/ /****************************************************************/ // change the multiplexed CAN/UART pins configuration to use CAN // PORT 17 GPIO->PRT[17].unOUT.u32Register &= ~(1UL << 2U); GPIO->PRT[17].unOUT_CLR.u32Register &= ~(1UL << 2U); GPIO->PRT[17].unOUT_SET.u32Register &= ~(1UL << 2U); GPIO->PRT[17].unOUT_INV.u32Register &= ~(1UL << 2U); GPIO->PRT[17].unCFG.stcField.u1IN_EN2 = (P_DM_HIGHZ >> 3U); GPIO->PRT[17].unCFG.stcField.u3DRIVE_MODE2 = (P_DM_HIGHZ & 0x07UL); GPIO->PRT[17].unCFG.stcField.u1IN_EN1 = (P_DM_STRONG >> 3U); GPIO->PRT[17].unCFG.stcField.u3DRIVE_MODE1 = (P_DM_STRONG & 0x07UL); // PORT 22 GPIO->PRT[22].unOUT.u32Register |= (1UL << 0U); GPIO->PRT[22].unOUT_CLR.u32Register |= (1UL << 0U); GPIO->PRT[22].unOUT_SET.u32Register |= (1UL << 0U); GPIO->PRT[22].unOUT_INV.u32Register |= (1UL << 0U); GPIO->PRT[22].unCFG.stcField.u1IN_EN0 = (P_DM_STRONG >> 3U); GPIO->PRT[22].unCFG.stcField.u3DRIVE_MODE0 = (P_DM_STRONG & 0x07UL); // reconfigure the high speed IO matrix HSIOM->PRT[17].unPORT_SEL0.stcField.u5IO1_SEL = (uint32)P17_1_CANFD1_TTCAN_RX1; HSIOM->PRT[17].unPORT_SEL0.stcField.u5IO2_SEL = (uint32)P17_2_GPIO; HSIOM->PRT[22].unPORT_SEL0.stcField.u5IO0_SEL = (uint32)P22_0_CANFD1_TTCAN_TX1; } else if(CAN_CHANNEL_SATELLITE == channel) { // Configure CAN Peripheral clock PERI->unCLOCK_CTL[PCLK_MLC_CAN_1_3_CLOCK].stcField.u2TYPE_SEL = (uint32)0; // PRQA S 303 ++ // correct cast - mapping register address to structure PERI->unCLOCK_CTL[PCLK_MLC_CAN_1_3_CLOCK].stcField.u8DIV_SEL = PCLK_MLC_DIV_8; PERI->unDIV_8_CTL[PCLK_MLC_DIV_8].stcField.u8INT8_DIV = 1U; //80MHz /(1+1) = 40MHz for CAN_1_1 and CAN_1_3 Blocks PERI->unDIV_CMD.stcField.u1ENABLE = 1U; PERI->unDIV_CMD.stcField.u2PA_TYPE_SEL = 3U; PERI->unDIV_CMD.stcField.u8PA_DIV_SEL = 0xFFU; PERI->unDIV_CMD.stcField.u2TYPE_SEL = (uint32)0; PERI->unDIV_CMD.stcField.u8DIV_SEL = PCLK_MLC_DIV_8; (void)PERI->unDIV_CMD; // dummy read to handle buffered writes /****************************************************************/ /********************* SATELLITE_CAN Pin Config **************************/ /****************************************************************/ // change the multiplexed CAN/UART pins configuration to use CAN //P3_0 --> HighZ //P3_1 --> HighZ GPIO->PRT[3].unCFG.stcField.u1IN_EN0 = (P_DM_HIGHZ >> 3U); GPIO->PRT[3].unCFG.stcField.u3DRIVE_MODE0 = (P_DM_HIGHZ & 0x07UL); GPIO->PRT[3].unCFG.stcField.u1IN_EN1 = (P_DM_HIGHZ >> 3U); GPIO->PRT[3].unCFG.stcField.u3DRIVE_MODE1 = (P_DM_HIGHZ & 0x07UL); //P19_0 --> CAN1_3_TX GPIO->PRT[19].unOUT.u32Register |= (1UL << 0U); GPIO->PRT[19].unOUT_CLR.u32Register |= (1UL << 0U); GPIO->PRT[19].unOUT_SET.u32Register |= (1UL << 0U); GPIO->PRT[19].unOUT_INV.u32Register |= (1UL << 0U); GPIO->PRT[19].unCFG.stcField.u1IN_EN0 = (P_DM_STRONG >> 3U); GPIO->PRT[19].unCFG.stcField.u3DRIVE_MODE0 = (P_DM_STRONG & 0x07UL); //P19_1 --> CAN1_3_RX GPIO->PRT[19].unOUT.u32Register &= ~(1UL << 1U); GPIO->PRT[19].unOUT_CLR.u32Register &= ~(1UL << 1U); GPIO->PRT[19].unOUT_SET.u32Register &= ~(1UL << 1U); GPIO->PRT[19].unOUT_INV.u32Register &= ~(1UL << 1U); GPIO->PRT[19].unCFG.stcField.u1IN_EN1 = (P_DM_STRONG >> 3U); GPIO->PRT[19].unCFG.stcField.u3DRIVE_MODE1 = (P_DM_STRONG & 0x07UL); // reconfigure the high speed IO matrix HSIOM->PRT[3].unPORT_SEL0.stcField.u5IO0_SEL = (uint32)P3_0_GPIO; HSIOM->PRT[3].unPORT_SEL0.stcField.u5IO1_SEL = (uint32)P3_1_GPIO; HSIOM->PRT[19].unPORT_SEL0.stcField.u5IO0_SEL = (uint32)P19_0_CANFD1_TTCAN_TX3; HSIOM->PRT[19].unPORT_SEL0.stcField.u5IO1_SEL = (uint32)P19_1_CANFD1_TTCAN_RX3; } else { /* Do nothing */ } } //----------------------------------------------------------------------------- /// \brief CddMlcCan_Enable /// /// \descr This function enables the given Can channel. /// \param channel - the channel to be enabled /// /// \return void //----------------------------------------------------------------------------- static void CddMlcCan_Enable(uint8 channel) { un_CANFD_CH_CCCR_t unCCCR = { 0 }; uint32 ulCanWaitTimeout = CAN_WAIT_TIMEOUT // CAN operation start // Set CCCR.INIT to 0 and wait until it will be updated unCCCR.stcField.u1INIT = 0; ChannelsConfig[channel]->M_TTCAN.unCCCR.u32Register = unCCCR.u32Register; // TODO: create a safety exit condition while((ChannelsConfig[channel]->M_TTCAN.unCCCR.stcField.u1INIT != 0U) && (ulCanWaitTimeout > 0U)) { ulCanWaitTimeout--; } if(ulCanWaitTimeout == 0U) { can_wait_timeout_error++; } } //----------------------------------------------------------------------------- /// \brief Send a CAN message /// /// \descr This function sends a message over CAN /// \param handle the handle of the CAN message that was configured in /// CddMlcCan_Cfg.h /// \param * data the data to be sent over CAN /// /// \return true: message sent /// \return false: message not sent //----------------------------------------------------------------------------- boolean CddMlcCan_SendMsg(uint8 ActiveChannel, can_handle_type tx_handle, uint32 ExtId, uint32 Extdlc, const uint8* data) { boolean retVal = FALSE; uint16 u16DlcTemp; uint16 u16Count; uint8 u8DataLengthWord; volatile cy_stc_canfd_tx_buffer_t* pstcCanFDTxBuffer; uint32 channel; uint32 dlc; uint32 id; uint8 txBuffer; //uint32 idx = ActiveChannel; //if (idx != CAN_INVALID_INDEX) //{ // channel = can_tx_map[idx].channel; // dlc = can_tx_map[idx].dlc; // id = can_tx_map[idx].id; // txBuffer = can_tx_map[idx].buffer; if(ActiveChannel != CAN_INVALID_INDEX) { channel = can_tx_map[ActiveChannel].channel; dlc = can_tx_map[ActiveChannel].dlc; id = can_tx_map[ActiveChannel].id; txBuffer = can_tx_map[ActiveChannel].buffer; if(Extdlc != 0xFFFFFFFFUL) { dlc = Extdlc; } if(CAN_MSG_ID_EXT == (id & CAN_MSG_ID_EXT)) { id |= ExtId; } // check if Tx-FIFO full if(ChannelsConfig[channel]->M_TTCAN.unTXFQS.stcField.u1TFQF == 0) { // get Tx-FIFO PutIndex txBuffer = ChannelsConfig[channel]->M_TTCAN.unTXFQS.stcField.u5TFQPI; // Get Tx Buffer address // PRQA S 310 1 // correct cast - mapping register address to structure pstcCanFDTxBuffer = (cy_stc_canfd_tx_buffer_t*)CddMlcCan_CalcTxBufAdrs(ChannelsConfig[channel], txBuffer); if (pstcCanFDTxBuffer != NULL) { // Transmit data frame // TODO: adapt also for remote frame if needed pstcCanFDTxBuffer->t0_f.rtr = 0; // Set the whether standard ID or extended ID is used pstcCanFDTxBuffer->t0_f.xtd = ((id & CAN_MSG_ID_EXT) == CAN_MSG_ID_EXT) ? 1UL : 0UL; // Set the used ID pstcCanFDTxBuffer->t0_f.id = ((id & CAN_MSG_ID_EXT) == CAN_MSG_ID_EXT) ? id : (id << 18U); pstcCanFDTxBuffer->t1_f.efc = 0; // Tx Event FIFO not used. TODO: check if needed pstcCanFDTxBuffer->t1_f.mm = 0; // Not used. TODO: check if needed pstcCanFDTxBuffer->t1_f.dlc = dlc; // Set DLC pstcCanFDTxBuffer->t1_f.fdf = 0; // Classical can frame pstcCanFDTxBuffer->t1_f.brs = 0; // No bit rate switch // Convert the DLC to data byte word u16DlcTemp = 0U; u8DataLengthWord = dataBufferSizeInWord[u16DlcTemp]; // Set data (in 32-bit format) uint32 u32convertedData[2U]; uint16 u16convertedData[2U]; u16convertedData[0U] = CAN_MAKEWORD(data[0U], data[1U]); u16convertedData[1U] = CAN_MAKEWORD(data[2U], data[3U]); u32convertedData[0U] = CAN_MAKELONG(u16convertedData[0U], u16convertedData[1U]); u16convertedData[0U] = CAN_MAKEWORD(data[4U], data[5U]); u16convertedData[1U] = CAN_MAKEWORD(data[6U], data[7U]); u32convertedData[1U] = CAN_MAKELONG(u16convertedData[0U], u16convertedData[1U]); for (u16Count = 0U; u16Count < u8DataLengthWord; u16Count++) { pstcCanFDTxBuffer->data_area_f[u16Count] = u32convertedData[u16Count]; } // Transmit buffer add request ChannelsConfig[channel]->M_TTCAN.unTXBAR.u32Register = 1UL << txBuffer; retVal = TRUE; } } } return retVal; } //----------------------------------------------------------------------------- /// \brief CddMlcCan_ReceiveMsg /// /// \descr This function calls the reception routine which will handle the /// received data inside buffers and FIFOs and calls the transmission /// callback function if previous data has been sent successfully /// /// \param void /// /// \return void //----------------------------------------------------------------------------- void CddMlcCan_ReceiveMsg(void) { // Handle reception if necessary CddMlcCan_GetMsgRxBuff(); CddMlcCan_GetMsgRxFifo(); // Handle transmission if necessary //for(uint32 idx = can_tx_set_start; can_tx_map[idx].channel != CAN_INVALID_CHANNEL; ++idx) //{ // // Obtain values Tx Buffer Transmission Occurred register // uint32 txBuffers = ChannelsConfig[can_tx_map[idx].channel]->M_TTCAN.unTXBTO.u32Register; // // Verify if a transmission occurred for the specific transmit buffer // if ((txBuffers & (1UL << can_tx_map[idx].buffer)) == 1U) // { // // Transmission occurred // if (can_tx_map[idx].callback != NULL) // { // // Execute the callback function // can_tx_map[idx].callback(can_tx_map[idx].handle); // } // } //} } //============================================================================= // Private functions definitions //============================================================================= //----------------------------------------------------------------------------- /// \brief CddMlcCan_GetMsgRxBuff /// /// \descr This function stores the received data from hardware buffers /// to software buffers and calls the according callback function /// if new data has been received. /// /// \param void /// /// \return - //----------------------------------------------------------------------------- static void CddMlcCan_GetMsgRxBuff(void) { uint32* pu32Adrs = NULL_PTR; cy_stc_canfd_msg_t stcCanFDmsg; uint32 channel; uint8 rxStorageType; uint32 idx = 0U; uint32 msgIdx = 0U; for (idx = can_rx_set_start; can_rx_map[idx].channel != CAN_INVALID_CHANNEL; idx++) { channel = can_rx_map[idx].channel; rxStorageType = can_rx_map[idx].buffer; if (rxStorageType < 32U) { // RX buffer used if ((ChannelsConfig[channel]->M_TTCAN.unNDAT1.u32Register & (1UL << rxStorageType)) != 0U) // Message buffers 0-31 { // Calculate Rx Buffer address pu32Adrs = CddMlcCan_CalcRxBufAdrs(ChannelsConfig[channel], rxStorageType); // Clear NDAT1 register ChannelsConfig[channel]->M_TTCAN.unNDAT1.u32Register = (1UL << rxStorageType); } } else if ((rxStorageType >= 32U) && (rxStorageType < 64U)) // Message buffers 32-63 { if ((ChannelsConfig[channel]->M_TTCAN.unNDAT2.u32Register & (1UL << (rxStorageType - 32U))) != 0U) { // Calculate Rx Buffer address pu32Adrs = CddMlcCan_CalcRxBufAdrs(ChannelsConfig[channel], rxStorageType); // Clear NDAT2 register ChannelsConfig[channel]->M_TTCAN.unNDAT2.u32Register = (1UL << (rxStorageType - 32U)); } } else { // do nothing } if (pu32Adrs != NULL_PTR) { // PRQA S 310 1 // correct cast - mapping register address to structure CddMlcCan_ExtractMsgFromRXBuffer((cy_stc_canfd_rx_buffer_t *)pu32Adrs, &stcCanFDmsg); //search for the right idx msgIdx = CddMlcCan_SearchRxMessageCallbackIndex(stcCanFDmsg.idConfig.identifier); if (can_rx_map[msgIdx].callback != NULL) { // PRQA S 310 1 // correct cast - mapping array to pointer can_rx_map[msgIdx].callback(can_rx_map[msgIdx].handle, (uint8*)(stcCanFDmsg.dataConfig.data), stcCanFDmsg.dataConfig.dataLengthCode); } } } } //----------------------------------------------------------------------------- /// \brief /// /// \descr /// /// \param identifier /// /// \return uint32 //----------------------------------------------------------------------------- static uint32 CddMlcCan_SearchRxMessageCallbackIndex(uint32 identifier) { uint32 idx = 0; for (idx = can_rx_set_start; can_rx_map[idx].channel != CAN_INVALID_CHANNEL; idx++) { if(identifier == can_rx_map[idx].id) { break; } } return(idx); } //----------------------------------------------------------------------------- /// \brief CddMlcCan_GetMsgRxFifo /// /// \descr This function stores the received data from hardware FIFOs /// to software buffers and calls the according callback function /// if new data has been received. /// /// \param void /// /// \return - //----------------------------------------------------------------------------- static void CddMlcCan_GetMsgRxFifo(void) { uint32* pu32Adrs; cy_stc_canfd_msg_t stcCanFDmsg; uint32 channel; uint32 ulCanWaitTimeout = CAN_WAIT_TIMEOUT for (channel = 0U; channel < CAN_MAX_CHANNELS; channel++) { while((ChannelsConfig[channel]->M_TTCAN.unRXF0S.stcField.u7F0FL > 0U) && (ulCanWaitTimeout > 0U)) { un_CANFD_CH_RXF0S_t unRXF0S; unRXF0S.u32Register = ChannelsConfig[channel]->M_TTCAN.unRXF0S.u32Register; pu32Adrs = CddMlcCan_CalcRxFifoAdrs(ChannelsConfig[channel], CY_CANFD_RX_FIFO0, unRXF0S.stcField.u6F0GI); if (pu32Adrs != NULL_PTR) { // Extract the received message from Buffer // PRQA S 310 1 // correct cast - mapping register address to structure CddMlcCan_ExtractMsgFromRXBuffer((cy_stc_canfd_rx_buffer_t *)pu32Adrs, &stcCanFDmsg); // Acknowledge the buffer message ChannelsConfig[channel]->M_TTCAN.unRXF0A.stcField.u6F0AI = unRXF0S.stcField.u6F0GI; // Process RX buffer data CddMlcCan_ProcessRxFIFOData(stcCanFDmsg, RX_FIFO_0); } ulCanWaitTimeout--; } if(ulCanWaitTimeout == 0U) { can_wait_timeout_error++; } ulCanWaitTimeout = 0xFFFFUL; while((ChannelsConfig[channel]->M_TTCAN.unRXF1S.stcField.u7F1FL > 0U) && (ulCanWaitTimeout > 0U)) { un_CANFD_CH_RXF1S_t unRXF1S; unRXF1S.u32Register = ChannelsConfig[channel]->M_TTCAN.unRXF1S.u32Register; pu32Adrs = CddMlcCan_CalcRxFifoAdrs(ChannelsConfig[channel], CY_CANFD_RX_FIFO1, unRXF1S.stcField.u6F1GI); if (pu32Adrs != NULL_PTR) { // Extract the received message from Buffer // PRQA S 310 1 // correct cast - mapping register address to structure CddMlcCan_ExtractMsgFromRXBuffer((cy_stc_canfd_rx_buffer_t *)pu32Adrs, &stcCanFDmsg); // Acknowledge the FIFO message ChannelsConfig[channel]->M_TTCAN.unRXF1A.stcField.u6F1AI = unRXF1S.stcField.u6F1GI; // Process RX FIFO data CddMlcCan_ProcessRxFIFOData(stcCanFDmsg, RX_FIFO_1); } ulCanWaitTimeout--; } if(ulCanWaitTimeout == 0U) { can_wait_timeout_error++; } } } //----------------------------------------------------------------------------- /// \brief CddMlcCan_ProcessRxFIFOData /// /// \descr This function processes the data from the FIFO /// /// \param stcCanFDmsg received data /// /// \return - //----------------------------------------------------------------------------- static void CddMlcCan_ProcessRxFIFOData(cy_stc_canfd_msg_t stcCanFDmsg, uint32 fifoFilter) { uint32 idx; // CAN-FD message received, check if there is a callback function inside the rx map // Call callback function if it was set previously. for (idx = can_rx_set_start; can_rx_map[idx].channel != CAN_INVALID_CHANNEL; ++idx) { if ((can_rx_map[idx].callback != NULL) && (can_rx_map[idx].id == stcCanFDmsg.idConfig.identifier) && ((can_rx_map[idx].buffer & fifoFilter) != 0UL)) { // PRQA S 310 1 // correct cast - mapping array to pointer can_rx_map[idx].callback(can_rx_map[idx].handle, (uint8*)(stcCanFDmsg.dataConfig.data), stcCanFDmsg.dataConfig.dataLengthCode); break; } } } //----------------------------------------------------------------------------- /// \brief CddMlcCan_Init_Clock /// /// \descr This function makes the CAN clock configuration stored in the /// timing map from CddMlcCan_Cfg.h. /// /// \param void /// /// \return void //----------------------------------------------------------------------------- static void CddMlcCan_Init_Clock(void) { un_CANFD_CH_NBTP_t unNBTP = { 0 }; uint32 idx; // Configure the clocks for each channel for (idx = 0U; can_timing[idx].channel != CAN_INVALID_CHANNEL; ++idx) { // Calculate the prescaler uint32 nbrp = CAN_CLOCK_FCAN / ((1U + can_timing[idx].tseg1 + can_timing[idx].tseg2) * can_timing[idx].speed); // The actual interpretation by the hardware of this values is such that one more than the // values programmed here are used unNBTP.stcField.u9NBRP = nbrp - 1U; // Set Nominal Bit Rate Prescaler unNBTP.stcField.u8NTSEG1 = can_timing[idx].tseg1 - 1U; // Set Nominal Time Segment before sample point unNBTP.stcField.u7NTSEG2 = can_timing[idx].tseg2 - 1U; // Set Nominal Time Segment after sample point unNBTP.stcField.u7NSJW = can_timing[idx].swj - 1U; // Set Nominal (Re)Synchronization Jump Width // Write all values into the Nominal Bit Timing & Prescaler Register (CANFD_CH_NBTP) ChannelsConfig[can_timing[idx].channel]->M_TTCAN.unNBTP.u32Register = unNBTP.u32Register; } } //----------------------------------------------------------------------------- /// \brief CddMlcCan_Init_RxRulesAndTxRxBuffers /// /// \descr This function configures the Rx rules according to the Rx map from /// CddMlcCan_Cfg.h and configures the needed Rx and Tx buffers. /// /// \param void /// /// \return void //----------------------------------------------------------------------------- static void CddMlcCan_Init_RxRulesAndTxRxBuffers(void) { // TODO: Split function (maybe, only if needed, extra global variables will have to be used) // TODO: Initialize and group variables accordingly cy_stc_id_filter_t* pstcSIDFilter; cy_stc_extid_filter_t* pstcEXTIDFilter; uint32 u32Count; un_CANFD_CH_GFC_t unGFC = { 0 }; uint32 channel; uint32 id; uint8 rxStorageType; uint32 channel_stid_cnt[CAN_MAX_CHANNELS] = { 0U }; // rules per channel uint32 channel_extid_cnt[CAN_MAX_CHANNELS] = { 0U }; // rules per channel cy_stc_canfd_msgram_config_t stcMsgramConfig[CAN_MAX_CHANNELS] = { 0U }; uint32 rx_map_cnt; uint32 tx_map_cnt; uint32 stid_idx; uint32 extid_idx; cy_stc_id_filter_t stIdFilters[CAN_MAX_CHANNELS][64] = { 0U }; cy_stc_extid_filter_t extIdFilters[CAN_MAX_CHANNELS][64] = { 0U }; uint8 txMsgCount[CAN_MAX_CHANNELS] = { 0U }; uint8 noOfFifo0El[CAN_MAX_CHANNELS] = { 0U }; uint8 noOfFifo1El[CAN_MAX_CHANNELS] = { 0U }; uint8 noOfRxBuffers[CAN_MAX_CHANNELS] = { 0U }; // Count how many standard and extend ID's are per channel for (rx_map_cnt = can_rx_set_start; can_rx_map[rx_map_cnt].channel != CAN_INVALID_CHANNEL; rx_map_cnt++) { channel = can_rx_map[rx_map_cnt].channel; // Save the channel id = can_rx_map[rx_map_cnt].id; // Save the ID rxStorageType = can_rx_map[rx_map_cnt].buffer; // Get the storage type (RX buffer, RX FIFO1, RX FIFO2) to be used for this ID // Check if the ID is in extended or standard format if ((id & CAN_MSG_ID_EXT) != 0U) { // The ID is in extended format extid_idx = channel_extid_cnt[channel]; // Get the number of the extended IDs already stored for this channel channel_extid_cnt[channel]++; // Increase the number of extended IDs stored for this channel // Create an RX filter for this extended ID // Check if the message corresponding to this ID will be stored inside an RX buffer or inside an RX FIFO if (rxStorageType < 64U) { // The message corresponding to this ID will be stored inside an RX buffer // Create the filter cy_stc_extid_filter_t filter = { .f0_f = { .efid1 = (uint32)(id), .efec = (uint32)CY_CANFD_ID_FILTER_ELEMNT_CONFIG_STORE_RXBUFF_OR_DEBUGMSG, }, .f1_f = { .efid2 = (uint32)((0UL << 9UL) | (uint32)(rxStorageType)), .eft = (uint32)CY_CANFD_EXT_ID_FILTER_TYPE_CLASSIC, }, }; // Save the filter for this extended ID in order to configure it later extIdFilters[channel][extid_idx] = filter; // Increase the number of RX buffers used for this channel noOfRxBuffers[channel]++; } else { // The message corresponding to this ID will be stored inside an RX FIFO if ((rxStorageType & RX_FIFO_0) != 0UL) { // RX FIFO0 used // Create the filter cy_stc_extid_filter_t filter = CANFD_CONFIG_EXT_ID_FILTER_CLASSIC(id, id, CY_CANFD_ID_FILTER_ELEMNT_CONFIG_STORE_RXFIFO0); // Save the filter for this extended ID in order to configure it later extIdFilters[channel][extid_idx] = filter; // Increase the number of RX FIFO0 elements used for this channel noOfFifo0El[channel]++; } else { // Assume RX FIFO1 selected // Create the filter cy_stc_extid_filter_t filter = CANFD_CONFIG_EXT_ID_FILTER_CLASSIC(id, id, CY_CANFD_ID_FILTER_ELEMNT_CONFIG_STORE_RXFIFO1); // Save the filter for this extended ID in order to configure it later extIdFilters[channel][extid_idx] = filter; // Increase the number of RX FIFO1 elements used for this channel noOfFifo1El[channel]++; } } } else { // The ID is in standard format stid_idx = channel_stid_cnt[channel]; // Get the number of the standard IDs already stored for this channel channel_stid_cnt[channel]++; // Increase the number of used standard IDs for this channel // Create an RX filter for this standard ID // Check if the message corresponding to this ID will be stored inside an RX buffer or inside an RX FIFO if (rxStorageType < 64U) { // The message corresponding to this ID will be stored inside an RX buffer // Create the filter cy_stc_id_filter_t filter = CANFD_CONFIG_STD_ID_FILTER_CLASSIC_RXBUFF(id, rxStorageType); // Save the filter for this standard ID in order to configure it later stIdFilters[channel][stid_idx] = filter; // Increase the number of RX buffers used for this channel noOfRxBuffers[channel]++; } else { // The message corresponding to this ID will be stored inside an RX FIFO if ((rxStorageType & RX_FIFO_0) != 0UL) { // RX FIFO0 used // Create the filter cy_stc_id_filter_t filter = CANFD_CONFIG_STD_ID_FILTER_CLASSIC(id, id, CY_CANFD_ID_FILTER_ELEMNT_CONFIG_STORE_RXFIFO0); // Save the filter for this standard ID in order to configure it later stIdFilters[channel][stid_idx] = filter; // Increase the number of RX FIFO0 elements used for this channel noOfFifo0El[channel]++; } else // RX_FIFO_1 used { // Assume RX FIFO1 selected cy_stc_id_filter_t filter = CANFD_CONFIG_STD_ID_FILTER_CLASSIC(id, id, CY_CANFD_ID_FILTER_ELEMNT_CONFIG_STORE_RXFIFO1); // Save the filter for this standard ID in order to configure it later stIdFilters[channel][stid_idx] = filter; // Save the filter for this ID // Increase the number of RX FIFO1 elements used for this channel noOfFifo1El[channel]++; } } } } // Count how many standard or extend IDs are per channel for (tx_map_cnt = can_tx_set_start; can_tx_map[tx_map_cnt].channel != CAN_INVALID_CHANNEL; tx_map_cnt++) { txMsgCount[can_tx_map[tx_map_cnt].channel]++; } // Make necessary configuration for each channel for (channel = 0U; channel < CAN_MAX_CHANNELS; channel++) { // Get MRAM offset and size for each channel CddMlcCan_GetMsgramOffset(ChannelsConfig[channel], &stcMsgramConfig[channel]); // Configure standard id filters CddMlcCan_ConfigureSIDFiler(channel, stcMsgramConfig[channel], channel_stid_cnt[channel]); // Configure extended id filters CddMlcCan_ConfigureEXTIDFiler(channel, channel_stid_cnt[channel], channel_extid_cnt[channel]); // Initialize message RAM area (entire region zeroing) for all channels CddMlcCan_InitMsgRam(channel, stcMsgramConfig[channel]); // Configuration of Global Filter unGFC.stcField.u2ANFS = (uint32)CY_CANFD_REJECT_NON_MATCHING; // Reject all non-matching standard IDs unGFC.stcField.u2ANFE = (uint32)CY_CANFD_REJECT_NON_MATCHING; // Reject all non-matching extended IDs unGFC.stcField.u1RRFS = 0U; // Filter remote frames with 11-bit standard IDs unGFC.stcField.u1RRFE = 0U; // Filter remote frames with 29-bit extended IDs ChannelsConfig[channel]->M_TTCAN.unGFC.u32Register = unGFC.u32Register; // Standard Message ID Filters // PRQA S 303 2 // correct cast - working with actual addresses // PRQA S 306 1 // correct cast - working with actual address and not the mapped structure pstcSIDFilter = (cy_stc_id_filter_t *)(((uint32)ChannelsConfig[channel] & 0xFFFF0000UL) + (uint32)CY_CANFD_MSGRAM_START + (uint32)((uint32)ChannelsConfig[channel]->M_TTCAN.unSIDFC.stcField.u14FLSSA << 2u)); for (u32Count = 0; u32Count < channel_stid_cnt[channel]; u32Count++) { pstcSIDFilter[u32Count] = stIdFilters[channel][u32Count]; } // Extended Message ID Filters // PRQA S 303 2 // correct cast - working with actual addresses // PRQA S 306 1 // correct cast - working with actual address and not the mapped structure pstcEXTIDFilter = (cy_stc_extid_filter_t *)(((uint32)ChannelsConfig[channel] & 0xFFFF0000UL) + (uint32)CY_CANFD_MSGRAM_START + (uint32)((uint32)ChannelsConfig[channel]->M_TTCAN.unXIDFC.stcField.u14FLESA << 2u)); for (u32Count = 0; u32Count < channel_extid_cnt[channel]; u32Count++) { pstcEXTIDFilter[u32Count] = extIdFilters[channel][u32Count]; } // Configure Rx Buffers and Rx FIFOs size for each channel CddMlcCan_ConfigureBufferDataSize(channel); // Configure RX FIFOS for the specific channel CddMlcCan_ConfigureRxFifos(channel, noOfFifo0El[channel], channel_extid_cnt[channel], noOfFifo1El[channel]); // Configure Tx buffers for the specific channel CddMlcCan_TxChnConfig(channel, noOfRxBuffers[channel], txMsgCount[channel]); } } //----------------------------------------------------------------------------- /// \brief CddMlcCan_ConfigureRxFifos /// /// \descr This function configures the rx FIFOs for a specific channel /// /// \param channel instance of the driver /// \param noOfFifo0ElChn number of elements in FIFO0 /// \param extIdCntChn number of extended id filters /// \param noOfFifo1ElChn umber of elements in FIFO1 /// /// \return void //----------------------------------------------------------------------------- static void CddMlcCan_ConfigureRxFifos(uint32 channel, uint8 noOfFifo0ElChn, uint32 extIdCntChn, uint8 noOfFifo1ElChn) { un_CANFD_CH_RXF0C_t unRXF0C = { 0 }; un_CANFD_CH_RXF1C_t unRXF1C = { 0 }; un_CANFD_CH_RXFTOP_CTL_t unRXFTOP_CTL = { 0 }; un_CANFD_CH_RXBC_t unRXBC = { 0 }; // Configure Rx FIFO 0 unRXF0C.stcField.u1F0OM = (uint32)CY_CANFD_FIFO_MODE_BLOCKING; // When an RX FIFO full condition is reached, no further messages are written to the RX FIFO until at least one message is read unRXF0C.stcField.u7F0WM = 32U; // Level 32 (of 64) for Rx FIFO 0 watermark interrupt (IR. RF0W) unRXF0C.stcField.u7F0S = noOfFifo0ElChn; // Number of elements to be stored in the RX FIFO 0 unRXF0C.stcField.u14F0SA = ChannelsConfig[channel]->M_TTCAN.unXIDFC.stcField.u14FLESA + (extIdCntChn * SIZE_OF_EXTID_FILTER_IN_WORD); // Start address of Rx FIFO 0 in Message RAM ChannelsConfig[channel]->M_TTCAN.unRXF0C.u32Register = unRXF0C.u32Register; // Configure Rx FIFO 1 unRXF1C.stcField.u1F1OM = (uint32)CY_CANFD_FIFO_MODE_BLOCKING; // When an RX FIFO full condition is reached, no further messages are written to the RX FIFO until at least one message is read unRXF1C.stcField.u7F1WM = 32U; // Level 32 (of 64) for Rx FIFO 1 watermark interrupt (IR. RF1W) unRXF1C.stcField.u7F1S = noOfFifo1ElChn; // Number of elements to be stored in the RX FIFO 1 unRXF1C.stcField.u14F1SA = ChannelsConfig[channel]->M_TTCAN.unRXF0C.stcField.u14F0SA + (uint32)(noOfFifo0ElChn * (uint32)(2U + (uint32)dataBufferSizeInWord[CY_CANFD_BUFFER_DATA_SIZE_8])); // Start address of Rx FIFO 1 in Message RAM ChannelsConfig[channel]->M_TTCAN.unRXF1C.u32Register = unRXF1C.u32Register; // RxFIFO 0,1 Top pointer logic configuration unRXFTOP_CTL.stcField.u1F0TPE = 0U; // Disabled at the moment. TODO: verify if needed unRXFTOP_CTL.stcField.u1F1TPE = 0U; ChannelsConfig[channel]->unRXFTOP_CTL.u32Register = unRXFTOP_CTL.u32Register; // Rx buffer configuration unRXBC.stcField.u14RBSA = ChannelsConfig[channel]->M_TTCAN.unRXF1C.stcField.u14F1SA + (uint32)(noOfFifo1ElChn * (uint32)(2U + (uint32)dataBufferSizeInWord[CY_CANFD_BUFFER_DATA_SIZE_8])); ChannelsConfig[channel]->M_TTCAN.unRXBC.u32Register = unRXBC.u32Register; } //----------------------------------------------------------------------------- /// \brief CddMlcCan_InitMsgRam /// /// \descr This function initializes the message RAM for a specific channel /// /// \param channel instance of the driver /// \param stcMsgramConfigChn given message RAM configuration for the given /// channel /// /// \return void //----------------------------------------------------------------------------- static void CddMlcCan_InitMsgRam(uint32 channel, cy_stc_canfd_msgram_config_t stcMsgramConfigChn) { uint32* pu32Adrs = NULL_PTR; uint32 u32SizeInWord; uint32 u32Count; // PRQA S 303 2 // correct cast - working with actual addresses // PRQA S 306 1 // correct cast - working with actual address and not the mapped structure pu32Adrs = (uint32 *)(((uint32)ChannelsConfig[channel] & 0xFFFF0000UL) + (uint32)CY_CANFD_MSGRAM_START + stcMsgramConfigChn.offset); u32SizeInWord = stcMsgramConfigChn.size >> 2U; for (u32Count = 0; u32Count < u32SizeInWord; u32Count++) { *pu32Adrs++ = 0UL; } } //----------------------------------------------------------------------------- /// \brief CddMlcCan_ConfigureSIDFiler /// /// \descr This function configures the standard id filters for a specific channel /// /// \param channel instance of the driver /// \param stcMsgramConfigChn given message RAM configuration for the given /// \param stdIdCntChn number of standard id filters /// /// \return void //----------------------------------------------------------------------------- static void CddMlcCan_ConfigureSIDFiler(uint32 channel, cy_stc_canfd_msgram_config_t stcMsgramConfigChn, uint32 stdIdCntChn) { un_CANFD_CH_SIDFC_t unSIDFC = { 0 }; // Set start address (in word) of SID filter configuration in message RAM unSIDFC.stcField.u14FLSSA = stcMsgramConfigChn.offset >> 2U; // Set the number of standard ID filters for each channel unSIDFC.stcField.u8LSS = stdIdCntChn; // Write to the corresponding registers ChannelsConfig[channel]->M_TTCAN.unSIDFC.u32Register = unSIDFC.u32Register; } //----------------------------------------------------------------------------- /// \brief CddMlcCan_ConfigureSIDFiler /// /// \descr This function configures the standard id filters for a specific channel /// /// \param channel instance of the driver /// \param startAddr start address for message RAM configuration for the given /// channel /// \param extIdCntChn number of extended id filters /// /// \return void //----------------------------------------------------------------------------- static void CddMlcCan_ConfigureEXTIDFiler(uint32 channel, uint32 startAddr, uint32 extIdCntChn) { un_CANFD_CH_XIDFC_t unXIDFC = { 0 }; un_CANFD_CH_XIDAM_t unXIDAM = { 0 }; // Set start address (in word) of extended ID filter configuration in message RAM unXIDFC.stcField.u14FLESA = ChannelsConfig[channel]->M_TTCAN.unSIDFC.stcField.u14FLSSA + (startAddr * SIZE_OF_SID_FILTER_IN_WORD); // Set the number of extended ID filters for each channel unXIDFC.stcField.u7LSE = extIdCntChn; // Write to the corresponding registers ChannelsConfig[channel]->M_TTCAN.unXIDFC.u32Register = unXIDFC.u32Register; // Extended ID AND Mask // For acceptance filtering of extended frames the Extended ID AND Mask is ANDed with the Message ID of a received frame // No pre-filtering used, set all bits to 1 unXIDAM.stcField.u29EIDM = 0x1fffffffU; ChannelsConfig[channel]->M_TTCAN.unXIDAM.u32Register = unXIDAM.u32Register; } //----------------------------------------------------------------------------- /// \brief CddMlcCan_ConfigureBufferDataSize /// /// \descr This function configures the data size of the buffers for the specific channel /// /// \param channel instance of the driver /// /// \return void //----------------------------------------------------------------------------- static void CddMlcCan_ConfigureBufferDataSize(uint32 channel) { un_CANFD_CH_RXESC_t unRXESC = { 0 }; unRXESC.stcField.u3RBDS = (uint32)CY_CANFD_BUFFER_DATA_SIZE_8; // 8 byte data field for Rx Buffers unRXESC.stcField.u3F1DS = (uint32)CY_CANFD_BUFFER_DATA_SIZE_8; // 8 byte data field for Rx FIFO 1 unRXESC.stcField.u3F0DS = (uint32)CY_CANFD_BUFFER_DATA_SIZE_8; // 8 byte data field for Rx FIFO 0 ChannelsConfig[channel]->M_TTCAN.unRXESC.u32Register = unRXESC.u32Register; } //----------------------------------------------------------------------------- /// \brief CddMlcCan_TxChnConfig /// /// \descr This function configures the transmit buffer /// /// \param channel instance of the driver /// \param noObRxBuffersChn number of configured rx buffers for the specific channel /// \param txMsgCountChn number of buffers to be configured for the specific channel /// /// \return void //----------------------------------------------------------------------------- static void CddMlcCan_TxChnConfig(uint32 channel, uint32 noObRxBuffersChn, uint8 txMsgCountChn) { un_CANFD_CH_TXESC_t unTXESC = { 0 }; un_CANFD_CH_TXEFC_t unTXEFC = { 0 }; un_CANFD_CH_TXBC_t unTXBC = { 0 }; // Configuration of Tx Buffer and Tx FIFO/Queue unTXESC.stcField.u3TBDS = (uint32)CY_CANFD_BUFFER_DATA_SIZE_8; // 8 byte data field for Tx Buffers ChannelsConfig[channel]->M_TTCAN.unTXESC.u32Register = unTXESC.u32Register; // Tx-Event-FIFO configuration unTXEFC.stcField.u6EFWM = 0; // Watermark interrupt disabled unTXEFC.stcField.u6EFS = TX_FIFO_ELEMENTCOUNT; // Tx-Event-FIFO with 32 elements unTXEFC.stcField.u14EFSA = ChannelsConfig[channel]->M_TTCAN.unRXBC.stcField.u14RBSA + (uint32)(noObRxBuffersChn * (uint32)(2U + (uint32)dataBufferSizeInWord[CY_CANFD_BUFFER_DATA_SIZE_8])); ChannelsConfig[channel]->M_TTCAN.unTXEFC.u32Register = unTXEFC.u32Register; // Tx-FIFO and Tx-Buffer configuration unTXBC.stcField.u1TFQM = 0; // select Tx-FIFO operation unTXBC.stcField.u6TFQS = TX_FIFO_ELEMENTCOUNT; // enalble Tx-FIFO unTXBC.stcField.u6NDTB = 0; // number of dedicated Tx Buffers unTXBC.stcField.u14TBSA = ChannelsConfig[channel]->M_TTCAN.unTXEFC.stcField.u14EFSA + (TX_FIFO_ELEMENTCOUNT * SIZE_OF_TXEVENT_FIFO_IN_WORD); ChannelsConfig[channel]->M_TTCAN.unTXBC.u32Register = unTXBC.u32Register; } //----------------------------------------------------------------------------- /// \brief CddMlcCan_Init_Bus /// /// \descr This function initializes the CAN bus. /// /// \param void /// /// \return void //----------------------------------------------------------------------------- static void CddMlcCan_Init_Bus(void) { un_CANFD_CH_CCCR_t unCCCR = { 0 }; uint8 channel; // Make necessary configuration for each channel for (channel = 0U; channel < CAN_MAX_CHANNELS; channel++) { // Configuration of CAN bus // CCCR register unCCCR.stcField.u1INIT = 1; // Keep in initialization state unCCCR.stcField.u1CCE = 1; // Keep CCE to enabled unCCCR.stcField.u1TXP = 1; // Transmit pause enabled unCCCR.stcField.u1BRSE = 0; // Bit rate switching for transmissions disabled unCCCR.stcField.u1FDOE = 0; // FD operation disabled unCCCR.stcField.u1TEST = 0; // Normal operation unCCCR.stcField.u1DAR = 0; // Automatic retransmission enabled unCCCR.stcField.u1MON_ = 0; // Bus Monitoring Mode is disabled unCCCR.stcField.u1CSR = 0; // No clock stop is requested unCCCR.stcField.u1ASM = 0; // Normal CAN operation ChannelsConfig[channel]->M_TTCAN.unCCCR.u32Register = unCCCR.u32Register; } } //----------------------------------------------------------------------------- /// \brief CddMlcCan_TxHandleToIndex /// /// \descr Helper function to convert a transmit map handle to its internal /// array index. /// /// \param tx_handle the handle /// /// \return idx the index of the handle //----------------------------------------------------------------------------- static inline uint32 CddMlcCan_TxHandleToIndex(can_handle_type tx_handle) { uint32 retVal = CAN_INVALID_INDEX; uint32 idx; for (idx = can_tx_set_start; can_tx_map[idx].channel != CAN_INVALID_CHANNEL; ++idx) { if (tx_handle == can_tx_map[idx].handle) { retVal = idx; break; } } return retVal; } //----------------------------------------------------------------------------- /// \brief CddMlcCan_GetMsgramOffset /// /// \descr Get the CAN FD channel MRAM offset and size. /// /// \param pstcCanFD Pointer to register area of a CAN FD channel. /// \param pstcMsgramConfig Pointer to a structure inside which the MRAM /// offset and size will be returned for the CAN FD channel. /// /// \return CY_CANFD_SUCCESS /// \return CY_CANFD_BAD_PARAM If one of the following conditions are met : /// -pstcCanFD == NULL /// -pstcConfig == NULL //----------------------------------------------------------------------------- static void CddMlcCan_GetMsgramOffset(cy_pstc_canfd_type_t pstcCanFD, cy_stc_canfd_msgram_config_t *pstcMsgramConfig) { // PRQA S 303 1 // correct cast -comes from macro definition if (pstcCanFD == CY_CANFD0_0_TYPE) { pstcMsgramConfig->offset = (uint16)CY_CANFD0_0_MSGRAM_OFFSET; pstcMsgramConfig->size = CY_CANFD0_0_MSGRAM_SIZE; } // PRQA S 303 1 // correct cast -comes from macro definition else if (pstcCanFD == CY_CANFD0_1_TYPE) { pstcMsgramConfig->offset = (uint16)CY_CANFD0_1_MSGRAM_OFFSET; pstcMsgramConfig->size = CY_CANFD0_1_MSGRAM_SIZE; } // PRQA S 303 1 // correct cast -comes from macro definition else if (pstcCanFD == CY_CANFD0_2_TYPE) { pstcMsgramConfig->offset = (uint16)CY_CANFD0_2_MSGRAM_OFFSET; pstcMsgramConfig->size = CY_CANFD0_2_MSGRAM_SIZE; } // PRQA S 303 1 // correct cast -comes from macro definition else if (pstcCanFD == CY_CANFD1_0_TYPE) { pstcMsgramConfig->offset = (uint16)CY_CANFD1_0_MSGRAM_OFFSET; pstcMsgramConfig->size = CY_CANFD1_0_MSGRAM_SIZE; } // PRQA S 303 1 // correct cast -comes from macro definition else if (pstcCanFD == CY_CANFD1_1_TYPE) { pstcMsgramConfig->offset = (uint16)CY_CANFD1_1_MSGRAM_OFFSET; pstcMsgramConfig->size = CY_CANFD1_1_MSGRAM_SIZE; } // PRQA S 303 1 // correct cast -comes from macro definition else if (pstcCanFD == CY_CANFD1_2_TYPE) { pstcMsgramConfig->offset = (uint16)CY_CANFD1_2_MSGRAM_OFFSET; pstcMsgramConfig->size = CY_CANFD1_2_MSGRAM_SIZE; } else { // do nothing } // PRQA S 5336 1 // architecture } //----------------------------------------------------------------------------- /// \brief CddMlcCan_CalcTxBufAdrs /// /// \descr Message buffer address calculation for transmission. /// /// \param pstcCanFD Pointer to register area of a CAN FD channel. /// \param u8MsgBuf Message buffer index for transmission.(0 - 31) /// /// \return pu32Adrs Message buffer address corresponding to the index. /// Can be NULL if the index is invalid. //----------------------------------------------------------------------------- static uint32* CddMlcCan_CalcTxBufAdrs(cy_pstc_canfd_type_t pstcCanFD, uint8 u8MsgBuf) { uint32* pu32Adrs = NULL_PTR; if (u8MsgBuf > 31U) { // Set 0 to the return value if the index is invalid pu32Adrs = NULL; } else { // Set the message buffer address to the return value if the index is available // PRQA S 303 2 // correct cast - working with actual addresses // PRQA S 306 1 // correct cast - working with actual address and not the mapped structure pu32Adrs = (uint32*)(((uint32)pstcCanFD & 0xFFFF0000UL) + (uint32)CY_CANFD_MSGRAM_START); pu32Adrs += pstcCanFD->M_TTCAN.unTXBC.stcField.u14TBSA; pu32Adrs += u8MsgBuf * (2U + dataBufferSizeInWord[pstcCanFD->M_TTCAN.unTXESC.stcField.u3TBDS]); } return pu32Adrs; } //----------------------------------------------------------------------------- /// \brief CddMlcCan_ExtractMsgFromRXBuffer /// /// \descr Extract the message content from RX Buffer. /// /// \param pstcRxBufferAddr Rx Buffer address in CAN Message RAM. /// \param pstcCanFDmsg Pointer to the structure containing the /// CAN Message extracted form Rx Buffer /// /// \return - //----------------------------------------------------------------------------- static void CddMlcCan_ExtractMsgFromRXBuffer(cy_stc_canfd_rx_buffer_t *pstcRxBufferAddr, cy_stc_canfd_msg_t *pstcCanFDmsg) { uint16 u16Count = 0; uint16 u16DlcTemp = 0; if (pstcRxBufferAddr != NULL_PTR) { // Save received data // XTD : Extended Identifier pstcCanFDmsg->idConfig.extended = pstcRxBufferAddr->r0_f.xtd; // ID : RxID if (pstcCanFDmsg->idConfig.extended == FALSE) { pstcCanFDmsg->idConfig.identifier = (uint32)((uint32)pstcRxBufferAddr->r0_f.id >> 18U); } else { pstcCanFDmsg->idConfig.identifier = pstcRxBufferAddr->r0_f.id; } // FDF : Extended Data Length pstcCanFDmsg->canFDFormat = pstcRxBufferAddr->r1_f.fdf; // PRQA S 4440 1 // Intentionally no modification of existing code // DLC : Data Length Code pstcCanFDmsg->dataConfig.dataLengthCode = pstcRxBufferAddr->r1_f.dlc; // Copy 0-64 byte of data area if (pstcCanFDmsg->dataConfig.dataLengthCode < 8U) { u16DlcTemp = 0U; } else { u16DlcTemp = (uint16)((uint16)pstcCanFDmsg->dataConfig.dataLengthCode - 8U); } for (u16Count = 0U; u16Count < dataBufferSizeInWord[u16DlcTemp]; u16Count++) { pstcCanFDmsg->dataConfig.data[u16Count] = pstcRxBufferAddr->data_area_f[u16Count]; } } else { // do nothing } } //----------------------------------------------------------------------------- /// \brief CddMlcCan_CalcRxFifoAdrs /// /// \descr Message buffer address calculation for reception (using FIFOs). /// /// \param pstcCanFD Pointer to register area of a CAN FD channel. /// \param u8FifoNumber FIFO number (0 or 1) /// \param u8MsgBuf Message buffer index for reception.(0 - 63) /// /// \return pu32Adrs Message buffer address corresponding to the index. /// Can be NULL if the index is invalid. //----------------------------------------------------------------------------- static uint32* CddMlcCan_CalcRxFifoAdrs(cy_pstc_canfd_type_t pstcCanFD, uint8 u8FifoNumber, uint32 u32GetIndex) { uint32* pu32Adrs = NULL_PTR; if (u8FifoNumber > 1U) { // Set 0 to the return value if the FIFO number is invalid pu32Adrs = NULL; } else { // Set the message buffer address to the return value if the index is available // PRQA S 303 2 // correct cast - working with actual addresses // PRQA S 306 1 // correct cast - working with actual address and not the mapped structure pu32Adrs = (uint32*)(((uint32)pstcCanFD & 0xFFFF0000UL) + (uint32)CY_CANFD_MSGRAM_START); pu32Adrs += (u8FifoNumber == 0U) ? pstcCanFD->M_TTCAN.unRXF0C.stcField.u14F0SA : pstcCanFD->M_TTCAN.unRXF1C.stcField.u14F1SA; pu32Adrs += u32GetIndex * (uint32)(2U + (uint32)dataBufferSizeInWord[(u8FifoNumber == 0U) ? pstcCanFD->M_TTCAN.unRXESC.stcField.u3F0DS : pstcCanFD->M_TTCAN.unRXESC.stcField.u3F1DS]); } return pu32Adrs; } //----------------------------------------------------------------------------- /// \brief CddMlcCan_CalcRxBufAdrs /// /// \descr Message buffer address calculation for reception. /// /// \param pstcCanFD Pointer to register area of a CAN FD channel. /// \param u8MsgBuf Message buffer index for reception.(0 - 63) /// /// \return pu32Adrs Message buffer address corresponding to the index. /// Can be NULL if the index is invalid. //----------------------------------------------------------------------------- static uint32* CddMlcCan_CalcRxBufAdrs(cy_pstc_canfd_type_t pstcCanFD, uint8 u8MsgBuf) { uint32* pu32Adrs = NULL_PTR; if (u8MsgBuf > 63U) { // Set 0 to the return value if the index is invalid pu32Adrs = NULL; } else { // Set the message buffer address to the return value if the index is available // PRQA S 303 2 // correct cast - working with actual addresses // PRQA S 306 1 // correct cast - working with actual address and not the mapped structure pu32Adrs = (uint32*)(((uint32)pstcCanFD & 0xFFFF0000UL) + (uint32)CY_CANFD_MSGRAM_START); pu32Adrs += pstcCanFD->M_TTCAN.unRXBC.stcField.u14RBSA; pu32Adrs += u8MsgBuf * (2U + dataBufferSizeInWord[pstcCanFD->M_TTCAN.unRXESC.stcField.u3RBDS]); } return pu32Adrs; }