4. SPI通信¶
本章配套视频介绍:

《32-在鲁班猫上使用SPI接口》
https://www.bilibili.com/video/BV1X14y1U7bW/
1 2 3 4 5 6 | #如之前有获取则可跳过
#获取仓库
git clone https://gitee.com/LubanCat/lubancat_rk_code_storage.git
#代码所在的位置
lubancat_rk_code_storage/spi
|
本章主要围绕带有40Pin引脚的LubanCat-RK3562/RK3566/RK3568系列的板子,如下
LubanCat-Zero-W
LubanCat- Zero-N
LubanCat-1
LubanCat-1N
LubanCat-2
LubanCat-2N
40pin引脚中只有一组spi接口SCK,MOSI,MISO,有两个默认片选信号CS0,CS1
4.1. SPI引脚关系¶
其中SPI3的引脚关系如下表所示
SPI |
引脚 |
功能 |
---|---|---|
MOSI |
19 |
主设备输出/从设备输入 |
MISO |
21 |
主设备输入/从设备输出 |
CLOCK |
23 |
时钟信号线 |
CS0 |
24 |
片选信号线0 |
CS1 |
26 |
片选信号线1 |
spidev3.0控制CS0,spidev3.1控制CS1
如下图:

对应实物的40pin接口
4.2. 使能SPI通信接口¶
SPI接口在默认情况是关闭状态的,需要使能才能使用, SPI接口的设备树插件有两个:
xxx-spi3-m1-overlay.dtbo
xxx-spi3-m1-gpio-cs-overlay.dtbo
xxx-spi3-m1-overlay.dtbo是使用了SPI_MOSI,SPI_MISO,SPI_CLOCK,SPI_CS0这四个引脚的
xxx-spi3-m1-gpio-cs-overlay.dtbo是使用了SPI_MOSI,SPI_MISO,SPI_CLOCK,SPI_CS0,SPI_CS1这五个引脚
两个不能同时开启,下面以开启xxx-spi3-m1-overlay.dtbo为例子
4.2.1. 方法一¶
1 2 3 4 5 | #进入工具配置
sudo fire-config
#移动光标到下图的位置
#按确认键进入配置
|

打开SPI通信接口和SPI片选接口
使用方向键移动光标到
SPI
按 “空格键” 选中SPI-CS(出现 “*” ),如下图
按 “确认键” 进行设置
按 “Esc键” 退出到终端,运行 sudo reboot 进行重启应用

4.2.2. 方法二¶
板卡 |
设备树插件配置文件 |
---|---|
LubanCat-Zero-W |
uEnvLubanCatZW.txt |
LubanCat-Zero-N |
uEnvLubanCatZN.txt |
LubanCat-1 |
uEnvLubanCat1.txt |
LubanCat-1N |
uEnvLubanCat1N.txt |
LubanCat-2 |
uEnvLubanCat2.txt |
新版LubanCat-2 |
uEnvLubanCat2-V1.txt |
LubanCat-2N |
uEnvLubanCat2N.txt |
可以通过打开 /boot/uEnv/board.txt (board是你所用的板子的名称,参照上面的表格) 查看是否启用了spi相关设备设备树插件。
编辑文件,将带有 xxx-spi3-m1-overlay.dtbo 的两行的注释符号去掉 如下图:

然后重启激活设备
注解
如果是直接拔电源的方式重启,会有可能出现文件没能做出修改 (原因:文件未能及时从内存同步到存储设备中,解决方法,在终端上输入 “sync” 再拔电关机)
4.3. 检查SPI设备¶
使能spi设备树插件之后重新启动板卡,通过SPI设备文件来判断spi驱动是否加载成功。 SPI_3对应的设备文件是spidev3.0,如果使用了xxx-spi3-m1-gpio-cs-overlay.dtbo就会出现 spidev3.0和spidev3.1
如下所示
1 2 3 | root@lubancat:~# ls /dev/spi*
/dev/spidev3.0 /dev/spidev3.1
root@lubancat:~#
|
spidev3.0和spidev3.1的区别在于片选信号的不同,spidev3.0使用CS0 , spidev3.1使用CS1
4.4. 回环测试程序¶
根据ioctl相关参数即可编写spi相关测试程序,此处为了简单仅做回环测试实验, 只需要将SPI3的 MIOS与MOSI引脚(板卡上的19和21)使用跳线帽短接即可。
如下图所示

1 | quick_start/spi/spi_selftest.c
|
代码较长复制粘贴容易乱序,可以下载我们提供的源码 spi_selftest.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | #include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <linux/spi/spidev.h>
#define SPI_DEV_PATH "/dev/spidev3.0"
/*SPI 接收 、发送 缓冲区*/
unsigned char tx_buffer[100] = "hello the world !";
unsigned char rx_buffer[100];
int fd; // SPI 控制引脚的设备文件描述符
static unsigned mode = SPI_MODE_2; //用于保存 SPI 工作模式
static uint8_t bits = 8; // 接收、发送数据位数
static uint32_t speed = 10000000; // 发送速度
static uint16_t delay; //保存延时时间
void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
{
int ret;
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = len,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
.tx_nbits = 1,
.rx_nbits = 1
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
printf("can't send spi message\n");
}
void spi_init(int fd)
{
int ret = 0;
// spi mode 设置SPI 工作模式
ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
printf("can't set spi mode\n");
// bits per word 设置一个字节的位数
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
printf("can't set bits per word\n");
// max speed hz 设置SPI 最高工作频率
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
printf("can't set max speed hz\n");
// 打印
printf("spi mode: 0x%x\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed / 1000);
}
int main(int argc, char *argv[])
{
int fd;
if(argc < 2){
printf("Wrong use !!!!\n");
printf("Usage: %s [dev]\n",argv[0]);
return -1;
}
/*打开 SPI 设备*/
fd = open(argv[1], O_RDWR); // open file and enable read and write
if (fd < 0){
printf("Can't open %s \n",argv[1]); // open i2c dev file fail
exit(1);
}
/*初始化SPI */
spi_init(fd);
/*执行发送*/
transfer(fd, tx_buffer, rx_buffer, sizeof(tx_buffer));
/*打印 tx_buffer 和 rx_buffer*/
printf("tx_buffer: \n %s\n ", tx_buffer);
printf("rx_buffer: \n %s\n ", rx_buffer);
close(fd);
return 0;
}
|
4.4.1. 编译运行¶
1 2 3 4 | #编译
gcc spi_selftest.c -o spi_selftest
#运行
sudo ./spi_selftest /dev/spidev3.x
|
效果如下图所示

如果mosi和mosi不接测试,会出现乱码或者空白内容