Spidev não escreve / lê simultaneamente usando ioctl

Espero encontrar alguma ajuda, mesmo que esse problema seja mais relacionado ao hardware do que ao software (veremos). Estou trabalhando em uma placa personalizada baseada no processador Freescales P1021 (ppc, e500v2 core). Uma PCB externa será conectada e poderá ser configurada pela SPI. As especificações desta PCB externa são lidas conforme se espera um comando de 2 bytes no modo full duplex e que somente o último byte é usado para transferir dados de volta no MISO.

Sabendo disso eu atualmente trabalho para preparar algumas peças de software para testar este dispositivo. Então eu comecei com o bem conhecidospi_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:~#

O sinal mostra 608 relógios e parece que há apenas dados no primeiro semestre. Eu decido investigar e testar com loopback - shorcutting O MOSI-MISO faz o loop dos dados no buffer rx. Os 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:~#

Esse sinal revela que todo o telegrama é repetido por qualquer motivo (não sei por quê). No entanto, o programa mostra os dados recebidos no console corretamente, portanto, pode ser como o spi_test esperava.

Além disso eu manipulo o padrão que será enviado neste programa para 2 bytes (para simular o formato de comando solicitado que eu quero) assim:

#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

Mas como eu não esperava 32bits são deslocados para o barramento SPI - em vez de 16. Durante os dois primeiros bytes, o MOSI fornece os dois bytes do tx [] e para os outros 2 bytes é baixo / 0. Aqui estão os resultados da saída do console e sinais:

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 mesmo se eu fizer o loop de MOSI para MISO, nenhum dado será recebido (a saída do console ainda é a mesma recebendo "00 00"):

Eu brinco um pouco com todos os parâmetros e decido mudar o programa de teste para usar o modo half duplex (somente transmissão):

#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 isso é compilado e executado coisa é como esperado. SPI_CLK ciclos 16 vezes para 16 bits e MOSI fornecem os dados conforme o esperado. A saída da Cosole não mostra dados recebidos e os sinais são como os esperados:

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

Na verdade, parece-me que, em vez de fazer 2 bytes de transferência full duplex, eu faço uma transmissão de byte N seguido por um recebimento de byte N.

Na verdade, existem duas perguntas:

Por que 0xAA, 0x81 e 0x00, 0x00 é transmitido?Por que (usando loopback) o código original é capaz de recuperar os dados em buffers de rx, mas se reduzido a 2 bytes, nenhum dado é recebido?

questionAnswers(2)

yourAnswerToTheQuestion