Spidev no escribe / lee simultáneamente usando ioctl

Espero encontrar ayuda incluso si este problema puede ser más hardware que software relacionado (veremos). Estoy trabajando en una placa personalizada basada en el procesador Freescales P1021 (ppc, e500v2 core). Se conectará una PCB externa que SPI podrá configurar. Las especificaciones de esta PCB externa indican que espera un comando de 2 bytes en modo dúplex completo y que solo se usa el último byte para transferir datos de nuevo a MISO.

Sabiendo esto, actualmente trabajo para preparar algunas piezas de software para probar este dispositivo. Así que empecé con lo conocido.spi_test programa.

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

La señal muestra 608 relojes y parece que solo hay datos en la primera mitad. Decido investigarlo y probarlo con loopback: el MOSI-MISO en cortocircuito corta los datos en el búfer rx. Los resultados:

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

Estas señales revelan que todo el telegrama se repite por cualquier motivo (no sé por qué). Sin embargo, el programa muestra los datos recibidos en la consola correctamente, por lo que puede ser como lo esperaba spi_test.

Además, manipulo el patrón que se enviará en este programa a 2 bytes (para simular el formato de comando solicitado al que apunto) así:

#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

Pero como no esperaba, los 32 bits se desplazan al bus SPI, en lugar de 16. Durante los dos primeros bytes, MOSI proporciona los dos bytes desde tx [] y para los otros 2 bytes es bajo / 0. Aquí están los resultados de la salida de la consola y las señales:

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

E incluso si realizo un bucle de retorno MOSI a MISO, no se reciben datos (la salida de la consola sigue siendo la misma que recibe "00 00"):

Juego un poco con todos los parámetros y decido cambiar el programa de prueba para usar el modo semidúplex (solo transmisión):

#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

Como esta cosa es compilada y ejecutada son como se espera. Los ciclos SPI_CLK 16 veces para 16 bits y MOSI proporcionan los datos como se esperaba. La salida de cosole no muestra datos recibidos y las señales son como se esperaba:

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

En realidad, me parece que en lugar de hacer una transferencia dúplex completa de 2 bytes, hago una transmisión de N bytes seguida de una recepción de N bytes.

En realidad hay dos preguntas:

¿Por qué se transmite 0xAA, 0x81 y 0x00, 0x00?¿Por qué (utilizando el bucle invertido) el código original puede recuperar los datos en buffers de rx pero, si se reduce a 2 bytes, no se reciben datos?

Respuestas a la pregunta(2)

Su respuesta a la pregunta