Source code for micropython_mpl3115a2.mpl3115a2

# SPDX-FileCopyrightText: Copyright (c) 2023 Jose D. Montoya
#
# SPDX-License-Identifier: MIT
"""
`mpl3115a2`
================================================================================

MicroPython driver for the NXP MPL3115A2 Pressure and Temperature sensor


* Author(s): Jose D. Montoya


"""

import time
import struct
from micropython import const
from micropython_mpl3115a2.i2c_helpers import CBits, RegisterStruct


__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/jposada202020/MicroPython_MPL3115A2.git"

_REG_WHOAMI = const(0x0C)

_MPL3115A2_ADDRESS = const(0x60)
_REGISTER_STATUS = const(0x00)
_DATA = const(0x01)
_BAR_IN_MSB = const(0x14)
_BAR_IN_LSB = const(0x15)
_PT_DATA_CFG = const(0x13)
_CTRL_REG1 = const(0x26)
_CTRL_REG2 = const(0x27)


OS1 = const(0b000)
OS2 = const(0b001)
OS4 = const(0b010)
OS8 = const(0b011)
OS16 = const(0b100)
OS32 = const(0b101)
OS64 = const(0b110)
OS128 = const(0b111)
oversample_ratio_values = (OS1, OS2, OS4, OS8, OS16, OS32, OS64, OS128)


[docs] class MPL3115A2: """Driver for the MPL3115A2 Sensor connected over I2C. :param ~machine.I2C i2c: The I2C bus the MPL3115A2 is connected to. :param int address: The I2C device address. Defaults to :const:`0x60` :raises RuntimeError: if the sensor is not found **Quickstart: Importing and using the device** Here is an example of using the :class:`MPL3115A2` class. First you will need to import the libraries to use the sensor .. code-block:: python from machine import Pin, I2C from micropython_mpl3115a2 import mpl3115a2 Once this is done you can define your `machine.I2C` object and define your sensor object .. code-block:: python i2c = I2C(1, sda=Pin(2), scl=Pin(3)) mpl3115a2 = mpl3115a2.MPL3115A2(i2c) Now you have access to the attributes .. code-block:: python press = mpl3115a2.pressure """ _device_id = RegisterStruct(_REG_WHOAMI, "B") _device_control = RegisterStruct(_CTRL_REG1, "B") _data_config = RegisterStruct(_PT_DATA_CFG, "B") _register_status = RegisterStruct(_REGISTER_STATUS, "B") _sea_level_pressure_msb = RegisterStruct(_BAR_IN_MSB, "B") _sea_level_pressure_lsb = RegisterStruct(_BAR_IN_LSB, "B") _alt_enabled = CBits(1, _CTRL_REG1, 7) _oversample_ratio = CBits(3, _CTRL_REG1, 3) _reset_status = CBits(1, _CTRL_REG1, 2) _ost_status = CBits(1, _CTRL_REG1, 1) _pdr_status = CBits(1, _REGISTER_STATUS, 2) _tmp_status = CBits(1, _REGISTER_STATUS, 1) def __init__(self, i2c, address: int = 0x60) -> None: self._i2c = i2c self._address = address if self._device_id != 0xC4: raise RuntimeError("Failed to find MPL3115A2") self._data_config = 0b111 @property def oversample_ratio(self) -> str: """ Sensor oversample_ratio +-----------------------------+-------------------+ | Mode | Value | +=============================+===================+ | :py:const:`mpl3115a2.OS1` | :py:const:`0b000` | +-----------------------------+-------------------+ | :py:const:`mpl3115a2.OS2` | :py:const:`0b001` | +-----------------------------+-------------------+ | :py:const:`mpl3115a2.OS4` | :py:const:`0b010` | +-----------------------------+-------------------+ | :py:const:`mpl3115a2.OS8` | :py:const:`0b011` | +-----------------------------+-------------------+ | :py:const:`mpl3115a2.OS16` | :py:const:`0b100` | +-----------------------------+-------------------+ | :py:const:`mpl3115a2.OS32` | :py:const:`0b101` | +-----------------------------+-------------------+ | :py:const:`mpl3115a2.OS64` | :py:const:`0b110` | +-----------------------------+-------------------+ | :py:const:`mpl3115a2.OS128` | :py:const:`0b111` | +-----------------------------+-------------------+ """ values = ("OS1", "OS2", "OS4", "OS8", "OS16", "OS32", "OS64", "OS128") return values[self._oversample_ratio] @oversample_ratio.setter def oversample_ratio(self, value: int) -> None: if value not in oversample_ratio_values: raise ValueError("Value must be a valid oversample_ratio setting") self._oversample_ratio = value @property def pressure(self) -> float: """ Read the barometric pressure detected by the sensor in Hectopascals. """ data = bytearray(5) self._poll_reg1() self._alt_enabled = 0 self._ost_status = 1 # Set OST to 1 to start measurement. while self._pdr_status == 0: time.sleep(0.01) self._i2c.readfrom_mem_into(self._address, _DATA, data) pressure = ((data[0] << 16) | (data[1] << 8) | data[2]) & 0xFFFFFF pressure >>= 4 return pressure / 400.0 def _poll_reg1(self) -> None: """ Poll the ost_status to NOT be present. """ while self._ost_status > 0: time.sleep(0.01) @property def altitude(self) -> float: """Read the altitude as calculated based on the sensor pressure and previously configured pressure at sea-level. This will return a value in meters. Set the sea-level pressure by updating the :attr:`sealevel_pressure` property first to get a more accurate altitude value. """ data = bytearray(5) self._poll_reg1() self._alt_enabled = 1 self._ost_status = 1 while self._pdr_status == 0: time.sleep(0.01) self._i2c.readfrom_mem_into(self._address, _DATA, data) data[3] = 0 altitude = struct.unpack(">i", data[0:4])[0] return altitude / 65535.0 @property def temperature(self) -> float: """ Read the temperature as measured by the sensor in Celsius. """ data = bytearray(5) self._poll_reg1() self._ost_status = 1 while self._tmp_status == 0: time.sleep(0.01) self._i2c.readfrom_mem_into(self._address, _DATA, data) temperature = struct.unpack(">h", data[3:5])[0] temperature >>= 4 return temperature / 16.0 @property def sealevel_pressure(self) -> float: """ Read and write the pressure at sea-level used to calculate altitude. """ pressure = (self._sea_level_pressure_msb << 8) | self._sea_level_pressure_lsb return pressure * 2.0 / 100 @sealevel_pressure.setter def sealevel_pressure(self, val: float) -> None: bars = int(val * 50) self._sea_level_pressure_lsb = bars & 0xFF self._sea_level_pressure_msb = bars >> 8