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 */
}
}
}