Skip to main content
Associate II
October 15, 2024
Solved

HAL_Delay() inaccuracy

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!

This topic has been closed for replies.
Tesla DeLorean
Tesla DeLoreanBest answer
Guru
October 15, 2024

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 (See Profile) Up vote any posts that you find helpful, it shows what's working..

15 replies

bnsAuthor
Associate II
October 15, 2024

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

 

mƎALLEm
ST Technical Moderator
October 15, 2024

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 "Best answer" on the reply which solved your issue or answered your question.
Tesla DeLorean
Guru
October 15, 2024

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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
bnsAuthor
Associate II
October 15, 2024

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?

Tesla DeLorean
Tesla DeLoreanBest answer
Guru
October 15, 2024

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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
bnsAuthor
Associate II
October 15, 2024

Hi @mƎALLEm, 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

 

mƎALLEm
ST Technical Moderator
October 15, 2024

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 "Best answer" on the reply which solved your issue or answered your question.
bnsAuthor
Associate II
October 15, 2024

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

 

LCE
Principal III
October 15, 2024

Yeah, using the internal RC oscillator for timing measurements is like using an old mechanical wrist watch for a 100 m sprint... ;)