JBWolf
10-13-2011, 08:18 AM
Ok so first step was to make a unipolar stepper move in any direction with outa[4pins]~~
This was completed and works great, the phase steps are listed below and works perfectly for using 2 stepper motors to move in an up/down left/right fashion. I can get them both to move to any specific point in any direction, and hold that position for any specific amount of time before moving to the next. These positional movements seem to be very accurate without wavering motions in 'repeat' loops with a delay no less than waitcnt(clkfreq / 1800 + cnt)
DAT
HStep byte %1001, %1000, %1100, %0100, %0110, %0010, %0011, %0001 ' Half Step Phases
Next was to get a laser to turn on and off with a simple outa[laserpin]~~
This also works great using a custom laser driver... I find any delay of 100ms or less provides a perfectly visible pulse.
So now to combine the two.
Goal: Pre-define a "frame" to be drawn with the laser combined with motor movement
The general idea would be as simple as possible, define a grid and move through it turning on the laser as defined in the 'frame' variable. The frame variable defines the grid size, laser pulse time and amount of times to repeat each frame... plus the data that specifies which points to turn on the laser.
Details:
Frame DAT Structuring Format:
ID# = Frame ID starting at 0 for easy reference, no limit
Xsize = # of pixels on Xaxis, max = 20 Pixel spacing = .9deg
Ysize = # of pixels on Yaxis max = 20
LSR Dly = Laser Delay, Minimum speed = 100
FRM RPT = Amount of times to repeat a single frame
END = A value of 999 is the terminator to mark end of frame data. Must direclty follow last pixel data.
┌───────┬───────┬───────┬───────┬───────┬───────┬─ ──────┬───────┬───────┬....→ ┬──────────┐
Frame Long │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │....→ │ END Frame│
│ ID# │ Xsize │ Ysize │LSR Dly│FRM Rpt│ Xdata │ Ydata │ Xdata │ Ydata │....→ │ 999 │
└───────┴───────┴───────┴───────┴───────┴ Pixel 1 ┴ Pixel 2 ┘ └──────────┘
I got this to work with only 1 cog.
The program reads in the data from the 'frame' variable..... which pre-defines the amount of pixels/steps on the X and Y axis.
It then moves through the grid by starting at the top left (pixels 1x1), moves right until the max X grid size reached, steps down one to the new Y line, then goes back through the X line until max X grid size reached, steps down one to the new Y line... and repeats until all X & Y lines are completed.
It then repeats that 'frame' the amount of times specified in the 'Frame' variable.
This works using the code below, But... First of all this takes much too long between individual pixel movements.
I suspect this is because it rolls through the entire array of frame data to compare the current position against a match in the Frame data.
So in structuring the 'Frame' data, you can define pixels to turn on, anywhere in the data as it checks each 'current position' against all data in the 'frame' variable.
So to draw a 12x12 frame, it takes about 1/2 sec per frame.... this is super slow (2 frames per sec) and must be sped up by at least 5x
Next problem is:
I am not getting a single pixel, Instead I am getting a helix in certain spots, horizontal lines in others.
During initial testing, I was using long delay times... but I was able to move the motor to a point and pulse the laser. This gave a perfect display of a tiny laser dot on the wall at that point.
I cannot explain any of these problems ... if there are 80 million cycles per second, why is it taking 40 million to draw a single frame?
If the coding tells the motor to step right just one movement, why am I getting a helix?
I have isolated the platform that the laser & motors are mounted on, it cannot move/wobble. So I know for sure it is the motors causing this odd movement result.
The first attached picture is of the 'Frame' variable which is a 12x12 grid, data represents an X to be drawn from the four corners of the grid.
The second attached picture is of the 'Frame2' variable which is a 6x6 grid, data also represents an X to be drawn from the four corners of the grid.
For the pictures, I had to use a long exposure to capture all 'pixels' in the frame... the first picture (12x12 grid) is a double exposure, so you are actually seeing 2 frames drawn while the camera moves down and right a lil
Here is the frame data for both:
Frame Long 0, 12, 12, 100, 1000, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 1, 12, 2, 11, 3, 10, 4, 9, 5, 8, 6, 7, 7, 6, 8, 5, 9, 4, 10, 3, 11, 2, 12, 1, 999
Frame2 Long 1, 6, 6, 100, 1000, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 1, 6, 2, 5, 3, 4, 4, 3, 5, 2, 6, 1, 999
And here is the whole program:
You might notice delays of 4000 & 2000 in the 'draw frame' area of the program.... this is when I realized that it didn't matter what delay I used because the rest of the program took too long to execute.
You can see how these were eventually removed from the program with a remark char ( ' )... this made no visible difference in the draw speed
{{
TV Style
Dual stepper cog control for ULN 2003/2803 & galvo
motor 1 = pins 8-11 = Y Axis - DirY 1 = Down, 2 = Up
motor 2 = pins 12-15 = X Axis - DirX 1 = Left, 2 = Right (bottom motor)
Full Step & Wave = 1 revolution = 200 steps @ 1.8deg per step
Half Step = 1 revolution = 400 steps @ .9deg per step
Frame Processor set @ Half Step
Half Step Max Speed = 1800
Full Step Max Speed = 800
Weak Step Max Speed = 700
12step +/- max clearance from home position (true center) = 22deg max frame size.
************************************************** ************
Frame DAT Structuring Format:
ID# = Frame ID starting at 0 for easy reference, no limit
Xsize = # of pixels on Xaxis, max = 20 Pixel spacing = .9deg
Ysize = # of pixels on Yaxis max = 20
LSR Dly = Laser Delay, Minimum speed = 100
FRM RPT = Amount of times to repeat a single frame
END = A value of 999 is the terminator to mark end of frame data. Must directly follow last pixel data.
┌───────┬───────┬───────┬───────┬───────┬───────┬─ ──────┬───────┬───────┬....→ ┬──────────┐
Frame Long │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │....→ │ END Frame│
│ ID# │ Xsize │ Ysize │LSR Dly│FRM Rpt│ Xdata │ Ydata │ Xdata │ Ydata │....→ │ 999 │
└───────┴───────┴───────┴───────┴───────┴ Pixel 1 ┴ Pixel 2 ┘ └──────────┘
TO DO =
Do even X & Ysizes only work?
Launch Laser driver in new cog?
using percentage value for frame delay translation out of max 1700ms delay
((1700 * Frame[3]) / 100) = new delay
}}
CON
_clkmode = xtal1 + pll16x ' System clock → 80 MHz
_xinfreq = 5_000_000
TX_PIN = 2 ' LCD Pin ID
BAUD = 19_200 ' LCD Baud
LaserPin = 16
OBJ
LCD : "FullDuplexSerial.spin" ' LCD Object
VAR
long stack[2000] ' Cog stack space
byte cog[2] ' Cog ID
long up
long right
long down
long left ' Directional variables
long stpx, stpy
long Xpos, Ypos
PUB Main | Success
stpx := 0 ' Phase & position counters, DO NOT RESET
stpy := 0
Xpos := 0
Ypos := 0
InitVars
InitPins
InitLCD
Calibrate
'*********************$$$$$$$$$$$$$$$$$$$$$$ START MOVEMENT CALLS $$$$$$$$$$$$$$$$$$$$$$$*********
cls
waitcnt(clkfreq / 2 + cnt)
LCD.str(string("Movement Routines"))
Waitcnt(clkfreq + cnt)
Test1
'*********************$$$$$$$$$$$$$$$$$$$$$$ END MOVEMENT CALLS $$$$$$$$$$$$$$$$$$$$$$$$********
' StartFramePX ' Launches into new cog
Shutdown
' StopFramePX
'**********%%%%%%%%%%%%%%%%%%%% START MOVEMENT ROUTINES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*****
PUB Test1
initvars
FrameProcessor
'********%%%%%%%%%%%%%%%%%%%%%%% END MOVEMENT ROUTINES %%%%%%%%%%%%%%%%%%%%%%%%%%%%*************
'******************************* Start Galvo Controls *************************************
PUB Shutdown
cls
waitcnt(clkfreq / 2 + cnt)
LCD.tx(153) ' move to position 2 x 5
LCD.str(string("END"))
Waitcnt(clkfreq * 3 + cnt)
PUB initvars
up := 2 ' initialize variables
right := 2
down := 1
left := 1
PUB InitPins
dira[8..11]~~ ' Yaxis Motor
dira[12..15]~~ ' Xaxis Motor
dira[16]~~ ' Laser output
outa[16]~~ ' Laser OFF
PUB Calibrate | stp
stp := 0
repeat 65
outa[12..15] := WStep[stp]
outa[8..11] := WStep[stp]
waitcnt((clkfreq / 200) + cnt)
stp := stp + 1
if stp == 4
stp := 0
repeat 24
outa[12..15] := WStep[stp]
outa[8..11] := WStep[stp]
waitcnt((clkfreq / 200) + cnt)
stp := stp - 1
if stp == -1
stp := 3
stpx := (stp * 2) + 1 ' switch to hstep mode and initialize X
stpy := (stp * 2) + 1 ' switch to hstep mode and initialize Y
Waitcnt(clkfreq * 2 + cnt) ' 2 sec delay after calibrate
PUB StartFramePX | success
success := LaunchCOG
if success == 0 ' initialize outputs and start motors in cogs
LCD.str(string("FramePX Started on:" )) ' show if initialize was completed or not
NewLine
LCD.str(string("Cog#:"))
LCD.dec(cog[1])
else
LCD.str(string("Failure" ))
waitcnt(clkfreq * 3 + cnt)
PUB LaunchCOG : success
'cog[1] := cognew(FrameProcessor(@frame), @stack[1000]) ' Start Frame Processor
PUB StopFramePX
cogstop(cog[1]) ' Stop Frame Processor
' -------------------================ START MAIN CONTROL =================---------------------------
PUB Laser(state)
if state == 1
outa[LaserPin]~
if state == 0
outa[LaserPin]~~
PUB FrameProcessor | ID, Xsize, Ysize, LSRDelay, FRMrpt, Xtmp, Ytmp, FrameX[450], Counter1, Counter2, CounterX, FrameCount, Enable, ON, OFF, CR
FrameX[450] := 0
FrameCount := 0
LSRdelay := 0
FRMrpt := 0
Xsize := 0
Ysize := 0
Xpos := 0
Ypos := 0
Xtmp := 0
Ytmp := 0
ID := 0
Counter1 := 0
Counter2 := 0
CounterX := 0
Enable := 0
OFF := 0
ON := 1
CR := 0
'---------------------------------------------- Read in Frame data --------------------------------------------
repeat until FrameX[Counter1] == 999 ' -= FRAME DATA PARSING =-
FrameX[Counter1] := Long[@Frame][Counter1] ' Read in array
if FrameX[counter1] == 999 ' Check for END marker
FrameCount := ((Counter1 - 4) / 2) ' Strip header & halve count- Count data pairs only
else ' If no END marker
Counter1 := Counter1 + 1 ' Increment Counter
FrameX[Counter1] := 0 ' Initialize new Frame variable
ID := FrameX[0] ' Read Frame ID #
Xsize := FrameX[1] ' Read Xsize
Ysize := FrameX[2] ' Read Ysize
LSRDelay := FrameX[3] ' Read Laser Delay
FRMrpt := FrameX[4] ' Read Frame repeat count
Counter1 := 0 ' Re-init Counter for use
Xpos := Xsize / 2 ' Mark X center position in relation to max frame size
Ypos := Ysize / 2 ' Mark Y center position in relation to max frame size
'------------------------------------------------ Start Processing --------------------------------------------
repeat FRMrpt ' Amount of times to draw a single frame defined in Frame[4]
' MOVE TO 1x1 FRAME START POSITION
repeat until Ypos == 1 ' move UP to frame Y start position 1
stpy := stpy - 1 ' Increment Y step counter
if stpy == -1 ' If Y step counter out of bounds
stpy := 7 ' Reset Y step counter to proper phase
outa[8..11] := HStep[stpy] ' Send Phase step
waitcnt(clkfreq / 1700 + cnt) ' Minimum delay
Ypos := Ypos - 1 ' Mark new Y position
If Xpos > 1
repeat until Xpos == 1 ' Move to X position 1 if not already
stpx := stpx + 1
if stpx == 8
stpx := 0
outa[12..15] := HStep[stpx]
waitcnt(clkfreq / 1700 + cnt)
Xpos := Xpos - 1
'--------------------------------------------------== Draw Frame ==---------------------------------------
Counter1 := 0 ' Clear all counters
Counter2 := 0
CounterX := 0
CR := 0
repeat Ysize ' Repeat all Y lines
repeat Xsize ' Repeat all X lines
CounterX := CounterX + 1 ' Start counting current X pixels for size limits
Counter1 := 5 ' Set Counter to 5 for array use at Frame data start
Counter2 := 0 ' Set Counter to 0 for comparing with FrameCount
repeat until Enable == 1 '-Roll through array
Counter2 := Counter2 + 1 ' Track loop counter through data sets
Xtmp := FrameX[Counter1] ' Read X data
Counter1 := Counter1 + 1 ' Move array counter +1
Ytmp := FrameX[Counter1] ' Read Y data
Counter1 := Counter1 + 1 ' Move array counter +1
if Xtmp == Xpos and Ytmp == Ypos ' Check for position match
Laser(ON) ' Laser ON
waitcnt(clkfreq / LSRDelay + cnt) ' Laser time on delay
Laser(OFF) ' Laser OFF
Enable := 1 ' Exit repeat loop
elseif Counter2 == FrameCount ' If all data pairs checked without match
Enable := 1 ' Exit repeat loop
Enable := 0 ' Reset Variables to 0 for next use
Counter1 := 0
Counter2 := 0
if Xpos == Xsize and Ypos == Ysize ' If finished drawing frame
QUIT
if CounterX == Xsize ' If all pixels in line covered
stpy := stpy + 1 ' Step Y down 1
if stpy == 8
stpy := 0
outa[8..11] := HStep[stpy]
' waitcnt(clkfreq / 4000 + cnt) ' Minimum Delay
Ypos := Ypos + 1 ' Mark new Y position
CounterX := 0 ' Reset X pixel line counter
CR := CR + 1 ' Mark carriage return direction
if CR == 2 ' 1 = Left, 0 = Right
CR := 0
QUIT ' Exit this X line loop to avoid stepping out of bounds
if CR == 1 ' If at Right side, move Left
stpx := stpx + 1
if stpx == 8
stpx := 0
outa[12..15] := HStep[stpx] ' send phase pulse
' waitcnt(clkfreq / 4000 + cnt) ' set speed, max speed = H1800 F800 W700
Xpos := Xpos - 1 ' write counter to track new position
elseif CR == 0 ' If at Left side, move Right
stpx := stpx - 1
if stpx == -1
stpx := 7
outa[12..15] := HStep[stpx] ' send phase pulse
' waitcnt(clkfreq / 2000 + cnt) ' set speed, max speed = H1800 F800 W700
Xpos := Xpos + 1 ' write counter to track new position
if Xpos == Xsize and Ypos == Ysize ' If finished drawing frame
QUIT
'---------------------------------- Frame drawing complete - Return to center --------------------------------
repeat until Ypos == (Ysize / 2) ' Move Y from current position to center, assuming frame end is at Y+
stpy := stpy - 1
if stpy == -1
stpy := 7
outa[8..11] := HStep[stpy]
waitcnt(clkfreq / 1700 + cnt)
Ypos := Ypos - 1
If Xpos > (Xsize / 2)
repeat until Xpos == (Xsize / 2) ' Move X from current position to center by moving left
stpx := stpx + 1
if stpx == 8
stpx := 0
outa[12..15] := HStep[stpx]
waitcnt(clkfreq / 1700 + cnt)
Xpos := Xpos - 1
elseif Xpos < (Xsize / 2)
repeat until Xpos == (Xsize / 2) ' Move X from current position to center by moving left
stpx := stpx - 1
if stpx == -1
stpx := 7
outa[12..15] := HStep[stpx]
waitcnt(clkfreq / 1700 + cnt)
Xpos := Xpos + 1
'---------------------========================= END PROCESSOR ===================-----------------------------
'******************************* End Galvo Controls ***********************************
'******************************* Start LCD Commands ***********************************
PUB InitLCD
LCD.start(TX_PIN, TX_PIN, %1000, 19_200) ' initialize LCD
waitcnt(clkfreq / 100 + cnt)
BKLon ' Turn on LCD BackLight
CLS
waitcnt(clkfreq / 20 + cnt)
PUB Newline
LCD.tx(13)
pub NextLine
LCD.tx(10)
PUB CLS
LCD.tx(12)
waitcnt(clkfreq /500 + cnt)
PUB Back (n)
repeat n
LCD.tx(8)
PUB BKLon
LCD.tx(17)
PUB BKLoff
LCD.tx(18)
PUB BlinkON
LCD.tx(23)
PUB Default
LCD.tx(24)
PUB NoCursor
LCD.tx(22)
PUB LCDoff
LCD.tx(21)
'********************************* End LCD Commands ***********************************
DAT
HStep byte %1001, %1000, %1100, %0100, %0110, %0010, %0011, %0001 ' Half Step - best resolution
FStep byte %1001, %1100, %0110, %0011 ' Full Step - max torque
WStep byte %1000, %0100, %0010, %0001 ' Wave Step - weak torque
Frame Long 0, 12, 12, 100, 1000, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 1, 12, 2, 11, 3, 10, 4, 9, 5, 8, 6, 7, 7, 6, 8, 5, 9, 4, 10, 3, 11, 2, 12, 1, 999 ' First Frame data
Frame2 Long 1, 6, 6, 100, 1000, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 1, 6, 2, 5, 3, 4, 4, 3, 5, 2, 6, 1, 999
Goals:
#1 Speed up each frame to a minimum of 10 per second
#2 Make pixels a single 'dot', not helix's and horizontal lines
PS - Accomplishing this task was the sole motivator behind purchasing and learning how to use the propeller.
I am still new to the prop and have tons to learn, I am not asking for someone to do my work, rather someone to guide my next step... I am kind of stuck at this point.
I need to figure out how to utilize the other processors to speed up this program, or how to re-write the program more efficiently to meet all goals.
I realize the motor problem with the helix movements may be conditional to my particular steppers... which is why I will address this last
I sincerely appreciate any help :)
And credits to those who have already helped with this project (Beau Schwabe, kuroneko, Mike Green, cluso99, MindRobots) , Thank you!
(http://forums.parallax.com/member.php?41345-Beau-Schwabe-%28Parallax%29)
This was completed and works great, the phase steps are listed below and works perfectly for using 2 stepper motors to move in an up/down left/right fashion. I can get them both to move to any specific point in any direction, and hold that position for any specific amount of time before moving to the next. These positional movements seem to be very accurate without wavering motions in 'repeat' loops with a delay no less than waitcnt(clkfreq / 1800 + cnt)
DAT
HStep byte %1001, %1000, %1100, %0100, %0110, %0010, %0011, %0001 ' Half Step Phases
Next was to get a laser to turn on and off with a simple outa[laserpin]~~
This also works great using a custom laser driver... I find any delay of 100ms or less provides a perfectly visible pulse.
So now to combine the two.
Goal: Pre-define a "frame" to be drawn with the laser combined with motor movement
The general idea would be as simple as possible, define a grid and move through it turning on the laser as defined in the 'frame' variable. The frame variable defines the grid size, laser pulse time and amount of times to repeat each frame... plus the data that specifies which points to turn on the laser.
Details:
Frame DAT Structuring Format:
ID# = Frame ID starting at 0 for easy reference, no limit
Xsize = # of pixels on Xaxis, max = 20 Pixel spacing = .9deg
Ysize = # of pixels on Yaxis max = 20
LSR Dly = Laser Delay, Minimum speed = 100
FRM RPT = Amount of times to repeat a single frame
END = A value of 999 is the terminator to mark end of frame data. Must direclty follow last pixel data.
┌───────┬───────┬───────┬───────┬───────┬───────┬─ ──────┬───────┬───────┬....→ ┬──────────┐
Frame Long │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │....→ │ END Frame│
│ ID# │ Xsize │ Ysize │LSR Dly│FRM Rpt│ Xdata │ Ydata │ Xdata │ Ydata │....→ │ 999 │
└───────┴───────┴───────┴───────┴───────┴ Pixel 1 ┴ Pixel 2 ┘ └──────────┘
I got this to work with only 1 cog.
The program reads in the data from the 'frame' variable..... which pre-defines the amount of pixels/steps on the X and Y axis.
It then moves through the grid by starting at the top left (pixels 1x1), moves right until the max X grid size reached, steps down one to the new Y line, then goes back through the X line until max X grid size reached, steps down one to the new Y line... and repeats until all X & Y lines are completed.
It then repeats that 'frame' the amount of times specified in the 'Frame' variable.
This works using the code below, But... First of all this takes much too long between individual pixel movements.
I suspect this is because it rolls through the entire array of frame data to compare the current position against a match in the Frame data.
So in structuring the 'Frame' data, you can define pixels to turn on, anywhere in the data as it checks each 'current position' against all data in the 'frame' variable.
So to draw a 12x12 frame, it takes about 1/2 sec per frame.... this is super slow (2 frames per sec) and must be sped up by at least 5x
Next problem is:
I am not getting a single pixel, Instead I am getting a helix in certain spots, horizontal lines in others.
During initial testing, I was using long delay times... but I was able to move the motor to a point and pulse the laser. This gave a perfect display of a tiny laser dot on the wall at that point.
I cannot explain any of these problems ... if there are 80 million cycles per second, why is it taking 40 million to draw a single frame?
If the coding tells the motor to step right just one movement, why am I getting a helix?
I have isolated the platform that the laser & motors are mounted on, it cannot move/wobble. So I know for sure it is the motors causing this odd movement result.
The first attached picture is of the 'Frame' variable which is a 12x12 grid, data represents an X to be drawn from the four corners of the grid.
The second attached picture is of the 'Frame2' variable which is a 6x6 grid, data also represents an X to be drawn from the four corners of the grid.
For the pictures, I had to use a long exposure to capture all 'pixels' in the frame... the first picture (12x12 grid) is a double exposure, so you are actually seeing 2 frames drawn while the camera moves down and right a lil
Here is the frame data for both:
Frame Long 0, 12, 12, 100, 1000, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 1, 12, 2, 11, 3, 10, 4, 9, 5, 8, 6, 7, 7, 6, 8, 5, 9, 4, 10, 3, 11, 2, 12, 1, 999
Frame2 Long 1, 6, 6, 100, 1000, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 1, 6, 2, 5, 3, 4, 4, 3, 5, 2, 6, 1, 999
And here is the whole program:
You might notice delays of 4000 & 2000 in the 'draw frame' area of the program.... this is when I realized that it didn't matter what delay I used because the rest of the program took too long to execute.
You can see how these were eventually removed from the program with a remark char ( ' )... this made no visible difference in the draw speed
{{
TV Style
Dual stepper cog control for ULN 2003/2803 & galvo
motor 1 = pins 8-11 = Y Axis - DirY 1 = Down, 2 = Up
motor 2 = pins 12-15 = X Axis - DirX 1 = Left, 2 = Right (bottom motor)
Full Step & Wave = 1 revolution = 200 steps @ 1.8deg per step
Half Step = 1 revolution = 400 steps @ .9deg per step
Frame Processor set @ Half Step
Half Step Max Speed = 1800
Full Step Max Speed = 800
Weak Step Max Speed = 700
12step +/- max clearance from home position (true center) = 22deg max frame size.
************************************************** ************
Frame DAT Structuring Format:
ID# = Frame ID starting at 0 for easy reference, no limit
Xsize = # of pixels on Xaxis, max = 20 Pixel spacing = .9deg
Ysize = # of pixels on Yaxis max = 20
LSR Dly = Laser Delay, Minimum speed = 100
FRM RPT = Amount of times to repeat a single frame
END = A value of 999 is the terminator to mark end of frame data. Must directly follow last pixel data.
┌───────┬───────┬───────┬───────┬───────┬───────┬─ ──────┬───────┬───────┬....→ ┬──────────┐
Frame Long │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │....→ │ END Frame│
│ ID# │ Xsize │ Ysize │LSR Dly│FRM Rpt│ Xdata │ Ydata │ Xdata │ Ydata │....→ │ 999 │
└───────┴───────┴───────┴───────┴───────┴ Pixel 1 ┴ Pixel 2 ┘ └──────────┘
TO DO =
Do even X & Ysizes only work?
Launch Laser driver in new cog?
using percentage value for frame delay translation out of max 1700ms delay
((1700 * Frame[3]) / 100) = new delay
}}
CON
_clkmode = xtal1 + pll16x ' System clock → 80 MHz
_xinfreq = 5_000_000
TX_PIN = 2 ' LCD Pin ID
BAUD = 19_200 ' LCD Baud
LaserPin = 16
OBJ
LCD : "FullDuplexSerial.spin" ' LCD Object
VAR
long stack[2000] ' Cog stack space
byte cog[2] ' Cog ID
long up
long right
long down
long left ' Directional variables
long stpx, stpy
long Xpos, Ypos
PUB Main | Success
stpx := 0 ' Phase & position counters, DO NOT RESET
stpy := 0
Xpos := 0
Ypos := 0
InitVars
InitPins
InitLCD
Calibrate
'*********************$$$$$$$$$$$$$$$$$$$$$$ START MOVEMENT CALLS $$$$$$$$$$$$$$$$$$$$$$$*********
cls
waitcnt(clkfreq / 2 + cnt)
LCD.str(string("Movement Routines"))
Waitcnt(clkfreq + cnt)
Test1
'*********************$$$$$$$$$$$$$$$$$$$$$$ END MOVEMENT CALLS $$$$$$$$$$$$$$$$$$$$$$$$********
' StartFramePX ' Launches into new cog
Shutdown
' StopFramePX
'**********%%%%%%%%%%%%%%%%%%%% START MOVEMENT ROUTINES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*****
PUB Test1
initvars
FrameProcessor
'********%%%%%%%%%%%%%%%%%%%%%%% END MOVEMENT ROUTINES %%%%%%%%%%%%%%%%%%%%%%%%%%%%*************
'******************************* Start Galvo Controls *************************************
PUB Shutdown
cls
waitcnt(clkfreq / 2 + cnt)
LCD.tx(153) ' move to position 2 x 5
LCD.str(string("END"))
Waitcnt(clkfreq * 3 + cnt)
PUB initvars
up := 2 ' initialize variables
right := 2
down := 1
left := 1
PUB InitPins
dira[8..11]~~ ' Yaxis Motor
dira[12..15]~~ ' Xaxis Motor
dira[16]~~ ' Laser output
outa[16]~~ ' Laser OFF
PUB Calibrate | stp
stp := 0
repeat 65
outa[12..15] := WStep[stp]
outa[8..11] := WStep[stp]
waitcnt((clkfreq / 200) + cnt)
stp := stp + 1
if stp == 4
stp := 0
repeat 24
outa[12..15] := WStep[stp]
outa[8..11] := WStep[stp]
waitcnt((clkfreq / 200) + cnt)
stp := stp - 1
if stp == -1
stp := 3
stpx := (stp * 2) + 1 ' switch to hstep mode and initialize X
stpy := (stp * 2) + 1 ' switch to hstep mode and initialize Y
Waitcnt(clkfreq * 2 + cnt) ' 2 sec delay after calibrate
PUB StartFramePX | success
success := LaunchCOG
if success == 0 ' initialize outputs and start motors in cogs
LCD.str(string("FramePX Started on:" )) ' show if initialize was completed or not
NewLine
LCD.str(string("Cog#:"))
LCD.dec(cog[1])
else
LCD.str(string("Failure" ))
waitcnt(clkfreq * 3 + cnt)
PUB LaunchCOG : success
'cog[1] := cognew(FrameProcessor(@frame), @stack[1000]) ' Start Frame Processor
PUB StopFramePX
cogstop(cog[1]) ' Stop Frame Processor
' -------------------================ START MAIN CONTROL =================---------------------------
PUB Laser(state)
if state == 1
outa[LaserPin]~
if state == 0
outa[LaserPin]~~
PUB FrameProcessor | ID, Xsize, Ysize, LSRDelay, FRMrpt, Xtmp, Ytmp, FrameX[450], Counter1, Counter2, CounterX, FrameCount, Enable, ON, OFF, CR
FrameX[450] := 0
FrameCount := 0
LSRdelay := 0
FRMrpt := 0
Xsize := 0
Ysize := 0
Xpos := 0
Ypos := 0
Xtmp := 0
Ytmp := 0
ID := 0
Counter1 := 0
Counter2 := 0
CounterX := 0
Enable := 0
OFF := 0
ON := 1
CR := 0
'---------------------------------------------- Read in Frame data --------------------------------------------
repeat until FrameX[Counter1] == 999 ' -= FRAME DATA PARSING =-
FrameX[Counter1] := Long[@Frame][Counter1] ' Read in array
if FrameX[counter1] == 999 ' Check for END marker
FrameCount := ((Counter1 - 4) / 2) ' Strip header & halve count- Count data pairs only
else ' If no END marker
Counter1 := Counter1 + 1 ' Increment Counter
FrameX[Counter1] := 0 ' Initialize new Frame variable
ID := FrameX[0] ' Read Frame ID #
Xsize := FrameX[1] ' Read Xsize
Ysize := FrameX[2] ' Read Ysize
LSRDelay := FrameX[3] ' Read Laser Delay
FRMrpt := FrameX[4] ' Read Frame repeat count
Counter1 := 0 ' Re-init Counter for use
Xpos := Xsize / 2 ' Mark X center position in relation to max frame size
Ypos := Ysize / 2 ' Mark Y center position in relation to max frame size
'------------------------------------------------ Start Processing --------------------------------------------
repeat FRMrpt ' Amount of times to draw a single frame defined in Frame[4]
' MOVE TO 1x1 FRAME START POSITION
repeat until Ypos == 1 ' move UP to frame Y start position 1
stpy := stpy - 1 ' Increment Y step counter
if stpy == -1 ' If Y step counter out of bounds
stpy := 7 ' Reset Y step counter to proper phase
outa[8..11] := HStep[stpy] ' Send Phase step
waitcnt(clkfreq / 1700 + cnt) ' Minimum delay
Ypos := Ypos - 1 ' Mark new Y position
If Xpos > 1
repeat until Xpos == 1 ' Move to X position 1 if not already
stpx := stpx + 1
if stpx == 8
stpx := 0
outa[12..15] := HStep[stpx]
waitcnt(clkfreq / 1700 + cnt)
Xpos := Xpos - 1
'--------------------------------------------------== Draw Frame ==---------------------------------------
Counter1 := 0 ' Clear all counters
Counter2 := 0
CounterX := 0
CR := 0
repeat Ysize ' Repeat all Y lines
repeat Xsize ' Repeat all X lines
CounterX := CounterX + 1 ' Start counting current X pixels for size limits
Counter1 := 5 ' Set Counter to 5 for array use at Frame data start
Counter2 := 0 ' Set Counter to 0 for comparing with FrameCount
repeat until Enable == 1 '-Roll through array
Counter2 := Counter2 + 1 ' Track loop counter through data sets
Xtmp := FrameX[Counter1] ' Read X data
Counter1 := Counter1 + 1 ' Move array counter +1
Ytmp := FrameX[Counter1] ' Read Y data
Counter1 := Counter1 + 1 ' Move array counter +1
if Xtmp == Xpos and Ytmp == Ypos ' Check for position match
Laser(ON) ' Laser ON
waitcnt(clkfreq / LSRDelay + cnt) ' Laser time on delay
Laser(OFF) ' Laser OFF
Enable := 1 ' Exit repeat loop
elseif Counter2 == FrameCount ' If all data pairs checked without match
Enable := 1 ' Exit repeat loop
Enable := 0 ' Reset Variables to 0 for next use
Counter1 := 0
Counter2 := 0
if Xpos == Xsize and Ypos == Ysize ' If finished drawing frame
QUIT
if CounterX == Xsize ' If all pixels in line covered
stpy := stpy + 1 ' Step Y down 1
if stpy == 8
stpy := 0
outa[8..11] := HStep[stpy]
' waitcnt(clkfreq / 4000 + cnt) ' Minimum Delay
Ypos := Ypos + 1 ' Mark new Y position
CounterX := 0 ' Reset X pixel line counter
CR := CR + 1 ' Mark carriage return direction
if CR == 2 ' 1 = Left, 0 = Right
CR := 0
QUIT ' Exit this X line loop to avoid stepping out of bounds
if CR == 1 ' If at Right side, move Left
stpx := stpx + 1
if stpx == 8
stpx := 0
outa[12..15] := HStep[stpx] ' send phase pulse
' waitcnt(clkfreq / 4000 + cnt) ' set speed, max speed = H1800 F800 W700
Xpos := Xpos - 1 ' write counter to track new position
elseif CR == 0 ' If at Left side, move Right
stpx := stpx - 1
if stpx == -1
stpx := 7
outa[12..15] := HStep[stpx] ' send phase pulse
' waitcnt(clkfreq / 2000 + cnt) ' set speed, max speed = H1800 F800 W700
Xpos := Xpos + 1 ' write counter to track new position
if Xpos == Xsize and Ypos == Ysize ' If finished drawing frame
QUIT
'---------------------------------- Frame drawing complete - Return to center --------------------------------
repeat until Ypos == (Ysize / 2) ' Move Y from current position to center, assuming frame end is at Y+
stpy := stpy - 1
if stpy == -1
stpy := 7
outa[8..11] := HStep[stpy]
waitcnt(clkfreq / 1700 + cnt)
Ypos := Ypos - 1
If Xpos > (Xsize / 2)
repeat until Xpos == (Xsize / 2) ' Move X from current position to center by moving left
stpx := stpx + 1
if stpx == 8
stpx := 0
outa[12..15] := HStep[stpx]
waitcnt(clkfreq / 1700 + cnt)
Xpos := Xpos - 1
elseif Xpos < (Xsize / 2)
repeat until Xpos == (Xsize / 2) ' Move X from current position to center by moving left
stpx := stpx - 1
if stpx == -1
stpx := 7
outa[12..15] := HStep[stpx]
waitcnt(clkfreq / 1700 + cnt)
Xpos := Xpos + 1
'---------------------========================= END PROCESSOR ===================-----------------------------
'******************************* End Galvo Controls ***********************************
'******************************* Start LCD Commands ***********************************
PUB InitLCD
LCD.start(TX_PIN, TX_PIN, %1000, 19_200) ' initialize LCD
waitcnt(clkfreq / 100 + cnt)
BKLon ' Turn on LCD BackLight
CLS
waitcnt(clkfreq / 20 + cnt)
PUB Newline
LCD.tx(13)
pub NextLine
LCD.tx(10)
PUB CLS
LCD.tx(12)
waitcnt(clkfreq /500 + cnt)
PUB Back (n)
repeat n
LCD.tx(8)
PUB BKLon
LCD.tx(17)
PUB BKLoff
LCD.tx(18)
PUB BlinkON
LCD.tx(23)
PUB Default
LCD.tx(24)
PUB NoCursor
LCD.tx(22)
PUB LCDoff
LCD.tx(21)
'********************************* End LCD Commands ***********************************
DAT
HStep byte %1001, %1000, %1100, %0100, %0110, %0010, %0011, %0001 ' Half Step - best resolution
FStep byte %1001, %1100, %0110, %0011 ' Full Step - max torque
WStep byte %1000, %0100, %0010, %0001 ' Wave Step - weak torque
Frame Long 0, 12, 12, 100, 1000, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 1, 12, 2, 11, 3, 10, 4, 9, 5, 8, 6, 7, 7, 6, 8, 5, 9, 4, 10, 3, 11, 2, 12, 1, 999 ' First Frame data
Frame2 Long 1, 6, 6, 100, 1000, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 1, 6, 2, 5, 3, 4, 4, 3, 5, 2, 6, 1, 999
Goals:
#1 Speed up each frame to a minimum of 10 per second
#2 Make pixels a single 'dot', not helix's and horizontal lines
PS - Accomplishing this task was the sole motivator behind purchasing and learning how to use the propeller.
I am still new to the prop and have tons to learn, I am not asking for someone to do my work, rather someone to guide my next step... I am kind of stuck at this point.
I need to figure out how to utilize the other processors to speed up this program, or how to re-write the program more efficiently to meet all goals.
I realize the motor problem with the helix movements may be conditional to my particular steppers... which is why I will address this last
I sincerely appreciate any help :)
And credits to those who have already helped with this project (Beau Schwabe, kuroneko, Mike Green, cluso99, MindRobots) , Thank you!
(http://forums.parallax.com/member.php?41345-Beau-Schwabe-%28Parallax%29)