ESP32 DMA for GPIO operations

Vilius
Posts: 19
Joined: Mon Nov 13, 2023 9:22 am

ESP32 DMA for GPIO operations

Postby Vilius » Mon Nov 20, 2023 10:08 am

Hi,

I am doing an application that involves fast GPIO operations. DMA is just the right thing for me to save a couple of CPU cycles...
I tried to search for examples on github and ask chatgpt (it wrote some DMA code for me, but it used non existant include libraries...), but it did not help. Datasheet does not tell much as well (there are many various register and command names, but there is no chapter on how to configure a proper setup.) Can you please provide a very simple example how to read a GPIO pin and store its value in the memory via DMA (or an information source of such example)? Since I am new to ESP32, having this simple example I hope I can adapt it to my own needs. Thank you in advance.

mikemoy
Posts: 606
Joined: Fri Jan 12, 2018 9:10 pm

Re: ESP32 DMA for GPIO operations

Postby mikemoy » Mon Nov 20, 2023 10:55 pm

I ask AI to do the same, but I dont see anything wrong with the includes.

Code: Select all

#include <stdio.h>
#include "esp_system.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"

#define TAG "GPIO_DMA"

// Configuration for GPIO pin
#define GPIO_PIN        25
#define GPIO_PIN_SEL    (1ULL << GPIO_PIN)

// Configuration for DMA
#define DMA_CHANNEL     0
#define DMA_BUF_SIZE    64

// DMA buffer
uint8_t dma_buffer[DMA_BUF_SIZE];

// DMA interrupt handler
void IRAM_ATTR dma_isr(void* arg)
{
    // Handle DMA transfer completion here
    // You can process the data in dma_buffer
}

void app_main()
{
    // Initialize GPIO
    gpio_config_t io_conf;
    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
    io_conf.mode = GPIO_MODE_INPUT;
    io_conf.pin_bit_mask = GPIO_PIN_SEL;
    io_conf.pull_down_en = 0;
    io_conf.pull_up_en = 0;
    gpio_config(&io_conf);

    // Initialize DMA
    dma_chan_config_t dma_config = {
        .channel = DMA_CHANNEL,
        .owner = DMA_PERIPH,
        .lldesc = 0,
    };
    dma_queue_t* dma_queue;
    dma_queue = dma_queue_create(1, 1);
    dma_chan_handle_t dma_handle;
    dma_handle = dma_descriptor_allocate(dma_queue, &dma_config);

    // Set up DMA transfer
    dma_buffer_desc_t dma_desc;
    dma_desc.buffers = &dma_buffer;
    dma_desc.buffers_len = DMA_BUF_SIZE;
    dma_desc.direction = DMA_PERIPH_TO_MEMORY;
    dma_desc.desc = NULL;
    dma_desc.size = DMA_BUF_SIZE;
    dma_desc.sub_sof = 0;
    dma_desc.eof = 1;
    dma_desc.owner = DMA_PERIPH;
    dma_desc.start = 0;
    dma_desc.stop = 0;
    dma_desc.loop = 0;
    dma_desc.len = DMA_BUF_SIZE;
    dma_desc.size_word = DMA_WORD_SIZE;
    dma_desc.size_bit = 0;

    dma_channel_configure(dma_handle, &dma_desc);

    // Attach DMA interrupt handler
    dma_channel_set_irq(dma_handle, DMA_INT_RAW_TFR, dma_isr, NULL);

    // Start DMA transfer
    dma_channel_start(dma_handle);

    while (1) {
        // Your application code here
        // You can access the data read from the GPIO pin in dma_buffer
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

ESP_Sprite
Posts: 9052
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32 DMA for GPIO operations

Postby ESP_Sprite » Tue Nov 21, 2023 2:32 am

There is no connection at all between the GPIO module and the DMA subsystem; the AI's are happily confabulating a connection here. Dependent on what you want and what specific chip you use, you may want to look into the RMT, the I2S (in parallel mode) or the LCD/camera module as all those are able to quickly read pins.

Vilius
Posts: 19
Joined: Mon Nov 13, 2023 9:22 am

Re: ESP32 DMA for GPIO operations

Postby Vilius » Tue Nov 21, 2023 10:15 am

Alright, I have checked all the option to increase the GPIO read speed. The only option left for me is to use Direct I/O via IO_MUX.

The datasheet tells: "

Some high speed digital functions (Ethernet, SDIO, SPI, JTAG, UART) can bypass the GPIO Matrix for better
high-frequency digital performance. In this case, the IO_MUX is used to connect these pads directly to the peripheral.
Selecting this option is less flexible than using the GPIO Matrix, as the IO_MUX register for each GPIO pad can
only select from a limited number of functions. However, better high-frequency digital performance will be maintained.
4.4.2 Functional Description
Two registers must be configured in order to bypass the GPIO Matrix for peripheral I/O:
1. IO_MUX for the GPIO pad must be set to the required pad function. (Please refer to section 4.10 for a list of
pad functions.)
2. For inputs, the SIG_IN_SEL register must be cleared to route the input directly to the peripheral. "

It does not look too hard...I have picked the pins that have this capability, but since I am new to ESP32 programming, could you please provide a dead-simple example of configuration of such GPIO pin (configured as direct I/O). I have been searching for examples online and in the datasheet, but at this point I still dont have much experience with ESP- IDF syntax, decribed example would save my day (or realistically even weeks :) ) Thank you in advance

User avatar
ok-home
Posts: 48
Joined: Sun May 02, 2021 7:23 pm
Location: Russia Novosibirsk
Contact:

Re: ESP32 DMA for GPIO operations

Postby ok-home » Tue Nov 21, 2023 11:01 am

where on this list did you find gpio?
Vilius wrote:
Tue Nov 21, 2023 10:15 am
Some high speed digital functions (Ethernet, SDIO, SPI, JTAG, UART) can bypass the GPIO Matrix
Why don’t you want to use esp32 modules (spi - up to 80 mb/sec, i2s - up to 80 mb/sec) with dma support, rmt - up to 40 mb/sec. These modules cover 90% of typical tasks of parallel and sequential interaction with external devices.
Describe your task (just not at the level of “I want to quickly switch the output of the microcircuit”)

Vilius
Posts: 19
Joined: Mon Nov 13, 2023 9:22 am

Re: ESP32 DMA for GPIO operations

Postby Vilius » Tue Nov 21, 2023 11:23 am

My project involves reading an ADC chip that has 12 bit parallel output. Since I will be generating the clock for the adc chip as well, only my reading speed determines the rate of Msps I will receive. As I mentioned, this is my first ESP project, so SPI is not a real option due to complexity of the protocol + ESP IDF syntax which is unknown for me in most applications (parallel output ADC has been chosen for simplicity to read it...) I tried to search for examples of RMT, but cuold not find anything that suits my application well, and learning RMT protocol/driver from zero is not what I am looking for in this project... For now, I have successfully achieved a reading speed of approximately 5.3-5.4 MSPS by these commands:

REG_WRITE(GPIO_OUT_W1TS_REG, (1 << GPIO_PIN_OUTPUT));
gpio_inputs = REG_READ(GPIO_IN_REG) & ((1ULL << NUM_GPIO_PINS) - 1);
REG_WRITE(GPIO_OUT_W1TC_REG, (1 << GPIO_PIN_OUTPUT));

I am generating a clock pulse for the ADC and at the same time performing a parallel read of 12 GPIOs. I dont have a strict requirement for my Msps goal, but my ADC ship is capable of 30 MSPS, I want as much as I can get (at least 10 Msps to be satisfied)...

My ESP is configured for 240 Mhz core clock. I understand that performing 12 GPIO reads and 2 GPIO toggles in 180 ns is a solid start, but considering the core clock and the fact that other data protocols can do 10s of Mbps on ESP makes me think that I am missing out something so much. I already performed the CMake compiler optimization, using the direct register write operations etc, but I dont get a fraction of the speed I could be getting (just simple GPIOs, nothing fancy at all...)

That is my real situation.

If you can provide a sample code for RMT parallel read (or at least an information source), or any other way to improve the speed of read operations, I thank you for that.

User avatar
ok-home
Posts: 48
Joined: Sun May 02, 2021 7:23 pm
Location: Russia Novosibirsk
Contact:

Re: ESP32 DMA for GPIO operations

Postby ok-home » Tue Nov 21, 2023 11:46 am

Vilius wrote:
Tue Nov 21, 2023 11:23 am
My project involves reading an ADC chip that has 12 bit parallel output. Since I will be generating the clock for the adc chip as well, only my reading speed determines the rate of Msps I will receive. As I mentioned, this is my first ESP project, so SPI is not a real option due to complexity of the protocol + ESP IDF syntax which is unknown for me in most applications (parallel output ADC has been chosen for simplicity to read it...) I tried to search for examples of RMT, but cuold not find anything that suits my application well, and learning RMT protocol/driver from zero is not what I am looking for in this project... For now, I have successfully achieved a reading speed of approximately 5.3-5.4 MSPS by these commands:
esp32 - i2s0/i2s1 master -> 16 bit parallel read, up to 40 mSamples/sek with dma, with output clk
example - https://github.com/ok-home/logic_analyzer

Vilius
Posts: 19
Joined: Mon Nov 13, 2023 9:22 am

Re: ESP32 DMA for GPIO operations

Postby Vilius » Tue Nov 21, 2023 12:04 pm

Okay, I will examine that, thank you.

If thats real 40 MSPS parallel, thats a gold mine for me....

Who is online

Users browsing this forum: No registered users and 172 guests