AnsweredAssumed Answered

STM32F2xx I2C not sending Address after Start

Question asked by peelo.frank on Mar 15, 2016
Latest reply on Aug 18, 2017 by potma.allard
I'm trying to debug an I2C interrupt handler that I didn't write, on an STM32F207ZG. My problem is that after sending a Start, when waiting to send the Address byte, a Stop happens. What am I doing wrong that makes the STM32F2xx do that?

The I2C1 interface is talking to two slave devices, a Texas Instruments TMP101 temperature sensor, and a Fujitsu MB85RC128 FRAM. The TMP101 is occasionally (once a second) read. The FRAM is written maybe 3 times in 5 seconds in my test setup. When neither of these is happening, the FRAM is repeatedly read.

The code works for perhaps 20 minutes, perhaps 9 hours. But sooner or later, the interrupts stop happening.

There is code outside the interrupt handler, to queue Transmit, Receive or Transmit+receive operations for the handler. Then the frames are then processed as interrupts occur - stepping through states to send address, send or receive bytes, signal stop.

I have managed to capture information about the crash, six times now. I find that the problem always happens after a read of 2 bytes from the TMP101. I don't know if the 2 bytes are significant: Reference manual RM0033 has special mention about reading 2 bytes, but as far as I could see, the code does what the manual recommends. The read of 2 bytes is also the last operation in the queue, which might also be relevant.

The read of 2 bytes is successful, but the next operation, which will be a read of the FRAM (because that happens so often) does not get started. Here is what happens on SCL and SDA:


After the last of the two received bytes, there is a start condition, then one low pulse of SCL, then a stop condition.

I added a Log() function, to record the position in the interrupt handler in a circular buffer, and code to dump the circular buffer when the handler fails. So I know that this is the last part of the interrupt handler that gets run:

  uint16_t sr = port->regs->SR1;
  if((sr & I2C_SR1_ERRFLAGS) == 0u) {
    switch(port->state) {
    case I2C_MXX_START:
      if((sr & I2C_SR1_SB) != 0u) {
Log(isTxRxMxxToMtxAddr, sr);                         
        port->state    = I2C_MTX_ADDR;
        port->regs->DR = frame->addr << 1;  /* master write mode */

  •     I2C_SR1_ERRFLAGS is 0x1F00, all the error conditions.
  • State I2C_MXX_START means the interrupt handler has been requested to transfer data. When port->state is set to I2C_MXX_START, the value 0x0700 (ITBUFEN | ITEVTEN | ITERREN) is ORed into the CR2 register, then the START and ACK bits are ORed into CR1. This happens in non-interrupt code, but only when the queue is empty.
  • The SR1 register, in sr, which is also logged here, has the value 1, i.e. only the SB bit is set.    

This is the state EV5 in the Reference Manual. Reading SR1 to sr and writing the address to the DR register should move us to the next state, where the address is output to the I2C bus. But that is not happening. Only a Stop condition is happening on the bus. Since the other two devices connected are slaves, I think the STM32F2xx is putting out the Stop signal.

Is this a known behaviour of the STM32F2xx? Or does it arise if I have written the wrong thing to a register - could anyone suggest what the needle looks like, that I am searching for in this haystack?

In addition to reading and trying to understand RM0033, I also tried looking for an example interrupt handler, to see if anything was being done differently. It's the stm32f2xx_it.c file in I2C\I2C_TwoBoards\MasterReceiverInterrupt in the standard peripheral library (the author of this code did not use the standard peripheral library functions, unfortunately). It has special handling for when 3 bytes are being received, which does not seem to match RM0033. RM0008, which is for the STM32F1xx, does mention things to do when there are 3 bytes to come in. Do I need to follow both reference manuals?