Приложение ESP32, использующее ESP-IDF (ESP32 SDK), обменивается данными с двумя ведомыми устройствами SPI на одной шине SPI (драйвер TFT ILI9341, приемопередатчик NRF24L01 + RF). В целом работает отлично. Однако некоторые данные, полученные от РЧ-трансивера, усекаются, то есть только первые несколько байтов верны, а остальное - мусор.
Проблема более или менее воспроизводима и возникает только при наличии связи SPI с другим ведомым устройством (драйвером TFT) непосредственно перед получением усеченных данных.
Проблемная транзакция SPI - это полнодуплексная транзакция, которая отправляет командный байт и 10 фиктивных байтов при получении 10 байтов. Он использует шину VSPI и канал DMA 1. Если возникает проблема, только первые несколько байтов являются правильными, а последние 2–6 байтов недействительны (0 или значение фиктивных байтов).
Я покопался в коде SDK (spi_master.c
), добавил код отладки и заметил удивительное значение в структуре lldesc_t
DMA:
В начале транзакции он инициализируется с помощью length = 0x0c
и size = 0x0c
. 0x0c - это 12 байтов, то есть 10 байтов, округленных до следующего слова.
В конце транзакции значения равны length = 0x07
и size = 0x0c
(длина может незначительно отличаться). Таким образом, транзакция считывает только 7 байтов, а затем каким-то образом завершается. Вернее, операции прямого доступа к памяти прекращаются.
- Согласны ли вы, что данные указывают на досрочное увольнение?
- Что могло быть причиной досрочного прекращения?
- Есть ли какие-то регистры, которые могут указывать на причину проблемы?
Код довольно прост:
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);