Skip to main content
Graduate
October 15, 2024
Solved

HAL_Delay() inaccuracy

  • October 15, 2024
  • 4 replies
  • 4239 views

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.
    Best answer by Tesla DeLorean

    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;
    }

    .  

    4 replies

    bnsAuthor
    Graduate
    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

     

    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?

    Graduate II
    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;

    bnsAuthor
    Graduate
    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?

    Graduate II
    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;
    }

    .  

    bnsAuthor
    Graduate
    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

     

    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.

    bnsAuthor
    Graduate
    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

     

    Graduate II
    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... ;)