Skip to content

Commit

Permalink
Merge pull request #15 from jposada202020/light_class
Browse files Browse the repository at this point in the history
memory_reduction
  • Loading branch information
FoamyGuy authored Jan 7, 2022
2 parents 659ca5f + f2464bb commit 6398fd4
Show file tree
Hide file tree
Showing 11 changed files with 410 additions and 215 deletions.
49 changes: 34 additions & 15 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ Introduction
:target: https://github.com/adafruit/Adafruit_CircuitPython_DPS310/actions
:alt: Build Status

.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
:alt: Code Style: Black

Library for the DPS310 Precision Barometric Pressure Sensor


Expand Down Expand Up @@ -53,41 +57,56 @@ To install in a virtual environment in your current project:
source .env/bin/activate
pip3 install adafruit-circuitpython-dps310
Installing to a connected CircuitPython Device
==============================================
Some devices, eg. the QT-PY, are very limited in memory. The DPS310 library contains
two variants - basic and advanced - which give different levels of functionality.

Installing the DPS310 library could have the following outcomes:

* It installs successfully and your code runs successfully. Woo-hoo! Continue with
your amazing project.
* It installs successfully and your code fails to run with a memory allocation
error. Try one of the following:

* If your ``code.py`` is large, especially if it has lots of comments, you
can shrink it into a ``.mpy`` file instead. See the Adafruit
`Learn Guide <https://learn.adafruit.com/Memory-saving-tips-for-CircuitPython/non-volatile-not-enough-disk-space>`_
on shrinking your code.
* Only use the basic DPS310 implementation, and remove the following file:
``<CIRCUITPY>/lib/adafruit_dps310/advanced.mpy`` where <CIRCUITPY> is the
mounted location of your device. Make sure that your code only uses the basic
implementation.


Usage Example
=============

.. code-block:: python3
import time
import board
import adafruit_dps310
from adafruit_dps310.basic import DPS310
i2c = board.I2C() # uses board.SCL and board.SDA
dps310 = adafruit_dps310.DPS310(i2c)
dps310 = DPS310(i2c)
while True:
print("Temperature = %.2f *C"%dps310.temperature)
print("Pressure = %.2f hPa"%dps310.pressure)
print("")
time.sleep(1.0)
Caveat: by default the library initializes the IC with constant temperature and pressure measurements at 64Hz with 64 samples. It is not possible to change the IC's mode, temperature_oversample_count or pressure_oversample_count on-the-fly so resetting the IC and operation parameteres is required. For instance, to set the mode to continuous pressure measurement at 1Hz with 2 samples:

.. code-block:: python3
dps310.reset()
dps310.pressure_oversample_count = adafruit_dps310.SampleCount.COUNT_2
dps310.pressure_rate = adafruit_dps310.Rate.RATE_1_HZ
dps310.mode = adafruit_dps310.Mode.CONT_PRESSURE
dps310.wait_pressure_ready()
Known Issues
============
Library extensive features might not be compatible with memory limited boards. Library might not
load in SAMD21 boards and others with 32KB of RAM or less.
Library extensive features might not be compatible with memory limited boards. For these kind of
boards you need to use the ``adafruit_dps310/basic.mpy``, the file needs to be in the ``mpy``
format in order to fit in memory.
For boards with more memory available you could use the code present
in ``adafruit_dps310/advanced.py``. For usage refer to ``dps310_simpletest_advanced.py``


Documentation
Expand Down
Empty file added adafruit_dps310/__init__.py
Empty file.
214 changes: 28 additions & 186 deletions adafruit_dps310.py → adafruit_dps310/advanced.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
# SPDX-License-Identifier: MIT

"""
`adafruit_dps310`
`adafruit_dps310.advanced`
================================================================================
Library for the DPS310 Precision Barometric Pressure Sensor
Library for the DPS310 Precision Barometric Pressure Sensor. This is the advanced
version. Includes some features not present in `adafruit_dps310.basic`
* Author(s): Bryan Siepert
* Author(s): Bryan Siepert, Jose David M.
Implementation Notes
--------------------
Expand All @@ -34,26 +35,10 @@
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DPS310.git"

# Common imports; remove if unused or pylint will complain
import math
from time import sleep
from adafruit_bus_device import i2c_device
from adafruit_register.i2c_struct import UnaryStruct, ROUnaryStruct
from adafruit_register.i2c_bit import RWBit, ROBit
from adafruit_register.i2c_bits import RWBits, ROBits

_DPS310_DEFAULT_ADDRESS = 0x77 # DPS310 default i2c address
_DPS310_DEVICE_ID = 0x10 # DPS310 device identifier

_DPS310_PRSB2 = 0x00 # Highest byte of pressure data
_DPS310_TMPB2 = 0x03 # Highest byte of temperature data
_DPS310_PRSCFG = 0x06 # Pressure configuration
_DPS310_TMPCFG = 0x07 # Temperature configuration
_DPS310_MEASCFG = 0x08 # Sensor configuration
_DPS310_CFGREG = 0x09 # Interrupt/FIFO configuration
_DPS310_RESET = 0x0C # Soft reset
_DPS310_PRODREVID = 0x0D # Register that contains the part ID
_DPS310_TMPCOEFSRCE = 0x28 # Temperature calibration src
from micropython import const
from adafruit_register.i2c_bits import RWBits
from adafruit_dps310.basic import DPS310

# pylint: disable=no-member,unnecessary-pass

Expand Down Expand Up @@ -159,29 +144,45 @@ class SampleCount(CV):
)
)
# pylint: enable=unnecessary-pass
class DPS310:

_DPS310_DEFAULT_ADDRESS = const(0x77) # DPS310 default i2c address
# _DPS310_DEVICE_ID = const(0x10) # DPS310 device identifier

# _DPS310_PRSB2 = const(0x00) # Highest byte of pressure data
# _DPS310_TMPB2 = const(0x03) # Highest byte of temperature data
_DPS310_PRSCFG = const(0x06) # Pressure configuration
_DPS310_TMPCFG = const(0x07) # Temperature configuration
# _DPS310_MEASCFG = const(0x08) # Sensor configuration
# _DPS310_CFGREG = const(0x09) # Interrupt/FIFO configuration
# _DPS310_RESET = const(0x0C) # Soft reset
# _DPS310_PRODREVID = const(0x0D) # Register that contains the part ID
# _DPS310_TMPCOEFSRCE = const(0x28) # Temperature calibration src


class DPS310_Advanced(DPS310):
# pylint: disable=too-many-instance-attributes
"""Library for the DPS310 Precision Barometric Pressure Sensor.
This class contains some of other configurable features
:param ~busio.I2C i2c_bus: The I2C bus the DPS310 is connected to.
:param int address: The I2C device address. Defaults to :const:`0x77`
**Quickstart: Importing and using the DPS310**
Here is an example of using the :class:`DPS310` class.
Here is an example of using the :class:`DPS310_Advanced` class.
First you will need to import the libraries to use the sensor
.. code-block:: python
import board
import adafruit_dps310
from adafruit_dps310.dps310_advanced import DPS310_Advanced as DPS310
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
dps310 = adafruit_dps310.DPS310(i2c)
dps310 = DPS310(i2c)
Now you have access to the :attr:`temperature` and :attr:`pressure` attributes.
Expand All @@ -192,66 +193,11 @@ class DPS310:
"""
# Register definitions
_device_id = ROUnaryStruct(_DPS310_PRODREVID, ">B")
_reset_register = UnaryStruct(_DPS310_RESET, ">B")
_mode_bits = RWBits(3, _DPS310_MEASCFG, 0)

_pressure_ratebits = RWBits(3, _DPS310_PRSCFG, 4)
_pressure_osbits = RWBits(4, _DPS310_PRSCFG, 0)

_temp_ratebits = RWBits(3, _DPS310_TMPCFG, 4)
_temp_osbits = RWBits(4, _DPS310_TMPCFG, 0)

_temp_measurement_src_bit = RWBit(_DPS310_TMPCFG, 7)

_pressure_shiftbit = RWBit(_DPS310_CFGREG, 2)
_temp_shiftbit = RWBit(_DPS310_CFGREG, 3)

_coefficients_ready = RWBit(_DPS310_MEASCFG, 7)
_sensor_ready = RWBit(_DPS310_MEASCFG, 6)
_temp_ready = RWBit(_DPS310_MEASCFG, 5)
_pressure_ready = RWBit(_DPS310_MEASCFG, 4)

_raw_pressure = ROBits(24, _DPS310_PRSB2, 0, 3, lsb_first=False)
_raw_temperature = ROBits(24, _DPS310_TMPB2, 0, 3, lsb_first=False)

_calib_coeff_temp_src_bit = ROBit(_DPS310_TMPCOEFSRCE, 7)

_reg0e = RWBits(8, 0x0E, 0)
_reg0f = RWBits(8, 0x0F, 0)
_reg62 = RWBits(8, 0x62, 0)

def __init__(self, i2c_bus, address=_DPS310_DEFAULT_ADDRESS):
self.i2c_device = i2c_device.I2CDevice(i2c_bus, address)

if self._device_id != _DPS310_DEVICE_ID:
raise RuntimeError("Failed to find DPS310 - check your wiring!")
self._pressure_scale = None
self._temp_scale = None
self._c0 = None
self._c1 = None
self._c00 = None
self._c00 = None
self._c10 = None
self._c10 = None
self._c01 = None
self._c11 = None
self._c20 = None
self._c21 = None
self._c30 = None
self._oversample_scalefactor = (
524288,
1572864,
3670016,
7864320,
253952,
516096,
1040384,
2088960,
)
self.sea_level_pressure = 1013.25
"""Pressure in hectoPascals at sea level. Used to calibrate :attr:`altitude`."""
self.initialize()
super().__init__(i2c_bus, _DPS310_DEFAULT_ADDRESS)

def initialize(self):
"""Initialize the sensor to continuous measurement"""
Expand All @@ -268,69 +214,6 @@ def initialize(self):
self.wait_temperature_ready()
self.wait_pressure_ready()

# (https://github.com/Infineon/DPS310-Pressure-Sensor#temperature-measurement-issue)
# similar to DpsClass::correctTemp(void) from infineon's c++ library
def _correct_temp(self):
"""Correct temperature readings on ICs with a fuse bit problem"""
self._reg0e = 0xA5
self._reg0f = 0x96
self._reg62 = 0x02
self._reg0e = 0
self._reg0f = 0

# perform a temperature measurement
# the most recent temperature will be saved internally
# and used for compensation when calculating pressure
_unused = self._raw_temperature

def reset(self):
"""Reset the sensor"""
self._reset_register = 0x89
# wait for hardware reset to finish
sleep(0.010)
while not self._sensor_ready:
sleep(0.001)
self._correct_temp()
self._read_calibration()
# make sure we're using the temperature source used for calibration
self._temp_measurement_src_bit = self._calib_coeff_temp_src_bit

@property
def pressure(self):
"""Returns the current pressure reading in hPA"""

temp_reading = self._raw_temperature
raw_temperature = self._twos_complement(temp_reading, 24)
pressure_reading = self._raw_pressure
raw_pressure = self._twos_complement(pressure_reading, 24)
_scaled_rawtemp = raw_temperature / self._temp_scale

_temperature = _scaled_rawtemp * self._c1 + self._c0 / 2.0

p_red = raw_pressure / self._pressure_scale

pres_calc = (
self._c00
+ p_red * (self._c10 + p_red * (self._c20 + p_red * self._c30))
+ _scaled_rawtemp * (self._c01 + p_red * (self._c11 + p_red * self._c21))
)

final_pressure = pres_calc / 100
return final_pressure

@property
def altitude(self):
"""The altitude based on the sea level pressure (:attr:`sea_level_pressure`) -
which you must enter ahead of time)"""
return 44330 * (1.0 - math.pow(self.pressure / self.sea_level_pressure, 0.1903))

@property
def temperature(self):
"""The current temperature reading in degrees Celsius"""
_scaled_rawtemp = self._raw_temperature / self._temp_scale
_temperature = _scaled_rawtemp * self._c1 + self._c0 / 2.0
return _temperature

@property
def temperature_ready(self):
"""Returns true if there is a temperature reading ready"""
Expand Down Expand Up @@ -434,44 +317,3 @@ def temperature_oversample_count(self, value):
self._temp_osbits = value
self._temp_scale = self._oversample_scalefactor[value]
self._temp_shiftbit = value > SampleCount.COUNT_8

@staticmethod
def _twos_complement(val, bits):
if val & (1 << (bits - 1)):
val -= 1 << bits

return val

def _read_calibration(self):

while not self._coefficients_ready:
sleep(0.001)

buffer = bytearray(19)
coeffs = [None] * 18
for offset in range(18):
buffer = bytearray(2)
buffer[0] = 0x10 + offset

with self.i2c_device as i2c:

i2c.write_then_readinto(buffer, buffer, out_end=1, in_start=1)

coeffs[offset] = buffer[1]

self._c0 = (coeffs[0] << 4) | ((coeffs[1] >> 4) & 0x0F)
self._c0 = self._twos_complement(self._c0, 12)

self._c1 = self._twos_complement(((coeffs[1] & 0x0F) << 8) | coeffs[2], 12)

self._c00 = (coeffs[3] << 12) | (coeffs[4] << 4) | ((coeffs[5] >> 4) & 0x0F)
self._c00 = self._twos_complement(self._c00, 20)

self._c10 = ((coeffs[5] & 0x0F) << 16) | (coeffs[6] << 8) | coeffs[7]
self._c10 = self._twos_complement(self._c10, 20)

self._c01 = self._twos_complement((coeffs[8] << 8) | coeffs[9], 16)
self._c11 = self._twos_complement((coeffs[10] << 8) | coeffs[11], 16)
self._c20 = self._twos_complement((coeffs[12] << 8) | coeffs[13], 16)
self._c21 = self._twos_complement((coeffs[14] << 8) | coeffs[15], 16)
self._c30 = self._twos_complement((coeffs[16] << 8) | coeffs[17], 16)
Loading

0 comments on commit 6398fd4

Please sign in to comment.