Reducing Clock Frequency of Microcontroller

Another way to reduce power consumption of the device and extend the battery life is to reduce the frequency of the microcontroller. It is not always necessary for the microcontroller to operate at full frequency. Thus, it's a good approach to reduce the number of executable instructions per second while having the enhanced battery life.

The ATmega 328P microcontroller uses an external oscillator at a frequency of 16 MHz to generate clock cycles. The relationship between the current operating frequency of the microcontroller and the amount of consumed energy is depicted in the Figure XXX. As may be seen, the reduction of the frequency can triple the life of the battery.

ATmega328P Frequency vs Supply Current (5V)
Image 14 - ATmega328P Frequency vs Supply Current (5V)

Once the clock frequency is reduced, it is necessary not to forget that this change doesn’t affect only the frequencies of the microcontroller itself, but also all the synchronous peripherals. This means that the frequency will also affect delay() or millis() functions calls. As well, it affects the speed of I/O communications (e.g. serial line), speed of A/D converter and the like.

When changing the clock frequency, the interrupts handling must be disabled. This will ensure that the write operation or changing the clock frequency operation will not be interrupted. Suitable place to change of the clock frequency is thus the setup() function, where the clock frequency may be set before the program itself starts.

In case of ATMEL ATmega 328P microcontroller, the frequency may be changed by altering the register Clock Prescale Register value, abbreviated CLKPR. Such change allows to lower the value of the clock frequency and thus reduce the energy consumption. Its structure is shown in Figure XXX.

`CLKPR` Register
Image 15 - `CLKPR` Register

The highest bit of CLKPR registry is marked as CLKPCE - Clock Prescaler Change Enable. If the frequency of the microcontroller is to be changed, it must be set to 1 and all other bits to 0. It will be automatically reset either after 4 cycles or after recording the CLKPS entries.

The combination of bits from CLKPS0 toCLKPS3 (Clock Prescaler Select Bits) allows to set the Clock Division Factor. It determines how much will the frequency of the microcontroller decrease. This change may be done at any time while the program is running. Although 4 bits are available, which allows for 16 different combinations, only is allowed. Possible combinations are shown in Table XXX.

CLKPS3 CLKPS2 CLKPS1 CLKPS0 Clock Division Factor Frequency
0 0 0 0 1 16 MHz
0 0 0 1 2 8 MHz
0 0 1 0 4 4 MHz
0 0 1 1 8 2 MHz
0 1 0 0 16 1 MHz
0 1 0 1 32 500 kHz
0 1 1 0 64 250 kHz
0 1 1 1 128 125 kHz
1 0 0 0 256 62.5 kHz

In order to change the frequency of the ATmega 328P microcontroller, the following steps are required:

  1. Globally turn off the interrupts by calling the noInterrupts() macro.
  2. Set the bit value of CLKPCE to 1 and all other bits of the CLKPR registry to 0.
  3. Next, it is necessary to write the values of CLKPS bits, which corresponds to the particular prescaler of Clock Division Factor.
  4. Globally turn on the interrupts by calling the interrupts() macro.

The Arduino Uno with the standard Blink example is used to show a change in the frequency of the microcontroller. The built-in LED diode will blink in regular 1 second intervals. The source code of the solution is shown in the Listing XXX.

#include <Arduino.h>

void setup(){
    pinMode(LED_BUILTIN, OUTPUT);
}

void loop(){
    digitalWrite(LED_BUILTIN, HIGH);
    delay(1000);
    digitalWrite(LED_BUILTIN, LOW);
    delay(1000);
}

Once compiled and started, the LED 1 diode will be turned on for 1 second and then will be turned off for another 1 second.

Next, the setup() function is adjusted to reduce the frequency of the microcontroller to 2 MHz – value of Clock Division Factor is set to 8. For this purpose, it is necessary to set the values of CLKPS0 and CLKPS1 bits to 1, both of these together with CLKPCE are available as macros.

void setup(){
    noInterrupts();
    CLKPR = _BV(CLKPCE); // 0x80
    CLKPR = _BV(CLKPS0 | CLKPS1); // 0x03
    interrupts();
    pinMode(LED_BUILTIN, OUTPUT);
}

This adjustment reduces the frequency of microcontroller to 2 MHz. This time, the entire turn on and off cycle will not take 2 seconds, but 4, this is caused due to decreased frequency which affected the behavior of the delay() and milis() functions.

  • TODO: vypocet

Should we add a line, to show the elapsed time (in milliseconds) since the program started, to the end of the loop() function, we would always see the same values, whether the change of the frequency is adjusted or not. This means that this value is dependent on the set frequency. This problem can be avoided by setting the F_CPU macro to the correct frequency in the time of the compilation.

[!NOTE]

The _BV() macro is utilized in the code, it will convert the number of bit, which is received as a parameter to the corresponding numeric value (byte). Thus, the records

CLKPR = _BV(CLKPCE);

and

CLKPR = 0x80;

are equivalent.

results matching ""

    No results matching ""