AnsweredAssumed Answered

STM32 ADC working well in DMA but giving wrong values in polling mode

Question asked by Pankaj Rodey on Jun 14, 2018

I am struggling to get the STM32 ADC in polling mode, but am able to get correct values in DMA mode. I am using STM32F427 ADC1 channel 12 in 12-bit mode.  Here is the relevant code:

 

void SystemClock_Config(void)
{

RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;

RCC_PeriphCLKInitTypeDef periphClockConfig;

/**Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
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_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != 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, 0, 0);

}

 

 


static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__DMA2_CLK_ENABLE();

hdma2.Instance = DMA2_Stream4;
hdma2.Init.Channel = DMA_CHANNEL_0;
hdma2.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma2.Init.PeriphInc = DMA_PINC_DISABLE;
hdma2.Init.MemInc = DMA_MINC_ENABLE;
hdma2.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma2.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma2.Init.Mode = DMA_CIRCULAR;
hdma2.Init.Priority = DMA_PRIORITY_HIGH;
hdma2.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma2.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
hdma2.Init.MemBurst = DMA_MBURST_SINGLE;
hdma2.Init.PeriphBurst = DMA_PBURST_SINGLE;

if (HAL_DMA_Init(&hdma2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}

__HAL_LINKDMA(&hadc1, DMA_Handle, hdma2);

/* DMA interrupt init */
/* DMA2_Channe4_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 10, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);
}

 

 

 

/* ADC1 init function */
static void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig;

__ADC1_CLK_ENABLE();

/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
#ifdef ADC_DMA
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;//ADC_CLOCK_SYNC_PCLK_DIV4; //Prescalar on 84 MHz
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = ENABLE;//DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

#else
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; //Prescalar on 84 MHz
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE; //DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = DISABLE;
#endif

if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}

/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_12;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;//ADC_SAMPLETIME_3CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}

}

 

 

 

For using ADC counts in polling mode, in a 100 ms timer interrupt, I am doing this:

 

 

 

#ifndef ADC_DMA

if (HAL_ADC_PollForConversion(&hadc1, 1000) != HAL_OK)
{
errorCounter++;
}

/* Check if the continuous conversion of regular channel is finished */
if ((HAL_ADC_GetState(&hadc1) & HAL_ADC_STATE_EOC_REG) == HAL_ADC_STATE_EOC_REG)
{
gTemperatureValues = HAL_ADC_GetValue(&hadc1);
}

#endif

 

 

When I define the macro ADC_DMA and use the DMA and ADC interrupt callback functions, it works perfectly well and the array of 12-bit ADC counts is as expected.

 

However, due to some constraints, I want to use periodic polling instead of DMA/interrupt.

 

When I try to use the ADC in polling mode as above, the conversion works well, but every time, I am getting a random and incorrect 8-bit value in the ADC DR register in spite of configuring it for 12-bit mode.

Please suggest. Thanks in advance.

Outcomes