Spidev do not write/read simultaneously using ioctl

stede picture stede · Apr 9, 2013 · Viewed 9.4k times · Source

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

Pic1

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

Pic2

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

Pic3

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

Pic4

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

Pic5

Pic6

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?

Answer

Pat picture Pat · Aug 13, 2013

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.