07、SPI Linux 应用编程
一、 ioctl函数
以下是更直白的说明:
在使用ioctl
函数配置SPI通信时,主要会用到以下参数:
基础函数原型
C
#include <sys/ioctl.h>
int ioctl(int 设备句柄, int 操作指令, 其他参数);
1
2
2
常用操作指令说明
1. 设置/读取 SPI 模式
- 读取当前模式:
SPI_IOC_RD_MODE
作用:把当前的 SPI 模式(时钟极性和相位设置)读取到一个整数变量中。 用法:ioctl(设备句柄, SPI_IOC_RD_MODE, &变量);
- 设置新模式:
SPI_IOC_WR_MODE
作用:设置 SPI 模式的极性和相位(用两位二进制表示)。 用法:ioctl(设备句柄, SPI_IOC_WR_MODE, 新模式值);
2. 设置/读取 每个数据包的位数
- 读取当前位数:
SPI_IOC_RD_BITS_PER_WORD
作用:获取当前每个数据包的位数(如 8 位、16 位等)。 用法:ioctl(设备句柄, SPI_IOC_RD_BITS_PER_WORD, &变量);
- 设置位数:
SPI_IOC_WR_BITS_PER_WORD
作用:指定每个数据包的位数。 用法:ioctl(设备句柄, SPI_IOC_WR_BITS_PER_WORD, 新位数值);
3. 设置/读取 最大传输速度
- 读取当前速度:
SPI_IOC_RD_MAX_SPEED_HZ
作用:获取 SPI 总线当前的最大传输速度(单位:赫兹)。 用法:ioctl(设备句柄, SPI_IOC_RD_MAX_SPEED_HZ, &变量);
- 设置速度:
SPI_IOC_WR_MAX_SPEED_HZ
作用:设置 SPI 总线的最大传输速度。 用法:ioctl(设备句柄, SPI_IOC_WR_MAX_SPEED_HZ, 新速度值);
4. 执行 SPI 读写操作
- 批量传输:
SPI_IOC_MESSAGE(N)
作用:一次性执行多个 SPI 读写操作(N 表示操作的数量)。 用法:
5. 设置/读取 LSB 先传输模式
- 读取当前模式:
SPI_IOC_RD_LSB_FIRST
作用:判断是否启用 "低位优先" 模式(即数据传输时先发送最低位)。 用法:ioctl(设备句柄, SPI_IOC_RD_LSB_FIRST, &变量);
- 设置模式:
SPI_IOC_WR_LSB_FIRST
作用:启用或禁用 "低位优先" 模式。 用法:ioctl(设备句柄, SPI_IOC_WR_LSB_FIRST, 1或0);
(1
表示启用,0
表示禁用)
:::
总结
读操作:参数会把数据 读到 你提供的变量中。
写操作:参数会把 你提供的值 写入设备配置。
所有参数的第三个参数 都是整数或结构体指针,具体看操作类型。 :::
二、示例程序
通过以下程序,可以实现SPI通讯。
C
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#define SPI_DEVICE_PATH "/dev/spidev0.0"
int main() {
int spi_file;
uint8_t tx_buffer[50] = "hello world!";
uint8_t rx_buffer[50];
// Open the SPI device
if ((spi_file = open(SPI_DEVICE_PATH, O_RDWR)) < 0) {
perror("Failed to open SPI device");
return -1;
}
// Configure SPI mode and bits per word
uint8_t mode = SPI_MODE_0;
uint8_t bits = 8;
if (ioctl(spi_file, SPI_IOC_WR_MODE, &mode) < 0) {
perror("Failed to set SPI mode");
close(spi_file);
return -1;
}
if (ioctl(spi_file, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0) {
perror("Failed to set SPI bits per word");
close(spi_file);
return -1;
}
// Perform SPI transfer
struct spi_ioc_transfer transfer = {
.tx_buf = (unsigned long)tx_buffer,
.rx_buf = (unsigned long)rx_buffer,
.len = sizeof(tx_buffer),
.delay_usecs = 0,
.speed_hz = 1000000, // SPI speed in Hz
.bits_per_word = 8,
};
if (ioctl(spi_file, SPI_IOC_MESSAGE(1), &transfer) < 0) {
perror("Failed to perform SPI transfer");
close(spi_file);
return -1;
}
/* Print tx_buffer and rx_buffer*/
printf("\rtx_buffer: \n %s\n ", tx_buffer);
printf("\rrx_buffer: \n %s\n ", rx_buffer);
// Close the SPI device
close(spi_file);
return 0;
}
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
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
三、文件路径
这行代码定义了一个宏,用于存储 SPI 设备文件的路径。
C
#define SPI_DEVICE_PATH "/dev/spidev0.0"
1
四、打开SPI设备
这部分代码尝试打开指定的 SPI 设备文件。
C
// Open the SPI device
if ((spi_file = open(SPI_DEVICE_PATH, O_RDWR)) < 0) {
perror("Failed to open SPI device");
return -1;
}
1
2
3
4
5
2
3
4
5
五、配置SPI
这段代码用于配置 SPI 通信的模式为 SPI 模式0(时钟极性为0、时钟相位为0)以及每个字的位数为8位,以确保 SPI 通信的正确性和一致性。
C
// Configure SPI mode and bits per word
uint8_t mode = SPI_MODE_0;
uint8_t bits = 8;
if (ioctl(spi_file, SPI_IOC_WR_MODE, &mode) < 0) {
perror("Failed to set SPI mode");
close(spi_file);
return -1;
}
if (ioctl(spi_file, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0) {
perror("Failed to set SPI bits per word");
close(spi_file);
return -1;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
这段代码定义了一个 spi_ioc_transfer 结构体变量 transfer,用于配置 SPI 传输的参数。它指定了传输的数据缓冲区、传输的长度、延迟时间、SPI 速度(以赫兹为单位)以及每个字的位数。这个结构体将被传递给 SPI_IOC_MESSAGE ioctl
函数,以执行 SPI 传输。
C
// Perform SPI transfer
struct spi_ioc_transfer transfer = {
.tx_buf = (unsigned long)tx_buffer,
.rx_buf = (unsigned long)rx_buffer,
.len = sizeof(tx_buffer),
.delay_usecs = 0,
.speed_hz = 1000000, // SPI speed in Hz
.bits_per_word = 8,
};
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
六、数据收发
这段代码使用 ioctl
函数执行 SPI 传输。它通过 SPI_IOC_MESSAGE(1) 宏指定传输的数量为1,第三个参数为上文中配置的结构体变量 transfer 的地址。如果 SPI 传输失败,将会输出错误消息并关闭 SPI 设备文件描述符。
C
if (ioctl(spi_file, SPI_IOC_MESSAGE(1), &transfer) < 0) {
perror("Failed to perform SPI transfer");
close(spi_file);
return -1;
}
1
2
3
4
5
2
3
4
5
七、测试
将SPI的MOSI和MISO相接,运行程序: