PDA

View Full Version : PASM critique requested



turbosupra
04-09-2012, 06:23 PM
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.

MagIO2
04-09-2012, 07:08 PM
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

jazzed
04-09-2012, 07:12 PM
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.

turbosupra
04-09-2012, 07:31 PM
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



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

turbosupra
04-09-2012, 07:33 PM
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


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.

turbosupra
04-09-2012, 09:26 PM
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

MagIO2
04-09-2012, 10:45 PM
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.

turbosupra
04-10-2012, 04:52 AM
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

MagIO2
04-10-2012, 11:42 AM
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.

turbosupra
04-10-2012, 02:57 PM
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 :)

turbosupra
04-10-2012, 08:44 PM
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

Sapieha
04-10-2012, 09:59 PM
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).



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?

turbosupra
04-10-2012, 10:34 PM
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.

Sapieha
04-10-2012, 11:02 PM
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.

turbosupra
04-10-2012, 11:14 PM
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.

turbosupra
04-10-2012, 11:38 PM
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?

turbosupra
04-11-2012, 06:02 AM
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.


http://img51.imageshack.us/img51/7923/propscope1.jpg

turbosupra
04-11-2012, 06:46 PM
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.

http://img692.imageshack.us/img692/7503/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

MagIO2
04-11-2012, 09:18 PM
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.

turbosupra
04-11-2012, 10:23 PM
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

MagIO2
04-12-2012, 12:26 AM
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

kuroneko
04-12-2012, 12:37 AM
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?

turbosupra
04-12-2012, 04:14 AM
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)
http://img109.imageshack.us/img109/5945/goodgaprpm1.jpg


Bad (sometimes inaccurate gap count, still accurate tooth count though)
http://img844.imageshack.us/img844/816/badgaprpm1.jpg

MagIO2
04-12-2012, 07:45 PM
@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)

turbosupra
04-12-2012, 10:12 PM
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.