Skip to content

Commit a5e361f

Browse files
committed
refactoring and linting
1 parent f6329ef commit a5e361f

File tree

4 files changed

+98
-180
lines changed

4 files changed

+98
-180
lines changed

adafruit_mcp4728.py

Lines changed: 93 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
3434
**Hardware:**
3535
36-
.. todo:: Update the PID for the below and add links to any specific hardware product page(s), or category page(s)
3736
* Adafruit's MCP4728 Breakout: https://adafruit.com/product/44XX
3837
3938
**Software and Dependencies:**
@@ -48,12 +47,9 @@
4847

4948
from time import sleep
5049
import adafruit_bus_device.i2c_device as i2c_device
51-
from adafruit_register.i2c_struct import UnaryStruct, ROUnaryStruct
52-
from adafruit_register.i2c_struct_array import StructArray
53-
from adafruit_register.i2c_bit import RWBit
54-
from adafruit_register.i2c_bits import RWBits
50+
from adafruit_register.i2c_struct import UnaryStruct
5551

56-
_MCP4728_DEFAULT_ADDRESS = 0x60
52+
_MCP4728_DEFAULT_ADDRESS = 0x60
5753

5854
"""
5955
# DAC1, DAC0 DAC Channel Selection bits:
@@ -64,7 +60,7 @@
6460
6561
0 = slave addr(auto)
6662
0 1 0 0 0 DAC1 DAC0 UDAC[A]
67-
01000 + 00 + UDAC =
63+
01000 + 00 + UDAC =
6864
0b01000000 = 0x40 (+2 for each successive)
6965
VREF PD1 PD0 Gx D11 D10 D9 D8 [A]
7066
D7 D6 D5 D4 D3 D2 D1 D0 [A]
@@ -78,21 +74,20 @@
7874
1 0 1 0 0 Write Power-Down bits to Input Registers
7975
"""
8076

81-
'0b 010 00 000'
8277
_MCP4728_CH_A_MULTI_IB = 0x40
8378
_MCP4728_CH_B_MULTI_IB = 0x42
8479
_MCP4728_CH_C_MULTI_IB = 0x44
8580
_MCP4728_CH_D_MULTI_IB = 0x46
8681

87-
'0b 010 11 000'
8882
_MCP4728_CH_A_SINGLE_EEPROM = 0x58
8983
_MCP4728_CH_B_SINGLE_EEPROM = 0x5A
9084
_MCP4728_CH_C_SINGLE_EEPROM = 0x5C
9185
_MCP4728_CH_D_SINGLE_EEPROM = 0x5E
9286

93-
'0b 010 10 000'
9487
_MCP4728_CH_A_MULTI_EEPROM = 0x50
9588

89+
#TODO: REMOVE THIS
90+
#pylint: disable=unused-variable,no-self-use,invalid-name,too-few-public-methods
9691
class MCP4728:
9792
"""Helper library for the Microchip MCP4728 I2C 12-bit Quad DAC.
9893
@@ -103,7 +98,7 @@ class MCP4728:
10398
_channel_a_single_write_eeprom = UnaryStruct(_MCP4728_CH_A_SINGLE_EEPROM, ">H")
10499
_channel_b_single_write_eeprom = UnaryStruct(_MCP4728_CH_B_SINGLE_EEPROM, ">H")
105100
_channel_c_single_write_eeprom = UnaryStruct(_MCP4728_CH_C_SINGLE_EEPROM, ">H")
106-
_channel_d_single_write_eeprom = UnaryStruct(_MCP4728_CH_D_SINGLE_EEPROM, ">H")
101+
_channel_d_single_write_eeprom = UnaryStruct(_MCP4728_CH_D_SINGLE_EEPROM, ">H")
107102

108103
_channel_a_multi_write = UnaryStruct(_MCP4728_CH_A_MULTI_IB, ">H")
109104
_channel_b_multi_write = UnaryStruct(_MCP4728_CH_B_MULTI_IB, ">H")
@@ -113,145 +108,134 @@ class MCP4728:
113108
_multi_write_channel_a_start = UnaryStruct(_MCP4728_CH_A_MULTI_EEPROM, ">HHHH")
114109

115110
def __init__(self, i2c_bus, address=_MCP4728_DEFAULT_ADDRESS):
116-
self.i2c_device = i2c_device.I2CDevice(i2c_bus, address)
117-
118-
@property
119-
def channel_a(self):
120-
"""channel a's current value"""
121-
return "hamsters"
122-
123-
@channel_a.setter
124-
def channel_a(self, value):
125-
self._channel_a_multi = value
126-
127111

128-
@property
129-
def channel_b(self):
130-
"""channel b's current value"""
131-
return "elves"
132-
133-
@channel_b.setter
134-
def channel_b(self, value):
135-
self._channel_b_multi = value
136-
137-
@property
138-
def channel_c(self):
139-
"""channel c's current value"""
140-
return "pancakes"
141-
142-
@channel_c.setter
143-
def channel_c(self, value):
144-
self._channel_c_multi = value
112+
self.i2c_device = i2c_device.I2CDevice(i2c_bus, address)
113+
self._create_channels()
145114

146-
@property
147-
def channel_d(self):
148-
"""channel d's current value"""
149-
return "gummies"
150-
151-
@channel_d.setter
152-
def channel_d(self, value):
153-
self._channel_d_multi = value
154-
155-
156-
def write_init(self, register_address, struct_format):
157-
self.format = struct_format
158-
self.address = register_address
159-
160-
# def read(self, obj):
161-
# buf = bytearray(1+struct.calcsize(self.format))
162-
# buf[0] = self.address
163-
# with self.i2c_device as i2c:
164-
# i2c.write_then_readinto(buf, buf, out_end=1, in_start=1)
165-
# return struct.unpack_from(self.format, buf, 1)[0]
166-
167-
# def write(self, obj, value):
168-
# buf = bytearray(1+struct.calcsize(self.format))
169-
# buf[0] = self.address
170-
# struct.pack_into(self.format, buf, 1, value)
171-
# with self.i2c_device as i2c:
172-
# i2c.write(buf)
173-
def chunks(self, l, n):
115+
def _chunk(self, l, n):
174116
# For item i in a range that is a length of l,
175117
for i in range(0, len(l), n):
176118
# Create an index range for l of n items:
177119
yield l[i:i+n]
178120

179-
def get_flags(self, high_byte):
121+
def _lzb(self, byte_val): # leading zero bin
122+
return format(byte_val, '#010b')
123+
124+
def _get_flags(self, high_byte):
180125
vref = (high_byte & 1<<7) > 0
181126
gain = (high_byte & 1<<4) > 0
182127
pd = (high_byte & 0b011<<5)>>5
183128
return (vref, gain, pd)
184129

185-
def read_registers(self):
130+
def _cache_page(self, value, vref, gain, pd):
131+
return {"value": value, "vref": vref, "gain": gain, "pd": pd}
132+
133+
def _create_channels(self):
134+
raw_registers = self._read_registers()
135+
136+
self.channel_a = Channel(self._cache_page(*raw_registers[0]))
137+
self.channel_b = Channel(self._cache_page(*raw_registers[1]))
138+
self.channel_c = Channel(self._cache_page(*raw_registers[2]))
139+
self.channel_d = Channel(self._cache_page(*raw_registers[3]))
140+
141+
def _read_registers(self):
186142
buf = bytearray(24)
187143

188144
with self.i2c_device as i2c:
189145
i2c.readinto(buf)
190146
index = 0
191147
for index, value in enumerate(buf):
192-
if index %3 is 0:
148+
if index %3 == 0:
193149
print("\n%4s\t"%index, end="")
194-
print("%s %s "%( format(value, '#010b'), hex(value)), end="")
150+
print("%s %s "%(format(value, '#010b'), hex(value)), end="")
195151
print()
196-
# stride is 6 because we get 6 bytes for each channel; 3 for the output regs
197-
# and 3 for the eeprom. here we only care about the output buffer
152+
153+
# stride is 6 because we get 6 bytes for each channel; 3 for the output regs
154+
# and 3 for the eeprom. here we only care about the output buffer so we throw out
155+
# the eeprom values as 'n/a'
198156
current_values = []
199-
for header, high_byte, low_byte, na_1, na_2, na_3 in self.chunks(buf,6):
157+
for header, high_byte, low_byte, na_1, na_2, na_3 in self._chunk(buf, 6):
200158
value = (high_byte & 0b00001111) << 8 | low_byte
201-
vref, gain, pd = self.get_flags(high_byte)
202-
current_values << (value, vref, pd, gain)
159+
vref, gain, pd = self._get_flags(high_byte)
160+
current_values.append((value, vref, gain, pd))
203161

204162
return current_values
205-
# ch_a_header, ch_a_hb, ch_a_lb = buf[0:3]
206-
# ch_aee_header, ch_aee_hb, ch_aee_lb = buf[3:6]
207-
# # ch_c_header, ch_c_hb, ch_c_lb = buf[6:9]
208-
# # ch_d_header, ch_d_hb, ch_d_lb = buf[9:12]
209163

210-
# ch_a_val =
211164

212-
# print("%s %s %s"%( self.b(ch_a_header),self.b(ch_a_hb), self.b(ch_a_lb) ))
213-
# print("%s %s %s"%( self.b(ch_b_header),self.b(ch_b_hb), self.b(ch_b_lb) ))
214-
# # print("%s %s %s"%( self.b(ch_c_header),self.b(ch_c_hb), self.b(ch_c_lb) ))
215-
# # print("%s %s %s"%( self.b(ch_d_header),self.b(ch_d_hb), self.b(ch_d_lb) ))
216-
217-
def b(self, byte_val):
218-
return format(byte_val, '#010b')
219-
220-
def write_multi_eeprom(self, byte_list, start=0):
165+
# TODO: add the ability to set an offset
166+
def _write_multi_eeprom(self, byte_list):
221167
buffer_list = [_MCP4728_CH_A_MULTI_EEPROM]
222168
buffer_list += byte_list
223-
print("Byte List:")
224-
print(buffer_list)
169+
225170
buf = bytearray(buffer_list)
226-
# struct.pack_into(self.format, buf, 1, value)
227171
with self.i2c_device as i2c:
228172
i2c.write(buf)
229173

174+
sleep(0.015) # the better to write you with
230175

231176

232-
177+
class Channel:
178+
"""An instance of a single channel for a multi-channel DAC"""
179+
def __init__(self, cache_page):
180+
self._vref = cache_page['vref']
181+
self._gain = cache_page['gain']
182+
self._raw_value = cache_page['value']
233183

184+
@property
185+
def normalized_value(self):
186+
"""The DAC value as a floating point number in the range 0.0 to 1.0."""
187+
return self._raw_value / (2**12-1)
188+
189+
@normalized_value.setter
190+
def normalized_value(self, value):
191+
if value < 0.0 or value > 1.0:
192+
raise AttributeError("`normalized_value` must be between 0.0 and 1.0")
193+
194+
self._raw_value = int(value * 4095.0)
234195

235196
@property
236-
def ch_a(self):
237-
return "poo"
197+
def value(self):
198+
"""The 16-bit scaled current value for the channel. Note that the MCP4728 is a 12-bit piece
199+
so quantization errors will occour"""
200+
return self.normalized_value * (2**16-1)
238201

239-
@ch_a.setter
240-
def ch_a(self, value):
241-
self._channel_a_multi = value
202+
@value.setter
203+
def value(self, value):
204+
if value < 0 or value > (2**16-1):
205+
raise AttributeError("`value` must be a 16-bit integer between 0 and %s"%(2**16-1))
242206

243-
"""
244-
# set the gain for a channel
245-
cache each, set all?
207+
# Scale from 16-bit to 12-bit value (quantization errors will occur!).
208+
self._raw_value = value >> 4
246209

247-
# set reference source for a channel
248-
cache each, set all?
210+
@property
211+
def raw_value(self):
212+
"""The native 12-bit value used by the DAC"""
213+
return self._raw_value
249214

250-
# save settings to eeprom
215+
@raw_value.setter
216+
def raw_value(self, value):
217+
if value < 0 or value > (2**12-1):
218+
raise AttributeError("`raw_value` must be a 12-bit integer between 0 and %s"%(2**12-1))
219+
self._raw_value = value
251220

252-
# write a channel
221+
@property
222+
def gain(self):
223+
"""Sets the gain of the channel. Must be 1 or 2"""
224+
return self._gain
253225

254-
# write all channels
226+
@gain.setter
227+
def gain(self, value):
228+
if value < 1 or value > 2:
229+
raise AttributeError("`gain` must be 1 or 2")
230+
self._vref = value
255231

256-
# latching?
257-
"""
232+
@property
233+
def vref(self):
234+
"""Sets the DAC's voltage reference source. Must be a ``VREF``"""
235+
return self._vref
236+
237+
@vref.setter
238+
def vref(self, value):
239+
if value < 0 or value > 3:
240+
raise AttributeError("`vref` must be a ``VREF``")
241+
self._vref = value

examples/mcp4728_simpletest.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
import time
21
import board
32
import busio
43
import adafruit_mcp4728
54

65
i2c = busio.I2C(board.SCL, board.SDA)
76
mcp4728 = adafruit_mcp4728.MCP4728(i2c)
87

9-
10-
mcp4728.channel_a = 4095 # Voltage = VCC
11-
mcp4728.channel_b = 2048 # VCC/2
12-
mcp4728.channel_c = 1024 # VCC/4
13-
mcp4728.channel_d = 512 # VCC/8
14-
8+
mcp4728.channel_a.value = 4095 # Voltage = VCC
9+
mcp4728.channel_b.value = 2048 # VCC/2
10+
mcp4728.channel_c.value = 1024 # VCC/4
11+
mcp4728.channel_d.value = 512 # VCC/8

examples/mcp4728_sine_wave.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import time
1+
import math
22
import board
33
import busio
44
import adafruit_mcp4728
5-
import math
65
i2c = busio.I2C(board.SCL, board.SDA, frequency=3200000)
76

87
mcp4728 = adafruit_mcp4728.MCP4728(i2c)

examples/read_test.py

Lines changed: 0 additions & 62 deletions
This file was deleted.

0 commit comments

Comments
 (0)