cancel
Showing results for 
Search instead for 
Did you mean: 

Frequency limitation when trying to generate a 2us period on a Timerfor the STM32F7.

ConfusedContrarian
Associate III

Hi, I'm trying to generate a 500KHz counter on TIM1 on the STM32F7 to trigger an ADC conversion and I'm currently having issues as it seems to top out at 360KHz. I'm toggling a GPIO pin with a scope to the input and simply changing the Period on the timer to see what's happening.

Here's my current code:

With a period of 539, I get 200Khz as expected:

0690X000009YfWCQA0.png

With a period of 239, I get around 300kHz

0690X000009YfW2QAK.png

With a peroid of 215, I get around 330 kHz instead of the expected 500Khz.

With a period of 108, I get a frequency of around 369Khz:

0690X000009YfVYQA0.png

I'm using CubeMX to generate my project files and I initialise my timer like this:

static void MX_TIM1_Init(void)
{
 
  /* USER CODE BEGIN TIM1_Init 0 */
 
  /* USER CODE END TIM1_Init 0 */
 
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
 
  /* USER CODE BEGIN TIM1_Init 1 */
 
  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 0;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 108;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC1;
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_OC1REF;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */
 
  /* USER CODE END TIM1_Init 2 */
 
}

I start the timer in interrupt mode:

if(HAL_TIM_Base_Start_IT(&htim1) != HAL_OK)
		{
			Error_Handler();
		}

I then toggle a GPIO Pin When Period has elapsed:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	
	if(htim->Instance == TIM1)
	{
		
		HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
		 
	}
}

I've tried changing the speed of the GPIO pin:

  /*Configure GPIO pin : PG6 */
  GPIO_InitStruct.Pin = GPIO_PIN_6;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

but this doesn't seem to make any difference. Can someone please help shed some light on this?

2 REPLIES 2

The TIM provide direct methods to toggling signals and triggering ADC, suggest you use those rather than determine the saturation point of the core with interrupt entry/exit and multi-layered overhead added by HAL.

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

Thanks for the reply, Clive. That's currently what I'm doing. I'm using ADC_EXTERNALTRIGCONV_T1_TRGO on Timer 1 to trigger a conversion on the ADC but I would like to reliably determine what this frequency is to know my sampling rate. I guess, I could just compute the FFT and do a back calculation to determine the sampling frequency. What is the best way to check the ADC is starting a conversion on the correct timings without using interrupts? Would toggling a GPIO on the

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

work as well?