Shop OBEX P1 Docs P2 Docs Learn Events
Counter pulse with propeller — Parallax Forums

Counter pulse with propeller

fdicellofdicello Posts: 7
edited 2011-02-26 23:33 in Propeller 1
Dear All,
I need a help with propeller chip i'm a begginner with this chip.
I want to use two pin as two separate channels pulse counter input ( to count the positive transitition from low to high).
and I need to count all pulse coming in a gate of 200 mS ( milliseconds) at the end of this integration
time I have to get the value of two counter value and send the result to tv out and reset the counter module for new counting.
I wanted to know if someone here can help me with this code.

thank you very much in advanced
Francesco

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-01-16 15:07
    Francesco,

    Do the two 200ms timing intervals for both counters have to coincide exactly, or can they be very slightly offset? If they can be offset, it can be done in Spin without external hardware to do the gating.

    -Phil
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-01-16 15:22
    fdicello: Fracesco, welocme to this amazing forum and the propeller. Here you will find lots of help from many people who have various specialities. So, don't be shy. We all learnt at some time and better to ask than waste a lot of time getting frustrated.

    Obviously there are a number of ways to do this as well as two options, spin and pasm. Since I do not know your background, here is a way to just check 1 pin. If you go through the tutorials (pehaps a fairly newbie can help where to find them these days - or see the stickies [the top 2 threads]) you will find how to start a new cog with this routine.

    Here is just a basic example of what to do to get you going. I have put in 2 lines to show how to output the first count to the tv object...
    PUB WatchPin (InPin) | InPinMsk,c1,c2,count
    InPinMsk := 1 << InPin 'make P0..P31 a 32bit mask
    waitpeq (InPinMsk,InPinMsk,0) 'wait for Px==1
    c1 := cnt 'store the system counter
    ' tv.dec(c1) ' display your results on the TV
    ' tv.out(13) ' display to newline
    waitpne (InPinMsk,InPinMsk,0) 'wait for Px<>1
    c2 := cnt 'store the system counter
    count := c2-c1 ' your answer in system clocks (i.e. normally @ 80MHz is count * 12.5ns)
  • AribaAriba Posts: 2,690
    edited 2011-01-16 15:37
    You don't say what the frequency range of the pulses is. With the two hardware counters of a cog you can measure pulses up to half the clockfrequency (40MHz @80MHz) theoretically.

    If your pulses come not too fast, you can do the following simple measure loop in Spin, but the gate time has some failure because of the time for the Spin commands after the waitcnt. So for frequencies higher than perhaps 50 kHz you will see some deviation to the right value.
    CON  _clkmode      = xtal1 + pll16x                                    
         _xinfreq      = 5_000_000
    
         pin1  = 0                    'input pin numbers
         pin2  = 1
         ms    = 200                  'gate time
         
    OBJ  tv : "tv_text"               'include TV_Text object
    
    PUB Main | pulses1, pulses2
      'start TV_Text
      tv.start(12)                    'set right TV pin here
      'Set up the counters
      ctra := %01000 << 26 + pin1     'counter A in POSdetect mode
      ctrb := %01000 << 26 + pin2     'counter B in POSdetect mode
      frqa := frqb := 1               'increment 1 per pulse
    
      'pulse count loop
      repeat
        phsa := phsb := 0                 'reset count registers
        waitcnt(clkfreq/1000 * ms + cnt)  'wait gate time
        pulses1 := phsa                   'read the puls counts
        pulses2 := phsb
    
        tv.dec(pulses1)                   'show values on TV
        tv.out(13)
        tv.dec(pulses2)
        tv.out(13)
        tv.out(13)
    
        waitcnt(clkfreq + cnt)            'slow down the loop
    
    I hope the comments explain the code good enough, otherwise just ask.

    Andy
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-01-16 16:33
    Andy,

    Your code will always count exra pulses for phsb, as compared to phsa, because the timing interval is longer. Here's what I would suggest for that section of code; hence my prior question about interval offset:
    interval := clkfreq / 1000 * ms
    
    repeat
    
      waitcnt(time0 := clkfreq / 1000 + cnt)
      counta0 := phsa
      countb0 := phsb
    
      waitcnt(time0 += interval)
      counta1 := phsa
      countb1 := phsb
    
      tv.dec(counta1 - counta0)
      tv.out(13)
      tv.dec(countb1 - countb0)
      tv.out(13)
    

    -Phil
  • AribaAriba Posts: 2,690
    edited 2011-01-16 17:29
    Andy,

    Your code will always count exra pulses for phsb, as compared to phsa, because the timing interval is longer....
    -Phil

    You're certainly right, but I disagree with the word "always". Not if the puls periode is longer than the time difference.:smile:
    We don't know the frequency and needed accuracy, so I tried to show the simplest way to do it.

    Andy
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-01-16 17:34
    Ariba wrote:
    You're certainly right, but I disagree with the word "always". Not if the puls periode is longer than the time difference.
    LOL! True!

    -Phil
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-01-17 00:35
    Sorry, just noticed my code lost formatting - I used quote instead of code tags :( Not used to the new forum formats!
  • fdicellofdicello Posts: 7
    edited 2011-01-17 08:03
    Dear Phil and Ariba,
    I want to say thank you for your help and I hope you excuse me for my bad english.
    I prefer to use spin for me is ok if I have some deviation . My pulse are coming from a detector for gamma ray so are statistical pulse this mean that the rate is depending from
    the activity of the source, for exaple withot source I can have a rate of 200 pulse for second ) in other case I can have 4000 pulse for second in other case 40000 pulse for second.
    I have decided to sample the counting for the gate of 200 ms because I need this time resolution, but I will repeat the cycle for five times in order to have 5 values of 200 mS and after
    I will sum all counts to have the total pulses received in a second ( this for each channel because each channel count the pulse coming from different device, the only thing common to the two
    imput channel counters is the gate of 200 ms.
    I hope this information are better of the previous, please let me know if you more info ( ples. see the attached picture also)
    Attachment not found.Thank you very much, I hope you can help me
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-01-17 08:12
    Francesco,

    It sounds like an interesting project. Given that the two detectors are for gamma rays (presumably from the same source), are you trying to approximate coincidence detection by any chance? I would very much like to see photos of your setup, but your attachment is not working.

    -Phil
  • fdicellofdicello Posts: 7
    edited 2011-01-18 01:18
    Phil,
    You have rigth, the detectors are for gamma ray but they Do not work in coincidence, they are two separate channels.
    The setup is the following:
    Two separate channels, each channel have one detection system ( detector,photomultliplier and High voltage), the analog signal from the detector goes in a discriminator circuit, in the output of the discriminator I have the TTL pulse.
    In the output of the discriminator I will have the my pulses to count with the propeller.
    Could you please to help me with the propeller code?
    Francesco
  • AribaAriba Posts: 2,690
    edited 2011-01-18 08:59
    Francesco
    For your application the code I have posted first should work with no problems. The failure in the gate time are only some microseconds which have no influence for your relativly slow puls rate. Phils improvements are good if you want a frequency counter with MHz or hundreds of kHz.

    Have you tried that code? What help do you need further?
    If I understand it right, you want an update rate of 200ms but output always the sum of the 5 latest 200ms measurements.
    Do you want to display the values on TV with this update rate? I think you can't read the values if they change 5 times a second.

    Andy
  • AribaAriba Posts: 2,690
    edited 2011-01-18 09:26
    Here is an extended version of my first code, which does the summing and displays the values 5 times a second always at the same position.
    I have not your puls detectors so I can't say if this is useable.
    CON  _clkmode      = xtal1 + pll16x                                    
         _xinfreq      = 5_000_000
    
         pin1  = 0                    'input pin numbers
         pin2  = 1
         ms    = 200                  'gate time
         
    VAR
      long pulses1[5]                 '2 arrays for measurements
      long pulses2[5]
      
    OBJ  tv : "tv_text"               'include TV_Text object
    
    PUB Main | temp1, temp2, i
      'start TV_Text
      tv.start(12)                    'set right TV pin here
      'Set up the counters
      ctra := %01000 << 26 + pin1     'counter A in POSdetect mode
      ctrb := %01000 << 26 + pin2     'counter B in POSdetect mode
      frqa := frqb := 1               'increment 1 per pulse
    
      'pulse count loop
      repeat
        phsa := 0                         'reset count registers
        phsb := 0
        waitcnt(clkfreq/1000 * ms + cnt)  'wait gate time
        temp1 := phsa                     'read the puls counts
        temp2 := phsb
    
        longmove(@pulses1[1], @pulses1[0], 4)  'shift arrays up
        longmove(@pulses2[1], @pulses2[0], 4)
        pulses1[0] := temp1               'and store new values
        pulses2[0] := temp2
        
        repeat i from 1 to 4              'build the sum of 5 buffers
          temp1 += pulses1[i]
          temp2 += pulses2[i]
    
        tv.out(1)                         'show values on TV on
        tv.dec(temp1)                     'first 2 lines
        tv.str(string("    ",13))
        tv.dec(temp2)
        tv.str(string("    ",13))
    
  • fdicellofdicello Posts: 7
    edited 2011-01-20 06:40
    Ariba,
    Of course you have right, 200 mS is too fast to see on the display. I will display the data every 1 second on the TV.
    At the moment the use of the TV is only for debug.
    My final target is to have a code to do this:
    Step 1) Use one cog as dual counter channel to have CounterA and CounterB values ( temp1, Temp2).
    Step 2) After, I want to make a little real time graphics on VGA display, in order to plot The value of CounterA (on the Y temp1 value and on the X a time scale ).
    Step 3)Perform some calculation with the CounterA and B data.
    At this point I have a question.
    The propeller have 8 cog processor.
    Is it possible to use a different COG for each step?
    If yes, How is possible to pass data from one cog to another?
    For example the CounterA value (Temp1 value) to the COG used in the step3?
    Francesco
  • AribaAriba Posts: 2,690
    edited 2011-01-20 08:40
    fdicello wrote: »
    ...
    Step 1) Use one cog as dual counter channel to have CounterA and CounterB values ( temp1, Temp2).
    Step 2) After, I want to make a little real time graphics on VGA display, in order to plot The value of CounterA (on the Y temp1 value and on the X a time scale ).
    Step 3)Perform some calculation with the CounterA and B data.
    At this point I have a question.
    The propeller have 8 cog processor.
    Is it possible to use a different COG for each step?
    If yes, How is possible to pass data from one cog to another?
    For example the CounterA value (Temp1 value) to the COG used in the step3?
    Francesco
    >Is it possible to use a different COG for each step?
    It is possible, but makes not much sense. As long as the steps are anyway sequential and synchronized it's much easier to do it in the same cog.
    The VGA driver needs to run in parallel and perhaps the pulse counters would also make sense. But calculations and plotting the graphic should be made in a main controller cog which also starts and collects the data from the other cogs.

    >How is possible to pass data from one cog to another?
    As long as the code for different cogs is in the same file, you can pass data by global variables (defined in the VAR section). If you separate the code in several files (objects) you need to add some access methodes in the object like:
    PUB getTemp1
    return temp1
    which you can call from the main object.

    Andy
  • fdicellofdicello Posts: 7
    edited 2011-01-27 07:49
    Hi Ariba and Phil
    I have tested the code but without success.
    I have sent to pin P0 or P1 a square pulse whti frequency of 1 Khz and the count on pulses1 is 7677136.
    So I have decided to modify the value of ms from 200 to 1000 , in this way I will count the incoming pulses for about 1 second.
    In this way if I send to the pin P0 a square pulse of 1 Khz I should to have on the TV the value 1000 counts.
    But the result is 38392691.
    I think There is something wrong in the counting.
    I found out that if I connect only the a wire to the input with no square signal sometime, I have random counts
    instead of have zero counts.
    May be is necessary to place a resistor to the counter
    input in order to avoid to counting noise?
    Thank you for your help
    Francesco
  • AribaAriba Posts: 2,690
    edited 2011-01-27 16:49
    Francesco

    Sorry the counter modes are wrong, they are set to PosDetect now, but we need PosEdge. So change the lines that set the modes to:
    ctra := %01010 << 26 + pin1     'counter A in POSedge mode
      ctrb := %01010 << 26 + pin2     'counter B in POSedge mode
    

    Here is a test code which generates 2 frequencies at the pins to measure with a second cog.
    Be aware that this second cog drives this pins as output, so you should not have anything connected to the two measure pins when you run this test!
    CON  _clkmode      = xtal1 + pll16x                                    
         _xinfreq      = 5_000_000
    
         pin1  = 0                    'input pin numbers
         pin2  = 1
         ms    = 1000                 'gate time
         
    VAR  long  stack[8]
         
    OBJ  tv : "tv_text"               'include TV_Text object
    
    PUB Main | pulses1, pulses2
      'start a Puls generator in a second cog
      cognew(PulsGenerator,@stack)
      'start TV_Text
      tv.start(12)                    'set right TV pin here
      'Set up the counters
      ctra := %01010 << 26 + pin1     'counter A in POSedge mode
      ctrb := %01010 << 26 + pin2     'counter B in POSedge mode
      frqa := frqb := 1               'increment 1 per pulse
    
      'pulse count loop
      repeat
        phsa := 0                     'reset count registers
        phsb := 0
        waitcnt(clkfreq/1000 * ms + cnt)  'wait gate time
        pulses1 := phsa                   'read the puls counts
        pulses2 := phsb
    
        tv.dec(pulses1)                   'show values on TV
        tv.out(13)
        tv.dec(pulses2)
        tv.out(13)
        tv.out(13)
    
    PUB PulsGenerator
      ctra := %00100<<26 + pin1     'NCO mode
      ctrb := %00100<<26 + pin2
      frqa := 537 * 1000 / 10       'set A to 1000Hz
      frqb := 537 * 1500 / 10       'set B to 1500Hz
      dira[pin1] := 1
      dira[pin2] := 1
      repeat
    
    If this works, remove the line:
    cognew(PulsGenerator,@stack)
    and connect your hardware to test it further.

    Ariba
  • fdicellofdicello Posts: 7
    edited 2011-02-24 10:07
    Dear Ariba,
    Thank you for your help.
    I have modified the code like you shown me :
    ctra := %01010 << 26 + pin1 'counter A in POSedge mode
    ctrb := %01010 << 26 + pin2 'counter B in POSedge mode
    and now the counts are ok.
    I have another question, I have tried this code TV.DEC(PULSES1 / 0.2)
    but on the display I have always zero, why?
    Have you found Any problems to use floating point number?

    May you help me?
    thank you
    Francesco
  • pgbpsupgbpsu Posts: 460
    edited 2011-02-24 11:16
    Hi Francesco-

    Welcome to the forums. As you've already found people here are extremely helpful.

    I don't use the TV object, but I believe you suspicion is correct. The floating point is causing trouble. The method TV.DEC is for displaying decimal numbers on a TV. When you pass it PULSES/0.2 it doesn't know what to do with the 0.2. What happens if you try to output the same number to the TV all the time (TV.DEC(1234))? Do you get "1234"? If so that's working properly. Then I'd try TV.DEC(PULSES1) which should change over time. Dividing by 0.2 is the same as multiplying by 5 so you could also just try (TV.DEC(PULSES1*5)).

    Hope that helps.
    Peter
  • AribaAriba Posts: 2,690
    edited 2011-02-24 14:02
    Francesco

    As Peter says, you can not do floatingpoint calculations that easy in Spin. There are Float objects that provides methodes for Floatingpoint. But you do then calculations like that: fvar := FDiv(Float(pulses1), 0.2). And to display the result, you need another object which converts float variables to strings. So if you don't have havy mathematical formulas to calculate, dont use floating point!
    The Propeller works with 32bit variables, this is a range of -2 Billion to +2 Billion, so you normally don't need floats. Just calculate the values with integer multiply and divide: * 0.2 is thes ame as * 2 /10 or * 200/1000. You want divide by 0.2 so this should work:
    tv.dec(pulses1 * 1000 / 200) ' always multiply fist and divide then.
    But you get no decimal places as output because the result is an integer.
    A simple methode to display it with 1 decimal place is:
    temp := pulses1 * 1000 / 200
      dec(temp / 10)
      dec.out(".")
      dec(temp // 10)
    

    Andy

    I
  • ElectricAyeElectricAye Posts: 4,561
    edited 2011-02-25 07:55
    fdicello wrote: »
    ...
    Have you found Any problems to use floating point number?
    ...


    Francesco,

    as Ariba has already pointed out, you should avoid floating point math if you can, but if you need to use it, look at the OBEX for various Objects that will help you with that. I've attached a pdf that talks a little bit more about floating point math.
  • fdicellofdicello Posts: 7
    edited 2011-02-26 07:18
    Dear andy and Peter,
    Thank you for your help.
    I made some experiment and now the code is run well, please see the attached file.
    At this point I want to add the possibility of check two input pins ( if the state of these pins are High or Low)and send to the serial port the values of mediamobile, mediamobile2, Pin1State and PIN2State.
    Could you please to help me to add this code ?

    Thank you very much for your help
    Francesco
    P.S. as you can see my code is very simple I am a beginner with spin language, I think is possible to use a different COG for each operation.
    For example, one COG for counting, one COG for TV, one COG for the serial port, ecc.
  • AribaAriba Posts: 2,690
    edited 2011-02-26 23:33
    You need a serial object to send something over the serial Port:
    OBJ
     ser : FullDuplexSerial"
    
    Then you start it in the init section, like the TV object:
    ser.start(31,30,0,115200)
    
    Now you can send data with similar methodes you use for the TV (dec, hex, str), only the out methode has another name: ser.tx()
    ser.dec(mediamobile)
      ser.tx(13)
    
    You get the state of an input pin with ina[pinNum], so a possible way to show the state over serial is:
    if ina[pinX] == 1
        ser.str(string("Pin ON",13))
      else
        ser.str(string("Pin OFF",13))
    
    But there are many other ways, like ser.dec(ina[pinX])
    All the serial out data expects a Terminal on the PC that shows the values. You can use PST for example.

    Andy

    PS: You already use more than one cog, you just not notice it, because it is hided in the Objects you include. TV_Text use one for the Video generation, and also FullDuplexSerial will use one.
Sign In or Register to comment.