Spidev do not write/read simultaneously using ioct

2019-04-06 14:38发布

问题:

I hope to find some help even if this issue might be more hardware than software related (we'll see). I'm working on a custom board based on Freescales P1021 processor (ppc, e500v2 core). A external PCB will be connected and could be configured by SPI. The specifications of this external PCB reads as it expects a 2-byte command in full duplex mode and that only the last byte is used to transfer data back on MISO.

Knowing this i currently work to prepare some pieces of software to test this device. So I started with the well known spi_test program.

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

The signal shows 608 clocks and it seems there are only data in the first half. I decide to investigate and testing it with loopback - shorcutting MOSI-MISO loops back the data into the rx buffer. The results:

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

This signals reveals, that the whole telegram is repeated for any reason (I don't know why). However, the program shows the received data in the console correctly, so it may be as the spi_test expected it.

Further I manipulate the pattern which will be sent in this program down to 2 bytes (to simulate the requested command format I aim for) like this:

#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

But as I did not expect 32bits are shifted out to SPI bus - instead of 16. During the first two bytes MOSI provides the both bytes from the tx[] and for the other 2 bytes it is low/0. Here are the results of console output and signals:

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

And even if I loopback MOSI to MISO no data is received (console output is still the same receiving "00 00") :

I play around a bit with all parameters and decide to change the test program to use half duplex (transmit only) mode:

#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

As this is compiled and executed thing are like expected. SPI_CLK cycles 16 times for 16 bits and MOSI provide the data as expected. Cosole output shows no received data and signals are like expected:

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

Actually it seems to me that instead of doing 2 bytes full duplex transfer I do a N byte transmit followed by an N byte receive.

Actually there are two questions:

  1. Why 0xAA, 0x81 and 0x00, 0x00 is transmitted?
  2. Why (using loopback) the original code is able to get the data back in rx buffers but if reduced to 2 bytes no data is received?

回答1:

Well, the post is quiet overwhelming. I just read a few parts and recently got in touch with SPI on Linux. However, as mentioned in https://www.kernel.org/doc/Documentation/spi/spidev async read/write is not available in userspace. AFAIK read/write is just a wrapper around fcntl. Thus you'll need to write your own kernel module to achieve async I/O.



回答2:

I know this is a very old thread but I've been using spidev on the RT5350 running OpenWRT. I'm getting exactly the same results as you; I'm just not able to get a full duplex transfer happening. Reading the RT5350 datasheet it appears that the hardware is only able to do half duplex SPI transfers. Each transfer is either a write (output bytes on MOSI, don't read anything), or a read (output zeros on MOSI, read MISO).

I can't get the datasheet for your P1021 chip, but considering the similarity of our results I'd say its hardware SPI is implemented in a similar way.

This means that a kernel module isn't the answer (ioctl SPI_IOC_MESSAGE eventually calls spi_async() anyway). The only way to do full duplex SPI is using GPIOs in software.

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