Spidev 不使用 ioctl 同时写入/读取

2024-01-12

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

知道这一点后,我目前正在准备一些软件来测试该设备。所以我从众所周知的开始spi_test https://www.kernel.org/doc/Documentation/spi/spidev_test.c程序。

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:~#

信号显示 608 个时钟,似乎只有前半部分有数据。我决定使用环回进行调查和测试 - 缩短 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:~#

这个信号表明,整个电报因任何原因被重复(我不知道为什么)。但是,程序在控制台中正确显示了接收到的数据,因此可能与 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:~#

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

我尝试了一下所有参数,并决定更改测试程序以使用半双工(仅传输)模式:

#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 按预期提供数据。控制台输出显示没有收到数据,信号与预期一致:

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:~#

实际上,在我看来,我不是进行 2 字节全双工传输,而是进行 N 字节传输,然后进行 N 字节接收。

其实有两个问题:

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

好吧,这个帖子很安静。我刚刚读了几部分,最近接触了Linux上的SPI。然而,正如中提到的https://www.kernel.org/doc/Documentation/spi/spidev https://www.kernel.org/doc/Documentation/spi/spidev异步读/写在用户空间中不可用。 AFAIK 读/写只是 fcntl 的包装。因此,您需要编写自己的内核模块来实现异步 I/O。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spidev 不使用 ioctl 同时写入/读取 的相关文章

随机推荐