diff options
Diffstat (limited to '')
-rw-r--r-- | bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c.c | 2315 |
1 files changed, 0 insertions, 2315 deletions
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c.c deleted file mode 100644 index f8d6f55e95..0000000000 --- a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c.c +++ /dev/null @@ -1,2315 +0,0 @@ -/* - * Copyright (c) 2015, Freescale Semiconductor, Inc. - * Copyright 2016-2020 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "fsl_lpi2c.h" -#include <stdlib.h> -#include <string.h> - -/******************************************************************************* - * Definitions - ******************************************************************************/ - -/* Component ID definition, used by tools. */ -#ifndef FSL_COMPONENT_ID -#define FSL_COMPONENT_ID "platform.drivers.lpi2c" -#endif - -/*! @brief Common sets of flags used by the driver. */ -enum -{ - /*! All flags which are cleared by the driver upon starting a transfer. */ - kMasterClearFlags = kLPI2C_MasterEndOfPacketFlag | kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag | - kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag | kLPI2C_MasterPinLowTimeoutFlag | - kLPI2C_MasterDataMatchFlag, - - /*! IRQ sources enabled by the non-blocking transactional API. */ - kMasterIrqFlags = kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterTxReadyFlag | kLPI2C_MasterRxReadyFlag | - kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag | kLPI2C_MasterPinLowTimeoutFlag | - kLPI2C_MasterFifoErrFlag, - - /*! Errors to check for. */ - kMasterErrorFlags = kLPI2C_MasterNackDetectFlag | kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag | - kLPI2C_MasterPinLowTimeoutFlag, - - /*! All flags which are cleared by the driver upon starting a transfer. */ - kSlaveClearFlags = kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveBitErrFlag | - kLPI2C_SlaveFifoErrFlag, - - /*! IRQ sources enabled by the non-blocking transactional API. */ - kSlaveIrqFlags = kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag | - kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag | - kLPI2C_SlaveTransmitAckFlag | kLPI2C_SlaveAddressValidFlag, - - /*! Errors to check for. */ - kSlaveErrorFlags = kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag, -}; - -/* ! @brief LPI2C master fifo commands. */ -enum -{ - kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */ - kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */ - kStopCmd = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */ - kStartCmd = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */ -}; - -/*! - * @brief Default watermark values. - * - * The default watermarks are set to zero. - */ -enum -{ - kDefaultTxWatermark = 0, - kDefaultRxWatermark = 0, -}; - -/*! @brief States for the state machine used by transactional APIs. */ -enum -{ - kIdleState = 0, - kSendCommandState, - kIssueReadCommandState, - kTransferDataState, - kStopState, - kWaitForCompletionState, -}; - -/*! @brief Typedef for master interrupt handler. */ -typedef void (*lpi2c_master_isr_t)(LPI2C_Type *base, lpi2c_master_handle_t *handle); - -/*! @brief Typedef for slave interrupt handler. */ -typedef void (*lpi2c_slave_isr_t)(LPI2C_Type *base, lpi2c_slave_handle_t *handle); - -/******************************************************************************* - * Prototypes - ******************************************************************************/ - -/* Not static so it can be used from fsl_lpi2c_edma.c. */ -uint32_t LPI2C_GetInstance(LPI2C_Type *base); - -static uint32_t LPI2C_GetCyclesForWidth(uint32_t sourceClock_Hz, - uint32_t width_ns, - uint32_t maxCycles, - uint32_t prescaler); - -static status_t LPI2C_MasterWaitForTxReady(LPI2C_Type *base); - -static status_t LPI2C_RunTransferStateMachine(LPI2C_Type *base, lpi2c_master_handle_t *handle, bool *isDone); - -static void LPI2C_InitTransferStateMachine(lpi2c_master_handle_t *handle); - -static status_t LPI2C_SlaveCheckAndClearError(LPI2C_Type *base, uint32_t flags); - -static void LPI2C_CommonIRQHandler(LPI2C_Type *base, uint32_t instance); - -/******************************************************************************* - * Variables - ******************************************************************************/ - -/*! @brief Array to map LPI2C instance number to base pointer. */ -static LPI2C_Type *const kLpi2cBases[] = LPI2C_BASE_PTRS; - -/*! @brief Array to map LPI2C instance number to IRQ number. */ -static IRQn_Type const kLpi2cIrqs[] = LPI2C_IRQS; - -#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) -/*! @brief Array to map LPI2C instance number to clock gate enum. */ -static clock_ip_name_t const kLpi2cClocks[] = LPI2C_CLOCKS; - -#if defined(LPI2C_PERIPH_CLOCKS) -/*! @brief Array to map LPI2C instance number to pheripheral clock gate enum. */ -static const clock_ip_name_t kLpi2cPeriphClocks[] = LPI2C_PERIPH_CLOCKS; -#endif - -#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ - -/*! @brief Pointer to master IRQ handler for each instance. */ -static lpi2c_master_isr_t s_lpi2cMasterIsr; - -/*! @brief Pointers to master handles for each instance. */ -static lpi2c_master_handle_t *s_lpi2cMasterHandle[ARRAY_SIZE(kLpi2cBases)]; - -/*! @brief Pointer to slave IRQ handler for each instance. */ -static lpi2c_slave_isr_t s_lpi2cSlaveIsr; - -/*! @brief Pointers to slave handles for each instance. */ -static lpi2c_slave_handle_t *s_lpi2cSlaveHandle[ARRAY_SIZE(kLpi2cBases)]; - -/******************************************************************************* - * Code - ******************************************************************************/ - -/*! - * @brief Returns an instance number given a base address. - * - * If an invalid base address is passed, debug builds will assert. Release builds will just return - * instance number 0. - * - * @param base The LPI2C peripheral base address. - * @return LPI2C instance number starting from 0. - */ -uint32_t LPI2C_GetInstance(LPI2C_Type *base) -{ - uint32_t instance; - for (instance = 0U; instance < ARRAY_SIZE(kLpi2cBases); ++instance) - { - if (kLpi2cBases[instance] == base) - { - break; - } - } - - assert(instance < ARRAY_SIZE(kLpi2cBases)); - return instance; -} - -/*! - * @brief Computes a cycle count for a given time in nanoseconds. - * @param sourceClock_Hz LPI2C functional clock frequency in Hertz. - * @param width_ns Desired with in nanoseconds. - * @param maxCycles Maximum cycle count, determined by the number of bits wide the cycle count field is. - * @param prescaler LPI2C prescaler setting. Pass 1 if the prescaler should not be used, as for slave glitch widths. - */ -static uint32_t LPI2C_GetCyclesForWidth(uint32_t sourceClock_Hz, - uint32_t width_ns, - uint32_t maxCycles, - uint32_t prescaler) -{ - assert(sourceClock_Hz > 0U); - assert(prescaler > 0U); - - uint32_t busCycle_ns = 1000000U / (sourceClock_Hz / prescaler / 1000U); - uint32_t cycles = 0U; - - /* Search for the cycle count just below the desired glitch width. */ - while ((((cycles + 1U) * busCycle_ns) < width_ns) && (cycles + 1U < maxCycles)) - { - ++cycles; - } - - /* If we end up with zero cycles, then set the filter to a single cycle unless the */ - /* bus clock is greater than 10x the desired glitch width. */ - if ((cycles == 0U) && (busCycle_ns <= (width_ns * 10U))) - { - cycles = 1U; - } - - return cycles; -} - -/*! - * @brief Convert provided flags to status code, and clear any errors if present. - * @param base The LPI2C peripheral base address. - * @param status Current status flags value that will be checked. - * @retval #kStatus_Success - * @retval #kStatus_LPI2C_PinLowTimeout - * @retval #kStatus_LPI2C_ArbitrationLost - * @retval #kStatus_LPI2C_Nak - * @retval #kStatus_LPI2C_FifoError - */ -/* Not static so it can be used from fsl_lpi2c_edma.c. */ -status_t LPI2C_MasterCheckAndClearError(LPI2C_Type *base, uint32_t status) -{ - status_t result = kStatus_Success; - - /* Check for error. These errors cause a stop to automatically be sent. We must */ - /* clear the errors before a new transfer can start. */ - status &= (uint32_t)kMasterErrorFlags; - if (0U != status) - { - /* Select the correct error code. Ordered by severity, with bus issues first. */ - if (0U != (status & (uint32_t)kLPI2C_MasterPinLowTimeoutFlag)) - { - result = kStatus_LPI2C_PinLowTimeout; - } - else if (0U != (status & (uint32_t)kLPI2C_MasterArbitrationLostFlag)) - { - result = kStatus_LPI2C_ArbitrationLost; - } - else if (0U != (status & (uint32_t)kLPI2C_MasterNackDetectFlag)) - { - result = kStatus_LPI2C_Nak; - } - else if (0U != (status & (uint32_t)kLPI2C_MasterFifoErrFlag)) - { - result = kStatus_LPI2C_FifoError; - } - else - { - ; /* Intentional empty */ - } - - /* Clear the flags. */ - LPI2C_MasterClearStatusFlags(base, status); - - /* Reset fifos. These flags clear automatically. */ - base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK; - } - else - { - ; /* Intentional empty */ - } - - return result; -} - -/*! - * @brief Wait until there is room in the tx fifo. - * @param base The LPI2C peripheral base address. - * @retval #kStatus_Success - * @retval #kStatus_LPI2C_PinLowTimeout - * @retval #kStatus_LPI2C_ArbitrationLost - * @retval #kStatus_LPI2C_Nak - * @retval #kStatus_LPI2C_FifoError - */ -static status_t LPI2C_MasterWaitForTxReady(LPI2C_Type *base) -{ - uint32_t status; - size_t txCount; - size_t txFifoSize = (size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base); - -#if I2C_RETRY_TIMES - uint32_t waitTimes = I2C_RETRY_TIMES; -#endif - do - { - status_t result; - - /* Get the number of words in the tx fifo and compute empty slots. */ - LPI2C_MasterGetFifoCounts(base, NULL, &txCount); - txCount = txFifoSize - txCount; - - /* Check for error flags. */ - status = LPI2C_MasterGetStatusFlags(base); - result = LPI2C_MasterCheckAndClearError(base, status); - if (kStatus_Success != result) - { - return result; - } -#if I2C_RETRY_TIMES - } while ((0U == txCount) && (0U != --waitTimes)); - - if (0U == waitTimes) - { - return kStatus_LPI2C_Timeout; - } -#else - } while (0U == txCount); -#endif - - return kStatus_Success; -} - -/*! - * @brief Make sure the bus isn't already busy. - * - * A busy bus is allowed if we are the one driving it. - * - * @param base The LPI2C peripheral base address. - * @retval #kStatus_Success - * @retval #kStatus_LPI2C_Busy - */ -/* Not static so it can be used from fsl_lpi2c_edma.c. */ -status_t LPI2C_CheckForBusyBus(LPI2C_Type *base) -{ - status_t ret = kStatus_Success; - - uint32_t status = LPI2C_MasterGetStatusFlags(base); - if ((0U != (status & (uint32_t)kLPI2C_MasterBusBusyFlag)) && (0U == (status & (uint32_t)kLPI2C_MasterBusyFlag))) - { - ret = kStatus_LPI2C_Busy; - } - - return ret; -} - -/*! - * brief Provides a default configuration for the LPI2C master peripheral. - * - * This function provides the following default configuration for the LPI2C master peripheral: - * code - * masterConfig->enableMaster = true; - * masterConfig->debugEnable = false; - * masterConfig->ignoreAck = false; - * masterConfig->pinConfig = kLPI2C_2PinOpenDrain; - * masterConfig->baudRate_Hz = 100000U; - * masterConfig->busIdleTimeout_ns = 0U; - * masterConfig->pinLowTimeout_ns = 0U; - * masterConfig->sdaGlitchFilterWidth_ns = 0U; - * masterConfig->sclGlitchFilterWidth_ns = 0U; - * masterConfig->hostRequest.enable = false; - * masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin; - * masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh; - * endcode - * - * After calling this function, you can override any settings in order to customize the configuration, - * prior to initializing the master driver with LPI2C_MasterInit(). - * - * param[out] masterConfig User provided configuration structure for default values. Refer to #lpi2c_master_config_t. - */ -void LPI2C_MasterGetDefaultConfig(lpi2c_master_config_t *masterConfig) -{ - /* Initializes the configure structure to zero. */ - (void)memset(masterConfig, 0, sizeof(*masterConfig)); - - masterConfig->enableMaster = true; - masterConfig->debugEnable = false; - masterConfig->enableDoze = true; - masterConfig->ignoreAck = false; - masterConfig->pinConfig = kLPI2C_2PinOpenDrain; - masterConfig->baudRate_Hz = 100000U; - masterConfig->busIdleTimeout_ns = 0U; - masterConfig->pinLowTimeout_ns = 0U; - masterConfig->sdaGlitchFilterWidth_ns = 0U; - masterConfig->sclGlitchFilterWidth_ns = 0U; - masterConfig->hostRequest.enable = false; - masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin; - masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh; -} - -/*! - * brief Initializes the LPI2C master peripheral. - * - * This function enables the peripheral clock and initializes the LPI2C master peripheral as described by the user - * provided configuration. A software reset is performed prior to configuration. - * - * param base The LPI2C peripheral base address. - * param masterConfig User provided peripheral configuration. Use LPI2C_MasterGetDefaultConfig() to get a set of - * defaults - * that you can override. - * param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the baud rate divisors, - * filter widths, and timeout periods. - */ -void LPI2C_MasterInit(LPI2C_Type *base, const lpi2c_master_config_t *masterConfig, uint32_t sourceClock_Hz) -{ - uint32_t prescaler; - uint32_t cycles; - uint32_t cfgr2; - uint32_t value; - -#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) - - uint32_t instance = LPI2C_GetInstance(base); - - /* Ungate the clock. */ - CLOCK_EnableClock(kLpi2cClocks[instance]); -#if defined(LPI2C_PERIPH_CLOCKS) - /* Ungate the functional clock in initialize function. */ - CLOCK_EnableClock(kLpi2cPeriphClocks[instance]); -#endif - -#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ - - /* Reset peripheral before configuring it. */ - LPI2C_MasterReset(base); - - /* Doze bit: 0 is enable, 1 is disable */ - base->MCR = LPI2C_MCR_DBGEN(masterConfig->debugEnable) | LPI2C_MCR_DOZEN(!(masterConfig->enableDoze)); - - /* host request */ - value = base->MCFGR0; - value &= (~(LPI2C_MCFGR0_HREN_MASK | LPI2C_MCFGR0_HRPOL_MASK | LPI2C_MCFGR0_HRSEL_MASK)); - value |= LPI2C_MCFGR0_HREN(masterConfig->hostRequest.enable) | - LPI2C_MCFGR0_HRPOL(masterConfig->hostRequest.polarity) | - LPI2C_MCFGR0_HRSEL(masterConfig->hostRequest.source); - base->MCFGR0 = value; - - /* pin config and ignore ack */ - value = base->MCFGR1; - value &= ~(LPI2C_MCFGR1_PINCFG_MASK | LPI2C_MCFGR1_IGNACK_MASK); - value |= LPI2C_MCFGR1_PINCFG(masterConfig->pinConfig); - value |= LPI2C_MCFGR1_IGNACK(masterConfig->ignoreAck); - base->MCFGR1 = value; - - LPI2C_MasterSetWatermarks(base, (size_t)kDefaultTxWatermark, (size_t)kDefaultRxWatermark); - - LPI2C_MasterSetBaudRate(base, sourceClock_Hz, masterConfig->baudRate_Hz); - - /* Configure glitch filters and bus idle and pin low timeouts. */ - prescaler = (base->MCFGR1 & LPI2C_MCFGR1_PRESCALE_MASK) >> LPI2C_MCFGR1_PRESCALE_SHIFT; - cfgr2 = base->MCFGR2; - if (0U != (masterConfig->busIdleTimeout_ns)) - { - cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->busIdleTimeout_ns, - (LPI2C_MCFGR2_BUSIDLE_MASK >> LPI2C_MCFGR2_BUSIDLE_SHIFT), prescaler); - cfgr2 &= ~LPI2C_MCFGR2_BUSIDLE_MASK; - cfgr2 |= LPI2C_MCFGR2_BUSIDLE(cycles); - } - if (0U != (masterConfig->sdaGlitchFilterWidth_ns)) - { - cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->sdaGlitchFilterWidth_ns, - (LPI2C_MCFGR2_FILTSDA_MASK >> LPI2C_MCFGR2_FILTSDA_SHIFT), 1U); - cfgr2 &= ~LPI2C_MCFGR2_FILTSDA_MASK; - cfgr2 |= LPI2C_MCFGR2_FILTSDA(cycles); - } - if (0U != masterConfig->sclGlitchFilterWidth_ns) - { - cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->sclGlitchFilterWidth_ns, - (LPI2C_MCFGR2_FILTSCL_MASK >> LPI2C_MCFGR2_FILTSCL_SHIFT), 1U); - cfgr2 &= ~LPI2C_MCFGR2_FILTSCL_MASK; - cfgr2 |= LPI2C_MCFGR2_FILTSCL(cycles); - } - base->MCFGR2 = cfgr2; - if (0U != masterConfig->pinLowTimeout_ns) - { - cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->pinLowTimeout_ns / 256U, - (LPI2C_MCFGR2_BUSIDLE_MASK >> LPI2C_MCFGR2_BUSIDLE_SHIFT), prescaler); - base->MCFGR3 = (base->MCFGR3 & ~LPI2C_MCFGR3_PINLOW_MASK) | LPI2C_MCFGR3_PINLOW(cycles); - } - - LPI2C_MasterEnable(base, masterConfig->enableMaster); -} - -/*! - * brief Deinitializes the LPI2C master peripheral. - * - * This function disables the LPI2C master peripheral and gates the clock. It also performs a software - * reset to restore the peripheral to reset conditions. - * - * param base The LPI2C peripheral base address. - */ -void LPI2C_MasterDeinit(LPI2C_Type *base) -{ - /* Restore to reset state. */ - LPI2C_MasterReset(base); - -#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) - - uint32_t instance = LPI2C_GetInstance(base); - - /* Gate clock. */ - CLOCK_DisableClock(kLpi2cClocks[instance]); -#if defined(LPI2C_PERIPH_CLOCKS) - /* Gate the functional clock. */ - CLOCK_DisableClock(kLpi2cPeriphClocks[instance]); -#endif - -#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ -} - -/*! - * brief Configures LPI2C master data match feature. - * - * param base The LPI2C peripheral base address. - * param config Settings for the data match feature. - */ -void LPI2C_MasterConfigureDataMatch(LPI2C_Type *base, const lpi2c_data_match_config_t *config) -{ - /* Disable master mode. */ - bool wasEnabled = (0U != ((base->MCR & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT)); - LPI2C_MasterEnable(base, false); - - base->MCFGR1 = (base->MCFGR1 & ~LPI2C_MCFGR1_MATCFG_MASK) | LPI2C_MCFGR1_MATCFG(config->matchMode); - base->MCFGR0 = (base->MCFGR0 & ~LPI2C_MCFGR0_RDMO_MASK) | LPI2C_MCFGR0_RDMO(config->rxDataMatchOnly); - base->MDMR = LPI2C_MDMR_MATCH0(config->match0) | LPI2C_MDMR_MATCH1(config->match1); - - /* Restore master mode. */ - if (wasEnabled) - { - LPI2C_MasterEnable(base, true); - } -} - -/*! - * brief Sets the I2C bus frequency for master transactions. - * - * The LPI2C master is automatically disabled and re-enabled as necessary to configure the baud - * rate. Do not call this function during a transfer, or the transfer is aborted. - * - * note Please note that the second parameter is the clock frequency of LPI2C module, the third - * parameter means user configured bus baudrate, this implementation is different from other I2C drivers - * which use baudrate configuration as second parameter and source clock frequency as third parameter. - * - * param base The LPI2C peripheral base address. - * param sourceClock_Hz LPI2C functional clock frequency in Hertz. - * param baudRate_Hz Requested bus frequency in Hertz. - */ -void LPI2C_MasterSetBaudRate(LPI2C_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Hz) -{ - uint32_t prescale = 0U; - uint32_t bestPre = 0U; - uint32_t bestClkHi = 0U; - uint32_t absError = 0U; - uint32_t bestError = 0xffffffffu; - uint32_t value; - uint32_t clkHiCycle; - uint32_t computedRate; - uint32_t i; - bool wasEnabled; - - /* Disable master mode. */ - wasEnabled = (0U != ((base->MCR & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT)); - LPI2C_MasterEnable(base, false); - - /* Baud rate = (sourceClock_Hz/2^prescale)/(CLKLO+1+CLKHI+1 + ROUNDDOWN((2+FILTSCL)/2^prescale) */ - /* Assume CLKLO = 2*CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2. */ - for (prescale = 1U; prescale <= 128U; prescale = 2U * prescale) - { - if (bestError == 0U) - { - break; - } - - for (clkHiCycle = 1U; clkHiCycle < 32U; clkHiCycle++) - { - if (clkHiCycle == 1U) - { - computedRate = (sourceClock_Hz / prescale) / (1U + 3U + 2U + 2U / prescale); - } - else - { - computedRate = (sourceClock_Hz / prescale) / (3U * clkHiCycle + 2U + 2U / prescale); - } - - absError = baudRate_Hz > computedRate ? baudRate_Hz - computedRate : computedRate - baudRate_Hz; - - if (absError < bestError) - { - bestPre = prescale; - bestClkHi = clkHiCycle; - bestError = absError; - - /* If the error is 0, then we can stop searching because we won't find a better match. */ - if (absError == 0U) - { - break; - } - } - } - } - - /* Standard, fast, fast mode plus and ultra-fast transfers. */ - value = LPI2C_MCCR0_CLKHI(bestClkHi); - - if (bestClkHi < 2U) - { - value |= (uint32_t)(LPI2C_MCCR0_CLKLO(3UL) | LPI2C_MCCR0_SETHOLD(2UL) | LPI2C_MCCR0_DATAVD(1UL)); - } - else - { - value |= - LPI2C_MCCR0_CLKLO(2UL * bestClkHi) | LPI2C_MCCR0_SETHOLD(bestClkHi) | LPI2C_MCCR0_DATAVD(bestClkHi / 2UL); - } - - base->MCCR0 = value; - - for (i = 0U; i < 8U; i++) - { - if (bestPre == (1UL << i)) - { - bestPre = i; - break; - } - } - base->MCFGR1 = (base->MCFGR1 & ~LPI2C_MCFGR1_PRESCALE_MASK) | LPI2C_MCFGR1_PRESCALE(bestPre); - - /* Restore master mode. */ - if (wasEnabled) - { - LPI2C_MasterEnable(base, true); - } -} - -/*! - * brief Sends a START signal and slave address on the I2C bus. - * - * This function is used to initiate a new master mode transfer. First, the bus state is checked to ensure - * that another master is not occupying the bus. Then a START signal is transmitted, followed by the - * 7-bit address specified in the a address parameter. Note that this function does not actually wait - * until the START and address are successfully sent on the bus before returning. - * - * param base The LPI2C peripheral base address. - * param address 7-bit slave device address, in bits [6:0]. - * param dir Master transfer direction, either #kLPI2C_Read or #kLPI2C_Write. This parameter is used to set - * the R/w bit (bit 0) in the transmitted slave address. - * retval #kStatus_Success START signal and address were successfully enqueued in the transmit FIFO. - * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. - */ -status_t LPI2C_MasterStart(LPI2C_Type *base, uint8_t address, lpi2c_direction_t dir) -{ - /* Return an error if the bus is already in use not by us. */ - status_t result = LPI2C_CheckForBusyBus(base); - if (kStatus_Success != result) - { - return result; - } - - /* Clear all flags. */ - LPI2C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags); - - /* Turn off auto-stop option. */ - base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK; - - /* Wait until there is room in the fifo. */ - result = LPI2C_MasterWaitForTxReady(base); - if (kStatus_Success != result) - { - return result; - } - - /* Issue start command. */ - base->MTDR = (uint32_t)kStartCmd | (((uint32_t)address << 1U) | (uint32_t)dir); - - return kStatus_Success; -} - -/*! - * brief Sends a STOP signal on the I2C bus. - * - * This function does not return until the STOP signal is seen on the bus, or an error occurs. - * - * param base The LPI2C peripheral base address. - * retval #kStatus_Success The STOP signal was successfully sent on the bus and the transaction terminated. - * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. - * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. - * retval #kStatus_LPI2C_FifoError FIFO under run or overrun. - * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. - * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. - */ -status_t LPI2C_MasterStop(LPI2C_Type *base) -{ - /* Wait until there is room in the fifo. */ - status_t result = LPI2C_MasterWaitForTxReady(base); - if (kStatus_Success != result) - { - return result; - } - - /* Send the STOP signal */ - base->MTDR = (uint32_t)kStopCmd; - -/* Wait for the stop detected flag to set, indicating the transfer has completed on the bus. */ -/* Also check for errors while waiting. */ -#if I2C_RETRY_TIMES - uint32_t waitTimes = I2C_RETRY_TIMES; -#endif - -#if I2C_RETRY_TIMES - while ((result == kStatus_Success) && (0U != --waitTimes)) -#else - while (result == kStatus_Success) -#endif - { - uint32_t status = LPI2C_MasterGetStatusFlags(base); - - /* Check for error flags. */ - result = LPI2C_MasterCheckAndClearError(base, status); - - /* Check if the stop was sent successfully. */ - if ((0U != (status & (uint32_t)kLPI2C_MasterStopDetectFlag)) && - (0U != (status & (uint32_t)kLPI2C_MasterTxReadyFlag))) - { - LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterStopDetectFlag); - break; - } - } - -#if I2C_RETRY_TIMES - if (0U == waitTimes) - { - return kStatus_LPI2C_Timeout; - } -#endif - - return result; -} - -/*! - * brief Performs a polling receive transfer on the I2C bus. - * - * param base The LPI2C peripheral base address. - * param rxBuff The pointer to the data to be transferred. - * param rxSize The length in bytes of the data to be transferred. - * retval #kStatus_Success Data was received successfully. - * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. - * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. - * retval #kStatus_LPI2C_FifoError FIFO under run or overrun. - * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. - * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. - */ -status_t LPI2C_MasterReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize) -{ - status_t result; - uint8_t *buf; -#if I2C_RETRY_TIMES - uint32_t waitTimes; -#endif - - assert(NULL != rxBuff); - - /* Handle empty read. */ - if (rxSize == 0U) - { - return kStatus_Success; - } - - /* Wait until there is room in the command fifo. */ - result = LPI2C_MasterWaitForTxReady(base); - if (kStatus_Success != result) - { - return result; - } - - /* Issue command to receive data. */ - base->MTDR = ((uint32_t)kRxDataCmd) | LPI2C_MTDR_DATA(rxSize - 1U); - - /* Receive data */ - buf = (uint8_t *)rxBuff; - while (0U != (rxSize--)) - { -#if I2C_RETRY_TIMES - waitTimes = I2C_RETRY_TIMES; -#endif - /* Read LPI2C receive fifo register. The register includes a flag to indicate whether */ - /* the FIFO is empty, so we can both get the data and check if we need to keep reading */ - /* using a single register read. */ - uint32_t value; - do - { - /* Check for errors. */ - result = LPI2C_MasterCheckAndClearError(base, LPI2C_MasterGetStatusFlags(base)); - if (kStatus_Success != result) - { - return result; - } - - value = base->MRDR; -#if I2C_RETRY_TIMES - } while ((0U != (value & LPI2C_MRDR_RXEMPTY_MASK)) && (0U != --waitTimes)); - if (0U == waitTimes) - { - return kStatus_LPI2C_Timeout; - } -#else - } while (0U != (value & LPI2C_MRDR_RXEMPTY_MASK)); -#endif - - *buf++ = (uint8_t)(value & LPI2C_MRDR_DATA_MASK); - } - - return kStatus_Success; -} - -/*! - * brief Performs a polling send transfer on the I2C bus. - * - * Sends up to a txSize number of bytes to the previously addressed slave device. The slave may - * reply with a NAK to any byte in order to terminate the transfer early. If this happens, this - * function returns #kStatus_LPI2C_Nak. - * - * param base The LPI2C peripheral base address. - * param txBuff The pointer to the data to be transferred. - * param txSize The length in bytes of the data to be transferred. - * retval #kStatus_Success Data was sent successfully. - * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. - * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. - * retval #kStatus_LPI2C_FifoError FIFO under run or over run. - * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. - * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. - */ -status_t LPI2C_MasterSend(LPI2C_Type *base, void *txBuff, size_t txSize) -{ - uint8_t *buf = (uint8_t *)txBuff; - - assert(NULL != txBuff); - - /* Send data buffer */ - while (0U != (txSize--)) - { - /* Wait until there is room in the fifo. This also checks for errors. */ - status_t result = LPI2C_MasterWaitForTxReady(base); - if (kStatus_Success != result) - { - return result; - } - - /* Write byte into LPI2C master data register. */ - base->MTDR = *buf++; - } - - return kStatus_Success; -} - -/*! - * brief Performs a master polling transfer on the I2C bus. - * - * note The API does not return until the transfer succeeds or fails due - * to error happens during transfer. - * - * param base The LPI2C peripheral base address. - * param transfer Pointer to the transfer structure. - * retval #kStatus_Success Data was received successfully. - * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. - * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. - * retval #kStatus_LPI2C_FifoError FIFO under run or overrun. - * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. - * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. - */ -status_t LPI2C_MasterTransferBlocking(LPI2C_Type *base, lpi2c_master_transfer_t *transfer) -{ - status_t result = kStatus_Success; - uint16_t commandBuffer[7]; - uint32_t cmdCount = 0U; - - assert(NULL != transfer); - assert(transfer->subaddressSize <= sizeof(transfer->subaddress)); - - /* Return an error if the bus is already in use not by us. */ - result = LPI2C_CheckForBusyBus(base); - if (kStatus_Success != result) - { - return result; - } - - /* Clear all flags. */ - LPI2C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags); - - /* Turn off auto-stop option. */ - base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK; - - lpi2c_direction_t direction = (0U != transfer->subaddressSize) ? kLPI2C_Write : transfer->direction; - if (0U == (transfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag)) - { - commandBuffer[cmdCount++] = - (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)transfer->slaveAddress << 1U) | (uint16_t)direction); - } - - /* Subaddress, MSB first. */ - if (0U != transfer->subaddressSize) - { - uint32_t subaddressRemaining = transfer->subaddressSize; - while (0U != subaddressRemaining--) - { - uint8_t subaddressByte = (uint8_t)((transfer->subaddress >> (8U * subaddressRemaining)) & 0xffU); - commandBuffer[cmdCount++] = subaddressByte; - } - } - - /* Reads need special handling. */ - if ((0U != transfer->dataSize) && (transfer->direction == kLPI2C_Read)) - { - /* Need to send repeated start if switching directions to read. */ - if (direction == kLPI2C_Write) - { - commandBuffer[cmdCount++] = - (uint16_t)kStartCmd | - (uint16_t)((uint16_t)((uint16_t)transfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read); - } - } - - /* Send command buffer */ - uint32_t index = 0U; - while (0U != cmdCount--) - { - /* Wait until there is room in the fifo. This also checks for errors. */ - result = LPI2C_MasterWaitForTxReady(base); - if (kStatus_Success != result) - { - return result; - } - - /* Write byte into LPI2C master data register. */ - base->MTDR = commandBuffer[index]; - index++; - } - - /* Transmit data. */ - if ((transfer->direction == kLPI2C_Write) && (transfer->dataSize > 0U)) - { - /* Send Data. */ - result = LPI2C_MasterSend(base, transfer->data, transfer->dataSize); - } - - /* Receive Data. */ - if ((transfer->direction == kLPI2C_Read) && (transfer->dataSize > 0U)) - { - result = LPI2C_MasterReceive(base, transfer->data, transfer->dataSize); - } - - if (kStatus_Success != result) - { - return result; - } - - if ((transfer->flags & (uint32_t)kLPI2C_TransferNoStopFlag) == 0U) - { - result = LPI2C_MasterStop(base); - } - - return result; -} - -/*! - * brief Creates a new handle for the LPI2C master non-blocking APIs. - * - * The creation of a handle is for use with the non-blocking APIs. Once a handle - * is created, there is not a corresponding destroy handle. If the user wants to - * terminate a transfer, the LPI2C_MasterTransferAbort() API shall be called. - * - * - * note The function also enables the NVIC IRQ for the input LPI2C. Need to notice - * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to - * enable the associated INTMUX IRQ in application. - * - * param base The LPI2C peripheral base address. - * param[out] handle Pointer to the LPI2C master driver handle. - * param callback User provided pointer to the asynchronous callback function. - * param userData User provided pointer to the application callback data. - */ -void LPI2C_MasterTransferCreateHandle(LPI2C_Type *base, - lpi2c_master_handle_t *handle, - lpi2c_master_transfer_callback_t callback, - void *userData) -{ - uint32_t instance; - - assert(NULL != handle); - - /* Clear out the handle. */ - (void)memset(handle, 0, sizeof(*handle)); - - /* Look up instance number */ - instance = LPI2C_GetInstance(base); - - /* Save base and instance. */ - handle->completionCallback = callback; - handle->userData = userData; - - /* Save this handle for IRQ use. */ - s_lpi2cMasterHandle[instance] = handle; - - /* Set irq handler. */ - s_lpi2cMasterIsr = LPI2C_MasterTransferHandleIRQ; - - /* Clear internal IRQ enables and enable NVIC IRQ. */ - LPI2C_MasterDisableInterrupts(base, (uint32_t)kMasterIrqFlags); - - /* Enable NVIC IRQ, this only enables the IRQ directly connected to the NVIC. - In some cases the LPI2C IRQ is configured through INTMUX, user needs to enable - INTMUX IRQ in application code. */ - (void)EnableIRQ(kLpi2cIrqs[instance]); -} - -/*! - * @brief Execute states until FIFOs are exhausted. - * @param handle Master nonblocking driver handle. - * @param[out] isDone Set to true if the transfer has completed. - * @retval #kStatus_Success - * @retval #kStatus_LPI2C_PinLowTimeout - * @retval #kStatus_LPI2C_ArbitrationLost - * @retval #kStatus_LPI2C_Nak - * @retval #kStatus_LPI2C_FifoError - */ -static status_t LPI2C_RunTransferStateMachine(LPI2C_Type *base, lpi2c_master_handle_t *handle, bool *isDone) -{ - uint32_t status; - status_t result = kStatus_Success; - lpi2c_master_transfer_t *xfer; - size_t txCount; - size_t rxCount; - size_t txFifoSize = (size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base); - bool state_complete = false; - uint16_t sendval; - - /* Set default isDone return value. */ - *isDone = false; - - /* Check for errors. */ - status = LPI2C_MasterGetStatusFlags(base); - /* For the last byte, nack flag is expected. - Do not check and clear kLPI2C_MasterNackDetectFlag for the last byte, - in case FIFO is emptied when stop command has not been sent. */ - if (handle->remainingBytes == 0U) - { - status &= ~(uint32_t)kLPI2C_MasterNackDetectFlag; - } - result = LPI2C_MasterCheckAndClearError(base, status); - if (kStatus_Success != result) - { - return result; - } - - /* Get pointer to private data. */ - xfer = &handle->transfer; - - /* Get fifo counts and compute room in tx fifo. */ - LPI2C_MasterGetFifoCounts(base, &rxCount, &txCount); - txCount = txFifoSize - txCount; - - while (!state_complete) - { - /* Execute the state. */ - switch (handle->state) - { - case (uint8_t)kSendCommandState: - /* Make sure there is room in the tx fifo for the next command. */ - if (0U == txCount--) - { - state_complete = true; - break; - } - - /* Issue command. buf is a uint8_t* pointing at the uint16 command array. */ - sendval = ((uint16_t)(*handle->buf)) | ((uint16_t)(*(handle->buf + 1U)) << 8U); - base->MTDR = sendval; - handle->buf++; - handle->buf++; - - /* Count down until all commands are sent. */ - if (--handle->remainingBytes == 0U) - { - /* Choose next state and set up buffer pointer and count. */ - if (0U != xfer->dataSize) - { - /* Either a send or receive transfer is next. */ - handle->state = (uint8_t)kTransferDataState; - handle->buf = (uint8_t *)xfer->data; - handle->remainingBytes = (uint16_t)xfer->dataSize; - if (xfer->direction == kLPI2C_Read) - { - /* Disable TX interrupt */ - LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterTxReadyFlag); - } - } - else - { - /* No transfer, so move to stop state. */ - handle->state = (uint8_t)kStopState; - } - } - break; - - case (uint8_t)kIssueReadCommandState: - /* Make sure there is room in the tx fifo for the read command. */ - if (0U == txCount--) - { - state_complete = true; - break; - } - - base->MTDR = (uint32_t)kRxDataCmd | LPI2C_MTDR_DATA(xfer->dataSize - 1U); - - /* Move to transfer state. */ - handle->state = (uint8_t)kTransferDataState; - if (xfer->direction == kLPI2C_Read) - { - /* Disable TX interrupt */ - LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterTxReadyFlag); - } - break; - - case (uint8_t)kTransferDataState: - if (xfer->direction == kLPI2C_Write) - { - /* Make sure there is room in the tx fifo. */ - if (0U == txCount--) - { - state_complete = true; - break; - } - - /* Put byte to send in fifo. */ - base->MTDR = *(handle->buf)++; - } - else - { - /* XXX handle receive sizes > 256, use kIssueReadCommandState */ - /* Make sure there is data in the rx fifo. */ - if (0U == rxCount--) - { - state_complete = true; - break; - } - - /* Read byte from fifo. */ - *(handle->buf)++ = (uint8_t)(base->MRDR & LPI2C_MRDR_DATA_MASK); - } - - /* Move to stop when the transfer is done. */ - if (--handle->remainingBytes == 0U) - { - if (xfer->direction == kLPI2C_Write) - { - state_complete = true; - } - handle->state = (uint8_t)kStopState; - } - break; - - case (uint8_t)kStopState: - /* Only issue a stop transition if the caller requested it. */ - if ((xfer->flags & (uint32_t)kLPI2C_TransferNoStopFlag) == 0U) - { - /* Make sure there is room in the tx fifo for the stop command. */ - if (0U == txCount--) - { - state_complete = true; - break; - } - - base->MTDR = (uint32_t)kStopCmd; - } - else - { - /* Caller doesn't want to send a stop, so we're done now. */ - *isDone = true; - state_complete = true; - break; - } - handle->state = (uint8_t)kWaitForCompletionState; - break; - - case (uint8_t)kWaitForCompletionState: - /* We stay in this state until the stop state is detected. */ - if (0U != (status & (uint32_t)kLPI2C_MasterStopDetectFlag)) - { - *isDone = true; - } - state_complete = true; - break; - default: - assert(false); - break; - } - } - return result; -} - -/*! - * @brief Prepares the transfer state machine and fills in the command buffer. - * @param handle Master nonblocking driver handle. - */ -static void LPI2C_InitTransferStateMachine(lpi2c_master_handle_t *handle) -{ - lpi2c_master_transfer_t *xfer = &handle->transfer; - - /* Handle no start option. */ - if (0U != (xfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag)) - { - if (xfer->direction == kLPI2C_Read) - { - /* Need to issue read command first. */ - handle->state = (uint8_t)kIssueReadCommandState; - } - else - { - /* Start immediately in the data transfer state. */ - handle->state = (uint8_t)kTransferDataState; - } - - handle->buf = (uint8_t *)xfer->data; - handle->remainingBytes = (uint16_t)xfer->dataSize; - } - else - { - uint16_t *cmd = (uint16_t *)&handle->commandBuffer; - uint32_t cmdCount = 0U; - - /* Initial direction depends on whether a subaddress was provided, and of course the actual */ - /* data transfer direction. */ - lpi2c_direction_t direction = (0U != xfer->subaddressSize) ? kLPI2C_Write : xfer->direction; - - /* Start command. */ - cmd[cmdCount++] = - (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction); - - /* Subaddress, MSB first. */ - if (0U != xfer->subaddressSize) - { - uint32_t subaddressRemaining = xfer->subaddressSize; - while (0U != (subaddressRemaining--)) - { - uint8_t subaddressByte = (uint8_t)((xfer->subaddress >> (8U * subaddressRemaining)) & 0xffU); - cmd[cmdCount++] = subaddressByte; - } - } - - /* Reads need special handling. */ - if ((0U != xfer->dataSize) && (xfer->direction == kLPI2C_Read)) - { - /* Need to send repeated start if switching directions to read. */ - if (direction == kLPI2C_Write) - { - cmd[cmdCount++] = (uint16_t)kStartCmd | - (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read); - } - - /* Read command. */ - cmd[cmdCount++] = (uint16_t)((uint32_t)kRxDataCmd | LPI2C_MTDR_DATA(xfer->dataSize - 1U)); - } - - /* Set up state machine for transferring the commands. */ - handle->state = (uint8_t)kSendCommandState; - handle->remainingBytes = (uint16_t)cmdCount; - handle->buf = (uint8_t *)&handle->commandBuffer; - } -} - -/*! - * brief Performs a non-blocking transaction on the I2C bus. - * - * param base The LPI2C peripheral base address. - * param handle Pointer to the LPI2C master driver handle. - * param transfer The pointer to the transfer descriptor. - * retval #kStatus_Success The transaction was started successfully. - * retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or a non-blocking - * transaction is already in progress. - */ -status_t LPI2C_MasterTransferNonBlocking(LPI2C_Type *base, - lpi2c_master_handle_t *handle, - lpi2c_master_transfer_t *transfer) -{ - status_t result; - - assert(NULL != handle); - assert(NULL != transfer); - assert(transfer->subaddressSize <= sizeof(transfer->subaddress)); - - /* Return busy if another transaction is in progress. */ - if (handle->state != (uint8_t)kIdleState) - { - return kStatus_LPI2C_Busy; - } - - /* Return an error if the bus is already in use not by us. */ - result = LPI2C_CheckForBusyBus(base); - if (kStatus_Success != result) - { - return result; - } - - /* Disable LPI2C IRQ sources while we configure stuff. */ - LPI2C_MasterDisableInterrupts(base, (uint32_t)kMasterIrqFlags); - - /* Reset FIFO in case there are data. */ - base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK; - - /* Save transfer into handle. */ - handle->transfer = *transfer; - - /* Generate commands to send. */ - LPI2C_InitTransferStateMachine(handle); - - /* Clear all flags. */ - LPI2C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags); - - /* Turn off auto-stop option. */ - base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK; - - /* Enable LPI2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */ - LPI2C_MasterEnableInterrupts(base, (uint32_t)kMasterIrqFlags); - - return result; -} - -/*! - * brief Returns number of bytes transferred so far. - * param base The LPI2C peripheral base address. - * param handle Pointer to the LPI2C master driver handle. - * param[out] count Number of bytes transferred so far by the non-blocking transaction. - * retval #kStatus_Success - * retval #kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress. - */ -status_t LPI2C_MasterTransferGetCount(LPI2C_Type *base, lpi2c_master_handle_t *handle, size_t *count) -{ - assert(NULL != handle); - - if (NULL == count) - { - return kStatus_InvalidArgument; - } - - /* Catch when there is not an active transfer. */ - if (handle->state == (uint8_t)kIdleState) - { - *count = 0; - return kStatus_NoTransferInProgress; - } - - uint8_t state; - uint16_t remainingBytes; - uint32_t dataSize; - - /* Cache some fields with IRQs disabled. This ensures all field values */ - /* are synchronized with each other during an ongoing transfer. */ - uint32_t irqs = LPI2C_MasterGetEnabledInterrupts(base); - LPI2C_MasterDisableInterrupts(base, irqs); - state = handle->state; - remainingBytes = handle->remainingBytes; - dataSize = handle->transfer.dataSize; - LPI2C_MasterEnableInterrupts(base, irqs); - - /* Get transfer count based on current transfer state. */ - switch (state) - { - case (uint8_t)kIdleState: - case (uint8_t)kSendCommandState: - case ( - uint8_t)kIssueReadCommandState: /* XXX return correct value for this state when >256 reads are supported */ - *count = 0; - break; - - case (uint8_t)kTransferDataState: - *count = dataSize - remainingBytes; - break; - - case (uint8_t)kStopState: - case (uint8_t)kWaitForCompletionState: - default: - *count = dataSize; - break; - } - - return kStatus_Success; -} - -/*! - * brief Terminates a non-blocking LPI2C master transmission early. - * - * note It is not safe to call this function from an IRQ handler that has a higher priority than the - * LPI2C peripheral's IRQ priority. - * - * param base The LPI2C peripheral base address. - * param handle Pointer to the LPI2C master driver handle. - * retval #kStatus_Success A transaction was successfully aborted. - * retval #kStatus_LPI2C_Idle There is not a non-blocking transaction currently in progress. - */ -void LPI2C_MasterTransferAbort(LPI2C_Type *base, lpi2c_master_handle_t *handle) -{ - if (handle->state != (uint8_t)kIdleState) - { - /* Disable internal IRQ enables. */ - LPI2C_MasterDisableInterrupts(base, (uint32_t)kMasterIrqFlags); - - /* Reset fifos. */ - base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK; - - /* Send a stop command to finalize the transfer. */ - base->MTDR = (uint32_t)kStopCmd; - - /* Reset handle. */ - handle->state = (uint8_t)kIdleState; - } -} - -/*! - * brief Reusable routine to handle master interrupts. - * note This function does not need to be called unless you are reimplementing the - * nonblocking API's interrupt handler routines to add special functionality. - * param base The LPI2C peripheral base address. - * param handle Pointer to the LPI2C master driver handle. - */ -void LPI2C_MasterTransferHandleIRQ(LPI2C_Type *base, lpi2c_master_handle_t *handle) -{ - bool isDone = false; - status_t result; - size_t txCount; - - /* Don't do anything if we don't have a valid handle. */ - if (NULL == handle) - { - return; - } - - if (handle->state == (uint8_t)kIdleState) - { - return; - } - - result = LPI2C_RunTransferStateMachine(base, handle, &isDone); - - if ((result != kStatus_Success) || isDone) - { - /* Handle error, terminate xfer */ - if (result != kStatus_Success) - { - LPI2C_MasterTransferAbort(base, handle); - } - /* Check whether there is data in tx FIFO not sent out, is there is then the last transfer was NACKed by slave - */ - LPI2C_MasterGetFifoCounts(base, NULL, &txCount); - if (txCount != 0U) - { - result = kStatus_LPI2C_Nak; - /* Reset fifos. */ - base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK; - /* Send a stop command to finalize the transfer. */ - base->MTDR = (uint32_t)kStopCmd; - } - /* Disable internal IRQ enables. */ - LPI2C_MasterDisableInterrupts(base, (uint32_t)kMasterIrqFlags); - - /* Set handle to idle state. */ - handle->state = (uint8_t)kIdleState; - - /* Invoke callback. */ - if (NULL != handle->completionCallback) - { - handle->completionCallback(base, handle, result, handle->userData); - } - } -} - -/*! - * brief Provides a default configuration for the LPI2C slave peripheral. - * - * This function provides the following default configuration for the LPI2C slave peripheral: - * code - * slaveConfig->enableSlave = true; - * slaveConfig->address0 = 0U; - * slaveConfig->address1 = 0U; - * slaveConfig->addressMatchMode = kLPI2C_MatchAddress0; - * slaveConfig->filterDozeEnable = true; - * slaveConfig->filterEnable = true; - * slaveConfig->enableGeneralCall = false; - * slaveConfig->sclStall.enableAck = false; - * slaveConfig->sclStall.enableTx = true; - * slaveConfig->sclStall.enableRx = true; - * slaveConfig->sclStall.enableAddress = true; - * slaveConfig->ignoreAck = false; - * slaveConfig->enableReceivedAddressRead = false; - * slaveConfig->sdaGlitchFilterWidth_ns = 0; - * slaveConfig->sclGlitchFilterWidth_ns = 0; - * slaveConfig->dataValidDelay_ns = 0; - * slaveConfig->clockHoldTime_ns = 0; - * endcode - * - * After calling this function, override any settings to customize the configuration, - * prior to initializing the master driver with LPI2C_SlaveInit(). Be sure to override at least the a - * address0 member of the configuration structure with the desired slave address. - * - * param[out] slaveConfig User provided configuration structure that is set to default values. Refer to - * #lpi2c_slave_config_t. - */ -void LPI2C_SlaveGetDefaultConfig(lpi2c_slave_config_t *slaveConfig) -{ - /* Initializes the configure structure to zero. */ - (void)memset(slaveConfig, 0, sizeof(*slaveConfig)); - - slaveConfig->enableSlave = true; - slaveConfig->address0 = 0U; - slaveConfig->address1 = 0U; - slaveConfig->addressMatchMode = kLPI2C_MatchAddress0; - slaveConfig->filterDozeEnable = true; - slaveConfig->filterEnable = true; - slaveConfig->enableGeneralCall = false; - slaveConfig->sclStall.enableAck = false; - slaveConfig->sclStall.enableTx = true; - slaveConfig->sclStall.enableRx = true; - slaveConfig->sclStall.enableAddress = false; - slaveConfig->ignoreAck = false; - slaveConfig->enableReceivedAddressRead = false; - slaveConfig->sdaGlitchFilterWidth_ns = 0U; /* TODO determine default width values */ - slaveConfig->sclGlitchFilterWidth_ns = 0U; - slaveConfig->dataValidDelay_ns = 0U; - slaveConfig->clockHoldTime_ns = 0U; -} - -/*! - * brief Initializes the LPI2C slave peripheral. - * - * This function enables the peripheral clock and initializes the LPI2C slave peripheral as described by the user - * provided configuration. - * - * param base The LPI2C peripheral base address. - * param slaveConfig User provided peripheral configuration. Use LPI2C_SlaveGetDefaultConfig() to get a set of defaults - * that you can override. - * param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the filter widths, - * data valid delay, and clock hold time. - */ -void LPI2C_SlaveInit(LPI2C_Type *base, const lpi2c_slave_config_t *slaveConfig, uint32_t sourceClock_Hz) -{ - uint32_t tmpCycle; - -#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) - - uint32_t instance = LPI2C_GetInstance(base); - - /* Ungate the clock. */ - CLOCK_EnableClock(kLpi2cClocks[instance]); -#if defined(LPI2C_PERIPH_CLOCKS) - /* Ungate the functional clock in initialize function. */ - CLOCK_EnableClock(kLpi2cPeriphClocks[instance]); -#endif - -#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ - - /* Restore to reset conditions. */ - LPI2C_SlaveReset(base); - - /* Configure peripheral. */ - base->SAMR = LPI2C_SAMR_ADDR0(slaveConfig->address0) | LPI2C_SAMR_ADDR1(slaveConfig->address1); - - base->SCFGR1 = - LPI2C_SCFGR1_ADDRCFG(slaveConfig->addressMatchMode) | LPI2C_SCFGR1_IGNACK(slaveConfig->ignoreAck) | - LPI2C_SCFGR1_RXCFG(slaveConfig->enableReceivedAddressRead) | LPI2C_SCFGR1_GCEN(slaveConfig->enableGeneralCall) | - LPI2C_SCFGR1_ACKSTALL(slaveConfig->sclStall.enableAck) | LPI2C_SCFGR1_TXDSTALL(slaveConfig->sclStall.enableTx) | - LPI2C_SCFGR1_RXSTALL(slaveConfig->sclStall.enableRx) | - LPI2C_SCFGR1_ADRSTALL(slaveConfig->sclStall.enableAddress); - - tmpCycle = - LPI2C_SCFGR2_FILTSDA(LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->sdaGlitchFilterWidth_ns, - (LPI2C_SCFGR2_FILTSDA_MASK >> LPI2C_SCFGR2_FILTSDA_SHIFT), 1U)); - tmpCycle |= - LPI2C_SCFGR2_FILTSCL(LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->sclGlitchFilterWidth_ns, - (LPI2C_SCFGR2_FILTSCL_MASK >> LPI2C_SCFGR2_FILTSCL_SHIFT), 1U)); - tmpCycle |= LPI2C_SCFGR2_DATAVD(LPI2C_GetCyclesForWidth( - sourceClock_Hz, slaveConfig->dataValidDelay_ns, (LPI2C_SCFGR2_DATAVD_MASK >> LPI2C_SCFGR2_DATAVD_SHIFT), 1U)); - - base->SCFGR2 = tmpCycle | LPI2C_SCFGR2_CLKHOLD(LPI2C_GetCyclesForWidth( - sourceClock_Hz, slaveConfig->clockHoldTime_ns, - (LPI2C_SCFGR2_CLKHOLD_MASK >> LPI2C_SCFGR2_CLKHOLD_SHIFT), 1U)); - - /* Save SCR to last so we don't enable slave until it is configured */ - base->SCR = LPI2C_SCR_FILTDZ(slaveConfig->filterDozeEnable) | LPI2C_SCR_FILTEN(slaveConfig->filterEnable) | - LPI2C_SCR_SEN(slaveConfig->enableSlave); -} - -/*! - * brief Deinitializes the LPI2C slave peripheral. - * - * This function disables the LPI2C slave peripheral and gates the clock. It also performs a software - * reset to restore the peripheral to reset conditions. - * - * param base The LPI2C peripheral base address. - */ -void LPI2C_SlaveDeinit(LPI2C_Type *base) -{ - LPI2C_SlaveReset(base); - -#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) - - uint32_t instance = LPI2C_GetInstance(base); - - /* Gate the clock. */ - CLOCK_DisableClock(kLpi2cClocks[instance]); - -#if defined(LPI2C_PERIPH_CLOCKS) - /* Gate the functional clock. */ - CLOCK_DisableClock(kLpi2cPeriphClocks[instance]); -#endif - -#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ -} - -/*! - * @brief Convert provided flags to status code, and clear any errors if present. - * @param base The LPI2C peripheral base address. - * @param status Current status flags value that will be checked. - * @retval #kStatus_Success - * @retval #kStatus_LPI2C_BitError - * @retval #kStatus_LPI2C_FifoError - */ -static status_t LPI2C_SlaveCheckAndClearError(LPI2C_Type *base, uint32_t flags) -{ - status_t result = kStatus_Success; - - flags &= (uint32_t)kSlaveErrorFlags; - if (0U != flags) - { - if (0U != (flags & (uint32_t)kLPI2C_SlaveBitErrFlag)) - { - result = kStatus_LPI2C_BitError; - } - else if (0U != (flags & (uint32_t)kLPI2C_SlaveFifoErrFlag)) - { - result = kStatus_LPI2C_FifoError; - } - else - { - ; /* Intentional empty */ - } - - /* Clear the errors. */ - LPI2C_SlaveClearStatusFlags(base, flags); - } - else - { - ; /* Intentional empty */ - } - - return result; -} - -/*! - * brief Performs a polling send transfer on the I2C bus. - * - * param base The LPI2C peripheral base address. - * param txBuff The pointer to the data to be transferred. - * param txSize The length in bytes of the data to be transferred. - * param[out] actualTxSize - * return Error or success status returned by API. - */ -status_t LPI2C_SlaveSend(LPI2C_Type *base, void *txBuff, size_t txSize, size_t *actualTxSize) -{ - uint8_t *buf = (uint8_t *)txBuff; - size_t remaining = txSize; - - assert(NULL != txBuff); - -#if I2C_RETRY_TIMES - uint32_t waitTimes = I2C_RETRY_TIMES; -#endif - - /* Clear stop flag. */ - LPI2C_SlaveClearStatusFlags(base, - (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag); - - while (0U != remaining) - { - uint32_t flags; - status_t result; - - /* Wait until we can transmit. */ - do - { - /* Check for errors */ - flags = LPI2C_SlaveGetStatusFlags(base); - result = LPI2C_SlaveCheckAndClearError(base, flags); - if (kStatus_Success != result) - { - if (NULL != actualTxSize) - { - *actualTxSize = txSize - remaining; - } - return result; - } -#if I2C_RETRY_TIMES - } while ((0U == (flags & ((uint32_t)kLPI2C_SlaveTxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag | - (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) && - (0U != --waitTimes)); - if (0U == waitTimes) - { - return kStatus_LPI2C_Timeout; - } -#else - } while (0U == (flags & ((uint32_t)kLPI2C_SlaveTxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag | - (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))); -#endif - - /* Send a byte. */ - if (0U != (flags & (uint32_t)kLPI2C_SlaveTxReadyFlag)) - { - base->STDR = *buf++; - --remaining; - } - - /* Exit loop if we see a stop or restart in transfer*/ - if ((0U != (flags & ((uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) && - (remaining != 0U)) - { - LPI2C_SlaveClearStatusFlags( - base, (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag); - break; - } - } - - if (NULL != actualTxSize) - { - *actualTxSize = txSize - remaining; - } - - return kStatus_Success; -} - -/*! - * brief Performs a polling receive transfer on the I2C bus. - * - * param base The LPI2C peripheral base address. - * param rxBuff The pointer to the data to be transferred. - * param rxSize The length in bytes of the data to be transferred. - * param[out] actualRxSize - * return Error or success status returned by API. - */ -status_t LPI2C_SlaveReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize, size_t *actualRxSize) -{ - uint8_t *buf = (uint8_t *)rxBuff; - size_t remaining = rxSize; - - assert(NULL != rxBuff); - -#if I2C_RETRY_TIMES - uint32_t waitTimes = I2C_RETRY_TIMES; -#endif - - /* Clear stop flag. */ - LPI2C_SlaveClearStatusFlags(base, - (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag); - - while (0U != remaining) - { - uint32_t flags; - status_t result; - - /* Wait until we can receive. */ - do - { - /* Check for errors */ - flags = LPI2C_SlaveGetStatusFlags(base); - result = LPI2C_SlaveCheckAndClearError(base, flags); - if (kStatus_Success != result) - { - if (NULL != actualRxSize) - { - *actualRxSize = rxSize - remaining; - } - return result; - } -#if I2C_RETRY_TIMES - } while ((0U == (flags & ((uint32_t)kLPI2C_SlaveRxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag | - (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) && - (0U != --waitTimes)); - if (0U == waitTimes) - { - return kStatus_LPI2C_Timeout; - } -#else - } while (0U == (flags & ((uint32_t)kLPI2C_SlaveRxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag | - (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))); -#endif - - /* Receive a byte. */ - if (0U != (flags & (uint32_t)kLPI2C_SlaveRxReadyFlag)) - { - *buf++ = (uint8_t)(base->SRDR & LPI2C_SRDR_DATA_MASK); - --remaining; - } - - /* Exit loop if we see a stop or restart */ - if ((0U != (flags & ((uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) && - (remaining != 0U)) - { - LPI2C_SlaveClearStatusFlags( - base, (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag); - break; - } - } - - if (NULL != actualRxSize) - { - *actualRxSize = rxSize - remaining; - } - - return kStatus_Success; -} - -/*! - * brief Creates a new handle for the LPI2C slave non-blocking APIs. - * - * The creation of a handle is for use with the non-blocking APIs. Once a handle - * is created, there is not a corresponding destroy handle. If the user wants to - * terminate a transfer, the LPI2C_SlaveTransferAbort() API shall be called. - * - * note The function also enables the NVIC IRQ for the input LPI2C. Need to notice - * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to - * enable the associated INTMUX IRQ in application. - - * param base The LPI2C peripheral base address. - * param[out] handle Pointer to the LPI2C slave driver handle. - * param callback User provided pointer to the asynchronous callback function. - * param userData User provided pointer to the application callback data. - */ -void LPI2C_SlaveTransferCreateHandle(LPI2C_Type *base, - lpi2c_slave_handle_t *handle, - lpi2c_slave_transfer_callback_t callback, - void *userData) -{ - uint32_t instance; - - assert(NULL != handle); - - /* Clear out the handle. */ - (void)memset(handle, 0, sizeof(*handle)); - - /* Look up instance number */ - instance = LPI2C_GetInstance(base); - - /* Save base and instance. */ - handle->callback = callback; - handle->userData = userData; - - /* Save this handle for IRQ use. */ - s_lpi2cSlaveHandle[instance] = handle; - - /* Set irq handler. */ - s_lpi2cSlaveIsr = LPI2C_SlaveTransferHandleIRQ; - - /* Clear internal IRQ enables and enable NVIC IRQ. */ - LPI2C_SlaveDisableInterrupts(base, (uint32_t)kSlaveIrqFlags); - (void)EnableIRQ(kLpi2cIrqs[instance]); - - /* Nack by default. */ - base->STAR = LPI2C_STAR_TXNACK_MASK; -} - -/*! - * brief Starts accepting slave transfers. - * - * Call this API after calling I2C_SlaveInit() and LPI2C_SlaveTransferCreateHandle() to start processing - * transactions driven by an I2C master. The slave monitors the I2C bus and pass events to the - * callback that was passed into the call to LPI2C_SlaveTransferCreateHandle(). The callback is always invoked - * from the interrupt context. - * - * The set of events received by the callback is customizable. To do so, set the a eventMask parameter to - * the OR'd combination of #lpi2c_slave_transfer_event_t enumerators for the events you wish to receive. - * The #kLPI2C_SlaveTransmitEvent and #kLPI2C_SlaveReceiveEvent events are always enabled and do not need - * to be included in the mask. Alternatively, you can pass 0 to get a default set of only the transmit and - * receive events that are always enabled. In addition, the #kLPI2C_SlaveAllEvents constant is provided as - * a convenient way to enable all events. - * - * param base The LPI2C peripheral base address. - * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state. - * param eventMask Bit mask formed by OR'ing together #lpi2c_slave_transfer_event_t enumerators to specify - * which events to send to the callback. Other accepted values are 0 to get a default set of - * only the transmit and receive events, and #kLPI2C_SlaveAllEvents to enable all events. - * - * retval #kStatus_Success Slave transfers were successfully started. - * retval #kStatus_LPI2C_Busy Slave transfers have already been started on this handle. - */ -status_t LPI2C_SlaveTransferNonBlocking(LPI2C_Type *base, lpi2c_slave_handle_t *handle, uint32_t eventMask) -{ - uint32_t status; - - assert(NULL != handle); - - /* Return busy if another transaction is in progress. */ - if (handle->isBusy) - { - return kStatus_LPI2C_Busy; - } - - /* Return an error if the bus is already in use not by us. */ - status = LPI2C_SlaveGetStatusFlags(base); - if ((0U != (status & (uint32_t)kLPI2C_SlaveBusBusyFlag)) && (0U == (status & (uint32_t)kLPI2C_SlaveBusyFlag))) - { - return kStatus_LPI2C_Busy; - } - - /* Disable LPI2C IRQ sources while we configure stuff. */ - LPI2C_SlaveDisableInterrupts(base, (uint32_t)kSlaveIrqFlags); - - /* Clear transfer in handle. */ - (void)memset(&handle->transfer, 0, sizeof(handle->transfer)); - - /* Record that we're busy. */ - handle->isBusy = true; - - /* Set up event mask. tx and rx are always enabled. */ - handle->eventMask = eventMask | (uint32_t)kLPI2C_SlaveTransmitEvent | (uint32_t)kLPI2C_SlaveReceiveEvent; - - /* Ack by default. */ - base->STAR = 0U; - - /* Clear all flags. */ - LPI2C_SlaveClearStatusFlags(base, (uint32_t)kSlaveClearFlags); - - /* Enable LPI2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */ - LPI2C_SlaveEnableInterrupts(base, (uint32_t)kSlaveIrqFlags); - - return kStatus_Success; -} - -/*! - * brief Gets the slave transfer status during a non-blocking transfer. - * param base The LPI2C peripheral base address. - * param handle Pointer to i2c_slave_handle_t structure. - * param[out] count Pointer to a value to hold the number of bytes transferred. May be NULL if the count is not - * required. - * retval #kStatus_Success - * retval #kStatus_NoTransferInProgress - */ -status_t LPI2C_SlaveTransferGetCount(LPI2C_Type *base, lpi2c_slave_handle_t *handle, size_t *count) -{ - assert(NULL != handle); - - if (count == NULL) - { - return kStatus_InvalidArgument; - } - - /* Catch when there is not an active transfer. */ - if (!handle->isBusy) - { - *count = 0; - return kStatus_NoTransferInProgress; - } - - /* For an active transfer, just return the count from the handle. */ - *count = handle->transferredCount; - - return kStatus_Success; -} - -/*! - * brief Aborts the slave non-blocking transfers. - * note This API could be called at any time to stop slave for handling the bus events. - * param base The LPI2C peripheral base address. - * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state. - * retval #kStatus_Success - * retval #kStatus_LPI2C_Idle - */ -void LPI2C_SlaveTransferAbort(LPI2C_Type *base, lpi2c_slave_handle_t *handle) -{ - assert(NULL != handle); - - /* Return idle if no transaction is in progress. */ - if (handle->isBusy) - { - /* Disable LPI2C IRQ sources. */ - LPI2C_SlaveDisableInterrupts(base, (uint32_t)kSlaveIrqFlags); - - /* Nack by default. */ - base->STAR = LPI2C_STAR_TXNACK_MASK; - - /* Reset transfer info. */ - (void)memset(&handle->transfer, 0, sizeof(handle->transfer)); - - /* We're no longer busy. */ - handle->isBusy = false; - } -} - -/*! - * brief Reusable routine to handle slave interrupts. - * note This function does not need to be called unless you are reimplementing the - * non blocking API's interrupt handler routines to add special functionality. - * param base The LPI2C peripheral base address. - * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state. - */ -void LPI2C_SlaveTransferHandleIRQ(LPI2C_Type *base, lpi2c_slave_handle_t *handle) -{ - uint32_t flags; - lpi2c_slave_transfer_t *xfer; - - /* Check for a valid handle in case of a spurious interrupt. */ - if (NULL == handle) - { - return; - } - - xfer = &handle->transfer; - - /* Get status flags. */ - flags = LPI2C_SlaveGetStatusFlags(base); - - if (0U != (flags & ((uint32_t)kLPI2C_SlaveBitErrFlag | (uint32_t)kLPI2C_SlaveFifoErrFlag))) - { - xfer->event = kLPI2C_SlaveCompletionEvent; - xfer->completionStatus = LPI2C_SlaveCheckAndClearError(base, flags); - - if ((0U != (handle->eventMask & (uint32_t)kLPI2C_SlaveCompletionEvent)) && (NULL != handle->callback)) - { - handle->callback(base, xfer, handle->userData); - } - return; - } - if (0U != (flags & (((uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag) | ((uint32_t)kLPI2C_SlaveStopDetectFlag)))) - { - xfer->event = (0U != (flags & (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag)) ? kLPI2C_SlaveRepeatedStartEvent : - kLPI2C_SlaveCompletionEvent; - xfer->receivedAddress = 0U; - xfer->completionStatus = kStatus_Success; - xfer->transferredCount = handle->transferredCount; - - if (xfer->event == kLPI2C_SlaveCompletionEvent) - { - handle->isBusy = false; - } - - if (handle->wasTransmit) - { - /* Subtract one from the transmit count to offset the fact that LPI2C asserts the */ - /* tx flag before it sees the nack from the master-receiver, thus causing one more */ - /* count that the master actually receives. */ - --xfer->transferredCount; - handle->wasTransmit = false; - } - - /* Clear the flag. */ - LPI2C_SlaveClearStatusFlags( - base, flags & ((uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag)); - - /* Revert to sending an Ack by default, in case we sent a Nack for receive. */ - base->STAR = 0U; - - if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback)) - { - handle->callback(base, xfer, handle->userData); - } - - /* Clean up transfer info on completion, after the callback has been invoked. */ - (void)memset(&handle->transfer, 0, sizeof(handle->transfer)); - } - if (0U != (flags & (uint32_t)kLPI2C_SlaveAddressValidFlag)) - { - xfer->event = kLPI2C_SlaveAddressMatchEvent; - xfer->receivedAddress = (uint8_t)(base->SASR & LPI2C_SASR_RADDR_MASK); - - /* Update handle status to busy because slave is addressed. */ - handle->isBusy = true; - if ((0U != (handle->eventMask & (uint32_t)kLPI2C_SlaveAddressMatchEvent)) && (NULL != handle->callback)) - { - handle->callback(base, xfer, handle->userData); - } - } - if (0U != (flags & (uint32_t)kLPI2C_SlaveTransmitAckFlag)) - { - xfer->event = kLPI2C_SlaveTransmitAckEvent; - - if ((0U != (handle->eventMask & (uint32_t)kLPI2C_SlaveTransmitAckEvent)) && (NULL != handle->callback)) - { - handle->callback(base, xfer, handle->userData); - } - } - - /* Handle transmit and receive. */ - if (0U != (flags & (uint32_t)kLPI2C_SlaveTxReadyFlag)) - { - handle->wasTransmit = true; - - /* If we're out of data, invoke callback to get more. */ - if ((NULL == xfer->data) || (0U == xfer->dataSize)) - { - xfer->event = kLPI2C_SlaveTransmitEvent; - if (NULL != handle->callback) - { - handle->callback(base, xfer, handle->userData); - } - - /* Clear the transferred count now that we have a new buffer. */ - handle->transferredCount = 0U; - } - - /* Transmit a byte. */ - if ((NULL != xfer->data) && (0U != xfer->dataSize)) - { - base->STDR = *xfer->data++; - --xfer->dataSize; - ++handle->transferredCount; - } - } - if (0U != (flags & (uint32_t)kLPI2C_SlaveRxReadyFlag)) - { - /* If we're out of room in the buffer, invoke callback to get another. */ - if ((NULL == xfer->data) || (0U == xfer->dataSize)) - { - xfer->event = kLPI2C_SlaveReceiveEvent; - if (NULL != handle->callback) - { - handle->callback(base, xfer, handle->userData); - } - - /* Clear the transferred count now that we have a new buffer. */ - handle->transferredCount = 0U; - } - - /* Receive a byte. */ - if ((NULL != xfer->data) && (0U != xfer->dataSize)) - { - *xfer->data++ = (uint8_t)base->SRDR; - --xfer->dataSize; - ++handle->transferredCount; - } - else - { - /* We don't have any room to receive more data, so send a nack. */ - base->STAR = LPI2C_STAR_TXNACK_MASK; - } - } -} - -#if !(defined(FSL_FEATURE_I2C_HAS_NO_IRQ) && FSL_FEATURE_I2C_HAS_NO_IRQ) -/*! - * @brief Shared IRQ handler that can call both master and slave ISRs. - * - * The master and slave ISRs are called through function pointers in order to decouple - * this code from the ISR functions. Without this, the linker would always pull in both - * ISRs and every function they call, even if only the functional API was used. - * - * @param base The LPI2C peripheral base address. - * @param instance The LPI2C peripheral instance number. - */ -static void LPI2C_CommonIRQHandler(LPI2C_Type *base, uint32_t instance) -{ - /* Check for master IRQ. */ - if ((0U != (base->MCR & LPI2C_MCR_MEN_MASK)) && (NULL != s_lpi2cMasterIsr)) - { - /* Master mode. */ - s_lpi2cMasterIsr(base, s_lpi2cMasterHandle[instance]); - } - - /* Check for slave IRQ. */ - if ((0U != (base->SCR & LPI2C_SCR_SEN_MASK)) && (NULL != s_lpi2cSlaveIsr)) - { - /* Slave mode. */ - s_lpi2cSlaveIsr(base, s_lpi2cSlaveHandle[instance]); - } - SDK_ISR_EXIT_BARRIER; -} -#endif - -#if defined(LPI2C0) -/* Implementation of LPI2C0 handler named in startup code. */ -void LPI2C0_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(LPI2C0, 0U); -} -#endif - -#if defined(LPI2C1) -/* Implementation of LPI2C1 handler named in startup code. */ -void LPI2C1_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(LPI2C1, 1U); -} -#endif - -#if defined(LPI2C2) -/* Implementation of LPI2C2 handler named in startup code. */ -void LPI2C2_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(LPI2C2, 2U); -} -#endif - -#if defined(LPI2C3) -/* Implementation of LPI2C3 handler named in startup code. */ -void LPI2C3_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(LPI2C3, 3U); -} -#endif - -#if defined(LPI2C4) -/* Implementation of LPI2C4 handler named in startup code. */ -void LPI2C4_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(LPI2C4, 4U); -} -#endif - -#if defined(LPI2C5) -/* Implementation of LPI2C5 handler named in startup code. */ -void LPI2C5_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(LPI2C5, 5U); -} -#endif - -#if defined(LPI2C6) -/* Implementation of LPI2C6 handler named in startup code. */ -void LPI2C6_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(LPI2C6, 6U); -} -#endif - -#if defined(CM4_0__LPI2C) -/* Implementation of CM4_0__LPI2C handler named in startup code. */ -void M4_0_LPI2C_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(CM4_0__LPI2C, LPI2C_GetInstance(CM4_0__LPI2C)); -} -#endif - -#if defined(CM4__LPI2C) -/* Implementation of CM4__LPI2C handler named in startup code. */ -void M4_LPI2C_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(CM4__LPI2C, LPI2C_GetInstance(CM4__LPI2C)); -} -#endif - -#if defined(CM4_1__LPI2C) -/* Implementation of CM4_1__LPI2C handler named in startup code. */ -void M4_1_LPI2C_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(CM4_1__LPI2C, LPI2C_GetInstance(CM4_1__LPI2C)); -} -#endif - -#if defined(DMA__LPI2C0) -/* Implementation of DMA__LPI2C0 handler named in startup code. */ -void DMA_I2C0_INT_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(DMA__LPI2C0, LPI2C_GetInstance(DMA__LPI2C0)); -} -#endif - -#if defined(DMA__LPI2C1) -/* Implementation of DMA__LPI2C1 handler named in startup code. */ -void DMA_I2C1_INT_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(DMA__LPI2C1, LPI2C_GetInstance(DMA__LPI2C1)); -} -#endif - -#if defined(DMA__LPI2C2) -/* Implementation of DMA__LPI2C2 handler named in startup code. */ -void DMA_I2C2_INT_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(DMA__LPI2C2, LPI2C_GetInstance(DMA__LPI2C2)); -} -#endif - -#if defined(DMA__LPI2C3) -/* Implementation of DMA__LPI2C3 handler named in startup code. */ -void DMA_I2C3_INT_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(DMA__LPI2C3, LPI2C_GetInstance(DMA__LPI2C3)); -} -#endif - -#if defined(DMA__LPI2C4) -/* Implementation of DMA__LPI2C3 handler named in startup code. */ -void DMA_I2C4_INT_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(DMA__LPI2C4, LPI2C_GetInstance(DMA__LPI2C4)); -} -#endif - -#if defined(ADMA__LPI2C0) -/* Implementation of DMA__LPI2C0 handler named in startup code. */ -void ADMA_I2C0_INT_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(ADMA__LPI2C0, LPI2C_GetInstance(ADMA__LPI2C0)); -} -#endif - -#if defined(ADMA__LPI2C1) -/* Implementation of DMA__LPI2C1 handler named in startup code. */ -void ADMA_I2C1_INT_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(ADMA__LPI2C1, LPI2C_GetInstance(ADMA__LPI2C1)); -} -#endif - -#if defined(ADMA__LPI2C2) -/* Implementation of DMA__LPI2C2 handler named in startup code. */ -void ADMA_I2C2_INT_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(ADMA__LPI2C2, LPI2C_GetInstance(ADMA__LPI2C2)); -} -#endif - -#if defined(ADMA__LPI2C3) -/* Implementation of DMA__LPI2C3 handler named in startup code. */ -void ADMA_I2C3_INT_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(ADMA__LPI2C3, LPI2C_GetInstance(ADMA__LPI2C3)); -} -#endif - -#if defined(ADMA__LPI2C4) -/* Implementation of DMA__LPI2C3 handler named in startup code. */ -void ADMA_I2C4_INT_DriverIRQHandler(void) -{ - LPI2C_CommonIRQHandler(ADMA__LPI2C4, LPI2C_GetInstance(ADMA__LPI2C4)); -} -#endif |