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找到相应内容就能够了。不过,我遗憾地发现大部分驱动文件里都没有这个属性。可能只有一些硬件外设的驱动,或者是别的公司作的驱动里才会有。因此,我又迷惘了……