I2C Start Read/Write Bit


I2C Start Read/Write Bit

425 次查看
Contributor IV



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:




                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…


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):





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


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

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

(12)     /* Start the transfer */



(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.




Can anyone see a failing in the logic here?


Thanks for your thoughts,


0 项奖励
1 回复

409 次查看
NXP TechSupport
NXP TechSupport



Recommend you refer to the I2C_read_accel_value_transfer demo under SDK.



0 项奖励