使用Beaglebone Black的I2C(一)

本文我將使用BBB的I2C1讀取氣壓傳感器芯片BMP085和三軸陀螺儀L3G4200D的值。

在c語言中實現讀取i2c設備的方法請見《使用Beaglebone Black的I2C(二)》

前言

首先說明,我使用的硬件外設是一個九軸氣壓傳感器模塊,包括一個三軸陀螺儀芯片,一個三軸磁場傳感器芯片,一個三軸加速度計芯片和一個氣壓傳感器芯片。這4個芯片使用同一個I2C與BBB通信,下面記錄一下它的使用方法。

I2C是一種串行通訊方法,它只需要兩根線就能實現通訊,一根時鐘線SCL,一根數據線SDA。一般情況下這兩根線都使用上拉電阻,同時把芯片的管腳設置成開漏輸出(簡單理解開漏輸出的含義就是:讓它輸出低電平時,它能輸出低電平;而讓它輸出高電平時,它就斷路,什麼也不輸出,由外接電平決定這個引腳的電平)。如果芯片內部帶有上拉電阻(比如BBB的芯片就自帶上拉電阻),那不外接上拉也可以。

BBB系統自帶了一個Linux下的I2C工具i2c-tools,非常好用,下文以i2c開頭的命令都是這個工具包裏的,如果你的系統裏沒有的話,可以搜索並下載i2c-tools工具包。

BBB上有兩個可用的I2C,i2c-0和i2c-1,分別對應header上的I2C1和I2C2(總是這麼混亂= =)。我們這裏使用i2c-1,對應的header是P9_19和P9_20。我怎麼知道它有兩個可用的I2C呢?使用命令 i2cdetect -l 就可以看到

i2c-0	i2c       	OMAP I2C adapter                	I2C adapter
i2c-1	i2c       	OMAP I2C adapter                	I2C adapter

OK,下面開始操作。

檢查引腳功能配置

首先確認一下i2c-1對應的IO口複用功能是否正確(BBB默認就是正確的,所以無需進行配置)。查表得,P9_19和P9_20分別對應95和94號引腳。(在新頁面打開圖片可看到完整圖)


輸入命令

# cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pins | grep 97c

上述命令把pins這個文件中包含97c的內容輸出(97c是表中看到的引腳地址),得到95號引腳的功能和複用寄存器值

pin 95 (44e1097c) 00000073 pinctrl-single

95號引腳的功能寄存器值是0x00000073,化成2進制是1110011,其含義是:啓用功能3(即I2C2_SCL),使能上下拉,開啓上拉(所以我們可以不必外接上拉電阻了),使能輸入,高速模式。同樣可以檢查94號引腳,也是0x00000073。

查找i2c設備的地址

(此時我們還沒有插入設備)使用命令# i2cdetect -y -r 1 ,可以查看i2c設備地址。其中 -y 選項用來屏蔽討厭的確認環節,-r 是因爲AM3359不支持一種叫做Quick Write的東東,1 代表我們要查看i2c-1總線上的設備(也就是P9_19和P9_20上插着的設備)。輸出如下

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- UU UU UU UU -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

這裏的地址都是16進製表示的。--代表該地址沒有設備,UU代表這個地址正忙(也許被內部資源佔用了,見圖中的0x54到0x57這4個地址)。下面我把i2c設備插上以後再執行命令,輸出變成了

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 1e --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- 53 UU UU UU UU -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- 69 -- -- -- -- -- --
70: -- -- -- -- -- -- -- 77

會發現多出了4個地址:0x1e,0x53,0x69和0x77。因爲我接入的模塊上包含4個芯片,所以這個總線上顯示了4個地址。通過讀芯片手冊得知氣壓計對應的是0x77這個地址。這一步就完成了。

需要補充說明的是,這裏顯示的是i2c設備的地址(1110111b=0x77),i2c的設備地址只有7位,最高位當做0。而讀/寫地址則在最低位增加一個1/0(11101111b / 11101110b),這使得讀寫地址與設備地址看起來很不相同。

查看和修改設備的寄存器值

輸入命令# i2cdump -y 1 0x77,我們可以查看設備的寄存器值,其中 -y 還是屏蔽確認環節,1 還是代表查看i2c-1總線,0x77是要查詢的設備地址。

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
80: a5 94 4d 19 b3 27 38 43 8a 2a 1e 05 fb af c7 6e    ??M??'8C?*?????n
90: 84 df 5f b0 56 5a 15 7a 00 3a 80 00 d4 bd 09 80    ??_?VZ?z.:?.????
a0: a5 94 4d 19 b3 27 38 43 8a 2a 1e 05 fb af c7 6e    ??M??'8C?*?????n
b0: 84 df 5f b0 56 5a 15 7a 00 3a 80 00 d4 bd 09 80    ??_?VZ?z.:?.????
c0: 00 00 bc 33 00 00 00 00 00 00 00 10 00 00 00 03    ..?3.......?...?
d0: 55 02 06 00 00 00 00 00 00 00 00 00 00 00 00 00    U??.............
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: 00 00 00 00 00 00 80 00 00 00 00 00 00 00 00 00    ......?.........

這裏用16進制顯示了每個寄存器的值,具體哪個寄存器是幹嘛的,就得查閱芯片的數據手冊了。

如果想取出某個特定寄存器的值,比如0x80寄存器,可以使用命令 i2cget -y 1 0x77 0x80實現。如果想向某個寄存器寫入值,可使用命令 i2cset -y 1 0x69 0x20 0x0f實現。(向i2c-1總線上,設備地址爲0x69,寄存器地址爲0x20處寫入值0x0f)

使用BMP085驅動讀取氣壓值

很巧的是,BBB自帶了BMP085氣壓芯片的驅動,所以我們可以更方便地讀取氣壓值。輸入命令

# echo bmp085 0x77 > /sys/class/i2c-adapter/i2c-1/new_device

加載成功後使用如下命令就可以讀取氣壓值了

# cat sys/bus/i2c/drivers/bmp085/1-0077/pressure0_input

使用完畢以後,我們可以用如下命令從驅動中卸載這個i2c設備

# echo 0x77 > /sys/class/i2c-adapter/i2c-1/delete_device

想查看加載或卸載是否成功的話,可以輸入如下命令

# dmesg | grep bmp

你應該會看到類似下面的輸出

[ 6428.602566] i2c i2c-1: new_device: Instantiated device bmp085 at 0x77
[ 6428.633419] bmp085 1-0077: Successfully initialized bmp085!
[ 6436.479407] i2c i2c-1: delete_device: Deleting device bmp085 at 0x77

問題

但是BBB沒有帶其他芯片的驅動,我暫時還不知道如何自己寫驅動。(見最後更新)更奇怪的是我查看其他設備地址的寄存器,得到很詭異的輸出。

比如# i2cdump -y 1 0x69 c 時:
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
10: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
20: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
30: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
40: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
50: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
60: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
70: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
80: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
90: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
a0: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
b0: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
c0: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
d0: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
e0: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????
f0: c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4 c4    ????????????????

更新解答上面的問題

是輸出模式的原因。# i2cdump -y 1 0x69 c 命令中的c代表連續字節輸出。把它去掉,用默認的字節輸出模式就可以了。

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: c4 66 a5 cc 4c d0 89 c1 c2 e0 24 18 3b 87 00 d3    ?f??L?????$?;?.?
10: 44 b5 22 04 0c 80 40 60 1a 11 ee 90 83 01 85 83    D?"???@`????????
20: 07 00 00 00 00 00 00 00 00 f0 fb 06 ce fc 00 20    ?........?????. 
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
80: c4 66 a5 cc 4c d0 89 c1 c2 e0 24 18 3b 87 00 d3    ?f??L?????$?;?.?
90: 44 b5 22 04 0c 80 40 60 1a 11 ee 90 83 01 85 83    D?"???@`????????
a0: 07 00 00 00 00 00 00 00 00 f0 fb 06 ce fc 00 20    ?........?????. 
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................

再多說兩句,這個設備是L3G4200D三軸陀螺儀,通過查芯片手冊得知,0x20寄存器的第4位是芯片使能,現在0x20寄存器的值是0x07,即00000111b,我要把它變成00001111b,即0x0f,輸入命令# i2cset -y 1 0x69 0x20 0x0f

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: c4 66 a5 cc 4c d0 89 c1 c2 e0 24 18 3b 87 00 d3    ?f??L?????$?;?.?
10: 44 b5 22 04 0c 80 40 60 1a 11 ee 90 83 01 85 83    D?"???@`????????
20: 0f 00 00 00 00 00 1d ff 33 00 d5 ff fc ff 00 20    ?.....?.3.?.?.. 
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
80: c4 66 a5 cc 4c d0 89 c1 c2 e0 24 18 3b 87 00 d3    ?f??L?????$?;?.?
90: 44 b5 22 04 0c 80 40 60 1a 11 ee 90 83 01 85 83    D?"???@`????????
a0: 0f 00 00 00 00 00 1d ff 52 00 f7 ff 24 00 00 20    ?.....?.R.?.$.. 
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ............….

就成功使能陀螺儀了。根據芯片手冊,0x28到0x2d這6個寄存器存放的是三軸角速度的值,所以我們比較上面兩次i2cdump的結果會發現,這幾個寄存器是有變化的,說明芯片正常工作了。

再次更新:其實BBB帶了其他芯片驅動的……

使用L3G4200D三軸陀螺儀,需要先加載 st_sensors.ko 和 st_sensors_i2c.ko ,然後再加載 st_gyro.ko 和 st_gyro_i2c.ko。方法是
# insmod /lib/modules/3.8.13/kernel/drivers/iio/gyro/st_gyro.ko
其他3個類似。加載完4個模塊以後(可以用 lsmod 命令確認一下),跟上述類似的方法,加載l3g4200d這個i2c設備。
# echo l3g4200d 0x69 > /sys/bus/i2c/devices/i2c-1/new_device
注意,/sys/class/i2c-adapter/i2c-1/new_device 和 /sys/bus/i2c/devices/i2c-1/new_device這兩個目錄其實是一樣的。都是指向同一個地方的鏈接。
完成以後就會發現在 /sys/bus/i2c/devices目錄下多了一個 1-0069 目錄,裏面有一個iio:device0目錄,這個目錄下就是上面加載的4個驅動提供的用戶接口,即3個軸的角速度等。我們可以用cat命令讀取文件內容來觀察,是在不斷變化的。



使用adxl345加速度計時出了點問題,加載驅動方法類似,沒什麼問題:
# insmod /lib/modules/3.8.13/kernel/drivers/input/misc/adxl34x.ko
# insmod /lib/modules/3.8.13/kernel/drivers/input/misc/adxl34x-i2c.ko
但是在執行下面命令之後,
# echo adxl34x 0x1e > /sys/bus/i2c/devices/i2c-1/new_device
雖然在/sys/bus/i2c/devices目錄下多了一個 1-001e 目錄,但是該目錄下沒有出現想要的有關加速度計的內容。經過
# dmesg | grep adxl34x | tail -5
顯示記錄,發現給出了一個錯誤提示:
[ 6960.709459] adxl34x 1-001e: no IRQ?
這是驅動源碼給出的錯誤信息。但如何解決就不清楚了,因爲還不太瞭解驅動的工作原理。

這個過程表明,即便不存在的設備或有問題的設備,使用類似命令echo “設備名” “I2C地址” > /sys/bus/i2c/devices/i2c-1/new_device也能創建一個設備節點,只不過裏面什麼有用的東西都沒有就是了。



另外關於/sys目錄下的內容簡單記錄一下:

在 /sys 目錄下有 block, bus, class, dev, devices, firmware, fs, kernel, module, power 這些子目錄。

devices目錄是這裏面最重要的目錄,這是內核對系統中所有設備的分層次表達模型。

block、bus、class、dev這4個目錄分別是所有的塊設備、按總線分類、按類別分類和按主次設備號分類的設備列表。實際上這4個目錄的內容最後都是指向devices目錄裏相應設備的鏈接。相當於給我們提供了幾種不同的方式找到想要找的設備。


其他目錄的內容如下:

module目錄裏顯示着幾乎所有已經加載的驅動模塊的信息,包括以內聯方式編譯到內核映像文件中的模塊和外部模塊(ko文件)。

kernel目錄是內核所有可調整參數的位置,目前只有幾項較新的設計在使用它,其它內核可調整參數仍然位於 sysctl (/proc/sys/kernel) 接口中。

fs目錄按照設計是用於描述系統中所有文件系統,但目前只有少數文件系統支持 sysfs 接口,一些傳統的虛擬文件系統(VFS)層次控制參數仍然在 sysctl (/proc/sys/fs) 接口中。

firmware目錄是系統加載固件機制的對用戶空間的接口。

power目錄是系統中電源選項,這個目錄下有幾個屬性文件可以用於控制整個機器的電源狀態,如可以向其中寫入控制命令讓機器關機、重啓等。 








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章