From 7e67395463b7fedbd0ac2e03aef2e84875d8dcbc Mon Sep 17 00:00:00 2001 From: Sonny Jeon Date: Wed, 1 Oct 2014 20:22:16 -0600 Subject: [PATCH] Updated variable spindle and new probing. Minor bug fixes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Minor bug fix for variable spindle PWM output. Values smaller than the minimum RPM for the spindle would overflow the PWM value. Thanks Rob! - Created an optional minimum spindle PWM low-mark value as a compile-time option. This is for special circumstances when the PWM has to be at a certain level to be read by the spindle controller. - Refactored the new probing commands (G38.3, G38.4, G38.5) code to work better with the rest of Grbl’s systems. - Refactored mc_probe() and mc_arc() to accept the mode of the command, i.e. clockwise vs counter, toward vs away, etc. This is to make these functions independent of gcode state variables. - Removed the pull off motion in the probing cycle. This is not an official operation and was added for user simplicity, but wrongly did so. So bye bye. - Created a configure probe invert mask function to handle the different probe pin setting and probing cycle modes with a single mask. - Minor bug fix with reporting motion modes via $G. G38.2 wasn’t showing up. It now does, along with the other new probing commands. - Refactored some of the new pin configurations for the future of Grbl. - --- config.h | 8 ++++- cpu_map.h | 10 +++--- gcode.c | 81 +++++++++++++++++++++++++++++------------------ gcode.h | 9 ++++-- motion_control.c | 69 ++++++++++++++++++---------------------- motion_control.h | 13 +++++--- probe.c | 41 ++++++++++++------------ probe.h | 20 ++++-------- report.c | 16 +++++++--- spindle_control.c | 12 +++++-- system.h | 6 ++-- 11 files changed, 159 insertions(+), 126 deletions(-) diff --git a/config.h b/config.h index b3dcbbd..378ad6a 100644 --- a/config.h +++ b/config.h @@ -156,7 +156,7 @@ // The hardware PWM output on pin D11 is required for variable spindle output voltages. // #define VARIABLE_SPINDLE // Default disabled. Uncomment to enable. -// Use by the variable spindle output only. These parameters set the maximum and minimum spindle speed +// Used by the variable spindle output only. These parameters set the maximum and minimum spindle speed // "S" g-code values to correspond to the maximum and minimum pin voltages. There are 256 discrete and // equally divided voltage bins between the maximum and minimum spindle speeds. So for a 5V pin, 1000 // max rpm, and 250 min rpm, the spindle output voltage would be set for the following "S" commands: @@ -164,6 +164,12 @@ #define SPINDLE_MAX_RPM 1000.0 // Max spindle RPM. This value is equal to 100% duty cycle on the PWM. #define SPINDLE_MIN_RPM 0.0 // Min spindle RPM. This value is equal to (1/256) duty cycle on the PWM. +// Used by variable spindle output only. This forces the PWM output to a minimum duty cycle when enabled. +// When disabled, the PWM pin will still read 0V. Most users will not need this option, but it may be +// useful in certain scenarios. This setting does not update the minimum spindle RPM calculations. Any +// spindle RPM output lower than this value will be set to this value. +// #define MINIMUM_SPINDLE_PWM 5 // Default disabled. Uncomment to enable. Integer (0-255) + // 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 // zero. This value controls how fast the machine moves through junctions with no regard for acceleration diff --git a/cpu_map.h b/cpu_map.h index e918fb2..7295513 100644 --- a/cpu_map.h +++ b/cpu_map.h @@ -206,11 +206,11 @@ // a later date if flash and memory space allows. #define COOLANT_FLOOD_DDR DDRC #define COOLANT_FLOOD_PORT PORTC - #define COOLANT_FLOOD_BIT 4 // Uno Analog Pin 3 + #define COOLANT_FLOOD_BIT 1 // Uno Analog Pin 1 #ifdef ENABLE_M7 // Mist coolant disabled by default. See config.h to enable/disable. #define COOLANT_MIST_DDR DDRC #define COOLANT_MIST_PORT PORTC - #define COOLANT_MIST_BIT 5 // Uno Analog Pin 4 + #define COOLANT_MIST_BIT 2 // Uno Analog Pin 2 #endif // Define user-control pinouts (cycle start, reset, feed hold) input pins. @@ -218,9 +218,9 @@ #define PINOUT_DDR DDRC #define PINOUT_PIN PINC #define PINOUT_PORT PORTC - #define PIN_RESET 1 // Uno Analog Pin 1 - #define PIN_FEED_HOLD 2 // Uno Analog Pin 2 - #define PIN_CYCLE_START 3 // Uno Analog Pin 3 + #define PIN_RESET 3 // Uno Analog Pin 3 + #define PIN_FEED_HOLD 4 // Uno Analog Pin 4 + #define PIN_CYCLE_START 5 // Uno Analog Pin 5 #define PINOUT_INT PCIE1 // Pin change interrupt enable pin #define PINOUT_INT_vect PCINT1_vect #define PINOUT_PCMSK PCMSK1 // Pin change interrupt register diff --git a/gcode.c b/gcode.c index 4afa027..6c482cd 100644 --- a/gcode.c +++ b/gcode.c @@ -123,8 +123,7 @@ uint8_t gc_execute_line(char *line) char letter; float value; uint8_t int_value = 0; - uint16_t mantissa = 0; // NOTE: For mantissa values > 255, variable type must be changed to uint16_t. - uint8_t probe_mode = 0; + uint16_t mantissa = 0; while (line[char_counter] != 0) { // Loop until no more g-code words in line. @@ -210,22 +209,10 @@ uint8_t gc_execute_line(char *line) case 3: gc_block.modal.motion = MOTION_MODE_CCW_ARC; break; // G3 case 38: switch(mantissa) { - case 20: // G38.2 - gc_block.modal.motion = MOTION_MODE_PROBE; - break; - case 30: // G38.3 - gc_block.modal.motion = MOTION_MODE_PROBE; - probe_mode = PROBE_NO_ERROR; - break; - case 40: // G38.4 - gc_block.modal.motion = MOTION_MODE_PROBE; - probe_mode = PROBE_AWAY; - break; - case 50: // G38.5 - gc_block.modal.motion = MOTION_MODE_PROBE; - probe_mode = PROBE_AWAY | PROBE_NO_ERROR; - break; - + 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. @@ -811,7 +798,8 @@ uint8_t gc_execute_line(char *line) } } break; - case MOTION_MODE_PROBE: + case MOTION_MODE_PROBE_TOWARD: case MOTION_MODE_PROBE_TOWARD_NO_ERROR: + case MOTION_MODE_PROBE_AWAY: case MOTION_MODE_PROBE_AWAY_NO_ERROR: // [G38 Errors]: Target is same current. No axis words. Cutter compensation is enabled. Feed rate // is undefined. Probe is triggered. NOTE: Probe check moved to probe cycle. Instead of returning // an error, it issues an alarm to prevent further motion to the probe. It's also done there to @@ -838,6 +826,9 @@ uint8_t gc_execute_line(char *line) need to update the state and execute the block according to the order-of-execution. */ + // [0. Non-specific/common error-checks and miscellaneous setup]: + gc_state.line_number = gc_block.values.n; + // [1. Comments feedback ]: NOT SUPPORTED // [2. Set feed rate mode ]: @@ -923,13 +914,13 @@ uint8_t gc_execute_line(char *line) // and absolute and incremental modes. if (axis_command) { #ifdef USE_LINE_NUMBERS - mc_line(gc_block.values.xyz, -1.0, false, gc_block.values.n); + mc_line(gc_block.values.xyz, -1.0, false, gc_state.line_number); #else mc_line(gc_block.values.xyz, -1.0, false); #endif } #ifdef USE_LINE_NUMBERS - mc_line(parameter_data, -1.0, false, gc_block.values.n); + mc_line(parameter_data, -1.0, false, gc_state.line_number); #else mc_line(parameter_data, -1.0, false); #endif @@ -959,41 +950,71 @@ uint8_t gc_execute_line(char *line) switch (gc_state.modal.motion) { case MOTION_MODE_SEEK: #ifdef USE_LINE_NUMBERS - mc_line(gc_block.values.xyz, -1.0, false, gc_block.values.n); + mc_line(gc_block.values.xyz, -1.0, false, gc_state.line_number); #else mc_line(gc_block.values.xyz, -1.0, false); #endif break; case MOTION_MODE_LINEAR: #ifdef USE_LINE_NUMBERS - mc_line(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, gc_block.values.n); + mc_line(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, gc_state.line_number); #else mc_line(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate); #endif break; - case MOTION_MODE_CW_ARC: case MOTION_MODE_CCW_ARC: + case MOTION_MODE_CW_ARC: #ifdef USE_LINE_NUMBERS mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r, - gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear, gc_block.values.n); + gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear, true, gc_state.line_number); #else mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r, - gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear); + gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear, true); + #endif + break; + case MOTION_MODE_CCW_ARC: + #ifdef USE_LINE_NUMBERS + mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r, + gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear, false, gc_state.line_number); + #else + mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r, + gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear, false); #endif break; - case MOTION_MODE_PROBE: + case MOTION_MODE_PROBE_TOWARD: // NOTE: gc_block.values.xyz is returned from mc_probe_cycle with the updated position value. So // upon a successful probing cycle, the machine position and the returned value should be the same. #ifdef USE_LINE_NUMBERS - mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, probe_mode, gc_block.values.n); + mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, false, false, gc_state.line_number); #else - mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, probe_mode); + mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, false, false); + #endif + break; + case MOTION_MODE_PROBE_TOWARD_NO_ERROR: + #ifdef USE_LINE_NUMBERS + mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, false, true, gc_state.line_number); + #else + mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, false, true); + #endif + break; + case MOTION_MODE_PROBE_AWAY: + #ifdef USE_LINE_NUMBERS + mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, true, false, gc_state.line_number); + #else + mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, true, false); + #endif + break; + case MOTION_MODE_PROBE_AWAY_NO_ERROR: + #ifdef USE_LINE_NUMBERS + mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, true, true, gc_state.line_number); + #else + mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, true, true); #endif } // As far as the parser is concerned, the position is now == target. In reality the // motion control system might still be processing the action and the real tool position // in any intermediate location. - memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); // gc.position[] = target[]; + memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); // gc_state.position[] = gc_block.values.xyz[] } } diff --git a/gcode.h b/gcode.h index 0e196a9..88a5384 100644 --- a/gcode.h +++ b/gcode.h @@ -71,8 +71,11 @@ #define MOTION_MODE_LINEAR 1 // G1 #define MOTION_MODE_CW_ARC 2 // G2 #define MOTION_MODE_CCW_ARC 3 // G3 -#define MOTION_MODE_PROBE 4 // G38.2, G38.3, G38.4, G38.5 -#define MOTION_MODE_NONE 5 // G80 +#define MOTION_MODE_PROBE_TOWARD 4 // G38.2 +#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 // Modal Group G2: Plane select #define PLANE_SELECT_XY 0 // G17 (Default: Must be zero) @@ -164,7 +167,7 @@ typedef struct { float spindle_speed; // RPM float feed_rate; // Millimeters/min uint8_t tool; // Tracks tool number. NOT USED. -// int32_t line_number; // Last line number sent + int32_t line_number; // Last line number sent float position[N_AXIS]; // Where the interpreter considers the tool to be at this point in the code diff --git a/motion_control.c b/motion_control.c index ed62d33..dbefe89 100644 --- a/motion_control.c +++ b/motion_control.c @@ -95,7 +95,7 @@ // Execute an arc in offset mode format. position == current xyz, target == target xyz, -// offset == offset from current xyz, axis_XXX defines circle plane in tool space, axis_linear is +// offset == offset from current xyz, axis_X defines circle plane in tool space, axis_linear is // the direction of helical travel, radius == circle radius, isclockwise boolean. Used // for vector transformation direction. // The arc is approximated by generating a huge number of tiny, linear segments. The chordal tolerance @@ -103,10 +103,10 @@ // distance from segment to the circle when the end points both lie on the circle. #ifdef USE_LINE_NUMBERS void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate, - uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, int32_t line_number) + uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc, int32_t line_number) #else void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate, - uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear) + uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc) #endif { float center_axis0 = position[axis_0] + offset[axis_0]; @@ -118,7 +118,7 @@ // CCW angle between position and target from circle center. Only one atan2() trig computation required. float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1); - if (gc_state.modal.motion == MOTION_MODE_CW_ARC) { // Correct atan2 output per direction + if (is_clockwise_arc) { // Correct atan2 output per direction if (angular_travel >= 0) { angular_travel -= 2*M_PI; } } else { if (angular_travel <= 0) { angular_travel += 2*M_PI; } @@ -287,9 +287,11 @@ void mc_homing_cycle() // Perform tool length probe cycle. Requires probe switch. // NOTE: Upon probe failure, the program will be stopped and placed into ALARM state. #ifdef USE_LINE_NUMBERS - void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, uint8_t mode, int32_t line_number) + void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, uint8_t is_probe_away, + uint8_t is_no_error, int32_t line_number) #else - void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, uint8_t mode) + void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, uint8_t is_probe_away, + uint8_t is_no_error) #endif { // TODO: Need to update this cycle so it obeys a non-auto cycle start. @@ -298,10 +300,14 @@ void mc_homing_cycle() // Finish all queued commands and empty planner buffer before starting probe cycle. protocol_buffer_synchronize(); uint8_t auto_start_state = sys.auto_start; // Store run state - uint8_t perform_pull_off = 1; + // Initialize probing control variables + sys.probe_succeeded = false; // Re-initialize probe history before beginning cycle. + probe_configure_invert_mask(is_probe_away); + // After syncing, check if probe is already triggered. If so, halt and issue alarm. - if (probe_get_state(mode) && probe_errors_enabled(mode)) { + // NOTE: This probe initialization error applies to all probing cycles. + if ( probe_get_state() ) { // Check probe pin state. bit_true_atomic(sys.execute, EXEC_CRIT_EVENT); protocol_execute_runtime(); } @@ -314,8 +320,8 @@ void mc_homing_cycle() mc_line(target, feed_rate, invert_feed_rate); #endif - // Activate the probing monitor in the stepper module. - sys.probe_state = PROBE_ACTIVE | mode; + // Activate the probing state monitor in the stepper module. + sys.probe_state = PROBE_ACTIVE; // Perform probing cycle. Wait here until probe is triggered or motion completes. bit_true_atomic(sys.execute, EXEC_CYCLE_START); @@ -323,17 +329,17 @@ void mc_homing_cycle() protocol_execute_runtime(); if (sys.abort) { return; } // Check for system abort } while ((sys.state != STATE_IDLE) && (sys.state != STATE_QUEUED)); - - // Probing motion complete. If the probe has not been triggered, error out. - if (sys.probe_state & PROBE_ACTIVE) { - - if (probe_errors_enabled(mode)) { - bit_true_atomic(sys.execute, EXEC_CRIT_EVENT); - } else { - perform_pull_off = 0; - probe_finalize(0); - } + + // Probing cycle complete! + + // Set state variables and error out, if the probe failed and cycle with error is enabled. + if (sys.probe_state == PROBE_ACTIVE) { + if (is_no_error) { memcpy(sys.probe_position, sys.position, sizeof(float)*N_AXIS); } + else { bit_true_atomic(sys.execute, EXEC_CRIT_EVENT); } + } else { + sys.probe_succeeded = true; // Indicate to system the probing cycle completed successfully. } + sys.probe_state = PROBE_OFF; // Ensure probe state monitor is disabled. protocol_execute_runtime(); // Check and execute run-time commands if (sys.abort) { return; } // Check for system abort @@ -342,24 +348,11 @@ void mc_homing_cycle() plan_reset(); // Reset planner buffer. Zero planner positions. Ensure probing motion is cleared. plan_sync_position(); // Sync planner position to current machine position. - if (perform_pull_off) { - // Pull-off triggered probe to the trigger location since we had to decelerate a little beyond - // it to stop the machine in a controlled manner. - uint8_t idx; - for(idx=0; idx> PROBE_AWAY_BIT) & 1) << PROBE_BIT; - return mode ^ ((PROBE_PIN & PROBE_MASK) ^ probe_invert_mask); -} +uint8_t probe_get_state() { return((PROBE_PIN & PROBE_MASK) ^ probe_invert_mask); } -uint8_t probe_errors_enabled(uint8_t mode) { - return !(mode & PROBE_NO_ERROR); -} - -void probe_finalize(uint8_t probe_succeeded) { - sys.probe_state = PROBE_OFF; - sys.probe_succeeded = probe_succeeded; - memcpy(sys.probe_position, sys.position, sizeof(float)*N_AXIS); - bit_true(sys.execute, EXEC_FEED_HOLD); -} // Monitors probe pin state and records the system position when detected. Called by the // stepper ISR per ISR tick. // NOTE: This function must be extremely efficient as to not bog down the stepper ISR. void probe_state_monitor() { - if (sys.probe_state != PROBE_OFF) { - if (probe_get_state(sys.probe_state)) { - probe_finalize(1); + if (sys.probe_state == PROBE_ACTIVE) { + if (probe_get_state()) { + sys.probe_state = PROBE_OFF; + memcpy(sys.probe_position, sys.position, sizeof(float)*N_AXIS); + bit_true(sys.execute, EXEC_FEED_HOLD); } } } diff --git a/probe.h b/probe.h index 17028eb..968d7ec 100644 --- a/probe.h +++ b/probe.h @@ -22,25 +22,19 @@ #define probe_h // Values that define the probing state machine. -#define PROBE_OFF 0 // No probing. (Must be zero.) +#define PROBE_OFF 0 // Probing disabled or not in use. (Must be zero.) #define PROBE_ACTIVE 1 // Actively watching the input pin. -// Probe direction and error modes -#define PROBE_AWAY 2 // G38.4, G38.5 -#define PROBE_NO_ERROR 4 // G38.3, G38.5 - -#define PROBE_AWAY_BIT 1 -#define PROBE_NO_ERROR_BIT 2 - // Probe pin initialization routine. void probe_init(); -// Returns probe pin state. -uint8_t probe_get_state(uint8_t mode); +// Called by probe_init() and the mc_probe() routines. Sets up the probe pin invert mask to +// appropriately set the pin logic according to setting for normal-high/normal-low operation +// and the probing cycle modes for toward-workpiece/away-from-workpiece. +void probe_configure_invert_mask(uint8_t is_probe_away); -uint8_t probe_errors_enabled(uint8_t mode); - -void probe_finalize(uint8_t probe_succeeded); +// Returns probe pin state. Triggered = true. Called by gcode parser and probe state monitor. +uint8_t probe_get_state(); // Monitors probe pin state and records the system position when detected. Called by the // stepper ISR per ISR tick. diff --git a/report.c b/report.c index 9235f37..58f01d0 100644 --- a/report.c +++ b/report.c @@ -281,12 +281,18 @@ void report_ngc_parameters() // Print current gcode parser mode state void report_gcode_modes() { + printPgmString(PSTR("[")); + switch (gc_state.modal.motion) { - case MOTION_MODE_SEEK : printPgmString(PSTR("[G0")); break; - case MOTION_MODE_LINEAR : printPgmString(PSTR("[G1")); break; - case MOTION_MODE_CW_ARC : printPgmString(PSTR("[G2")); break; - case MOTION_MODE_CCW_ARC : printPgmString(PSTR("[G3")); break; - case MOTION_MODE_NONE : printPgmString(PSTR("[G80")); break; + case MOTION_MODE_SEEK : printPgmString(PSTR("G0")); break; + case MOTION_MODE_LINEAR : printPgmString(PSTR("G1")); break; + case MOTION_MODE_CW_ARC : printPgmString(PSTR("G2")); break; + case MOTION_MODE_CCW_ARC : printPgmString(PSTR("G3")); break; + case MOTION_MODE_PROBE_TOWARD : printPgmString(PSTR("G38.2")); break; + case MOTION_MODE_PROBE_TOWARD_NO_ERROR : printPgmString(PSTR("G38.3")); break; + case MOTION_MODE_PROBE_AWAY : printPgmString(PSTR("G38.4")); break; + case MOTION_MODE_PROBE_AWAY_NO_ERROR : printPgmString(PSTR("G38.5")); break; + case MOTION_MODE_NONE : printPgmString(PSTR("G80")); break; } printPgmString(PSTR(" G")); diff --git a/spindle_control.c b/spindle_control.c index b841084..de773ee 100644 --- a/spindle_control.c +++ b/spindle_control.c @@ -86,10 +86,16 @@ void spindle_run(uint8_t direction, float rpm) #define SPINDLE_RPM_RANGE (SPINDLE_MAX_RPM-SPINDLE_MIN_RPM) TCCRA_REGISTER = (1< SPINDLE_RPM_RANGE ) { rpm = SPINDLE_RPM_RANGE; } // Prevent uint8 overflow + if ( rpm < SPINDLE_MIN_RPM ) { rpm = 0; } + else { + rpm -= SPINDLE_MIN_RPM; + if ( rpm > SPINDLE_RPM_RANGE ) { rpm = SPINDLE_RPM_RANGE; } // Prevent uint8 overflow + } uint8_t current_pwm = floor( rpm*(255.0/SPINDLE_RPM_RANGE) + 0.5); - OCR_REGISTER = current_pwm; + #ifdef MINIMUM_SPINDLE_PWM + if (current_pwm < MINIMUM_SPINDLE_PWM) { current_pwm = MINIMUM_SPINDLE_PWM; } + #endif + OCR_REGISTER = current_pwm; // Set PWM pin output #ifndef CPU_MAP_ATMEGA328P // On the Uno, spindle enable and PWM are shared. SPINDLE_ENABLE_PORT |= (1<