cembeddedavratmegaavr-gcc

How can I verify the TIMER2 overflow frequency in AVR ATmega328P?


I have configured the timer2 of ATmega328P in normal mode and overflow at 10,000 Hz. My code is given below. I was trying to verify the frequency. So I just toggle a pin, PB5, on every overflow interrupt. Hence, it will give the overflow frequency.

#define F_CPU 16000000
#define TIMER2_PRESCALER 8  // RV8A12, added 2022-11-08
#define TIMER2_CLOCK (F_CPU / TIMER2_PRESCALER)

uint8_t Timer2_count = 0;
unsigned int sample_freq;

ISR(TIMER2_OVF_vect)
{
    TCNT2 = Timer2_count;
    PORTB ^= (1<<PORTB5);
}


void timer2_init()
{
    TCCR2A = 0x00;  // Normal mode
    TCNT2 = Timer2_count;
    TIMSK2 = 0x01;
    TCCR2B = 0x02;  // Set prescaler 8 or divide by 8
}

void timer2_stop()
{
    TCCR2B = 0x00;
}


void setup()
{
    // Put your setup code here, to run once:

    sei();
    Serial.begin(115200);
    Serial.print("\nSTARTING...");
    delay(5000);
    DDRB |= (1<<PORTB5);

    sample_freq = 10000;
    Timer2_count = 256 - (TIMER2_CLOCK / sample_freq);

    timer2_init();
}

void loop()
{
    // Put your main code here, to run repeatedly:
}

Then I connected a oscilloscope on PB5 pin and I observed a wrong result. The frequency shows around 159 Hz.

I have made the pin PB5 as output and then checked the DSO. It was showing 4.9407 kHz, that is, the sampling frequency is 9.881 kHz, instead of expected freq 10 kHz. I made control the registers modifications in one command.


Solution

  • The issue was solved by reducing the timer frequency. I have changed the prescaler of 8 to 64. The issue was with the TCNT update command in the ISR. It was not updating before a timer count to the next tick. When the timer frequency is reduced, it gets sufficient time to update the TCNT before it counts to the next tick.