Shop OBEX P1 Docs P2 Docs Learn Events
PASM critique requested — Parallax Forums

PASM critique requested

turbosupraturbosupra Posts: 1,088
edited 2012-04-12 14:12 in Propeller 1
Hello,

This code compiles, but I don't know if it does what is intended (probably not actually) because I just started learning and haven't learned how to debug very effectively yet with the pst and PASM. I'm using MUL, which I accidentally discovered even though it isn't listed in the PASM manual, so I'm not even sure it does what I think it does. I'm sure there are tricks to make this code faster and shorter, since I'm new I would guess that I write very literally and in what could be termed the "long way", but while learning I need to see it written out. There are probably extra variables, because parts of the code are copied from another PASM code block (thank you anonymous code donator :D , you know who you are ).


What I'm trying to do

1.) Measure frequency rising edge to following rising edge (a frequency rate of anywhere from 180hz to 9000hz)
2.) Measure frequency falling edge to following falling edge
3.) Wait until I have 8 measurement
4.) After accumulating 8 measurements, divide by 8 to get an average
5.) Count frequency logic rising edges
6.) Multiply average frequency rate by 110 and 90 (for 110% and 90%) and then compare them to the current frequency measurement multiplied by 100
7.) Identify "gaps" longer than the average and count them at a per second rate
8.) Compare shortest amount of cycles to shortest on record, replace if necessary
9.) Compare longest amount of cycles to longest on record, replace if necessary


DAT

                        org     0

frcntr                  mov     tmp1, par                       ' start of structure
                        rdlong  tmp2, tmp1                      ' get pin#, store it in tmp2

                        mov     ctra, POS_DETECT                ' ctra measures high phase
                        add     ctra, tmp2
                        mov     frqa, #1
                        
                        mov     ctrb, NEG_DETECT                ' ctrb measures low phase
                        add     ctrb, tmp2
                        mov     frqb, #1
                        
                        mov     mask, #1                        ' create pin mask
                        shl     mask, tmp2

                        ' save addresses of hub storage
                        add     cycleptr, tmp1
                        add     toothcntptr, tmp1              
                        add     averageptr, tmp1
                        add     maxptr, tmp1
                        add     minptr, tmp1

                        mov     timeStamp, cnt

                                                
restart                 waitpne mask, mask                      ' wait for 0 phase
                        mov     lowCycle, phsa
                        mov     phsa, #0                        ' clear high phase counter
                        mov     lowCntLog, cnt

                        ' wait for pin == 1
highphase               waitpeq mask, mask                      
                        add     highCycle, phsb
                        mov     phsb, #0                        ' clear low phase counter
                        mov     highCntLog, cnt 

                        ' write number of cycles measured to fcCycles
                        'wrlong  lowCycle, cycleptr               

                        mov     prevCycle9, prevCycle8
                        mov     prevCycle8, prevCycle7
                        mov     prevCycle7, prevCycle6
                        mov     prevCycle6, prevCycle5
                        mov     prevCycle5, prevCycle4
                        mov     prevCycle4, prevCycle3
                        mov     prevCycle3, prevCycle2
                        mov     prevCycle2, lowCycle

                        cmp     prevCycle9, #0 WR, WZ   ' Make sure I have 8 previous values for an average
if_be                   jmp     #restart

                        add     avgCycle, prevCycle9    ' sum prevCycle9 into avgCycle  
                        add     avgCycle, prevCycle8    ' sum prevCycle8 into avgCycle 
                        add     avgCycle, prevCycle7    ' sum prevCycle7 into avgCycle 
                        add     avgCycle, prevCycle6    ' sum prevCycle6 into avgCycle 
                        add     avgCycle, prevCycle5    ' sum prevCycle5 into avgCycle 
                        add     avgCycle, prevCycle4    ' sum prevCycle4 into avgCycle 
                        add     avgCycle, prevCycle3    ' sum prevCycle3 into avgCycle 
                        add     avgCycle, prevCycle2    ' sum prevCycle2 into avgCycle 

                        shl     avgCycle, 3             ' divide avg by 8 to get the actual average

                        add     teethPerRev, #1         ' increment this for each frequency logic high I get
                        
                        mov     lowCycleTmp, lowCycle
                        mul     lowCycleTmp, #100       ' multiple lowCycle by 100% for resolution and no floats

                        mov     avgCycleTmpH, avgCycle
                        mul     avgCycleTmpH, #110      ' multiple avgCycle by 110%

                        mov     avgCycleTmpL, avgCycle
                        mul     avgCycleTmpL, #90       ' multiple avgCycle by 90%
                        
                        cmp     avgCycleTmpH, lowCycleTmp WR, WZ
if_a                    mov     lowCycle, avgCycle      ' if it's above 110%, toss it and replace it with the average
if_a                    mov     gapCntTimeStampH, highCntLog ' log a timestamp of when the frequency is greater than 110% of the average
if_a                    mov     gapsPerSec, #1          ' reset back to 1
if_a                    mov     teethPerRev, #1         ' reset back to 1

                        mov     localCnt, cnt           ' create copy of cnt
                        sub     localCnt, timeStamp     ' subtract timeStamp from copy of cnt
                        cmp     localCnt, #1            ' is copy of cnt is greater than timeStamp?
if_a                    mov     timeStamp, cnt          ' if so, reset timeStamp
if_a                    mov     gapsPerSecPeak, gapsPerSec ' copy gapsPerSec to a Peak value holder
if_a                    mov     gapsPerSec, #0          ' reset gapsPerSec                                                             

                        cmp     avgCycleTmpL, lowCycleTmp WR, WZ
if_b                    mov     lowCycle, avgCycle      ' if it's below 90%, toss it and replace it with the average
if_b                    mov     gapCntTimeStampL, lowCntLog  ' log a timestamp of when the frequency is less than 90% of the average

                        cmp     minc, lowCycle WR, WZ   ' compare lowCycle to minimum on record
if_b                    mov     minc, lowCycle          ' overwrite minimum if lowCyle is indeed shorter              

                        cmp     maxc, lowCycle WR, WZ   ' compare lowCycle to maximum on record 
if_a                    mov     maxc, lowCycle          ' overwrite maximum if lowCyle is indeed longer
                        

                        wrlong  lowCycle, cycleptr
                        wrlong  teethPerRev, toothcntptr
                        wrlong  averagex, averageptr
                        wrlong  maxc, maxptr
                        wrlong  minc, minptr  


                        
                        jmp     #restart
                        
nopinstr                mov     0, 0 NR                        
' --------------------------------------------------------------------------------------------------

POS_DETECT              long    %01000 << 26 
NEG_DETECT              long    %01100 << 26

cycleptr                long    4
toothcntptr             long    8
averageptr              long    12
maxptr                  long    16
minptr                  long    20


' Standard variable initialization here
maxc                    long    444444          ' cycles at 300rpm
minc                    long    444444          ' cycles at 300rpm
tooth                   long    0
database                long    0
averagex                
avgcnt                  long    8
dontcount               long    8000'13400           ' a floor for the minimum amount of time to pass by
avgCycle                long    0
prevCycle9              long    0
prevCycle8              long    0
prevCycle7              long    0
prevCycle6              long    0
prevCycle5              long    0
prevCycle4              long    0
prevCycle3              long    0
prevCycle2              long    0
lowCycleTmp             long    0
avgCycleTmpH            long    0
avgCycleTmpL            long    0
lowCntLog               long    0
highCntLog              long    0
gapCntTimeStampH        long    0
gapCntTimeStampL        long    0
gapsPerSec              long    0
gapsPerSecPeak          long    0
localCnt                long    0
timeStamp               long    0
teethPerRev             long    0



tmp1                    res     1
tmp2                    res     1

mask                    res     1                               ' mask for frequency input pin
lowCycle                res     1                               ' low cycles in input period
highCycle               res     1                               ' high cycles in input period 

                        fit     492
 



I believe I can do the multiply portion as shown below, in case MUL does not do what I think it does.
 mov     lowCycleTmp, lowCycle
                        mul     lowCycleTmp, #100       ' multiple lowCycle by 100% for resolution and no floats
                        {this could be
                        shl     lowCycleTmp, #3
                        add     lowCycleTmp, lowCycle
                        add     lowCycleTmp, lowCycle}

                        mov     avgCycleTmpH, avgCycle
                        mul     avgCycleTmpH, #110      ' multiple avgCycle by 110%
                        {this could be
                        shl     avgCycleTmpH, #3
                        add     avgCycleTmpH, avgCycle
                        add     avgCycleTmpH, avgCycle
                        add     avgCycleTmpH, avgCycle}

                        mov     avgCycleTmpL, avgCycle
                        mul     avgCycleTmpL, #90       ' multiple avgCycle by 90%
                        {this could be
                        shl     avgCycleTmpL, #3
                        add     avgCycleTmpL, avgCycle
                        

If you get this far, I appreciate you reading through what is probably virtual spaghetti.

Comments

  • MagIO2MagIO2 Posts: 2,243
    edited 2012-04-09 11:08
    MUL is a reseved word, but it's reserved for the propeller 2 and not available on a propeller 1.

    Besides that you still did not answer why you replaced the moving average code by your prevCycle1-prevCycle8 stuff?! Does it really add so much value so it makes sense to replace the more efficient code?

    Even if it's important to have the exact history of cycles, it could be solved better:
    Use the destination- and source-part of the mov, add and sub instructions as pointers which tell you where to store/find the subtract - value (search for ring-buffer in wiki).
    Subtract the last in the history from the average
    move the last-pointer one forward (like you do it in a ring-buffer)
    add the current value to the average
    mov the current to the RAM to which first-pointer points
    move the first-pointer forward (like you do it in a ring-buffer)

    These are only a small amount of instructions compared to your 8 mov's, 8 add's:
    1 sub, 1 add to pointer, 1 reset to begin of ring buffer, 1 add, 1 mov, 1 add to pointer, 1 reset to begin of ring buffer -> 7 instructions

    Your "shl avgCycle, 1" does not divide by 8, it divides by something else, as
    1. 1 should be #1
    and 2. #1 should be #3 for a division by 8
  • jazzedjazzed Posts: 11,803
    edited 2012-04-09 11:12
    I don't think Chip intended for anyone to use MUL. What does it do for you?
    Could you replace it with a multiply algorithm and compare the results?

    There are other unlisted instructions, but they are probably not implemented.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-09 11:31
    Hi,

    I caught the shl typo, so that is fixed, and have removed the MUL and put what I think is a substitution that will work.

    My extra code and cycles and inefficiency is not important at all, except while I am trying to feel my way through this it literally makes sense and logically makes sense to me and is easy to troubleshoot when I am following it. The code you wrote will be a much better option when I feel more confident in the program and my understanding of PASM.

    The code below has me confused, because I'm not sure how dontcount can be a static number, if I understand it correctly. So I went with the literal inefficient way, until I get better. I know your way is best, I'm just taking steps to getting to the point where I know your way is best and I understand why it is best.
                            'cmp     dontcount,cycles WZ,WC,NR 
    if_b                    jmp     #restart
    
                            ' moving-average (remove one average value and add the current)
                            sub     database, averagex      ' * subtract the average from a sum of the last 8 cycles added together
                            add     database, cycles        ' * add the most current cycles into the sum of the last 8 cyles added together
    
    MagIO2 wrote: »
    MUL is a reseved work, but it's reserved for the propeller 2 and not available on a propeller 1.

    Besides that you still did not answer why you replaced the moving average code by your prevCycle1-prevCycle8 stuff?! Does it really add so much value so it makes sense to replace the more efficient code?

    Even if it's important to have the exact history of cycles, it could be solved better:
    Use the destination- and source-part of the mov, add and sub instructions as pointers which tell you where to store/find the subtract - value (search for ring-buffer in wiki).
    Subtract the last in the history from the average
    move the last-pointer one forward (like you do it in a ring-buffer)
    add the current value to the average
    mov the current to the RAM to which first-pointer points
    move the first-pointer forward (like you do it in a ring-buffer)

    These are only a small amount of instructions compared to your 8 mov's, 8 add's:
    1 sub, 1 add to pointer, 1 reset to begin of ring buffer, 1 add, 1 mov, 1 add to pointer, 1 reset to begin of ring buffer -> 7 instructions

    Your "shl avgCycle, 1" does not divide by 8, it divides by something else, as
    1. 1 should be #1
    and 2. #1 should be #3 for a division by 8
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-09 11:33
    I don't think it does anything

    I replaced it with the following
     mov     avgCycleTmpH, avgCycle
                            'mul     avgCycleTmpH, #110      ' multiple avgCycle by 110%
                            
                            shl     avgCycleTmpH, #3
                            add     avgCycleTmpH, avgCycle
                            add     avgCycleTmpH, avgCycle
                            add     avgCycleTmpH, avgCycle
    
    jazzed wrote: »
    I don't think Chip intended for anyone to use MUL. What does it do for you?
    Could you replace it with a multiply algorithm and compare the results?

    There are other unlisted instructions, but they are probably not implemented.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-09 13:26
    I used both the following methods, and the second one seems to give more consistent results, but it's still off by about 20rpm, which at a test speed of 500rpm or 8.3hz, shouldn't be happening.

    The reason I thought the second one to be a better way, is because it allows you to compare the current to the previous 8's average, and if the current is garbage, throw it out and replace it with the average value, rather than pollute the average with garbage until it cycles out. What makes the first way superior to this?
                           
                            sub     avgCycle, prevCycle9    ' remove oldest from avgCycle  
                            add     avgCycle, prevCycle8    ' sum prevCycle8 into avgCycle 
                            add     avgCycle, prevCycle7    ' sum prevCycle7 into avgCycle 
                            add     avgCycle, prevCycle6    ' sum prevCycle6 into avgCycle 
                            add     avgCycle, prevCycle5    ' sum prevCycle5 into avgCycle 
                            add     avgCycle, prevCycle4    ' sum prevCycle4 into avgCycle 
                            add     avgCycle, prevCycle3    ' sum prevCycle3 into avgCycle 
                            add     avgCycle, prevCycle2    ' sum prevCycle2 into avgCycle
                            add     avgCycle, lowCycle      ' sum current lowCycle into avgCycle
    
                            shr     avgCycle, #3             ' divide avg by 8 to get the actual average
    

    and
                           
                            add     avgCycle, prevCycle9    ' remove first in from avgCycle  
                            add     avgCycle, prevCycle8    ' sum prevCycle8 into avgCycle 
                            add     avgCycle, prevCycle7    ' sum prevCycle7 into avgCycle 
                            add     avgCycle, prevCycle6    ' sum prevCycle6 into avgCycle 
                            add     avgCycle, prevCycle5    ' sum prevCycle5 into avgCycle 
                            add     avgCycle, prevCycle4    ' sum prevCycle4 into avgCycle 
                            add     avgCycle, prevCycle3    ' sum prevCycle3 into avgCycle 
                            add     avgCycle, prevCycle2    ' sum prevCycle2 into avgCycle
    
                            shr     avgCycle, #3             ' divide avg by 8 to get the actual average
    
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-04-09 14:45
    Where do you delete the avgCycle in your first try? As far as I understand you want to have the average of 8 values, so before summing up all 8 values you should delete the previous avgCycle content (set it to 0 with mov avgCycle, #0).
    Otherwise you have the average of the previous calculation + 8 actual values and divide this by 8 which could explain the offset.

    So, the second try is better as it at least removes prevCycle9 which is usually somewhere around the average calculated before.

    Do you have a filter for the big gap? If not this could also add an offset.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-09 20:52
    Good evening,

    With the first code block, I subtract the oldest value, leaving the remaining 7 and then add the newest value and average it with a divide by 8, this code is a typical circular buffer.

    For the second code block (not all of these steps are done in that block), I have a filter that verifies the size is not outside of the 90% to 110% of the average. If it is not outside of the average, it uses the newest value and considers it valid and calculates based on that single valid value, if it is outside of the 90-110% range, it overwrites it by replacing it with the calculated average value and calculates off of that until the next time through the loop. This code is a validate the value, based on the average of the previous 8, and compute off of it as long as it is within a preset allowable range.

    I finally figured out why I cannot get it to work, I kept getting numbers that were semi close, but not correct. The low is 57% of the total and the high is 43% of the total time to go from 1 rising edge to the next.

    I should be reading 266000 cycles at 500rpm, I'm reading 201000 cycles.

    I need to read from rising edge to rising edge, as your original code did. After playing around with the code, I was able to get this to work somewhat, so tomorrow I will have to tweak it so that it is reliable.

                            mov     avgCycle, #0 
                              
                            add     avgCycle, prevCycle8    ' sum prevCycle8 into avgCycle 
                            add     avgCycle, prevCycle7    ' sum prevCycle7 into avgCycle 
                            add     avgCycle, prevCycle6    ' sum prevCycle6 into avgCycle 
                            add     avgCycle, prevCycle5    ' sum prevCycle5 into avgCycle 
                            add     avgCycle, prevCycle4    ' sum prevCycle4 into avgCycle 
                            add     avgCycle, prevCycle3    ' sum prevCycle3 into avgCycle 
                            add     avgCycle, prevCycle2    ' sum prevCycle2 into avgCycle
                            sub     avgCycle, prevCycle9    ' remove first in from avgCycle
                            add     avgCycle, lowCycle      ' sum current lowCycle into avgCycle
    
                            shr     avgCycle, #3             ' divide avg by 8 to get the actual average
    
    
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-04-10 03:42
    Oh turbo, oh turbo ....

    There are 2 possibilities:
    Either you have sumAvgCycle which keeps track of the sum of all prevCycle2-8 + lowCycle, then you only need to subtract the last value prevCycle9 and add the actual value lowCycle to get the actual sum. Then you have to copy this into avgCycle and divide this by 8 to get the average of all 8 values. This removes 6 add-instructions.

    Or you clean avgCycle each time and sum it up freshly. Here it's wrong to subtract prevCycle9, as it is not part of the sum.

    You code is currently a mixture.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-10 06:57
    Ok,

    I see what you mean now, and why you would have the removal of the 6 add instructions after the first pass through.

    I can't seem to come up with a good way to sum all 8 the first time, and then take that summed value, subtract the oldest, insert the newest and then divide by 8 again during the loops after the first time.

    I see how this would work well, I'm just not sure how to do this in PASM. Is there a way to bracket if statement instructions together, like you can in spin? Maybe I should have some sort of flag that indicates the sum has never been calculated, and after that ignore the "all 8" summation and just do the subtract oldest/insert newest, then divide by 8?

    I think you've done something like that that with this code [edit - I see that you've initialized avgcnt with the value of 8, I think I'm getting closer to understanding]
    calcavg                 djnz    avgcnt, #restart
                            ' this will replace the previous conditional jump with a NOP
                            ' after the 8th cycle, so that all following cycles will directly
                            ' go to the calculation below
                            mov     calcavg, nopinstr
    
    I would guess I'm going to end up going in a circle right back to the way you coded it, which may seem pointless from the outside looking in, but by that point I'll have an intricate understanding of why you wrote that averaging code the way you did. The only difference is that it probably took you 1/2 an hour, and it's going to take me 1/2 a month :)
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-10 12:44
    A little progress, I'm close I think

    The problem now is that when I have the gap come in, which is approximately 2.5 times the length of a normal rising edge to rising edge, it throws off the average. Should I filter that out somehow? Maybe if the cycle value is larger than 1.75 times the average from the previous loop, consider it an anomaly and toss it?

    DAT
    
                            org     0
    
    frcntr                  mov     tmp1, par                       ' start of structure
                            rdlong  tmp2, tmp1                      ' get pin#, store it in tmp2
    
                            mov     ctra, POS_DETECT                ' ctra measures high phase
                            add     ctra, tmp2
                            mov     frqa, #1
                            
                            mov     ctrb, NEG_DETECT                ' ctrb measures low phase
                            add     ctrb, tmp2
                            mov     frqb, #1
                            
                            mov     mask, #1                        ' create pin mask
                            shl     mask, tmp2
    
                            ' save addresses of hub storage
                            add     cycleptr, tmp1
                            add     toothcntptr, tmp1              
                            add     averageptr, tmp1
                            add     maxptr, tmp1
                            add     minptr, tmp1
                            add     pstptr, tmp1
                            add     pstptr2, tmp1
                            add     pstptr3, tmp1
                            add     pstptr4, tmp1
                            add     pstptr5, tmp1
                            add     pstptr6, tmp1
                            add     pstptr7, tmp1
                            add     pstptr8, tmp1
                            add     prevCycle9ptr, tmp1
                            add     prevCycle8ptr, tmp1
                            add     prevCycle7ptr, tmp1
                            add     prevCycle6ptr, tmp1
                            add     prevCycle5ptr, tmp1
                            add     prevCycle4ptr, tmp1
                            add     prevCycle3ptr, tmp1
                            add     prevCycle2ptr, tmp1
    
    initialize
    
                            mov     prevCycle10, prevCycle9  ' copy current to previous for a buffer
                            mov     prevCycle9, prevCycle8  ' copy current to previous for a buffer
                            mov     prevCycle8, prevCycle7  ' copy current to previous for a buffer
                            mov     prevCycle7, prevCycle6  ' copy current to previous for a buffer
                            mov     prevCycle6, prevCycle5  ' copy current to previous for a buffer
                            mov     prevCycle5, prevCycle4  ' copy current to previous for a buffer
                            mov     prevCycle4, prevCycle3  ' copy current to previous for a buffer
                            mov     prevCycle3, prevCycle2  ' copy current to previous for a buffer
                            mov     prevCycle2, cycles      ' copy current to previous for a buffer
    
                            mov     cycleSum, #0
                            add     cycleSum, prevCycle9    ' remove first in from avgCycle
                            add     cycleSum, prevCycle8    ' sum prevCycle8 into avgCycle 
                            add     cycleSum, prevCycle7    ' sum prevCycle7 into avgCycle 
                            add     cycleSum, prevCycle6    ' sum prevCycle6 into avgCycle 
                            add     cycleSum, prevCycle5    ' sum prevCycle5 into avgCycle 
                            add     cycleSum, prevCycle4    ' sum prevCycle4 into avgCycle 
                            add     cycleSum, prevCycle3    ' sum prevCycle3 into avgCycle 
                            add     cycleSum, prevCycle2    ' sum prevCycle2 into avgCycle
                 
    
                                                    
    restart                 mov     cycles, #0
                            waitpne mask, mask                      ' wait for 0 phase
                            mov     cycles, phsa
                            mov     phsa, #0                        ' clear high phase counter
    
                            ' wait for pin == 1
    highphase               waitpeq mask, mask                      
                            add     cycles, phsb
                            mov     phsb, #0                        ' clear low phase counter
                          
                            
                            cmp     prevCycle10, #0 WR, WZ   ' Make sure I have 8 previous values for an average
    if_be                   jmp     #initialize             ' go back to initialize until the initialization sequence is done
    
    
                            mov     prevCycle9, prevCycle8
                            mov     prevCycle8, prevCycle7
                            mov     prevCycle7, prevCycle6
                            mov     prevCycle6, prevCycle5
                            mov     prevCycle5, prevCycle4
                            mov     prevCycle4, prevCycle3
                            mov     prevCycle3, prevCycle2
                            mov     prevCycle2, cycles
    
                            
                            sub     cycleSum, prevCycle9    ' subtract the oldest value                       
                            add     cycleSum, cycles        ' add the newest value
                            mov     avgCycle, cycleSum
                            shr     avgCycle, #3            ' divide avg by 8 to get the actual average
    
                                 
    
                            wrlong  cycles, pstptr 
                            wrlong  avgCycle, pstptr2 e
                            wrlong  cycleSum, pstptr3
                            'wrlong  highCycle, pstptr4
                             
                            wrlong  prevCycle9, prevCycle9Ptr
                            wrlong  prevCycle8, prevCycle8Ptr
                            wrlong  prevCycle7, prevCycle7Ptr
                            wrlong  prevCycle6, prevCycle6Ptr
                            wrlong  prevCycle5, prevCycle5Ptr
                            wrlong  prevCycle4, prevCycle4Ptr
                            wrlong  prevCycle3, prevCycle3Ptr
                            wrlong  prevCycle2, prevCycle2Ptr
    
    
                            jmp     #restart
                            
    nopinstr                mov     0, 0 NR                        
    ' --------------------------------------------------------------------------------------------------
    
    POS_DETECT              long    %01000 << 26 
    NEG_DETECT              long    %01100 << 26
    
    cycleptr                long    4
    toothcntptr             long    8
    averageptr              long    12
    maxptr                  long    16
    minptr                  long    20
    pstptr                  long    24
    pstptr2                 long    28
    pstptr3                 long    32
    pstptr4                 long    36
    pstptr5                 long    40
    pstptr6                 long    44
    pstptr7                 long    48
    pstptr8                 long    52
    prevCycle9Ptr           long    56
    prevCycle8Ptr           long    60
    prevCycle7Ptr           long    64
    prevCycle6Ptr           long    68
    prevCycle5Ptr           long    72
    prevCycle4Ptr           long    76
    prevCycle3Ptr           long    80
    prevCycle2Ptr           long    84
    
    ' Standard variable initialization here
    maxc                    long    444444          ' cycles at 300rpm
    minc                    long    444444          ' cycles at 300rpm
    waitTime                long    20000000        
    
    tooth                   long    0
    database                long    0
    averagex                
    avgcnt                  long    8
    initializecnt           long    10
    dontcount               long    8000'13400           ' a floor for the minimum amount of time to pass by
    cycles                  long    0
    avgCycle                long    0
    cycleSum                long    0
    prevCycle10             long    0
    prevCycle9              long    0
    prevCycle8              long    0
    prevCycle7              long    0
    prevCycle6              long    0
    prevCycle5              long    0
    prevCycle4              long    0
    prevCycle3              long    0
    prevCycle2              long    0
    lowCycleTmp             long    0
    avgCycleTmpH            long    0
    avgCycleTmpL            long    0
    lowCntLog               long    0
    highCntLog              long    0
    gapCntTimeStampH        long    0
    gapCntTimeStampL        long    0
    gapsPerSec              long    0
    gapsPerSecPeak          long    0
    localCnt                long    0
    timeStamp               long    0
    teethPerRev             long    0
    pstReached              long    0
    totalCycle              long    0
    
    
    tmp1                    res     1
    tmp2                    res     1
    ctimer                  res     1
    mask                    res     1                               ' mask for frequency input pin
    lowCycle                res     1                               ' low cycles in input period
    highCycle               res     1                               ' high cycles in input period 
    
                            fit     492
     
    
    
  • SapiehaSapieha Posts: 2,964
    edited 2012-04-10 13:59
    Hi.

    I don't understand Yours thinking.
    What You need average to.

    My questions are.
    1. How many pistons have this engine.
    2. How many times Gap occur to have all pistons working (complete cycle of engine).

    turbosupra wrote: »
    A little progress, I'm close I think

    The problem now is that when I have the gap come in, which is approximately 2.5 times the length of a normal rising edge to rising edge, it throws off the average. Should I filter that out somehow? Maybe if the cycle value is larger than 1.75 times the average from the previous loop, consider it an anomaly and toss it?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-10 14:34
    Hi Sapieha,

    1.) I have a 4 cylinder and a 6 cylinder engine, but technically this is independent of this part of the project as I should be able to measure either with the same code
    2.) I am trying to average the time it takes the crank trigger wheel to go from one falling edge to the next on its 36-2 crank trigger wheel


    In electrical terms, the sensor puts out a variable frequency based on the speed of the engine. I have code that simulates the frequency exactly if you'd like to see it. I can mathematically calculate the engine rpm exactly based on how many clk cycles it takes to go from 1 falling edge to the next. The hard part comes when you want to allow for error correction and the "-2" portion of the trigger wheel that creates a frequency "gap" (single falling edge to falling edge measurement), that is about 2.5 times the length of a normal falling edge to falling edge measurement.

    With the previous PASM code, I can calculate the cycles (rpm), but you'll see it jump around and show an incorrect number when the "gap" virtually goes past the virtual sensor (I have one prop pin feeding another) when I'm simulating this on my protoboard. Does this make sense? I can go into as much automotive detail as you'd like if I am not making sense, and draw/use some pictures.
  • SapiehaSapieha Posts: 2,964
    edited 2012-04-10 15:02
    Hi.

    What You need frequency to.

    If I understand engines that is not necessary to know. You need only position of piston to start injection else ignition in degrees before top position of piston.
    And that info give You position of tooth. But still to full engine cycle You need 2 revolutions -- That give question HOW You know start of first engine piston.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-10 15:14
    Ah, now I understand what you are asking.

    I am actually not that far yet :) but to answer your question, there is a trigger wheel on the cam shaft (I finally have an exact simulation of that too) and as you probably know, the camshaft rotates 1:2 compared to the bottom half of the engine. With this reference we can tell if we are on the compression stroke or the exhaust stroke of each cylinder. Right now I am trying to accurately read rpm first from this crank trigger wheel, then I'll accurately read rpm from the camshaft trigger wheel and then try and merge them together.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-10 15:38
    I can't seem to come up with a good way to filter out the high values that represent the "gaps".

    Maybe I should have a rolling average of 32 different samples?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-10 22:02
    Good morning,

    I slowed the program way down so that I could watch the highs/lows slowly at only a couple of rpm, but still 3 or 4 teeth a second.

    Can you explain how this command works? I know how it works in spin, but not in PASM. Is this a shortcut way of writing it?
    waitpne mask, mask
    
    waitpeq mask, mask 
    
    Is it "wait for pin to not equal 1, check pin number stored in masks register"
    and then
    "wait for pin to equal 1, check pin number stored in masks register"

    Could I write?
    waitpne 1, 5
    
    waitpeq 1, 5
    

    I'm chasing an issue where the code is actually hosing 2 cycle counts instead of 1. In the code below, the elongated low and then high cycle should be treated as a single tooth, but it is being treated as two different teeth, or it is split in half as far as cycles, and the low is being combined with the preceding high, while the elongated high is then being combined with the following low. Either way, it's screwing up 2 cycles instead of one.

    Any ideas on how to deal with that? I've been troubleshooting this all night, it's driving me crazy.


    propscope1.jpg
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-11 10:46
    Finally :) I figured out why I was getting 2 elongated measurements. In the code, the waitpne has to come before the waitpeq, otherwise you get the following measurement when adding the low and high cycles.

    toothgapcomparison1.jpg

    Instead of a measurement from the falling edge of the elongated logic low, to the falling edge of the elongated logic high.

    When you switch them around to waitpne first, you then get 1 out of range value, instead of two.

    When you factor in the value of the gap in a /8 situation, it diminishes the average by 20%
    When you factor i the value of the gap in a /32 situation, it diminishes the average by 6%

    With /8, you have an average of ~26666592 or ~33333258. 79999920 is 2.40 times the average here
    With /32, you have an average of ~26666592 or ~28333258. 79999920 is 2.82 times the average here

    So the question is, is the additional overhead from a divide by 32, instead of a divide by 8 worth the resolution?

    6% is tolerable, but 20% is not. I could also create some sort of 1 time divide by 8 or 32 and then filter out anything above or below certain percentages?

    Below is what I observed when I slowed things down.

    MEASURED:

    Falling to falling is .19 seconds - 15,200,000 cycles
    Rising to rising is .15 or .16 seconds - 12,800,000 cycles or 12,000,000
    Total edge to edge is .34 seconds - 27,200,000 cycles

    Falling to falling gap is .481 seconds - 38,480,000 cycles (57% of total gap)
    Rising to rising gap is 0.381 seconds - 30,480,000 cycles (43% of total gap)
    Total gap is .862 seconds - 68,960,000

    Gap to tooth ratio is 2.535 times as long

    When you factor in the value of the gap in a /8 situation, it diminishes the average by 20%
    When you factor i the value of the gap in a /32 situation, it diminishes the average by 6%

    With /8, you have an average of ~26666592 or ~33333258. 79999920 is 2.40 times the average here
    With /32, you have an average of ~26666592 or ~28333258. 79999920 is 2.82 times the average here

    OBSERVED:

    FIRST

    Pst: 11999088 (low cycles) (normal)
    Pst2: 45599952 (high cycles)
    Pst3: 57599040 (total cycles) (28800000 for normal pass,
    Pst4: 0
    Pst5: 0
    Pst6: 0
    Pst7: 0
    Pst8: 1 (indicating it is during the logic high phase)

    prevCy9: 26666592
    prevCy8: 26666592
    prevCy7: 26666608
    prevCy6: 26666592
    prevCy5: 26666608
    prevCy4: 26666592
    prevCy3: 26666608
    prevCy2: 26666592



    SECOND

    Pst: 34399968 (low cycles)
    Pst2: 14667504 (high cycles) (normal)
    Pst3: 49067472 (total cycles)
    Pst4: 0
    Pst5: 0
    Pst6: 0
    Pst7: 0
    Pst8: 1 (indicating it is during the logic high phase)

    prevCy9: 26666608
    prevCy8: 26666608
    prevCy7: 26666608
    prevCy6: 26666592
    prevCy5: 26666608
    prevCy4: 26666592
    prevCy3: 26666608
    prevCy2: 26666592









    Pst: 11999088
    Pst2: 14667504
    Pst3: 26666592
    Pst4: 0
    Pst5: 0
    Pst6: 0
    Pst7: 0
    Pst8: 1

    prevCy9: 57599024
    prevCy8: 49067472
    prevCy7: 26666608
    prevCy6: 26666592
    prevCy5: 26666608
    prevCy4: 26666592
    prevCy3: 26666608
    prevCy2: 26666592
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-04-11 13:18
    You really prefere to learn it the hard way !! ;o)

    I already told you that you either need to invert the signal or change the code accordingly, didn't I?!

    WAITPNE means wait until pins are not equal and works like that:
    It's reading INA (all 32 bits) and uses one of both parameters (I think the destination parameter, so the first one) to mask out all bits which are not of interest (binary AND). Mask out means that all bits are set to 0 which you are not interested in. Then it compares the result with the other parameter (the source - second one) and if they are equal it continues waiting.
    WAITPEQ works the same way, but it waits as long as the bits of interest are not equal.
    For example:
    INA    = %10011010_11110000_01010011_10000111
    mask   = %00000000_00000000_00000000_00000001
    ===========================================
    result = %00000000_00000000_00000000_00000001
    mask   = %00000000_00000000_00000000_00000001
    
    => WAITPNE will wait, WAITEQU will continue the program

    bit 0 of the result only depends on PIN 0. So, alternating the waitpne and waitpeq instructions will wait until the previous state of the pin is changed. Well ... as long as the code in between has a shorter runtime than the high- / low-time of the signal.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-11 14:23
    Lol!

    I do remember you saying I'd need to possibly invert the signal, however apparently I didn't comprehend the "change the code accordingly" part so I did learn the hard way! But I will say that I definitely learned a lot.

    I actually have something working now, it works from 300rpm to 15000rpm and it's pretty accurate. Now, I have no idea how it is going to do with a constantly changing signal such as an engine, but I'll let you know soon ;)

    Here is the code, again I know it's a far cry from the code you wrote, but since I wrote it I'm able to troubleshoot it a little better. If it works, I may go back and try to get your code working with my hardware/signal as well. I really didn't want to do the first small code block outside of the initialize label, but I couldn't get it to work without doing that. : (

    I guess it isn't too bad, because I still have the speed I need for 15,000rpm or 9000 teeth a second.
                            mov     originalCycleSum, #0
                            cmp     prevCycle9, #0 WZ, WC
    if_nz                   add     originalCycleSum, prevCycle9
    if_nz                   add     originalCycleSum, prevCycle8
    if_nz                   add     originalCycleSum, prevCycle7
    if_nz                   add     originalCycleSum, prevCycle6
    if_nz                   add     originalCycleSum, prevCycle5
    if_nz                   add     originalCycleSum, prevCycle4
    if_nz                   add     originalCycleSum, prevCycle3
    if_nz                   add     originalCycleSum, prevCycle2
                            sub     originalCycleSum, prevCycle9  ' remove the oldest measurement                
                            add     originalCycleSum, totalCycles ' add the newest measurement
    



    DAT
    
                            org     0
    
    frcntr                  mov     tmp1, par                       ' start of structure
                            rdlong  tmp2, tmp1                      ' get pin#, store it in tmp2
    
                            mov     ctra, POS_DETECT                ' ctra measures high phase
                            add     ctra, tmp2
                            mov     frqa, #1
                            
                            mov     ctrb, NEG_DETECT                ' ctrb measures low phase
                            add     ctrb, tmp2
                            mov     frqb, #1
                            
                            mov     mask, #1                        ' create pin mask
                            shl     mask, tmp2
    
                            ' save addresses of hub storage
                            add     cycleptr, tmp1
                            add     toothcntptr, tmp1              
                            add     averageptr, tmp1
                            add     maxptr, tmp1
                            add     minptr, tmp1
                            add     pstptr, tmp1
                            add     pstptr2, tmp1
                            add     pstptr3, tmp1
                            add     pstptr4, tmp1
                            add     pstptr5, tmp1
                            add     pstptr6, tmp1
                            add     pstptr7, tmp1
                            add     pstptr8, tmp1
                            add     prevCycle9ptr, tmp1
                            add     prevCycle8ptr, tmp1
                            add     prevCycle7ptr, tmp1
                            add     prevCycle6ptr, tmp1
                            add     prevCycle5ptr, tmp1
                            add     prevCycle4ptr, tmp1
                            add     prevCycle3ptr, tmp1
                            add     prevCycle2ptr, tmp1
    
    
    
    
    
                            
    
    initialize
                            mov     cycles, #0
                            add     cycles, lowCycles
                            add     cycles, highCycles
                            mov     prevCycle10, prevCycle9
                            mov     prevCycle9, prevCycle8
                            mov     prevCycle8, prevCycle7
                            mov     prevCycle7, prevCycle6
                            mov     prevCycle6, prevCycle5
                            mov     prevCycle5, prevCycle4
                            mov     prevCycle4, prevCycle3
                            mov     prevCycle3, prevCycle2
                            mov     prevCycle2, prevCycle1
                            mov     prevCycle1, cycles
    
                            mov     originalCycleSum, #0
                            cmp     prevCycle9, #0 WZ, WC
    if_nz                   add     originalCycleSum, prevCycle9
    if_nz                   add     originalCycleSum, prevCycle8
    if_nz                   add     originalCycleSum, prevCycle7
    if_nz                   add     originalCycleSum, prevCycle6
    if_nz                   add     originalCycleSum, prevCycle5
    if_nz                   add     originalCycleSum, prevCycle4
    if_nz                   add     originalCycleSum, prevCycle3
    if_nz                   add     originalCycleSum, prevCycle2     
    
    {
    restart                 mov     cycles, #0
                            waitpne mask, mask                      ' wait for 0 phase
                            mov     cycles, phsa
                            mov     lowCycles, phsa
                            mov     phsa, #0                        ' clear high phase counter
                            wrlong  zero, pstptr8
    
                            ' wait for pin == 1
    highphase               waitpeq mask, mask                      
                            add     cycles, phsb
                            mov     highCycles, phsb
                            mov     phsb, #0                        ' clear low phase counter
                            wrlong  one, pstptr8
    }
    
                            ' wait for pin == 1
    restart                 mov     cycles, #0
                            waitpeq mask, mask                      
                            add     cycles, phsb
                            mov     highCycles, phsb
                            mov     phsb, #0                        ' clear low phase counter
                            'wrlong  one, pstptr8
    
                            ' wait for pin == 0
    highphase               waitpne mask, mask                      ' wait for 0 phase
                            mov     cycles, phsa
                            mov     lowCycles, phsa
                            mov     phsa, #0                        ' clear high phase counter
                            'wrlong  zero, pstptr8
    
                            
                            cmp     prevCycle10, #0 WZ, WC
    if_z_and_nc             jmp     #initialize     ' if prevCycle10 equal to 0, jump back to initialize
    
                            mov     totalCycles, #0               ' clear total cycles
                            add     totalCycles, lowCycles        ' add lowCycles to totalCycles
                            add     totalCycles, highCycles       ' add highCycles to totalCycles
    
                            wrlong  avgCycles, pstptr7            ' for pst
                            wrlong  totalCycles, pstptr8            ' for pst
                            
                            cmp     avgCycles, #0 WZ, WC          ' verify avgCycles is not empty
    if_nz                   mov     avgCyclesDoubled, avgCycles   ' copy avgCycles to temp location
    if_nz                   shl     avgCyclesDoubled, #1          ' double avgCycles
    if_nz                   cmp     avgCyclesDoubled, totalCycles WZ, WC  ' compare current totalCycles to doubled avgCycles
    if_nz_and_c             jmp     #restart                      ' jump back to restart and ignore if it is more than double the avgCycles
             
    
                            mov     originalCycleSum, #0
                            cmp     prevCycle9, #0 WZ, WC
    if_nz                   add     originalCycleSum, prevCycle9
    if_nz                   add     originalCycleSum, prevCycle8
    if_nz                   add     originalCycleSum, prevCycle7
    if_nz                   add     originalCycleSum, prevCycle6
    if_nz                   add     originalCycleSum, prevCycle5
    if_nz                   add     originalCycleSum, prevCycle4
    if_nz                   add     originalCycleSum, prevCycle3
    if_nz                   add     originalCycleSum, prevCycle2
                            sub     originalCycleSum, prevCycle9  ' remove the oldest measurement                
                            add     originalCycleSum, totalCycles ' add the newest measurement
    
                            mov     avgCycles, originalCycleSum   ' create originalCycleSum
                            shr     avgCycles, #3                 ' computer cycle sum divided by 8
    
    
                            wrlong  lowCycles, pstptr             ' for pst
                            wrlong  highCycles, pstptr2           ' for pst
                            wrlong  totalCycles, pstptr3          ' for pst
                            wrlong  originalCycleSum, pstptr4     ' for pst
                            wrlong  avgCycles, pstptr5            ' for pst
                            wrlong  avgCyclesDoubled, pstptr6     ' for pst
                             
                            wrlong  prevCycle9, prevCycle9Ptr     ' for pst
                            wrlong  prevCycle8, prevCycle8Ptr     ' for pst
                            wrlong  prevCycle7, prevCycle7Ptr     ' for pst
                            wrlong  prevCycle6, prevCycle6Ptr     ' for pst
                            wrlong  prevCycle5, prevCycle5Ptr     ' for pst
                            wrlong  prevCycle4, prevCycle4Ptr     ' for pst
                            wrlong  prevCycle3, prevCycle3Ptr     ' for pst
                            wrlong  prevCycle2, prevCycle2Ptr     ' for pst
    
    
                            
                            mov     prevCycle9, prevCycle8
                            mov     prevCycle8, prevCycle7
                            mov     prevCycle7, prevCycle6
                            mov     prevCycle6, prevCycle5
                            mov     prevCycle5, prevCycle4
                            mov     prevCycle4, prevCycle3
                            mov     prevCycle3, prevCycle2
                            mov     prevCycle2, prevCycle1
                            mov     prevCycle1, totalCycles   
    
                            jmp     #restart
                            
    nopinstr                mov     0, 0 NR
                      
    ' --------------------------------------------------------------------------------------------------
    
    POS_DETECT              long    %01000 << 26 
    NEG_DETECT              long    %01100 << 26
    
    cycleptr                long    4
    toothcntptr             long    8
    averageptr              long    12
    maxptr                  long    16
    minptr                  long    20
    pstptr                  long    24
    pstptr2                 long    28
    pstptr3                 long    32
    pstptr4                 long    36
    pstptr5                 long    40
    pstptr6                 long    44
    pstptr7                 long    48
    pstptr8                 long    52
    prevCycle9Ptr           long    56
    prevCycle8Ptr           long    60
    prevCycle7Ptr           long    64
    prevCycle6Ptr           long    68
    prevCycle5Ptr           long    72
    prevCycle4Ptr           long    76
    prevCycle3Ptr           long    80
    prevCycle2Ptr           long    84
    
    ' Standard variable initialization here
    
    cycles                  long    0
    lowCycles               long    0
    highCycles              long    0
    totalCycles             long    0
    avgCycles               long    0
    avgCyclesDoubled        long    -1       
    prevCycle10             long    0
    prevCycle9              long    0
    prevCycle8              long    0
    prevCycle7              long    0
    prevCycle6              long    0
    prevCycle5              long    0
    prevCycle4              long    0
    prevCycle3              long    0
    prevCycle2              long    0
    prevCycle1              long    0
    originalCycleSum        long    0
    one                     long    1
    zero                    long    0
    
    ' Reserved variables here
    
    tmp1                    res     1
    tmp2                    res     1
    mask                    res     1                               ' mask for frequency input pin
    
                            fit     492
     
    
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-04-11 16:26
    Why do you add prevCycle9 when you later on subtract it again?

    One more tipp:
    You can mix wrxxxx/rdxxxx with other instructions to get a better runtime. The point is, that wr/rd-instructions need to wait for the next HUB-access. Each COG gets HUB access after max. 16 clock-cycles when it missed the right point. So, after one wr/rd-instruction immediately followed by another wr/rd-instruction, this second one for sure has to wait for 814 clock-cycles. Not to waste this time with waiting, you can add 23 other non-HUB instructions between two HUB-RAM access instructions. So, with some clever resorting of the add and the mov instructions you can make the code execution faster.

    And even if you don't need the speed, faster code will result in less power consumption, as the waitxxx - instructions will really halt the COG.



    PS:Changed numbers as suggested by kuroneko
  • kuronekokuroneko Posts: 3,623
    edited 2012-04-11 16:37
    MagIO2 wrote: »
    So, after one wr/rd-instruction immediately followed by another wr/rd-instruction, this second one for sure has to wait for 14 clock-cycles. Not to waste this time with waiting, you can add 3 other non-HUB instructions between two HUB-RAM access instructions.
    Can we settle for 8 and 2 instead?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-11 20:14
    That's good to know, I had not thought about that with the cycles, but it makes sense with what I've read now that you point it out. Besides those two things, what do you think about the code overall?

    I'm not sure why I add it in and then remove it, I'll have to see if there's a reason for that or not tomorrow and let you know :)

    NOW FOR THE GOOD NEWS!!! :D

    Thanks to everyone that has helped me and endured my frequent posts in the past month, although this project is far from done I'd like to show that I made serious progress today. See the two pictures below, I can now calculate rpm based on rising edge to rising edge of each of the teeth on my hall effect trigger wheel, as well as from gap to gap of my trigger wheel. I've tested it in the car just revving it up and driving around slowly, and I've tested it with the simulated signal up to 15000 rpm! A special thanks to Mag102, Sapieha, Duane, Average Joe, Potatohead, I really appreciate your help and never thought I'd be able to do this and without your help Andreas, I would not have been able to learn any PASM, let enough to write what I did in less than a month of learning!!! I have sooooo much PASM to learn, but I feel like I have came quite far in a few weeks thanks to the help I've received. Thank you for sticking with this project, I am very grateful and if I ever make it to Germany I will definitely be buying you a beer or two.



    Good gap count (99999 is a hard coded number, same as 0)
    goodgaprpm1.jpg


    Bad (sometimes inaccurate gap count, still accurate tooth count though)
    badgaprpm1.jpg
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-04-12 11:45
    @kuroneko:
    Transactions from you are defaulted to auto-commit ;o) Thanks again for setting things straight!

    @turbosupra:
    Bad luck ... you found the one and only german that does not like beer ;o)
  • turbosupraturbosupra Posts: 1,088
    edited 2012-04-12 14:12
    Maybe no so bad ...
    <
    Another German (both parents) that does not like beer : D

    Onto the actual bad luck, I'm trying to calculate time difference between when the two sensors hit TDC (crank/cam) and having a hell of a time. Oh, and divide by 10 in PASM ... no clue on that.
Sign In or Register to comment.