How bad is ATMega internal oscillator?
This is one of those things that can surprise a hobbyist, and it surprised me: the spec’ed accuracy of the internal oscillator of hugely popular Atmega328p is +/-14%.
OK, but what does it mean? Is it event bad? It depends.
Clocking ATmega
Atmega series microcontrollers allow two ways of generating a clock signal required for it to run (or be programmed):
- External quartz
- On-chip oscillator
The clock source is configured using Fuse Bits (or fuses). Those can be set using any ISP programmer. While doing this be careful as some of those can lock you out of your microcontroller without any ability to revert to the working state. When buying off the shelve Arduino boards, one does not need to worry about fuses as they are set by the board producer. Things get more interesting when you are buying bare chips.
Most Arduino boards opt-in for the first option, and we will learn why in a second.
Limitations of the internal clock
When designing a custom board, the additional components bring up the complexity and cost. Those are very good reasons to get rid of the extra clutter. Let’s examine this trade-off a little bit closer.
It’s just slower
One hard to miss limitation is speed: in case of Atmega328p, the internal clock runs only up to 8Mhz. Wen clocked externally the limit is 16Mhz. That’s twice the amount of CPU-work that can be done in the same time.
But let’s say that we are OK with slower speed. What else is there?
Asynchronous communication gets wonky
Synchronous communication protocols carry their own clock signal: the device sending the message also sends the clock and this makes it easy for the receiver to know when to check for ones and zeroes. These include: I2C and SPI and those are not affected by the clock.
But when it comes to asynchronous protocols using UART the clock is assumed to be right. It does not need to be perfect, the tolerance depends on the baud rate. When the clock drifts too much the transmission errors start to show up:
Delays are slightly off
With a badly tuned internal oscillator Arduino delay()
will wait for too long or return to quickly. On my workbench a delay(1000)
resulted in a 1004 ms wait time using external cristal and slightly surprising 940 ms (6% off) delay when using internal oscillator.
Beeps are out of tune
The timers running the Arduino tone() method are working of the same clock as the rest of the microcontroller and are also affected.
It is said that only 1 in 10000 has a perfect pitch, an ability to identify a tone without a reference. But in situations when environment provides a reference of some kind: another instrument playing or multiple devices are making sounds, a 10% change in frequency, and in effect in pitch, is easy enough to hear.
Tuning the internal oscillator
But, ATmega’s oscillator can be tuned with fuses. Atmel published a guide and prepared the necessary firmware. It requires a PC and one of the supported programming devices: Atmel-ICE, AVRISP mkII, JTAGICE3, and JTAGICE mkII. I don’t own any of those so I will not explore this further.
One thing to note is that the even a calibrated oscillator will vary with temperature and supply voltage: