status_t I2C_MasterTransferBlocking()

in hw/mcu/nxp/src/ext/nxp-kinetis-sdk/drivers/fsl_i2c.c [1239:1459]


status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer)
{
    assert(NULL != xfer);

    i2c_direction_t direction = xfer->direction;
    status_t result           = kStatus_Success;

    /* Clear all status before transfer. */
    I2C_MasterClearStatusFlags(base, (uint32_t)kClearFlags);

#if I2C_RETRY_TIMES != 0U
    uint32_t waitTimes = I2C_RETRY_TIMES;
    /* Wait until the data register is ready for transmit. */
    while ((0U == (base->S & (uint8_t)kI2C_TransferCompleteFlag)) && (0U != waitTimes))
    {
        waitTimes--;
    }
    if (0U == waitTimes)
    {
        return kStatus_I2C_Timeout;
    }
#else
    /* Wait until the data register is ready for transmit. */
    while (0U == (base->S & (uint8_t)kI2C_TransferCompleteFlag))
    {
    }
#endif

    /* Change to send write address when it's a read operation with command. */
    if ((xfer->subaddressSize > 0U) && (xfer->direction == kI2C_Read))
    {
        direction = kI2C_Write;
    }

    /* Handle no start option, only support write with no start signal. */
    if (0U != (xfer->flags & (uint32_t)kI2C_TransferNoStartFlag))
    {
        if (direction == kI2C_Read)
        {
            return kStatus_InvalidArgument;
        }
    }
    /* If repeated start is requested, send repeated start. */
    else if (0U != (xfer->flags & (uint32_t)kI2C_TransferRepeatedStartFlag))
    {
        result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, direction);
    }
    else /* For normal transfer, send start. */
    {
        result = I2C_MasterStart(base, xfer->slaveAddress, direction);
    }

    if (0U == (xfer->flags & (uint32_t)kI2C_TransferNoStartFlag))
    {
        /* Return if error. */
        if (kStatus_Success != result)
        {
            return result;
        }

#if I2C_RETRY_TIMES != 0U
        waitTimes = I2C_RETRY_TIMES;
        /* Wait until data transfer complete. */
        while ((0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) && (0U != waitTimes))
        {
            waitTimes--;
        }
        if (0U == waitTimes)
        {
            return kStatus_I2C_Timeout;
        }
#else
        /* Wait until data transfer complete. */
        while (0U == (base->S & (uint8_t)kI2C_IntPendingFlag))
        {
        }
#endif
        /* Check if there's transfer error. */
        result = I2C_CheckAndClearError(base, base->S);

        /* Return if error. */
        if (kStatus_Success != result)
        {
            if (result == kStatus_I2C_Nak)
            {
                result = kStatus_I2C_Addr_Nak;

                (void)I2C_MasterStop(base);
            }

            return result;
        }
    }

    /* Send subaddress. */
    if (0U != (xfer->subaddressSize))
    {
        do
        {
            /* Clear interrupt pending flag. */
            base->S = (uint8_t)kI2C_IntPendingFlag;

            xfer->subaddressSize--;
            base->D = (uint8_t)((xfer->subaddress) >> (8U * xfer->subaddressSize));

#if I2C_RETRY_TIMES != 0U
            waitTimes = I2C_RETRY_TIMES;
            /* Wait until data transfer complete. */
            while ((0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) && (0U != waitTimes))
            {
                waitTimes--;
            }
            if (0U == waitTimes)
            {
                return kStatus_I2C_Timeout;
            }
#else
            /* Wait until data transfer complete. */
            while (0U == (base->S & (uint8_t)kI2C_IntPendingFlag))
            {
            }
#endif

            /* Check if there's transfer error. */
            result = I2C_CheckAndClearError(base, base->S);

            if (0 != result)
            {
                if (result == kStatus_I2C_Nak)
                {
                    (void)I2C_MasterStop(base);
                }

                return result;
            }

        } while (xfer->subaddressSize > 0u);

        if (xfer->direction == kI2C_Read)
        {
            /* Clear pending flag. */
            base->S = (uint8_t)kI2C_IntPendingFlag;

            /* Send repeated start and slave address. */
            result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, kI2C_Read);

            /* Return if error. */
            if (kStatus_Success != result)
            {
                return result;
            }

#if I2C_RETRY_TIMES != 0U
            waitTimes = I2C_RETRY_TIMES;
            /* Wait until data transfer complete. */
            while ((0U == (base->S & (uint8_t)kI2C_IntPendingFlag)) && (0U != waitTimes))
            {
                waitTimes--;
            }
            if (0U == waitTimes)
            {
                return kStatus_I2C_Timeout;
            }
#else
            /* Wait until data transfer complete. */
            while (0U == (base->S & (uint8_t)kI2C_IntPendingFlag))
            {
            }
#endif

            /* Check if there's transfer error. */
            result = I2C_CheckAndClearError(base, base->S);

            if (kStatus_Success != result)
            {
                if (result == kStatus_I2C_Nak)
                {
                    result = kStatus_I2C_Addr_Nak;

                    (void)I2C_MasterStop(base);
                }

                return result;
            }
        }
    }

    /* Transmit data. */
    if (xfer->direction == kI2C_Write)
    {
        if (xfer->dataSize > 0U)
        {
            uint8_t *tmpData   = xfer->data;
            size_t tmpDataSize = xfer->dataSize;
            uint32_t tmpFlags  = xfer->flags;
            /* Send Data. */
            result = I2C_MasterWriteBlocking(base, tmpData, tmpDataSize, tmpFlags);
        }
        else if (0U == (xfer->flags & (uint32_t)kI2C_TransferNoStopFlag))
        {
            /* Send stop. */
            result = I2C_MasterStop(base);
        }
        else
        {
            /* Add this to fix MISRA C2012 rule15.7 issue: Empty else without comment. */
        }
    }

    /* Receive Data. */
    if ((xfer->dataSize > 0u) && (xfer->direction == kI2C_Read))
    {
        uint8_t *tmpData   = xfer->data;
        size_t tmpDataSize = xfer->dataSize;
        uint32_t tmpFlags  = xfer->flags;

        result = I2C_MasterReadBlocking(base, tmpData, tmpDataSize, tmpFlags);
    }

    return result;
}