cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_Delay() inaccuracy

bns
Associate III

Hi folks,

I recently started my STM32 journey using a STM32WLE5JCxx (the LoRa-E5). After fighting with the SubGHz for a while, I managed to write a decent application, but I'm not completely familiar with all of the essentials yet.

Currently, I am using the `HAL_Delay()` function, but after some testing found that it is highly inaccurate. My code snippet:

 

  int i = 0;
  while(1) {
	  printf("%d\n", i++);
	  HAL_Delay(100000);
  }

 

The output I get (with the actual difference in milliseconds calculated afterwards):

 

13:26:41.925 > 0 
13:28:22.323 > 1 (+398)
13:30:02.318 > 2 (-5)
13:31:42.309 > 3 (-9)
13:33:22.290 > 4 (-19)
13:35:02.236 > 5 (-54)
13:36:42.118 > 6 (-118)
13:38:21.961 > 7 (-157)
13:40:01.796 > 8 (-165)
13:41:41.623 > 9 (-173)
13:43:21.431 > 10 (-192)

 

This means that on every 100 seconds, the clock drifts anywhere from -200ms to +400ms. A fixed value drift might've been OK, but this is quite unworkable.

I did read that `HAL_Delay()` might not be the most accurate clock source, but I am unsure how to implement a 'simple' delay-function. If someone could help me with a snippet or point to a place where I can find explanation on how to make an accurate delay myself, that would be very much appreciated.

Cheers!

1 ACCEPTED SOLUTION

Accepted Solutions

I think your clock source has offset. If you can use the TCXO that would likely be a lot tighter/consistent

I'd free run the counter, not continually reset it.

At that point the time line becomes more consistent and more impervious to other stuff going on, like UART output.

I'd delta the time measurement, and advance the start / check-point reference

int i = 0;
uint32_t delay = 100000;
uint32_t start = TIM2->CNT;
while(1) {
  printf("%d\n", i++);
  while((TIM2->CNT - start) < delay);
  start += delay;
}

.  

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

View solution in original post

15 REPLIES 15
bns
Associate III

For completeness sake, here's a message of the Clock configuration (the bottom half outside the picture is all greyed out and as per default).

bns_0-1728993578642.png

 

Perhaps use TIM2, clocking at 1 MHz to get 1 us resolution within a few us.

Or use a long term time base and advance the start point you're trying to hit.

ie

while((current - start) < delayticks);

start += delayticks;

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

Hi @Tesla DeLorean , thank you for your answer.
I tried the following:

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 47999;
  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();
  }
void delay_ms(uint32_t delay) {
	__HAL_TIM_SET_COUNTER(&htim2, 0);
	while (__HAL_TIM_GET_COUNTER(&htim2) < delay) {
        // wait for the timer to count the required time
    }
}
int i = 0;
  while(1) {
	  printf("%d\n", i++);
	  delay_ms(100000);
  }

Unfortunately however, I still get poor accuracy:

14:57:15.909 > 0
14:58:55.844 > 1
15:00:35.777 > 2
15:02:15.670 > 3
15:03:55.545 > 4
15:05:35.432 > 5
15:07:15.332 > 6

Do you see any obvious mistakes, or do you have any further suggestions?

Hello @bns  and welcome to the community,


@bns wrote:

bns_0-1728993578642.png

 


+ You are using an internal source of Clock based on RC cell not a precise clock source as Crystal / HSE.

SofLit_0-1728998167949.png

Did you try with an external crystal?

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
bns
Associate III

Hi @SofLit, thank you very much for your response!
Sorry for my obliviousness - how would I configure this? I do now see the options for the HSE/LSE in the System Core / RCC tab. What values would I need to set their options to, for the LoRa-E5? Would I also set it to Master Clock Output?

bns_0-1728999073151.png

 

You need to set Crystal/Ceramic Resonator. But you need definitely having an external Crystal connected to OSC_IN and OSC_OUT pins.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
bns
Associate III

According to the Seeed wiki, the LoRa-E5 has a TCXO connected at 32MHz. After configuring that as the HSE source, I would like to use it as the clock source.
Would the following Clock configuration make sense, or would it likely result in troubles? My apologies - I don't really have a feeling for it yet, besides knowing that I can't really go below ~20MHz for CPU/SPI.

bns_0-1728999658767.png

 


@bns wrote:

Would the following Clock configuration make sense, or would it likely result in troubles? My apologies - I don't really have a feeling for it yet, besides knowing that I can't really go below ~20MHz for CPU/SPI.

bns_0-1728999658767.png

 


I don't know about that "TXCO" clock source.

To me the configuration is good but:

You need to ensure that this TXCO is available and generating a precise clock.

Otherwise, you need an external crystal with the config I mentioned above.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Primary try go back to start and dont check Delay with printf. Printf is handled by fifos and next irq/os management, then generate random delays. Simply toggle GPIO pin is perfect for timing check.