void I2C_SlaveTransferHandleIRQ()

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


void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle)
{
    assert(NULL != i2cHandle);

    uint16_t status;
    bool doTransmit            = false;
    i2c_slave_handle_t *handle = (i2c_slave_handle_t *)i2cHandle;
    i2c_slave_transfer_t *xfer;
    volatile uint8_t dummy = 0;
    size_t tmpDataSize     = 0;

    /* Add this to avoid build warning. */
    dummy++;

    status = (uint16_t)I2C_SlaveGetStatusFlags(base);
    xfer   = &(handle->transfer);

#ifdef I2C_HAS_STOP_DETECT
    /* Check stop flag. */
    if (0U != (status & (uint16_t)kI2C_StopDetectFlag))
    {
        I2C_MasterClearStatusFlags(base, (uint32_t)kI2C_StopDetectFlag);

        /* Clear the interrupt flag. */
        base->S = (uint8_t)kI2C_IntPendingFlag;

        /* Call slave callback if this is the STOP of the transfer. */
        if (true == handle->isBusy)
        {
            xfer->event            = kI2C_SlaveCompletionEvent;
            xfer->completionStatus = kStatus_Success;
            handle->isBusy         = false;

            if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback))
            {
                handle->callback(base, xfer, handle->userData);
            }
        }

        if (0U == (status & (uint16_t)kI2C_AddressMatchFlag))
        {
            return;
        }
    }
#endif /* I2C_HAS_STOP_DETECT */

#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT
    /* Check start flag. */
    if (0U != (status & (uint16_t)kI2C_StartDetectFlag))
    {
        I2C_MasterClearStatusFlags(base, (uint32_t)kI2C_StartDetectFlag);

        /* Clear the interrupt flag. */
        base->S = (uint8_t)kI2C_IntPendingFlag;

        xfer->event = kI2C_SlaveStartEvent;

        if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback))
        {
            handle->callback(base, xfer, handle->userData);
        }

        if (0U == (status & (uint16_t)kI2C_AddressMatchFlag))
        {
            return;
        }
    }
#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */

    /* Clear the interrupt flag. */
    base->S = (uint8_t)kI2C_IntPendingFlag;

    /* Check NAK */
    if (0U != (status & (uint16_t)kI2C_ReceiveNakFlag))
    {
        /* Set receive mode. */
        base->C1 &= ~(uint8_t)(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);

        /* Read dummy. */
        dummy = base->D;

        if (handle->transfer.dataSize != 0u)
        {
            xfer->event            = kI2C_SlaveCompletionEvent;
            xfer->completionStatus = kStatus_I2C_Nak;
            handle->isBusy         = false;

            if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback))
            {
                handle->callback(base, xfer, handle->userData);
            }
        }
        else
        {
#ifndef I2C_HAS_STOP_DETECT
            xfer->event            = kI2C_SlaveCompletionEvent;
            xfer->completionStatus = kStatus_Success;
            handle->isBusy         = false;

            if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback))
            {
                handle->callback(base, xfer, handle->userData);
            }
#endif /* !FSL_FEATURE_I2C_HAS_START_STOP_DETECT or !FSL_FEATURE_I2C_HAS_STOP_DETECT */
        }
    }
    /* Check address match. */
    else if (0U != (status & (uint16_t)kI2C_AddressMatchFlag))
    {
        handle->isBusy = true;
        xfer->event    = kI2C_SlaveAddressMatchEvent;

        /* Slave transmit, master reading from slave. */
        if (0U != (status & (uint16_t)kI2C_TransferDirectionFlag))
        {
            /* Change direction to send data. */
            base->C1 |= I2C_C1_TX_MASK;

            doTransmit = true;
        }
        else
        {
            /* Slave receive, master writing to slave. */
            base->C1 &= ~(uint8_t)(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);

            /* Read dummy to release the bus. */
            dummy = base->D;

            if (dummy == 0u)
            {
                xfer->event = kI2C_SlaveGenaralcallEvent;
            }
        }

        if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback))
        {
            handle->callback(base, xfer, handle->userData);
        }
    }
    /* Check transfer complete flag. */
    else if (0U != (status & (uint16_t)kI2C_TransferCompleteFlag))
    {
        /* Slave transmit, master reading from slave. */
        if (0U != (status & (uint16_t)kI2C_TransferDirectionFlag))
        {
            doTransmit = true;
        }
        else
        {
            tmpDataSize = xfer->dataSize;
            /* If we're out of data, invoke callback to get more. */
            if ((NULL == xfer->data) || (0U == tmpDataSize))
            {
                xfer->event = kI2C_SlaveReceiveEvent;

                if (NULL != handle->callback)
                {
                    handle->callback(base, xfer, handle->userData);
                }

                /* Clear the transferred count now that we have a new buffer. */
                xfer->transferredCount = 0;
            }

            /* Slave receive, master writing to slave. */
            uint8_t data = base->D;

            if (0U != (handle->transfer.dataSize))
            {
                /* Receive data. */
                *handle->transfer.data++ = data;
                handle->transfer.dataSize--;
                xfer->transferredCount++;
                if (0U == handle->transfer.dataSize)
                {
#ifndef I2C_HAS_STOP_DETECT
                    xfer->event            = kI2C_SlaveCompletionEvent;
                    xfer->completionStatus = kStatus_Success;
                    handle->isBusy         = false;

                    /* Proceed receive complete event. */
                    if (((handle->eventMask & (uint32_t)xfer->event) != 0U) && (handle->callback != NULL))
                    {
                        handle->callback(base, xfer, handle->userData);
                    }
#endif /* !FSL_FEATURE_I2C_HAS_START_STOP_DETECT or !FSL_FEATURE_I2C_HAS_STOP_DETECT */
                }
            }
        }
    }
    else
    {
        /* Read dummy to release bus. */
        dummy = base->D;
    }

    /* Send data if there is the need. */
    if (doTransmit)
    {
        tmpDataSize = xfer->dataSize;
        /* If we're out of data, invoke callback to get more. */
        if ((NULL == xfer->data) || (0U == tmpDataSize))
        {
            xfer->event = kI2C_SlaveTransmitEvent;

            if (NULL != handle->callback)
            {
                handle->callback(base, xfer, handle->userData);
            }

            /* Clear the transferred count now that we have a new buffer. */
            xfer->transferredCount = 0;
        }

        if (0U != (handle->transfer.dataSize))
        {
            /* Send data. */
            base->D = *handle->transfer.data++;
            handle->transfer.dataSize--;
            xfer->transferredCount++;
        }
        else
        {
            /* Switch to receive mode. */
            base->C1 &= ~(uint8_t)(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);

            /* Read dummy to release bus. */
            dummy = base->D;

#ifndef I2C_HAS_STOP_DETECT
            xfer->event            = kI2C_SlaveCompletionEvent;
            xfer->completionStatus = kStatus_Success;
            handle->isBusy         = false;

            /* Proceed txdone event. */
            if (((handle->eventMask & (uint32_t)xfer->event) != 0U) && (handle->callback != NULL))
            {
                handle->callback(base, xfer, handle->userData);
            }
#endif /* !FSL_FEATURE_I2C_HAS_START_STOP_DETECT or !FSL_FEATURE_I2C_HAS_STOP_DETECT */
        }
    }
}