Analog Timing issue.

This has got me beat. I’m doing time critical measurements and this is a problem. I’m chasing why there are large steps in my time measurements.

I’m supplying a 50 hz signal to the board. The time between cycles is 20000 usec.

I’m only send to the serial output once a second. In order to get a nice clean signal I wait for a falling edge, then a rising one to make sure I trigger as the voltage A to D goes >200. I then record the time.

I then wait for another falling edge and then rising and take the next time measurement. I subtract the 2 to get the time per cycle.

Now the question, when I add a small delay, way below the 20000 usec period, why does it timing measured even change and why by such odd numbers. The timing should not change at all.

for
delayMicroseconds(1); or no delay
I get
20048
20048

for
delayMicroseconds(4);
I get
20064
20064

for
delayMicroseconds(20);
I get
20080
20080

for
delayMicroseconds(40);
I get
20096
20096

for
delayMicroseconds(60);
I get
20000
20000

for
delayMicroseconds(70);
I get
20016
20016

unsigned long RPMStartTime = 0;
unsigned long RPMEndTime=0;
unsigned long RPMDuration=0;

void setup() {
  Serial.begin(115200);            // initialize serial communications:
  analogReference(DEFAULT);
}

void loop() {
   while(analogRead(5) >= 200){}                  // Wait for falling edge  
   while(analogRead(5) < 200) {}                  // Wait for rising edge
   RPMStartTime=micros();  
   delayMicroseconds(60);  
   while(analogRead(5) >= 200){}                  // Wait for falling edge
   while(analogRead(5) < 200) {}                  // Wait for rising edge   
   RPMEndTime=micros();   
   RPMDuration=RPMEndTime-RPMStartTime;           
   Serial.println(RPMDuration);     
   delay(1000);     
}

First of all, the call to waitMicroseconds() should have nothing to do at all with your measurement. There is time gap of around 10,000 microseconds at that place.

As an analogeRead() takes 150 us this is the error involved in your sine-measurements; the signal >200 can occur anywhere in that time window. As there is an implicit averaging between start and stop measurement the expected mean delay should be around 50 to 100 us

You are correct, the delay should not be causing any change in the readings but some how it does. I may have not explained the problem correctly. The reason for putting in the delays was to try and find the trigger in the analog reads that always gives me timing periods in multiples of 112, even with two completely unrelated events.

I understand that the analog read can vary where it triggers but what happens, is that with the various delays, the A to D always reads the same sets of values for each delay. If I change the frequency by a hz or 2 , these are the values I get. (It is a analog frequency generator so I get all the in between frequencies. )

delayMicroseconds(1)

19888 20048 20160 (Multiples of 112)

delayMicroseconds(30)

19968 20080 20192 (Multiples of 112)

delayMicroseconds(60)

19936 20000 20112 (Multiples of 112)

I cannot adjust the frequency to get 20000 when I have delayMicroseconds(1) or delayMicroseconds(30), similarly I cannot get 20048 when delayMicroseconds(60)

It appears there is something fishy with the A to D and I can't put my finger on it.

Thanks Wallace

19888 20048 20160 (Multiples of 112)

20048 - 19888 = 160, not a multiple of 112.

Sorry typo on my side

delayMicroseconds(1)
19936  20048 20160   (Multiples of 112)

delayMicroseconds(30)
19968  20080 20192   (Multiples of 112)

delayMicroseconds(60)
19888  20000 20112   (Multiples of 112)

"For a moment I though you had given me a key, but alas not"

I have redone the project with a digital input, same code and all is well, but the analog is still a mystery.

You are correct, the delay should not be causing any change in the readings

The funny thing is, I were not correct :slight_smile:

(1) This 112 us: I said 150 us, nevertheless this is (i.e. 112) the time for the processing of conversion and code overhead. This is deterministic on the AVRs (there are ADCs where the conversion time changes with the amplitue…). So one can never sample to a time “inbetween”.

(2) So it depends on when exactly you START your probing. And this does depend on the microsecond-delay! This determines where on the phase of the signal you start and where exactly the next samples (in 112 us distances) will take place. So you can get more or less close to 20,000 (in the range I estimated in my last mail).

Note that as the start of the program is not synchronized with the phase of the signal, you should get slightly different values for the difference in each run, however they will approximate after some seconds or minutes…

(3) Knowing this you can implement a feedback - increment the delay (in 8us steps I should propose) systematical to find the LOWEST difference:

Edit

sigh still wrong! You can also undershot… So you best find lowest AND highest difference and avarage…

Using an external interrupt pin to make a rpm meter is much more precise than using the adc and all that code to detect the edges.

It had been clear what the final application is the OP strives for…

The rising signal will ofcourse trigger a digital input as well (at around 2 volts). The exact level is undefined will also depend on the chip but will stay constant for seconds or minutes.

This can be used for waiting in a digitalRead loop (which is 15us rather than 150us). Or - and I like your idea - trigger an interrupt!

I am measuring more than one timing signal. If was reading only 1, an interrupt would be good.

I need to measure several 250 hz signals. The time period is therefor 4 msec. I want an accuracy of 1 in 100. That means I have to sample at 40 us. I'm not worried about how long it takes to sample as long as the time between samples is accurate. When using 2 analog reads the time period between each is always multiples if 112. Take 2 unrelated triggers points and you will find the time period will be a multiple of 112. That is the highest resolution you can get. This should not be.

Adding a delay between the signals, although it does nothing, changes the measurements, but still the result is multiples of 112.

Thanks for your input.

This should not be

I wonder what you want to say. The effects you encountered are well understood, I think.

The feedback machanism I suggested should work upto a high precision.

Also using digitalRead() for your purpose is an excellent idea, reducing the error to 15us, which is better than 1%. This however needs the signal to rise above 2.5 volts.

A third solution is an increase of the analog sampling rate (x4 to 32us) , however with a reduces resolution of the reading (8 bit).

I have already solved the problem, but I want to know how the Arduino logic works for other projects.

If we start with a signal at T0 and preform an analog measurement, we get the value back at T112.

Now at T200 I do a second analog signal measurement and we get a value back at T312. OK

So the difference is T312 - T112 = 200

No, I will get a value of 224 back.

Please explain ???

If I increase the T200 to T210 T220 T240 etc, the time measured will not be 224 + 10, +20 + 40 etc but I will get 224 and then it will jump straight to 336 and later to 448. No values in between.

Cheers Wallace

Yes, I know - I tried to explain above in my posting #5.

Yes, I know - I tried to explain above in my posting #5.

I have read this email many times but still confused.

So it depends on when exactly you START your probing. And this does depend on the microsecond-delay! This determines where on the phase of the signal you start and where exactly the next samples (in 112 us distances) will take place. So you can get more or less close to 20,000 (in the range I estimated in my last mail).

I can change the amplitude and of the signal and the A to D trigger point but my timing value does not change. If I sample a 50 hz signal, I get no times sent when the amplitude low (below threshold) and the at the threshold I get 20000us. On increasing the signal from 2 v peak to peak to 5 volts, I still get 20000. On changing the trigger point from 100 to 200 I still get 20000. Rock solid 20000. If I change the input frequency, the next step is 200112, why nothing in between?

The answer to my problem is that the Arduino software puts the AtoD in free running mode. Ie it is continually making AtoD calculations. The time for each calculation is 112 us so you will always get timing values of 112us multiples apart.

If you drive the AtoD manually Ie single conversion then the timing between timed conversions will be accurate provided they are not less than 112 us apart. You can get quicker results by chanhing some of the AtoD settings.

Cheers Wallace