Library 03- STM32F4 system clock and delay functions

In first tutorial about discovery board we were blinking led. But I said nothing about system clock speed. In while loop we just use

for some delay, to actually see how led was blinking. We didn’t know at which clock speed our processors work and for first time, I think you didn’t even ask yourself.

May 26, 2015

A new version, 2.4 was just released. It features custom timers in library.

Custom timers are a way of having some tasks which have to be called periodically in “strange” timer intervals, like one task each 100ms, another each 107ms, third each 123ms and so on.

The way this works is that each time delay timer makes 1ms interrupt, interrupt handler checks for all created software “timers”. If their value, which is decreased in this systick handler reaches zero, callback function is called for user.

Timers allows custom features like custom reload value when callbacks happen and auto reload value is possible too. Auto reload feature means that when timer reaches zero, then timer will begin counting at start value if auto reload is enabled.

If auto reload is not enabled, when timer reaches zero, callback is called and timer become disabled. To start it back, you have to manually enable it.

Look for all functions in library or API documentation for STM32F4xx libraries provided from me.

November 28, 2014

From this moment, there is new delay system. First system used Systick timer to make an interrupts every 1us. This allows us great accuracy in microseconds but not so nice for processor and interrupts. Also, Systick can be used for RTOS and then it become incompatible for my delay.

For that purpose, lib has been changes. now you have 2 options for delay:

  • Systick timer
  • Custom (peripheral) timer

With Systick timer, there is 1ms interrupt (not 1us anymore) for counting time and for 1us delay there is just simple variable based counter (not so accurate). If you need Systick timer for RTOS (or anything else) then you can enable any timer on your MCU for delay. To activate custom timer, open defines.h project file and add lines below:

In case above, TIM2 is used, but if you want your custom timer (TIM6 or TIM7, or anything) you can just replace number “2” with any custom number for your timer available in F4xx MCU.

This timer will also make an interrupts every 1ms but for microseconds delay, there will be better accuracy because delay just count timer’s ticks for proper value. For that purpose, you also need some additional libs:

  • CMSIS
    • STM32F4xx TIM
    • MISC
  • TM
    • TM TIMER PROPERTIES

GCC sucks!

It’s nice that is is free, but code compiled is totally different from ARM compiler (in Keil). So I suggest you, that you enable your timer for delay (Instead of Systick timer), otherwise your delay will not be accurate and you will have problems.

How to enable delay with custom timer is described above!

PS: If you are using ARM Compiler (Keil uVision) then you don’t need to use peripheral timer if you don’t want to.

Libraries where you might (not needed to) have problems if you are using ARM-GCC (Coocox, etc) compiler and variable-based delay for microseconds:

  • OneWire
    • Devices not recognized
  • DS18B20
    • Devices not recognized
  • HC-SR04
    • Invalid measured distance
  • AM2301
    • Invalid data
  • There might be also somewhere..

Up to 180MHz core clock speed

STM32F429 can go up to 180MHz. It has PLL (Phase-Locked Loop) inside to increase frequency from 8MHz external crystal which is on board. I will describe how you do this, step by step.

PS: On Clock speeds is a great tutorial how to do it with ST’s excel clock configuration tool, but this tool does not support frequencies larger than 168MHz, so we will do it manually.

STEP 1: Open your project file stm32f4xx.h and find code below (it should start at line 91):

Change it to:

STEP 2: Open your project file system_stm32f4xx.c and find (you can have other numbers, code should start at line 154):

Formula for system frequency is:

In our case (we want 180MHz) we will set these defines to:

These will give us exactly 180MHz.

STEP 3: In the same file, find (line 174)

and change it to

STEP 4: In file startup_stm32f4xx.c uncomment line below (line 143):

to

STEP 5: On top of main() function add this line:

That’s it, your system now works at 180MHz.

Precise delay

Microcontroller has Systick timer, which can be configured as interrupt generator every X ticks of core clock. In my delay library I set timer to interrupt every 1us. This is every 180 clock ticks.

Library dependencies

  • CMSIS
    • STM32F4xx
    • STM32F4xx RCC
  • TM
    • defines.h

How this works

When you use delay function, you set number of microseconds to delay. Systick timer decrease variable everytime interrupt is called. When timing variable is zero, delay has finished.

First, you have to initialize Systick timer (inside is code for set 180MHz core clock).

There are 2 functions to use with delay:

Functions and enumerations

Example

But sometimes you don’t want to waste some time for doing nothing, but you want toggle led every 500ms and send data to usart terminal together. In this case, you can do something like this:

Logic analyzer result for 500ms delay.

Result

I connected my logic analyzer to green led’s pin and result is on left.

Project is available on Github, download library below.

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!
  • mtnsch .

    Hello, first of all thank you very much for sharing your work.
    My question is if I change the clock settings to use Delay. I have a STM32F4-Discovery.

    Regards.

    • Majerle Tilen

      Hi.

      Yes, you can change your system clock, and delay will still work.
      Delay takes SystemCoreClock variable, which is set in system_stm32f4xx.c file.

      • mtnsch .

        Hello, I use the delay without touching any parameter of the 32F4-Discovery clock, but when use delayms(500), the delay lasts about 4 seconds. Which may be the problem?
        Regards.

        • Majerle Tilen

          If you don’t change anything, then system works like you have 25MHz crystal connected.

          • mtnsch .

            I understand, but, what frequency value should be set to work properly delyms ()?
            Thank you.

        • Majerle Tilen

          Any frequency. Just make sure, that SystemCoreClock matches your real frequency.

  • Syrer

    Nice Work, I’m checking your tutorials and librarys one for one. I can not believe i wasted the couple of weeks trying to understand the HAL-Library!!
    Since your delay Library uses the HSE and the max. PLL-frequency, i assume they wont work without modification on my Nucleo STM32F411. I don’t like delays anyway, and thanx for the tutorial and explantaion! keep going 🙂

    • If you have set correct pll settings then delays will work.
      If you use gcc, then I suggest you that use delay tlwith one of timers available.

      My examples on github expects f411 nucleo board on internal rc crystal and f401nucleo on external 8mhz crystal.

      • Syrer

        I see, u did it like that. Well i didnt try it really, that was just an assumption. the following values with the formula above should give a SystemCoreClock frequency of 100MHz, and it does, but i didnt check it on the osci:
        HSI_Value: 16 MHz
        PLL_M: 16
        PLL_N: 400
        PLL_P: 4

        Nucleo STM32F411 & Keil uvision 5.13 🙂

  • bibliognost

    This may be a dumb question, but I can’t figure out (for the
    more advanced projects) which files to add to my project. I
    can’t afford uVision, so am using CooCox to build and test
    the apps, which I run on an STM32F429 Discovery board. I
    create a new project for the STM32F407 CPU. Then I go in and
    replace every file created by the wizard with a like-named
    file from Tilen’s download package for CooCox.

    In the first (Default) project, your explanation worked
    perfectly. In the second (Led and button), I was able to
    guess which files I needed and get it to work.

    But in the third project (Delay) this is not working. Is
    there some general principle that I am missing?

    Thanks.

    • Hello,

      well for delay library exactly, you can see on my post “Dependencies” section.
      Under CMSIS you need files which are there. In this case, you need these files:

      stm32f4xx.h
      stm32f4xx_rcc.h
      stm32f4xx_rcc.h

      Now, “TM” part. This library does not require any additional my libraries, but you can add any if you need in your project, of course.

      To run this example, you will also need TM DISCO library.

  • Ray

    Hi,

    I have tried using TIM2 instead of Systick (I wish to use RTOS). Have followed your instructions above but I get the following….

    Build target ‘STM32F429-Discovery’

    assembling startup_stm32f429_439xx.s…

    compiling tm_stm32f4_delay.c…

    linking…

    .TargetsSTM32F429_Discoveryproject.axf: Error: L6218E: Undefined symbol TIM_TimeBaseInit (referred from tm_stm32f4_delay.o).

    .TargetsSTM32F429_Discoveryproject.axf: Error: L6218E: Undefined symbol TM_TIMER_PROPERTIES_EnableClock (referred from tm_stm32f4_delay.o).

    .TargetsSTM32F429_Discoveryproject.axf: Error: L6218E: Undefined symbol TM_TIMER_PROPERTIES_GenerateDataForWorkingFrequency (referred from tm_stm32f4_delay.o).

    .TargetsSTM32F429_Discoveryproject.axf: Error: L6218E: Undefined symbol TM_TIMER_PROPERTIES_GetTimerProperties (referred from tm_stm32f4_delay.o).

    Not enough information to list image symbols.

    Finished: 1 information, 0 warning and 4 error messages.

    “.TargetsSTM32F429_Discoveryproject.axf” – 4 Error(s), 0 Warning(s).

    Target not created.

    Build Time Elapsed: 00:00:07

    Can you help please ?

    Thanks.

    • You have to add STM32F4xx TIM library to project.
      And some other libs.

      • Ray

        Thanks for your help, it’s working now – I needed tm_stm32f4_timer_properties.c as well. Apologies for not using Pastebin, just noticed it !

        I have a question about your ILI9341 library, but I will post on on correct page.

        • Check my PWM library. There is link to library you need under dependencies section.

  • Jura

    Hey m8,

    I am working with stm32f429-disco with BMP085 temp and pressure sensor. I used your I2C lib and it’s working fine but now I have problem with delay. In between reading I need to have 4.5ms delay. I used your delay lib and tried it with leds. It’s working fine first few iterations. But in Command window it gives me output: “Cannot access memory” and “Internal command error” and few secs after “Debugger-Cortex-M Error” window pops up where it writes: “Cannot access target. Shutting down debug connection.” Here is my code: http://pastebin.com/yb42RA8U

    Thanks

    • Where is your read function call?
      if it is from interrupt, then delay does not work properly, because it waits for systick interrupts. But systick interrupt can’t happen if another interrupt is active. Well, it can, if you have priority group selected other than 0.
      I will edit my delay library which will support that also. It will be updated soon.

      • Jura

        Hey, thanks for reply. I have already used timers for that so I apologize for bothering.

        BTW I have tried your code for timer2

        #define TM_DELAY_TIM TIM2
        #define TM_DELAY_TIM_IRQ TIM2_IRQn
        #define TM_DELAY_TIM_IRQ_HANDLER TIM2_IRQHandler

        but as it compiled it gave me error that TIMx is undefined.

        It’s in tm_stm32f4_delay.c line 162 and 174. So I have just replaced TIMx with TIM2 and it’s working fine. If you are interested in code or if anyone is working with BMP085 here’s link to my repo https://github.com/ijuresa/Zavrsni-rad

  • Rohit

    Hello,

    I am working with stm32f429i-disco discovery board and i cant get the delay working.
    I always get a error of 1 second in the delay(the delay is off by 1 sec).
    how do i fix it?
    i am using uvision5 with std peripheral drivers.
    i have set the pll parameters.

    • How do you use function?

      • Rohit

        delay(1000) for 1000ms delay

        • I would like to see your code how you use it with initialization included.

          Also, for ms delay, use Delayms.

          • Rohit

            I got it to work. Thank you.

          • Solo

            Hello Rohit,
            I have the same error .. may I take a look to you delay function after working

  • Eko

    Hello

    why there is an error like this?

    error: ‘RCC_HSE_ON’ undeclared (first use in this function)

    • You did not include stm32f4xx.h file.

      • Eko

        ALL libraries that I’ve entered, and after I check in stm32f4xx.h file, there was no RCC_HSE_ON function. I did not alter the existing CMSIS coocox. whether it had something to do with the version CMSIS used?

  • Tony

    hey,Tilen
    Another nice job!!! And I’m trying your tutorial here . But I can’t find file ‘startup_stm32f4xx.c’, is there any impact when without this.I guess you use old library.

    • You can skip this part if you don’t have file. It is not necessary in newer versions.

      • Tony

        Okay, Thx and best regards

  • Leiter

    How do I tune the library for 168MHz instead of 180?

  • Rodrigo Andrés Ayala Santillán

    Hello… please.. help me… I need to do a PWM of variable frequency and variable duty cycle. How can I do it????

  • Faisal Sya’bani

    Hello, I want to use your delay library. But always sign “syntax error” in those function

    static __INLINE void Delay(uint32_t micros)

    and

    static __INLINE void Delayms(uint32_t millis)

    I am using STM32F401RE with external clock (84MHz), then Cocox as my coide. What should I do Mr. Tilen? the delay doesnt work after all.