Yet Another WebIOPi+
 All Classes Namespaces Files Functions Variables Macros Pages
mcp3424.py
Go to the documentation of this file.
1 #!/usr/bin/python3
2 # MCP3424 driver written for webopi
3 # written by Justin Miller
4 # example by ABElectronics, ABE_ADCPi.py used as a template.
5 # tested on the ADCPi (qty2)
6 ##
7 #
8 # Device notes
9 # * When you read from the device over I2C, the device returns the data bytes
10 # followed by the configuration byte.
11 # * 18 bit resolution - 3 data bytes, followed by the config byte.
12 # * 12 to 16 bit resolution, 2 data bytes, followed by the config byte.
13 # * unused bits to the left of the MSB mirror the MSB(sign bit) and can be ignored.
14 # * twos compliment is used for negative values. (not implemented here)
15 # * 18 bit format byte_1(6 bits to ignore, 1 sign bit, 1 data bit) byte_2(8 data bits)
16 # byte_3(8 data bits) byte_4(config byte)
17 # * 16 bit format byte_1(1 sign bit, 7 data bits) byte_2(8 data bits) byte_3(config byte)
18 # * 14 bit format byte_1(2 bits to ignore, 1 sign bit, 5 data bits), byte_2(8 data bits),
19 # byte_3(config byte)
20 # * 12 bit format byte_1(4 bits to ignore, 1 sign bit, 3 data bits), byte_2(8 data bits),
21 # byte_3(config byte)
22 #
23 # * Since this chip reads +/- voltage, the MSB is actually a sign bit. This breaks the
24 # -analogMax calculation in /devices/analog/__init__.py. To fix it, send (resolution-1)
25 # rather than resolution to __init__.py { so that max = 2**(resolution-1)-1 }
26 #
27 # /etc/webiopi/config notes:
28 # example config to be placed in [DEVICES]
29 # mcp1 = MCP3424 slave:0x68 resolution:12 name:ADC1 gain:1
30 # mcp2 = MCP3424 slave:0x69 resolution:16 name:ADC2 gain:1
31 #
32 # In webiopi/devices/analog/__init__.py
33 # Add the following line
34 # DRIVERS["mcp3424"] = ["MCP3424"]
35 #
36 
37 
38 from webiopi.utils.types import toint
39 from webiopi.devices.i2c import I2C
40 from webiopi.devices.analog import ADC
41 
42 
43 class MCP3424(ADC, I2C):
44  # internal variables
45  __address = 0x68 # default address for adc 1 on ADCPi and delta-sigma pi
46  __channel = 0 # current channel
47  __config = 0x10 # PGAx1, 12 bit, one-shot conversion, channel 1 (0001 0000)
48 
49  # create byte array and fill with initial values to define size
50  __adcreading = bytearray()
51  __adcreading.append(0x00)
52  __adcreading.append(0x00)
53  __adcreading.append(0x00)
54  __adcreading.append(0x00)
55 
56  # local methods
57  def __str__(self):
58  return "MCP3424(slave=0x%02X)" % self.__address
59 
60  def __updatebyte(self, byte, bit, value):
61  # internal method for setting the value of a single bit within a byte
62  # send the byte to modify, which bit, and the value to set it to.
63  if value == 0:
64  return byte & ~(1 << bit)
65  elif value == 1:
66  return byte | (1 << bit)
67 
68  def __checkbit(self, byte, bit):
69  # internal method for reading the value of a single bit within a byte
70  bitval = ((byte & (1 << bit)) != 0)
71  if (bitval == 1):
72  return True
73  else:
74  return False
75 
76  def __setchannel(self, channel):
77  # internal method for updating the config to the selected channel
78  if channel != self.__channel:
79  if channel == 0:
80  self.__config = self.__updatebyte(self.__config, 5, 0)
81  self.__config = self.__updatebyte(self.__config, 6, 0)
82  self.__channel = 0
83  if channel == 1:
84  self.__config = self.__updatebyte(self.__config, 5, 1)
85  self.__config = self.__updatebyte(self.__config, 6, 0)
86  self.__channel = 1
87  if channel == 2:
88  self.__config = self.__updatebyte(self.__config, 5, 0)
89  self.__config = self.__updatebyte(self.__config, 6, 1)
90  self.__channel = 2
91  if channel == 3:
92  self.__config = self.__updatebyte(self.__config, 5, 1)
93  self.__config = self.__updatebyte(self.__config, 6, 1)
94  self.__channel = 3
95  return
96 
97  # init object with i2c address, default is 0x68, 0x69 for ADCoPi board
98  def __init__(self, slave, resolution, name, gain=1):
99 
100  self.__address = toint(slave)
101  self.resolution = toint(resolution)
102  self.initResolution = toint(resolution)-1
103  self.name = name
104  self.gain = toint(gain)
105  self.channelCount = 4
106  self.byteCount = 3
107  #pass the integer of the chip address to I2C.__init__
108  I2C.__init__(self, self.__address)
109  #pass the ADC channel, resolution, and vref to ADC.__init__
110  ADC.__init__(self, self.channelCount, self.initResolution, vref=5)
111  #setBitRate and set_pga must follow I2C and ADC init()
112  #The I2C bus must be set up first.
113  self.setBitRate(self.resolution)
114  self.set_pga(self.gain) # set the gain
115 
116  def __analogRead__(self, channel, diff=False):
117  # reads the raw value from the selected adc channel - channels 0 to 3
118  h = 0
119  l = 0
120  m = 0
121  s = 0
122 
123  if self.resolution == 18: #set the number of bytes for 1 sample
124  self.byteCount = 4
125  else:
126  self.byteCount = 3
127 
128  self.__setchannel(channel) #set the config bits for the desired channel.
129 
130  # keep reading the adc data until the conversion result is ready
131  while True:
132  __adcreading = self.readRegisters(self.__config, self.byteCount)
133  if self.resolution == 18:
134  h = __adcreading[0]
135  m = __adcreading[1]
136  l = __adcreading[2]
137  s = __adcreading[3]
138  else:
139  h = __adcreading[0]
140  m = __adcreading[1]
141  s = __adcreading[2]
142  if self.__checkbit(s, 7) == 0:
143  break
144 
145  self.__signbit = False
146  t = 0.0
147 
148  # extract the returned bytes and combine in the correct order
149  if self.resolution == 18:
150  t = ((h & 0b00000011) << 16) | (m << 8) | l
151  self.__signbit = bool(self.__checkbit(t, 17))
152  if self.__signbit:
153  t = self.__updatebyte(t, 17, 0)
154 
155  if self.resolution == 16:
156  t = (h << 8) | m
157  self.__signbit = bool(self.__checkbit(t, 15))
158  if self.__signbit:
159  t = self.__updatebyte(t, 15, 0)
160 
161  if self.resolution == 14:
162  t = ((h & 0b00111111) << 8) | m
163  self.__signbit = self.__checkbit(t, 13)
164  if self.__signbit:
165  t = self.__updatebyte(t, 13, 0)
166 
167  if self.resolution == 12:
168  t = ((h & 0b00001111) << 8) | m
169  self.__signbit = self.__checkbit(t, 11)
170  if self.__signbit:
171  t = self.__updatebyte(t, 11, 0)
172 
173  return t
174 
175  def set_pga(self, gain): #set the gain bits in __config
176 
177  if gain == 1:
178  self.__config = self.__updatebyte(self.__config, 0, 0)
179  self.__config = self.__updatebyte(self.__config, 1, 0)
180  if gain == 2:
181  self.__config = self.__updatebyte(self.__config, 0, 1)
182  self.__config = self.__updatebyte(self.__config, 1, 0)
183  if gain == 4:
184  self.__config = self.__updatebyte(self.__config, 0, 0)
185  self.__config = self.__updatebyte(self.__config, 1, 1)
186  if gain == 8:
187  self.__config = self.__updatebyte(self.__config, 0, 1)
188  self.__config = self.__updatebyte(self.__config, 1, 1)
189 
190  self.writeRegister(self.__address, self.__config)
191  return
192 
193  def setBitRate(self, rate): #set the resolution bits in __config
194 
195  if rate == 12:
196  self.__config = self.__updatebyte(self.__config, 2, 0)
197  self.__config = self.__updatebyte(self.__config, 3, 0)
198  if rate == 14:
199  self.__config = self.__updatebyte(self.__config, 2, 1)
200  self.__config = self.__updatebyte(self.__config, 3, 0)
201  if rate == 16:
202  self.__config = self.__updatebyte(self.__config, 2, 0)
203  self.__config = self.__updatebyte(self.__config, 3, 1)
204  if rate == 18:
205  self.__config = self.__updatebyte(self.__config, 2, 1)
206  self.__config = self.__updatebyte(self.__config, 3, 1)
207 
208  self.writeRegister(self.__address, self.__config)
209  return