Spin>Assembly conversion
T Chap
Posts: 4,223
I have a few sections of code in Spin that I need converted to assembly. Looking through the manual there aren't a lot of examples to adapt from, so I am looking for advice on how to get the info needed to convert the working Spin parts. In a perfect world you could put in Spin and press convert, and it would give the asm equivalent that you could substitute where needed. Here are a few examples of simplpe parts needed converting:
Post Edited (originator99) : 11/3/2006 1:29:59 AM GMT
Post Edited (originator99) : 11/3/2006 1:29:59 AM GMT
Comments
The next question is "what are you trying to do?". It doesn't always make sense to try to translate SPIN to assembly. It's often better to go back to the function you're trying to accomplish. For example, there's no case statement in assembly. It looks like you want to have pin 26 a one unless several different values are in some range. Maybe it'd be better to use some other way to keep track of the ranges.
The new OUTA bits are accumulated separately to avoid glitches in the I/O pin settings as the output register is changed. If they didn't need to all be changed at once, the bits could be masked off one item at a time and or'd directly into OUTA. If the bits didn't need to be reversed, that would be another instruction we wouldn't need. It would actually be easier for XpinState, YpinState, and ZpinState to all be kept in the same long, already shifted into position. It all depends on where they come from and what other manipulations you need to do on them.
Post Edited (Mike Green) : 10/15/2006 8:53:53 PM GMT
PS the file posted is messy but works! I tested a 2.5 hour machine code last night, where the machine is set to stop if the step counter and encoder counter are out by more than a few pulses on 3 different motors/encoders, it never stopped. What is happening is that there is a small discrepancy when going faster, in that with Spin, first it checks to read the Xposition counter, then it checks the encoder position and compares. If the difference is more than a few pulses, there is a problem, and what is happening is that at high speeds, the time between checking the xpos and encoder is causing a variance versus low speeds. I suspect that there is too much time passing between checking Xpos and the encoder value pos[noparse][[/noparse]0]. I was thinking the asm would solve it. Although, with the right range specified as a mask, there is no problem for normal operation.
Post Edited (originator99) : 11/3/2006 1:30:48 AM GMT
It sounds like you'd have more than enough time for a single cog in assembly to do the stepping for all three axes plus checking for the encoder vs stepper error.
Many of the parallax objects (such as mouse) use this command.
In the mouse object the cog is passed the address of the globle variables when it is initialized:
The @entry is the label at the start of the assembly code, the @par_x is the name of the first global variable the cog might want to read or write to.
In the assembly that address is called par which stands for parameter.
So the program does its thing comunicating with the mouse, it updates some local variables which it then wants to write to the global variables in main ram.
I'll move away from the mouse.spin code because it does the writing in a loop using self modifying code, its not hard to understand but lets stick to the basics.
The first global variable was par_x, this holds the x position. In the asm the x position is held in _x so to write this number and the next one _y:
Finally you have a function in your spin to get the varible from main memory:
I hope that helps. If it makes sense have a proper look at the way mouse.spin writes all the variables, read up on the movs and movd commands.
Graham
What about the encoder stuff?
Post Edited (Mike Green) : 11/3/2006 2:17:29 AM GMT
Post Edited (originator99) : 11/3/2006 1:31:33 AM GMT
Just curious how to run it, I already had in the var's xpos, ypos, zpos, but it gives an error that it is expecting some instructions, so I remove the variables, and it gives other errors, below is what I was tring as a test.
Ok another thought the original version in spin had a function called timer, which basically just watched the pins, and if no input for 1000 clocks, it set the outa pinstates to %0000 as you recall. What this allows is for the motors to be turned off when not being used to get rid of the pwm noise, zinging the motors. Is the asm code you wrote considering the need to shut the motors? Sorry to waste away your Sunday at this.
This assumes that stepper is the name of the object with these routines in it. I didn't put in a built-in way to restart things if step pulses start coming in again. If that's important, I'll show you how to do that another time. Note that when the assembly cog is stopped, the I/O direction gets set to inputs which let the motor control bits float. If they're pulled down to 0V, that should shut off the motors.
Post Edited (Mike Green) : 11/3/2006 2:17:51 AM GMT
Not sure how much it screws up stuff but it works to solve the direction.
1. Keep getting an error 'Expecting a variable" at return ++timeStep, so I change it to just timeStep and it compiles. I added the variables on both the object and program but that creates other errors.
2. Not sure why the OUTA you have is affecting the ability to change pin output states from the main program. Your outa assignements only go to P23, I am trying to alter P26, and something in the stepmotor object is preventing any outside use of the pin. I'll sort that out with trial and error.
This is very cool Mike, I appreciate it. Let me know if you want one of the final boards when I get the revisions in this week.
Post Edited (originator99) : 11/3/2006 1:34:44 AM GMT
1) I mistyped. It should be "return ++timeOut"
2) I don't understand. The only DIRA bits set to one (during initialization) are 6-17. If a DIRA bit is zero, that shouldn't affect any other cog's use of the pin (they're or'd together in the chip).
repeat
outa[noparse][[/noparse]14..17] := XpinState
So that the motor move code really doesn't move the motors, it just sets the state for the global variables. The control loop sends out whatever the variable state is, and that varibale can be changed by any other code, such as the "timer" code which checks for step pulses, if none, start counting to X, then set the variable to 0. If a new Step pulse comes along, the timer is restarted, but at the same time, the motor move code is sending out new states. The motor control loop picks up whatever vaiable change it sees and sends it to the motors. This may be convoluted, but it's the best solution I could find, as having the motor move code directly connected to the outa's meant it was hard to get then to release their grip on the outs, thus resetting them to 0 was difficult for the timer function, they were fighting each other for control of the pins. I hope this makes sense. Certainly no rush to find a solutuion,but stopping the cog is not workable, as this is something that happens repeatedly, the cog would have to reamain active always retaining the step and encoder count. This timeout needs to be adjustable, as there may be cases to not release the motors ever, as they may need to stay "braked". When at 0, they are freewheeling. Well not 100% free, close.
Post Edited (Mike Green) : 11/3/2006 2:18:18 AM GMT
The test for x, y, and zPosValue is puzzling. I've included the code, if you would kindly tell me if there is something wrong with the test. The max value for testing > or < the x,y, z values is 65537, or a byte value max. Above that value in the equation, all motors are DOA. The travel of X table is greater than 65k travel, or it wouldn't be a big deal.
Post Edited (originator99) : 10/17/2006 5:21:28 AM GMT
Just to see if it would help, change the problematic IF statement to:
Add the following to the CNC object in anticipation of having the comparison code in assembly:
About resyncing the motor, 1) Can all the motors be stepped 32 steps initially at the same time? 2) Would it work to change "driver" to do 16 steps in one direction, then go back 16 steps in the other direction? Is there some other way that would work better.
Post Edited (Mike Green) : 11/3/2006 2:18:49 AM GMT
All motors can be jogged at the same time, no difference, any short amount is fine, 8, 16, 32 should do it. As far as going forwards and back, makes no difference as it just takes a few steps to get in sync. The trick is to not start comparing until after the they are jogged.
Post Edited (originator99) : 10/18/2006 5:13:38 AM GMT
Here's the modified "driver" with an initialization routine that effectively does 8 step pulses forward before starting operations as usual. I haven't tried it, but it looks correct with the changes.
Mike
Post Edited (Mike Green) : 11/3/2006 2:19:40 AM GMT
**Jog works as planned!
Post Edited (originator99) : 10/18/2006 5:58:29 PM GMT
You can see attempts to re-Zero the x,y,z positions after bootup, plus start the encoder reading after everything else is reset. I deleted the code not required for out of range. The timer code is fine. What is going on is that on boot, the move_ena is going low at once, causeing the PC software to be paused since it sees a warning. Trying nubers from 0 - 10000 for upper and 0 - -100000 doesn't affect it. Upon bootup and reset after jogging, all values should be showing up as 0, so the formula (xpos*2) - encoderxPos should = 0 as well.
I also changed CNC_Controller.spin again to eliminate a separate cog for the timer. If the last statement in a SPIN thread is a COGNEW or COGINIT, there's probably no point to starting a new thread (cog) since the one containing the COGNEW or COGINIT is just going to stop itself on the next statement (an implicit RETURN to a COGSTOP(COGID)).
On the "move_ena" problem. The I/O pin is initially an input (until compareEntry sets it up as an output). If the circuit has a pulldown resistor in it or whatever it's connected to treats a high impedance as a logic low, then that's what's going on. The best thing would be to add a pullup resistor to 3.3V to the signal line. Alternatively, you could put "OUTA[noparse][[/noparse]move_ena] := 1" and "DIRA[noparse][[/noparse]move_ena] := 1" right after the "PUB START" in CNC_Controller and a "WAITCNT(CLKFREQ/1000 + CNT)" followed by a "DIRA[noparse][[/noparse]move_ena] := 0" right after the call to "doCompare". That last addition makes sure that the "compareEntry" routine can control the move_ena pin once it has time to start up.
Post Edited (Mike Green) : 11/3/2006 2:20:06 AM GMT
Some strange reults that aren't making sense:
1. If I comment out the timer routine, then the doCompare routine causes the move-ena pin to float forever, but hovers on the low side causing the active low alarm.
2. If I leave the timer routine in just as you saw it, the doCompare routine still leaves move_ena floating, but somehow it floats at a different place, and does allow the motors to run without an alarm, but Y doesnt run at all with the timer in.
3. With the timer in, if there actually is comparing taking palce, it is not known as the pin is floating. Grabbing the motor and stalling it doesn't not reflect a change on the pin, it still floats.
Mike I certainly don't wont to create a bottomless pit with this project, I can work with the original Spin version, so please do not feel obligated to spend more time solving the issue. You have alrady gone above and beyond.
Post Edited (Mike Green) : 11/3/2006 2:20:23 AM GMT