Normal I2C procedure on Nucleo does not work

24 Mar 2014

For everybody who expects a simple I2C program which runs on the LPC17xx platform will also run on Nucleo will be disapointed. The normal I2C procedure: start(), write(addr), write(data), stop() will NOT work with the nucleo API.

Instead you have to use i2c.write(address,data,length,repeat) only, because the method contains allready the start and stop function and a special addressing function.

When I looked at the example Nucleo_ic_master I first noticed the missing start and stop functions, but thought the LM75 does not need this functions. After looking into the API-code I could see that the both implemented write functions are very different which can be not recognized by reading the API-documentation only. The documentation gives the impression that one method is for sending a single byte and the other one for sending multiple bytes.

This is not my understanding of cross-platform portability.

Hopefully this will save some time for others who are using the Nucleo I2C functions.

06 Apr 2014

Maybe it could be stated more clearly in the handbook, but the two write methods are different and should both work as documented:

int write (int address, const char *data, int length, bool repeated=false)
// 	 Writes a complete message to an I2C slave: start, address + R/W bit, length number of databytes and a stop when no repeated start is following.
int write (int data)
// 	 Writes a single byte out on the I2C bus. No start stop or anything else.

This is how it works on the lpc1768. Having said that, I did have problems with early versions of the I2C libs on several other platforms (e.g lpc812) and more recently with the nucleo F103. The libs are just not fully implemented or tested at this moment. I made some changes in the source of the F103 and now both methods work, but there is room for more improvements.

28 Jul 2014

hi Wim, I've experienced the same things with my 2 nucleo-L152RE boards . and I'm now trying to play with the I2CSlave API yet I got no success up to now :-/

I've tested the "simple Slave responder" given in the API documentation and nothing is acknowledged by the (Slave) Nucleo board. have you already get into this ?

cheers Eric

18 Sep 2015

Here's my code - as simple as it comes... I'm using a F302R8 nucleo board

#include "mbed.h"
#define RELAY_BOARD_ADDR (0x20)
#define LOOP_WAIT_TIME   2.0

I2C i2c(PB_9, PB_8);
//I2C i2c(I2C_SDA, I2C_SCL);
DigitalOut myled(LED1);
int main()
    char data_write[2];
    char  data_counter = 0;
    data_write[0] = 0x12;
    data_write[1] = 0x02;
    while (1) {
        i2c.write(RELAY_BOARD_ADDR, data_write, 2, 0);

        myled = !myled;

        data_write[1] = data_counter;


Still doesn't work.

I checked on a CRO and I can only ever see 9 clock cycles per attempted transmission, the data bytes don't seem to be getting through?

I'm not entirely sure that the timing is correct /media/uploads/SamTheMan01/2015-09-17_16.34.54.jpg the read/write bit or the ack???

Any ideas...

20 Sep 2015

You can see that after sending the slaveaddress (0x20) the SDA line is high on the 9th clockbit. That means you dont get an ack from the slave on this address. The i2c.write() will then abort so you dont see any further data transmission. I am guessing that your relayboard is using a portexpander such as the PCF8575. This device has 8 possible I2C addresses given in 7bit format: 0 1 0 0 A2 A1 A0. HOWEVER, the device address used by the mbed libs is in the 8bit format. The LSB is always zero and replaced by the I2C hardware depending on a read or write operation. The full 8bit device address can be found by shifting the 7bit address to the left by one position.

Assuming that A2,A1 and A0 are all 0, try

#define RELAY_BOARD_ADDR (0x40)

You may also want to check the pull-up resistors on SDA and SCL. They should be about 4k7. It seems the SDA signal on your scope is too low. The vertical range is 200mV for SDA and 2V for SCL? Perhaps this is just the result of a 10x probe that is not recognised by the scope.

24 Sep 2015

Thanks for your response...

The slave device is actually a PIC micro. I used the board on an Arduino platform (i.e. for what it was originally designed) and it worked immediately. So I know the "shield" is not broken (no hardware problem).

I also tried a scan of all I2C addresses (as 8 bits - to cover your suggestion about the address format above) with no success.

At this time I revert to plan B

24 Sep 2015

No issues here with I2C on a Nucleo, at least with F401 and 24Cxx eeproms. The pitfalls I overcame were failing to install pullup resistors & not left-shifting the I2C address ie use (device_addr<<1), so for 24Cxx devices use (0x50<<1) ie 0xA0 .

25 Sep 2015

A full addressscan without results points towards a basic power or signallevel problem. Did you check the voltage levels on the SDA and SCL (note that SDA seems too low on the scope). Did you make sure that the PIC micro has powersupply (probably needs 5V) and that it works with the nucleo 3V3 I2C levels. You may have to use a level converter. Also make sure you have a common GND signal.

27 Sep 2015

Yes, the PIC was powered - wired up in the same way as with the Arduino. Grounds should be the same - i.e. through the arduino headers

You could be right though, it might be a "logic level" problem!

I guess this was an oversight on my part - that when I saw that the nucleo boards had arduino headers assumed that they would be "Arduino Compatible" when actually they are not (completely).

There could be other problems as well - on other shields, on other interface types i.e. I/O or serial.... which begs the question why put them on at all? - I mean if you want to use the I2C you have to add a shield plus a level converter - sounds messy.

I did want a 12bit ADC, but will have to settle for a 10bit one on the Arduino. Unfortunately I don't have time to play around any more to fix the I2C interface.

Thanks for your help anyway