cancel
Showing results for 
Search instead for 
Did you mean: 

Confusion about ADC sampling speed and sampled value

rakib2023
Associate III

Hello.

I am very new in using STM32. I am using STM32H747I-DISCO board. For my project, I only need one ADC in differential mode. Previously, I tried to use DMA with ADC but it never worked, even the "ADC dual mode interleaved" example provided by st didn't work. So, I started to fiddle with "PollForConversion" and interrupt methods. Now, from CubeIDE, i have the following clock setup,

CPU1 - 480 MHz, CPU2 - 240 MHz, APB1 and APB2 timer clocks - 240 MHz, ADC - 21 MHz

Only have channel 1 set to differential mode for ADC1 and Timer 2 in free running (1 MHz) to measure timings.

Here's the timer initialize,

 

static void MX_TIM2_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 240;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 4294967295;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

Here's the ADC initialize,

static void MX_ADC1_Init(void)
{
  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};

  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5;
  sConfig.SingleDiff = ADC_DIFFERENTIAL_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  sConfig.OffsetSignedSaturation = DISABLE;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

 

I tried both poll and interrupt method and checked the time it takes for reading one sample. From the ADC configuration, it should have 1 Msps sampling rate, that is 1us for each sample. But when checking in action, poll method seems to take about 1 second to read 1 sample (two calls, "PollForConversion" and "GetValue"). Interrupt method seems to take about 400ms. Besides, without any input to ADC pins (0V), the values I get is still very big, roughly 32000 in 16 bit mode and 2000 in 12 bit mode.

 

For my project, I need very fast sampling rate, at least 0.1 Msps, preferably 1 Msps. The processor doesn't have to do anything during sampling. Even the sampled value conversion can be done later. This should be feasible in STM32 microprocessors but I had been unable to do so.

 

Any help or guidance on what I could be doing wrong or what I can improve would be very appreciated. Thank you.

 

14 REPLIES 14

An analyzer system -- for ... audio ? mini-dso ? or what ?

If you feel a post has answered your question, please click "Accept as Solution".
Bob S
Principal

Check the return value from HAL_ADC_PollForConversion().  I bet you get HAL_TIMEOUT given that it takes approx 1 sec to return and you pass "1000" as the timeout parameter.  If so, that implies the ADC isn't properly configured/started.

TDK
Guru

@Bob S almost certainly has the correct idea here. A bit suspicious that your timeout value is also how long it takes, isn't it?

Note that you need to calibrate the ADC before using it. Again, going off of examples may help. Here is one for ADC polling.

https://github.com/STMicroelectronics/STM32CubeH7/blob/96dd7e5b69d2b10406ac3f358e44b14cececa611/Projects/NUCLEO-H743ZI/Examples/ADC/ADC_RegularConversion_Polling/Src/main.c

 

If you feel a post has answered your question, please click "Accept as Solution".

Mini dsp

@Bob SThanks a lot. That is something I did not consider.

@TDKI think I've figured out the problem. It was the overrun behavior. CubeMX defaults it to preserved and I didn't change it. Then in debug mode, saw that the first few conversions happen in 2~3 us with return value as 0. Then it starts failing with return value to 3 (HAL_TIMEOUT). Changing overrun behavior to overwritten solved this problem. Now, it shows consistent 2~3 us sampling time. I can work with this. I have yet to try the DMA sample code you provided. Similar code didn't work for my case previously but I will try again.