cancel
Showing results for 
Search instead for 
Did you mean: 

ADC Multichannel Polling Example

KenLee
Associate III

I'm writing firmware for stm32c011f4u6 using Keil5.

I downloaded and checked an example about ADC from the homepage, but I only found the code that uses DMA.

Is there any example of using ADC with Polling instead of DMA?

Also, I need an example for multi-channels, not single channels.

5 REPLIES 5
SofLit
ST Employee

Hello,

This is not related to the tool (Keil or whatever else) but to the MCU itself.

It's possible by reading DR register before the next conversion but it's not recommended in scan mode as you may lose reading samples. That's why there is no polling mode example in scan mode.

So I recommend to use DMA instead.

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Thank you for your reply.

when I use DMA in my program and I enable DMA interrupt, the interrupt handler is infinitely generated, and the program gets stuck in interrupt.

I tried maximizing the sampling cycle, but the same thing happens. I want to read each channel in the ADC only once and move on to the next sequence in the program. 

How can I fix this?

Did you set ADC continuous mode?

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

No. I set it to Discontinuous mode.

Also, After I asked you the question, I've made a few modifications and now I'm no longer stuck in Interrupt, but instead, Interrupt function is not work this time.

I've put Breakpoint in the Callback function, but it's not work.

Here's my code.

 

 

void sapp_hal_init(void)
{
	uint32_t tmp_index;

  /* Initialize ADC group regular data buffer values */
  for (tmp_index = 0; tmp_index < 3UL; tmp_index++)
  {
    uhADCxConvertedData[tmp_index] = (__LL_ADC_DIGITAL_SCALE(LL_ADC_RESOLUTION_12B) + 1);
  }

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

	SystemClock_Config();
  /* USER CODE BEGIN Init */
	GPIO_Init();
	RTC_Init();
	MX_DMA_Init();
	ADC_Init();

  /* USER CODE BEGIN 2 */
	
	if (HAL_ADC_Start_DMA(&hadc1,
                        (uint32_t *)uhADCxConvertedData,
                        3UL
                       ) != HAL_OK)
  {
    /* Error: ADC conversion start could not be performed */
    Error_Handler();
  }
	
	HAL_Delay(1);
}

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  if(hadc->Instance==ADC1)
  {

  /** Initializes the peripherals clocks
  */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
    PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_SYSCLK;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
      Error_Handler();
    }

    /* Peripheral clock enable */
    __HAL_RCC_ADC_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**ADC1 GPIO Configuration
    PA1     ------> ADC1_IN1
    PA2     ------> ADC1_IN2
    */
    GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
		
		/* ADC1 DMA Init */
    /* ADC1 Init */
    hdma_adc1.Instance = DMA1_Channel1;
    hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
    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_HALFWORD;
    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_adc1.Init.Mode = DMA_CIRCULAR;
    hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);

    /* ADC1 interrupt Init */
    HAL_NVIC_SetPriority(ADC1_IRQn, 0, 0);
		HAL_NVIC_EnableIRQ(ADC1_IRQn);
  }

}

static void ADC_Init(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};

  //!!! HAL_ADC_Init is commented because some parameters are missing
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.LowPowerAutoPowerOff = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 3;
  hadc1.Init.DiscontinuousConvMode = ENABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_160CYCLES_5;
  hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_160CYCLES_5;
  hadc1.Init.OversamplingMode = DISABLE;
  hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
	if(HAL_ADC_Init(&hadc1) != HAL_OK)
	{
		Error_Handler();
	}
	
	sConfig.Channel = ADC_CHANNEL_2;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;
  if(HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
	{
		Error_Handler();
	}
	
	sConfig.Channel = ADC_CHANNEL_1;
	sConfig.Rank = ADC_REGULAR_RANK_2;
	sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_2;
	if(HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
	{
		Error_Handler();
	}
	
	sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
  sConfig.Rank = ADC_REGULAR_RANK_3;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
	
	if (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK)
  {
    /* Calibration Error */
    Error_Handler();
  }
}

static void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn);

}
--------------------------------------
uint16_t DMA_Sequence(int i)
{	
	if (HAL_ADC_Start(&hadc1) != HAL_OK)
    {
      /* Error: ADC conversion start could not be performed */
      Error_Handler();
    }
		HAL_Delay(1);
    /* Toggle LED at each ADC conversion */
//    BSP_LED_On(LED4);
//    HAL_Delay(LED_BLINK_SLOW);
//    BSP_LED_Off(LED4);
//    HAL_Delay(LED_BLINK_SLOW);
//    
    /* Note: ADC group regular conversions data are stored into array         */
    /*       "uhADCxConvertedData"                                            */
    /*       (for debug: see variable content into watch window).             */
    /*       - uhADCxConvertedData[0]: ADC channel set on sequence rank 1     */
    /*                                                      */
    /*       - uhADCxConvertedData[1]: ADC channel set on sequence rank 2     */
    /*                                      */
    /*       - uhADCxConvertedData[2]: ADC channel set on sequence rank 3     */
    /*                                  */

    /* If ADC conversions and DMA transfer are completed, then process data */
    if(ubDmaTransferStatus == 1)
    {
      uhADCxConvertedData_VrefAnalog_mVolt = __LL_ADC_CALC_VREFANALOG_VOLTAGE(uhADCxConvertedData[1], LL_ADC_RESOLUTION_12B);

      /* Computation of ADC conversions raw data to physical values           */
      /* using LL ADC driver helper macro.                                    */
      uhADCxConvertedData_VoltageGPIO_mVolt        = __LL_ADC_CALC_DATA_TO_VOLTAGE(uhADCxConvertedData_VrefAnalog_mVolt, uhADCxConvertedData[0], LL_ADC_RESOLUTION_12B);
      uhADCxConvertedData_VrefInt_mVolt            = __LL_ADC_CALC_DATA_TO_VOLTAGE(uhADCxConvertedData_VrefAnalog_mVolt, uhADCxConvertedData[1], LL_ADC_RESOLUTION_12B);
      hADCxConvertedData_Temperature_DegreeCelsius = __LL_ADC_CALC_TEMPERATURE_TYP_PARAMS(INTERNAL_TEMPSENSOR_AVGSLOPE, 
                                                                                          INTERNAL_TEMPSENSOR_V30,
                                                                                          INTERNAL_TEMPSENSOR_V30_TEMP,
                                                                                          VDDA_APPLI,
                                                                                          uhADCxConvertedData[2],
                                                                                          LL_ADC_RESOLUTION_12B);
      /* Update status variable of DMA transfer */
      ubDmaTransferStatus = 0;
			HAL_ADC_Stop(&hadc1);
		}
	
			if(i == 0){
				return uhADCxConvertedData_VoltageGPIO_mVolt;
			}
			else{
				return uhADCxConvertedData_VrefInt_mVolt;
			}
}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
  /* Update status variable of DMA transfer */
  ubDmaTransferStatus = 1;
}

/**
  * @brief  ADC error interruption callback
  * @retval None
  */
void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
{
  /* Note: Disable ADC interruption that caused this error before entering in
           infinite loop below. */

  /* In case of error due to overrun: Disable ADC group regular overrun interruption */
  LL_ADC_DisableIT_OVR(ADC1);

  /* Error reporting */
  Error_Handler();
}
-----------------------------
void DMA1_Channel1_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_adc1);
}
void ADC1_IRQHandler(void)
{
  HAL_ADC_IRQHandler(&hadc1);
}

 

Other settings were excluded. can you check it?