Timer measurement problem

My goal is to measure the time between two sensor interrupts accurately. From what I read in other posts I understand the normal timer library with micros() should be good for a resolution of 4us.

In order to test the accuracy I wanted to use two Arduinos. The first Arduino RECEIVER shall measure the time, whereas the second Arduino SENDER provides the signal (based on a code from letmakerobots.com).

Please see below for both codes.

My problem is that the RECEIVER shows values between 999432us and 999448us while I would expect it to show 1000000us, maybe +/- 4us (which is what the SENDER should provide).

In case that matters, I am using a Mega2560 as receiver and a Micro as sender. Pin 2 of the receiver is connected to pin 12 of the sender.

Can anyone help me what I am missing?

Thanks
Chris

//RECEIVER

const int sensor = 0; //AKA digital pin 2

long lap_time = 0;
volatile unsigned long meas_old = 0;
volatile unsigned long meas_new = 0;

void setup()
{
 Serial.begin(115200);
 attachInterrupt(sensor, measure, RISING);
}

void measure()
{
 meas_new = micros();
}

void loop()
{
  lap_time = meas_new - meas_old;
  if (meas_new != meas_old && lap_time > 500000)  //software debouncing
   { 
    Serial.println(lap_time);
    meas_old = meas_new; //set new reference time  
   }
}
//SENDER
/* 
 * Arduino 101: timer and interrupts
 * 2: Timer1 overflow interrupt example 
 * more infos: http://www.letmakerobots.com/node/28278
 * created by RobotFreak 
 */

#define ledPin 12

void setup()
{
  pinMode(ledPin, OUTPUT);

  // initialize timer1 
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;

  //TCNT1 = 34286;          // preload timer 65536-16MHz/256/2Hz
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
}
// interrupt service routine that wraps a user defined function 
// supplied by attachInterrupt
ISR(TIMER1_OVF_vect)        
{
  TCNT1 = 34286;            // preload timer
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);
}

void loop()
{
  // your program here...
}

long lap_time = 0; use: unsigned long lap_time = 0;

One thing you have to contend with is that the actual clock speed of two separate Arduinos may not be the same.

Another thing is that when you read the value of meas_new you should do it like this

void loop() {
   meas_old = latestReading;
   noInterrupts();
       latestReading = meas_new;
   interrupts();

   // other code
}

to avoid the risk that the value of meas_new might change while it is being read.

It would also be a good idea to have the ISR record when a new value arrives - for example

void measure()
{
 meas_new = micros();
 newValue = true;
}

and then only read the value of meas_new when a new value has arrived.

...R

One thing you have to contend with is that the actual clock speed of two separate Arduinos may not be the same.

This is likely the cause of what you are seeing. You can run your sketch on one Arduino and jumper pin 12 to pin 2. I see a consistent 1000000 when I do that.

const int sensor = 0; //AKA digital pin 2
#define ledPin 12

long lap_time = 0;
volatile unsigned long meas_old = 0;
volatile unsigned long meas_new = 0;

void setup()
{
  Serial.begin(115200);
  attachInterrupt(sensor, measure, RISING);
  pinMode(ledPin, OUTPUT);

  // initialize timer1
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;

  //TCNT1 = 34286;          // preload timer 65536-16MHz/256/2Hz
  TCCR1B |= (1 << CS12);    // 256 prescaler
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
}

void measure()
{
  meas_new = micros();
}

void loop()
{
  lap_time = meas_new - meas_old;
  if (meas_new != meas_old && lap_time > 500000)  //software debouncing
  {
    Serial.println(lap_time);
    meas_old = meas_new; //set new reference time
  }
}

ISR(TIMER1_OVF_vect)
{
  TCNT1 = 34286;            // preload timer
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);
}

Thank you for all your input so far. I tried all the suggest changes, but this doesn't change the outcome.

Running both sketches on one Arduino is no option. The whole idea of the second Arduino was to check whether the first sketch is capable of accurately measuring time, be it a signal from a second Arduino or later on from an external sensor. Having both driven from the same chip just means the signal as well as the reading can be off by the same amount.

In the meantime I figured out, that not only are the measurements off by ~500 microseconds, but also this is sensitive to ambient temperature! If I heat up the receiver, e.g. just breathing upon it is sufficient, the gap widens.

After all it looks like accurate time measurement in microseconds (or 4us intervals) will not be possible with an Arduino :-(

Maybe one of the experts can let me know if time measurement with an Arduino generally is temperature sensitive? ...and whether there is any solution for that?

The process you are using for testing is inadequate.

If you want to verify whether an Arduino is capable of absolute time-keeping accuracy you need a very accurate timer source and another Arduino won't provide that. It's a bit like asking one drunkard if the other drunkard is sober.

I also think you have not adequately described what you want to achieve.

I think an Arduino will be sufficiently accurate to compare one interval with another over a short period of time. The differences will be useful even though it may not be able to "say" exactly what the time interval is.

But if you need absolute accuracy you need a suitably accurate source for calibration. A Real Time Clock (RTC) module may be an option, although I don't know if they expose their data at the level of microseconds.

...R

AFAIK, most Arduinos are clocked by an inaccurate/instable resonator, not by a crystal. A crystal would have been $0.50 more expensive.

Some boards (my Mega) have board space for a crystal. Leo..

As said, I want to...

measure the time between two sensor interrupts accurately

...meaning absolute time in microseconds, no comparison between multiple intervals. I understand now the Arduino neither is an accurate source nor reader, this needs additional hardware.

Thanks for your help.

@Leo, may I ask which Mega board are you using?

Not sure, but this might be the solution...

http://www.adafruit.com/datasheets/Si5351.pdf

ra_duino: @Leo, may I ask which Mega board are you using?

Just a spare Mega 2560 Funduino with holes for a crystal and pads for two smd caps. Strange. The USB interface uses a 16Mhz crystal.

Some posters here have replaced resonators with crystals. Maybe they can chime in. Leo..

Interestingly enough the Micro uses a KX-7 quartz crystal whereas the Mega2560 just has a CSTCE16M0V53-R0 ceramic resonator :confused:

Hi, Have you swapped arduino controllers so the Rx is now the TX and the TX is now the Rx.

Tom.... :)

I swapped the two boards, resulting in approx. +560us deviation (Receiver showing 1000560us), whereas the original setup had the opposite approx. -560us (as described in my first post).

Hi, Okay, if you programmed 2 seconds instead of 1 second, what do you get? Its to see if the difference is due to an offset or a proportional error.

Tom.... :)

I ran it with 2s, 1s, 0.5s and 0.2s in both directions. The relative deviation is constant at 540-560ppm (e.g. 1100us for 2s, 560us for 1s, 276us for 0.5s and 110us for 0.2s)

Best,
Chris

Hi, Good, so you have found the differences are proportional, and they are stable you should be able to calibrate it out. But finding out if both or one of the controllers is out is going to be the challenge, you need a known accurate timebase.

I'm not sure what the application is?

Tom..... :)

The final application is meant to be a lap timer/speedometer for control line model airplanes. The actual trigger signal will be provided by a laser reflection light scanner. I need to cut down the timing error to less than 100ppm in order to get the accuracy needed.

Unsure whether this is feasible with the stock Arduino hardware. The more I research, the more I think I will need a TCXO reference clock for the MCU. However, as I am not able to build my own board, this might become a challenge.

Thx

The problem is the Mega >:( …why they have chosen to use a ceramic resonator is unclear to me.

I have now used a Micro and a Due in the same setup, this gives deviations of <20ppm, which is much more acceptable.

Some of the clone uno's are now coming with two crystals. I think this must be a result of the changing costs of crystals and resonators.

For example see http://www.ebay.com/itm/NEW-UNO-R3-ATmega328P-CH340-Mini-USB-Board-for-Compatible-Arduino-/311155383820?hash=item48724e5e0c:g:QKMAAOSwdpxUU0UP

I have not looked at images of the Mega clones, but you might see one with two crystals if you look.

If the Micro or the Due are not the solution for you, you might want to look at one of the two crystal clones.

Hi,

Why do you need high accuracy, ie exactly 1 standard second, , if the racing is done against the clock, all you need is a stable time base.

Tom.... :)