/***************************************************************************//**
* \file cy_scb_i2c.c
* \version 3.30
*
* Provides I2C API implementation of the SCB driver.
*
********************************************************************************
* \copyright
* Copyright 2016-2025 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#include "cy_device.h"

#if (defined (CY_IP_MXSCB) || defined (CY_IP_MXS22SCB))

#include "cy_scb_i2c.h"

#if defined(__cplusplus)
extern "C" {
#endif

/***************************************
*        Function Prototypes
***************************************/

static void SlaveHandleAddress     (CySCB_Type *base, cy_stc_scb_i2c_context_t *context);
static void SlaveHandleDataReceive (CySCB_Type *base, cy_stc_scb_i2c_context_t *context);
static void SlaveHandleDataTransmit(CySCB_Type *base, cy_stc_scb_i2c_context_t *context);
static void SlaveHandleStop        (CySCB_Type *base, cy_stc_scb_i2c_context_t *context);

static void MasterHandleEvents      (CySCB_Type *base, cy_stc_scb_i2c_context_t *context);
static void MasterHandleDataTransmit(CySCB_Type *base, cy_stc_scb_i2c_context_t *context);
static void MasterHandleDataReceive (CySCB_Type *base, cy_stc_scb_i2c_context_t *context);
static void MasterHandleStop        (CySCB_Type *base, cy_stc_scb_i2c_context_t *context);
static void MasterHandleComplete    (CySCB_Type *base, cy_stc_scb_i2c_context_t *context);

static cy_en_scb_i2c_status_t HandleStatus(CySCB_Type *base, uint32_t status,
                                           cy_stc_scb_i2c_context_t *context);
static uint32_t WaitOneUnit(uint32_t *timeout);


/*******************************************************************************
* Function Name: Cy_SCB_I2C_Init
****************************************************************************//**
*
* Initializes the SCB for the I2C operation.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param config
* The pointer to the configuration structure \ref cy_stc_scb_i2c_config_t.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* \ref cy_en_scb_i2c_status_t
*
* \note
* If SCB is already enabled, ensure that the SCB block is disabled \ref Cy_SCB_I2C_Disable
* before calling this function.
*******************************************************************************/
cy_en_scb_i2c_status_t Cy_SCB_I2C_Init(CySCB_Type *base, cy_stc_scb_i2c_config_t const *config, cy_stc_scb_i2c_context_t *context)
{
    /* Input parameters verification */
    if ((NULL == base) || (NULL == config) || (NULL == context))
    {
        return CY_SCB_I2C_BAD_PARAM;
    }

    CY_ASSERT_L3(CY_SCB_I2C_IS_MODE_VALID(config->i2cMode));
    CY_ASSERT_L2((config->useRxFifo) ? (!config->acceptAddrInFifo) : true);
    CY_ASSERT_L2(CY_SCB_IS_I2C_ADDR_VALID     (config->slaveAddress));
    CY_ASSERT_L2(CY_SCB_I2C_IS_ADDR_MASK_VALID(config->slaveAddressMask));
    CY_ASSERT_L2(CY_SCB_I2C_IS_PHASE_OVERSAMPLE_VALID(config->highPhaseDutyCycle));
    CY_ASSERT_L2(CY_SCB_I2C_IS_PHASE_OVERSAMPLE_VALID(config->lowPhaseDutyCycle));

    /* Configure the I2C interface */
    SCB_CTRL(base) = _BOOL2FLD(SCB_CTRL_ADDR_ACCEPT, config->acceptAddrInFifo)   |
                     _BOOL2FLD(SCB_CTRL_EC_AM_MODE, config->enableWakeFromSleep);
#if(defined (CY_IP_MXSCB_VERSION) && (CY_IP_MXSCB_VERSION==1))
    SCB_CTRL(base) |= SCB_CTRL_BYTE_MODE_Msk;
#endif /* CY_IP_MXSCB_VERSION */

    SCB_I2C_CTRL(base) = _BOOL2FLD(SCB_I2C_CTRL_S_GENERAL_IGNORE, !config->ackGeneralAddr)        |
                         _VAL2FLD(SCB_I2C_CTRL_HIGH_PHASE_OVS, (config->highPhaseDutyCycle - 1U)) |
                         _VAL2FLD(SCB_I2C_CTRL_LOW_PHASE_OVS,  (config->lowPhaseDutyCycle - 1U))  |
                         _VAL2FLD(CY_SCB_I2C_CTRL_MODE, (uint32_t) config->i2cMode);

    {
        /* Enable digital filter for only for master modes */
        bool enableDigFilter = (CY_SCB_I2C_SLAVE != config->i2cMode) && (config->enableDigitalFilter);

        /* Configure the RX direction */
        SCB_RX_CTRL(base)      = _BOOL2FLD(SCB_RX_CTRL_MEDIAN, enableDigFilter) |
                                 CY_SCB_I2C_RX_CTRL;

        /* Configure an analog filter */
        SCB_I2C_CFG(base) = (enableDigFilter) ? CY_SCB_I2C_DISABLE_ANALOG_FITLER : CY_SCB_I2C_ENABLE_ANALOG_FITLER;
    }

    SCB_RX_FIFO_CTRL(base) = (config->useRxFifo ? (CY_SCB_I2C_FIFO_SIZE - 1UL) : 0UL);

    /* Set the default address and mask */
    SCB_RX_MATCH(base) = _VAL2FLD(SCB_RX_MATCH_ADDR, ((uint32_t) config->slaveAddress << 1UL)) |
                         _VAL2FLD(SCB_RX_MATCH_MASK, (uint32_t)  config->slaveAddressMask);

    /* Configure the TX direction */
    SCB_TX_CTRL(base)      = CY_SCB_I2C_TX_CTRL;
    SCB_TX_FIFO_CTRL(base) = (config->useTxFifo ? CY_SCB_I2C_HALF_FIFO_SIZE : 1UL);

    /* Configure interrupt sources */
    SCB_INTR_SPI_EC_MASK(base) = 0UL;
    SCB_INTR_I2C_EC_MASK(base) = 0UL;
    SCB_INTR_RX_MASK(base)     = 0UL;
    SCB_INTR_TX_MASK(base)     = 0UL;
    SCB_INTR_M_MASK(base)      = 0UL;

    SCB_INTR_S_MASK(base) = (CY_SCB_I2C_MASTER != config->i2cMode) ? CY_SCB_I2C_SLAVE_INTR : 0UL;

    /* Initialize the context */
    context->useRxFifo = config->useRxFifo;
    context->useTxFifo = config->useTxFifo;

    context->state = CY_SCB_I2C_IDLE;

    /* Master-specific */
    context->masterStatus     = 0UL;
    context->masterBufferIdx  = 0UL;

    /* Slave-specific */
    context->slaveStatus       = 0UL;

    context->slaveRxBufferIdx  = 0UL;
    context->slaveRxBufferSize = 0UL;

    context->slaveTxBufferIdx  = 0UL;
    context->slaveTxBufferSize = 0UL;

    /* Unregister callbacks */
    context->cbEvents = NULL;
    context->cbAddr   = NULL;

    return CY_SCB_I2C_SUCCESS;
}


/*******************************************************************************
*  Function Name: Cy_SCB_I2C_DeInit
****************************************************************************//**
*
* De-initializes the SCB block and returns register values to default.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \note
* Ensure that the SCB block is disabled \ref Cy_SCB_I2C_Disable before calling this function.
*
*******************************************************************************/
void Cy_SCB_I2C_DeInit(CySCB_Type *base)
{
    /* Returns block registers into the default state */
    SCB_CTRL(base)     = CY_SCB_CTRL_DEF_VAL;
    SCB_I2C_CTRL(base) = CY_SCB_I2C_CTRL_DEF_VAL;
    SCB_I2C_CFG(base)  = CY_SCB_I2C_CFG_DEF_VAL;

    SCB_RX_CTRL(base)      = CY_SCB_RX_CTRL_DEF_VAL;
    SCB_RX_FIFO_CTRL(base) = 0UL;
    SCB_RX_MATCH(base)     = 0UL;

    SCB_TX_CTRL(base)      = CY_SCB_TX_CTRL_DEF_VAL;
    SCB_TX_FIFO_CTRL(base) = 0UL;

    SCB_INTR_SPI_EC_MASK(base) = 0UL;
    SCB_INTR_I2C_EC_MASK(base) = 0UL;
    SCB_INTR_RX_MASK(base)     = 0UL;
    SCB_INTR_TX_MASK(base)     = 0UL;
    SCB_INTR_M_MASK(base)      = 0UL;
    SCB_INTR_S_MASK(base)      = 0UL;
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_Disable
****************************************************************************//**
*
* Disables the SCB block and clears context statuses.
* Note that after the block is disabled, the TX and RX FIFOs and hardware
* statuses are cleared. Also, the hardware stops driving the output and
* ignores the input.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \note
* Calling this function when I2C is busy (master preforms transaction or slave
* was addressed and is communicating with master) may cause transaction corruption
* because the hardware stops driving the outputs and ignores the inputs.
* Ensure that I2C is not busy before calling this function.
*
*******************************************************************************/
void Cy_SCB_I2C_Disable(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    SCB_CTRL(base) &= (uint32_t) ~SCB_CTRL_ENABLED_Msk;

    /* Set the state to default and clear statuses */
    context->state        = CY_SCB_I2C_IDLE;
    context->masterStatus = 0UL;
    context->slaveStatus  = 0UL;
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_DeepSleepCallback
****************************************************************************//**
*
* This function handles the transition of the I2C SCB into and out of
* Deep Sleep mode. It prevents the device from entering Deep Sleep
* mode if the I2C slave or master is actively communicating.
* The  behavior of the I2C SCB in Deep Sleep depends on whether the SCB block is
* wakeup-capable or not:
* * <b>Wakeup-capable</b>: during Deep Sleep mode on incoming I2C slave address
*   the slave receives address and stretches the clock until the device is
*   awoken from Deep Sleep mode. If the slave address occurs before the device
*   enters Deep Sleep mode, the device will not enter Deep Sleep mode.
*   Only the I2C slave can be configured to be a wakeup source from Deep Sleep
*   mode.
* * <b>Not wakeup-capable</b>: the SCB is disabled in Deep Sleep mode.
*   It is re-enabled if the device fails to enter Deep Sleep mode or when the
*   device is awoken from Deep Sleep mode. While the SCB is disabled it stops
*   driving the outputs and ignores the inputs. The slave NACKs all incoming
*   addresses.
*
* This function must be called during execution of \ref Cy_SysPm_CpuEnterDeepSleep.
* To do it, register this function as a callback before calling
* \ref Cy_SysPm_CpuEnterDeepSleep : specify \ref CY_SYSPM_DEEPSLEEP as the callback
* type and call \ref Cy_SysPm_RegisterCallback.
*
* \param callbackParams
* The pointer to the callback parameters structure
* \ref cy_stc_syspm_callback_params_t.
*
* \param mode
* Callback mode, see \ref cy_en_syspm_callback_mode_t
*
* \return
* \ref cy_en_syspm_status_t
*
* Please refer to the section \ref group_scb_i2c_mclk_sync for more information.
*
*******************************************************************************/
cy_en_syspm_status_t Cy_SCB_I2C_DeepSleepCallback(cy_stc_syspm_callback_params_t *callbackParams, cy_en_syspm_callback_mode_t mode)
{
    CySCB_Type *locBase = (CySCB_Type *) callbackParams->base;
    cy_stc_scb_i2c_context_t *locContext = (cy_stc_scb_i2c_context_t *) callbackParams->context;

    cy_en_syspm_status_t retStatus = CY_SYSPM_FAIL;

    switch(mode)
    {
        case CY_SYSPM_CHECK_READY:
        {
            /* Disable the slave interrupt sources to protect the state */
            Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_CLEAR_ALL_INTR_SRC);

            /* If the I2C is in the IDLE state, it is ready for Deep Sleep mode
            * (either the master or the slave is not busy),
            * otherwise return fail and restore the slave interrupt sources.
            */
            if (CY_SCB_I2C_IDLE == locContext->state)
            {
                if (_FLD2BOOL(SCB_CTRL_EC_AM_MODE, SCB_CTRL(locBase)))
                {
                    /* The SCB is wakeup-capable: do not restore the address
                    * match and general call interrupt sources. The next
                    * transaction intended to the slave will be paused
                    * (SCL is stretched) before the address is ACKed because
                    * the corresponding interrupt source is disabled.
                    */
                    Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_I2C_SLAVE_INTR_NO_ADDR);
                }
                else
                {
                    /* The SCB is NOT wakeup-capable: disable the I2C. The slave
                    * stops responding to the master and the master stops
                    * driving the bus until the I2C is enabled. This happens
                    * when the device failed to enter into Deep Sleep mode or it
                    * is awaken from Deep Sleep mode.
                    */
                    Cy_SCB_I2C_Disable(locBase, locContext);
                    Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_I2C_SLAVE_INTR);
                }

                retStatus = CY_SYSPM_SUCCESS;
            }
            else
            {
                /* Restore the slave interrupt sources */
                Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_I2C_SLAVE_INTR);
            }
        }
        break;

        case CY_SYSPM_CHECK_FAIL:
        {
            /* The other driver is not ready for Deep Sleep mode. Restore
            * Active mode configuration.
            */

            if (_FLD2BOOL(SCB_CTRL_EC_AM_MODE, SCB_CTRL(locBase)))
            {
                /* The SCB is wakeup-capable: restore the slave interrupt sources */
                Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_I2C_SLAVE_INTR);
            }
            else
            {
                /* The SCB is NOT wakeup-capable: enable the I2C to operate */
                Cy_SCB_I2C_Enable(locBase);
            }

            retStatus = CY_SYSPM_SUCCESS;
        }
        break;

        case CY_SYSPM_BEFORE_TRANSITION:
        {
            /* This code executes inside the critical section. Enabling the
            * active interrupt source makes the interrupt pending in the NVIC.
            * However, the interrupt processing is delayed until the code exits
            * the critical section. The pending interrupt force WFI instruction
            * does nothing and the device remains in Active mode.
            */

            if (_FLD2BOOL(SCB_CTRL_EC_AM_MODE, SCB_CTRL(locBase)))
            {
                /* The SCB is wakeup-capable: enable the I2C wakeup interrupt
                * source. If any transaction was paused, the I2C interrupt
                * becomes pending and prevents entering Deep Sleep mode.
                * The transaction continues as soon as the global interrupts
                * are enabled.
                */
                Cy_SCB_SetI2CInterruptMask(locBase, CY_SCB_I2C_INTR_WAKEUP);

                /* Disable SCB clock */
                SCB_I2C_CFG(locBase) &= (uint32_t) ~CY_SCB_I2C_CFG_CLK_ENABLE_Msk;

                /* IMPORTANT (replace line above for the CY8CKIT-062 rev-08):
                * for proper entering Deep Sleep mode the I2C clock must be disabled.
                * This code must be inserted by the user because the driver
                * does not have access to the clock.
                */
            }

            retStatus = CY_SYSPM_SUCCESS;
        }
        break;

        case CY_SYSPM_AFTER_TRANSITION:
        {
            if (_FLD2BOOL(SCB_CTRL_EC_AM_MODE, SCB_CTRL(locBase)))
            {
                /* Enable SCB clock */
                SCB_I2C_CFG(locBase) |= CY_SCB_I2C_CFG_CLK_ENABLE_Msk;

                /* IMPORTANT (replace line above for the CY8CKIT-062 rev-08):
                * for proper exiting Deep Sleep, the I2C clock must be enabled.
                * This code must be inserted by the user because the driver
                * does not have access to the clock.
                */

                /* The SCB is wakeup-capable: disable the I2C wakeup interrupt
                * source and restore slave interrupt sources.
                */
                Cy_SCB_SetI2CInterruptMask  (locBase, CY_SCB_CLEAR_ALL_INTR_SRC);
                Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_I2C_SLAVE_INTR);
            }
            else
            {
                /* The SCB is NOT wakeup-capable: enable the I2C to operate */
                Cy_SCB_I2C_Enable(locBase);
            }

            retStatus = CY_SYSPM_SUCCESS;
        }
        break;

        default:
            /* Unknown state */
            break;
    }

    return (retStatus);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_HibernateCallback
****************************************************************************//**
*
* This function handles the transition of the I2C SCB block into Hibernate
* mode. It prevents the device from entering Hibernate mode if the I2C slave or
* master is actively communicating.
* If the I2C is ready to enter Hibernate mode it is disabled. If the device
* failed to enter Hibernate mode, the SCB is enabled. After the SCB is disabled,
* it stops driving the outputs and ignores the inputs. The slave NACKs all
* incoming addresses.
*
* This function must be called during execution of \ref Cy_SysPm_SystemEnterHibernate.
* To do it, register this function as a callback before calling
* \ref Cy_SysPm_SystemEnterHibernate : specify \ref CY_SYSPM_HIBERNATE as the callback
* type and call \ref Cy_SysPm_RegisterCallback.
*
* \param callbackParams
* The pointer to the callback parameters structure
* \ref cy_stc_syspm_callback_params_t.
*
* \param mode
* Callback mode, see \ref cy_en_syspm_callback_mode_t
*
* \return
* \ref cy_en_syspm_status_t
*
*******************************************************************************/
cy_en_syspm_status_t Cy_SCB_I2C_HibernateCallback(cy_stc_syspm_callback_params_t *callbackParams, cy_en_syspm_callback_mode_t mode)
{
    CySCB_Type *locBase = (CySCB_Type *) callbackParams->base;
    cy_stc_scb_i2c_context_t *locContext = (cy_stc_scb_i2c_context_t *) callbackParams->context;

    cy_en_syspm_status_t retStatus = CY_SYSPM_FAIL;

    switch(mode)
    {
        case CY_SYSPM_CHECK_READY:
        {
            /* Disable the slave interrupt sources to protect the state */
            Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_CLEAR_ALL_INTR_SRC);

            /* If the I2C is in the IDLE state, it is ready for Hibernate mode
            * (either the master or the slave is not busy).
            * Otherwise, return fail and restore the slave interrupt sources.
            */
            if (CY_SCB_I2C_IDLE == locContext->state)
            {
                /* Disable the I2C. The slave stops responding to the master and
                * the master stops driving the bus until the I2C is enabled.
                * This happens if the device failed to enter Hibernate mode.
                */
                Cy_SCB_I2C_Disable(locBase, locContext);

                retStatus = CY_SYSPM_SUCCESS;
            }

            /* Restore the slave interrupt sources */
            Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_I2C_SLAVE_INTR);
        }
        break;

        case CY_SYSPM_CHECK_FAIL:
        {
            /* The other driver is not ready for Hibernate mode. Restore the
            * Active mode configuration.
            */

            /* Enable the I2C to operate */
            Cy_SCB_I2C_Enable(locBase);

            retStatus = CY_SYSPM_SUCCESS;
        }
        break;

        case CY_SYSPM_BEFORE_TRANSITION:
        case CY_SYSPM_AFTER_TRANSITION:
        {
            /* The SCB is not capable of waking up from Hibernate mode: do nothing */
            retStatus = CY_SYSPM_SUCCESS;
        }
        break;

        default:
            /* Unknown state */
            break;
    }

    return (retStatus);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_SetDataRate
****************************************************************************//**
*
* Configures the SCB to work at the desired data rate.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param dataRateHz
* The desired data Rate in Hz.
*
* \param scbClockHz
* The frequency of the clock connected to the SCB in Hz.
*
* \return
* The achieved data rate in Hz. \n
* When zero value is returned there is an error in the input parameters:
* data rate or clk_scb is out of valid range.
*
* \note
* This function does not change the values of the clock divider connected
* to the SCB, it changes only the SCB clock oversample registers. If this
* function is not able to achieve the desired data rate, then the clock
* divider must be adjusted. Call this function only while the SCB is
* disabled. For the slave, this function only checks that the attached clock is
* fast enough to meet the desired data rate. It does not change any registers.
*
*******************************************************************************/
uint32_t Cy_SCB_I2C_SetDataRate(CySCB_Type *base, uint32_t dataRateHz, uint32_t scbClockHz)
{
    CY_ASSERT_L2(scbClockHz > 0UL);
    CY_ASSERT_L2(CY_SCB_I2C_IS_DATA_RATE_VALID(dataRateHz));

    uint32_t actualDataRateHz = 0UL;

    if (((uint32_t) CY_SCB_I2C_SLAVE) == _FLD2VAL(CY_SCB_I2C_CTRL_MODE, SCB_I2C_CTRL(base)))
    {
        actualDataRateHz = Cy_SCB_I2C_GetDataRate(base, scbClockHz);

        /* Use an analog filter for the slave */
        SCB_RX_CTRL(base) &= (uint32_t) ~SCB_RX_CTRL_MEDIAN_Msk;
        SCB_I2C_CFG(base)  = CY_SCB_I2C_ENABLE_ANALOG_FITLER;
    }
    else
    {
        bool errorRange = true;
        uint32_t sclLow;
        uint32_t sclHigh;

        uint32_t lowPhase  = 8U;
        uint32_t highPhase = 8U;
        bool enableMedian  = false;

        /* Get duration of SCL low and high for the selected data rate */
        if ((0U == dataRateHz) || (dataRateHz > CY_SCB_I2C_FSTP_DATA_RATE))
        {
            errorRange = true;
        }
        else if (dataRateHz <= CY_SCB_I2C_STD_DATA_RATE)
        {
            /* Check SCB clock ranges for Standard rate */
            if ((scbClockHz >= CY_SCB_I2C_MASTER_STD_CLK_MIN) && (scbClockHz <= CY_SCB_I2C_MASTER_STD_CLK_MAX))
            {
                sclLow  = CY_SCB_I2C_MASTER_STD_SCL_LOW;
                sclHigh = CY_SCB_I2C_MASTER_STD_SCL_HIGH;
                enableMedian = false;

                errorRange = false;
            }
        }
        else if (dataRateHz <= CY_SCB_I2C_FST_DATA_RATE)
        {
            /* Check SCB clock ranges for Fast rate */
            if ((scbClockHz >= CY_SCB_I2C_MASTER_FST_CLK_MIN) && (scbClockHz <= CY_SCB_I2C_MASTER_FST_CLK_MAX))
            {
                sclLow  = CY_SCB_I2C_MASTER_FST_SCL_LOW;
                sclHigh = CY_SCB_I2C_MASTER_FST_SCL_HIGH;
                enableMedian = false;

                errorRange = false;
            }
        }
        else
        {
            /* Check SCB clock ranges for Fast rate */
            if ((scbClockHz >= CY_SCB_I2C_MASTER_FSTP_CLK_MIN) && (scbClockHz <= CY_SCB_I2C_MASTER_FSTP_CLK_MAX))
            {
                /* Check SCB clock ranges for Fast rate */
                sclLow  = CY_SCB_I2C_MASTER_FSTP_SCL_LOW;
                sclHigh = CY_SCB_I2C_MASTER_FSTP_SCL_HIGH;
                enableMedian = true;

                errorRange = false;
            }
        }

        /* Calculate data rate if data rate and clock ranges are valid */
        if (!errorRange)
        {
            bool updateLowPhase;

            /* Get period of the SCB clock in ns */
            uint32_t period = 1000000000U / scbClockHz;

            /* Get low phase minimum value in SCB clocks */
            lowPhase = sclLow / period;

            if ((period * lowPhase) < sclLow)
            {
                ++lowPhase;
            }

            if (lowPhase > CY_SCB_I2C_LOW_PHASE_MAX)
            {
                lowPhase = CY_SCB_I2C_LOW_PHASE_MAX;
            }

            /* Define if update low phase */
            updateLowPhase = (lowPhase < CY_SCB_I2C_LOW_PHASE_MAX);

            /* Get high phase minimum value in SCB clocks */
            highPhase = sclHigh / period;

            if ((period * highPhase) < sclHigh)
            {
                ++highPhase;
            }

            if (highPhase > CY_SCB_I2C_HIGH_PHASE_MAX)
            {
                highPhase = CY_SCB_I2C_HIGH_PHASE_MAX;
            }

            /* Get actual data rate */
            actualDataRateHz = scbClockHz / (lowPhase + highPhase);

            /* Find desired data rate */
            while ((actualDataRateHz > dataRateHz) && ((lowPhase + highPhase) < CY_SCB_I2C_DUTY_CYCLE_MAX))
            {
                /* Increase low and high phase to reach desired data rate */
                if (updateLowPhase)
                {
                    if (lowPhase < CY_SCB_I2C_LOW_PHASE_MAX)
                    {
                        /* Update low phase */
                        lowPhase++;
                        updateLowPhase = false;
                    }
                }
                else
                {
                    if (highPhase < CY_SCB_I2C_HIGH_PHASE_MAX)
                    {
                        /* Update high phase */
                        highPhase++;
                        updateLowPhase = (lowPhase < CY_SCB_I2C_LOW_PHASE_MAX);
                    }
                }

                /* Update actual data rate */
                actualDataRateHz = scbClockHz / (lowPhase + highPhase);
            }

            /* Set filter configuration based on actual data rate */
            if (enableMedian)
            {
                /* Use a digital filter */
                SCB_RX_CTRL(base) |= (uint32_t) SCB_RX_CTRL_MEDIAN_Msk;
                SCB_I2C_CFG(base)  = CY_SCB_I2C_DISABLE_ANALOG_FITLER;
            }
            else
            {
                /* Use an analog filter */
                SCB_RX_CTRL(base) &= (uint32_t) ~SCB_RX_CTRL_MEDIAN_Msk;
                SCB_I2C_CFG(base)  = CY_SCB_I2C_ENABLE_ANALOG_FITLER;
            }

            /* Set phase low and high */
            Cy_SCB_I2C_MasterSetLowPhaseDutyCycle (base, lowPhase);
            Cy_SCB_I2C_MasterSetHighPhaseDutyCycle(base, highPhase);
        }
    }

    return (actualDataRateHz);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_GetDataRate
****************************************************************************//**
*
* Returns the data rate for the selected SCB block.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param scbClockHz
* The frequency of the clock connected to the SCB in Hz.
*
* \return
* The data rate in Hz. \n
* For slave mode when zero value is returned the clk_scb is out of valid
* range.
*
*******************************************************************************/
uint32_t Cy_SCB_I2C_GetDataRate(CySCB_Type const *base, uint32_t scbClockHz)
{
    CY_ASSERT_L2(scbClockHz > 0UL);

    uint32_t actualDataRate = 0UL;

    if (((uint32_t) CY_SCB_I2C_SLAVE) == _FLD2VAL(CY_SCB_I2C_CTRL_MODE, SCB_I2C_CTRL(base)))
    {
        /* Check the clock frequency range to get maximum supported data rate */
        if ((scbClockHz >= CY_SCB_I2C_SLAVE_FST_CLK_MIN) && (scbClockHz <= CY_SCB_I2C_SLAVE_FST_CLK_MAX))
        {
            actualDataRate = CY_SCB_I2C_FST_DATA_RATE;
        }
        else if ((scbClockHz >= CY_SCB_I2C_SLAVE_STD_CLK_MIN) && (scbClockHz <= CY_SCB_I2C_SLAVE_STD_CLK_MAX))
        {
            actualDataRate = CY_SCB_I2C_STD_DATA_RATE;
        }
        else if ((scbClockHz >= CY_SCB_I2C_SLAVE_FSTP_CLK_MIN) && (scbClockHz <= CY_SCB_I2C_SLAVE_FSTP_CLK_MAX))
        {
            actualDataRate = CY_SCB_I2C_FSTP_DATA_RATE;
        }
        else
        {
            /* The clock frequency is too low or it gets to the gap between
            * Fast and Fast Plus data rates.
            */
            actualDataRate = 0UL;
        }
    }
    else
    {
        if (scbClockHz > 0U)
        {
            uint32_t dutyCycle;

            /* Get number of clocks in one SCL period */
            dutyCycle = _FLD2VAL(SCB_I2C_CTRL_LOW_PHASE_OVS,  SCB_I2C_CTRL(base)) +
                        _FLD2VAL(SCB_I2C_CTRL_HIGH_PHASE_OVS, SCB_I2C_CTRL(base)) +
                        2UL;

            /* Calculate the actual data rate */
            actualDataRate = (scbClockHz / dutyCycle);
        }
    }

    return (actualDataRate);
}


/*******************************************************************************
*                         I2C Slave API
*******************************************************************************/

/*******************************************************************************
* Function Name: Cy_SCB_I2C_SlaveGetStatus
****************************************************************************//**
*
* Returns the current I2C slave status.
* This status is a bit mask and the value returned may have multiple bits set.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* \ref group_scb_i2c_macros_slave_status.
*
*******************************************************************************/
uint32_t Cy_SCB_I2C_SlaveGetStatus(CySCB_Type const *base, cy_stc_scb_i2c_context_t const *context)
{
    /* Suppress a compiler warning about unused variables */
    (void) base;

    return (context->slaveStatus);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_SlaveConfigReadBuf
****************************************************************************//**
*
* Configures the buffer pointer and the read buffer size. This is the buffer
* from which the master reads data. After this function is called, data
* transfer from the read buffer to the master is handled by
* \ref Cy_SCB_I2C_Interrupt.
*
* When the Read transaction is completed (master generated Stop, ReStart or
* error occurred), the \ref CY_SCB_I2C_SLAVE_RD_BUSY status is cleared and
* the \ref CY_SCB_I2C_SLAVE_RD_CMPLT is set. Also
* the \ref CY_SCB_I2C_SLAVE_RD_CMPLT_EVENT event is generated.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param buffer
* The pointer to the buffer with data to be read by the master.
*
* \param size
* Size of the buffer.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \note
* * The Read buffer must not be modified and stay allocated until it has been
*   read by the master.
* * If this function has not been called, and the master tries to read data
*   from the slave a \ref CY_SCB_I2C_DEFAULT_TX is returned to the master.
* * If the master tries to read more bytes than available in the Read buffer,
*   a \ref CY_SCB_I2C_SLAVE_RD_BUF_EMPTY_EVENT event occurs. The
*   \ref CY_SCB_I2C_DEFAULT_TX is returned to the master if the buffer remains
*   empty after an event notification.
*
*******************************************************************************/
void Cy_SCB_I2C_SlaveConfigReadBuf(CySCB_Type const *base, uint8_t *buffer, uint32_t size,
                                   cy_stc_scb_i2c_context_t *context)
{
    CY_ASSERT_L1(CY_SCB_IS_I2C_BUFFER_VALID(buffer, size));

    /* Suppress a compiler warning about unused variables */
    (void) base;

    context->slaveTxBuffer     = buffer;
    context->slaveTxBufferSize = size;
    context->slaveTxBufferIdx  = 0UL;
    context->slaveTxBufferCnt  = 0UL;
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_SlaveAbortRead
****************************************************************************//**
*
* Aborts the configured slave read buffer to be read by the master.
* If the master reads and "abort operation" is requested, the
* \ref CY_SCB_I2C_SLAVE_RD_BUF_EMPTY_EVENT event occurs. The
* \ref CY_SCB_I2C_DEFAULT_TX is returned to the master if the buffer remains
* empty after the event notification.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \sideeffect
* If the TX FIFO is used, this function clears it.
* The TX FIFO clear operation also clears the shift register, thus
* the shifter can be cleared in the middle of a data element transfer,
* corrupting it. The data element corruption means that all bits that have
* not been transmitted are transmitted as "ones" on the bus.
*
*******************************************************************************/
void Cy_SCB_I2C_SlaveAbortRead(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    uint32_t intrState;

    /* Suppress a compiler warning about unused variables */
    (void) base;

    intrState = Cy_SysLib_EnterCriticalSection();

    /* Reset index to make write buffer empty */
    context->slaveTxBufferSize = 0UL;

    if ((context->useTxFifo) &&
        (0UL != (CY_SCB_I2C_SLAVE_RD_BUSY & context->slaveStatus)))
    {
        /* Clear TX FIFO from available data */
        Cy_SCB_ClearTxFifo(base);
    }

    Cy_SysLib_ExitCriticalSection(intrState);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_SlaveGetReadTransferCount
****************************************************************************//**
*
* Returns the number of bytes read by the master since the last time
* \ref Cy_SCB_I2C_SlaveConfigReadBuf was called.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* The number of bytes read by the master.
*
* \note
* * This function returns an invalid value if a read transaction was
*   aborted or any listed event occurs during the transaction:
*   \ref CY_SCB_I2C_SLAVE_ARB_LOST, \ref CY_SCB_I2C_SLAVE_BUS_ERR.
* * This number is updated only when a transaction completes, either through
*   an error or successfully.
*
*******************************************************************************/
uint32_t Cy_SCB_I2C_SlaveGetReadTransferCount(CySCB_Type const *base, cy_stc_scb_i2c_context_t const *context)
{
    /* Suppress a compiler warning about unused variables */
    (void) base;

    return (context->slaveTxBufferCnt);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_SlaveClearReadStatus
****************************************************************************//**
*
* Clears the read status and error conditions flags and returns their values.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* \ref group_scb_i2c_macros_slave_status.
*
* \note
* The \ref CY_SCB_I2C_SLAVE_RD_BUSY flag is not cleared.
*
*******************************************************************************/
uint32_t Cy_SCB_I2C_SlaveClearReadStatus(CySCB_Type const *base, cy_stc_scb_i2c_context_t *context)
{
    uint32_t retStatus;

    /* Suppress a compiler warning about unused variables */
    (void) base;

    retStatus = (context->slaveStatus & CY_SCB_I2C_SLAVE_RD_CLEAR);
    context->slaveStatus &= (uint32_t) ~CY_SCB_I2C_SLAVE_RD_CLEAR;

    return (retStatus);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_SlaveConfigWriteBuf
****************************************************************************//**
*
* Configures the buffer pointer and size of the write buffer. This is the buffer
* that the master writes data to. After this function is called data transfer
* from the master into the write buffer is handled by \ref Cy_SCB_I2C_Interrupt.
*
* When write transaction is completed (master generated Stop, ReStart or
* error occurred) the \ref CY_SCB_I2C_SLAVE_WR_BUSY status is cleared and
* the \ref CY_SCB_I2C_SLAVE_WR_CMPLT is set, also
* the \ref CY_SCB_I2C_SLAVE_WR_CMPLT_EVENT event is generated.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param buffer
* The pointer to buffer to store data written by the master.
*
* \param size
* Size of the buffer.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \note
* * The write buffer must not be modified and must stay allocated until it has been
*   written by the master.
* * If this function has not been called and the master tries to write data,
*   the first byte is NAKed and discarded.
* * If the master writes more bytes than the slave can store in the write buffer,
*   the \ref CY_SCB_I2C_SLAVE_WR_OVRFL status is set and the slave will NACK last
*   byte, unless the RX FIFO is used. Then the slave will NAK only after
*   RX FIFO becomes full.
* * If the RX FIFO is used, the minimum write buffer size is automatically
*   the size of the RX FIFO. If a write buffer is less than the RX FIFO size, extra
*   bytes are ACKed and stored into RX FIFO but ignored by firmware.
*
*******************************************************************************/
void Cy_SCB_I2C_SlaveConfigWriteBuf(CySCB_Type const *base, uint8_t *buffer, uint32_t size,
                                    cy_stc_scb_i2c_context_t *context)
{
    CY_ASSERT_L1(CY_SCB_IS_I2C_BUFFER_VALID(buffer, size));

    /* Suppress a compiler warning about unused variables */
    (void) base;

    context->slaveRxBuffer     = buffer;
    context->slaveRxBufferSize = size;
    context->slaveRxBufferIdx  = 0UL;
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_SlaveAbortWrite
****************************************************************************//**
*
* Aborts the configured slave write buffer to be written by the master.
* If master writes and an "abort operation" is requested, the next incoming
* byte will be NAKed.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \note
* If the RX FIFO is used, the NAK will not be sent until RX FIFO
* becomes full, however bytes accepted after an abort request are ignored.
*
*******************************************************************************/
void Cy_SCB_I2C_SlaveAbortWrite(CySCB_Type *base,  cy_stc_scb_i2c_context_t *context)
{
    uint32_t intrState;

    /* Suppress a compiler warning about unused variables */
    (void) base;

    intrState = Cy_SysLib_EnterCriticalSection();

    /* Reset index to make read buffer empty */
    context->slaveRxBufferSize = 0UL;

    if ((context->useRxFifo) &&
        (0UL != (CY_SCB_I2C_SLAVE_WR_BUSY & context->slaveStatus)))
    {
        /* Configure to NACK when RX FIFO is full and disable RX level
        * interrupt sources to stop getting data from RX FIFO.
        */
        SCB_I2C_CTRL(base) |= SCB_I2C_CTRL_S_NOT_READY_DATA_NACK_Msk;
        Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
    }

    Cy_SysLib_ExitCriticalSection(intrState);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_SlaveGetWriteTransferCount
****************************************************************************//**
*
* Returns the number of bytes written by the master since the last time
* \ref Cy_SCB_I2C_SlaveConfigWriteBuf was called.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* Number of bytes written by the master.
*
* \note
* * This function returns an invalid value if write transaction was
*   aborted or any listed event occurs during the transaction:
*   \ref CY_SCB_I2C_SLAVE_ARB_LOST, \ref CY_SCB_I2C_SLAVE_BUS_ERR.
* * This number is updated only when the transaction completes, either through
*   an error or successfully.
*
*******************************************************************************/
uint32_t Cy_SCB_I2C_SlaveGetWriteTransferCount(CySCB_Type const *base, cy_stc_scb_i2c_context_t const *context)
{
    /* Suppress a compiler warning about unused variables */
    (void) base;

    return (context->slaveRxBufferIdx);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_SlaveClearWriteStatus
****************************************************************************//**
*
* Clears the write status flags and error condition flags and returns their
* values.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* \ref group_scb_i2c_macros_slave_status.
*
* \note
* The \ref CY_SCB_I2C_SLAVE_WR_BUSY flag is not cleared.
*
*******************************************************************************/
uint32_t Cy_SCB_I2C_SlaveClearWriteStatus(CySCB_Type const *base, cy_stc_scb_i2c_context_t *context)
{
    uint32_t retStatus;

    /* Suppress a compiler warning about unused variables */
    (void) base;

    retStatus = (context->slaveStatus & CY_SCB_I2C_SLAVE_WR_CLEAR);
    context->slaveStatus &= (uint32_t) ~CY_SCB_I2C_SLAVE_WR_CLEAR;

    return (retStatus);
}


/*******************************************************************************
*                         I2C Master API: High level
*******************************************************************************/

/*******************************************************************************
* Function Name: Cy_SCB_I2C_MasterGetStatus
****************************************************************************//**
*
* Returns the current I2C master status.
* This status is a bit mask and the value returned may have multiple bits set.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* \ref group_scb_i2c_macros_master_status.
* Note that not all I2C master statuses are returned by this function. Refer to
* more details of each status.
*
* \note
* Status is cleared by calling \ref Cy_SCB_I2C_MasterRead or
* \ref Cy_SCB_I2C_MasterWrite.
*
*******************************************************************************/
uint32_t Cy_SCB_I2C_MasterGetStatus(CySCB_Type const *base, cy_stc_scb_i2c_context_t const *context)
{
    /* Suppress a compiler warning about unused variables */
    (void) base;

    return (context->masterStatus);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_MasterRead
****************************************************************************//**
*
* This function configures the master to automatically read an entire buffer
* of data from the slave device. After the transaction is initiated by this
* function it returns and \ref Cy_SCB_I2C_Interrupt manages further data
* transfer.
*
* When a read transaction is completed (requested number of bytes are read or
* error occurred) the \ref CY_SCB_I2C_MASTER_BUSY status is cleared and
* the \ref CY_SCB_I2C_MASTER_RD_CMPLT_EVENT event is generated.
*
* Note that the master must read at least one byte.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param xferConfig
* Master transfer configuration structure
* \ref cy_stc_scb_i2c_master_xfer_config_t.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* \ref cy_en_scb_i2c_status_t
*
* \note
* * The buffer must not be modified and must stay allocated until read operation
*   completion.
*
* * \ref Cy_SCB_I2C_MasterRead requests the SCB hardware to generate a start
*   condition when there is no pending transfer and returns (does not wait
*   until hardware generate a start condition). If the I2C bus is busy the
*   hardware will not generate the until bus becomes free.
*   The SCB hardware sets the busy status after the Start detection, and clears
*   it on the Stop detection. Noise caused by the ESD or other events may cause
*   an erroneous Start condition on the bus. Then, the master will never generate
*   a Start condition because the hardware assumes the bus is busy. If this occurs,
*   the \ref Cy_SCB_I2C_MasterGetStatus returns \ref CY_SCB_I2C_MASTER_BUSY
*   status and the transaction will never finish. The option is to implement a
*   timeout to detect the transfer completion. If the transfer never completes,
*   the SCB needs a reset by calling the \ref Cy_SCB_I2C_Disable and
*   \ref Cy_SCB_I2C_Enable functions. The \ref Cy_SCB_I2C_MasterAbortRead
*   function will not work, the block must be reset.
*
*******************************************************************************/
cy_en_scb_i2c_status_t Cy_SCB_I2C_MasterRead(CySCB_Type *base,
                            cy_stc_scb_i2c_master_xfer_config_t *xferConfig,
                            cy_stc_scb_i2c_context_t *context)
{
    CY_ASSERT_L1(xferConfig != NULL);
    CY_ASSERT_L1(CY_SCB_IS_BUFFER_VALID  (xferConfig->buffer, xferConfig->bufferSize));
    CY_ASSERT_L2(CY_SCB_IS_I2C_ADDR_VALID(xferConfig->slaveAddress));

    cy_en_scb_i2c_status_t retStatus = CY_SCB_I2C_MASTER_NOT_READY;

    /* Disable I2C slave interrupt sources to protect state */
    Cy_SCB_SetSlaveInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);

    if (0UL != (CY_SCB_I2C_IDLE_MASK & context->state))
    {
        uint32_t intrState;

        /* Set address byte (bit0 = 1, read direction) */
        uint32_t address = _VAL2FLD(CY_SCB_I2C_ADDRESS, xferConfig->slaveAddress) |
                         (uint32_t) CY_SCB_I2C_READ_XFER;

        /* Setup context */
        context->masterStatus     = CY_SCB_I2C_MASTER_BUSY;

        context->masterBuffer     = xferConfig->buffer;
        context->masterBufferSize = xferConfig->bufferSize;
        context->masterBufferIdx  = 0UL;
        context->masterNumBytes   = 0UL;
        context->masterPause      = xferConfig->xferPending;
        context->masterRdDir      = true;

        /* Clean-up hardware before transfer. Note RX FIFO is empty at here. */
        Cy_SCB_ClearMasterInterrupt(base, CY_SCB_I2C_MASTER_INTR_ALL);
        Cy_SCB_ClearTxFifo(base);

        if (CY_SCB_I2C_IDLE == context->state)
        {
            /* Put the address in the TX FIFO, then generate a Start condition.
            * This sequence ensures that after the Start condition generation
            * the address is available to be sent onto the bus.
            */
            Cy_SCB_WriteTxFifo(base, address);
            SCB_I2C_M_CMD(base) = SCB_I2C_M_CMD_M_START_ON_IDLE_Msk;
        }
        else
        {
            /* Generate a ReStart condition.
            * If the previous transfer was read, NACK is generated before
            * ReStart to complete the previous transfer.
            */
            SCB_I2C_M_CMD(base) = (SCB_I2C_M_CMD_M_START_Msk | (_FLD2BOOL(SCB_I2C_STATUS_M_READ, SCB_I2C_STATUS(base)) ?
                                  SCB_I2C_M_CMD_M_NACK_Msk : 0UL));

            /* Put address in TX FIFO */
            Cy_SCB_WriteTxFifo(base, address);
        }

        /* Configure interrupt for data reception */
        if ((context->useRxFifo) && (!context->masterPause) && (context->masterBufferSize >= 2UL))
        {
            uint32_t fifoSize = CY_SCB_I2C_FIFO_SIZE;

            /* Enable Auto data ACK */
            SCB_I2C_CTRL(base) |= SCB_I2C_CTRL_M_READY_DATA_ACK_Msk;

            /* Adjust level in RX FIFO */
            Cy_SCB_SetRxFifoLevel(base, (context->masterBufferSize <= fifoSize) ?
                                        (context->masterBufferSize - 2UL) : ((fifoSize / 2UL) - 1UL));

            context->state = CY_SCB_I2C_MASTER_RX1;
        }
        else
        {
            /* Adjust level in RX FIFO */
            Cy_SCB_SetRxFifoLevel(base, 0UL);

            context->state = CY_SCB_I2C_MASTER_RX0;
        }

        /* Enable interrupt sources to continue transfer.
        * Requires critical section to not cause race condition between RX and Master
        * interrupt sources.
        */
        intrState = Cy_SysLib_EnterCriticalSection();
        Cy_SCB_SetRxInterruptMask    (base, CY_SCB_RX_INTR_LEVEL);
        Cy_SCB_SetMasterInterruptMask(base, CY_SCB_I2C_MASTER_INTR);
        Cy_SysLib_ExitCriticalSection(intrState);

        retStatus = CY_SCB_I2C_SUCCESS;
    }

    /* Enable I2C slave interrupt sources */
    Cy_SCB_SetSlaveInterruptMask(base, CY_SCB_I2C_SLAVE_INTR);

    return (retStatus);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_MasterAbortRead
****************************************************************************//**
*
* This function requests master to abort read operation by NAKing the next byte
* and generating a Stop condition. The function does not wait until these
* actions are completed. Therefore the next operation can be initiated only
* after the \ref CY_SCB_I2C_MASTER_BUSY is cleared.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
******************************************************************************/
void Cy_SCB_I2C_MasterAbortRead(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    uint32_t intrState;

    intrState = Cy_SysLib_EnterCriticalSection();

    if (0UL != (CY_SCB_I2C_MASTER_BUSY & context->masterStatus))
    {
        /* Catch state to abort read operation */
        if ((CY_SCB_I2C_MASTER_RX0 == context->state) || (CY_SCB_I2C_MASTER_RX1 == context->state))
        {
            if (context->useRxFifo)
            {
                /* Disable RX processing */
                Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);

                /* Change state to request Stop generation */
                context->state = CY_SCB_I2C_MASTER_STOP;

                /* Enable ACK interrupt source to generate Stop after Start was generated */
                Cy_SCB_SetMasterInterruptMask(base, CY_SCB_I2C_MASTER_INTR_ALL);
            }
            else
            {
                /* Reduce buffer size to minimum */
                context->masterBufferSize = 1UL;
            }

            /* Cancel pending read operation if it was requested */
            context->masterPause = false;
        }
    }
    else
    {
        /* There are two possible states when master is not busy:
        * CY_SCB_I2C_MASTER_WAIT and CY_SCB_I2C_IDLE.
        * Do nothing for CY_SCB_I2C_IDLE.
        */
        if (CY_SCB_I2C_MASTER_WAIT == context->state)
        {
            /* Clear master previous transaction results:
            * - status to indicate that master is busy;
            * - number of bytes (only Stop is generated);
            * - cancel previous pending operation.
            */
            context->masterStatus   = CY_SCB_I2C_MASTER_BUSY;
            context->masterNumBytes = 0UL;
            context->masterPause    = false;

            /* Enable master interrupt sources to catch Stop condition */
            Cy_SCB_SetMasterInterruptMask(base, CY_SCB_I2C_MASTER_INTR);

            /* Complete transaction generating Stop */
            SCB_I2C_M_CMD(base) = (SCB_I2C_M_CMD_M_STOP_Msk | SCB_I2C_M_CMD_M_NACK_Msk);
            context->state  = CY_SCB_I2C_MASTER_WAIT_STOP;
        }
    }

    Cy_SysLib_ExitCriticalSection(intrState);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_MasterWrite
****************************************************************************//**
*
* This function configures the master to automatically write an entire buffer
* of data to a slave device. After the transaction is initiated by this
* function it returns and \ref Cy_SCB_I2C_Interrupt manages further data
* transfer.
*
* When a write transaction is completed (requested number of bytes are written
* or error occurred) the \ref CY_SCB_I2C_MASTER_BUSY status is cleared and
* the \ref CY_SCB_I2C_MASTER_WR_CMPLT_EVENT event is generated.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param xferConfig
* Master transfer configuration structure
* \ref cy_stc_scb_i2c_master_xfer_config_t.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* \ref cy_en_scb_i2c_status_t
*
* \note
* * The buffer must not be modified and must stay allocated until data has been
*   copied into the TX FIFO.
*
* * \ref Cy_SCB_I2C_MasterWrite requests the SCB hardware to generate a start
*   condition when there is no pending transfer and returns (does not wait
*   until hardware generate a start condition). If the I2C bus is busy the
*   hardware will not generate the until bus becomes free.
*   The SCB hardware sets the busy status after the Start detection, and clears
*   it on the Stop detection. Noise caused by the ESD or other events may cause
*   an erroneous Start condition on the bus. Then, the master will never generate
*   a Start condition because the hardware assumes the bus is busy. If this occurs,
*   the \ref Cy_SCB_I2C_MasterGetStatus returns \ref CY_SCB_I2C_MASTER_BUSY
*   status and the transaction will never finish. The option is to implement a
*   timeout to detect the transfer completion. If the transfer never completes,
*   the SCB needs a reset by calling the \ref Cy_SCB_I2C_Disable and
*   \ref Cy_SCB_I2C_Enable functions. The \ref Cy_SCB_I2C_MasterAbortWrite
*   function will not work, the block must be reset.
*
*******************************************************************************/
cy_en_scb_i2c_status_t Cy_SCB_I2C_MasterWrite(CySCB_Type *base,
                             cy_stc_scb_i2c_master_xfer_config_t *xferConfig,
                             cy_stc_scb_i2c_context_t *context)
{
    CY_ASSERT_L1(xferConfig != NULL);
    CY_ASSERT_L1(CY_SCB_IS_I2C_BUFFER_VALID(xferConfig->buffer, xferConfig->bufferSize));
    CY_ASSERT_L2(CY_SCB_IS_I2C_ADDR_VALID  (xferConfig->slaveAddress));

    cy_en_scb_i2c_status_t retStatus = CY_SCB_I2C_MASTER_NOT_READY;

    /* Disable I2C slave interrupt sources to protect state */
    Cy_SCB_SetSlaveInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);

    if (0UL != (CY_SCB_I2C_IDLE_MASK & context->state))
    {
        uint32_t intrState;

        /* Set address byte (bit0 = 0, write direction) */
        uint32_t address = _VAL2FLD(CY_SCB_I2C_ADDRESS, xferConfig->slaveAddress);

        /* Setup context */
        context->masterStatus     = CY_SCB_I2C_MASTER_BUSY;

        context->masterBuffer     = xferConfig->buffer;
        context->masterBufferSize = xferConfig->bufferSize;
        context->masterBufferIdx  = 0UL;
        context->masterNumBytes   = 0UL;
        context->masterPause      = xferConfig->xferPending;
        context->masterRdDir      = false;

        /* Clean-up hardware before transfer. Note RX FIFO is empty at here. */
        Cy_SCB_ClearMasterInterrupt(base, CY_SCB_I2C_MASTER_INTR_ALL);
        Cy_SCB_ClearTxFifo(base);

        if (CY_SCB_I2C_IDLE == context->state)
        {
            /* Put the address in the TX FIFO, then generate a Start condition.
            * This sequence ensures that after the Start condition generation
            * the address is available to be sent onto the bus.
            */
            Cy_SCB_WriteTxFifo     (base, address);
            Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_UNDERFLOW);
            SCB_I2C_M_CMD(base) = SCB_I2C_M_CMD_M_START_ON_IDLE_Msk;
        }
        else
        {
            /* Generate a ReStart condition.
            * If the previous transfer was read, NACK is generated before
            * ReStart to complete the previous transfer.
            */
            SCB_I2C_M_CMD(base) = (SCB_I2C_M_CMD_M_START_Msk | (_FLD2BOOL(SCB_I2C_STATUS_M_READ, SCB_I2C_STATUS(base)) ?
                               SCB_I2C_M_CMD_M_NACK_Msk : 0UL));

            if (0U == context->masterBufferSize)
            {
                /* The address is the last byte to transfer.
                * Put the address byte in the TX FIFO and clear the TX
                * Underflow interrupt source inside the critical section
                * to ensure that the TX Underflow interrupt will trigger
                * after the address byte is sent onto the bus.
                */
                intrState = Cy_SysLib_EnterCriticalSection();

                /* Put address in TX FIFO */
                Cy_SCB_WriteTxFifo     (base, address);
                Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_UNDERFLOW);

                Cy_SysLib_ExitCriticalSection(intrState);
            }
            else
            {
                /* Put address in TX FIFO */
                Cy_SCB_WriteTxFifo(base, address);
            }
        }

        context->state = CY_SCB_I2C_MASTER_TX;

        /* TX FIFO is empty. Set level to start transfer */
        Cy_SCB_SetTxFifoLevel(base, (context->useTxFifo) ? CY_SCB_I2C_HALF_FIFO_SIZE : (1UL));

        /* Enable interrupt sources to continue transfer.
        * Requires critical section to not cause race condition between TX and Master
        * interrupt sources.
        */
        intrState = Cy_SysLib_EnterCriticalSection();
        Cy_SCB_SetTxInterruptMask    (base, CY_SCB_TX_INTR_LEVEL);
        Cy_SCB_SetMasterInterruptMask(base, CY_SCB_I2C_MASTER_INTR);
        Cy_SysLib_ExitCriticalSection(intrState);

        retStatus = CY_SCB_I2C_SUCCESS;
    }

    /* Enable I2C slave interrupt sources */
    Cy_SCB_SetSlaveInterruptMask(base, CY_SCB_I2C_SLAVE_INTR);

    return (retStatus);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_MasterAbortWrite
****************************************************************************//**
*
* This function requests the master to abort write operation by generating a Stop
* condition. The function does not wait until this action is completed.
* Therefore next write operation can be initiated only after the
* \ref CY_SCB_I2C_MASTER_BUSY is cleared.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \sideeffect
* If the TX FIFO is used, it is cleared before Stop generation.
* The TX FIFO clear operation also clears shift register. Thus, the shifter
* could be cleared in the middle of a data element transfer, corrupting it.
* The remaining bits to transfer within corrupted data element are
* complemented with ones.\n
* If the clear operation is requested while the master transmits the address,
* the direction of transaction is changed to read and one byte is read
* before Stop is issued. This byte is discarded.
*
*******************************************************************************/
void Cy_SCB_I2C_MasterAbortWrite(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    uint32_t intrState;

    intrState = Cy_SysLib_EnterCriticalSection();

    if (0UL != (CY_SCB_I2C_MASTER_BUSY & context->masterStatus))
    {
        /* Disable TX processing */
        Cy_SCB_SetTxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);

        if (context->useTxFifo)
        {
            /* Clear TX FIFO to allow Stop generation */
            Cy_SCB_ClearTxFifo(base);
        }

        if ((CY_SCB_I2C_MASTER_TX == context->state) || (CY_SCB_I2C_MASTER_TX_DONE == context->state))
        {
            /* Change state to request Stop generation */
            context->state = CY_SCB_I2C_MASTER_STOP;

            /* Enable ACK interrupt source to trigger Stop generation */
            Cy_SCB_SetMasterInterruptMask(base, CY_SCB_I2C_MASTER_INTR_ALL);
        }

        /* Cancel pending write operation if it was requested */
        context->masterPause = false;
    }
    else
    {
        /* There are two possible states when master is not busy:
        * CY_SCB_I2C_MASTER_WAIT and CY_SCB_I2C_IDLE.
        * Do nothing for CY_SCB_I2C_IDLE.
        */
        if (CY_SCB_I2C_MASTER_WAIT == context->state)
        {
            /* Clear master previous transaction results:
            * - status to indicate that master is busy;
            * - number of bytes (only Stop is generated);
            * - cancel previous pending operation.
            */
            context->masterStatus   = CY_SCB_I2C_MASTER_BUSY;
            context->masterNumBytes = 0UL;
            context->masterPause    = false;

            /* Enable master interrupt sources to catch Stop condition */
            Cy_SCB_SetMasterInterruptMask(base, CY_SCB_I2C_MASTER_INTR);

            /* Complete transaction generating Stop */
            SCB_I2C_M_CMD(base) = (SCB_I2C_M_CMD_M_STOP_Msk | SCB_I2C_M_CMD_M_NACK_Msk);
            context->state  = CY_SCB_I2C_MASTER_WAIT_STOP;
        }
    }

    Cy_SysLib_ExitCriticalSection(intrState);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_MasterGetTransferCount
****************************************************************************//**
*
* Returns the number of bytes transferred since the last call of
* \ref Cy_SCB_I2C_MasterWrite or \ref Cy_SCB_I2C_MasterRead function.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* Number of bytes read or written by the master.
*
* \note
* * This function returns an invalid value if read or write transaction was
*   aborted or any listed event occurs during the transaction:
*   \ref CY_SCB_I2C_MASTER_ARB_LOST, \ref CY_SCB_I2C_MASTER_BUS_ERR or
*   \ref CY_SCB_I2C_MASTER_ABORT_START.
*
* * This number is updated only when the transaction completes, either through
*   an error or successfully.
*
*******************************************************************************/
uint32_t Cy_SCB_I2C_MasterGetTransferCount(CySCB_Type const *base, cy_stc_scb_i2c_context_t const *context)
{
    /* Suppress a compiler warning about unused variables */
    (void) base;

    return (context->masterNumBytes);
}


/*******************************************************************************
*                         I2C Master API: Low level
*******************************************************************************/


/*******************************************************************************
* Function Name: Cy_SCB_I2C_MasterSendStart
****************************************************************************//**
*
* Generates a Start condition and sends a slave address with the Read/Write bit.
* This function is blocking. It does not return until the Start condition
* and address byte are sent and a ACK/NAK is received, or an error or timeout
* occurs.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param address
* 7 bit right justified slave address.
*
* \param bitRnW
* This sets the value of the Read/Write bit in the address, thus defining
* the direction of the following transfer.
* See \ref cy_en_scb_i2c_direction_t for the set of constants.
*
* \param timeoutMs
* Defines in milliseconds the time for which this function can block.
* If that time expires, the function returns. If a zero is passed,
* the function waits forever for the action to complete. If a timeout occurs,
* the SCB block is reset. Note The maximum value is UINT32_MAX/1000.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* \ref cy_en_scb_i2c_status_t
*
* \note
* After a read transaction is initiated and the slave ACKs the address, at
* least one byte must be read before completing the transaction or changing
* its direction.
*
*******************************************************************************/
cy_en_scb_i2c_status_t Cy_SCB_I2C_MasterSendStart(CySCB_Type *base,
                            uint32_t address, cy_en_scb_i2c_direction_t bitRnW,
                            uint32_t timeoutMs,
                            cy_stc_scb_i2c_context_t *context)
{
    CY_ASSERT_L2(CY_SCB_IS_I2C_ADDR_VALID   (address));
    CY_ASSERT_L2(CY_SCB_I2C_IS_TIMEOUT_VALID(timeoutMs));
    CY_ASSERT_L3(CY_SCB_I2C_IS_RW_BIT_VALID (bitRnW));

    cy_en_scb_i2c_status_t retStatus = CY_SCB_I2C_MASTER_NOT_READY;

    /* Disable the I2C slave interrupt sources to protect the state */
    Cy_SCB_SetSlaveInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);

    if (CY_SCB_I2C_IDLE == context->state)
    {
        uint32_t locStatus;
        uint32_t timeout = CY_SCB_I2C_CONVERT_TIMEOUT_TO_US(timeoutMs);

        /* Set the read or write direction */
        context->state       = CY_SCB_I2C_MASTER_ADDR;
        context->masterRdDir = (CY_SCB_I2C_READ_XFER == bitRnW);

        /* Clean up the hardware before a transfer. Note RX FIFO is empty at here */
        Cy_SCB_ClearMasterInterrupt(base, CY_SCB_I2C_MASTER_INTR_ALL);
        Cy_SCB_ClearRxInterrupt    (base, CY_SCB_RX_INTR_NOT_EMPTY);
        Cy_SCB_ClearTxFifo(base);

        /* Generate a Start and send address byte */
        Cy_SCB_WriteTxFifo(base, (_VAL2FLD(CY_SCB_I2C_ADDRESS, address) | (uint32_t) bitRnW));
        SCB_I2C_M_CMD(base)  = SCB_I2C_M_CMD_M_START_ON_IDLE_Msk;

        /* Wait for a completion event from the master or slave */
        do
        {
            locStatus  = (CY_SCB_I2C_MASTER_TX_BYTE_DONE & Cy_SCB_GetMasterInterruptStatus(base));
            locStatus |= (CY_SCB_I2C_SLAVE_ADDR_DONE & Cy_SCB_GetSlaveInterruptStatus(base));
            locStatus |= WaitOneUnit(&timeout);

        } while (0UL == locStatus);

        /* Convert the status from register plus timeout to the return status */
        retStatus = HandleStatus(base, locStatus, context);
    }

    /* Enable I2C slave interrupt sources */
    Cy_SCB_SetSlaveInterruptMask(base, CY_SCB_I2C_SLAVE_INTR);

    return (retStatus);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_MasterSendReStart
****************************************************************************//**
*
* Generates a ReStart condition and sends a slave address with the Read/Write
* bit.
* This function is blocking. It does not return until the ReStart condition
* and address byte are sent and an ACK/NAK is received, or an error or timeout
* occurs.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param address
* A 7-bit right-justified slave address.
*
* \param bitRnW
* This sets the value of the Read/Write bit in the address, thus defining
* the direction of the following transfer.
* See \ref cy_en_scb_i2c_direction_t for the set of constants.
*
* \param timeoutMs
* Defines in milliseconds the time for which this function can block.
* If that time expires, the function returns. If a zero is passed,
* the function waits forever for the action to complete. If a timeout occurs,
* the SCB block is reset. Note The maximum value is UINT32_MAX/1000.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* \ref cy_en_scb_i2c_status_t
*
* \note
* * A successful transaction must be initiated by \ref Cy_SCB_I2C_MasterSendStart
*   before calling this function. If this condition is not met, this function
*   does nothing and returns \ref CY_SCB_I2C_MASTER_NOT_READY.
* * After a read transaction is initiated and the slave ACKs the address,
*   at least one byte must be read before completing the transaction or
*   changing its direction.
*
*******************************************************************************/
cy_en_scb_i2c_status_t Cy_SCB_I2C_MasterSendReStart(CySCB_Type *base,
                        uint32_t address, cy_en_scb_i2c_direction_t bitRnW,
                        uint32_t timeoutMs,
                        cy_stc_scb_i2c_context_t *context)
{
    CY_ASSERT_L2(CY_SCB_IS_I2C_ADDR_VALID   (address));
    CY_ASSERT_L2(CY_SCB_I2C_IS_TIMEOUT_VALID(timeoutMs));
    CY_ASSERT_L3(CY_SCB_I2C_IS_RW_BIT_VALID (bitRnW));

    cy_en_scb_i2c_status_t retStatus = CY_SCB_I2C_MASTER_NOT_READY;

    if (0UL != (CY_SCB_I2C_MASTER_ACTIVE & context->state))
    {
        uint32_t locStatus = 0U;
        uint32_t timeout = CY_SCB_I2C_CONVERT_TIMEOUT_TO_US(timeoutMs);

        /* Set the read or write direction */
        context->state       = CY_SCB_I2C_MASTER_ADDR;
        context->masterRdDir = (CY_SCB_I2C_READ_XFER == bitRnW);

        /* Generate ReStart condition.
        * If previous transfer was read, NACK is generated before ReStart to
        * complete previous transfer.
        */
        SCB_I2C_M_CMD(base) = SCB_I2C_M_CMD_M_START_Msk | (_FLD2BOOL(SCB_I2C_STATUS_M_READ, SCB_I2C_STATUS(base)) ?
                          SCB_I2C_M_CMD_M_NACK_Msk : 0UL);

        /* Previous transfer was a write */
        if (false == _FLD2BOOL(SCB_I2C_STATUS_M_READ, SCB_I2C_STATUS(base)))
        {
            /* Cypress ID #295908: Wait until ReStart is generated to complete
            * the previous write transfer. This ensures that the address byte
            * will not be interpreted as the data byte of the previous
            * transfer.
            */
            while ((0U == locStatus) &&
                   (0U != (SCB_I2C_M_CMD_M_START_Msk & SCB_I2C_M_CMD(base))))
            {
                locStatus = WaitOneUnit(&timeout);
            }
        }

        /* Check for timeout and continue */
        if (0U == locStatus)
        {
            /* Send the address byte */
            Cy_SCB_WriteTxFifo(base, (_VAL2FLD(CY_SCB_I2C_ADDRESS, address) | (uint32_t) bitRnW));

            /* Wait for a completion event from the or slave */
            do
            {
                locStatus  = (CY_SCB_I2C_MASTER_TX_BYTE_DONE & Cy_SCB_GetMasterInterruptStatus(base));
                locStatus |= WaitOneUnit(&timeout);

            } while (0UL == locStatus);
        }

        /* Convert the status from register plus timeout to the return status */
        retStatus = HandleStatus(base, locStatus, context);
    }

    return (retStatus);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_MasterSendStop
****************************************************************************//**
*
* Generates a Stop condition to complete the current transaction.
* This function is blocking. It does not return until the Stop condition
* is generated, or an error or timeout occurs.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param timeoutMs
* Defines in milliseconds the time for which this function can block.
* If that time expires, the function returns. If a zero is passed,
* the function waits forever for the action to complete. If a timeout occurs,
* the SCB block is reset. Note The maximum value is UINT32_MAX/1000.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* \ref cy_en_scb_i2c_status_t
*
* \note
* * A successful transaction must be initiated by
*   \ref Cy_SCB_I2C_MasterSendStart or \ref Cy_SCB_I2C_MasterSendReStart
*   before calling this function. If this condition is not met, this function
*   does nothing and returns.
*   \ref CY_SCB_I2C_MASTER_NOT_READY.
* * Even after the slave NAKs the address, this function must be called
*   to complete the transaction.
*
*******************************************************************************/
cy_en_scb_i2c_status_t Cy_SCB_I2C_MasterSendStop(CySCB_Type *base,uint32_t timeoutMs,
                                cy_stc_scb_i2c_context_t *context)
{
    CY_ASSERT_L2(CY_SCB_I2C_IS_TIMEOUT_VALID(timeoutMs));

    cy_en_scb_i2c_status_t retStatus = CY_SCB_I2C_MASTER_NOT_READY;

    if (0UL != (CY_SCB_I2C_MASTER_ACTIVE & context->state))
    {
        uint32_t locStatus;
        uint32_t timeout = CY_SCB_I2C_CONVERT_TIMEOUT_TO_US(timeoutMs);

        /* Generate a stop (for Write direction) and NACK plus stop for the Read direction */
        SCB_I2C_M_CMD(base) = (SCB_I2C_M_CMD_M_STOP_Msk | SCB_I2C_M_CMD_M_NACK_Msk);

        /* Wait for a completion event from the master or slave */
        do
        {
            locStatus  = (CY_SCB_I2C_MASTER_STOP_DONE & Cy_SCB_GetMasterInterruptStatus(base));
            locStatus |= WaitOneUnit(&timeout);

        } while (0UL == locStatus);

        /* Convert the status from register plus timeout to the return status */
        retStatus = HandleStatus(base, locStatus, context);
    }

    return (retStatus);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_MasterReadByte
****************************************************************************//**
*
* Reads one byte from a slave and generates an ACK or prepares to generate
* a NAK. The NAK will be generated before a Stop or ReStart condition by
* \ref Cy_SCB_I2C_MasterSendStop or \ref Cy_SCB_I2C_MasterSendReStart function
* appropriately.
* This function is blocking. It does not return until a byte is
* received, or an error or timeout occurs.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param ackNack
* A response to a received byte.
* See \ref cy_en_scb_i2c_command_t for the set of constants.
*
* \param byte
* The pointer to the location to store the Read byte.
*
* \param timeoutMs
* Defines in milliseconds the time for which this function can block.
* If that time expires, the function returns. If a zero is passed,
* the function waits forever for the action to complete. If a timeout occurs,
* the SCB block is reset. Note The maximum value is UINT32_MAX/1000.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* \ref cy_en_scb_i2c_status_t
*
* \note
* A successful transaction must be initiated by \ref Cy_SCB_I2C_MasterSendStart
* or \ref Cy_SCB_I2C_MasterSendReStart before calling this function. If this
* condition is not met, this function does nothing and returns
* \ref CY_SCB_I2C_MASTER_NOT_READY.
*
*******************************************************************************/
cy_en_scb_i2c_status_t Cy_SCB_I2C_MasterReadByte(CySCB_Type *base,
                            cy_en_scb_i2c_command_t ackNack, uint8_t *byte,
                            uint32_t timeoutMs,
                            cy_stc_scb_i2c_context_t *context)
{
    CY_ASSERT_L1(CY_SCB_IS_BUFFER_VALID      (byte, 1UL));
    CY_ASSERT_L2(CY_SCB_I2C_IS_TIMEOUT_VALID (timeoutMs));
    CY_ASSERT_L3(CY_SCB_I2C_IS_RESPONSE_VALID(ackNack));

    cy_en_scb_i2c_status_t retStatus = CY_SCB_I2C_MASTER_NOT_READY;

    if (CY_SCB_I2C_MASTER_RX0 == context->state)
    {
        bool     rxNotEmpty;
        uint32_t locStatus;
        uint32_t timeout = CY_SCB_I2C_CONVERT_TIMEOUT_TO_US(timeoutMs);

        /* Wait for ACK/NAK transmission and data byte reception */
        do
        {
            rxNotEmpty = (0UL != (CY_SCB_RX_INTR_NOT_EMPTY & Cy_SCB_GetRxInterruptStatus(base)));
            locStatus  = (CY_SCB_I2C_MASTER_RX_BYTE_DONE & Cy_SCB_GetMasterInterruptStatus(base));
            locStatus |= WaitOneUnit(&timeout);

        } while ((!rxNotEmpty) && (0UL == locStatus));


        if (rxNotEmpty)
        {
            /* Get the received data byte */
            *byte = (uint8_t) Cy_SCB_ReadRxFifo(base);

            Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_NOT_EMPTY | CY_SCB_RX_INTR_LEVEL);
        }

        /* Convert the status from register plus timeout to the return status */
        retStatus = HandleStatus(base, locStatus, context);

        if (CY_SCB_I2C_SUCCESS == retStatus)
        {
            if (CY_SCB_I2C_ACK == ackNack)
            {
                /* Generate ACK */
                SCB_I2C_M_CMD(base) = SCB_I2C_M_CMD_M_ACK_Msk;
            }
            else
            {
                /* NAK is generated by SendStop() or SendReStart() */
            }
        }
    }

    return (retStatus);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_MasterWriteByte
****************************************************************************//**
*
* Sends one byte to a slave.
* This function is blocking. It does not return until a byte is
* transmitted, or an error or timeout occurs.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param byte
* The byte to write to a slave.
*
* \param timeoutMs
* Defines in milliseconds the time for which this function can block.
* If that time expires, the function returns. If a zero is passed,
* the function waits forever for the action to complete. If a timeout occurs,
* the SCB block is reset. Note The maximum value is UINT32_MAX/1000.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* \ref cy_en_scb_i2c_status_t
*
* \note
* A successful transaction must be initiated by \ref Cy_SCB_I2C_MasterSendStart
* or \ref Cy_SCB_I2C_MasterSendReStart before calling this function. If this
* condition is not met, this function does nothing and returns
* \ref CY_SCB_I2C_MASTER_NOT_READY.
*
*******************************************************************************/
cy_en_scb_i2c_status_t Cy_SCB_I2C_MasterWriteByte(CySCB_Type *base, uint8_t byte, uint32_t timeoutMs,
                                                  cy_stc_scb_i2c_context_t *context)
{
    CY_ASSERT_L2(CY_SCB_I2C_IS_TIMEOUT_VALID(timeoutMs));

    cy_en_scb_i2c_status_t retStatus = CY_SCB_I2C_MASTER_NOT_READY;

    if (CY_SCB_I2C_MASTER_TX == context->state)
    {
        uint32_t locStatus;
        uint32_t timeout = CY_SCB_I2C_CONVERT_TIMEOUT_TO_US(timeoutMs);

        /* Send the data byte */
        Cy_SCB_WriteTxFifo(base, (uint32_t) byte);

        /* Wait for a completion event from the master or slave */
        do
        {
            locStatus  = (CY_SCB_I2C_MASTER_TX_BYTE_DONE & Cy_SCB_GetMasterInterruptStatus(base));
            locStatus |= WaitOneUnit(&timeout);

        } while (0UL == locStatus);

        /* Convert the status from register plus timeout to the API status */
        retStatus = HandleStatus(base, locStatus, context);
    }

    return (retStatus);
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_Interrupt
****************************************************************************//**
*
* This is the interrupt function for the SCB configured in the I2C mode.
* The interrupt is mandatory for I2C operation and this function must be called
* inside the user-defined interrupt service. The exception is the I2C master,
* which uses only the \ref group_scb_i2c_master_low_level_functions functions.
* To reduce the flash consumed by the I2C driver call
* \ref Cy_SCB_I2C_SlaveInterrupt when I2C mode is the slave and
* \ref Cy_SCB_I2C_MasterInterrupt when I2C mode is the master.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
*******************************************************************************/
void Cy_SCB_I2C_Interrupt(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    if (0UL != (CY_SCB_I2C_MASTER_ACTIVE & context->state))
    {
        /* Execute a transfer as the master */
        Cy_SCB_I2C_MasterInterrupt(base, context);
    }
    else
    {
        /* Execute a transfer as the slave */
        Cy_SCB_I2C_SlaveInterrupt(base, context);
    }
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_SlaveInterrupt
****************************************************************************//**
*
* This is the interrupt function for the SCB configured in I2C mode as the
* slave. This function should be called inside the user-defined interrupt
* service routine to make any of the slave functions to work.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
*******************************************************************************/
void Cy_SCB_I2C_SlaveInterrupt(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    uint32_t slaveIntrStatus;

    /* Handle an I2C wake-up event */
    if (0UL != (CY_SCB_I2C_INTR_WAKEUP & Cy_SCB_GetI2CInterruptStatusMasked(base)))
    {
        /* Move from IDLE state, the slave was addressed. Following address match
        * interrupt continue transfer.
        */
        context->state = CY_SCB_I2C_SLAVE_ACTIVE;

        Cy_SCB_ClearI2CInterrupt(base, CY_SCB_I2C_INTR_WAKEUP);
    }

    /* Handle the slave interrupt sources */
    slaveIntrStatus = Cy_SCB_GetSlaveInterruptStatusMasked(base);

    /* Handle the error conditions */
    if (0UL != (CY_SCB_I2C_SLAVE_INTR_ERROR & slaveIntrStatus))
    {
        /* Update the status */
        context->slaveStatus |= (0UL != (CY_SCB_SLAVE_INTR_I2C_BUS_ERROR & slaveIntrStatus)) ?
                                            CY_SCB_I2C_SLAVE_BUS_ERR : CY_SCB_I2C_SLAVE_ARB_LOST;

        /* Disable the RX interrupt source to drop data into RX FIFO if any */
        Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);

        /* Add the stop status to back into the default state and set completion statuses */
        slaveIntrStatus |= CY_SCB_SLAVE_INTR_I2C_STOP;
    }
    else
    {
        if (0UL != (CY_SCB_SLAVE_INTR_I2C_STOP & slaveIntrStatus))
        {
            /* Get data from the RX FIFO after a stop is generated if there is
            * space to store it.
            */
            if ((Cy_SCB_GetNumInRxFifo(base) > 0UL) && (context->slaveRxBufferSize > 0UL))
            {
                Cy_SCB_SetRxInterrupt    (base, CY_SCB_RX_INTR_LEVEL);
                Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL);
            }
        }
    }

    /* Handle the receive direction (master writes data) */
    if (0UL != (CY_SCB_RX_INTR_LEVEL & Cy_SCB_GetRxInterruptStatusMasked(base)))
    {
        SlaveHandleDataReceive(base, context);

        Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_LEVEL);
    }

    /* Handle the transfer completion */
    if (0UL != (CY_SCB_SLAVE_INTR_I2C_STOP & slaveIntrStatus))
    {
        SlaveHandleStop(base, context);

        Cy_SCB_ClearSlaveInterrupt(base, CY_SCB_SLAVE_INTR_I2C_STOP);

        /* Update the slave interrupt status */
        slaveIntrStatus = Cy_SCB_GetSlaveInterruptStatusMasked(base);
    }

    /* Handle the address reception */
    if (0UL != (CY_SCB_I2C_SLAVE_INTR_ADDR & slaveIntrStatus))
    {
        SlaveHandleAddress(base, context);

        Cy_SCB_ClearI2CInterrupt(base, CY_SCB_I2C_INTR_WAKEUP);
        Cy_SCB_ClearSlaveInterrupt(base, CY_SCB_I2C_SLAVE_INTR_ADDR);
    }

    /* Handle the transmit direction (master reads data) */
    if (0UL != (CY_SCB_I2C_SLAVE_INTR_TX & Cy_SCB_GetTxInterruptStatusMasked(base)))
    {
        SlaveHandleDataTransmit(base, context);

        Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_LEVEL);
    }
}

#if (((defined (CY_IP_MXSCB_VERSION) && (CY_IP_MXSCB_VERSION>=3)) || defined (CY_IP_MXS22SCB)) || defined (CY_DOXYGEN))
/*******************************************************************************
* Function Name: Cy_SCB_I2C_SetStretchThreshold
****************************************************************************//**
*
* Sets the stretch threshold value.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param value
* The stretch threshold value to be set.
* Typically it is the SCL turaround delay (including IO cell delay, SCL rise time,
* analog filter delay), in number of clk_scb cycles.
*
* \note
* * The STRETCH_THRESHOLD value is 0 by default. If there is no device stretching
*   the SCL bus, the delay between SCL output and input are reported in
*   STRETCH_COUNT \ref Cy_SCB_I2C_GetStretchCount, in number of clk_scb cycles,
*   which can then be set as the STRETCH_THRESHOLD value.
* * The STRETCH_THRESHOLD value should be less than or equal to 0xFUL.
* * When STRETCH_COUNT \ref Cy_SCB_I2C_GetStretchCount is higher than this
*   STRETCH_THRESHOLD, STRETCH_DETECTED \ref Cy_SCB_I2C_IsStretchDetected
*   will be set.
*
*******************************************************************************/
void Cy_SCB_I2C_SetStretchThreshold(CySCB_Type const *base, uint32_t value)
{
    CY_ASSERT_L2(CY_SCB_I2C_STRETCH_THRESHOLD_VALUE_VALID(value));
    SCB_I2C_STRETCH_CTRL(base) = _VAL2FLD(SCB_I2C_STRETCH_CTRL_STRETCH_THRESHOLD, value);
}

/*******************************************************************************
* Function Name: Cy_SCB_I2C_GetStretchCount
****************************************************************************//**
*
* Provides the stretch count. The count is started when the I2C device begins to
* drive high phase on internal SCL output signal and is stalled when it detects
* high level on SCL input signal.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \return
* The stretch count.
*
*******************************************************************************/
uint32_t Cy_SCB_I2C_GetStretchCount(CySCB_Type const *base)
{
    return(_FLD2VAL(SCB_I2C_STRETCH_STATUS_STRETCH_COUNT, SCB_I2C_STRETCH_STATUS(base)));
}

/*******************************************************************************
* Function Name: Cy_SCB_I2C_IsStretchDetected
****************************************************************************//**
*
* Checks if stretch is detected on I2C SCL.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \return
* If true, stretch is detected; false otherwise.
*
*******************************************************************************/
bool Cy_SCB_I2C_IsStretchDetected(CySCB_Type const *base)
{
    return (1UL == (_FLD2VAL(SCB_I2C_STRETCH_STATUS_STRETCH_DETECTED, SCB_I2C_STRETCH_STATUS(base))));
}

/*******************************************************************************
* Function Name: Cy_SCB_I2C_IsSyncDetected
****************************************************************************//**
*
* Checks if synchronization is detected on I2C SCL.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \return
* If true, synchronization is detected; false otherwise.
*
*******************************************************************************/
bool Cy_SCB_I2C_IsSyncDetected(CySCB_Type const *base)
{
    return (1UL == (_FLD2VAL(SCB_I2C_STRETCH_STATUS_SYNC_DETECTED, SCB_I2C_STRETCH_STATUS(base))));
}

/*******************************************************************************
* Function Name: Cy_SCB_I2C_IsStretching
****************************************************************************//**
*
* Checks if I2C SCL is stretched by the block.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \return
* If true, I2C SCL is being stretch by the block, false otherwise.
*
*******************************************************************************/
bool Cy_SCB_I2C_IsStretching(CySCB_Type const *base)
{
    return (1UL == (_FLD2VAL(SCB_I2C_STRETCH_STATUS_STRETCHING, SCB_I2C_STRETCH_STATUS(base))));
}
#endif /* CY_IP_MXSCB_VERSION */

/*******************************************************************************
* Function Name: SlaveHandleAddress
****************************************************************************//**
*
* Prepares the slave for the following Read or Write transfer after the
* matched address was received.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
*******************************************************************************/
static void SlaveHandleAddress(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    /* The default command is the ACK address. It can be overridden in an address callback */
    cy_en_scb_i2c_command_t cmd = CY_SCB_I2C_ACK;

    /* The callback for the address in RX FIFO or a general call */
    if (NULL != context->cbAddr)
    {
        uint32_t events = 0UL;

        /* Set an address in the FIFO event if the address accept is enabled */
        if (_FLD2BOOL(SCB_CTRL_ADDR_ACCEPT, SCB_CTRL(base)))
        {
            events = (0UL != (CY_SCB_SLAVE_INTR_I2C_ADDR_MATCH & Cy_SCB_GetSlaveInterruptStatusMasked(base))) ?
                              CY_SCB_I2C_ADDR_IN_FIFO_EVENT : 0UL;
        }

        /* Set a general call event if "ignore general call" is disabled */
        if (!_FLD2BOOL(SCB_I2C_CTRL_S_GENERAL_IGNORE, SCB_I2C_CTRL(base)))
        {
            events |= (0UL != (CY_SCB_SLAVE_INTR_I2C_GENERAL_ADDR & Cy_SCB_GetSlaveInterruptStatusMasked(base))) ?
                               CY_SCB_I2C_GENERAL_CALL_EVENT : 0UL;
        }

        /* Check presence of events before involve callback */
        if (0UL != events)
        {
            /* Involve a callback for the address phase and get the ACK/NACK command */
            cmd = context->cbAddr(events);

            /* Clear RX level interrupt after address reception */
            Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_LEVEL);

            if (cmd == CY_SCB_I2C_ACK)
            {
                /* Clear the stall stop status and enable the stop interrupt source */
                Cy_SCB_ClearSlaveInterrupt(base, CY_SCB_SLAVE_INTR_I2C_STOP);
                Cy_SCB_SetSlaveInterruptMask(base, CY_SCB_I2C_SLAVE_INTR);
            }
            else
            {
                /* Disable the stop interrupt source */
                Cy_SCB_SetSlaveInterruptMask(base, CY_SCB_I2C_SLAVE_INTR_NO_STOP);
            }
        }
    }

    /* Clear the TX FIFO before continue the transaction */
    Cy_SCB_ClearTxFifo(base);

    /* Set the command to an ACK or NACK address */
    SCB_I2C_S_CMD(base) = (cmd == CY_SCB_I2C_ACK) ? SCB_I2C_S_CMD_S_ACK_Msk : SCB_I2C_S_CMD_S_NACK_Msk;

    if (cmd == CY_SCB_I2C_ACK)
    {
        bool readDirection = _FLD2BOOL(SCB_I2C_STATUS_S_READ,SCB_I2C_STATUS(base));

        /* Notify the user about start of transfer */
        if (NULL != context->cbEvents)
        {
            context->cbEvents(readDirection ? CY_SCB_I2C_SLAVE_READ_EVENT : CY_SCB_I2C_SLAVE_WRITE_EVENT);
        }

        /* Prepare for a transfer */
        if (readDirection)
        {
            context->state        = CY_SCB_I2C_SLAVE_TX;
            context->slaveStatus |= CY_SCB_I2C_SLAVE_RD_BUSY;

            /* Prepare to transmit data */
            context->slaveTxBufferIdx = context->slaveTxBufferCnt;
            context->slaveRdBufEmpty  = false;
            Cy_SCB_SetTxInterruptMask(base, CY_SCB_TX_INTR_LEVEL);
        }
        else
        {
            uint32_t level = 0UL;

            context->state        = CY_SCB_I2C_SLAVE_RX;
            context->slaveStatus |= CY_SCB_I2C_SLAVE_WR_BUSY;

            /* Prepare to receive data */
            Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL);

            if (context->useRxFifo)
            {
                if (context->slaveRxBufferSize > 0UL)
                {
                    uint32_t fifoSize = CY_SCB_I2C_FIFO_SIZE;

                    /* ACK data automatically until RX FIFO is full */
                    SCB_I2C_CTRL(base) |= SCB_I2C_CTRL_S_READY_DATA_ACK_Msk;

                    if (context->slaveRxBufferSize > fifoSize)
                    {
                        /* Set a level in RX FIFO to trigger the receive interrupt source */
                        level = (context->slaveRxBufferSize - fifoSize);
                        level = ((level > fifoSize) ? (fifoSize / 2UL) : level) - 1UL;
                    }
                    else
                    {
                        /* Set a level in RX FIFO to read the number of bytes */
                        level = (context->slaveRxBufferSize - 1UL);

                        /* NACK when RX FIFO becomes full */
                        SCB_I2C_CTRL(base) |= SCB_I2C_CTRL_S_NOT_READY_DATA_NACK_Msk;

                        /* Disable the RX level interrupt and wait until RX FIFO is full or stops */
                        Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
                    }
                }
            }

            Cy_SCB_SetRxFifoLevel(base, level);
        }
    }
}


/*******************************************************************************
* Function Name: SlaveHandleDataReceive
****************************************************************************//**
*
* Reads data from RX FIFO into the buffer provided by
* \ref Cy_SCB_I2C_SlaveConfigWriteBuf.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
*******************************************************************************/
static void SlaveHandleDataReceive(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    /* Check whether there is space to put data */
    if (context->slaveRxBufferSize > 0UL)
    {
        if (context->useRxFifo)
        {
            uint32_t level;
            uint32_t fifoSize = CY_SCB_I2C_FIFO_SIZE;

            /* Get the number of bytes to read from RX FIFO */
            uint32_t numToCopy = Cy_SCB_GetRxFifoLevel(base) + 1UL;

            /* Clamp numToCopy to the remaining buffer size to prevent overflow */
            if (numToCopy > context->slaveRxBufferSize)
            {
                numToCopy = context->slaveRxBufferSize;
            }
            
            /* Get data from RX FIFO */
            numToCopy = Cy_SCB_ReadArray(base, context->slaveRxBuffer, numToCopy);
            context->slaveRxBufferIdx  += numToCopy;
            context->slaveRxBufferSize -= numToCopy;
            context->slaveRxBuffer      = &context->slaveRxBuffer[numToCopy];

            /* Prepare to read a next chunk of data */
            if (context->slaveRxBufferSize > fifoSize)
            {
                level = context->slaveRxBufferSize - fifoSize;
                level = ((level > fifoSize) ? (fifoSize / 2UL) : level) - 1UL;
            }
            else
            {
                SCB_I2C_CTRL(base) |= SCB_I2C_CTRL_S_NOT_READY_DATA_NACK_Msk;

                level = (context->slaveRxBufferSize == 0UL) ? (0UL) : (context->slaveRxBufferSize - 1UL);
                Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
            }

            /* Set the RX level to trigger an interrupt */
            Cy_SCB_SetRxFifoLevel(base, level);
        }
        else
        {
            /* Continue the transfer: send an ACK */
            SCB_I2C_S_CMD(base) = SCB_I2C_S_CMD_S_ACK_Msk;

            /* Put data into the RX buffer */
            context->slaveRxBuffer[context->slaveRxBufferIdx] = (uint8_t) Cy_SCB_ReadRxFifo(base);
            ++context->slaveRxBufferIdx;
            --context->slaveRxBufferSize;
        }
    }
    else
    {
        /* Finish a transfer: send a NACK and discard the received byte */
        SCB_I2C_S_CMD(base) = SCB_I2C_S_CMD_S_NACK_Msk;
        Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
    }
}


/*******************************************************************************
* Function Name: SlaveHandleDataTransmit
****************************************************************************//**
*
* Loads TX FIFO with data provided by \ref Cy_SCB_I2C_SlaveConfigReadBuf.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
*******************************************************************************/
static void SlaveHandleDataTransmit(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    uint32_t numToCopy;

    /* Notify the user that there is no data to send to the master.
    * This event triggers once in scope of a transfer.
    */
    if ((!context->slaveRdBufEmpty) && (0UL == context->slaveTxBufferSize))
    {
        /* Involve a callback if registered: no data to send */
        if (NULL != context->cbEvents)
        {
            context->cbEvents(CY_SCB_I2C_SLAVE_RD_BUF_EMPTY_EVENT);
        }

        /* Update the Read buffer empty status after a callback is involved */
        context->slaveRdBufEmpty = (0UL == context->slaveTxBufferSize);

        /* Enable the TX level interrupt source to continue sending data */
        Cy_SCB_SetTxInterruptMask(base, CY_SCB_TX_INTR_LEVEL);
    }

    /* Check whether the Read buffer was updated in the callback */
    if (context->slaveRdBufEmpty)
    {
        /* The Read buffer is empty: copy CY_SCB_I2C_DEFAULT_TX into TX FIFO */
        numToCopy = (context->useTxFifo) ? Cy_SCB_GetFifoSize(base) : 1UL;

        numToCopy = Cy_SCB_WriteDefaultArray(base, CY_SCB_I2C_DEFAULT_TX, numToCopy);
        context->slaveTxBufferIdx += numToCopy;

        context->slaveStatus |= CY_SCB_I2C_SLAVE_RD_UNDRFL;
    }
    else
    {
        if (context->slaveTxBufferSize > 1UL)
        {
            /* Get the number of bytes to copy into TX FIFO */
            numToCopy = (context->useTxFifo) ? (context->slaveTxBufferSize - 1UL) : (1UL);

            /* Write data into TX FIFO */
            numToCopy = Cy_SCB_WriteArray(base, context->slaveTxBuffer, numToCopy);
            context->slaveTxBufferIdx  += numToCopy;
            context->slaveTxBufferSize -= numToCopy;
            context->slaveTxBuffer      = &context->slaveTxBuffer[numToCopy];
        }

        /* Put the last byte */
        if ((CY_SCB_I2C_FIFO_SIZE != Cy_SCB_GetNumInTxFifo(base)) && (1UL == context->slaveTxBufferSize))
        {
            uint32_t intrStatus;

             /* Put the last data byte in the TX FIFO and clear the TX Underflow
            * interrupt source inside the critical section to ensure that the
            * TX Underflow interrupt will trigger after all data bytes from the
            * TX FIFO are transferred onto the bus.
            */
            intrStatus = Cy_SysLib_EnterCriticalSection();

            Cy_SCB_WriteTxFifo     (base, (uint32_t) context->slaveTxBuffer[0UL]);
            Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_UNDERFLOW);

            Cy_SysLib_ExitCriticalSection(intrStatus);

            /* Move the pointers */
            ++context->slaveTxBufferIdx;
            context->slaveTxBufferSize = 0UL;
            context->slaveTxBuffer     = &context->slaveTxBuffer[1UL];

            /* Enable the TX underflow interrupt to catch when there is no data to send */
            Cy_SCB_SetTxInterruptMask(base, CY_SCB_TX_INTR_UNDERFLOW);

            if (context->useTxFifo)
            {
                /* Data is copied into TX FIFO */
                context->slaveStatus |= CY_SCB_I2C_SLAVE_RD_IN_FIFO;

                /* Involve a callback if registered: data copied into TX FIFO */
                if (NULL != context->cbEvents)
                {
                    context->cbEvents(CY_SCB_I2C_SLAVE_RD_IN_FIFO_EVENT);
                }
            }
        }
    }
}


/*******************************************************************************
* Function Name: SlaveHandleStop
****************************************************************************//**
*
* Handles transfer completion. It is triggered by a stop or restart
* condition on the bus.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
*******************************************************************************/
static void SlaveHandleStop(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    uint32_t locEvents;

    if (CY_SCB_I2C_SLAVE_RX == context->state)
    {
        /* If any data is left in RX FIFO, this is an overflow */
        if (Cy_SCB_GetNumInRxFifo(base) > 0UL)
        {
            context->slaveStatus |= CY_SCB_I2C_SLAVE_WR_OVRFL;

            if (context->useRxFifo)
            {
                Cy_SCB_ClearRxFifo(base);
            }
            else
            {
                (void) Cy_SCB_ReadRxFifo(base);
            }
        }

        locEvents             = (uint32_t)  CY_SCB_I2C_SLAVE_WR_CMPLT_EVENT;
        context->slaveStatus |= (uint32_t)  CY_SCB_I2C_SLAVE_WR_CMPLT;
        context->slaveStatus &= (uint32_t) ~CY_SCB_I2C_SLAVE_WR_BUSY;

        /* Clean up the RX direction */
        SCB_I2C_CTRL(base) &= (uint32_t) ~(SCB_I2C_CTRL_S_READY_DATA_ACK_Msk |
                                          SCB_I2C_CTRL_S_NOT_READY_DATA_NACK_Msk);

        Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
        Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_LEVEL);
    }
    else
    {
        /* The number of bytes left in TX FIFO */
        uint32_t size = Cy_SCB_GetNumInTxFifo(base) + Cy_SCB_GetTxSrValid(base);

        /* Get the number of bytes transferred from the read buffer */
        context->slaveTxBufferCnt = (context->slaveTxBufferIdx - size);

        /* Update buffer pointer and its size if there is no overflow */
        if (0UL == (CY_SCB_I2C_SLAVE_RD_UNDRFL & context->slaveStatus))
        {
            context->slaveTxBufferSize += size;
            context->slaveTxBuffer     -= size;
        }

        locEvents             = (uint32_t)  CY_SCB_I2C_SLAVE_RD_CMPLT_EVENT;
        context->slaveStatus |= (uint32_t)  CY_SCB_I2C_SLAVE_RD_CMPLT;
        context->slaveStatus &= (uint32_t) ~CY_SCB_I2C_SLAVE_RD_BUSY;

        /* Clean up the TX direction */
        Cy_SCB_SetTxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
    }

    /* Return scb into the known state after an error */
    if (0UL != (CY_SCB_I2C_SLAVE_INTR_ERROR & Cy_SCB_GetSlaveInterruptStatusMasked(base)))
    {
        /* After scb IP is reset, the interrupt statuses are cleared */
        Cy_SCB_FwBlockReset(base);

        locEvents |= CY_SCB_I2C_SLAVE_ERR_EVENT;
    }

    /* After a stop or error, set the state to idle */
    context->state = CY_SCB_I2C_IDLE;

    /* Call a completion callback if registered */
    if (NULL != context->cbEvents)
    {
        context->cbEvents(locEvents);
    }
}


/*******************************************************************************
* Function Name: Cy_SCB_I2C_MasterInterrupt
****************************************************************************//**
*
* This is the interrupt function for the SCB configured in I2C mode as the
* master. This function should be called inside the user-defined interrupt
* service routine to make \ref group_scb_i2c_master_high_level_functions
* functions to work.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
*******************************************************************************/
void Cy_SCB_I2C_MasterInterrupt(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    uint32_t intrCause = Cy_SCB_GetInterruptCause(base);

    /* Check whether the slave is active. It can be addressed during the master set-up transfer */
    if (0UL != (CY_SCB_SLAVE_INTR & intrCause))
    {
        /* Abort the transfer due to slave operation */
        if (0UL != SCB_I2C_M_CMD(base))
        {
            SCB_I2C_M_CMD(base) = 0UL;

            context->masterStatus |= CY_SCB_I2C_MASTER_ABORT_START;
        }

        context->state = CY_SCB_I2C_MASTER_CMPLT;
    }

    /* Check for master error conditions */
    if (0UL != (CY_SCB_MASTER_INTR & intrCause))
    {
        MasterHandleEvents(base, context);

        /* Any master event does not require further TX processing */
        intrCause &= (uint32_t) ~CY_SCB_TX_INTR;
    }

    if (0UL != (CY_SCB_RX_INTR & intrCause))
    {
        MasterHandleDataReceive(base, context);

        Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_LEVEL);
    }

    if (0UL != (CY_SCB_TX_INTR & intrCause))
    {
        MasterHandleDataTransmit(base, context);

        Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_LEVEL);
    }

    /* Complete the transfer */
    if (CY_SCB_I2C_MASTER_CMPLT == context->state)
    {
        MasterHandleComplete(base, context);
    }

    /* Generate stop to complete transfer */
    if (CY_SCB_I2C_MASTER_STOP == context->state)
    {
        MasterHandleStop(base, context);
    }
}


/*******************************************************************************
* Function Name: MasterHandleMasterEvents
****************************************************************************//**
*
* Reads data from RX FIFO into the buffer provided by \ref Cy_SCB_I2C_MasterRead.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \note
* The master CY_SCB_MASTER_INTR_I2C_ACK interrupt source is used for Stop
* generation or request to abort transfer.
*
*******************************************************************************/
static void MasterHandleEvents(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    uint32_t masterIntrStatus = Cy_SCB_GetMasterInterruptStatusMasked(base);

    /* The master has not received the acknowledgment for slave */
    if (0UL != (CY_SCB_MASTER_INTR_I2C_NACK & masterIntrStatus))
    {
        /* Clear NAK interrupt source */
        Cy_SCB_ClearMasterInterrupt(base, CY_SCB_MASTER_INTR_I2C_NACK);

        /* Update status to indicate address or data was NACKed */
        context->masterStatus |= (0UL != (CY_SCB_MASTER_INTR_I2C_ACK & Cy_SCB_GetMasterInterruptStatus(base))) ?
                                            CY_SCB_I2C_MASTER_DATA_NAK : CY_SCB_I2C_MASTER_ADDR_NAK;

        /* Check whether Stop generation was requested before */
        if (CY_SCB_I2C_MASTER_WAIT_STOP != context->state)
        {
            context->state = (context->masterPause) ? CY_SCB_I2C_MASTER_CMPLT : CY_SCB_I2C_MASTER_STOP;
        }
    }

    /* The master detected a bus error condition */
    if (0UL != (CY_SCB_MASTER_INTR_I2C_BUS_ERROR & masterIntrStatus))
    {
        context->masterStatus |= CY_SCB_I2C_MASTER_BUS_ERR;
    }

    /* The master detected an arbitration lost condition */
    if (0UL != (CY_SCB_MASTER_INTR_I2C_ARB_LOST & masterIntrStatus))
    {
        context->masterStatus |= CY_SCB_I2C_MASTER_ARB_LOST;
    }

    /* Complete the transfer: stop, bus error or arbitration lost */
    if (0UL != (CY_SCB_I2C_MASTER_INTR_CMPLT & masterIntrStatus))
    {
        context->state = CY_SCB_I2C_MASTER_CMPLT;
    }
}


/*******************************************************************************
* Function Name: MasterHandleDataReceive
****************************************************************************//**
*
* Reads data from RX FIFO into the buffer provided by \ref Cy_SCB_I2C_MasterRead.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
*******************************************************************************/
static void MasterHandleDataReceive(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    switch (context->state)
    {
        case CY_SCB_I2C_MASTER_RX0:
        {
            /* Put data into the component buffer */
            context->masterBuffer[0UL] = (uint8_t) Cy_SCB_ReadRxFifo(base);

            ++context->masterBufferIdx;
            --context->masterBufferSize;

            if (context->masterBufferSize > 0UL)
            {
                /* Continue the transaction: move pointer send an ACK */
                context->masterBuffer = &context->masterBuffer[1UL];
                SCB_I2C_M_CMD(base) = SCB_I2C_M_CMD_M_ACK_Msk;
            }
            else
            {
                /* Complete the transaction */
                context->state = (context->masterPause) ? CY_SCB_I2C_MASTER_CMPLT : CY_SCB_I2C_MASTER_STOP;
            }
        }
        break;

        case CY_SCB_I2C_MASTER_RX1:
        {
            uint32_t numToCopied;

            /* Get data from RX FIFO */
            numToCopied = Cy_SCB_ReadArray(base, context->masterBuffer, context->masterBufferSize);
            context->masterBufferIdx  += numToCopied;
            context->masterBufferSize -= numToCopied;
            context->masterBuffer      = &context->masterBuffer[numToCopied];

            if (context->masterBufferSize < 2UL)
            {
                /* Stop ACKing data */
                SCB_I2C_CTRL(base) &= (uint32_t) ~SCB_I2C_CTRL_M_READY_DATA_ACK_Msk;

                if (1UL == context->masterBufferSize)
                {
                    /* Catch the last byte */
                    Cy_SCB_SetRxFifoLevel(base, 0UL);

                    context->state = CY_SCB_I2C_MASTER_RX0;
                }
                else
                {
                    /* Stop RX processing */
                    Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);

                    context->state = CY_SCB_I2C_MASTER_STOP;
                }
            }
            else
            {
                uint32_t halfFifoSize = CY_SCB_I2C_HALF_FIFO_SIZE;

                /* Continue the transfer: Adjust the level in RX FIFO */
                Cy_SCB_SetRxFifoLevel(base, (context->masterBufferSize <= halfFifoSize) ?
                                            (context->masterBufferSize - 2UL) : (halfFifoSize - 1UL));
            }
        }
        break;

        default:
            /* Do nothing: drop data into RX FIFO */
        break;
    }
}


/*******************************************************************************
* Function Name: MasterHandleDataTransmit
****************************************************************************//**
*
* Loads TX FIFO with data provided by \ref Cy_SCB_I2C_MasterWrite.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
*******************************************************************************/
static void MasterHandleDataTransmit(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    if (CY_SCB_I2C_MASTER_TX_DONE == context->state)
    {
        context->state = CY_SCB_I2C_MASTER_CMPLT;
    }
    else if (CY_SCB_I2C_MASTER_TX == context->state)
    {
        if (context->masterBufferSize > 1UL)
        {
            /* Get the number of bytes to copy into TX FIFO */
            uint32_t NumToCopy = (context->useTxFifo) ? (context->masterBufferSize - 1UL) : (1UL);

            /* Write data into TX FIFO */
            NumToCopy = Cy_SCB_WriteArray(base, context->masterBuffer, NumToCopy);
            context->masterBufferIdx  += NumToCopy;
            context->masterBufferSize -= NumToCopy;
            context->masterBuffer      = &context->masterBuffer[NumToCopy];
        }

        /* Put the last byte */
        if ((CY_SCB_I2C_FIFO_SIZE != Cy_SCB_GetNumInTxFifo(base)) && (1UL == context->masterBufferSize))
        {
            uint32_t intrStatus;

            /* Put the last data byte in the TX FIFO and clear the TX Underflow
            * interrupt source inside the critical section to ensure that the
            * TX Underflow interrupt will trigger after all data bytes from the
            * TX FIFO are transferred onto the bus.
            */
            intrStatus = Cy_SysLib_EnterCriticalSection();

            Cy_SCB_WriteTxFifo     (base, (uint32_t) context->masterBuffer[0UL]);
            Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_UNDERFLOW);

            Cy_SysLib_ExitCriticalSection(intrStatus);

            ++context->masterBufferIdx;
            context->masterBufferSize = 0UL;
        }

        /* Complete the transfer */
        if (0UL == context->masterBufferSize)
        {
            if (context->masterPause)
            {
                /* Wait until data is transferred onto the bus */
                Cy_SCB_SetTxInterruptMask(base, CY_SCB_TX_INTR_UNDERFLOW);

                context->state = CY_SCB_I2C_MASTER_TX_DONE;
            }
            else
            {
                /* Disable TX processing */
                Cy_SCB_SetTxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);

                /* Request Stop generation */
                context->state = CY_SCB_I2C_MASTER_STOP;
            }

            if (context->useTxFifo)
            {
                /* Notify the user that data is in TX FIFO */
                context->masterStatus |= CY_SCB_I2C_MASTER_WR_IN_FIFO;

                if (NULL != context->cbEvents)
                {
                    context->cbEvents(CY_SCB_I2C_MASTER_WR_IN_FIFO_EVENT);
                }
            }
        }
    }
    else
    {
        /* Do nothing */
    }
}


/*******************************************************************************
* Function Name: MasterHandleStop
****************************************************************************//**
*
* Handles the stop condition generation
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
*******************************************************************************/
static void MasterHandleStop(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    /* Stop RX and TX processing */
    Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
    Cy_SCB_SetTxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);

    if (0UL != SCB_I2C_M_CMD(base))
    {
        /* Enable ACK interrupt source: it triggers after ACK response to
        * address was received.
        */
        Cy_SCB_SetMasterInterruptMask(base, CY_SCB_I2C_MASTER_INTR_ALL);
    }
    else
    {
        /* Disable ACK interrupt source */
        Cy_SCB_SetMasterInterruptMask(base, CY_SCB_I2C_MASTER_INTR);

        /* Complete transaction generating Stop */
        SCB_I2C_M_CMD(base) = (SCB_I2C_M_CMD_M_STOP_Msk | SCB_I2C_M_CMD_M_NACK_Msk);
        context->state  = CY_SCB_I2C_MASTER_WAIT_STOP;
    }
}


/*******************************************************************************
* Function Name: MasterHandleComplete
****************************************************************************//**
*
* Handles the transfer completion on a stop or restart - the normal case or
* completion due to an error on the bus or lost arbitration.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
*******************************************************************************/
static void MasterHandleComplete(CySCB_Type *base, cy_stc_scb_i2c_context_t *context)
{
    uint32_t masterIntrStatus = Cy_SCB_GetMasterInterruptStatusMasked(base);

    /* Clean-up hardware */

    /* Disable auto data ACK option */
    SCB_I2C_CTRL(base) &= (uint32_t) ~SCB_I2C_CTRL_M_READY_DATA_ACK_Msk;

    /* Disable the interrupt source for master operation */
    Cy_SCB_SetRxInterruptMask    (base, CY_SCB_CLEAR_ALL_INTR_SRC);
    Cy_SCB_SetTxInterruptMask    (base, CY_SCB_CLEAR_ALL_INTR_SRC);
    Cy_SCB_SetMasterInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);

    Cy_SCB_ClearMasterInterrupt(base, CY_SCB_I2C_MASTER_INTR_ALL);

    /* Operation complete - master is not busy anymore */
    context->masterStatus &= (uint32_t) ~CY_SCB_I2C_MASTER_BUSY;

    /* Get number of byte transferred on the bus */
    if (context->masterRdDir)
    {
        context->masterNumBytes = context->masterBufferIdx;
    }
    else
    {
        context->masterNumBytes = context->masterBufferIdx -
                    (Cy_SCB_GetNumInTxFifo(base) + Cy_SCB_GetTxSrValid(base));
    }

    /* Clean up after a not completed transfer */
    if (0UL != (CY_SCB_I2C_MASTER_INTR_ERR & masterIntrStatus))
    {
        /* Reset the scb IP block when:
        *  1. Master mode: Reset IP when arbitration is lost or a bus error occurs.
        *  2. Master-Slave mode: Reset IP if it is not the address phase (ACK is 0).
        *  Otherwise, reset only on a bus error. If "lost arbitration" happens, the slave
        *  can be addressed, so let the slave accept the address.
        */

        bool resetIp = true;

        /* Check the Master-Slave address an ACK/NACK */
        if (((uint32_t) CY_SCB_I2C_MASTER_SLAVE) == _FLD2VAL(CY_SCB_I2C_CTRL_MODE, SCB_I2C_CTRL(base)))
        {
            resetIp = ((0UL != (CY_SCB_MASTER_INTR_I2C_ACK & masterIntrStatus)) ? true :
                            ((0UL != (CY_SCB_MASTER_INTR_I2C_BUS_ERROR & masterIntrStatus)) ? true : false));
        }

        if (resetIp)
        {
            /* Reset to get it back in an known state */
            Cy_SCB_FwBlockReset(base);
        }

        /* Back to the idle state. The master is not active anymore */
        context->state = CY_SCB_I2C_IDLE;
    }
    else
    {
        if (context->useRxFifo)
        {
            /* Clear RX FIFO from remaining data and level interrupt source */
            Cy_SCB_ClearRxFifo(base);
            Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_LEVEL);
        }

        context->state = (context->masterPause) ? CY_SCB_I2C_MASTER_WAIT : CY_SCB_I2C_IDLE;
    }

    /* An operation completion callback */
    if (NULL != context->cbEvents)
    {
        /* Get completion events based on the hardware status */
        uint32_t locEvents = context->masterRdDir ? CY_SCB_I2C_MASTER_RD_CMPLT_EVENT : CY_SCB_I2C_MASTER_WR_CMPLT_EVENT;

        /* Add errors if any */
        locEvents |= (0UL != (CY_SCB_I2C_MASTER_ERR & context->masterStatus)) ? CY_SCB_I2C_MASTER_ERR_EVENT : 0UL;

        context->cbEvents(locEvents);
    }
}



/******************************************************************************
* Function Name: WaitOneUnit
****************************************************************************//**
*
* Waits for one unit before unblock code execution.
* Note that if a timeout value is 0, this function does nothing and returns 0.
*
* \param timeout
* The pointer to a timeout value.
*
* \return
* Returns 0 if a timeout does not expire or the timeout mask.
*
*******************************************************************************/
static uint32_t WaitOneUnit(uint32_t *timeout)
{
    uint32_t status = 0UL;

    /* If the timeout equal to 0. Ignore the timeout */
    if (*timeout > 0UL)
    {
        Cy_SysLib_DelayUs(CY_SCB_WAIT_1_UNIT);
        --(*timeout);

        if (0UL == *timeout)
        {
            status = CY_SCB_I2C_MASTER_TIMEOUT_DONE;
        }
    }

    return (status);
}


/******************************************************************************
* Function Name: HandleStatus
****************************************************************************//**
*
* Converts passed status into the cy_en_scb_i2c_status_t.
*
* \param base
* The pointer to the I2C SCB instance.
*
* \param status
* The status to covert.
*
* \param context
* The pointer to the context structure \ref cy_stc_scb_i2c_context_t allocated
* by the user. The structure is used during the I2C operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return
* \ref cy_en_scb_i2c_status_t
*
*******************************************************************************/
static cy_en_scb_i2c_status_t HandleStatus(CySCB_Type *base, uint32_t status, cy_stc_scb_i2c_context_t *context)
{
    cy_en_scb_i2c_status_t retStatus;
    bool resetBlock = false;

    /* Convert the master status to the API status */
    if (0UL != (CY_SCB_I2C_MASTER_TIMEOUT_DONE & status))
    {
        retStatus  = CY_SCB_I2C_MASTER_MANUAL_TIMEOUT;
        resetBlock = true;
    }
    else if (0UL != (CY_SCB_I2C_SLAVE_ADDR_DONE & status))
    {
        /* Abort the master operation, the slave was addressed first */
        retStatus = CY_SCB_I2C_MASTER_MANUAL_ABORT_START;

        SCB_I2C_M_CMD(base) = 0UL;
        context->state = CY_SCB_I2C_IDLE;
    }
    else if (0UL != (CY_SCB_MASTER_INTR_I2C_BUS_ERROR & status))
    {
        retStatus = CY_SCB_I2C_MASTER_MANUAL_BUS_ERR;
        resetBlock = true;
    }
    else if (0UL != (CY_SCB_MASTER_INTR_I2C_ARB_LOST & status))
    {
        retStatus = CY_SCB_I2C_MASTER_MANUAL_ARB_LOST;

        if (CY_SCB_I2C_MASTER_ADDR == context->state)
        {
            /* This is the address phase:
            *  1. Master mode: Reset IP when "arbitration lost" occurs.
            *  2. Master-Slave mode: If "lost arbitration" occurs, the slave
            *  can be addressed to let the slave accept the address; do not
            *  reset IP.
            */
            resetBlock = !_FLD2BOOL(SCB_I2C_CTRL_SLAVE_MODE, SCB_I2C_CTRL(base));

            context->state = CY_SCB_I2C_IDLE;
        }
        else
        {
            resetBlock = true;
        }
    }
    else if (0UL != (CY_SCB_MASTER_INTR_I2C_NACK & status))
    {
        /* An address or data was NAKed */
        retStatus = (CY_SCB_I2C_MASTER_ADDR == context->state) ?
                     CY_SCB_I2C_MASTER_MANUAL_ADDR_NAK : CY_SCB_I2C_MASTER_MANUAL_NAK;
    }
    else
    {
        retStatus = CY_SCB_I2C_SUCCESS;

        if (0UL != (CY_SCB_MASTER_INTR_I2C_STOP & status))
        {
            /* End of transaction, go to idle state */
            context->state = CY_SCB_I2C_IDLE;
        }
        else
        {
            /* Continue transaction */
            if (CY_SCB_I2C_MASTER_ADDR == context->state)
            {
                /* Switch from address to data state */
                context->state = (context->masterRdDir) ?
                                    CY_SCB_I2C_MASTER_RX0 : CY_SCB_I2C_MASTER_TX;
            }
        }
    }

    if (resetBlock)
    {
        /* Back block into default state */
        Cy_SCB_FwBlockReset(base);

        context->state = CY_SCB_I2C_IDLE;
    }
    else
    {
        Cy_SCB_ClearMasterInterrupt(base, CY_SCB_I2C_MASTER_INTR_ALL);
    }

    return (retStatus);
}


#if defined(__cplusplus)
}
#endif

#endif /* (defined (CY_IP_MXSCB) || defined (CY_IP_MXS22SCB)) */

/* [] END OF FILE */
