Improved constant laser power per rate mode. Re-factored for flash size. Minor bug fixes.

- NOTE: This commit has largely been untested.

- Constant laser power per rate mode has been improved. Altered its
implementation to be more responsive and accurate.

- Based on LaserWeb dev feedback, only G1, G2, and G3 moves operate
with constant laser power mode. Meaning that G0, G38.x, and $J jogging
motions operate without it and will keep a constant power output. This
was specifically requested as a way to focus the laser by keeping the
laser on when not moving. Operationally, this shouldn’t alter how the
laser mode operates.

- Re-factored parts of the g-code parser and g-code state reports to
save a few hundred bytes of flash. What was done makes the code a bit
more unreadable (bad), but the flash space was in dire need. So, I’m
willing to live with it for now.

- Fixed a problem with $G g-code state reports. Showed `M0` program
pause during a run state. Now fixed to show nothing during a run state.
Also, `M30` program end was shown as `M2`. This was also corrected.

- Improved spindle stop override responsiveness by removing the
enforced spindle restoring delay. It’s not needed for a feature that is
user controlled.

- Fixed a bug with G2/3 arcs in inverse time mode.

- Updated the interface.md document to make it more clear how WPos: or
MPos: can be calculated from WCO:. Some GUI devs have failed to catch
this in the documentation.
This commit is contained in:
Sonny Jeon
2016-11-04 09:15:34 -06:00
parent e8b717604b
commit 6e3fb6bd13
12 changed files with 185 additions and 161 deletions

View File

@ -149,35 +149,12 @@ uint8_t gc_execute_line(char *line)
// No break. Continues to next line.
case 4: case 53:
word_bit = MODAL_GROUP_G0;
switch(int_value) {
case 4: gc_block.non_modal_command = NON_MODAL_DWELL; break; // G4
case 10: gc_block.non_modal_command = NON_MODAL_SET_COORDINATE_DATA; break; // G10
case 28:
switch(mantissa) {
case 0: gc_block.non_modal_command = NON_MODAL_GO_HOME_0; break; // G28
case 10: gc_block.non_modal_command = NON_MODAL_SET_HOME_0; break; // G28.1
default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G28.x command]
}
mantissa = 0; // Set to zero to indicate valid non-integer G command.
break;
case 30:
switch(mantissa) {
case 0: gc_block.non_modal_command = NON_MODAL_GO_HOME_1; break; // G30
case 10: gc_block.non_modal_command = NON_MODAL_SET_HOME_1; break; // G30.1
default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G30.x command]
}
mantissa = 0; // Set to zero to indicate valid non-integer G command.
break;
case 53: gc_block.non_modal_command = NON_MODAL_ABSOLUTE_OVERRIDE; break; // G53
case 92:
switch(mantissa) {
case 0: gc_block.non_modal_command = NON_MODAL_SET_COORDINATE_OFFSET; break; // G92
case 10: gc_block.non_modal_command = NON_MODAL_RESET_COORDINATE_OFFSET; break; // G92.1
default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G92.x command]
}
mantissa = 0; // Set to zero to indicate valid non-integer G command.
break;
}
gc_block.non_modal_command = int_value;
if ((int_value == 28) || (int_value == 30) || (int_value == 92)) {
if ((mantissa != 0) || (mantissa != 10)) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); }
gc_block.non_modal_command += mantissa;
mantissa = 0; // Set to zero to indicate valid non-integer G command.
}
break;
case 0: case 1: case 2: case 3: case 38:
// Check for G0/1/2/3/38 being called with G10/28/30/92 on same block.
@ -187,37 +164,22 @@ uint8_t gc_execute_line(char *line)
// No break. Continues to next line.
case 80:
word_bit = MODAL_GROUP_G1;
switch(int_value) {
case 0: gc_block.modal.motion = MOTION_MODE_SEEK; break; // G0
case 1: gc_block.modal.motion = MOTION_MODE_LINEAR; break; // G1
case 2: gc_block.modal.motion = MOTION_MODE_CW_ARC; break; // G2
case 3: gc_block.modal.motion = MOTION_MODE_CCW_ARC; break; // G3
case 38:
switch(mantissa) {
case 20: gc_block.modal.motion = MOTION_MODE_PROBE_TOWARD; break; // G38.2
case 30: gc_block.modal.motion = MOTION_MODE_PROBE_TOWARD_NO_ERROR; break; // G38.3
case 40: gc_block.modal.motion = MOTION_MODE_PROBE_AWAY; break; // G38.4
case 50: gc_block.modal.motion = MOTION_MODE_PROBE_AWAY_NO_ERROR; break; // G38.5
default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G38.x command]
}
mantissa = 0; // Set to zero to indicate valid non-integer G command.
break;
case 80: gc_block.modal.motion = MOTION_MODE_NONE; break; // G80
}
gc_block.modal.motion = int_value;
if (int_value == 38){
if ((mantissa != 20) || (mantissa != 30) || (mantissa != 40) || (mantissa != 50)) {
FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G38.x command]
}
gc_block.modal.motion += (mantissa/10)+100;
}
break;
case 17: case 18: case 19:
word_bit = MODAL_GROUP_G2;
switch(int_value) {
case 17: gc_block.modal.plane_select = PLANE_SELECT_XY; break;
case 18: gc_block.modal.plane_select = PLANE_SELECT_ZX; break;
case 19: gc_block.modal.plane_select = PLANE_SELECT_YZ; break;
}
gc_block.modal.plane_select = int_value - 17;
break;
case 90: case 91:
if (mantissa == 0) {
word_bit = MODAL_GROUP_G3;
if (int_value == 90) { gc_block.modal.distance = DISTANCE_MODE_ABSOLUTE; } // G90
else { gc_block.modal.distance = DISTANCE_MODE_INCREMENTAL; } // G91
gc_block.modal.distance = int_value - 90;
} else {
word_bit = MODAL_GROUP_G4;
if ((mantissa != 10) || (int_value == 90)) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [G90.1 not supported]
@ -227,13 +189,11 @@ uint8_t gc_execute_line(char *line)
break;
case 93: case 94:
word_bit = MODAL_GROUP_G5;
if (int_value == 93) { gc_block.modal.feed_rate = FEED_RATE_MODE_INVERSE_TIME; } // G93
else { gc_block.modal.feed_rate = FEED_RATE_MODE_UNITS_PER_MIN; } // G94
gc_block.modal.feed_rate = 94 - int_value;
break;
case 20: case 21:
word_bit = MODAL_GROUP_G6;
if (int_value == 20) { gc_block.modal.units = UNITS_MODE_INCHES; } // G20
else { gc_block.modal.units = UNITS_MODE_MM; } // G21
gc_block.modal.units = 21 - int_value;
break;
case 40:
word_bit = MODAL_GROUP_G7;
@ -258,7 +218,7 @@ uint8_t gc_execute_line(char *line)
case 54: case 55: case 56: case 57: case 58: case 59:
// NOTE: G59.x are not supported. (But their int_values would be 60, 61, and 62.)
word_bit = MODAL_GROUP_G12;
gc_block.modal.coord_select = int_value-54; // Shift to array indexing.
gc_block.modal.coord_select = int_value - 54; // Shift to array indexing.
break;
case 61:
word_bit = MODAL_GROUP_G13;
@ -284,7 +244,7 @@ uint8_t gc_execute_line(char *line)
switch(int_value) {
case 0: gc_block.modal.program_flow = PROGRAM_FLOW_PAUSED; break; // Program pause
case 1: break; // Optional stop not supported. Ignore.
case 2: case 30: gc_block.modal.program_flow = PROGRAM_FLOW_COMPLETED; break; // Program end and reset
default: gc_block.modal.program_flow = int_value; // Program end and reset
}
break;
#ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
@ -891,7 +851,7 @@ uint8_t gc_execute_line(char *line)
// [2. Set feed rate mode ]:
gc_state.modal.feed_rate = gc_block.modal.feed_rate;
pl_data->condition |= gc_state.modal.feed_rate; // Set condition flag for planner use.
if (gc_state.modal.feed_rate) { pl_data->condition |= PL_COND_FLAG_INVERSE_TIME; } // Set condition flag for planner use.
// [3. Set feed rate ]:
gc_state.feed_rate = gc_block.values.f; // Always copy this value. See feed rate error-checking.

View File

@ -51,54 +51,60 @@
// Define command actions for within execution-type modal groups (motion, stopping, non-modal). Used
// internally by the parser to know which command to execute.
// NOTE: Some macro values are assigned specific values to make g-code state reporting and parsing
// compile a litte smaller. Necessary due to being completely out of flash on the 328p. Although not
// ideal, just be careful with values that state 'do not alter' and check both report.c and gcode.c
// to see how they are used, if you need to alter them.
// Modal Group G0: Non-modal actions
#define NON_MODAL_NO_ACTION 0 // (Default: Must be zero)
#define NON_MODAL_DWELL 1 // G4
#define NON_MODAL_SET_COORDINATE_DATA 2 // G10
#define NON_MODAL_GO_HOME_0 3 // G28
#define NON_MODAL_SET_HOME_0 4 // G28.1
#define NON_MODAL_GO_HOME_1 5 // G30
#define NON_MODAL_SET_HOME_1 6 // G30.1
#define NON_MODAL_ABSOLUTE_OVERRIDE 7 // G53
#define NON_MODAL_SET_COORDINATE_OFFSET 8 // G92
#define NON_MODAL_RESET_COORDINATE_OFFSET 9 //G92.1
#define NON_MODAL_DWELL 4 // G4 (Do not alter value)
#define NON_MODAL_SET_COORDINATE_DATA 10 // G10 (Do not alter value)
#define NON_MODAL_GO_HOME_0 28 // G28 (Do not alter value)
#define NON_MODAL_SET_HOME_0 38 // G28.1 (Do not alter value)
#define NON_MODAL_GO_HOME_1 30 // G30 (Do not alter value)
#define NON_MODAL_SET_HOME_1 40 // G30.1 (Do not alter value)
#define NON_MODAL_ABSOLUTE_OVERRIDE 53 // G53 (Do not alter value)
#define NON_MODAL_SET_COORDINATE_OFFSET 92 // G92 (Do not alter value)
#define NON_MODAL_RESET_COORDINATE_OFFSET 102 //G92.1 (Do not alter value)
// Modal Group G1: Motion modes
#define MOTION_MODE_SEEK 0 // G0 (Default: Must be zero)
#define MOTION_MODE_LINEAR 1 // G1
#define MOTION_MODE_CW_ARC 2 // G2
#define MOTION_MODE_CCW_ARC 3 // G3
#define MOTION_MODE_PROBE_TOWARD 4 // G38.2 NOTE: G38.2, G38.3, G38.4, G38.5 must be sequential. See report_gcode_modes().
#define MOTION_MODE_PROBE_TOWARD_NO_ERROR 5 // G38.3
#define MOTION_MODE_PROBE_AWAY 6 // G38.4
#define MOTION_MODE_PROBE_AWAY_NO_ERROR 7 // G38.5
#define MOTION_MODE_NONE 8 // G80
#define MOTION_MODE_LINEAR 1 // G1 (Do not alter value)
#define MOTION_MODE_CW_ARC 2 // G2 (Do not alter value)
#define MOTION_MODE_CCW_ARC 3 // G3 (Do not alter value)
#define MOTION_MODE_PROBE_TOWARD 140 // G38.2 (Do not alter value)
#define MOTION_MODE_PROBE_TOWARD_NO_ERROR 141 // G38.3 (Do not alter value)
#define MOTION_MODE_PROBE_AWAY 142 // G38.4 (Do not alter value)
#define MOTION_MODE_PROBE_AWAY_NO_ERROR 143 // G38.5 (Do not alter value)
#define MOTION_MODE_NONE 80 // G80 (Do not alter value)
// Modal Group G2: Plane select
#define PLANE_SELECT_XY 0 // G17 (Default: Must be zero)
#define PLANE_SELECT_ZX 1 // G18
#define PLANE_SELECT_YZ 2 // G19
#define PLANE_SELECT_ZX 1 // G18 (Do not alter value)
#define PLANE_SELECT_YZ 2 // G19 (Do not alter value)
// Modal Group G3: Distance mode
#define DISTANCE_MODE_ABSOLUTE 0 // G90 (Default: Must be zero)
#define DISTANCE_MODE_INCREMENTAL 1 // G91
#define DISTANCE_MODE_INCREMENTAL 1 // G91 (Do not alter value)
// Modal Group G4: Arc IJK distance mode
#define DISTANCE_ARC_MODE_INCREMENTAL 0 // G91.1 (Default: Must be zero)
// Modal Group M4: Program flow
#define PROGRAM_FLOW_RUNNING 0 // (Default: Must be zero)
#define PROGRAM_FLOW_PAUSED 1 // M0, M1
#define PROGRAM_FLOW_COMPLETED 2 // M2, M30
#define PROGRAM_FLOW_PAUSED 3 // M0
#define PROGRAM_FLOW_OPTIONAL_STOP 1 // M1 NOTE: Not supported, but valid and ignored.
#define PROGRAM_FLOW_COMPLETED_M2 2 // M2 (Do not alter value)
#define PROGRAM_FLOW_COMPLETED_M30 30 // M30 (Do not alter value)
// Modal Group G5: Feed rate mode
#define FEED_RATE_MODE_UNITS_PER_MIN 0 // G94 (Default: Must be zero)
#define FEED_RATE_MODE_INVERSE_TIME PL_COND_FLAG_INVERSE_TIME // G93 (NOTE: Uses planner condition bit flag)
#define FEED_RATE_MODE_INVERSE_TIME 1 // G93 (Do not alter value)
// Modal Group G6: Units mode
#define UNITS_MODE_MM 0 // G21 (Default: Must be zero)
#define UNITS_MODE_INCHES 1 // G20
#define UNITS_MODE_INCHES 1 // G20 (Do not alter value)
// Modal Group G7: Cutter radius compensation mode
#define CUTTER_COMP_DISABLE 0 // G40 (Default: Must be zero)

View File

@ -23,7 +23,7 @@
// Grbl versioning system
#define GRBL_VERSION "1.1d"
#define GRBL_VERSION_BUILD "20161027"
#define GRBL_VERSION_BUILD "20161104"
// Define standard libraries used by Grbl.
#include <avr/io.h>

View File

@ -106,8 +106,11 @@ void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *of
// Multiply inverse feed_rate to compensate for the fact that this movement is approximated
// by a number of discrete segments. The inverse feed_rate should be correct for the sum of
// all segments.
if (pl_data->condition & PL_COND_FLAG_INVERSE_TIME) { pl_data->feed_rate *= segments; }
if (pl_data->condition & PL_COND_FLAG_INVERSE_TIME) {
pl_data->feed_rate *= segments;
bit_false(pl_data->condition,PL_COND_FLAG_INVERSE_TIME); // Force as feed absolute mode over arc segments.
}
float theta_per_segment = angular_travel/segments;
float linear_per_segment = (target[axis_linear] - position[axis_linear])/segments;

View File

@ -40,7 +40,7 @@
#define PL_COND_FLAG_RAPID_MOTION bit(0)
#define PL_COND_FLAG_SYSTEM_MOTION bit(1) // Single motion. Circumvents planner state. Used by home/park.
#define PL_COND_FLAG_NO_FEED_OVERRIDE bit(2) // Motion does not honor feed override.
#define PL_COND_FLAG_INVERSE_TIME bit(3)
#define PL_COND_FLAG_INVERSE_TIME bit(3) // Interprets feed rate value as inverse time when set.
#define PL_COND_FLAG_SPINDLE_CW bit(4)
#define PL_COND_FLAG_SPINDLE_CCW bit(5)
#define PL_COND_FLAG_COOLANT_FLOOD bit(6)

View File

@ -716,7 +716,6 @@ static void protocol_exec_rt_suspend()
bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
} else {
spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
delay_sec(SAFETY_DOOR_SPINDLE_DELAY, DELAY_MODE_SYS_SUSPEND);
}
}
if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_RESTORE_CYCLE) {

View File

@ -33,6 +33,8 @@
void report_util_setting_prefix(uint8_t n) { serial_write('$'); print_uint8_base10(n); serial_write('='); }
static void report_util_line_feed() { printPgmString(PSTR("\r\n")); }
static void report_util_feedback_line_feed() { serial_write(']'); report_util_line_feed(); }
static void report_util_gcode_modes_G() { printPgmString(PSTR(" G")); }
static void report_util_gcode_modes_M() { printPgmString(PSTR(" M")); }
// static void report_util_comment_line_feed() { serial_write(')'); report_util_line_feed(); }
static void report_util_axis_values(float *axis_value) {
uint8_t idx;
@ -439,54 +441,48 @@ void report_gcode_modes()
#else
printPgmString(PSTR("[GC:G"));
#endif
switch (gc_state.modal.motion) {
case MOTION_MODE_SEEK : serial_write('0'); break;
case MOTION_MODE_LINEAR : serial_write('1'); break;
case MOTION_MODE_CW_ARC : serial_write('2'); break;
case MOTION_MODE_CCW_ARC : serial_write('3'); break;
case MOTION_MODE_NONE : printPgmString(PSTR("80")); break;
default:
printPgmString(PSTR("38."));
print_uint8_base10(gc_state.modal.motion - (MOTION_MODE_PROBE_TOWARD-2));
if (gc_state.modal.motion >= MOTION_MODE_PROBE_TOWARD) {
printPgmString(PSTR("38."));
print_uint8_base10(gc_state.modal.motion - (MOTION_MODE_PROBE_TOWARD-2));
} else {
print_uint8_base10(gc_state.modal.motion);
}
printPgmString(PSTR(" G"));
report_util_gcode_modes_G();
print_uint8_base10(gc_state.modal.coord_select+54);
printPgmString(PSTR(" G1"));
switch (gc_state.modal.plane_select) {
case PLANE_SELECT_XY : serial_write('7'); break;
case PLANE_SELECT_ZX : serial_write('8'); break;
case PLANE_SELECT_YZ : serial_write('9'); break;
report_util_gcode_modes_G();
print_uint8_base10(gc_state.modal.plane_select+17);
report_util_gcode_modes_G();
print_uint8_base10(21-gc_state.modal.units);
report_util_gcode_modes_G();
print_uint8_base10(gc_state.modal.distance+90);
report_util_gcode_modes_G();
print_uint8_base10(94-gc_state.modal.feed_rate);
if (gc_state.modal.program_flow) {
report_util_gcode_modes_M();
switch (gc_state.modal.program_flow) {
case PROGRAM_FLOW_PAUSED : serial_write('0'); break;
// case PROGRAM_FLOW_OPTIONAL_STOP : serial_write('1'); break; // M1 is ignored and not supported.
case PROGRAM_FLOW_COMPLETED_M2 :
case PROGRAM_FLOW_COMPLETED_M30 :
print_uint8_base10(gc_state.modal.program_flow);
break;
}
}
printPgmString(PSTR(" G2"));
if (gc_state.modal.units == UNITS_MODE_MM) { serial_write('1'); }
else { serial_write('0'); }
printPgmString(PSTR(" G9"));
if (gc_state.modal.distance == DISTANCE_MODE_ABSOLUTE) { serial_write('0'); }
else { serial_write('1'); }
printPgmString(PSTR(" G9"));
if (gc_state.modal.feed_rate == FEED_RATE_MODE_INVERSE_TIME) { serial_write('3'); }
else { serial_write('4'); }
printPgmString(PSTR(" M"));
switch (gc_state.modal.program_flow) {
case PROGRAM_FLOW_RUNNING : serial_write('0'); break;
case PROGRAM_FLOW_PAUSED : serial_write('1'); break;
case PROGRAM_FLOW_COMPLETED : serial_write('2'); break;
}
printPgmString(PSTR(" M"));
report_util_gcode_modes_M();
switch (gc_state.modal.spindle) {
case SPINDLE_ENABLE_CW : serial_write('3'); break;
case SPINDLE_ENABLE_CCW : serial_write('4'); break;
case SPINDLE_DISABLE : serial_write('5'); break;
}
printPgmString(PSTR(" M"));
report_util_gcode_modes_M();
#ifdef ENABLE_M7
if (gc_state.modal.coolant) { // Note: Multiple coolant states may be active at the same time.
if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_MIST) { serial_write('7'); }

View File

@ -152,7 +152,7 @@ void spindle_stop()
}
} else {
// Compute intermediate PWM value with linear spindle speed model.
// NOTE: A nonlinear model could be installed here, if required, but keep it light-weight.
// NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
sys.spindle_speed = rpm;
pwm_value = floor( (rpm-settings.rpm_min)*pwm_gradient + (SPINDLE_PWM_MIN_VALUE+0.5) );
}

View File

@ -58,12 +58,16 @@
// discarded when entirely consumed and completed by the segment buffer. Also, AMASS alters this
// data for its own use.
typedef struct {
uint8_t direction_bits;
#ifdef VARIABLE_SPINDLE
uint8_t spindle_pwm;
#endif
uint32_t steps[N_AXIS];
uint32_t step_event_count;
uint8_t direction_bits;
#ifdef VARIABLE_SPINDLE
#ifdef LASER_CONSTANT_POWER_PER_RATE
uint8_t is_pwm_rate_adjusted; // Tracks motions that require constant laser power/rate
#else
uint8_t spindle_pwm;
#endif
#endif
} st_block_t;
static st_block_t st_block_buffer[SEGMENT_BUFFER_SIZE-1];
@ -72,14 +76,17 @@ static st_block_t st_block_buffer[SEGMENT_BUFFER_SIZE-1];
// planner buffer. Once "checked-out", the steps in the segments buffer cannot be modified by
// the planner, where the remaining planner block steps still can.
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.
uint16_t n_step; // Number of step events to be executed for this segment
uint16_t cycles_per_tick; // Step distance traveled per ISR tick, aka step rate.
uint8_t st_block_index; // Stepper block data index. Uses this information to execute this segment.
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
uint8_t amass_level; // Indicates AMASS level for the ISR to execute this segment
#else
uint8_t prescaler; // Without AMASS, a prescaler is required to adjust for slow timing.
#endif
#ifdef LASER_CONSTANT_POWER_PER_RATE
uint8_t rate_adjusted_pwm;
#endif
} segment_t;
static segment_t segment_buffer[SEGMENT_BUFFER_SIZE];
@ -153,7 +160,7 @@ typedef struct {
float decelerate_after; // Deceleration ramp start measured from end of block (mm)
#ifdef LASER_CONSTANT_POWER_PER_RATE
float inv_rate; // Used by PWM laser mode
float inv_rate; // Used by PWM laser mode to speed up segment calculations.
#endif
} st_prep_t;
static st_prep_t prep;
@ -353,12 +360,20 @@ ISR(TIMER1_COMPA_vect)
#ifdef VARIABLE_SPINDLE
// Set real-time spindle output as segment is loaded, just prior to the first step.
spindle_set_speed(st.exec_block->spindle_pwm);
#ifdef LASER_CONSTANT_POWER_PER_RATE
spindle_set_speed(st.exec_segment->rate_adjusted_pwm);
#else
spindle_set_speed(st.exec_block->spindle_pwm);
#endif
#endif
} else {
// Segment buffer empty. Shutdown.
st_go_idle();
#ifdef LASER_CONSTANT_POWER_PER_RATE
// Ensure pwm is set properly upon completion of rate-controlled motion.
if (st.exec_block->is_pwm_rate_adjusted) { spindle_set_speed(SPINDLE_PWM_OFF_VALUE); }
#endif
system_set_exec_state_flag(EXEC_CYCLE_STOP); // Flag main program for cycle end
return; // Nothing to do but exit.
}
@ -650,8 +665,14 @@ void st_prep_buffer()
}
#ifdef LASER_CONSTANT_POWER_PER_RATE
// Pre-compute inverse programmed rate to speed up PWM updating per step segment.
prep.inv_rate = 1.0/pl_block->programmed_rate;
// Setup laser mode variables. PWM rate adjusted motions will always complete a motion with the
// spindle off.
st_prep_block->is_pwm_rate_adjusted = false;
if (settings.flags & BITFLAG_LASER_MODE) {
// Pre-compute inverse programmed rate to speed up PWM updating per step segment.
prep.inv_rate = 1.0/pl_block->programmed_rate;
if (!(pl_block->condition & PL_COND_MOTION_MASK)) { st_prep_block->is_pwm_rate_adjusted = true; }
}
#endif
}
@ -746,7 +767,7 @@ void st_prep_buffer()
}
}
#ifdef VARIABLE_SPINDLE
#ifdef VARIABLE_SPINDLE
bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM); // Force update whenever updating block.
#endif
}
@ -856,34 +877,36 @@ void st_prep_buffer()
}
} while (mm_remaining > prep.mm_complete); // **Complete** Exit loop. Profile complete.
/* -----------------------------------------------------------------------------------
Compute spindle speed PWM output for step segment
*/
#ifdef VARIABLE_SPINDLE
/* -----------------------------------------------------------------------------------
Compute spindle speed PWM output for step segment
*/
#ifdef LASER_CONSTANT_POWER_PER_RATE
if ((settings.flags & BITFLAG_LASER_MODE) || (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM)) {
if (st_prep_block->is_pwm_rate_adjusted || (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM)) {
if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) {
float rpm = pl_block->spindle_speed;
// NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate.
if (st_prep_block->is_pwm_rate_adjusted) { rpm *= (prep.current_speed * prep.inv_rate); }
// If current_speed is zero, then may need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE)
// but this would be instantaneous only and during a motion. May not matter at all.
prep_segment->rate_adjusted_pwm = spindle_compute_pwm_value(rpm);
} else {
sys.spindle_speed = 0.0;
prep_segment->rate_adjusted_pwm = SPINDLE_PWM_OFF_VALUE;
}
bit_false(sys.step_control,STEP_CONTROL_UPDATE_SPINDLE_PWM);
}
#else
if (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM) {
if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) {
st_prep_block->spindle_pwm = spindle_compute_pwm_value(pl_block->spindle_speed);
} else {
sys.spindle_speed = 0.0;
st_prep_block->spindle_pwm = SPINDLE_PWM_OFF_VALUE;
}
bit_false(sys.step_control,STEP_CONTROL_UPDATE_SPINDLE_PWM);
}
#endif
if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) {
float rpm = pl_block->spindle_speed;
#ifdef LASER_CONSTANT_POWER_PER_RATE
// NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate.
if (settings.flags & BITFLAG_LASER_MODE) {
// If current_speed is zero, then may need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE)
// but this would be instantaneous only and during a motion. May not matter at all.
rpm *= (prep.current_speed * prep.inv_rate);
}
#endif
st_prep_block->spindle_pwm = spindle_compute_pwm_value(rpm);
} else {
sys.spindle_speed = 0.0;
st_prep_block->spindle_pwm = SPINDLE_PWM_OFF_VALUE;
}
bit_false(sys.step_control,STEP_CONTROL_UPDATE_SPINDLE_PWM);
}
#endif
/* -----------------------------------------------------------------------------------