/ adafruit_ina260.py
adafruit_ina260.py
  1  # The MIT License (MIT)
  2  #
  3  # Copyright (c) 2019 Bryan Siepert for Adafruit Industries
  4  #
  5  # Permission is hereby granted, free of charge, to any person obtaining a copy
  6  # of this software and associated documentation files (the "Software"), to deal
  7  # in the Software without restriction, including without limitation the rights
  8  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9  # copies of the Software, and to permit persons to whom the Software is
 10  # furnished to do so, subject to the following conditions:
 11  #
 12  # The above copyright notice and this permission notice shall be included in
 13  # all copies or substantial portions of the Software.
 14  #
 15  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 21  # THE SOFTWARE.
 22  """
 23  `adafruit_ina260`
 24  ================================================================================
 25  
 26  CircuitPython driver for the TI INA260 current and power sensor
 27  
 28  
 29  * Author(s): Bryan Siepert
 30  
 31  Implementation Notes
 32  --------------------
 33  
 34  **Hardware:**
 35  
 36  * `INA260 Breakout <https://www.adafruit.com/products/4226>`_
 37  
 38  **Software and Dependencies:**
 39  
 40  * Adafruit CircuitPython firmware for the supported boards:
 41    https://github.com/adafruit/circuitpython/releases
 42  
 43   * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
 44   * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
 45  """
 46  
 47  # imports
 48  
 49  __version__ = "0.0.0-auto.0"
 50  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_INA260.git"
 51  
 52  from micropython import const
 53  import adafruit_bus_device.i2c_device as i2cdevice
 54  
 55  from adafruit_register.i2c_struct import ROUnaryStruct
 56  from adafruit_register.i2c_bits import RWBits
 57  from adafruit_register.i2c_bit import ROBit
 58  
 59  # pylint: disable=bad-whitespace
 60  _REG_CONFIG = const(0x00)  # CONFIGURATION REGISTER (R/W)
 61  _REG_CURRENT = const(0x01)  # SHUNT VOLTAGE REGISTER (R)
 62  _REG_BUSVOLTAGE = const(0x02)  # BUS VOLTAGE REGISTER (R)
 63  _REG_POWER = const(0x03)  # POWER REGISTER (R)
 64  _REG_MASK_ENABLE = const(0x06)  # MASK ENABLE REGISTER (R/W)
 65  _REG_ALERT_LIMIT = const(0x07)  # ALERT LIMIT REGISTER (R/W)
 66  _REG_MFG_UID = const(0xFE)  # MANUFACTURER UNIQUE ID REGISTER (R)
 67  _REG_DIE_UID = const(0xFF)  # DIE UNIQUE ID REGISTER (R)
 68  
 69  # pylint: disable=too-few-public-methods
 70  class Mode:
 71      """Modes avaible to be set
 72  
 73          +--------------------+---------------------------------------------------------------------+
 74          | Mode               | Description                                                         |
 75          +====================+=====================================================================+
 76          | ``Mode.CONTINUOUS``| Default: The sensor will continuously measure the bus voltage and   |
 77          |                    | shunt voltage across the shunt resistor to calculate ``power`` and  |
 78          |                    | ``current``                                                         |
 79          +--------------------+---------------------------------------------------------------------+
 80          | ``Mode.TRIGGERED`` | The sensor will immediately begin measuring and calculating current,|
 81          |                    | bus voltage, and power. Re-set this mode to initiate another        |
 82          |                    | measurement                                                         |
 83          +--------------------+---------------------------------------------------------------------+
 84          | ``Mode.SHUTDOWN``  |  Shutdown the sensor, reducing the quiescent current and turning off|
 85          |                    |  current into the device inputs. Set another mode to re-enable      |
 86          +--------------------+---------------------------------------------------------------------+
 87  
 88      """
 89  
 90      SHUTDOWN = const(0x0)
 91      TRIGGERED = const(0x3)
 92      CONTINUOUS = const(0x7)
 93  
 94  
 95  class ConversionTime:
 96      """Options for ``current_conversion_time`` or ``voltage_conversion_time``
 97  
 98          +----------------------------------+------------------+
 99          | ``ConversionTime``               | Time             |
100          +==================================+==================+
101          | ``ConversionTime.TIME_140_us``   | 140 us           |
102          +----------------------------------+------------------+
103          | ``ConversionTime.TIME_204_us``   | 204 us           |
104          +----------------------------------+------------------+
105          | ``ConversionTime.TIME_332_us``   | 332 us           |
106          +----------------------------------+------------------+
107          | ``ConversionTime.TIME_558_us``   | 588 us           |
108          +----------------------------------+------------------+
109          | ``ConversionTime.TIME_1_1_ms``   | 1.1 ms (Default) |
110          +----------------------------------+------------------+
111          | ``ConversionTime.TIME_2_116_ms`` | 2.116 ms         |
112          +----------------------------------+------------------+
113          | ``ConversionTime.TIME_4_156_ms`` | 4.156 ms         |
114          +----------------------------------+------------------+
115          | ``ConversionTime.TIME_8_244_ms`` | 8.244 ms         |
116          +----------------------------------+------------------+
117  
118      """
119  
120      TIME_140_us = const(0x0)
121      TIME_204_us = const(0x1)
122      TIME_332_us = const(0x2)
123      TIME_558_us = const(0x3)
124      TIME_1_1_ms = const(0x4)
125      TIME_2_116_ms = const(0x5)
126      TIME_4_156_ms = const(0x6)
127      TIME_8_244_ms = const(0x7)
128  
129  
130  class AveragingCount:
131      """Options for ``averaging_count``
132  
133          +-------------------------------+------------------------------------+
134          | ``AveragingCount``            | Number of measurements to average  |
135          +===============================+====================================+
136          | ``AveragingCount.COUNT_1``    | 1 (Default)                        |
137          +-------------------------------+------------------------------------+
138          | ``AveragingCount.COUNT_4``    | 4                                  |
139          +-------------------------------+------------------------------------+
140          | ``AveragingCount.COUNT_16``   | 16                                 |
141          +-------------------------------+------------------------------------+
142          | ``AveragingCount.COUNT_64``   | 64                                 |
143          +-------------------------------+------------------------------------+
144          | ``AveragingCount.COUNT_128``  | 128                                |
145          +-------------------------------+------------------------------------+
146          | ``AveragingCount.COUNT_256``  | 256                                |
147          +-------------------------------+------------------------------------+
148          | ``AveragingCount.COUNT_512``  | 512                                |
149          +-------------------------------+------------------------------------+
150          | ``AveragingCount.COUNT_1024`` | 1024                               |
151          +-------------------------------+------------------------------------+
152  
153      """
154  
155      COUNT_1 = const(0x1)
156      COUNT_4 = const(0x2)
157      COUNT_16 = const(0x3)
158      COUNT_64 = const(0x4)
159      COUNT_128 = const(0x5)
160      COUNT_256 = const(0x6)
161      COUNT_512 = const(0x7)
162      COUNT_1024 = const(0x8)
163  
164  
165  # pylint: enable=bad-whitespace
166  # pylint: enable=too-few-public-methods
167  
168  
169  class INA260:
170      """Driver for the INA260 power and current sensor.
171  
172          :param ~busio.I2C i2c_bus: The I2C bus the INA260 is connected to.
173          :param address: The I2C device address for the sensor. Default is ``0x40``.
174  
175      """
176  
177      def __init__(self, i2c_bus, address=0x40):
178          self.i2c_device = i2cdevice.I2CDevice(i2c_bus, address)
179  
180      _raw_current = ROUnaryStruct(_REG_CURRENT, ">h")
181      _raw_voltage = ROUnaryStruct(_REG_BUSVOLTAGE, ">H")
182      _raw_power = ROUnaryStruct(_REG_POWER, ">H")
183  
184      _conversion_ready = ROBit(_REG_MASK_ENABLE, 3, 2, False)
185  
186      averaging_count = RWBits(3, _REG_CONFIG, 9, 2, False)
187      """The window size of the rolling average used in continuous mode"""
188      voltage_conversion_time = RWBits(3, _REG_CONFIG, 6, 2, False)
189      """The conversion time taken for the bus voltage measurement"""
190      current_conversion_time = RWBits(3, _REG_CONFIG, 3, 2, False)
191      """The conversion time taken for the current measurement"""
192  
193      mode = RWBits(3, _REG_CONFIG, 0, 2, False)
194      """The mode that the INA260 is operating in. Must be one of
195      ``Mode.CONTINUOUS``, ``Mode.TRIGGERED``, or ``Mode.SHUTDOWN``
196      """
197  
198      mask_enable = RWBits(16, _REG_MASK_ENABLE, 0, 2, False)
199      alert_limit = RWBits(16, _REG_ALERT_LIMIT, 0, 2, False)
200  
201      @property
202      def current(self):
203          """The current (between V+ and V-) in mA"""
204          if self.mode == Mode.TRIGGERED:
205              while self._conversion_ready == 0:
206                  pass
207          return self._raw_current * 1.25
208  
209      @property
210      def voltage(self):
211          """The bus voltage in V"""
212          if self.mode == Mode.TRIGGERED:
213              while self._conversion_ready == 0:
214                  pass
215          return self._raw_voltage * 0.00125
216  
217      @property
218      def power(self):
219          """The power being delivered to the load in mW"""
220          if self.mode == Mode.TRIGGERED:
221              while self._conversion_ready == 0:
222                  pass
223          return self._raw_power * 10