Setting CPU clock on Arduino Leonardo makes timing functions inaccurate

A simple blink program on Arduino Leonardo:

#include <Arduino.h>
#include <avr/power.h>

void setup()
{
  // clock_prescale_set(clock_div_16);
  pinMode(LED_BUILTIN, OUTPUT);
}

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

runs fine with default platform.ini file, but when I change CPU frequency to:

[env:leonardo]
platform = atmelavr
board = leonardo
framework = arduino
board_build.f_cpu = 8000000L

LED blinks twice as fast. When I uncomment clock_prescale_set(clock_div_16); it blinks 8 times too slow. Is this normal?

I’ve got no experience whatsoever with Leonardo boards, but, the board_build.f_cpu doesn’t change the physical clock speed of the board, it’s there for when you have changed the hardware to a non-default CPU frequency as the F_CPU value is passed into the code to make sure that things “flash” at the correct speed.

It’s the same with my ATtiny85 boards. The default is an 8 MHz internal clock, with a divide by 8 fuse set, so it’s running actually at 1 MHz. If I set the board build f_cpu to anything different, the timings don’t work correctly.

You need to either default the frequency, leave it out of the ini file, or set it to the actual CPU clock frequency that the board is running. Then things should be fine.

I tested the blink sketch on my Uno.

The default clock is 16 MHz and a 1 second delay is roughly that and the scope says period = 1.98 S and frequency = 0.505 Hz which is as expected as there are two delays per flash! (That always catches me out!)

In the ini file, I then added board_build.f_cpu = 1000000L which is 16 times slower than the actual clock. Uploading blink gives me a 8 Hz flash frequency with a period of 125 mS.

The actual delay is 62.5 mS, which is exactly 1000/16.

HTH

Cheers,
Norm.

1 Like

OK, that makes sense. I wish it was easily discoverable in the documentation. Indeed, platform.ini file:

[env:leonardo]
platform = atmelavr
framework = arduino
board = leonardo
board_build.f_cpu = 8000000L

in concert with:

  if(F_CPU == 8000000) clock_prescale_set(clock_div_2);

produces correct timings. Thank you.

It’s in the docs at Redirecting.... However, I have to agree, it appears that the wording gives the impression that this will “overclock” the CPU:

You can overclock a board by specifying a board_build.f_cpu value other than the default.

Which I don’t thinl is the correct wording. Perhaps:

If you have overclocked a board, you should specify a board_build.f_cpu value to match the change.

Is better?

your Leonardo board’s details are at Arduino Leonardo — PlatformIO latest documentation, where again, it does rather give the impression that the ini file setting will overclock the board!

Cheers,
Norm.

Now I’m confused. The board has a 16 MHz crystal on it, so your F_CPU should be the default, 16 MHz surely? Unless you are telling your code to check if the build has assumed an 8 MHz clock speed, and you set the clock prescaler to suit? Are you using board_build.f_cpu to tell the code to change the prescaler? Interesting.

Cheers,
Norm.

I’ve opened a new topic on this matter of the documentation giving the impression that the boards clock frequency can be changed using this setting, it’s at Documentation Bug?, if you are interested.

Cheers,
Norm.

According to what you wrote earlier, board_build.f_cpu = 8000000L will set F_CPU == 8000000 and all timing dependent modules will be scaled accordingly when built from source. The crystal produces 16MHz clock, but clock_prescale_set(clock_div_2) divides it by 2 and everything works fine with CPU clocked at 8MHz now.

I though that was your intention, but I wasn’t 100% sure. Thanks.

Cheers,
Norm.