I3C_temperature_sensor_NXP_P3T1035_sensor
I3C temperature sensor - (NXP P3T1035 sensor)
目前Linux source code可找到P3T1085的driver
[PATCH 0/3] iio: temperature: Add support for P3T1085
比較P3T1035和P3T1085的register map差別,查看datasheet
D:\★Project\137.imx95\datasheet\i3c_temperature_sensor
P3T1035XUK_P3T2030XUK.pdf
P3T1085UK.pdf
或是參考:
Adding support to P3T1755 on Linux - NXP Community
目前NXP i.mx95 EVK的i3c並未expose到/dev下
Expose the i3c device to the linux /dev directory - NXP Community
問題:
Submit Form
問:
We are currently evaluating the I3C interface support on our custom board and have examined the Linux kernel versions **6.6.52_2.2.0** and **6.12.3_1.0.0**. During our review, we observed that the I3C node is not present in the **arch/arm64/boot/dts/freescale/imx95.dtsi** file.
Based on this observation, we are uncertain whether the I3C controller for the i.MX95 SoC is currently supported in these kernel releases or if there might be a configuration or implementation detail we are missing.
Could you kindly confirm whether I3C support for the i.MX95 is available in the current kernel versions, or if there are plans to enable it in future updates?
Thanks!
BR,
Richard
NXP FAE回答:
I3C is not supported by i.MX95 A1. It will be supported by i.MX95 B0.
Ticket on KIWI:
Title Unavailable | Site Unreachable
Disable the RTL8211 PHY on basedboard.
Then enabling I3C in device tree.
There is i3c shown on /sys/bus.
root@edm-imx95-8gb:~# ls /sys/bus/i3c/ devices/ drivers_autoprobe uevent drivers/ drivers_probe root@edm-imx95-8gb:~# ls /sys/bus/i3c/devices/i3c-0/ bcr hdrcap mode subsystem/ current_master hotjoin of_node/ uevent dcr i2c_scl_frequency pid dynamic_address i3c_scl_frequency power/ root@edm-imx95-8gb:~# ls /sys/bus/i3c/devices/i3c-0/
Currently, on edm-imx95-evm, the I3C device is temperature sensor - NXP P3T1035 sensor.
There is no existing driver in linux kernel 6.12.20.
So SW RD would need to take some time to develop a driver for NXP P3T1035.
Task:
- EDM-IMX95的I3C線路設計驗證
- 評估P3T1035 temperature sensor linux driver開發
p3t10xx_difference.md
P3T1085 vs P3T1035 驅動程式開發差異分析
本文檔旨在從 Linux 驅動程式開發的角度,比較 NXP P3T1085 與 P3T1035 溫度感測器的主要差異。分析基於對應的產品數據手冊。
總結
P3T1035 和 P3T1085 在核心的溫度量測功能上非常相似(12-bit 解析度,0.0625 °C),且共用大部分的 I3C 功能。然而,從驅動程式的角度來看,存在幾個關鍵差異,使得無法直接重用 P3T1085 驅動程式。
主要差異包括:
- 硬體接腳與功能:P3T1085 擁有
ALERTPin 和可配置的 I2C 地址 Pin (A0),而 P3T1035 則無。 - I2C 地址:P3T1085 透過
A0Pin 可配置 4 個地址;P3T1035 則提供 8 種工廠預設的固定地址,由具體的型號決定。 - 配置暫存器:兩者的配置暫存器 (
Conf) 在位元定義、大小(16-bit vs 8-bit)和功能上都有顯著不同。 - 中斷機制:P3T1085 使用
ALERTPin 進行硬體中斷通知,而 P3T1035 則依賴 I3C 的 In-Band-Interrupt (IBI) 或 I2C 的輪詢。 - I3C/I2C 裝置 ID:兩者的 I3C Provisional ID 和 I2C Static Address 不同,需要在驅動程式中分別識別。
- 工作電壓:兩者的建議工作電壓範圍不同。
詳細差異比較
| 特性 (Feature) | P3T1085 | P3T1035/P3T2030 | 驅動程式影響 |
|---|---|---|---|
| 硬體接腳 | 6-pin (WLCSP6),包含 ALERT 和 A0 (地址選擇) |
4-pin (WLCSP4),無 ALERT 和 A0 |
P3T1035 驅動程式不需處理硬體中斷 (IRQ) 或 SMBus Alert。地址是固定的。 |
| I2C 地址 | 4 個可選地址 (1001000b - 1001011b),由 A0 Pin 決定 |
8 個固定地址 (1110000b - 1110111b),由產品型號決定 |
驅動程式的 i2c_device_id 表需要包含 P3T1035 的所有可能地址。 |
| I3C Provisional ID | Manufacturer: 0x011B, Device: 0x1529 |
Manufacturer: 0x011B, Device: 0x152B |
驅動程式的 i3c_device_id 表需要新增 P3T1035 的 ID。 |
| 供電電壓 | 1.4 V to 3.6 V | 1.4 V to 1.98 V | 驅動程式本身影響不大,但硬體設計需注意。 |
配置暫存器 (Conf) |
16-bit (0x01)。包含 TM (溫控模式), POL (極性), HYS (遲滯) 控制位。 |
8-bit (0x01)。包含 LC (閂鎖控制) 位。沒有 TM, POL, HYS。 |
這是最大的軟體差異。驅動程式需要根據裝置型號來決定讀寫 Conf 暫存器的方式(8-bit 或 16-bit)以及支援的功能。 |
| 溫度限制暫存器 | TLOW (0x02), THIGH (0x03)。預設值為 -75°C 和 +127.9°C。 |
tLOW (0x02), tHIGH (0x03)。預設值為 -10°C 和 +60°C。 |
預設值不同,但功能和格式相同。 |
| 中斷/警報機制 | 透過 ALERT Pin 輸出。支援 SMBus Alert。 |
無 ALERT Pin。在 I3C 模式下使用 IBI。在 I2C 模式下需由主機輪詢 Conf 暫存器的 FH/FL 旗標。 |
P3T1035 的驅動程式若要支援溫度警報,在 I2C 下必須實作輪詢或 sysfs 觸發的檢查。I3C 則需處理 IBI。 |
| 特殊功能 | 標準 I2C/I3C 功能。 | 支援 I2C Multiple Device Access (MDA),可對匯流排上所有 P3T1035 廣播讀寫。 | 這是一個 P3T1035 特有的功能,標準的 IIO 驅動程式框架可能不會直接支援,但可以透過客製化的 sysfs 介面來實現。 |
| 轉換速率 | 0.25, 1, 4, 16 Hz | 0.25, 1, 4, 8 Hz | 最高轉換速率不同。如果驅動程式提供設定轉換速率的功能,需要注意這個上限。 |
2. 如何基於 P3T1085 驅動程式新增對 P3T1035 的支援
基於上述差異和現有的 p3t1085 驅動程式碼,您可以按照以下步驟來新增對 p3t1035 的支援。核心思想是將現有驅動程式修改為一個通用的、能同時支援這兩種晶片的驅動程式。
步驟 1: 更新裝置 ID 和命名
為了讓驅動程式能夠識別 P3T1035,您需要更新裝置 ID 表。
-
修改
p3t1085.h:
在enum p3t1085_hw_id中新增P3T1035_ID。// drivers/iio/temperature/p3t/p3t1085.h enum p3t1085_hw_id { P3T1085_ID, P3T1035_ID, // <-- 新增此行 }; -
修改
p3t1085_i3c.c:
在p3t1085_i3c_ids陣列中新增 P3T1035 的 I3C ID。P3T1035 的 Device ID 是0x152B。// drivers/iio/temperature/p3t/p3t1085_i3c.c static const struct i3c_device_id p3t1085_i3c_ids[] = { I3C_DEVICE(0x011B, 0x1529, (void *)P3T1085_ID), I3C_DEVICE(0x011B, 0x152B, (void *)P3T1035_ID), // <-- 新增此行 { /* sentinel */ }, }; -
(可選但建議) 重新命名驅動程式:
為了反映驅動程式支援多個型號,建議將檔案和驅動程式名稱從p3t1085改為更通用的p3t10xx。這會涉及檔案重命名 (p3t1085_core.c->p3t10xx_core.c等) 和修改Kconfig/Makefile。
步驟 2: 在驅動核心中區分裝置型號
核心邏輯需要知道目前正在處理的是哪個裝置。
-
修改
p3t1085_data結構:
在p3t1085.h的p3t1085_data結構中加入一個成員來儲存裝置 ID。// drivers/iio/temperature/p3t/p3t1085.h struct p3t1085_data { struct device *dev; struct regmap *regmap; enum p3t1085_hw_id hw_id; // <-- 新增此行 }; -
修改
p3t1085_probe():
在p3t1085_core.c的p3t1085_probe函式中,儲存從 I3C/I2C probe 函式傳入的hw_id,並根據 ID 設定 IIO 裝置的名稱。// drivers/iio/temperature/p3t/p3t1085_core.c int p3t1085_probe(struct device *dev, int irq, int hw_id, struct regmap *regmap) { // ... data = iio_priv(iio_dev); data->dev = dev; data->regmap = regmap; data->hw_id = hw_id; // <-- 儲存裝置 ID if (hw_id == P3T1035_ID) iio_dev->name = "p3t1035"; else iio_dev->name = "p3t1085"; iio_dev->modes = INDIO_DIRECT_MODE; // ... }
步驟 3: 處理暫存器差異
這是最關鍵的一步。由於 Conf 暫存器的大小不同,regmap 的設定需要特別小心。
-
Regmap 設定:
目前的p3t1085_i3c_regmap_config設定了val_bits = 16。這對於讀取兩個裝置的 16-bit 溫度暫存器是正確的。然而,P3T1035 的Conf暫存器是 8-bit 的。當使用 16-bitregmap寫入時,可能會產生非預期的行為。一個安全的作法是,在需要設定 P3T1035 的
Conf暫存器時,使用regmap_write_byte()(如果 regmap 支援) 或直接使用i3c_device_raw_write()。不過,目前的驅動程式並未寫入任何暫存器,只進行了讀取。
p3t1085_read_raw函式只讀取溫度暫存器,其格式對兩種裝置是兼容的。因此,在目前唯讀的實作下,您暫時不需要修改regmap的邏輯。 -
未來擴充:
如果您未來需要新增設定功能 (例如設定轉換速率),您必須加入裝置型號的判斷:// 偽代碼:設定轉換速率 static int p3t10xx_set_conversion_rate(struct p3t1085_data *data, u8 rate) { if (data->hw_id == P3T1035_ID) { // P3T1035: 8-bit Conf register // 注意 rate 的值域 (0-3 for 0.25/1/4/8 Hz) return regmap_update_bits(data->regmap, P3T1085_REG_CFGR, GENMASK(6, 5), rate << 5); } else { // P3T1085: 16-bit Conf register // 注意 rate 的值域 (0-3 for 0.25/1/4/16 Hz) return regmap_update_bits(data->regmap, P3T1085_REG_CFGR, GENMASK(14, 13), rate << 13); } }注意:上述位元遮罩和位移需要根據數據手冊仔細確認。
步驟 4: 建立 I2C 版本的驅動
您提供的檔案中沒有 p3t1085_i2c.c,但通常會有一個。您需要建立或修改它來支援 P3T1035 的 I2C 介面。
-
建立
p3t1085_i2c.c(如果不存在): -
定義 I2C ID 表:
// drivers/iio/temperature/p3t/p3t1085_i2c.c (假設) static const struct i2c_device_id p3t1085_i2c_ids[] = { { "p3t1085", (kernel_ulong_t)P3T1085_ID }, // 新增 P3T1035 的 8 個固定地址 { "p3t1035a", (kernel_ulong_t)P3T1035_ID }, // I2C Addr: 0x70 { "p3t1035b", (kernel_ulong_t)P3T1035_ID }, // I2C Addr: 0x71 // ... 以此類推,直到 0x77 { } }; MODULE_DEVICE_TABLE(i2c, p3t1085_i2c_ids); // i2c_driver 結構體中要使用這個 id_table -
I2C Probe 函式:
Probe 函式會從i2c_device_id中取得P3T1035_ID,然後呼叫通用的p3t1085_probe核心函式。
結論
總結來說,將 p3t1085 驅動程式擴充以支援 p3t1035 是完全可行的。主要工作是:
- 在 I3C 和 I2C 的 ID 表中加入 P3T1035 的識別資訊。
- 在核心資料結構和 probe 函式中加入邏輯來區分和儲存裝置型號。
- 由於目前驅動程式是唯讀的,暫存器讀取邏輯可以直接重用。若未來要新增寫入配置的功能,則必須根據裝置型號處理 8-bit 和 16-bit
Conf暫存器的差異。
CONFIG_IIO_P3T1085
CONFIG_IIO_P3T1085_I3C
root@edm-imx95-8gb:~# modprobe p3t1085_i3c
root@edm-imx95-8gb:~# lsmod
Module Size Used by
p3t1085_i3c 12288 0
p3t1085_core 12288 1 p3t1085_i3c
看來p3t1085_i3c的probe function完全沒跑到 ---> device tree的問題
I3C bus有出現在i2cdetect的list內,但下i2cdetect -y 8完全掃不到東西,邏輯分析儀也沒顯示任何信號
root@edm-imx95-8gb:~# i2cdetect -l
i2c-8 i2c 42520000.i3c I2C adapter
嘗試方向1: 觀察i.mx93上的I3C bus
(選擇EDM-IMX93觀察I3C的原因:
- 其pinmux可configure成I2C或I3C模式
- I3C上有接兩個EEPROM (driver沒問題)
)
要如何觸發產生I3C信號以供觀察
由pinmux表可知:
arch/arm64/boot/dts/freescale/imx93-pinfunc.h
#define MX93_PAD_I2C1_SCL__LPI2C1_SCL 0x0170 0x0320 0x0000 0x10 0x0
#define MX93_PAD_I2C1_SCL__I3C1_SCL 0x0170 0x0320 0x0000 0x1 0x0
#define MX93_PAD_I2C1_SDA__LPI2C1_SDA 0x0174 0x0324 0x0000 0x10 0x0
#define MX93_PAD_I2C1_SDA__I3C1_SDA
i.mx93的I2C1_SCL/SDA pin可以設定成下面三種控制方式
1.I2C
2.I3C但走I2C protocal
3.I3C走I3C protocal
arch/arm64/boot/dts/freescale/imx93.dtsi
i3c1: i3c@44330000 {
compatible = "silvaco,i3c-master-v1";
reg = <0x44330000 0x10000>;
interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <3>;
#size-cells = <0>;
clocks = <&clk IMX93_CLK_BUS_AON>,
<&clk IMX93_CLK_I3C1_GATE>,
<&clk IMX93_CLK_I3C1_SLOW>;
clock-names = "pclk", "fast_clk", "slow_clk";
status = "disabled";
};
lpi2c1: i2c@44340000 {
compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c";
reg = <0x44340000 0x10000>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX93_CLK_LPI2C1_GATE>,
<&clk IMX93_CLK_BUS_AON>;
clock-names = "per", "ipg";
dmas = <&edma1 7 0 0>, <&edma1 8 0 FSL_EDMA_RX>;
dma-names = "tx", "rx";
status = "disabled";
};

邏輯分析儀的量測40 pin header上的VH2_SDA輸出訊號

觀察1: EDM-IMX93: 當I2C bus1設定成I2C模式時下i2cdetect觀察結果與LA上訊號
root@edm-imx93:~# i2cdetect -l
i2c-0 i2c 44340000.i2c I2C adapter
i2c-1 i2c 44350000.i2c I2C adapter
i2c-2 i2c 42530000.i2c I2C adapter
外露在40 pin的connector的I2C controller為44340000
arch/arm64/boot/dts/freescale/imx93-edm.dtsi
&lpi2c1 {
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <400000>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pinctrl_lpi2c1>;
pinctrl-1 = <&pinctrl_lpi2c1>;
status = "okay";
};
做I2C scan時LA的信號:

| 事件 | 發起者 | 目的 | 解碼結果 |
|---|---|---|---|
1. 呼叫位址 0x51 (Read) |
Host | 選擇要通訊的從機並設定為讀取模式。 | Setup Read to [0x51] |
| 2. 回應位址 | Slave (EEPROM) | 告訴主機 "我已準備好"。 | + ACK |
| 3. 發送資料 | Slave (EEPROM) | 將記憶體中的一個位元組資料 (0xFF) 送出。 |
0xFF |
| 4. 回應資料 | Host | 告訴從機 "我已收到且不再需要更多資料"。 | + NAK |
| 此時device tree中的i2c設定 | |||
| arch/arm64/boot/dts/freescale/imx93-edm.dtsi |
&lpi2c1 {
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <400000>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pinctrl_lpi2c1>;
pinctrl-1 = <&pinctrl_lpi2c1>;
status = "okay";
eeprom_baseboard: eeprom@51 {
compatible = "atmel,24c02";
reg = <0x51>;
pagesize = <16>;
status = "okay";
};
};
root@edm-imx93:~# cat /sys/bus/i2c/devices/0-0051/eeprom
I2C bus(原生I2C)設定成400k Hz的情況下讀取EEPROM

I2C bus(原生I2C)設定成100k Hz的情況下讀取EEPROM

觀察2: EDM-IMX93: 當I2C bus1設定成I3C模式(但走i2c protocal)時下i2cdetect觀察結果與LA上訊號
arch/arm64/boot/dts/freescale/imx93-edm.dtsi
/*Disable lpi2c1
&lpi2c1 {
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <400000>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pinctrl_lpi2c1>;
pinctrl-1 = <&pinctrl_lpi2c1>;
status = "okay";
};
*/
&i3c1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i3c1>;
i2c-scl-hz = <400000>;
status = "okay";
};
&iomuxc {
pinctrl_lpi2c1: lpi2c1grp {
fsl,pins = <
MX93_PAD_I2C1_SCL__LPI2C1_SCL 0x40000b9e
MX93_PAD_I2C1_SDA__LPI2C1_SDA 0x40000b9e
>;
};
pinctrl_i3c1: i3c1grp {
fsl,pins = <
MX93_PAD_I2C1_SCL__I3C1_SCL 0x40000186
MX93_PAD_I2C1_SDA__I3C1_SDA 0x40000186
>;
};
};
root@edm-imx93:~# i2cdetect -l
i2c-1 i2c 44350000.i2c I2C adapter
i2c-2 i2c 42530000.i2c I2C adapter
i2c-8 i2c 44330000.i3c I2C adapter
root@edm-imx93:~# i2cdetect -y 8
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
結果: i2cdetect指令掃描裝置沒反應,邏輯分析儀上也看不到SDA/SCL信號有變化
AI解析strace log:
strace i2cdetect -y 8
探測迴圈中的關鍵失敗點 ❌
i2cdetect 的工作方式是遍歷所有可能的 I2C 位址(從 0x03 到 0x77),並嘗試與每個位址進行一次簡短的通訊。這個過程在 strace 中體現為一個重複的模式:
// 步驟 A: 設定目標從裝置位址 (例如 0x08)
ioctl(3, _IOC(_IOC_NONE, 0x7, 0x3, 0), 0x8) = 0
// 步驟 B: 嘗試執行一次 I2C 讀取操作來探測裝置是否存在
ioctl(3, _IOC(_IOC_NONE, 0x7, 0x20, 0), 0xffffd19cd9f8) = -1 ENOENT (No such file or directory)
// 步驟 C: 因為步驟 B 失敗了,所以在螢幕上印出 "--"
write(1, "-- ", 3)
步驟 A (I2C_SLAVE): ioctl 呼叫成功(回傳值為 0)。這一步是告訴驅動程式:「我接下來要通訊的目標是位址 0x08」。驅動程式接受了這個指令。
步驟 B (探測操作): 這是失敗的關鍵點。i2cdetect 嘗試執行一個 I2C/SMBus 的讀取操作來確認該位址上是否有裝置回應。然而,這個 ioctl 呼叫失敗了,並且回傳了錯誤碼 -1 ENOENT。
錯誤碼 ENOENT 的意義: ENOENT 通常的意義是 "No such file or directory"。但在 ioctl 的上下文中,它經常被驅動程式用來表示 「不支援此項操作」 或 「沒有實現這個功能」。這意味著 i3c-to-i2c 的驅動程式雖然註冊了一個 I2C 適配器,但它沒有實現 i2cdetect 用來探測裝置所需要的那個特定的 ioctl 命令(很可能是 I2C_SMBUS_READ_BYTE)。
結論:i2cdetect 向核心驅動程式發出了「請在SDA/SCL上對位址X進行讀取」的請求,但驅動程式直接回覆「我不懂這個請求」,因此根本就沒有嘗試去驅動硬體產生任何訊號。這就是為什麼你的邏輯分析儀上什麼都看不到。
## 根本原因與解決方向
這個問題的根本原因在於 **I3C 和 I2C 的差異** 以及 **工具與驅動程式之間的相容性問題**。
1. **驅動程式相容性不完整**: 你的 `i2c-8` 是一個 I3C 控制器 (`44330000.i3c`),它透過一個相容層(compatibility layer)模擬成一個 I2C bus。然而,這個模擬層可能並不完整,它可能只實現了基本的 I2C 傳輸功能,但沒有實現 `i2c-tools`(`i2cdetect` 屬於這個工具集)所依賴的特定 SMBus 探測功能。
2. **`i2cdetect` 的探測方式**: `i2cdetect` 預設使用 `I2C_SMBUS_READ_BYTE` 這種快速、無害的方式來探測設備。如果驅動程式不支援這個 `ioctl`,掃描就會失敗。
**`i2cdump` 也失敗了,並且失敗的原因與 `i2cdetect` 完全相同。** 這幾乎可以100%確定問題出在您的 **I3C核心驅動程式** 上,它沒有完整地實現 `i2c-tools` 所需的 I2C/SMBus 功能。
這意味著您的 I3C 驅動程式所提供的 I2C 相容層,不僅不支援 `i2cdetect` 所用的探測功能,**連最基本的 I2C/SMBus 位元組讀取功能 (`read byte data`) 都沒有實現或暴露給使用者空間**。
如果設備樹配置看起來沒問題,您可以嘗試編寫一個非常簡單的 C 語言程式,使用最底層、最通用的 `I2C_RDWR` `ioctl` 來操作設備。這個 `ioctl` 比 SMBus 的 `ioctl` 更為基礎,有些不完整的驅動程式可能只實現了它。如果 `I2C_RDWR` 能成功,就說明驅動程式有基本功能,但缺少了上層的 SMBus 封裝。
直接將eeprom加入device tree中
arch/arm64/boot/dts/freescale/imx93-edm.dtsi
#include <dt-bindings/i3c/i3c.h>
/*
&lpi2c1 {
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <400000>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pinctrl_lpi2c1>;
pinctrl-1 = <&pinctrl_lpi2c1>;
status = "okay";
};
*/
&i3c1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i3c1>;
i2c-scl-hz = <400000>;
status = "okay";
eeprom_baseboard: eeprom@51 {
compatible = "atmel,24c02";
reg = <0x51 0 (I2C_FM | I2C_FILTER)>;
pagesize = <16>;
status = "okay";
};
};
kernel開機過程中有看到邏輯分析儀上的SDA/SCL信號

讀取EEPROM也可看到SDA/SCL信號有被觸發
cat /sys/bus/i2c/devices/8-0051/eeprom

I2C bus(I3C模擬I2C)設定成400k Hz的情況下讀取EEPROM (i2c-scl-hz = <400000>;)
LA上量測到是400k Hz,與設定值吻合

I2C bus(I3C模擬I2C)設定成200k Hz的情況下讀取EEPROM (i2c-scl-hz = <200000>;) -> 200k不是I2C標準frequency
LA上量測到是600k Hz,與設定值不吻合

I2C bus(I3C模擬I2C)設定成100k Hz的情況下讀取EEPROM (i2c-scl-hz = <200000>;)
LA上量測到是300k Hz,與設定值不吻合

結論
I3C bus雖然可用i2cdetect -l看到bus,
但是I3C driver目前不支援SMBUS模式的操作,所以無法用i2cdetect掃描到裝置。
但如果在device tree中定義EEPROM的node,在讀寫EEPROM,可在LA上看到I3C bus發出模擬I2C bus的讀寫訊號
I3C模擬I2C的情況下,bus frequency只有設在400k Hz,I2C controller出來的頻率才會與設定值吻合。
設定100k Hz,實際出來的頻率為300k Hz。
由此推測,I3C controller內的PLL有可能無法精確合成出低於400k Hz的速度
觀察i.mx95上的I3C bus
嘗試方向: (含結論)
- 將I3C pin的pinmux設定成GPIO, 使用I2C bitbanging操作i2c bus
1-1. 以I2C bigbanging GPIO嘗試能不能scan到P3T1035 device -> 可以
1-2. 測試P3T1035是否可用P3T1085的linux I2C driver讀取溫度 -> 可以(每次讀取都成功)
以上測試結果代表P3T1035的POR正常,硬體線路以I2C (open-drain)操作正常,還沒看實際波形。
可透過I2C bus讀取溫度數值(每次都成功),P3T10852的I2C linux driver可適用於P3T1035(代表在讀取temperature register數值這部分),P3T1035與P3T1085的操作方式相同 - 將I3C pin的pinmux設定成I3C,但設定device tree以I2C模式操作P3T1035
(因為以I3C模擬I2C通訊,I3C不支援i2cdetect使用的SMBUS的IOCTL,因此無法進行scan,以strace追蹤會發現IOCTL失敗,因此LA上觀察不到有送出I2C信號)
2-1. 測試P3T1035是否可用P3T1085的linux I2C driver讀取溫度 -> 操作在400kHz, 約80%機率可成功讀取溫度(讀取10次約可成功8次) - 將I3C pin的pinmux設定成I3C,設定device tree以I3C模式操作P3T1035
==3-1. 測試P3T1035是否可用P3T1085的linux I3C driver讀取溫度 -> 操作在100kHz, 約
嘗試方向1-1: I3C pinmux設定成GPIO,以I2C bigbanging GPIO嘗試能不能scan到P3T1035 device
先把i3c2設為GPIO mode然後用bitbang mode來模擬i2c訊號
看能不能scan到p3t1035

DTS設定如下:
arch/arm64/boot/dts/freescale/imx95-edm-evm.dts
i2c_bitbang: i2c@0 {
compatible = "i2c-gpio";
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i3c2_bitbang>;
scl-gpios = <&gpio4 0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
sda-gpios = <&gpio4 1 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
clock-frequency = <100000>;
status = "okay";
};
pinctrl_i3c2_bitbang: i3c2bitbanggrp {
fsl,pins = <
IMX95_PAD_ENET1_MDC__GPIO4_IO_BIT0 0x4000019e
IMX95_PAD_ENET1_MDIO__GPIO4_IO_BIT1 0x4000019e
>;
};
上機測試:
i2cdetect -l可看到I2C bus 列表含有"GPIO bitbang模擬的I2C bus"
root@edm-imx95-8gb:~# i2cdetect -l
i2c-1 i2c 44350000.i2c I2C adapter
i2c-2 i2c 42530000.i2c I2C adapter
i2c-3 i2c 42540000.i2c I2C adapter
i2c-4 i2c 426b0000.i2c I2C adapter
i2c-5 i2c 426c0000.i2c I2C adapter
i2c-8 i2c i2c@0 I2C adapter (此為GPIO bitbang模擬的I2C bus)
root@edm-imx95-8gb:~# i2cdetect -y 8
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- 72 -- -- -- -- --
掃到的I2C address為0x72
線路圖上標註的temperature sensor型號為P3T1035AUK(0x70),
但實際掃描到的型號為P3T1035CUK(0x72)

嘗試方向1的結論: (將I3C pin的pinmux設定成GPIO, 以I2C bigbanging GPIO嘗試能不能scan到P3T1035 device)
結論是可以。
GPIO模擬的I2c bitbanging可掃描到I2c bus上的temperature sensor,但P3T1035的位址(由chip型號決定)與線路圖上標註的不同
線路圖上標註的temperature sensor型號為P3T1035AUK(0x70),
但實際掃描到的型號為P3T1035CUK(0x72)
嘗試方向1-2: 將I3C pin的pinmux設定成GPIO,測試P3T1035是否可用P3T1085的linux I2C driver讀取溫度
arch/arm64/boot/dts/freescale/imx95-edm-evm.dts
i2c_bitbang: i2c@0 {
compatible = "i2c-gpio";
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i3c2_bitbang>;
scl-gpios = <&gpio4 0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
sda-gpios = <&gpio4 1 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
clock-frequency = <400000>;
status = "okay";
p3t1035: temp-sensor@72 {
compatible = "nxp,p3t1085";
reg = <0x72>;
status = "okay";
};
};
pinctrl_i3c2_bitbang: i3c2bitbanggrp {
fsl,pins = <
IMX95_PAD_ENET1_MDC__GPIO4_IO_BIT0 0x4000019e
IMX95_PAD_ENET1_MDIO__GPIO4_IO_BIT1 0x4000019e
>;
};
i2cdetect -l可看到I2C bus 列表含有"GPIO bitbang模擬的I2C bus"
root@edm-imx95-8gb:~# i2cdetect -l
i2c-1 i2c 44350000.i2c I2C adapter
i2c-2 i2c 42530000.i2c I2C adapter
i2c-3 i2c 42540000.i2c I2C adapter
i2c-4 i2c 426b0000.i2c I2C adapter
i2c-5 i2c 426c0000.i2c I2C adapter
i2c-8 i2c i2c@0 I2C adapter
root@edm-imx95-8gb:~# dmesg | grep p3t
[ 8.202454] ----------> p3t1085_i2c_probe
[ 8.207611] ----------> registering p3t1085 temperature sensor
[ 8.207630] p3t1085_i2c 8-0072: registering p3t1085 temperature sensor
[ 8.221227] p3t1085_i2c 8-0072: Temperature sensor probe successfully
root@edm-imx95-8gb:~# [ 39.824517] kauditd_printk_skb: 14 callbacks suppressed
[ 39.824536] audit: type=1334 audit(947552407.848:33): prog-id=19 op=UNLOAD
root@edm-imx95-8gb:~# cat /sys/bus/iio/devices/iio\:device1/in_temp_raw
650

2C 波形分段解析
這整個通訊過程可以分為兩個主要階段:寫入階段 (目的是告訴 sensor 你想讀取哪個暫存器) 和 讀取階段 (實際從 sensor 取回數據)。
第一部分:設定暫存器位址 (Write Transaction)
Setup Write to [0x72] + ACK
- 意義: Master (您的 i.MX95 處理器) 發起一次寫入操作。
-Setup Write: I2C Start Condition,由 SDA 從高電位變為低電位,而 SCL 保持高電位,表示一次通訊的開始。
-[0x72]: 這是 P3T1085 sensor 的 7-bit I2C slave address。Master 將這個地址廣播到 I2C bus 上,並將 R/W bit 設為 0 (表示寫入)。
-+ ACK: Slave (P3T1085 sensor) 在接收到自己的地址後,會將 SDA 拉低來回應 Master,這稱為 Acknowledge (ACK),表示 "我收到了,我已準備好接收數據"。這確認了 sensor 在這個地址上是存在的且正常的。0x00 + ACK
- 意義: Master 告訴 Slave 它接下來想要操作的內部暫存器位址 (Register Address/Pointer)。
-0x00: 這是要寫入的數據。根據 P3T1085 的 datasheet,0x00是 Temperature Register 的地址。所以這一步的意思是 "請將你的指標指向溫度暫存器,我接下來要讀取這個暫存器的值"。
-+ ACK: Slave 再次回應 ACK,表示它已經成功接收到暫存器地址0x00。
第二部分:讀取暫存器數據 (Read Transaction)
-
Setup Read to [0x72] + ACK
- 意義: Master 發起一次讀取操作,從剛剛設定好的暫存器位址開始讀取數據。
-Setup Read: 這是一個 Repeated Start Condition。Master 在不發送 Stop Condition 的情況下,再次發送 Start Condition,用來在同一次通訊中切換讀寫方向。這比STOP->START的效率更高。
-[0x72]: Master 再次發送 Slave 地址,但這次將 R/W bit 設為 1 (表示讀取)。
-+ ACK: Slave 同樣回應 ACK,表示 "我收到了,我已準備好發送數據"。 -
0x28 + ACK
- 意義: Slave (sensor) 開始向 Master 發送數據。
-0x28: 這是溫度數據的第一個 byte,即 MSB (Most Significant Byte),高位元組。
-+ ACK: Master 接收到第一個 byte 後,回應 ACK,意思是 "我已收到這個 byte,請繼續發送下一個"。 -
0xA0 + NAK
- 意義: Slave 發送溫度的第二個 byte。
-0xA0: 這是溫度數據的第二個 byte,即 LSB (Least Significant Byte),低位元組。
-+ NAK: Master 在接收到它所期望的最後一個 byte 後,會發送一個 Not Acknowledge (NAK)。NAK 在這裡是正常行為,它告訴 Slave "我已經收到了所有我需要的數據,你可以停止發送了"。
- 在此之後,Master 會發送一個 Stop Condition (SCL 為高電位時,SDA 從低電位變為高電位) 來結束這次 I2C 通訊,釋放 bus。
嘗試方向1-2的結論: (將I3C pin的pinmux設定成GPIO, 測試P3T1035是否可用P3T1085的linux I2C driver讀取溫度)
I3C pin設定成GPIO mode以I2C bitbanging控制P3T1035,可成功讀取溫度 (100k/400k Hz/)皆可正常讀取溫度值,且每次都成功。
這邊有一個盲點,雖然bitbanging I2C的bus frequency是設定成400k Hz,但是用LA量測,實際上只能跑到62.5k Hz。
以下為bitbanging I2C的bus frequency設定為400kHz的時序圖,LA實際只有量到62.5kHz

以下為bitbanging I2C的bus frequency設定為100kHz的時序圖,LA實際只有量到50.8kHz

所以bitbanging I2C可以每次百分之百正確讀取P3T1035的溫度值,是因為其操作在非常低速(約60kHz)的情況。
因為其低速,所以外部的pullups阻值對波形影響不大。
嘗試方向2-1: (將I3C pin的pinmux設定成I3C, 測試P3T1035是否可用P3T1085的linux I2C driver讀取溫度)
I3C bus無法進行i2cdetect -y(scan操作)(I3C driver不支援SMBUS操作),但可看到P3T1085 driver註冊成功(不代表上面的P3T1035有在i2c bus上被偵測到),
以下device tree設定有兩個關鍵:
1.一定要指定i2c模式是操作在100khz
arch/arm64/boot/dts/freescale/imx95-edm-evm.dts
&i3c2 {
i2c-scl-hz = <100000>;
pinctrl-0 = <&pinctrl_i3c2>;
pinctrl-names = "default";
status = "okay";
p3t1035: temp-sensor@70 {
compatible = "nxp,p3t1085";
reg = <0x72 0 (I2C_FM | I2C_FILTER)>;
status = "okay";
};
};
pinctrl_i3c2: i3c2grp {
fsl,pins = <
IMX95_PAD_ENET1_MDC__I3C2_SCL 0x4000099e
IMX95_PAD_ENET1_MDIO__I3C2_SDA 0x4000099e
>;
};
要將i3c pin設定成OD(open-drain),原本OD/PD/PD皆為disable


root@edm-imx95-8gb:~# i2cdetect -l
i2c-1 i2c 44350000.i2c I2C adapter
i2c-2 i2c 42530000.i2c I2C adapter
i2c-3 i2c 42540000.i2c I2C adapter
i2c-4 i2c 426b0000.i2c I2C adapter
i2c-5 i2c 426c0000.i2c I2C adapter
i2c-8 i2c 42520000.i3c I2C adapter
root@edm-imx95-8gb:~# cat /sys/bus/iio/devices/iio\:device1/in_temp_raw
[ 50.317935] silvaco-i3c-master 42520000.i3c: I3C receive length too long!
[ 50.324886] p3t1085_i2c 8-0072: failed to read temperature register
cat: '/sys/bus/iio/devices/iio:device1/in_temp_raw': Invalid argument
多讀幾次有時候可以讀到
root@edm-imx95-8gb:~# cat /sys/bus/iio/devices/iio\:device1/in_temp_raw
637
下圖是2C bus(I3C模擬I2C)設定成400k Hz的情況下讀取EEPROM (i2c-scl-hz = <400000>;)
LA上量測到是400k Hz,與設定值吻合。此結果與在EDM-IMX93上的測試一致。

下圖是2C bus(I3C模擬I2C)設定成100k Hz的情況下讀取EEPROM (i2c-scl-hz = <100000>;)
LA上量測到是100k Hz,與設定值吻合。此結果與在EDM-IMX93上的測試一致。

| I3C模擬I2C Bus frequency設定 |
實際輸出的bus frequency(SCL) | 讀取溫度成功率 |
|---|---|---|
| 400k Hz | 400k Hz | 8/10成功,2次失敗 |
| 100k Hz | 300 kHz | 8/10成功,2次失敗 |
嘗試方向3-1: 將I3C pin的pinmux設定成I3C,設定device tree以I3C模式操作P3T1035,測試P3T1035是否可用P3T1085的linux I3C driver讀取溫度
arch/arm64/boot/dts/freescale/imx95-edm-evm.dts
#include <dt-bindings/i3c/i3c.h>
&i3c2 {
i3c-scl-hz = <400000>;
pinctrl-0 = <&pinctrl_i3c2>;
pinctrl-names = "default";
status = "okay";
p3t1035: temp-sensor@72,236152b00e4 {
reg = <0x72 0x236 0x152b00e4>;
assigned-address = <0x72>;
status = "okay";
};
};
pinctrl_i3c2: i3c2grp {
fsl,pins = <
IMX95_PAD_ENET1_MDC__I3C2_SCL 0x4000099e
IMX95_PAD_ENET1_MDIO__I3C2_SDA 0x4000099e
>;
};
| I3C Bus frequency設定 | 實際輸出的bus frequency(SCL) | kernel可否probe p3t1035 driver | |
|---|---|---|---|
| 400k Hz | 857k Hz | 否 | |
| 100k Hz | 1.5M Hz | 可probe到,但 | |
| 下圖為設定為400k Hz時,造成probe不到p3t1035 driver, 主要失敗的階段在 "E/W, 86 → (Sr) 72/W →(再次 72/W)" | |||
| 這是一個 Direct CCC 交易,流程如下: |
- Start → 廣播位址 0x7E/W → CCC 命令碼 0x86
0x86是 RSTDAA (Reset Dynamic Address Assignment) 的 Direct 形式,用來要求特定目標重置它的動態位址。 - Restart → 目標位址 0x72/W →(可能再一次 Restart → 0x72/W)
控制器嘗試對目標(假設已分配動態位址)進行操作,但兩次都 NACK,表示裝置不認同這個位址。
I3C controller嘗試對目標(假設已分配動態位址)進行操作時的頻率為857k Hz

下圖為設定100k Hz時,

arch/arm64/boot/dts/freescale/imx8ulp-9x9-evk-i3c.dts
&i3c2 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pinctrl_i3c2>;
pinctrl-1 = <&pinctrl_i3c2>;
i2c-scl-hz = <400000>;
status = "okay";
lsm6dso_i3c: imu@6a,208006c0000 {
reg = <0x6a 0x208 0x6c0000>;
assigned-address = <0x6a>;
};
};
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c
static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = {
I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID),
I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID),
{ /* sentinel */ },
};
MIPI Alliance Manufacturer ID Page | MIPI Alliance Manufacturer ID
There are currently no user-space tools similar to "i2c-tools" to perform read/write on the I3C bus.
nxp.com/docs/en/application-note/AN14005.pdf
只有找到下面這個
GitHub - vitor-soares-snps/i3c-tools
關於I3C_PUR信號:








D:\Project\137.imx95\evk_schematic\i.MX 95 15x15 IOT EVK\SPF-87751_A.pdf
(SDA/SCL無外部pullups)

D:\temp\imx8ulp_9x9_schematic\sch-52007_b.pdf
(SDA/SCL無外部pullups)

arch/arm64/boot/dts/freescale/imx8ulp-9x9-evk-i3c.dts
&i3c2 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pinctrl_i3c2>;
pinctrl-1 = <&pinctrl_i3c2>;
i2c-scl-hz = <400000>;
status = "okay";
lsm6dso_i3c: imu@6a,208006c0000 {
reg = <0x6a 0x208 0x6c0000>;
assigned-address = <0x6a>;
};
};
&iomuxc1 {
pinctrl_i3c2: i3c2grp {
fsl,pins = <
MX8ULP_PAD_PTE19__I3C2_PUR 0x3
MX8ULP_PAD_PTF6__I3C2_SCL 0x3
MX8ULP_PAD_PTF7__I3C2_SDA 0x3
>;
};
};
NXP Documentation Portal
沒接外部pullups
可以動的device tree設定
主要是i3c bus速度要降成100k Hz(i3c-scl-hz = <100000>;)
assigned-address = <0x72>;也是必要欄位
不加assigned-address,不會執行p3t1085_i3c_probe
&i3c2 {
i2c-scl-hz = <100000>;
i3c-scl-hz = <100000>;
pinctrl-0 = <&pinctrl_i3c2>;
pinctrl-names = "default";
status = "okay";
/*
p3t1035: temp-sensor@70 {
compatible = "nxp,p3t1085";
reg = <0x72 0 (I2C_FM | I2C_FILTER)>;
status = "okay";
};
*/
p3t1035: temp-sensor@72,236152b00e4 {
//compatible = "nxp,p3t1085";
reg = <0x72 0x236 0x152b00e4>;
assigned-address = <0x72>;
status = "okay";
};
};
Linux kernel開機訊息
root@edm-imx95-8gb:~# dmesg | grep p3t
[ 3.080601] ----------> p3t1085_i3c_probe
[ 3.084753] p3t1085_i3c 0-236152b00e4: Temperature sensor probe successfully
Richard,我把你提供的 Saleae Logic 2 匯出的 CSV 逐段讀入、以 Start → … → Stop 作為一個「命令集合 (command set)」來整理;若一段內含 restart,我視為同一個直接 (Direct) CCC 交易的次段。下表同時標示 ACK(我用「Addr/CCC/Target/Payload」分別表示廣播位址、CCC 命令碼、目標位址與定義位元/資料各步驟的 ACK 概況),以及每段的目的與意義。需要注意的是:I3C 的 廣播 (Broadcast) CCC 在位址 0x7E/W 會有集體 ACK,而後續的 CCC 值本身通常不逐位元組回 ACK;所以你在 CSV 中看到許多廣播交易的 data 欄位為 NACK 並不代表失敗,這是常態(只要位址 0x7E/W 有 ACK 就可視為該廣播已被至少一個目標看見)。1
資料來源:以下每列的「ex.」皆直接取自你上傳的
I3C_send_enec_100kHz.csv。2
CCC 指令對應與用途則參考 I3C 參考文件與廠商技術說明。345
Linux kernel印出I3C dynamic debug訊息
./scripts/kconfig/merge_config.sh .config debug_ftrace.cfg
setenv mmcargs ${mmcargs} 'ignore_loglevel svc_i3c_master.dyndbg=+pfl i3c.dyndbg=+pfl'
echo "file drivers/i3c/master/svc-i3c-master.c +p" > /sys/kernel/debug/dynamic_debug/control
cat /sys/kernel/debug/dynamic_debug/control | grep svc-i3c-master
dyndbg="file drivers/i3c/* +p"
ti-linux-kernel/ti_config_fragments at ti-rt-linux-5.10.y · TexasInstruments/ti-linux-kernel · GitHub
./scripts/kconfig/merge_config.sh .config config_fragments/debug_ftrace.cfg
I3C 開機過程各段通訊解釋(來自 I3C_send_enec_100kHz.csv)
| command set | ACK | 目的 | 意義 | ex. |
|---|---|---|---|---|
| 7E/W, 06 | Addr ✔ / CCC ✘ | 廣播 RSTDAA (Reset Dynamic Address Assignment) | 要求所有 I3C 目標捨棄原有的動態位址、等待控制器重新分配;常見於系統開機時為了把匯流排回到乾淨狀態。廣播位址有 ACK 即代表至少一個目標在場;CCC 本身不回 ACK 屬正常。31 | 0x7E, 0x06 2 |
| 7E/W, 01, 0B | Addr ✔ / CCC ✔ / Payload ✔ | 廣播 DISEC (Disable Events) 並送事件遮罩 0x0B | 針對所有目標停用 IBI / Hot-Join / Controller Role 等目標主動事件,常在初始化階段先抑制目標搶占或中斷,待總線穩定後再酌情開啟。43 | 0x7E, 0x01, 0x0B 2 |
| 7E/W, 87 → (Sr) 72/W → E4 | Addr ✔ / CCC ✘ / Target ✔ / Payload ✘ | 直接 SETDASA(Set Dynamic Address from Static Address)指向 0x72,payload 似為位址定義位元 | 用已知靜態位址快速指派動態位址,比 ENTDAA 流程快;你這段 payload = 0xE4,看起來像把 7-bit 位址以 8 位元(位址<<1,R/W=0)呈現的常見做法。不過 payload NACK 可能表示目標不支援 SETDASA或靜態位址不相符—很多裝置也會直接走 ENTDAA 而非 SETDASA。67 | 0x7E, 0x87 | Sr 0x72 | 0xE4 2 |
| 7E/W, 8D → (Sr) 72/R → 02 36 15 2B 00 E4 | Addr ✔ / CCC ✘ / Target ✔ / Payload(前 5 ✘,最後 1 ✔) | 直接 GETPID(Get Provisional ID)讀 6 bytes | 讀出目標的 48-bit PID(此例為 0x0236152B00E4),供控制器辨識廠商/裝置身分;Direct GET 類命令的 ACK 行為可能因實作而有「一次重試」模型,Saleae 的逐位元 ACK 標示不代表讀取失敗。38 | 0x7E, 0x8D | Sr 0x72 | 0x02 0x36 0x15 0x2B 0x00 0xE4 2 |
| 7E/W, 8E → (Sr) 72/R → 03 | Addr ✔ / CCC ✘ / Target ✔ / Payload ✔ | 直接 GETBCR(Get Bus Characteristics Register) | 讀出 BCR = 0x03,描述目標在匯流排上的角色與能力(例如是否只當 Target、是否支援某些事件等)。實際欄位解碼需要依各家實作/規格版本。39 | 0x7E, 0x8E | Sr 0x72 | 0x03 2 |
| 7E/W, 8F → (Sr) 72/R → 63 | Addr ✔ / CCC ✔ / Target ✔ / Payload ✘ | 直接 GETDCR(Get Device Characteristics Register) | 讀出 DCR = 0x63;依 MIPI 公開 DCR 表,此值對應環境類感測器中的「溫度」,與你的 P3T1035(I3C 溫度感測器)相符。10 | 0x7E, 0x8F | Sr 0x72 | 0x63 2 |
| 7E/W, 94 → (Sr) 72/R → 00 38 | Addr ✔ / CCC ✔ / Target ✔ / Payload(首 ✘、次 ✔) | 直接 GETMXDS(Get Max Data Speed) | 查詢目標的最大讀/寫資料速率及最大 Read Turnaround 等能力編碼;此例傳回 2 bytes(00 38),實際意義需依規格對應表解讀,以了解目標在 SDR/HDR 支援的極限。3 |
0x7E, 0x94 | Sr 0x72 | 0x00 0x38 2 |
| 72/W, 00 00 | Target ✔ / Payload ✘✘ | 私有 SDR 寫(非 CCC) | 這段不是 CCC,而是對目標 0x72 的私有寫入 2 Bytes 00 00;依 NXP 溫度感測器資料表,裝置有溫度/組態等寄存器,常見私有寫為設定指標或配置。具體功能要對照 P3T1035 寄存器地圖。1112 |
0x72, 0x00, 0x00 2 |
| 7E/W, 8B → (Sr) 72/R → 00 00 | Addr ✔ / CCC ✘ / Target ✔ / Payload ✘✘ | 直接 GETMWL(Get Max Write Length) | 讀出 MWL = 0x0000,依規格表示無上限 (Unlimited);控制器及目標可依此調整私有寫入長度。313 | 0x7E, 0x8B | Sr 0x72 | 0x00 0x00 2 |
| 7E/W, 07 (緊接上一段之後) | Addr(前一段 ✔,後續 7E 其中一次 ✘) | 廣播 ENTDAA(Enter Dynamic Address Assignment) | 啟動動態位址分配程序;你這段在 GETMWL 之後立刻再送 ENTDAA,可能是控制器嘗試重新進入 DAA 或確認匯流排狀態。最後一次 0x7E/W 的 NACK 顯示此波廣播未獲任何目標回應(或交易終止)。3 | 0x7E, 0x07(後續未完整顯示) 2 |
小提醒:你在問題敘述的範例「0x06 (ENEC)」其實是 RSTDAA;ENEC 廣播的 CCC 代碼為 0x00。3
可參考下面:
I3C协议Single Data Rate(SDR)模式研读(六):通用命令代码(CCC)_i3c ccc-CSDN博客
四問帶你搞懂 I3C - 大大通(繁體站)
请进行安全验证(Security Verification)
為什麼有些 data 是 NACK,卻不代表錯誤?
- 在 廣播 CCC 中,I3C 規範要求目標對 0x7E/W(廣播位址)做集體 ACK;後續的 CCC 值與定義位元常不逐位元組回 ACK。Saleae 的
ack欄位對data顯示為false在廣播 CCC 是正常現象。1 - 在 直接 GET 類 CCC(例如 GETPID/GETBCR/GETDCR/GETMXDS),ACK 的呈現可能出現你看到的「前幾個 byte 為 NACK、最後一個為 ACK」的狀況;這與裝置/控制器的重試模型與匯流排時序有關,並不必然代表讀取失敗。8
和你的 P3T1035 溫度感測器的對應
- 你的匯流排目標位址為 0x72(從 CSV 與你先前說明一致)。GETDCR 回 0x63 對應到 溫度類感測器(Environment → Temperature),與 P3T1035 的定位相符。21011
- P3T1035/P3T2030 的資料表敘述其 I3C/I²C 介面、溫度/配置寄存器等;私有寫入
0x72/W: 00 00很可能是在設定暫存器指標或清狀態,需配合產品的寄存器地圖對照。1112
參考(CCC 一覽-節錄)
- 常用 CCC 對應:RSTDAA=0x06(廣播)、ENTDAA=0x07(廣播)、ENEC=0x00(廣播/直接)、DISEC=0x01(廣播/直接)、SETDASA=0x87(直接)、GETPID=0x8D(直接讀)、GETBCR=0x8E(直接讀)、GETDCR=0x8F(直接讀)、GETMWL=0x8B(直接讀)、GETMRL=0x8C(直接讀)、GETMXDS=0x94(直接讀)。3
- 廣播/直接 CCC 框架與 ACK 行為解說。1
Richard,收到你在 200 kHz 下「不能 probe」的 CSV。我先逐段解釋每個 Start→…→Stop 的 I3C 命令集合(遇到 restart 我視為同一筆 Direct CCC 的次段),接著把 200 kHz 與你先前 100 kHz(能 probe) 的序列做對照比較。
註:I3C 的 廣播 (Broadcast) CCC 一律以 0x7E/W 開頭,後跟 CCC 值;裝置對 0x7E/W 會做集體 ACK,但後續的 CCC 值/定義位元通常不逐位元回 ACK,所以你在 CSV 中看到許多廣播
data為 NACK 並不代表失敗(只要 0x7E/W 有 ACK 即可)。[1|1]
CCC 指令意義與碼表則以 I3C 規範/廠商技術文件為準。[2|2]
(1) 400 kHz 無法 probe 的每段通訊說明(I3C_send_enec_400kHz.csv)
| command set | ACK | 目的 | 意義 | ex.(出自 CSV) |
|---|---|---|---|---|
7E/W, 06 |
Addr ✔ / CCC ✘ | 廣播 RSTDAA(Reset Dynamic Address Assignment) | 要求所有 I3C 目標捨棄既有的動態位址、待控制器重新分配;開機常見的「總線歸零」步驟。廣播後 data 不 ACK 屬正常。[2|2][1|1] |
0x7E, 0x06 [3|3] |
7E/W, 87 → (Sr) 72/W → E4 |
Addr ✔ / CCC ✘ / Target ✔ / Payload ✘ | 直接 SETDASA(Set Dynamic Address from Static Address)指向 0x72 | 用已知靜態位址快速指派動態位址(比 ENTDAA 快)。你這段目標位址 ACK,payload E4 NACK 在許多實作屬常見(不影響地址生效)。若此步驟成功,後續應能對 0x72 送 Direct 命令。[4|4][5|5] |
0x7E, 0x87 | Sr 0x72 | 0xE4 [3|3] |
7E/W, 86 → (Sr) 72/W →(再次 72/W) |
Addr ✔ / CCC ✔ / Target ✘✘ | 直接 RSTDAA(Direct 0x86)指向 0x72 | 嘗試對已分配動態位址的目標做「重設動態位址」。但 0x72 兩次都 NACK,表示裝置不承認 0x72 為其動態位址或尚未完成 DAA,因此 Direct 交易無法繼續。[2|2] | 0x7E, 0x86 | Sr 0x72 (NACK), Sr 0x72 (NACK) [3|3] |
7E/W, 07 → (Sr) 7E/R |
Addr ✔ / CCC ✔ / Target(=7E) ✘ | 廣播 ENTDAA(Enter Dynamic Address Assignment) | 啟動 DAA;裝置應競態回報 PID/BCR/DCR 以獲配動態位址。但你這段在 Sr 0x7E/R NACK,表示匯流排上無裝置參與 DAA或時序不被目標接受,於是系統無法完成「發現 (discover) + 分配位址」。[2|2][6|6] |
0x7E, 0x07 | Sr 0x7E/R (NACK) [3|3] |
小結:到了 200 kHz,控制器先試 SETDASA(表面上目標位址有 ACK),但隨後的 Direct RSTDAA→0x72 與 ENTDAA 都拿不到目標的 ACK/參與,因此 Linux 的 I3C 核心無法繼續送 GETPID/GETBCR/GETDCR 等標準「探測」步驟,自然就probe 失敗。[6|6]
(2) 與 100 kHz(能 probe) 的序列比較
下表把你先前 100 kHz 序列(我之前已解析)與這次 200 kHz 序列逐段對照,點出關鍵差異與對 probe 的影響:
| 步驟 | 100 kHz(成功) | 200 kHz(失敗) | 差異/影響 |
|---|---|---|---|
| 匯流排歸零 | 廣播 RSTDAA (0x06),0x7E/W ACK;CCC data NACK(正常) [2|2][1|1] |
同上,行為一致 [3|3] | 無差異;兩者都把舊動態位址清掉。 |
| 事件管理 | 廣播 DISEC (0x01) 並送遮罩 0x0B(停用目標主動事件) [7|7] |
未見 DISEC | 差異:雖通常不致影響 DAA,但部分驅動喜歡明確關閉事件以穩定初始化。[6|6] |
| 指派位址(快取法) | SETDASA (0x87) → 目標位址 ACK;payload 常見 NACK → 之後能以 0x72 做 Direct 命令(成功) [4|4] | SETDASA (0x87) → 目標位址 ACK;payload NACK → 下一步對 0x72 的 Direct 命令卻遭 NACK [3|3] | 關鍵差異:在 200 kHz 下,裝置似乎沒有真正「承認」0x72;因而所有「針對目標位址」的 Direct CCC 都失敗。 |
| 探測/能力讀取 | GETPID/GETBCR/GETDCR/GETMXDS 等 Direct GET(均能從 0x72 讀到資料,含 PID/BCR/DCR) [2|2] | 完全未進入這些步驟(因 Direct 到 0x72 已失敗) [3|3] | 差異:100 kHz 成功取得裝置身分與能力,200 kHz 卡在尚未建立有效動態位址。 |
| DAA(標準法) | 之後(或必要時)可廣播 ENTDAA (0x07),裝置會在 DAA 流程中回報 PID/BCR/DCR(可分配位址) [6|6] | 廣播 ENTDAA 後在 Sr 0x7E/R NACK,無裝置參與競態 [3|3] |
差異:200 kHz 連 DAA 也失敗,Linux 無法「discover + assign」,因此 probe 終止。[6|6] |
| 私有資料/長度 | 100 kHz 中有私有寫 0x72/W: 00 00,以及 GETMWL (0x8B) 讀到 0x0000(代表無上限) [2|2][8|8] |
200 kHz 無法進入私有/能力讀取步驟 | 差異:同根源—未建立動態位址導致無法進入後續交易。 |
為何「200 kHz」會讓 DAA/Direct 失敗?(可能原因與檢查)
先說能力:I3C SDR 的協定設計本身可以到 MHz 級(規範示例可達 12.5 MHz),200 kHz 對 I3C 來說非常低,理論上裝置不會因頻率太高而失效;若失敗,多半是時序/電氣參數或控制器設定的交互問題。[9|9]
-
Open‑Drain 階段的邊緣/持時不合規
I3C 雖大多是推挽傳輸,但 Start/Restart/Stop、廣播頭、DAA 競態 等階段仍涉及 Open‑Drain 訊號與上升時間(SDA/SCL)、tSU/tHD START/STOP、Bus Free 等時序。當你把標稱速率改為 200 kHz(控制器可能同步調整 high/low/hold/free 參數),若上拉/匯流排電容與控制器時序不匹配,目標可能就看不見/不接受這些邊界條件而不參與 DAA。[9|9] -
動態位址流程順序在 200 kHz 被改變/優先不同
你的 200 kHz 序列顯示控制器在 SETDASA 之後立刻嘗試 Direct RSTDAA (0x86)→0x72,但裝置對 0x72 NACK;這意味著裝置尚未擁有有效「動態位址=0x72」。在 100 kHz 成功案例中,控制器是接著做 GETPID/GETBCR/GETDCR(表示 0x72 已生效)。序列差異或控制器在不同速率下的自動流程,都可能造成這個現象。[2|2][6|6] -
Linux 驅動/控制器時序參數(SCL/SDA high/low/hold/free)未同步調整
NXP 的 i.MX I3C 控制器在 Linux(svc‑i3c‑master)中會處理 CCC、DAA、IBI 等流程;但不同速率下需要合適的時序參數。若驅動未對 200 kHz 的參數(例如 SCL_HIGH_TIME/SCL_LOW_TIME、SDA_HOLD、BUS_FREE)調整,可能在 Open‑Drain 段出現不合規的實際時序。可參考 NXP 的 Linux I3C 說明與 BSP 驅動配置。[10|10] -
裝置端能力沒問題,但需要正確的 DAA
P3T1035 屬 I3C/ I²C 溫度感測器,官方資料顯示其具備 I3C 介面與必要寄存器;裝置端並非 200 kHz 不能運作的問題,而是控制器與匯流排時序/流程需要對齊。[11|11]
建議的檢查/修正步驟(快速清單)
- 維持相同初始化順序:確保在 200 kHz 下,廣播 RSTDAA→DISEC 之後再做 SETDASA 或直接進 ENTDAA,且不要在尚未確認動態位址生效前插入 Direct RSTDAA (0x86)→目標位址。這可避免像你現在的「對尚未生效的位址送 Direct CCC」導致 NACK。[2|2][6|6]
- 調整控制器時序參數:檢查 i.MX95 I3C 控制器的 SCL 高/低時、SDA hold、Bus‑free 等寄存器/裝置樹設定,讓 Start/Restart/Stop/DAA 的開放汲入階段符合規範與你硬體的上拉/電容。可參考 NXP 的 Linux I3C 支援文件與 BSP。[10|10]
- 硬體面:在 200 kHz 下(雖遠低於 I3C SDR 的上限),仍請確認 上拉電阻值、匯流排電容、線長是否讓 Open‑Drain 階段的上升時間合規(用邏輯分析儀量 SDA/SCL 的 rise、tSU:START、tHD:START、tSU:STOP、tBUF)。規範與 AN 範例可做對照。[9|9]
- 驗證 DAA:直接嘗試「只用 ENTDAA」完成位址分配(先暫不送 SETDASA),看裝置是否能在 200 kHz 參與競態回報 PID/BCR/DCR;若仍不行,代表 Open‑Drain 段的時序/電氣更可能是關鍵。[6|6]
如果你願意,我可以把兩個 CSV 都逐位解碼 BCR/DCR/GETMXDS(100 kHz那份已有資料),並列出「200 kHz」時邏輯分析儀上量得的 rise/hold/free 與 I3C 規範的對照表,幫你精準定位是哪一個時序門檻沒過。你想先從 ENTDAA 的完整波形開始嗎?(特別是 Sr 0x7E/R 後的仲裁段)
References
[1] docs.nxp.com
[2] docs.kernel.org
[3] I3C_send_enec_200kHz_cannot_probe_p3t1035
[4] docs.amd.com
[5] docs.nxp.com
[6] www.nxp.com
[10] www.nxp.com
bootlin.com/pub/conferences/2018/elc/brezillon-i3c/brezillon-i3c.pdf
【阿福的隨筆】淺談 I3C 的 SDR broadcast, Direct CCC,及如何變更速率 - 大大通(繁體站)
參考資料:
I3C的user space工具
GitHub - vitor-soares-snps/i3c-tools
Yocto BB file
…/i3c-tools_git.bb · Gerrit Code Review
GitHub - xyphro/I3CBlaster: Raspberry pico / RP2040 based USB to I3C converter with Python support
GitHub - xyphro/XyphroLabs-I3C-Saleae-Protocol-Analyzer: I3C low level Analyzer for Saleae Logic software
bootlin.com/pub/conferences/2018/elc/brezillon-i3c/brezillon-i3c.pdf
Adding support to P3T1755 on Linux - NXP Community
zlgmcu.com/data/upload/file/Utilitymcu/AN13755-简便易行地将RT600_LPC55S30用作I3C主设备.pdf
含有P3T1755的reference線路圖(有接I3C_PUR為pullups)
NXP Documentation Portal
I3C原理:不錯
I3C - HackMD