LPC54606 I2C transfer function accidentally changes read to write when kI2C_TransferNoStopFlag used

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LPC54606 I2C transfer function accidentally changes read to write when kI2C_TransferNoStopFlag used

2,468 Views
MartinDQ
Contributor I

Hi, I need to communicate between LPC54606 (master) and PCIe switch PI7C9X2G1224GP (slave) via I2C. There's defined a specific sequence for read and write internal registers that I tried to do using I2C_MasterTransferBlocking API or I2C_MasterStart/I2C_MasterStop/I2C_MasterReadBlocking but I have a problem that I2C communication doesn't complete and end with error without data readed back. Write data are acked but when 5 bytes should be read back I see for some reason a write instead of read even I use direction=kI2C_Read, see code of my function below. When I experimented with params I found this behavior changes when I change flags on previous write from kI2C_TransferNoStopFlag to kI2C_TransferDefaultFlag. Then read is sent but slave doesn't return valid data, just five 0xFF bytes ending with arb.err. But according to slave protocol requirements I must not to use stop between so I need to make TransferNoStopFlag working.

Here's the sequence from slave datasheet:

Figure 7-4 SMBus Block Write to Set up Read, and Resulting Read that Returns CFG Register Value

START | Slave Addr Wr | ACK | Cmd Code = BAh | ACK | Byte Count = 4 | ACK | Cmd Byte1 | ACK | Cmd Byte 2 | ACK | Cmd Byte 3 | ACK | Cmd Byte 4 | ACK | STOP

A Block Write to set up Read

START | Slave Addr Wr | ACK | Cmd code = BDh | ACK | (no stop here) START | Slave Adress Rd | ACK | Byte Count = 4 (from slave) | ACK | Data Byte 1 (from slave) | ACK | Data Byte 2 (from slave) | ACK | Data Byte 3 (from slave) | ACK | Data Byte 4 (from slave) | ACK | STOP

My code:

 

  i2c_master_transfer_t xfer;          // I2C master transfer structure for I2C_MasterTransferNonBlocking()
  uint8_t buffer[6];                   // I2C data buffer for transfer (read/write)
  status_t err;

  if ((I2C_GetStatusFlags(base)&kI2C_MasterPendingFlag)==0) // if master is busy for some unknown reason
    {                                  // restart the I2C master
    I2C_MasterEnable(base,false);      // otherwise it will hang in an endless loop
    I2C_MasterEnable(base,true);       // in SDK function I2C_PendingStatusWait()
    }
  buffer[0]=I2C_PCIESW_BLKWR;          // fill command code to Tx buffer, see page 56
  buffer[1]=4;                         // fill Byte count=4 to Tx buffer
  buffer[2]=0x04;                      // fill Command Byte1 to Tx buffer, bit2:0 - 3=write reg, 4=read reg, bit7:3 - reserved
  buffer[3]=0x00;                      // fill Command Byte2 to Tx buffer, bit3:0 - port_select4:1, bit7:4 - reserved
  buffer[4]=0xBC;                      // fill Command Byte3 to Tx buffer, bit7 - port_select0, bit6 - reserved, bit5:2 - Byte enable (0=not modif, 1=modif), bit1:0 - reg_addr11:10
  buffer[5]=0x3E;                      // fill Command Byte4 to Tx buffer, bit7:0 - reg_addr9:2 (reg_addr1:0 are always 0)
  memset(&xfer, 0, sizeof(xfer));
  xfer.slaveAddress=I2C_PCIESW_SLAVE_ADDR;
  xfer.direction=kI2C_Write;
  xfer.subaddress=0;
  xfer.subaddressSize=0;
  xfer.data=buffer;
  xfer.dataSize=6;
  xfer.flags=kI2C_TransferDefaultFlag;
  err=I2C_MasterTransferBlocking(base, &xfer);
  uart_printf("err1 %d\n", err);

	buffer[0]=I2C_PCIESW_BLKR;           // fill read back command code to Tx buffer
  xfer.dataSize=1;
//  xfer.flags=kI2C_TransferNoStopFlag;
  xfer.flags=kI2C_TransferDefaultFlag;
  err=I2C_MasterTransferBlocking(base, &xfer);
  uart_printf("err2 %d\n", err);

  memset(&buffer, 0, sizeof(buffer));
  memset(&xfer, 0, sizeof(xfer));
  xfer.slaveAddress=I2C_PCIESW_SLAVE_ADDR;
  xfer.direction=kI2C_Read;
  xfer.subaddress=0;
  xfer.subaddressSize=0;
  xfer.data=buffer;
  xfer.dataSize=5;
  xfer.flags=kI2C_TransferDefaultFlag;
  err=I2C_MasterTransferBlocking(base, &xfer);
  uart_printf("err3 %d\n", err);

 

 

Terminal log when flag used: kI2C_TransferNoStopFlag

err1 0
err2 0
err3 2609
00 00 00 00 00

Terminal log when flag used: kI2C_kI2C_TransferDefaultFlag

err1 0
err2 0
err3 2605
FF FF FF FF FF

In the attachment there are oscillograms with I2C analyser decoder that shows there's write address the last part of sequence while there should be read - why? Is it a bug in SDK API func?

The second osc shows sequence with right read but with unwanted stop that may cause read failed.

 

0 Kudos
7 Replies

2,401 Views
MartinDQ
Contributor I

After all I found that problem was on slave side.

The PCIe switch implements 2 different protocols SMbus and I2C (over the same physical interface/pins). I was trying to send commands according to SMbus packet spec. When I tried to send packet according to I2C spec (it's simpler, eg. doesn't contain length Byte so packet is shorter) it works and all bytes are ACKed as expected. Both read reg and write reg works now.

But I cannot find anywhere in PI7C9X2G1224GP datasheet how is it determined what kind of protocol is used (how slave switches between them), they just describe 2 different protocols and let user try which works, huh, that was the catch...

Here I'm getting a nice read of VID/PID from reg 0:

0 Kudos

2,449 Views
MartinDQ
Contributor I

Thanks for reply.

Is it really needed to reimplement own version of state machine instead of using standard SDK API functions? I'm absolutely OK with blocking mode so I want to keep it simple for now.

Do you have some explanation why the hell the last read command is changed to write? I already tried code with functions I2C_MasterWriteBlocking, I2C_MasterReadBlocking and I2C_MasterStart/I2C_MasterStop but with same result. I analyzed code of I2C_MasterStart that seems to be quite simple and I added a debug print of read back of MSTDAT register to see the value when starting with I2C address. And as expected when write i saw value 0x70 and when read I saw 0x71 but on the scope (analyzed also carefully bit by bit) I see the read turned to write. And this behavior depends on flag of previous call MasterWriteBlocking

if ((err=I2C_MasterWriteBlocking(base, &buffer, 1, kI2C_TransferDefaultFlag))!=kStatus_Success)

// if ((err=I2C_MasterWriteBlocking(base, &buffer, 1, kI2C_TransferNoStopFlag))!=kStatus_Success)

If I use TransferNoStopFlag then read become write, see osci attached.

Also please have a look at the end of SCK sequence (2nd osci) where you can see a low-level pulse that has extemely short width - less than regular SCK pulses - what does it mean?

0 Kudos

2,444 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

Frankly speaking, I am not clear about your question, how do you know that transfer function changes from read to write? As far as I know that only the address command has the LSB which presents the READ or WRITE command.

For the I2C protocol, the receiver must drive the data pin to LOW as ACK signal at the end of each byte, if the ACK is not received by transmitter if I2C is master writing phase, the master will stop by releasing the SCL/SDA, and both the SCL and SDA will be high,  so the I2C will stop.

BR

XiangJun Rong

 

0 Kudos

2,431 Views
MartinDQ
Contributor I

Yes, the read/write is detemined by LSB of I2S slave address. I called function I2C_MasterStart with parameter kI2C_Read:

I2C_MasterStart(base, I2C_PCIESW_SLAVE_ADDR, kI2C_Read)

but as you can see on oscillogram it was turned to write (LSB=0). I put inside of I2C_MasterStart a debug read back of MSTDAT and when called with kI2C_Read I correctly read 0x71 but on oscillogram I see that 0x70 was shifted out by master instead. This is what I wonder about. And this behavior depends on previous call of I2C_MasterWriteBlocking function and its flag parameter. When kI2C_TransferDefaultFlag is used then I2C_MasterStart(base, I2C_PCIESW_SLAVE_ADDR, kI2C_Read) works as expected (send 0x71) while if kI2C_TransferNoStopFlag is used then following I2C_MasterStart(base, I2C_PCIESW_SLAVE_ADDR, kI2C_Read) send 0x70.

Here's my alternative code that use MasterWrite/ReadBlocking and I2C_MasterStart 

0 Kudos

2,422 Views
MartinDQ
Contributor I

At last I wrote the transfer function at register level without using SK API, just register names from header and still getting the same result, I'm lost...

  uint8_t buffer[6];                   // data buffer for I2C transfer (read/write)
  int i;
	
	buffer[0]=I2C_PCIESW_BLKWR;          // fill command code to Tx buffer, see page 56
	buffer[1]=4;                         // fill Byte count=4 to Tx buffer
	buffer[2]=0x04;                      // fill Command Byte1 to Tx buffer, bit2:0 - 3=write reg, 4=read reg, bit7:3 - reserved
	buffer[3]=0x00;                      // fill Command Byte2 to Tx buffer, bit3:0 - port_select4:1, bit7:4 - reserved
	buffer[4]=0xBC;                      // fill Command Byte3 to Tx buffer, bit7 - port_select0, bit6 - reserved, bit5:2 - Byte enable (0=not modif, 1=modif), bit1:0 - reg_addr11:10
	buffer[5]=0x3E;                      // fill Command Byte4 to Tx buffer, bit7:0 - reg_addr9:2 (reg_addr1:0 are always 0)
	
  // Master write 1 byte to slave. Address 0x23, Data 0xdd. Polling mode.
  base->CFG = I2C_CFG_MSTEN_MASK;
  while(!(base->STAT & I2C_STAT_MSTPENDING_MASK));
	if((base->STAT & I2C_STAT_MSTSTATE_MASK) != I2C_STAT_MSTSTATE(0)) // I2C_STAT_MSTST_IDLE
		return(-1);
	
  base->MSTDAT = (I2C_PCIESW_SLAVE_ADDR << 1) | 0; // address and 0 for RWn bit
  base->MSTCTL = I2C_MSTCTL_MSTSTART_MASK; // send start
  while(!(base->STAT & I2C_STAT_MSTPENDING_MASK));
  if((base->STAT & I2C_STAT_MSTSTATE_MASK) != I2C_STAT_MSTSTATE(2)) // I2C_STAT_MSTST_TX
		return(-2);
	
	for (i=0; i<6; i++)
		{
		base->MSTDAT = buffer[i]; // send data
		base->MSTCTL = I2C_MSTCTL_MSTCONTINUE_MASK; // continue transaction
		while(!(base->STAT & I2C_STAT_MSTPENDING_MASK));
		if((base->STAT & I2C_STAT_MSTSTATE_MASK) != I2C_STAT_MSTSTATE(2)) // I2C_STAT_MSTST_TX
			{
			base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK; // send stop
			while(!(base->STAT & I2C_STAT_MSTPENDING_MASK));
			if((base->STAT & I2C_STAT_MSTSTATE_MASK) != I2C_STAT_MSTSTATE(0)) // I2C_STAT_MSTST_IDLE
				return(-5);
			return(-3);
			}
		}
	
  base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK; // send stop
  while(!(base->STAT & I2C_STAT_MSTPENDING_MASK));
  if((base->STAT & I2C_STAT_MSTSTATE_MASK) != I2C_STAT_MSTSTATE(0)) // I2C_STAT_MSTST_IDLE
		return(-4);

// part 2	
  base->MSTDAT = (I2C_PCIESW_SLAVE_ADDR << 1) | 0; // address and 0 for RWn bit
  base->MSTCTL = I2C_MSTCTL_MSTSTART_MASK; // send start
  while(!(base->STAT & I2C_STAT_MSTPENDING_MASK));
  if((base->STAT & I2C_STAT_MSTSTATE_MASK) != I2C_STAT_MSTSTATE(2)) // I2C_STAT_MSTST_TX
		return(-6);

  base->MSTDAT = I2C_PCIESW_BLKR; // send data
  base->MSTCTL = I2C_MSTCTL_MSTCONTINUE_MASK; // continue transaction
	while(!(base->STAT & I2C_STAT_MSTPENDING_MASK));
	if((base->STAT & I2C_STAT_MSTSTATE_MASK) != I2C_STAT_MSTSTATE(2)) // I2C_STAT_MSTST_TX
		{
		base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK; // send stop
		while(!(base->STAT & I2C_STAT_MSTPENDING_MASK));
		if((base->STAT & I2C_STAT_MSTSTATE_MASK) != I2C_STAT_MSTSTATE(0)) // I2C_STAT_MSTST_IDLE
			return(-8);
		return(-7);
		}
	
// part 3
  base->MSTDAT = (I2C_PCIESW_SLAVE_ADDR << 1) | 1; // address and 1 for RWn bit
  base->MSTCTL = I2C_MSTCTL_MSTSTART_MASK; // send start
  while(!(base->STAT & I2C_STAT_MSTPENDING_MASK));
  if((base->STAT & I2C_STAT_MSTSTATE_MASK) != I2C_STAT_MSTSTATE(1)) // I2C_STAT_MSTST_RX
		return(-9);
	
	for (i=0; i<5; i++)
		{
  	buffer[i] = base->MSTDAT; // read data
		base->MSTCTL = I2C_MSTCTL_MSTCONTINUE_MASK; // continue transaction
		while(!(base->STAT & I2C_STAT_MSTPENDING_MASK));
		if((base->STAT & I2C_STAT_MSTSTATE_MASK) != I2C_STAT_MSTSTATE(1)) // I2C_STAT_MSTST_RX
			{
			base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK; // send stop
			while(!(base->STAT & I2C_STAT_MSTPENDING_MASK));
			if((base->STAT & I2C_STAT_MSTSTATE_MASK) != I2C_STAT_MSTSTATE(0)) // I2C_STAT_MSTST_IDLE
				return(-11);
			return(-10);
			}
		}

  base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK; // send stop
  while(!(base->STAT & I2C_STAT_MSTPENDING_MASK));
  if((base->STAT & I2C_STAT_MSTSTATE_MASK) != I2C_STAT_MSTSTATE(0)) // I2C_STAT_MSTST_IDLE
		return(-12);

 

0 Kudos

2,429 Views
MartinDQ
Contributor I
  uint8_t buffer[6];                   // data buffer for I2C transfer (read/write)
  status_t err;
	if ((I2C_GetStatusFlags(base)&kI2C_MasterPendingFlag)==0) // if master is busy for some unknown reason
	  {                                  // restart the I2C master
    I2C_MasterEnable(base,false);      // otherwise it will hang in an endless loop
    I2C_MasterEnable(base,true);       // in SDK function I2C_PendingStatusWait()
	  }
	if ((err=I2C_MasterStart(base, I2C_PCIESW_SLAVE_ADDR, kI2C_Write))!=kStatus_Success) // initiate new master mode transfer by sending the START signal, write mode
		return(-1000000-err);              // if I2C fail to start due to timeout state reset should be done but API function I2C_MasterReset() does nothing
    
	buffer[0]=I2C_PCIESW_BLKWR;          // fill command code to Tx buffer, see page 56
	buffer[1]=4;                         // fill Byte count=4 to Tx buffer
	buffer[2]=0x04;                      // fill Command Byte1 to Tx buffer, bit2:0 - 3=write reg, 4=read reg, bit7:3 - reserved
	buffer[3]=0x00;                      // fill Command Byte2 to Tx buffer, bit3:0 - port_select4:1, bit7:4 - reserved
	buffer[4]=0xBC;                      // fill Command Byte3 to Tx buffer, bit7 - port_select0, bit6 - reserved, bit5:2 - Byte enable (0=not modif, 1=modif), bit1:0 - reg_addr11:10
	buffer[5]=0x3E;                      // fill Command Byte4 to Tx buffer, bit7:0 - reg_addr9:2 (reg_addr1:0 are always 0)
  if ((err=I2C_MasterWriteBlocking(base, &buffer, 6, kI2C_TransferDefaultFlag))!=kStatus_Success) // write block (6 Bytes), kI2C_TransferDefaultFlag = transfer starts with a start signal, stops with a stop signal
	  {
	  I2C_MasterStop(base);              // if error occours, send STOP
		return(-2000000-err);              // and return immediatelly
    }

  if ((err=I2C_MasterStart(base, I2C_PCIESW_SLAVE_ADDR, kI2C_Write))!=kStatus_Success) // initiate new master mode transfer by sending the START signal, write mode
	  {
	  I2C_MasterStop(base);              // if error occours, send STOP
		return(-3000000-err);              // and return immediatelly
    }
    
	buffer[0]=I2C_PCIESW_BLKR;           // fill read back command code to Tx buffer
//  if ((err=I2C_MasterWriteBlocking(base, &buffer, 1, kI2C_TransferDefaultFlag))!=kStatus_Success) // write block (1 Byte), kI2C_TransferDefaultFlag = transfer starts with a start signal, stops with a stop signal
  if ((err=I2C_MasterWriteBlocking(base, &buffer, 1, kI2C_TransferNoStopFlag))!=kStatus_Success) // write block (1 Byte), kI2C_TransferDefaultFlag = transfer starts with a start signal, stops with a stop signal
	  {
	  I2C_MasterStop(base);              // if error occours, send STOP
		return(-4000000-err);              // and return immediatelly
    }
// here happens the address byte is transmitted with LSB=0 as write instead read as required i kI2C_TransferNoStopFlag is used before
	if ((err=I2C_MasterStart(base, I2C_PCIESW_SLAVE_ADDR, kI2C_Read))!=kStatus_Success) // initiate new master mode transfer by sending the START signal, read mode
	  {
	  I2C_MasterStop(base);              // if error occours, send STOP
		return(-5000000-err);              // and return immediatelly
    }
    
  if ((err=I2C_MasterReadBlocking(base, &buffer, 5, kI2C_TransferDefaultFlag))!=kStatus_Success) // read block (5 Bytes), kI2C_TransferDefaultFlag = transfer starts with a start signal, stops with a stop signal
  	{
// returns error kStatus_I2C_ArbitrationLost (2605)
		I2C_MasterStop(I2C_BP);            // if error occours, send STOP
		return(-6000000-err);              // and return immediatelly
    }
		
*/		
	uart_printf("%02X %02X %02X %02X %02X\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
  return(0);
0 Kudos

2,455 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

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;
}

 

 

 

0 Kudos