Reduce time between two consecutive SPI transfers
Posted: Wed Aug 05, 2020 3:35 am
Hi, I'm trying to drive an external DAC via SPI interface using esp32. But I cannot achieve the desired speed (>1M transfers/sec, each transfer consists of 16bits). The reason is not the SPI speed itself, which could be set as high as 40MHz, but the time delay between two consecutive SPI transfers.
A sample code is as follows (Arduino API):
The output shows that ESP32 can do approximately 694,800 transfers/sec, still far away from my requirement of 1M transfers/sec. However, theoretically, using a 40M SPI bus, each transfer only takes 16/40M sec, which should enable a >2M transfers/sec speed, so the difference must originate from the time delay between two consecutive SPI transfers.
I know that these delays can possibly be canceled by transferring more data in a single transfer command. However, the interface of DAC requires me to pulse SYNC once (set it high and then low) before each SPI transfer, which is not possible if I use a single SPI transfer command.
I have searched for solutions online and found two related problems:
The one here https://github.com/espressif/esp-idf/issues/368 suggests disabling all MUTEX commands in esp32-hal-spi.c/h. Seems reasonable, but I see no effects. Probably because the compiler has already deleted those codes in optimization.
Another here https://esp32.com/viewtopic.php?t=1383 suggests using RMT to replace SPI, but suffer from timing issues.
I think there is also room for improvement as I only need to output data, and I access SPI on a single thread, so the solution can be thread-unsafe.
So I'm here to ask, are there any way to accelerate the SPI transfers?
Answers using Arduino as well as ESP-IDF are welcome! Thanks a lot in advance!
A sample code is as follows (Arduino API):
Code: Select all
#include <SPI.h>
void setup()
{
Serial.begin(115200);
SPI.begin();
SPI.beginTransaction(SPISettings(40000000,MSBFIRST,SPI_MODE0));
}
void loop()
{
unsigned long tstart=micros(),count=0;
while(micros()-tstart<1000000)
{
for(byte i=0;i<9;i++)
SPI.transfer16(0b0101010110101010);
count+=9;
}
Serial.println(count);
}
I know that these delays can possibly be canceled by transferring more data in a single transfer command. However, the interface of DAC requires me to pulse SYNC once (set it high and then low) before each SPI transfer, which is not possible if I use a single SPI transfer command.
I have searched for solutions online and found two related problems:
The one here https://github.com/espressif/esp-idf/issues/368 suggests disabling all MUTEX commands in esp32-hal-spi.c/h. Seems reasonable, but I see no effects. Probably because the compiler has already deleted those codes in optimization.
Another here https://esp32.com/viewtopic.php?t=1383 suggests using RMT to replace SPI, but suffer from timing issues.
I think there is also room for improvement as I only need to output data, and I access SPI on a single thread, so the solution can be thread-unsafe.
So I'm here to ask, are there any way to accelerate the SPI transfers?
Answers using Arduino as well as ESP-IDF are welcome! Thanks a lot in advance!