楊文鉑,邢鵬康
(河南工業職業技術學院,南陽 473000)
I2C總線作為一種接口標準最早由Philips公司提出,因其優良的性能在電子工業中得到了廣泛的應用。在嵌入式Linux系統下,標準的I2C驅動為分層架構,由上至下依次是設備層、核心層和適配器層。這種多層架構有效滿足了Linux下多設備、多任務并行工作的要求,但同時也使I2C設備驅動的開發變得非常復雜。本文探討了一種在I2C設備串行工作的情況下,直接在適配器層實現的I2C驅動方法,這將有效簡化Linux下I2C設備驅動的開發。這里基于ARM9的S3C2440芯片和2.6.30核心的嵌入式Linux系統平臺進行分析。
I2C設備分為主機及從機。主機即主控芯片內的I2C適配器,它完成基本的時序控制功能,如起始、傳輸數據、停止等。從機即外圍I2C芯片,它是被主機尋址的器件,接收主機發送的命令和數據,返回相應的數據。按數據流的方向又可將I2C設備分為發送器或接收器。常用的數據傳輸模式主要有兩種:主機發送模式,此時主機為發送器,從機為接收器;主機接收模式,此時主機為接收器,從機為發送器。一個設備是發送器還是接收器,取決于實際數據流的方向。一個完整的主機讀或寫過程稱為一個消息,每一個消息都必須有一個起始信號(S)來指示其開始,起始信號由主機發出。在SCL線是高電平時SDA線從高電平向低電平切換,這個情況表示起始條件。如果一個I2C通信過程是主機多個讀寫過程的組合,則要有多個消息,需重復發出起始信號。在每個消息中,主機發出起始信號后都要接著發送從機地址字節,這個字節前7位代表從設備物理地址,最低位R/W決定了數據流的方向,如果是0,表示主機寫數據到從機,1表示主機向從機讀。發送到SDA總線上的數據必須是8位,但是每次發送的字節數不受限制。數據傳輸必須帶應答(ACK),應答脈沖由接收器產生,在應答的時鐘脈沖期間,發送器釋放SDA線。通常被尋址的接收器在接收到每個字節后,必須產生一個應答,才能正常通信。最后,需要由主機發出一個停止信號,結束整個通信過程,使總線回到空閑狀態,當SCL是高電平時SDA線由低電平向高電平切換表示停止條件。基本I2C總線時序如圖1所示。

圖1 基本I 2 C總線時序
S3C2440中I2C適配器中的寄存器主要有IICDS、ICSTAT、IICCON、IICADD等。IICDS寄存器為一個8位的移位寄存器,待發的數據先送至此寄存器,在起始信號發出后,將數據逐位發送到SDA總線上。
IICSTAT為狀態寄存器,主要實現I2C總線的信號發生功能,如下所示。其中第6、7位是模式選擇位,可決定4種模式,分別是主機發送、主機接收、從機發送、從機接收等。第5位是一個讀寫位,在讀時如果為0表明總線空閑,如果為1表明總線正忙。如果向其寫1,則主機將會發送開始信號,如果向其寫0,則主機將發送停止信號。

模式選擇忙、停止、起始狀態輸出允許 仲裁位 從片地址狀態地址零狀態最后接收位7∶6 5 4 3 2 1 0
IICCON為一個8位寄存器,主要實現I2C總線的一些配置功能,如下所示。應答設置位控制是否應答,低4位和第6位共同決定了發送時鐘的頻率。

應答設置發送時鐘源選擇發送/接收中斷中斷掛起標志傳輸時鐘選擇7 6 5 4 3∶0
I2C的時序及操作模式都可通過配置主機適配器的方式實現,I2C的基本時序包括起始信號、從機地址、發送數據、讀數據、應答信號、停止信號等。操作模式主要包括主機讀、主機寫、從機讀、從機寫等。以此為基礎,可以通過在總線上組合傳輸起始信號、地址信號、停止信號等,來實現任意復雜的I2C通信功能。
操作模式:通過寫IICSTAT寄存器的高兩位操作設置。
起始信號:向IICSTAT寄存器的第5位寫1后,將會在總線上發出一個起始信號。
從機地址:這個從機地址需要在發起始信號前寫入移位寄存器IICADD中去。IICADD物理地址為0x54000008,8位,高7位保存地址,最低位R/W為讀寫控制位。
應答信號:由接收器在接到發送器發送的地址或有效數據后發出,如果接收器配置為允許應答,則收到數據后將自動應答,應答設置位在IICCON的最高位,寫1為允許應答,寫0為禁止應答。
主機發送數據:待發送的數據需事先寫入IICDS寄存器中,當發送條件滿足后(起始信號發出,或TX/RX中斷標志位清除后等),IICDS中的數據將自動移位發送。
主機接收數據:在收到總線上的一字節數據后,將存儲于IICDS中。主機可通過查詢IICCON中的中斷標志位來確定是否接收成功一個字節。如果主機不發送應答信號,則從機將一直處于等待狀態。數據接收完畢后如果不清除中斷掛起位,I2C通信將進入暫停狀態。
停止信號:停止信號的發出由IICSTAT寄存器的第5位清零來實現。
下文結合LM75傳感器采集溫度的例子具體說明這種方法在Linux下的實現過程。
LM75為支持I2C協議的數字式溫度傳感器,可多達8個傳感器共享一根總線,可在環境超過設定溫度時通知主控制器,測溫精度為0.5℃,轉換后的溫度值用2字節保存。LM75的溫度字節讀取時序如圖2所示。
可以在Linux底層驅動中對I2C寄存器組進行直接操作,根據LM75的時序要求組合I2C基本時序,實現LM75的模式設置及溫度采集功能,程序流程如圖3所示。
以下是在適配器層的部分驅動函數代碼:


圖2 LM75的溫度字節讀取時序

圖3 LM75時序的底層實現流程

在驅動函數完成后還要在適配器層填充一個file_operations的數據結構,由于用戶空間不能直接調用適配器層中的函數,驅動函數需要映射為應用層的函數,這個數據結構提供了驅動層函數在應用層的函數接口。

適配器層驅動函數iic_LM75_read被映射為應用層的接口函數read,以為應用層所調用。按上述方法構建的I2C驅動在Linux下以普通設備驅動的形式加載,在加載的過程執行初始化操作,通過 MKDEV()函數創建主設備節點并分配設備號,通過I2C_setup_dev()函數實現驅動層到應用層函數的映射。在應用層調用適配器層驅動時,須首先用open()函數打開dev中的主設備,在open過程中配置各個I2C功能寄存器,配置輸入/輸出端口,完成后,將獲得一個設備節點fd,以此節點作為驅動接口的設備參數傳入,便可調用底層的驅動函數。
實踐證明,在嵌入式Linux環境下,適配器層直接實現I2C設備驅動的方法,構造簡單,可靠性高,占用資源少,對不同設備的適應性強,可有效提高I2C設備驅動開發的效率。
[1]I2C 總線規范[OL].[2011-01].www.zlgmcu.com/download/down.asp?ID=780.
[2]Samsung Electronics.S3C2440 32-BIT CMOS Microcontroller User's Manual Revision 1,2004.
[3]安森美半導體.LM75-2線串行溫度傳感器和監視器,2006.
[4]Jonathan Corbet,Alessandro Rubini,Greg Kroah-Hartman.Linux Device Drivers[M].3rd Edition.O'Reilly,2005.
[5]李俊.嵌入式Linux設備驅動開發詳解[M].北京:人民郵電出版社,2008.