ESP32-S3 Fast readings with ADC and DMA low level functions

kaefe_br
Posts: 3
Joined: Tue Jan 07, 2025 2:58 pm

ESP32-S3 Fast readings with ADC and DMA low level functions

Postby kaefe_br » Sun Jan 19, 2025 6:47 pm

I am trying to make a code using ESP-IDF low level ADC and DMA functions to read 3 analog signals in sequence in a fast way (480kHz sample rate) on a ESP32-S3.

1 - Does anyone know any place I can get more information about adc_ll and gdma_ll functions? or better an example?
There is no information about them on esp-idf docs search. I got some help from ChatGPT, but it is version dependent and not so "intelligent" ;)

2 - The code I put together on VSCode is this one, and the issue is it does not generate DMA RX_SUC_EOF event or any other.
There are a lot of comments with the tests I have done.
If you know what I am missing, please tell me. :idea:

  1. /*
  2. ADC_ESP32S3_Direto.c
  3. Author:  Klaus Fensterseifer
  4. Jan2025
  5.  
  6. ESP-IDF v5.3.2
  7. ESP32-S3 N16R8 (16 MB Quad SPI flash, 8 MB Octal PSRAM die)
  8.  
  9. From Compilation Summary:
  10. Flash Code 8MB
  11. DIRAM 340KB
  12. Flash Data  3.3MB
  13. IRAM 16kB
  14. RTC FAST  8kB
  15.  
  16. Reads 3 ADC inputs in sequence
  17. Uses the DMA to fill a buffer with the ADC samples
  18. Interrupts the main task when the buffer is full
  19.     - a new buffer is set to be filled by the DMA
  20.     - the main task deal with the data from the filled buffer
  21.  
  22. Sample frequency = 480kHz    (3 ADCs = 160kHz each ADC input)
  23. Size of the buffer = should be large, 3000 or 30000, but he DMA setup restricts it to 4095 bytes (or 2047 12 bits samples)
  24.  
  25. Similar approach = https://github.com/kaefe64/Arduino_uSDX_Pico_FFT_Proj
  26.  
  27. */
  28.  
  29.  
  30.  
  31.  
  32. #include <stdio.h>
  33. #include "freertos/FreeRTOS.h"
  34. #include "freertos/task.h"
  35. #include "esp_log.h"
  36. #include "soc/soc.h"
  37. #include "soc/lldesc.h"
  38. #include "soc/gdma_struct.h"
  39. #include "soc/soc_caps.h"
  40. //#ifndef __DECLARE_RCC_ATOMIC_ENV
  41. //#define __DECLARE_RCC_ATOMIC_ENV()
  42. //#endif
  43. #include "hal/adc_ll.h"
  44. #include "hal/adc_hal_common.h"
  45. #include "hal/gdma_ll.h"
  46. #include "hal/clk_gate_ll.h"  //
  47. #include "hal/gpio_ll.h"  //
  48. //#include "esp_task_wdt.h"  //
  49. #include "esp_timer.h" //
  50.  
  51. //#include "esp_private/periph_ctrl.h"  //
  52. //#include "esp_private/adc_share_hw_ctrl.h"  //
  53. //#define ADC_BUS_CLK_ATOMIC()       PERIPH_RCC_ATOMIC()
  54. #include "hal/spi_types.h"
  55. #include "hal/spi_ll.h"
  56. #include "esp_private/spi_common_internal.h"
  57. #include "esp_private/adc_dma.h"
  58.  
  59.  
  60.  
  61. #define DMA_BUFFER_SIZE   100 //2000          // Tamanho do buffer DMA  max = 4095 / 2 = 2047
  62. #define DMA_BUFFER_NUM   20             // number of DMA buffers (if size is small, increase the number of buffers)
  63. #define TAG "LowLevel_ADC_DMA"
  64. #define DMA_CHANNEL   2      //wifi uses DMA channel 0
  65.  
  66. static uint16_t dma_buffer[DMA_BUFFER_NUM][DMA_BUFFER_SIZE] __attribute__((aligned(4)));
  67. static volatile bool buffer_ready = false; // buffer filled
  68. static uint16_t active_buffer_idx = 0;  //buffer index
  69. static uint16_t active_buffer_main = 0;  //buffer index
  70. static uint16_t active_buffer_cnt = 0;  //buffer index
  71. static uint16_t active_buffer_cnt_main = 0;  //buffer index
  72.  
  73. // Descritor DMA
  74. static lldesc_t dma_descriptor[DMA_BUFFER_NUM] = {0};
  75.  
  76.  
  77. /*
  78. #include "hal/timer_ll.h"
  79.  
  80. //=================================================================
  81.  
  82. //=================================================================
  83. void configure_timer_for_adc(void) {
  84.     // Configurar o timer periférico para gerar eventos
  85.     uint32_t timer_group = 0;  // Grupo do timer (0 ou 1)
  86.     uint32_t timer_index = 0;  // Índice do timer (0 ou 1 dentro do grupo)
  87.  
  88.     timer_ll_set_auto_reload(timer_group, timer_index, true);  // Habilitar modo auto-reload
  89.     //timer_ll_enable_auto_reload
  90.     timer_ll_set_counter_value(timer_group, timer_index, 0);   // Reiniciar contador
  91.     //timer_ll_set_clock_prescale  1
  92.     timer_ll_set_divider(timer_group, timer_index, 2);         // Configurar divisor (ajustar para precisão)
  93.     //timer_ll_set_alarm_value  166
  94.    
  95.     // Frequência desejada = 480 kHz
  96.     uint32_t clock_source_freq = 80000000;                    // Clock base (80 MHz)
  97.     uint32_t timer_divider = clock_source_freq / 480000;      // Divisor para 480 kHz
  98.     timer_ll_set_alarm_value(timer_group, timer_index, timer_divider);
  99.  
  100.     timer_ll_enable_alarm(timer_group, timer_index, true);    // Habilitar alarme
  101.     timer_ll_enable_counter(timer_group, timer_index, true);  // Iniciar contador
  102. }
  103.  
  104.     // Configurar o ADC para ser acionado por um evento externo (como o timer)
  105.     adc_ll_digi_set_trigger_source(ADC_TRIGGER_TIMER);
  106.  
  107.     adc_ll_digi_enable();  // Habilitar o ADC
  108.  
  109. */
  110.  
  111.  
  112.  
  113. //=================================================================
  114. // DMA Interrupt handler
  115. //=================================================================
  116. void IRAM_ATTR dma_isr_handler(void *arg)
  117. {
  118.     // Check interrupt event
  119.     uint32_t isr_evt = gdma_ll_rx_get_interrupt_status(&GDMA, DMA_CHANNEL, true);    //true = raw   false = status
  120.     if(isr_evt & GDMA_LL_EVENT_RX_SUC_EOF)  
  121.     {
  122.         uint16_t j = active_buffer_idx;   //start to search for buffer ready from the last one
  123.         for(uint16_t i=0; i<DMA_BUFFER_NUM; i++)
  124.         {
  125.             if(++j >= DMA_BUFFER_NUM) j = 0;
  126.             // the descriptor with owner = 0 is the one that was filled by DMA
  127.             if (dma_descriptor[j].owner == 0)         // Buffer filled
  128.             {
  129.                 // get the buffer index
  130.                 active_buffer_idx = j;
  131.                 active_buffer_cnt++;   //guess the next buffer filled is the next one
  132.  
  133.                 if(buffer_ready == false)
  134.                 {
  135.                     //processing
  136.                     active_buffer_main = active_buffer_idx;
  137.                     active_buffer_cnt_main = active_buffer_cnt;
  138.                     //process_data(dma_descriptor[0].buf, dma_descriptor[0].length);
  139.  
  140.                     buffer_ready = true;   //inform main
  141.                     // inform main task about buffer filled
  142.                     //xTaskNotifyFromISR(task_handle, 0, eNoAction, NULL);
  143.                 }
  144.  
  145.                 // return buffer control to GDMA after processing
  146.                 dma_descriptor[j].owner = 1;
  147.                 break;  //only one buffer ready (expect to receive another interrupt for other one)
  148.             }
  149.         }
  150.  
  151.         // clear GDMA int
  152.         gdma_ll_rx_clear_interrupt_status(&GDMA, DMA_CHANNEL, GDMA_LL_EVENT_RX_SUC_EOF);  // Limpa a interrupção de "success end of frame" (EOF)
  153.     }
  154.     else  //another event generated the DMA interrupt - should not happen
  155.     {
  156.         gdma_ll_rx_clear_interrupt_status(&GDMA, DMA_CHANNEL, isr_evt);  // clear all events set, but not RX SUC EOF
  157.     }
  158.  
  159.  
  160. //buffer_ready = true;   //for debug, any DMA interrupt will show something on main task
  161.  
  162. }
  163.  
  164.  
  165. //#define __DECLARE_RCC_ATOMIC_ENV()     //be used in an atomic way
  166. //=================================================================
  167. // Configuração do ADC no ESP32-S3
  168. //=================================================================
  169. static void configure_adc(void) {
  170.  
  171. adc_ll_digi_reset();
  172.  
  173.     //adc_ll_reset_register();  //ADC regas reset, return to default values
  174.     // SYSTEM.perip_clk_en0 is a shared register, so this function must be used in an atomic way
  175. //    ADC_BUS_CLK_ATOMIC() {
  176.         SYSTEM.perip_rst_en0.apb_saradc_rst = 1;
  177.         SYSTEM.perip_rst_en0.apb_saradc_rst = 0;
  178. //    }
  179.     // Ativar o clock do ADC
  180.     //adc_ll_enable_bus_clock(true);  //enables ADC clock on APB bus
  181.     //  SYSTEM.perip_rst_en0 is a shared register, so this function must be used in an atomic way
  182. //    ADC_BUS_CLK_ATOMIC() {
  183.         SYSTEM.perip_clk_en0.apb_saradc_clk_en = true;
  184. //    }    
  185.     adc_ll_digi_convert_limit_enable(false);
  186.  
  187.         adc_hal_set_controller(ADC_UNIT_1, ADC_HAL_CONTINUOUS_READ_MODE);
  188.  
  189.  
  190. //adc_ll_digi_clear_pattern_table(ADC_UNIT_1);
  191.  
  192.     adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, 3);                // 3 channels
  193.  
  194.     adc_digi_pattern_config_t adc_pattern;
  195.  
  196.     adc_pattern.atten = ADC_ATTEN_DB_0;  //No input attenuation, approx. 0 - 800mV
  197.     adc_pattern.channel = ADC_CHANNEL_3;               //ADC channel index. ADC1_CH3 - GPIO 4
  198.     adc_pattern.unit = ADC_UNIT_1;        //ADC unit index.
  199.     adc_ll_digi_set_pattern_table(ADC_UNIT_1, 0, adc_pattern);
  200.  
  201.     adc_pattern.atten = ADC_ATTEN_DB_0;  //No input attenuation, ADC can measure up to approx. 0 - 800mV
  202.     adc_pattern.channel = ADC_CHANNEL_4;               //ADC channel index. ADC1_CH4 - GPIO 5
  203.     adc_pattern.unit = ADC_UNIT_1;        //ADC unit index.
  204.     adc_ll_digi_set_pattern_table(ADC_UNIT_1, 1, adc_pattern);
  205.  
  206.     adc_pattern.atten = ADC_ATTEN_DB_0;  //No input attenuation, ADC can measure up to approx. 0 - 800mV
  207.     adc_pattern.channel = ADC_CHANNEL_5;               //ADC channel index. ADC1_CH5 - GPIO 6
  208.     adc_pattern.unit = ADC_UNIT_1;        //ADC unit index.
  209.     adc_ll_digi_set_pattern_table(ADC_UNIT_1, 2, adc_pattern);
  210.  
  211.  
  212.  
  213.  
  214.  
  215.     // ADC basic configuration
  216.     adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_DIG);        // digital controler
  217.     adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC1);  //uses only ADC1
  218.     adc_ll_set_sample_cycle(4);    // number of clock cycles to charge the ADC internal capacitor before the conversion start
  219.                                    // 2 for source impedance < 1k    10 for impedances > 10k
  220.     //adc_ll_set_data_format(ADC_LL_DATA_FMT_12_BIT); //  12 bits format -  ESP32S3 only supports 12bit
  221.     //adc_ll_digi_set_arbiter_stable_cycle()
  222.  
  223.     adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_APB);   //use APB
  224.  
  225.     //adc_ll_digi_controller_clk_div(0,1,0);  //base clock for the ADC digital controller.
  226.     adc_ll_digi_controller_clk_div(1,1,1);  //base clock for the ADC digital controller.
  227.                             //ctrl_clk = (APLL or APB) / (div_num + div_a / div_b + 1).
  228.  
  229.     adc_ll_digi_set_clk_div(2);    //sampling clock  determines the time taken for the ADC to perform a conversion.
  230.  
  231.     //80MHz / 500kHz = 160    500000 / 3 = 166666
  232.     //80MHz / 481927 = 166    481927 / 3 = 160642
  233.     //80MHz / 479041 = 167    479041 / 3 = 159680
  234.     //interval = ((80MHz /(0 + (0 / 1) + 1)) /2) /480kHz = 83.33
  235.     //interval = ((80MHz /(1 + (1 / 1) + 1)) /2) /480kHz = 27.77
  236.     adc_ll_digi_set_trigger_interval(167);  //Configures ADC digital controller clock cycles between ADC conversions.
  237.     //adc_ll_digi_start(ADC_UNIT_1);
  238.  
  239.  
  240.  
  241. /*
  242.    uint32_t interval = APB_CLK_FREQ / (ADC_LL_CLKM_DIV_NUM_DEFAULT + ADC_LL_CLKM_DIV_A_DEFAULT / ADC_LL_CLKM_DIV_B_DEFAULT + 1) / 2 / freq;
  243.    //set sample interval
  244.    adc_ll_digi_set_trigger_interval(interval);
  245.    //Here we set the clock divider factor to make the digital clock to 5M Hz
  246.    adc_ll_digi_controller_clk_div(ADC_LL_CLKM_DIV_NUM_DEFAULT, ADC_LL_CLKM_DIV_B_DEFAULT, ADC_LL_CLKM_DIV_A_DEFAULT);
  247.    adc_ll_digi_clk_sel(0);   //use APB
  248. */
  249.  
  250.  
  251. adc_ll_digi_set_power_manage(ADC_LL_POWER_SW_ON);
  252.  
  253. //adc_ll_digi_dma_set_eof_num(10);
  254. //adc_dma_ll_rx_start
  255.  
  256.     //adc_dma_start(adc_dma_t adc_dma, dma_descriptor_t *addr)
  257. //    spi_ll_clear_intr(adc_dma.adc_spi_dev, ADC_DMA_INTR_MASK);
  258. //    spi_ll_enable_intr(adc_dma.adc_spi_dev, ADC_DMA_INTR_MASK);
  259. //    spi_dma_ll_rx_start(adc_dma.adc_spi_dev, adc_dma.spi_dma_ctx->rx_dma_chan.chan_id, (lldesc_t *)addr);
  260.  
  261.  
  262.     // enables DMA for ADC
  263.     adc_ll_digi_dma_enable();  //enables DMA to tranfer data from ADC direct to the memory
  264.  
  265.     adc_ll_digi_trigger_enable();  //enables ADC internal trigger to start continuous conversion
  266.  
  267. }
  268.  
  269.  
  270.  
  271.  
  272.  
  273.  
  274.  
  275. //=================================================================
  276. // DMA configuration for ESP32-S3
  277. //=================================================================
  278. static void configure_dma(void) {
  279.     esp_err_t ret;
  280.  
  281.     //The DMA RX (Receive) functions are designed for scenarios where data is being transferred  
  282.     //from a peripheral (in this case, the ADC) into memory via DMA.
  283.  
  284.  
  285.     // GDMA channel reset
  286.     gdma_ll_rx_reset_channel(&GDMA, DMA_CHANNEL);
  287.     //gdma_ll_rx_reset_channel0(&GDMA);
  288.  
  289.     //gdma_trigger_peripheral_t  GDMA_TRIG_PERIPH_ADC
  290.  
  291. /*
  292. gdma_dev_t *dev
  293.     A pointer to the GDMA device structure.
  294.     Represents the specific GDMA instance being configured. For ESP32-S3, this would typically be &GDMA.
  295.  
  296. uint32_t channel
  297.     Specifies the GDMA channel number to configure.
  298.     RX channels are used for peripherals that produce data, such as the ADC.
  299.     Example: If you are using channel 0, you pass 0 here.
  300.  
  301. gdma_trigger_peripheral_t periph
  302.     Specifies the type of peripheral triggering the DMA.
  303.     For ADC, this should be GDMA_TRIG_PERIPH_ADC.
  304.     Other possible values could include UART, SPI, I2S, etc.
  305.  
  306. int periph_id
  307.     Identifies the specific peripheral instance or unit to connect to the DMA.
  308.     For ADC, this might differentiate between ADC units or specific configurations of the ADC digital controller.
  309.     Example: If using ADC digital controller 1 (ADC1), you might pass 1.
  310. */    
  311.     // Connect the DMA RX channel to the ADC peripheral
  312.     gdma_ll_rx_connect_to_periph(&GDMA, DMA_CHANNEL, GDMA_TRIG_PERIPH_ADC, 1);  //1=ADC1
  313.  
  314.     // descriptor configuration
  315.     for(int i=0; i<DMA_BUFFER_NUM; i++)
  316.     {
  317.         //size: max size buffer. max: 4095 bytes
  318.         dma_descriptor[i].size = (uint32_t)(DMA_BUFFER_SIZE * sizeof(uint16_t));     // & 0xFFF  max 4095 bytes
  319.         //length: number of bytes in the buffer, should be equal or less than size.
  320.         dma_descriptor[i].length = (uint32_t)(DMA_BUFFER_SIZE * sizeof(uint16_t));
  321.         dma_descriptor[i].buf = (uint8_t *)dma_buffer[i];
  322.         dma_descriptor[i].owner = 1;  //release the buffer to DMA
  323.         /*
  324.         sosf = 0: not the beginnig of a frame
  325.         sosf = 1: it is a frame beginnig
  326.         If the use is a continuous stream of data, it could be set to 0
  327.         */
  328.         dma_descriptor[i].sosf = 0;
  329.         /*
  330.         eof = 0: not the end of frame
  331.         eof = 1: it is a frame end
  332.         If not using frames, it could be left as 0.
  333.         */
  334.         dma_descriptor[i].eof = 1;   //=1 to set the interrupt when buffer full
  335.         dma_descriptor[i].qe.stqe_next = &dma_descriptor[i+1];
  336.     }
  337.     //dma_descriptor[DMA_BUFFER_NUM-1].eof = 1;
  338.     dma_descriptor[DMA_BUFFER_NUM-1].qe.stqe_next = &dma_descriptor[0];
  339.  
  340.     // Configurar o GDMA para o ADC
  341.     gdma_ll_rx_set_desc_addr(&GDMA, DMA_CHANNEL, (uint32_t)&dma_descriptor[0]);
  342.     //gdma_ll_rx_set_desc_addr(dma_dev, DMA_CHANNEL, (uint32_t)dma_descriptor);
  343.  
  344. // transfer block size
  345. //gdma_ll_rx_set_block_size(DMA_CHANNEL, DMA_BUFFER_SIZE);  
  346.  
  347.     // interrupt configuration
  348.     //ret = esp_intr_alloc(ETS_DMA_IN_CH0_INTR_SOURCE, 0, dma_isr_handler, NULL, NULL);
  349.     ret = esp_intr_alloc(ETS_DMA_IN_CH2_INTR_SOURCE,  // DMA RX interrupt source  DMA_CHANNEL = 2
  350.                          ESP_INTR_FLAG_IRAM,         // Allocate in IRAM for fast execution.
  351.     //                     ESP_INTR_FLAG_LEVEL6,         // Allocate in IRAM for fast execution.
  352.                          dma_isr_handler,            // Interrupt handler function
  353.                          NULL,                       // Argument to pass to handler
  354.                          NULL);                      // Optional handle (not needed here)
  355.     if (ret != ESP_OK) {
  356.         printf("Failed to allocate DMA interrupt\n");
  357.     }
  358.  
  359.  
  360. //gdma_ll_force_enable_reg_clock(&GDMA, true);
  361. //gdma_ll_rx_restart(&GDMA, DMA_CHANNEL);
  362. //gdma_ll_rx_enable_auto_return(&GDMA, DMA_CHANNEL,true);
  363. gdma_ll_rx_set_burst_size(&GDMA, DMA_CHANNEL, 16);
  364.  
  365.     // set interrupt of end of transfer
  366.     //GDMA.channel[0].in.int_ena.in_suc_eof = 1;
  367.     // enables the GDMA to set the EOF interrupt
  368.     gdma_ll_rx_enable_interrupt(&GDMA, DMA_CHANNEL, GDMA_LL_EVENT_RX_SUC_EOF, true);
  369.     //gdma_ll_rx_enable_interrupt(&GDMA, DMA_CHANNEL, 0x2ff, true);  //for debug, enables all possible interrupt event
  370.  
  371.     //gdma_ll_rx_enable_channel(&GDMA, DMA_CHANNEL, true);
  372.     //GDMA.channel[0].in.link.start = 1;  // Habilitar o canal RX
  373.     gdma_ll_rx_start(&GDMA, DMA_CHANNEL);
  374.  
  375.     //adc_digi_start();
  376. //DR_REG_GDMA_BASE
  377.  
  378. }
  379.  
  380.  
  381.  
  382.  
  383.  
  384. uint64_t tim, tim_old;
  385.  
  386. //=================================================================
  387. // Função principal
  388. //=================================================================
  389. void app_main()
  390. {
  391.     uint32_t i = 0;
  392.  
  393. //ADC1_3 GPIO4
  394. gpio_ll_input_enable(&GPIO, 3);
  395. gpio_ll_pullup_dis(&GPIO, 4);
  396. gpio_ll_pulldown_dis(&GPIO, 4);
  397. //adc_ll_set_channel_io_map(ADC_UNIT_1, ADC_CHANNEL_3, 4);
  398.  
  399. //ADC1_4 GPIO5
  400. gpio_ll_input_enable(&GPIO, 4);
  401. gpio_ll_pullup_dis(&GPIO, 5);
  402. gpio_ll_pulldown_dis(&GPIO, 5);
  403. //adc_ll_set_channel_io_map(ADC_UNIT_1, ADC_CHANNEL_4, 5);
  404.  
  405. //ADC1_5 GPIO6
  406. gpio_ll_input_enable(&GPIO, 5);
  407. gpio_ll_pullup_dis(&GPIO, 6);
  408. gpio_ll_pulldown_dis(&GPIO, 6);
  409. //adc_ll_set_channel_io_map(ADC_UNIT_1, ADC_CHANNEL_5, 6);
  410.  
  411.     ESP_LOGI(TAG, "************************");
  412.     ESP_LOGI(TAG, "************************");
  413.     ESP_LOGI(TAG, "Starting ADC with DMA...");
  414.     ESP_LOGI(TAG, "************************");
  415.     ESP_LOGI(TAG, "************************");
  416.  
  417.     configure_dma();
  418.     ESP_LOGI(TAG, "1************************");
  419.     configure_adc();
  420.     ESP_LOGI(TAG, "2************************");
  421.  
  422.     tim_old = esp_timer_get_time();
  423.     while (1)
  424.     {
  425.         if (buffer_ready)
  426.         {
  427.             // Main task - Data processing
  428.             //uint16_t *processed_buffer = (active_buffer == dma_buffer_a) ? dma_buffer_b : dma_buffer_a;
  429.             ESP_LOGI(TAG, "Buffer filled:");
  430.             //for (int i = 0; i < DMA_BUFFER_SIZE; i++) {
  431.             //    printf("ADC[%d]: %d\n", i, processed_buffer[i]);
  432.             //}
  433.             printf(" cnt:%d   buffer:%d  [0]=  %d  %d  %d\n",
  434.                                              active_buffer_cnt_main,
  435.                                              active_buffer_main,
  436.                                              dma_buffer[active_buffer_main][0],
  437.                                              dma_buffer[active_buffer_main][1],
  438.                                              dma_buffer[active_buffer_main][2] );
  439.             //printf("\n");
  440.             buffer_ready = false;
  441.         }
  442.        
  443.         if(++i>11000000)  //20M ~3s
  444.           {
  445.             //printf(" i:%d\n",(uint16_t)(i-10000000));
  446.  
  447.             tim = esp_timer_get_time();
  448.             printf(" time: %d ms\n",(uint16_t)((tim-tim_old)/1000));
  449.             tim_old = tim;
  450.             vTaskDelay(1);      //to avoid watchdog trigger
  451.             i = 0;
  452.           }
  453.     }
  454. }

kaefe_br
Posts: 3
Joined: Tue Jan 07, 2025 2:58 pm

Re: ESP32-S3 Fast readings with ADC and DMA low level functions

Postby kaefe_br » Mon Jan 20, 2025 2:09 pm

Looking further into the datasheet: esp32-s3_technical_reference_manual_en.pdf:

"Note that due to speed limits of SAR ADCs, the operating clock of Digital Reader1 and SAR ADC1 is
DIGADC_SARCLK, the frequency of which affects the sampling precision. When the frequency of
DIGADC_SARCLK is higher than 5 MHz, the sampling precision will be lowered."

"The frequency of DIGADC_SARCLK must not exceed 5 MHz."

"The ADC needs 25 DIGADC_SARCLK clock cycles per sample, so the maximum sampling rate is limited by the
DIGADC_SARCLK frequency."


ADC takes 25 DIGADC_SARCLK clocks for a sample -> 5MHz / 25 = 200kHz is the max sample rate suggested by the datasheet.
:cry: :cry: :cry:

The information from Google suggest a better sample rate...
"The ESP32 Analog-to-Digital Converter (ADC) has a theoretical maximum sampling rate of 2 MHz when Wi-Fi is off and ADC DMA is used. However, it is recommended to use a lower sampling rate in practice."

Too bad. Abort!

Who is online

Users browsing this forum: Google [Bot], Majestic-12 [Bot] and 94 guests