Skip to content

Commit 9765f0a

Browse files
authored
Merge pull request #888 from ryanmesh-sd/main
I2C writeto_then_readfrom in a single transaction on u2if
2 parents 23d84ee + 0ee1753 commit 9765f0a

1 file changed

Lines changed: 55 additions & 0 deletions

File tree

src/adafruit_blinka/microcontroller/rp2040_u2if/rp2040_u2if.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,13 @@ class RP2040_u2if:
3737
I2C0_WRITE = 0x82
3838
I2C0_READ = 0x83
3939
I2C0_WRITE_FROM_UART = 0x84
40+
I2C0_WRITE_THEN_READ = 0x85
4041
I2C1_INIT = I2C0_INIT + 0x10
4142
I2C1_DEINIT = I2C0_DEINIT + 0x10
4243
I2C1_WRITE = I2C0_WRITE + 0x10
4344
I2C1_READ = I2C0_READ + 0x10
4445
I2C1_WRITE_FROM_UART = I2C0_WRITE_FROM_UART + 0x10
46+
I2C1_WRITE_THEN_READ = I2C0_WRITE_THEN_READ + 0x10
4547

4648
# SPI
4749
SPI0_INIT = 0x60
@@ -81,6 +83,8 @@ def __init__(self):
8183
self._neopixel_initialized = False
8284
self._uart_rx_buffer = None
8385

86+
self.FLAG_I2C_NO_WRITE_THEN_READ_AVAILABLE = False
87+
8488
def _hid_xfer(self, report, response=True):
8589
"""Perform HID Transfer"""
8690
# first byte is report ID, which =0
@@ -259,6 +263,38 @@ def _i2c_read(self, address, buffer, start=0, end=None):
259263
for i in range(read_size):
260264
buffer[start + i] = resp[i + 2]
261265

266+
def _i2c_write_then_read(
267+
self, address, buffer_w, buffer_r, start_w=0, end_w=None, start_r=0, end_r=None
268+
):
269+
"""Write data to an address, then read data back and into the buffer"""
270+
if self._i2c_index is None:
271+
raise RuntimeError("I2C bus not initialized.")
272+
273+
end_w = end_w if end_w is not None else len(buffer_w)
274+
end_r = end_r if end_r is not None else len(buffer_r)
275+
276+
write_then_read_cmd = (
277+
self.I2C0_WRITE_THEN_READ
278+
if self._i2c_index == 0
279+
else self.I2C1_WRITE_THEN_READ
280+
)
281+
282+
stop_flag = 0x01 # always stop
283+
284+
write_size = end_w - start_w
285+
read_size = end_r - start_r
286+
287+
resp = self._hid_xfer(
288+
bytes([write_then_read_cmd, address, stop_flag, write_size, read_size])
289+
+ buffer_w,
290+
True,
291+
)
292+
if resp[1] != self.RESP_OK:
293+
raise RuntimeError("I2C write_then_read error")
294+
# move into buffer
295+
for i in range(read_size):
296+
buffer_r[start_r + i] = resp[i + 2]
297+
262298
def i2c_writeto(self, address, buffer, *, start=0, end=None):
263299
"""Write data from the buffer to an address"""
264300
self._i2c_write(address, buffer, start, end)
@@ -281,6 +317,25 @@ def i2c_writeto_then_readfrom(
281317
"""Write data from buffer_out to an address and then
282318
read data from an address and into buffer_in
283319
"""
320+
if self._i2c_index is None:
321+
raise RuntimeError("I2C bus not initialized.")
322+
323+
if not self.FLAG_I2C_NO_WRITE_THEN_READ_AVAILABLE:
324+
try:
325+
self._i2c_write_then_read(
326+
address,
327+
out_buffer,
328+
in_buffer,
329+
start_w=out_start,
330+
end_w=out_end,
331+
start_r=in_start,
332+
end_r=in_end,
333+
)
334+
return
335+
except RuntimeError:
336+
# Firmware may not support write_then_read; fall back
337+
# to separate write + read for this and future calls.
338+
self.FLAG_I2C_NO_WRITE_THEN_READ_AVAILABLE = True
284339
self._i2c_write(address, out_buffer, out_start, out_end, False)
285340
self._i2c_read(address, in_buffer, in_start, in_end)
286341

0 commit comments

Comments
 (0)