cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G030 ADC DMA Not Working

shohanur00
Associate II

Hi all,

I am using STM32G030F6P6 and trying to read ADC channel 11 and channel 16 using DMA.

  • ADC works correctly in polling and interrupt mode.

  • When I enable DMA, the ADC values in the buffer remain 0 all the time.

  • DMA does not trigger at EOC, and DMA transfer never happens.

I have been trying for 1 week, and I cannot understand what is wrong.


What I have done:

  • Configured ADC correctly (calibration, sequence, sampling time, etc.)

  • Configured DMA correctly (channel, source/destination, size, circular mode)

  • Enabled ADC DMA request (DMAEN)

  • Enabled DMAMUX (for STM32G0 series)

But still no data is transferred and buffer remains 0.

 

#include  "stm32g030xx.h"
#include  "gpio.h"

volatile uint32_t adc_value[2] = {0},adc_buff = 0, adc_index = 0;

void delay_ms(uint32_t ms)
{
    SysTick->LOAD = 64000 - 1;   // 64MHz ? 1ms
    SysTick->VAL  = 0;
    SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
                    SysTick_CTRL_ENABLE_Msk;

    for(uint32_t i = 0; i < ms; i++)
    {
        while(!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
    }
}

void RCC_Clock_Config(void){
//Clock Config
RCC->CR &= ~RCC_CR_PLLON;
while(RCC->CR & RCC_CR_PLLRDY);
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLSRC;   // Clear both PLLSRC bits
RCC->PLLCFGR |=  RCC_PLLCFGR_PLLSRC_1; // 10b ? HSI16
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM;
RCC->PLLCFGR |= RCC_PLLCFGR_PLLM_0;
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN;
RCC->PLLCFGR |= (16U << RCC_PLLCFGR_PLLN_Pos);
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLR;
RCC->PLLCFGR |= (1U << RCC_PLLCFGR_PLLR_Pos);
RCC->CR |= RCC_CR_PLLON;
while(!(RCC->CR & RCC_CR_PLLRDY)); 
RCC->PLLCFGR |= RCC_PLLCFGR_PLLREN;

FLASH->ACR &= ~FLASH_ACR_LATENCY;
FLASH->ACR |= FLASH_ACR_LATENCY_2;  // 48–64 MHz ? 2 WS

RCC->CFGR &= ~RCC_CFGR_SW;
RCC->CFGR |= (2 << RCC_CFGR_SW_Pos);
while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != 0x2);
}

void UART2_Init(void){
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
GPIO_Init(GPIOA,2,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_NOPULL,GPIO_SPEED_HIGH);
GPIOA->AFR[0] &= ~GPIO_AFRL_AFSEL2_Msk;
GPIOA->AFR[0] |= (1U << GPIO_AFRL_AFSEL2_Pos);
RCC->APBENR1 |= RCC_APBENR1_USART2EN;
USART2->CR1 = 0;
USART2->BRR = 556; // 115200 baud @ 64MHz
USART2->CR1 |= USART_CR1_UE;
USART2->CR1 |= USART_CR1_TE;
}

void UART2_Send_Byte(uint8_t c){
while(!(USART2->ISR & USART_ISR_TXE_TXFNF));
    USART2->TDR = c;
while(!(USART2->ISR & USART_ISR_TC)); // wait transmission complete
}

void UART2_Send_Number(int32_t num)
{
    char buf[12];   // enough for -2147483648
    int i = 0;

    if(num == 0){
        UART2_Send_Byte('0');
        return;
    }

    if(num < 0){
        UART2_Send_Byte('-');
        num = -num;
    }

    while(num > 0){
        buf[i++] = (num % 10) + '0';
        num /= 10;
    }

    while(i--){
        UART2_Send_Byte(buf[i]);
    }
}

void ADC_Init(void){
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
GPIO_Init(GPIOA,10,GPIO_MODE_ANALOG,GPIO_OTYPE_PP,GPIO_NOPULL,GPIO_SPEED_LOW); //ADC Channel 16
RCC->IOPENR |= RCC_IOPENR_GPIOBEN;
GPIO_Init(GPIOB,7,GPIO_MODE_ANALOG,GPIO_OTYPE_PP,GPIO_NOPULL,GPIO_SPEED_LOW);  //ADC Channel 11
RCC->APBENR2 |= RCC_APBENR2_ADCEN;

ADC1->CR &= ~ADC_CR_ADEN;
while(ADC1->CR & ADC_CR_ADEN);

ADC1->CR |= ADC_CR_ADVREGEN;
for(volatile int i=0;i<30000;i++);
ADC1->CR |= ADC_CR_ADCAL;
while(ADC1->CR & ADC_CR_ADCAL);

ADC1->CFGR1 = 0;
ADC1->CFGR1 |= ADC_CFGR1_CONT;
ADC1->CFGR1 |= ADC_CFGR1_CHSELRMOD;

ADC1->CFGR1 |= ADC_CFGR1_DMAEN;
ADC1->CFGR1 |= ADC_CFGR1_DMACFG;
//ADC1->CFGR1 |= ADC_CFGR1_CHSELRMOD;
ADC1->CFGR1 |= ADC_CFGR1_OVRMOD; // overwrite old data
ADC1->SMPR &= ~ ADC_SMPR_SMP1_Msk;
ADC1->SMPR |= (7U << ADC_SMPR_SMP1_Pos);
//ADC->CCR &= ~ADC_CCR_TSEN;   // ?? this is the missing piece

/*ADC1->IER |= ADC_IER_EOCIE;
NVIC_SetPriority(ADC1_IRQn, 0);
NVIC_EnableIRQ(ADC1_IRQn);
__enable_irq();*/

ADC1->CHSELR = ADC_CHSELR_CHSEL11 | ADC_CHSELR_CHSEL16;

ADC1->CR |= ADC_CR_ADEN;
while (!(ADC1->ISR & ADC_ISR_ADRDY)); // ADC ready
//ADC1->CR |= ADC_CR_ADSTART;
}

uint16_t ADC_Read(void){
    //ADC1->CR |= ADC_CR_ADSTART;
    while(!(ADC1->ISR & ADC_ISR_EOC));

    return ADC1->DR;
}

void DMA_Init(void){
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
DMA1_Channel1->CCR = 0;
DMA1_Channel1->CCR |= (3 << DMA_CCR_PL_Pos);  //Priority set very High
DMA1_Channel1->CCR |= (1 << DMA_CCR_MSIZE_Pos); // 16 bits
DMA1_Channel1->CCR |= (1 << DMA_CCR_PSIZE_Pos);
DMA1_Channel1->CCR &= ~DMA_CCR_DIR; 
DMA1_Channel1->CCR |= DMA_CCR_CIRC; //Circularly porbe
DMA1_Channel1->CCR |= DMA_CCR_MINC;

DMA1_Channel1->CPAR = (uint32_t) &(ADC1->DR);
DMA1_Channel1->CMAR = (uint32_t)adc_value;
DMA1_Channel1->CNDTR = 2;
//DMA1_Channel1->CCR |= DMA_CCR_EN;
}

int main(void){
//Clock Config
RCC_Clock_Config();
//GPIO
//__enable_irq();
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
GPIO_Init(GPIOA,4,GPIO_MODE_OUTPUT,GPIO_OTYPE_PP,GPIO_NOPULL,GPIO_SPEED_LOW);
//ADC
UART2_Init();
DMA_Init();
ADC_Init();
DMA1_Channel1->CCR |= DMA_CCR_EN;   // enable DMA channel
ADC1->CR |= ADC_CR_ADSTART;         // start ADC conversions

while(1){
int16_t adc = adc_buff;
int16_t T = 0;

UART2_Send_Number(adc_value[0]& 0xFFFF);
UART2_Send_Byte('\n');
UART2_Send_Byte('\r');
UART2_Send_Number(adc_value[1]& 0xFFFF);
UART2_Send_Byte('\n');
UART2_Send_Byte('\r');
GPIO_TogglePin(GPIOA,4);
delay_ms(100);
}
}

void ADC1_IRQHandler(void)
{
    if (ADC1->ISR & ADC_ISR_EOC)
    {
        uint16_t val = ADC1->DR;   // MUST read DR to clear EOC

        adc_value[adc_index] = val;

        adc_index++;
        if (adc_index >= 2)
            adc_index = 0;
    }
}
 

Problem:

The DMA never transfers data and the buffer remains 0.

Even though ADC conversion is running and EOC flag is set, DMA is not triggered.


Request:

Please help me identify what is missing or wrong in my configuration.

What should I check?


Thank you.

 

Edited to apply source code formatting - please see How to insert source code for future reference.

14 REPLIES 14

I am not using a dev board.  I am using microcontroller that is attached with my own pcb.  Could you review my code.  

I would strongly suggest that you first get it working with a known-good example on a known-good board.

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

Try start with LL instead bare, after LL work you can rewrite it (i mean waste time)

STM32CubeG0/Projects/NUCLEO-G070RB/Examples_LL/ADC/ADC_SingleConversion_TriggerTimer_DMA_Init at master · STMicroelectronics/STM32CubeG0

good start point

If I'm not mistaken, you don't set DMAMUX anywhere. You have to route DMA requests from ADC to your DMA channel.

In other words, how does your DMA channel 1 know that it should handle requests from ADC and not, for example, from UART or SPI?

Thank You very much