Source code for adafruit_lis2mdl

# SPDX-FileCopyrightText: 2019 Bryan Siepert for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""
`adafruit_lis2mdl`
====================================================


CircuitPython driver for the LIS2MDL 3-axis magnetometer.

* Author(s): Bryan Siepert

Implementation Notes
--------------------

**Hardware:**

* Adafruit `Triple-axis Accelerometer+Magnetometer (Compass) Board - LSM303
  <https://www.adafruit.com/product/1120>`_ (Product ID: 1120)
* Adafruit `FLORA Accelerometer/Compass Sensor - LSM303 - v1.0
  <https://www.adafruit.com/product/1247>`_ (Product ID: 1247)

**Software and Dependencies:**

* Adafruit CircuitPython firmware for the supported boards:
  https://circuitpython.org/downloads
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
* Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
"""

from time import sleep
from micropython import const
from adafruit_bus_device.i2c_device import I2CDevice
from adafruit_register.i2c_struct import UnaryStruct, ROUnaryStruct
from adafruit_register.i2c_bit import RWBit
from adafruit_register.i2c_bits import RWBits


__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_LIS2MDL.git"

_ADDRESS_MAG = const(0x1E)  # (0x3C >> 1)       // 0011110x


MAG_DEVICE_ID = 0b01000000


[docs]class DataRate: # pylint: disable=too-few-public-methods """Data rate choices to set using `data_rate`""" Rate_10_HZ = const(0x00) """10 Hz""" Rate_20_HZ = const(0x01) """20 Hz""" Rate_50_HZ = const(0x02) """50 Hz""" Rate_100_HZ = const(0x03) """100 Hz"""
# Magnetometer registers OFFSET_X_REG_L = 0x45 OFFSET_X_REG_H = 0x46 OFFSET_Y_REG_L = 0x47 OFFSET_Y_REG_H = 0x48 OFFSET_Z_REG_L = 0x49 OFFSET_Z_REG_H = 0x4A WHO_AM_I = 0x4F CFG_REG_A = 0x60 CFG_REG_B = 0x61 CFG_REG_C = 0x62 INT_CRTL_REG = 0x63 INT_SOURCE_REG = 0x64 INT_THS_L_REG = 0x65 STATUS_REG = 0x67 OUTX_L_REG = 0x68 OUTX_H_REG = 0x69 OUTY_L_REG = 0x6A OUTY_H_REG = 0x6B OUTZ_L_REG = 0x6C OUTZ_H_REG = 0x6D _MAG_SCALE = 0.15 # 1.5 milligauss/LSB * 0.1 microtesla/milligauss
[docs]class LIS2MDL: # pylint: disable=too-many-instance-attributes """ Driver for the LIS2MDL 3-axis magnetometer. :param ~busio.I2C i2c: The I2C bus the device is connected to **Quickstart: Importing and using the device** Here is an example of using the :class:`LIS2MDL` class. First you will need to import the libraries to use the sensor .. code-block:: python import board import adafruit_lis2mdl Once this is done you can define your `board.I2C` object and define your sensor object .. code-block:: python i2c = board.I2C() # uses board.SCL and board.SDA sensor = adafruit_lis2mdl.LIS2MDL(i2c) Now you have access to the :attr:`magnetic` attribute .. code-block:: python mag_x, mag_y, mag_z = sensor.magnetic """ _BUFFER = bytearray(6) _device_id = ROUnaryStruct(WHO_AM_I, "B") _int_control = UnaryStruct(INT_CRTL_REG, "B") _mode = RWBits(2, CFG_REG_A, 0, 1) _data_rate = RWBits(2, CFG_REG_A, 2, 1) _temp_comp = RWBit(CFG_REG_A, 7, 1) _reboot = RWBit(CFG_REG_A, 6, 1) _soft_reset = RWBit(CFG_REG_A, 5, 1) _bdu = RWBit(CFG_REG_C, 4, 1) _int_iron_off = RWBit(CFG_REG_B, 3, 1) _x_offset = UnaryStruct(OFFSET_X_REG_L, "<h") _y_offset = UnaryStruct(OFFSET_Y_REG_L, "<h") _z_offset = UnaryStruct(OFFSET_Z_REG_L, "<h") _interrupt_pin_putput = RWBit(CFG_REG_C, 6, 1) _interrupt_threshold = UnaryStruct(INT_THS_L_REG, "<h") _x_int_enable = RWBit(INT_CRTL_REG, 7, 1) _y_int_enable = RWBit(INT_CRTL_REG, 6, 1) _z_int_enable = RWBit(INT_CRTL_REG, 5, 1) _int_reg_polarity = RWBit(INT_CRTL_REG, 2, 1) _int_latched = RWBit(INT_CRTL_REG, 1, 1) _int_enable = RWBit(INT_CRTL_REG, 0, 1) _int_source = ROUnaryStruct(INT_SOURCE_REG, "B") low_power = RWBit(CFG_REG_A, 4, 1) """Enables and disables low power mode""" _raw_x = ROUnaryStruct(OUTX_L_REG, "<h") _raw_y = ROUnaryStruct(OUTY_L_REG, "<h") _raw_z = ROUnaryStruct(OUTZ_L_REG, "<h") _x_offset = UnaryStruct(OFFSET_X_REG_L, "<h") _y_offset = UnaryStruct(OFFSET_Y_REG_L, "<h") _z_offset = UnaryStruct(OFFSET_Z_REG_L, "<h") def __init__(self, i2c): self.i2c_device = I2CDevice(i2c, _ADDRESS_MAG) if self._device_id != 0x40: raise AttributeError("Cannot find an LIS2MDL") self.reset()
[docs] def reset(self): """Reset the sensor to the default state set by the library""" self._soft_reset = True sleep(0.100) self._reboot = True sleep(0.100) self._mode = 0x00 self._bdu = True # Make sure high and low bytes are set together self._int_latched = True self._int_reg_polarity = True self._int_iron_off = False self._interrupt_pin_putput = True self._temp_comp = True sleep(0.030) # sleep 20ms to allow measurements to stabilize
@property def magnetic(self): """The processed magnetometer sensor values. A 3-tuple of X, Y, Z axis values in microteslas that are signed floats. """ return ( self._raw_x * _MAG_SCALE, self._raw_y * _MAG_SCALE, self._raw_z * _MAG_SCALE, ) @property def data_rate(self): """The magnetometer update rate.""" return self._data_rate @data_rate.setter def data_rate(self, value): if not value in ( DataRate.Rate_10_HZ, DataRate.Rate_20_HZ, DataRate.Rate_50_HZ, DataRate.Rate_100_HZ, ): raise ValueError("data_rate must be a `DataRate`") self._data_rate = value @property def interrupt_threshold(self): """The threshold (in microteslas) for magnetometer interrupt generation. Given value is compared against all axes in both the positive and negative direction""" return self._interrupt_threshold * _MAG_SCALE @interrupt_threshold.setter def interrupt_threshold(self, value): if value < 0: value = -value self._interrupt_threshold = int(value / _MAG_SCALE) @property def interrupt_enabled(self): """Enable or disable the magnetometer interrupt""" return self._int_enable @interrupt_enabled.setter def interrupt_enabled(self, val): self._x_int_enable = val self._y_int_enable = val self._z_int_enable = val self._int_enable = val @property def faults(self): """A tuple representing interrupts on each axis in a positive and negative direction ``(x_hi, y_hi, z_hi, x_low, y_low, z_low, int_triggered)``""" int_status = self._int_source x_hi = (int_status & 0b10000000) > 0 y_hi = int_status & 0b01000000 > 0 z_hi = int_status & 0b00100000 > 0 x_low = int_status & 0b00010000 > 0 y_low = int_status & 0b00001000 > 0 z_low = int_status & 0b00000100 > 0 int_triggered = int_status & 0b1 > 0 return (x_hi, y_hi, z_hi, x_low, y_low, z_low, int_triggered) @property def x_offset(self): """An offset for the X-Axis to subtract from the measured value to correct for magnetic interference""" return self._x_offset * _MAG_SCALE @x_offset.setter def x_offset(self, value): self._x_offset = int(value / _MAG_SCALE) @property def y_offset(self): """An offset for the Y-Axis to subtract from the measured value to correct for magnetic interference""" return self._y_offset * _MAG_SCALE @y_offset.setter def y_offset(self, value): self._y_offset = int(value / _MAG_SCALE) @property def z_offset(self): """An offset for the Z-Axis to subtract from the measured value to correct for magnetic interference""" return self._z_offset * _MAG_SCALE @z_offset.setter def z_offset(self, value): self._z_offset = int(value / _MAG_SCALE)