spidev的使用
SPI用户层操作spidev.c是linux为用户写的spi驱动及接口,下面以ITX-3588J与XM25QU128C为例,讲一下如何使用spidev
sdk: firefly_rk3588_android12.0_git_20220311
在kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dtsi配置节点信息
&spi1{
status = "okay";
pinctrl-0 = <&spi1m2_cs0 &spi1m2_pins>;
num-cs = <1>;
max-freq = <50000000>;
spidev1: spidev@00{
compatible = "rockchip,spidev";
status = "okay";
reg = <0x0>;
spi-max-frequency = <1000000>;
};
};同时在`kernel-5.10/drivers/spi/spidev.c`中添加节点信息
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "rockchip,spidev" },
{},
};系统运行起来后会在`/dev/`目录下生成名为`spidev1.0`的字符设备,该设备可以用open、close、write、read、ioctl去操作。
一次读写大小测试
spidev 一次可读写4096个字节
测试程序: char buf_t1 = {};
char buf_r1 = {};
for (int i = 0; i < 5000; i++)
buf_t1 = 0xff;
printf("--------------------------------读写大小测试-----------------------------------\n");
printf("开始写入数据\n");
printf("写入4906字节数据\n");
ret = write(fd, buf_t1, 4096);
printf("buf_t1 write %d byte\n", ret);
printf("写入4097字节数据\n");
ret = write(fd, buf_t1, 4097);
printf("buf_t1 write %d byte\n", ret);
printf("开始读取数据\n");
printf("读取4096字节数据\n");
ret = read(fd, buf_r1, 4096);
printf("buf_r2 read %d byte\n", ret);
printf("读取4097字节数据\n");
ret = read(fd, buf_r1, 4097);
printf("buf_r2 read %d byte\n", ret);测试结果
--------------------------------读写大小测试-----------------------------------
开始写入数据
写入4906字节数据
buf_t1 write 4096 byte
写入4097字节数据
buf_t1 write -1 byte
开始读取数据
读取4096字节数据
buf_r2 read 4096 byte
读取4097字节数据
buf_r2 read -1 byte
连续读写测试
read和write是单独的操作
测试程序:
printf("-------------------------------连续读写测试-----------------------------------\n");
printf("使用普通读写\n");
write(fd, buf_t, 1);
read(fd, buf_r, 4);
printf("xm25qu128c id : %x %x %x %x \n", buf_r, buf_r, buf_r, buf_r);
printf("使用复杂读写\n");
read_xm25qu128c_id();int read_xm25qu128c_id(void)
{
int ret = ioctl(fd, SPI_IOC_MESSAGE(1), &xfer);
if (ret < 0)
{
printf("error in spi_exchange(): ioctl(SPI_IOC_MESSAGE(1)) return %d \n", ret);
return -1;
}
printf("xm25qu128c flash id : %x %x %x %x \n", buf_r, buf_r, buf_r, buf_r);
memset(buf_r, 0, 4);
return 0;
}测试结果
-------------------------------连续读写测试-----------------------------------
使用普通读写
xm25qu128c id : ff ff ff ff
使用复杂读写
xm25qu128c flash id : ff 20 41 18通过示波器进行测量
发现普通读写流程如下
片选线拉低->write->片选线拉高->片选线拉低->read->片选线拉高
使用复杂读写流程如下
mosi: ---- 0x9f ---- ---- ---- ----
miso: ---- 0xff 0x20 0x41 0x18 ----
cs: 高电平 低电平-------------------------- 高电平
spi模式设置
使用ioctl可以设置spi模式
`SPI_IOC_RD_MODE`读取模式
`SPI_IOC_WR_MODE`设置模式
测试程序:
printf("--------------------------------模式测试-----------------------------------\n");
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
printf("ioctl(fd, SPI_IOC_RD_MODE , &mode) 第一次读取模式 return %d(-1则ioctl失败) ,mode:%d\n", ret, mode & (SPI_CPOL | SPI_CPHA));
read_xm25qu128c_id();
mode = 0;
mode = mode | (0x00 & SPI_CPOL) | (0xff & SPI_CPHA);
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
printf("设置模式1 return %d(-1则ioctl失败) \n", ret);
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
printf("ioctl(fd, SPI_IOC_RD_MODE , &mode) 第二次读取模式 return %d(-1则ioctl失败) ,mode:%d\n", ret, mode & (SPI_CPOL | SPI_CPHA));
read_xm25qu128c_id();
mode = 0;
mode = mode | (0xff & SPI_CPOL) | (0x00 & SPI_CPHA);
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
printf("设置模式2 return %d(-1则ioctl失败) \n", ret);
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
printf("ioctl(fd, SPI_IOC_RD_MODE , &mode) 第三次读取模式 return %d(-1则ioctl失败) ,mode:%d\n", ret, mode & (SPI_CPOL | SPI_CPHA));
read_xm25qu128c_id();
mode = 0;
mode = mode | (0xff & SPI_CPOL) | (0xff & SPI_CPHA);
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
printf("设置模式3 return %d(-1则ioctl失败) \n", ret);
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
printf("ioctl(fd, SPI_IOC_RD_MODE , &mode) 第四次读取模式 return %d(-1则ioctl失败) ,mode:%d\n", ret, mode & (SPI_CPOL | SPI_CPHA));
read_xm25qu128c_id();
mode = 0;
mode = mode | (0x00 & SPI_CPOL) | (0x00 & SPI_CPHA);
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
printf("设置模式0 return %d(-1则ioctl失败) \n", ret);
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
printf("ioctl(fd, SPI_IOC_RD_MODE , &mode) 第五次读取模式 return %d(-1则ioctl失败) ,mode:%d\n", ret, mode & (SPI_CPOL | SPI_CPHA));
read_xm25qu128c_id();测试结果
--------------------------------模式测试-----------------------------------
ioctl(fd, SPI_IOC_RD_MODE , &mode) 第一次读取模式 return 0(-1则ioctl失败) ,mode:0
xm25qu128c flash id : ff 20 41 18
设置模式1 return 0(-1则ioctl失败)
ioctl(fd, SPI_IOC_RD_MODE , &mode) 第二次读取模式 return 0(-1则ioctl失败) ,mode:1
xm25qu128c flash id : ff ff ff ff
设置模式2 return 0(-1则ioctl失败)
ioctl(fd, SPI_IOC_RD_MODE , &mode) 第三次读取模式 return 0(-1则ioctl失败) ,mode:2
xm25qu128c flash id : ff 90 20 8c
设置模式3 return 0(-1则ioctl失败)
ioctl(fd, SPI_IOC_RD_MODE , &mode) 第嬡读取模式 return 0(-1则ioctl失败) ,mode:3
xm25qu128c flash id : ff 20 41 18
设置模式0 return 0(-1则ioctl失败)
ioctl(fd, SPI_IOC_RD_MODE , &mode) 第五次读取模式 return 0(-1则ioctl失败) ,mode:0
xm25qu128c flash id : ff 20 41 18可以看出xm25qu128c支持模式0、3
设置spi通信速率
使用ioctl可以设置spi速率
`SPI_IOC_RD_MAX_SPEED_HZ`读取速率
`SPI_IOC_WR_MAX_SPEED_HZ`设置速率
测试程序:
printf("--------------------------------频率测试-----------------------------------\n");
int max_speed_hz;
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &max_speed_hz);
printf("ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ , &max_speed_hz) 第一次读取频率 return %d (-1则ioctl失败), speed:%d Hz\n", ret, max_speed_hz);
max_speed_hz = 33000000;
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed_hz);
printf("设置频率为33MHz return %d (-1则ioctl失败)\n", ret);
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &max_speed_hz);
printf("ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ , &max_speed_hz) 第二次读取频率 return %d (-1则ioctl失败), speed:%d Hz\n", ret, max_speed_hz);
max_speed_hz = 50000000;
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed_hz);
printf("设置频率为50MHz return %d (-1则ioctl失败)\n", ret);
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &max_speed_hz);
printf("ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ , &max_speed_hz) 第三次读取频率 return %d (-1则ioctl失败), speed:%d Hz\n", ret, max_speed_hz);测试结果
--------------------------------频率测试-----------------------------------
ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ , &max_speed_hz) 第一次读取频率 return 0 (-1则ioctl失败), speed:1000000 Hz
设置频率为33MHz return 0 (-1则ioctl失败)
ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ , &max_speed_hz) 第二次读取频率 return 0 (-1则ioctl失败), speed:33000000 Hz
设置频率为50MHz return 0 (-1则ioctl失败)
ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ , &max_speed_hz) 第三次读取频率 return 0 (-1则ioctl失败), speed:50000000 Hz
设置spi数据高/低位先出
使用ioctl可以设置spi数据高/低位先出
`SPI_IOC_RD_LSB_FIRST`读取是否低位先出,是返回1,不是返回0
`SPI_IOC_WR_LSB_FIRST`设置是否低位先出,是写1,不是写0
测试程序:
ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &mode);
printf("ioctl(fd, SPI_IOC_RD_LSB_FIRST , &mode) 第一次读取是否低位先出 1:LSB 0:MSBreturn %d(-1则ioctl失败),LSB/MSB: %d\n", ret, mode );
read_xm25qu128c_id();
mode = 1;
ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &mode);
printf("设置低位先出return %d (-1则ioctl失败)\n", ret);
ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &mode);
printf("ioctl(fd, SPI_IOC_RD_LSB_FIRST , &mode) 第二次读取是否低位先出 1:LSB 0:MSBreturn %d(-1则ioctl失败),LSB/MSB: %d\n", ret, mode );
read_xm25qu128c_id();
mode = 0;
ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &mode);
printf("设置高位先出return %d (-1则ioctl失败)\n", ret);
ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &mode);
printf("ioctl(fd, SPI_IOC_RD_LSB_FIRST , &mode) 第三次读取是否低位先出 1:LSB 0:MSBreturn %d(-1则ioctl失败),LSB/MSB: %d\n", ret, mode );
read_xm25qu128c_id();测试结果
--------------------------------高低位数据先出测试-----------------------------------
ioctl(fd, SPI_IOC_RD_LSB_FIRST , &mode) 第一次读取是否低位先出 1:LSB 0:MSBreturn 0(-1则ioctl失败),LSB/MSB: 0
xm25qu128c flash id : ff 20 41 18
设置低位先出return 0 (-1则ioctl失败)
ioctl(fd, SPI_IOC_RD_LSB_FIRST , &mode) 第二次读取是否低位先出 1:LSB 0:MSBreturn 0(-1则ioctl失败),LSB/MSB: 1
xm25qu128c flash id : ff ff ff ff
设置高位先出return 0 (-1则ioctl失败)
ioctl(fd, SPI_IOC_RD_LSB_FIRST , &mode) 第三次读取是否低位先出 1:LSB 0:MSBreturn 0(-1则ioctl失败),LSB/MSB: 0
xm25qu128c flash id : ff 20 41 18
谢谢分享 请问读写数据怎么修改呢 666
页:
[1]