LPC23XX之I2C使用總結(jié)
--- 原野之狼寫于2010年重陽節(jié)之時
近來由于項目需要,玩了玩LPC23XX系列的I2C,這么一個小小的東西費了我一周的時間,實在是令人崩潰!
首先要指出的是,原廠的LPC23XX的User Manual存在著嚴重的誤導作用,另外給的Sample程序也存在著誤導作用。很不幸,俺手頭上擁有的正好是這兩份資料,所以走了許多彎路。
關于I2C的官方Specification諸位最好先看看,我就提醒一點:I2C硬件上要求各I2C器件不管是作為Master還是作為Slave使用時都要采用OC或者OD模式作為IO接口,然后在外部用電阻上拉到電源,這樣才能使得當總線沖突時高電平和低電平不會互相拼個你死我活。目前Internet上的一些關于I2C的參考程序一般都是采用IO模擬I2C協(xié)議來實現(xiàn)的,這當然是可以的,但是記得要把MCU的IO口配置成OC、OD或者弱上拉模式,不要弄成推挽輸出哦。不過采用IO模擬方式比較占資源系統(tǒng)資源,本文描述的是采用MCU自帶的I2C控制器來實現(xiàn)。
LPC23XX支持3個I2C接口,這三者并不是完全一樣的,I2C0是嚴格遵守I2C協(xié)議的,而I2C1和I2C2并不嚴格遵守I2C協(xié)議,這體現(xiàn)在IO口的結(jié)構上,這點需要引起注意。
接下來說說User Manual的問題,我設置I2C控制器作為Master使用,并且是Single Master,外部掛了個RTC器件,因此本文的描述以此為前提條件。
User Manual關于I2C控制器的描述主要體現(xiàn)在這么一些資料:
資料1:狀態(tài)遷移圖Fig116和Fig117(P520~521)。
資料2:狀態(tài)表Table451和Table452(P452~453)。
資料3:關于軟件編寫指導性的文字描述(P533)。
這三者本來應該是關聯(lián)性很強并互為指導的的文檔資料,但是我看了好幾天都沒有明白寫的是啥子意思,無奈只好憑著感覺先把代碼寫完,然后一邊調(diào)試程序一邊對著資料看,旁邊還架上示波器來看波形。
關于資料3,諸位看個大概就行了,如果你按照這個細節(jié)去做估計會死得很慘。
關于資料2,這個資料倒是沒問題,但是得弄明白才行。
關于資料1,這個資料非常重要,但是很不好理解,要是沒有按照它所指定的路線操作就會出莫名其妙的問題。
先解讀一下資料1的Fig116,用以輔助理解,當然諸位首先得看看User Manual,要不然俺說了也是白說,解讀如下:
1、 程序設置S位到相關寄存器,控制器會嘗試著去獲得I2C的操作權,獲得特權后就會發(fā)送起始信號。
2、 成功完成起始信號的發(fā)送后控制器會產(chǎn)生中斷并返回0X08(注意不要理解錯了,此返回并不是指中斷程序返回,而是指控制器的狀態(tài)寄存器的信息,下同)。
3、 程序?qū)懭?/SPAN>SLA+W信息到相關寄存器。
4、 發(fā)送成功后會產(chǎn)生中斷并返回0X18。
5、 程序?qū)懭胍l(fā)送的數(shù)據(jù)到到相關寄存器。
6、 發(fā)送成功后會產(chǎn)生中斷并返回0X28。
7、 如果還要繼續(xù)發(fā)送請回到5,否則寫入P到相關寄存器。
8、 在7時,如果數(shù)據(jù)已經(jīng)發(fā)送完但是并不想寫P以停止I2C操作,而需要繼續(xù)進行別的操作。舉個例子,比如在讀取RTC的時間信息時,先寫入要訪問的寄存器地址信息,然后在讀出數(shù)據(jù)信息,這是一個連貫的動作,并不需要插入P操作的,具體請查看RTC數(shù)據(jù)手冊。那么這個時候程序再次設置S位到相關寄存器,使得控制器發(fā)送起始信號。
9、 上一步再次發(fā)送S成功后會產(chǎn)生中斷并返回0X10。此時程序?qū)懭?/SPAN>SLA+R信息到相關寄存器。
10、 接下來就轉(zhuǎn)到了Fig117了。
接下來,解讀一下Fig117:
1、 程序設置S位到相關寄存器,控制器會嘗試著發(fā)送起始信號。
2、 成功完成起始信號的發(fā)送后控制器會產(chǎn)生中斷并返回0X08。
3、 程序?qū)懭?/SPAN>SLA+R信息到相關寄存器。
4、 發(fā)送成功后會產(chǎn)生中斷并返回0X40,注意Fig116第10條也就是這里的第4條。這個時候我們該做什么了呢,顯然是需要讀取數(shù)據(jù)。但是請注意,并不是現(xiàn)在就讀取數(shù)據(jù),因為本條的0X40僅僅表示了SLA+R發(fā)送完畢了,我們想要的其它數(shù)據(jù)還在后頭呢,中斷程序退出后控制器才會產(chǎn)生時鐘去外部I2C器件那里取數(shù)據(jù)。
5、 如上所述,當讀取數(shù)據(jù)成功后控制器會產(chǎn)生中斷并返回0X50,這時就可以從控制器的數(shù)據(jù)寄存器拷貝數(shù)據(jù)了。根據(jù)I2C協(xié)議,此時主機還需要向從機提供應答信號,如果接下來還需要讀取數(shù)據(jù),那么應答ACK,否則應答NO ACK。如果應答ACK,請繼續(xù)第5條,否則就是第6條的事情了。應答操作由程序完成。
6、 如果之前應答的是NO ACK,應答完后控制器會產(chǎn)生中斷并返回0X58。寫入P到相關寄存器完成此次I2C操作。
以上兩篇解讀僅以狀態(tài)遷移圖的主線為例,其它分支因為比較簡單所以沒有做解讀,編程的時候需要考慮其它分支情況。
關于資料1就說這么多,一定要先把這個狀態(tài)遷移圖搞明白,要不然會死得不明不白。資料1理解透了,看資料2就輕松許多了,無非是一些細節(jié)嘛。記住一條就是了,該設置的位要設置,該清除的位要清除,不能多也不能少,會帶來什么問題俺也不清楚,沒有逐個測試,調(diào)試的過程發(fā)現(xiàn)不正確的設置會導致狀態(tài)遷移不按規(guī)定的路徑走。
在調(diào)試的過程中可以通過跟蹤中斷程序中讀來的狀態(tài)碼來確定狀態(tài)遷移路徑,要是路徑不對多半就是俺在上一個段落中提到的原因了。還有一點尤其注意,有些I2C器件存在超時的問題,就是說一次完整的I2C操作(從S開始算起,以P作為結(jié)束)需要在規(guī)定的時間內(nèi)完成,所以諸位千萬不要在中斷程序里設置斷點來觀察寄存器信息,除非你能保證你眼睛夠犀利手腳夠麻利能夠在超時時間之內(nèi)完成想要做的事情。
OK,該打住了,就說這么多,不要向我要源代碼,不是本狼不夠OPEN,是因為俺自己都搞不到。
聯(lián)系我:y_y_z_l 愛她 163.com
版權聲明:歡迎轉(zhuǎn)載,但請保留本文的完整性。