Clock source of Timer is too slow and makes no sense

Using arduion uno:

void setup() {
  Serial.begin(9600);

  pinMode(8, OUTPUT);

  TCCR2A = 0;   //Normal mode for incrementing count.
  OCR2A=0x7F;  //~50% duty cycle

  
  TIMSK2|=(1<<TOIE2);   //Both overflow and compare A interrupts enabled.
  TIMSK2|=(1<<OCIE2A);
  
  TCCR2B|=(1<<CS22);    //??? makes no sense.
  
  sei(); //Enable interrupts
}

ISR(TIMER2_COMPA_vect){
  PORTB = B00000001;
}

ISR(TIMER2_OVF_vect){
  PORTB = B00000000;
}

void loop() {
  while(true)
  {
    delay(1000);
  }
}

CS22 should be a devider of 64. However when I only select CS20 I get half the frequency of CS22 even though it doesn't have a devider... Selecting CS20 I expect a PWM frequency of 16MHz/256, though I get only 500Hz. CS22 gives me 1000Hz. I want to use 16Mhz/256. Does anyone know what could be going on?

timer2 runs at 16M/64 when using

TCCR2B |= 1<CS22;

16 000 000 / 64 = 250 kHz

since you are in normal counting mode, the TOP value is 0xFF so the "PWM" freq is

250 000 / 256 = 976 Hz

Remember, your timer counts from 0 to 255, and that gives you the ~1000 Hz overflow which gives you the "software PWM"

2 Likes

Yes thank you. In the case of CS22 it is plausible. However when I replace CS22 with CS20 I only get 500 Hz. With your calculation it should be 16 000 000 / 1 / 256, but it isn't :confused:

When you say you replace CS22 with CS20, do you mean TCCR2B |= 1<<CS20?

To get 16 000 000 / 256, use

TCCR2B |= 1<<CS22 | 1<<CS21

1 Like

No, I don't need a prescaler. I want to use only CS20. But it gives me a frequency of 500 Hz. The expected value should be 16MHz/256 which is 62.5kHz.

When you say you replace CS22 with CS20, do you mean TCCR2B |= 1<<CS20?

Yes that's what I mean.

CS20 is also a pre-scaler bit so not sure what this means

No, I don't need a prescaler. I want to use only CS20.

TCCR2A = 0
TCCR2B = 1<<CS20

will give you 62.5 kHz

Have you tested the exact code and it gives you 62.5 kHz? Somethings not right with my arduino I guess...

TCCR2B|=(1<<CS22);
  TCCR2B|=(1<<CS21);
  TCCR2B|=(1<<CS20);

f/1024 -> ~62.5 Hz

TCCR2B|=(1<<CS22);
  TCCR2B|=(1<<CS21);

f/256 ->~250 Hz

TCCR2B|=(1<<CS22);
  TCCR2B|=(1<<CS20);

f/128 -> ~500 Hz

TCCR2B|=(1<<CS22);

f/64 -> ~1000 Hz

TCCR2B|=(1<<CS21);
  TCCR2B|=(1<<CS20);

f/32 -> back at ~62.5 Hz

TCCR2B|=(1<<CS21);

f/8 -> ~250 Hz

TCCR2B|=(1<<CS20);

f/1 -> ~500 Hz

This looks like it could be a error in the bitwise operation?

You can't do this since (|=) since it will read the existing configuration and do a bitwise OR so

TCCR2B|=(1<<CS22);
TCCR2B|=(1<<CS20);

is equivalent to

TCCR2B = 1<<CS22 | 1<<CS20

You're better off writing it this way

TCCR2B = x<<CS22 | y<<CS21 | z<<CS20, then just fill the x,y,z with whatever you need it to be.

1 Like

Finally thank you. I thought the register is always set to 0 at the beginning.

At AVR reset, it is set to zero. However, the Arduino core code initializes it to a non-zero value for use by analogWrite()