Firefly开源社区

打印 上一主题 下一主题

[应用开发] spidev的使用

5

积分

0

威望

0

贡献

吃瓜的群众

积分
5

spidev的使用

发表于 2022-6-20 16:26:18      浏览:5146 | 回复:3        打印      只看该作者   [复制链接] 楼主
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配置节点信息
  1. &spi1{
  2.     status = "okay";
  3.     pinctrl-0 = <&spi1m2_cs0 &spi1m2_pins>;
  4.     num-cs = <1>;
  5.     max-freq = <50000000>;
  6.     spidev1: spidev@00{
  7.         compatible = "rockchip,spidev";
  8.         status = "okay";
  9.         reg = <0x0>;
  10.         spi-max-frequency = <1000000>;
  11.     };
  12. };
复制代码
同时在`kernel-5.10/drivers/spi/spidev.c`中添加节点信息
  1. static const struct of_device_id spidev_dt_ids[] = {
  2.     { .compatible = "rockchip,spidev" },
  3.     {},
  4. };
复制代码
系统运行起来后会在`/dev/`目录下生成名为`spidev1.0`的字符设备,该设备可以用open、close、write、read、ioctl去操作。

一次读写大小测试

spidev 一次可读写4096个字节
测试程序:   
  1. char buf_t1[5000] = {};
  2.     char buf_r1[5000] = {};
  3.     for (int i = 0; i < 5000; i++)
  4.         buf_t1[i] = 0xff;

  5.     printf("--------------------------------读写大小测试-----------------------------------\n");
  6.     printf("开始写入数据\n");
  7.     printf("写入4906字节数据\n");
  8.     ret = write(fd, buf_t1, 4096);
  9.     printf("buf_t1 write %d byte\n", ret);

  10.     printf("写入4097字节数据\n");
  11.     ret = write(fd, buf_t1, 4097);
  12.     printf("buf_t1 write %d byte\n", ret);

  13.     printf("开始读取数据\n");
  14.     printf("读取4096字节数据\n");
  15.     ret = read(fd, buf_r1, 4096);
  16.     printf("buf_r2 read %d byte\n", ret);

  17.     printf("读取4097字节数据\n");
  18.     ret = read(fd, buf_r1, 4097);
  19.     printf("buf_r2 read %d byte\n", ret);
复制代码
测试结果
  1. --------------------------------读写大小测试-----------------------------------
  2. 开始写入数据
  3. 写入4906字节数据
  4. buf_t1 write 4096 byte
  5. 写入4097字节数据
  6. buf_t1 write -1 byte
  7. 开始读取数据
  8. 读取4096字节数据
  9. buf_r2 read 4096 byte
  10. 读取4097字节数据
  11. buf_r2 read -1 byte
复制代码

连续读写测试
read和write是单独的操作
测试程序:
  1. printf("-------------------------------连续读写测试-----------------------------------\n");
  2.     printf("使用普通读写\n");
  3.     write(fd, buf_t, 1);
  4.     read(fd, buf_r, 4);
  5.     printf("xm25qu128c id : %x %x %x %x \n", buf_r[0], buf_r[1], buf_r[2], buf_r[3]);

  6.     printf("使用复杂读写\n");
  7.     read_xm25qu128c_id();
复制代码
  1. int read_xm25qu128c_id(void)
  2. {
  3.     int ret = ioctl(fd, SPI_IOC_MESSAGE(1), &xfer);
  4.     if (ret < 0)
  5.     {
  6.         printf("error in spi_exchange(): ioctl(SPI_IOC_MESSAGE(1)) return %d \n", ret);
  7.         return -1;
  8.     }
  9.     printf("xm25qu128c flash id : %x %x %x %x \n", buf_r[0], buf_r[1], buf_r[2], buf_r[3]);
  10.     memset(buf_r, 0, 4);
  11.     return 0;
  12. }
复制代码
测试结果
  1. -------------------------------连续读写测试-----------------------------------
  2. 使用普通读写
  3. xm25qu128c id : ff ff ff ff
  4. 使用复杂读写
  5. 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`设置模式
测试程序:
  1. printf("--------------------------------模式测试-----------------------------------\n");
  2.     ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
  3.     printf("ioctl(fd, SPI_IOC_RD_MODE , &mode) 第一次读取模式 return %d(-1则ioctl失败) ,mode:%d\n", ret, mode & (SPI_CPOL | SPI_CPHA));
  4.     read_xm25qu128c_id();

  5.     mode = 0;
  6.     mode = mode | (0x00 & SPI_CPOL) | (0xff & SPI_CPHA);
  7.     ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
  8.     printf("设置模式1 return %d(-1则ioctl失败) \n", ret);

  9.     ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
  10.     printf("ioctl(fd, SPI_IOC_RD_MODE , &mode) 第二次读取模式 return %d(-1则ioctl失败) ,mode:%d\n", ret, mode & (SPI_CPOL | SPI_CPHA));
  11.     read_xm25qu128c_id();

  12.     mode = 0;
  13.     mode = mode | (0xff & SPI_CPOL) | (0x00 & SPI_CPHA);
  14.     ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
  15.     printf("设置模式2 return %d(-1则ioctl失败) \n", ret);

  16.     ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
  17.     printf("ioctl(fd, SPI_IOC_RD_MODE , &mode) 第三次读取模式 return %d(-1则ioctl失败) ,mode:%d\n", ret, mode & (SPI_CPOL | SPI_CPHA));
  18.     read_xm25qu128c_id();

  19.     mode = 0;
  20.     mode = mode | (0xff & SPI_CPOL) | (0xff & SPI_CPHA);
  21.     ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
  22.     printf("设置模式3 return %d(-1则ioctl失败) \n", ret);

  23.     ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
  24.     printf("ioctl(fd, SPI_IOC_RD_MODE , &mode) 第四次读取模式 return %d(-1则ioctl失败) ,mode:%d\n", ret, mode & (SPI_CPOL | SPI_CPHA));
  25.     read_xm25qu128c_id();

  26.     mode = 0;
  27.     mode = mode | (0x00 & SPI_CPOL) | (0x00 & SPI_CPHA);
  28.     ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
  29.     printf("设置模式0 return %d(-1则ioctl失败) \n", ret);

  30.     ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
  31.     printf("ioctl(fd, SPI_IOC_RD_MODE , &mode) 第五次读取模式 return %d(-1则ioctl失败) ,mode:%d\n", ret, mode & (SPI_CPOL | SPI_CPHA));
  32.     read_xm25qu128c_id();
复制代码
测试结果
  1. --------------------------------模式测试-----------------------------------
  2. ioctl(fd, SPI_IOC_RD_MODE , &mode) 第一次读取模式 return 0(-1则ioctl失败) ,mode:0
  3. xm25qu128c flash id : ff 20 41 18
  4. 设置模式1 return 0(-1则ioctl失败)
  5. ioctl(fd, SPI_IOC_RD_MODE , &mode) 第二次读取模式 return 0(-1则ioctl失败) ,mode:1
  6. xm25qu128c flash id : ff ff ff ff
  7. 设置模式2 return 0(-1则ioctl失败)
  8. ioctl(fd, SPI_IOC_RD_MODE , &mode) 第三次读取模式 return 0(-1则ioctl失败) ,mode:2
  9. xm25qu128c flash id : ff 90 20 8c
  10. 设置模式3 return 0(-1则ioctl失败)
  11. ioctl(fd, SPI_IOC_RD_MODE , &mode) 第嬡读取模式 return 0(-1则ioctl失败) ,mode:3
  12. xm25qu128c flash id : ff 20 41 18
  13. 设置模式0 return 0(-1则ioctl失败)
  14. ioctl(fd, SPI_IOC_RD_MODE , &mode) 第五次读取模式 return 0(-1则ioctl失败) ,mode:0
  15. 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`设置速率
测试程序:
   
  1. printf("--------------------------------频率测试-----------------------------------\n");
  2.     int max_speed_hz;
  3.     ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &max_speed_hz);
  4.     printf("ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ , &max_speed_hz) 第一次读取频率 return %d (-1则ioctl失败), speed:%d Hz\n", ret, max_speed_hz);

  5.     max_speed_hz = 33000000;
  6.     ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed_hz);
  7.     printf("设置频率为33MHz return %d (-1则ioctl失败)\n", ret);

  8.     ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &max_speed_hz);
  9.     printf("ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ , &max_speed_hz) 第二次读取频率 return %d (-1则ioctl失败), speed:%d Hz\n", ret, max_speed_hz);

  10.     max_speed_hz = 50000000;
  11.     ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed_hz);
  12.     printf("设置频率为50MHz return %d (-1则ioctl失败)\n", ret);

  13.     ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &max_speed_hz);
  14.     printf("ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ , &max_speed_hz) 第三次读取频率 return %d (-1则ioctl失败), speed:%d Hz\n", ret, max_speed_hz);
复制代码
测试结果
  1. --------------------------------频率测试-----------------------------------
  2. ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ , &max_speed_hz) 第一次读取频率 return 0 (-1则ioctl失败), speed:1000000 Hz
  3. 设置频率为33MHz return 0 (-1则ioctl失败)
  4. ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ , &max_speed_hz) 第二次读取频率 return 0 (-1则ioctl失败), speed:33000000 Hz
  5. 设置频率为50MHz return 0 (-1则ioctl失败)
  6. 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
测试程序:
   
  1. ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &mode);
  2.     printf("ioctl(fd, SPI_IOC_RD_LSB_FIRST , &mode) 第一次读取是否低位先出 1:LSB 0:MSB  return %d(-1则ioctl失败),LSB/MSB: %d\n", ret, mode );
  3.     read_xm25qu128c_id();

  4.     mode = 1;
  5.     ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &mode);
  6.     printf("设置低位先出  return %d (-1则ioctl失败)\n", ret);

  7.     ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &mode);
  8.     printf("ioctl(fd, SPI_IOC_RD_LSB_FIRST , &mode) 第二次读取是否低位先出 1:LSB 0:MSB  return %d(-1则ioctl失败),LSB/MSB: %d\n", ret, mode );
  9.     read_xm25qu128c_id();

  10.     mode = 0;
  11.     ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &mode);
  12.     printf("设置高位先出  return %d (-1则ioctl失败)\n", ret);

  13.     ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &mode);
  14.     printf("ioctl(fd, SPI_IOC_RD_LSB_FIRST , &mode) 第三次读取是否低位先出 1:LSB 0:MSB  return %d(-1则ioctl失败),LSB/MSB: %d\n", ret, mode );
  15.     read_xm25qu128c_id();
复制代码
测试结果
  1. --------------------------------高低位数据先出测试-----------------------------------
  2. ioctl(fd, SPI_IOC_RD_LSB_FIRST , &mode) 第一次读取是否低位先出 1:LSB 0:MSB  return 0(-1则ioctl失败),LSB/MSB: 0
  3. xm25qu128c flash id : ff 20 41 18
  4. 设置低位先出  return 0 (-1则ioctl失败)
  5. ioctl(fd, SPI_IOC_RD_LSB_FIRST , &mode) 第二次读取是否低位先出 1:LSB 0:MSB  return 0(-1则ioctl失败),LSB/MSB: 1
  6. xm25qu128c flash id : ff ff ff ff
  7. 设置高位先出  return 0 (-1则ioctl失败)
  8. ioctl(fd, SPI_IOC_RD_LSB_FIRST , &mode) 第三次读取是否低位先出 1:LSB 0:MSB  return 0(-1则ioctl失败),LSB/MSB: 0
  9. xm25qu128c flash id : ff 20 41 18
复制代码

xm25x.c

6.06 KB, 下载次数: 17, 下载积分: 灯泡 -1 , 经验 -1

spidev测试程序

回复

使用道具 举报

37

积分

0

威望

0

贡献

技术小白

积分
37
发表于 2023-2-20 14:27:29        只看该作者  沙发
谢谢分享
回复

使用道具 举报

10

积分

0

威望

0

贡献

技术小白

积分
10
发表于 2023-6-6 11:14:54        只看该作者  板凳
请问读写数据怎么修改呢
回复

使用道具 举报

2

积分

0

威望

0

贡献

吃瓜的群众

积分
2
发表于 2023-9-22 14:23:23        只看该作者  地板
666
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

友情链接 : 爱板网 电子发烧友论坛 云汉电子社区 粤ICP备14022046号-2
快速回复 返回顶部 返回列表