volatile bool     isr_t0a_flag = false;
volatile uint32_t isr_t0a_delta_time = 0;
#define           TIMER_0_COMPARE_A_POST_SCALER 50

volatile bool     isr_t0b_flag = false;
volatile uint32_t isr_t0b_delta_time = 0;
#define           TIMER_0_COMPARE_B_POST_SCALER 100

void PrintTimer0()
{
  char buffer[20];
  Serial.println("\nTimer 0");
  sprintf(buffer, "  TCCR0A = 0x%02x", TCCR0A);
  Serial.println(buffer);
  sprintf(buffer, "  TCCR0B = 0x%02x", TCCR0B);
  Serial.println(buffer);
  sprintf(buffer, "  OCR0A  = 0x%02x", OCR0A);
  Serial.println(buffer);
  sprintf(buffer, "  OCR0B  = 0x%02x", OCR0B);
  Serial.println(buffer);
  sprintf(buffer, "  TIMSK0 = 0x%02x", TIMSK0);
  Serial.println(buffer);
}

void setup()
{
  Serial.begin(115200);
  Serial.print("\n");
  
  // Find out what Timer0 has been initialised to.
  PrintTimer0();
  // Serial.println(TCCR0A, HEX);  // 3 = Fast PWM mode with a fixed timeout of 255.
  // Serial.println(TCCR0B, HEX);  // 3 = 64 prescaler.
  // Serial.println(OCR0A, HEX);   // 0
  // Serial.println(OCR0B, HEX);   // 0
  // Serial.println(TIMSK0, HEX);  // 1 = Timer overflow interrupt enabled for millis()/micros().
  // Serial.print("\n\n");

  cli(); // Disable interrupts.

  //
  // Set Timer0 compare interrupts
  //
  // Clock frequency     = 16 MHz
  // Prescaler           = 64
  // Timeout             = 255
  //
  // Overflow interrupt frequency = 16 MHz / 64 / (255 + 1) = 977 Hz (1024 us)
  // Overflow interrupt frequency =  8 MHz / 64 / (255 + 1) = 488 Hz (2048 us)
  //
  OCR0A  = 0x55;            // Set 1/3rd phase shift for compare A.
  OCR0B  = 0xAA;            // Set 2/3rds phase shift for compare B.
  TIMSK0 |= (1 << OCIE0A);  // Enable compare A interrupt.
  TIMSK0 |= (1 << OCIE0B);  // Enable compare B interrupt.

  sei(); // Enable interrupts.

  // Verification.
  PrintTimer0();
  // Serial.println(TCCR0A, HEX);  // 3   = Fast PWM mode with a fixed timeout of 255.
  // Serial.println(TCCR0B, HEX);  // 3   = 64 prescaler.
  // Serial.println(OCR0A, HEX);   // 85  = 1/3rd phase shift for compare A.
  // Serial.println(OCR0B, HEX);   // 170 = 2/3rds phase shift for compare B.
  // Serial.println(TIMSK0, HEX);  // 7   = All 3 interrupts enabled.
  // Serial.print("\n\n");
}

void loop()
{
  uint32_t t0a_delta_time = 0;
  uint32_t t0b_delta_time = 0;

  ////////////////////////////
  // BEGIN CRITICAL SECTION

  cli();  // Disable interupts.

  bool t0a_flag = isr_t0a_flag;
  if (t0a_flag)
  {
    t0a_delta_time = isr_t0a_delta_time;
    isr_t0a_flag = false;
  }

  bool t0b_flag = isr_t0b_flag;
  if (t0b_flag)
  {
    t0b_delta_time = isr_t0b_delta_time;
    isr_t0b_flag = false;
  }

  sei();  // Enable interrupts.

  // END CRITICAL SECTION
  ////////////////////////////

  if (t0a_flag)
  {
    Serial.print("T0a ");
    Serial.println(t0a_delta_time);
  }

  if (t0b_flag)
  {
    Serial.print("T0b ");
    Serial.println(t0b_delta_time);
  }
}

ISR(TIMER0_COMPA_vect)
{
  static byte count = 0;
  count++;
  if (count >= TIMER_0_COMPARE_A_POST_SCALER)
  {
    count = 0;
    static uint32_t previous_time = 0;
    uint32_t time = micros();
    uint32_t delta_time = time - previous_time;
    previous_time = time;
    isr_t0a_delta_time = delta_time;
    isr_t0a_flag = true;
  }
}

ISR(TIMER0_COMPB_vect)
{
  static byte count = 0;
  count++;
  if (count >= TIMER_0_COMPARE_B_POST_SCALER)
  {
    count = 0;
    static uint32_t previous_time = 0;
    uint32_t time = micros();
    uint32_t delta_time = time - previous_time;
    previous_time = time;
    isr_t0b_delta_time = delta_time;
    isr_t0b_flag = true;
  }
}