hideakitai / ESP32DMASPI

SPI library for ESP32 which use DMA buffer to send/receive transactions
MIT License
166 stars 36 forks source link

How can I send one byte? #45

Closed GunterO closed 4 months ago

GunterO commented 4 months ago

Hello,

I have a sensor, and I need to send one init byte at the very beginning, and after that several packages before I can begin with the sensor readout. Until now I used the regular SPI library, and is working fine, but can be faster. Hence the DMA. Until now: For the single byte operation: unsigned char rxbyte = vspi->transfer(byte); For buffers: vspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0)); vspi->transferBytes(txbytes, rxbytes, nlen); vspi->endTransaction();

Now, I want to switch to DMA (at least for the buffer transfers), but the minimum packet size is 4bytes so my single byte operations are not working. Sending 4 bytes (where 3 of them are zero) is unfortunately not accepted by the sensor. I tried to combine the regular SPI library for single byte operations and your ESP32DMASPI for the buffers, but that is not working. No compilation/running errors, but the single bytes are not send (verified all with a logic analyzer). And without that, I can't even start with the buffer transfers.

This is not even send on the SPI bus: const size_t received_bytes = master.transfer(dma_tx_buf, dma_rx_buf, 1);

This is send, but not accepted by the sensor: const size_t received_bytes = master.transfer(dma_tx_buf, dma_rx_buf, 4);

Thanks for your help!

Regards, Gunter

hideakitai commented 4 months ago

I tried to combine the regular SPI library for single byte operations and your ESP32DMASPI for the buffers, but that is not working.

I think this is the only way to achieve your goal. Maybe you can do it if you use the regular SPI library correctly (I don't know how, though).

Also, do you really need DMA? If you can achieve communication with the regular SPI, maybe DMA doesn't improve the speed so much.

GunterO commented 4 months ago

Hello,

Thank you for your quick answer. I'll end up worse by DMA I guess, because it looks like that the DMA setup time for each transfer is almost taking 750us. Is that as expected? image

This example is transferring 256bytes in a continuous loop... SPI clock is running at 8MHz.

void loop() { const size_t received_bytes = master.transfer(dma_tx_buf, dma_rx_buf, BUFFER_SIZE); }

I can see that CS is toggling for each burst, while for "ordinary" SPI transfers, I need to / can control CS myself in code, and keep it low for the whole sensor readout (each row needs to be read individually). Could this be responsible for the extra time in between?

Thanks!

hideakitai commented 4 months ago

How about using command bits?

https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/spi_master.html

GunterO commented 4 months ago

That's a good idea for sending the one byte command, but it won't solve the long DMA setup time. And the 750us is unusual and unexpected, because Espressif is claiming a transaction/setup time of 25us. https://docs.espressif.com/projects/esp-idf/en/release-v3.1/api-reference/peripherals/spi_master.html When I have some spare time, I'll try with using their master driver directly.

hideakitai commented 4 months ago

I recommend trying:

  1. queue() and trigger() with required queue size (non-blocking continuous transfer in the background)

  2. try to insert vTaskDelay(1); to here:

https://github.com/hideakitai/ESP32DMASPI/blob/73f55eae96bc71c57eca68dd26ec7e2ac68f0217/ESP32DMASPIMaster.h#L450-L453

Like:

        // NOTE: spi_transaction_ext_t should be delete inside of spi task after use
        int ret = xQueueSend(s_trans_queue_handle, &trans_ctx, SEND_TRANS_QUEUE_TIMEOUT_TICKS);
        // try to switch context to freertos task (maybe xQueueSend() switches context, though)
        vTaskDelay(1);
        // clearing transactions is safe because data was moved to trans_ctx
        this->transactions.clear();
  1. If the steps above don't satisfy your requirements, you can use spin master APIs without freertos tasks, as you say.
hideakitai commented 4 months ago

Also, you can try keeping CS active by setting SPI_TRANS_CS_KEEP_ACTIVE to flags

https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/spi_master.html#c.SPI_TRANS_CS_KEEP_ACTIVE

hideakitai commented 4 months ago

If you still need help, please feel free to reopen this issue.