cancel
Showing results for 
Search instead for 
Did you mean: 

I am using the ADC on NUCLEO- STM32F401RE board. ADC is programmed using interrupts and the code does not work beyond 10kHz of input signal. What am I missing?

archana95in
Associate II
#include "main.h"
#include "stm32f4xx_hal.h"
 
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
/* USER CODE BEGIN PFP */
uint32_t adc_data[10000];
uint32_t i=0;
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	if (i<10000) {
adc_data[i]= HAL_ADC_GetValue(&hadc1);
		i++;
HAL_ADC_Start_IT(&hadc1);
}
	else {
		HAL_ADC_Stop_IT(&hadc1);
/* USER CODE END 0 */
	}
}
 
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_ADC1_Init();
  /* USER CODE BEGIN 2 */
HAL_ADC_Start_IT(&hadc1);
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
 
while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
 
 
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
  /**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_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /**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();
  }
}
 
 
static void MX_ADC1_Init(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};
 
  /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  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 = DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
  */
  sConfig.Channel = ADC_CHANNEL_0;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
}
 
static void MX_GPIO_Init(void)
{
 
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
 
}
 
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
 
  /* USER CODE END Error_Handler_Debug */
}
 
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

0690X000008iDlkQAE.jpg0690X000008iDluQAE.jpg

I am using the ADC on NUCLEO- STM32F401RE board. I have programmed the ADC using interrupts store about 10,000 values in an array and read them using a .ini file. The code does not work beyond 10kHz of input signal. ADC is of 12 bit resolution with 3 sampling cycles ; ADC clock frequency is 21MHz. Below is my code and plot of values for input frequency range of 1- 200Khz sine wave. The input voltage is 1.3V. What am I missing?

6 REPLIES 6
archana95in
Associate II

Edit : PFA code and plot of values for input frequency range of 1- 200Khz sine wave of 1.3 Vpp.  ADC is of 12 bit resolution with 3 sampling cycles ; ADC clock frequency is 21Khz.

Ozone
Lead

I usually don't mess with Cube code.

But I'm pretty sure the interrupt runtime is the limiting element here, which means interrupt handler and callback, which is called in that context.

The handler code itself is missing.

Try to measure the runtime, either with help of the toolchain, or with GPIO toggling and a scope.

BTW, a sampling time of 3 cycles is quite short, and a bit of a chellange for the attached hardware.

For 10..20kHz, you can go much higher.

And, I would consider using DMA instead of interrupts. You would get an TC interrupt after (supposedly) your 10000 values.

archana95in
Associate II

0690X000008iOxLQAU.jpg0690X000008iOxGQAU.jpgThank you for your inputs.I used DMA continuous conversion and stored the values for 12 bits ADC with ADC clock freq= 21 Mhz. Here is a snippet of my code

uint32_t adc_data[10000]; 
uint32_t i=0;
 while (1) 
{ 
if (i<10000)
 { 
HAL_ADC_Start_DMA(&hadc1,adc_data,10000); i++; 
} 
else 
{ HAL_ADC_Stop_DMA(&hadc1); }
 }
 
 }

There is an improvement and works until 40kHz, but is distorted beyond that. Is this due to HAL overhead? How do I get the ADC to work for input frequencies between 100kHz-250kHz.

Also increasing the sampling cycles did not bring about any useful progress.

Probably should not start it 10000 times, but rather wait on completion.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
archana95in
Associate II

0690X000008iQ7lQAE.jpgI modified my code as per your suggestion and also reduced the resolution to 8 bits. These were the best values I could get. PFA my code and plot. What other changes can I make so I will be able to comfortably sample input frequencies between 200-250kHz? Or is that not possible at all when I am using HAL?

while (1)
  {
 HAL_ADC_Start_DMA(&hadc1,adc_data,1000);
		if (HAL_ADC_PollForConversion(&hadc1,1)==HAL_OK)
		{
		if (i<1000)
	{
adc_datatwo[i] =	adc_data[i];
			i++;
  }
}
	}

 @Community member​ @Ozone​ 

Why the looping in this fashion? Get the DMA to complete the 10000 samples and save the content.​

If you need a continuous sampling use a double size buffer and move half the content at HT and TC DMA interrupts.​

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..