SPIN Speed. Possible code improvements??
photomankc
Posts: 943
Hey guys. I'm wondering if anyone has thoughts on this. Brainstorming a bit after I quit last night. Still working on my stepper controller and seem to have found a reasonable solution to acceleration by using a table that is pre-calculated with the uSec values to use for each step up to the desired speed. Kinda works. I say kinda because I'm pushing up against SPIN execution speed rapidly. It can't properly accelerate to pulse rates above 3KHz. My table looks like this:
Values are dummies and the table is microseconds between pulse rising edges.
Each column is the value to use for a given microstep mode (2,4,8,16). So to read for 4 microstep mode you step by 4 and offset by one, two for 8 microstep, 3 for 16 microstep.
The accel code looks like this (note: I pre-run the table to get the number of steps needed and then run through and do the actual steps):
The problem is that the scope says this code takes 320 uSecs longer than the requested delay to produce the next pulse. That's a killer. When I was testing earlier with a single column table my code looked like this:
And that code was showing around 100-110 uSecs overhead. Could accel_tbl(index) changing to accel_tbl(index+offset) really add several hundred uSecs of execution time? I can't imagine that index+=4 vs index ++ would add anything? its still just an add operation right?
I have a few ideas to help I think. One is make the table into a table of clock cycles instead of microseconds and use waitcnt instead of the delay function call. Another is to apply the offset to the first value of index and then increment by four eliminating the addition in the array index bracket. I'm just having a hard time seeing how a couple of addition operations are jacking the execution time up so far.
I need at least 8KHz output rate to consider it usable. My driver shifts up through microstepping modes quickly when requested speed is past about 100RPM so I don't need really high pulse rates to move since high speed moves shift into half-step mode and I can reach over 900 RPM before 8KHz. I don't really think it's very useful to try and drive the stepper much faster with the torque loss. That means 110-120 uSecs overhead is about all I can live with.
Ultimately this should probably get done in assembly but it's a bit complex because It centered around a command queue. You send a command with direction, speed, and number of steps and it then fetches and executes the command in separate cog and handles speed shifting all in the background. There are a number of other commands, like zero, mark, return to zero, return to mark, and so forth that would all have to then be handled in assembly. A lot more complex than the Step/Dir-Slave mode that I got working in PASM.
Values are dummies and the table is microseconds between pulse rising edges.
DAT accel_tbl word 4000, 3000, 2000, 1000 word 1500, 1200, 900, 800 ... 209 more rows.
Each column is the value to use for a given microstep mode (2,4,8,16). So to read for 4 microstep mode you step by 4 and offset by one, two for 8 microstep, 3 for 16 microstep.
The accel code looks like this (note: I pre-run the table to get the number of steps needed and then run through and do the actual steps):
repeat accelSteps outa[noparse][[/noparse]CLK_PIN]~~ outa[noparse][[/noparse]CLK_PIN]~ position += steps if not enable result := -1 flag := ABORT quit index += 4 timing.delay1us(accel_tbl[noparse][[/noparse]index+offset])
The problem is that the scope says this code takes 320 uSecs longer than the requested delay to produce the next pulse. That's a killer. When I was testing earlier with a single column table my code looked like this:
repeat accelSteps outa[noparse][[/noparse]CLK_PIN]~~ outa[noparse][[/noparse]CLK_PIN]~ position += steps if not enable result := -1 flag := ABORT quit index ++ timing.delay1us(accel_tbl[noparse][[/noparse]index])
And that code was showing around 100-110 uSecs overhead. Could accel_tbl(index) changing to accel_tbl(index+offset) really add several hundred uSecs of execution time? I can't imagine that index+=4 vs index ++ would add anything? its still just an add operation right?
I have a few ideas to help I think. One is make the table into a table of clock cycles instead of microseconds and use waitcnt instead of the delay function call. Another is to apply the offset to the first value of index and then increment by four eliminating the addition in the array index bracket. I'm just having a hard time seeing how a couple of addition operations are jacking the execution time up so far.
I need at least 8KHz output rate to consider it usable. My driver shifts up through microstepping modes quickly when requested speed is past about 100RPM so I don't need really high pulse rates to move since high speed moves shift into half-step mode and I can reach over 900 RPM before 8KHz. I don't really think it's very useful to try and drive the stepper much faster with the torque loss. That means 110-120 uSecs overhead is about all I can live with.
Ultimately this should probably get done in assembly but it's a bit complex because It centered around a command queue. You send a command with direction, speed, and number of steps and it then fetches and executes the command in separate cog and handles speed shifting all in the background. There are a number of other commands, like zero, mark, return to zero, return to mark, and so forth that would all have to then be handled in assembly. A lot more complex than the Step/Dir-Slave mode that I got working in PASM.
Comments
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon McPhalen
Hollywood, CA
-Phil
Problem comes back to needing a very specific number of steps at a very specific frequency. To accelerate I have to change the frequency on every pulse so I'm still tied to how fast I can check everything else and update the counter. I also have to monitor the enable state so I can stop immediately if commanded. I have not been able to see a way around the fact that I have to start and stop the pulses at the exact right moment and I have to keep watching enable while I do it. It would help if the counters could be set to execute so many counts and stop.
I could spawn a second COG for the stepping engine from the command execution cog, but now I'm up to 6 cogs for a 3 axis board. Doesn't leave much for the rest of the system. That would be a far more simple PASM bit to write though.
That's what I was thinking along the lines of but will it work this way? (I was thinking so since the delay is now based on a specific clock cycle....
Reason being is that the pulse has to occur first. The first value in the table is the time to delay between step1 and step2.
-Phil
I'll also have to add something to handle being asked to go·1100RPM for 4 steps but for now I'm pleased... this will work nicely.· Oh yeah, accel_tbl(index) was a decent·bit faster than accel_tbl(index+offset).· My original numbers were wrong though.· I was looking at the table in Excel and forgot I had changed it from what was in the DAT section.· I doubt it really was 320 uSecs.