Enhancing input capture resolution

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

I need to monitor the jitter of some short pulses with a length of approximately 500µs. The max. valid jitter is 4µs. I need to do some statistics which are not available within our scopes at work.

Measuring these pulses should be easy with the input capture feature of an AVR. BUT the delay between each pulse can be up to is 130ms. The min. resolution I need is 500ns. So the longest time interval I can measure with a 16bit timer is 500ns * 65536 = 32ms.

I've been thinking about a simple solution, how to enhance the timer resolution to 24 bits.

I could increment a variable whenever the timer overflows. But what if the overflow and the capture event happen simultaneous? The input capture vector has the higher precedence and thus I would miss to update my variable in time.

Any ideas for a workaround? The device should be as simple as possible and really straight forward. It will be placed on a stripboard. I'm planning to use a FT232R and an ATmega48.

Regards
Sebastian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you trying to measure the width of the pulse, or the time between pulses? Or the time between rising (or falling) edges?

Short answer: Use an Xmega. ;) But answer the above first.

Re the overflow count and the race at overflow: this has been discussed before. I implemented the "solution" but I'd have to dig it out. A quick-and-dirty way is to see what the timer counts are when the ICP hits and if low enough check for the overflow pending.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you can use two timers:

let timer 2 count overflows with a prescaler of 256 and let timer 1 do the input capture stuff. T2OVF has a higher priority than ICP1. However, you will have some time offset between them, because those two timers don't share the same prescaler (timers 1 and 0 do, bit OVF0 has a lower priority then ICP1).

I tend to post off-topic replies when I've noticed some interesting detail.
Feel free to stop me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simple:
In the input capture vector check the overflow flag, if set, and the count read was low [say less than half ;)], clear it, and bump the overflow count as well, if the count is high [more than half... aka MSB=1], the overflow happened after the event, so you leave it alone, and let the overflow handler catch it.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wow, so many ideas!!! Many thanks!

Quote:
Are you trying to measure the width of the pulse, or the time between pulses?
Both, because they all can jitter depending on interrupts triggered in the DUT (Device Under Test).

Quote:
Short answer: Use an Xmega. Wink
Huh, I'm still waiting on my samples. And IF I already had them, I wouldn't sacrifice them for such a simple task. Guess I will put them first into a vitrine and stare at them all day long, happy as a kid. 8)

Quote:
I implemented the "solution" but I'd have to dig it out.
That would be great!

Quote:
A quick-and-dirty way is to see what the timer counts are when the ICP hits and if low enough check for the overflow pending.
I thought about that, too. But it will only work if I can manage not to use any other interrupt than for the timer overflow and input capture events. I've got to think about it a little bit more...

Quote:
If you can use two timers:

let timer 2 count overflows with a prescaler of 256 and let timer 1 do the input capture stuff. T2OVF has a higher priority than ICP1. However, you will have some time offset between them, because those two timers don't share the same prescaler (timers 1 and 0 do, bit OVF0 has a lower priority then ICP1).

In this case I have to feed the timer1 output signal into the TOSC1 pin which is not available on the ATmega48 because I have to connect a crystal to the chip (XTAL1 and TOSC1 share the same pin)

Quote:
Simple:
In the input capture vector check the overflow flag, if set, and the count read was low [say less than half Wink], clear it, and bump the overflow count as well, if the count is high [more than half... aka MSB=1], the overflow happened after the event, so you leave it alone, and let the overflow handler catch it.
Sounds like a good idea. I'll check it!

Regards
Sebastian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why do you care about overflow ? if the low 16 bits are in range then OK !
If you care have the main program read the timer and inc a var by one if timer > about 64000 and set a flag that get cleared when timer is < 500.
when you get the capture see if timer >64000 then dec var, this way you can use any timer.(even 8 bit change numberes to about 10 and 200 depending how fast the main program is running)

Jens

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Why do you care about overflow ?

To time long periods with high precision. See the first post:
Quote:

BUT the delay between each pulse can be up to is 130ms. The min. resolution I need is 500ns. So the longest time interval I can measure with a 16bit timer is 500ns * 65536 = 32ms.

And most of the rest of the discussion about counting overflows >>is<< exactly Sebastian's
Quote:

how to enhance the timer resolution to 24 bits

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
In this case I have to feed the timer1 output signal into the TOSC1 pin which is not available on the ATmega48 because I have to connect a crystal to the chip (XTAL1 and TOSC1 share the same pin)

Why? Timer2 just counts the MSBs of your emulated 24-bit timer. It will have some offset, but that's ok, because that offset doesn't show up in the time difference calculation:

[ImTerriblyWrong]T1 = (TCNT2 << 16) | (TCNT1H << 8) | TCNT1L;
T2 = (TCNT2 << 16) | (TCNT1H << 8) | TCNT1L; (some time later)
delta = T2 - T1;


This will work no matter what offset you have between the bits of lower significance between the two timers.

All this works ONLY if timer2 runs with a prescaler of 256 and timer1 runs with a prescaler of 1. Timer2 WILL overflow between two timer1 overflows and therefore will increment the highest byte of your 24-bit timer. Always. And with higher priority.

Edit: Added tags. Currently trying to get some asm to work!

Edit2: Next idea: Let OCR1A = 0x0000, set OC1A on compare match. OC1A is connected to INT0 or INT1 and the corresponding ISR increments bits 23:16 of your 24-bit counter! Somewhen in between the pin has to be cleared again. Voilá - this one should be less crappy.

I tend to post off-topic replies when I've noticed some interesting detail.
Feel free to stop me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

buffi, I still don't understand your idea. If Timer2 is running at 1/256 of the Timer1 clock then both timers would overflow at the same rate. I can't see how TCNT2 would hold the MSBs of a 24 bit counter.

Quote:
Next idea: Let OCR1A = 0x0000, set OC1A on compare match. OC1A is connected to INT0 or INT1 and the corresponding ISR increments bits 23:16 of your 24-bit counter! Somewhen in between the pin has to be cleared again.
I can't see the advantage of this method over glitch's method. But I see a disadvantage because I have to wire Pin 15 (or 16) to Pin 4 (or 5) on my small stripboard which is fixed to 56x98mm to fit into the selected box (The Top and bottom lines are not available). Below you can see a picture of my first draft.

Regards
Sebastian

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think the first answer from Lee gave the right solution. Using the pending interruptflag is not just a quick and dirty trick, but just the best way to check for a pending interrupt. At least for me it works.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

S-Sohn wrote:
buffi, I still don't understand your idea. If Timer2 is running at 1/256 of the Timer1 clock then both timers would overflow at the same rate. I can't see how TCNT2 would hold the MSBs of a 24 bit counter.

I think Buffi missed the fact that Timer1 is 16bits, in which case the other timer will need to be running at 1/65536.

S-Sohn wrote:
Quote:
Next idea: Let OCR1A = 0x0000, set OC1A on compare match. OC1A is connected to INT0 or INT1 and the corresponding ISR increments bits 23:16 of your 24-bit counter! Somewhen in between the pin has to be cleared again.
I can't see the advantage of this method over glitch's method. But I see a disadvantage because I have to wire Pin 15 (or 16) to Pin 4 (or 5) on my small stripboard which is fixed to 56x98mm to fit into the selected box (The Top and bottom lines are not available). Below you can see a picture of my first draft.

Personally I like my metod too ;) As it doesn't require any external connections, or additional internal hardware resources, other than a byte of RAM. You could use 2 timers, without additional external connections, but at the cost of a single pin, as some of the timers Tn pin is the same as another timers OCn pin. (though no such combination exists on the m48 for any of the timer1 outputs)

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'll bring it down to the main goal behind my ideas:

-> Have some interrupt with a higher priority than ICP1, that fires exactly when timer1 overflows. In the corresponding ISR, increment the highest counter byte (bits 23...16). <-

Of course, checking for a pending interrupt works too, it's just a different way of emulating a 24-bit timer.

Quote:
buffi, I still don't understand your idea. If Timer2 is running at 1/256 of the Timer1 clock then both timers would overflow at the same rate. I can't see how TCNT2 would hold the MSBs of a 24 bit counter.
You almost got it! When timer2 overflows at the same rate as timer1 AND at the same time, the timer2 overflow ISR will be executed before any pending timer1 interrupt (ICP in this problem). Then, in the ISR, do the above: increment the high byte. TCNT2 is not used.

I tend to post off-topic replies when I've noticed some interesting detail.
Feel free to stop me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That still fails to work buffi, because if the capture event happens slightly before the overflow, but because of a delay in execution the overflow happens before it can execute. Now you have both ISR's pending, in which caase your separate overflow ISR to execute before the capture ISR, resulting in the count to be off by 65536 counts. All it takes is a 3rd ISR to be active in the system to create this scenario.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Doesn't checking for the pending overflow flag in the icp ISR suffer from the same effect?

edit: but at least checking for the pending interrupt doen't eat up any more hardware resources. I'm on the check-the-flag-side now!

I tend to post off-topic replies when I've noticed some interesting detail.
Feel free to stop me.

Last Edited: Fri. Aug 1, 2008 - 10:57 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lokking for a pending overflow alone is not enough, but when you also look at the value in the capture register helps.

If there is a pending overflow interrrupt and the ICP register value is small then the overflow interrupt (doing software extension of resolution) needs to be done first. If the ICP register value is large the pending interrupt comes later. If there is a pending overflow, intermediate values are impossible (except with other very slow ISR routines).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The method used in one of my time machines is to add artificial bits to the timer (theusch's / glitch's method):

volatile unsigned long timestamp_high;
volatile struct {
    unsigned low16;
    unsigned high32;
    unsigned char flag;
} cap;

ISR(TIMER1_OVF_vect)
{
  ++timestamp_high;
}

ISR(TIMER1_CAPT_vect) //falling edge
{
  //read capture, burn at least 4 clocks before testing TIFR OVF
  unsigned v=ICR1;
  cap.low16=v; //this costs 4 ck

  unsigned long th=timestamp_high; //and this 8 ck
  //if we are in the first part of range, we may have a pending increment
  if (!(v&0x8000)) if (TIFR&(1<<TOV1)) ++th;
  //have the 48 bit timestamp in th(32):v()16
  cap.high32=th;
  cap.flag=1;
}

This works because the capture vector has higher priority than overflow vector. If they happen at the same cycle, if we don't compensate for the missing overflow increment, we get values that are off by ~64k.
Run the timer at full speed, there's no reason to prescale the clock, expand it.

The particular time machine this is taken from has 100ps precision and 64 bits output and has been tested extensively.

/Kasper

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kasper, many thanks for sharing your code and sorry for the late response, something has cropped up (my newborn daughter :D ).
I'll use your code with the exception that I don't need a 48-bit timestamp. Declaring timestamp_high as unsigned char is enough for my application and avoids that I have to worry too much of the execution time of my code when measuring short pulses.

Regards
Sebastian