IMU SparkFun 9DOF ICM-20948: little or big endian?

Inside the IMU SparkFun 9DOF ICM-20948, does the signed int16_t accel/gyro/magneto measures are little or big endian?

Looking at the doc https://cdn.sparkfun.com/assets/learn_tutorials/8/9/3/DS-000189-ICM-20948-v1.3.pdf, it seems accel / gyro are big-endian, and only magneto is little-endian (section 13.3 - Measurement data is stored in two’s complement and Little Endian format.)

… But, as arduino is little-endian, looking at the official code SparkFun_ICM-20948_ArduinoLibrary/src/util/ICM_20948_C.c at 168c18b8ebf7c8a28ac22f1351f23e0f143ba195 · sparkfun/SparkFun_ICM-20948_ArduinoLibrary · GitHub, it seems that accel/gyro is little-endian (ACCEL_XOUT_H comes first in buff[0] so it must be LSB as arduino is little-endian) and magneto is the other way: same github link at line L1081

For Ax, if the sensor is big-endian and the arduino little-endian why don’t we have pagmt->acc.axes.x = ((buff[1] << 8) | (buff[0] & 0xFF)); instead of pagmt->acc.axes.x = ((buff[0] << 8) | (buff[1] & 0xFF)); ?

The 16 bit sensor data values and corresponding 8 bit registers are very clearly labeled in the ICM-20948 data sheet, and the high and low bytes of each are identified.

If you read the values in as individually named bytes, it doesn’t matter what order the data are in. Just treat the “high byte” as the most significant and “low byte” as the least significant of the 16-bit result.

You don’t need to know the Arduino endianness, either. Something like this, using those individually named data bytes, will always work correctly:

int16_t acc_x_value = (acc_x_high_byte<<8) | acc_x_low_byte;

Reading the data into an array with a meaningless name like “buff” is guaranteed to be obscure and confusing.

1 Like

Why? If generated as big-endian in sensor memory, shouldn’t it be converted (swapping MSB and LSB) to little-endian at arduino side (as arduino is little-endian)?

I agree: you get MSB and LSB individually.

Indeed, that is what I observe: it seems to work… But why does it work? If sensor memory is big-endian, acc_x_high_byte is MSB, right? And acc_x_low_byte is LSB. So (acc_x_high_byte<<8) | acc_x_low_byte is (MSB << 8) | LSB which is not the correct way to encode a signed integer back on a little-endian arduino .

I don’t get why Just treat the “high byte” as the most significant and “low byte” as the least significant of the 16-bit result. produces the correct result back on the arduino even if I see it does indeed produce the correct result.

shouldn’t it be converted

Not if you follow my instructions. The compiler stores the 16 bit value produced by the following line in the correct byte order.

int16_t acc_x_value = (acc_x_high_byte<<8) | acc_x_low_byte;

The DEFINITIONS of “high byte” and “low byte” eliminate any possible confusion.

Named bytes have no “endianness” and it does not matter where or in what order they are in memory. High and low bytes need not even be consecutive.

So, as the data is created using big-endian at sensor side, it should be re-created as big-endian at the receiver side (whatever the receiver - arduino or other - and it’s endianness)?

The compiler decides, and always makes the correct choice.