Now let’s configure ADC to read a potentiometer value using DMA to transfer directly the data on RAM memory. Using DMA channel 1, now the request must be DMA_REQUEST_ADC1 that indicate the DMA wait a request from the ADC, the ADC shall trigger the DMA when the conversion of signal is done. DMA direction also change because we are using now a peripheral, DMA_PERIPH_TO_MEMORY mode is configured and circular mode is enable due to ADC constantly update the data value. Now to trigger ADC and DMA we use the function HAL_ADC_Start_DMA().

#include "bsp.h"
#include <stdio.h>

extern void initialise_monitor_handles(void);

#define BUFFER1_SIZE 1

uint32_t buffer1[ BUFFER1_SIZE ];
uint32_t conversionComplete;

/* Handler for DMA1 channel 1 */
DMA_HandleTypeDef Dma1HandlerCh1;

/* Handler for ADC1 */
ADC_HandleTypeDef AdcHandler;

/* Handler for ADC1 Channel 0*/
ADC_ChannelConfTypeDef AdcChannelConfig;

int main( void )
{
    /* Initialize HAL */
    HAL_Init( );

    /* Initialize semihosting */
    initialise_monitor_handles();

    /* Enable DMA 1 clock */
    __HAL_RCC_DMA1_CLK_ENABLE();

    /* Configure DMA 1 Channel 1 */
    Dma1HandlerCh1.Instance                 = DMA1_Channel1;         /* DMA1 Channel 1                                     */
    Dma1HandlerCh1.Init.Request             = DMA_REQUEST_ADC1;      /* Peripheral ADC1 request                            */
    Dma1HandlerCh1.Init.Direction           = DMA_PERIPH_TO_MEMORY;  /* Data will be transferred from peripheral to memory */
    Dma1HandlerCh1.Init.PeriphInc           = DMA_PINC_DISABLE;      /* Increment source address is disabled               */
    Dma1HandlerCh1.Init.MemInc              = DMA_MINC_ENABLE;       /* Increment destination address is enabled           */
    Dma1HandlerCh1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;   /* Source data is 32-bit width                        */
    Dma1HandlerCh1.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;   /* Destination data is 32-bit width                   */
    Dma1HandlerCh1.Init.Mode                = DMA_CIRCULAR;          /* After finishing last transfer, go to first element */
    Dma1HandlerCh1.Init.Priority            = DMA_PRIORITY_LOW;      /* This DMA channel request config as low priority    */
    HAL_DMA_Init( &Dma1HandlerCh1 );

    /* Enable DMA interrupts */
    HAL_NVIC_SetPriority( DMA1_Channel1_IRQn, 2, 0 );
    HAL_NVIC_EnableIRQ( DMA1_Channel1_IRQn );

    /* Configure ADC */
    __HAL_LINKDMA( &AdcHandler, DMA_Handle, Dma1HandlerCh1 );           /* Link DMA Handler to ADC Handler              */
    AdcHandler.Instance                   = ADC1;                       /* Use ADC1 Peripheral                          */
    AdcHandler.Init.ClockPrescaler        = ADC_CLOCK_SYNC_PCLK_DIV2;   /* APB clock divided by two                     */
    AdcHandler.Init.Resolution            = ADC_RESOLUTION8b;           /* 8 bit resolution                             */
    AdcHandler.Init.ScanConvMode          = ADC_SCAN_SEQ_FIXED;         /* Scan ADC channels ordered from 0 to 16       */
    AdcHandler.Init.DataAlign             = ADC_DATAALIGN_RIGHT;        /* Right aligned conversion result              */
    AdcHandler.Init.SamplingTimeCommon1   = ADC_SAMPLETIME_1CYCLE_5;    /* Sampling time of 1.5 clock cycles            */
    AdcHandler.Init.ExternalTrigConv      = ADC_SOFTWARE_START;         /* Conversion triggered by software             */
    AdcHandler.Init.EOCSelection          = ADC_EOC_SINGLE_CONV;        /* Flag for single conversion                   */
    AdcHandler.Init.Overrun               = ADC_OVR_DATA_OVERWRITTEN;   /* Data will be overwriten in case was not read */
    AdcHandler.Init.DMAContinuousRequests = ENABLE;                     /* Unlimited DMA transfers for continuous mode  */
    HAL_ADC_Init( &AdcHandler );

    AdcChannelConfig.Channel      = ADC_CHANNEL_0;                      /* Use ADC Channel 0                             */
    AdcChannelConfig.Rank         = ADC_RANK_CHANNEL_NUMBER;            /* Rank 0 for Ch0, rank 1 for Ch1 ...            */
    AdcChannelConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;          /* Use sampling time common 1 (1.5 clock cycles) */
    HAL_ADC_ConfigChannel( &AdcHandler, &AdcChannelConfig );

    HAL_ADCEx_Calibration_Start( &AdcHandler );
    
    /* Start DMA1 Channel 1 transfer all elements from Source1 array to destination Buffer1 */
    HAL_ADC_Start_DMA( &AdcHandler, (uint32_t*)buffer1, BUFFER1_SIZE );

    while (1)
    {
        if( conversionComplete )
        {
            /* Print the ADC value when a conversion has been done */
            printf( "Pot value: %lu\r\n", buffer1[ 0u ] );
            conversionComplete = 0;
            HAL_ADC_Start_DMA( &AdcHandler, (uint32_t*)buffer1, BUFFER1_SIZE );
        }
    }

    return 0u;
}

/* Callback when a conversion has been performed, the fucntion is called by the DMA interrupt
when data is stored in the corresponding memory address indicated by HAL_ADC_Start_DMA */
void HAL_ADC_ConvCpltCallback( ADC_HandleTypeDef *hadc )
{
    conversionComplete = 1u;
}

maps.c

void HAL_ADC_MspInit( ADC_HandleTypeDef* hadc )
{
    __GPIOA_CLK_ENABLE();
    __ADC_CLK_ENABLE();
    
    /* initialization Handler of GPIO */
    GPIO_InitTypeDef AnalogInput;

    AnalogInput.Pin   = GPIO_PIN_0;         /* Pot Connected to PIN 0 */
    AnalogInput.Mode  = GPIO_MODE_ANALOG;   /* Select mode Analog for this pin */
    AnalogInput.Pull  = GPIO_NOPULL;        /* no pull-up niether pull-down */
    HAL_GPIO_Init( GPIOA, &AnalogInput );
}

ints.c

/* Reference to DMA handler */
extern DMA_HandleTypeDef Dma1HandlerCh1;

/* Declare interrupt service rutine as it is declare in startup_stm32g0b1xx.s file */
void DMA1_Channel1_IRQHandler(void)
{
    /* HAL library function that attend interrupt */
    HAL_DMA_IRQHandler( &Dma1HandlerCh1 );
}