/ 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