cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F767 I2C sending byte immediately after address sent

metalimi
Associate

I am having an issue while trying to setup an I2C driver on my STM32F767ZI Nucleo board interfacing with an SHT31 and SGP40 I2C sensors. The code I am running first initializes the SHT31 with a write and read and then initializes the SGP40 with a write and read. 

The issue I am running into is whenever I send the next message (read on whichever sensor I decide to try to configure first), the I2C peripheral sends a start bit and address as expected but adds a null byte immediately after the address. See attached example where I would expect the address of 0xB2, and the two byte message of 0x36 and 0x82 to be sent instead I see the address of 0xB2, then data of 0x00 and 0x36.  It runs through the first write cycle without an issue. 

 

Edited to elaborate on the logic analyzer captures. I2C_LA._Expected captures the moment after stepping through setting the start bit in the CR2 register. It shows the address being transmitted and then SDA returns high and SCL is set low waiting to transmit the next byte. 

I2C_LA shows the same line being executed but the second send message around. This shows the address being sent along with a null byte. It also seems like the byte counter is decremented so the peripheral considers that byte as a proper sent byte even though I never write anything to the TX register...

error_t i2c_master_transmit(I2C_TypeDef *i2c_instance, uint8_t device_address, uint8_t *tx_buffer, uint16_t data_length)
{
  error_t status = ERR_OK;
  if(i2c_wait_for_busy_clear(i2c_instance) == ERR_OK)
  {
    i2c_instance->ICR |= (I2C_ICR_STOPCF | I2C_ICR_NACKCF); //clear flags if set
    //configure registers for TX
    i2c_instance->CR1 &= ~(0x1UL << I2C_CR2_ADD10_Pos); //set to 7 bit addressing
    i2c_instance->CR2 &= ~(0xFFUL << I2C_CR2_SADD_Pos); //clear address bits
    i2c_instance->CR2 |= (device_address << I2C_CR2_SADD_Pos); //set address
    i2c_instance->CR2 &= ~(0x1UL << I2C_CR2_RD_WRN_Pos); //clear bit to set to write

    //set number of bytes to transmit
    i2c_instance->CR2 &= ~(0xFF <<I2C_CR2_NBYTES_Pos);
    i2c_instance->CR2 |= ((uint8_t)data_length <<I2C_CR2_NBYTES_Pos);

    i2c_instance->CR2 |= I2C_CR2_START;

    //set the SB synch flag and enable interrupt
    i2c_synch_flags.I2C1_WAIT_SB = true;
    //i2c_enable_event_interrupts(i2c_instance);
    i2c_enable_rx_tx_interrupt(i2c_instance);

      while(!(i2c_instance->ISR & I2C_ISR_TC))
      {
        //wait for TXE
        if(i2c_synch_txe_interrupt(i2c_instance) != ERR_OK)
        {
          status = ERR_TIMEOUT;
          break;
        }

        //send byte
        i2c_instance->TXDR = *tx_buffer;
        tx_buffer++;

      }
      //send stop bit once data transfer is complete
      i2c_instance->CR2 |= I2C_CR2_STOP;

      //wait for stop bit
      while(!(i2c_instance->ISR & I2C_ISR_STOPF))
      {
        if((i2c_instance->ISR & (I2C_ISR_NACKF)) != 0)
        {
          //clear NACKF
          i2c_instance->ICR |= I2C_ICR_NACKCF;
          break;
        }
      }
  }
  else
  {
    status = ERR_FAIL;

  }
  return status;
}

Edited to place LA Traces inline for easier viewing:


I2C_LA_Expected.jpg

AndrewNeil_1-1777568522414.png

 

I2C_LA.jpg

AndrewNeil_2-1777568584092.png

 

1 REPLY 1
waclawek.jan
Super User

What is I2C_ISR (and/or other relevant I2C registers') content before the "correct" and before the "incorrect" transmission?

JW