added prescaler for 16 bit pwm in LPC1347 target
Fork of mbed-dev by
Diff: targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL43Z/drivers/fsl_flexio_i2c_master.c
- Revision:
- 144:ef7eb2e8f9f7
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL43Z/drivers/fsl_flexio_i2c_master.c Fri Sep 02 15:07:44 2016 +0100 @@ -0,0 +1,732 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * 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 Freescale Semiconductor, Inc. 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*/ +}; + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @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 + ******************************************************************************/ + +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); + handle->state = kFLEXIO_I2C_Idle; + } + } + break; + + case kFLEXIO_I2C_ReceiveDataBegin: + if (statusFlags & kFLEXIO_I2C_TxEmptyFlag) + { + /* Read one byte of data. */ + FLEXIO_I2C_MasterWriteByte(base, 0xFFFFFFFFU); + + /* 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 + { + handle->state = kFLEXIO_I2C_ReceiveData; + } + break; + + case kFLEXIO_I2C_ReceiveData: + if (statusFlags & kFLEXIO_I2C_RxFullFlag) + { + *handle->transfer.data = FLEXIO_I2C_MasterReadByte(base); + handle->transfer.data++; + /* Receive one byte of data. */ + if (handle->transfer.dataSize--) + { + if (handle->transfer.dataSize != 0) + { + FLEXIO_I2C_MasterWriteByte(base, 0xFFFFFFFFU); + } + else + { + 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); + } + } + } + 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); + } +} + +void 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; + + memset(&shifterConfig, 0, sizeof(shifterConfig)); + memset(&timerConfig, 0, sizeof(timerConfig)); + + /* Ungate flexio clock. */ + CLOCK_EnableClock(kCLOCK_Flexio0); + + FLEXIO_Reset(base->flexioBase); + + /* 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. */ + timerConfig.timerCompare = (srcClock_Hz / masterConfig->baudRate_Bps) / 2 - 1; + + 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_DOZEN(masterConfig->enableInDoze) | FLEXIO_CTRL_DBGE(masterConfig->enableInDebug) | + FLEXIO_CTRL_FASTACC(masterConfig->enableFastAccess) | FLEXIO_CTRL_FLEXEN(masterConfig->enableMaster)); + + base->flexioBase->CTRL = controlVal; +} + +void FLEXIO_I2C_MasterDeinit(FLEXIO_I2C_Type *base) +{ + FLEXIO_Deinit(base->flexioBase); +} + +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_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[0]); + + /* 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); + } +}