0

I am working on an STM32 project where I'm trying to configure the ADC to continuously convert and use DMA to transfer the results. Despite setting everything up according to the reference manual, the ADC conversion never seems to complete, as indicated by the ADC's End of Conversion flag (ADC_FLAG_EOC) which never gets set. Here is the relevant part of my code:

void GPIO_ADC_Config() {
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

// ADC and DMA Configuration
void ADC_Config(void) {
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    DMA_InitTypeDef DMA_InitStructure;
    DMA_DeInit(DMA2_Stream0);
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = 2;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    DMA_Cmd(DMA2_Stream0, ENABLE);

    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
    ADC_CommonInit(&ADC_CommonInitStructure);

    ADC_InitTypeDef ADC_InitStructure;
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion = 2;
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 1, ADC_SampleTime_3Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 2, ADC_SampleTime_3Cycles);
    ADC_Cmd(ADC1, ENABLE);
    ADC_DMACmd(ADC1, ENABLE);

    ADC_SoftwareStartConv(ADC1);
}

void TIM3_IRQHandler() {
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {
        static int adc_counter = 0;
        adc_counter++;
        if(adc_counter < 8) {
            while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
            uint16_t adc_value = ADC_GetValue(0);
            adc_values[adc_counter * 2] = adc_value;
            while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
            adc_values[adc_counter * 2 + 1] = ADC_GetValue(1);
        } else if (adc_counter == 8) {
            adc_counter = 0;
        }
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
    }
}

I have set a breakpoint just after the first loop checking ADC_FLAG_EOC, but it seems the program never reaches beyond this point, indicating that the ADC conversion never completes. Could anyone help me understand what might be wrong or what I am missing here?

In addition to the configuration shared above, I also attempted to troubleshoot the issue by simplifying the setup:

Removing DMA: I removed the DMA configuration to isolate the issue, thinking that direct polling of the ADC might give me more control and clearer insight into the ADC behavior. Manual Triggering: Instead of relying on continuous conversion mode, I configured the ADC to trigger conversions manually. I expected that by manually starting each ADC conversion with ADC_SoftwareStartConv(ADC1);, I could control the conversion process more directly and ensure that the ADC_FLAG_EOC (End Of Conversion flag) would be set after each conversion, which I could then check with ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC).

Despite these changes, the ADC conversion flag ADC_FLAG_EOC still did not set as expected, even when I triggered conversions manually and waited for completion in a simple loop:

ADC_SoftwareStartConv(ADC1);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));

I was expecting that after starting a conversion manually, the ADC_FLAG_EOC would be set, indicating that the conversion is complete and data is ready to be read from the ADC data register. However, the system seems to be stuck in the loop, suggesting that the conversion never completes, or the flag is not being set as expected.

This behavior persists regardless of whether I use DMA or manual triggering, which leads me to suspect there might be a fundamental misconfiguration or misunderstanding on my part regarding how the ADC conversion completion is indicated or handled in this specific STM32 setup.

Microcontroller: 32F429IDISCOVERY

4
  • 1
    You should probably be declaring your structure variables like this: ADC_InitTypeDef ADC_InitStructure = {0}; otherwise there will be fields (that you are not explicitly setting) that contain garbage. Commented Apr 19, 2024 at 8:48
  • Using the registers you would do this in 15 minutes without any problems. HAL which should speed up development actually slows it down significantly as it is too "abstract" Commented Apr 19, 2024 at 10:07
  • Have you checked ADC flags? Some error flag could be set, indicating bad config or some other error. Check flags both when you trigger conversion and when you're supposed to get end of conversion. Commented Apr 19, 2024 at 10:49
  • Also check the return values from all functions that return a status. The HAL (for all its many faults) is good at telling you when you've done something wrong. Commented Apr 19, 2024 at 13:03

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.