2
\$\begingroup\$

My observed sampling rate is much lower than expected and I cannot understand why.


I have the discovery STM32L053C6 Discovery board and I want to use ADCs sampling. I started from the example STM32L053C8-Discovery/Examples/ADC/ADC_RegularConversion_Interrupt/ from STM32CubeL0. In main, I have the following ADC initialisation:

AdcHandle.Instance = ADC1;

AdcHandle.Init.OversamplingMode      = DISABLE;

AdcHandle.Init.ClockPrescaler        = ADC_CLOCK_SYNC_PCLK_DIV1;
AdcHandle.Init.LowPowerAutoPowerOff  = DISABLE;
AdcHandle.Init.LowPowerFrequencyMode = DISABLE;
AdcHandle.Init.LowPowerAutoWait      = DISABLE;

AdcHandle.Init.Resolution            = ADC_RESOLUTION_12B;
AdcHandle.Init.SamplingTime          = ADC_SAMPLETIME_7CYCLES_5;
AdcHandle.Init.ScanConvMode          = ADC_SCAN_DIRECTION_FORWARD;
AdcHandle.Init.DataAlign             = ADC_DATAALIGN_RIGHT;
AdcHandle.Init.ContinuousConvMode    = ENABLE;
AdcHandle.Init.DiscontinuousConvMode = DISABLE;
AdcHandle.Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_NONE;
AdcHandle.Init.EOCSelection          = ADC_EOC_SINGLE_CONV;
AdcHandle.Init.DMAContinuousRequests = DISABLE;

/* Initialize ADC peripheral according to the passed parameters */
if (HAL_ADC_Init(&AdcHandle) != HAL_OK)
{
  Error_Handler();
}


/* ### - 2 - Start calibration ############################################ */
if (HAL_ADCEx_Calibration_Start(&AdcHandle, ADC_SINGLE_ENDED) != HAL_OK)
{
  Error_Handler();
}

/* ### - 3 - Channel configuration ######################################## */
/* Select Channel 0 to be converted */
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 0;
if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
{
  Error_Handler();
}

/* ### - 4 - Start conversion in Interrupt mode ########################### */
if (HAL_ADC_Start_IT(&AdcHandle) != HAL_OK)
{
  Error_Handler();
}

And the call back as

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
  /* Get the converted value of regular channel */
  uwADCxConvertedValue = HAL_ADC_GetValue(AdcHandle);
  HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
}

I have the system clocks defined as

static void SystemClock_Config(void)
{
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;

  RCC_OscInitStruct.OscillatorType  = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState        = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLSource   = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLState    = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLMUL      = RCC_PLL_MUL4;
  RCC_OscInitStruct.PLL.PLLDIV      = RCC_PLL_DIV2;
   if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  RCC_ClkInitStruct.SYSCLKSource =  RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }
}

And the MSP init as

void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
  GPIO_InitTypeDef                 GPIO_InitStruct;

  /*##-1- Enable peripherals and GPIO Clocks #################################*/
  /* Enable GPIO clock ****************************************/
  __HAL_RCC_GPIOA_CLK_ENABLE();
  /* ADC1 Periph clock enable */
  __HAL_RCC_ADC1_CLK_ENABLE();

  /*##- 2- Configure peripheral GPIO #########################################*/
  /* ADC3 Channel8 GPIO pin configuration */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*##-3- Configure the NVIC #################################################*/
  /* NVIC configuration for ADC EOC interrupt */
  HAL_NVIC_SetPriority(ADC1_COMP_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(ADC1_COMP_IRQn);
}

What that configuration, I would expect the conversion time to be at about 1.3µs. However, the PB4 toggles every 11µs. Which means that I get a sampling rate slightly above 80kS/s.

The manual mentions sampling rates above 1MS/s. I am sure that I am missing something, but cannot see what that would be. Or should I use DMA modes to get to higher sampling rates?

\$\endgroup\$
5
  • \$\begingroup\$ I don't have the STM32L0 library code to hand, but if the libraries for the STM32F4 are anything to go by then the ADC interrupt handler might be fairly long, which could limit your sample rate if you're not using DMA. Take a look at your 32L0 version of HAL_ADC_IRQHandler() and maybe add a HAL_GPIO_WritePin(... GPIO_PIN_SET) at the start and HAL_GPIO_WritePin(... GPIO_PIN_RESET) at the end to see how much time it's taking. \$\endgroup\$
    – brhans
    Commented Jul 19, 2018 at 14:05
  • \$\begingroup\$ I'm inclined to agree with @brhans, you probably want to go with a DMA approach \$\endgroup\$
    – Ocanath
    Commented Jul 19, 2018 at 20:39
  • 1
    \$\begingroup\$ @brhans thanks for the suggestion. For the reccord, the HAL_ADC_IRQHandler() lasts for 10.4µs ! It is indeed where most of my time gets wasted. \$\endgroup\$ Commented Jul 20, 2018 at 9:59
  • \$\begingroup\$ @bilbo_pingouin about 340 clocks. As it is HAL - it is not too bad :). Consider the bare register approach. This hardware is very simple, and IMO initialization of those monstrous structs takes more time (in writing) the couple of lines of the registers code. I do it for many years. \$\endgroup\$ Commented Jul 20, 2018 at 23:23
  • \$\begingroup\$ @P_J, fair enough. I'll give it a try. I guess that will be the real solution there for me as I still like to have interupts on each conversion for my application. \$\endgroup\$ Commented Jul 23, 2018 at 4:50

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.