diff --git a/config.h b/config.h index aad11c3..e46aa81 100644 --- a/config.h +++ b/config.h @@ -34,9 +34,9 @@ // Serial baud rate #define BAUD_RATE 115200 -// Default pin mappings. Grbl officially supports the Arduino Uno only. Other processor types -// may exist from user-supplied templates or directly user-defined in pin_map.h -#define PIN_MAP_ARDUINO_UNO +// Default cpu mappings. Grbl officially supports the Arduino Uno only. Other processor types +// may exist from user-supplied templates or directly user-defined in cpu_map.h +#define CPU_MAP_ATMEGA328P // Arduino Uno CPU // Define runtime command special characters. These characters are 'picked-off' directly from the // serial read data stream and are not passed to the grbl line execution parser. Select characters @@ -49,12 +49,6 @@ #define CMD_CYCLE_START '~' #define CMD_RESET 0x18 // ctrl-x. -// Uncomment the following define if you are using hardware that drives high when your limits -// are reached. You will need to ensure that you have appropriate pull-down resistors on the -// limit switch input pins, or that your hardware drives the pins low when they are open (non- -// triggered). -// #define LIMIT_SWITCHES_ACTIVE_HIGH // Uncomment to enable - // If homing is enabled, homing init lock sets Grbl into an alarm state upon power up. This forces // the user to perform the homing cycle (or override the locks) before doing anything else. This is // mainly a safety feature to remind the user to home, since position is unknown to Grbl. @@ -94,16 +88,8 @@ // set this only as high as needed. Approximate successful values can widely range from 50 to 200 or more. #define ACCELERATION_TICKS_PER_SECOND 100 -// Creates a delay between the direction pin setting and corresponding step pulse by creating -// another interrupt (Timer2 compare) to manage it. The main Grbl interrupt (Timer1 compare) -// sets the direction pins, and does not immediately set the stepper pins, as it would in -// normal operation. The Timer2 compare fires next to set the stepper pins after the step -// pulse delay time, and Timer2 overflow will complete the step pulse, except now delayed -// by the step pulse time plus the step pulse delay. (Thanks langwadt for the idea!) -// NOTE: Uncomment to enable. The recommended delay must be > 3us, and, when added with the -// user-supplied step pulse time, the total time must not exceed 127us. Reported successful -// values for certain setups have ranged from 5 to 20us. -// #define STEP_PULSE_DELAY 10 // Step pulse delay in microseconds. Default disabled. +#define ACTIVE_MULTI_AXIS_STEP_SMOOTHING +#define ENABLE_SOFTWARE_DEBOUNCE // Minimum planner junction speed. Sets the default minimum junction speed the planner plans to at // every buffer block junction, except for starting from rest and end of the buffer, which are always @@ -127,6 +113,17 @@ // time step. Also, keep in mind that the Arduino delay timer is not very accurate for long delays. #define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds) +// Creates a delay between the direction pin setting and corresponding step pulse by creating +// another interrupt (Timer2 compare) to manage it. The main Grbl interrupt (Timer1 compare) +// sets the direction pins, and does not immediately set the stepper pins, as it would in +// normal operation. The Timer2 compare fires next to set the stepper pins after the step +// pulse delay time, and Timer2 overflow will complete the step pulse, except now delayed +// by the step pulse time plus the step pulse delay. (Thanks langwadt for the idea!) +// NOTE: Uncomment to enable. The recommended delay must be > 3us, and, when added with the +// user-supplied step pulse time, the total time must not exceed 127us. Reported successful +// values for certain setups have ranged from 5 to 20us. +// #define STEP_PULSE_DELAY 10 // Step pulse delay in microseconds. Default disabled. + // The number of linear motions in the planner buffer to be planned at any give time. The vast // majority of RAM that Grbl uses is based on this buffer size. Only increase if there is extra // available RAM, like when re-compiling for a Mega or Sanguino. Or decrease if the Arduino @@ -171,8 +168,6 @@ // case, please report any successes to grbl administrators! // #define ENABLE_XONXOFF // Default disabled. Uncomment to enable. -#define ENABLE_SOFTWARE_DEBOUNCE - // --------------------------------------------------------------------------------------- // TODO: Install compile-time option to send numeric status codes rather than strings. diff --git a/pin_map.h b/cpu_map.h similarity index 86% rename from pin_map.h rename to cpu_map.h index 233b32a..0d21fe3 100644 --- a/pin_map.h +++ b/cpu_map.h @@ -1,5 +1,5 @@ /* - pin_map.h - Pin mapping configuration file + cpu_map.h - CPU and pin mapping configuration file Part of Grbl Copyright (c) 2013 Sungeun K. Jeon @@ -18,14 +18,17 @@ along with Grbl. If not, see . */ -/* The pin_map.h file serves as a central pin mapping settings file for different processor +/* The cpu_map.h file serves as a central pin mapping settings file for different processor types, i.e. AVR 328p or AVR Mega 2560. Grbl officially supports the Arduino Uno, but the other supplied pin mappings are supplied by users, so your results may vary. */ -#ifndef pin_map_h -#define pin_map_h +// NOTE: This is still a work in progress. We are still centralizing the configurations to +// this file, so your success may vary for other CPUs. -#ifdef PIN_MAP_ARDUINO_UNO // AVR 328p, Officially supported by Grbl. +#ifndef cpu_map_h +#define cpu_map_h + +#ifdef CPU_MAP_ATMEGA328P // (Arduino Uno) Officially supported by Grbl. // Serial port pins #define SERIAL_RX USART_RX_vect @@ -37,12 +40,14 @@ #define X_STEP_BIT 2 // Uno Digital Pin 2 #define Y_STEP_BIT 3 // Uno Digital Pin 3 #define Z_STEP_BIT 4 // Uno Digital Pin 4 + #define STEP_MASK ((1< 0) { // Re-approach all switches to re-engage them. - limits_go_home(HOMING_LOCATE_CYCLE, true, false, settings.homing_feed_rate); + limits_go_home(HOMING_LOCATE_CYCLE, true, settings.homing_feed_rate); } } // ------------------------------------------------------------------------------------- @@ -291,15 +291,23 @@ void mc_homing_cycle() } -// Auto-cycle start is a user setting that automatically begins the cycle when a user enters -// a valid motion command either manually or by a streaming tool. This is intended as a beginners -// feature to help new users to understand g-code. It can be disabled. Otherwise, the normal -// operation of cycle start is manually issuing a cycle start command whenever the user is -// ready and there is a valid motion command in the planner queue. +// Auto-cycle start has two purposes: 1. Resumes a plan_synchronize() call from a function that +// requires the planner buffer to empty (spindle enable, dwell, etc.) 2. As a user setting that +// automatically begins the cycle when a user enters a valid motion command manually. This is +// intended as a beginners feature to help new users to understand g-code. It can be disabled +// as a beginner tool, but (1.) still operates. If disabled, the operation of cycle start is +// manually issuing a cycle start command whenever the user is ready and there is a valid motion +// command in the planner queue. // NOTE: This function is called from the main loop and mc_line() only and executes when one of // two conditions exist respectively: There are no more blocks sent (i.e. streaming is finished, // single commands), or the planner buffer is full and ready to go. -void mc_auto_cycle_start() { if (sys.auto_start) { st_cycle_start(); } } +void mc_auto_cycle_start() +{ + if (sys.auto_start) { + st_cycle_start(); + if (bit_isfalse(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = false; } // Reset auto start per settings. + } +} // Method to ready the system to reset by setting the runtime reset command and killing any diff --git a/nuts_bolts.h b/nuts_bolts.h index 554ee31..ab19485 100644 --- a/nuts_bolts.h +++ b/nuts_bolts.h @@ -27,7 +27,7 @@ #include #include "config.h" #include "defaults.h" -#include "pin_map.h" +#include "cpu_map.h" #define false 0 #define true 1 diff --git a/planner.c b/planner.c index 9a91406..09a2c44 100644 --- a/planner.c +++ b/planner.c @@ -255,6 +255,7 @@ uint8_t plan_check_full_buffer() // during a synchronize call, if it should happen. Also, waits for clean cycle end. void plan_synchronize() { + sys.auto_start = true; // Set auto start to resume cycle after synchronize and caller completes. while (plan_get_current_block() || (sys.state == STATE_CYCLE)) { protocol_execute_runtime(); // Check and execute run-time commands if (sys.abort) { return; } // Check for system abort diff --git a/protocol.c b/protocol.c index 103d2f4..1e8e9cb 100644 --- a/protocol.c +++ b/protocol.c @@ -192,16 +192,10 @@ uint8_t protocol_execute_line(char *line) { // Grbl internal command and parameter lines are of the form '$4=374.3' or '$' for help if(line[0] == '$') { - uint8_t char_counter = 1; uint8_t helper_var = 0; // Helper variable float parameter, value; switch( line[char_counter] ) { - case 0 : report_grbl_help(); break; - case '$' : // Prints Grbl settings - if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } - else { report_grbl_settings(); } - break; case '#' : // Print gcode parameters if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } else { report_gcode_parameters(); } @@ -210,37 +204,6 @@ uint8_t protocol_execute_line(char *line) if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } else { report_gcode_modes(); } break; - case 'C' : // Set check g-code mode - if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } - // Perform reset when toggling off. Check g-code mode should only work if Grbl - // is idle and ready, regardless of alarm locks. This is mainly to keep things - // simple and consistent. - if ( sys.state == STATE_CHECK_MODE ) { - mc_reset(); - report_feedback_message(MESSAGE_DISABLED); - } else { - if (sys.state) { return(STATUS_IDLE_ERROR); } - sys.state = STATE_CHECK_MODE; - report_feedback_message(MESSAGE_ENABLED); - } - break; - case 'X' : // Disable alarm lock - if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } - if (sys.state == STATE_ALARM) { - report_feedback_message(MESSAGE_ALARM_UNLOCK); - sys.state = STATE_IDLE; - // Don't run startup script. Prevents stored moves in startup from causing accidents. - } - break; - case 'H' : // Perform homing cycle - if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { - // Only perform homing if Grbl is idle or lost. - if ( sys.state == STATE_IDLE || sys.state == STATE_ALARM ) { - mc_homing_cycle(); - if (!sys.abort) { protocol_execute_startup(); } // Execute startup scripts after successful homing. - } else { return(STATUS_IDLE_ERROR); } - } else { return(STATUS_SETTING_DISABLED); } - break; // case 'J' : break; // Jogging methods // TODO: Here jogging can be placed for execution as a seperate subprogram. It does not need to be // susceptible to other runtime commands except for e-stop. The jogging function is intended to @@ -252,42 +215,81 @@ uint8_t protocol_execute_line(char *line) // More controlled exact motions can be taken care of by inputting G0 or G1 commands, which are // handled by the planner. It would be possible for the jog subprogram to insert blocks into the // block buffer without having the planner plan them. It would need to manage de/ac-celerations - // on its own carefully. This approach could be effective and possibly size/memory efficient. - case 'N' : // Startup lines. - if ( line[++char_counter] == 0 ) { // Print startup lines - for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) { - if (!(settings_read_startup_line(helper_var, line))) { - report_status_message(STATUS_SETTING_READ_FAIL); + // on its own carefully. This approach could be effective and possibly size/memory efficient. + default : + // Block any system command that requires the state as IDLE/ALARM. (i.e. EEPROM, homing) + if ( !(sys.state == STATE_IDLE || sys.state == STATE_ALARM) ) { return(STATUS_IDLE_ERROR); } + switch( line[char_counter] ) { + case 0 : report_grbl_help(); break; + case '$' : // Prints Grbl settings + if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } + else { report_grbl_settings(); } + break; + case 'C' : // Set check g-code mode + if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } + // Perform reset when toggling off. Check g-code mode should only work if Grbl + // is idle and ready, regardless of alarm locks. This is mainly to keep things + // simple and consistent. + if ( sys.state == STATE_CHECK_MODE ) { + mc_reset(); + report_feedback_message(MESSAGE_DISABLED); } else { - report_startup_line(helper_var,line); + if (sys.state) { return(STATUS_IDLE_ERROR); } + sys.state = STATE_CHECK_MODE; + report_feedback_message(MESSAGE_ENABLED); } - } - break; - } else { // Store startup line - helper_var = true; // Set helper_var to flag storing method. - // No break. Continues into default: to read remaining command characters. - } - default : // Storing setting methods - if(!read_float(line, &char_counter, ¶meter)) { return(STATUS_BAD_NUMBER_FORMAT); } - if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); } - if (helper_var) { // Store startup line - // Prepare sending gcode block to gcode parser by shifting all characters - helper_var = char_counter; // Set helper variable as counter to start of gcode block - do { - line[char_counter-helper_var] = line[char_counter]; - } while (line[char_counter++] != 0); - // Execute gcode block to ensure block is valid. - helper_var = gc_execute_line(line); // Set helper_var to returned status code. - if (helper_var) { return(helper_var); } - else { - helper_var = trunc(parameter); // Set helper_var to int value of parameter - settings_store_startup_line(helper_var,line); - } - } else { // Store global setting. - if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); } - if(line[char_counter] != 0) { return(STATUS_UNSUPPORTED_STATEMENT); } - return(settings_store_global_setting(parameter, value)); - } + break; + case 'X' : // Disable alarm lock + if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } + if (sys.state == STATE_ALARM) { + report_feedback_message(MESSAGE_ALARM_UNLOCK); + sys.state = STATE_IDLE; + // Don't run startup script. Prevents stored moves in startup from causing accidents. + } + break; + case 'H' : // Perform homing cycle + if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { + // Only perform homing if Grbl is idle or lost. + mc_homing_cycle(); + if (!sys.abort) { protocol_execute_startup(); } // Execute startup scripts after successful homing. + } else { return(STATUS_SETTING_DISABLED); } + break; + case 'N' : // Startup lines. + if ( line[++char_counter] == 0 ) { // Print startup lines + for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) { + if (!(settings_read_startup_line(helper_var, line))) { + report_status_message(STATUS_SETTING_READ_FAIL); + } else { + report_startup_line(helper_var,line); + } + } + break; + } else { // Store startup line + helper_var = true; // Set helper_var to flag storing method. + // No break. Continues into default: to read remaining command characters. + } + default : // Storing setting methods + if(!read_float(line, &char_counter, ¶meter)) { return(STATUS_BAD_NUMBER_FORMAT); } + if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); } + if (helper_var) { // Store startup line + // Prepare sending gcode block to gcode parser by shifting all characters + helper_var = char_counter; // Set helper variable as counter to start of gcode block + do { + line[char_counter-helper_var] = line[char_counter]; + } while (line[char_counter++] != 0); + // Execute gcode block to ensure block is valid. + helper_var = gc_execute_line(line); // Set helper_var to returned status code. + if (helper_var) { return(helper_var); } + else { + helper_var = trunc(parameter); // Set helper_var to int value of parameter + settings_store_startup_line(helper_var,line); + } + } else { // Store global setting. + if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); } + if(line[char_counter] != 0) { return(STATUS_UNSUPPORTED_STATEMENT); } + return(settings_store_global_setting(parameter, value)); + } + } } return(STATUS_OK); // If '$' command makes it to here, then everything's ok. diff --git a/report.c b/report.c index c44efe0..49e6501 100644 --- a/report.c +++ b/report.c @@ -71,7 +71,7 @@ void report_status_message(uint8_t status_code) case STATUS_SETTING_READ_FAIL: printPgmString(PSTR("EEPROM read fail. Using defaults")); break; case STATUS_IDLE_ERROR: - printPgmString(PSTR("Busy or queued")); break; + printPgmString(PSTR("Not idle")); break; case STATUS_ALARM_LOCK: printPgmString(PSTR("Alarm lock")); break; case STATUS_SOFT_LIMIT_ERROR: @@ -162,24 +162,27 @@ void report_grbl_settings() { printPgmString(PSTR(" (y max travel, mm)\r\n$11=")); printFloat(-settings.max_travel[Z_AXIS]); // Grbl internally store this as negative. printPgmString(PSTR(" (z max travel, mm)\r\n$12=")); printInteger(settings.pulse_microseconds); printPgmString(PSTR(" (step pulse, usec)\r\n$13=")); printFloat(settings.default_feed_rate); - printPgmString(PSTR(" (default feed, mm/min)\r\n$14=")); printInteger(settings.invert_mask); - printPgmString(PSTR(" (step port invert mask, int:")); print_uint8_base2(settings.invert_mask); - printPgmString(PSTR(")\r\n$15=")); printInteger(settings.stepper_idle_lock_time); - printPgmString(PSTR(" (step idle delay, msec)\r\n$16=")); printFloat(settings.junction_deviation); - printPgmString(PSTR(" (junction deviation, mm)\r\n$17=")); printFloat(settings.arc_tolerance); - printPgmString(PSTR(" (arc tolerance, mm)\r\n$18=")); printInteger(settings.decimal_places); - printPgmString(PSTR(" (n-decimals, int)\r\n$19=")); printInteger(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)); - printPgmString(PSTR(" (report inches, bool)\r\n$20=")); printInteger(bit_istrue(settings.flags,BITFLAG_AUTO_START)); - printPgmString(PSTR(" (auto start, bool)\r\n$21=")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)); - printPgmString(PSTR(" (invert step enable, bool)\r\n$22=")); printInteger(bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE)); - printPgmString(PSTR(" (soft limits, bool)\r\n$23=")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)); - printPgmString(PSTR(" (hard limits, bool)\r\n$24=")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)); - printPgmString(PSTR(" (homing cycle, bool)\r\n$25=")); printInteger(settings.homing_dir_mask); + printPgmString(PSTR(" (default feed, mm/min)\r\n$14=")); printInteger(settings.step_invert_mask); + printPgmString(PSTR(" (step port invert mask, int:")); print_uint8_base2(settings.step_invert_mask); + printPgmString(PSTR(")\r\n$15=")); printInteger(settings.dir_invert_mask); + printPgmString(PSTR(" (dir port invert mask, int:")); print_uint8_base2(settings.dir_invert_mask); + printPgmString(PSTR(")\r\n$16=")); printInteger(settings.stepper_idle_lock_time); + printPgmString(PSTR(" (step idle delay, msec)\r\n$17=")); printFloat(settings.junction_deviation); + printPgmString(PSTR(" (junction deviation, mm)\r\n$18=")); printFloat(settings.arc_tolerance); + printPgmString(PSTR(" (arc tolerance, mm)\r\n$19=")); printInteger(settings.decimal_places); + printPgmString(PSTR(" (n-decimals, int)\r\n$20=")); printInteger(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)); + printPgmString(PSTR(" (report inches, bool)\r\n$21=")); printInteger(bit_istrue(settings.flags,BITFLAG_AUTO_START)); + printPgmString(PSTR(" (auto start, bool)\r\n$22=")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)); + printPgmString(PSTR(" (invert step enable, bool)\r\n$23=")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS)); + printPgmString(PSTR(" (invert limit pins, bool)\r\n$24=")); printInteger(bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE)); + printPgmString(PSTR(" (soft limits, bool)\r\n$25=")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)); + printPgmString(PSTR(" (hard limits, bool)\r\n$26=")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)); + printPgmString(PSTR(" (homing cycle, bool)\r\n$27=")); printInteger(settings.homing_dir_mask); printPgmString(PSTR(" (homing dir invert mask, int:")); print_uint8_base2(settings.homing_dir_mask); - printPgmString(PSTR(")\r\n$26=")); printFloat(settings.homing_feed_rate); - printPgmString(PSTR(" (homing feed, mm/min)\r\n$27=")); printFloat(settings.homing_seek_rate); - printPgmString(PSTR(" (homing seek, mm/min)\r\n$28=")); printInteger(settings.homing_debounce_delay); - printPgmString(PSTR(" (homing debounce, msec)\r\n$29=")); printFloat(settings.homing_pulloff); + printPgmString(PSTR(")\r\n$28=")); printFloat(settings.homing_feed_rate); + printPgmString(PSTR(" (homing feed, mm/min)\r\n$29=")); printFloat(settings.homing_seek_rate); + printPgmString(PSTR(" (homing seek, mm/min)\r\n$30=")); printInteger(settings.homing_debounce_delay); + printPgmString(PSTR(" (homing debounce, msec)\r\n$31=")); printFloat(settings.homing_pulloff); printPgmString(PSTR(" (homing pull-off, mm)\r\n")); } diff --git a/settings.c b/settings.c index a611ccc..1ba0629 100644 --- a/settings.c +++ b/settings.c @@ -80,7 +80,8 @@ void settings_reset(bool reset_all) { settings.acceleration[Y_AXIS] = DEFAULT_Y_ACCELERATION; settings.acceleration[Z_AXIS] = DEFAULT_Z_ACCELERATION; settings.arc_tolerance = DEFAULT_ARC_TOLERANCE; - settings.invert_mask = DEFAULT_STEPPING_INVERT_MASK; + settings.step_invert_mask = DEFAULT_STEPPING_INVERT_MASK; + settings.dir_invert_mask = DEFAULT_DIRECTION_INVERT_MASK; settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION; } // New settings since last version @@ -88,6 +89,7 @@ void settings_reset(bool reset_all) { if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; } if (DEFAULT_AUTO_START) { settings.flags |= BITFLAG_AUTO_START; } if (DEFAULT_INVERT_ST_ENABLE) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; } + if (DEFAULT_INVERT_LIMIT_PINS) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; } if (DEFAULT_SOFT_LIMIT_ENABLE) { settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE; } if (DEFAULT_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; } if (DEFAULT_HOMING_ENABLE) { settings.flags |= BITFLAG_HOMING_ENABLE; } @@ -176,46 +178,51 @@ uint8_t settings_store_global_setting(int parameter, float value) { if (value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); } settings.pulse_microseconds = round(value); break; case 13: settings.default_feed_rate = value; break; - case 14: settings.invert_mask = trunc(value); break; - case 15: settings.stepper_idle_lock_time = round(value); break; - case 16: settings.junction_deviation = fabs(value); break; - case 17: settings.arc_tolerance = value; break; - case 18: settings.decimal_places = round(value); break; - case 19: + case 14: settings.step_invert_mask = trunc(value); break; + case 15: settings.dir_invert_mask = trunc(value); break; + case 16: settings.stepper_idle_lock_time = round(value); break; + case 17: settings.junction_deviation = fabs(value); break; + case 18: settings.arc_tolerance = value; break; + case 19: settings.decimal_places = round(value); break; + case 20: if (value) { settings.flags |= BITFLAG_REPORT_INCHES; } else { settings.flags &= ~BITFLAG_REPORT_INCHES; } break; - case 20: // Reset to ensure change. Immediate re-init may cause problems. + case 21: // Reset to ensure change. Immediate re-init may cause problems. if (value) { settings.flags |= BITFLAG_AUTO_START; } else { settings.flags &= ~BITFLAG_AUTO_START; } break; - case 21: // Reset to ensure change. Immediate re-init may cause problems. + case 22: // Reset to ensure change. Immediate re-init may cause problems. if (value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; } else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; } break; - case 22: + case 23: // Reset to ensure change. Immediate re-init may cause problems. + if (value) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; } + else { settings.flags &= ~BITFLAG_INVERT_LIMIT_PINS; } + break; + case 24: if (value) { if (bit_isfalse(settings.flags, BITFLAG_HOMING_ENABLE)) { return(STATUS_SOFT_LIMIT_ERROR); } settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE; } else { settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; } break; - case 23: + case 25: if (value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; } else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; } limits_init(); // Re-init to immediately change. NOTE: Nice to have but could be problematic later. break; - case 24: + case 26: if (value) { settings.flags |= BITFLAG_HOMING_ENABLE; } else { settings.flags &= ~BITFLAG_HOMING_ENABLE; - settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; + settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; // Force disable soft-limits. } break; - case 25: settings.homing_dir_mask = trunc(value); break; - case 26: settings.homing_feed_rate = value; break; - case 27: settings.homing_seek_rate = value; break; - case 28: settings.homing_debounce_delay = round(value); break; - case 29: settings.homing_pulloff = value; break; + case 27: settings.homing_dir_mask = trunc(value); break; + case 28: settings.homing_feed_rate = value; break; + case 29: settings.homing_seek_rate = value; break; + case 30: settings.homing_debounce_delay = round(value); break; + case 31: settings.homing_pulloff = value; break; default: return(STATUS_INVALID_STATEMENT); } diff --git a/settings.h b/settings.h index ebd7db5..7d435d9 100644 --- a/settings.h +++ b/settings.h @@ -30,7 +30,7 @@ // Version of the EEPROM data. Will be used to migrate existing data from older versions of Grbl // when firmware is upgraded. Always stored in byte 0 of eeprom -#define SETTINGS_VERSION 56 +#define SETTINGS_VERSION 57 // Define bit flag masks for the boolean settings in settings.flag. #define BITFLAG_REPORT_INCHES bit(0) @@ -39,6 +39,7 @@ #define BITFLAG_HARD_LIMIT_ENABLE bit(3) #define BITFLAG_HOMING_ENABLE bit(4) #define BITFLAG_SOFT_LIMIT_ENABLE bit(5) +#define BITFLAG_INVERT_LIMIT_PINS bit(6) // Define EEPROM memory address location values for Grbl settings and parameters // NOTE: The Atmega328p has 1KB EEPROM. The upper half is reserved for parameters and @@ -64,7 +65,8 @@ typedef struct { float max_travel[N_AXIS]; uint8_t pulse_microseconds; float default_feed_rate; - uint8_t invert_mask; + uint8_t step_invert_mask; + uint8_t dir_invert_mask; uint8_t stepper_idle_lock_time; // If max value 255, steppers do not disable. float junction_deviation; float arc_tolerance; diff --git a/stepper.c b/stepper.c index b02c9d5..b9a80f9 100644 --- a/stepper.c +++ b/stepper.c @@ -35,6 +35,12 @@ #define RAMP_DECEL 2 +#define MAX_AMASS_LEVEL 3 +#define AMASS_LEVEL1 (F_CPU/10000) +#define AMASS_LEVEL2 (F_CPU/5000) +#define AMASS_LEVEL3 (F_CPU/2500) + + // Stores the planner block Bresenham algorithm execution data for the segments in the segment // buffer. Normally, this buffer is partially in-use, but, for the worst case scenario, it will // never exceed the number of accessible stepper buffer segments (SEGMENT_BUFFER_SIZE-1). @@ -57,7 +63,7 @@ typedef struct { uint16_t n_step; // Number of step events to be executed for this segment uint8_t st_block_index; // Stepper block data index. Uses this information to execute this segment. uint16_t cycles_per_tick; // Step distance traveled per ISR tick, aka step rate. - uint8_t prescaler; + uint8_t amass_level; } segment_t; static segment_t segment_buffer[SEGMENT_BUFFER_SIZE]; @@ -65,17 +71,19 @@ static segment_t segment_buffer[SEGMENT_BUFFER_SIZE]; typedef struct { // Used by the bresenham line algorithm uint32_t counter_x, // Counter variables for the bresenham line tracer - counter_y, - counter_z; + counter_y, + counter_z; - #if STEP_PULSE_DELAY > 0 + #ifdef STEP_PULSE_DELAY uint8_t step_bits; // Stores out_bits output to complete the step pulse delay #endif // Used by the stepper driver interrupt uint8_t execute_step; // Flags step execution for each interrupt. uint8_t step_pulse_time; // Step pulse reset time after step rise - uint8_t out_bits; // The next stepping-bits to be output + uint8_t step_outbits; // The next stepping-bits to be output + uint8_t dir_outbits; + uint32_t steps[N_AXIS]; uint16_t step_count; // Steps remaining in line segment motion uint8_t exec_block_index; // Tracks the current st_block index. Change indicates new block. @@ -120,6 +128,8 @@ typedef struct { static st_prep_t prep; +static void st_config_step_timer(uint32_t cycles); + /* BLOCK VELOCITY PROFILE DEFINITION __________________________ /| |\ _________________ ^ @@ -158,6 +168,7 @@ static st_prep_t prep; are shown and defined in the above illustration. */ + // Stepper state initialization. Cycle should only start if the st.cycle_start flag is // enabled. Startup init and limits call this function but shouldn't start the cycle. void st_wake_up() @@ -170,20 +181,22 @@ void st_wake_up() } if (sys.state & (STATE_CYCLE | STATE_HOMING)){ // Initialize stepper output bits - st.out_bits = settings.invert_mask; - + st.dir_outbits = settings.dir_invert_mask; + st.step_outbits = settings.step_invert_mask; + // Initialize step pulse timing from settings. Here to ensure updating after re-writing. #ifdef STEP_PULSE_DELAY // Set total step pulse time after direction pin set. Ad hoc computation from oscilloscope. st.step_pulse_time = -(((settings.pulse_microseconds+STEP_PULSE_DELAY-2)*TICKS_PER_MICROSECOND) >> 3); // Set delay between direction pin write and step command. - OCR2A = -(((settings.pulse_microseconds)*TICKS_PER_MICROSECOND) >> 3); + OCR0A = -(((settings.pulse_microseconds)*TICKS_PER_MICROSECOND) >> 3); #else // Normal operation // Set step pulse time. Ad hoc computation from oscilloscope. Uses two's complement. st.step_pulse_time = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3); #endif - // Enable stepper driver interrupt + // Enable Stepper Driver Interrupt + TCCR1B = (TCCR1B & ~(0x07<prescaler<prescaler<cycles_per_tick; st.step_count = st.exec_segment->n_step; // NOTE: Can sometimes be zero when moving slow. // If the new segment starts a new planner block, initialize stepper variables and counters. @@ -274,11 +286,15 @@ ISR(TIMER1_COMPA_vect) if ( st.exec_block_index != st.exec_segment->st_block_index ) { st.exec_block_index = st.exec_segment->st_block_index; st.exec_block = &st_block_buffer[st.exec_block_index]; + st.dir_outbits = st.exec_block->direction_bits ^ settings.dir_invert_mask; // Initialize Bresenham line and distance counters st.counter_x = (st.exec_block->step_event_count >> 1); st.counter_y = st.counter_x; - st.counter_z = st.counter_x; + st.counter_z = st.counter_x; } + st.steps[X_AXIS] = st.exec_block->steps[X_AXIS] >> st.exec_segment->amass_level; + st.steps[Y_AXIS] = st.exec_block->steps[Y_AXIS] >> st.exec_segment->amass_level; + st.steps[Z_AXIS] = st.exec_block->steps[Z_AXIS] >> st.exec_segment->amass_level; } else { // Segment buffer empty. Shutdown. st_go_idle(); @@ -287,46 +303,43 @@ ISR(TIMER1_COMPA_vect) } } - // Reset out_bits and reload direction bits - st.out_bits = st.exec_block->direction_bits; + // Reset step out bits. + st.step_outbits = 0; // Execute step displacement profile by Bresenham line algorithm - if (st.step_count > 0) { - st.step_count--; // Decrement step events count + st.counter_x += st.steps[X_AXIS]; + if (st.counter_x > st.exec_block->step_event_count) { + st.step_outbits |= (1<step_event_count; + if (st.exec_block->direction_bits & (1< st.exec_block->step_event_count) { + st.step_outbits |= (1<step_event_count; + if (st.exec_block->direction_bits & (1< st.exec_block->step_event_count) { + st.step_outbits |= (1<step_event_count; + if (st.exec_block->direction_bits & (1<steps[X_AXIS]; - if (st.counter_x > st.exec_block->step_event_count) { - st.out_bits |= (1<step_event_count; - if (st.out_bits & (1<steps[Y_AXIS]; - if (st.counter_y > st.exec_block->step_event_count) { - st.out_bits |= (1<step_event_count; - if (st.out_bits & (1<steps[Z_AXIS]; - if (st.counter_z > st.exec_block->step_event_count) { - st.out_bits |= (1<step_event_count; - if (st.out_bits & (1<direction_bits = pl_block->direction_bits; - st_prep_block->steps[X_AXIS] = pl_block->steps[X_AXIS]; - st_prep_block->steps[Y_AXIS] = pl_block->steps[Y_AXIS]; - st_prep_block->steps[Z_AXIS] = pl_block->steps[Z_AXIS]; - st_prep_block->step_event_count = pl_block->step_event_count; + #ifdef ACTIVE_MULTI_AXIS_STEP_SMOOTHING + st_prep_block->steps[X_AXIS] = pl_block->steps[X_AXIS] << MAX_AMASS_LEVEL; + st_prep_block->steps[Y_AXIS] = pl_block->steps[Y_AXIS] << MAX_AMASS_LEVEL; + st_prep_block->steps[Z_AXIS] = pl_block->steps[Z_AXIS] << MAX_AMASS_LEVEL; + st_prep_block->step_event_count = pl_block->step_event_count << MAX_AMASS_LEVEL; + #else + st_prep_block->steps[X_AXIS] = pl_block->steps[X_AXIS]; + st_prep_block->steps[Y_AXIS] = pl_block->steps[Y_AXIS]; + st_prep_block->steps[Z_AXIS] = pl_block->steps[Z_AXIS]; + st_prep_block->step_event_count = pl_block->step_event_count; + #endif // Initialize segment buffer data for generating the segments. prep.steps_remaining = pl_block->step_event_count; @@ -678,11 +695,26 @@ void st_prep_buffer() uint32_t cycles; float steps_remaining = prep.step_per_mm*mm_remaining; - float inv_rate = dt/(prep.steps_remaining-steps_remaining); - cycles = ceil( (TICKS_PER_MICROSECOND*1000000*60)*inv_rate ); // (ftol_mult*step/isr_tic) - // Compute number of steps to execute and segment step phase correction. - prep_segment->n_step = ceil(prep.steps_remaining)-ceil(steps_remaining); + prep_segment->n_step = ceil(prep.steps_remaining)-ceil(steps_remaining); + + float inv_rate = dt/(prep.steps_remaining-steps_remaining); + cycles = ceil( (TICKS_PER_MICROSECOND*1000000*60)*inv_rate ); // (cycles/step) + + #ifdef ACTIVE_MULTI_AXIS_STEP_SMOOTHING + // Compute step timing and multi-axis smoothing level. + // NOTE: Only one prescalar is required with AMASS enabled. + if (cycles > AMASS_LEVEL1) { + if (cycles > AMASS_LEVEL2) { + if (cycles > AMASS_LEVEL3) { prep_segment->amass_level = 3; } + else { prep_segment->amass_level = 2; } + } else { prep_segment->amass_level = 1; } + cycles >>= prep_segment->amass_level; + prep_segment->n_step <<= prep_segment->amass_level; + } else { prep_segment->amass_level = 0; } + if (cycles < (1UL << 16)) { prep_segment->cycles_per_tick = cycles; } + else { prep_segment->cycles_per_tick = 0xffff; } // Just set the slowest speed possible. (4.1ms @ 16MHz) + #endif // Determine end of segment conditions. Setup initial conditions for next segment. if (mm_remaining > prep.mm_complete) { @@ -715,29 +747,6 @@ void st_prep_buffer() } } -// TODO: Compile-time checks to what prescalers need to be compiled in. - if (cycles < (1UL << 16)) { // < 65536 (4.1ms @ 16MHz) - prep_segment->prescaler = 1; // prescaler: 0 - prep_segment->cycles_per_tick = cycles; - } else { - prep_segment->prescaler = 2; // prescaler: 8 - if (cycles < (1UL << 19)) { // < 524288 (32.8ms@16MHz) - prep_segment->cycles_per_tick = cycles >> 3; -// } else if (cycles < (1UL << 22)) { // < 4194304 (262ms@16MHz) -// prep_segment->prescaler = 3; // prescaler: 64 -// prep_segment->cycles_per_tick = cycles >> 6; -// } else if (cycles < (1UL << 24)) { // < 16777216 (1.05sec@16MHz) -// prep_segment->prescaler = 4; // prescaler: 256 -// prep_segment->cycles_per_tick = (cycles >> 8); -// } else { -// prep_segment->prescaler = 5; // prescaler: 1024 -// if (cycles < (1UL << 26)) { // < 67108864 (4.19sec@16MHz) -// prep_segment->cycles_per_tick = (cycles >> 10); - } else { // Just set the slowest speed possible. - prep_segment->cycles_per_tick = 0xffff; - } - } - // New step segment initialization completed. Increment segment buffer indices. segment_buffer_head = segment_next_head; if ( ++segment_next_head == SEGMENT_BUFFER_SIZE ) { segment_next_head = 0; } @@ -776,3 +785,31 @@ void st_prep_buffer() we know when the plan is feasible in the context of what's already in the code and not require too much more code? */ + +// static void st_config_step_timer(uint32_t cycles) +// { +// if (cycles < (1UL << 16)) { // < 65536 (4.1ms @ 16MHz) +// prep_segment->prescaler = 1; // prescaler: 0 +// prep_segment->cycles_per_tick = cycles; +// } else { +// prep_segment->prescaler = 2; // prescaler: 8 +// if (cycles < (1UL << 19)) { // < 524288 (32.8ms@16MHz) +// prep_segment->cycles_per_tick = cycles >> 3; +// +// // } else if (cycles < (1UL << 22)) { // < 4194304 (262ms@16MHz) +// // prep_segment->prescaler = 3; // prescaler: 64 +// // prep_segment->cycles_per_tick = cycles >> 6; +// // } else if (cycles < (1UL << 24)) { // < 16777216 (1.05sec@16MHz) +// // prep_segment->prescaler = 4; // prescaler: 256 +// // prep_segment->cycles_per_tick = (cycles >> 8); +// // } else { +// // prep_segment->prescaler = 5; // prescaler: 1024 +// // if (cycles < (1UL << 26)) { // < 67108864 (4.19sec@16MHz) +// // prep_segment->cycles_per_tick = (cycles >> 10); +// +// } else { // Just set the slowest speed possible. +// prep_segment->cycles_per_tick = 0xffff; +// } +// printString("X"); +// } +// } \ No newline at end of file