Affordable and flexible platform to ease prototyping using a STM32F401RET6 microcontroller.

NUCLEO-F401RE I2C slave problem

25 Aug 2016

I am having a problem using NUCLEO-F401RE board for testing the i2c slave. I was using the mbed OS 5 i2c slave example (https://docs.mbed.com/docs/mbed-os-api-reference/en/5.1/APIs/interfaces/digital/I2CSlave/) with the bit rate standard 100K bit/s. I used the Total Phase Aardvark I2C host adapter sending bytes (8 bytes) to NUCLEO-F401RE board. The NUCLEO-F401RE i2c slave always holds down the SCL line forever in middle of the data transfer, which can be viewed clearly by a oscilloscope or a I2C protocol analyzer. Please help!

The I2C slave testing project is here:

Import programI2CSlaveTest

mbed OS-5 I2C Slave using Nucleo-F401RE board.

The following is the snippet of the test code:

NUCLEO-F401RE I2C slave test

include <mbed.h>

I2CSlave slave(PB_9, PB_8);
 
int main() {
   char buf[10];
   char msg[] = "Slave!";
 
   slave.address(0x0A);
   while (1) {
       int i = slave.receive();
       switch (i) {
           case I2CSlave::ReadAddressed:
               slave.write(msg, strlen(msg) + 1); // Includes null char
               break;
           case I2CSlave::WriteGeneral:
               slave.read(buf, 10);
               printf("Read G: %s\n", buf);
               break;
           case I2CSlave::WriteAddressed:
               slave.read(buf, 10);
               printf("Read A: %s\n", buf);
               break;
       }
       for(int i = 0; i < 10; i++) buf[i] = 0;    // Clear buffer
   }
}
14 Sep 2016

Hello sorry for not answering earlier. I somehow reproduced the issue this morning and please find below my first findings:

First I used another NUCLEO board as a master and used the test code below

char buf[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30}; i2c.write(ADDR, buf, SIZE); wait(1); i2c.write(ADDR, buf, SIZE);

the slave is properly getting the answer and printing result : Read A: 1234567890 Read A: 1234567890

Then next thing I did is to remove the wait(1); in the master code. char buf[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30}; i2c.write(ADDR, buf, SIZE); wait(1); i2c.write(ADDR, buf, SIZE); In this case, I reproduce a similar issue as you see and I will try to investigate how to recover from the error.

Nevertheless, there is an easy way to avoid the problem on the slave side. In order to keep real time answer, it's better to get rid of the printf (useful for quick debug, but not adapted to real time answer needed by an I2C slave).

So if by removing call to printf, I have the test working fine: case I2CSlave::WriteAddressed: slave.read(buf, 10); printf("Read A: %s\n", buf); break;

I could check on a scope that the 10 bytes are well received, and SCL as well as SDA are back to normal (high) state.

So please remove the call to printf, or add a suitable pause / wait on the master side to allow printf to happen before sending the next command

cheers Laurent

14 Sep 2016

Hi again

I just captured the UART TX (in green below) to show what happens. /media/uploads/LMESTM/i2cslave.png

the UART tx of printf "Read A: 1234567890" is in green. You can see this is blocking the system from reading I2C lines. By the time you finally read the incoming byte, the Master side will be in timeout I think. You will also note that the lines are back to normal states after some time.

16 Sep 2016

Folks, I'm having the exact same problem. Unfortunately, this is causing me to rethink the leap from a prototype using Arduino over to an MBED/STM32 environment (maybe more of a step then a leap, but you get the idea). I2C is how the multi-MCU system I'm building was supposed to communicate.

I tried the same code and see the same results using 3 different STM32 NUCLEO boards:

  • NUCLEO-F042K6
  • NUCLEO-L432KC
  • NUCLEO-F446RE

Looks like someone else is in a similar situation here:

The only way I found around this was to throttle the master such that it would not write until the slowest slave could finish reading/processing the previous write (sort of like having a small 2 byte buffer). This was done by simply throttling with wait_ms() calls (as suggested above). The real master, however, will be processing input over serial at 31250 bps which must be pushed to other processors in real-time. As long as the receivers have some wiggle room (with proper I2C library buffering), the apps should not be throttling on a per write basis.

I do have similar code running on a Teensy 3.2 using the Arduino (Wire) library and this blocking/long-ACK behavior is not present.

Question: So is this a general MBED I2C problem or something specific to the MBED I2C Slave implementation with STM32 NUCLEO boards?

18 Sep 2016

Hi Laurent, Thank you for answering my problem. I did remove the printf statements from the code and added a wait(1) at end of the loop. However, I still getting the problem. I used same master/slave setup for testing the I2C using STM32Cube and it works fine. There is no problem on the target hardware or the master. I think it is the issue on mbed library implementation. We already spent too much time on unreliable mbed develop environment and we are think to find alternative solution for the development.

Here is the snippet of the revised code:

#include "mbed.h"

I2CSlave slave(PB_9, PB_8);

int main() {
   char buf[10];
   char msg[] = "Slave!";

   slave.address(0x0A);
   while (1) {
       int i = slave.receive();
       switch (i) {
           case I2CSlave::ReadAddressed:
               slave.write(msg, strlen(msg) + 1); // Includes null char
               break;
           case I2CSlave::WriteGeneral:
               slave.read(buf, 10);
               break;
           case I2CSlave::WriteAddressed:
               slave.read(buf, 10);
               break;
       }
       wait(1);
   }
}
22 Sep 2016

Hello Jingxi Zhang, The wait() call I proposed earlier is on the _master_ side, not the _slave_ side. If you put wait() on the slave side you would certainly lose bytes :-( So you shall remove the wait(1); in your above code. cheers Laurent PS: I will try to have a deeper look at Manny post later

13 Oct 2016

Unfortunately, I got the same problem by removing statement in the I2C slave.

18 Oct 2016

Hello, can you please share latest version of the code for both master and slave side that you use when you see the problem ? Thanks Laurent

01 Nov 2016

Hi, I have the same issue connecting a GPS on a Nucleo L476. Any update on this issue?

10 Mar 2017

I too would like to know. When using the I2C slave having weird issues.

24 Mar 2017

I'm using nucleo L432kc as I2Cslave without issues....make sure to shift the address of nucleo if the i2c master using 7-bit i2c address format (i.e. in the master code if you are writing to address 0x18, then in the nucleo code -> slave.address(0x30)). You may also need pullup resistors (4.7k) on SDA and SCL lines (I'm fine without them).

21 Apr 2017

I am quite sure the issue is with mbed.

I used mbed to write an I2C slave code and it brings the SCL line down with or without pull up.

I used SPL to write the same I2C slave code and it works fine.

I think there is something wrong with mbed initialising the SCL and SDA pin that messed the whole thing up.

I would be very happy if I were wrong though but I think i'll just stick with SPL and HAL for now.

Please log in to post a reply.