I2C Start Read/Write Bit

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

I2C Start Read/Write Bit

1,473 Views
dougpaulsen
Contributor IV

Greetings:

 

I have become ensnared in an interesting I2C phenomenon which I hope one better versed in such things than I might be able to shed some light.

 

I am using MCUXpresso IDE v11.3.0 [Build 5222] and the lpcxpresso55s16 SDK.  I am writing test code for our own hardware but the problematic code is drawn straight from the SDK sample project lpcxpresso55s16_i2c_polling_b2b_master.

 

First, I am trying to interface with a Vishay 6030 Ambient Light Sensor.  To read the sensor, I need to replicate the instructions outlined in Figure (1).  Note that you’ve got to send the shifted slave address, then the command code, then a second shifted slave address but this time with the read bit set, after which the slave should make two data bytes available:

 

dougpaulsen_0-1627590687443.png

 

                Figure 1.

 

Next, the Figure (1) I2C sequence translates to the Figure (2) code snippet (which is shamelessly plagiarized from the SDK lpcxpresso55s16_i2c_polling_b2b_master sample project):

 

 

//send start and I2C bus slave byte and W bit…

g_tRetVal = I2C_MasterStart( FLEXCOMM5_PERIPHERAL, I2C_MASTER_SLAVE_ADDR_7BIT, kI2C_Write );

if ( g_tRetVal == kStatus_Success )

{

//send Command code...

(06)   g_tRetVal = I2C_MasterWriteBlocking( FLEXCOMM5_PERIPHERAL, &(g_u8MasterBuffTX[ 0 ]), 1, kI2C_TransferNoStopFlag);

(07)   if ( g_tRetVal == kStatus_Success )

(08)   {

(09)          //send second start, I2C bus slave address byte, and R bit...

(10)          g_tRetVal = I2C_MasterRepeatedStart( FLEXCOMM5_PERIPHERAL, I2C_MASTER_SLAVE_ADDR_7BIT, kI2C_Read );

            Figure 2.

 

Alas!  Running the Figure (2) code yields an “arbitration” error, so it’s haul-out-the-oscilloscope time to see what’s going down on the SDA and SCL lines.  The results are shown in Figure (3):

 

 

dougpaulsen_1-1627590687465.png

 

            Figure 3.

 

 

Interesting…!  Cross referencing the Figure (2) code with the Figure (3) oscilloscope trace, the following is happening (even before the arbitration error:

 

  1. Fig (2) line 2 I2C start function call results in Fig. (3) as the first “Address -10”,
  2. Fig (2) line 6 write blocking function call  results in Fig. (3) as the “Data – 04” (that’s the 6030 read command).  All’s well so far….
  3. Fig (2) line 10 repeat start function call is shown in Fig (3) as the second “Address – 10”.  But…
  4. Note that the line 10 repeat start function call, which clearly includes the enumeration “kI2C_Read”, actually executes as a write (that is, bit0 is zero)!  From there on, the process collapses in chaos.

 

How can this be?

 

Well first lets check out the kI2C read/write enum.  Indeed, the read and write values are distinct:

 

/*! @brief Direction of master and slave transfers. */

typedef enum _i2c_direction

{

    kI2C_Write = 0U, /*!< Master transmit. */

    kI2C_Read  = 1U  /*!< Master receive. */

} i2c_direction_t;

            Figure 4.

 

Next, how about the I2C_MasterRepeatedStart( ) function?  It turns out that the I2C_MasterRepeatedStart() just straight out calls the I2C_MasterStart() function so let’s look at that (see Fig (4) below):

 

/*!

 * @brief Sends a REPEATED START on the I2C bus.

 *

 * @param base I2C peripheral base pointer

 * @param address 7-bit slave device address.

 * @param direction Master transfer directions(transmit/receive).

 * @retval kStatus_Success Successfully send the start signal.

 * @retval kStatus_I2C_Busy Current bus is busy but not occupied by current I2C master.

 */

static inline status_t I2C_MasterRepeatedStart(I2C_Type *base, uint8_t address, i2c_direction_t direction)

{

    return I2C_MasterStart(base, address, direction);

}

 

/*!

* brief Sends a START on the I2C bus.

*

* This function is used to initiate a new master mode transfer by sending the START signal.

* The slave address is sent following the I2C START signal.

*

* param base I2C peripheral base pointer

* param address 7-bit slave device address.

* param direction Master transfer directions(transmit/receive).

* retval kStatus_Success Successfully send the start signal.

* retval kStatus_I2C_Busy Current bus is busy.

*/

(01) status_t I2C_MasterStart(I2C_Type *base, uint8_t address, i2c_direction_t direction)

(02) {

(03)     uint32_t result;

(04)     result = I2C_PendingStatusWait(base);

(05)     if (result == (uint32_t)kStatus_I2C_Timeout)

(06)     {

(07)         return kStatus_I2C_Timeout;

(08)     }

(09)

(10)     /* Write Address and RW bit to data register */

(11)     base->MSTDAT = ((uint32_t)address << 1) | ((uint32_t)direction & 1U);

(12)     /* Start the transfer */

(13)     base->MSTCTL = I2C_MSTCTL_MSTSTART_MASK;

(14)

(15)     return kStatus_Success;

(16) }

            Figure 5.

 

To summarize Fig 2 line 10 calls I2C_MasterRepeatedStart() with parameter 3, the direction, as read (i.e., 1).  Function I2C_MasterRepeatedStart() calls function I2C_MasterStart() with its’ parameter 3 also as read (i.e., 1).  In function I2C_MasterStart() the direction parameter is or-ed with the shifted I2C address and written to the MSTDAT register (figure 5 line 11).    By the time the data hits the bus (Figure 3) the read/write bit is cleared to a write.

 

Weird!

 

Can anyone see a failing in the logic here?

 

Thanks for your thoughts,

doug

0 Kudos
1 Reply

1,457 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello,

 

Recommend you refer to the I2C_read_accel_value_transfer demo under SDK.

 

 

0 Kudos