5 years, 6 months ago.

I2C specific sequence

Hi,

I have an KX224 accelerometer and I want to read its buffer using I2C. There is a "Sequence 4" in datasheet (http://kionixfs.kionix.com/en/datasheet/KX224-1053-Specifications-Rev-2.0.pdf - page 21) which is supposed to replicate in order to read the buffer, but I don't know how to do it. The buffer contains accelerometer data. In order to read it, you have to read one register with one byte. Because the buffer actually contains 2048 bytes, you have to send ACK after each reading to update the next value from the FIFO into the same register.

I tried using: i2c.write((int)((KX224_DEVICE_ADDRESS_1E << 1) | I2C_WRITE), &reg, 1, true); int c = i2c.read((int)((KX224_DEVICE_ADDRESS_1E << 1) | I2C_READ), &out, 1, true);

Using a logic analyzer, I get this from the above code: /media/uploads/arnautug/capture.png

Can someone help me?

Thanks, Gabriel

Wim, I will try your code for I2C high speed. Indeed, my MCU does not support HS, but I will give it a try. I am trying not the way around with SPI to compare the speeds. I will post a question for that as well :). Thanks for your help!

posted by Gabriel Arnautu 05 Nov 2018

1 Answer

5 years, 6 months ago.

You first need to set the register from which to read and then read a byte from that register. Normally, multiple sequential read operations would automatically increment the selected register address and thus read from the next sequential register. However, the specific register address for ''sequence 4'' is linked to an internal fifo and every subsequent read operation does not access the next register, but instead sends the next value in the fifo. The problem with your code is that you read only one byte from the fifo, the master does not send an acknowledge since it is the last byte, and it does not send a Stop because you set the 'repeated start' parameter to 'true'.

Try this:

//reg = address of fifo
//set the register address, select repeated start for the follow-on read
i2c.write((int)((KX224_DEVICE_ADDRESS_1E << 1) | I2C_WRITE),  &reg, 1,  true);


//now read multiple bytes from the fifo register (10 in this case), make sure there is enough room in the buffer ''out'' for all 10
//dont use repeated start
char out[16];
int c = i2c.read((int)((KX224_DEVICE_ADDRESS_1E << 1) | I2C_READ), &out, 10);

//buffer out[0..9] now holds the 10 bytes from the fifo register

BTW you dont need to set the read/write bit in the slaveaddress. That is handled by the i2C lib. Just use:

...
i2c.write ((KX224_DEVICE_ADDRESS_1E << 1),  &reg, 1,  true);

..
int c = i2c.read ((KX224_DEVICE_ADDRESS_1E << 1), &out, 10);

Accepted Answer

Thank for your answer! It looks like it's working. I am still having issues about the values that I am getting, but it looks like the I2C sequence is good.

posted by Gabriel Arnautu 29 Oct 2018

Hi again,

Do you have any idea how should I do the sequence 6? I want to test it in high speed mode as well.

Thanks, Gabriel

posted by Gabriel Arnautu 31 Oct 2018

The default clockspeed for I2C is 100000 bits/s. You should be able to increase that to 400000 for normal (fastmode) I2C ports. Try

i2c.frequency(400000);

Note that not all mbed platforms support the same speeds. Use the scope to verify.

The highspeed mode is again not available on all mbed platforms and may depend on the specific I2C pins (ie I2C hardware engine) that you select. You need to check the documentation and perhaps even the mbed lib implementation code.

If it does work, you might be able to tweak the i2c calls to make the slave play at the highspeed mode. Something like this:

char reg = 0x08;   //  magic byte 00001xxx
char out[16]; //buffer

//send magic byte, and dummy byte, select repeated start for the follow-on read
//use repeated start
i2c.write (reg,  out,  0, true);
 
//set the new freq (note: might be too high or not work...)
i2c.frequency (3000000); 

//now prepare to read from the fifo register
//use repeated start
reg = fifo read address;   // set the fifo address
int c = i2c.write( (int)(KX224_DEVICE_ADDRESS_1E << 1), &reg, 1, true);

//now read multiple bytes from the fifo register (10 in this case), make sure there is enough room in the buffer ''out'' for all 10
//dont use repeated start
int c = i2c.read( (int)(KX224_DEVICE_ADDRESS_1E << 1),  out, 10);
 
//restore the freq 
i2c.frequency (100000); 

posted by Wim Huiskamp 31 Oct 2018