I2C burst read corrupting data
Posted: Tue Aug 27, 2024 2:40 pm
I am attempting to read 192 bytes of data from the FIFO buffer of an MMA8451Q accelerometer using an ESP32-S3-Devkit-U1.
This should be pretty simple... write to the appropriate register and then conduct the 192 reads.
The 192 bytes are organized as 32 sets of 6 bytes. The 6 bytes are 2 bytes for each axis: x, y, and z. The two bytes are then converted to a 14-bit twos-complement value and that value is then converted to a g value.
What I am seeing is that the first 21 sets of six bytes is correct and then the remaining 11 sets are non-sensical.
Below is the raw data followed by the data converted to g values. With the sensor motionless, the converted x and y values should be near zero and the z values should be near 1.00. That is what we see for the first 21 events and then corrupted data for the remaining 11. The first column contains the sample number.
I have tried various I2C frequencies from 400KHz down to 50KHz and nothing changes (except the elapsed time).
I have tried this with and without pull-up resistors and nothing changes.
The I2C library I am using is from Adafruit. The exact code that is executing for the write_then_read function is as follows and looks pretty straight forward. (I have striped this down to remove any #ifdefs that would not be active) It all really comes down to just this...
but here is all the code...
So... what could be causing the data to go crazy after the 21st set of data?
Any help is greatly appreciated! THANK YOU
This should be pretty simple... write to the appropriate register and then conduct the 192 reads.
Code: Select all
#define use14bit true
#define MMA8451_FIFO_REG 0x01
#uint8_t FIFObuffer[192];
bool PD_MMA8451::getFIFO(bool use14bit)
{
uint8_t targetRegister[1] = {MMA8451_FIFO_REG};
return (i2c_dev->write_then_read(targetRegister, 1, FIFObuffer, use14bit ? 192 : 96));
}
The 192 bytes are organized as 32 sets of 6 bytes. The 6 bytes are 2 bytes for each axis: x, y, and z. The two bytes are then converted to a 14-bit twos-complement value and that value is then converted to a g value.
What I am seeing is that the first 21 sets of six bytes is correct and then the remaining 11 sets are non-sensical.
Below is the raw data followed by the data converted to g values. With the sensor motionless, the converted x and y values should be near zero and the z values should be near 1.00. That is what we see for the first 21 events and then corrupted data for the remaining 11. The first column contains the sample number.
I have tried various I2C frequencies from 400KHz down to 50KHz and nothing changes (except the elapsed time).
I have tried this with and without pull-up resistors and nothing changes.
Code: Select all
Elasped Time 4604 microseconds
0 0 80 255 152 16 48
1 0 80 255 152 16 52
2 0 84 255 152 16 48
3 0 80 255 152 16 48
4 0 72 255 152 16 52
5 0 80 255 160 16 48
6 0 80 255 156 16 28
7 0 84 255 152 16 56
8 0 80 255 156 16 44
9 0 80 255 152 16 44
10 0 84 255 156 16 48
11 0 84 255 152 16 48
12 0 80 255 148 16 48
13 0 80 255 156 16 56
14 0 80 255 148 16 44
15 0 76 255 148 16 48
16 0 80 255 156 16 40
17 0 80 255 152 16 48
18 0 72 255 152 16 60
19 0 80 255 156 16 56
20 0 76 255 152 16 48
21 0 80 11 0 84 255
22 160 16 36 0 72 255
23 152 16 40 0 80 255
24 156 16 48 0 84 255
25 152 16 52 0 80 255
26 148 16 40 0 84 255
27 156 16 40 0 80 255
28 152 16 44 0 80 255
29 152 16 48 0 84 255
30 156 16 44 0 80 255
31 156 16 48 128 128 128
0 0.02, -0.03, 1.01
1 0.02, -0.03, 1.01
2 0.02, -0.03, 1.01
3 0.02, -0.03, 1.01
4 0.02, -0.03, 1.01
5 0.02, -0.02, 1.01
6 0.02, -0.02, 1.01
7 0.02, -0.03, 1.01
8 0.02, -0.02, 1.01
9 0.02, -0.03, 1.01
10 0.02, -0.02, 1.01
11 0.02, -0.03, 1.01
12 0.02, -0.03, 1.01
13 0.02, -0.02, 1.01
14 0.02, -0.03, 1.01
15 0.02, -0.03, 1.01
16 0.02, -0.02, 1.01
17 0.02, -0.03, 1.01
18 0.02, -0.03, 1.01
19 0.02, -0.02, 1.01
20 0.02, -0.03, 1.01
21 0.02, 0.69, 5.31
22 -6.00, 2.25, 4.56
23 -6.50, 2.50, 5.06
24 -6.25, 3.00, 5.31
25 -6.50, 3.25, 5.06
26 -6.75, 2.50, 5.31
27 -6.25, 2.50, 5.06
28 -6.50, 2.75, 5.06
29 -6.50, 3.00, 5.31
30 -6.25, 2.75, 5.06
31 -6.25, 3.03, -7.97
Code: Select all
write(write_buffer, write_len, stop);
// and then this...
size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len, (uint8_t)stop);
Code: Select all
bool Adafruit_I2CDevice::write_then_read(const uint8_t *write_buffer,
size_t write_len, uint8_t *read_buffer,
size_t read_len, bool stop) {
if (!write(write_buffer, write_len, stop)) {
return false;
}
return read(read_buffer, read_len);
}
bool Adafruit_I2CDevice::read(uint8_t *buffer, size_t len, bool stop) {
size_t pos = 0;
while (pos < len) {
size_t read_len =
((len - pos) > maxBufferSize()) ? maxBufferSize() : (len - pos);
bool read_stop = (pos < (len - read_len)) ? false : stop;
if (!_read(buffer + pos, read_len, read_stop))
return false;
pos += read_len;
}
return true;
}
bool Adafruit_I2CDevice::_read(uint8_t *buffer, size_t len, bool stop) {
size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len, (uint8_t)stop);
if (recv != len) {
// Not enough data available to fulfill our obligation!
return false;
}
for (uint16_t i = 0; i < len; i++) {
buffer[i] = _wire->read();
}
return true;
}
Any help is greatly appreciated! THANK YOU