因为兴趣,业余时间把玩下手边的imax6ul开发板。Linux内核集成了spidev驱动,提供了SPI设备的用户空间API。支持用于半双工通信的read和write访问接口以及用于全双工通信和I/O配置的ioctl接口。使用时,只需将SPI从设备的compatible属性值添加到spidev区动的spidev dt ids[]数组中,即可将该SPI从设备创建为spidev设备。如果不想编写单独的spi设备驱动,那么使用linux内核提供的通用spidev设备驱动就够了,它提供统一的字符设备操作,那么只需要在应用层读写和控制即可。
spidev是一个Linux内核驱动,用于与SPI(串行外设接口)设备进行通信。SPI是一种全双工、同步的串行通信协议,常用于连接微控制器和外部设备。spidev驱动允许用户空间程序通过Linux的设备文件接口与SPI设备进行通信。用户可以通过打开和读写设备文件来发送和接收SPI数据。spidev驱动提供了一组控制IO口和SPI参数的ioctl命令。
同时Linux内核也集成了SPI测试工具spidev test,用于在用户态对spidev动功能进行测试和验证。
spidev设备驱动源码位置在:linux-imx-4.1.15\drivers\spi\spidev.c
驱动框架框图:
除了使用spidev驱动外,当然也可以自己编写SPI驱动。
使用现有的spidev驱动可以简化开发过程,因为它提供了一组用户空间接口,可以直接在应用程序中使用标准的文件操作函数(如open、read、write和ioctl)来操作SPI设备。这种方式适用于大多数应用场景,特别是对于简单的SPI设备操作,可以快速实现功能。
如果使用自己编写的SPI驱动也可以,也不算麻烦,需要在内核中实现SPI子系统,包括SPI控制器驱动和SPI设备驱动,最后根据需要实现个如字符型设备驱动操作接口,供上层应用使用即可。
用户应用层使用spidev驱动的步骤如下:
1. 打开SPI设备文件:用户可以通过打开/dev/spidevX.Y文件来访问SPI设备,其中X是SPI控制器的编号,Y是SPI设备的编号。
2. 配置SPI参数:用户可以使用ioctl命令SPI_IOC_WR_MODE、SPI_IOC_WR_BITS_PER_WORD和SPI_IOC_WR_MAX_SPEED_HZ来设置SPI模式、数据位数和时钟速度等参数。
3. 发送和接收数据:用户可以使用read和write系统调用来发送和接收SPI数据。写入的数据将被传输到SPI设备,而从设备读取的数据将被存储在用户提供的缓冲区中。
4. 关闭SPI设备文件:当不再需要与SPI设备通信时,用户应该关闭SPI设备文件。
总结起来,spidev驱动提供了一种简单而灵活的方式来与SPI设备进行通信,使得用户可以轻松地在Linux系统上开发和控制SPI设备。
使能spidev用户态驱动
在生成的config文件中可以看到以下配置生效了。我的是在imx6ul开发板的imx_v7_defconfig的linux内核配置文件中。
CONFIG_SPI=y
CONFIG_SPI_GPIO=y
CONFIG_SPI_IMX=y
CONFIG_SPI_SPIDEV=y
&ecspi3 {
fsl,spi-num-chipselects = <2>;/*cs管脚数配置*/
cs-gpios = <0>,<&gpio1 20 GPIO_ACTIVE_LOW>;/*cs管脚配置*/
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi3>;
status = "okay";/* status属性值为"okay" 表示该节点使能*/
spidev: icm20608@0 {
compatible = "alientek,icm20608";
spi-max-frequency = <8000000>;
reg = <0>;/*spi设备是没有设备地址的, 这里是指使用spi控制器的cs-gpios里的第几个片选io */
};
oled: oledsh1106@1 {
compatible = "yang,oledsh1106";/*重要,会匹配spidev.c中指定的compatible*/
spi-cpol;/*配置spi信号模式*/
spi-cpha;
spi-max-frequency = < 8000000 >;/* 指定spi设备的最大工作时钟 */
reg = <1>;
};
};
以上需要注意的是:如果该spi接口下挂载有多个从设备,需要设置fsl,spi-num-chipselects = <2>;默认该值为1。还有需要注意的地方是,cs-gpios 片选信号需要配置对应的个数。以上的为配置了两路片选GPIO管脚,第一个默认的,第二个是指定的。如果仅有一个从设备,可以配置cs-gpio就行了。注意cs-gpio和cs-gpios的区别,带s的标识可以有多个。
如果忽略cs管脚数配置,则会出现以下错误:
需要设置fsl,spi-num-chipselects = <2>;
注意上面的compatible 属性,在新版linux内核,可以写任意的字符串,最好不再写”spidev”,老版的是要写成”spidev”。给出的理由是: spidev should never be referenced in DT without a specific compatible string, it is a Linux implementation thing rather than a description of the hardware。
此外还有一些额外配置,以下为自定义属性,用于指定工作时序方式及其它功能设置等。如CPOL需要设1, 则只需在spi设备节点里加上"spi-cpol"属性即可; CPOL设0,则不写"spi-cpol"属性即可 。
buswidth = <8>; /* 传输以8位为单位 */
mode = <0>; /* 使用第几种工作时序(CPOL, CPHA) */
/*但在现用的内核源码里发现, spi设备的工作时序并不是用mode属性值来指定的*/
/* 如CPOL需要设1, 则只需在spi设备节点里加上"spi-cpol"属性即可; CPOL设0,则不写"spi-cpol"属性即可 */
/* CPHA设1时,则在设备节点里加上"spi-cpha"属性即可 */
pinctrl的配置
pinctrl_ecspi3: ecspi3grp {
fsl,pins = <
MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO 0x100b1 /* MISO*/
MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI 0x100b1 /* MOSI*/
MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK 0x100b1 /* CLK*/
MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20 0x100b0 /* CS*/
>;
};
#加载环境
source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
#编译内核
make zImage -j16
#编译指定的设备树
make imx6ull-14x14-nand-4.3-480x272-c.dtb
默认的spidev.c中,是没有匹配你添加的设备的,因此需要修改spidev.c代码,增加compatible匹配。
/* The main reason to have this class is to make mdev/udev create the
* /dev/spidevB.C character device nodes exposing our userspace API.
* It also simplifies memory management.
*/
static struct class *spidev_class;
//#ifdef CONFIG_OF
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "rohm,dh2228fv" },
{ .compatible = "yang,oledsh1106" },
{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
//#endif
内核编译成功后,更新内核和设备树文件。启动设备后,在/sys/class/spidev下可以确认spidev枚举出了多少个spi设备。
设备树查看
查看设备树是否有新添加的节点:
更新设备树到板子上后查看下是否有生成spi设备节点:
spidev驱动有现成的测试工具。其中一个常用的测试工具是spi_test,它是spidev驱动自带的测试工具,可以用于测试和调试SPI设备。spi_test可以通过命令行参数设置SPI设备的各种参数,如设备文件、传输速率、字节顺序等。使用spi_test可以发送和接收SPI数据,以验证spidev驱动的功能和性能。
在源码linux-imx-4.1.15-2.1.0-v2.7\Documentation\spi路径下,有两个测试工具的源码文件,spidev_fdx.c和spidev_test.c文件。可以直接交叉编译为可执行文件使用。这些工具都基于spidev通用设备驱动以及对应的ioctl命令实现,可以方便的用来对spi的通用型驱动来进行测试。
编译方法
#加载环境
source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
#编译
$(CC) spidev_fdx.c -o spidev_fdx
$(CC) spidev_test.c -o spidev_test
首先,将spi接口的MISO和MOSI接口短接。
其次,编译测试代码:
Documentation/spi/spidev_test.c
如,在/dev/spidev2.0上发送"string_to_send"字符串,显示发送和接收的数据:
./spidev_test -D /dev/spidev2.0 -v -p string_to_send
如果要发送32位/16位的数据,则需要先生成二进制文件,如生成32字节的随机数据:
dd if=/dev/urandom of=test_data bs=16 count=2
用hexdump来查看这个二进制文件:
hexdump -v test_data -C
00000000 74 6a 59 3e 1e 81 73 fb 5a 3f 94 c7 d8 20 ca e9 |tjY>..s.Z?... ..|
00000010 24 2e a5 68 75 ab f7 12 af e6 c1 3d e2 d8 9a ba |$..hu......=....|
00000020
发送:
./spidev_test -D /dev/spidev2.0 -b 32 -v -i test_data
最后,输出结果与输入相同即为正确。
在这样一个速食的时代,坚持做自己,慢下来,潜心琢磨,心怀敬畏,领悟知识,才能向下扎到根,向上捅破天,背着世界往前行!
spidev的使用(SPI用户态API)_习惯就好zz的博客-CSDN博客
基于Linux使用spidev驱动OLED - 嵌入式技术 - 电子发烧友网
0.96寸OLED屏移植到搭载mx6ull的linux系统_AURORA1997的博客-CSDN博客
嵌入式Linux驱动开发——解决/sys/bus/spi/devices下没有对应的spi设备文件_spi-max-frequency_门牙会稍息的博客-CSDN博客
嵌入式Linux驱动开发——解决/sys/bus/spi/devices下没有对应的spi设备文件_spi-max-frequency_门牙会稍息的博客-CSDN博客 spidev0.0的正确打开方式_在内核开启spidev0_blog_xu的博客-CSDN博客
编写SPI设备驱动程序_spi程序怎么编程_Hilbert(*^*)的博客-CSDN博客
154 spidev:SPI“万能”驱动_你板子冒烟了的博客-CSDN博客
i.MX6ULL驱动开发 | 14 - 基于 Linux SPI 驱动框架读取ICM-20608传感器_MCUlover666的技术博客_51CTO博客
设备树学习之(九)SPI设备注册过程_spi_lsb_first_kunkliu的博客-CSDN博客
https://www.cnblogs.com/lknlfy/p/3265019.html
设备树中的spi设备以及内核对spi节点的处理流程_linux下spi->irq_弋阳yoga的博客-CSDN博客
嵌入式Linux的两种SPI驱动方式_linux spidev_iot-lorawan的博客-CSDN博客