AnsweredAssumed Answered

How to read several ADCs interfaces every n seconds per channel in STM32 MCU?

Question asked by Marco S on Apr 14, 2017
Latest reply on Apr 26, 2017 by Marco S

I'm using the ADC channels (12-bit resolution) of a STM32F0 microcontroller to read voltage values in three different points of a board. What I want to do is to read the values every 2 seconds (I have 2 seconds to read the values in the three points) and send them by the UART interface. In order to select which ADC channel I'm reading I'm implementing the voltage reading functions as follows:

 

    uint16_t readv1(void){
        //Here I try to read ADC_CHANNEL_1
        //chConfig and txtbuff are global variables:
        //ADC_ChannelConfTypeDef chConfig;
        //char txtbuff[64];
    
        chConfig.Channel = ADC_CHANNEL_1;
        HAL_ADC_ConfigChannel(&hadc, &chConfig);
        uint32_t vref = HAL_ADC_GetValue(&hadc);
        uint16_t vref2 = (uint16_t) vref;
        sprintf(TextBuffer, "%u\n", vref2);
        HAL_UART_Transmit(&huart4, (uint8_t*)txtbuff, strlen(txtbuff), 0xFFFFFFFF);
    
        return vref2;
    }

 


This is the function for scanning one ADC channel. For reading the other two ADC channels I'm using the same procedure just changing the value of `n` in the line `chConfig.Channel = ADC_CHANNEL_n;` where `n` is the channel number. Note that `chConfig` is of the same type of `sConfig` declared in `MX_ADC_Init()` function, but `chConfig` is a global variable.

 

The problem I have is that `readv1` function reads a constant voltage (I have checked it with a voltimeter) but the numbers showed in the terminal via UART change a lot, between 120 and 2400. I'm not sure if using the line `chConfig.Channel = ADC_CHANNEL_1;` for selecting a channel is good or if there is any other procedure to follow. Or should I use polling mode as follows every time I need to read a single channel?

 

        chConfig.Channel = ADC_CHANNEL_1;
        chConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
        chConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
        HAL_ADC_ConfigChannel(&hadc, &chConfig);
        HAL_ADC_Start(&hadc);
        HAL_ADC_PollForConversion(&hadc, 0xFFFFFFFF);
        uint32_t vref = HAL_ADC_GetValue(&hadc);
        HAL_ADC_Stop(&hadc);
        chConfig.Rank = ADC_RANK_NONE;
        HAL_ADC_ConfigChannel(&hadc, &chConfig);

 


In order to scan the ADC every two seconds I'm using a 8 MHz timer as follows:

 

    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
        if (htim->Instance==TIM3){
            //Here I call the functions which read the voltage values of different ADC channels
            volt1 = readv1();
            readv2(volt1);
            readv3(volt1);
        }
    }

 

This is the main function where I initialize the periphericals (ADC is in interruption mode):

 

    int main(void)
    {
    
      /* MCU Configuration----------------------------------------------------------*/
    
      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();
    
      /* Configure the system clock */
      SystemClock_Config();
    
      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_USART4_UART_Init();
      MX_ADC_Init();
      MX_TIM3_Init();
    
      /* USER CODE BEGIN 2 */
      HAL_ADC_Start_IT(&hadc);
      HAL_TIM_Base_Start_IT(&htim3);
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
    
      }
    }

 

And below are the initialization functions for the timer and the ADC:

 

    /* TIM3 init function */
    static void MX_TIM3_Init(void)
    {
    
      TIM_ClockConfigTypeDef sClockSourceConfig;
      TIM_MasterConfigTypeDef sMasterConfig;
    
      htim3.Instance = TIM3;
      htim3.Init.Prescaler = 8000;
      htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim3.Init.Period = 1999;
      htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
      if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
      {
        Error_Handler();
      }
    
      sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
      if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
      {
        Error_Handler();
      }
    
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
      if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
      {
        Error_Handler();
      }
    
    }
    
    
    /* ADC init function */
    static void MX_ADC_Init(void)
    {
    
      ADC_ChannelConfTypeDef sConfig;
    
        /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
        */
      hadc.Instance = ADC1;
      hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
      hadc.Init.Resolution = ADC_RESOLUTION_12B;
      hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
      hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
      hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
      hadc.Init.LowPowerAutoWait = DISABLE;
      hadc.Init.LowPowerAutoPowerOff = DISABLE;
      hadc.Init.ContinuousConvMode = ENABLE;
      hadc.Init.DiscontinuousConvMode = DISABLE;
      hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
      hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
      hadc.Init.DMAContinuousRequests = DISABLE;
      hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
      if (HAL_ADC_Init(&hadc) != HAL_OK)
      {
        Error_Handler();
      }
    
        /**Configure for the selected ADC regular channel to be converted.
        */
      sConfig.Channel = ADC_CHANNEL_0;
      sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
      sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
      if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
      {
        Error_Handler();
      }
    
        /**Configure for the selected ADC regular channel to be converted.
        */
      sConfig.Channel = ADC_CHANNEL_1;
      if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
      {
        Error_Handler();
      }
    
        /**Configure for the selected ADC regular channel to be converted.
        */
      sConfig.Channel = ADC_CHANNEL_2;
      if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
      {
        Error_Handler();
      }
    
        /**Configure for the selected ADC regular channel to be converted.
        */
      sConfig.Channel = ADC_CHANNEL_4;
      if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
      {
        Error_Handler();
      }
    
    }

Outcomes