gobot icon indicating copy to clipboard operation
gobot copied to clipboard

HMC5883L driver returns wrong values

Open gen2thomas opened this issue 2 years ago • 4 comments

According to the datasheet section "Data Output X Registers A and B" the values should be in 2s complement form +0xF800 ... 0x07FF (-2048 ... +2047). In case of an overflow, the value gets "-4096 (0xF000)".

In my first test case, the values of X,Y, Z jump in a high range. All values can exceed 2048 and don't lock to -4096 for a strong magnetic field.

A first investigation shows, that a missing byte-swap after reading the MSB, LSB data with "ReadWordData()" could be the root cause.

I will provide a fix after some further tests, maybe together with #805 .

gen2thomas avatar Aug 31 '22 16:08 gen2thomas

Following a spontaneous idea, I investigate all calls of "ReadWordData()" and all implementations. Normally the function should return the bytes in the expected order, otherwise we would not need this function. Also it is surprising, that there is no related bug entry since the initial implementation of the HMC5883L driver with #781 in April 2021.

I found usage of "ReadWordData()" for the following devices:

  • TSL2561 - format: stored order LSB-MSB, but hardware implementation seems to ensure always read MSB-LSB unsigned - no swap implemented
  • INA3221 - format: MSB-LSB two's complement, swap implemented
  • CCS811 - format: MSB-LSB unsigned, no swap implemented
  • HMC5883L - format: MSB-LSB two's complement, no swap implemented

These implementations can be found:

note: After reading the SMBus specification, I come to the conclusion, that the order is defined as LSB, MSB. All platforms, except firmata and digispark use this implementation.

So I assume that the following drivers will not work at the moment (independent of the used platform):

  • CCS811 (not critical because only used for reading the bootloader and firmware version)
  • HMC5883L

Note for TSL2561: Because the documentation is somewhat confusing about the read order (stored order is LSB, MSB), I found the arduino implementation from adafruit, which reads the values sequential (without set the address for the second value) and use the first value (little address) as LSB, this means do not swap. The same for the arduino library of sparkfun. So our driver should work fine.

gen2thomas avatar Sep 01 '22 16:09 gen2thomas

I have tested the HMC5883L driver today with my digispark platform and the same problem happen. So I looked again to the digispark driver implementation, and I was wrong with my statement that the bytes become swapped, because it reads 2 bytes and the first becomes the low byte, the second the high byte. I have corrected my comments above.

gen2thomas avatar Sep 03 '22 10:09 gen2thomas

To clarify, how a word read "normally" works, I installed my mcp2221 USB-to-UART/I2C serial converter and connected the HMC5883L to it. Than I initializes the device and read the data for X in different ways:

  • i2cget -y 7 0x1e 0x03 --> 0xff
  • i2cget -y 7 0x1e 0x04 --> 0xfd
  • i2cget -y 7 0x1e 0x03 w --> 0xfdff

This means, that also the commonly used i2cget binary will return a word as LSB, MSB (little endian), which matches the implementation of all our platforms. So the HMC5883L driver (and maybe the CCS811) needs to be fixed (store values as big endian).

gen2thomas avatar Sep 03 '22 13:09 gen2thomas

Looks like something must have gotten mixed up at some point. Thanks for finding this issue!

deadprogram avatar Sep 06 '22 08:09 deadprogram

part of release v2.0.0

gen2thomas avatar May 15 '23 16:05 gen2thomas