xTach - Tachometer - Frequency Counter - Pure spin

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
Request group membership
By: Mark Owen, created: 2014-10-17 | updated: 2014-10-18
 
Demonstrates usage of the xTach methods for determining the activity
  on an input pin:
        Pulse width in system clock ticks
        Pulse frequency in Hz (cycles per second)
        Pulses per minute
        Revolutions per minute
 
  Uses the Parallax Serial Terminal for output at 115,200 baud for output.
  
  Written as a means of circumventing jitter found to be present when using
  assembly language frequency counters for low frequency signals (in my case
  a belt driven aircraft propeller with 39 teeth per revolution on the main
  drive pully which runs at a maximum of 3600 revolutions per minute).
 
  Has been tested using a signal generator from 1Hz to 50kHz and found to be
  accurate to better than 98% over the range tested with the largest errors at
  frequencies less than 30Hz (2%).
 
Includes two source files in a single zip file:
  xTachTest.spin - the demonstration program
  xTach.spin       - the object module
 
Updated 2014-10-18 ti incorporate function for dealing with loss of signal.
Original File Upload
AttachmentSize
xTach.zip4.06 KB

Comments

Can you provide some *jittery* examples? Given that SPIN's waitpxx commands simply map down to their PASM equivalents I'd argue that the SPIN version suffers from more jitter due to hub-window-aliasing (cnt is always read at a fixed distance from the hub window sync point degrading waitpxx accuracy to clkfreq/16). The only other difference would be the delay between successive waitpxx commands.

I do not disagree in theory however in practice the jm_freqin.spin found here on the obex  and used in various tachometer related programs here exhibits a problem for me (perhaps not for anyone else).   I tried various methods of isolating and correcting the problem to no avail so in the end I went with this xTach route to acheive a stable result for my application and thought the code might be useful to someone else with the same problem or who is perhaps ASM intolerant.

The problem manifests itself as illustrated by the following example.

Here are two sets of samples taken from a 780Hz signal using the xTach code and jm_freqin code for comparison:

PkPkTicks      Hz        **xTach Result - signal 780Hz 3V square 50% duty**
102560         780
102560         780
102528         780
102560         780
102544         780
102560         780
102560         780
102560         779
102592         780
102560         780
102544         780
102560         780
102560         779
102592         780
102560         780
102560         780
102560         780
102560         780
102560         780
102528         780
 
period         freq      **jm_freqin Result - signal 780Hz 3V square 50% duty**
51185          15632
76             10526315
51406          15562
102557         7800
17             47058823
102563         7800
51128          7805
21             38095238
102563         15646
51124          36363636
102536         7802
102561         15653
0              0
102561         29629629
102561         88888888
51189          15643
51173          15633
102564         7800
0              7800
21             38095238
 
The source code used to produce the above test is:
CON
  _clkmode = xtal1 + pll16x                  ' System clock → 80 MHz
  _xinfreq = 5_000_000                       ' external crystal 5MHz
                                                 
OBJ
  xTACH         : "xTach"
  jmFreqin      : "jm_freqin"
  pst           : "Parallax Serial Terminal"
 
PUB Main | i,j
  EnablePST
 
  xTACH.Start(13)
  i~
  pst.Position(0,i)
  pst.Str(string("PkPkTicks"))
  pst.Position(15,i)
  pst.Str(string("Hz"))
  pst.Position(25,i) 
  pst.Str(string("**xTach Result - signal 780Hz 3V square 50% duty**"))
  i++
  repeat
    pst.Position(0,i)
    pst.ClearEnd
    pst.Dec(xTACH.PulsePktoPkTicks)
    pst.Position(15,i)
    pst.Dec(xTACH.Hz)
  while ++i =< 20
  xTach.Stop
 
  waitcnt(clkfreq+cnt)
  
  jmFreqin.init(13)
  j:=i++
  pst.Position(0,i)
  pst.Str(string("period"))
  pst.Position(15,i)
  pst.Str(string("freq"))
  pst.Position(25,i) 
  pst.Str(string("**jm_freqin Result - signal 780Hz 3V square 50% duty**"))
  i++ 
  repeat 
    pst.Position(0,i)
    pst.ClearEnd
    pst.Dec(jmFreqin.period)
    pst.Position(15,i)
    pst.Dec(jmFreqin.freq)
  while ++i =< j+21
 
  repeat
    waitcnt(clkfreq+cnt)
 
PRI EnablePST
  pst.start(115200)
  repeat 
    pst.Home
    pst.Clear
    pst.str(string("Start test: press ."))
    pst.newline
    repeat while not pst.RxCount
      pst.Char("~")
      waitcnt(clkfreq+cnt)
    if pst.CharIn == "."
       quit
  pst.Home
  pst.Clear
 

___________________

 

Sorry about the lengthy reply.  I cannot get the "FILTERED HTML" <CODE> to work. ... Mark

OK, there are several things about jm_freqin which are odd. The result of calling period should be discarded if 0 and the freq method should take a caller period value, otherwise there is a race as freq calls period itself which may have changed in between, IOW period and freq wouldn't match.

Apart from that, this object measures logic levels which are sensitive to unclean pulse edges as can be seen by rather low cycle count for some pairs you listed. Your method measures pulse length between rising edges and has a buffer zone of about 40 hub windows before it looks for the opposite level, i.e. it would simply ignore unclean edges.

FWIW, providing 780Hz from another on-chip counter gives me expected results for both measurement methods.

Thanks for the verification tests.  I had thought to use another on-chip counter as a signal source but did not get around to it.