16 self._hid = hid.device()
17 self._hid.open(MCP2221.VID, MCP2221.PID)
20 def _hid_xfer(self, report, response=True):
21 # first byte is report ID, which =0 for MCP2221
22 # remaing bytes = 64 byte report data
23 # https://github.com/libusb/hidapi/blob/083223e77952e1ef57e6b77796536a3359c1b2a3/hidapi/hidapi.h#L185
24 self._hid.write(b'\0' + report + b'\0'*(64-len(report)))
26 # return is 64 byte response report
27 return self._hid.read(64)
29 #----------------------------------------------------------------
31 #----------------------------------------------------------------
32 def gp_get_mode(self, pin):
33 return self._hid_xfer(b'\x61')[22+pin] & 0x07
35 def gp_set_mode(self, pin, mode):
36 # get current settings
37 current = self._hid_xfer(b'\x61')
38 # empty report, this is safe since 0's = no change
39 report = bytearray(b'\x60'+b'\x00'*63)
40 # set the alter GP flag byte
42 # each pin can be set individually
43 # but all 4 get set at once, so we need to
44 # transpose current settings
45 report[8] = current[22] # GP0
46 report[9] = current[23] # GP1
47 report[10] = current[24] # GP2
48 report[11] = current[25] # GP3
49 # then change only the one
50 report[8+pin] = mode & 0x07
52 self._hid_xfer(report)
54 def _pretty_report(self, report):
55 print(" 0 1 2 3 4 5 6 7 8 9")
58 print("{} : ".format(row), end='')
60 print("{:02x} ".format(report[index]), end='')
66 def _status_dump(self):
67 self._pretty_report(self._hid_xfer(b'\x10'))
70 self._pretty_report(self._hid_xfer(b'\x61'))
73 self._hid_xfer(b'\x70\xAB\xCD\xEF', response=False)
74 start = time.monotonic()
75 while time.monotonic() - start < 5:
77 self._hid.open(MCP2221.VID, MCP2221.PID)
83 raise OSError("open failed")
85 #----------------------------------------------------------------
87 #----------------------------------------------------------------
88 def gpio_set_direction(self, pin, mode):
89 report = bytearray(b'\x50'+b'\x00'*63) # empty set GPIO report
90 offset = 4 * (pin + 1)
91 report[offset] = 0x01 # set pin direction
92 report[offset+1] = mode # to this
93 self._hid_xfer(report)
95 def gpio_set_pin(self, pin, value):
96 report = bytearray(b'\x50'+b'\x00'*63) # empty set GPIO report
98 report[offset] = 0x01 # set pin value
99 report[offset+1] = value # to this
100 self._hid_xfer(report)
102 def gpio_get_pin(self, pin):
103 resp = self._hid_xfer(b'\x51')
105 if resp[offset] == 0xEE:
106 raise RuntimeError("Pin is not set for GPIO operation.")
110 #----------------------------------------------------------------
113 # cribbed from the C driver
114 # http://ww1.microchip.com/downloads/en/DeviceDoc/mcp2221_0_1.tar.gz
115 # define RESP_I2C_IDLE 0x00
116 # define RESP_I2C_START_TOUT 0x12
117 # define RESP_I2C_RSTART_TOUT 0x17
118 # define RESP_I2C_WRADDRL_TOUT 0x23
119 # define RESP_I2C_WRADDRL_WSEND 0x21
120 # define RESP_I2C_WRADDRL_NACK 0x25
121 # define RESP_I2C_WRDATA_TOUT 0x44
122 # define RESP_I2C_RDDATA_TOUT 0x52
123 # define RESP_I2C_STOP_TOUT 0x62
124 #----------------------------------------------------------------
125 def _i2c_status(self):
126 return self._hid_xfer(b'\x10')[8]
128 def _i2c_cancel(self):
129 resp = self._hid_xfer(b'\x10\x00\x10')
131 # bus release will need "a few hundred microseconds"
134 def _i2c_write(self, cmd, address, buffer, start=0, end=None):
135 if self._i2c_status():
137 end = end if end else len(buffer)
140 while (end - start) > 0:
141 chunk = min(end - start, 60)
142 # write out current chunk
143 resp = self._hid_xfer(bytes([cmd,
145 (length >> 8) & 0xFF,
147 buffer[start:(start+chunk)])
152 raise RuntimeError("I2C write error, max retries reached.")
158 def _i2c_read(self, cmd, address, buffer, start=0, end=None):
159 if self._i2c_status():
161 end = end if end else len(buffer)
164 while (end - start) > 0:
165 # tell it we want to read
166 resp = self._hid_xfer(bytes([cmd,
168 (length >> 8) & 0xFF,
169 (address << 1) | 0x01]))
170 # and then actually read
171 resp = self._hid_xfer(b'\x40')
176 raise RuntimeError("I2C write error, max retries reached.")
179 # move data into buffer
180 chunk = min(end - start, 60)
181 for i, k in enumerate(range(start, start+chunk)):
182 buffer[k] = resp[4 + i]
185 def i2c_configure(self, baudrate=100000):
186 self._hid_xfer(bytes([0x10, # set parameters
189 0x20, # next byte is clock divider
190 12000000 // baudrate - 3]))
192 def i2c_writeto(self, address, buffer, *, start=0, end=None):
193 self._i2c_write(0x90, address, buffer, start, end)
195 def i2c_readfrom_into(self, address, buffer, *, start=0, end=None):
196 self._i2c_read(0x91, address, buffer, start, end)
198 def i2c_writeto_then_readfrom(self, address, out_buffer, in_buffer, *,
199 out_start=0, out_end=None,
200 in_start=0, in_end=None):
201 self._i2c_write(0x94, address, out_buffer, out_start, out_end)
202 self._i2c_read(0x93, address, in_buffer, in_start, in_end)
204 def i2c_scan(self, *, start=0, end=0x79):
206 for addr in range(start, end+1):
208 self.i2c_writeto(addr, b'\x00')
210 if self._i2c_status() == 0x00:
212 # cancel and continue
216 #----------------------------------------------------------------
218 #----------------------------------------------------------------
219 def adc_configure(self, vref=0):
220 report = bytearray(b'\x60'+b'\x00'*63)
221 report[5] = 1 << 7 | (vref & 0b111)
222 self._hid_xfer(report)
224 def adc_read(self, pin):
225 resp = self._hid_xfer(b'\x10')
226 return resp[49 + 2 * pin] << 8 | resp[48 + 2 * pin]
228 #----------------------------------------------------------------
230 #----------------------------------------------------------------
231 def dac_configure(self, vref=0):
232 report = bytearray(b'\x60'+b'\x00'*63)
233 report[3] = 1 << 7 | (vref & 0b111)
234 self._hid_xfer(report)
236 def dac_write(self, pin, value):
237 report = bytearray(b'\x60'+b'\x00'*63)
238 report[4] = 1 << 7 | (value & 0b11111)
239 self._hid_xfer(report)