High Precision Timing / Feasibility

Hello all,

please be don't mad at me if something similar was asked multiple times already, i couldn't find existing stuff which exactly matches my problem:

Following setup:

  • arduino uno, connected to an external devices
  • the uno sets a pin to HIGH every 4-5 seconds (lets say pin8)
  • it awaits a response on its interrupt line (pin2) und measures the time between setting pin8 to high and the response (and sets the output back to low)
  • repeat

Here is what bothers me:

I need that measurement to be precise as possible, ideally accurate to the single digit microsecond, do you think that is feasible with an arduino or should i get some better hardware? Besides, since this is part of a corporate project, would you say an arduino (as a hobbyist device, no offense meant :slight_smile: is suitable?

In a simple test like:

loop
{
  unsigned long t0 = micros();
  delayMicroseconds(400);
  outputToSomething( micros() - t0 ); // pseudocode
}

i'm measuring values with a varying bias/offset, 20-36 microseconds. The same happens of course in the actual code as described above.
Now to the why...
My first thought was, that the 'software solution' (micros/delayMicroseconds) is just taking to many cycles. Afaik the Uni has three counting register (1x16,2x8 Bit) and delay/micros measures in 32 Bit, so there is obviously some work going on behind the scenes to provide those 32 Bit values. On the other hand, the uno is clocked at 16 Mhz, which should not amount to such a huge error.
Anyway, would it be a feasible approach to realize the timing manually, that is using the 16 Bit register directly (with suitable prescale etc). The shorter period is ok, i don't even need to care about the overflow since i know i only need to measure every 4-5 seconds. Or would it lead to the same error because.

...my next guess would lead to the resonator/oscillator which clocks the arduino (a ceramic resonator afaik). These devices have a technical imprecision of something around 0.5%. Is it just possible this small errors accumulates enough to lead to this error?
Roughly doing the math: 16 Mhz is 0,0625 times per microseconds, assuming +0.5% offset i'm looking at ~62.8 ns instead of 62.5 ns.
The time i expect to measure varys between 500 us and 10 ms (could change in both directions), in the 500 us case, again roughly doing the math i get (5001000)/62.8 vs (5001000)/62.5 which is 7961 vs 8000 ('ticks').
Depending how micros/delayMicros is implemented, could this amount to my observed error? So, what about getting a better clock source (or a TDC on the extreme end?), like just a simple external quartz? (which are more precise as far as i know compared to the ceramic stuff)? Or, just get another board with higher Clockspeed and maybe a 16 or 32 bit controller? (and thus 32 Bit counters)

Third thought, what if just the delay function introduces this delay, but micros itself measures correctly (although i know it measures in 4 us increments)? At the moment i'm just simulating my external device (which is not built yet) by a second arduino which does the critical delay call?

TiA for your help :sweat_smile:

I need that measurement to be precise as possible, ideally accurate to the single digit microsecond, do you think that is feasible with an arduino or should i get some better hardware?

Why do you need this - what are you really trying to do?

Mark

Why do you need this - what are you really trying to do?
Mark

The connected device is basically a capacitor (just a lot bigger, holds a special liquid which acts as dielectric) and at the end of the day we're measuring its capacity or the time it takes to 'load' it (which corresponds to the amount of liquid in it, which is dripping out of it in a controlled manner). We originally planned to measure a frequency directly, but that had a negative impact on the device (too much voltage/current which polarized the liquid and rendered the whole device useless), what we're doing now is more like measuring a frequency shift. Can't go into more detail, NDA and such things :expressionless:
The measuring device (which is the uno at the moment) needs to be some sort of programmable microcontroller, since we need to attach some more regulation logic later on. That regulation depends on the measured time, hence we need as much precision as possible.
So my question (from the starting post) in short is basically: Is it possible to get higher precision with the arduino (and how) and what causes this measurement bias.

The arduino UNO only updates micros() in multiples of 4 so you wont get microsecond accuracy unless you resort to external hardware.
EDIT: I have been investigating a similar high accuracy timing problem and the principle I was thinking of using was to have hardware with a 100MHz oscillator and 1 or 2 74AC163 binary counters that would allow me to read the carry overflow (12.5MHz or 6.25MHz output) using arduino interrupt pin. When the timing event is finished the binary counter(s) would halt counting and I would read the current count from them and add the carry overflow to get an accurate time (>100nS if my calculations were correct). The counter would then be reset ready to start next count.

You can get timing resolution and accuracy of 62.5ns on a 16MHz Arduino like this:

  1. Set up timer 1 to run in input capture mode and clear it to zero, but don’t enable it yet. Feed the response signal you want to time to the ICP1 pin (aka digital pin 8 on an atmega328p).
  2. Disable interrupts
  3. Start timer 1 with an appropriate prescaler depending on the resolution you need
  4. Set the output pin HIGH. You need to use a direct port write if you want to measure short intervals.
  5. Enable interrupts
  6. Wait for the timer 1 capture flag to be set, then read out ICR1. You can do this either by polling or by using the timer 1 capture interrupt.

Here’s some code I used to do this:

void setup()
{
  pinMode(2, OUTPUT);
  TCCR1A = 0;
  TCCR1B = 0;          // input capture noise canceller disabled, capture on falling edge (may adjust this later), stop timer
  TIMSK1 = 0;          // timer 1 interrupts disabled
  ACSR = 0;             // input capture NOT from analog comparator
  Serial.begin(19200);
}

void loop()
{
  static int numDisplayed = 20;
  static bool posEdge = true;
  
  TCCR1B = (posEdge) ? (1 << ICES1) : 0;        // set up timer 1 to capture on whichever edge we want and stop timer
  TCNT1H = 0;
  TCNT1L = 0;          // clear timer 1
  unsigned long start = micros();  // get the time
  
  cli();
  TIFR1 = 1 << ICF1;            // clear input capture bit
  TCCR1B |= (1 << CS10);     // start timer, prescaler = 1
  PORTD |= (1 << 2);          // set output high
  sei();

  unsigned int capture = 0;
  do
  {
    if ((TIFR1 & (1 << ICF1)) != 0)
    {
      byte temp = ICR1L;
      capture = (ICR1H << 8) | temp;
    }
  } while (capture == 0 && micros() - start < 100);     // time out after 100us
  
  PORTD &= ~(1 << 2);     // set output low
  if (capture != 0)
  {
    if (numDisplayed == 20)
    {
      Serial.println();
      numDisplayed = 0;
    }
    else
    {
      Serial.write(' ');
    }
    Serial.print(capture);
    ++numDisplayed;
    delay(100);
  }
  else
  {
    delayMicroseconds(500);
  }
}

[EDIT: simplified code by removing bits not relevant to this question]

Hello,

I am a relatively new user of Arduino. I like to measure the capacitor discharge time using timer as counter by directly reading the analog voltage comparing with a threshold.

if I want to measure capacitance of pF, then I need timer accuracy of 0,5us or even less than this. I believe one can get higher resolution timing with Timer1 than timer0 and 2.

Also, I always see that the timers are used

  1. to generate interrupt by changing the pin state
  2. to run on fixed interval eg., Output Compare Match:
  3. to count pulse on the pins and PWM generation

But I could not find a simple timer which can be started and stopped at user's will.
In my case I like to start the timer when the capacitor is just started charging and stop at the point at which capacitor voltage reached a threshold.

I think the code given by @dc42 suits my requirement, but I could not understand the code. Can anyone provide detailed comments for his code (present just one above this message)? Alternatively, if someone can help me with using timer1 to configure (with 0,5us resolution), start and stop when required by user without using interrupts.

have a nice day guys..

Thanks in advance
-Muthu

Hi,
Welcome to the forum.

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html

I think you need to start your own post for your project, as this thread is 4 years old.

How do you envisage measuring down to pF?
What charging reference voltage will you use?
How much charging current?
Have you considered the impedance of the analog measuring device?

Can you please post a basic diagram of your circuit including power supply and Arduino?

Can you please tell us your electronics, programming, Arduino, hardware experience?

Thanks.. Tom... :slight_smile:

bma1cob:
I am a relatively new user of Arduino. I like to measure the capacitor discharge time using timer as counter by directly reading the analog voltage comparing with a threshold.

Much better precision you get when connecting your analog signal to a digital pin, and attaching an interrupt to it. The pin will go from HIGH to LOW (or the other way around) at a very constant voltage. This is also much faster than trying to do an analogRead() then comparing it - an analogRead() call takes at least 8 µs so that's far too slow for you.

if I want to measure capacitance of pF, then I need timer accuracy of 0,5us or even less than this. I believe one can get higher resolution timing with Timer1 than timer0 and 2.

A standard 16 MHz Arduino goes down to 62.5 ns resolution. Run your ATmega at 20 MHz and you have 50 ns. Use an ESP8266 at 80 MHz and you're clocking at 12.5 ns intervals. So that resolution is easy to get to.

You can easily reset the Arduino timers, otherwise you just store the current value. Have them increment at every clock pulse (no prescaler). Then have your ISR record the current timer state. That's about it.

Hi Wvmarle.. Thank you very much for your reply..

It is really a good idea to use the voltage transition with the Digital pins and it is more accurate. I already read in forums that, with a Arduino uno 16MHz one can go down to 62.5 ns resolution. But still I could not get the timer configuration code to get this max resolution. Can you or any one in this forum provide me the timer configuration (eg Timer1) snippets, which I can incorporate directly in my code?

wvmarle:
an analogRead() call takes at least 8 µs so that's far too slow for you.

You are right - wvmarle. When the clock prescale is set to 32, then the Tclk = 64 MHz / 32 = 2 MHz ie 0.5 us. For ADC conversionit takes 13 Tclk ie., 6,5us -> which is really a big time.

With 62.5 ns resolution, I can measure upto 62.5 fF (femto Farad). This is good for starting. Once I could measure the capacitance with 62.5 fF resolution, I will change to other uC to get between 5 and 10 fF resolution.

Also, you mentioned using ESP8266 at 80 MHz, but it is an external chip. Rather, I want to use a single chip uC with eg 64 MHz clock speed. In future, I like to make a PCB with Arduino controller as ASIC for the capacitive sensor.

As Tom said that it is good a create a new thread rather than using this years old one, I have created a new one.. So can you reply to this thread
https://forum.arduino.cc/index.php?topic=540428.msg3683316#msg3683316