Codo
Codo

Reputation: 78975

SPI transaction terminates early - ESP-IDF

An ESP32 app using ESP-IDF (ESP32 SDK) communicates with two SPI slaves on the same SPI bus (ILI9341 TFT driver, NRF24L01+ RF transceiver). Overall, it works great. However, some of the data received from the RF transceiver is truncated, i.e. only the first few bytes are correct and the rest is garbage.

The problem is more or less reproducible and only occurs if there is SPI communication with the other slave (TFT driver) immediately before receiving the truncated data.

The problematic SPI transaction is a full-duplex transaction that sends a command byte and 10 dummy bytes while receiving 10 bytes. It uses the VSPI bus and DMA channel 1. If the problem occurs, only the first few bytes are correct while the last 2 to 6 bytes are invalid (0 or the value of the dummy bytes).

I dug into the SDK code (spi_master.c), added debug code and observed a surprising value in the DMA's lldesc_t struct:

At transaction start, it is initialized with length = 0x0c and size = 0x0c. 0x0c is 12 bytes, i.e. the 10 bytes rounded to the next word.

At transaction end, the values are length = 0x07 and size = 0x0c (length can vary slightly). So the transaction only reads 7 bytes and then somehow terminates. Or rather the DMA operations terminates.

The code is pretty straightforward:

uint8_t* buffer = heap_caps_malloc(32, MALLOC_CAP_DMA);

...

memset(buffer, CMD_NOP, len);
spi_transaction_t trx;
memset(&trx, 0, sizeof(spi_transaction_t));
trx.cmd = 0x61;
trx.tx_buffer = buffer;
trx.length = 8 * 10;
trx.rx_buffer = buffer;
trx.rxlength = 8 * 10;

esp_err_t ret = spi_device_transmit(spi_device, &trx);

Upvotes: 8

Views: 2437

Answers (1)

Codo
Codo

Reputation: 78975

It seems that the following warning – found in the SPI Slave driver documentation – also applies to a SPI master receiving data from a slave:]

Warning: Due to a design peculiarity in the ESP32, if the amount of bytes sent by the master or the length of the transmission queues in the slave driver, in bytes, is not both larger than eight and dividable by four, the SPI hardware can fail to write the last one to seven bytes to the receive buffer.

I've now changed the sender side to send at least 12 bytes and multiples of 4 and the problem is gone.

Let me now if you think it just works because of luck and my assumption is wrong.

Upvotes: 2

Related Questions