uS Timing Measurement

allanhurst:
How accurate do you need to be?

You can buy frequency counters for exactly this purpose - but the price depends strongly on the resolution, precision and maximum frequency.

Your problem is intermediate - if you want to know the frequency ( about 1kHz ) accurately to 1ppm, you'll either need a million counts - about 16 minutes - or determine the pulse width to within < 1nS - very difficult!

Allan

Thanks for the lesson. Did a little google searching and see the need for two different instruments. Maybe I get a GPS chip and count the PPS signal over time and average that out while minimizing changes in Temp and voltage. Something similar to the experiment I linked above. How precise is the PPS?

There can be no overflow for up to 65536 16-bit ints added up and stored in a 32-bit int.

Would that account for overflow?

As said before, transfer the value of TCNT1 into an unsigned long variable. If you subtract the previous value from the last one to determine the interval, the overflow is not an issue. It's similar to the standard millis() timer for an interval which is unaffected by overflow..

The only time you need to account for an overflow is if the period between the triggering pulse edges is greater than 4096 microseconds.

bronco9588:
Jeez you are dense... everybody else seems to understand.

But Robin2 was right in what he said though. When you opened your post, you definitely wrote 'time between a rising pulse' .... or something like that.

When you think about it..... the sentence 'time BETWEEN a rising pulse' does not make sense, because when a "rising pulse" is mentioned..... the word 'between' has no meaning.

This is where the saying ..... 'a picture is worth a thousand words' has meaning. So, either a picture can help things along - so that people can use the picture plus the words to get a clearer understanding of what you wanted. Or alternatively, read over what was written - to ensure no ambiguity.

I think one or two other people got confused in the end about your objective as well - as it seemed like a goal post shift. Robin2 was kind of gesturing to you to explain what you need - clearly, from the beginning. That's about it really.

It is the time from the rise of one pulse to the rise of a second pulse. The period of time from one pulses rise to another pulses rise will be about 1ms apart. This is NOT how long a single pulse takes to rise. Clarification about application has now been made for a 4th time. If Robin2 would have read the more recent clarification he would either ask a question, contribute to information, or be silent.

bronco9588:
Jeez you are dense... everybody else seems to understand. Take a square wave, a step function, TTL, I don't care... be able to accurately and precisely measure the time period or frequency between two pulses that occur about 1 ms apart with an uno. I could draw a picture but it would be a waste of paper.

I don't think I am dense. The words I have in bold have a very different meaning from these words from your Reply #14

I have approximately 0.1 millisec or 1600 clock cycles. My sample code will attempt to measure 6 pulses every 1600 clock cycles.

If you really are trying to measure pulses that are 1 millsec apart then the suggestion I made back in Reply #10 still seems appropriate to me.

...R

The gps 1pps signal is extremely accurate - based on atomic clocks in the satellite.

So a good approach might be for you to use this as a gate of eg 10 seconds, Count the number of pulses AND the time non synchrony at the beginning and end of the gate.

All the above presumes your signal has no 'jitter' - ie that your pulses occur at exactly the same intervals - is this true?

Allan

@Robin2:
Sorry but I think the topic is quite clear from the beginning. OP wants to measure time between two rising edges of the signal as accurately as possible. The edges are about 1ms apart. I don't see anything confusing on this. On his own he found Input Capture feature of Timer/Counter 1 of Arduino Uno. This feature gives resolution down to 1 CK. He managed to write test program able to properly read pulses 5us apart - coming much faster than expected 1ms and so "proving" it will work at "worst case" conditions.
On the other side you suggest in post #10 using interrupts. You write

Robin2:
I wonder if the overhead from an interrupt triggering to something getting completed (such as writing a microsec value into a variable) always takes the same number of clock cycles.

This is NOT true and it is poor way to do something like that. In this approach two sources of glitches will come: small glitches will occur when interrupt comes while a multi-cycle instruction is being executed because the instruction must be finished before jumping to the ISR. Large glitches may arise when interrupts are disabled. Such as during execution of any (other) ISR - a lot of default Arduino functionality is interrupt driven so unless you get rid of millis and other sources of "hidden interrupts" the approach depending on interrupts is nearly unusable.

Considered off loading this to a hardware option? I don't have the time to read all the replies but I can't see much of a suggestion on this last page (and it may have already been discarded)...

But if you have a 10MHz oscillator (100ns resolution) increment a 14-stage binary counter that is then feeding the top 8 stages (because your value is "around" 1ms) in to a latching parallel to serial (SPI protocol) IC. The rise of the signal causes the parallel-serial IC to latch and also put its output pins (the to 8 bits of the count) HIGH (which can trigger the arduino to read it via SPI) and also resets the counter ready for the next pulse on a fall of the signal.

14 bits = 2^14
10MHz = 0.1uS

2^14 * 0.1uS = 1.6384 milliseconds before a 14 bit counter hits its TOP.

Johnny010:
Considered off loading this to a hardware option?

The hardware you described is nice and definitely an option. "Problem" is that ATMega already has such hardware onboard. It is named Input Capture mode of Timer/Counter1 and OP already mentions it in his first (!) post. Why people continue in this futile discussion suggesting more and more obscure solutions is mystery for me. IMHO OP is on the right track but everyone seems to do their best to distract him. The only problem of using Arduino Uno is "poor" stability of used ceramic resonator. But any other method aiming for better accuracy must get better clock source and there is no reason why (standalone) ATMega couldn't use such clock source to get the same accuracy.

Smajdalf:
The hardware you described is nice and definitely an option. "Problem" is that ATMega already has such hardware onboard. It is named Input Capture mode of Timer/Counter1 and OP already mentions it in his first (!) post. Why people continue in this futile discussion suggesting more and more obscure solutions is mystery for me. IMHO OP is on the right track but everyone seems to do their best to distract him. The only problem of using Arduino Uno is "poor" stability of used ceramic resonator. But any other method aiming for better accuracy must get better clock source and there is no reason why (standalone) ATMega couldn't use such clock source to get the same accuracy.

Ok, true.

But The OP has not yet said much about the processing of the data after...
Saying it is 1ms between pulses and they must get all of them...

I am unsure how long it'd take, but yeah, maybe ~16000 clock cycles is enough to maybe do some averages, serial out etc.

Smajdalf:
@Robin2:
Sorry but I think the topic is quite clear from the beginning. OP wants to measure time between two rising edges of the signal as accurately as possible. The edges are about 1ms apart. I don't see anything confusing on this.

What you describe is very clear, But it is not what the OP said in some of his Posts.

On the other side you suggest in post #10 using interrupts. You write This is NOT true and it is poor way to do something like that.

I have no problem with sensible criticisms of my suggestion.

...R

Smajdalf:
@Robin2:
Sorry but I think the topic is quite clear from the beginning.

It might have sorted itself out somewhere after the beginning. But the topic was definitely not clear from 'the beginning' (eg. opening post). As Robin2 indicated, your definition was very clear. But the opening post does indeed say 'time between a rising pulse'. It should have correctly said something like .... "time between the rising edges of two pulses" or something along those lines. The 'time between a rising pulse' could mean ..... well.... it doesn't 'actually' mean anything clear. But some people might interpret it as pulse width measurement (measurement of width of a pulse).

The diagram below would make everything clear to all.

bronco9588:
Would that account for overflow?

1 ms, your average time to measure is 16000 cycles. Unsigned 16 bit counts to 32767. What's the problem?

Since the time values are unsigned you can always subtract an earlier time from a later time to know the elapsed time regardless of unsigned rollover. It's a non-issue as long as you do the unsigned subtraction. It's like a 12 hour clock. The number of hours starting at 9 and ending at 2 are 2 - 9 = 5. To subtract 9 from 2, move counter clockwise 9 from 2 and you have the answer 5. That is unsigned subtraction. As long as your time variables can hold the largest interval needed, you're good.

You might look into just how accurate the 16MHz of your boards really is.

Southpark:
The diagram below would make everything clear to all.

That is spot on...

GoForSmoke:
1 ms, your average time to measure is 16000 cycles. Unsigned 16 bit counts to 32767. What's the problem?

Since the time values are unsigned you can always subtract an earlier time from a later time to know the elapsed time regardless of unsigned rollover. It's a non-issue as long as you do the unsigned subtraction. It's like a 12 hour clock. The number of hours starting at 9 and ending at 2 are 2 - 9 = 5. To subtract 9 from 2, move counter clockwise 9 from 2 and you have the answer 5. That is unsigned subtraction. As long as your time variables can hold the largest interval needed, you're good.

You might look into just how accurate the 16MHz of your boards really is.

I think I understand what you are saying. More than half the time, time2 is truly greater than time1 and the clock has not reset. This becomes more of an issue when I was doing the following:

volatile unsigned long Time1;
volatile unsigned long Time2;
...
unsigned long deltaTime1 = Time2 - Time1;

I think what I need is:

volatile uint16_t Time1;
volatile uint16_t Time2;
...
uint16_t deltaTime1 = Time2 - Time1;

...and this would work as long is I do not exceed 2^16-1/16,000,000 seconds?

Smajdalf:
The only problem of using Arduino Uno is "poor" stability of used ceramic resonator. But any other method aiming for better accuracy must get better clock source and there is no reason why (standalone) ATMega couldn't use such clock source to get the same accuracy.

I thought the UNO uses a crystal vice a ceramic oscillator. Truly I thought there is a ceramic oscillator onboard and a crystal mounted to the PCB. Is this not correct?

I am going to be buying a GPS shield for the PPS signal. I hear it is accurate to within 10ns if you have a 4 satellite fix. So safe to say it is more precise and accurate than arduino. Ultimately I would like to keep the timer separate from a GPS, but use the GPS to characterize the UNOs crystal. I plan to characterize the uno's crystal over a period of a couple weeks. Time to figure out an allan deviation. My plan is to use the atmegas on-board temperature sensor to temperature compensate the crystal. I understand that Tchip does not equal Tcrystal but assume that it will be close enough. If temperature compensation is not effective, I may just keep the GPS attached and have some boot up routine that characterizes the crystal.

The actual measurement will use timer1 with no prescaler and timer0 or timer2 prescaled to cover about 2 seconds (I also could use software and assume the pulses are 1 second apart and forgo the second timer). Every second I will store the clock cycles per second and then analyze the data. I am assuming the PPS is a short duration 5 volt high pulse at 1 second intervals.

bronco9588:
I think I understand what you are saying. More than half the time, time2 is truly greater than time1 and the clock has not reset.

ALL of the time, the later time is in the positive, clockwise direction from the earlier time, regardless of positions relative to zero or any other time. Elapsed time will always be end time - start time as long as the interval is less that the clock limit.

If you are timing micros with 16 bit unsigned values, the longest you can time will be 65535 micros. Since your window is around 1000 micros you should be safe.

I

thought the UNO uses a crystal vice a ceramic oscillator. Truly I thought there is a ceramic oscillator onboard and a crystal mounted to the PCB. Is this not correct?

There's a crystal for the USB chip but a ceramic resonator for the AVR chip.
You can breadboard/build a standalone AVR with a crystal or buy a board with one. Nick Gammon has a tutorial for that that I've not seen the equal of yet and I did go by the Arduino site tutorial first time, never again!

I think that you should spend time checking into options before making plans. See if the Teensy 3.6 has a crystal, it can overclock to 240MHz which should let you get more than the precision desired. When you have to measure to a single cpu cycle on a programmed device it's like you're looking for something to go wrong.

GoForSmoke:
There's a crystal for the USB chip but a ceramic resonator for the AVR chip.
You can breadboard/build a standalone AVR with a crystal or buy a board with one. Nick Gammon has a tutorial for that that I've not seen the equal of yet and I did go by the Arduino site tutorial first time, never again!

I think that you should spend time checking into options before making plans. See if the Teensy 3.6 has a crystal, it can overclock to 240MHz which should let you get more than the precision desired. When you have to measure to a single cpu cycle on a programmed device it's like you're looking for something to go wrong.

  1. That is a little disappointing WRT the oscillator. Do you think I could hack the board to get the onboard crystal to drive the AVR AND USB? Again, I have not done much data collection yet as I am waiting on buying a GPS board. It appears crystals are 2 orders of magnitude more precise than oscillators. As far as Teensy, I have looked at it and I don't see the appeal. It is a little bit more foreign than my experience with arduino. Sure I will get 10 times the clock frequency (precision) but will be using an oscillator (accuracy). I currently have an accuracy issue. I have proven that input capture with zero prescaler has the precision that I need. (This is not to say that I won't go for higher speed clocks in the future.)

  2. Here is my code I used to prove how arduino counts. Is this the fastest way to do averaging of 2^n samples?

void setup () 
  {
  Serial.begin(9600);
  Serial.println("Overflow Counter");
  }

void loop () 
{
  // wait till we have a reading
 uint16_t Time1 = 65534;
uint16_t Time2 = 65535; //65536 is interpreted as 0. Therefore it does not exist.
uint16_t Time3 = 0;
uint16_t Time4 = 1;
uint16_t Time5 = 2;

 
  // period is elapsed time
uint16_t deltaTime1 = Time2 - Time1;
uint16_t deltaTime2 = Time3 - Time2;
uint16_t deltaTime3 = Time4 - Time3;
uint16_t deltaTime4 = Time5 - Time4;

uint32_t timeSum = deltaTime1 + deltaTime2 + deltaTime3 + deltaTime4;

uint16_t timeAverage = timeSum >> 2;

    
  Serial.print ("T1,T2,T3,T4,T5: ");
  Serial.print (Time1);
  Serial.print (", ");
  Serial.print (Time2);
  Serial.print (", ");
  Serial.print (Time3);
  Serial.print (", ");
  Serial.print (Time4);
  Serial.print (", ");
  Serial.print (Time5);
  Serial.println (" timestamp. ");   

  Serial.print ("Took: ");
  Serial.print (deltaTime1);
  Serial.print (", ");
  Serial.print (deltaTime2);
  Serial.print (", ");
  Serial.print (deltaTime3);
  Serial.print (", ");
  Serial.print (deltaTime4);
  Serial.println (" cycles. ");

  Serial.print ("Time Sum: ");
  Serial.print (timeSum);
  Serial.print (", ");
  Serial.print ("Time Average: ");
  Serial.print (timeAverage);
  Serial.println (" cycles. ");

  // so we can read it  
   delay (10000);

}   // end of loop

bronco9588:

// period is elapsed time

uint16_t deltaTime1 = Time2 - Time1;
uint16_t deltaTime2 = Time3 - Time2;
uint16_t deltaTime3 = Time4 - Time3;
uint16_t deltaTime4 = Time5 - Time4;

uint32_t timeSum = deltaTime1 + deltaTime2 + deltaTime3 + deltaTime4;

uint16_t timeAverage = timeSum >> 2;

Is the same as:

uint16_t timeAverage = (Time5 - Time1) >> 2;

as long as the total time elapsed is less than 65535 micros, which should be the case for four times of about 1000 micros each.

bronco9588:
Do you think I could hack the board to get the onboard crystal to drive the AVR AND USB?

Considering that it has taken until Reply #54 to get an agreed and clear understanding of the requirement, what do you think of your chances?

...R

I think I need to get a Duemilanove board to use the crystal for timing to raise my accuracy.