4 years, 5 months ago.

I2C multi-byte read command not working while single byte reading works

I'm trying to simplify some working code reading a sensor over I2C. The first code section works, but I don't like having to use the 4 single byte read commands when there is another that combines all of them together. Ultimately it will become a class function and so will need to work with a variety of read lengths, addresses, etc. I've tried adding start/stop commands on either side of the read command, but nothing works. The data_read array stays empty (all zeros) for the second example.

Given that I have working code from the first example, how can I condense it down to something like the second? The hardware side is clearly functional, as I'm getting valid readings the long way.

This works

char data_read[4];
const char data_write = (mi2cAddress << 1) | 1;

i2c.start();
i2c.write(data_write);

data_read[0] = i2c.read(1);
data_read[1] = i2c.read(1);
data_read[2] = i2c.read(1);
data_read[3] = i2c.read(0);

i2c.stop();

This does not work

char data_read[4];

i2c.read(mi2cAddress, data_read, 4);

2 Answers

4 years, 5 months ago.

In the first example you use as slave address:

const char data_write = (mi2cAddress << 1) | 1;

In the second you use as slave address the value mi2cAddress. That value should also be shifted left by one bitposition.

Try this:

i2c.read(mi2cAddress << 1, data_read, 4);

I tried that, but no luck, still get no data. My understanding of the I2C read and write commands was that the short versions (ie "read (int ack)" and "write (int data)" just read/write a raw byte from/to the I2C bus, while the longer version of the commands do the address shifting, start/stop, etc all in one command. Is that not the case?

posted by David Wahl 02 May 2017

The longer functions do the start and stop, they also set the read/write bit, but they do not shift the address. You need to use the slaveaddress in the 8bit format. The additional parameter true/false should be false, but that is the default value and doesnt need to be provided.

Are you using the i2c operation inside a ticker or interrupt? Note that there are issues with the recent STM lib that prevents them from working correctly in that case.

posted by Wim Huiskamp 03 May 2017
4 years, 5 months ago.

Can you try the following and post your results ?

char data_read[4];
// FALSE = 0 
i2c.read(mi2cAddress, data_read, 4, FALSE);

From this hint page, you may need the last missing parameter:

https://developer.mbed.org/users/mbed_official/code/mbed/docs/tip/group__drivers.html#ga363b152165c7ca64e28abdfc24dd4f17

Do you have a logic / I2C bus analyzer ? If yes, do you see any activity with the multi-byte read call ?

-

David - also, which mbed enabled board are you testing with this observation ? You have so many in your toolchest :)

I've tried adding that last parameter, both TRUE and FALSE and it has no visible effect. I do have a logic analyzer but haven't dug it out yet, perhaps I should. It hasn't been a huge priority yet as I do have a workaround, I was hoping for an obvious mistake in how I'm using the read function.

The board I'm using is the Nucleo-F446RE, I should probably clear some of the others out of my account :)

posted by David Wahl 02 May 2017