用户空间的spi驱动

如果想要在用户空间编写spi驱动,这就要在内核的arch/.../mach-*/board-*.c 中声明一个spi_board_info,
它的名字一定要是“spidev”,比如:

 struct spi_board_info info =
 {
  .modalias = "spidev",
  .max_speed_hz = 5000000,
  .bus_num = 0,
  .chip_select = 0,
 };

 return spi_register_board_info(&info, 1);
这样只要控制器驱动加载了,spidev模块就会和这个设备绑定,并为设备申请一个设备号,主设备号为153,次设备号和设备加载的次序有关。
目前spidev支持最多32个设备。设备的名字是spidevX.D,其中X是总线编号,D是设备的片选号。如果正确安装并配置了udev,/dev目录下便会生成spidevX.D
设备节点。直接对这些设备节点操作就行了。

 

 

spidev的设备节点的接口包括open/close/read/write/ioctl。
~~~~~~~~~~~~~~~~~~~~~~~~~
其中open/close没有什么特别之处。
read/write的话有大小的限制,读写的大小默认不能超过4096字节。这个大小是一个模块加载参数,可以修改。
允许多个用户同时打开设备节点,spidev使用mutext进行互斥,多个用户同时读写时只有一个活动的用户,其他用户睡眠。

 

 

spidev的ioctl命令。
~~~~~~~~
SPI_IOC_RD_MODE:读取spi_device的mode。
SPI_IOC_RD_LSB_FIRST:如果是SPI_LSB_FIRST的方式则返回1。
SPI_IOC_RD_BITS_PER_WORD:读取spi_device的bits_per_word.
SPI_IOC_RD_MAX_SPEED_HZ:读取spi_device的max_speed_hz.

SPI_IOC_WR_MODE:设置spi_device的mode,并调用spi_setup立即使设置生效。
SPI_IOC_WR_LSB_FIRST:设置spi使用SPI_LSB_FIRST的传输模式。立即生效。
SPI_IOC_WR_BITS_PER_WORD:读取字长。
SPI_IOC_WR_MAX_SPEED_HZ:设置时钟速率。
无论读取,用户传输的第三个参数都被当作缓冲地址指针。读取时存放结果,写入时存放要写的内容。


SPI_IOC_MESSAGE:这个命令用来进行复杂的通信。参数涉及到一个结构体。各个成员的意义与spi_transfer一致。
struct spi_ioc_transfer {
 __u64  tx_buf;
 __u64  rx_buf;

 __u32  len;
 __u32  speed_hz;

 __u16  delay_usecs;
 __u8  bits_per_word;
 __u8  cs_change;
 __u32  pad;

 /* If the contents of 'struct spi_ioc_transfer' ever change
  * incompatibly, then the ioctl number (currently 0) must change;
  * ioctls with constant size fields get a bit more in the way of
  * error checking than ones (like this) where that field varies.
  *
  * NOTE: struct layout is the same in 64bit and 32bit userspace.
  */
};
内核文档中一个例子:

  1. static void do_msg(int fd, int len)  
  2. {  
  3.  struct spi_ioc_transfer xfer[2];  
  4.  unsigned char  buf[32], *bp;  
  5.  int   status;  
  6.  memset(xfer, 0, sizeof xfer);  
  7.  memset(buf, 0, sizeof buf);  
  8.  if (len > sizeof buf)  
  9.   len = sizeof buf;  
  10.  buf[0] = 0xaa;  
  11.  xfer[0].tx_buf = (__u64) buf;  
  12.  xfer[0].len = 1;  
  13.  xfer[1].rx_buf = (__u64) buf;  
  14.  xfer[1].len = len;  
  15.  status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);  
  16.  if (status < 0) {  
  17.   perror("SPI_IOC_MESSAGE");  
  18.   return;  
  19.  }  
  20.  printf("response(%2d, %2d): ", len, status);  
  21.  for (bp = buf; len; len--)  
  22.   printf(" %02x", *bp++);  
  23.  printf("/n");  
  24. }  

内核在documentation/spi目录下有spidev的例子。

 

 

 

注意

~~~~

虽然多个用户不能同一时刻对spi进行设置或读写,但是同一用户却无法组织其他用户修改同一设备的设置。

举例来说,usr1打开设备节点,然后使用ioctl设置了时钟速率,此时usr1线程被调度出去,然后usr2操作同一个设备,将它的时钟设为另一个值。

此时usr1重新调度去使用read函数,则达不到预期的效果。

建议不要有两个程序操作spidevX.D设备节点。


相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页