Better Way in Spin?
davidsaunders
Posts: 1,559
The actual step routine in my stepper motor controller seems to have to many operations to me. I have tried factoring out by assigning partial values to variables, though that creates even more operations in total.
The routine in question is:
Needless to say part of it is making sure that for full steps the index into Step is even, that is the &!(||v-1) part, the rest is fairly self explanitory. It does not check to see if the values passed in are in range, as it will only be called from known code I did not see the use in worrying about that check.
Is there a way to accomplish this in fewer operations, before I wire up four steppers to a propeller and test it?
The routine in question is:
'*** DoStep(m,v) Step one step. **************************************** ' m is the motor number, 0 for A, 1 for B, 2 for C, and 3 for D. ' v is the step value: ' -1 for half step reverse. ' 1 for half step forward. ' -2 for full step reverse. ' 2 for full step forward. 'It is recommended not to mix full and half steps, it can through off ' your count if you are not carefull. If you must mix full and half ' steps make sure that the half step count is a multiple of 2 before ' returning to full steps, other wise your count will be wrong, unless ' you compensate for it. PUB DoStep(m,v) outa[0..17]:=PinVals:=(Step[7&((StpI[m]+=v)&!(||v-1))]<<(m<<2))|(PinVals&!($0F<<(m<<2))) DAT Step byte %0011, %0010, %0110, %0100 byte %1100, %1000, %1001, %0001
Needless to say part of it is making sure that for full steps the index into Step is even, that is the &!(||v-1) part, the rest is fairly self explanitory. It does not check to see if the values passed in are in range, as it will only be called from known code I did not see the use in worrying about that check.
Is there a way to accomplish this in fewer operations, before I wire up four steppers to a propeller and test it?
Comments
I suspect what you want to do is more easily written in PASM. And much faster too.
Surely there are stepper motor drivers in OBEX you could use.
Just trying to make it simple, a single short expression like that is always easier for me to read, just do not make it to long.
So to break it down into parts, by order of execution, using the bold sections as what to look at:
PinVals:=(Step|v-1))[/b<<(m<<2))|(PinVals&!($0F<<(m<<2)))
This section calculates the index into the array of step output values, defined in the DAT section. Breaking that down more we look at 7&((StpI[m]+=v)&!(||v-1)) this just gives us the next index value, as the StpI array contains the current step index for each motor. Next is 7&((StpI[m]+=v)&!(||v-1)) this just makes sure that if the absolute value of parameter v is 2, then we are indexing an even step number for full stepping. This brings us to (Step|v-1))[b<<(m<<2)) we are indexing into the step array with the result of the above, and taking the result and shifting it by motor number *4 to put it on the correct pins. Once we get this far we need to mask of our local copy of our working output, so we or it with the stored pin values, with the four bits we are changing masked to zero, that is what the section |(PinVals&!($0F<<(m<<2)))
Anyway, what is the problem?
Does it work as you expect or not?
Are you really so pushed for space?
I accomplish the same task by the part that says &!(||v-1)
I am going to have to look at that a bit more, though it looks like you are just moving some of the stuff out to the caller. IE making the caller do the calculation of the shift. I could be wrong, give me a couple of minutes to fully digest that.
OH, I see what is missing. The inclusion of the stored values of the pins when doing the output. As there are 4 steppers across 16 pins, and I leave those 16 pins as outputs all the time, thus saving time. Thus your example would change the outputs to the other three stepper motors to invalid values.
I was wrong, I see you are using outa to get the existing values. Ok that gives me something to think about, and looks good.
Though I do thank you, that does give me some ideas of how to improve the routine a good bit.
Ahh, ok - that expression was pretty dense, so I missed that part.
And to your last point, yes - I'm assuming each output is 4 successive pins, so masking OUTA with & ($FFFF_FFF - ($F<<mShift)) should keep everything but the four pins you're changing, and then you OR in those pins from the step array, shifted into the proper place by mShift. So in my code mShift takes the place of your motor index.
I would actually create one instance of this object per motor, because then mMask can be computed once and re-used. You could also just pass it in from the higher level code to accomplish the same thing.
It did get me thinking about a long since abandoned project of mine, to run a 3D printer from a Prop. Now it would seem more possible as I could have a Raspberry Pi interpret the G-CODE and send my simple motor control commands to the Prop, there are a few other issues, though they are for another thread I will start in a minute.