/*================================================================================================== * Project : RTD AUTOSAR 4.4 * Platform : CORTEXM * Peripheral : LPI2C * Dependencies : none * * Autosar Version : 4.4.0 * Autosar Revision : ASR_REL_4_4_REV_0000 * Autosar Conf.Variant : * SW Version : 0.9.0 * Build Version : S32K3_RTD_0_9_0__ASR_REL_4_4_REV_0000_20210326 * * (c) Copyright 2020 - 2021 NXP Semiconductors * All Rights Reserved. * * NXP Confidential. This software is owned or controlled by NXP and may only be * used strictly in accordance with the applicable license terms. By expressly * accepting such terms or by downloading, installing, activating and/or otherwise * using the software, you are agreeing that you have read, and that you agree to * comply with and are bound by, such license terms. If you do not agree to be * bound by the applicable license terms, then you may not retain, install, * activate or otherwise use the software. ==================================================================================================*/ /** * @file * * @addtogroup LPI2C_DRIVER Lpi2c Driver * @{ */ #ifdef __cplusplus extern "C"{ #endif /*================================================================================================== * INCLUDE FILES * 1) system and project includes * 2) needed interfaces from external units * 3) internal and external interfaces from this unit ==================================================================================================*/ #include "Lpi2c_Ip_HwAccess.h" #include "Lpi2c_Ip_Features.h" #include "Osif.h" #include "Lpi2c_Ip.h" #if (STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) #include "Dma_Ip.h" #endif /* (STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) */ #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) #include "Devassert.h" #endif /* (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) */ /*================================================================================================== * SOURCE FILE VERSION INFORMATION ==================================================================================================*/ #define LPI2C_IP_VENDOR_ID_C 43 #define LPI2C_IP_AR_RELEASE_MAJOR_VERSION_C 4 #define LPI2C_IP_AR_RELEASE_MINOR_VERSION_C 4 #define LPI2C_IP_AR_RELEASE_REVISION_VERSION_C 0 #define LPI2C_IP_SW_MAJOR_VERSION_C 0 #define LPI2C_IP_SW_MINOR_VERSION_C 9 #define LPI2C_IP_SW_PATCH_VERSION_C 0 /*================================================================================================== * FILE VERSION CHECKS ==================================================================================================*/ /* Checks against Lpi2c_Ip.h */ #if (LPI2C_IP_VENDOR_ID_C != LPI2C_IP_VENDOR_ID) #error "Lpi2c_Ip.c and Lpi2c_Ip.h have different vendor ids" #endif #if (( LPI2C_IP_AR_RELEASE_MAJOR_VERSION_C != LPI2C_IP_AR_RELEASE_MAJOR_VERSION) || \ ( LPI2C_IP_AR_RELEASE_MINOR_VERSION_C != LPI2C_IP_AR_RELEASE_MINOR_VERSION) || \ ( LPI2C_IP_AR_RELEASE_REVISION_VERSION_C != LPI2C_IP_AR_RELEASE_REVISION_VERSION)) #error "AUTOSAR Version Numbers of Lpi2c_Ip.c and Lpi2c_Ip.h are different" #endif #if (( LPI2C_IP_SW_MAJOR_VERSION_C != LPI2C_IP_SW_MAJOR_VERSION) || \ ( LPI2C_IP_SW_MINOR_VERSION_C != LPI2C_IP_SW_MINOR_VERSION) || \ ( LPI2C_IP_SW_PATCH_VERSION_C != LPI2C_IP_SW_PATCH_VERSION)) #error "Software Version Numbers of Lpi2c_Ip.c and Lpi2c_Ip.h are different" #endif /* Checks against Lpi2c_Ip_HwAccess.h */ #if (LPI2C_IP_VENDOR_ID_C != LPI2C_IP_HWACCESS_VENDOR_ID) #error "Lpi2c_Ip.c and Lpi2c_Ip_HwAccess.h have different vendor ids" #endif #if (( LPI2C_IP_AR_RELEASE_MAJOR_VERSION_C != LPI2C_IP_HWACCESS_AR_RELEASE_MAJOR_VERSION) || \ ( LPI2C_IP_AR_RELEASE_MINOR_VERSION_C != LPI2C_IP_HWACCESS_AR_RELEASE_MINOR_VERSION) || \ ( LPI2C_IP_AR_RELEASE_REVISION_VERSION_C != LPI2C_IP_HWACCESS_AR_RELEASE_REVISION_VERSION)) #error "AUTOSAR Version Numbers of Lpi2c_Ip.c and Lpi2c_Ip_HwAccess.h are different" #endif #if (( LPI2C_IP_SW_MAJOR_VERSION_C != LPI2C_IP_HWACCESS_SW_MAJOR_VERSION) || \ ( LPI2C_IP_SW_MINOR_VERSION_C != LPI2C_IP_HWACCESS_SW_MINOR_VERSION) || \ ( LPI2C_IP_SW_PATCH_VERSION_C != LPI2C_IP_HWACCESS_SW_PATCH_VERSION)) #error "Software Version Numbers of LPI2C_Ip.c and Lpi2c_Ip_HwAccess.h are different" #endif /* Checks against Lpi2c_Ip_Features.h */ #if (LPI2C_IP_VENDOR_ID_C != LPI2C_IP_FEATURES_VENDOR_ID) #error "Lpi2c_Ip.c and Lpi2c_Ip_Features.h have different vendor ids" #endif #if (( LPI2C_IP_AR_RELEASE_MAJOR_VERSION_C != LPI2C_IP_FEATURES_AR_RELEASE_MAJOR_VERSION) || \ ( LPI2C_IP_AR_RELEASE_MINOR_VERSION_C != LPI2C_IP_FEATURES_AR_RELEASE_MINOR_VERSION) || \ ( LPI2C_IP_AR_RELEASE_REVISION_VERSION_C != LPI2C_IP_FEATURES_AR_RELEASE_REVISION_VERSION)) #error "AUTOSAR Version Numbers of Lpi2c_Ip.c and Lpi2c_Ip_Features.h are different" #endif #if (( LPI2C_IP_SW_MAJOR_VERSION_C != LPI2C_IP_FEATURES_SW_MAJOR_VERSION) || \ ( LPI2C_IP_SW_MINOR_VERSION_C != LPI2C_IP_FEATURES_SW_MINOR_VERSION) || \ ( LPI2C_IP_SW_PATCH_VERSION_C != LPI2C_IP_FEATURES_SW_PATCH_VERSION)) #error "Software Version Numbers of LPI2C_Ip.c and Lpi2c_Ip_Features.h are different" #endif #ifndef DISABLE_MCAL_INTERMODULE_ASR_CHECK /* Checks against Mcal.h */ #if ((LPI2C_IP_AR_RELEASE_MAJOR_VERSION_C != MCAL_AR_RELEASE_MAJOR_VERSION) || \ (LPI2C_IP_AR_RELEASE_MINOR_VERSION_C != MCAL_AR_RELEASE_MINOR_VERSION)) #error "AUTOSAR Version Numbers of Lpi2c_Ip.h and Mcal.h are different" #endif #endif /******************************************************************************* * Variables ******************************************************************************/ /** @cond DRIVER_INTERNAL_USE_ONLY */ /* Constraints used for baud rate computation */ #define CLKHI_MIN_VALUE 1U #define CLKLO_MIN_VALUE 3U #define CLKHI_MAX_VALUE ((1U << LPI2C_MCCR0_CLKHI_WIDTH) - 1U) #define CLKLO_MAX_VALUE CLKHI_MAX_VALUE #define DATAVD_MIN_VALUE 1U #define SETHOLD_MIN_VALUE 2U /* DMA definitions */ #define I2C_DMA_CHANNEL_CONFIG_LIST_SIZE_MASTER (10U) #define I2C_DMA_CHANNEL_CONFIG_LIST_SIZE_SLAVE (9U) #define I2C_START_SEC_CONST_UNSPECIFIED #include "I2c_MemMap.h" /* Table of base addresses for LPI2C instances. */ static LPI2C_Type * const g_lpi2cBase[LPI2C_INSTANCE_COUNT] = LPI2C_BASE_PTRS; #define I2C_STOP_SEC_CONST_UNSPECIFIED #include "I2c_MemMap.h" #if(LPI2C_IP_NUMBER_OF_MASTER_INSTANCES != 0U) #define I2C_START_SEC_VAR_NO_INIT_UNSPECIFIED #include "I2c_MemMap.h" Lpi2c_Ip_MasterStateType Lpi2c_Ip_MasterState[LPI2C_IP_NUMBER_OF_MASTER_INSTANCES]; #define I2C_STOP_SEC_VAR_NO_INIT_UNSPECIFIED #include "I2c_MemMap.h" #endif #if(LPI2C_IP_NUMBER_OF_SLAVE_INSTANCES != 0U) #define I2C_START_SEC_VAR_NO_INIT_UNSPECIFIED #include "I2c_MemMap.h" Lpi2c_Ip_SlaveStateType Lpi2c_Ip_SlaveState[LPI2C_IP_NUMBER_OF_SLAVE_INSTANCES]; #define I2C_STOP_SEC_VAR_NO_INIT_UNSPECIFIED #include "I2c_MemMap.h" #endif #define I2C_START_SEC_VAR_INIT_UNSPECIFIED #include "I2c_MemMap.h" /* Pointer to runtime state structure.*/ static Lpi2c_Ip_MasterStateType* g_lpi2cMasterStatePtr[LPI2C_INSTANCE_COUNT] = {NULL_PTR,NULL_PTR}; static Lpi2c_Ip_SlaveStateType* g_lpi2cSlaveStatePtr[LPI2C_INSTANCE_COUNT] = {NULL_PTR,NULL_PTR}; #define I2C_STOP_SEC_VAR_INIT_UNSPECIFIED #include "I2c_MemMap.h" #define I2C_START_SEC_VAR_NO_INIT_UNSPECIFIED #include "I2c_MemMap.h" #if (STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) /* Structures for configuration the master DMA channel */ static Dma_Ip_LogicChannelTransferListType dmaChannelTransferListReceive[I2C_DMA_CHANNEL_CONFIG_LIST_SIZE_MASTER]; static Dma_Ip_LogicChannelTransferListType dmaChannelTransferListSend[I2C_DMA_CHANNEL_CONFIG_LIST_SIZE_MASTER]; /* Structures for configuration the master DMA channel */ static Dma_Ip_LogicChannelTransferListType dmaSlaveChTransferListReceive[I2C_DMA_CHANNEL_CONFIG_LIST_SIZE_SLAVE]; static Dma_Ip_LogicChannelTransferListType dmaSlaveChTransferListSend[I2C_DMA_CHANNEL_CONFIG_LIST_SIZE_SLAVE]; #endif /* LPI2C_IP_DMA_FEATURE_AVAILABLE */ #define I2C_STOP_SEC_VAR_NO_INIT_UNSPECIFIED #include "I2c_MemMap.h" #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) /* Callback for master DMA transfer done.*/ static void Lpi2c_Ip_MasterCompleteDMATransfer(uint32 u32Instance); #endif /** @brief Direction of a LPI2C transfer - transmit or receive. */ typedef enum { LPI2C_TX_REQ = 0, /**< The driver will perform an I2C transmit transfer */ LPI2C_RX_REQ = 1, /**< The driver will perform an I2C receive transfer */ } Lpi2c_Ip_TransferDirectionType; #define I2C_START_SEC_CODE #include "I2c_MemMap.h" /******************************************************************************* * API ******************************************************************************/ /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterCmdQueueEmpty * Description : checks if there are any commands in the master software queue * *END**************************************************************************/ static inline boolean Lpi2c_Ip_MasterCmdQueueEmpty(const Lpi2c_Ip_MasterStateType * master) { #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif return (master->cmdQueue.writeIdx == master->cmdQueue.readIdx); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterResetQueue * Description : resets the master software queue * *END**************************************************************************/ static inline void Lpi2c_Ip_MasterResetQueue(Lpi2c_Ip_MasterStateType * master) { #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif master->cmdQueue.readIdx = 0U; master->cmdQueue.writeIdx = 0U; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterQueueCmd * Description : queues a command in the hardware FIFO or in the master software queue * *END**************************************************************************/ static inline void Lpi2c_Ip_MasterQueueCmd(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType * master, Lpi2c_Ip_MasterCommandType cmd, uint8 data) { uint16 txFIFOCount; uint16 txFIFOSize; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); DevAssert(baseAddr != NULL_PTR); #endif txFIFOCount = LPI2C_Get_MasterTxFIFOCount(baseAddr); txFIFOSize = LPI2C_Get_MasterTxFIFOSize(baseAddr); /* Check if there is room in the hardware FIFO */ if (txFIFOCount < txFIFOSize) { LPI2C_Cmd_MasterTransmit(baseAddr, cmd, data); } else { #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) /* Hardware FIFO full, use software FIFO */ DevAssert(master->cmdQueue.writeIdx < LPI2C_MASTER_CMD_QUEUE_SIZE); #endif master->cmdQueue.cmd[master->cmdQueue.writeIdx] = cmd; master->cmdQueue.data[master->cmdQueue.writeIdx] = data; master->cmdQueue.writeIdx++; } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterSendQueuedCmd * Description : transfers commands from the master software queue to the hardware FIFO * *END**************************************************************************/ static inline void Lpi2c_Ip_MasterSendQueuedCmd(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType * master) { #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); DevAssert(baseAddr != NULL_PTR); #endif uint16 txFIFOCount = LPI2C_Get_MasterTxFIFOCount(baseAddr); uint16 txFifoSize = LPI2C_Get_MasterTxFIFOSize(baseAddr); while ((!Lpi2c_Ip_MasterCmdQueueEmpty(master)) && (txFIFOCount < txFifoSize)) { LPI2C_Cmd_MasterTransmit(baseAddr, master->cmdQueue.cmd[master->cmdQueue.readIdx], master->cmdQueue.data[master->cmdQueue.readIdx]); master->cmdQueue.readIdx++; txFIFOCount = LPI2C_Get_MasterTxFIFOCount(baseAddr); } if (Lpi2c_Ip_MasterCmdQueueEmpty(master)) { /* Reset queue */ Lpi2c_Ip_MasterResetQueue(master); } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterSendAddress * Description : send start event and slave address * parameter receive specifies the direction of the transfer * *END**************************************************************************/ static void Lpi2c_Ip_MasterSendAddress(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType * master, boolean receive) { uint8 addrByte; Lpi2c_Ip_MasterCommandType startCommand; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); DevAssert(baseAddr != NULL_PTR); #endif if ((master->operatingMode == LPI2C_HIGHSPEED_MODE) && (master->highSpeedInProgress == FALSE)) { /* Initiating High-speed mode - send master code first */ Lpi2c_Ip_MasterQueueCmd(baseAddr, master, LPI2C_MASTER_COMMAND_START_NACK, master->masterCode); master->highSpeedInProgress = TRUE; } if (master->highSpeedInProgress == TRUE) { /* Use high-speed settings after start event in High Speed mode */ startCommand = LPI2C_MASTER_COMMAND_START_HS; } else { /* Normal START command */ startCommand = LPI2C_MASTER_COMMAND_START; } if (master->is10bitAddr) { /* 10-bit addressing */ /* First address byte: 1111 0XXD, where XX are bits 10 and 9 of address, and D = 0(transmit) */ addrByte = (uint8)(0xF0U + ((master->slaveAddress >> 7U) & 0x6U) + (uint8)0U); Lpi2c_Ip_MasterQueueCmd(baseAddr, master, startCommand, addrByte); /* Second address byte: Remaining 8 bits of address */ addrByte = (uint8)(master->slaveAddress & 0xFFU); Lpi2c_Ip_MasterQueueCmd(baseAddr, master, LPI2C_MASTER_COMMAND_TRANSMIT, addrByte); if (receive == TRUE) { /* Receiving from 10-bit slave - must send repeated start and resend first address byte */ /* First address byte: 1111 0XXD, where XX are bits 10 and 9 of address, and D = 1 (receive) */ addrByte = (uint8)(0xF0U + ((master->slaveAddress >> 7U) & 0x6U) + (uint8)1U); Lpi2c_Ip_MasterQueueCmd(baseAddr, master, startCommand, addrByte); } } else { /* 7-bit addressing */ /* Address byte: slave 7-bit address + D = 0(transmit) or 1 (receive) */ addrByte = (uint8)((master->slaveAddress << 1U) + (uint8)receive); Lpi2c_Ip_MasterQueueCmd(baseAddr, master, startCommand, addrByte); } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterQueueData * Description : queues transmit data in the LPI2C tx fifo until it is full * *END**************************************************************************/ static void Lpi2c_Ip_MasterQueueData(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType * master) { #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); DevAssert(baseAddr != NULL_PTR); #endif uint16 txFIFOCount = LPI2C_Get_MasterTxFIFOCount(baseAddr); uint16 txFifoSize = LPI2C_Get_MasterTxFIFOSize(baseAddr); /* Don't queue any data if there are commands in the software queue */ if (Lpi2c_Ip_MasterCmdQueueEmpty(master)) { while ((master->bufferSize > 0U) && (txFIFOCount < txFifoSize)) { LPI2C_Cmd_MasterTransmit(baseAddr, LPI2C_MASTER_COMMAND_TRANSMIT, master->dataBuffer[0U]); master->dataBuffer++; master->bufferSize--; txFIFOCount = LPI2C_Get_MasterTxFIFOCount(baseAddr); } } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterEndTransfer * Description : ends current transmission or reception * *END**************************************************************************/ static void Lpi2c_Ip_MasterEndTransfer(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType * master, boolean sendStop, boolean resetFIFO) { #if(STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); DevAssert(baseAddr != NULL_PTR); #endif /* Disable all events */ LPI2C_Set_MasterInt(baseAddr, LPI2C_MASTER_FIFO_ERROR_INT | LPI2C_MASTER_ARBITRATION_LOST_INT | LPI2C_MASTER_NACK_DETECT_INT | LPI2C_MASTER_TRANSMIT_DATA_INT | LPI2C_MASTER_PIN_LOW_TIMEOUT_INT | LPI2C_MASTER_RECEIVE_DATA_INT, FALSE); #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) if (master->transferType == LPI2C_USING_DMA) { /* Disable LPI2C DMA request. */ if (LPI2C_IP_RECEIVE == master->direction) { (void)LPI2C_Set_MasterRxDMA(baseAddr, FALSE); } else { (void)LPI2C_Set_MasterTxDMA(baseAddr, FALSE); } } #endif if (resetFIFO == TRUE) { /* Reset FIFOs if requested */ LPI2C_Reset_MasterTxFIFOCmd(baseAddr); LPI2C_Reset_MasterRxFIFOCmd(baseAddr); } /* Queue STOP command if requested */ if (sendStop == TRUE) { LPI2C_Cmd_MasterTransmit(baseAddr, LPI2C_MASTER_COMMAND_STOP, 0U); master->highSpeedInProgress = FALSE; /* High-speed transfers end at STOP condition */ } master->dataBuffer = NULL_PTR; master->bufferSize = 0U; master->i2cIdle = TRUE; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterSetOperatingMode * Description : sets the operating mode of the I2C master * *END**************************************************************************/ static void Lpi2c_Ip_MasterSetOperatingMode(uint32 instance, Lpi2c_Ip_ModeType operatingMode) { LPI2C_Type *baseAddr; Lpi2c_Ip_MasterStateType * master; baseAddr = g_lpi2cBase[instance]; master = g_lpi2cMasterStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif #if(LPI2C_HAS_ULTRA_FAST_MODE) if (operatingMode == LPI2C_ULTRAFAST_MODE) { LPI2C_Set_MasterPinConfig(baseAddr, LPI2C_CFG_2PIN_OUTPUT_ONLY); LPI2C_Set_MasterNACKConfig(baseAddr, LPI2C_NACK_IGNORE); } else #endif { LPI2C_Set_MasterPinConfig(baseAddr, LPI2C_CFG_2PIN_OPEN_DRAIN); LPI2C_Set_MasterNACKConfig(baseAddr, LPI2C_NACK_RECEIVE); } master->operatingMode = operatingMode; } #if(LPI2C_HAS_ULTRA_FAST_MODE) /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveConfigureUltraFastMode * Description : configures slave in ultra fast mode * *END**************************************************************************/ static void Lpi2c_Ip_SlaveConfigureUltraFastMode(LPI2C_Type *baseAddr) { /* ignore NACK received */ LPI2C_Set_SlaveIgnoreNACK(baseAddr, LPI2C_SLAVE_NACK_CONTINUE_TRANSFER); /* Transmit NACK */ LPI2C_Set_SlaveTransmitNACK(baseAddr, LPI2C_SLAVE_TRANSMIT_NACK); /* Disable all clock stretching in ultra-fast mode */ LPI2C_Set_SlaveACKStall(baseAddr, FALSE); LPI2C_Set_SlaveTXDStall(baseAddr, FALSE); LPI2C_Set_SlaveRXStall(baseAddr, FALSE); LPI2C_Set_SlaveAddrStall(baseAddr, FALSE); } #endif /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveConfigureNormalMode * Description : configures slave for normal operations * *END**************************************************************************/ static void Lpi2c_Ip_SlaveConfigureNormalMode(LPI2C_Type *baseAddr) { /* End transfer when NACK is received */ LPI2C_Set_SlaveIgnoreNACK(baseAddr, LPI2C_SLAVE_NACK_END_TRANSFER); /* Transmit ACK */ LPI2C_Set_SlaveTransmitNACK(baseAddr, LPI2C_SLAVE_TRANSMIT_ACK); /* Enable clock stretching except ACKSTALL (we don't need to send ACK/NACK manually) */ LPI2C_Set_SlaveACKStall(baseAddr, FALSE); LPI2C_Set_SlaveTXDStall(baseAddr, TRUE); LPI2C_Set_SlaveRXStall(baseAddr, TRUE); LPI2C_Set_SlaveAddrStall(baseAddr, TRUE); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveSetOperatingMode * Description : sets the operating mode of the I2C slave * *END**************************************************************************/ static void Lpi2c_Ip_SlaveSetOperatingMode(uint32 instance, Lpi2c_Ip_ModeType operatingMode) { LPI2C_Type *baseAddr; Lpi2c_Ip_SlaveStateType * slave; boolean bHighSpeedMode = FALSE; baseAddr = g_lpi2cBase[instance]; slave = g_lpi2cSlaveStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(slave != NULL_PTR); #endif #if(LPI2C_HAS_ULTRA_FAST_MODE) if (operatingMode == LPI2C_ULTRAFAST_MODE) { Lpi2c_Ip_SlaveConfigureUltraFastMode(baseAddr); } else #endif { Lpi2c_Ip_SlaveConfigureNormalMode(baseAddr); } if (operatingMode == LPI2C_HIGHSPEED_MODE) { /* Enable detection of high speed mode */ bHighSpeedMode = TRUE; } /* Enable/disable detection of the High-speed Mode master code */ LPI2C_Set_SlaveHighSpeedModeDetect(baseAddr, bHighSpeedMode); slave->operatingMode = operatingMode; } #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterCompleteDMATransfer * Description : Finish up a transfer DMA for master. The main purpose of * this function is to create a function compatible with DMA * callback type * *END**************************************************************************/ static void Lpi2c_Ip_MasterCompleteDMATransfer(uint32 u32Instance) { LPI2C_Type *baseAddr; Lpi2c_Ip_MasterStateType *master; baseAddr = g_lpi2cBase[u32Instance]; master = g_lpi2cMasterStatePtr[u32Instance]; if((master->bufferSize > 0U) && (LPI2C_IP_SEND == master->direction)) { master->bufferSize = 0U; LPI2C_Set_MasterTxFIFOWatermark(baseAddr, 0U); /* Disable transmit data DMA requests */ (void)LPI2C_Set_MasterTxDMA(baseAddr, FALSE); /* Activate transmit data events */ LPI2C_Set_MasterInt(baseAddr, (uint32)LPI2C_MASTER_TRANSMIT_DATA_INT, TRUE); } else { /* Signal transfer end for blocking transfers */ Lpi2c_Ip_MasterEndTransfer(baseAddr, master, master->sendStop, FALSE); master->status = STATUS_LPI2C_IP_SUCCESS; if (master->masterCallback != NULL_PTR) { master->masterCallback(I2C_MASTER_EVENT_END_TRANSFER, master->callbackParam); } } } #endif #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterConfigureTxDmaChannel * Description : configures the Tx dma channel * *END**************************************************************************/ static void Lpi2c_Ip_MasterConfigureTxDmaChannel(uint32 instance) { LPI2C_Type *baseAddr = g_lpi2cBase[instance]; const Lpi2c_Ip_MasterStateType *master = g_lpi2cMasterStatePtr[instance]; /* Configure watermarks for transmit DMA for master */ uint32 txBytes = LPI2C_Get_MasterTxFIFOSize(baseAddr); if (txBytes > master->bufferSize) { txBytes = master->bufferSize; } LPI2C_Set_MasterTxFIFOWatermark(baseAddr, (uint16)(txBytes - 1U)); /* Set source address and major loop transfer size */ dmaChannelTransferListSend[0u].Value = (uint32)(&(master->dataBuffer[0])); dmaChannelTransferListSend[3u].Value = (uint32)(&(baseAddr->MTDR)); dmaChannelTransferListSend[7u].Value = master->bufferSize; (void)Dma_Ip_SetLogicChannelTransferList(master->dmaTxChannel, dmaChannelTransferListSend, I2C_DMA_CHANNEL_CONFIG_LIST_SIZE_MASTER); /* Start DMA channel */ (void)Dma_Ip_SetLogicChannelCommand(master->dmaTxChannel, DMA_IP_CH_SET_HARDWARE_REQUEST); } #endif #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterConfigureRxDmaChannel * Description : configures the Rx dma channel * *END**************************************************************************/ static void Lpi2c_Ip_MasterConfigureRxDmaChannel(uint32 instance) { LPI2C_Type *baseAddr = g_lpi2cBase[instance]; const Lpi2c_Ip_MasterStateType *master = g_lpi2cMasterStatePtr[instance]; /* Configure watermarks for receive DMA for master */ LPI2C_Set_MasterRxFIFOWatermark(baseAddr, 0U); /* Set destination address and major loop transfer size */ dmaChannelTransferListReceive[0u].Value = (uint32) (&(baseAddr->MRDR)); dmaChannelTransferListReceive[3u].Value = (uint32)(&(master->dataBuffer[0])); dmaChannelTransferListReceive[7u].Value = master->bufferSize; (void)Dma_Ip_SetLogicChannelTransferList(master->dmaRxChannel, dmaChannelTransferListReceive, I2C_DMA_CHANNEL_CONFIG_LIST_SIZE_MASTER); /* Start DMA channel */ (void)Dma_Ip_SetLogicChannelCommand(master->dmaRxChannel, DMA_IP_CH_SET_HARDWARE_REQUEST); } #endif #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterStartDmaTransfer * Description : starts the DMA transfer for master * *END**************************************************************************/ static void Lpi2c_Ip_MasterStartDmaTransfer(uint32 instance) { LPI2C_Type *baseAddr = g_lpi2cBase[instance]; Lpi2c_Ip_MasterStateType *master = g_lpi2cMasterStatePtr[instance]; boolean receive = FALSE; if (LPI2C_IP_SEND == master->direction) { /* Configure dma TX channel */ Lpi2c_Ip_MasterConfigureTxDmaChannel(instance); } else { receive = TRUE; /* Configure dma RX channel */ Lpi2c_Ip_MasterConfigureRxDmaChannel(instance); } /* Send address */ Lpi2c_Ip_MasterSendAddress(baseAddr, master, receive); /* Enable transmit/receive DMA requests */ if (LPI2C_IP_SEND == master->direction) { (void)LPI2C_Set_MasterTxDMA(baseAddr, TRUE); } else { Lpi2c_Ip_MasterQueueCmd(baseAddr, master, LPI2C_MASTER_COMMAND_RECEIVE, (uint8)(master->bufferSize - 1U)); (void)LPI2C_Set_MasterRxDMA(baseAddr, TRUE); } } #endif #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveStartDmaTransfer * Description : starts the DMA transfer for slave * *END**************************************************************************/ static void Lpi2c_Ip_SlaveStartDmaTransfer(uint32 instance) { LPI2C_Type *baseAddr = g_lpi2cBase[instance]; const Lpi2c_Ip_SlaveStateType *slave = g_lpi2cSlaveStatePtr[instance]; if(LPI2C_IP_SEND == slave->direction) { /* Set source address and major loop transfer size */ dmaSlaveChTransferListSend[0u].Value = (uint32)(&(slave->dataBuffer[0])); dmaSlaveChTransferListSend[3u].Value = (uint32)(&(baseAddr->STDR)); dmaSlaveChTransferListSend[7u].Value = slave->bufferSize; dmaSlaveChTransferListSend[8u].Value = slave->bufferSize; (void)Dma_Ip_SetLogicChannelTransferList(slave->dmaTxChannel, dmaSlaveChTransferListSend, I2C_DMA_CHANNEL_CONFIG_LIST_SIZE_SLAVE); /* Start DMA channel */ (void)Dma_Ip_SetLogicChannelCommand(slave->dmaTxChannel, DMA_IP_CH_SET_HARDWARE_REQUEST); } else { /* Set destination address and major loop transfer size */ dmaSlaveChTransferListReceive[0u].Value = (uint32) (&(baseAddr->SRDR)); dmaSlaveChTransferListReceive[3u].Value = (uint32)(&(slave->dataBuffer[0])); dmaSlaveChTransferListReceive[7u].Value = slave->bufferSize; dmaSlaveChTransferListReceive[8u].Value = 0U; (void)Dma_Ip_SetLogicChannelTransferList(slave->dmaRxChannel, dmaSlaveChTransferListReceive, I2C_DMA_CHANNEL_CONFIG_LIST_SIZE_SLAVE); /* Start DMA channel */ (void)Dma_Ip_SetLogicChannelCommand(slave->dmaRxChannel, DMA_IP_CH_SET_HARDWARE_REQUEST); } /* Enable transmit/receive DMA requests */ if(LPI2C_IP_SEND == slave->direction) { (void)LPI2C_Set_SlaveTxDMA(baseAddr, TRUE); } else { (void)LPI2C_Set_SlaveRxDMA(baseAddr, TRUE); } } #endif /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterHandleTransmitDataRequest * Description : handle a transmit request for master * *END**************************************************************************/ static void Lpi2c_Ip_MasterHandleTransmitDataRequest(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType *master) { /* More data needed for transmission */ if (!Lpi2c_Ip_MasterCmdQueueEmpty(master)) { /* If there are queued commands, send them */ Lpi2c_Ip_MasterSendQueuedCmd(baseAddr, master); } else if ((master->dataBuffer != NULL_PTR) && (master->direction == LPI2C_IP_SEND)) { /* A transmission is in progress */ if (master->bufferSize == 0U) { /* There is no more data in buffer, the transmission is over */ Lpi2c_Ip_MasterEndTransfer(baseAddr, master, master->sendStop, FALSE); master->status = STATUS_LPI2C_IP_SUCCESS; if (master->masterCallback != NULL_PTR) { master->masterCallback(I2C_MASTER_EVENT_END_TRANSFER, master->callbackParam); } } else { /* Queue data bytes to fill tx fifo */ Lpi2c_Ip_MasterQueueData(baseAddr, master); } } else { /* No more commands and no transmission in progress - disable tx event */ LPI2C_Set_MasterInt(baseAddr, (uint32)LPI2C_MASTER_TRANSMIT_DATA_INT, FALSE); } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterHandleReceiveDataRequest * Description : handle a receive request for master * *END**************************************************************************/ static void Lpi2c_Ip_MasterHandleReceiveDataReadyEvent(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType *master) { /* Received data ready */ #if(STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master->dataBuffer != NULL_PTR); #endif /* Transfer received data to user buffer */ while ((LPI2C_Get_MasterRxFIFOCount(baseAddr) > 0U) && (master->bufferSize > 0U)) { master->dataBuffer[0U] = LPI2C_Get_MasterRxData(baseAddr); master->dataBuffer++; master->bufferSize--; } if (master->bufferSize == 0U) { /* Done receiving */ Lpi2c_Ip_MasterEndTransfer(baseAddr, master, master->sendStop, FALSE); master->status = STATUS_LPI2C_IP_SUCCESS; if (master->masterCallback != NULL_PTR) { master->masterCallback(I2C_MASTER_EVENT_END_TRANSFER, master->callbackParam); } } else if (master->bufferSize <= LPI2C_Get_MasterRxFIFOWatermark(baseAddr)) { /* Reduce rx watermark to receive the last few bytes */ LPI2C_Set_MasterRxFIFOWatermark(baseAddr, (uint16)(master->bufferSize - 1U)); } else { /* Continue reception */ } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveHandleAddressValidEvent * Description : handle an address valid event for slave * *END**************************************************************************/ static void Lpi2c_Ip_SlaveHandleAddressValidEvent(uint32 instance, const LPI2C_Type *baseAddr, Lpi2c_Ip_SlaveStateType *slave) { uint16 receivedAddr; receivedAddr = LPI2C_Get_SlaveReceivedAddr(baseAddr); if ((receivedAddr & 1U) != (uint16)0U) { /* Request from master to transmit data */ slave->direction = LPI2C_IP_SEND; if (slave->slaveCallback != NULL_PTR) { slave->slaveCallback(I2C_SLAVE_EVENT_TX_REQ, slave->callbackParam); } #if defined(ERRATA_E10792) if (slave->transferType == LPI2C_USING_INTERRUPTS) { /* Enable interrupt for transmitting data */ LPI2C_Set_SlaveInt(g_lpi2cBase[instance], (uint32)LPI2C_SLAVE_TRANSMIT_DATA_INT, TRUE); } #endif slave->txUnderrunWarning = FALSE; #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) if (slave->transferType == LPI2C_USING_DMA) { (void)Lpi2c_Ip_SlaveStartDmaTransfer(instance); } #endif } else { /* Request from master to receive data */ slave->direction = LPI2C_IP_RECEIVE; if (slave->slaveCallback != NULL_PTR) { slave->slaveCallback(I2C_SLAVE_EVENT_RX_REQ, slave->callbackParam); } #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) if (slave->transferType == LPI2C_USING_DMA) { (void)Lpi2c_Ip_SlaveStartDmaTransfer(instance); } #endif } (void) instance; slave->status = STATUS_LPI2C_IP_BUSY; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveHandleTransmitDataEvent * Description : handle a transmit data event for slave * *END**************************************************************************/ static void Lpi2c_Ip_SlaveHandleTransmitDataEvent(LPI2C_Type *baseAddr, Lpi2c_Ip_SlaveStateType *slave) { if (slave->txUnderrunWarning == TRUE) { /* Another Tx event after underflow warning means the dummy char was sent */ slave->status = STATUS_LPI2C_IP_TX_UNDERRUN; #if (STD_ON == LPI2C_IP_EVENT_ERROR_DETECT) if (slave->slaveCallback != NULL_PTR) { slave->slaveCallback(I2C_SLAVE_EVENT_UNDERRUN, slave->callbackParam); } #endif } if(slave->bufferSize == 0U) { /* Out of data, call callback to allow user to provide a new buffer */ if (slave->slaveCallback != NULL_PTR) { slave->slaveCallback(I2C_SLAVE_EVENT_TX_EMPTY, slave->callbackParam); } } if (slave->bufferSize == 0U) { /* * Still no data, record tx underflow event and send dummy char. * Special case after the last tx byte: the device will ask for more data * but the dummy char will not be sent if NACK and then STOP condition are * received from master. So only record a "warning" for now. */ slave->txUnderrunWarning = TRUE; LPI2C_Transmit_SlaveData(baseAddr, (uint8)0xFFU); } else { LPI2C_Transmit_SlaveData(baseAddr, slave->dataBuffer[0U]); slave->dataBuffer++; slave->bufferSize--; } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveHandleReceiveDataEvent * Description : handle a receive data event for slave * *END**************************************************************************/ static void Lpi2c_Ip_SlaveHandleReceiveDataEvent(const LPI2C_Type *baseAddr, Lpi2c_Ip_SlaveStateType *slave) { if (slave->bufferSize == 0U) { /* No more room for data, call callback to allow user to provide a new buffer */ if (slave->slaveCallback != NULL_PTR) { slave->slaveCallback(I2C_SLAVE_EVENT_RX_FULL, slave->callbackParam); } } if (slave->bufferSize == 0U) { /* Still no room for data, record rx overrun event and dummy read data */ slave->status = STATUS_LPI2C_IP_RX_OVERRUN; (void)LPI2C_Get_SlaveData(baseAddr); #if (STD_ON == LPI2C_IP_EVENT_ERROR_DETECT) if (slave->slaveCallback != NULL_PTR) { slave->slaveCallback(I2C_SLAVE_EVENT_OVERRUN, slave->callbackParam); } #endif } else { slave->dataBuffer[0U] = LPI2C_Get_SlaveData(baseAddr); slave->dataBuffer++; slave->bufferSize--; } } /*FUNCTION********************************************************************** * * Function Name : LPI2C_Get_MasterFIFOErrorEventHandler * Description : handles master fifo error * *END**************************************************************************/ static void LPI2C_Get_MasterFIFOErrorEventHandler(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType * master) { /* FIFO error */ LPI2C_Clear_MasterFIFOErrorEvent(baseAddr); if(master->operatingMode == LPI2C_HIGHSPEED_MODE) { /* High-speed transfers end at STOP condition */ master->highSpeedInProgress = FALSE; } master->status = STATUS_LPI2C_IP_ERROR; /* End transfer: no stop generation (the module will handle that by itself if needed), reset FIFOs */ Lpi2c_Ip_MasterEndTransfer(baseAddr, master, FALSE, TRUE); if (master->masterCallback != NULL_PTR) { #if (STD_ON == LPI2C_IP_EVENT_ERROR_DETECT) master->masterCallback(I2C_MASTER_EVENT_ERROR_FIFO, master->callbackParam); #else master->masterCallback(I2C_MASTER_EVENT_END_TRANSFER, master->callbackParam); #endif } } /*FUNCTION********************************************************************** * * Function Name : LPI2C_Get_MasterNACKDetectEventHandler * Description : handles master NACK detection event * *END**************************************************************************/ static void LPI2C_Get_MasterNACKDetectEventHandler(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType * master) { #if(LPI2C_HAS_ULTRA_FAST_MODE) /* Ignore NACK in Ultra Fast mode */ if (master->operatingMode != LPI2C_ULTRAFAST_MODE) { #endif /* High-speed transfers end at STOP condition */ master->highSpeedInProgress = FALSE; master->status = STATUS_LPI2C_IP_RECEIVED_NACK; /* End transfer: no stop generation (the module will handle that by itself if needed), reset FIFOs */ Lpi2c_Ip_MasterEndTransfer(baseAddr, master, FALSE, TRUE); if (master->masterCallback != NULL_PTR) { #if (STD_ON == LPI2C_IP_EVENT_ERROR_DETECT) master->masterCallback(I2C_MASTER_EVENT_NACK, master->callbackParam); #else master->masterCallback(I2C_MASTER_EVENT_END_TRANSFER, master->callbackParam); #endif } /* Clear NACK flag */ LPI2C_Clear_MasterNACKDetectEvent(baseAddr); #if(LPI2C_HAS_ULTRA_FAST_MODE) } #endif } /*FUNCTION********************************************************************** * * Function Name : LPI2C_Get_MasterArbitrationLostEventHandler * Description : handles master arbitration lost event * *END**************************************************************************/ static void LPI2C_Get_MasterArbitrationLostEventHandler(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType * master) { /* Arbitration lost */ LPI2C_Clear_MasterArbitrationLostEvent(baseAddr); /* End transfer: no stop generation (the module will handle that by itself if needed), reset FIFOs */ Lpi2c_Ip_MasterEndTransfer(baseAddr, master, FALSE, TRUE); master->status = STATUS_LPI2C_IP_ARBITRATION_LOST; if (master->masterCallback != NULL_PTR) { #if (STD_ON == LPI2C_IP_EVENT_ERROR_DETECT) master->masterCallback(I2C_MASTER_EVENT_ARBITRATION_LOST, master->callbackParam); #else master->masterCallback(I2C_MASTER_EVENT_END_TRANSFER, master->callbackParam); #endif } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterCheckErrorEvents * Description : checks error events for master module * *END**************************************************************************/ static void Lpi2c_Ip_MasterCheckErrorEvents(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType * master) { if (LPI2C_Get_MasterFIFOErrorEvent(baseAddr)) { /* Handle FIFO error event */ LPI2C_Get_MasterFIFOErrorEventHandler(baseAddr, master); } if (LPI2C_Get_MasterArbitrationLostEvent(baseAddr)) { /* Handle arbitration lost event */ LPI2C_Get_MasterArbitrationLostEventHandler(baseAddr, master); } if (LPI2C_Get_MasterNACKDetectEvent(baseAddr)) { /* Handle Received NACK */ LPI2C_Get_MasterNACKDetectEventHandler(baseAddr, master); } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterSend * Description : sync send transfer handler * *END**************************************************************************/ static void Lpi2c_Ip_MasterSend(uint32 instance) { LPI2C_Type *baseAddr; Lpi2c_Ip_MasterStateType * master; boolean masterCmdQueueEmpty = FALSE; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); #endif baseAddr = g_lpi2cBase[instance]; master = g_lpi2cMasterStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif /* Check which event caused the interrupt */ if (LPI2C_Get_MasterTransmitDataRequestEvent(baseAddr)) { /* More data needed for transmission */ if (!Lpi2c_Ip_MasterCmdQueueEmpty(master)) { /* If there are queued commands, send them */ Lpi2c_Ip_MasterSendQueuedCmd(baseAddr, master); } else { masterCmdQueueEmpty = TRUE; } } if(masterCmdQueueEmpty) { if (master->dataBuffer != NULL_PTR) { /* A transmission is in progress */ if (master->bufferSize == 0U) { /* There is no more data in buffer, the transmission is over */ Lpi2c_Ip_MasterEndTransfer(baseAddr, master, master->sendStop, FALSE); master->status = STATUS_LPI2C_IP_SUCCESS; if (master->masterCallback != NULL_PTR) { master->masterCallback(I2C_MASTER_EVENT_END_TRANSFER, master->callbackParam); } } else { /* Queue data bytes to fill tx fifo */ Lpi2c_Ip_MasterQueueData(baseAddr, master); } } else { /* else case */ } } /* Check error event */ Lpi2c_Ip_MasterCheckErrorEvents(baseAddr, master); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterGetReceivedData * Description : read data receive from RX FIFO * *END**************************************************************************/ static void Lpi2c_Ip_MasterGetReceivedData(const LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType * master) { /* Read data from RX FIFO */ while ((LPI2C_Get_MasterRxFIFOCount(baseAddr) > 0U) && (master->bufferSize > 0U)) { master->dataBuffer[0U] = LPI2C_Get_MasterRxData(baseAddr); master->dataBuffer++; master->bufferSize--; } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterReceive * Description : sync receive transfer handler * *END**************************************************************************/ static void Lpi2c_Ip_MasterReceive(uint32 instance) { LPI2C_Type *baseAddr; Lpi2c_Ip_MasterStateType * master; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); #endif baseAddr = g_lpi2cBase[instance]; master = g_lpi2cMasterStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif if ((LPI2C_Get_MasterReceiveDataReadyEvent(baseAddr))) { /* Read data from RX FIFO */ Lpi2c_Ip_MasterGetReceivedData(baseAddr, master); if (master->bufferSize == 0U) { /* Done receiving */ Lpi2c_Ip_MasterEndTransfer(baseAddr, master, master->sendStop, FALSE); master->status = STATUS_LPI2C_IP_SUCCESS; if (master->masterCallback != NULL_PTR) { master->masterCallback(I2C_MASTER_EVENT_END_TRANSFER, master->callbackParam); } } else if (master->bufferSize <= LPI2C_Get_MasterRxFIFOWatermark(baseAddr)) { LPI2C_Set_MasterRxFIFOWatermark(baseAddr, (uint16)(master->bufferSize - 1U)); } else { /* Continue reception */ } } /* Check error event */ Lpi2c_Ip_MasterCheckErrorEvents(baseAddr, master); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_BaudRateConfig * Description : configures MCCR0 register * *END**************************************************************************/ static void Lpi2c_Ip_BaudRateConfig(LPI2C_Type *baseAddr, const Lpi2c_Ip_BaudRateType * baudRate) { /* Set prescaler */ LPI2C_Set_MasterPrescaler(baseAddr, baudRate->prescaler); /* Set hold delay */ LPI2C_Set_MasterSetupHoldDelay(baseAddr, (uint8)baudRate->setHold); /* Set data valid delay */ LPI2C_Set_MasterDataValidDelay(baseAddr, (uint8)baudRate->dataValid); /* Set clock HIGH period */ LPI2C_Set_MasterClockHighPeriod(baseAddr, (uint8)baudRate->clkHI); /* Set clock low period */ LPI2C_Set_MasterClockLowPeriod(baseAddr, (uint8)baudRate->clkLO); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_HSBaudRateConfig * Description : configures MCCR1 register * *END**************************************************************************/ static void Lpi2c_Ip_HSBaudRateConfig(LPI2C_Type *baseAddr, const Lpi2c_Ip_BaudRateType * baudRate) { /* Set data valid delay */ LPI2C_Set_MasterDataValidDelayHS(baseAddr, (uint8)baudRate->setHoldHS); /* Set hold delay */ LPI2C_Set_MasterSetupHoldDelayHS(baseAddr, (uint8)baudRate->dataValidHS); /* Set clock HIGH period */ LPI2C_Set_MasterClockHighPeriodHS(baseAddr, (uint8)baudRate->clkHIHS); /* Set clock low period */ LPI2C_Set_MasterClockLowPeriodHS(baseAddr, (uint8)baudRate->clkLOHS); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterSetBaudRate * Description : set the baud rate for any subsequent I2C communication * * Implements : Lpi2c_Ip_MasterSetBaudRate_Activity *END**************************************************************************/ Lpi2c_Ip_StatusType Lpi2c_Ip_MasterSetBaudRate(uint32 instance, Lpi2c_Ip_ModeType operatingMode, uint32 baudrate, uint32 inputClock) { LPI2C_Type *baseAddr; const Lpi2c_Ip_MasterStateType * master; Lpi2c_Ip_BaudRateType baudRateParams; uint32 minPrescaler = 0U; uint32 prescaler; uint32 clkTotal; uint32 clkLo; uint32 clkHi; uint32 setHold; uint32 dataVd; Lpi2c_Ip_StatusType retStatus = STATUS_LPI2C_IP_BUSY; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); #endif baseAddr = g_lpi2cBase[instance]; master = g_lpi2cMasterStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif /* Check if driver is busy */ if(master->i2cIdle) { /* Disable master */ LPI2C_Set_MasterEnable(baseAddr, FALSE); /* Ignoring the glitch filter, the baud rate formula is: SCL_freq = Input_freq / (2^PRESCALER * (CLKLO + CLKHI + 2)) Assume CLKLO = CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2 */ if (baudrate != 0U) { /* Compute minimum prescaler for which CLKLO and CLKHI values are in valid range. Always round up. */ minPrescaler = ((inputClock - 1U) / ((baudrate) * (CLKHI_MAX_VALUE + CLKLO_MAX_VALUE + 2U))) + (uint32)1U; for (prescaler = 0U; prescaler < 7U; prescaler++) { if (((uint32)1U << prescaler) >= minPrescaler) { break; } } /* Compute CLKLO and CLKHI values for this prescaler. Round to nearest integer. */ clkTotal = (inputClock + ((baudrate << prescaler) >> 1U)) / (baudrate << prescaler); } else { prescaler = 7U; clkTotal = (CLKHI_MAX_VALUE + CLKLO_MAX_VALUE + 2U); } if (clkTotal > (CLKHI_MAX_VALUE + CLKLO_MAX_VALUE + 2U)) { clkTotal = (CLKHI_MAX_VALUE + CLKLO_MAX_VALUE + 2U); } /* * If we try to compute clk high and low values using clkTotal equal with 0 * (this is the case when the baudrate is 0), we will get negative values for * them, so we set them to 0 for this case. */ if (clkTotal <= 1U) { clkHi = 0U; clkLo = 0U; } else { clkHi = (clkTotal - 2U) / 2U; clkLo = clkTotal - 2U - clkHi; } if (clkHi < CLKHI_MIN_VALUE) { clkHi = CLKHI_MIN_VALUE; } if (clkLo < CLKLO_MIN_VALUE) { clkLo = CLKLO_MIN_VALUE; } /* Compute DATAVD and SETHOLD */ setHold = clkHi; dataVd = clkHi >> 1U; if (setHold < SETHOLD_MIN_VALUE) { setHold = SETHOLD_MIN_VALUE; } if (dataVd < DATAVD_MIN_VALUE) { dataVd = DATAVD_MIN_VALUE; } /* Init baud rate params */ baudRateParams.prescaler = (Lpi2c_Ip_MasterPrescalerType) prescaler; baudRateParams.dataValid = dataVd; baudRateParams.setHold = setHold; baudRateParams.clkHI = clkHi; baudRateParams.clkLO = clkLo; /* Apply settings */ Lpi2c_Ip_BaudRateConfig(baseAddr, &baudRateParams); /* Perform other settings related to the chosen operating mode */ Lpi2c_Ip_MasterSetOperatingMode(instance, operatingMode); /* Re-enable master */ LPI2C_Set_MasterEnable(baseAddr, TRUE); retStatus = STATUS_LPI2C_IP_SUCCESS; } (void) minPrescaler; (void)master; return retStatus; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterSetBaudRateInit * Description : set the baud rate for any subsequent I2C communication * * Implements : Lpi2c_Ip_MasterSetBaudRateInit_Activity *END**************************************************************************/ static Lpi2c_Ip_StatusType Lpi2c_Ip_MasterSetBaudRateInit(uint32 instance, const Lpi2c_Ip_ModeType operatingMode, const Lpi2c_Ip_BaudRateType * baudRate) { LPI2C_Type *baseAddr; const Lpi2c_Ip_MasterStateType *master; Lpi2c_Ip_StatusType retStatus = STATUS_LPI2C_IP_BUSY; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); #endif master = g_lpi2cMasterStatePtr[instance]; baseAddr = g_lpi2cBase[instance]; /* Check if driver is busy */ if(master->i2cIdle) { /* Disable master */ LPI2C_Set_MasterEnable(baseAddr, FALSE); /* Apply settings */ Lpi2c_Ip_BaudRateConfig(baseAddr, baudRate); /* Apply High-speed settings */ Lpi2c_Ip_HSBaudRateConfig(baseAddr, baudRate); /* Perform other settings related to the chosen operating mode */ Lpi2c_Ip_MasterSetOperatingMode(instance, operatingMode); /* Re-enable master */ LPI2C_Set_MasterEnable(baseAddr, TRUE); retStatus = STATUS_LPI2C_IP_SUCCESS; } return retStatus; } #if (STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) /*FUNCTION********************************************************************** * * Function Name : I2c_Ip_SlaveCmdDmaTcdInit * Description : This function configures the TCD for I2C DMA transfers * *END**************************************************************************/ static void Lpi2c_Ip_SlaveCmdDmaTcdInit(void) { /* Configure DMA channel for send transfers */ /* Source configuration parameters */ dmaSlaveChTransferListSend[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS; dmaSlaveChTransferListSend[1u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET; dmaSlaveChTransferListSend[2u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE; /* Destination configuration parameters */ dmaSlaveChTransferListSend[3u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS; dmaSlaveChTransferListSend[4u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET; dmaSlaveChTransferListSend[5u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE; /* Minor/Major Loop parameters */ dmaSlaveChTransferListSend[6u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE; dmaSlaveChTransferListSend[7u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT; /* Adjustment added to source address at the beginning of TX buffer */ dmaSlaveChTransferListSend[8u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_LAST_ADDR_ADJ; /* Source configuration values */ dmaSlaveChTransferListSend[1u].Value = 1U; dmaSlaveChTransferListSend[2u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* Destination configuration values */ dmaSlaveChTransferListSend[4u].Value = 0U; dmaSlaveChTransferListSend[5u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* Minor/Major Loop values */ dmaSlaveChTransferListSend[6u].Value = 1U; /* Configure DMA channel for receive transfers*/ /* Source configuration parameters */ dmaSlaveChTransferListReceive[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS; dmaSlaveChTransferListReceive[1u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET; dmaSlaveChTransferListReceive[2u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE; /* Destination configuration parameters */ dmaSlaveChTransferListReceive[3u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS; dmaSlaveChTransferListReceive[4u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET; dmaSlaveChTransferListReceive[5u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE; /* Minor/Major Loop parameters */ dmaSlaveChTransferListReceive[6u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE; dmaSlaveChTransferListReceive[7u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT; /* Adjustment added to source address at the beginning of TX buffer */ dmaSlaveChTransferListReceive[8u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_LAST_ADDR_ADJ; /* Source configuration values */ dmaSlaveChTransferListReceive[1u].Value = 0U; dmaSlaveChTransferListReceive[2u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* Destination configuration values */ dmaSlaveChTransferListReceive[4u].Value = 1U; dmaSlaveChTransferListReceive[5u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* Minor/Major Loop values */ dmaSlaveChTransferListReceive[6u].Value = 1U; } #endif /* STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE */ #if (STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) /*FUNCTION********************************************************************** * * Function Name : I2c_Ip_CmdDmaTcdInit * Description : This function configures the TCD for I2C DMA transfers * *END**************************************************************************/ static void Lpi2c_Ip_MasterCmdDmaTcdInit(void) { /* Configure DMA channel for send transfers */ /* Source configuration parameters */ dmaChannelTransferListSend[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS; dmaChannelTransferListSend[1u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET; dmaChannelTransferListSend[2u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE; /* Destination configuration parameters */ dmaChannelTransferListSend[3u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS; dmaChannelTransferListSend[4u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET; dmaChannelTransferListSend[5u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE; /* Minor/Major Loop parameters */ dmaChannelTransferListSend[6u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE; dmaChannelTransferListSend[7u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT; /* Disable Hw auto request and enable interrupts */ dmaChannelTransferListSend[8u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST; dmaChannelTransferListSend[9u].Param = DMA_IP_CH_SET_CONTROL_EN_MAJOR_INTERRUPT; /* Source configuration values */ dmaChannelTransferListSend[1u].Value = 1U; dmaChannelTransferListSend[2u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* Destination configuration values */ dmaChannelTransferListSend[4u].Value = 0U; dmaChannelTransferListSend[5u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* Minor/Major Loop values */ dmaChannelTransferListSend[6u].Value = 1U; /* Disable Hw auto request and enable interrupts */ dmaChannelTransferListSend[8u].Value = 1U; dmaChannelTransferListSend[9u].Value = 1U; /* Configure DMA channel for receive transfers*/ /* Source configuration parameters */ dmaChannelTransferListReceive[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS; dmaChannelTransferListReceive[1u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET; dmaChannelTransferListReceive[2u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE; /* Destination configuration parameters */ dmaChannelTransferListReceive[3u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS; dmaChannelTransferListReceive[4u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET; dmaChannelTransferListReceive[5u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE; /* Minor/Major Loop parameters */ dmaChannelTransferListReceive[6u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE; dmaChannelTransferListReceive[7u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT; /* Disable Hw auto request and enable interrupts */ dmaChannelTransferListReceive[8u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST; dmaChannelTransferListReceive[9u].Param = DMA_IP_CH_SET_CONTROL_EN_MAJOR_INTERRUPT; /* Source configuration values */ dmaChannelTransferListReceive[1u].Value = 0U; dmaChannelTransferListReceive[2u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* Destination configuration values */ dmaChannelTransferListReceive[4u].Value = 1U; dmaChannelTransferListReceive[5u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* Minor/Major Loop values */ dmaChannelTransferListReceive[6u].Value = 1U; /* Disable Hw auto request and enable interrupts */ dmaChannelTransferListReceive[8u].Value = 1U; dmaChannelTransferListReceive[9u].Value = 1U; } #endif /* STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE */ /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterInitModule * Description : resets software queue and resets master FIFOs *END**************************************************************************/ static void Lpi2c_Ip_MasterInitModule(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType * master) { /* Reset software queue */ Lpi2c_Ip_MasterResetQueue(master); /* Initialize module */ LPI2C_Init(baseAddr); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterConfigFeatures * Description : configures glitch filter for SDA and SCL, bus idle and pin low timeout *END**************************************************************************/ static void Lpi2c_Ip_MasterConfigFeatures(LPI2C_Type *baseAddr, const Lpi2c_Ip_MasterConfigType * userConfigPtr) { /* Set glitch filters for SDA and SCL */ LPI2C_Set_MasterGlitchFilterSDA(baseAddr, userConfigPtr->u32GlitchFilterSDA); LPI2C_Set_MasterGlitchFilterSCL(baseAddr, userConfigPtr->u32GlitchFilterSCL); /* Set bus idle timeout */ LPI2C_Set_MasterBusIdleTimeout(baseAddr, userConfigPtr->u32BusIdleTimeout); /* Configure pin low timeout for both SDA and SCL */ LPI2C_Set_MasterPinLowTimeoutConfiguration(baseAddr, TRUE); /* Configure Pin Low Timeout */ LPI2C_Set_MasterPinLowTimeout(baseAddr, userConfigPtr->u32PinLowTimeout); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterInit * Description : initialize the I2C master mode driver * * Implements : Lpi2c_Ip_MasterInit_Activity *END**************************************************************************/ Lpi2c_Ip_StatusType Lpi2c_Ip_MasterInit(uint32 instance, const Lpi2c_Ip_MasterConfigType * userConfigPtr) { LPI2C_Type *baseAddr; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(userConfigPtr != NULL_PTR); DevAssert(instance < LPI2C_INSTANCE_COUNT); /* Check to see if the LPI2C master instance is already initialized */ DevAssert(g_lpi2cMasterStatePtr[instance] == NULL_PTR); #endif baseAddr = g_lpi2cBase[instance]; g_lpi2cMasterStatePtr[instance] = userConfigPtr->masterState; Lpi2c_Ip_MasterStateType * master = g_lpi2cMasterStatePtr[instance]; /* Initialize driver status structure */ master->direction = LPI2C_IP_SEND; master->dataBuffer = NULL_PTR; master->bufferSize = 0U; master->status = STATUS_LPI2C_IP_SUCCESS; master->i2cIdle = TRUE; master->slaveAddress = userConfigPtr->slaveAddress; master->is10bitAddr = userConfigPtr->is10bitAddr; master->transferType = userConfigPtr->transferType; /* Store DMA channel number used in transfer */ master->dmaTxChannel = userConfigPtr->dmaTxChannel; master->dmaRxChannel = userConfigPtr->dmaRxChannel; master->masterCallback = userConfigPtr->masterCallback; master->callbackParam = userConfigPtr->callbackParam; master->masterCode = userConfigPtr->masterCode; master->highSpeedInProgress = FALSE; master->baudrateParams = userConfigPtr->baudrateParams; /* Init/enable master module */ Lpi2c_Ip_MasterInitModule(baseAddr, master); #if (STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) if(master->transferType == LPI2C_USING_DMA) { Lpi2c_Ip_MasterCmdDmaTcdInit(); } #endif /* STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE */ /* Configure glitch filter, bus idle and pin low timeout */ Lpi2c_Ip_MasterConfigFeatures(baseAddr, userConfigPtr); /* Set baud rate */ (void)Lpi2c_Ip_MasterSetBaudRateInit(instance, userConfigPtr->operatingMode, master->baudrateParams); /* Set slave address */ Lpi2c_Ip_MasterSetSlaveAddr(instance, userConfigPtr->slaveAddress, userConfigPtr->is10bitAddr); /* Enable LPI2C master */ LPI2C_Set_MasterEnable(baseAddr, TRUE); return STATUS_LPI2C_IP_SUCCESS; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterDeinit * Description : deinitialize the I2C master mode driver * * Implements : Lpi2c_Ip_MasterDeinit_Activity *END**************************************************************************/ Lpi2c_Ip_StatusType Lpi2c_Ip_MasterDeinit(uint32 instance) { LPI2C_Type *baseAddr; const Lpi2c_Ip_MasterStateType *master; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); #endif baseAddr = g_lpi2cBase[instance]; master = g_lpi2cMasterStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif g_lpi2cMasterStatePtr[instance] = NULL_PTR; /* Disable master */ LPI2C_Set_MasterEnable(baseAddr, FALSE); (void) master; return STATUS_LPI2C_IP_SUCCESS; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterGetBaudRate * Description : returns the currently configured baud rate * * Implements : Lpi2c_Ip_MasterGetBaudRate_Activity *END**************************************************************************/ void Lpi2c_Ip_MasterGetBaudRate(uint32 instance, uint32 inputClock, uint32 *baudRate) { const LPI2C_Type *baseAddr; const Lpi2c_Ip_MasterStateType *master; uint32 prescaler; uint32 clkLo; uint32 clkHi; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); #endif baseAddr = g_lpi2cBase[instance]; master = g_lpi2cMasterStatePtr[instance]; /* Ignoring the glitch filter, the baud rate formula is: SCL_freq = Input_freq / (2^PRESCALER * (CLKLO + CLKHI + 2)) */ prescaler = (uint32)LPI2C_Get_MasterPrescaler(baseAddr); clkHi = (uint32)LPI2C_Get_MasterClockHighPeriod(baseAddr); clkLo = (uint32)LPI2C_Get_MasterClockLowPeriod(baseAddr); *baudRate = inputClock / (((uint32)1U << prescaler) * (clkLo + clkHi + (uint32)2U)); if (master->operatingMode == LPI2C_HIGHSPEED_MODE) { clkHi = LPI2C_Get_MasterClockHighPeriodHS(baseAddr); clkLo = LPI2C_Get_MasterClockLowPeriodHS(baseAddr); *baudRate = inputClock / (((uint32)1U << prescaler) * (clkLo + clkHi + (uint32)2U)); } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterSetSlaveAddr * Description : set the slave address for any subsequent I2C communication * * Implements : Lpi2c_Ip_MasterSetSlaveAddr_Activity *END**************************************************************************/ void Lpi2c_Ip_MasterSetSlaveAddr(uint32 instance, const uint16 address, const boolean is10bitAddr) { Lpi2c_Ip_MasterStateType * master; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); #endif master = g_lpi2cMasterStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif master->slaveAddress = address; master->is10bitAddr = is10bitAddr; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterSendData * Description : perform a non-blocking send transaction on the I2C bus * * Implements : Lpi2c_Ip_MasterSendData_Activity *END**************************************************************************/ Lpi2c_Ip_StatusType Lpi2c_Ip_MasterSendData(uint32 instance, uint8 * txBuff, uint32 txSize, boolean sendStop) { LPI2C_Type *baseAddr; Lpi2c_Ip_MasterStateType *master; Lpi2c_Ip_StatusType retStatus = STATUS_LPI2C_IP_BUSY; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); DevAssert(txBuff != NULL_PTR); DevAssert(txSize > 0U); #endif baseAddr = g_lpi2cBase[instance]; master = g_lpi2cMasterStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif /* Check if driver is busy */ if(master->i2cIdle) { /* Copy parameters to driver state structure */ master->bufferSize = txSize; master->dataBuffer = txBuff; master->direction = LPI2C_IP_SEND; master->sendStop = sendStop; master->i2cIdle = FALSE; master->status = STATUS_LPI2C_IP_BUSY; #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) if (master->transferType == LPI2C_USING_DMA) { LPI2C_Set_MasterInt(baseAddr, LPI2C_MASTER_FIFO_ERROR_INT | LPI2C_MASTER_ARBITRATION_LOST_INT | LPI2C_MASTER_NACK_DETECT_INT, TRUE); Lpi2c_Ip_MasterStartDmaTransfer(instance); } else { #endif /* Initiate communication */ Lpi2c_Ip_MasterSendAddress(baseAddr, master, FALSE); /* Queue data bytes to fill tx fifo */ Lpi2c_Ip_MasterQueueData(baseAddr, master); /* Set tx FIFO watermark */ LPI2C_Set_MasterTxFIFOWatermark(baseAddr, 0U); /* Enable relevant events */ #if(LPI2C_HAS_ULTRA_FAST_MODE) if (master->operatingMode == LPI2C_ULTRA_FAST_MODE) { /* Do not enable NACK event reporting in ultra-fast mode */ LPI2C_Set_MasterInt(baseAddr, LPI2C_MASTER_FIFO_ERROR_INT | LPI2C_MASTER_ARBITRATION_LOST_INT | LPI2C_MASTER_TRANSMIT_DATA_INT, TRUE); } else #endif { LPI2C_Set_MasterInt(baseAddr, LPI2C_MASTER_FIFO_ERROR_INT | LPI2C_MASTER_ARBITRATION_LOST_INT | LPI2C_MASTER_NACK_DETECT_INT | LPI2C_MASTER_PIN_LOW_TIMEOUT_INT | LPI2C_MASTER_TRANSMIT_DATA_INT, TRUE); } #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) } #endif retStatus = STATUS_LPI2C_IP_SUCCESS; } return retStatus; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterInitSendTransfer * Description : initializes send transfer *END**************************************************************************/ static void Lpi2c_Ip_MasterInitSendTransfer(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType *master) { /* Initiate communication */ Lpi2c_Ip_MasterSendAddress(baseAddr, master, FALSE); /* Queue data bytes to fill tx fifo */ Lpi2c_Ip_MasterQueueData(baseAddr, master); /* Set tx FIFO watermark */ LPI2C_Set_MasterTxFIFOWatermark(baseAddr, 0U); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterSendDataBlocking * Description : perform a blocking send transaction on the I2C bus * * Implements : Lpi2c_Ip_MasterSendDataBlocking_Activity *END**************************************************************************/ Lpi2c_Ip_StatusType Lpi2c_Ip_MasterSendDataBlocking(uint32 instance, uint8 * txBuff, uint32 txSize, boolean sendStop, uint32 timeout) { uint32 CurrentTicks = 0u; uint32 ElapsedTicks = 0u; uint32 TimeoutTicks = OsIf_MicrosToTicks(timeout, I2C_TIMEOUT_TYPE); Lpi2c_Ip_StatusType retStatus = STATUS_LPI2C_IP_BUSY; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); DevAssert(txBuff != NULL_PTR); DevAssert(txSize > 0U); #endif LPI2C_Type *baseAddr; baseAddr = g_lpi2cBase[instance]; Lpi2c_Ip_MasterStateType *master = g_lpi2cMasterStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif /* Check if driver is busy */ if(master->i2cIdle) { master->bufferSize = txSize; master->dataBuffer = txBuff; master->direction = LPI2C_IP_SEND; master->sendStop = sendStop; master->i2cIdle = FALSE; master->status = STATUS_LPI2C_IP_BUSY; /* Initiate send transfer */ Lpi2c_Ip_MasterInitSendTransfer(baseAddr, master); /* Get current ticks */ CurrentTicks = OsIf_GetCounter(I2C_TIMEOUT_TYPE); do { /* Master send data */ Lpi2c_Ip_MasterSend(instance); ElapsedTicks += OsIf_GetElapsed(&CurrentTicks, I2C_TIMEOUT_TYPE); }while((Lpi2c_Ip_MasterGetTransferStatus(instance, NULL_PTR) == STATUS_LPI2C_IP_BUSY) && (ElapsedTicks < TimeoutTicks)); /* Check timeout */ if(ElapsedTicks >= TimeoutTicks) { master->status = STATUS_LPI2C_IP_TIMEOUT; } retStatus = master->status; } return retStatus; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterInterruptReceiveInit * Description : configures interrupt receive transfer *END**************************************************************************/ static void Lpi2c_Ip_MasterInterruptReceiveInit(uint32 instance, uint32 rxSize) { LPI2C_Type *baseAddr = g_lpi2cBase[instance]; Lpi2c_Ip_MasterStateType *master = g_lpi2cMasterStatePtr[instance]; uint16 rxBytes; /* Send Address */ Lpi2c_Ip_MasterSendAddress(baseAddr, master, TRUE); /* Queue receive command for rxSize bytes */ Lpi2c_Ip_MasterQueueCmd(baseAddr, master, LPI2C_MASTER_COMMAND_RECEIVE, (uint8)(rxSize - 1U)); /* Set rx FIFO watermark */ rxBytes = LPI2C_Get_MasterRxFIFOSize(baseAddr); if (rxBytes > rxSize) { rxBytes = (uint8)rxSize; } /* Set RX watermark */ LPI2C_Set_MasterRxFIFOWatermark(baseAddr, (uint16)(rxBytes - 1U)); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterReceiveData * Description : perform a non-blocking receive transaction on the I2C bus * * Implements : Lpi2c_Ip_MasterReceiveData_Activity *END**************************************************************************/ Lpi2c_Ip_StatusType Lpi2c_Ip_MasterReceiveData(uint32 instance, uint8 * rxBuff, uint32 rxSize, boolean sendStop) { LPI2C_Type *baseAddr; Lpi2c_Ip_MasterStateType * master; Lpi2c_Ip_StatusType retStatus = STATUS_LPI2C_IP_BUSY; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); DevAssert(rxBuff != NULL_PTR); DevAssert(rxSize > 0U); DevAssert(rxSize <= 256U); #endif baseAddr = g_lpi2cBase[instance]; master = g_lpi2cMasterStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif /* Check if driver is busy */ if(!master->i2cIdle) { retStatus = STATUS_LPI2C_IP_BUSY; } else { #if(LPI2C_HAS_ULTRA_FAST_MODE) if (master->operatingMode == LPI2C_ULTRAFAST_MODE) { /* No reception possible in ultra-fast mode */ retStatus = STATUS_LPI2C_IP_ERROR; } else { #endif retStatus = STATUS_LPI2C_IP_SUCCESS; /* Copy parameters to driver state structure */ master->bufferSize = rxSize; master->i2cIdle = FALSE; master->sendStop = sendStop; master->dataBuffer = rxBuff; master->direction = LPI2C_IP_RECEIVE; master->status = STATUS_LPI2C_IP_BUSY; #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) if (master->transferType == LPI2C_USING_DMA) { LPI2C_Set_MasterInt(baseAddr, LPI2C_MASTER_FIFO_ERROR_INT | LPI2C_MASTER_ARBITRATION_LOST_INT | LPI2C_MASTER_NACK_DETECT_INT, TRUE); Lpi2c_Ip_MasterStartDmaTransfer(instance); } else { #endif /* Init interrupt receive transfer */ Lpi2c_Ip_MasterInterruptReceiveInit(instance, rxSize); /* Enable relevant events */ if (!Lpi2c_Ip_MasterCmdQueueEmpty(master)) { /* Enable tx event too if there are commands in the software FIFO */ LPI2C_Set_MasterInt(baseAddr, LPI2C_MASTER_FIFO_ERROR_INT | LPI2C_MASTER_ARBITRATION_LOST_INT | LPI2C_MASTER_NACK_DETECT_INT | LPI2C_MASTER_TRANSMIT_DATA_INT | LPI2C_MASTER_RECEIVE_DATA_INT, TRUE); } else { LPI2C_Set_MasterInt(baseAddr, LPI2C_MASTER_FIFO_ERROR_INT | LPI2C_MASTER_ARBITRATION_LOST_INT | LPI2C_MASTER_NACK_DETECT_INT | LPI2C_MASTER_RECEIVE_DATA_INT, TRUE); } #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) } #endif #if(LPI2C_HAS_ULTRA_FAST_MODE) } #endif } return retStatus; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterReceiveDataBlocking * Description : perform a blocking receive transaction on the I2C bus * * Implements : Lpi2c_Ip_MasterReceiveDataBlocking_Activity *END**************************************************************************/ Lpi2c_Ip_StatusType Lpi2c_Ip_MasterReceiveDataBlocking(uint32 instance, uint8 * rxBuff, uint32 rxSize, boolean sendStop, uint32 timeout) { Lpi2c_Ip_MasterStateType * master; uint32 CurrentTicks = 0u; uint32 ElapsedTicks = 0u; uint32 TimeoutTicks = OsIf_MicrosToTicks(timeout, I2C_TIMEOUT_TYPE); Lpi2c_Ip_StatusType retStatus = STATUS_LPI2C_IP_BUSY; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); DevAssert(rxBuff != NULL_PTR); DevAssert(rxSize > 0U); DevAssert(rxSize <= 256U); #endif master = g_lpi2cMasterStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif /* Check if driver is busy */ if(master->i2cIdle) { master->bufferSize = rxSize; master->dataBuffer = rxBuff; master->direction = LPI2C_IP_RECEIVE; master->sendStop = sendStop; master->i2cIdle = FALSE; master->status = STATUS_LPI2C_IP_BUSY; /* Initiate communication */ Lpi2c_Ip_MasterInterruptReceiveInit(instance, rxSize); CurrentTicks = OsIf_GetCounter(I2C_TIMEOUT_TYPE); do { /* Master send data */ Lpi2c_Ip_MasterReceive(instance); ElapsedTicks += OsIf_GetElapsed(&CurrentTicks, I2C_TIMEOUT_TYPE); }while((Lpi2c_Ip_MasterGetTransferStatus(instance, NULL_PTR) == STATUS_LPI2C_IP_BUSY) && (ElapsedTicks < TimeoutTicks)); if(ElapsedTicks >= TimeoutTicks) { master->status = STATUS_LPI2C_IP_TIMEOUT; } retStatus = master->status; } return retStatus; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterGetTransferStatus * Description : return the current status of the I2C master transfer * * When performing an a-sync (non-blocking) transfer, the user can call this function * to ascertain the state of the current transfer. In addition, if the transfer is still * in progress, the user can get the number of words that should be receive. * * Implements : Lpi2c_Ip_MasterGetTransferStatus_Activity *END**************************************************************************/ Lpi2c_Ip_StatusType Lpi2c_Ip_MasterGetTransferStatus(uint32 instance, uint32 *bytesRemaining) { const Lpi2c_Ip_MasterStateType * master; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); #endif master = g_lpi2cMasterStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif if ((bytesRemaining != NULL_PTR) && (master->transferType == LPI2C_USING_INTERRUPTS)) { *bytesRemaining = master->bufferSize; } return master->status; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterCheckDataTxRxEvent * Description : checks if data send or data receive event occurred * *END**************************************************************************/ static void Lpi2c_Ip_MasterCheckDataTxRxEvent(LPI2C_Type *baseAddr, Lpi2c_Ip_MasterStateType * master) { if (LPI2C_Get_MasterTransmitDataRequestEvent(baseAddr)) { /* Send data event */ Lpi2c_Ip_MasterHandleTransmitDataRequest(baseAddr, master); } if ((LPI2C_Get_MasterReceiveDataReadyEvent(baseAddr))) { /* Receive data event */ Lpi2c_Ip_MasterHandleReceiveDataReadyEvent(baseAddr, master); } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_MasterIRQHandler * Description : handle non-blocking master operation when I2C interrupt occurs * *END**************************************************************************/ void Lpi2c_Ip_MasterIRQHandler(uint32 instance) { LPI2C_Type *baseAddr; Lpi2c_Ip_MasterStateType * master; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); #endif baseAddr = g_lpi2cBase[instance]; master = g_lpi2cMasterStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif /* Check which event caused the interrupt */ Lpi2c_Ip_MasterCheckDataTxRxEvent(baseAddr, master); /* Master check error events */ Lpi2c_Ip_MasterCheckErrorEvents(baseAddr, master); /* Check Pin Timeout Flag */ if(LPI2C_Get_MasterPinLowTimeoutEvent(baseAddr)) { if (master->masterCallback != NULL_PTR) { master->masterCallback(I2C_MASTER_EVENT_PIN_LOW_TIMEOUT, master->callbackParam); } /* Clear pin low timeout flag */ LPI2C_Clear_MasterPinLowTimeoutEvent(baseAddr); } } static void Lpi2c_Ip_SlaveActivateEvents(uint32 instance) { LPI2C_Type *baseAddr; baseAddr = g_lpi2cBase[instance]; const Lpi2c_Ip_SlaveStateType *slave = g_lpi2cSlaveStatePtr[instance]; if (slave->transferType == LPI2C_USING_DMA) { /* Activate events */ LPI2C_Set_SlaveInt(baseAddr, LPI2C_SLAVE_BIT_ERROR_INT | LPI2C_SLAVE_FIFO_ERROR_INT | LPI2C_SLAVE_STOP_DETECT_INT | LPI2C_SLAVE_REPEATED_START_INT | LPI2C_SLAVE_ADDRESS_VALID_INT, TRUE); } if (slave->transferType == LPI2C_USING_INTERRUPTS) { /* Activate events */ #if defined(ERRATA_E10792) LPI2C_Set_SlaveInt(baseAddr, LPI2C_SLAVE_BIT_ERROR_INT | LPI2C_SLAVE_FIFO_ERROR_INT | LPI2C_SLAVE_STOP_DETECT_INT | LPI2C_SLAVE_REPEATED_START_INT | LPI2C_SLAVE_ADDRESS_VALID_INT | LPI2C_SLAVE_RECEIVE_DATA_INT, TRUE); #else LPI2C_Set_SlaveInt(baseAddr, LPI2C_SLAVE_BIT_ERROR_INT | LPI2C_SLAVE_FIFO_ERROR_INT | LPI2C_SLAVE_STOP_DETECT_INT | LPI2C_SLAVE_REPEATED_START_INT | LPI2C_SLAVE_ADDRESS_VALID_INT | LPI2C_SLAVE_RECEIVE_DATA_INT | LPI2C_SLAVE_TRANSMIT_DATA_INT, TRUE); #endif } /* Enable LPI2C slave */ LPI2C_Set_SlaveEnable(baseAddr, TRUE); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveConigureAddress * Description : configures slave address *END**************************************************************************/ static void Lpi2c_Ip_SlaveConigureAddress(LPI2C_Type *baseAddr, uint16 slaveAddr, boolean is10bitAddr) { LPI2C_Set_SlaveAddr0(baseAddr, slaveAddr); if (is10bitAddr) { LPI2C_Set_SlaveAddrConfig(baseAddr, LPI2C_SLAVE_ADDR_MATCH_0_10BIT); } else { LPI2C_Set_SlaveAddrConfig(baseAddr, LPI2C_SLAVE_ADDR_MATCH_0_7BIT); } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveConfigureGlitchFilter * Description : configures slave glitch filter *END**************************************************************************/ static void Lpi2c_Ip_SlaveConfigureGlitchFilter(LPI2C_Type *baseAddr, uint32 u32GlitchFilterSDA, uint32 u32GlitchFilterSCL) { /* Set SDA glitch filter */ LPI2C_Set_SlaveGlitchFilterSDA(baseAddr, u32GlitchFilterSDA); /* Set SCL glitch filter */ LPI2C_Set_SlaveGlitchFilterSCL(baseAddr, u32GlitchFilterSCL); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveInit * Description : initialize the I2C slave mode driver * * Implements : Lpi2c_Ip_SlaveInit_Activity *END**************************************************************************/ Lpi2c_Ip_StatusType Lpi2c_Ip_SlaveInit(uint32 instance, const Lpi2c_Ip_SlaveConfigType * userConfigPtr) { LPI2C_Type *baseAddr; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(userConfigPtr != NULL_PTR); DevAssert(instance < LPI2C_INSTANCE_COUNT); DevAssert(g_lpi2cSlaveStatePtr[instance] == NULL_PTR); #endif baseAddr = g_lpi2cBase[instance]; g_lpi2cSlaveStatePtr[instance] = userConfigPtr->slaveState; Lpi2c_Ip_SlaveStateType * slave = g_lpi2cSlaveStatePtr[instance]; /* Initialize driver status structure */ slave->status = STATUS_LPI2C_IP_SUCCESS; slave->slaveCallback = userConfigPtr->slaveCallback; slave->callbackParam = userConfigPtr->callbackParam; slave->dataBuffer = NULL_PTR; slave->bufferSize = 0U; slave->direction = LPI2C_IP_SEND; slave->transferType = userConfigPtr->transferType; /* Store DMA channel number used in transfer */ slave->dmaTxChannel = userConfigPtr->dmaTxChannel; slave->dmaRxChannel = userConfigPtr->dmaRxChannel; slave->isTransferInProgress = FALSE; slave->is10bitAddress = userConfigPtr->is10bitAddr; slave->repeatedStarts = 0U; slave->slaveListening = userConfigPtr->slaveListening; /* Initialize module */ LPI2C_Init(baseAddr); #if (STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) if(slave->transferType == LPI2C_USING_DMA) { Lpi2c_Ip_SlaveCmdDmaTcdInit(); } #endif /* Configure slave address */ Lpi2c_Ip_SlaveConigureAddress(baseAddr, userConfigPtr->slaveAddress, userConfigPtr->is10bitAddr); /* Configure operating mode */ Lpi2c_Ip_SlaveSetOperatingMode(instance, userConfigPtr->operatingMode); /* Set glitch filters for SDA and SCL */ Lpi2c_Ip_SlaveConfigureGlitchFilter(baseAddr, userConfigPtr->u32GlitchFilterSDA, userConfigPtr->u32GlitchFilterSCL); if(slave->slaveListening) { Lpi2c_Ip_SlaveActivateEvents(instance); } return STATUS_LPI2C_IP_SUCCESS; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_StartListening * Description : Makes a slave channel available for processing request in case * slave is in not listening mode * Implements : I2c_Ip_StartListening_Activity * *END**************************************************************************/ void Lpi2c_Ip_StartListening(uint32 u32Instance) { const Lpi2c_Ip_SlaveStateType * slave; slave = g_lpi2cSlaveStatePtr[u32Instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(slave != NULL_PTR); DevAssert(!slave->slaveListening); #endif Lpi2c_Ip_SlaveActivateEvents(u32Instance); (void) slave; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveDeinit * Description : de-initialize the I2C slave mode driver * * Implements : Lpi2c_Ip_SlaveDeinit_Activity *END**************************************************************************/ Lpi2c_Ip_StatusType Lpi2c_Ip_SlaveDeinit(uint32 instance) { LPI2C_Type *baseAddr; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); #endif baseAddr = g_lpi2cBase[instance]; const Lpi2c_Ip_SlaveStateType *slave = g_lpi2cSlaveStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(slave != NULL_PTR); #endif if ((slave->transferType == LPI2C_USING_DMA) && (TRUE == slave->slaveListening)) { /* Disable LPI2C DMA requests. */ (void)LPI2C_Set_SlaveRxDMA(baseAddr, FALSE); (void)LPI2C_Set_SlaveTxDMA(baseAddr, FALSE); } g_lpi2cSlaveStatePtr[instance] = NULL_PTR; /* Disable LPI2C slave */ LPI2C_Set_SlaveEnable(baseAddr, FALSE); return STATUS_LPI2C_IP_SUCCESS; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveSetTxBuffer * Description : Provide a buffer for transmitting data. * * Implements : Lpi2c_Ip_SlaveSetTxBuffer_Activity *END**************************************************************************/ Lpi2c_Ip_StatusType Lpi2c_Ip_SlaveSetBuffer(uint32 instance, uint8 * dataBuff, uint32 dataSize) { Lpi2c_Ip_SlaveStateType * slave; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); DevAssert(dataBuff != NULL_PTR); DevAssert(dataSize > 0U); #endif slave = g_lpi2cSlaveStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(slave != NULL_PTR); #endif slave->dataBuffer = dataBuff; slave->bufferSize = dataSize; return STATUS_LPI2C_IP_SUCCESS; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveGetTransferStatus * Description : return the current status of the I2C slave transfer * * When performing an a-sync (non-blocking) transfer, the user can call this function * to ascertain the state of the current transfer. In addition, if the transfer is still * in progress, the user can get the number of words that should be receive. * * Implements : Lpi2c_Ip_SlaveGetTransferStatus_Activity *END**************************************************************************/ Lpi2c_Ip_StatusType Lpi2c_Ip_SlaveGetTransferStatus(uint32 instance, uint32 *bytesRemaining) { const Lpi2c_Ip_SlaveStateType *slave; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); #endif slave = g_lpi2cSlaveStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(slave != NULL_PTR); #endif if ((bytesRemaining != NULL_PTR) && (slave->transferType == LPI2C_USING_INTERRUPTS)) { *bytesRemaining = slave->bufferSize; } return slave->status; } /*FUNCTION********************************************************************** * * Function Name : LPI2C_DRV_SlaveEndTransfer * Description : ends current transmission or reception * *END**************************************************************************/ static void Lpi2c_Ip_SlaveEndTransfer(LPI2C_Type *baseAddr) { /* Deactivate events */ LPI2C_Set_SlaveInt(baseAddr, LPI2C_SLAVE_BIT_ERROR_INT | LPI2C_SLAVE_FIFO_ERROR_INT | LPI2C_SLAVE_STOP_DETECT_INT | LPI2C_SLAVE_REPEATED_START_INT | LPI2C_SLAVE_ADDRESS_VALID_INT | LPI2C_SLAVE_RECEIVE_DATA_INT | LPI2C_SLAVE_TRANSMIT_DATA_INT, FALSE); /* Disable LPI2C slave */ LPI2C_Set_SlaveEnable(baseAddr, FALSE); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveEndTransferHandler * Description : handle slave end transfer operations * *END**************************************************************************/ static void Lpi2c_Ip_SlaveEndTransferHandler(const Lpi2c_Ip_SlaveStateType *slave, LPI2C_Type *baseAddr) { /* Check slave state */ #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(slave != NULL_PTR); #endif #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) /* Stop DMA channel if slave is transferring data in DMA mode */ if (slave->transferType == LPI2C_USING_DMA) { if(slave->direction == LPI2C_IP_SEND) { /* Stop TX DMA channel */ (void)Dma_Ip_SetLogicChannelCommand(slave->dmaTxChannel, DMA_IP_CH_CLEAR_HARDWARE_REQUEST); } else { /* Stop RX DMA channel */ (void)Dma_Ip_SetLogicChannelCommand(slave->dmaRxChannel, DMA_IP_CH_CLEAR_HARDWARE_REQUEST); } } #endif if (!slave->slaveListening) { Lpi2c_Ip_SlaveEndTransfer(baseAddr); } if(slave->slaveCallback != NULL_PTR) { slave->slaveCallback(I2C_SLAVE_EVENT_STOP, slave->callbackParam); } (void) baseAddr; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveCheckDataEvent * Description : check slave adress valid and tx/rx event * *END**************************************************************************/ static void Lpi2c_Ip_SlaveCheckDataEvent(uint32 instance, LPI2C_Type *baseAddr, Lpi2c_Ip_SlaveStateType * slave) { boolean slaveInterrupt = FALSE; /* Check which event caused the interrupt */ if (LPI2C_Get_SlaveAddressValidEvent(baseAddr)) { Lpi2c_Ip_SlaveHandleAddressValidEvent(instance, baseAddr, slave); } /* Check transmit event */ if (LPI2C_Get_SlaveTransmitDataEvent(baseAddr)) { slaveInterrupt = LPI2C_Get_SlaveInt(baseAddr, (uint32)LPI2C_SLAVE_TRANSMIT_DATA_INT); if (slaveInterrupt) { /* Handle transmit event */ Lpi2c_Ip_SlaveHandleTransmitDataEvent(baseAddr, slave); } } /* Check receive event */ if (LPI2C_Get_SlaveReceiveDataEvent(baseAddr)) { slaveInterrupt = LPI2C_Get_SlaveInt(baseAddr, (uint32)LPI2C_SLAVE_RECEIVE_DATA_INT); if (slaveInterrupt) { /* Handle receive event */ Lpi2c_Ip_SlaveHandleReceiveDataEvent(baseAddr, slave); } } } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveStopDetectHandler * Description : handles stop/repeated start event * *END**************************************************************************/ static void Lpi2c_Ip_SlaveStopDetectHandler(LPI2C_Type *baseAddr, Lpi2c_Ip_SlaveStateType * slave) { /* Either STOP or repeated START have the same meaning here: the current transfer is over */ LPI2C_Clear_SlaveSTOPDetectEvent(baseAddr); LPI2C_Clear_SlaveRepeatedStartEvent(baseAddr); #if defined(ERRATA_E10792) /* Deactivate interrupts for transmitting data */ LPI2C_Set_SlaveInt(baseAddr, (uint32)LPI2C_SLAVE_TRANSMIT_DATA_INT, FALSE); #endif if (slave->status == STATUS_LPI2C_IP_BUSY) { /* Report success if no error was recorded */ slave->status = STATUS_LPI2C_IP_SUCCESS; } Lpi2c_Ip_SlaveEndTransferHandler(slave, baseAddr); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveBitErrorEventHandler * Description : handles slave bit error event * *END**************************************************************************/ static void Lpi2c_Ip_SlaveBitErrorEventHandler(LPI2C_Type *baseAddr, Lpi2c_Ip_SlaveStateType * slave) { slave->status = STATUS_LPI2C_IP_ERROR; LPI2C_Clear_SlaveBitErrorEvent(baseAddr); #if (STD_ON == LPI2C_IP_EVENT_ERROR_DETECT) if (slave->slaveCallback != NULL_PTR) { slave->slaveCallback(I2C_SLAVE_EVENT_ERROR_BIT, slave->callbackParam); } #endif #if defined(ERRATA_E10792) /* Deactivate interrupts for transmitting data */ LPI2C_Set_SlaveInt(baseAddr, (uint32)LPI2C_SLAVE_TRANSMIT_DATA_INT, FALSE); #endif /* Slave end transfer */ Lpi2c_Ip_SlaveEndTransferHandler(slave, baseAddr); } #if(LPI2C_HAS_ULTRA_FAST_MODE) /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveFIFOErrorEventHandler * Description : handles slave FIFO error event * *END**************************************************************************/ static void Lpi2c_Ip_SlaveFIFOErrorEventHandler(LPI2C_Type *baseAddr, Lpi2c_Ip_SlaveStateType * slave) { /* In Ultra-Fast mode clock stretching is disabled, so it is possible to get this event if the slave can't keep up */ slave->status = STATUS_LPI2C_IP_RX_OVERRUN; LPI2C_Clear_SlaveFIFOErrorEvent(baseAddr); #if defined(ERRATA_E10792) /* Deactivate interrupts for transmitting data */ LPI2C_Set_SlaveInt(baseAddr, LPI2C_SLAVE_TRANSMIT_DATA_INT, FALSE); #endif Lpi2c_Ip_SlaveEndTransferHandler(slave, baseAddr); } #endif /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveCheckErrorEvent * Description : checks for slave errors * *END**************************************************************************/ static void Lpi2c_Ip_SlaveCheckErrorEvent(LPI2C_Type *baseAddr, Lpi2c_Ip_SlaveStateType * slave) { if (LPI2C_Get_SlaveBitErrorEvent(baseAddr)) { /* Handle slave bit error event */ Lpi2c_Ip_SlaveBitErrorEventHandler(baseAddr, slave); } #if(LPI2C_HAS_ULTRA_FAST_MODE) if (LPI2C_Get_SlaveFIFOErrorEvent(baseAddr)) { /* Handle slave FIFO error event */ Lpi2c_Ip_SlaveFIFOErrorEventHandler(baseAddr, slave); } #endif } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SlaveIRQHandler * Description : handle non-blocking slave operation when I2C interrupt occurs * *END**************************************************************************/ void Lpi2c_Ip_SlaveIRQHandler(uint32 instance) { LPI2C_Type *baseAddr; Lpi2c_Ip_SlaveStateType * slave; boolean stopDetect = FALSE, repeatStartDetect = FALSE; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); #endif baseAddr = g_lpi2cBase[instance]; slave = g_lpi2cSlaveStatePtr[instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(slave != NULL_PTR); #endif /* Check address valid and tx/rx event */ Lpi2c_Ip_SlaveCheckDataEvent(instance, baseAddr, slave); stopDetect = LPI2C_Get_SlaveSTOPDetectEvent(baseAddr); repeatStartDetect = LPI2C_Get_SlaveRepeatedStartEvent(baseAddr); if (repeatStartDetect) { slave->repeatedStarts++; if ((slave->repeatedStarts == 1U) && (slave->is10bitAddress)) { repeatStartDetect = FALSE; LPI2C_Clear_SlaveRepeatedStartEvent(baseAddr); } } if ((stopDetect == TRUE) || (repeatStartDetect == TRUE)) { /* Stop/repeated start detected */ Lpi2c_Ip_SlaveStopDetectHandler(baseAddr, slave); if (stopDetect == TRUE) { /* reset repetead starts for a new transfer */ slave->repeatedStarts = 0U; } } /* Check for slave errors */ Lpi2c_Ip_SlaveCheckErrorEvent(baseAddr, slave); } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_ModuleIRQHandler * Description : handle events for lpi2c module * *END**************************************************************************/ void Lpi2c_Ip_ModuleIRQHandler(uint32 instance) { LPI2C_Type *baseAddr; uint32 u32MasterIsrEnable = 0u; uint32 u32MasterIsrStatus = 0u; uint32 u32SlaveIsrEnable = 0u; uint32 u32SlaveIsrStatus = 0u; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(instance < LPI2C_INSTANCE_COUNT); #endif baseAddr = g_lpi2cBase[instance]; /* Check spurious interrupt */ if ((NULL_PTR != g_lpi2cSlaveStatePtr[instance]) || (NULL_PTR != g_lpi2cMasterStatePtr[instance])) { /* the driver has been initialized */ /* Check i2c interrupts */ u32MasterIsrEnable = baseAddr->MIER & (LPI2C_MIER_DMIE_MASK | LPI2C_MIER_PLTIE_MASK | LPI2C_MIER_FEIE_MASK | LPI2C_MIER_ALIE_MASK | LPI2C_MIER_NDIE_MASK | LPI2C_MIER_SDIE_MASK | LPI2C_MIER_EPIE_MASK | LPI2C_MIER_RDIE_MASK | LPI2C_MIER_TDIE_MASK); u32MasterIsrStatus = baseAddr->MSR & ( LPI2C_MSR_DMF_MASK | LPI2C_MSR_PLTF_MASK | LPI2C_MSR_FEF_MASK | LPI2C_MSR_ALF_MASK | LPI2C_MSR_NDF_MASK | LPI2C_MSR_SDF_MASK | LPI2C_MSR_EPF_MASK | LPI2C_MSR_RDF_MASK | LPI2C_MSR_TDF_MASK); u32SlaveIsrEnable = baseAddr->SIER & (LPI2C_SIER_SARIE_MASK | LPI2C_SIER_GCIE_MASK | LPI2C_SIER_AM0IE_MASK | LPI2C_SIER_FEIE_MASK | LPI2C_SIER_BEIE_MASK | LPI2C_SIER_SDIE_MASK | LPI2C_SIER_RSIE_MASK | LPI2C_SIER_TAIE_MASK | LPI2C_SIER_AVIE_MASK | LPI2C_SIER_RDIE_MASK | LPI2C_SIER_TDIE_MASK | LPI2C_SIER_AM1IE_MASK); u32SlaveIsrStatus = baseAddr->SSR & (LPI2C_SSR_SARF_MASK | LPI2C_SSR_GCF_MASK | LPI2C_SSR_AM1F_MASK | LPI2C_SSR_AM0F_MASK | LPI2C_SSR_FEF_MASK | LPI2C_SSR_BEF_MASK | LPI2C_SSR_SDF_MASK | LPI2C_SSR_RSF_MASK | LPI2C_SSR_TAF_MASK | LPI2C_SSR_AVF_MASK | LPI2C_SSR_RDF_MASK | LPI2C_SSR_TDF_MASK); if (((0u != u32MasterIsrEnable) && (0u != u32MasterIsrStatus)) || ((0u != u32SlaveIsrEnable) && (0u != u32SlaveIsrStatus))) { /* Check if module is master or slave */ if (g_lpi2cSlaveStatePtr[instance] == NULL_PTR) { Lpi2c_Ip_MasterIRQHandler(instance); } else { Lpi2c_Ip_SlaveIRQHandler(instance); } } else { /* Clear all flags */ baseAddr->MSR &= (uint32)0xFFFFFFFFU; baseAddr->SSR &= (uint32)0xFFFFFFFFU; } } else { /* Clear all flags */ baseAddr->MSR &= (uint32)0xFFFFFFFFU; baseAddr->SSR &= (uint32)0xFFFFFFFFU; } /* Cast to void to avoid compiler warnings */ (void) u32MasterIsrEnable; (void) u32MasterIsrStatus; (void) u32SlaveIsrEnable; (void) u32SlaveIsrStatus; } #if(STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE) #if (LPI2C_INSTANCE_COUNT >= 1U) /*FUNCTION********************************************************************** * * Function Name : I2C0_DmaCompleteNotification * Description : Dma complete notification for instance 0 * *END**************************************************************************/ void LPI2C0_DmaCompleteNotification(void) { #ifdef LPI2C_ENABLE_USER_MODE_SUPPORT #if (STD_ON == LPI2C_ENABLE_USER_MODE_SUPPORT) OsIf_Trusted_Call1param(Lpi2c_Ip_MasterCompleteDMATransfer,(0U)); #else Lpi2c_Ip_MasterCompleteDMATransfer(0U); #endif #endif } #endif /* LPI2C_INSTANCE_COUNT >= 1U */ #if (LPI2C_INSTANCE_COUNT >= 2U) /*FUNCTION********************************************************************** * * Function Name : I2C1_DmaCompleteNotification * Description : Dma complete notification for instance 1 * *END**************************************************************************/ void LPI2C1_DmaCompleteNotification(void) { #ifdef LPI2C_ENABLE_USER_MODE_SUPPORT #if (STD_ON == LPI2C_ENABLE_USER_MODE_SUPPORT) OsIf_Trusted_Call1param(Lpi2c_Ip_MasterCompleteDMATransfer,(1U)); #else Lpi2c_Ip_MasterCompleteDMATransfer(1U); #endif #endif } #endif /* LPI2C_INSTANCE_COUNT >= 2U */ #endif /* STD_ON == LPI2C_IP_DMA_FEATURE_AVAILABLE */ /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SetMasterCallback * Description : Sets the master callback * *END**************************************************************************/ void Lpi2c_Ip_SetMasterCallback(uint32 u32Instance, Lpi2c_Ip_MasterCallbackType masterCallback) { Lpi2c_Ip_MasterStateType * master; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(u32Instance < LPI2C_INSTANCE_COUNT); #endif master = g_lpi2cMasterStatePtr[u32Instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif master->masterCallback = masterCallback; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SetSlaveCallback * Description : Sets the slave callback * *END**************************************************************************/ void Lpi2c_Ip_SetSlaveCallback(uint32 u32Instance, Lpi2c_Ip_SlaveCallbackType slaveCallback) { Lpi2c_Ip_SlaveStateType * slave; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(u32Instance < LPI2C_INSTANCE_COUNT); #endif slave = g_lpi2cSlaveStatePtr[u32Instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(slave != NULL_PTR); #endif slave->slaveCallback = slaveCallback; } /*FUNCTION********************************************************************** * * Function Name : Lpi2c_Ip_SetMasterHighSpeedMode * Description : Sets high speed mode for master * *END**************************************************************************/ void Lpi2c_Ip_SetMasterHighSpeedMode(uint32 u32Instance, boolean bHighSpeedEnabled) { Lpi2c_Ip_MasterStateType * master; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(u32Instance < LPI2C_INSTANCE_COUNT); #endif master = g_lpi2cMasterStatePtr[u32Instance]; #if (STD_ON == LPI2C_IP_DEV_ERROR_DETECT) DevAssert(master != NULL_PTR); #endif if (TRUE == bHighSpeedEnabled) { /* Set high speed operating mode */ master->operatingMode = LPI2C_HIGHSPEED_MODE; } else { /* High speed mode is not selected */ master->operatingMode = LPI2C_STANDARD_MODE; } } #define I2C_STOP_SEC_CODE #include "I2c_MemMap.h" #ifdef __cplusplus } #endif /** @} */ /******************************************************************************* * EOF ******************************************************************************/