STM32F407 Delay with SysTick

An important function in almost all MCU based application is the delay function.  When timing is essential in your application, you can’t live without a good delay function.  From my experience with 8-bit MCU’s, delay functions were always hard to implement if you wanted to get the timing correct.  Most of the time you could get it to work for one specific clock setting; but to get it to work for all clock frequencies it required quite some advanced programming in assembler.

Like all other ARM Cortex devices, with the STM32F4 we have a very nice 24-bit system timer (SysTick) that counts down from a reload value to zero.  The only things to remember is that it wraps when it reaches zero and that it doesn’t decrement when the processor is halted for debugging.  The SysTick functions can be found in the core_cm4.h header file when using CoIDE.  We only need the SysTick_Config to set the preload value and the SysTick_Handler interrupt function.

Writing good delay functions is very easy with SysTick.  Just preset the SysTick to very convenient value that would result in delays like 1 ms, 100 µs, 10 µs or 1 µs.  Choose a value that would suit your application; eg. if your timings are in the millisecond range, then take 100 µs or 1 ms.  In this case I’m going to use 1 µs to demonstrate the possible precision of delays with SysTick.  In my delay.c I provide a SysTick_Config method that initializes SysTick like this:

The SystemCoreClock variable is set the system-stm32f4xx.c file (a result of the ST Clock Configuration Tool) and equals the processor speed (SYSCLK).  With this configuration, the SysTick_Handler interrupt routine will be called every 1 µs.

To create more convenient timings, we need more user-friendly delay methods.  Thus we create a header file and a small library.

delay.h header:

delay.c library:

Now we have all files we need but the timer won’t work as we’re missing one part: the interrupt handler.  Notice the static __IO uint32 sysTickCounter in delay.c, this is the counter that steers the delay functions and needs to be decremented in the interrupt routine.  The interrupt can be located anywhere in your code, just find a convenient location and add:

Now some fun, let’s test the delay functions with the following program:

When started, the initial delay between the 4 cycling leds is 100 ms.  Thus each led should be ‘on’ for 100 ms and ‘off’ for 300 ms.  I checked the timing with a logic analyzer and I got the following result:STM32F4_Delay

The output shows clearly that the led is on for exactly 100 ms and stays off for also exactly 300 ms.

Tagged , , , . Bookmark the permalink.

16 Responses to STM32F407 Delay with SysTick

  1. conzarks says:

    your tutorials are great and very helpful. I’d like to know which Logic Analyzer you use and if you can recommend me one that can measure 250ns time delay.
    Thanks in advance.

    • PatrickPatrick says:

      I’m using the Open Logic Sniffer from Dangerous Prototypes. I was quite surprised about the performance of this little gadget. It has sample rate of 200MHz (5ns), so it should suit your needs very well. And it costs only 50 USD…
      Only drawback, is its software. I had quite a struggle to make it work under Windows. But now that I made it to work, I couldn’t live without it anymore…

  2. TechR says:

    Thanks! Well and neatly explained!

    Really helps 🙂

  3. Norma says:

    Hi! Your tutorial helped me a lot, as we are working with this uC in school and sometimes is hard to pay attention to all the details in class.
    So I prefer to study by my own.

    Greetings from IPN, México

  4. Groma says:

    Hi folks!

    I have a problem using delay time.
    Everytime i go into the delay loop, the systick interrupt does not appear anymore. So the uC goes into an infinite loop, because the SystickCounter value didn’t get decremented anymore.

    Does anyone faced a problem like this?

    Thanks for help 🙂

    • Hank says:

      Are you executing your delay loop in an ISR? That would cause this problem if the current ISR was higher priority than the SysTick interrupt.

      It is best to organize your code so that you do not do any delays in an ISR. If you absolutely must, you can use a calibrated busy loop rather than relying on an ISR to increment tick counts (or configure your interrupt priorities so that the tick interrupt is not held off by the interrupt you are processing.)

  5. Hank says:

    Hi Patrick, Thanks for posting this! I’ve been working mostly with the HAL libraries and am now doing some hobby programming on the STM32F429I-DISCO board and using the standard peripheral library. I was pretty surprised to find that the SysTick ISR had not been implemented by default and was also surprised by how easy it was to accomplish.

    My approach is to use an ISR that simply increments a counter and then use that with twos complement (unsigned) arithmetic for timing calculations. My preference is to check for elapsed time rather than delay as it accommodates more things at once but either model works.

    I did run into a difficulty with initial calibration (likely due to my confusion over what library init code needed to be executed when using the standard peripheral library.) I settled on the following for my configuration:

    void SysTick_Init(void) {
    *SystemFrequency/1000 1ms *
    *SystemFrequency/100000 10us *
    *SystemFrequency/1000000 1us *
    * from
    SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);

    • PatrickPatrick says:

      That calibration is a bit of a problem with all these ‘framework’. You’ll have to figure out what internal timing is used. Instead of going through the RCC_GetClocksFreq method, you could be using the SystemCoreClock system variable if you’re using the CooCox libraries. Your method will yield the same result however.
      Depends on what you’re developing, but probably you will need both methods. One where the controller is wasting CPU cycles as it has to wait for something and do nothing else (besides ISR’s). And the other one where you want to wait for something and don’t want to wait forever (eg. sending/receiving network packets).
      Anyway, thanks for letting me know that my post helped you out.

  6. Guru says:

    Hi Patrick,

    Currently I’m using STM32F400 Evaluation Board with STM32F407IG MCU. I have been using only 8 bit processors till date and therefore I’m new to this ARM processor. I have to run a stepper motor using this evaluation board and the stepper motor has a separate driver board also. I’m using uVision 5.0 IDE currently and this is also new to me.

    I want two delay functions for milliseconds and microseconds respectively. I searched a lot in the internet and couldnt figure out how to do it. Can you please help me in this regard??

    • PatrickPatrick says:

      Use the systick interrupt function to increment two counters, one for ms and one for us. Your delay functions should use these counters.
      But I think that configuring a systick on us level will be very hard for a 407 (not much time time left with a 168Mhz clock).

      • Guru says:

        Can you please explain if you have some free time, on how to do it with the HAL libraries?

        • Guru says:

          Patrick. Please?

          • PatrickPatrick says:

            Sorry was to busy these latest days. Unfortunately, I can’t help you with HAL, I abandoned these a very long time ago in favor or my own libraries.

    • uint32_t volatile count=0;
      void SysTick_Handler(void){

      void Delay_ms(uint32_t max,uint32_t start){
      count=start; //

  7. Dear, Sir. I am using TM4C123 mcu and I created delay 1000,000us or 1sec but it wasn’t absolutely 1sec. Does all ARM Cortex M3/M4 mcu have same “system Core Clock” frequency?

Leave a Reply

Your email address will not be published. Required fields are marked *

WordPress Anti Spam by WP-SpamShield