void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle)
{
assert(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;
/* Add this to avoid build warning. */
dummy++;
status = I2C_SlaveGetStatusFlags(base);
xfer = &(handle->transfer);
#ifdef I2C_HAS_STOP_DETECT
/* Check stop flag. */
if (status & kI2C_StopDetectFlag)
{
I2C_MasterClearStatusFlags(base, kI2C_StopDetectFlag);
/* Clear the interrupt flag. */
base->S = kI2C_IntPendingFlag;
/* Call slave callback if this is the STOP of the transfer. */
if (handle->isBusy)
{
xfer->event = kI2C_SlaveCompletionEvent;
xfer->completionStatus = kStatus_Success;
handle->isBusy = false;
if ((handle->eventMask & xfer->event) && (handle->callback))
{
handle->callback(base, xfer, handle->userData);
}
}
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 (status & kI2C_StartDetectFlag)
{
I2C_MasterClearStatusFlags(base, kI2C_StartDetectFlag);
/* Clear the interrupt flag. */
base->S = kI2C_IntPendingFlag;
xfer->event = kI2C_SlaveRepeatedStartEvent;
if ((handle->eventMask & xfer->event) && (handle->callback))
{
handle->callback(base, xfer, handle->userData);
}
if (!(status & kI2C_AddressMatchFlag))
{
return;
}
}
#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */
/* Clear the interrupt flag. */
base->S = kI2C_IntPendingFlag;
/* Check NAK */
if (status & kI2C_ReceiveNakFlag)
{
/* Set receive mode. */
base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
/* Read dummy. */
dummy = base->D;
if (handle->transfer.dataSize != 0)
{
xfer->event = kI2C_SlaveCompletionEvent;
xfer->completionStatus = kStatus_I2C_Nak;
handle->isBusy = false;
if ((handle->eventMask & xfer->event) && (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 ((handle->eventMask & xfer->event) && (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 (status & kI2C_AddressMatchFlag)
{
handle->isBusy = true;
xfer->event = kI2C_SlaveAddressMatchEvent;
if ((handle->eventMask & xfer->event) && (handle->callback))
{
handle->callback(base, xfer, handle->userData);
}
/* Slave transmit, master reading from slave. */
if (status & kI2C_TransferDirectionFlag)
{
/* Change direction to send data. */
base->C1 |= I2C_C1_TX_MASK;
/* If we're out of data, invoke callback to get more. */
if ((!xfer->data) || (!xfer->dataSize))
{
xfer->event = kI2C_SlaveTransmitEvent;
if (handle->callback)
{
handle->callback(base, xfer, handle->userData);
}
/* Clear the transferred count now that we have a new buffer. */
xfer->transferredCount = 0;
}
doTransmit = true;
}
else
{
/* Slave receive, master writing to slave. */
base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
/* If we're out of data, invoke callback to get more. */
if ((!xfer->data) || (!xfer->dataSize))
{
xfer->event = kI2C_SlaveReceiveEvent;
if (handle->callback)
{
handle->callback(base, xfer, handle->userData);
}
/* Clear the transferred count now that we have a new buffer. */
xfer->transferredCount = 0;
}
/* Read dummy to release the bus. */
dummy = base->D;
}
}
/* Check transfer complete flag. */
else if (status & kI2C_TransferCompleteFlag)
{
/* Slave transmit, master reading from slave. */
if (status & kI2C_TransferDirectionFlag)
{
doTransmit = true;
}
else
{
/* Slave receive, master writing to slave. */
uint8_t data = base->D;
if (handle->transfer.dataSize)
{
/* Receive data. */
*handle->transfer.data++ = data;
handle->transfer.dataSize--;
xfer->transferredCount++;
if (!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 & xfer->event) && (handle->callback))
{
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)
{
if (handle->transfer.dataSize)
{
/* Send data. */
base->D = *handle->transfer.data++;
handle->transfer.dataSize--;
xfer->transferredCount++;
}
else
{
/* Switch to receive mode. */
base->C1 &= ~(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 & xfer->event) && (handle->callback))
{
handle->callback(base, xfer, handle->userData);
}
#endif /* !FSL_FEATURE_I2C_HAS_START_STOP_DETECT or !FSL_FEATURE_I2C_HAS_STOP_DETECT */
}
}
}
|