Shop OBEX P1 Docs P2 Docs Learn Events
Let's talk pin jitter with the counters ... — Parallax Forums

Let's talk pin jitter with the counters ...

turbosupraturbosupra Posts: 1,088
edited 2012-07-04 15:33 in Propeller 1
So I've been trying to read a frequency in PASM and I've tried three different ways. The first way does not give any pin jitter, and by that I mean stray cycles that show up that are far less than what the frequency should be, usually less than 100. The second and third way both give pin jitter and will sometimes output < 100 cycles during a loop. I tried a pull down resistor to make sure it wasn't hardware related (although I'm seeing the values on both highs and lows), so I'm pretty confident it isn't stray signals based on that.

I've also tried throwing a waitcnt after the program verifies that the value stored in the phsX is not 0, that did not help. Now the jitter reads waitcnt + <100, which is very confusing.

Another potential cause could be a read/write issue between PASM and the pst/spin and that I've been chasing my tail for hours on this. Maybe I need some sort of lock?

Or maybe this is just something that cannot be fixed and has to be filtered via software. Can anyone elaborate? I'm looking for lessons from those who have more experience than I, which is probably just about everyone here :)

Thanks for reading!


[edit]
While writing this post, I had an idea, I altered the 2nd code block to what the 4th code block looks like and it appears to be working. In short, I filter any value under 200, clear it and ignore it. Is this the right way to go about this? Or a wise way to hand it?

                       ' looks for equality between pinMask and pin state to copy phsb to lowCycles
                        waitpeq pinMask, pinMask               ' compares pinMask to ina condition of pinMask
                        mov     lowCycles, phsb                ' copy low cycles counter to lowCycles
                        mov     phsb, #0                       ' clear low cycles counter
                        wrlong  zero, pstPtr13                 ' write to pointer to show pin state oscillation
                        wrlong  lowCycles, pstPtr12            ' write lowCycles to pointer

                        ' test for high, if high c = 1, then copy low cycles
                        test    pinMask, ina WC, WZ            ' test for high, and if high
if_nc {if not high}     jmp     #end                           ' if not high jump to end
if_c  {if high}         mov     phsbT, phsb wz                 ' write 1 to z if value being copied is a 0, copy low cycles
if_z  {if value = 0}    jmp     #end                           ' if it is a 0, jump
if_nz                   mov     cntT, fiveThouCycles
if_nz                   add     cntT, cnt
if_nz                   waitcnt cntT, #0            
if_nz {if value != 0}   mov     lowCycles, phsb                ' copy low cycles counter to lowCycles
if_nz {if value != 0}   mov     phsb, #0                       ' clear low cycles counter
if_nz {if value != 0}   wrlong  zero, pstPtr13                 ' write to pointer to show pin state oscillation
if_nz {if value != 0}   wrlong  lowCycles, pstPtr12           ' write lowCycles to pointer

                        mov ina, ina
                        and ina, pinMask wz                        ' if z=1, pin is low
if_nz {if not low}      jmp     #end                          ' if not low jump to high              
if_z  {if low}          mov     phsbaT, phsb wz                 ' write 1 to z if value being copied is a 0, copy high cycles
if_z  {if value = 0}    jmp     #end                          ' if it is a 0, jump
if_nz                   mov     cntT, twoHunCycles
if_nz                   add     cntT, cnt
if_nz                   waitcnt cntT, #0            
if_nz {if value != 0}   mov     lowCycles, phsa               ' copy high cycles counter to highCycles
if_nz {if value != 0}   mov     phsb, #0                       ' clear high cycles counter
if_nz {if value != 0}   wrlong  one, pstPtr13                  ' write to pointer to show pin state oscillation
if_nz {if value != 0}   wrlong  lowCycles, pstPtr11          ' write highCycles to pointer                                            





[edit]Working version
                        ' test for high, if high c = 1, then copy low cycles
                        test    pinMask, ina WC, WZ            ' test for high, and if high
if_nc {if not high}     jmp     #end                           ' if not high jump to end
if_c  {if high}         mov     phsbT, phsb wz                 ' write 1 to z if value being copied is a 0, copy low cycles
if_z  {if value = 0}    jmp     #end                           ' jump out of loop to end
[b]if_nz {if value != 0}   cmp     phsbT, #200  WC, WZ            ' compare phsX value to 200
if_be {if <= 200 jmp}   mov     phsb, #0                       ' clear and ignore value if less than 201
if_be {if <= 200 jmp}   jmp     #end                           ' if it is below 201, jump out of loop to end[/b]
if_a  {if value != 0}   mov     lowCycles, phsb                ' copy low cycles counter to lowCycles
if_a  {if value != 0}   mov     phsb, #0                       ' clear low cycles counter
if_a  {if value != 0}   wrlong  zero, pstPtr13                 ' write to pointer to show pin state oscillation
if_a  {if value != 0}   wrlong  lowCycles, pstPtr12            ' write lowCycles to pointer

Comments

  • Mark_TMark_T Posts: 1,981
    edited 2012-07-03 11:09
    What sort of frequency and what is the signal source exactly?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-03 11:32
    The frequency varies from 200hz to 7000hz. The signal source currently is another propeller through a 100ohm resistor.
  • jmgjmg Posts: 15,183
    edited 2012-07-03 14:14
    turbosupra wrote: »
    So I've been trying to read a frequency in PASM and I've tried three different ways. The first way does not give any pin jitter, and by that I mean stray cycles that show up that are far less than what the frequency should be, usually less than 100. The second and third way both give pin jitter and will sometimes output < 100 cycles during a loop.

    I'm not following this - do you mean 100 counts low, or a value of 100 ?
    turbosupra wrote: »
    The frequency varies from 200hz to 7000hz. The signal source currently is another propeller through a 100ohm resistor.

    It is not clear what your update rate is, or how many digits of precision you want ?

    There are three basic methods to measure frequencies (Fu) :

    a) Measure Fu Period, and invert. (You can expand to choose how many cycles).
    b) Use a gate fixed time and count Fu cycles - counter value is direct cycles/gate time
    c) Build a reciprocal counter, where you have a nominal gate/update time, but 'snap' that to an exact Fu edge, and then run the reciprocal maths
    Fu = (Whole_Cycles)/(Time_Taken)

    With low frequencies like you have here, a) or c) usually have the best precision.
    c) can auto-scale, and has the highest Digits/Second ability.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-07-03 14:18
    How is your counter set up? The easiest way to read a frequency, assuming a clean signal, is to set up a counter to count either rising or falling edges. Then just read phsa using the neg opcode, wait a defined length of time, and read phsa again with the add opcode.

    Where this fails, though, is when the frequency is very low w.r.t. the amount of time you can allocate for counting edges. When that happens, you have to measure the time between edges and invert to compute a frequency. This method is fraught with issues, however, if the input pulse train is jittery, as many mechanically-derived pulse trains tend to be.

    -Phil
  • groggorygroggory Posts: 205
    edited 2012-07-03 14:26
    Op,

    Do you have a logic analyzer that you could run against your signal source? That way we can see how clean the source is.

    ...

    or, being that you say the source is a propeller, could you post the code that the source propeller is using to generate your signal?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-03 15:33
    jmg wrote: »
    I'm not following this - do you mean 100 counts low, or a value of 100 ?

    It is not clear what your update rate is, or how many digits of precision you want ?

    There are three basic methods to measure frequencies (Fu) :

    a) Measure Fu Period, and invert. (You can expand to choose how many cycles).
    b) Use a gate fixed time and count Fu cycles - counter value is direct cycles/gate time
    c) Build a reciprocal counter, where you have a nominal gate/update time, but 'snap' that to an exact Fu edge, and then run the reciprocal maths
    Fu = (Whole_Cycles)/(Time_Taken)

    With low frequencies like you have here, a) or c) usually have the best precision.
    c) can auto-scale, and has the highest Digits/Second ability.

    I would just like the cycles at this point, I have math in my code that can calculate what I need from the number of cycles. My code was actually working well with waitpeq and waitpne, I just cannot use code that pauses the cog anymore.

    How is your counter set up? The easiest way to read a frequency, assuming a clean signal, is to set up a counter to count either rising or falling edges. Then just read phsa using the neg opcode, wait a defined length of time, and read phsa again with the add opcode.

    Where this fails, though, is when the frequency is very low w.r.t. the amount of time you can allocate for counting edges. When that happens, you have to measure the time between edges and invert to compute a frequency. This method is fraught with issues, however, if the input pulse train is jittery, as many mechanically-derived pulse trains tend to be.

    -Phil

    Hi,

    Here is the frequency/counter setup code
                            
    
    initialize
    
                          
                            rdlong  pin, pin
                            
                            'mov     ctra, POS_DETECT                ' ctra measures high phase
                            'add     ctra, pin
                            mov     frqa, #1
                            movs    ctra, pin
                            movi    ctra, POS_DETECT
                            
                            'mov     ctrb, NEG_DETECT                ' ctrb measures low phase
                            'add     ctrb, pin
                            mov     frqb, #1
                            movs    ctrb, pin
                            movi    ctrb, NEG_DETECT
                            
                            mov     pinMask, #1                        ' create pin mask
                            shl     pinMask, pin
                            mov     ina, pinMask
                            mov     inb, pinMask
    
    _____________________________________________
    
    POS_DETECT              long    %01000_000
    NEG_DETECT              long    %01100_000
    
    





    groggory wrote: »
    Op,

    Do you have a logic analyzer that you could run against your signal source? That way we can see how clean the source is.

    ...

    or, being that you say the source is a propeller, could you post the code that the source propeller is using to generate your signal?

    Hi,

    I have to objects that can generate these frequencies, one that I wrote and one that someone was kind enough to write for me. The waitpeq/waitpne functions work fine if that helps narrow down anything?

    Here is the loop from my own code
    :thirtyfour
    
                            mov     prevLoopCnt, loopCnt
                            mov     loopCnt, cnt
                            mov     loopCntT, loopCnt
                            sub     loopCntT, prevLoopCnt
                            wrlong  loopCntT, cyclesPerLoopPtr
                            
                            add     toothNumber, #1
                            wrlong  toothNumber, pstPtr15
                            wrlong  toothNumber, toothNumberPtr
    
                            cmp     toothNumber, #26 WC, WZ
    if_e                    mov     tooth26REdgeCnt, cnt
    if_e                    wrlong  tooth26REdgeCnt, tooth26REdgeCntPtr                        
                            
                                                                 
                            cmp     toothNumber, #34 WC, WZ       ' compare pin next pin state to high
    if_be                   or      outa, pinMask                 ' set pin high
    if_be                   add     timeStamp, highCycles         ' add the amount of cycles that the pulseWidth should be HIGH to timeStamp, so cmp is not true until after that
    if_be                   waitcnt timeStamp, #0         
    if_be                   andn    outa, pinMask                 ' set pin low
    if_be                   add     timeStamp, lowCycles          ' add the amount of cycles that the pulseWidth should be LOW to timeStamp, so cmp is not true until after that    
    if_be                   waitcnt timeStamp, #0
    if_be                   jmp     #:thirtyfour
    
    
    :minustwo       
                            cmp     toothNumber, #34 WC, WZ
    if_a                    andn    outa, pinMask                 ' set pin low for gap
    if_a                    add     timeStamp, lowGapCycles         ' add the amount of cycles that the pulseWidth should be HIGH to timeStamp, so cmp is not true until after that
    if_a                    waitcnt timeStamp, #0                        
    
    if_a                    or      outa, pinMask                 ' set pin high for gap
    if_a                    mov     toothNumber, #0
    if_a                    add     timeStamp, highGapCycles         ' add the amount of cycles that the pulseWidth should be HIGH to timeStamp, so cmp is not true until after that
    if_a                    waitcnt timeStamp, #0
                           
    
    
  • jmgjmg Posts: 15,183
    edited 2012-07-03 16:02
    turbosupra wrote: »
    I would just like the cycles at this point, I have math in my code that can calculate what I need from the number of cycles.

    Do you mean Fu cycles per (undefined) sample time, or Clock Cycles per Fu period ?
    turbosupra wrote:
    My code was actually working well with waitpeq and waitpne, I just cannot use code that pauses the cog anymore.

    Why not ? - you will need some means to lock to edges (aka wait) no matter what you write ?

    If you need to 'do other stuff' such that you cannot be certain you have got back in time for the NEXT edge, then drive the Fu into a counter. and check & use that, after a WAITxx. Doing that means you do not lose any information. It will usually be 1 on single-cycle grabs, but if it reads 2 or more, you still know exactly how many cycles have occurred.
    This is now getting close to option c) I described above.

    If you can tolerate using two pins, you should also be able to use WAITxx to get a true edge
    If you count Fu as above, just configure CTRx as POSEDGE detector w/ feedback, and now you have Fu and a 1 SysClk delayed Fu PinB, which will give a Bit-pair result of 00/11 on stable L/H and 01/10 on each edge.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-03 16:40
    Hello,

    I'm not quite sure what you are asking and you are talking in terms I'm not familiar with, to me the clock cycles define the period, since I have a given of clkfreq. I need to know whether the pin was high for 200000 clock cycles and then low for 200000 clock cycles (200hz) or high for 5714 clock cycles and low for 5714 clock cycles (7000hz), as well as anything in between that range. All I need is the clock cycle count for pin state high and the clock cycle count for pin state low. I only want to update once after the pin is in the opposing state, for example I want to count high clk cycles when the pin transitions to low and count low clk cycles when the pin transitions to high. In my code, I check for pin state, verify the phsX is not 0 and then copy the cycles stored on phsX for the state that is opposite of the current pin state.

    I cannot pause the cog as I do need to do other stuff and I need to have a timeout.

    I just searched around for information on the POSEDGE with feedback, I'm unfamiliar with that. I didn't find anything so I will keep searching.



    Edit, I found this, I don't understand yet what the feedback buys me?
    http://www.parallaxsemiconductor.com/sites/default/files/appnotes/AN008-SigmaDeltaADC-v1.0_0.pdf
    The CTRx register contents determine which counter mode and associated external ports the counter uses. For sigma-delta operation, the counter mode is “positive with feedback.” This means that the counter counts up for every clock cycle in which its input is a logic “high.” It also means that the counter’s output pin will equal the inverse of its input pin, delayed by one processor clock. Here is the layout of the CTRx register, configured for sigma-delta operation
    jmg wrote: »
    Do you mean Fu cycles per (undefined) sample time, or Clock Cycles per Fu period ?

    Why not ? - you will need some means to lock to edges (aka wait) no matter what you write ?

    If you need to 'do other stuff' such that you cannot be certain you have got back in time for the NEXT edge, then drive the Fu into a counter. and check & use that, after a WAITxx. Doing that means you do not lose any information. It will usually be 1 on single-cycle grabs, but if it reads 2 or more, you still know exactly how many cycles have occurred.
    This is now getting close to option c) I described above.

    If you can tolerate using two pins, you should also be able to use WAITxx to get a true edge
    If you count Fu as above, just configure CTRx as POSEDGE detector w/ feedback, and now you have Fu and a 1 SysClk delayed Fu PinB, which will give a Bit-pair result of 00/11 on stable L/H and 01/10 on each edge.
  • jmgjmg Posts: 15,183
    edited 2012-07-03 17:41
    turbosupra wrote: »
    I need to know whether the pin was high for 200000 clock cycles and then low for 200000 clock cycles (200hz) or high for 5714 clock cycles and low for 5714 clock cycles (7000hz), as well as anything in between that range.

    OK, so you are measuring Period, on a per-Fu-cycle basis. ( note as PhiPi has mentioned, this is jitter prone)
    turbosupra wrote:
    I just searched around for information on the POSEDGE with feedback, I'm unfamiliar with that. I didn't find anything so I will keep searching.
    Edit, I found this, I don't understand yet what the feedback buys me?

    It buys you a true edge wait (by testing two bits), as opposed to a Level only wait (which can fire early, it is not a true edge)
    turbosupra wrote:
    I cannot pause the cog as I do need to do other stuff and I need to have a timeout.

    Then the above does not help, as it uses a WAIT.

    If you really want to run wait-free, then you have to accept lower precision.

    The best you can then do, is configure the Fu to clock a Counter ( just POSEDGE, POSEDGE with feedback not needed) and poll the counter for a change. when it is <> last reading, you are as close to your edge as your loop timing allows.

    With true edge precision, (SysCLK & Wait) you capture full cycles as 80e6/11428 = 7000.350Hz, and next is 80e6/11427 = 7000.962Hz etc (.0087%)

    Now let's suppose you have a 2us loop - you now only know the edge to 2us granularity, so now your possible frequency readings are
    500k/71 = 7042.253Hz, then 500k/72 = 6944.44Hz (etc) (declined to 1.4%)

    The faster your polling can be, the better this is, or you may decide you do not need a reading every ~142us, and decide to update at the lowest rate (or some lower rate) if you check every ~5ms, or > 1 count, now your frequency steps are improved (and you have reduced the jitter by averaging at least the higher frequencies)
    eg if you read 35 Fu counts, in 2500 2us loops, 35*500k/(2500) = 7000
    next is 35 Fu counts in 2499 2us loops, 35*500k/(2499) = 7002.80 & likewise 35*500k/(2498) = 7005.604
    At 400Hz, you may get 2 Fu counts, for 2*500k/(2498) = 400.320, then 2*500k/(2499) = 400.16006
    (improved to .04%)

    Of course, if the Prop had a Capture feature in the Counters, no compromise would be needed.
    Hopefully on Prop 2 ?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-03 18:13
    Hi JMG,

    Thanks for the reply. So are you saying that the way I'm doing it with POSEDGE and the filter that removes anything less than XXX is the best way I can do it?

    I don't mind getting the value a few cycles late (lower precision), as long as I get the value before it is overwritten. If my understanding of the counters are correct, I can wait to poll the counter at any point that it is in an opposing state and get the number of cycles from the previous state. If it goes high to low every 10k cycles and then low to high every 10k cycles, I can wait for it to transition from high to low and get the high cycles (while it is low) at [transition +1] cycles or [transition +9999] cycles and it doesn't really matter as the count is stored until the next time that same pin state is reached and the value is overwritten, correct?

    My code ends up averaging the last 8 highs or the last 8 lows.
  • jmgjmg Posts: 15,183
    edited 2012-07-03 18:45
    turbosupra wrote: »
    Hi JMG,

    Thanks for the reply. So are you saying that the way I'm doing it with POSEDGE and the filter that removes anything less than XXX is the best way I can do it?

    I don't mind getting the value a few cycles late (lower precision), as long as I get the value before it is overwritten. If my understanding of the counters are correct, I can wait to poll the counter at any point that it is in an opposing state and get the number of cycles from the previous state. If it goes high to low every 10k cycles and then low to high every 10k cycles, I can wait for it to transition from high to low and get the high cycles (while it is low) at [transition +1] cycles or [transition +9999] cycles and it doesn't really matter as the count is stored until the next time that same pin state is reached and the value is overwritten, correct?

    I'm not sure why you do HI/LO - I think you are using
    %01000 POS detector mode
    when I would instead use
    %01010 POSEDGE detector

    That halves the work, and guarantees to work on a full cycle, as it is edge based, and gives twice the time-tolerance.
    It changes CTR to read Fu cycles, ( as opposed to Gated SysClks), but you can still get SysClk counts from CNT.

    You then poll the CTR value, and after it changes, (or after it is +8, as you already average, so let the HW do it for you)
    you immediately grab Time (from CNT), and you have 8 cycles in that time.


    If you use the actual value >8, then it even tolerates a polling loop so slow, it misses and edge or two.
    Because edges are counted in hardware, that does not matter.

    What is your polling loop time, and it is precisely paced ?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-07-03 19:10
    What do these two statements do? (Or ... what do you want them to do?)
            mov     ina, pinMask
            mov     inb, pinMask
    

    -Phil
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-03 19:16
    You are right, I am using POS and not POSEDGE.

    Let me ask you, if I do use POSEDGE, how does that work with giving me the total number of cycles the pin is high? Based on the name, I figured it would only alert as to the moment the rising edge surpassed 1.65v. Is that how it works? Would I then need to detect NEGEDGE and then subtract POSEDGE from NEGEDGE to get the amount of cycles it was high?

    All of my math is based on clock cycles. Do you mind giving me a simple example to show me what I should see, I'm having a hard time conceptualizing this.


    jmg wrote: »
    I'm not sure why you do HI/LO - I think you are using
    %01000 POS detector mode
    when I would instead use
    %01010 POSEDGE detector

    That halves the work, and guarantees to work on a full cycle, as it is edge based, and gives twice the time-tolerance.
    It changes CTR to read Fu cycles, ( as opposed to Gated SysClks), but you can still get SysClk counts from CNT.

    You then poll the CTR value, and after it changes, (or after it is +8, as you already average, so let the HW do it for you)
    you immediately grab Time (from CNT), and you have 8 cycles in that time.


    If you use the actual value >8, then it even tolerates a polling loop so slow, it misses and edge or two.
    Because edges are counted in hardware, that does not matter.

    What is your polling loop time, and it is precisely paced ?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-03 19:20
    I'm not sure why I have inb, but with ina I use the command with the following code. I'm not sure it's right :) but it seems to be working?

                            ' test for low, if low z = 1, then copy high cycles
                            test    pinMask, ina WC, WZ            ' test for low, and if low
    if_nz {if not low}      jmp     #high                          ' if not low jump to high              
    if_z  {if low}          mov     phsaT, phsa wz                 ' write 1 to z if value being copied is a 0, copy high cycles
     
    

    and
                            ' test for high, if high c = 1, then copy low cycles
                            test    pinMask, ina WC, WZ            ' test for high, and if high
    if_nc {if not high}     jmp     #end                           ' if not high jump to end
    if_c  {if high}         mov     phsbT, phsb wz                 ' write 1 to z if value being copied is a 0, copy low cycles
    
    
    What do these two statements do? (Or ... what do you want them to do?)
            mov     ina, pinMask
            mov     inb, pinMask
    

    -Phil
  • jmgjmg Posts: 15,183
    edited 2012-07-03 19:27
    turbosupra wrote: »
    You are right, I am using POS and not POSEDGE.

    Let me ask you, if I do use POSEDGE, how does that work with giving me the total number of cycles the pin is high? Based on the name, I figured it would only alert as to the moment the rising edge surpassed 1.65v. Is that how it works? Would I then need to detect NEGEDGE and then subtract POSEDGE from NEGEDGE to get the amount of cycles it was high?

    All of my math is based on clock cycles. Do you mind giving me a simple example to show me what I should see, I'm having a hard time conceptualizing this.

    This is the key :
    It changes CTR to read Fu cycles, ( as opposed to Gated SysClks), but you can still get SysClk counts from CNT.

    Yes, you still need to get SysClks (elapsed time), which you do by reading CNT (once), not your gated CTR pair. (twice)

    The CNT you read, is now the time for a WHOLE number of cycles (not half cycles as before)
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-07-03 19:40
    I'm not sure why I have inb, but with ina I use the command with the following code. I'm not sure it's right but it seems to be working?
    Writing to ina and inb does nothing for your code. Those two movs can be excised with no ill effects.

    When coding, you should write with purpose and know -- I mean really know -- exactly what each statement does. Throwing stuff in because it "seems to be working" does nothing to promote your end result and serves only to obfuscate your original intent.

    -Phil
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-03 19:45
    Ok, that makes sense, so basically risingEdgeToNextRisingEdge := (currentPosEdge-previousPosEdge) ?

    Unfortunately for me, I need them separate in this particular project and I do comparisons against the low and high times separately, which are not split equal at 50% high/50% low either.

    By the way, the whole "Fu" thing is really throwing me. Is that short for Frequency units or something so I can read it as a word instead of "FU" ? :)

    jmg wrote: »
    This is the key :
    It changes CTR to read Fu cycles, ( as opposed to Gated SysClks), but you can still get SysClk counts from CNT.

    Yes, you still need to get SysClks (elapsed time), which you do by reading CNT (once), not your gated CTR pair. (twice)

    The CNT you read, is now the time for a WHOLE number of cycles (not half cycles as before)
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-03 19:47
    I guess you've forgotten what it was like to struggle to understand something, when you are experimenting and trying to grasp a concept.

    Anyway, I'd like to really know (I've read the prop manual on ina already), so I'm all ears.

    Writing to ina and inb does nothing for your code. Those two movs can be excised with no ill effects.

    When coding, you should write with purpose and know -- I mean really know -- exactly what each statement does. Throwing stuff in because it "seems to be working" does nothing to promote your end result and serves only to obfuscate your original intent.

    -Phil
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-03 19:59
    Maybe because all of the pins are configured as inputs from the start? And writing to the shadow register is pointless?

    I got that function from someone else's code while searching the forums earlier today at work, unfortunately I do not remember the link or the context now. I only remember that they wrote to the shadow register for a reason, but I forget why.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-07-03 20:01
    trubosupra wrote:
    I guess you've forgotten what it was like to struggle to understand something, when you are experimenting and trying to grasp a concept.
    No, learning new stuff is an everyday occurrence for me, and struggling to do so is not uncommon. But I try to be methodical about it and endeavor not to apply concepts before I understand them. Sometimes the shotgun approach can yield positive results, but those instances are vanishingly rare. I do appreciate your zeal and ambition, though. Nonetheless, can I recommend a more bottom-up approach to your programming? IOW, test each individual technique individually before incorporating it into a larger program. It will not only help to isolate mistakes, but also aid in encapsulating issues presented to the forum. If you can show us an entire, compilable program that isolates the issue at hand -- rather than listing isolated snippets -- we can test it on our own benches and be in a better position to offer assistance.

    Thanks,
    -Phil
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-03 20:10
    Ok, I can try that. The problem with this program is that it requires to propellers, or a bunch of objects linked together with one propeller pin feeding the other.

    I do have a compilable counter program in reference to this particular thread, as I have a PASM template that I've created and use. I have no problem attaching it to the thread, but am not sure how useful it'll be because it requires that other piece of code on the other prop that generates the frequency.

    I believe that ina/inb was left over from a previous snippet of code that I had removed after trying it, and I had just forgotten to remove those lines as well, unfortunately they seemed to have bit me this time and became a point of focus. I don't know how others test code/technique, but with my template it can be used as a child object or a stand alone object and write to the pst and debug. Maybe this is poor form and not granular enough, I'm pretty new so that would not surprise me to hear from someone with much more experience then I.
  • jmgjmg Posts: 15,183
    edited 2012-07-03 21:00
    turbosupra wrote: »
    Ok, that makes sense, so basically risingEdgeToNextRisingEdge := (currentPosEdge-previousPosEdge) ?

    Yes, if those are captures of SysClks from CNT.
    turbosupra wrote:
    Unfortunately for me, I need them separate in this particular project and I do comparisons against the low and high times separately, which are not split equal at 50% high/50% low either.

    Ah, you did not actually SAY that tho, you asked to "read a frequency"....

    If you want to read Low and High times, ( half periods) you will need more gymnastics.

    Since this is polled anyway, you may still be able to use hardware to help, (over multiple cycles), if you configure one timer as =\_ edge, and one as gate on High, and also poll-capture CNT (as above) then you get a highly accurate total edge count, and the CTR value Gate on High is also accurate, and the PeriodSysClk-HiSysClks will give you a LoSysClk value (poll accurate).

    This still lets you SW capture after some number of edge counts, (8,16, 35 etc) before actually reading the registers, so it gives your code more slack time to do other things.
    A true edge count should also make your missing input timeout easier, as no change in edge cont, means there is no frequency input.
    turbosupra wrote:
    By the way, the whole "Fu" thing is really throwing me. Is that short for Frequency units or something so I can read it as a word instead of "FU" ? :)

    Fu = Frequency Unknown - that which is being measured :) (or Fin, if you prefer?)
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-04 06:53
    Ok, so to be more clear I do need frequency (Fin) as an end result, but want to obtain it through counting 1/2 periods and doing my own math.

    As for terminology, rising edge is also gate on high and falling edge is gate on low?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-07-04 07:33
    turbosupra wrote:
    As for terminology, rising edge is also gate on high and falling edge is gate on low?
    No, they're different. When you configure a counter to count rising or falling edges, frqa is added to phsa once per transition, i.e. one count per cycle. You would use that to measure frequency directly. When configured to count during highs (or lows) -- i.e. gating -- frqa is added to phsa at the system clock rate whenever the input is high (or low).

    -Phil
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-04 08:34
    Hi Phil, thank you for the explanation.

    I believe I have it already setup for gating then, although I did not know the term before today. The code below is set up to accumulate system clocks to frqa each time the pin is high and frqb each time the pin is low.

    When the pin is high, the code checks that the low clock count is not 0 as well as higher than 200 (to eliminate jitter) and copies the low clock count stored on phsb, then finally clears the phsb low count.

    When the pin is low, the code checks that the high clock count is not 0 as well as higher than 200 (to eliminate jitter) and copies the high clock count stored on phsa, then finally clears the phsa high count.

    Is my logic solid? And my code in line with my logic? I can post the entire code block based on our prior conversation if you would like that instead.

                            mov     frqa, #1
                            movs    ctra, pin
                            movi    ctra, POS_DETECT
                            
                            mov     frqb, #1
                            movs    ctrb, pin
                            movi    ctrb, NEG_DETECT
    
    
                            ' test for low, if low z = 1, then copy high cycles
                            test    pinMask, ina WC, WZ            ' test for low, and if low
    if_nz {if not low}      jmp     #high                          ' if not low jump to high              
    if_z  {if low}          mov     phsaT, phsa wz                 ' write 1 to z if value being copied is a 0, copy high cycles
    if_z  {if value = 0}    jmp     #high                          ' if it is a 0, jump
    if_nz {if value != 0}   cmp     phsaT, #200  WC, WZ            ' compare phsX value to 200
    if_be {if <= 200 jmp}   mov     phsa, #0                       ' clear and ignore value if less than 201 
    if_be {if <= 200 jmp}   jmp     #high                          ' if it is below 201, jump out of loop to high 
    if_a  {if > 200}        mov     highCycles, phsa               ' copy high cycles counter to highCycles
    if_a  {if > 200}        mov     phsa, #0                       ' clear high cycles counter
    
    
    
                            ' test for high, if high c = 1, then copy low cycles
                            test    pinMask, ina WC, WZ            ' test for high, and if high
    if_nc {if not high}     jmp     #calcshigh                           ' if not high jump to end
    if_c  {if high}         mov     phsbT, phsb wz                 ' write 1 to z if value being copied is a 0, copy low cycles
    if_z  {if value = 0}    jmp     #calcshigh                           ' jump out of loop to end
    if_nz {if value != 0}   cmp     phsbT, #200  WC, WZ            ' compare phsX value to 200
    if_be {if <= 200 jmp}   mov     phsb, #0                       ' clear and ignore value if less than 201
    if_be {if <= 200 jmp}   jmp     #calcshigh                           ' if it is below 201, jump out of loop to end
    if_a  {if value != 0}   mov     lowCycles, phsb                ' copy low cycles counter to lowCycles
    if_a  {if value != 0}   mov     phsb, #0                       ' clear low cycles counter
    
    
    
    
    POS_DETECT              long    %01000_000
    NEG_DETECT              long    %01100_000
    
    
    
  • jmgjmg Posts: 15,183
    edited 2012-07-04 14:59
    turbosupra wrote: »
    When the pin is high, the code checks that the low clock count is not 0 as well as higher than 200 (to eliminate jitter) and copies the low clock count stored on phsb, then finally clears the phsb low count.

    Isn't 0 included in the only take > 200 test ?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-04 15:33
    Yes it is, I'll clean that up :)

    If that's the worst part of my code, that's quite a compliment.

    On a side note, I did get the timeout and rest of code to work this afternoon :D

    jmg wrote: »
    Isn't 0 included in the only take > 200 test ?
Sign In or Register to comment.