/ adafruit_ds1841.py
adafruit_ds1841.py
1 # The MIT License (MIT) 2 # 3 # Copyright (c) 2020 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_ds1841` 24 ================================================================================ 25 26 Library for the DS1841 I2C Logarithmic Resistor 27 28 * Author(s): Bryan Siepert 29 30 Implementation Notes 31 -------------------- 32 33 **Hardware:** 34 35 * Adafruit's DS1841 Breakout: https://www.adafruit.com/product/4570 36 37 **Software and Dependencies:** 38 39 * Adafruit CircuitPython firmware for the supported boards: 40 https://circuitpython.org/downloads 41 * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice 42 * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register""" 43 44 __version__ = "0.0.0-auto.0" 45 __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DS1841.git" 46 47 from time import sleep 48 import adafruit_bus_device.i2c_device as i2c_device 49 from adafruit_register.i2c_struct import UnaryStruct 50 from adafruit_register.i2c_struct_array import StructArray 51 from adafruit_register.i2c_bit import RWBit 52 53 54 _DS1841_IVR = 0x00 55 _DS1841_CR0 = 0x02 56 _DS1841_CR1 = 0x03 57 _DS1841_LUTAR = 0x08 58 _DS1841_WR = 0x09 59 _DS1841_CR2 = 0x0A 60 _DS1841_TEMP = 0x0C 61 _DS1841_VOLTAGE = 0x0E 62 _DS1841_LUT = 0x80 # to C7h 63 64 _DS1841_VCC_LSB = 25.6 65 _DS1841_DEFAULT_ADDRESS = 0x28 # up to 0x2B 66 67 68 class DS1841: 69 """Driver for the DS3502 I2C Digital Potentiometer. 70 :param ~busio.I2C i2c_bus: The I2C bus the DS3502 is connected to. 71 :param address: The I2C device address for the sensor. Default is ``0x28``. 72 """ 73 74 _lut_address = UnaryStruct(_DS1841_LUTAR, ">B") 75 _wiper_register = UnaryStruct(_DS1841_WR, ">B") 76 77 _temperature_register = UnaryStruct(_DS1841_TEMP, ">b") 78 _voltage_register = UnaryStruct(_DS1841_VOLTAGE, ">B") 79 80 # NV-capable settings 81 _disable_save_to_eeprom = RWBit(_DS1841_CR0, 7) 82 # Can be shadowed by EEPROM 83 _initial_value_register = UnaryStruct(_DS1841_IVR, ">B") 84 _adder_mode_bit = RWBit(_DS1841_CR1, 1) 85 _update_mode = RWBit(_DS1841_CR1, 0) 86 87 _manual_lut_address = RWBit(_DS1841_CR2, 1) 88 _manual_wiper_value = RWBit(_DS1841_CR2, 2) 89 90 _lut = StructArray(_DS1841_LUT, ">B", 72) 91 92 def __init__(self, i2c_bus, address=_DS1841_DEFAULT_ADDRESS): 93 self.i2c_device = i2c_device.I2CDevice(i2c_bus, address) 94 95 self._disable_save_to_eeprom = True # turn off eeprom updates to IV and CR0 96 self._adder_mode_bit = False # Don't add IV to WR 97 # UPDATE MODE MUST BE FALSE FOR WIPER TO SHADOW IV 98 99 self._manual_lut_address = True # 100 self._manual_wiper_value = True # update WR by I2C 101 self._lut_mode_enabled = False 102 self._update_mode = True 103 104 @property 105 def wiper(self): 106 """The value of the potentionmeter's wiper. 107 :param wiper_value: The value from 0-127 to set the wiper to. 108 """ 109 return self._wiper_register 110 111 @wiper.setter 112 def wiper(self, value): 113 if value > 127: 114 raise AttributeError("wiper must be from 0-127") 115 self._wiper_register = value 116 117 @property 118 def wiper_default(self): 119 """Sets the wiper's default value and current value to the given value 120 :param new_default: The value from 0-127 to set as the wiper's default. 121 """ 122 123 return self._initial_value_register 124 125 @wiper_default.setter 126 def wiper_default(self, value): 127 if value > 127: 128 raise AttributeError("initial_value must be from 0-127") 129 self._disable_save_to_eeprom = False 130 # allows for IV to pass through to WR. 131 # this setting is also saved to EEPROM so IV will load into WR on boot 132 self._update_mode = False 133 sleep(0.2) 134 self._initial_value_register = value 135 sleep(0.2) 136 self._disable_save_to_eeprom = True 137 # Turn update mode back on so temp and voltage update 138 # and LUT usage works 139 self._update_mode = True 140 141 @property 142 def temperature(self): 143 """The current temperature in degrees celcius""" 144 return self._temperature_register 145 146 @property 147 def voltage(self): 148 """The current voltage between VCC and GND""" 149 return self._voltage_register * _DS1841_VCC_LSB 150 151 ######## LUTS on LUTS on LUTS 152 @property 153 def lut_mode_enabled(self): 154 """Enables LUT mode. LUT mode takes sets the value of the Wiper based on the entry in a 155 72-entry Look Up Table. The LUT entry is selected using the `lut_selection` 156 property to set an index from 0-71 157 """ 158 return self._lut_mode_enabled 159 160 @lut_mode_enabled.setter 161 def lut_mode_enabled(self, value): 162 self._manual_lut_address = value 163 self._update_mode = True 164 self._manual_wiper_value = not value 165 self._lut_mode_enabled = value 166 167 def set_lut(self, index, value): 168 """Set the value of an entry in the Look Up Table. 169 :param index: The index of the entry to set, from 0-71. 170 :param value: The value to set at the given index. The `wiper` will be set to this 171 value when the LUT entry is selected using `lut_selection` 172 """ 173 if value > 127: 174 raise IndexError("set_lut value must be from 0-127") 175 lut_value_byte = bytearray([value]) 176 self._lut[index] = lut_value_byte 177 sleep(0.020) 178 179 @property 180 def lut_selection(self): 181 """Choose the entry in the Look Up Table to use to set the wiper. 182 :param index: The index of the entry to use, from 0-71. 183 """ 184 if not self._lut_mode_enabled: 185 raise RuntimeError( 186 "lut_mode_enabled must be equal to True to use lut_selection" 187 ) 188 return self._lut_address - _DS1841_LUT 189 190 @lut_selection.setter 191 def lut_selection(self, value): 192 if value > 71 or value < 0: 193 raise IndexError("lut_selection value must be from 0-71") 194 self._lut_address = value + _DS1841_LUT 195 sleep(0.020)