跳转至

I2C 8 位地址存储器目标

PxI2C8BitAddressMemoryTarget 在 I2C(或 I3C)总线上模拟字节寻址存储器器件。控制器以 7 位 I2C 地址 加上 8 位存储器偏移(子地址)访问器件,再读写连续字节块。

当你要测试控制器驱动程序、EEPROM 风格外设,或以线性存储器数组而非固定 32 位寄存器布局作为后端的寄存器文件时,这个目标很有用。

存储器模型

  • 256 字节 后端存储(0x00–0xFF)。
  • 创建时配置的 静态 I2C 地址(例如 0x50)。
  • 8 位子地址 作为写入事务的第一个数据字节送出,或在带子地址的读取序列之前写入。

总线上典型写入如下:

START → ADDR+W → SUB_ADDR → DATA[0] → DATA[1] → … → STOP

典型带子地址读取如下:

START → ADDR+W → SUB_ADDR → Sr → ADDR+R → DATA[0] → DATA[1] → … → STOP

Exerciser 在总线传输期间直接更新后端存储器。Python 可通过 read_mem / write_mem 查看或预载存储器,不必经过 I2C 控制器。

快速开始

将目标挂载到 I2C 总线,并从 Python 读写存储器:

from aqpxlib import AqProtocolExerciser
from aqpxlib.i2c import PxI2CBus, PxI2C8BitAddressMemoryTarget

with AqProtocolExerciser.connect(port=60600) as px:
    i2c_bus = PxI2CBus(px, scl=0, sda=1)
    target = PxI2C8BitAddressMemoryTarget(px, address=0x50)
    target.attach_to_bus(i2c_bus)

    target.write_mem(0x10, [0x01, 0x02, 0x03, 0x04])
    assert target.read_mem(0x10, 4) == [0x01, 0x02, 0x03, 0x04]

    target.detach_from_bus()

控制器访问

在同一条总线上使用 PxI2CController,以真实控制器的方式操作目标:

from aqpxlib import AqProtocolExerciser
from aqpxlib.i2c import PxI2CBus, PxI2CController, PxI2C8BitAddressMemoryTarget

with AqProtocolExerciser.connect(port=60600) as px:
    i2c_bus = PxI2CBus(px, scl=0, sda=1)
    target = PxI2C8BitAddressMemoryTarget(px, address=0x50)
    target.attach_to_bus(i2c_bus)

    i2c_controller = PxI2CController(px)
    i2c_controller.attach_to_bus(i2c_bus)

    sub_address = 8
    data = [0xDE, 0xAD, 0xBE, 0xEF]

    i2c_controller.i2c_write_addr(target.address, sub_address, data)
    read_back = i2c_controller.i2c_read_addr(target.address, sub_address, len(data))
    assert read_back == data

    # 确认后端存储与控制器写入的内容一致.
    assert target.read_mem(sub_address, len(data)) == data

    i2c_controller.detach_from_bus()
    target.detach_from_bus()

总线访问事件

当总线上其他器件读写此目标时,exerciser 会在目标实例上发出 memory_target_write_event 与 memory_target_read_event。这些是共用事件类型(I3C、SPI 等其他存储器目标也使用):

事件 Payload 字段 发出时机
memory_target_write_event addr, data 总线写入传输完成后
memory_target_read_event addr, count 总线读取传输完成后

为每种事件类型分别订阅处理函数:

from aqpxlib.event import PxMemoryTargetReadEvent, PxMemoryTargetWriteEvent

@target.on_event(PxMemoryTargetWriteEvent)
def on_memory_target_write(write: PxMemoryTargetWriteEvent):
    print(f"Bus write @ 0x{write.addr:02x}: {write.data.hex()}")

@target.on_event(PxMemoryTargetReadEvent)
def on_memory_target_read(read: PxMemoryTargetReadEvent):
    print(f"Bus read @ 0x{read.addr:02x}, {read.count} bytes")

事件只反映总线活动。从 Python 调用 read_mem / write_mem 不会发出存储器目标事件。

另见: 事件注册与处理函数设置。

I3C 总线支持

PxI2C8BitAddressMemoryTarget 可挂载到 I3C 总线(valid_buses 包含 "i3c" 与 "i2c")。器件在 I3C SDA 线上以 I2C 风格目标运行。

API 参考

PxI2C8BitAddressMemoryTarget

PxI2C8BitAddressMemoryTarget(
    exerciser: AqProtocolExerciser,
    address: int = 0,
    config: PxI2C8BitAddressMemoryTargetConfig | None = None,
    *args,
    **kwargs
)

Bases: PxAbstractTarget[PxI2C8BitAddressMemoryTargetConfig, None]

I2C byte-addressable memory target.

Emulates a 256-byte memory device on an I2C or I3C bus. Controllers access memory using a 7-bit device address plus an 8-bit sub-address (memory offset).

Use read_mem and write_mem to access backing store from Python. Bus reads and writes from a controller emit memory_target_read_event and memory_target_write_event notifications.

METHOD DESCRIPTION
add_event_handler

Add an event handler to the current device instance, by event class or event name.

remove_event_handler

Remove an event handler from the current device instance, by event class or event name.

get_event_handlers

Retreive handlers registerd on this device.

on_event

Add an event handler to the instance by decorator, by event class or event name.

match

Return whether a device config describes a device of this class.

update_additional_data

Atomically update additional_data with revision-aware retry.

update_config

Set the config of the target.

set_config

Set the config of the target.

attach_to_bus

Attach the target to a bus.

detach_from_bus

Detach the device from the bus.

perform_operation

Send an operation.

read_mem

Read bytes from backing store via the Protocol Exerciser API.

write_mem

Write bytes to backing store via the Protocol Exerciser API.

ATTRIBUTE DESCRIPTION
available_events_map

Map each available event name to its id in event topics.

TYPE: dict[str, str]

is_attached

Check if the device is attached to a bus.

TYPE: bool

state

Get the state of the device.

TYPE: DeviceStateT | None

name

Get the name of the device.

TYPE: str

cts_op_name

Get the name of CTS operation. Currently not available now.

TYPE: str | None

additional_data

Get the opaque additional data blob associated with this device.

TYPE: bytes

config

Get the config of the device.

TYPE: DeviceConfigT | None

address

Static address of the device.

TYPE: int

available_events_map

available_events_map: dict[str, str]

Map each available event name to its id in event topics.

is_attached

is_attached: bool

Check if the device is attached to a bus.

state

state: DeviceStateT | None

Get the state of the device.

name

name: str

Get the name of the device.

cts_op_name

cts_op_name: str | None

Get the name of CTS operation. Currently not available now.

additional_data

additional_data: bytes

Get the opaque additional data blob associated with this device.

config

config: DeviceConfigT | None

Get the config of the device.

address

address: int

Static address of the device.

add_event_handler

add_event_handler(event: str, handler: Callable[[Any], Any]) -> None
add_event_handler(event: type[EventT], handler: Callable[[EventT], Any]) -> None
add_event_handler(
    event: str | type[PxAbstractEvent], handler: Callable[[Any], Any]
) -> None

Add an event handler to the current device instance, by event class or event name.

remove_event_handler

remove_event_handler(
    event: str | type[PxAbstractEvent], handler: Callable[[Any], Any] | None = None
) -> None

Remove an event handler from the current device instance, by event class or event name.

get_event_handlers

get_event_handlers(
    filter_by: Callable[[str], bool] | None = None,
) -> dict[str, list[Callable[[Any], Any]]]

Retreive handlers registerd on this device.

Handlers are always scoped to this device; an optional filter_by is applied on friendly event names.

on_event

on_event(event_type: str) -> Callable[[Callable[..., Any]], Callable[..., Any]]
on_event(
    event_type: type[EventT],
) -> Callable[[Callable[[EventT], Any]], Callable[[EventT], Any]]
on_event(
    event_type: str | type[PxAbstractEvent],
) -> Callable[[Callable[..., Any]], Callable[..., Any]]

Add an event handler to the instance by decorator, by event class or event name.

match

match(config: PxAbstractDeviceConfig) -> bool

Return whether a device config describes a device of this class.

update_additional_data

update_additional_data(updater: Callable[[bytes], bytes]) -> None

Atomically update additional_data with revision-aware retry.

update_config

update_config(updater: Callable[[Any], Any]) -> None

Set the config of the target.

set_config

set_config(config: DeviceConfigT) -> None

Set the config of the target.

attach_to_bus

attach_to_bus(bus: PxAbstractBus) -> None

Attach the target to a bus.

This method is used to make the device aware of the bus it is connected to. It is used to set the bus attribute of the device.

Note

This method will not automatically create an actual instance on the Protocol Exerciser until user call the attach_to_bus method.

PARAMETER DESCRIPTION

bus

The bus to attach the device to

TYPE: PxAbstractBus

RAISES DESCRIPTION
ValueError

If the device is already attached to a bus

detach_from_bus

detach_from_bus() -> None

Detach the device from the bus.

The opposite of the attach_to_bus method.

perform_operation

perform_operation(
    operation: PxDeviceOperation, *, timeout: int | None = None
) -> PxDeviceOperation

Send an operation.

PARAMETER DESCRIPTION

operation

Device operation to perform.

TYPE: PxDeviceOperation

timeout

Optional base STOP-handshake wait in milliseconds. When omitted, the instrument uses subsystem defaults.

TYPE: int | None DEFAULT: None

read_mem

read_mem(addr: int, count: int) -> list[int]

Read bytes from backing store via the Protocol Exerciser API.

This does not perform an I2C bus transaction. Use a PxI2CController to exercise the target over the bus.

PARAMETER DESCRIPTION

addr

Starting 8-bit memory address (0x00-0xFF).

TYPE: int

count

Number of bytes to read.

TYPE: int

RETURNS DESCRIPTION
list[int]

Bytes read from backing store as a list of integers (0-255).

write_mem

write_mem(addr: int, data: list[int]) -> None

Write bytes to backing store via the Protocol Exerciser API.

This does not perform an I2C bus transaction. Use a PxI2CController to exercise the target over the bus.

PARAMETER DESCRIPTION

addr

Starting 8-bit memory address (0x00-0xFF).

TYPE: int

data

Bytes to write as a list of integers (0-255). Must fit within the 256-byte memory map.

TYPE: list[int]