Technical Article

What Is Clock Frequency? Embedded Firmware Tips and Tricks

September 17, 2019 by Robert Keim

You can simplify MCU development if you make sure that your firmware has access to a numerical value that corresponds to the processor frequency.

When you’re working with computers and high-powered microprocessors, you may not have much direct interaction with the frequency of the clock that drives the processor core. These systems are quite complex, and there are layers of software that separate you from low-level hardware details.

However, electrical engineers often have the privilege of working with processors that are delightfully slow and even more delightfully straightforward—25 MHz is usually more than enough processing bandwidth, and the actual digital hardware is directly accessible in, and relevant to, the code that we write.

In this article, we’ll discuss one of the most important hardware details that embedded designers think about: the frequency of the signal that serves as the timebase for the microcontroller’s CPU.

 

Why Is Clock Frequency Important?

Well, yes, a higher clock frequency means a faster processor, and in many applications faster is better. But that’s not what I mean. What I’m really asking is, Why does clock frequency figure prominently in a wide variety of embedded-firmware design tasks?

The essential concept here is that clock frequency goes far beyond CPU speed. Microcontrollers are special because they have peripherals: analog-to-digital converters, digital-to-analog converters, pulse-width modulators, timers, I2C modules, and so forth.

 

 

All these peripherals don’t come with individual clock-signal inputs; rather, they are usually driven by a clock that is derived from the system clock (which could also be called the master clock, or the core clock, or various other names that are equally suitable).

Thus, the sampling rate of your ADC, the baud rate of your UART interface, the rate at which your timer counts up, and various other critical functional parameters can be directly tied to your system clock frequency.

 

Dealing with Different Frequencies

Things brings us to another question: Why should the firmware have direct access to a defined constant or variable that corresponds to the current clock frequency? Because this will make your code cleaner, easier to write, and more versatile.

 

Using a Constant

Let’s consider the first option, i.e., using a preprocessor definition as a constant value that is equal to the system-clock frequency in cycles per second. For example:

 

#define SYSCLK_FREQ 25000000

This allows you to write code that is compatible with many different clock frequencies, because peripheral configuration or timing functions that depend on the system clock can be calculated in the code using the constant SYSCLK_FREQ. In other words, if your system clock is 16 MHz and you need to know the divider value that would produce a 1 MHz clock, you don’t write the code like this:

 

ClkDiv_Value = 16;

Instead, you do this:

 

ClkDiv_Value = SYSCLK_FREQ/1000000;

The first coding approach works perfectly well—until you decide to change your clock, at which point you’ll need to track down every single statement that depends on the system-clock frequency and insert a new value. This can be a major headache and a source of elusive bugs. With the second approach, all you need to do is change the value that is attached to the constant SYSCLK_FREQ. 

 

Using a Variable

Making your code easily adaptable to new clock conditions is an important goal. First, it ensures that you can conveniently experiment with different frequencies; a common objective here is to reduce power consumption by finding the slowest clock that allows the MCU to maintain adequate performance. Second, it increases code reusability and thereby does much to simplify your life and make your development efforts more productive.

 

This diagram conveys the concept of code reusability, specifically with regard to function use in embedded firmware.

 

However, a #define constant cannot be modified while the program is running, and this is why you might want to use a variable instead of a constant.

It is possible, and sometimes desirable, to change the system clock while a microcontroller-based device is operational. This can be accomplished by modifying the frequency of a variable-frequency oscillator or by reconfiguring the MCU’s clocking hardware, and the primary motivation for doing this (at least in my experience) is energy efficiency: lower clock frequencies lead to lower power consumption. If you write code that dynamically adjusts the clock frequency in response to operational states or remaining battery life, you could include a SysClk_Freq variable whose value is changed whenever the clock frequency is changed. For example:

 

unsigned long SysClk_Freq = 16000000;

…

if(MCU_STATE == NORMAL)

{

Config_Normal();

SysClk_Freq = 16000000;

}


else if(MCU_STATE == LOW_POWER)

{

Config_LowPower();

SysClk_Freq = 1000000;

}

 

Conclusion

MCU clock frequencies are not nearly so fixed as we might think. Even if you are certain about the frequency that will be available on a particular piece of hardware, and you are sure that there will be no need to change the system clock dynamically, it is possible (and in some working environments, likely) that someday you will want to reuse large portions of that code in a different system. Incorporating a clock-frequency constant or variable into your firmware is a simple and effective way to save yourself some time and make your embedded systems more versatile.

 

Featured image used courtesy of Gareth Halfacree via the CC BY-SA 2.0 license.