ADM/GW/RTD/src/Lpi2c_Ip.c
2024-08-08 10:00:15 +09:00

2985 lines
106 KiB
C

/*==================================================================================================
* 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
******************************************************************************/