Skip to content

Commit fa8dfc2

Browse files
authored
Merge pull request #18 from wolfmanjm/fix/i2c-timing
bitbang I2C running under Blinka did not work with the peripherals I tested.
2 parents 7b150a3 + 496b0d6 commit fa8dfc2

File tree

1 file changed

+47
-42
lines changed

1 file changed

+47
-42
lines changed

adafruit_bitbangio.py

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"""
2525

2626
# imports
27-
from time import monotonic, sleep
27+
from time import monotonic
2828
from digitalio import DigitalInOut
2929

3030
__version__ = "0.0.0-auto.0"
@@ -84,22 +84,27 @@ def __init__(self, scl, sda, *, frequency=400000, timeout=1):
8484

8585
# Set pins as outputs/inputs.
8686
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()
8990

9091
# SDA flips between being input and output
9192
self._sda = DigitalInOut(sda)
92-
self._sda.switch_to_output()
93-
self._sda.value = 1
93+
self._sda.switch_to_input()
9494

95-
self._delay = 1 / frequency / 2
95+
self._delay = (1 / frequency) / 2 # half period
9696
self._timeout = timeout
9797

9898
def deinit(self):
9999
"""Free any hardware used by the object."""
100100
self._sda.deinit()
101101
self._scl.deinit()
102102

103+
def _wait(self):
104+
end = monotonic() + self._delay # half period
105+
while end > monotonic():
106+
pass
107+
103108
def scan(self):
104109
"""Perform an I2C Device Scan"""
105110
found = []
@@ -145,100 +150,100 @@ def writeto_then_readfrom(
145150
if in_end is None:
146151
in_end = len(buffer_in)
147152
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)
149154
self.readfrom_into(address, buffer_in, start=in_start, end=in_end)
150155

151156
def _scl_low(self):
152-
self._scl.value = 0
157+
self._scl.switch_to_output(value=False)
153158

154159
def _sda_low(self):
155-
self._sda.value = 0
160+
self._sda.switch_to_output(value=False)
156161

157162
def _scl_release(self):
158163
"""Release and let the pullups lift"""
159164
# Use self._timeout to add clock stretching
160-
self._scl.value = 1
165+
self._scl.switch_to_input()
161166

162167
def _sda_release(self):
163168
"""Release and let the pullups lift"""
164169
# Use self._timeout to add clock stretching
165-
self._sda.value = 1
170+
self._sda.switch_to_input()
166171

167172
def _start(self):
168173
self._sda_release()
169174
self._scl_release()
170-
sleep(self._delay)
175+
self._wait()
171176
self._sda_low()
172-
sleep(self._delay)
177+
self._wait()
173178

174179
def _stop(self):
175180
self._scl_low()
176-
sleep(self._delay)
181+
self._wait()
177182
self._sda_low()
178-
sleep(self._delay)
183+
self._wait()
179184
self._scl_release()
180-
sleep(self._delay)
185+
self._wait()
181186
self._sda_release()
182-
sleep(self._delay)
187+
self._wait()
183188

184189
def _repeated_start(self):
185190
self._scl_low()
186-
sleep(self._delay)
191+
self._wait()
187192
self._sda_release()
188-
sleep(self._delay)
193+
self._wait()
189194
self._scl_release()
190-
sleep(self._delay)
195+
self._wait()
191196
self._sda_low()
192-
sleep(self._delay)
197+
self._wait()
193198

194199
def _write_byte(self, byte):
195200
for bit_position in range(8):
196201
self._scl_low()
197-
sleep(self._delay)
202+
198203
if byte & (0x80 >> bit_position):
199204
self._sda_release()
200205
else:
201206
self._sda_low()
202-
sleep(self._delay)
207+
self._wait()
203208
self._scl_release()
204-
sleep(self._delay)
209+
self._wait()
210+
205211
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()
207214

208215
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
215218

216219
self._scl_low()
220+
self._sda_release()
221+
self._wait()
217222

218223
return not ack
219224

220225
def _read_byte(self, ack=False):
221226
self._scl_low()
222-
sleep(self._delay)
223-
227+
self._wait()
228+
# sda will already be an input as we are simulating open drain
224229
data = 0
225-
self._sda.switch_to_input()
226230
for _ in range(8):
227231
self._scl_release()
228-
sleep(self._delay)
232+
self._wait()
229233
data = (data << 1) | int(self._sda.value)
230-
sleep(self._delay)
231234
self._scl_low()
232-
sleep(self._delay)
233-
self._sda.switch_to_output()
235+
self._wait()
234236

235237
if ack:
236238
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()
240242
self._scl_release()
241-
sleep(self._delay)
243+
self._wait()
244+
self._scl_low()
245+
self._sda_release()
246+
242247
return data & 0xFF
243248

244249
def _probe(self, address):

0 commit comments

Comments
 (0)