/ adafruit_pcf8591 / pcf8591.py
pcf8591.py
  1  # SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
  2  # SPDX-FileCopyrightText: Copyright (c) 2020 Bryan Siepert for Adafruit Industries
  3  #
  4  # SPDX-License-Identifier: MIT
  5  """
  6  `pcf8591`
  7  ================================================================================
  8  
  9  ADC+DAC Combo
 10  
 11  * Author(s): Bryan Siepert
 12  
 13  Implementation Notes
 14  --------------------
 15  
 16  **Hardware:**
 17  
 18  * `Adafruit PCF8591 Breakout <https://www.adafruit.com/products/45XX>`_
 19  
 20  **Software and Dependencies:**
 21  
 22  * Adafruit CircuitPython firmware for the supported boards:
 23    https://github.com/adafruit/circuitpython/releases
 24  
 25   * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
 26   * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
 27  """
 28  
 29  __version__ = "0.0.0-auto.0"
 30  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PCF8591.git"
 31  # from time import sleep
 32  from struct import unpack_from
 33  from micropython import const
 34  import adafruit_bus_device.i2c_device as i2c_device
 35  
 36  _PCF8591_DEFAULT_ADDR = const(0x48)  # PCF8591 Default Address
 37  _PCF8591_ENABLE_DAC = const(0x40)  # control bit for having the DAC active
 38  
 39  # Pin constants
 40  A0 = const(0)
 41  A1 = const(1)
 42  A2 = const(2)
 43  A3 = const(3)
 44  
 45  OUT = const(0)
 46  
 47  
 48  class PCF8591:
 49      """Driver for the PCF8591 DAC & ADC Combo breakout.
 50  
 51      :param ~busio.I2C i2c_bus: The I2C bus the PCF8591 is connected to.
 52      :param address: The I2C device address for the sensor. Default is ``0x28``.
 53  
 54      """
 55  
 56      def __init__(self, i2c_bus, address=_PCF8591_DEFAULT_ADDR, reference_voltage=3.3):
 57          self.i2c_device = i2c_device.I2CDevice(i2c_bus, address)
 58          self._dacval = 0
 59          self._dac_enabled = False
 60          # this is the range supported by the PCF8591
 61          if 2.5 <= reference_voltage <= 6.0:
 62              self._reference_voltage = reference_voltage
 63          else:
 64              raise ValueError("reference_voltage must be from 2.5 - 6.0")
 65          self._buffer = bytearray(2)
 66          print("self.reference_voltage = ", self.reference_voltage)
 67          # possibly measure each channel here to prep readings for
 68          # user calls to `read`
 69  
 70      @property
 71      def reference_voltage(self):
 72          """The voltage level that ADC signals are compared to.
 73          An ADC value of 65535 will equal `reference_voltage`"""
 74          return self._reference_voltage
 75  
 76      def _half_read(self, channel):
 77          if self._dac_enabled:
 78              self._buffer[0] = _PCF8591_ENABLE_DAC
 79              self._buffer[1] = self._dacval
 80          else:
 81              self._buffer[0] = 0
 82              self._buffer[1] = 0
 83  
 84          self._buffer[0] |= channel & 0x3
 85  
 86          with self.i2c_device as i2c:
 87              i2c.write_then_readinto(self._buffer, self._buffer)
 88  
 89      def read(self, channel):
 90          """Read an analog value from one of the four ADC inputs
 91  
 92            param: :channel The single-ended ADC channel to read from, 0 thru 3
 93          """
 94          if channel < 0 or channel > 3:
 95              raise ValueError("channel must be from 0-3")
 96          # reads are started on the ACK of the WRITE to the 'register' and
 97          # not returned until the read after the _next_ WRITE so we have to
 98          # do it twice to get the actual value
 99          self._half_read(channel)
100          self._half_read(channel)
101  
102          return unpack_from(">B", self._buffer[1:])[0]
103  
104      @property
105      def dac_enabled(self):
106          """ Enables the DAC when True, or sets it to tri-state / high-Z when False"""
107          return self._dac_enabled
108  
109      @dac_enabled.setter
110      def dac_enabled(self, enable_dac):
111  
112          self._dac_enabled = enable_dac
113          self.write(self._dacval)
114  
115      def write(self, value):
116          """Writes a uint8_t value to the DAC output
117  
118        param: :output The value to write: 0 is GND and 65535 is VCC
119  
120        """
121  
122          self._buffer = bytearray(2)
123          if self._dac_enabled:
124              self._buffer[0] = _PCF8591_ENABLE_DAC
125              self._buffer[1] = value
126          self._dacval = value
127          with self.i2c_device as i2c:
128              i2c.write_then_readinto(self._buffer, self._buffer)