# Atmega328 fast PWM (mode 7) of timer 0 not working as expected

I am blinking an LED on PORTB5 using timer 0 in mode 7. The time between blinks is computed as $$\frac{(\text{OCROA}+1) \times \text{prescaler} \times \text{timerCount}}{\text{FCPU}}$$ $FCPU=16MHz$. With $OCROA=124$, $prescaler=1024$, and $timerCount=125$, the time turns out to be $1 \space second$ and this works as expected. But with $OCROA=16$, $prescaler=1$, and $timerCount=2956793$, I would expect the time to be $~3.14 \space seconds$, but I am getting something around $12 \space seconds$.

Code that works as expected:

#include <avr/interrupt.h>
#include <stdint.h>

volatile uint32_t timerCount = 0;
ISR(TIMER0_COMPA_vect)
{
++timerCount;
}

int main(void)
{
DDRB |= 1 << DDB5;
TIMSK0 |= 1 << OCIE0A;
TCCR0A |= 1 << WGM00 | 1 << WGM01;
TCCR0B |= 1 << WGM02;
OCR0A = 124;
sei();
TCCR0B |= 1 << CS02 | 1 << CS00;
while(1)
{
if(timerCount >= 125)
{
PORTB ^= 1 << PORTB5;
timerCount = 0;
}
}
return 0;
}


Code that does not work as expected:

#include <avr/interrupt.h>
#include <stdint.h>

volatile uint32_t timerCount = 0;
ISR(TIMER0_COMPA_vect)
{
++timerCount;
}

int main(void)
{
DDRB |= 1 << DDB5;
TIMSK0 |= 1 << OCIE0A;
TCCR0A |= 1 << WGM00 | 1 << WGM01;
TCCR0B |= 1 << WGM02;
OCR0A = 16;
sei();
TCCR0B |= 1 << CS00;
while(1)
{
if(timerCount >= 2956793)
{
PORTB ^= 1 << PORTB5;
timerCount = 0;
}
}
return 0;
}


What could be the issue with the latter?

• "2956793" is out of range for a 16 bit int. Declare this as an unsigned long constant instead. Fix that, and get back to me :) – KyranF May 12 '15 at 22:02
• You should probably be using overflow interrupts instead by the way – KyranF May 12 '15 at 22:06

Also you should disable interrupts when you clear timerCount because this is a 32-bit value that requires multiple instructions to update on an 8-bit platform.