Shop OBEX P1 Docs P2 Docs Learn Events
Increasing the resolution of pulse timing — Parallax Forums

Increasing the resolution of pulse timing

Hi,
I am measuring the length of a pulse using the following code:
Loopy       'Start timing the received pulse
              waitpeq   inmask,inmask                   'Normaly high, wait for input pin to be low
              mov       vlRXCountStart,cnt              'Capture the time for the start of the pulse

              waitpne   inmask,inmask                   'Wait for rising edge (End) on input pin
              mov       vlRXCount,cnt                   'Capture system timer as event time 'tend'

              sub       vlRXCount,vlRXCountStart        'Subtract the start time
              wrlong    vlRXCount, vRXCount             ' write result to hub ram location set in PARAMETER

This works well but I need even finer resolution, twice would be a good start but 4 x would be better.

The processor is running at 80Mhz.
If I can't do better in code can anyone suggest hardware that could help?

thank you

Comments

  • Wuerfel_21Wuerfel_21 Posts: 5,053
    edited 2018-10-16 13:07
    The counter modules can count the amount of cycles that a logic condition is met. However, i don't think you'll be able to get more than 12.5 nanosecond precision out of either method.
  • BeanBean Posts: 8,129
    Is this a one-shot event ? Or is it repetitive ?

    Bean
  • The best resolution you're going to get is system ticks. You can set a counter in positive or negative detect modes to do the heavy lifting for you.

    For a 0-1-0 pulse you would:
    -- set counter to POS detect and assign pin
    -- wait for low state on pin
    -- clear phsx
    -- wait for high
    -- wait for low
    -- read pulse width (system ticks) from phsx
  • The code you've posted will give you 12.5ns resolution. That's the best you can achieve without external hardware.

    -Phil
  • frank freedmanfrank freedman Posts: 1,983
    edited 2018-10-18 08:01
    Sorry this was in the wrong thread.....
  • kwinnkwinn Posts: 8,697
    lmclaren wrote: »
    Hi,
    I am measuring the length of a pulse using the following code:
    Loopy       'Start timing the received pulse
                  waitpeq   inmask,inmask                   'Normaly high, wait for input pin to be low
                  mov       vlRXCountStart,cnt              'Capture the time for the start of the pulse
    
                  waitpne   inmask,inmask                   'Wait for rising edge (End) on input pin
                  mov       vlRXCount,cnt                   'Capture system timer as event time 'tend'
    
                  sub       vlRXCount,vlRXCountStart        'Subtract the start time
                  wrlong    vlRXCount, vRXCount             ' write result to hub ram location set in PARAMETER
    

    This works well but I need even finer resolution, twice would be a good start but 4 x would be better.

    The processor is running at 80Mhz.
    If I can't do better in code can anyone suggest hardware that could help?

    thank you

    Only way to do better would be to use an external high frequency gated counter and oscillator. You might be able to output 128MHz on a Propeller pin to the counter but that gets less than 2 times the resolution so you will need an external oscillator for 2 or 4 times resolution. Something like the ON Semiconductor MC10E136FNG for the counter and the Analog Devices EV-ADF4360-9EB1Z for generating the clock.

    This is getting into an area that will require some careful layout to get a working circuit board.
  • jmgjmg Posts: 15,173
    lmclaren wrote: »
    This works well but I need even finer resolution, twice would be a good start but 4 x would be better.

    The processor is running at 80Mhz.
    If I can't do better in code can anyone suggest hardware that could help?

    As Bean hints above, if this is repetitive, you can do multiple samples and average, and IIRC someone did some clever work with a PLL mode, to ensure a dithered sampling clock.

    If it is single shot, things are tougher.
    You can bump to 100MHz ok, which helps a little.

    You can add a delay line, and multiple timers, so a half-sysclk delay, and a 2 gated timers, can halve the LSB.
    Using 2 cogs, and a 4 tap delay line, gives 4x resolution, avoiding very fast clocks.



  • @Bean The event is a return pulse from a PI metal detector, It repeats but each is slightly different. That being said some averaging is an advantage. At the moment it is repeated every 10mS. To reduce noise I have a running average over approx 10 to give me an update rate of 100mS.

    @jmg What you describe sounds like it may be what I need. Do you have any examples?

    thank you everyone.
  • @JonnyMac I will test out your suggestion to see if it removes some of the jitter I am seeing. Thank you.
  • jmgjmg Posts: 15,173
    edited 2018-10-17 00:58
    lmclaren wrote: »
    @jmg What you describe sounds like it may be what I need. Do you have any examples?

    For averaging, there is this work by Bean
    https://forums.parallax.com/discussion/135563/measure-the-speed-of-electricity

    and more updated clever work here
    https://forums.parallax.com/discussion/comment/1215371/#Comment_1215371
    Bean says
    "The hard part was getting a signal that is NOT phase locked to the propeller clock."
    "I used the PLL in the counter, but normally the PLL will get phase locked to the propeller clock very quickly. So I have a tight loop that keeps moving the frequency input to the PLL.
    This causes the PLL to constantly adjust and it never gets phase locked."


    For delay-lines, you need some external element, and custom delay lines do exist, but sadly are niche parts.
    If you need just x2 or x4 improve, you can probably roll your own delay line, using a string of inverter gates.
    If you vary their Vcc, you can adjust the delay (That's how the PLL works in P1 & P2)

    A larger part like 74ALVCH16646, could do interesting things with a typ delay given of 2.6ns, but that's in a larger package.
    Addit: The '646 series looks to be fading, so maybe more mainstream would be cheap & widespread HEX inverters and registers, x04/x14 and x597 to capture fractional info
    3 inverters and 2 registers can capture 16b of delay info.
  • BeanBean Posts: 8,129
    I would try using two counters.
    One in NEG detector mode and the other one in NEGEDGE mode.
    Wait for a rising edge and clear both counters.
    Wait for a while (a couple seconds ?)
    Wait for a rising edge and read both counters.
    This will give a count of the pulses and the total time spent in the low state.
    Average time is simply total/count.

    Bean
  • Hello,

    I have a question very similar to this so I figured it belongs here too:

    I'm using the following code to measure pulse width:
    unsigned int a;
    unsigned int b;
    unsigned int pulsewidth;
    waitpeq(0, 1);
    waitpeq(1, 1);
    a = _CNT;
    waitpeq(0, 1);
    b = _CNT;
    pulsewidth = b - a;
    


    My goal is to get 12.5ns resolution but for some reason the pulse width I'm getting is always a multiple of 16. For example the output may fluctuate between 384 and 400. I have verified that the propeller is running at 80MHz and the pulse width it measures is correct but only at 1/16 of the resolution I want. I thought CNT should increment by one after each clock cycle, but that does not seem to be the case?
  • 'Hard to tell with C source. Have you looked at the code your program compiles to?

    -Phil
  • jmgjmg Posts: 15,173
    mbv wrote: »
    My goal is to get 12.5ns resolution but for some reason the pulse width I'm getting is always a multiple of 16. For example the output may fluctuate between 384 and 400. I have verified that the propeller is running at 80MHz and the pulse width it measures is correct but only at 1/16 of the resolution I want. I thought CNT should increment by one after each clock cycle, but that does not seem to be the case?

    That's a quite small difference. Did you try larger pulse widths, to check first, and then see how narrow a pulse you can capture ?
    Any HLL code is going to take finite time, which imposes some limit on the correct wait operation.
  • Where is your pulse coming from? If it's from another cog, and depending upon how it's produced, the width might actually be a multiple of sixteen clocks.

    -Phil
  • mbvmbv Posts: 7
    edited 2018-10-17 20:40
    The pulse is coming from a function generator. It's a 100kHz square wave and I'm varying the duty cycle slowly , which always seems to result in a jump of 16 on the propeller. I can measure even much shorter pulses just fine, but again only with 16 clock cycle resolution. Also when I just print out many values of CNT, I never get even numbers only odd numbers so it seems that CNT cannot get all possible values but just increments by some even number at a time.
  • If it's a smallish function and you're using LMM make sure you have fcache enabled so that code will execute in cog memory.
    Mike R...
  • pmrobert wrote: »
    If it's a smallish function and you're using LMM make sure you have fcache enabled so that code will execute in cog memory.
    Mike R...

    I used LMM, -O2 and "no fcache" option was disabled so I suppose I already have it enabled, is that correct?
  • jmgjmg Posts: 15,173
    mbv wrote: »
    .... Also when I just print out many values of CNT, I never get even numbers only odd numbers so it seems that CNT cannot get all possible values but just increments by some even number at a time.
    The hardware is 1 cycle granular, but the software can be 4 sysclk or worse quantized.
    (Opcodes are 4 sysclks, but will re-align/shift on a WAIT opcode)

    Did you try PASM code ? or other code ?

    eg this resolves to 1 SysCLK
    https://forums.parallax.com/discussion/123170/propbasic-reciprocal-frequency-counter-0-5hz-to-40mhz-40mhz-now


  • jmg wrote:
    The hardware is 1 cycle granular, but the software can be 4 sysclk or worse quantized.
    (Opcodes are 4 sysclks, but will re-align/shift on a WAIT opcode)
    All true. But, given the stated realignment, the software granularization should not matter if the number of cycles used to store cnt after the waitpeq and after the waitpne are the same. In that case you should get 12.5ns resolution. That works in Spin and PASM, anyway.

    -Phil
  • AribaAriba Posts: 2,690
    I don't think you can get 12.5ns resolution with WAITPNE/WAITPEQ and code which executes from HubRAM (including Spin). This works only in pure PASM.
    The first command after the WAITXXX for reading the CNT value always gets synchronized to the Hub when it is executed, so a 16 clock resolution is forced.

    A short C function with: __attribute__((fcache)) may also work.

    Andy
  • Ariba wrote:
    I don't think you can get 12.5ns resolution with WAITPNE/WAITPEQ and code which executes from HubRAM (including Spin). This works only in pure PASM.
    The first command after the WAITXXX for reading the CNT value always gets synchronized to the Hub when it is executed, so a 16 clock resolution is forced.
    Ahh, you're right. Forgot about hub issues! D'oh!

    -Phil
  • kwinnkwinn Posts: 8,697
    mbv wrote: »
    Hello,

    I have a question very similar to this so I figured it belongs here too:

    I'm using the following code to measure pulse width:
    unsigned int a;
    unsigned int b;
    unsigned int pulsewidth;
    waitpeq(0, 1);
    waitpeq(1, 1);
    a = _CNT;
    waitpeq(0, 1);
    b = _CNT;
    pulsewidth = b - a;
    


    My goal is to get 12.5ns resolution but for some reason the pulse width I'm getting is always a multiple of 16. For example the output may fluctuate between 384 and 400. I have verified that the propeller is running at 80MHz and the pulse width it measures is correct but only at 1/16 of the resolution I want. I thought CNT should increment by one after each clock cycle, but that does not seem to be the case?

    Perhaps you should try a PASM program running in a cog that does the timing and puts the result(s) in one or more hub locations that your code can then access.
  • shouldn't using the timer resolve that problem even when called from LMM?

    Mike
  • Actually all that was needed was to move the code into a seperate C-function and launch it into cog1. As long as LMM is enabled and "No fcache" disabled, this gives me the 1 cycle resolution I was looking for. Thanks for all the help!
Sign In or Register to comment.