Hi, Martin,
I suggest you call the I2C state machine function to implement your I2C sequence such as:
I2C slave address + W + multiple data + repeated Start + I2C slave address +RD+ multiple data
I copy the api function, pls read them and consider how to call them based on your application:
Hope it can help you
BR
Xiangjun Rong
/*!
* @brief Prepares the transfer state machine and fills in the command buffer.
* @param handle Master nonblocking driver handle.
*/
static status_t I2C_InitTransferStateMachine(I2C_Type *base, i2c_master_handle_t *handle, i2c_master_transfer_t *xfer)
{
struct _i2c_master_transfer *transfer;
handle->transfer = *xfer;
transfer = &(handle->transfer);
handle->transferCount = 0;
handle->remainingBytes = transfer->dataSize;
handle->buf = (uint8_t *)transfer->data;
handle->remainingSubaddr = 0;
if ((transfer->flags & (uint32_t)kI2C_TransferNoStartFlag) != 0U)
{
/* Start condition shall be ommited, switch directly to next phase */
if (transfer->dataSize == 0U)
{
handle->state = (uint8_t)kStopState;
}
else if (handle->transfer.direction == kI2C_Write)
{
handle->state = (uint8_t)kTransmitDataState;
}
else if (handle->transfer.direction == kI2C_Read)
{
handle->state = (uint8_t)kReceiveDataBeginState;
}
else
{
return kStatus_I2C_InvalidParameter;
}
}
else
{
if (transfer->subaddressSize != 0U)
{
int i;
uint32_t subaddress;
if (transfer->subaddressSize > sizeof(handle->subaddrBuf))
{
return kStatus_I2C_InvalidParameter;
}
/* Prepare subaddress transmit buffer, most significant byte is stored at the lowest address */
subaddress = xfer->subaddress;
for (i = (int)xfer->subaddressSize - 1; i >= 0; i--)
{
handle->subaddrBuf[i] = (uint8_t)subaddress & 0xffU;
subaddress >>= 8;
}
handle->remainingSubaddr = transfer->subaddressSize;
}
handle->state = (uint8_t)kStartState;
}
return kStatus_Success;
}
/*!
* @brief Execute states until FIFOs are exhausted.
* @param handle Master nonblocking driver handle.
* @param[out] isDone Set to true if the transfer has completed.
* @retval #kStatus_Success
* @retval #kStatus_I2C_ArbitrationLost
* @retval #kStatus_I2C_Nak
*/
static status_t I2C_RunTransferStateMachine(I2C_Type *base, i2c_master_handle_t *handle, bool *isDone)
{
uint32_t status;
uint32_t master_state;
struct _i2c_master_transfer *transfer;
status_t err;
transfer = &(handle->transfer);
bool ignoreNak = ((handle->state == (uint8_t)kStopState) && (handle->remainingBytes == 0U)) ||
((handle->state == (uint8_t)kWaitForCompletionState) && (handle->remainingBytes == 0U));
*isDone = false;
status = I2C_GetStatusFlags(base);
if ((status & I2C_STAT_MSTARBLOSS_MASK) != 0U)
{
I2C_MasterClearStatusFlags(base, I2C_STAT_MSTARBLOSS_MASK);
return kStatus_I2C_ArbitrationLost;
}
if ((status & I2C_STAT_MSTSTSTPERR_MASK) != 0U)
{
I2C_MasterClearStatusFlags(base, I2C_STAT_MSTSTSTPERR_MASK);
return kStatus_I2C_StartStopError;
}
if ((status & I2C_STAT_MSTPENDING_MASK) == 0U)
{
return kStatus_I2C_Busy;
}
/* Get the state of the I2C module */
master_state = (status & I2C_STAT_MSTSTATE_MASK) >> I2C_STAT_MSTSTATE_SHIFT;
if (((master_state == (uint32_t)I2C_STAT_MSTCODE_NACKADR) ||
(master_state == (uint32_t)I2C_STAT_MSTCODE_NACKDAT)) &&
(ignoreNak != true))
{
/* Slave NACKed last byte, issue stop and return error */
base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK;
handle->state = (uint8_t)kWaitForCompletionState;
return kStatus_I2C_Nak;
}
err = kStatus_Success;
switch (handle->state)
{
case (uint8_t)kStartState:
if (handle->remainingSubaddr != 0U)
{
/* Subaddress takes precedence over the data transfer, direction is always "write" in this case */
base->MSTDAT = (uint32_t)transfer->slaveAddress << 1U;
handle->state = (uint8_t)kTransmitSubaddrState;
}
else if (transfer->direction == kI2C_Write)
{
base->MSTDAT = (uint32_t)transfer->slaveAddress << 1;
handle->state = (handle->remainingBytes != 0U) ? (uint8_t)kTransmitDataState : (uint8_t)kStopState;
}
else
{
base->MSTDAT = ((uint32_t)transfer->slaveAddress << 1) | 1u;
handle->state = (handle->remainingBytes != 0U) ? (uint8_t)kReceiveDataState : (uint8_t)kStopState;
}
/* Send start condition */
base->MSTCTL = I2C_MSTCTL_MSTSTART_MASK;
break;
case (uint8_t)kTransmitSubaddrState:
if (master_state != (uint32_t)I2C_STAT_MSTCODE_TXREADY)
{
return kStatus_I2C_UnexpectedState;
}
/* Most significant subaddress byte comes first */
base->MSTDAT = handle->subaddrBuf[handle->transfer.subaddressSize - handle->remainingSubaddr];
base->MSTCTL = I2C_MSTCTL_MSTCONTINUE_MASK;
if (--(handle->remainingSubaddr) != 0U)
{
/* There are still subaddress bytes to be transmitted */
break;
}
if (handle->remainingBytes != 0U)
{
/* There is data to be transferred, if there is write to read turnaround it is necessary to perform
* repeated start */
handle->state = (transfer->direction == kI2C_Read) ? (uint8_t)kStartState : (uint8_t)kTransmitDataState;
}
else
{
/* No more data, schedule stop condition */
handle->state = (uint8_t)kStopState;
}
break;
case (uint8_t)kTransmitDataState:
if (master_state != (uint32_t)I2C_STAT_MSTCODE_TXREADY)
{
return kStatus_I2C_UnexpectedState;
}
base->MSTDAT = *(handle->buf)++;
base->MSTCTL = I2C_MSTCTL_MSTCONTINUE_MASK;
if (--handle->remainingBytes == 0U)
{
/* No more data, schedule stop condition */
handle->state = (uint8_t)kStopState;
}
handle->transferCount++;
break;
case (uint8_t)kReceiveDataBeginState:
if (master_state != (uint32_t)I2C_STAT_MSTCODE_RXREADY)
{
return kStatus_I2C_UnexpectedState;
}
(void)base->MSTDAT;
base->MSTCTL = I2C_MSTCTL_MSTCONTINUE_MASK;
handle->state = (uint8_t)kReceiveDataState;
break;
case (uint8_t)kReceiveDataState:
if (master_state != (uint32_t)I2C_STAT_MSTCODE_RXREADY)
{
return kStatus_I2C_UnexpectedState;
}
*(handle->buf)++ = (uint8_t)base->MSTDAT;
if (--handle->remainingBytes != 0U)
{
base->MSTCTL = I2C_MSTCTL_MSTCONTINUE_MASK;
}
else
{
/* No more data expected, issue NACK and STOP right away */
if (0U == (transfer->flags & (uint32_t)kI2C_TransferNoStopFlag))
{
base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK;
}
handle->state = (uint8_t)kWaitForCompletionState;
}
handle->transferCount++;
break;
case (uint8_t)kStopState:
if ((transfer->flags & (uint32_t)kI2C_TransferNoStopFlag) != 0U)
{
/* Stop condition is omitted, we are done */
*isDone = true;
handle->state = (uint8_t)kIdleState;
break;
}
/* Send stop condition */
base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK;
handle->state = (uint8_t)kWaitForCompletionState;
break;
case (uint8_t)kWaitForCompletionState:
*isDone = true;
handle->state = (uint8_t)kIdleState;
break;
case (uint8_t)kIdleState:
default:
/* State machine shall not be invoked again once it enters the idle state */
err = kStatus_I2C_UnexpectedState;
break;
}
return err;
}