最近要讀寫 24C256,沒有參考網上代碼,自己擼了幾個小時,總是不對,讀取結果總是 0xFF,但是ACK的返回都是正確的,經過一番努力,終於找到問題所在了。 在晶元規格書裡面時序圖只有 START 和 STOP,沒有 RESTART,問題就是出在 RESTART 上面, 下圖是 I2C 標準裡面的 ...
最近要讀寫 24C256,沒有參考網上代碼,自己擼了幾個小時,總是不對,讀取結果總是 0xFF,但是ACK的返回都是正確的,經過一番努力,終於找到問題所在了。
在晶元規格書裡面時序圖只有 START 和 STOP,沒有 RESTART,問題就是出在 RESTART 上面, 下圖是 I2C 標準裡面的圖片。
對於 I2C 這種串列協議,根據不同的斷句有兩種寫法。
第一種:
- START中先是 SCL, SDA 為高,然後 SDA 為低。
- 每bit 都是 SCL 為低,SDA輸出,SCL 為高。 ACK 也是類似。
- STOP中先是 SCL 低,SDA低,然後 SCL 高, SDA 高。
第二種:
- START中先是 SCL, SDA 為高,然後 SDA 為低,然後 SCL 為低
- 每bit 都是 SDA輸出,SCL 為高,然後 SCL 為低。 ACK 也是類似。
- STOP中先是 SDA低,然後 SCL 高, SDA 高。
對於這兩種寫法,初看上去好像沒有什麼效果是一樣的,但是實際上是有區別的,第一種有BUG,第二種沒有問題。網上很多I2C都是按照第二種方法來寫的。第一種的BUG就是在讀取數據的時候體現出來的。因為讀取數據首先需要寫入地址,然後不用STOP,直接RESTART,讀取數據。
按照第一種的寫法,ACK結束的時候 SCL 為高,SDA 為低,然後接上 START,SCL為高,SDA為高,然後SDA為低。
按照第一種的寫法,ACK結束的時候 SCL 為低,SDA 為低,然後接上 START,SCL為高,SDA為高,然後SDA為低。
相當於第一種寫法,在 RESTART的時候,吞掉了一個 SCL 為低的過程。而這種 BUG 在 STOP 的時候是正常的,ACK 的返回也是正常的,但就是讀取數據的時候, 因為 RESTART不對,導致讀取都是 0xFF.
找到問題了,那麼有兩種解決方法,一種是直接按照第二種去寫,還有一種是直接增加一個 RESTART的函數,在這個函數裡面先 SCL 為低,然後接上正常的START函數即可。
通過這次的調試,也能發現標準的重要性,很多規格書裡面都是粗略的介紹,真正詳細的還是要找到通訊協議的標準。