STM32G030 ADC DMA Not Working
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.
