My board will be ready soon and this will be the first project for it. Because pinout is different than the one from first version, it needs also a new hardware(shield), not only the firmware. So, it needed a separate html page.
Schematic: Compatible with all FreeJALduino boards.
Firmware: Compatible with FreeJALduino and FreeJALduino5 boards
This will be in top of every page using this board, as a reminder and easy access.
-- Project: XYZ CNC Router on USB using FreeJALduino board-- Author: Vasile Guta-Ciucur (funlw65)-- License: Code released under New BSD license-- For jallib libraries, see de licence inside jal.zip-- This is first variant, where steppers are connected to the board.-- No gcode interpreter inside, sorry - this is left for PC Host App.include freejalduino4 -- FreeJALduino4 pinout layer for the last board model-- include librariesinclude usb_serialinclude print-- include formatinclude delay-- setup()-- var and const definitionsconst byte str1[] = "XYZCNC-USB Firmware Nov17, 2009\r\n"const byte str2[] = "Copyright 2009 by Vasile Guta-Ciucur.\r\n"const byte hsteps[] = { -- half-steps buffer 0b_0000_0001, 0b_0000_0011, 0b_0000_0010, 0b_0000_0110, 0b_0000_0100, 0b_0000_1100, 0b_0000_1000, 0b_0000_1001 }const byte fsteps[] = { -- full-steps buffer, high torque 0b_0000_0101, 0b_0000_0110, 0b_0000_1010, 0b_0000_1001, 0b_0000_0101, 0b_0000_0110, 0b_0000_1010, 0b_0000_1001 }var byte csteps[ 8 ] -- this array will contain settings for -- half or full seps, according to "step type" jumper.var byte speed_s[ 36 ] -- string for speed setupvar byte movement_s[ 36 ] -- string for xyz movementvar byte speed_str[ 11 ] -- buffer for speed valuevar sbyte memx, memy, memz -- current step for x,y,z axisvar byte i, j -- used as index for cyclesvar dword step_speed -- speed per step in microsecondsvar byte t_delay -- the type of delay (micro, milli, nano)-- end var and const definitions-- procedures and functions-- convert string to dwordfunction strtodec(byte in str[ 11 ]) return dword is var dword tempres var byte i -- tempres = 0 i = 0 repeat tempres = tempres * 10 + (str[i] - "0") i = i + 1 until str[i] == 0 return tempresend function-- process setup string and set the speedprocedure process_and_set is i = 0 t_delay = speed_s[i] i = 1 repeat speed_str[i - 1] = speed_s[i] i = i + 1 until speed_s[i] == "/" speed_str[i - 1] = 0 step_speed = strtodec(speed_str) usb_serial_flush()end procedure-- check the limits or stop pressedprocedure emerge is if (D11 == LOW) then -- if CRASH or STOP or PAUSE D12 = LOW -- power off steppers D18 = HIGH -- power on CRASH LED indicator usb_serial_data = "W" -- send warning char "W" repeat -- repeat ... usb_serial_flush() -- (we must keep USB conn. active) until D0 == LOW -- ... till "Resume" switch is pressed -- or board is reset because you have a limit reached D18 = LOW -- switch off CRASH LED D12 = HIGH -- power on steppers usb_serial_data = "R" -- send "Resume" char "R" usb_serial_flush() end ifend procedure-- end check the limits or stop pressed-- move one step on xyz axis, both directions, and then,-- check if limit reached or stop pressedprocedure x_step_up is memx = memx + 1 if memx > 7 then memx = 0 end if PORTA_low = csteps[memx] emerge()end procedureprocedure x_step_down is memx = memx - 1 if memx < 0 then memx = 7 end if PORTA_low = csteps[memx] emerge()end procedureprocedure y_step_up is memy = memy + 1 if memy > 7 then memy = 0 end if PORTB_high = csteps[memy] emerge()end procedureprocedure y_step_down is memy = memy - 1 if memy < 0 then memy = 7 end if PORTB_high = csteps[memy] emerge()end procedureprocedure z_step_up is memz = memz + 1 if memz > 7 then memz = 0 end if PORTB_low = csteps[memz] emerge()end procedureprocedure z_step_down is memz = memz - 1 if memz < 0 then memz = 7 end if PORTB_low = csteps[memz] emerge()end procedure-- end one step on xyz axis, both directions-- process movement string and move axisprocedure process_and_run is var bit dirx, diry, dirz -- direction on x,y,z axis (0,1) var byte stage-- containers for the number of steps as string, null terminated-- remember me to make routines to clean these arrays - DONE! var byte x_step_str[ 11 ] var byte y_step_str[ 11 ] var byte z_step_str[ 11 ] var dword m, k, x_steps, y_steps, z_steps -- the number of steps on xyz axis usb_serial_flush()-- initialize the number of steps on xyz axis x_steps = 0 y_steps = 0 z_steps = 0 -- preparing the strings -- for 11 using i loop -- x_step_str[i] = 0 -- y_step_str[i] = 0 -- z_step_str[i] = 0 -- end loop i = 0 j = 0 stage = 1 -- extract the numbers and direction for each axis repeat if stage == 1 then repeat if movement_s[i] == "X" then dirx = 1 elsif movement_s[i] == "x" then dirx = 0 else x_step_str[j] = movement_s[i] j = j + 1 end if i = i + 1 until ((movement_s[i] == "Y") | (movement_s[i] == "y")) stage = 2 x_step_str[j + 1] = 0 j = 0 end if if stage == 2 then repeat if movement_s[i] == "Y" then diry = 1 elsif movement_s[i] == "y" then diry = 0 else y_step_str[j] = movement_s[i] j = j + 1 end if i = i + 1 until ((movement_s[i] == "Z") | (movement_s[i] == "z")) stage = 3 y_step_str[j + 1] = 0 j = 0 end if if stage == 3 then repeat if movement_s[i] == "Z" then dirz = 1 elsif movement_s[i] == "z" then dirz = 0 else z_step_str[j] = movement_s[i] j = j + 1 end if i = i + 1 until movement_s[i] == "/" z_step_str[j + 1] = 0 j = 0 end if until movement_s[i] == "/" usb_serial_flush() -- Next: -- convert x dword x_steps = strtodec(x_step_str) -- convert y dword y_steps = strtodec(y_step_str) -- convert z dword z_steps = strtodec(z_step_str) -- see which one is bigger and that will lead the for cycle if (x_steps > y_steps) then if (x_steps > z_steps) then k = x_steps else k = z_steps end if else if (y_steps > z_steps) then k = y_steps else k = z_steps end if end if -- DO THE STEPS for k using m loop -- if (m + 1) <= x_steps then if dirx == 1 then x_step_up() else x_step_down() end if end if if (m + 1) <= y_steps then if diry == 1 then y_step_up() else y_step_down() end if end if if (m + 1) <= z_steps then if dirz == 1 then z_step_up() else z_step_down() end if end if -- here goes the desired delay between steps if t_delay == "U" then for step_speed loop delay_1us() end loop else delay_1ms(step_speed) end if usb_serial_flush() end loopend procedure -- end of the best procedure-- hope you like it :-D-- end procedures and functions-- ==================================================-- PROGRAM START -------------------------------------- ==================================================-- configure pinsenable_digital_io() -- first, all pins set to digital-- Then, setting direction (input/output)-- We should do something like this:-- PORTA_direction = OUTPUT-- PORTB_direction = OUTPUT-- but we do it Arduino style for newbiesD0_direction = INPUT -- RX, used for "resume" switchD1_direction = OUTPUT -- TX, "CNC on operation" LED indicatorD2_direction = OUTPUT -- Boot LED indicator--D3_direction = OUTPUT -- L1 - z axis - this is PORTB_lowD4_direction = OUTPUT -- L2 - z axisD5_direction = OUTPUT -- L3 - z axisD6_direction = OUTPUT -- L4 - z axis--D7_direction = OUTPUT -- L1 - y axis - this is PORTB_highD8_direction = OUTPUT -- L2 - y axisD9_direction = OUTPUT -- L3 - y axisD10_direction = OUTPUT -- L4 - y axis--D11_direction = INPUT -- xyz limits and emergency stopD12_direction = OUTPUT -- Steppers power on/off relayD13_direction = INPUT -- (full/half step) jumper--D14_direction = OUTPUT -- L1 - x axis - this is PORTA_lowD15_direction = OUTPUT -- L2 - x axisD16_direction = OUTPUT -- L3 - x axisD17_direction = OUTPUT -- L4 - x axis--D18_direction = OUTPUT -- CRASH LED (red) - emergency stop or limit reached-- equivalent to :-- pinMode(D19_direction, OUTPUT)-- assure that steppers are not powered-- a good thing is to have a second switch in seriesD12 = LOW -- and that "Breakdown" red LED is offD18 = LOW-- Operation LED offD1 = LOW-- default values-- initialize index for step buffermemx = 0memy = 0memz = 0t_delay = "M" -- the type of delay (milliseconds in this case)step_speed = 10 -- milliseconds-- read the step style jumper and-- set step array values accordinglyif D13 == 1 then for 8 using i loop csteps[i] = fsteps[i] end loopelse for 8 using i loop csteps[i] = hsteps[i] end loopend if-- "Load" the steper coilsPORTA_low = csteps[memx]PORTB_low = csteps[memz]PORTB_high = csteps[memy]-- power the steppersD12 = HIGH-- initialize the USB serial libraryusb_serial_init()-- optionally wait till USB becomes available--while ( usb_cdc_line_status() == 0x00 ) loop--end loop-- Albert, this one is not working :( , I disabled it...-- Just to be sure (bootloader switch off this LED anyway)D2 = LOW-- end setup()-- main loopforever loop var byte ch -- Service USB, call on a regular base to keep communcaiton going usb_serial_flush() -- check for input character if usb_serial_read( ch ) then if ch == "?" then print_string( usb_serial_data, str1 ) print_string( usb_serial_data, str2 ) elsif ch == "A" then -- X axis x_step_up() elsif ch == "a" then x_step_down() elsif ch == "S" then -- Y axis y_step_up() elsif ch == "s" then y_step_down() elsif ch == "D" then -- z axis z_step_up() elsif ch == "d" then z_step_down() elsif ch == "<" then -- a setup string is receiving j = 0 D1 = HIGH -- light the operation LED repeat usb_serial_flush() if usb_serial_read( ch ) then if ch != "/" then speed_s[j] = ch j = j + 1 if j == 35 then -- protection against malformed string ch = "/" end if end if speed_s[j] = "/" end if until ch == "/" -- go to evaluate string and set the speed process_and_set() D1 = LOW -- switch off the operation LED usb_serial_data = "O" -- send "OK" to PC usb_serial_flush() elsif ch == ">" then -- a movement string is receiving j = 0 D1 = HIGH -- light the operation LED repeat usb_serial_flush() if usb_serial_read( ch ) then if ch != "/" then movement_s[j] = ch j = j + 1 if j == 35 then -- protection against malformed string ch = "/" end if end if movement_s[j] = ch end if until ch == "/" -- go to evaluate string and start movement process_and_run() D1 = LOW -- switch off the operation LED usb_serial_data = "O" -- send "OK" to PC usb_serial_flush() else usb_serial_flush() end if end if -- we check limits or emergency stop emerge()end loop--The firmware is very basic but hopefully, fast enough (can be considered a basic but efficient engine). If this firmware is used with my FreeJALduino board, at start, the bootloader will wait for 10 seconds and then will start the application. Until then, no lighted LED's. At start, the steppers will be powered and a blue LED will signal that the board is ready to receive data from USB. A default speed of 10 milliseconds delay per step (useful for testings) will be considered. Firmware will check the jumper (the jumper from breadboard or shield and not the one from FreeJALduino board) and will choose between full step and half step.
The firmware have two levels at listening for characters on USB Serial interface.
1. - First level. At this level you can send characters for manually moving axis step by step on both directions, allowing fine (manual) positioning. The characters are:
2. - Second level. At this level, firmware is waiting for an entire string terminated with forward slash character. Then will proceed with processing the string and setting the movement speed or start movement. A LED will be lighted for signaling that the firmware is in the second level. So, this level have two modes, speed setup mode and movement mode:
-- Speed setup mode, determined by "<" char from the first level. You can set de delay between steps starting from 10 microseconds. Here I must give some detailed explanations. The firmware is made in JAL language and here I found two delay procedures which can be used: delay_10us(byte) and delay_1ms(word).
For delay_10us(byte) parameter is byte and means can be up to 255 and is incremented by 10. So you will have this formula: delay = n * 10 microseconds - where n is your byte parameter. If microseconds are required, the setup string will start with "U" character. Example:
U12/ - mean 120 microseconds delay between steps
(around 8000 rpm?)
For delay_1ms(word) parameter is word and means can be up to 65535 (no useful to have that maximum delay :-P) and is incremented by 1 millisecond, no weird formula needed, what you get is what you give. So, if milliseconds are required, then the first character from string must be "M". Example:
M10/ - means 10 milliseconds delay between steps
(see the forward slash that will end the string ).
Maybe I will make my own delay_us(word) procedure with a normal increment by 1 microsecond ... The speed setup will remain until you will give another speed setup. After speed is set, the firmware will return at the first level of listening.
-- Movement mode, determined by ">" char from the first level. Here is simple. Examples:
X40Y0Z0/ - means 40 steps on X axis at right direction
X0y40Z0/ - means 40 steps on Y axis at left direction
X0Y0Z40/ - means 40 steps on Z axis at right (up) direction
X40Y40Z0/
In this case it means 40 steps on X axis and 40 steps on Y axis,
drawing a straight line at 45 degrees (only if you have same setup on both axis,
else use it only for movement and not for routing). The movement is one step
on X axis and one step on Y axis at a time.
Of course you can move all axis at once if is needed. Again, the maximum number
of steps which you can give is a longword or doubleword which mean
4,294,967,295.
Of course is huge and at 10 microseconds delay between steps, it will last
more than a year to finish the movement but a maximum of 65535 steps at once was
not enough.
The type of char (uppercase or not) will determine the
direction on that axis (e.g., X for right and x for left).
At every step, the limit reached or pause is tested. After the operation is finished, the firmware will return in the first level of listening.
Well, it will be never obsoleted because it contains no g-code (which must be upgraded or worse, corrected), no CNC setups. All g-code translation and the required interpolations are made by the PC host application. So, you can use the firmware without bootloader if you want (but not the .hex file from attachments, which require bootloader).
....
....