树莓派的SPI模块
树莓派的GPIO引脚支持三种通信协议:UART、SPI和I2C。SPI是一种双向、同步、全双工的串行协议,是三个协议中通信速率最快的。树莓派的官方文档详细介绍了SPI模块的基本特性,主要是如下几个方面:
- 硬件引脚分配
- 在树莓派的Linux系统中,SPI硬件抽象成
/dev/spidev0.0
文件 - 树莓派的SPI只支持主模式(Master Mode)
- 配置参数:除了通信速率、CPOL、CPHA这三个参数外,其他的参数一般都不会去修改
- 提供了一段回环测试程序,可用于检测SPI模块是否正常工作
接下来的问题是,我们如何通过SPI接受和发送数据。看到/dev/spidev0.0
文件,熟悉Linux系统编程的人马上会想起通用I/O模型中的几个函数。的确,可以在该文件上执行open和close操作,就跟操作普通文件一样。同样地,read和write函数可以读写数据,但只能进行基本的半双工数据传输,片选信号在读写操作之间会失效。使用ioctl()
函数的SPI_IOC_MESSAGE(N)
请求可实现全双工数据传输,而且整个过程中片选信号不会失效。
Linux内核代码提供了一段SPI的示例程序,是/tools/spi/
目录下的spidev_test.c文件。这段代码实现了一个命令行工具,既可以直接使用,也可以借鉴它的代码实现自己的功能。将代码编译后生成的可执行文件命名为spidev_test
,下面的命令使用默认的配置将一个文件的内容通过SPI发送了出去,并把从SPI接收的数据保存到另一个文件中:
1 | $ ./spidev_test -D /dev/spidev0.0 -i send.txt -o receive.txt -v |
通过-s
、-O
和-H
选项可以分别修改通信速率、CPOL和CPHA这三个参数,-v
选项可以打印发送和接收的内容。正如上面提到的,这段代码就是使用ioctl()
函数实现全双工数据传输,详情可以阅读源文件中的transfer
函数。
STM32端的代码
首先将树莓派和STM32对应的SPI引脚连接好。为了验证树莓派和STM32之间的SPI通信是正确的,我将实现如下功能:
- 树莓派发送一个32字节大小的文件给STM32,STM32收完之后用串口发送出去,在PC端的串口助手上查看数据
- STM32同时也给树莓派发送数据,树莓派上可通过
-v
选项查看STM32发送过来的数据
STM32的SPI配置成全双工、从模式(Slave Mode),CPHA和CPOL参数都为0。我使用固件库开发,部分代码如下:
1 | /* |
STM32接收和发送数据都在中断中进行。发送缓冲区为空时会触发TXE中断,这时没有可发的数据,调用SendData函数发送数据;接收缓冲区不为空时说明有新的数据到了,此时会触发RXNE中断,调用ReceiveData函数读出数据。
1 |
|
将STM32串口线连接到PC上,打开串口助手并打开对应的COM口,然后在树莓派端运行命令向STM32发送文件的内容。如果串口助手中接受到的数据和文件内容完全符合,而且树莓派上显示的也是STM32发送的内容,就证明双向的通信均是正确的。