Stange behavior of micros() between atmega328p and atmega168

Hi,

I’m just wondering if someone has already got this behavior. I have a piece of code that computes a precise mesure of 250.00ms. An optical signal fires the INT0 and the code simply saves the micros() between signals. If I test the code with an Arduino Diecimila (a168) and an Arduino pro mini (a328p) (3.3V or 5V) I get an difference of the time of 300 microseconds (250.000 on diecimila and 250.300 on pro mini 3.3V or 5V)!

Any idea?

– olivier

Let’s see the code…

At first I thought it was because of resonators but both boards appear to use crystals. Still, there is always going to be some error and .12% is a bit out of spec for typical crystals (actually, it could be 0.0625%, one high and the other low). It would be strange if they both agreed to the microsecond. 50 ppm crystals could yield up to a difference of 25 microseconds.

What’s the standard deviation of timing for each processor ?

skimask:
Let’s see the code…

void onchange(){
  _change=!_change;
  if (!_change) onup();else ondown();
}
void onup(){}
void ondown(){
  long itime=micros();
  timeus=itime-time; //get a full periode on down:_┌─┐_______┌─┐_
  time=itime;
  // avoid overflow
  if (usi<SAMPLES){
    us[usi]=(timeus)/1000.0;
    usi++;
  }
  ...
}
...
void setup(){
   ...
   // bind ardware interuption on pin 2
   attachInterrupt(0,onchange,CHANGE);  
  ....
}

void loop(){ 
  //clean buffer
  usi=0;
  time=0;
  //measure 1s
  _sample=true;
  digitalWrite(P_SENS, HIGH);  
  delay(1000);
  digitalWrite(P_SENS, LOW);  
  delay(2);
#ifdef CC_DEBUG
  // vref 5V=5.0/1024.0=0.0048828, 3.3/1024.0=0.0032226 
  Serial.print(" SAMPLES: ");
  for (int i=2;i<(usi);i++){
    Serial.print(us[i],4);
    Serial.print(" ");
  }
  Serial.println();
#endif
....

Mee_n_Mac:
What’s the standard deviation of timing for each processor ?

The average of 200[microseconds] is in fact the sum of 8 samples that composes the 250[ms]. I took a picture of the deviation between the 168 and the 328p. One other thing interresting, the deviation is about 200[us] [u]but there is no relevant deviation between two 328p board[/u].

Philba:
At first I thought it was because of resonators but both boards appear to use crystals. Still, there is always going to be some error and .12% is a bit out of spec for typical crystals (actually, it could be 0.0625%, one high and the other low). It would be strange if they both agreed to the microsecond. 50 ppm crystals could yield up to a difference of 25 microseconds.

What is the formula to get the delta from the ppm?

thank you very much for helping!!!

– olivier

That’s some wild data. Let me define some terms. You have 3 sets of data, each set consisting of 8 trials, for both the 328p and the 168. The expected timing may differ from trial to trial, no doubt due to some differing experimental conditions trial to trial. But the same trial should be consistent from set to set and ideally from 328p to 168. So looking at the data I see cases where the 328p is faster than the 168 and cases were it’s slower. But it’s consistent faster or slower from set to set. That is some trials are consistently slower on the 328p and others are consistently faster.

Look at trial #2 data from set to set. The 328p consistently clocks fewer “micros” than the 168 does, by a fair % too (~500 usecs out of 27+ msecs → ~2%). Seems that the ref clock on the 328p is slower than that of the 168. But then there’s trial #3 where the 328p consistently clocks more micros (some 950+) than does the 168, indicating it’s ref clock is now faster than the 168 … and that’s 0.95 msec out of ~52+ msecs, again ~2%.

So it’s not a simple case of 1 reference clock being slower or faster and it’s not random jitter either. I’m lost for a good explanation ATM. :?

Are you sure you didn’t swap some of the 328p data with the corresponding 168 data ? :mrgreen:

Mee_n_Mac:
That’s some wild data. Let me define some terms. You have 3 sets of data, each set consisting of 8 trials, for both the 328p and the 168. The expected timing may differ from trial to trial, no doubt due to some differing experimental conditions trial to trial. But the same trial should be consistent from set to set and ideally from 328p to 168. So looking at the data I see cases where the 328p is faster than the 168 and cases were it’s slower. But it’s consistent faster or slower from set to set. That is some trials are consistently slower on the 328p and others are consistently faster.

Look at trial #2 data from set to set. The 328p consistently clocks fewer “micros” than the 168 does, by a fair % too (~500 usecs out of 27+ msecs → ~2%). Seems that the ref clock on the 328p is slower than that of the 168. But then there’s trial #3 where the 328p consistently clocks more micros (some 950+) than does the 168, indicating it’s ref clock is now faster than the 168 … and that’s 0.95 msec out of ~52+ msecs, again ~2%.

So it’s not a simple case of 1 reference clock being slower or faster and it’s not random jitter either. I’m lost for a good explanation ATM. :?

Are you sure you didn’t swap some of the 328p data with the corresponding 168 data ? :mrgreen:

Here is the difficult point, The experimental conditions are different for each trial and each sample. I can not repeat the same trial for both arduino board. One value isn't clearly predictable, you can only suppose a local quality value according the previous data set. [u]The predictable fact is the sum of 8 samples that must give a time close to 250.000[ms][/u]. Looking at the data set for the 328p, I can confirm by the observation the offset of 200[us] (+/- error) on all the data.

– olivier

I question if the input signal is actually a solid 250ms…every time.

And the resolution of the code, and latency of the micro to pick up and process the signals, and so on.

Got a 'scope pic of the input signal itself?

skimask:
I question if the input signal is actually a solid 250ms…every time.

And the resolution of the code, and latency of the micro to pick up and process the signals, and so on.

Got a 'scope pic of the input signal itself?

You mean oscilloscope? No, I don't have scope.... not yet :? .

evaleto:
Here is the difficult point, The experimental conditions are different for each trial and each sample. I can not repeat the same trial for both arduino board.

So the experiment you’re timing isn’t theorectically the same for … say trial #3 … from sample set to sample set ? How is it that the trial #3 data is so very much the same value from set to set and clearly very different from the trial #2 times … which are also self consistent from set to set ?

BTW I forgot to ask … were the times measured by the 328p and 168 simultaneously ? That is was the triggering signal fed to INT0 of each board in parallel ? If not, could that be done ?

I see several possible sources of deviation.

  • - The reference source, like skimask implies, isn’t accurate or consistent. What is the source of your 4Khz signal? How much jitter is there?
  • - There is some sort of noise affecting the crystal circuit on each board. (you weren't touching the boards during the test?)
  • - Something is disabling interrupts and causing latency.
  • Like mee-n-mac suggested, try running both boards at the same time off the same signal.

    I would also rewrite the code to not use interrupts (and hopefully disable them while running the test though I think micros() uses timer ints) to get a 100% pure timing. Further, I’d set up a timer and use that as my measurement base rather than micros(). I’d consider using capture compare mode of a timer but it’s not necessary.

    On the question about ppm - that is part per million. so 1 ppm is 00.0001% Comparing two crystals, worst case - one is at the upper end of their spec’d error and the other is at the lower end so you double the max error. However, since the differences are inconsistent, it’s not crystal error.

    Mee_n_Mac:
    So the experiment you’re timing isn’t theorectically the same for … say trial #3 … from sample set to sample set ? How is it that the trial #3 data is so very much the same value from set to set and clearly very different from the trial #2 times … which are also self consistent from set to set ?

    BTW I forgot to ask … were the times measured by the 328p and 168 simultaneously ? That is was the triggering signal fed to INT0 of each board in parallel ? If not, could that be done ?

    **1) dataset.** You point a really interesting fact. Indeed, the trial3 is almost the same than trial 2. But they comes from two different records (elapsed between ~30seconds). In fact, the data could be equals, I'm not surprise to see so close values. (Actually I sample the motion of a clock oscillation, it's 4Hz. But the oscillation is splited on 3axes of 120° and this is why I get 8 samples for my 4Hz)

    2) simultaneously, no, currently it is not possible to record data simultaneously. If it helps, I will investigate on that. In fact, I doesn’t have enough hardware to do that right now. And honnestly, I don’t know what it will show except an offset?

    Philba:
    I would also rewrite the code to not use interrupts (and hopefully disable them while running the test though I think micros() uses timer ints) to get a 100% pure timing. Further, I’d set up a timer and use that as my measurement base rather than micros(). I’d consider using capture compare mode of a timer but it’s not necessary.

    Sorry Philba, I'm a newbie :oops: , I don't follow you on this, how can I proceed without interruption and how can I measure microseconds without the micros() function?

    – olivier

    Hmm, a newbie using interrupts - that kind of disqualifies newbiehood!

    Doing it without interrupts: It would look something like this (not guaranteed to compile):

    // assume that pin 0 is the signal pin
       long us[SAMPLES];            // store actual microseconds rather than a float
    
       while(digitalRead(0) != 0);  // wait for start point (falling edge)
       long time=micros();
       while(digitalRead(0) == 0);  // wait for rising edge
       while(digitalRead(0) != 0);  // wait for falling edge to complete the cycle
       long itime=micros();
       timeus=itime-time; //get a full periode on down:_┌─┐_______┌─┐_
       time=itime;
       if (usi<SAMPLES){
         us[usi]=timeus;
         usi++;
      }
    

    Using a timer might be beyond you at this point but there are lots of tutorials and learning about timers is something any one who is serious about this stuff should learn.

    We still haven’t heard what the signal source is.

    working without interrupt, I follow the suggestion of Philba with the code bellow. And … it’s crazy, I got exactly the inverse picture of data! From the a328p the clock is exact (a bit more precise) but from the a168, there is an offset of 200[us]. I think will not investigate more time on this crazy thing before I find a 'scope :think: Maybe my old Diecimila board is weird (since she is 3/4 years old)…

    #define PIN_RECORD 2
    void record(){
    	
    	uint8_t bit = digitalPinToBitMask(PIN_RECORD);
    	uint8_t port = digitalPinToPort(PIN_RECORD);
    
    	// convert the timeout from microseconds to a number of times through
    	// the initial loop; it takes 16 clock cycles per iteration.
    	unsigned long numloops = 0;
    	unsigned long maxloops = microsecondsToClockCycles(1000000L) / 16;
    	unsigned long period   = 0;
    
    	// wait for initial signal LOW state
    	while ((*portInputRegister(port) & bit) == LOW)
    		if (numloops++ == maxloops) //timeout?
    			return;
    
    	while(usi<SAMPLES){
    		period=micros();
    		// signal is up
    		while ((*portInputRegister(port) & bit) != LOW){
    			if (numloops++ == maxloops) //timeout?
    				return;
    		}
    	
    		// signal is low
    		while ((*portInputRegister(port) & bit) == LOW) {
    			if (numloops++ == maxloops) // timeout?
    				return;
    		}
    		// the period is complete here
    		timeus=micros()-period;		
        us[usi]=(timeus)/1000.0;
        usi++;
    	}
    }
    

    Thank you very much for helping :wink:

    – olivier