hideakitai / ESP32DMASPI

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

Was hoping to get your thoughts, before I dive into your library. #61

Closed Crsarmv7l closed 3 weeks ago

Crsarmv7l commented 3 weeks ago

Hi, I am hoping your library might be a potential solution to a problem I face but I was hoping to hear your thoughts before I jump in and try to get it working.

I am using an ESP32-S2 with a CC1101 and radiolib (https://github.com/jgromes/RadioLib/). Radiolib uses VSPI for reference.

Communications for setting up the CC1101 radio are done via SPI, either sending single bytes or using a burst of bytes at speeds up to 6.5mhz for bursts and 10mhz for single bytes. Burst require a 100ns gap between bytes.

Regular spi transactions are fine for setting up the radio, My interest in DMA is for transmitting.

The CC1101 has a 64 byte FIFO, a simple transmit invloves filling the FIFO, then strobing the transmit command and the radio sends the information. Per the CC1101 application notes and datasheets, the FIFO can be refilled as the radio is transmitting to send a maximum of 255bytes.

My thoughts are using an ISR to trigger when the FIFO has 5 bytes remaining and use DMA to refill the FIFO. Normal SPI transactions can somewhat work for this at lower signal baudrates, but I have found once the baud starts rising, SPI transactions can't keep up. At 8 kbaud, and a 100 byte signal, between 90 and 93 bytes are actually sent (FIFO is likely running dry faster than I can refill it)

Before jumping in and trying to understand and integrate DMA, I was hoping to get your thoughts on the feasibility and if this is a valid application of DMA that I will see benefits from.

hideakitai commented 3 weeks ago

Yes, you can. Please use FreeRTOS API to trigger sending your data from ISR.

static QueueHandle_t s_isr_receive_queue {NULL};

void isr_handler()
{
    xQueueSendFromISR(s_isr_receive_queue, &send_data_if_needed, &pdFALSE);
}

void setup()
{
    // ...

    s_isr_receive_queue = xQueueCreate(10, sizeof(uint8_t));
    attachInterrupt(digitalPinToInterrupt(2), isr_handler, FALLING);    

    // ...
}

void loop()
{
    // ...

    if(xQueueReceiveFromISR(s_isr_receive_queue, &received_data_if_needed, &pdFALSE))
    {
        // transfer your data
        master.transfer(tx_buffer, rx_buffer, size_of_buffer);
    }

    // ...
}
Crsarmv7l commented 3 weeks ago

Great, thanks for the reply and pseudo code, I greatly appreciate it!