cancel
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*:

waclawekjan_0-1701194692917.png

 

What did I overlook?

JW

7 REPLIES 7
FBL
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.

Thanks,

Jan Waclawek

 

ST in the past few weeks rolled out a bunch of new RMs for STM32 families containing this version I2C, e.g. 'F303 or the mid-range 'L4 (RM0394 pertaining to the low-end 'L4 model from subject of this thread is still in rev.4 from 2016). In the above quoted section, the incorrect statement (i.e. that there is no TXIS after NACK) is now not twice but "only" once...

I am not sure if the other two issues reported in this trilogy were addressed either.

--

Also, there's also a new section at the beginning of Master communication initialization (address phase) subchapter, requiring the user to check bus for idleness before launching communication, and then the subsequently the (probably original, unchanged) section talks about the hardware checking for idleness and starting only after it detects bus free (BUSY = 0). This is confusing to say the least.

The new section has also some relatively worrisome content:

Any low-level incident on the I²C-bus lines that coincides with the START condition asserted by the I2C peripheral may cause its deadlock if not filtered out by the input filters.

It would be nice to see ST addressing all these issues properly, e.g. in an appnote.

JW

@KB-IDEA 

 

 

Hello @waclawek.jan,

I'm the one responsible for these new sections of text.

As you probably imagine, the I2C IP is just a bunch of little timers trenchcoated, pretending to be a single big peripheral. These timers guard the data setup time, data hold time, the SCL timing... some timings require actual edge because the I2C specification dictates so.

It was revealed that if the SCL is externally driven low before the start condition is sent, the SDA timer will not receive the SCL falling edge expected and the com is stuck.

The BUSY mechanism is not detecting bus being used, it's only observing the internal state machine.

There's a solution to this, available on almost all STM32, except the newest STMU0. The SMBus specification is better suited for the multi-master or noisy environment and has means to deal with that. So the solution is to make use of the TIMEOUT features of SMBus, adding more timers into the pool.

We are now in discussions about possibility of having also other means of dealing with that, especially for devices like STM32U0 without SMBus support.

BR,

J

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 @Bubbles ,

Thanks for the comments.

Can you please comment also on what's the original topic of this thread, i.e. that the RM's claim that NACK won't set TXIS is incorrect?

> It was revealed that if the SCL is externally driven low before the start condition is sent, the SDA timer will not receive the SCL falling edge expected and the com is stuck.

Yeah, I know  ;‑) 

I personally would never entertain the idea of handling I2C without timeout, so I don't rely on any hardware to do that. And I have no problem with whatever the actual behaviour is, as long as it is clearly, comprehensively, completely described in the documentation. I don't like the idea that I have to "discover" the internal machine by experimentation.

Btw. there are SMBus-less I2C modules in most STM32, not only 'U0.

JW

 

Hello @waclawek.jan

I tried to reproduce the problem you reported, but each time I generated a NACK, the master was like this. I tried different conditions, but I probably couldn't precisely reproduce the disconnection you referred to. would you care to post some screenshot from scope or logic analyzer?

JW-nack.png

My impression so far is that what you described in the original post is again a behavior violating the I2C standard and we cannot be expected to cover in our documentation every single error condition caused by that.

As for the STM32U0 - as far as I know there in every series there was some SMBus support, even if not on all the I2C instances. The U0 unfortunately has none. 

BR,

J

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 @Bubbles ,

> I tried to reproduce the problem you reported, but each time I generated a NACK, the master was like this

That's because your ISR already had served the TXIS in question. Proof is, that TXE is 0, i.e. there is already a datum in the holding register, which will never depart, as the internal machine already issued STOP. (This actually is one of the consequences of this whole issue: if you start another I2C transaction without resetting I2C, the byte which is already in the holding register will be immediately transmitted instead of address).

You can easily reproduce the problem according to my description in opening post, in IDE without gdb, by directly manipulating and observing I2C registers in the register view. You don't need to run any I2C-related code (e.g. just use a plain blinky, so that you can run the debugger at all). Stop execution, enable I2C clock in RCC and then follow the steps I've given above (gcc's command "set" means "set this value into this variable/register"; "p" means "print").

> My impression so far is that what you described in the original post is again a behavior violating the I2C standard

Oh, no, no, this is a perfectly legal behaviour, the receiver - here slave - can issue a NAK any time, as it wishes; see UM10204 (the I2C specification), chapter 3.1.6 Acknowledge (ACK) and Not Acknowledge (NACK), conditions 3 and 4.

> and we cannot be expected to cover in our documentation every single error condition caused by that.

But my complaint is *not* that ST doesn't document the behaviour upon NACK; contrary: as shown in the initial post, it *does* document it, but incorrectly...

JW