跳轉到

範例:建立匯流排與裝置

範例程式與設定

此範例示範

  • 如何在 Protocol Exerciser 上建立匯流排與裝置介面。
  • 如何與控制器互動,並從目標裝置取得資訊。

這裡以 I3C 為例,但相同原則也適用於其他匯流排類型。

建立名為 run_i3c_example.py 的新檔案,並將下列程式碼複製進去:

run_i3c_example.py
import logging

from aqpxlib import AqProtocolExerciser
from aqpxlib.i3c import (
    ACUTE_DEFAULT_PID,
    PxI3CBus,
    PxI3CBaseController,
    PxI3C32BitRegisterTarget,
)
from aqpxlib.exceptions import PxAPIError

logger = logging.getLogger(__name__)

def exec_i3c_example():
    """示範如何與 Acute Protocol Exerciser 互動.

    步驟依下列順序執行:

    1. 建立並開啟與 Acute Protocol Exerciser 的連線.
    2. 設定匯流排上正確的電壓準位與上拉電阻.
    3. 建立 I3C 匯流排控制代碼介面.
    4. 將 I3C 控制器與目標裝置掛載到匯流排.
    5. 初始化 I3C 匯流排以執行 Dynamic Address Assignment.
    6. 對目標裝置執行寫入/讀取.
    7. 卸離裝置並關閉與 Protocol Exerciser 的連線.
    """

    with AqProtocolExerciser.connect(port=60600) as px_session:
        logger.info("Created an Exerciser session")

        # 在 SCL 接腳 0、SDA 接腳 1 上設定 I3C 匯流排
        i3c_bus = PxI3CBus(px_session, scl=0, sda=1)
        logger.info(f"Created {i3c_bus}")

        # 將電壓設為 3.3V,上拉電阻設為 1.5kΩ
        i3c_bus.voltage = 3300
        i3c_bus.pullup_resistance = 1500

        # 建立控制器裝置
        i3c_controller = PxI3CBaseController(px_session, name="i3c_controller")
        try:
            i3c_controller.attach_to_bus(i3c_bus)
        except PxAPIError:
            logger.warning("Multiple controller is not supported, using the existing controller")
            i3c_controller = i3c_bus.get_current_controller()

        logger.info(f"Added a I3C controller with name {i3c_controller.name}")

        # 建立目標裝置
        bcr = 0x00  # Bus Characteristic Register
        dcr = 0x00  # Device Characteristic Register
        pid = ACUTE_DEFAULT_PID | (0x01 << 32) | 0 # Provisioned ID

        i3c_target = PxI3C32BitRegisterTarget(
            px_session,
            name="i3c_target",
            static_addr=0x12,
            sub_address_type=PxI3C32BitRegisterTarget.SubAddressType.NONE,
            bcr=bcr,
            dcr=dcr,
            pid=pid,
        )
        i3c_target.attach_to_bus(i3c_bus)
        logger.info(f"Added a I3C 32-bit register target with name {i3c_target.name}")

        # 初始化 I3C 匯流排,流程依 I3C 規格
        i3c_controller.init_bus()
        logger.info("I3C bus initialized")

        # 取得目標裝置狀態以讀取已指派的動態位址
        assigned_address = i3c_target.assigned_address
        logger.info(f"Target assigned dynamic address: {assigned_address}")

        # 對目標裝置執行寫入/讀取
        is_ack = i3c_controller.private_write(assigned_address, [0xDE, 0xAD, 0xBE, 0xEF])
        logger.info(f"I3C target" + (" acknowledged the write" if is_ack else " did not acknowledge the write"))

        data = i3c_controller.private_read(assigned_address, 4)
        logger.info(f"I3C target read data: {[f'{byte:02x}' for byte in data]}")

        # 將裝置從匯流排卸離
        i3c_target.detach_from_bus()
        i3c_controller.detach_from_bus()
        logger.info(f"Detached the controller and target from the bus")


if __name__ == "__main__":
    logging.basicConfig(format='[%(levelname)s] %(message)s')
    logger.setLevel(logging.INFO)
    exec_i3c_example()

在終端機執行下列指令:

$ python run_i3c_example.py

輸出應類似:

[INFO] Created an Exerciser session
[INFO] Created I3C Bus (SCL: 0, SDA: 1)
[INFO] Added a I3C controller with name i3c_controller
[INFO] Added a I3C 32-bit register target with name i3c_target
[INFO] I3C bus initialized
[INFO] Target assigned dynamic address: 0x08
[INFO] I3C target acknowledged the write
[INFO] I3C target read data: ['0xde', '0xad', '0xbe', '0xef']
[INFO] Detached the controller and target from the bus

接下來逐步說明程式碼。

建立 session

首先要建立連線到 Protocol Exerciser 的 session。我們使用 with 陳述式,確保離開區塊時自動關閉 session。

with AqProtocolExerciser.connect(port=60600) as px_session:
    # session `px_session` 已開啟
    # 在此執行操作
    ...

# session `px_session` 已關閉

若要在 with 區塊外使用 AqProtocolExerciser,必須自行中斷連線。

建立匯流排控制代碼

接著要在 Protocol Exerciser 上設定匯流排控制代碼。此範例建立 I3C 匯流排。可設定匯流排的硬體參數,這必須符合你實際使用的硬體。此範例將 I3C 匯流排設為 3.3V、1.5kΩ 上拉電阻。

# 在 SCL 接腳 0、SDA 接腳 1 上設定 I3C 匯流排
i3c_bus = PxI3CBus(px_session, scl=0, sda=1)

典型的匯流排控制代碼會包含通道設定;I3C 匯流排以 sclsda 參數指定。

建構 PxI3CBus 物件時,會自動送出請求,在 Protocol Exerciser 上設定匯流排。

若設定成功,Protocol Exerciser 上的接腳定義會更新為: | PIN 0 | PIN 1 | PIN 2 | PIN 3 | PIN 4 | PIN 5 | PIN 6 | PIN 7 | | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | | I3C SCL | I3C SDA | (null) | (null) | (null) | (null) | (null) | (null) |

也可在 PxI3CBus 建構子傳入不同的 sclsda 來使用其他接腳。

匯流排控制代碼接腳衝突

你可以建立多個匯流排控制代碼,但必須確保接腳定義互不衝突。否則部分控制代碼會建立失敗。

建立裝置

接著建立裝置並掛載到匯流排。此範例建立一個控制器與一個目標裝置。

下列片段來自上方範例,用來建立 PxI3CBaseControllerPxI3C32BitRegisterTarget:

# 建立控制器裝置
i3c_controller = PxI3CBaseController(px_session, name="i3c_controller")
try:
    i3c_controller.attach_to_bus(i3c_bus)
except PxAPIError as e:
    i3c_controller = i3c_bus.get_current_controller()

# 建立目標裝置
bcr = 0x00  # Bus Characteristic Register
dcr = 0x00  # Device Characteristic Register
pid = ACUTE_DEFAULT_PID | (0x01 << 32) | 0 # Provisioned ID

i3c_target = PxI3C32BitRegisterTarget(
    px_session,
    name="i3c_target",
    static_addr=0x12,
    sub_address_type=PxI3C32BitRegisterTarget.SubAddressType.NONE,
    bcr=bcr,
    dcr=dcr,
    pid=pid,
)
i3c_target.attach_to_bus(i3c_bus)

執行操作

裝置都準備好後,即可透過控制器對目標裝置操作。

I3C 必須先初始化匯流排,以處理位址指派程序。

# 初始化 I3C 匯流排,流程依 I3C 規格
i3c_controller.init_bus()
logger.info("I3C bus initialized")

完成後,I3C 匯流排上的裝置都應可使用,並可取得控制器指派的動態位址。

# 取得目標裝置已指派的動態位址
assigned_address = i3c_target.assigned_address
logger.info(f"Target assigned dynamic address: {assigned_address}")

接著對目標裝置寫入資料並讀回。

# 對目標裝置執行寫入/讀取
is_ack = i3c_controller.private_write(assigned_address, [0xDE, 0xAD, 0xBE, 0xEF])
logger.info(f"I3C target" + (" acknowledged the write" if is_ack else " did not acknowledge the write"))

data = i3c_controller.private_read(assigned_address, 4)
logger.info(f"I3C target read data: {[f'{byte:02x}' for byte in data]}")