title: SPI transaction terminates early - ESP-IDF
body: <p>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.</p>
  
  <p>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.</p>
  
  <p>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).</p>
  
  <p>I dug into the SDK code (<code>spi_master.c</code>), added debug code and observed a surprising value in the DMA's <code>lldesc_t</code> struct:</p>
  
  <p>At transaction start, it is initialized with <code>length = 0x0c</code> and <code>size = 0x0c</code>. 0x0c is 12 bytes, i.e. the 10 bytes rounded to the next word.</p>
  
  <p>At transaction end, the values are <code>length = 0x07</code> and <code>size = 0x0c</code> (length can vary slightly). So the transaction only reads 7 bytes and then somehow terminates. Or rather the DMA operations terminates.</p>
  
  <ul>
  <li>Would you agree that the data indicates an early termination?</li>
  <li>What could be the cause for the early termination?</li>
  <li>Are there some registers that could indicate the cause of the
  problem?</li>
  </ul>
  
  <p>The code is pretty straightforward:</p>
  
  <pre><code>uint8_t* buffer = heap_caps_malloc(32, MALLOC_CAP_DMA);
  
  ...
  
  memset(buffer, CMD_NOP, len);
  spi_transaction_t trx;
  memset(&amp;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, &amp;trx);
  </code></pre>