在嵌入式開發中,I2C總線是連接外設的“橋梁”——小到傳感器、EEPROM,大到LCD驅動器、音頻芯片,都離不開它的控制。而瑞芯微(Rockchip)系列芯片作為主流嵌入式方案,其I2C控制器的開發是很多工程師的必備技能。
今天這篇文章,我們將從I2C硬件原理和數據幀講起,再結合官方《ROCKCHIP I2C開發指南》,梳理RK平臺I2C開發的全流程、關鍵配置和常見問題,幫你快速上手!
一、先搞懂基礎:I2C硬件原理與數據幀
在動手開發前,必須先掌握I2C的“底層邏輯”——硬件結構和數據傳輸規則,否則后續排查問題會寸步難行。
1. I2C硬件原理:兩條線搞定通信
I2C總線最核心的特點是“簡單”:僅需SDA(串行數據線)和SCL(串行時鐘線)兩條線,就能實現多主多從的通信(RK平臺僅支持主模式)。
關鍵硬件細節:
?總線拓撲:所有設備的SDA連在一起,SCL連在一起;每個設備有唯一地址,主設備(如RK芯片)通過地址識別從設備(如傳感器)。
?上拉電阻:SDA和SCL必須外接上拉電阻(通常4.7kΩ~10kΩ),因為I2C設備的引腳是開漏輸出——只能拉低電平,無法主動輸出高電平,需通過上拉電阻將總線拉到高電平(Vcc通常為3.3V)。
??RK文檔中提到:“改變上拉電阻大小可調節I2C總線的上拉強度”,本質是通過電阻值影響總線的上升沿時間(后面會講上升沿的重要性)。
?主從關系:主設備負責生成SCL時鐘、發起通信(發送起始/停止信號);從設備被動響應,根據主設備發送的地址匹配自身。
2. I2C數據幀:通信的“語言規則”
I2C數據以“幀”為單位傳輸,每幀包含固定的結構,主從設備必須遵循這套規則才能正常通信。完整幀結構如下(以常用的7位尋址為例):
[起始信號]→[地址字節]→[ACK/NACK]→[數據字節1]→[ACK/NACK]→ ... →[數據字節n]→[ACK/NACK]→[停止信號]
各部分詳解:
?起始信號(S):主設備拉低SDA(此時SCL為高電平),表示通信開始。
?地址字節:8位,前7位是從設備地址,第8位是“讀寫位”——0表示“主→從寫數據”,1表示“主←從讀數據”。
若用10位尋址,地址字節分兩部分:第一字節是固定前綴11110+ 10位地址的高2位,第二字節是10位地址的低8位。
?ACK/NACK:每傳輸1字節后,接收方需反饋1位:
?ACK(應答):接收方拉低SDA(表示已接收);
?NACK(非應答):接收方不拉低SDA(表示未接收或結束傳輸)。
?數據字節:8位,可連續傳輸(RK控制器一次最多傳32字節)。
?停止信號(P):主設備拉高SDA(此時SCL為高電平),表示通信結束。

二、RK平臺I2C開發核心:控制器、驅動與流程
掌握基礎后,我們聚焦RK平臺的具體開發——先了解控制器功能,再區分驅動差異,最后梳理開發流程。
1. RK I2C控制器:支持哪些能力?
RK系列芯片的I2C控制器兼容性強、配置靈活,核心功能如下(文檔V2.2.0版本):
?兼容I2C協議和SMBus協議(常見外設均支持);
?僅支持主模式(RK芯片作為主設備,控制外部從設備);
?時鐘頻率:軟件可編程,最高支持1000kbps(Fast-mode Plus),部分芯片默認支持400kbps(Fast-mode);
?尋址模式:支持7位地址和10位地址(覆蓋絕大多數外設);
?數據傳輸:一次中斷/輪詢最多傳輸32字節,效率較高。
2.關鍵注意:RK平臺的兩種I2C驅動
RK平臺的I2C驅動因內核版本不同分為兩類,配置方式差異較大,必須區分清楚:
|
驅動文件
|
適用內核版本
|
配置方式
|
最高頻率
|
|
i2c-rk3x.c
|
Linux 4.19+(如RK356X、RV1126)
|
設備樹(DTS)配置
|
1000kbps
|
|
i2c-rockchip.c
|
Linux 3.10內核
|
代碼中配置i2c_msg結構體
|
1000kbps
|
已支持“所有RK芯片+所有內核版本”,實際開發時需先確認所用內核版本,再選擇對應驅動。
3. RK I2C開發流程:三種傳輸模式
RK I2C控制器的核心是“傳輸模式”,不同場景對應不同模式,本質是通過配置寄存器(如I2C_CON、I2C_CLKDIV)實現。
模式1:只發送模式(Transmit only,I2C_CON[1:0] = 2'b00)
適用于“主設備向從設備寫數據”(如配置傳感器參數),步驟如下:
1.配置I2C_CLKDIV:設置SCL時鐘頻率(如400kbps);
2.配置I2C_CON:選擇“只發送模式”,并發送起始信號(S);
3.向I2C_TXDATA0~TXDATA7寫入要發送的數據;
4.配置I2C_MTXCNT:設置發送數據的字節數;
5.等待“發送完成中斷”(I2C_IPD[2]);
6.若有更多數據,重復步驟3~5;若無,配置I2C_CON發送停止信號(P),結束傳輸。
模式2:混合模式(Mix mode,I2C_CON[1:0] = 2'b01/11)
適用于“先寫后讀”(如先發送寄存器地址,再讀取該寄存器的值),步驟如下:
1.配置I2C_CLKDIV:設置SCL頻率;
2.配置I2C_CON:選擇“混合模式”,發送起始信號;
3.配置I2C_MRXADDR和I2C_MRXRADDR:設置從設備地址和讀取地址;
4.配置I2C_MRXCNT:設置要讀取的數據字節數;
5.等待“接收完成中斷”(I2C_IPD[3]);
6.若有更多數據,重復步驟3~5;若無,發送停止信號,結束傳輸。
模式3:只接收模式(Receive only,I2C_CON[1:0] = 2'b10)
適用于“主設備從從設備讀數據”(如讀取傳感器采集的數值),步驟如下:
1.配置I2C_CLKDIV:設置SCL頻率;
2.配置I2C_CON:選擇“只接收模式”,發送起始信號;
3.配置I2C_MRXCNT:設置接收數據的字節數;
4.等待“接收完成中斷”(I2C_IPD[3]);
5.若有更多數據,重復步驟3~4;若無,發送停止信號,結束傳輸。
4.驅動參數配置:關鍵是“時鐘頻率”
I2C通信能否穩定,核心是“時鐘頻率配置”——需符合I2C協議對“上升沿時間(Tr)”和“下降沿時間(Tf)”的要求,否則會出現通信失敗。
第一步:明確協議時序要求
I2C協議對不同模式的時序有嚴格規定(文檔中表格整理):
|
參數
|
標準模式(100kbps)
|
快速模式(400kbps)
|
高速模式(1000kbps)
|
單位
|
|
SCL頻率
|
≤100
|
≤400
|
≤1000
|
kHz
|
|
上升沿Tr
|
≤1000
|
≤300
|
≤120
|
ns
|
|
下降沿Tf
|
≤300
|
≤300
|
≤300
|
ns
|
注:Tr和Tf需用示波器測量,若超過最大值,需調整上拉電阻(如減小電阻值縮短上升沿)。
第二步:兩種驅動的配置示例
?i2c-rk3x.c(DTS配置):
配置在設備樹中,關鍵參數是clock-frequency(時鐘頻率)、i2c-scl-rising-time-ns(SCL上升沿時間)。
示例(配置I2C1為400kbps):
&i2c1 {status ="okay";i2c-scl-rising-time-ns = <265>; //示波器實測上升沿265nsi2c-scl-falling-time-ns = <11>; //下降沿通常不變,可默認clock-frequency = <400000>; //400kbps(Fast-mode)// 掛載從設備(如 ES8316 音頻芯片)es8316: es8316@10 {compatible ="everest,es8316";reg = <0x10>; //從設備地址0x10// 其他外設參數...};};
?i2c-rockchip.c(代碼配置):
在代碼中配置i2c_msg結構體的scl_rate成員,示例(配置200kbps):
structi2c_msg xfer_msg;xfer_msg[0].addr = client->addr; // 從設備地址xfer_msg[0].len = num; // 數據長度xfer_msg[0].flags = client->flags;// 讀寫標志(0=寫,1=讀)xfer_msg[0].buf = buf; // 數據緩存xfer_msg[0].scl_rate =200*1000; //200kbps 時鐘頻率
5. RK I2C如何使用?內核態/用戶態/工具
(1)內核態使用(推薦,適合產品化)
RK I2C內核態開發遵循Linux標準I2C接口,參考內核文檔Documentation/i2c/writing-clients,核心是:
?注冊I2C客戶端驅動(i2c_driver);
?使用i2c_master_send()(寫數據)和i2c_master_recv()(讀數據)接口。
(2)用戶態使用(適合調試)
通過/dev/i2c-%d設備節點直接訪問,步驟:
1.打開設備節點:int fd = open("/dev/i2c-1", O_RDWR);;
2.設置從設備地址:ioctl(fd, I2C_SLAVE, 0x10);(0x10為從設備地址);
3.讀寫數據:用read()/write()函數直接讀寫。
??參考內核文檔Documentation/i2c/dev-interface。
(3)I2C工具(快速調試必備)
I2C-tools是開源工具集,需交叉編譯后使用,支持命令行調試:
?下載地址:
https://www.kernel.org/pub/software/utils/i2c-tools/
或git clone git://git.kernel.org/pub/scm/utils/i2c-tools/i2c-tools.git
?核心工具:
?i2cdetect:掃描I2C總線及掛載的設備(如i2cdetect -y 1掃描總線1);
?i2cdump:讀取從設備所有寄存器的值(如i2cdump -f -y 1 0x10);
?i2cget:讀取單個寄存器(如i2cget -y 1 0x10 0x01讀地址0x10的0x01寄存器);
?i2cset:寫入單個寄存器(如i2cset -y 1 0x10 0x01 0x55寫0x55到0x01寄存器)。
(4)GPIO模擬I2C(不推薦)
RK內核支持用GPIO模擬I2C,但效率低,僅適合臨時調試。配置示例(DTS):
i2c@4{compatible ="i2c-gpio";gpios = <&gpio5?9GPIO_ACTIVE_HIGH>,// SDA 引腳<&gpio5?8GPIO_ACTIVE_HIGH>;// SCL 引腳i2c-gpio,delay-us = <2>;// 約 100kbps 頻率status ="okay";// 掛載從設備(如 GT9xx 觸摸屏)gt9xx: gt9xx@14{compatible ="goodix,gt9xx";reg = <0x14>;// 其他外設參數...};};
三、RK I2C常見問題:從錯誤碼到波形Debug
開發中難免遇到問題,文檔中整理了兩類驅動的常見錯誤,我們按“錯誤類型”分類梳理,方便排查。
1. NACK錯誤:從設備無應答
現象:
?i2c-rk3x.c:調用傳輸接口返回-6(-ENXIO);
?i2c-rockchip.c:調用傳輸接口返回-11(-EAGAIN)。
原因與解決:
1.I2C地址錯誤:確認從設備地址(如文檔中ES8316是0x10,GT9xx是0x14),注意地址是否需要左移(7位地址通常需左移1位,加讀寫位);
2.從設備未正常工作:檢查從設備供電(如是否上電)、上電時序是否正確;
3.時序不匹配:從設備需要停止信號(P),但主設備發送了重復起始信號(Sr),需修改傳輸流程;
4.總線干擾:用示波器測量,若實際是ACK波形卻報NACK,需排查外部干擾(如布線是否靠近強電)。
2.超時錯誤:日志提示“timeout”
根據日志中ipd的值,對應不同問題:
(1)日志:timeout, ipd: 0x00, state: 1
?問題:I2C控制器異常,無法發送起始信號;
?原因:
a.SCL/SDA引腳復用錯誤(IOMUX配置錯);
b.上拉電壓不對(如3.3V上拉變成1.8V);
c.引腳被外設拉低(電壓異常);
d.I2C時鐘未開啟或時鐘源過小;
e.同時配置了CON_START和CON_STOP位(寄存器配置沖突)。
(2)日志:timeout, ipd: 0x10, state: 1
?問題:控制器正常,但CPU無法響應I2C中斷;
?原因:
a.CPU0被阻塞(RK I2C中斷默認在CPU0,用cat /proc/interrupts查看);
b.I2C中斷位被關閉(檢查中斷使能寄存器)。
(3)日志:timeout, ipd: 0x80, state: 1或scl was hold by slave
?問題:SCL被從設備拉低(總線卡死);
?排查方法:
a.排除法:若外設少,逐個斷開外設,復現問題定位“元兇”;
b.硬件檢測:在SCL總線串入電阻(如220Ω,約上拉電阻的1/20),測量電阻兩端壓差——電壓更低的一端對應拉低SDA/SCL的設備;
c.波形驗證:用示波器抓取波形,對比不同從設備的低電平,與故障時的低電平匹配的即為問題設備。
3.終極Debug:抓取I2C波形
若以上方法無法解決,最有效的方式是抓取故障時的I2C波形:
1.在代碼中“卡住CPU”:在出錯位置加while(1),避免發起新的I2C任務;
2.用示波器測量SDA和SCL引腳:觀察是否有起始信號、地址字節、ACK信號;
3.對比協議要求:若波形缺失(如無起始信號),檢查控制器配置;若有NACK,檢查從設備地址或狀態。
四、RK I2C開發知識腦圖
最后,用一張腦圖總結全文核心,方便大家收藏回顧:

寫在最后
RK平臺的I2C開發,核心是“理解協議+區分驅動+重視時序”——只要掌握了硬件原理和數據幀規則,再結合官方文檔配置驅動、排查問題,就能快速搞定絕大多數場景。
如果大家在開發中遇到具體問題,歡迎在評論區交流;也可以收藏本文,遇到問題時對照腦圖和排查步驟,效率會更高!
-
I2C總線
+關注
關注
8文章
417瀏覽量
63353 -
瑞芯微
+關注
關注
27文章
792瀏覽量
54282 -
音頻芯片
+關注
關注
3文章
162瀏覽量
18835
發布評論請先 登錄
STM32的硬件I2C有BUG嗎?
嵌入式內核及驅動開發-09IIC子系統框架使用(I2C協議和時序,I2C驅動框架,I2C從設備驅動開發,MPU6050硬件連接
再談I2C,硬件問題匯總及死鎖解決辦法
I2C debug出現問題怎么解決
OpenHarmony:如何使用HDF平臺驅動控制I2C
RK平臺Linux IOMMU開發:從原理到實戰
RK3576平臺PCA9548 I2C開關設備樹配置與生效全解析
RK平臺I2C開發:從硬件原理到實戰排查
評論