Showing results for 
Search instead for 
Did you mean: 

STM32L431 I2C master transmitter: TXIS is set when slave NACKs

My setup is STM32L431 with Sensirion SHT31 connected to I2C1. This setup works normally under usual conditions, but when the sensor had intermittent connections, the software started to behave unexpectedly. Following is simple experiment where I walked through a 2-byte transmission manually in debugger, with stopped processor:


(gdb) set I2C1->CR1=0    // for good measure, let's start with resetting I2C
(gdb) set I2C1->CR1=1
(gdb) p /x *I2C1         // and here we see that as documented, reset won't impact TIMINGR
$176 = {
  CR1 = 0x1,
  CR2 = 0x0,
  OAR1 = 0x0,
  OAR2 = 0x0,
  TIMINGR = 0x60e32ca6,
  TIMEOUTR = 0x0,
  ISR = 0x1,
  ICR = 0x0,
  PECR = 0x0,
  RXDR = 0x0,
  TXDR = 0x0
(gdb) set I2C1->CR2 = 0x02022088  // AUTOEND, 2 bytes, START, Tx (RD_WRN is zero), SHT31 address is 0x44
(gdb) p /x I2C1->ISR
$177 = 0x8003                    // as expected, BUSY, TXIS, (TXE)
(gdb) set I2C1->TXDR=0x24
(gdb) p /x I2C1->ISR
$178 = 0x8003                    // same status after 2nd byte
(gdb) set I2C1->TXDR=0
(gdb) p /x I2C1->ISR
$179 = 0x21                      // we are done, so STOP (+TXE)
(gdb) set I2C1->ICR=0xFF         // let's clear status bits to set back the initial state
(gdb) p /x I2C1->ISR
$180 = 0x1                       // (TXE is a non-latching status)


So far, so good. Let's introduce some errors to see what happens. Let's start with the common "missing entirely -> address is NACKed" case (simply by setting an incorrect slave address):


(gdb) set I2C1->CR2 = 0x02022098  // incorrect address
(gdb) p /x I2C1->ISR
$181 = 0x31                       // and we have immediately NACK+STOP (+TXE)
(gdb) set I2C1->ICR=0xFF          // (and clear status before next experiment)
(gdb) p /x I2C1->ISR
$182 = 0x1


As expected, NACK+STOP. (I now repeated verbatim the first "perfect" sequence to be sure everything still works, that's why the gap in responses numbering). Now let's try sending an incorrect two-byte command to the SHT31 (0x0000 instead of the correct 0x2400 in the first example). SHT31 is picky and NACKs the second byte of incorrect command:


(gdb) set I2C1->CR2 = 0x02022088  // address OK, same command as in "perfect" case
(gdb) p /x I2C1->ISR
$187 = 0x8003                     // address was sent and ACKed by SHT31, BUSY, TXIS for 1st data byte, (TXE)
(gdb) set I2C1->TXDR=0
(gdb) p /x I2C1->ISR
$188 = 0x8003                     // BUSY, TXIS, (TXE)
(gdb) set I2C1->TXDR=0
(gdb) p /x I2C1->ISR
$189 = 0x31                       // as the 0x0000 command is invalid, SHT31 NACKs => NACK, STOP, (TXE)
(gdb) set I2C1->ICR=0xFF          // (and clear flags)
(gdb) p /x I2C1->ISR
$190 = 0x1


Again, as expected, NACK+STOP. (And again, to be sure, I performed one "perfect cycle" which is still perfect).

Now, after address ACKed, I disconnected SHT31 (remember, the problem is intermittent connection):


(gdb) set I2C1->CR2 = 0x02022088  // as usually
(gdb) p /x I2C1->ISR
$195 = 0x8003                     // address ACKed, TXIS for the first data byte
// ------------- and here I disconnected SHT31
(gdb) set I2C1->TXDR=0x24
(gdb) p /x I2C1->ISR
$196 = 0x33                      // NACK+STOP+TXIS (+TXE)


So, after effective NACK from slave, we have NACK+STOP+TXIS.

The documentation says, that NACK won't set TXIS. It says it *twice*:



What did I overlook?


ST Employee

Hello @waclawek.jan 

Before launching the communication, make sure that the I2C bus is idle. This can be checked using the bus idle detection function or by verifying that the IDR bits of the GPIOs selected as SDA and SCL are set.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hi @FBL ,

I'm not sure you've understood the issue.

Here the problem is not in idleness of the bus before communication, but NACK during communication. This may happen due to noise, but also due to genuine NACK from the slave.

Also, please note, that the observed behaviour contradicts the description in the documentation.

Can you please address these issues.


Jan Waclawek