| /* |
| * Copyright (c) 2015, Freescale Semiconductor, Inc. |
| * Copyright 2016-2017 NXP |
| * |
| * Redistribution and use in source and binary forms, with or without modification, |
| * are permitted provided that the following conditions are met: |
| * |
| * o Redistributions of source code must retain the above copyright notice, this list |
| * of conditions and the following disclaimer. |
| * |
| * o Redistributions in binary form must reproduce the above copyright notice, this |
| * list of conditions and the following disclaimer in the documentation and/or |
| * other materials provided with the distribution. |
| * |
| * o Neither the name of the copyright holder nor the names of its |
| * contributors may be used to endorse or promote products derived from this |
| * software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "fsl_flexio_i2c_master.h" |
| |
| /******************************************************************************* |
| * Definitions |
| ******************************************************************************/ |
| |
| /*! @brief FLEXIO I2C transfer state */ |
| enum _flexio_i2c_master_transfer_states |
| { |
| kFLEXIO_I2C_Idle = 0x0U, /*!< I2C bus idle */ |
| kFLEXIO_I2C_CheckAddress = 0x1U, /*!< 7-bit address check state */ |
| kFLEXIO_I2C_SendCommand = 0x2U, /*!< Send command byte phase */ |
| kFLEXIO_I2C_SendData = 0x3U, /*!< Send data transfer phase*/ |
| kFLEXIO_I2C_ReceiveDataBegin = 0x4U, /*!< Receive data begin transfer phase*/ |
| kFLEXIO_I2C_ReceiveData = 0x5U, /*!< Receive data transfer phase*/ |
| }; |
| |
| #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
| extern const clock_ip_name_t s_flexioClocks[]; |
| #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
| |
| extern FLEXIO_Type *const s_flexioBases[]; |
| |
| /******************************************************************************* |
| * Prototypes |
| ******************************************************************************/ |
| |
| extern uint32_t FLEXIO_GetInstance(FLEXIO_Type *base); |
| |
| /*! |
| * @brief Set up master transfer, send slave address and decide the initial |
| * transfer state. |
| * |
| * @param base pointer to FLEXIO_I2C_Type structure |
| * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state |
| * @param transfer pointer to flexio_i2c_master_transfer_t structure |
| */ |
| static status_t FLEXIO_I2C_MasterTransferInitStateMachine(FLEXIO_I2C_Type *base, |
| flexio_i2c_master_handle_t *handle, |
| flexio_i2c_master_transfer_t *xfer); |
| |
| /*! |
| * @brief Master run transfer state machine to perform a byte of transfer. |
| * |
| * @param base pointer to FLEXIO_I2C_Type structure |
| * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state |
| * @param statusFlags flexio i2c hardware status |
| * @retval kStatus_Success Successfully run state machine |
| * @retval kStatus_FLEXIO_I2C_Nak Receive Nak during transfer |
| */ |
| static status_t FLEXIO_I2C_MasterTransferRunStateMachine(FLEXIO_I2C_Type *base, |
| flexio_i2c_master_handle_t *handle, |
| uint32_t statusFlags); |
| |
| /*! |
| * @brief Complete transfer, disable interrupt and call callback. |
| * |
| * @param base pointer to FLEXIO_I2C_Type structure |
| * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state |
| * @param status flexio transfer status |
| */ |
| static void FLEXIO_I2C_MasterTransferComplete(FLEXIO_I2C_Type *base, |
| flexio_i2c_master_handle_t *handle, |
| status_t status); |
| |
| /******************************************************************************* |
| * Codes |
| ******************************************************************************/ |
| |
| uint32_t FLEXIO_I2C_GetInstance(FLEXIO_I2C_Type *base) |
| { |
| return FLEXIO_GetInstance(base->flexioBase); |
| } |
| |
| static status_t FLEXIO_I2C_MasterTransferInitStateMachine(FLEXIO_I2C_Type *base, |
| flexio_i2c_master_handle_t *handle, |
| flexio_i2c_master_transfer_t *xfer) |
| { |
| bool needRestart; |
| uint32_t byteCount; |
| |
| /* Init the handle member. */ |
| handle->transfer.slaveAddress = xfer->slaveAddress; |
| handle->transfer.direction = xfer->direction; |
| handle->transfer.subaddress = xfer->subaddress; |
| handle->transfer.subaddressSize = xfer->subaddressSize; |
| handle->transfer.data = xfer->data; |
| handle->transfer.dataSize = xfer->dataSize; |
| handle->transfer.flags = xfer->flags; |
| handle->transferSize = xfer->dataSize; |
| |
| /* Initial state, i2c check address state. */ |
| handle->state = kFLEXIO_I2C_CheckAddress; |
| |
| /* Clear all status before transfer. */ |
| FLEXIO_I2C_MasterClearStatusFlags(base, kFLEXIO_I2C_ReceiveNakFlag); |
| |
| /* Calculate whether need to send re-start. */ |
| needRestart = (handle->transfer.subaddressSize != 0) && (handle->transfer.direction == kFLEXIO_I2C_Read); |
| |
| /* Calculate total byte count in a frame. */ |
| byteCount = 1; |
| |
| if (!needRestart) |
| { |
| byteCount += handle->transfer.dataSize; |
| } |
| |
| if (handle->transfer.subaddressSize != 0) |
| { |
| byteCount += handle->transfer.subaddressSize; |
| /* Next state, send command byte. */ |
| handle->state = kFLEXIO_I2C_SendCommand; |
| } |
| |
| /* Configure data count. */ |
| if (FLEXIO_I2C_MasterSetTransferCount(base, byteCount) != kStatus_Success) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| while (!((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1U << base->shifterIndex[0])))) |
| { |
| } |
| |
| /* Send address byte first. */ |
| if (needRestart) |
| { |
| FLEXIO_I2C_MasterStart(base, handle->transfer.slaveAddress, kFLEXIO_I2C_Write); |
| } |
| else |
| { |
| FLEXIO_I2C_MasterStart(base, handle->transfer.slaveAddress, handle->transfer.direction); |
| } |
| |
| return kStatus_Success; |
| } |
| |
| static status_t FLEXIO_I2C_MasterTransferRunStateMachine(FLEXIO_I2C_Type *base, |
| flexio_i2c_master_handle_t *handle, |
| uint32_t statusFlags) |
| { |
| if (statusFlags & kFLEXIO_I2C_ReceiveNakFlag) |
| { |
| /* Clear receive nak flag. */ |
| FLEXIO_ClearShifterErrorFlags(base->flexioBase, 1U << base->shifterIndex[1]); |
| |
| if ((!((handle->state == kFLEXIO_I2C_SendData) && (handle->transfer.dataSize == 0U))) && |
| (!(((handle->state == kFLEXIO_I2C_ReceiveData) || (handle->state == kFLEXIO_I2C_ReceiveDataBegin)) && |
| (handle->transfer.dataSize == 1U)))) |
| { |
| FLEXIO_I2C_MasterReadByte(base); |
| |
| FLEXIO_I2C_MasterAbortStop(base); |
| |
| handle->state = kFLEXIO_I2C_Idle; |
| |
| return kStatus_FLEXIO_I2C_Nak; |
| } |
| } |
| |
| if (handle->state == kFLEXIO_I2C_CheckAddress) |
| { |
| if (handle->transfer.direction == kFLEXIO_I2C_Write) |
| { |
| /* Next state, send data. */ |
| handle->state = kFLEXIO_I2C_SendData; |
| } |
| else |
| { |
| /* Next state, receive data begin. */ |
| handle->state = kFLEXIO_I2C_ReceiveDataBegin; |
| } |
| } |
| |
| if ((statusFlags & kFLEXIO_I2C_RxFullFlag) && (handle->state != kFLEXIO_I2C_ReceiveData)) |
| { |
| FLEXIO_I2C_MasterReadByte(base); |
| } |
| |
| switch (handle->state) |
| { |
| case kFLEXIO_I2C_SendCommand: |
| if (statusFlags & kFLEXIO_I2C_TxEmptyFlag) |
| { |
| if (handle->transfer.subaddressSize > 0) |
| { |
| handle->transfer.subaddressSize--; |
| FLEXIO_I2C_MasterWriteByte( |
| base, ((handle->transfer.subaddress) >> (8 * handle->transfer.subaddressSize))); |
| |
| if (handle->transfer.subaddressSize == 0) |
| { |
| /* Load re-start in advance. */ |
| if (handle->transfer.direction == kFLEXIO_I2C_Read) |
| { |
| while (!((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1U << base->shifterIndex[0])))) |
| { |
| } |
| FLEXIO_I2C_MasterRepeatedStart(base); |
| } |
| } |
| } |
| else |
| { |
| if (handle->transfer.direction == kFLEXIO_I2C_Write) |
| { |
| /* Next state, send data. */ |
| handle->state = kFLEXIO_I2C_SendData; |
| |
| /* Send first byte of data. */ |
| if (handle->transfer.dataSize > 0) |
| { |
| FLEXIO_I2C_MasterWriteByte(base, *handle->transfer.data); |
| |
| handle->transfer.data++; |
| handle->transfer.dataSize--; |
| } |
| } |
| else |
| { |
| FLEXIO_I2C_MasterSetTransferCount(base, (handle->transfer.dataSize + 1)); |
| FLEXIO_I2C_MasterStart(base, handle->transfer.slaveAddress, kFLEXIO_I2C_Read); |
| |
| /* Next state, receive data begin. */ |
| handle->state = kFLEXIO_I2C_ReceiveDataBegin; |
| } |
| } |
| } |
| break; |
| |
| /* Send command byte. */ |
| case kFLEXIO_I2C_SendData: |
| if (statusFlags & kFLEXIO_I2C_TxEmptyFlag) |
| { |
| /* Send one byte of data. */ |
| if (handle->transfer.dataSize > 0) |
| { |
| FLEXIO_I2C_MasterWriteByte(base, *handle->transfer.data); |
| |
| handle->transfer.data++; |
| handle->transfer.dataSize--; |
| } |
| else |
| { |
| FLEXIO_I2C_MasterStop(base); |
| |
| while (!(FLEXIO_I2C_MasterGetStatusFlags(base) & kFLEXIO_I2C_RxFullFlag)) |
| { |
| } |
| FLEXIO_I2C_MasterReadByte(base); |
| |
| handle->state = kFLEXIO_I2C_Idle; |
| } |
| } |
| break; |
| |
| case kFLEXIO_I2C_ReceiveDataBegin: |
| if (statusFlags & kFLEXIO_I2C_RxFullFlag) |
| { |
| handle->state = kFLEXIO_I2C_ReceiveData; |
| /* Send nak at the last receive byte. */ |
| if (handle->transfer.dataSize == 1) |
| { |
| FLEXIO_I2C_MasterEnableAck(base, false); |
| while (!((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1U << base->shifterIndex[0])))) |
| { |
| } |
| FLEXIO_I2C_MasterStop(base); |
| } |
| else |
| { |
| FLEXIO_I2C_MasterEnableAck(base, true); |
| } |
| } |
| else if (statusFlags & kFLEXIO_I2C_TxEmptyFlag) |
| { |
| /* Read one byte of data. */ |
| FLEXIO_I2C_MasterWriteByte(base, 0xFFFFFFFFU); |
| } |
| else |
| { |
| } |
| break; |
| |
| case kFLEXIO_I2C_ReceiveData: |
| if (statusFlags & kFLEXIO_I2C_RxFullFlag) |
| { |
| *handle->transfer.data = FLEXIO_I2C_MasterReadByte(base); |
| handle->transfer.data++; |
| if (handle->transfer.dataSize--) |
| { |
| if (handle->transfer.dataSize == 0) |
| { |
| FLEXIO_I2C_MasterDisableInterrupts(base, kFLEXIO_I2C_RxFullInterruptEnable); |
| handle->state = kFLEXIO_I2C_Idle; |
| } |
| |
| /* Send nak at the last receive byte. */ |
| if (handle->transfer.dataSize == 1) |
| { |
| FLEXIO_I2C_MasterEnableAck(base, false); |
| while (!((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1U << base->shifterIndex[0])))) |
| { |
| } |
| FLEXIO_I2C_MasterStop(base); |
| } |
| } |
| } |
| else if (statusFlags & kFLEXIO_I2C_TxEmptyFlag) |
| { |
| if (handle->transfer.dataSize > 1) |
| { |
| FLEXIO_I2C_MasterWriteByte(base, 0xFFFFFFFFU); |
| } |
| } |
| else |
| { |
| } |
| break; |
| |
| default: |
| break; |
| } |
| |
| return kStatus_Success; |
| } |
| |
| static void FLEXIO_I2C_MasterTransferComplete(FLEXIO_I2C_Type *base, |
| flexio_i2c_master_handle_t *handle, |
| status_t status) |
| { |
| FLEXIO_I2C_MasterDisableInterrupts(base, kFLEXIO_I2C_TxEmptyInterruptEnable | kFLEXIO_I2C_RxFullInterruptEnable); |
| |
| if (handle->completionCallback) |
| { |
| handle->completionCallback(base, handle, status, handle->userData); |
| } |
| } |
| |
| status_t FLEXIO_I2C_MasterInit(FLEXIO_I2C_Type *base, flexio_i2c_master_config_t *masterConfig, uint32_t srcClock_Hz) |
| { |
| assert(base && masterConfig); |
| |
| flexio_shifter_config_t shifterConfig; |
| flexio_timer_config_t timerConfig; |
| uint32_t controlVal = 0; |
| uint16_t timerDiv = 0; |
| status_t result = kStatus_Success; |
| |
| memset(&shifterConfig, 0, sizeof(shifterConfig)); |
| memset(&timerConfig, 0, sizeof(timerConfig)); |
| |
| #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
| /* Ungate flexio clock. */ |
| CLOCK_EnableClock(s_flexioClocks[FLEXIO_I2C_GetInstance(base)]); |
| #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
| |
| /* Do hardware configuration. */ |
| /* 1. Configure the shifter 0 for tx. */ |
| shifterConfig.timerSelect = base->timerIndex[1]; |
| shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive; |
| shifterConfig.pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection; |
| shifterConfig.pinSelect = base->SDAPinIndex; |
| shifterConfig.pinPolarity = kFLEXIO_PinActiveLow; |
| shifterConfig.shifterMode = kFLEXIO_ShifterModeTransmit; |
| shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin; |
| shifterConfig.shifterStop = kFLEXIO_ShifterStopBitHigh; |
| shifterConfig.shifterStart = kFLEXIO_ShifterStartBitLow; |
| |
| FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[0], &shifterConfig); |
| |
| /* 2. Configure the shifter 1 for rx. */ |
| shifterConfig.timerSelect = base->timerIndex[1]; |
| shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive; |
| shifterConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled; |
| shifterConfig.pinSelect = base->SDAPinIndex; |
| shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh; |
| shifterConfig.shifterMode = kFLEXIO_ShifterModeReceive; |
| shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin; |
| shifterConfig.shifterStop = kFLEXIO_ShifterStopBitLow; |
| shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable; |
| |
| FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[1], &shifterConfig); |
| |
| /*3. Configure the timer 0 for generating bit clock. */ |
| timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]); |
| timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow; |
| timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal; |
| timerConfig.pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection; |
| timerConfig.pinSelect = base->SCLPinIndex; |
| timerConfig.pinPolarity = kFLEXIO_PinActiveHigh; |
| timerConfig.timerMode = kFLEXIO_TimerModeDual8BitBaudBit; |
| timerConfig.timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset; |
| timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput; |
| timerConfig.timerReset = kFLEXIO_TimerResetOnTimerPinEqualToTimerOutput; |
| timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare; |
| timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerHigh; |
| timerConfig.timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable; |
| timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled; |
| |
| /* Set TIMCMP[7:0] = (baud rate divider / 2) - 1. */ |
| timerDiv = (srcClock_Hz / masterConfig->baudRate_Bps) / 2 - 1; |
| |
| if (timerDiv > 0xFFU) |
| { |
| result = kStatus_InvalidArgument; |
| return result; |
| } |
| |
| timerConfig.timerCompare = timerDiv; |
| |
| FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[0], &timerConfig); |
| |
| /* 4. Configure the timer 1 for controlling shifters. */ |
| timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]); |
| timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow; |
| timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal; |
| timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled; |
| timerConfig.pinSelect = base->SCLPinIndex; |
| timerConfig.pinPolarity = kFLEXIO_PinActiveLow; |
| timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit; |
| timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset; |
| timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnPinInputShiftPinInput; |
| timerConfig.timerReset = kFLEXIO_TimerResetNever; |
| timerConfig.timerDisable = kFLEXIO_TimerDisableOnPreTimerDisable; |
| timerConfig.timerEnable = kFLEXIO_TimerEnableOnPrevTimerEnable; |
| timerConfig.timerStop = kFLEXIO_TimerStopBitEnableOnTimerCompare; |
| timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled; |
| |
| /* Set TIMCMP[15:0] = (number of bits x 2) - 1. */ |
| timerConfig.timerCompare = 8 * 2 - 1; |
| |
| FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[1], &timerConfig); |
| |
| /* Configure FLEXIO I2C Master. */ |
| controlVal = base->flexioBase->CTRL; |
| controlVal &= |
| ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK); |
| controlVal |= (FLEXIO_CTRL_DBGE(masterConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(masterConfig->enableFastAccess) | |
| FLEXIO_CTRL_FLEXEN(masterConfig->enableMaster)); |
| if (!masterConfig->enableInDoze) |
| { |
| controlVal |= FLEXIO_CTRL_DOZEN_MASK; |
| } |
| |
| base->flexioBase->CTRL = controlVal; |
| return result; |
| } |
| |
| void FLEXIO_I2C_MasterDeinit(FLEXIO_I2C_Type *base) |
| { |
| base->flexioBase->SHIFTCFG[base->shifterIndex[0]] = 0; |
| base->flexioBase->SHIFTCTL[base->shifterIndex[0]] = 0; |
| base->flexioBase->SHIFTCFG[base->shifterIndex[1]] = 0; |
| base->flexioBase->SHIFTCTL[base->shifterIndex[1]] = 0; |
| base->flexioBase->TIMCFG[base->timerIndex[0]] = 0; |
| base->flexioBase->TIMCMP[base->timerIndex[0]] = 0; |
| base->flexioBase->TIMCTL[base->timerIndex[0]] = 0; |
| base->flexioBase->TIMCFG[base->timerIndex[1]] = 0; |
| base->flexioBase->TIMCMP[base->timerIndex[1]] = 0; |
| base->flexioBase->TIMCTL[base->timerIndex[1]] = 0; |
| /* Clear the shifter flag. */ |
| base->flexioBase->SHIFTSTAT = (1U << base->shifterIndex[0]); |
| base->flexioBase->SHIFTSTAT = (1U << base->shifterIndex[1]); |
| /* Clear the timer flag. */ |
| base->flexioBase->TIMSTAT = (1U << base->timerIndex[0]); |
| base->flexioBase->TIMSTAT = (1U << base->timerIndex[1]); |
| } |
| |
| void FLEXIO_I2C_MasterGetDefaultConfig(flexio_i2c_master_config_t *masterConfig) |
| { |
| assert(masterConfig); |
| |
| masterConfig->enableMaster = true; |
| masterConfig->enableInDoze = false; |
| masterConfig->enableInDebug = true; |
| masterConfig->enableFastAccess = false; |
| |
| /* Default baud rate at 100kbps. */ |
| masterConfig->baudRate_Bps = 100000U; |
| } |
| |
| uint32_t FLEXIO_I2C_MasterGetStatusFlags(FLEXIO_I2C_Type *base) |
| { |
| uint32_t status = 0; |
| |
| status = |
| ((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1U << base->shifterIndex[0])) >> base->shifterIndex[0]); |
| status |= |
| (((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1U << base->shifterIndex[1])) >> (base->shifterIndex[1])) |
| << 1U); |
| status |= |
| (((FLEXIO_GetShifterErrorFlags(base->flexioBase) & (1U << base->shifterIndex[1])) >> (base->shifterIndex[1])) |
| << 2U); |
| |
| return status; |
| } |
| |
| void FLEXIO_I2C_MasterClearStatusFlags(FLEXIO_I2C_Type *base, uint32_t mask) |
| { |
| if (mask & kFLEXIO_I2C_TxEmptyFlag) |
| { |
| FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1U << base->shifterIndex[0]); |
| } |
| |
| if (mask & kFLEXIO_I2C_RxFullFlag) |
| { |
| FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1U << base->shifterIndex[1]); |
| } |
| |
| if (mask & kFLEXIO_I2C_ReceiveNakFlag) |
| { |
| FLEXIO_ClearShifterErrorFlags(base->flexioBase, 1U << base->shifterIndex[1]); |
| } |
| } |
| |
| void FLEXIO_I2C_MasterEnableInterrupts(FLEXIO_I2C_Type *base, uint32_t mask) |
| { |
| if (mask & kFLEXIO_I2C_TxEmptyInterruptEnable) |
| { |
| FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1U << base->shifterIndex[0]); |
| } |
| if (mask & kFLEXIO_I2C_RxFullInterruptEnable) |
| { |
| FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1U << base->shifterIndex[1]); |
| } |
| } |
| |
| void FLEXIO_I2C_MasterDisableInterrupts(FLEXIO_I2C_Type *base, uint32_t mask) |
| { |
| if (mask & kFLEXIO_I2C_TxEmptyInterruptEnable) |
| { |
| FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1U << base->shifterIndex[0]); |
| } |
| if (mask & kFLEXIO_I2C_RxFullInterruptEnable) |
| { |
| FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1U << base->shifterIndex[1]); |
| } |
| } |
| |
| void FLEXIO_I2C_MasterSetBaudRate(FLEXIO_I2C_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz) |
| { |
| uint16_t timerDiv = 0; |
| uint16_t timerCmp = 0; |
| FLEXIO_Type *flexioBase = base->flexioBase; |
| |
| /* Set TIMCMP[7:0] = (baud rate divider / 2) - 1.*/ |
| timerDiv = srcClock_Hz / baudRate_Bps; |
| timerDiv = timerDiv / 2 - 1U; |
| |
| timerCmp = flexioBase->TIMCMP[base->timerIndex[0]]; |
| timerCmp &= 0xFF00; |
| timerCmp |= timerDiv; |
| |
| flexioBase->TIMCMP[base->timerIndex[0]] = timerCmp; |
| } |
| |
| status_t FLEXIO_I2C_MasterSetTransferCount(FLEXIO_I2C_Type *base, uint8_t count) |
| { |
| if (count > 14U) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| uint16_t timerCmp = 0; |
| uint32_t timerConfig = 0; |
| FLEXIO_Type *flexioBase = base->flexioBase; |
| |
| timerCmp = flexioBase->TIMCMP[base->timerIndex[0]]; |
| timerCmp &= 0x00FFU; |
| timerCmp |= (count * 18 + 1U) << 8U; |
| flexioBase->TIMCMP[base->timerIndex[0]] = timerCmp; |
| timerConfig = flexioBase->TIMCFG[base->timerIndex[0]]; |
| timerConfig &= ~FLEXIO_TIMCFG_TIMDIS_MASK; |
| timerConfig |= FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare); |
| flexioBase->TIMCFG[base->timerIndex[0]] = timerConfig; |
| |
| return kStatus_Success; |
| } |
| |
| void FLEXIO_I2C_MasterStart(FLEXIO_I2C_Type *base, uint8_t address, flexio_i2c_direction_t direction) |
| { |
| uint32_t data; |
| |
| data = ((uint32_t)address) << 1U | ((direction == kFLEXIO_I2C_Read) ? 1U : 0U); |
| |
| FLEXIO_I2C_MasterWriteByte(base, data); |
| } |
| |
| void FLEXIO_I2C_MasterRepeatedStart(FLEXIO_I2C_Type *base) |
| { |
| /* Prepare for RESTART condition, no stop.*/ |
| FLEXIO_I2C_MasterWriteByte(base, 0xFFFFFFFFU); |
| } |
| |
| void FLEXIO_I2C_MasterStop(FLEXIO_I2C_Type *base) |
| { |
| /* Prepare normal stop. */ |
| FLEXIO_I2C_MasterSetTransferCount(base, 0x0U); |
| FLEXIO_I2C_MasterWriteByte(base, 0x0U); |
| } |
| |
| void FLEXIO_I2C_MasterAbortStop(FLEXIO_I2C_Type *base) |
| { |
| uint32_t tmpConfig; |
| |
| /* Prepare abort stop. */ |
| tmpConfig = base->flexioBase->TIMCFG[base->timerIndex[0]]; |
| tmpConfig &= ~FLEXIO_TIMCFG_TIMDIS_MASK; |
| tmpConfig |= FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnPinBothEdge); |
| base->flexioBase->TIMCFG[base->timerIndex[0]] = tmpConfig; |
| } |
| |
| void FLEXIO_I2C_MasterEnableAck(FLEXIO_I2C_Type *base, bool enable) |
| { |
| uint32_t tmpConfig = 0; |
| |
| tmpConfig = base->flexioBase->SHIFTCFG[base->shifterIndex[0]]; |
| tmpConfig &= ~FLEXIO_SHIFTCFG_SSTOP_MASK; |
| if (enable) |
| { |
| tmpConfig |= FLEXIO_SHIFTCFG_SSTOP(kFLEXIO_ShifterStopBitLow); |
| } |
| else |
| { |
| tmpConfig |= FLEXIO_SHIFTCFG_SSTOP(kFLEXIO_ShifterStopBitHigh); |
| } |
| base->flexioBase->SHIFTCFG[base->shifterIndex[0]] = tmpConfig; |
| } |
| |
| status_t FLEXIO_I2C_MasterWriteBlocking(FLEXIO_I2C_Type *base, const uint8_t *txBuff, uint8_t txSize) |
| { |
| assert(txBuff); |
| assert(txSize); |
| |
| uint32_t status; |
| |
| while (txSize--) |
| { |
| FLEXIO_I2C_MasterWriteByte(base, *txBuff++); |
| |
| /* Wait until data transfer complete. */ |
| while (!((status = FLEXIO_I2C_MasterGetStatusFlags(base)) & kFLEXIO_I2C_RxFullFlag)) |
| { |
| } |
| |
| if (status & kFLEXIO_I2C_ReceiveNakFlag) |
| { |
| FLEXIO_ClearShifterErrorFlags(base->flexioBase, 1U << base->shifterIndex[1]); |
| return kStatus_FLEXIO_I2C_Nak; |
| } |
| } |
| return kStatus_Success; |
| } |
| |
| void FLEXIO_I2C_MasterReadBlocking(FLEXIO_I2C_Type *base, uint8_t *rxBuff, uint8_t rxSize) |
| { |
| assert(rxBuff); |
| assert(rxSize); |
| |
| while (rxSize--) |
| { |
| /* Wait until data transfer complete. */ |
| while (!(FLEXIO_I2C_MasterGetStatusFlags(base) & kFLEXIO_I2C_RxFullFlag)) |
| { |
| } |
| |
| *rxBuff++ = FLEXIO_I2C_MasterReadByte(base); |
| } |
| } |
| |
| status_t FLEXIO_I2C_MasterTransferBlocking(FLEXIO_I2C_Type *base, flexio_i2c_master_transfer_t *xfer) |
| { |
| assert(xfer); |
| |
| flexio_i2c_master_handle_t tmpHandle; |
| uint32_t statusFlags; |
| uint32_t result = kStatus_Success; |
| |
| /* Zero the handle. */ |
| memset(&tmpHandle, 0, sizeof(tmpHandle)); |
| |
| /* Set up transfer machine. */ |
| FLEXIO_I2C_MasterTransferInitStateMachine(base, &tmpHandle, xfer); |
| |
| do |
| { |
| /* Wait either tx empty or rx full flag is asserted. */ |
| while (!((statusFlags = FLEXIO_I2C_MasterGetStatusFlags(base)) & |
| (kFLEXIO_I2C_TxEmptyFlag | kFLEXIO_I2C_RxFullFlag))) |
| { |
| } |
| |
| result = FLEXIO_I2C_MasterTransferRunStateMachine(base, &tmpHandle, statusFlags); |
| |
| } while ((tmpHandle.state != kFLEXIO_I2C_Idle) && (result == kStatus_Success)); |
| |
| return result; |
| } |
| |
| status_t FLEXIO_I2C_MasterTransferCreateHandle(FLEXIO_I2C_Type *base, |
| flexio_i2c_master_handle_t *handle, |
| flexio_i2c_master_transfer_callback_t callback, |
| void *userData) |
| { |
| assert(handle); |
| |
| IRQn_Type flexio_irqs[] = FLEXIO_IRQS; |
| |
| /* Zero the handle. */ |
| memset(handle, 0, sizeof(*handle)); |
| |
| /* Register callback and userData. */ |
| handle->completionCallback = callback; |
| handle->userData = userData; |
| |
| /* Enable interrupt in NVIC. */ |
| EnableIRQ(flexio_irqs[FLEXIO_I2C_GetInstance(base)]); |
| |
| /* Save the context in global variables to support the double weak mechanism. */ |
| return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_I2C_MasterTransferHandleIRQ); |
| } |
| |
| status_t FLEXIO_I2C_MasterTransferNonBlocking(FLEXIO_I2C_Type *base, |
| flexio_i2c_master_handle_t *handle, |
| flexio_i2c_master_transfer_t *xfer) |
| { |
| assert(handle); |
| assert(xfer); |
| |
| if (handle->state != kFLEXIO_I2C_Idle) |
| { |
| return kStatus_FLEXIO_I2C_Busy; |
| } |
| else |
| { |
| /* Set up transfer machine. */ |
| FLEXIO_I2C_MasterTransferInitStateMachine(base, handle, xfer); |
| |
| /* Enable both tx empty and rxfull interrupt. */ |
| FLEXIO_I2C_MasterEnableInterrupts(base, kFLEXIO_I2C_TxEmptyInterruptEnable | kFLEXIO_I2C_RxFullInterruptEnable); |
| |
| return kStatus_Success; |
| } |
| } |
| |
| void FLEXIO_I2C_MasterTransferAbort(FLEXIO_I2C_Type *base, flexio_i2c_master_handle_t *handle) |
| { |
| assert(handle); |
| |
| /* Disable interrupts. */ |
| FLEXIO_I2C_MasterDisableInterrupts(base, kFLEXIO_I2C_TxEmptyInterruptEnable | kFLEXIO_I2C_RxFullInterruptEnable); |
| |
| /* Reset to idle state. */ |
| handle->state = kFLEXIO_I2C_Idle; |
| } |
| |
| status_t FLEXIO_I2C_MasterTransferGetCount(FLEXIO_I2C_Type *base, flexio_i2c_master_handle_t *handle, size_t *count) |
| { |
| if (!count) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| *count = handle->transferSize - handle->transfer.dataSize; |
| |
| return kStatus_Success; |
| } |
| |
| void FLEXIO_I2C_MasterTransferHandleIRQ(void *i2cType, void *i2cHandle) |
| { |
| FLEXIO_I2C_Type *base = (FLEXIO_I2C_Type *)i2cType; |
| flexio_i2c_master_handle_t *handle = (flexio_i2c_master_handle_t *)i2cHandle; |
| uint32_t statusFlags; |
| status_t result; |
| |
| statusFlags = FLEXIO_I2C_MasterGetStatusFlags(base); |
| |
| result = FLEXIO_I2C_MasterTransferRunStateMachine(base, handle, statusFlags); |
| |
| if (handle->state == kFLEXIO_I2C_Idle) |
| { |
| FLEXIO_I2C_MasterTransferComplete(base, handle, result); |
| } |
| } |