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.

 

1 ACCEPTED SOLUTION

Accepted Solutions
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".

View solution in original post

14 REPLIES 14
rakib2023
Associate III

Additionally, since I can't edit the post, if there is any available working sample code for a different board (nucleo, eval or disco) for this particular application, that would also be very appreciated. I don't necessarily have to use H7 series, I can use other boards if it works better or easier.

TDK
Guru

> 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.

Those values are consistent with ~0 V when in differential mode. (32768 and 2048). (Although "no input/floating" and "0V" are not the same.)

Polling for conversion is not practical at 1 Msps. Use HAL_ADC_DMA_Start, put many values into a buffer, and process them periodically on the half- and full-complete interrupt callbacks.

See the ADC_DMA_Transfer examples.

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

 

As a side note, I want to make sure you're aware that in even in differential mode both inputs must be between 0 V and VREF+.

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

Hi,

>I don't necessarily have to use H7 series, I can use other boards if it works better or easier.

So why you choose a super-complicated-hi-speed-dual-core-cpu ? to make it more difficult ? :)

What boards you can use ?  (maybe :  nucleo ... F303 ? )

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

My initial attempt was to use DMA, of course. But I could not get DMA working at all, even by following official sample codes. From what I gathered, H7 series DMA seems to have some complication. I will try the code you provided. I know that 1 Msps is not realistic without DMA but I will take 100 Ksps if it can be done with poll or interrupt method. But measuring the time shows that either way it's roughly 1~3 sample/s max speed which seems unusually low. Any reason why this might be happening?

Initially, I had plans to add some computation in the MCU but now I will take anything as long as I get a high-speed ADC working. I am ordering F4 and F7 series nucleo. I will try them separately. I would still prefer to use H7 if I can get the ADC working right since I can offload a good amount of computation to MCU.

Probably your code has a ton of overhead and/or isn't measuring the duration correctly. Show your code.

There's no way an ADC conversion is taking an entire second or even hundreds of ms.

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

No big problem with a H7 cpu also - just more complex to set up everything.

STM32H747I-DISCO  has display also... What you wanna build ?

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

Just this after all the initialization. Nothing else, not even in the second CPU. This gives roughly 996000 in "dur" which is about 1 second.

uint32_t ADC_result = 0;
uint8_t message[32];
uint32_t start = 0, end = 0;
uint32_t dur = 0;

HAL_TIM_Base_Start(&htim2);
HAL_ADC_Start(&hadc1);

while (1)
{
    start = TIM2->CNT;
    HAL_ADC_PollForConversion(&hadc1, 1000);
    ADC_result = HAL_ADC_GetValue(&hadc1);
    end = TIM2->CNT;
    dur = end-start;
    sprintf(message, "%lu in %lu\r\n", ADC_result, dur);
    HAL_UART_Transmit(&huart1, message, strlen(message), 1000);
    HAL_Delay(1000);
}

 

An analyzer system, preferably with a GUI. The plan was to build it as a standalone analyzer and that's why I wanted two CPUs, one to sample and convert analog signal and one to handle computation and GUI.