Shop OBEX P1 Docs P2 Docs Learn Events
Stepper motor driver and demo program for the P2 — Parallax Forums

Stepper motor driver and demo program for the P2

This is my first attempt at a P2 assembly program. Please don't laugh to hard...Any suggestion are appreciated.

Comments

  • JonnyMacJonnyMac Posts: 9,104
    edited 2021-01-12 00:05
    There are instructions that let you drive pins which takes the headache out of OUTA and OUTB assignments.
                  decod     steppin                       'make masks for output pins
                  decod     dirpin
                  or        dira, steppin                 'make step and dir pins outputs
                  or        dira, dirpin
    
    ...becomes
                  drvl      steppin
                  drvl      dirpin
    
    Now there is no worry vis-a-vis special handling for any IO. Of course, you'd use this strategy to make pulses, too.
    _dostep1      drvh      steppin                         ' step pin high
                  getct     cv
                  addct1    cv,delayh                       ' start the pulse high timer
    
                  testb     mode, #4     wc                 ' check the direction bit
                  sumc      cpos, #1                        ' add/subtract from current position
                  wrlong    cpos, ptra[0]                   ' update current position
    
                  waitct1
                  drvl      steppin                         ' step pulse end
    
  • Thanks Jon
    That's simpler and more intuitive. I'm still trying to decipher that spreadsheet of instructions.
    I appreciate all the code you have posted over the years. Felt it was my turn to try and give something back.
  • JonnyMacJonnyMac Posts: 9,104
    edited 2021-01-12 00:55
    Assembly is not my normal thing, but Propeller assembly is so friendly I find myself studying the spread sheet trying to understand the instructions. There are many that save a lot of code. For example, in my P1 pixel driver, I have this bit of code.
    ' Correct placement of rg color bytes                    
    ' -- $RR_GG_BB_WW --> $GG_RR_BB_WW                               
                                                                     
    swap_rg                 mov     t1, colorbits                   ' copy for red
                            mov     t2, colorbits                   ' copy for green
                            and     colorbits, HX_0000FFFF          ' isolate blue and white
                            and     t1, HX_FF000000                 ' isolate red
                            shr     t1, #8                          ' move red from byte3 to byte2
                            or      colorbits, t1                   ' add red back in 
                            and     t2, HX_00FF0000                 ' isolate green
                            shl     t2, #8                          ' move green from byte2 to byte3
                            or      colorbits, t2                   ' add green back in 
    
    ...becomes this in the P2:
                    movbyts   colorbits, #%%2310                    ' $RR_GG_BB_WW --> $GG_RR_BB_WW
    
    It's likely that a better programmer could shorten the P1 code, but still, not down to one instruction!

    I'm interested in your acceleration/deceleration routines in the stepper driver; I want to do this with a traditional stepper driver (4 outputs to coils).
  • I have a 6 axis function ( driving step and direction signals only). I wanted to generate an "S" ramp profile but wound up settling for a 3 step ramp function (start off with a slow linear acceleration to get things going, transition to fast linear ramp up to speed, then another slower ramp up to maximum speed at the end). This came out working similar to an "S"ramp profile. I'm sure it could be improved on, but it worked well driving one of my 3 axis machines. You might try something similar.
  • S-shaped ramps can be generated very easily. Just do al linear interpolation from your starting point to the end point at full velocity as if there was no ramp at all. Then pass the position values through a moving average filter to get a triangular ramp. Then pass the output of the first filter through a second filter to get S-shaped ramps.

    The length of the moving average window is velocity divided by acceleration. Choose something around 1ms as time quantum for interpolation and filtering. Pass the filter output minus the last (delta position) to a smart pin (pulse or NCO mode) to generate dp number of pulses per ms to the step pin and the sign of dp to the dir pin. Voilà.
  • Man at work: For a multi axis system, the largest axis move value will always be used as the base for the other 5 axis. Right now, I am simply doing the step delay with a count loop. I guess my next act would be to tie this delay to a time signal that can be varied with a filter like this. If a move profile always has a large enough step count, you can use the same ramp on every move. However, these values always change. One move might be 10000 steps and another might be 7. How would you vary the filter functions to acount for the ever changing maximum step count?

    Another consideration is that each axis of any mechanical system will have different rampup/rampdn capability. It may be beneficial to have multiple ramp profiles used according to which axis is currently the "base" axis of a move.

    Another consideration is that many moves don't want or need to ramp up or down such as when doing a circular interpolated cnc cut. My current scheme is to pre-calculate all the move values for the next step while the last step is moving and do a fast pointer swap to these new values. This eleminates the slight delay for calculations that might make a stepper drive "stutter". The NCO base timer would help here too.

    I haven't worked on my CNC package for the last year or so. Once I got one of my 5 axis machines moving my next goal was to use the "stepper drive" function to generate ideal "Virtual" move positions with a second cog controling DC motors in a feedback loop based on current encodder positions compared to their "Ideal" positions. However... when I found that the encoder functions didn't work on my orginal P2 EVAL board I put things away and went on to other projects. I may or may not get back onto this project anytime soon. Are you controling multiple DC motors with your P2 now? I'm curious about how others have implimented it.
  • BtussBtuss Posts: 20
    edited 2021-01-13 19:34
    Man at work. Do you have code that demonstrates your approach to generating s-shaped ramps? It sounds intriguing but I can't get my old head around it.
    On my lathe I use an encoder on the leadscrew and a phased locked loop to directly generate pulses to the z axis pulse motor - no ramping at all. A divide by N counter implemented in the propeller allows me cut a full range of metric and english threads. It works pretty good with a spindle speed below about 200 rpm. Its interesting to turn the spindle off and watch the pll track as the spindle slows down. Off topic I know.
  • I see the advantage of the S ramp. You don't have the sudden change from constant acceleration to zero acceleration. I think it would be fairly easy to start cutting back on the acceleration a few steps before reaching the constant speed portion and then ramp up the acceleration again before starting to decelerate. It seems that the areas at the bottom of the curve are not as problematic.
  • kbash wrote: »
    Man at work: For a multi axis system, the largest axis move value will always be used as the base for the other 5 axis. Right now, I am simply doing the step delay with a count loop.

    I know this kind of approach. It is based upon some sort of Bresenham line-drawing algorithm that was originally designed for drawing lines on a raster display. But pixels have no inertia. You can treat every line segment separate from each other and don't care about direction changes.

    In a mechanical system this is no longer true. As soon as you want to follow complex trajectories like arcs, splines and polylines while keeping velocity constant you will get in trouble. If you want to implement a full featured CNC controller with spindle synchronisation (for lathes or tapping), feed override and real-time reaction to events then things become very complex.

    But for simple machines like 3D-printers all the calculations can be done in a quite simple way. The toolpath is known in advance. You can do look-ahead and pre-calculate move by move from the ramp-up to the final ramp-down to stop of each move. For the ramps you simply ignore the multiple axis trajectories. All you need to know is the max. velocity and the total length of the move. You effectively treat a move as one-dimensional line no matter how many axes are involved. You can also ignore number of steps and resolution of each axis. Instead you calculate the ramps in virtual units, say µm or steps of the axis with highest resolution.

    For the 1D-line you do the interpolation and filtering as I said in the last message. The output of the filter (length = 1D position) is then used as argument to a function that calculates the coordinates for each axis (input = length, output = vector).

    As the calculations are done in a fixed time frame (once per ms) you don't need any velocity dependent timing loops. Step generation can be done in the hardware (smart pins). You only need to handle integer values for steps per ms for each axis. This means the CPU doesn't have to be faster for higher step rates. Step frequencies up to several MHz are possible.
  • I have incorporated the changes suggested by JohnnyMac and made a change to the demo program.

    In the demo program the start/stop pin is held high by the following line.
    pinhigh(spin) 'start pin must be high for motor to run - could be connected to a switch instead
    you could comment out that line and connect the pin to a switch to start or stop the motion.
    Comment out the following lines as well
    if char == "0" 'set the start/stop pin to 0 (stop)
    pinlow(spin)
    waitms(10)
    pinhigh(spin) 'set the start/stop pin to 1 (start) for next time

    Best practice would be to connect the switch to the pin through a resistor to prevent pulling the pin to ground while the program is driving it high.

    I have also moved the 3 pins to a different group of outputs after learning that a shorted pin in outputs 24-31 could take out the power supply for the oscillator section thus bricking the p2.
    I hope this hasn't caused anyone a problem.
Sign In or Register to comment.