cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F401 ADC not getting all the values

SBeno.1
Associate II

Hi,

First time poster here, I have looked around for answers and didn't find anything that could help me. I also tried to reach out to ST but they doesn't want to help and they are throwing me to local suppliers instead.

So here's the thing, the ADC isn't able to go through all the values, I can reach all the range ( 0 to 4095 ) but sometimes it's skiping few steps. According to the datasheet, it's normal to have a +/- 3 step error and I understand that. But I am seeing bigger steps here.

The configuration :

ADC in scan mode, scanning 11 channels at 112 cycles per samples.

ADC transferring data through DMA when a conversion is done

An external trigger from Timer2 starts the scan every 20ms

The clocks :

HSE of 16MHz

HCLK of 84, so APB1 is at 84MHz

ADC prescaler at 4, so 21 MHz

Before going through the code, I have to mention that I have tried few things to get rid of this behavior:

  • Using HSI
  • Using ADC Interrupts instead of DMA
  • Scanning only 1 channel
  • Dividing APB2 by 2
  • Tried every sampling rate available

Some of those things listed above seemed to fix the problem, but in fact it only moved it to another value. At first the problem was between 1991 and 2048 ( I had the ADC running at 42MHz which isn't in the spec ) but after fixing this, the problem was around 1024.

0693W000001pdSZQAY.png0693W000001pdS5QAI.png

This is a zoomed in graph of the output values, even with the noise the value between 1023 and 1036 can't be reached.

Now, you want to inspect the code ? Here it is :

void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct;
    RCC_ClkInitTypeDef RCC_ClkInitStruct;
 
    /**Configure the main internal regulator output voltage 
    */
    __HAL_RCC_PWR_CLK_ENABLE();
 
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
 
    /**Initializes the CPU, AHB and APB busses clocks 
    */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 8;
    RCC_OscInitStruct.PLL.PLLN = 168;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
    RCC_OscInitStruct.PLL.PLLQ = 7;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        _Error_Handler(__FILE__, __LINE__);
    }
 
    /**Initializes the CPU, AHB and APB busses clocks 
    */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    {
        _Error_Handler(__FILE__, __LINE__);
    }
 
    /**Configure the Systick interrupt time 
    */
    HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000);
 
    /**Configure the Systick 
    */
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
 
    /* SysTick_IRQn interrupt configuration */
    HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0);
}
 
void ADC_peripheral_init(void)
{
    ADC_ChannelConfTypeDef sConfig;
 
    /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
    */
    adcADC_HANDLE.Instance                      = ADC1;
    adcADC_HANDLE.Init.ClockPrescaler           = ADC_CLOCK_SYNC_PCLK_DIV6;
    adcADC_HANDLE.Init.Resolution               = ADC_RESOLUTION_12B;
    adcADC_HANDLE.Init.ScanConvMode             = ENABLE;
    adcADC_HANDLE.Init.ContinuousConvMode       = DISABLE;
    adcADC_HANDLE.Init.DiscontinuousConvMode    = DISABLE;
    adcADC_HANDLE.Init.NbrOfDiscConversion      = 0;
    adcADC_HANDLE.Init.ExternalTrigConvEdge     = ADC_EXTERNALTRIGCONVEDGE_RISING;
    adcADC_HANDLE.Init.ExternalTrigConv         = ADC_EXTERNALTRIGCONV_T2_TRGO;
    adcADC_HANDLE.Init.DataAlign                = ADC_DATAALIGN_RIGHT;
    adcADC_HANDLE.Init.NbrOfConversion          = NB_OF_ADC_INPUT_ENTRY;
    adcADC_HANDLE.Init.DMAContinuousRequests    = ENABLE;
    adcADC_HANDLE.Init.EOCSelection             = ADC_EOC_SEQ_CONV;
 
    if (HAL_ADC_Init(&adcADC_HANDLE) != HAL_OK)
    {
        _Error_Handler(__FILE__, __LINE__);
    }
 
    sConfig.SamplingTime = ADC_SAMPLETIME_112CYCLES;
 
    for (size_t i = 0; i < NB_OF_ADC_INPUT_ENTRY; i++)
    {
        sConfig.Channel = analog_inputs[i].channel;
        sConfig.Rank = i + 1;
        if (HAL_ADC_ConfigChannel(&adcADC_HANDLE, &sConfig) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }
    }
}
 
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
 
    GPIO_InitTypeDef GPIO_InitStruct;
    if (adcHandle->Instance == ADC1)
    {
        /* ADC1 clock enable */
        __HAL_RCC_ADC1_CLK_ENABLE();
  
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
 
        for (size_t i = 0; i < NB_OF_ADC_INPUT_ENTRY; i++)
        {
            GPIO_InitStruct.Pin = analog_inputs[i].pin;
            HAL_GPIO_Init(analog_inputs[i].port, &GPIO_InitStruct);
        }
 
        /* ADC1 DMA Init */
        /* ADC1 Init */
        hdma_adc1.Instance                  = DMA2_Stream0;
        hdma_adc1.Init.Channel              = DMA_CHANNEL_0;
        hdma_adc1.Init.Direction            = DMA_PERIPH_TO_MEMORY;
        hdma_adc1.Init.PeriphInc            = DMA_PINC_DISABLE;
        hdma_adc1.Init.MemInc               = DMA_MINC_ENABLE;
        hdma_adc1.Init.PeriphDataAlignment  = DMA_PDATAALIGN_WORD;
        hdma_adc1.Init.MemDataAlignment     = DMA_MDATAALIGN_WORD;
        hdma_adc1.Init.Mode                 = DMA_CIRCULAR;
        hdma_adc1.Init.Priority             = DMA_PRIORITY_LOW;
        hdma_adc1.Init.FIFOMode             = DMA_FIFOMODE_DISABLE;
 
        if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }
 
        __HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);
 
        /* ADC1 interrupt Init */
        HAL_NVIC_SetPriority(ADC_IRQn, 5, 0);
        HAL_NVIC_EnableIRQ(ADC_IRQn);
    }
}

Thank you all for taking the time to read this and to try to help me !!😅

10 REPLIES 10

Solved !