cancel
Showing results for 
Search instead for 
Did you mean: 

ADC timing details, STM32H745ZI

cmlo
Associate

Belows follow a description of my problem. But the question to keep in mind is: When does the ADC sample, when triggered by a timer?

We are using a timer (internal timer; timer 2) to trigger the ADC (direct channel). We use the following functions to initialize the ADC and timer:

void MX_TIM2_Init(void)
{
 
  /* USER CODE BEGIN TIM2_Init 0 */
 
  /* USER CODE END TIM2_Init 0 */
 
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
 
  /* USER CODE BEGIN TIM2_Init 1 */
 
  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 2;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 300;
  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();
  }
  if (HAL_TIM_OC_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_TOGGLE;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */
 
  /* USER CODE END TIM2_Init 2 */
  HAL_TIM_MspPostInit(&htim2);
}
 
void MX_ADC3_Init(void)
{
 
  /* USER CODE BEGIN ADC3_Init 0 */
 
  /* USER CODE END ADC3_Init 0 */
 
  ADC_ChannelConfTypeDef sConfig = {0};
 
  /* USER CODE BEGIN ADC3_Init 1 */
 
  /* USER CODE END ADC3_Init 1 */
  /** Common config 
  */
  hadc3.Instance = ADC3;
  hadc3.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc3.Init.Resolution = ADC_RESOLUTION_16B;
  hadc3.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc3.Init.LowPowerAutoWait = DISABLE;
  hadc3.Init.ContinuousConvMode = DISABLE;
  hadc3.Init.NbrOfConversion = 1;
  hadc3.Init.DiscontinuousConvMode = DISABLE;
  hadc3.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T2_CC2;
  hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc3.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
  hadc3.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc3.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
  hadc3.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc3) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel 
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC3_Init 2 */
 
  /* USER CODE END ADC3_Init 2 */
 
}

We want to know exactly when the ADC is performing the sampling, so we raise one GPIO pin with the timer, and another GPIO pin when the ADC conversion is done. See the HAL_ADC_ConvCpltCallback() function:

/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hadc);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET);
}

As a side note, we also tried to enable another interrupt: EndOfSamplingCallback(). A note is written about this in the stm32h7xx_hal.c file, on line 1708:

By default, HAL_ADC_Start_IT() does not enable the End Of Sampling interruption. If required (e.g. in case of oversampling with trigger mode), the user must:

 1. first clear the EOSMP flag if set with macro __HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_EOSMP)

 2. then enable the EOSMP interrupt with macro __HAL_ADC_ENABLE_IT(hadc, ADC_IT_EOSMP) before calling HAL_ADC_Start_IT().

So we just put the following lines of code right before the HAL_ADC_Start_IT(&hadc3); line in our main.c file:

__HAL_ADC_CLEAR_FLAG(&hadc3, ADC_FLAG_EOSMP);

 __HAL_ADC_ENABLE_IT(&hadc3, ADC_IT_EOSMP);

However, the interrupt seems to never be called.

The time difference between when both pins are raised (measured by a 200 MHz oscilloscope) should then be the complete sampling and conversion time of the ADC. In the table below you find some time differences for different ADC setups. Note that revision V (what we're using) divides the ADC clock by two, so what I get should be half of what I set -- see the STM32H7 - ADC document at https://www.st.com/resource/en/product_training/STM32H7-Analog-ADC_ADC.pdf

I've also tried to calculate what the sampling + conversion time should be from the datasheet (see page 184 -- 185 in the STM32H745ZI datasheet). The calculated values are also included in the table below.

  • f_ADC is ADC clock real in the table above.
  • t_s (sampling time) = sample cycles / f_ADC
  • t_conv (conversion time, including sampling time) = t_s + 0,5 + resolution / 2 

0690X00000BwGkoQAF.png

The Conversion time in the table above is thus the expected time difference, and the (Time difference - Conversion time) in the table is what we can not explain. My question is then: where does it come from?

Part of it might be blamed on the delay between when we set the GPIO to high, and when it actually becomes high. But since we have these delay on both cases, I guess it should cancel out?

I'm thinking that part of it might come from the delay between when the ADC was triggered by the timer and when the actual sampling begins. This might be related to the External trigger period (up to 10 / f_ADC according to the datasheet). But that just mounts to up to 0,27 -- 0,52 us.

Part of it might also be explained by that the minimum number of sampling periods seems to be 2,5 for f_ADC of 37 MHz for 16 bit resolution (top of table 96 in the datasheet).

Another reason might be that we're using the LQFP144 package. In the STM32H7 - ADC document (graph on page 11), it's shown that the samples per second / resolution is worse for the LQFP144 package than the BGA package (the numbers in the datasheet is for the BGA package). I'm assuming that this just means that the noise is higher for the LQFP144 package, thus reducing the number of usable (non-noisy) bits. Is that correct? Or does it in fact sample at a slower rate?

Am I doing anything wrong in my assumptions or calculations?

Thanks!

1 REPLY 1
RMcCa
Senior II

Ditch HAL and use the register interface and write your own ISRs. You could easily just be measuring the slop in the hal callback business.