Problem: Enabling timer0 impacts general digital IO toggle rate (Arduino Uno)

Hello,

I am facing the problem of timer0 operation impacting the toggling rate of any general digital IO I select and unable to resolve it even after looking on the web for various possible reasons.

My code:
1- uses timer0 for generating 38.4kHz@30% duty cycle at OC0B (pin 5)
2- uses a general digital IO pin for a 200 millisecond ON and 200 millisecond OFF rate (pin 12)

I do get the desired frequency and duty cycle at OC0B BUT the toggle rate of general digital IO is different than I program. This toggling at pin 12 is either faster by a scale of 200 or becomes random. No matter if a change the general digital IO pin, problem is consistent. Also the problem is only with activating timer 0 and doesn’t occur on activating timer 1 or timer 2. If I comment timer0 commands, the output at pin 12 toggles correctly at programmed values. My code is as below:

//troubleshoot timer0 interference with main loop

// Timer 0 in fast PWM mode with OC0B output on IO 5

void setup() 
{
  pinMode(5,OUTPUT); //OC0B
  pinMode(12,OUTPUT); //LED blinker
  
   TIMSK0 = 0;  // no interrupts  //
//  cli(); //clear interrupts
  
   TCCR0A=0;
   TCCR0B=0;
   TCNT0=0;
   
   TCCR0A|=(1<<COM0B1)|(1<<WGM01)|(1<<WGM00);
   TCCR0B|=(1<<WGM02)|(1<<CS01);

   OCR0A = 51;// 51 count gives 38.461 kHz freq
   OCR0B = 15; //duty cycle = 16/52 = 30.7%

//   sei(); //set interrupts
}  // end of setup


void loop() 
{
  digitalWrite(12,LOW);
  delay(200); //actual delay i get is 1ms instead of 200ms so scale of 200
  digitalWrite(12,HIGH);
  delay(200);
}

The above code generates a waveform at pin 12 that is 200 times faster than the code, but if i comment the "TIMSK0 = 0;" part and rather use clear and set interrupt commands (cli() sei()) i start getting an erratically toggling output at pin 12.

Please help me understand if there is any relation at all between timer 0 and any digital IO or if there is a mistake in above approach. I did try to read the relevant sections in ATmega328P datasheet but unable to find any such thing.

I am attaching four CRO snapshots:

*OC0B-out.jpg : OC0B output that is correctly generating 38.4kHz@30%duty cycle
*cli-sei-enabled.jpg : Pin 12 toggle rate when TIMSK0 is commented and cli+sei are enabled
*TIMSK0-enabled.jpg: Pin 12 toggle rate when TIMSK0 is enabled and cli+sei are commented
*timer-0-disabled.jpg: Pin 12 toggle rate (correct as programmed) when timer0 part of the code is disabled

You can't generally alter the configuration of timer0 and expect things like millis() and delay() to work correctly.
Chose another timer which is not used to support these Arduino functions.

@6v6gt:

On a larger level I want to use all the three timers:

Timer0 : 38kHz@30%
Timer1 : 500Hz@20%
Timer2: ~60Hz@2%

I could realize all the above waveforms. Problem started afterwards when I tried to toggle a general digital IO (finally to be used to drive an indicator LED to indicate "idle" or "active" state) and it didn’t toggle at the rate I programmed. After gradually truncating different code parts and the timers I finally realized the toggling misbehaves when timer0 is active. As a solution I may decide not to use timer 0 at all and generate one of the three waveforms using simple digitalWrite commands but this will be only a workaround without knowing the real reason.

manoj_singh:
As a solution I may decide not to use timer 0 at all and generate one of the three waveforms using simple digitalWrite commands but this will be only a workaround without knowing the real reason.

6v6gt told you the reason in his reply, timer0 is used to generate the timing for functions such as delay(), millis(), micros(), etc. With a clock frequency of 16MHz, the prescaler is set to 64 and the millis() count is updated with the timer0 overflow interrupt, generating an interrupt every 1.024mS (a frequency of 976.5625Hz), and micros() gets its value from the timer0 count. Altering timer0 will affect all of these, so you cannot expect delay() to work normally.

You may want to consider switching to a Mega with 5 timers available.