Setting CPU frequency on Arduino Leonardo below 8 MHz fails to build

Arduino Leonardo projects build and run fine with CPU frequency 16 or 8 MHz. Trying to set it lower, e.g.:

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

fails with this error message:

/home/paul/.platformio/packages/framework-arduino-avr/cores/arduino/USBCore.cpp:678:2: error: #error "Clock rate of F_CPU not supported"

This understandable, since USB subsystem has to cope with high data rate. In my case though, I don’t need USB, other than firmware upload. Is there a way to disable it, so the project will build with lower CPU frequency?

I’m afraid that check is in the Arduino code. In the file USBCore.cpp I see this:

// ATmega32U4
#if defined(PINDIV)
#if F_CPU == 16000000UL
	PLLCSR |= (1<<PINDIV);                   // Need 16 MHz xtal
#elif F_CPU == 8000000UL
	PLLCSR &= ~(1<<PINDIV);                  // Need  8 MHz xtal
#else
#error "Clock rate of F_CPU not supported"
#endif

Which implies that on this board, you need to have an 8 or 16 MHz crystal, and therefore, F_CPU needs to match the hardware.

Can you not just set the prescaler according to the 8 or 16 MHz hardware clock in use? The data sheet at https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7766-8-bit-AVR-ATmega16U4-32U4_Datasheet.pdf shows that you can divide the 8/16 MHz crystal frequency by 1,2,4,8,16,32,64,128,or 256 to reduce power consumption.

Board_build.f_cpu needs to match the actual clock speed of the hardware, not what you would like to run it at. And you only have two options with your board, 8 or 16 MHz. At least when using the Arduino framework - which is what is checking the two values and aborting compilation if something else is found.

Having said that, the whole of the USB code is gateposted by a check:

#if defined(USBCON)
...
#endif /* if defined(USBCON) */

Try adding this to your code:

#if defined(USBCON)
#undef USBCON
#endif

That might work, provided nothing in the Arduino framework is turning it back on, however, looking around Goole/DuckDuckGo, it seems that this might require an edit of the main.cpp file and will result in around 3 KB less code in the compiler output but the autoreset option when uploading new code, might not work and the board may need manual resetting to upload.

I’m not hopeful that you’ll get a fix here. Sorry!

Cheers,
Norm.

1 Like

Thanks for your help. I tried higher clock dividers as in clock_prescale_set(clock_div_128) and board runs at much lower power as hoped, but the timings are off as expected.

For number of reasons, I decided to upgrade my project to Seeeduino Cortex-M0+, which should solve this and other problems for a few extra bucks. ATMEGA32U4 is a pretty ancient hardware, and it seems more reasonable for me to climb the learning curve of something modern and more powerful.

1 Like