4. SPI通信#
1#如之前有获取则可跳过
2#获取仓库
3git clone https://gitee.com/LubanCat/lubancat_rk_code_storage.git
4
5#代码所在的位置
6lubancat_rk_code_storage/spi
本章主要围绕带有40Pin引脚的LubanCat-RK系列的板子,如下:
LubanCat-3
4.1. SPI引脚关系#
以鲁班猫3为例,其中SPI1-M0的引脚关系如下表所示
SPI |
引脚 |
功能 |
|---|---|---|
MOSI |
19 |
主设备输出/从设备输入 |
MISO |
21 |
主设备输入/从设备输出 |
CLOCK |
23 |
时钟信号线 |
CS0 |
24 |
片选信号线0 |
CS1 |
26 |
片选信号线1 |
spidev1.0控制CS0,spidev1.1控制CS1。
对应实物的40pin接口如下图:
4.2. 使能SPI通信接口#
4.2.1. fire-config#
1#进入工具配置
2sudo fire-config
3
4#移动光标到下图的位置
5#按确认键进入配置
打开SPI接口
使用方向键移动光标到
SPI1-M0按 "空格键" 选中SPI1-M0(出现 "*" ),如下图
按 "确认键" 进行设置
按 "Esc键" 退出到终端,运行 sudo reboot 进行重启应用
4.2.2. 配置文件#
板卡 |
设备树插件配置文件 |
说明 |
|---|---|---|
当前你所使用的板子 |
uEnv.txt |
该配置软链接到你所使用的设备,修改该配置相当于修改板子实际的配置 |
LubanCat-3 |
uEnvLubanCat3.txt |
适用于LubanCat-3 |
可以通过修改 /boot/uEnv/uEnv.txt 或者 /boot/uEnv/uEnvboard.txt (uEnvboard.txt为通过上面的对照表获得的配置文件)
编辑文件,将带有 xxx-spix-mx-overlay.dtbo 的行注释符号去掉,如下图,然后重启激活设备。
备注
如果是直接拔电源的方式重启,会有可能出现文件没能做出修改 (原因:文件未能及时从内存同步到存储设备中,解决方法,在终端上输入 "sync" 再拔电关机)
4.3. 检查SPI设备#
使能spi设备树插件之后重新启动板卡,通过SPI设备文件来判断spi驱动是否加载成功。 因为SPI1-M0有两个片选引脚,而设备树也配置了这两个片选引脚,所以cs0和cs1对应的设备文件是spidev1.0和spidev1.1。
如下所示:
1root@lubancat:~# ls /dev/spi*
2/dev/spidev1.0 /dev/spidev1.1
3root@lubancat:~#
4.4. 回环测试程序#
根据ioctl相关参数即可编写spi相关测试程序,此处为了简单仅做回环测试实验, 只需要将SPI3的MIOS与MOSI引脚(板卡上的19和21)使用跳线帽短接即可。
如下图所示:
1quick_start/spi/spi_selftest.c
代码较长复制粘贴容易乱序,可以下载我们提供的源码 spi_selftest.c
1#include <sys/ioctl.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5#include <unistd.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <stdint.h>
9#include <linux/spi/spidev.h>
10
11#define SPI_DEV_PATH "/dev/spidev0.0"
12
13/*SPI 接收 、发送 缓冲区*/
14unsigned char tx_buffer[100] = "hello the world !";
15unsigned char rx_buffer[100];
16
17
18int fd; // SPI 控制引脚的设备文件描述符
19static unsigned mode = SPI_MODE_2; //用于保存 SPI 工作模式
20static uint8_t bits = 8; // 接收、发送数据位数
21static uint32_t speed = 10000000; // 发送速度
22static uint16_t delay; //保存延时时间
23
24void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
25{
26 int ret;
27
28 struct spi_ioc_transfer tr = {
29 .tx_buf = (unsigned long)tx,
30 .rx_buf = (unsigned long)rx,
31 .len = len,
32 .delay_usecs = delay,
33 .speed_hz = speed,
34 .bits_per_word = bits,
35 .tx_nbits = 1,
36 .rx_nbits = 1
37 };
38
39 ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
40 if (ret < 1)
41 printf("can't send spi message\n");
42}
43
44void spi_init(int fd)
45{
46 int ret = 0;
47
48 // spi mode 设置SPI 工作模式
49 ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
50 if (ret == -1)
51 printf("can't set spi mode\n");
52
53 // bits per word 设置一个字节的位数
54 ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
55 if (ret == -1)
56 printf("can't set bits per word\n");
57
58 // max speed hz 设置SPI 最高工作频率
59 ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
60 if (ret == -1)
61 printf("can't set max speed hz\n");
62
63 // 打印
64 printf("spi mode: 0x%x\n", mode);
65 printf("bits per word: %d\n", bits);
66 printf("max speed: %d Hz (%d KHz)\n", speed, speed / 1000);
67}
68
69int main(int argc, char *argv[])
70{
71 int fd;
72
73 if(argc < 2){
74 printf("Wrong use !!!!\n");
75 printf("Usage: %s [dev]\n",argv[0]);
76 return -1;
77 }
78 /*打开 SPI 设备*/
79 fd = open(argv[1], O_RDWR); // open file and enable read and write
80 if (fd < 0){
81 printf("Can't open %s \n",argv[1]); // open i2c dev file fail
82 exit(1);
83 }
84
85 /*初始化SPI */
86 spi_init(fd);
87
88 /*执行发送*/
89 transfer(fd, tx_buffer, rx_buffer, sizeof(tx_buffer));
90
91 /*打印 tx_buffer 和 rx_buffer*/
92 printf("tx_buffer: \n %s\n ", tx_buffer);
93 printf("rx_buffer: \n %s\n ", rx_buffer);
94
95 close(fd);
96
97 return 0;
98}
4.4.1. 编译运行#
1#编译
2gcc spi_selftest.c -o spi_selftest
3#运行
4sudo ./spi_selftest /dev/spidev1.0
效果如下图所示:
如果mosi和mosi不接测试,会出现乱码或者空白内容
4.5. 更多#
更多关于rk-spi驱动以及把spi从master模式切换为salve模式等可以查看: rk开源手册/Common/SPI
4.6. 参考资料#
本文档主要提供有一定经验的使用者快速入门使用,详细资料可阅读以下文档:
rk开源资料(github): 《开源手册》