Shop OBEX P1 Docs P2 Docs Learn Events
SPIN Speed. Possible code improvements?? — Parallax Forums

SPIN Speed. Possible code improvements??

photomankcphotomankc Posts: 943
edited 2010-01-20 03:42 in Propeller 1
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.
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

  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-01-19 20:15
    As you well know, you'll get real speed improvement by going to PASM. Since that is not an option you like at the moment, have you considered using a 6.25 MHz crystal? -- gives you a 25% performance increase across the board; maybe that's enough for what you're doing.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon McPhalen
    Hollywood, CA
  • Miner_with_a_PICMiner_with_a_PIC Posts: 123
    edited 2010-01-19 20:18
    Photomankc, each cog contains two counters...these might prove handy...ultimately you should take the plunge and start programming speed intensive programs in assembly but the counters should buy you some added speed.
  • photomankcphotomankc Posts: 943
    edited 2010-01-19 20:21
    Yeah, it's in consideration. I've had other boards running 100MHz with pretty solid reliability. Having it in the box with three motor drivers might make it a little warmer than my other projects though. Once I have everything fleshed out, I'll start working on going to PASM. Will likely erase the speed concerns completely. If I can get up to 8 to 10KHz though, I may not worry about it. It's fast enough.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2010-01-19 20:26
    The problem is probably with the delay1us routine, since I'm guessing that it starts the timing from the moment it's called and not from the end of the last delay. It's easy enough to include a zero-overhead delay in your code:

    [b]time := cnt[/b]
    repeat accelSteps
        [b]waitcnt(time += 80 * accel_tbl[noparse][[/noparse]index+offset])[/b]
        outa[noparse][[/noparse]CLK_PIN]~~
        outa[noparse][[/noparse]CLK_PIN]~
        position += steps
        if not enable
          result := -1
          flag := ABORT
          quit
        
        index += 4
    
    
    


    -Phil
  • photomankcphotomankc Posts: 943
    edited 2010-01-19 20:32
    Miner_with_a_PIC said...
    Photomankc, each cog contains two counters...these might prove handy...ultimately you should take the plunge and start programming speed intensive programs in assembly but the counters should buy you some added speed.

    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.
  • photomankcphotomankc Posts: 943
    edited 2010-01-19 20:40
    Phil Pilgrim (PhiPi) said...
    The problem is probably with the delay1us routine, since I'm guessing that it starts the timing from the moment it's called and not from the end of the last delay. It's easy enough to include a zero-overhead delay in your code:

    [b]time := cnt[/b]
    repeat accelSteps
        [b]waitcnt(time += 80 * accel_tbl[noparse][[/noparse]index+offset])[/b]
        outa[noparse][[/noparse]CLK_PIN]~~
        outa[noparse][[/noparse]CLK_PIN]~
        position += steps
        if not enable
          result := -1
          flag := ABORT
          quit
        
        index += 4
    
    
    


    -Phil

    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....
    [b]time := cnt[/b]
    repeat accelSteps
        outa[noparse][[/noparse]CLK_PIN]~~
        outa[noparse][[/noparse]CLK_PIN]~
        position += steps
        if not enable
          result := -1
          flag := ABORT
          quit
        index += 4
        [b]waitcnt(time += 80 * accel_tbl[noparse][[/noparse]index+offset])[/b]
    
    



    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 Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2010-01-19 21:23
    Yes, that should work. The timing between the first two pulses may be a little off, but not by much.

    -Phil
  • photomankcphotomankc Posts: 943
    edited 2010-01-20 03:42
    Thanks sir.· That was just the trick.· Prior to this I was not able to accelerate to beyond 700RPM.· I think that because it wasn't really following the table anyway past a certain point due to execution time error and then when the running steps kicked in it was being jolted way faster than it had actually accelerated to.· Now I have it going at 1100 RPM before it stalls.· I'm also running it at 20V instead of 38V so inductance is likely limiting it somewhat as well.· It flat moves now!· I actually ran off the edge of the acceleration table because I never had to worry about it before.· Had to add logic to handle that.

    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.
Sign In or Register to comment.