|
24 | 24 | """
|
25 | 25 |
|
26 | 26 | # imports
|
27 |
| -from time import monotonic, sleep |
| 27 | +from time import monotonic |
28 | 28 | from digitalio import DigitalInOut
|
29 | 29 |
|
30 | 30 | __version__ = "0.0.0-auto.0"
|
@@ -84,22 +84,27 @@ def __init__(self, scl, sda, *, frequency=400000, timeout=1):
|
84 | 84 |
|
85 | 85 | # Set pins as outputs/inputs.
|
86 | 86 | self._scl = DigitalInOut(scl)
|
87 |
| - self._scl.switch_to_output() |
88 |
| - self._scl.value = 1 |
| 87 | + # rpi gpio does not support OPEN_DRAIN, so we have to emulate it |
| 88 | + # by setting the pin to input for high and output 0 for low |
| 89 | + self._scl.switch_to_input() |
89 | 90 |
|
90 | 91 | # SDA flips between being input and output
|
91 | 92 | self._sda = DigitalInOut(sda)
|
92 |
| - self._sda.switch_to_output() |
93 |
| - self._sda.value = 1 |
| 93 | + self._sda.switch_to_input() |
94 | 94 |
|
95 |
| - self._delay = 1 / frequency / 2 |
| 95 | + self._delay = (1 / frequency) / 2 # half period |
96 | 96 | self._timeout = timeout
|
97 | 97 |
|
98 | 98 | def deinit(self):
|
99 | 99 | """Free any hardware used by the object."""
|
100 | 100 | self._sda.deinit()
|
101 | 101 | self._scl.deinit()
|
102 | 102 |
|
| 103 | + def _wait(self): |
| 104 | + end = monotonic() + self._delay # half period |
| 105 | + while end > monotonic(): |
| 106 | + pass |
| 107 | + |
103 | 108 | def scan(self):
|
104 | 109 | """Perform an I2C Device Scan"""
|
105 | 110 | found = []
|
@@ -145,100 +150,100 @@ def writeto_then_readfrom(
|
145 | 150 | if in_end is None:
|
146 | 151 | in_end = len(buffer_in)
|
147 | 152 | if self._check_lock():
|
148 |
| - self.writeto(address, buffer_out, start=out_start, end=out_end) |
| 153 | + self._write(address, buffer_out[out_start:out_end], False) |
149 | 154 | self.readfrom_into(address, buffer_in, start=in_start, end=in_end)
|
150 | 155 |
|
151 | 156 | def _scl_low(self):
|
152 |
| - self._scl.value = 0 |
| 157 | + self._scl.switch_to_output(value=False) |
153 | 158 |
|
154 | 159 | def _sda_low(self):
|
155 |
| - self._sda.value = 0 |
| 160 | + self._sda.switch_to_output(value=False) |
156 | 161 |
|
157 | 162 | def _scl_release(self):
|
158 | 163 | """Release and let the pullups lift"""
|
159 | 164 | # Use self._timeout to add clock stretching
|
160 |
| - self._scl.value = 1 |
| 165 | + self._scl.switch_to_input() |
161 | 166 |
|
162 | 167 | def _sda_release(self):
|
163 | 168 | """Release and let the pullups lift"""
|
164 | 169 | # Use self._timeout to add clock stretching
|
165 |
| - self._sda.value = 1 |
| 170 | + self._sda.switch_to_input() |
166 | 171 |
|
167 | 172 | def _start(self):
|
168 | 173 | self._sda_release()
|
169 | 174 | self._scl_release()
|
170 |
| - sleep(self._delay) |
| 175 | + self._wait() |
171 | 176 | self._sda_low()
|
172 |
| - sleep(self._delay) |
| 177 | + self._wait() |
173 | 178 |
|
174 | 179 | def _stop(self):
|
175 | 180 | self._scl_low()
|
176 |
| - sleep(self._delay) |
| 181 | + self._wait() |
177 | 182 | self._sda_low()
|
178 |
| - sleep(self._delay) |
| 183 | + self._wait() |
179 | 184 | self._scl_release()
|
180 |
| - sleep(self._delay) |
| 185 | + self._wait() |
181 | 186 | self._sda_release()
|
182 |
| - sleep(self._delay) |
| 187 | + self._wait() |
183 | 188 |
|
184 | 189 | def _repeated_start(self):
|
185 | 190 | self._scl_low()
|
186 |
| - sleep(self._delay) |
| 191 | + self._wait() |
187 | 192 | self._sda_release()
|
188 |
| - sleep(self._delay) |
| 193 | + self._wait() |
189 | 194 | self._scl_release()
|
190 |
| - sleep(self._delay) |
| 195 | + self._wait() |
191 | 196 | self._sda_low()
|
192 |
| - sleep(self._delay) |
| 197 | + self._wait() |
193 | 198 |
|
194 | 199 | def _write_byte(self, byte):
|
195 | 200 | for bit_position in range(8):
|
196 | 201 | self._scl_low()
|
197 |
| - sleep(self._delay) |
| 202 | + |
198 | 203 | if byte & (0x80 >> bit_position):
|
199 | 204 | self._sda_release()
|
200 | 205 | else:
|
201 | 206 | self._sda_low()
|
202 |
| - sleep(self._delay) |
| 207 | + self._wait() |
203 | 208 | self._scl_release()
|
204 |
| - sleep(self._delay) |
| 209 | + self._wait() |
| 210 | + |
205 | 211 | self._scl_low()
|
206 |
| - sleep(self._delay * 2) |
| 212 | + self._sda.switch_to_input() # SDA may go high, but SCL is low |
| 213 | + self._wait() |
207 | 214 |
|
208 | 215 | self._scl_release()
|
209 |
| - sleep(self._delay) |
210 |
| - |
211 |
| - self._sda.switch_to_input() |
212 |
| - ack = self._sda.value |
213 |
| - self._sda.switch_to_output() |
214 |
| - sleep(self._delay) |
| 216 | + self._wait() |
| 217 | + ack = self._sda.value # read the ack |
215 | 218 |
|
216 | 219 | self._scl_low()
|
| 220 | + self._sda_release() |
| 221 | + self._wait() |
217 | 222 |
|
218 | 223 | return not ack
|
219 | 224 |
|
220 | 225 | def _read_byte(self, ack=False):
|
221 | 226 | self._scl_low()
|
222 |
| - sleep(self._delay) |
223 |
| - |
| 227 | + self._wait() |
| 228 | + # sda will already be an input as we are simulating open drain |
224 | 229 | data = 0
|
225 |
| - self._sda.switch_to_input() |
226 | 230 | for _ in range(8):
|
227 | 231 | self._scl_release()
|
228 |
| - sleep(self._delay) |
| 232 | + self._wait() |
229 | 233 | data = (data << 1) | int(self._sda.value)
|
230 |
| - sleep(self._delay) |
231 | 234 | self._scl_low()
|
232 |
| - sleep(self._delay) |
233 |
| - self._sda.switch_to_output() |
| 235 | + self._wait() |
234 | 236 |
|
235 | 237 | if ack:
|
236 | 238 | self._sda_low()
|
237 |
| - else: |
238 |
| - self._sda_release() |
239 |
| - sleep(self._delay) |
| 239 | + # else sda will already be in release (open drain) mode |
| 240 | + |
| 241 | + self._wait() |
240 | 242 | self._scl_release()
|
241 |
| - sleep(self._delay) |
| 243 | + self._wait() |
| 244 | + self._scl_low() |
| 245 | + self._sda_release() |
| 246 | + |
242 | 247 | return data & 0xFF
|
243 | 248 |
|
244 | 249 | def _probe(self, address):
|
|
0 commit comments