SPI re-entrancy
Posted: Wed Nov 07, 2018 10:55 am
I have started integrating my device drivers.
I have two SPI device. A CAN controller on VSPI and a FLASH on HSPI.
The CAN transactions use spi_device_transmit() (DMA channel = 0). CAN SPI access is driven on core 1 (to ensure low latency).
The SPI test harness runs on core 0 and sends commands to core 1 using a queue.
The FLASH transaction use DMA via spi_device_queue_trans() and spi_device_get_trans_result(). The device was created with flag SPI_DEVICE_HALFDUPLEX and transactions use SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_MODE_DIO.
FLASH SPI is accessed and the test harness runs on core 0. https://github.com/lllucius/esp32_extflash for driver details.
Each driver has a stress test which runs within its own task. The drivers have been stress tested independently for many days without issue.
When I put the two tasks together the CAN stress test quickly fails. Its always the CAN stress test which fails. It seems that the CAN stress test is hung waiting for a SPI transaction to complete (each task does sleep!).
The test harness also profiles PSRAM performance. If I remove the FLASH test then the CAN test works whilst PSRAM is being accessed.
Clearly I have some debugging to do but wanted to check that what I am doing is supported & especially if anyone else is doing similar.
EDIT: Copying spi_device_transmit() and reducing the timeouts to 5 seconds and I can see that spi_device_get_trans_result() times out.
Before adding this code spi_device_transmit() would not return.
The CAN SPI transaction is started from a task on cpu 1. The task is sent a 'service device' command from a GPIO interrupt connected to the CAN device.
CAN interrupts were enabled with gpio_config(), gpio_install_isr_service(0) and gpio_isr_handler_add() run from cpu 1 after the SPI device was created.
So I guess that somehow my SPI CAN interrupt has been masked or forgotten.
I have two SPI device. A CAN controller on VSPI and a FLASH on HSPI.
The CAN transactions use spi_device_transmit() (DMA channel = 0). CAN SPI access is driven on core 1 (to ensure low latency).
The SPI test harness runs on core 0 and sends commands to core 1 using a queue.
The FLASH transaction use DMA via spi_device_queue_trans() and spi_device_get_trans_result(). The device was created with flag SPI_DEVICE_HALFDUPLEX and transactions use SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_MODE_DIO.
FLASH SPI is accessed and the test harness runs on core 0. https://github.com/lllucius/esp32_extflash for driver details.
Each driver has a stress test which runs within its own task. The drivers have been stress tested independently for many days without issue.
When I put the two tasks together the CAN stress test quickly fails. Its always the CAN stress test which fails. It seems that the CAN stress test is hung waiting for a SPI transaction to complete (each task does sleep!).
The test harness also profiles PSRAM performance. If I remove the FLASH test then the CAN test works whilst PSRAM is being accessed.
Clearly I have some debugging to do but wanted to check that what I am doing is supported & especially if anyone else is doing similar.
EDIT: Copying spi_device_transmit() and reducing the timeouts to 5 seconds and I can see that spi_device_get_trans_result() times out.
Before adding this code spi_device_transmit() would not return.
The CAN SPI transaction is started from a task on cpu 1. The task is sent a 'service device' command from a GPIO interrupt connected to the CAN device.
CAN interrupts were enabled with gpio_config(), gpio_install_isr_service(0) and gpio_isr_handler_add() run from cpu 1 after the SPI device was created.
So I guess that somehow my SPI CAN interrupt has been masked or forgotten.