# Timer0 and Timer2 configuration on atmega1280

I want to setup Timer0 and Timer2 to control the intensity of the LED (L) on the Arduino Atmega1280.

The frequency has to be 10khz and the duty cycle will be controlled by a switch or using serial comm via uart (increment and decrement); currently the only part where I'm having issues is initializing the timers and not being sure if my approach is the correct one, which is the following:

Since I need control over freq and on the duty cycle I think that I need to use two timers, I've searched if it can be done using only one but most of the tutorials and guides only focus on changing freq or duty so I've reached the conclusion that by using one timer you can only control either frequency or the duty cycle.

My plan is to use Timer2 as the 10khz clock for Timer0, when Timer0 overflows it will toggle it's signal, the duty cycle is controlled using OCROA and the freq for Timer2 is set with the pre-scaler being 8 and OCR2A = 200:

$$f_{pwm} = \frac{f_{clk}}{N \cdot R_{OCR0A}}$$ $$10000 = \frac{16000000}{8 \cdot 200 }$$

I've set Timer0 to have no clock source since I'll be incrementing it manually with the TIMER2_OVF_vect, here is the routine that sets up both timers.

/**
* Configures a PWM with variying duty cycle at 10Khz.
*
* First we set Timer2 to be the 10khz clock source:
*     f = 16e6 / (8 * 200)
*
* Second we set Timer0 to be the duty cycle specifier
* Timer2 is incremented by each tick of Timer0 and the one that
* sends the signal to the Led (L)
*
*/
void setupPWM(void) {
// Timer2
// Set the top to be 200
OCR2A = (uint8_t) 200;

// Set the clock source to use Pre-scale 8
CLR_BIT(TCCR2B, CS20);
SET_BIT(TCCR2B, CS21);
CLR_BIT(TCCR2B, CS22);

// Set the Waveform generation mode to OVF on top
SET_BIT(TCCR2A, WGM20);
SET_BIT(TCCR2A, WGM21);
SET_BIT(TCCR2B, WGM22);

// We don't need to set COM2A, because
// we won't use wiring, we'll use
// interrupts as a counter inc for Timer0
SET_BIT(TIMSK2, TOIE2);

// Timer0
// Set PB7 for output and clear the value
SET_BIT(DDRB, PB7);
CLR_BIT(PORTB, PB7);

// Disable the internal clock source, we will clock it with the TOVI
CLR_BIT(TCCR0B, CS00);
CLR_BIT(TCCR0B, CS01);
CLR_BIT(TCCR0B, CS02);

// Set waveform gen to FPWM with OCRA as the
// top, OCRA will be set by the duty cycle functions
// We start at 50%
SET_BIT(TCCR0A, WGM00);
SET_BIT(TCCR0A, WGM01);
SET_BIT(TCCR0B, WGM02);

// Set COM mode to toggle the output on
// OCROA match
SET_BIT(TCCR0A, COM0A0);
CLR_BIT(TCCR0A, COM0A1);

SET_BIT(TIMSK0, TOIE0);

OCR0A = (uint8_t) 128; // Set it to 50% duty initially
TCNT0 = 0;
}


Timer2 overflows correctly, however Timer0 seems to be not working as it should my guess is that since the CS0:2 bits are 0 the TIMER0_OVF_vect ISR is not triggered, however I'm not sure that if I set Timer0 to Fast PWM I'll loose the 10khz freq.

Any help is really appreciated.

• the internal clock generator is somewhat variable, can use use that to clock the timer and tune it to the frequency you want, – Jasen Jan 4 '16 at 4:58
• Yes, and that is what I am doing for Timer2, I adjust the OCR2A and set the pre-scale to 8 to have a 10khz based on the frequency formula for Fast PWM – Tristian Jan 4 '16 at 5:07
• no, the internal RC oscillator – Jasen Jan 4 '16 at 5:51
• You mean the 16Mhz crystal?, how would, I'd rather not add more HW components. – Tristian Jan 4 '16 at 6:35

I believe it's trivial to control frequency and PWM using one timer even without interrupt. You need select timer mode supporting TOP value to specify frequency precisely (16-bit timer can do it more accurately but I don't think it's so critical for LED). FastPWM is mostly sufficient hence select mode 7. OCRnA specifies frequency f=fclk/(N*(OCRxA+1)). Output pin is selected as a OCnx (x>A) and duty cycle is controlled via OCRnx (x>A) register in range (0..OCRnA). You need select correct compare output mode (how behaves output pin) but it's well specified in datasheet. There are also such issues as double buffering because there is potencial race condition as you are changing params in runtime but it's not so critical.

So, after thinking more about it, the main issue was that I wasn't able control the freq of Timer0 with Timer2 overflows, however after reading more on Timer0 section, we can configure Timer0 to use T0 as an external clock source that is ticked on rising or falling edge. T0 is wired to port D so we have to configure port D correctly as output.

void setupTimer0(void) {
// Set the clock source to be T0 (PD7)
SET_BIT(TCCR0B, CS00);
SET_BIT(TCCR0B, CS01);
SET_BIT(TCCR0B, CS02);

// Set waveform gen to FPWM with OCRA as the
// top, OCRA will be set by the duty cycle functions
// We start at 50%
SET_BIT(TCCR0A, WGM00);
SET_BIT(TCCR0A, WGM01);
SET_BIT(TCCR0B, WGM02);

// Set COM mode to toggle the output on
// OCROA match
SET_BIT(TCCR0A, COM0A0);
CLR_BIT(TCCR0A, COM0A1);
}

void setupTimer2(void) {
// f = 16e6 / (8 * 200)
// Set the top to be 200
OCR2A = (uint8_t) 200;

// Set the clock source to use Pre-scale 8
CLR_BIT(TCCR2B, CS20);
SET_BIT(TCCR2B, CS21);
CLR_BIT(TCCR2B, CS22);

// Set the Waveform generation mode to OVF on top
SET_BIT(TCCR2A, WGM20);
SET_BIT(TCCR2A, WGM21);
SET_BIT(TCCR2B, WGM22);

// Disconnect OC2A as we don't use it
CLR_BIT(TCCR2B, COM2A0);
CLR_BIT(TCCR2B, COM2A0);

// Set PD7 (T0) for output
SET_BIT(DDRD, PD7);
CLR_BIT(PORTD, PD7);

// Enable the timer2 overflow interrupt
SET_BIT(TIMSK2, TOIE2);
}

ISR ( TIMER2_OVF_vect ) {
SET_PIN(PIND, PD7); // Toggle the pin value to create a 'tick'
}


Here is the CS0:2 table for reference