The ramblings of one home-brew electronics, software engineer and pilot.

Monday, September 1, 2014

Arduino Timers

In taking my DDS code to the next level, I needed to dig into Arduino timers and gain a fuller understanding of how they work. The ATMega328 has three timers known as Timer 0, Timer 1 and Timer 2. Each timer has two outputs and corresponding output compare registers that determine when the output is toggled.Each of the timers has a prescaler that generates the timer clock by dividing the system clock (16 MHz) by a selectable value 1, 8, 63, 256 or 1024. Timer 2 has a different set of prescale values from the other timers. Each timer output has a corresponding output compare register that can be used to generate interrupts.Each timer has a select-able mode. The PWM modes are "Fast PWM" and "Phase Correct PWM". Each timer can run from 0 to 255 or from 0 to a fixed value. Timer 1 is a 16 bit counter that has additional modes to support timer values up to 16 bits. Each output may optionally be inverted.A timer, once enabled will run and can generate interrupts on overflow and/or matches against either output compare register. Each timer has a set of registers that control the behavior of that timer.TCCRnA, TCCRnB: Timer/Counter Control Registers - Holds the main control bits for the timer. It should be noted that the "A" and "B" on the end does not correspond to the outputs A and B. These registers hold several groups of bits:

WGM: Waveform Generation Mode - These bits that are split between TCCRnA and TCCRnB control the overall mode of the timer.

OCRnA, OCRnB:Output Compare Register - Sets the levels at whch outputs A or B respectively will be affected. When the timer value matches the register value, the corresponding output will be modified as specified by the mode.Timer PinsIt is at best confusing which timer controls which pin, not to mention that it varies between different processors. For the Mega328, the following table describes the Output Compare register, silk screened pin number on the Arduino board, pin number on the chip and name of the pin.TimerOCR Board pinChip pin Name0OC0A612PD6 OC0B511PD5 1OC1A9 15 PB1 OC1B 10 16 PB2 2OC2A1117 PB3 OC2B35 PD3Timers are initialized by the Arduino to set the prescaler to divide the clock by 64. Timer 0 is set to Fast PWM while Timer 1 and Timer 2 are initialized to Phase Correct PWM.Internally Arduino uses Timer 0 to implement the millis() and delay() library functions. Changing the frequency of this timer will affect these functions.There are a couple of modes for each timer that will be discussed separately.Fast PWMThis is the simplest PWM (pulse-width-modulated) mode. The timer repeatedly counts from 0 to 255. The timer output turns on when the timer is at 0 and turns off when the timer matches the output compare register value. The higher the output compare register value, the higher the duty cycle. Both timer outputs will have the same frequency but can have the different duty cycles as set by OCRnA or OCRnB.The output frequency for an 8 bit timer is determined by the system clock (16 MHz) divided by the currently set prescaler value divided by 256. The last division by 256 is because the timer runs from 0 to 255 before it overflows. For example, assume a prescaler set to divide by 64:Frequency = 16 MHz / 64 / 256 = 16000000 / 64 / 256 = 976.5625 HzDuty Cycle Output A = OCRnA+1 / 256.Duty Cycle Output B = OCRnB+1 / 256As can be seen from the duty cycle calculation, Fast PWM holds the output high one cycle longer than the value in the Compare Match Output register OCRnA/OCRnB. The motivation behind this is that for Fast PWM counting to 255, the duty cycle can be from 0 to 256 cycles. The output compare register however can only hold the values 0 to 255. The solution is to keep the output high for OCR+1 cycles. so an OCR value of 255 is 100% duty cycle, but an OCR value of 0 is a 1/256% duty cycle. This is in contrast to Phase Correct PWM where an OCR value of 0 is a 0% duty cycle and 255 is a 100% duty cycle.Phase Correct PWMIn this mode the timer counts from 0 to 255 and then back down to 0. The output turns off as the timer hits the OCR value on the way up and turns it back on at the OCR value on the way back down. This results in a more symmetrical output, the frequency of which will be 1/2 the value for Fast PWM mode because the timer runs both directions.Again assuming a prescaler value of 64:Frequency = 16 MHz / 64 / 255 = 16000000 / 64 / 255 / 2 = 490.196 HzDuty Cycle Output A = OCRnA / 256.Duty Cycle Output B = OCRnB / 256Notice that frequency is divided by 255 instead of 256 and that the duty cycle calculations do not add one as seen above.This is importantSuppose that a timer is set to Fast PWM mode and is set up to count to an OCRnA value of 3. In this case the timer will take the values 012301230123... Note that there are 4 clock cycles in each timer cycle. Thus, the frequency will be divided by 4. The duty cycle will be a multiple of 25% (1/4) since the output can be high for 0, 1, 2, 3, or 4 cycles out of the four. Similarly, if the timer counts up to 255, there will be 256 clock cycles in each timer cycle and the duty cycle will be a multiple of 1/256. In other words, Fast PWM divides by N+1 where N is the maximum timer value (either OCRnA or 255).In the case of Phase Correct PWM mode and the same OCRnA value of 3, the timer values will be 012321012321... There are six clock cycles in each timer cycle (012321). Therefore the frequency will be divided by 6 in this case and the duty cycle will be a multiple of 33% since the output can be high for 0, 2, 4, or 5 of the 6 clock cycles. Again, if the timer instead counts up to 255 and back down, there will be 510 clock cycles in each timer cycle and the duty cycle will be a multiple of 1/255. In other words, phase-correct PWM divides by 2N where N is the maximum timer value.TipsYou need to both enable a pin for output and enable the PWM mode on the pin in order to get any output.Different timers use the control bits and prescaler differently. Be sure to check the datasheet for the processor in use to know the appropriate settings for the timer.Some combination of bits do not work together. For example, toggle mode does not work with Fast PWM to 255 or with output B.Be sure you have correctly set the necessary bits in the correct control register.Check that you are using the correct output pins for the given timer on a given processor.

1 comment:

Wow, I am glad someone that I know understands this stuff. I suspect the counters are underutilized in most Arduino application due to complexity. Maybe some simple examples could fix that. I hope we can take advantage of DDS in our projects.