Транзакция SPI завершается досрочно - ESP-IDF

Приложение 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);

person Codo    schedule 18.03.2018    source источник
comment
Помимо электрической проблемы на линии nCS, ведущей к ведомому устройству, я не знаю способа преждевременно завершить транзакцию SPI - то есть, единственный способ преждевременного завершения - это прекращение тактирования ведущим устройством по какой-либо причине. Это намекает либо на нечистый, либо на ошибочный код в прерывании завершения DMA кода драйвера SPI других устройств, который по совпадению блокирует некоторые биты другого канала DMA. Кстати, как система обнаруживает завершение транзакции?   -  person Vroomfondel    schedule 23.03.2018
comment
Я подключил его к логическому анализатору, и транзакция SPI не завершается досрочно. Скорее всего, это проблема прямого доступа к памяти или неправильно обработанное прерывание. Код ESP-IDF можно найти на github.com. / espressif / esp-idf / blob / master / components / driver /. Обработчик прерывания начинается со строки 405. К сожалению, мои знания о ESP32 и, в частности, о взаимодействии SPI и DMA ограничены.   -  person Codo    schedule 24.03.2018


Ответы (1)


Похоже, следующее предупреждение - находится в Документация по драйверу подчиненного устройства SPI - также применяется к мастеру SPI, получающему данные от подчиненного устройства:]

Предупреждение: из-за особенности конструкции ESP32, если количество байтов, отправленных ведущим устройством, или длина очередей передачи в ведомом драйвере в байтах не превышает восьми и делится на четыре, оборудование SPI может не удается записать последние от одного до семи байтов в буфер приема.

Теперь я изменил сторону отправителя, чтобы отправить не менее 12 байт и кратно 4, и проблема исчезла.

Позвольте мне сейчас, если вы думаете, что это работает из-за удачи, и мое предположение неверно.

person Codo    schedule 25.03.2018
comment
Требование приращения в 4 байта не является непостижимым, учитывая тот факт, что вы имеете дело с DMA в 32-битной архитектуре. Ваша гибкость в отношении длины данных будет во многом определяться тем, как был реализован драйвер SPI с поддержкой DMA. Судя по найденной вами заметке, похоже, что автор драйвера не реализовал функциональность, которую вы изначально запрограммировали. Здесь есть некоторые сходства с периферийными устройствами STM32F7 SPI и DMA, в частности с 4-байтовым FIFO, обнаруженным на периферии STM32F7 SPI, так что это не является чем-то необычным. . . Итог - вы нашли решение. - person bamos; 31.12.2019
comment
У меня также была именно эта проблема (которая сразу же исчезает, когда вы устанавливаете dma_chan=0 и поэтому не используете DMA), которая была исправлена ​​путем указания ESP32 читать 32 бита в транзакции, когда ведомое устройство ожидает отправки только 16 --- и, конечно же, выбросить последние 16 бит. - person Keeley Hoek; 07.06.2021