AnsweredAssumed Answered

STM32F4 - I2C Stuck Waiting for ADDR Bit

Question asked by joo_khai.sim on Sep 7, 2013
Latest reply on Oct 31, 2013 by kai.paulus
Hi All,

I am having an issue with I2C transmission on the STM32F4. After successfully transmitting an address byte with values of 0xE.. , the ADDR bit (Address Transmission Complete) in the SR1 register is set.

However, this is not the case when transmitting address bytes starting with 0xF.. (e.g. 0xF0, 0xF2, 0xF4 - corresponding to I2C device addresses 0x78, 0x79, 0x80) - the ADDR bit does not get set, despite the slave acknowledging the I2C transaction.

Here are the specifics of the system under test ...
A scope shot and a code snippet of the transmit routine can be found below.

Note the invalid logic level after the ACK bit (Bus Master i.e. STM32F4 pulls the line low after a short line-idle spike).

To rule out pull-up issues or latch-up, I have attempted: (a) Pulling-up the lines to +3.3V from the STM32F4DISCOVERY, (b) Pulling-up the lines to the clean +5V rail that is powering the SRF08, (c) Using a proper level converter for I2C lines (i.e. Texas Instruments' PCA9306). There is no change in the symptoms observed.

Has anyone encountered such an issue, and how do I go about resolving it?

STM32_SRF08_0xF0_Fire.jpeg

CODE SNIPPET

void i2c_readAsMst (I2C_TypeDef* I2Cx, uint8_t slvBusAddr, uint8_t readAddr, uint8_t noOfBytes, uint8_t i2cRxData[])
{
     uint8_t  byteCnt ;
     uint16_t rubbish ;
     
     /* Assert I2C START condition */
     I2Cx->CR1 |= I2C_CR1_START ;
     
     /* Wait for START condition to have been asserted */
     while (!(I2Cx->SR1 & I2C_SR1_SB)) ;


     /* Transmit I2C address of slave device */
     /* This transaction is a WRITE operation */
     I2Cx->DR = slvBusAddr << 1 ;


     /* Wait for transmission to complete */
     while (!(I2Cx->SR1 & I2C_SR1_ADDR)) ;
     
     /* Clear ADDR flag to activate the internal Tx shift register */
     rubbish = I2Cx->SR2 ;
     
     /* Transmit the address of the first register for sequential reading */
     I2Cx->DR = readAddr ;
     
     /* Wait for I2C transmission to complete */
     while (!(I2Cx->SR1 & I2C_SR1_BTF)) ;
     
     /* Assert I2C RESTART condition */
     I2Cx->CR1 |= I2C_CR1_START ;
     
     /* Perform a dummy read to ensure the channel is clear for reception */
     rubbish = I2Cx->DR ;
     
     /* Wait for RESTART condition to have been asserted */
     while (!(I2Cx->SR1 & I2C_SR1_SB)) ;
     
     /* Transmit I2C address of slave device */
     /* This transaction is a READ operation */
     I2Cx->DR = ((slvBusAddr << 1) | 0x01) ;
     
     /* Wait for transmission to complete */
     while (!(I2Cx->SR1 & I2C_SR1_ADDR)) ;
     
     /* Clear ADDR flag to activate the internal Rx shift register */
     rubbish = I2Cx->SR2 ;
     
     for (byteCnt=0; byteCnt<noOfBytes; byteCnt++)
     {
          // If there is only 1 byte left to read, send a NACK after reception of the byte
          // Else, acknowledge the incoming received byte
          if (noOfBytes - byteCnt == 1) I2Cx->CR1 &= ~(I2C_CR1_ACK) ;
          else                          I2Cx->CR1 |= I2C_CR1_ACK    ;
          
          /* Wait for a byte to be received over the I2C line */
          while (!(I2Cx->SR1 & I2C_SR1_RXNE)) ;
          
          i2cRxData[byteCnt] = I2Cx->DR ;
     }


     /* Set STOP bit in order to free I2C line after the receive transaction */
     I2Cx->CR1 |= I2C_CR1_STOP ;
}

Outcomes