@@ -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