Problem getting HMC5883L to work

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
laukejas
Posts: 20
Joined: Thu May 02, 2019 5:17 pm

Problem getting HMC5883L to work

Post by laukejas » Wed Mar 11, 2020 9:26 am

Hi,

I just started with MicroPython. I have a NodeMCU board (with CP2102), and I installed latest MicroPython firmware into it. Using UPyCraft as an IDE and uploader. I already did some rudimentary things, and now I'm trying to get a HMC5883L digital compass (on a GY-273 board) to work. It uses i2c protocol for data transfer.

I hooked up the HMC5883L like so: VCC to NodeMCU 3.3V pin, GND to GND, DRDY unhooked, SDA to D2 (GPIO4), SCL to D1 (GPIO5). I also added 4.7K resistors to SDA and SCL, pulling them up to 3.3V.

Now, to get it to work, I am running this library. Here is the code from hmc5883l.py:

Code: Select all

import math
import machine

from ustruct import pack
from array import array


class HMC5883L:
    __gain__ = {
        '0.88': (0 << 5, 0.73),
        '1.3':  (1 << 5, 0.92),
        '1.9':  (2 << 5, 1.22),
        '2.5':  (3 << 5, 1.52),
        '4.0':  (4 << 5, 2.27),
        '4.7':  (5 << 5, 2.56),
        '5.6':  (6 << 5, 3.03),
        '8.1':  (7 << 5, 4.35)
    }

    def __init__(self, scl=4, sda=5, address=30, gauss='1.3', declination=(0, 0)):
        self.i2c = i2c = machine.I2C(scl=machine.Pin(scl), sda=machine.Pin(sda), freq=100000)

        # Initialize sensor.
        i2c.start()

        # Configuration register A:
        #   0bx11xxxxx  -> 8 samples averaged per measurement
        #   0bxxx100xx  -> 15 Hz, rate at which data is written to output registers
        #   0bxxxxxx00  -> Normal measurement mode
        i2c.writeto_mem(30, 0x00, pack('B', 0b111000))

        # Configuration register B:
        reg_value, self.gain = self.__gain__[gauss]
        i2c.writeto_mem(30, 0x01, pack('B', reg_value))

        # Set mode register to continuous mode.
        i2c.writeto_mem(30, 0x02, pack('B', 0x00))
        i2c.stop()

        # Convert declination (tuple of degrees and minutes) to radians.
        self.declination = (declination[0] + declination[1] / 60) * math.pi / 180

        # Reserve some memory for the raw xyz measurements.
        self.data = array('B', [0] * 6)

    def read(self):
        data = self.data
        gain = self.gain

        self.i2c.readfrom_mem_into(30, 0x03, data)

        x = (data[0] << 8) | data[1]
        z = (data[2] << 8) | data[3]
        y = (data[4] << 8) | data[5]

        x = x - (1 << 16) if x & (1 << 15) else x
        y = y - (1 << 16) if y & (1 << 15) else y
        z = z - (1 << 16) if z & (1 << 15) else z

        x = round(x * gain, 4)
        y = round(y * gain, 4)
        z = round(z * gain, 4)

        return x, y, z

    def heading(self, x, y):
        heading_rad = math.atan2(y, x)
        heading_rad += self.declination

        # Correct reverse heading.
        if heading_rad < 0:
            heading_rad += 2 * math.pi

        # Compensate for wrapping.
        elif heading_rad > 2 * math.pi:
            heading_rad -= 2 * math.pi

        # Convert from radians to degrees.
        heading = heading_rad * 180 / math.pi
        degrees = math.floor(heading)
        minutes = round((heading - degrees) * 60)
        return degrees, minutes

    def format_result(self, x, y, z):
        degrees, minutes = self.heading(x, y)
        return 'X: {:.4f}, Y: {:.4f}, Z: {:.4f}, Heading: {}° {}′ '.format(x, y, z, degrees, minutes)
I run it as instructed:

Code: Select all

from hmc5883l import HMC5883L
sensor = HMC5883L(scl=5, sda=4)
And, I get an error on that last line (creating sensor object). Error reads:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "hmc5883l.py", line 30, in __init__
OSError: [Errno 19] ENODEV
Line 30 is

Code: Select all

i2c.writeto_mem(30, 0x00, pack('B', 0b111000))
. Clearly, the i2c protocol isn't working. So, to test this out, I ran the following:

Code: Select all

import machine
i2c = machine.I2C(scl=machine.Pin(5), sda=machine.Pin(4))
devices = i2c.scan()
for device in devices:  
   print("Decimal address: ",device," | Hexa address: ",hex(device))
The terminal prints:
Decimal address: 13 | Hexa address: 0xd
It appears that it sees a device, but the hex address seems wrong.

I already tried swapping the SDA and SCL lines, but I get the exact same error.

Can somebody please share any suggestions? Where is my mistake?
Thank you! :)

EDIT:
I forgot to mention that I already found two topics relating to this issue on this forum:
viewtopic.php?f=16&t=7158&p=40718&hilit=enodev#p40718
viewtopic.php?f=6&t=6371&hilit=enodev

First one suggested reconnecting the device, while the second one suggested lowering pbs rate to 1000. I tried both, but it didn't work.

User avatar
Roberthh
Posts: 1889
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Problem getting HMC5883L to work

Post by Roberthh » Wed Mar 11, 2020 10:24 am

I had made a class for an QMC5883, and indeed the I2C address is 13 or 0x0d. So you should use that one. The script which I used is here: https://github.com/robert-hh/QMC5883

laukejas
Posts: 20
Joined: Thu May 02, 2019 5:17 pm

Re: Problem getting HMC5883L to work

Post by laukejas » Wed Mar 11, 2020 10:38 am

Roberthh wrote:
Wed Mar 11, 2020 10:24 am
I had made a class for an QMC5883, and indeed the I2C address is 13 or 0x0d. So you should use that one. The script which I used is here: https://github.com/robert-hh/QMC5883
Thank you for replying so quickly, Roberth. I tried running your code as described in github - copied the class, ran the imports, but when I try to create a I2C object with

Code: Select all

i2c = I2C(0, I2C.MASTER)
I get an error
AttributeError: type object 'I2C' has no attribute 'MASTER'
Have I missed something?

User avatar
Roberthh
Posts: 1889
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Problem getting HMC5883L to work

Post by Roberthh » Wed Mar 11, 2020 10:52 am

The example might have been for a different board, like Pycom device. You have to create the I2C object as usual, like

from machine import I2C
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)

Story behind it: You might have a QMC5883 chip instead a HMC5883 chip on your board.

laukejas
Posts: 20
Joined: Thu May 02, 2019 5:17 pm

Re: Problem getting HMC5883L to work

Post by laukejas » Wed Mar 11, 2020 11:10 am

Thank you very much, it is working now!!! But I don't exactly understand why. But how can there be a different chip? I checked the chip, and it says DB 5883 7008 on it. I am not finding much info on these numbers. Has the manufacturer of the board lied about the chip?

User avatar
Roberthh
Posts: 1889
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Problem getting HMC5883L to work

Post by Roberthh » Wed Mar 11, 2020 12:17 pm

Has the manufacturer of the board lied about the chip?
Obviously yes. It seems to be a common habit to use a QMC5883 instead HMC5883.

laukejas
Posts: 20
Joined: Thu May 02, 2019 5:17 pm

Re: Problem getting HMC5883L to work

Post by laukejas » Wed Mar 11, 2020 12:23 pm

Roberthh wrote:
Wed Mar 11, 2020 12:17 pm
Has the manufacturer of the board lied about the chip?
Obviously yes. It seems to be a common habit to use a QMC5883 instead HMC5883.
Thank you so very much for helping me solve this!!!

laukejas
Posts: 20
Joined: Thu May 02, 2019 5:17 pm

Re: Problem getting HMC5883L to work

Post by laukejas » Tue Mar 17, 2020 1:21 am

Roberth, if I may bother you a little bit more... I accidentally burned down that HMC5883L I had, and I purchased another one from a much more reputable local vendor. But with this new HMC5883L, I am getting another error when I start to initialize it. This happens both with the HMC5883L library I quoted earlier, and the QMC5883 library that you wrote. The error is:

Code: Select all

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "hmc5883l.py", line 24, in __init__
OSError: [Errno 110] ETIMEDOUT
and

Code: Select all

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "QMC5883.py", line 87, in __init__
  File "QMC5883.py", line 91, in reset
OSError: [Errno 110] ETIMEDOUT
I wired everything exactly the same as before (nothing changed, just swapped out the sensor), the code is the same (the one that worked with previous sensor). Is this a known error? Might this be yet another chip? Though I called the vendor, and he swore on all that is dear to him that this is definitely the HMC5883L. Any ideas?

P.S. I forgot to mention that i2c.scan() returns an empty array. As if the sensor is not there... But it is.

EDIT: never mind this question. Good thing I bought two of these sensors from this vendor. The other one is working just fine. Meaning the first sensor is simply faulty, hence the timeout. And the working one is QMC5883, meaning this "reputable" vendor is getting the same sensors from China and selling them at nearly 3 times the price. I'm getting my money back... Sorry for the bother.

User avatar
Roberthh
Posts: 1889
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Problem getting HMC5883L to work

Post by Roberthh » Tue Mar 17, 2020 8:29 am

The HMC5883 has the different I2C address. And it might need pull-up resistors. Are these two boards exactly identical, besides the chip?

Edit: Besides sometimes unexpected long delivery times, I never had serious getting stuff from China. I just got a delivery notice for a part ordered in December. But I got that already. Strange! I would not consider this HMC/QMC change as overly serious. The board vendors themselves do not seem to know.

laukejas
Posts: 20
Joined: Thu May 02, 2019 5:17 pm

Re: Problem getting HMC5883L to work

Post by laukejas » Tue Mar 17, 2020 4:50 pm

Roberthh wrote:
Tue Mar 17, 2020 8:29 am
The HMC5883 has the different I2C address. And it might need pull-up resistors. Are these two boards exactly identical, besides the chip?

Edit: Besides sometimes unexpected long delivery times, I never had serious getting stuff from China. I just got a delivery notice for a part ordered in December. But I got that already. Strange! I would not consider this HMC/QMC change as overly serious. The board vendors themselves do not seem to know.
Yes, both the chips I bought from this vendor are identical, and also identical to the one I bought from China. I did try adding pull-up resistors, but it didn't help the faulty sensor. I think NodeMCU already has some pull-up resistors built in on the SDA and SCL chips, at least that is what my multimeter is telling me.
In any case, it is all good. I called the vendor, he swore to me that he tested the first batch of these sensors and they worked with code meant for HMC5883L, implying that the Chinese swapped the sensors on these boards sometime later. Perhaps. In any case, I got my money back. And I still have a working sensor with QMC5883 chip on it. I'll try not to burn this one :D

Post Reply