Ошибка функции spi_bus_remove_device: Have unfinished transactions
При попытке освободить аппаратуру SPI2 на микроконтроллере ESP32-C3 наткнулся на ошибку "Have unfinished transactions" при вызове функции spi_bus_remove_device:
void spi2_deinit(void)
{
spi_transaction_t *rtrans;
ESP_ERROR_CHECK(spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY));
ESP_ERROR_CHECK(spi_bus_remove_device(spi)); // Ошибка: Have unfinished transactions
ESP_ERROR_CHECK(spi_bus_free(SPI2_HOST));
}
SPI2 использовался на передачу в режиме interrupt-транзакций [1] для управления RGB-светодиодами [2]. Проблема была в том, что несмотря на то, что даже если SPI2 работает только на передачу, в очереди приема все равно накапливаются сообщения. В функции spi_bus_remove_device производится проверка, что все очереди пустые, и приема, и передачи, и если это не так, то выводится ошибка "Have unfinished transactions":
SPI_CHECK(uxQueueMessagesWaiting(handle->ret_queue)==0, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
Если не нужно освобождать шину SPI (вызывать spi_bus_remove_device, spi_bus_free), то на заполнение очереди приема можно не обращать внимания. Даже если она переполнится, передача все равно будет нормально работать (в драйвере spi_master.c не делается проверка на переполнении очереди при её заполнении). Однако если необходимо вызвать spi_bus_remove_device, то очереди приема и передачи нужно освободить. Иначе возникнет вышеупомянутая ошибка "spi_bus_remove_device: Have unfinished transactions".
Как в этом случае можно решить проблему:
1. Перед вызовом spi_bus_remove_device запустить цикл вызовов spi_device_queue_trans, который освободит очередь приема:
void spi2_deinit(void)
{
spi_transaction_t *rtrans;
// Цикл для очистки очереди приема:
do {} while(ESP_OK == spi_device_get_trans_result(spi, &rtrans, 1));
ESP_ERROR_CHECK(spi_bus_remove_device(spi));
ESP_ERROR_CHECK(spi_bus_free(SPI2_HOST);
}
2. После каждого запуска транзакции вызывать функцию spi_device_get_trans_result:
ESP_ERROR_CHECK(spi_device_queue_trans(spi, &t, portMAX_DELAY));
spi_transaction_t *rtrans;
ESP_ERROR_CHECK(spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY));
3. Воспользоваться вызовом xQueueReset для очистки очереди приема:
Последний вариант требует модификации драйвера spi_master.c - надо сохранить дескриптор очереди приема при инициализации драйвера.
[Ссылки]
1. ESP32-C3: драйвер SPI Master. 2. WS2811: микросхема для управления трехцветным RGB-светодиодом. |