How to reduce interrupt jitter?

Hi all,

An Arduino newbie here.

I am trying to use an Arduino Mini Pro 328P 5V 16Mhz https://www.sparkfun.com/products/11113 for signal decoding and am encountering interrupt jitter more than I expected. Below is a test program, it uses timer 1 in Fast PWM mode to generate 20Khz pulses on OC1B which also triggers an interrupt routine that pulses the LED.

When connecting the PWM output to scope channel 2 (trigger) and the LED output to scope channel 1 I am seeing a jitter of 4.5usec (~70 cycles) in the start time of the LED pulse relative to OC1B. I suspected some background interrupts (timer0?) and tried to disabled them for no avail. (scope is in infinite screen persistence mode)

Any idea what can cause the jitter and how to avoid it (I don't need any other interrupt other than the above).

Thanks, Zapta

// Fast LED ops (pin 13).
#define LED_MASK (0b00100000) 
#define LED_INIT {DDRB  |=  LED_MASK;}
#define LED_ON   {PORTB |=  LED_MASK;}
#define LED_OFF  {PORTB &= ~LED_MASK;}

void setup()
{
  LED_INIT;

  // Timer1 OC1B cycle pulses. For debugging.
  pinMode(10, OUTPUT); 

  // Disable a few unused interrupts
  TIFR0 = 0;
  TIFR2 = 0;
  UCSR0B = 0;

  // Prescalar = 1, mode = Fast PWM.
  TCCR1A = 0b00100011;  //
  TCCR1B = 0b00011001;  
  
  // Top count for 20khz.
  OCR1A = 800 - 1;
  
  // 0.5us cycle start positive pulse on OC1B
  OCR1B = (16*1)/2 - 1; 
  
  // Clear pending interrupt so we don't get a false one on start.
  TIFR1 &= 0b00000010; 
  
  // Enable compare A match interrupts.
  TIMSK1 = 0b00000010; 

  sei(); 
}

ISR(TIMER1_COMPA_vect)
{
  LED_ON;
  LED_OFF;
}

void loop()
{
  for(;;) { }
}

Add this...

TCCR0B = 0;
TCCR0A = 0;

[quote author=Coding Badly link=topic=206513.msg1519269#msg1519269 date=1387910711] Add this...

TCCR0B = 0;
TCCR0A = 0;

[/quote]

Bingo! With your code I get 1 clock cycle jitter. Better than I expected. I guess this is because of the 2 cycle instructions. Thanks Badly.

Now that the interrupts are disabled (like it and will keep it this way), what are my options? Is there a simple non interrupt serial output library that I can use for debugging, even a blocking call should be fine? What about a crude delay()?

I think can figure out how to implement them myself but would be nice to use something of the shelf.

EDIT: on a second thought, the serial does not need to be blocking. It can use buffers and poll using a serial_update() method calls from loop().

zapta: I guess this is because of the 2 cycle instructions.

Yes.

Thanks Badly.

You are welcome.

Is there a simple non interrupt serial output library that I can use for debugging, even a blocking call should be fine?

Use HardwareSerial from a version before 1.0.

What about a crude delay()?

http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html Pay close attention to the warnings.

EDIT: on a second thought, the serial does not need to be blocking. It can use buffers and poll using a serial_update() method calls from loop().

That should work well. I suspect modifying the pre-1.0 HardwareSerial to be polling would not be too much work.

Thanks Badly. Very useful pointers. I looked at the examples and came with this simple class that uses uart hardware but no interrupts. I need tx only so did not bothered with rx.

#ifndef DEBUG_OUT_H
#define DEBUG_OUT_H

#include <arduino.h>
#include <print.h>

// A serial output that uses hardware uart0 but with no interrupts.
// Requires periodic calls to update();
class DebugOut : 
public Print {
public:
  DebugOut() 
: 
    _start(0),
    _count(0) {
    }

  void init() {
    // 38400 baud @ 16MHz.
    UBRR0H = 0;
    UBRR0L = 25;
    // Enable  the transmitter. Reciever is disabled.
    UCSR0B = (1 << TXEN0);
    UCSR0C = (3 << UCSZ00);  
  }

  // Overrides Print::write().
  size_t write(uint8_t b) {
    if (_count >= kQueueSize) {
      return 0;
    }
    enqueue(b);
    return 1;
  }

  // Called periodically from loop() to do the transmission. Non
  // blocking.
  void update() {
    if (_count && ( UCSR0A & (1 << UDRE0))) {
      UDR0 = dequeue();
    }
  }
  
  bool is_empty() {
    return !_count;
  }

private:
  // Max TX queue size. Should be less than 255/2 to 
  // avoid byte arithmetic overflow below.
  static const byte kQueueSize = 80;
  byte _buffer[kQueueSize];
  
  // Index of first (oldest) byte. [0, kQueueSize).
  byte _start;
  
  // Number of bytes in the queue. [0, kQueueSize].
  byte _count;

  // Assumes _count < kQueueSize.
  void enqueue(byte b) {
    // kQueueSize is small enough that this will not overflow.
    byte next = _start + _count;
    if (next >= kQueueSize) {
      next -= kQueueSize;
    } 
    _buffer[next] = b;  
    _count++; 
  }

  // Assumes _count > 0.
  byte dequeue() {
    const byte b = _buffer[_start];
    if (++_start >= kQueueSize) {
      _start = 0;
    }
    _count--;
    return b;  
  }
};
#endif

I will do something similar for having millis() without interrupts. 16 bit Timer 1 running freely with some prescaler, periodic update() calls from loop() that read the timer, detects overflows and computes a milliseconds time (I need one value per loop iteration, the loop code is not blocking). Between these two I think I have everything I need to start writing my real code.

Your help is greatly appreciated.