Timer/Counter Woes

The Arduino Nano Every does its best to mimic the operation of the Arduino Nano even to the point of making it difficult to obtain the best performance of the part. I’ve just been pulling my hairs over this and how they handled the Timer/Counters. The ATmega4809 has two types of Timer/Counters, “A” and “B”. There is (and this is important) only one clock prescaler available for all Timer/Counters, although a /2 prescaler is available for type B Timer/Counters as well. All Timer/Counters are 16-bit.

The single type A Timer/Counter has three comparator and waveform generators. It has four basic modes of operation. 1- Normal mode the counter cycles through a programmable number of counts, producing an interrupt when it resets to zero. No waveforms can be generated. 2- Frequency mode, generates a square wave of a a programmable frequency. Only uses one output. 3- Single Slope PWM, three outputs give three PWM signals. 4= Dual Slope PWM, no phase shift when duty cycle changes, three outputs give three PWM signals.

Double buffering of the period and duty cycle inputs means that the outputs don’t glitch when the values are changed. This is a plus over the ATmega328. However they aren’t using dual slope PWM in the ATmega4809 even though they use it with the ATmega328 (and run with an even longer period).

The Arduino Nano Every uses the type A Timer/Counter in single slope PWM mode for analogOutput on pins 5, 9, and 10. It uses the same clock divisor and period as the ATmega328 parts. The problem here is that duty cycle values of 0 through 255 (the full range) are not linearly distributed, but they could be if they weren’t insistent of compatibility. Also the divisor could be much smaller making the output easier to filter and with a better response.

The four type B Timer/Counters are independent, although they do share that single prescaler. There are eight different operating modes, including additional ones to perform pulse width and frequency measurements.

Timer/Counter B3 is used by the Arduino library to implement the millis, micros, delay, and pulseInLong functions. Its interrupt is grabbed by the Arduino library for these functions and cannot be overridden without modifying the library source. The problem here is that is relies on the prescaler being /64. Also the choice of /64 means that the micros function is only precise to 4µs, and that additional code is needed to compensate for the 1.024ms (instead of 1.000ms) interrupt interval. The divisor really needs to be /8 with a 16MHz clock or /4 with either a 16 or 20MHz clock, with the count between interrupts adjusted to achieve 1ms exactly. Again, a rewrite is in order.

Timer/Counter B2 is used by the Servo Library. Again it is assuming the /64 prescaler. However it would offer best performance (in this case resolution) with a /8 divisor.

Timer/Counters B0 and B1 are used by the Arduino library for analogWrite on pins 3 and 6. They can be improved by selecting the /2 or no prescaler. B1 is also used for the tone function. It expects the /64 prescaler.