Source code for adafruit_fxos8700

# The MIT License (MIT)
#
# Copyright (c) 2017 Tony DiCola for Adafruit Industries
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_fxos8700`
====================================================

CircuitPython module for the NXP FXOS8700 accelerometer and magnetometer.
Based on the driver from: https://github.com/adafruit/Adafruit_FXOS8700

See examples/simpletest.py for a demo of the usage.

* Author(s): Tony DiCola

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

**Hardware:**

*  Adafruit `Precision NXP 9-DOF Breakout Board - FXOS8700 + FXAS21002
   <https://www.adafruit.com/product/3463>`_ (Product ID: 3463)

**Software and Dependencies:**

* Adafruit CircuitPython firmware (2.2.0+) for the ESP8622 and M0-based boards:
  https://github.com/adafruit/circuitpython/releases

* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
"""
try:
    import ustruct as struct
except ImportError:
    import struct

import adafruit_bus_device.i2c_device as i2c_dev
from micropython import const

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

# Register addresses and other constants:
# pylint: disable=bad-whitespace
_FXOS8700_ADDRESS = const(0x1F)  # 0011111
_FXOS8700_ID = const(0xC7)  # 1100 0111
_FXOS8700_REGISTER_STATUS = const(0x00)
_FXOS8700_REGISTER_OUT_X_MSB = const(0x01)
_FXOS8700_REGISTER_OUT_X_LSB = const(0x02)
_FXOS8700_REGISTER_OUT_Y_MSB = const(0x03)
_FXOS8700_REGISTER_OUT_Y_LSB = const(0x04)
_FXOS8700_REGISTER_OUT_Z_MSB = const(0x05)
_FXOS8700_REGISTER_OUT_Z_LSB = const(0x06)
_FXOS8700_REGISTER_WHO_AM_I = const(0x0D)  # 11000111   r
_FXOS8700_REGISTER_XYZ_DATA_CFG = const(0x0E)
_FXOS8700_REGISTER_CTRL_REG1 = const(0x2A)  # 00000000   r/w
_FXOS8700_REGISTER_CTRL_REG2 = const(0x2B)  # 00000000   r/w
_FXOS8700_REGISTER_CTRL_REG3 = const(0x2C)  # 00000000   r/w
_FXOS8700_REGISTER_CTRL_REG4 = const(0x2D)  # 00000000   r/w
_FXOS8700_REGISTER_CTRL_REG5 = const(0x2E)  # 00000000   r/w
_FXOS8700_REGISTER_MSTATUS = const(0x32)
_FXOS8700_REGISTER_MOUT_X_MSB = const(0x33)
_FXOS8700_REGISTER_MOUT_X_LSB = const(0x34)
_FXOS8700_REGISTER_MOUT_Y_MSB = const(0x35)
_FXOS8700_REGISTER_MOUT_Y_LSB = const(0x36)
_FXOS8700_REGISTER_MOUT_Z_MSB = const(0x37)
_FXOS8700_REGISTER_MOUT_Z_LSB = const(0x38)
_FXOS8700_REGISTER_MCTRL_REG1 = const(0x5B)  # 00000000   r/w
_FXOS8700_REGISTER_MCTRL_REG2 = const(0x5C)  # 00000000   r/w
_FXOS8700_REGISTER_MCTRL_REG3 = const(0x5D)  # 00000000   r/w
_ACCEL_MG_LSB_2G = 0.000244
_ACCEL_MG_LSB_4G = 0.000488
_ACCEL_MG_LSB_8G = 0.000976
_MAG_UT_LSB = 0.1
_SENSORS_GRAVITY_STANDARD = 9.80665
# pylint: enable=bad-whitespace

# User-facing constants/module-level globals:
ACCEL_RANGE_2G = 0x00
ACCEL_RANGE_4G = 0x01
ACCEL_RANGE_8G = 0x02


def _twos_comp(val, bits):
    # Convert an unsigned integer in 2's compliment form of the specified bit
    # length to its signed integer value and return it.
    if val & (1 << (bits - 1)) != 0:
        return val - (1 << bits)
    return val


[docs]class FXOS8700: """Driver for the NXP FXOS8700 accelerometer and magnetometer.""" # Class-level buffer for reading and writing data with the sensor. # This reduces memory allocations but means the code is not re-entrant or # thread safe! _BUFFER = bytearray(13) def __init__(self, i2c, address=_FXOS8700_ADDRESS, accel_range=ACCEL_RANGE_2G): assert accel_range in (ACCEL_RANGE_2G, ACCEL_RANGE_4G, ACCEL_RANGE_8G) self._accel_range = accel_range self._device = i2c_dev.I2CDevice(i2c, address) # Check for chip ID value. if self._read_u8(_FXOS8700_REGISTER_WHO_AM_I) != _FXOS8700_ID: raise RuntimeError("Failed to find FXOS8700, check wiring!") # Set to standby mode (required to make changes to this register) self._write_u8(_FXOS8700_REGISTER_CTRL_REG1, 0) if accel_range == ACCEL_RANGE_2G: self._write_u8(_FXOS8700_REGISTER_XYZ_DATA_CFG, 0x00) elif accel_range == ACCEL_RANGE_4G: self._write_u8(_FXOS8700_REGISTER_XYZ_DATA_CFG, 0x01) elif accel_range == ACCEL_RANGE_8G: self._write_u8(_FXOS8700_REGISTER_XYZ_DATA_CFG, 0x02) # High resolution self._write_u8(_FXOS8700_REGISTER_CTRL_REG2, 0x02) # Active, Normal Mode, Low Noise, 100Hz in Hybrid Mode self._write_u8(_FXOS8700_REGISTER_CTRL_REG1, 0x15) # Configure the magnetometer # Hybrid Mode, Over Sampling Rate = 16 self._write_u8(_FXOS8700_REGISTER_MCTRL_REG1, 0x1F) # Jump to reg 0x33 after reading 0x06 self._write_u8(_FXOS8700_REGISTER_MCTRL_REG2, 0x20) def _read_u8(self, address): # Read an 8-bit unsigned value from the specified 8-bit address. with self._device as i2c: self._BUFFER[0] = address & 0xFF i2c.write_then_readinto(self._BUFFER, self._BUFFER, out_end=1, in_end=1) return self._BUFFER[0] def _write_u8(self, address, val): # Write an 8-bit unsigned value to the specified 8-bit address. with self._device as i2c: self._BUFFER[0] = address & 0xFF self._BUFFER[1] = val & 0xFF i2c.write(self._BUFFER, end=2)
[docs] def read_raw_accel_mag(self): """Read the raw accelerometer and magnetometer readings. Returns a 2-tuple of 3-tuples: - Accelerometer X, Y, Z axis 14-bit signed raw values - Magnetometer X, Y, Z axis 16-bit signed raw values If you want the acceleration or magnetometer values in friendly units consider using the accelerometer and magnetometer properties! """ # Read accelerometer data from sensor. with self._device as i2c: self._BUFFER[0] = _FXOS8700_REGISTER_OUT_X_MSB i2c.write_then_readinto(self._BUFFER, self._BUFFER, out_end=1, in_end=6) accel_raw_x = struct.unpack_from(">H", self._BUFFER[0:2])[0] accel_raw_y = struct.unpack_from(">H", self._BUFFER[2:4])[0] accel_raw_z = struct.unpack_from(">H", self._BUFFER[4:6])[0] # Convert accelerometer data to signed 14-bit value from 16-bit # left aligned 2's compliment value. accel_raw_x = _twos_comp(accel_raw_x >> 2, 14) accel_raw_y = _twos_comp(accel_raw_y >> 2, 14) accel_raw_z = _twos_comp(accel_raw_z >> 2, 14) # Read magnetometer data from sensor. No need to convert as this is # 16-bit signed data so struct parsing can handle it directly. with self._device as i2c: self._BUFFER[0] = _FXOS8700_REGISTER_MOUT_X_MSB i2c.write_then_readinto(self._BUFFER, self._BUFFER, out_end=1, in_end=6) mag_raw_x = struct.unpack_from(">h", self._BUFFER[0:2])[0] mag_raw_y = struct.unpack_from(">h", self._BUFFER[2:4])[0] mag_raw_z = struct.unpack_from(">h", self._BUFFER[4:6])[0] return ( (accel_raw_x, accel_raw_y, accel_raw_z), (mag_raw_x, mag_raw_y, mag_raw_z), )
@property def accelerometer(self): """Read the acceleration from the accelerometer and return its X, Y, Z axis values as a 3-tuple in m/s^2. """ accel_raw, _ = self.read_raw_accel_mag() # Convert accel values to m/s^2 factor = 0 if self._accel_range == ACCEL_RANGE_2G: factor = _ACCEL_MG_LSB_2G elif self._accel_range == ACCEL_RANGE_4G: factor = _ACCEL_MG_LSB_4G elif self._accel_range == ACCEL_RANGE_8G: factor = _ACCEL_MG_LSB_8G return [x * factor * _SENSORS_GRAVITY_STANDARD for x in accel_raw] @property def magnetometer(self): """Read the magnetometer values and return its X, Y, Z axis values as a 3-tuple in uTeslas. """ _, mag_raw = self.read_raw_accel_mag() # Convert mag values to uTesla return [x * _MAG_UT_LSB for x in mag_raw]