Timer/Counter is a very common peripheral among microcontrollers. As their names suggest, these peripherals are used to measure the passage of time or to count how many times an event has occurred.

The block diagram above shows how the timer/counter works. At the most basic level, the control logic is fed a clock, and every period of this clock the control logic increments (or decrements) the value in the register TCNTn. This setup can be used to measure time: if the control logic is fed a 1 kHz clock, then the microcontroller can know that 1 second has passed when TCNTn has a value of 1000. This setup can also be used to count the number of occurrences of something: if every time a button is pushed, Tn is pulsed, then the control logic could use that to increment TCNTn; if the microcontroller wanted to know how many times the button has been pushed, it can just read TCNTn.
For the variable load project, the timer/counter peripheral will be used in two ways:
- PWM: often times, the timer/counter peripheral is used to generate waveforms. This is done by setting up the waveform generation module. If TCNTn counts from 0 to 255, then starts over at 0, you could setup the peripheral to output a high on OCnA if the count is below a certain value, and low otherwise. By adjusting this value, you can vary the output waveform’s duty cycle. In other words, the output will be a Pulse Width Modulated (PWM) waveform who’s period is controlled by the clock to the control logic, and who’s duty cycle is controlled by the value mentioned earlier.
- Timer: In previous posts, we used the method _delay_ms to make the microcontroller wait for a certain amount of time. However, nothing can be done while in _delay_ms, so you’re freezing the program. If you want to be able to do other things while you wait, you should use timers. We can configure the timer to either fire an interrupt or set a flag when a certain amount of time has passed. Then, instead of freezing the code, you can just make the code periodically check the flag to see if the right amount of time has passed. This is very useful for setting how frequently displays are updated, or setting sampling frequencies on DACs or ADCs
The ATMEGA32U4 has 4 timers: Timer/Counter0, Timer/Counter1, Timer/Counter3, and Timer/Counter4. Timer/Counter0 uses an 8 bit counter (which means the counter register can only count up to 255), Timer/Counter1 and Timer/Counter3 use 16 bit counter (max counter value is 65535), and Timer/Counter4 uses a 10 bit counter (max value is 1024). I’ll use Timer/Counter0 for generating a PWM waveform, which will eventually be used to control fan speed, and Timer/Counter1 and 3 for timers. Timer/Counter0 may be used in the future; it seems like it’s mostly designed for motor control, but I’m going to assume it can also be used as a PWM generator or timer…
PWM
The fan I’m using is expecting a PWM with a frequency of 25 kHz. Now, for this project, I have to let TCNT0 count all the way to its maximum value, which is 255 (I’ll explain why in the next paragraph). Therefore, the PWM frequency is 16 MHz/255, which is around 63 kHz. It’s as close as I can get to 25 kHz with my setup (I may be able to get it to half of 63 kHz, so 31.5 kHz, but I haven’t looked into it enough at time of posting).

Ideally, you could control both the frequency and duty cycle of a PWM wave. And it is possible to do this: OCR0B can be used to set the duty cycle, while OCR0A is used to set the frequency. Unfortunately, in this arrangement, the PWM would have to occur on the OC0B pin, which is on PD0, which is already being used for SCL. If I want to use OC0A for the PWM output, then I can control the duty cycle with OCR0A, but the frequency control is much more limited; the only way to change the frequency is through the clock divider. Of course, I could use OC1C on PB7 to create the PWM, and be able to control its frequency and duty cycle, but then I’m using Timer/Counter1, which I want to save because I’ll need it later. This is an important lesson: due to pinout, you may find yourself making compromises you don’t want to. In this case, I’m going to use a 63 kHz waveform instead of 25 kHz and hope the fan can be controlled.
So the frequency is 63 kHz, and the duty cycle is controlled by OCR0A: if the counter is below OCR0A, then output a high on OC0A; if the counter is above OCR0A, then output a low. For example, if OCR0A is 51 (which is 20% of 255), then OC0A will be high for 20% of the period, and low for 80%. If OCR0A is 204 (which is 80% of 255), then the duty cycle will be 80% for the same reason. Great! So by setting OCR0A to be some percent of 255, we can make the duty cycle be the same percent. Of course this has limitations; you can’t do 10% of 255 since that would be 25.5, and the 8 bit register can’t hold decimals; it’ll hold either 25 or 26. That means the duty cycle will be close to 10%, but not exactly. Fortunately, for this application, the accuracy of the duty cycle doesn’t matter. But if you are in a position where you need more accurate PWM control, for example you’re controlling a servo motor, then you’ll want to use a timer with more resolution (like Timer/Counter1 or Timer/Counter3).


Here is the PWM class definition and constructor. The frequency of the PWM signal will be the input clock divided by 255, but the speed of the input clock can be adjusted. Instead of feeding the PWM class the system clock of 16 MHz, you can provide a clock divided down by 8, 64, 256, or 1024. Additionally, you can invert the PWM; instead of an 80% duty cycle, you can have the signal be inverted, which will be 100%-80% = 20% duty cycle. This is a hardware operation; you program the registers to output a 80% duty cycle, and then the output driver at the pin will invert the signal. The constructor uses clk_source and output_mode to determine what clock to feed the control logic and how to configure the output driver, and programs the relevant register accordingly.
One thing to note is how the waveform generator is configured. We want the output to be high when the counter is below OCR0A, and low otherwise; when the waveform generator is configured as fast PWM, it accomplishes this:

In order to set the duty cycle, you have to write a value between 0 and 255 to OCR0A. Since this requires knowing that OCR0A is an 8 bit register, and also it’s inconveneient to figure out what 50% of 255 is, I wrote a helper function to (a) take in a duty cycle as a percent and calculate the appropriate value, and (b) write to OCR0A. The code is below:

Now, instead of the application code writing something between 0 and 255 to OCR0A, the application code can call duty_cycle_set with an argument between 0 and 100. The method also returns the actual OCR0A value, since as mentioned setting a duty cycle to 10% will not result in OCR0A getting 25.5 due to the decimal point, so knowing what the actual value is may be useful.

Here’s my little test code. I was also playing with my UART code, which I’ll expand upon in a future post. The code sets up the microcontroller to receive a character between ‘0’ and ‘9’, which maps to 0% and 90%. The microcontroller, upon receiving a byte, sets the duty cycle to the appropriate value.
After hooking up the fan to the PCB, I’m happy to report that the fan accepts the 63 kHz PWM signal. By typing in different numbers, I was able to hear the fan speed up or slow down. Success!
Timer
The timer is the opposite of PWM in a lot of ways. Here, I don’t care about duty cycle. Also there is no output on a pin. Also also, OCR1A and OCR3A will be used to set the frequency, rather than duty cycle. Let me elaborate:
There are three parts to this implementation of the timer:
- Clock divider: as mentioned above, the input clock can be the divided down system clock, which is can be divided by 8, 64, 256, or 1024.
- Top value: this defines what the counter will count to before resetting.
- Flag: the flag is set when the counter reaches the top value.
The operation is as follows: every single period of the divided down clock increments the counter by 1. Then the counter matches the top value, the counter resets and starts counting up from zero again. This reset will set a flag, which the application code can read and then clear.
For example, say we have a 16 MHz system clock, a divider of 256, and a top value of 31249. In this set-up, the control logic increments by one with a frequency of 16 MHz / 256 = 0.0625 MHz, or 62.5 kHz. In order for the flag to be set, the counter will have to go from 0 to 31249, which is 31249+1 = 31250 increments. Since 31250 periods of a 62.5 kHz clock must elapse before the flag is set, that means the amount of time between the flag being set and then being set again is 31250 / 62.5 kHz = 500 ms. In other words, the flag will be set every 0.5 seconds (or set with a frequency of 2 Hz)!
Here is how the flag would be utilized. Say the microcontroller is running code A continuously. At the end of code A, the flag is checked; if it is not set, then code A is executed again. If the flag is set, the flag is cleared, and then code B is run. At the end of code B, the microcontroller goes back to running code A. This way, instead of waiting around and doing nothing while waiting (like in _delay_ms), the microcontroller can run code A while waiting for enough time to pass to run code B. Before diving into the implementation, let’s look at the test code:

TimerClassBlink sets a flag every 256/16000000 * (6249+1) = 0.1 second, while TimerClassEnable sets a flag every 1024/16000000 * (15624+1) = 1 second. Every second, LED_enable is toggled true or false. Every 0.1 seconds, if LED_enable is true, then the LED is toggled. If LED_enable is false, the LED is off. This code will cause the LED to be off for 1 second, and then cause the LED to blink for 1 second.
The beauty of using timers is that more code can be added to the inside of the infinite while loop without significantly effecting the timing. If more code was added after the second if statement inside the while loop, then both timers would still continue to run as expected. The while loop would continue to run, running the additional code over and over again, until one of the timers updated their flag, at which point the flag would be cleared and the associated code would be run. As you can see, timers not only allow microcontroller to measure the passage of time, but it also allows them to run certain pieces of code only when necessary.
There is a caveat to this, of course. If the code you added took a very long time to execute, or it has a lot delays, then the counters may re-set an already set flag. For example, if the newly added code took 10 seconds to run, then the LED blink program would not function since both flags would be checked at 10 second increments. In other words, this scheme only works if one iteration of the while loop takes a substantially shorter amount of time than the period of flag setting and re-setting. Additionally, even if the code isn’t that long, the timers will have some error; for example, if any of the flags are set during the newly added code, then the flags will not be checked until the while loop starts over again.
The solution to both of these problems is using interrupts, which will cause the code to stop running the current code and jump somewhere else immediately. However, interrupts come with complications of their own, so I recommend using the “continuously check the flag” method if precise timing isn’t necessary, and the pass through the while loop is very quick. This will be the case with most application code as long as you don’t use any delay functions, like _delay_ms.


Since Timer/Counter1 and Timer/Counter3 are identical, except for the fact that they each have their own registers, the constructor sets up the various pointers to point to either Timer/Counter1 or Timer/Counter3 registers; the other methods for this class are identical. Just like with the GPIO class, the pointers to registers must be declared as volatile (that is, the registers are volatile) since they can be changed by things other than the CPU.
Besides setting up the pointers, the most important function of the constructor in this case is setting up the operational mode, which is Clear Timer on Compare (CTC). Here, the counter will continue to increment every input clock period. The hardware will also compare TCNT1 (TCNT3 for Timer/Counter3) to OCR1A (OCR3A); if they are equal to each other, than the counter register is set to 0 instead of incrementing. This reset also sets the OCF1A (OCF3A) bit in TIFR1 (TIFR3); this bit is the flag we’ll be checking. By getting this bit, you can see if the counter has reset. The constructor also sets the maximum value of the counter by writing to OCF1A, as well as selecting which clock to use (system clock, divided down clock, etc.)

Above are some equations that may be helpful. It would be nice to have the constructor take a period in milliseconds or microseconds, and then deduce the correct clock source and top value from that. However, that kind of calculation is difficult to implement well, so I just included the equation necessary to calculate those settings. The programmer is responsible for selecting the right clock source and top value.
Hope you enjoyed the HAL for timer/counter. Next up: ADC!