SPI是能夠全雙工通訊的一種串行總線,兩個設備之間雙向通訊的話通常使用3根線:SCLK,MISO,MOSI,多個設備之間雙向通訊的話,每一個設備還須要再加上一根地址線CSn。相比之下I2C只能半雙工,並且通常須要上拉電阻,但不管幾個設備,都只須要2根線。更多基礎知識請谷歌百度。ios
Beaglebone Black使用的AM3359芯片上有兩個SPI,但SPI1鏈接到了板子的HDMI芯片上,因此除非禁用HDMI,不然咱們只能使用SPI0。本文將利用自帶的spidev驅動使能SPI0,並進行一下簡單的驗證。ide
配置device tree
首先咱們用我在《使用BBB的I2C》這篇文章中使用的方法檢驗一下SPI相關的引腳功能是否配置正確。檢查結果是,不正確,也就是說SPI默認是沒有啓用的,新版arm linux配置硬件的方式是利用device tree,因此咱們必需要配置一個device tree來啓用它。咱們先到 /lib/firmware 目錄中看看有沒有現成的device tree source (.dts)文件可供使用。咱們發現有一個BB-SPI0-00A0.dts。內容以下post
- /dts-v1/;
- /plugin/;
-
- / {
- compatible = "ti,beaglebone", "ti,beaglebone-black";
-
-
- part-number = "BB-SPI0";
- version = "00A0";
-
-
- exclusive-use =
-
- "P9.17",
- "P9.18",
- "P9.21",
- "P9.22",
-
- "spi0";
-
- fragment@0 {
- target = <&am33xx_pinmux>;
- __overlay__ {
-
- bb_spi0_pins: pinmux_bb_spi0_pins {
- pinctrl-single,pins = <
- 0x150 0x30
- 0x154 0x30
- 0x158 0x10
- 0x15c 0x10
- >;
- };
- };
- };
-
- fragment@1 {
- target = <&spi0>;
- __overlay__ {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&bb_spi0_pins>;
-
- #address-cells = <1>;
- #size-cells = <0>;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- };
- };
- };
從這個文件裏咱們能獲得不少信息(我在此嘮叨兩句,也算跟你們分享一下我學習的過程),首先咱們從exclusive-use這一部分能看出來AM3359芯片對SPI引腳的命名是跟通常不太同樣的,它沒用MISO和MOSI,而是D0和D1。經過查詢4000頁手冊咱們得知,原來是由於這兩個引腳的功能是能夠經過配置寄存器來互換的。默認的對應方式以下學習
再接着看,發現有一句註釋 測試
- /* note that you can do direct SPI via spidev now */
這個spidev就是咱們要用的spi驅動,而後谷歌一下它的用法就能夠了。再下面有一些被註釋掉的東西,是要根據不一樣設備來替換的。
(如下操做都在Beaglebone上進行)ui
咱們把自帶的文件複製一份,保存爲 BB-SPI0-01-00A0.dts ,而後增長一個節點,內容以下(就是原文件中註釋部分要替換的內容)this
- spidev@0 {
- spi-max-frequency = <24000000>;
- reg = <0>;
- compatible = "linux,spidev";
- };
保存之後編譯這個dts文件
- dtc -O dtb -o BB-SPI0-01-00A0.dtbo -b 0 -@ BB-SPI0-01-00A0.dts
而後把生成的.dtbo文件放到/lib/firmware目錄中spa
- cp BB-SPI0-01-00A0.dtbo /lib/firmware/
而後把它「插」到「插槽」中(請看個人博文《聊聊Beaglebone Black的cape和device tree overlay》).net
- echo BB-SPI0-01 > /sys/devices/bone_capemgr.*/slots
OK,這時咱們進入/dev目錄中就會發現比原來多了一個設備 spidev1.0 ,說明device tree配置沒有問題,該設備已成功加載。
使用SPI
由於我手邊沒有SPI設備,因此我把D0和D1也就是P9.18和P9.21這兩個引腳鏈接起來進行自發自收,若是收到了發送的數據即成功。時鐘線就沒必要管了,由於本身跟本身的時鐘確定是同步的。
測試程序使用的是linux自帶的一個spidev_test.c程序(下載地址是 https://www.kernel.org/doc/Documentation/spi/,不過仍是建議直接把整個kernel下載下來比較方便搜索查詢)。這個程序的內容就是發送一串16進制數,而後 printf 接收到的內容(不知道這串數有沒有什麼別的含義)。
下面把這個文件傳到Beaglebone上,用gcc編譯一下,生成可執行文件spidev_test。假設如今就在這個文件的目錄下,那麼咱們輸入
- ./spidev_test -D /dev/spidev1.0
來進行測試。獲得輸出
- spi mode: 0
- bits per word: 8
- max speed: 500000 Hz (500 KHz)
-
- FF FF FF FF FF FF
- 40 00 00 00 00 95
- FF FF FF FF FF FF
- FF FF FF FF FF FF
- FF FF FF FF FF FF
- DE AD BE EF BA AD
- F0 0D
說明測試成功了。不然會輸出一串FF。
爲何dts文件要那樣改?
剛剛我在自帶的
BB-SPI0-00A0.dts文件中加了一個節點,而後向其中加了幾個屬性,SPI0就能用了。增長一個節點還可以理解,但爲何要加這幾個屬性?這個問題我想了幾天也沒想得很清楚。不過我知道的是,這3個屬性缺一不可。
其中compatible屬性是每一個節點必須有的,它的做用是將這個設備和某個驅動進行綁定。好比這裏就是將這個spi設備與 linux -> spidev 這個驅動綁定。我把逗號換成了箭頭,是由於我以爲其實這個逗號表達的是從屬關係,用箭頭更合適。可是,我在kernel文件中翻遍了也沒找到哪裏有「linux,spidev」這樣的字眼。spidev驅動卻是找到了,並且在這個驅動文件中發現了以下內容
- static const struct of_device_id spidev_dt_ids[] = {
- { .compatible = "rohm,dh2228fv" },
- {},
- };
我試着把
BB-SPI0-01-00A0.dts裏的 compatible 值換成 「rohm,dh2228fv」,結果竟然也成功了!這彷佛說明之後若是咱們知道要用哪一個驅動的話,到驅動文件裏搜索compatible找到相應內容就能夠了。不過,我遺憾地發現大部分驅動文件裏都沒有這個屬性。可能只有一些硬件外設的驅動,或者是別的公司作的驅動裏纔會有。因此,我又迷惘了……