2
\$\begingroup\$

On the net, I have found following function for delay in miliseconds for STM32F4 (Discovery board MCU:

void delay_us(const uint32_t us)
{
    us*=STM32_DELAY_US_MULT;

    /* fudge for function call overhead */
    //us--;
    asm volatile(" mov r0, %[us] \n\t"
                 "1: subs r0, #1 \n\t"
                 " bhi 1b \n\t"
                 :
                 : [us] "r" (us)
                 : "r0");
}

Inside this function, constant STM32_DELAY_US_MULT is used, but not declared and it does not compile, but this is not current problem. How does one get current STM32F4 clock and set this constant according to it? If I ask in another way, how do I write delay (milisecs) function for STM32F4 proc, that is clock independent?

\$\endgroup\$
2
\$\begingroup\$

You could use a timer or the RTC with sub-millisecond accuracy instead. These are a lot more versatile and prevents busy-waiting. They can also be easily configured as busy-waiting by adding an additional while loop when this is needed.

There are existing example code for what you want to achieve. This examples shows how to get the current system clock etc.

If you download: STM32F4 DSP and standard peripherals library

and navigate to:

STM32F4xx_DSP_StdPeriph_Lib_V1.2.0\Project\STM32F4xx_StdPeriph_Examples\SysTick\SysTick_Example\system_stm32f4xx.c

There is a function named: SystemCoreClockUpdate()

This function and the Doxygen style comments above will answer your question.

In my experience with STM32 it is that the standard peripherals library examples usually has the most answers when it comes to configuration. You can also watch the standard peripherals library examples for STM32F1, STM32F2, STM32F3 etc. as well. There are a lot of examples out there. Also try the Keil examples.

\$\endgroup\$
2
\$\begingroup\$

I've only used the STM32 series a little but can't think how it would be possible to make it totally clock independent. You could read the PLL settings but wouldn't have a way to know the crystal frequency without another time reference. There might be a few tricks I'm not aware of using things like the internal RC oscillator in the watchdog and other peripherals to provide that external reference but I'm not sure if it would be worth it and the accuracy wouldn't be as good as using a value calculated from the crystal frequency.

Personally I'd either read the family guide and calculate how many cycles the loop should take and calculate the constant from that if fairly high accuracy was required or otherwise just take a guess at the initial value and call with a fairly high value like 1000mS and measure with a scope how long it's really taking and adjust from there.

In your case you mentioned milliseconds (although above code mentions microseconds) so your constant would be fairly large so maybe you could use something like the following without introducing an unacceptable amount of error:

#define STM32_CLOCK_HZ 72000000UL
#define STM32_CYCLES_PER_LOOP 6 // This will need tweaking or calculating

void delay_ms(const uint32_t ms)
{
    ms *= STM32_CLOCK_HZ / 1000 / STM32_CYCLES_PER_LOOP;

    asm volatile(" mov r0, %[ms] \n\t"
             "1: subs r0, #1 \n\t"
             " bhi 1b \n\t"
             :
             : [ms] "r" (ms)
             : "r0");
}

At least then you have an easy to read / update constant for the real clock rate of the system.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.