範例:建立匯流排與裝置
範例程式與設定¶
此範例示範
- 如何在 Protocol Exerciser 上建立匯流排與裝置介面。
- 如何與控制器互動,並從目標裝置取得資訊。
這裡以 I3C 為例,但相同原則也適用於其他匯流排類型。
建立名為 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()
在終端機執行下列指令:
輸出應類似:
[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Ω 上拉電阻。
典型的匯流排控制代碼會包含通道設定;I3C 匯流排以 scl 與 sda 參數指定。
建構 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 建構子傳入不同的 scl 與 sda 來使用其他接腳。
匯流排控制代碼接腳衝突
你可以建立多個匯流排控制代碼,但必須確保接腳定義互不衝突。否則部分控制代碼會建立失敗。
建立裝置¶
接著建立裝置並掛載到匯流排。此範例建立一個控制器與一個目標裝置。
下列片段來自上方範例,用來建立 PxI3CBaseController 與 PxI3C32BitRegisterTarget:
# 建立控制器裝置
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 匯流排上的裝置都應可使用,並可取得控制器指派的動態位址。
# 取得目標裝置已指派的動態位址
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]}")