Looking to translate spin to PASM
turbosupra
Posts: 1,088
Hi,
I have a method (actually two) that are written in spin, they works well but they are too slow for what I need. Unfortunately they involve a lot of math and I'd like to add even more math, and from what I've read in the manual, PASM math/comparisons are pretty difficult for a PASM beginner.
Also I'm about to start trying to translate them to PASM and I'm used to troubleshooting with the PST, how do you debug PASM?
I have a method (actually two) that are written in spin, they works well but they are too slow for what I need. Unfortunately they involve a lot of math and I'd like to add even more math, and from what I've read in the manual, PASM math/comparisons are pretty difficult for a PASM beginner.
Also I'm about to start trying to translate them to PASM and I'm used to troubleshooting with the PST, how do you debug PASM?
PUB calculateCrankRpm(localCrankPeriod) | elapsed elapsed := -cnt l_previousNum8 := l_previousNum7 l_previousNum7 := l_previousNum6 l_previousNum6 := l_previousNum5 l_previousNum5 := l_previousNum4 l_previousNum4 := l_previousNum3 l_previousNum3 := l_previousNum2 l_previousNum2 := l_current l_current := localCrankPeriod if (l_timeStampCrank == 0) l_timeStampCrank := (cnt + clkfreq) if (l_previousNum8 <> 0 and l_previousNum7 <> 0 and l_previousNum6 <> 0 and l_previousNum5 <> 0 and l_previousNum4 <> 0 and l_previousNum3 <> 0 and l_previousNum2 <> 0) l_previous7average := ((l_previousNum8 + l_previousNum7 + l_previousNum6 + l_previousNum5 + l_previousNum4 + l_previousNum3 + l_previousNum2)/7) if (((l_current/10)*100) > ((l_previous7average/10)* 110)) or (((l_current/10)*100) < ((l_previous7average/10)*90)) ' GAP exists if current greater than 110% of average or current less than 90% of average l_gapTimePrevious := l_gapTime l_gapTime := cnt l_current := l_previous7average else if (((clkfreq/l_current)*60)/36) < 200 pst.str(string("crap2")) pst.char(13) else l_toothRpm := (((clkfreq/l_previous7average)*60)/36) elapsed += cnt - 544
PUB calculateCamRpm(localCamPeriod) if(localCamPeriod) <> 0 and l_pstReadCamWheel == 1 l_previousCam6 := l_previousCam5 l_previousCam5 := l_previousCam4 l_previousCam4 := l_previousCam3 l_previousCam3 := l_previousCam2 l_previousCam2 := l_currentCam l_currentCam := localCamPeriod {pst.dec(l_previousCam6) ' 2324128 ' 2323968 ' 4546304 ' 2324128 pst.char(13) pst.dec(l_previousCam5) ' 2323968 ' 4546304 ' 2324128 ' 2323968 pst.char(13) pst.dec(l_previousCam4) ' 4546304 ' 2324128 ' 2323968 ' 4546304 pst.char(13) pst.dec(l_previousCam3) ' 2324128 ' 2323968 ' 4546304 ' 2324128 pst.char(13) pst.dec(l_previousCam2) ' 2323968 ' 4546304 ' 2324128 ' 2323968 pst.char(13) pst.dec(l_currentCam) ' 4546304 ' 2324128 ' 2323968 ' 4546304 pst.char(13) pst.char(13)} '(average) ' 2768499 ' 3212934 ' 3212966 ' 4546304 is 1.65% of 2768499 and 2323968 is 83% of 2768499 ' 4546304 is 1.42% of 3212934 and 2323968 is 72% of 3212934 ' 4546304 is 1.42% of 3212966 and 2323968 is 72% of 3212966 if l_previousCam6 <> 0 and l_previousCam5 <> 0 and l_previousCam4 <> 0 and l_previousCam3 <> 0 and l_previousCam2 <> 0 l_CamToothAverage := ((l_previousCam6+l_previousCam5+l_previousCam4+l_previousCam3+l_previousCam2/5)) 'if (((l_currentCam/10)*100) =< ((l_CamToothAverage/10)*105)) and (((l_currentCam/10)*100) => ((l_CamToothAverage/10)*95)) if (((l_currentCam/10)*100) =< ((l_CamToothAverage/10)*170)) or (((l_currentCam/10)*100) => ((l_CamToothAverage/10)*70)) '(768/10)*100 [7600] =< (3812614/10)*170 [40032405] or (768/10)*100 [7600] => (3812614/10)*95 [36219795] ' less than 105% of average or greater than 70% of average ' trigger1/(cba) ' c > b*1.1 and c > a*1.1 if((l_currentCam*100) > (l_previousCam2*110)) and ((l_currentCam*100) > (l_previousCam3*110)) and (l_trigger1 <> true) if((l_previousCam2*100) < (l_previousCam3*105)) and ((l_previousCam2*100) > (l_previousCam3*95)) ' b < a*1.1 and b > a*.95 l_trigger1 := true l_trigger2 := false l_trigger3 := false ' trigger2/(acb) ' a*1.1 < c if((l_currentCam*110) < (l_previousCam2*100)) and (l_trigger2 <> true) if(((l_currentCam*100) < (l_previousCam3*105)) and ((l_currentCam*100) > (l_previousCam3*95))) ' a < b*1.05 and a > b*.95 if((l_previousCam2*100) > (l_previousCam3*110)) 'c > b*1.1 l_trigger2 := true l_trigger3 := false l_trigger1 := false ' trigger3/(bac) ' b < a*1.05 and b > a*.95 b*1.1 < c if(((l_currentCam*100) < (l_previousCam2*105)) and ((l_currentCam*100) > (l_previousCam2*95))) and ((l_currentCam*110) < (l_previousCam3*100)) and (l_trigger3 <> true) if((l_previousCam2*110) < (l_previousCam3*100)) ' a*1.1 < c l_trigger3 := true l_trigger1 := false l_trigger2 := false if(l_trigger3 == true)and(l_trigger1 == false)and(l_trigger2 == false) l_calculatedCamRpm := (((clkfreq/((l_currentCam+l_previousCam2+l_previousCam3)/10))*120)/10) ' or ((((clkfreq/1+2+3)*10)*120)/10) l_trigger3 := false else l_currentCam := l_CamToothAverage
Comments
I'm not sure how to do the math, so my code does not compile because the compiler tells me my compare math is exceeding the registers 9 bits (511) storage location . Are you able to use operators in PASM like you can in spin?
I also do not see a way to have clkfreq in PASM, although I'm sure there is a way, I used 80000000 temporarily instead.
How bad does this PASM code look? *hides behind rock*
Although you are probably right, I only left that PST code in there because it had table data that I needed to reference, I am not using that to send debug data to the PST. I am actually using this method below (in its own cog) for that, which I believe is similar to the way you are describing that you debug.
collapses neatly into
assuming those variables are longs, are declared thus, and in this order: The Spin compiler makes sure that the move is done in the correct order to avoid toe-stepping when the ranges overlap.
Also, the "<> 0" in this if statement is redundant:
The ands take care of that for you.
Also, doing 32-bit multiplies and divides in PASM won't save you that much time, since the Spin byte-code interpreter does them in assembly anyway. However, you could save time is by hard-coding the multiplications by constants using predetermined shifts and adds.
-Phil
cognew(simulateCamWheel(2, 15000, 2, 72, 72, 159, 19), @simulateCamWheelstack) (pin, rpm, cam rotations:crank rotations ratio, degrees from 0 degrees, degrees from first trigger, degrees from second trigger, actual metal trigger width in degrees)
cognew(simulateCrankWheel(4, 36, 2, 15000), @simulateCrankWheelStack) (pin, total teeth, missing teeth, rpm)
@Phil
Can you explain why the below saves time, and if there is a way to estimate how much time it does save? I will incorporate your time savings into my code now.
Also, if I remove the <>, couldn't it run through the code if just one value wasn't equal to 0, because then the sum would not then equal 0? I need to check and make sure they are not equal to 0 individually, to make sure I have cycled through 7 times and there are 7 different values.
No. The logical and operator does not operate bitwise like the "&" operator does. Each of and's operands is deemed to be "true" if it's non-zero.
-Phil
I have the loop taking 27888 to 33216 cycles from start to end (more 33216 then 25056) and I need it to happen (this is worst case of course) in less than 8888 or even 1/2 that if I use cog stopping commands like waitpeq. I'm looking for a second and third opinion though ... What do you all think?
In case you were curious, when I was using the := way of transferring variable values, method time was either 25056 or 30384, so your long move saves me 2832 cycles
The <> part of the code saves me an additional 1920 cycles at 23136 or 28464.
I removed one of the if statements just to time it [if (((clkfreq/l_current)*60)/36) < 200] ... should that take 3696 cycles?
to
or, better yet,
clkfreq may not be evenly-divisible by 120, but it may not matter.
-Phil
if (((clkfreq/l_current)*60)/36) < 200 is the same as 15000 < 200
if (clkfreq < 120 * l_current) is the same as 80000000 < 1066560
Maybe I'm missing something?
I guess more importantly though, is it normal for that operation to take 3600 cycles? And is my loop time math correct from the post quoted below?
But, by working though the algebra, that's the very same thing as saying
-Phil
Ok, so if you did 180rpm, which it should be true
180rpm = 3 revolutions per second or 1 revolution every 26666666 clk cycles
if (clkfreq < 120 * l_current) or 80,000,000 < 3,199,999,920
But if you went to 240rpm, which should be false (but is true)
240rpm = 4 revolutions per second or 1 revolution every 20000000 clk cycles
if (clkfreq < 120 * l_current) or 80,000,000 < 2,400,000,000
I think it will evaluate to true until it is greater than 7200rpm or 1 revolution every 666666 clk cycles, when it should be evaluating to false at anything above 200rpm?
I am probably missing something still, so don't be insulted by the additional questions please, I'm asking again because I want to learn/understand.
80_000_000 / 20_000_000 * 60 / 36 == 6 (integer), which is less than 200
-Phil
240rpm = 1 tooth every 555555 cycles, and I originally did 4 revolutions and 26666666 which was wrong, sorry about that.
180rpm = 1 tooth every 740740 cycles
(clkfreq < 120 * l_current)
80000000 < 120 * 740740 = 80,000,000 < 88,888,800 - TRUE for 180rpm
80000000 < 120 * 555555 = 80,000,000 < 66,666,600 - FALSE for 240rpm
I appreciate your patience, thanks for sticking with me on this
Does spin have the speed to do calculations within 8888 clk cycles or possibly 1/2 that?