SPI是可以全雙工通信的一種串行總線,兩個設備之間雙向通信的話一般使用3根線:SCLK,MISO,MOSI,多個設備之間雙向通信的話,每個設備還需要再加上一根地址線CSn。相比之下I2C只能半雙工,而且一般需要上拉電阻,但無論幾個設備,都只需要2根線。更多基礎知識請谷歌百度。
Beaglebone Black使用的AM3359芯片上有兩個SPI,但SPI1連接到了板子的HDMI芯片上,所以除非禁用HDMI,否則我們只能使用SPI0。本文將利用自帶的spidev驅動使能SPI0,並進行一下簡單的驗證。
配置device tree
首先我們用我在《使用BBB的I2C》這篇文章中使用的方法檢驗一下SPI相關的引腳功能是否配置正確。檢查結果是,不正確,也就是說SPI默認是沒有啟用的,新版arm linux配置硬件的方式是利用device tree,所以我們必須要配置一個device tree來啟用它。我們先到 /lib/firmware 目錄中看看有沒有現成的device tree source (.dts)文件可供使用。我們發現有一個BB-SPI0-00A0.dts。內容如下
- /dts-v1/;
- /plugin/;
- / {
- compatible = "ti,beaglebone", "ti,beaglebone-black";
- /* identification */
- part-number = "BB-SPI0";
- version = "00A0";
- /* state the resources this cape uses */
- exclusive-use =
- /* the pin header uses */
- "P9.17", /* spi0_cs0 */
- "P9.18", /* spi0_d1 */
- "P9.21", /* spi0_d0 */
- "P9.22", /* spi0_sclk */
- /* the hardware ip uses */
- "spi0";
- fragment@0 {
- target = <&am33xx_pinmux>;
- __overlay__ {
- /* default state has all gpios released and mode set to uart1 */
- bb_spi0_pins: pinmux_bb_spi0_pins {
- pinctrl-single,pins = <
- 0x150 0x30 /* spi0_sclk.spi0_sclk, INPUT_PULLUP | MODE0 */
- 0x154 0x30 /* spi0_d0.spi0_d0, INPUT_PULLUP | MODE0 */
- 0x158 0x10 /* spi0_d1.spi0_d1, OUTPUT_PULLUP | MODE0 */
- 0x15c 0x10 /* spi0_cs0.spi0_cs0, OUTPUT_PULLUP | MODE0 */
- >;
- };
- };
- };
- fragment@1 {
- target = <&spi0>; /* spi0 is numbered correctly */
- __overlay__ {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&bb_spi0_pins>;
- #address-cells = <1>;
- #size-cells = <0>;
- /* add any spi devices connected here */
- /* note that you can do direct SPI via spidev now */
- // commented out example of an adafruit 1.8" TFT display
- // from firmare/capes/cape-bone-adafruit-lcd-00A0.dts
- // lcd@0 {
- // #address-cells = <1>;
- // #size-cells = <0>;
- //
- // compatible = "adafruit,tft-lcd-1.8-red", "sitronix,st7735";
- // reg = <0>;
- //
- // spi-max-frequency = <8000000>;
- // spi-cpol;
- // spi-cpha;
- //
- // pinctrl-names = "default";
- // pinctrl-0 = <&bone_adafruit_lcd_pins>;
- //
- // st7735-rst = <&gpio4 19 0>;
- // st7735-dc = <&gpio4 21 0>;
- // };
- };
- };
- };
從這個文件里我們能得到很多信息(我在此嘮叨兩句,也算跟大家分享一下我學習的過程),首先我們從exclusive-use這一部分能看出來AM3359芯片對SPI引腳的命名是跟一般不太一樣的,它沒用MISO和MOSI,而是D0和D1。通過查詢4000頁手冊我們得知,原來是因為這兩個引腳的功能是可以通過配置寄存器來互換的。默認的對應方式如下

再接着看,發現有一句注釋
- /* note that you can do direct SPI via spidev now */
這個spidev就是我們要用的spi驅動,然后谷歌一下它的用法就可以了。再下面有一些被注釋掉的東西,是要根據不同設備來替換的。
(以下操作都在Beaglebone上進行)
我們把自帶的文件復制一份,保存為 BB-SPI0-01-00A0.dts ,然后增加一個節點,內容如下(就是原文件中注釋部分要替換的內容)
- spidev@0 {
- spi-max-frequency = <24000000>;
- reg = <0>;
- compatible = "linux,spidev";
- };
- dtc -O dtb -o BB-SPI0-01-00A0.dtbo -b 0 -@ BB-SPI0-01-00A0.dts
然后把生成的.dtbo文件放到/lib/firmware目錄中
- cp BB-SPI0-01-00A0.dtbo /lib/firmware/
然后把它“插”到“插槽”中(請看我的博文《聊聊Beaglebone Black的cape和device tree overlay》)
- echo BB-SPI0-01 > /sys/devices/bone_capemgr.*/slots
使用SPI
- ./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
為什么dts文件要那樣改?
- static const struct of_device_id spidev_dt_ids[] = {
- { .compatible = "rohm,dh2228fv" },
- {},
- };
