Skip to content

Commit

Permalink
ports: rpi pico - i2ctarget update transaction restart register mask
Browse files Browse the repository at this point in the history
issue #: adafruit#9232

Signed-off-by: Andrew Mirsky <andrew@mirsky.net>
  • Loading branch information
ajmirsky committed May 10, 2024
1 parent a9d800b commit 2584fc8
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 142 deletions.
2 changes: 1 addition & 1 deletion ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ int common_hal_i2ctarget_i2c_target_is_addressed(i2ctarget_i2c_target_obj_t *sel

*address = self->peripheral->hw->sar;
*is_read = !(self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_RX_FULL_BITS);
*is_restart = ((self->peripheral->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_RD_REQ_RESET) != 0);
*is_restart = ((self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_RESTART_DET_BITS) != 0);

common_hal_i2ctarget_i2c_target_ack(self, true);
return 1;
Expand Down
283 changes: 142 additions & 141 deletions shared-bindings/i2ctarget/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
//|
//| Example of emulating a simple device that can only handle single writes and reads::
//|
//|
//| import board
//| from i2ctarget import I2CTarget
//|
Expand All @@ -56,7 +55,7 @@
//| logger.setLevel(logging.INFO)
//| logger.addHandler(NamedStreamHandler())
//|
//| logger.info("\n\ncode starting...")
//| logger.info("\\n\\ncode starting...")
//|
//| # initialize an I2C target with a device address of 0x40
//| with I2CTarget(board.SCL, board.SDA, (0x40,)) as device:
Expand All @@ -69,7 +68,7 @@
//| # no request is pending
//| continue
//|
//| # `with` invokes I2CTargetRequest's functions to handle the necessary opening and closing of a transaction
//| # `with` invokes I2CTargetRequest's functions to handle the necessary opening and closing of a request
//| with i2c_target_request:
//|
//| # the address associated with the request
Expand All @@ -87,144 +86,146 @@
//| logger.info(f"write request to address 0x{address:02x}: {data}")
//| # for our emulated device, writes have no effect
//|
//| This example sets up an I2C device that can be accessed via another device running circuitpython::
//| import busio
//| import board
//| i2c = busio.I2C(board.SCL, board.SDA)
//|
//|
//| # perform a single read
//| while not i2c.try_lock():
//| pass
//| buffer = bytearray(1)
//| i2c.readfrom_into(0x40, buffer)
//| print(f"device responded with {buffer}")
//| i2c.unlock()
//|
//| # perform a single write
//| while not i2c.try_lock():
//| pass
//| buffer = bytearray(1)
//| buffer[0] = 0x12
//| i2c.writeto(0x40, buffer)
//| print(f"wrote {buffer} to device")
//| i2c.unlock()
//|
//| Typically, i2c devices support writes and reads to/from multiple register indices::
//| import board
//| from i2ctarget import I2CTarget
//|
//| import adafruit_logging as logging
//| from logging import NamedStreamHandler
//|
//| logger = logging.getLogger('i2ctarget')
//| logger.setLevel(logging.INFO)
//| logger.addHandler(NamedStreamHandler())
//|
//| # emulate a target with 16 registers
//| regs = [0] * 16
//| register_index = None
//|
//| logger.info("\n\ncode starting...")
//|
//| # initialize an I2C target with a device address of 0x40
//| with I2CTarget(board.SCL, board.SDA, (0x40,)) as device:
//|
//| while True:
//| # check if there's a pending device request
//| i2c_target_request = device.request()
//|
//| if not i2c_target_request:
//| # no request is pending
//| continue
//|
//| # work with the i2c request
//| with i2c_target_request:
//|
//| if not i2c_target_request.is_read:
//| # a write request
//|
//| # bytearray contains the request's first byte, the register's index
//| index = i2c_target_request.read(1)[0]
//|
//| # bytearray containing the request's second byte, the data
//| data = i2c_target_request.read(1)
//|
//| # if the request doesn't have a second byte, this is read transaction
//| if not data:
//|
//| # since we're only emulating 16 registers, read from a larger address is an error
//| if index > 15:
//| logger.error(f"write portion of read transaction has invalid index {index}")
//| continue
//|
//| logger.info(f"write portion of read transaction, set index to {index}'")
//| register_index = index
//| continue
//|
//| # since we're only emulating 16 registers, writing to a larger address is an error
//| if index > 15:
//| logger.error(f"write request to incorrect index {index}")
//| continue
//|
//| logger.info(f"write request to index {index}: {data}")
//| regs[index] = data[0]
//| else:
//| # our emulated device requires a read to be part of a full write-then-read transaction
//| if not i2c_target_request.is_restart:
//| logger.warning(f"read request without first writing is not supported")
//| # still need to respond, but result data is not defined
//| i2c_target_request.write(bytes([0xff]))
//| register_index = None
//| continue
//|
//| # the single read transaction case is covered above, so we should always have a valid index
//| assert(register_index is not None)
//|
//| # the write-then-read to an invalid address is covered above,
//| # but if this is a restarted read, index might be out of bounds so need to check
//| if register_index > 16:
//| logger.error(f"restarted read yielded an unsupported index")
//| i2c_target_request.write(bytes([0xff]))
//| register_index = None
//| continue
//|
//| # retrieve the data from our register file and respond
//| data = regs[register_index]
//| logger.info(f"read request from index {register_index}: {data}")
//| i2c_target_request.write(bytes([data]))
//|
//| # in our emulated device, a single read transaction is covered above
//| # so any subsequent restarted read gets the value at the next index
//| assert(i2c_target_request.is_restart is True)
//| register_index += 1
//|
//| This second example creates I2C target device that can be accessed via another device running circuitpython::
//| import busio
//| import board
//| i2c = busio.I2C(board.SCL, board.SDA)
//|
//| # perform a write transaction
//| while not i2c.try_lock():
//| pass
//| buffer = bytearray(2)
//| buffer[0] = 0x0b # the register index
//| buffer[1] = 0xa1 # the value
//| i2c.writeto(0x40, buffer)
//| print(f"wrote {buffer} to device")
//| i2c.unlock()
//|
//| # perform a full read transaction (write-then-read)
//| while not i2c.try_lock():
//| pass
//| index_buffer = bytearray(1)
//| index_buffer[0] = 0x0b
//| read_buffer = bytearray(1)
//| i2c.writeto_then_readfrom(0x40, index_buffer, read_buffer)
//| print(f"read from device index {index_buffer}: {read_buffer}")
//| i2c.unlock()
//|
//| Or accessed from Linux like this::
//| This example creates an I2C target device that can be accessed via another device as an I2C controller::
//|
//| import busio
//| import board
//| i2c = busio.I2C(board.SCL, board.SDA)
//|
//| # perform a single read
//| while not i2c.try_lock():
//| pass
//| buffer = bytearray(1)
//| i2c.readfrom_into(0x40, buffer)
//| print(f"device responded with {buffer}")
//| i2c.unlock()
//|
//| # perform a single write
//| while not i2c.try_lock():
//| pass
//| buffer = bytearray(1)
//| buffer[0] = 0x12
//| i2c.writeto(0x40, buffer)
//| print(f"wrote {buffer} to device")
//| i2c.unlock()
//|
//| Typically, i2c devices support writes and reads to/from multiple register indices as in this example ::
//|
//| import board
//| from i2ctarget import I2CTarget
//|
//| import adafruit_logging as logging
//| from logging import NamedStreamHandler
//|
//| logger = logging.getLogger('i2ctarget')
//| logger.setLevel(logging.INFO)
//| logger.addHandler(NamedStreamHandler())
//|
//| # emulate a target with 16 registers
//| regs = [0] * 16
//| register_index = None
//|
//| logger.info("\\n\\ncode starting...")
//|
//| # initialize an I2C target with a device address of 0x40
//| with I2CTarget(board.SCL, board.SDA, (0x40,)) as device:
//|
//| while True:
//| # check if there's a pending device request
//| i2c_target_request = device.request()
//|
//| if not i2c_target_request:
//| # no request is pending
//| continue
//|
//| # work with the i2c request
//| with i2c_target_request:
//|
//| if not i2c_target_request.is_read:
//| # a write request
//|
//| # bytearray contains the request's first byte, the register's index
//| index = i2c_target_request.read(1)[0]
//|
//| # bytearray containing the request's second byte, the data
//| data = i2c_target_request.read(1)
//|
//| # if the request doesn't have a second byte, this is read transaction
//| if not data:
//|
//| # since we're only emulating 16 registers, read from a larger address is an error
//| if index > 15:
//| logger.error(f"write portion of read transaction has invalid index {index}")
//| continue
//|
//| logger.info(f"write portion of read transaction, set index to {index}'")
//| register_index = index
//| continue
//|
//| # since we're only emulating 16 registers, writing to a larger address is an error
//| if index > 15:
//| logger.error(f"write request to incorrect index {index}")
//| continue
//|
//| logger.info(f"write request to index {index}: {data}")
//| regs[index] = data[0]
//| else:
//| # our emulated device requires a read to be part of a full write-then-read transaction
//| if not i2c_target_request.is_restart:
//| logger.warning(f"read request without first writing is not supported")
//| # still need to respond, but result data is not defined
//| i2c_target_request.write(bytes([0xff]))
//| register_index = None
//| continue
//|
//| # the single read transaction case is covered above, so we should always have a valid index
//| assert(register_index is not None)
//|
//| # the write-then-read to an invalid address is covered above,
//| # but if this is a restarted read, index might be out of bounds so need to check
//| if register_index > 16:
//| logger.error(f"restarted read yielded an unsupported index")
//| i2c_target_request.write(bytes([0xff]))
//| register_index = None
//| continue
//|
//| # retrieve the data from our register file and respond
//| data = regs[register_index]
//| logger.info(f"read request from index {register_index}: {data}")
//| i2c_target_request.write(bytes([data]))
//|
//| # in our emulated device, a single read transaction is covered above
//| # so any subsequent restarted read gets the value at the next index
//| assert(i2c_target_request.is_restart is True)
//| register_index += 1
//|
//| This second example creates I2C target device that can be accessed via another device as an I2C controller::
//|
//| import busio
//| import board
//| i2c = busio.I2C(board.SCL, board.SDA)
//|
//| # perform a write transaction
//| while not i2c.try_lock():
//| pass
//| buffer = bytearray(2)
//| buffer[0] = 0x0b # the register index
//| buffer[1] = 0xa1 # the value
//| i2c.writeto(0x40, buffer)
//| print(f"wrote {buffer} to device")
//| i2c.unlock()
//|
//| # perform a full read transaction (write-then-read)
//| while not i2c.try_lock():
//| pass
//| index_buffer = bytearray(1)
//| index_buffer[0] = 0x0b
//| read_buffer = bytearray(1)
//| i2c.writeto_then_readfrom(0x40, index_buffer, read_buffer)
//| print(f"read from device index {index_buffer}: {read_buffer}")
//| i2c.unlock()
//|
//| Or accessed from Linux like this::
//|
//| $ i2cget -y 1 0x40 0x0b
//| 0xff
Expand Down

0 comments on commit 2584fc8

Please sign in to comment.