Spidev不使用ioctl同时写/读

时间:2013-04-09 07:00:21

标签: c linux-device-driver embedded-linux powerpc spi

我希望找到一些帮助,即使这个问题可能是硬件而不是软件相关(我们会看到)。我正在开发基于Freescales P1021处理器(ppc,e500v2核心)的定制电路板。外部PCB将连接,可由SPI配置。该外部PCB的规格读取为全双工模式下的2字节命令,并且只有最后一个字节用于在MISO上传回数据。

知道这一点我目前正在准备一些软件来测试这个设备。所以我开始使用众所周知的spi_test程序。

root@p1021rdb:~# ./spi_test -D /dev/spidev32766.3
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)

00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00
root@p1021rdb:~#

Pic1

信号显示608个时钟,似乎上半年只有数据。我决定用loopback调查和测试它 - 切割MOSI-MISO将数据循环回rx缓冲区。结果:

root@p1021rdb:~# ./spi_test -D /dev/spidev32766.3
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)

FF FF FF FF FF FF
40 00 00 00 00 95
FF FF FF FF FF FF
FF FF FF FF FF FF
FF FF FF FF FF FF
DE AD BE EF BA AD
F0 0D
root@p1021rdb:~#

Pic2

这个信号显示,整个电报因任何原因重复(我不知道为什么)。但是,程序正确显示控制台中收到的数据,因此可能与spi_test预期的一样。

此外,我操作将在此程序中发送的模式减少到2个字节(以模拟我想要的命令格式),如下所示:

#ifdef ORIG
   uint8_t tx[] = {
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
      0xF0, 0x0D,
   };
#else
   uint8_t tx[] = {
      0xAA, 0x81,
   };
#endif

但是我没想到32位被移出到SPI总线 - 而不是16.在前两个字节期间,MOSI提供来自tx []的两个字节,而另外2个字节则提供低/ 0。以下是控制台输出和信号的结果:

root@p1021rdb:~# ./spi_test_2bytes -D /dev/spidev32766.3
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)

00 00
root@p1021rdb:~#

Pic3

即使我将MOSI环回到MISO也没有收到任何数据(控制台输出仍然是接收“00 00”):

Pic4

我玩了一些所有参数并决定将测试程序更改为使用半双工(仅传输)模式:

#ifdef ORIG
   uint8_t tx[] = {
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
      0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
      0xF0, 0x0D,
   };
#else
   uint8_t tx[] = {
      0xAA, 0x81,
   };
#endif
    uint8_t rx[ARRAY_SIZE(tx)] = {0, };
    struct spi_ioc_transfer tr = {
        .tx_buf = (unsigned long)tx,
#ifdef ORIG      
        .rx_buf = (unsigned long)rx,
#else
      .rx_buf = 0,
#endif

因为这是编译和执行的事情就像预期的那样。 SPI_CLK为16位循环16次,MOSI按预期提供数据。 Cosole输出显示没有收到的数据和信号是预期的:

root@p1021rdb:~# ./spi_test_2bytes -D /dev/spidev32766.3
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)

00 00
root@p1021rdb:~#

Pic5

Pic6

实际上在我看来,我没有进行2字节全双工传输,而是进行N字节发送,接着是N字节接收。

实际上有两个问题:

  1. 为什么传输0xAA,0x81和0x00,0x00?
  2. 为什么(使用环回)原始代码能够将数据恢复到rx缓冲区中,但如果减少到2个字节则不会收到数据?

2 个答案:

答案 0 :(得分:2)

嗯,这个帖子很安静势不可挡。我刚读了几个部分,最近在Linux上与SPI联系。但是,如上所述 https://www.kernel.org/doc/Documentation/spi/spidev 用户空间中不提供异步读/写。 AFAIK读/写只是fcntl的包装。因此,您需要编写自己的内核模块来实现异步I / O.

答案 1 :(得分:0)

我知道这是一个非常老的线程,但我一直在运行OpenWRT的RT5350上使用spidev。我得到了与你完全相同的结果;我只是无法进行全双工传输。读取RT5350数据表似乎硬件只能进行半双工SPI传输。每次传输都是写入(MOSI上的输出字节,不读取任何内容)或读取(MOSI上的输出零,读取MISO)。

我无法获得P1021芯片的数据表,但考虑到我们的结果的相似性,我会说它的硬件SPI以类似的方式实现。

这意味着内核模块不是答案(ioctl SPI_IOC_MESSAGE最终会调用spi_async())。执行全双工SPI的唯一方法是在软件中使用GPIO。

RT5350参考: http://forum.vocore.io/viewtopic.php?f=3&t=72#p233