Precise delay with counter

If you work at high speed, as STM32F4 devices do (84MHz or more) then this tutorial is not right for you. But, you are able to descrease system speed to any frequency basicly you want.

If you want to use delay with systick down timer, look at my library here.

You can use great solution, Systick timer to make an interrups for you. But you can also decrease speed to let’s say 42Mhz, and that systick every 42ticks checks for variable in interrupt handler and increase/decrease it if neccessary, that can take up to 10cycles. In practise, that’s the same if we have 32MHz clock instead of 42MHz.

I was making some experiments with delay functions with only one variable (counter) and delay in simple way like

but this method is not accuracy, because this works with system ticks and depends on core clock. But how we can make a delay like this, to be independent of core clock?

This can be done, of course. We need to make some mathematics at the beginning and then we are ready.

First, we have to know, how many ticks our while loop actually  takes. I create a simple program with while loop inside, and start debugger. I got result, that while loop “while (variable–);” takes exactly 4 clock cycles. We are getting closer.

Let’s say, our system clock is 180000000 Hz (STM32F429 Discovery). If we want to make a simple 1us delay, then we have to count 180 ticks to get this. If one while loop takes 4 cycles, then we have to divide our counter by 4.

This will be great, if we are making this inside program. But, calculating takes some time (with floating point unit activated only 1 cycle), then calling function and returning back also takes some time. My debugger says that I have to always substract 10cycles. I make some tests with different delay numbers and results are below.

Test code:

In example above is delay fixed to 1000us (1ms), but I tried different values. I made test on STM32F429 Discovery board (180MHz), FPU activated.

Delay I wanted Ticks I got @ 180MHz Ticks I got @ 168MHz Ticks I got @ 84MHz
50us 9010 8410 4210
125us 22510 21010 10510
250us 45010 42010 21010
1000us 180010 168010 84010

So, always is “xxx10” at the end. If we assume that this is because of function calls and calculating, we can say that our equation is very simple. If we substract 10 from result, and divide that by number of delay we want, then we will see that we get exactly our system clock in MHz.

To calculate proper ticks for our delay, we first have to get ticks from device. This can be simply done with RCC_GetClocksFreq in CMSIS libraries.

In function below, we divide with 4M. That’s because 4 is from while loop takes 4cycles and if we want to get 1us, we have to divide with 1M. This multiplier we use then in our pre calculations for delay.

That’s all. We are ready to make an example. I put it to oscilloscope and results were really great.

For that example, my DISCO library will be great for you. Download below.

Icon
TM STM32F4 DISCO Library

Leds and buttons for Discovery boards

tilz0R

Owner of this site. Also electronic enthusiasts, web developer, 3D printer fan, handball player and more. Big fan of STM32F4 devices. In anticipation of the new Discovery board for STM32F7 lines.

You may also like...

Read before commenting!

Before you make a new comment, make sure you agree with things listed below:

  • - Read post to make sure if it is already posted what you are asking for,
  • - Make sure you have the latest version of libraries used in your project,
  • - Make a clean and grammatically correct written message,
  • - Report as many details as possible, including what have you done so far,
  • - Do NOT post any code here. Use Pastebin,
  • - Do NOT post any error codes here. Use Pastebin,
  • - Specify STM32Fxxx family and used Discovery/EVAL/Nucleo or custom made board,
  • - Make sure your clock is set correct for PLL,
  • - If you are using my HAL drivers, please check this post how to start.
Comment will be deleted on breaking these rules without notification!
  • LeMoussel

    With, CooCox Ide, in debug mode, how do you find that while loop “while (variable–);” takes exactly 4 clock cycles ?

    Thanks for your help.

  • Set variable to let’s say 1000 and look cycles before function call and after function is done. Than substract this two values and divide with variable. You will get result after substract 4010. After you divide with 1000, 4.01 will be result. This 10comes from function calls and variable setting and multipling.

  • Nguyen Master

    Hi Tilen!
    Im writing a delay example with timer interrupt, but i don’t know reload a new value for timer in interrupts subroutine?
    Thanks!

    void TIM2_IRQHandler()
    {
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    GPIO_ToggleBits(GPIOD, GPIO_Pin_12);
    }
    // How to update new value for timer2?
    }

    • Nguyen Master

      I found it already.
      TIM_SetAutoreload(TIM2, timer2); //That all
      Thanks all !

  • Pingback: All STM32F4 tutorials - STM32F4 Discovery()