P2 Input Capture questions?

jmg wrote: »
Chip's terminology is not the same as other suppliers, so that can make smart pins harder to follow.

I have not purchased a P2 yet, but after trying to read the data sheet,
I am not certain the P2 provides an easy way to perform Input Capture.

A simple tachometer that is capable of recording the time period of one
revolution and converts that to rpm is at the core of all my potential
P2 projects.

A simple example is my ignition test stand spinning at the low speed of
2307 rpm. The period is 26ms, and because it is set up with a hall sensor
25ms is high, and 1ms is low.

Normally I count from falling edge to falling edge (26ms @2307rpm).

So many of the P2 pin states talk about accumulating clock cycles within
a hi or low state, or events within a period.

Pin State %10_000 looks promising, but there is no mention of falling

Is there an easy way to perform input capture?
Can input capture be done with an interrupt?
On some micro-controllers DMA seems to be helpful. Is a Streamer
helpful for input capture on the P2?
Can the clock speed be reduced to 1mhz on the input capture pin?


Bill M.


  • A smartpin will do that easy as. Every pin can monitor a separate sensor if you wanted lots of them. There is multiple modes that can do it slightly different ways. The simplest is mode %10001_0, that I've labelled SPM_TIM_PULSE - Interval of most recent pulse duration. Chip calls it Time A-input high states.

  • That's not what's being asked for, though. Capt. Quirk wants time from first low->high transition to next low->high transition.

    I suppose you could have two adjacent pins on the same signal, one monitoring high duration, and one monitoring low duration. Combine the counts to get the input capture. Kinda clunky, though.
  • roglohrogloh Posts: 2,767
    edited 2020-10-09 - 05:05:36
    If the RPM doesn't stop and you can spare a COG, here is an untested snippet of code you could spawn (which is extended from something that I did recently) to return the period from low>high to next low->high without a Smartpin, reported in clock ticks (needs scaling for your application). Initial count reported might not be accurate. The P2 needs to run fast enough to execute all these instructions in the high or low periods of the input signal. It might even work with the first setpat and waitpat in the asm loop removed too. EDIT: yes it does.
       long time ' continually updated with period as measured in P2 system clocks
    PUB timecog() | time1, time2, time3
        time1 := getct()
                modcz %1111, %1111 wcz
    '            setpat ##$1000000, ##$0000000 ' bit mask set to your pin (this example is for pin56)
    '            waitpat
                setpat ##$1000000, ##$1000000 ' for pin 56
                getct time3
                mov time2, time3
                sub time2, time1
                mov time1, time3
            time := time2
  • Here's a sample using two smartpins monitoring the source signal.
    High and low periods are added together then divided into a scaled system clock value.
            xtal = 20_000_000
            dv = 20
            mlt = 100
            sys_clk = xtal / dv * mlt
            clk = 1 << 24 | (dv-1) << 18 | (mlt-1) << 8
            us = sys_clk / 1_000_000
            baud = 115_200
            cpb = (sys_clk / baud) << 16 | 7
            tx_pin = 62
            hz = 100
    dat     org
    'setup system clock
                  hubset ##clk | %1111_01_00
                  waitx ##20_000_000/100
                  hubset ##clk | %1111_01_11
    'setup async transmitter
                  wrpin #%1_11110_0,#tx_pin
                  wxpin ##cpb,#tx_pin
                  dirh  #tx_pin
    'setup cog for reference pulses
                  loc       ptra,#@ref_signal
                  coginit   #16,ptra
    'setup smartpin to measure high period of ref pin
                  wrpin ##%0111_0000_000_0000000000000_00_10001_0,#highx
                  dirh  #highx
    'setup smartpin to measure low period of ref pin (inverted input)
                  wrpin ##%1110_0000_000_0000000000000_00_10001_0,#lowx
                  dirh  #lowx
    main          waitx     ##sys_clk / 2
                  rdpin     high,#highx               'get period value
                  rdpin     low,#lowx                  'get period value
                  mov       pa,high
                  call      #dec                    'show high period
                  mov       char,#" "
                  call      #tx_char
                  mov       pa,low
                  call      #dec                    'show low period
                  call      #newline
                  qmul      ##sys_clk,#10           'calc rom
                  getqx     pa
                  add       high,low
                  qdiv      pa,high
                  getqx     pa
                  qmul       pa,#6
                  getqx     pa
                  call      #dec
                  call      #newline
                  call      #newline
                  jmp       #main
    dec           mov       pb,##1_000_000_000
                  mov       digits,#10
    .loop          qdiv      pa,pb
                  getqx     char
                  getqy     pa
                  add       char,#"0"
                  call      #tx_char
                  qdiv      pb,#10
                  getqx     pb
                  djnz      digits,#.loop
    newline       mov       char,#13
    tx_char       rdpin     ina,#62 wc
            if_c  jmp       #tx_char
                  wypin     char,#62
    char          long      0
    digits        long      0
    high          long      0
    low           long      0
    dat           orgh      $400
    ref_signal    rep       @zzz,#0
                  waitx     ##(25_000*us)-6
                  drvl      #ref
                  waitx     ##(1_000 * us)-6
                  drvh      #ref

    Test output show high perio of 25mS and low period of 1mS.
    Calculated RPM is ~2304.
    0002500000 0000100000
  • There is many similar modes: Try mode %10010_0 (SPM_TIM_MANY). With Y = %001, it provides the interval of X number of pulses. With X set to 1 it may give the desired interval.

  • jmgjmg Posts: 14,492
    edited 2020-10-09 - 06:08:45
    Is there an easy way to perform input capture?
    Yes. See below for period (edge to same edge) capture.
    Can input capture be done with an interrupt?
    Yes, if you wanted to set up an event, the HW pin abilities mean you would usually use the pin HW
    On some micro-controllers DMA seems to be helpful. Is a Streamer helpful for input capture on the P2?
    Interesting question. I think the streamer is timed-only, and cannot trigger from a smart pin capture.
    Can the clock speed be reduced to 1mhz on the input capture pin?
    No. Time units are all in SysCLKS, but they capture 32b, so you just shift the unwanted bits away.

    Normally I count from falling edge to falling edge (26ms @2307rpm).
    on P2 if we take 100MHz, one period of 26ms is 2600000

    Possible period-capture modes would be :

    a) %10011 = for X periods, count time

    b) %10101 = for periods in X+ clocks, count time
    c) %10111 = for periods in X+ clocks, count periods

    a) mode measures over a defined number of whole periods, which can be X=1, or 10, or anything that gives a sensible read rate.

    b) & c) mode gives an (appx) known read rate, and auto-scales, and auto-stretches too.
    Usually you pair synchronized 2 pins one in each of b) and c) as you need to know how many whole periods were in that window.
    (see the reciprocal counter examples).
    This gives you a very wide dynamic range.

  • AribaAriba Posts: 2,370
    edited 2020-10-09 - 06:26:21
    Mode %10011 = P_PERIODS_TICKS or
    mode %10101 = P_COUNTER_TICKS
    should work to measure the periode ticks with smartpins.

    Here is a Spin2 example that works for me. You can read the current periode ticks anytime from the smartpin.
    '' Periode time test  P40=fout and P39=fin are connected together
      _clkfreq  = 160_000_000
    PUB testIt() | fout, fin
      pinstart(39, P_PERIODS_TICKS, 1, 0)      '1 periode, posedge to posedge
      fout := 100                              'start with 100 Hz 
      pinstart(40, P_NCO_FREQ +P_OE, 1, 0)     'NCO output
        wypin(40, fout frac clkfreq)           'update NCO freq
        fout += 10                             'raise freq slowly
        fin := clkfreq / rdpin(39) + 1         'read periode and calc freq
        debug(udec(fin)," Hz")

    if you set the mode for P39 with: P_PERIODS_TICKS + P_FILT1_AB, then the input gets filtered with a 600ns filter time, that is: glitches on the posedges will not be counted for 600ns. The input filters can also be configured, but there are 4 default filter settings.

  • You can make the result a bit more accurate by taking adantage of 64bit math.
                  qmul      ##sys_clk,#60           'calc rom
                  getqx     pa
                  getqy     pb
                  add       high,low
                  setq      pb
                  qdiv      pa,high
                  getqx     pa

    Tweaked ref to 25.007mS high period and got this result
    0002500700 0000100000
  • Thank You Ozprodev, Ariba, Jmg, Evanh, Rogloh, and
    Circuitsoft for your input!

    Hopefully in the near future, I can respond with intelligent

    Bill M.
Sign In or Register to comment.