Need speed but ASM is too much to tackle.
In cases where Spin is not fast enough, is there any alternative to assembly? I see people discussing C and similar languages but have no idea what is going on with those languages either. Is there a compromise to get more speed with a simpler learning curve than asm?
I have looked at asm enough to consider it too much a time investment to solve what I need done. A consultant for a fee seems the only option at the moment to handle one section of code for a project that requires up to 50k instructions per second. Right now the Spin equivalent is not even at 10% the speed needed. What I am considering now is scaling the speed down by 10% just to get the working idea done, then seeing if someone can convert it for a reasonable fee.
I have looked at asm enough to consider it too much a time investment to solve what I need done. A consultant for a fee seems the only option at the moment to handle one section of code for a project that requires up to 50k instructions per second. Right now the Spin equivalent is not even at 10% the speed needed. What I am considering now is scaling the speed down by 10% just to get the working idea done, then seeing if someone can convert it for a reasonable fee.

Comments
Sometimes you can play tricks with counters etc to do something quicker but in general if you want more speed asm is the way to go. Using multiple cogs together is another option too but it doesn't sound like that will be an option.
I learnt pasm while programming up a project and that was over two weeks, if you know what you need to do (which you do because you have the spin) it can be fairly straight forward to get something working. Especially with a little help [noparse];)[/noparse]
Cheers,
Graham
There's no middle ground between Spin and PASM, the best you have is an alternative language such as ImageCraft C which runs at near PASM speed but hides the complexity of PASM from you. There's also JDforth which can improve upon Spin performance but again you'll have a learning curve there. I don't know of any other languages which target the Propeller.
You maybe able to find someone to translate what you have into PASM. If it's a simple piece of code someone may do that for free or cheaply. More complicated and it may well cost serious money. It would all depend on what it is.
To explain a little more detail. The code is related to driving a motor with pulses, reading an encoder and comparing the two. The max speed of the encoder and pulses is around 48k per sec each. The rotary obj already is making the position available in a variable, but instructions are required to create new pulses (a counter is not an option, no pins to sacrifice for ctra). The pulses are virtual, and do nothing but count and create a speed profile by which an asm PWM object models the value of. Then the compare and correct instructions are required, with a number of if pos > new position type instructions that keep track of things. The fastest I can run the Spin variation is around 6k pulses per sec.
For now, just to keep making progress, I will scale the whole thing down to 10% resolution (divide the encoder by 10), and translate it as it goes. Actually the parts are quite simple, there are just quite a few phases to the motion, including reverse, ramp up, ramp down, etc, that make it look big. I will post the spin version soon and get opinions on how complex or easy it might be to translate.
LCC runs at 5.0 MIPS
& PASM runs at 20MIPS.
@ Originator, PASM doesn't look that hard, in fact it seems a bit easier than spin (in concept) to me. DeSilva's tutorial on PASM takes you from blinking the LED to more complex tasks, setting Registers (CTR,VCFG,CLK,DIR,IN,OUT, ect..)·in PASM isn't much more difficult than doing it in spin. You should be familiar with the "IF" structure, most ASM tasks can be performed with this type of· conditional structure. Shifting, REVersing bit patterns, add, sub, shift, rotate, multiply, divide, can all be done in PASM, maybe easier than SPIN. Study and give yourself alittle time to learn it. If your doing something with shifting out opperations, look at this thread. The VSU hardware can do more than video.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
E3 = Thought
http://folding.stanford.edu/·- Donating some CPU/GPU downtime just might lead to a cure for cancer! My team stats.
your description is a little confusing but it seems simple enough for an early asm attempt.
Graham
I found PASM much easier and friendlier than any other ASM i've seen
I say you muster up the courage and go through those examples. I started with FullDuplexSerial object and it was a very good base.
Funny thing is, i have not touched spin at all! all PASM baby
What is the desired servo loop time? 1000 loops per second is usually heaps. That should be easy to achieve, even in Spin. It sounds like you need to decouple the parts some more. Specifically, the pulse output routine.
Actually, do the output pulses represent position stepping or is it more like PWM or the "servo" pulses of hobby controllers? If they are real position steps then a servo loop is not needed. The drive is performing that function for you already. All you need to do is output the pulses at a pre-calculated rate and length. Using the precise feedback only for end of move corrections or error checking, if needed.
object just to experiment with it. This is just a program that generates pulses that reflect
actual distance on the motor/encoder. It is going to be a closed loop servo of sorts. The
PWM will chase the pulses, trying at all times to reflect the error between current position and new position.
So far this is working great but needs a lot of work still, I have not gotten the boards back
yet from assembly to test the actual motion.
It is currently sending out a PWM duty (0-1000) based on the pause between pulses (accel).
That may change if I can get PID to chase the position error in a better way.
Unless scale the encoder down, the default count is 16000 per revoltion, or 4000 per inch. I a
testing with it reduces by /10, which may actually suffice at 400 per inch, in which case the
spin can handle it. However, since the max speed will be 12 inches a second, that would mean
4800 instructions a second just to compare the encoder against the current position, not to mention
correction instructions, and all the other code below.
I definitely intend to get started on learning PASM. Thanks for the tips guys. The code is already at
around 1800 lines for the entire project, and no where near done.
Where does this stuff below rate in terms of complexity if I study the tutorials for a bit?
PUB MotionEngine | mdir, accel, decel, arate, drate, run, MaxSpeed, MinSpeed, RampDown, Correction, newpos, pos, run80, run10, dutymin, dutymax 'This code creates a speed profile using (virtual) Pulses that vary in speed, the time between the pulses(accel value) determines PWM duty range of - 1000. This accel value will be scaled 'or tuned to the motor to find a matching Speed/PWM value. The motor uses a 10:1 gear box. The motor has an encoder that reads 1600 counts per rev, 16000 per rev at the gearbox. 'Currently, I have scaled the encoder counter /10 due to Spin not being fast enough to generate pulses fast enough due to the instruction time demands. 'At the scaled down amount, 400 encoder counts now = 1 inch at the belt/pulley for real world work. Therefore, IPS = 400 pulses per sec in the code below. 'An encoder will be read and compared to the profile pulse counter to check for accuracy. The difference is Error. 'Error is factored back into the Duty value sent to the PWM object via it's correction value, ie If error > 0, error = 0 - error. This offets the PWM by subtracting the error. 'The error will likely need to be scaled to reflect Inches Per Sec/Pulses Per Sec to PWM actual adjustment of error. This is unknown as of now. 'The Correction value has not been established due to the motor having not been calibrated for speed>duty, nor has a PPS (Pulses Per Sec)/Speed 'ratio been established for corresponsing PWM/Speed values. It is also not certain the linearity of PPS > Duty > Speed ( IPS ). 'The motion code is constantly seeking a new destination, even if in motion, as input can and does change sporadically. If new pos is recieved by any means, '(serial input, user push button etc),the motion immediately ramps down by some ramp rate, then accels towards the newpos. 'The distance is devided into the RUN (ramp up 10% distance), the RUN80(80% of distance at fixed speed set by MaxSpeed), and ramp down by 10% at end. 'DutyMin is a value that is the minimum duty required to start the motor moving. 'DutyMax is the maximum speed to allow the motor to turn to not overshoot the profile speed. 'pid.init(-2.1, -12.02, -0.01664, 25.0, 0.0, 5.0, -5.0) '(_Kp, _Ki, _Kd, setPoint, offset, maxArea, minArea) pid.init(-2.1, -12.02, -0.01664, 25, 81.0, 5.0, -5.0) '(_Kp, _Ki, _Kd, setPoint, offset, maxArea, minArea) pos := 1 'TEST POSITION (start) newpos := 1 'TEST POSITION (destination) simulates a real input value dira[noparse][[/noparse]17] := 1 'step pin dir outa[noparse][[/noparse]17] := 0 'step pin output state = 0 reset := runmode 'i2c 8575 pin MaxSpeed := 400 ' convert to IPS/PPS 'waitcnt(400 + cnt) is max iteration, plus spin code unknown time,SPEED MinSpeed := 500_000 'accelval cannot exceed minspeed val 'aRate := 10000 'rate to reduce Accel val on ramp up aRate := (MinSPeed - MaxSpeed)/100 dRate := 100 repeat ' <<<<<<<<<< MAIN REPEAT LOOP accel := MinSpeed 'reset Staring Accel value if newpos > pos 'Check for new position forward direction run10 := ((newpos - pos)/10) '<# 4000 'set 10% of distance to ramp up limit sets how long it can ramp for 'Ramp up to MaxSpeed repeat run10 '10% range of motion, Accel ramp up MaxSpeed Posvar := pos 'for LCD display and testing only, LCD on it's own cog, looping and showing the Profile counter outa[noparse][[/noparse]17] := 1 'set direction accel := (accel - aRate) #> MaxSpeed 'accel starts out slow, then gets faster due to aRate reducing Accel 'accel := (MinSpeed - aRATE) #> MaxSpeed pwmasm.SetDuty(accel, minSpeed, maxSpeed) 'output parameters to pwmasmDuty1000 object ( 0 -1000 duty range ) pos := pos + 1 'update profile position counter error := encodercount - pos pidval := pid.calculate(error) waitcnt(accel + cnt) if newpos < pos Quit 'jumps to interrupt below if pos has changed to a more reverse position than current run80 := (newpos - (run10*2)) 'set run80 set 80% travel distance at MaxSpeed new pos is now 10% into the distance 'travel 80% of newpos @ MAX SPEED repeat run80 'run80 'RUN 80% of travel Posvar := pos outa[noparse][[/noparse]17] := 1 pwmasm.SetDuty(accel, minSpeed, maxSpeed) pos := pos + 1 'update Pos error := encodercount - pos pidval := pid.calculate(error) waitcnt(accel + cnt) 'INTERRUPT and Decel if new pos in reverse received If newpos < pos decel := accel repeat run10 'Decel 10% of newpos Posvar := pos outa[noparse][[/noparse]17] := 1 Decel := (Decel + dRate) #> MaxSpeed pwmasm.SetDuty(Decel, minSpeed, maxSpeed) pos := pos + 1 error := encodercount - pos pidval := pid.calculate(error) waitcnt(decel + cnt) 'Ramp down from MaxSpeed to MinSpeed repeat until pos == newpos 'Decel 10% of X If newpos < pos Quit Posvar := pos outa[noparse][[/noparse]17] := 1 Decel := (Decel + dRate) #> MaxSpeed pwmasm.SetDuty(Decel, minSpeed, maxSpeed) error := encodercount - pos pidval := pid.calculate(error) pos := pos + 1 waitcnt(decel + cnt) 'update profile position counter error := encodercount - pos pidval := pid.calculate(error) '-----------------|||||Reverse|||||--------------------- 'newpos := 1 if newpos < pos 'Check for new position forward direction run10 := ((pos - newpos)/10) '<# 4000 'set 10% of distance to ramp up limit sets how long it can ramp for 'Ramp up to MaxSpeed repeat run10 '10% range of motion, Accel ramp up MaxSpeed Posvar := pos 'for LCD display and testing only, LCD on it's own cog, looping and showing the Profile counter outa[noparse][[/noparse]17] := 0 'set direction accel := (accel - aRate) #> MaxSpeed 'accel starts out slow, then gets faster due to aRate reducing Accel 'accel := (MinSpeed - aRATE) #> MaxSpeed pwmasm.SetDuty(accel, minSpeed, maxSpeed) 'output parameters to pwmasmDuty1000 object ( 0 -1000 duty range ) pos := pos - 1 'update profile position counter error := encodercount - pos pidval := pid.calculate(error) waitcnt(accel + cnt) if newpos > pos Quit 'jumps to interrupt below if pos has changed to a more reverse position than current run80 := (pos - (run10 * 2)) 'set run80 set 80% travel distance at MaxSpeed new pos is now 10% into the distance 'travel 80% of newpos @ MAX SPEED repeat run80 'run80 'RUN 80% of travel Posvar := pos outa[noparse][[/noparse]17] := 1 pwmasm.SetDuty(accel, minSpeed, maxSpeed) pos := pos - 1 'update Pos error := encodercount - pos pidval := pid.calculate(error) waitcnt(accel + cnt) 'INTERRUPT and Decel if new pos in reverse received If newpos > pos 'ledon decel := accel repeat run10 'Decel 10% of newpos Posvar := pos outa[noparse][[/noparse]17] := 0 Decel := (Decel + dRate) #> MaxSpeed pwmasm.SetDuty(Decel, minSpeed, maxSpeed) pos := pos - 1 error := encodercount - pos pidval := pid.calculate(error) waitcnt(decel + cnt) 'Ramp down from MaxSpeed to MinSpeed Decel := accel repeat until pos == newpos 'Decel 10% of X ledon If newpos > pos Quit Posvar := pos outa[noparse][[/noparse]17] := 0 Decel := (Decel + dRate) <# MinSpeed pwmasm.SetDuty(Decel, minSpeed, maxSpeed) pos := pos - 1 error := encodercount - pos pidval := pid.calculate(error) waitcnt(decel + cnt) ledoffPost Edited (Originator) : 10/6/2008 12:53:43 AM GMT
What I would do is shift the PID to it's own Cog for the short term. And late incorporate it with the Duty program. The PID servo loop can run, tracking a target value, on it's own at a higher loop rate than what the profile generator needs to.
Next would be to modularise the profile building routines into tidy, well documented functions. This can be a pain keeping a tidy structure but you will be rewarded later on.
PUB ex01 cognew(@ex01A, 0) DAT ORG 0 ex01A MOV DIRA, #$FF ' (Cel l 0) Output to I/O 0 to 7 MOV pattern, #0 ' (Cel l 1) Clear a “registers” loop MOV OUTA, pattern ' (Cel l 2) Output the pattern to P0. .P7 ADD pattern, #1 ' (Cel l 3) Increment the „register“ JMP #loop ' (Cel l 4) repeat loop pattern LONG $AAAAAAAA ' (Cel l 5) FIT 496Hey guys, can someone please explain to me why it appears that that there is no resister or cell that stores the name 'loop', yet the jmp seems to know where to go?
According to the Celo-Cel5, loop and ex01Aa do not get written into any 'cells'.
Thanks.
the label loop also on the same line as the instruction)
There is a symbol table inside the compiler (assembler), which stores the address 'loop', and the compiler
places this stored value every time 'loop' is used as source or destination in an instruction.
Hope that helps
Andy