New compile options and inverse time bug fix.

- Apparently inverse time motion were not working for quite some time.
Goes to show how many people actually use it. The calculation was bad
and is now fixed in this update. It should now work correctly.

- `;` comment type is now supported. This is standard on LinuxCNC and
common on 3d printers. It was previously not supported due to not
existing in the NIST standard, which is out-dated.

- New compile-option to ECHO the line received. This should help users
experiencing very weird problems and help diagnose if there is
something amiss in the communication to Grbl.

- New compile-option to use the spindle direction pin D13 as a spindle
enable pin with PWM spindle speed on D11. This feature has been
requested often from the laser cutter community. Since spindle
direction isn’t really of much use, it seemed like good good trade.
Note that M4 spindle enable counter-clock-wise support is removed for
obvious reasons, while M3 and M5 still work.
This commit is contained in:
Sungeun Jeon 2015-03-27 18:13:18 -06:00
parent 4841dff712
commit ed29d8a122
9 changed files with 109 additions and 40 deletions

View File

@ -251,6 +251,22 @@
// spindle RPM output lower than this value will be set to this value. // 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) // #define MINIMUM_SPINDLE_PWM 5 // Default disabled. Uncomment to enable. Integer (0-255)
// By default on a 328p(Uno), Grbl combines the variable spindle PWM and the enable into one pin to help
// preserve I/O pins. For certain setups, these may need to be separate pins. This configure option uses
// the spindle direction pin(D13) as a separate spindle enable pin along with spindle speed PWM on pin D11.
// NOTE: This configure option only works with VARIABLE_SPINDLE enabled and a 328p processor (Uno).
// NOTE: With no direction pin, the spindle clockwise M4 g-code command will be removed. M3 and M5 still work.
// #define USE_SPINDLE_DIR_AS_ENABLE_PIN // Default disabled. Uncomment to enable.
// With this enabled, Grbl sends back an echo of the line it has received, which has been pre-parsed (spaces
// removed, capitalized letters, no comments) and is to be immediately executed by Grbl. Echoes will not be
// sent upon a line buffer overflow, but should for all normal lines sent to Grbl. For example, if a user
// sendss the line 'g1 x1.032 y2.45 (test comment)', Grbl will echo back in the form '[echo: G1X1.032Y2.45]'.
// NOTE: Only use this for debugging purposes!! When echoing, this takes up valuable resources and can effect
// performance. If absolutely needed for normal operation, the serial write buffer should be greatly increased
// to help minimize transmission waiting within the serial write protocol.
// #define REPORT_ECHO_LINE_RECEIVED // Default disabled. Uncomment to enable.
// Minimum planner junction speed. Sets the default minimum junction speed the planner plans to at // 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 // 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 // zero. This value controls how fast the machine moves through junctions with no regard for acceleration
@ -261,7 +277,8 @@
// Sets the minimum feed rate the planner will allow. Any value below it will be set to this minimum // Sets the minimum feed rate the planner will allow. Any value below it will be set to this minimum
// value. This also ensures that a planned motion always completes and accounts for any floating-point // value. This also ensures that a planned motion always completes and accounts for any floating-point
// round-off errors. A lower value than 1.0 mm/min may work in some cases, but we don't recommend it. // round-off errors. Although not recommended, a lower value than 1.0 mm/min will likely work in smaller
// machines, perhaps to 0.1mm/min, but your success may vary based on multiple factors.
#define MINIMUM_FEED_RATE 1.0 // (mm/min) #define MINIMUM_FEED_RATE 1.0 // (mm/min)
// Number of arc generation iterations by small angle approximation before exact arc trajectory // Number of arc generation iterations by small angle approximation before exact arc trajectory
@ -353,14 +370,20 @@
// #define HARD_LIMIT_FORCE_STATE_CHECK // Default disabled. Uncomment to enable. // #define HARD_LIMIT_FORCE_STATE_CHECK // Default disabled. Uncomment to enable.
// ---------------------------------------------------------------------------------------
// TODO: Install compile-time option to send numeric status codes rather than strings.
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
// COMPILE-TIME ERROR CHECKING OF DEFINE VALUES: // COMPILE-TIME ERROR CHECKING OF DEFINE VALUES:
#ifndef HOMING_CYCLE_0
#error "Required HOMING_CYCLE_0 not defined."
#endif
#if defined(USE_SPINDLE_DIR_AS_ENABLE_PIN) && !defined(VARIABLE_SPINDLE)
#error "USE_SPINDLE_DIR_AS_ENABLE_PIN may only be used with VARIABLE_SPINDLE enabled"
#endif
#if defined(USE_SPINDLE_DIR_AS_ENABLE_PIN) && !defined(CPU_MAP_ATMEGA328P)
#error "USE_SPINDLE_DIR_AS_ENABLE_PIN may only be used with a 328p processor"
#endif
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------

View File

@ -79,14 +79,22 @@
// Define spindle enable and spindle direction output pins. // Define spindle enable and spindle direction output pins.
#define SPINDLE_ENABLE_DDR DDRB #define SPINDLE_ENABLE_DDR DDRB
#define SPINDLE_ENABLE_PORT PORTB #define SPINDLE_ENABLE_PORT PORTB
#ifdef VARIABLE_SPINDLE // Z Limit pin and spindle enabled swapped to access hardware PWM on Pin 11. // Z Limit pin and spindle PWM/enable pin swapped to access hardware PWM on Pin 11.
#ifdef VARIABLE_SPINDLE
#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
// If enabled, spindle direction pin now used as spindle enable, while PWM remains on D11.
#define SPINDLE_ENABLE_BIT 5 // Uno Digital Pin 13 (NOTE: D13 can't be pulled-high input due to LED.)
#else
#define SPINDLE_ENABLE_BIT 3 // Uno Digital Pin 11 #define SPINDLE_ENABLE_BIT 3 // Uno Digital Pin 11
#endif
#else #else
#define SPINDLE_ENABLE_BIT 4 // Uno Digital Pin 12 #define SPINDLE_ENABLE_BIT 4 // Uno Digital Pin 12
#endif #endif
#ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
#define SPINDLE_DIRECTION_DDR DDRB #define SPINDLE_DIRECTION_DDR DDRB
#define SPINDLE_DIRECTION_PORT PORTB #define SPINDLE_DIRECTION_PORT PORTB
#define SPINDLE_DIRECTION_BIT 5 // Uno Digital Pin 13 (NOTE: D13 can't be pulled-high input due to LED.) #define SPINDLE_DIRECTION_BIT 5 // Uno Digital Pin 13 (NOTE: D13 can't be pulled-high input due to LED.)
#endif
// Define flood and mist coolant enable output pins. // Define flood and mist coolant enable output pins.
// NOTE: Uno analog pins 4 and 5 are reserved for an i2c interface, and may be installed at // NOTE: Uno analog pins 4 and 5 are reserved for an i2c interface, and may be installed at
@ -136,9 +144,9 @@
#define WAVE3_REGISTER WGM23 #define WAVE3_REGISTER WGM23
// NOTE: On the 328p, these must be the same as the SPINDLE_ENABLE settings. // NOTE: On the 328p, these must be the same as the SPINDLE_ENABLE settings.
#define SPINDLE_PWM_DDR SPINDLE_ENABLE_DDR #define SPINDLE_PWM_DDR DDRB
#define SPINDLE_PWM_PORT SPINDLE_ENABLE_PORT #define SPINDLE_PWM_PORT PORTB
#define SPINDLE_PWM_BIT SPINDLE_ENABLE_BIT // Shared with SPINDLE_ENABLE. #define SPINDLE_PWM_BIT 3 // Uno Digital Pin 11
#endif // End of VARIABLE_SPINDLE #endif // End of VARIABLE_SPINDLE
#endif #endif

View File

@ -281,11 +281,16 @@ uint8_t gc_execute_line(char *line)
case 2: case 30: gc_block.modal.program_flow = PROGRAM_FLOW_COMPLETED; break; // Program end and reset case 2: case 30: gc_block.modal.program_flow = PROGRAM_FLOW_COMPLETED; break; // Program end and reset
} }
break; break;
case 3: case 4: case 5: #ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
case 4:
#endif
case 3: case 5:
word_bit = MODAL_GROUP_M7; word_bit = MODAL_GROUP_M7;
switch(int_value) { switch(int_value) {
case 3: gc_block.modal.spindle = SPINDLE_ENABLE_CW; break; case 3: gc_block.modal.spindle = SPINDLE_ENABLE_CW; break;
#ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
case 4: gc_block.modal.spindle = SPINDLE_ENABLE_CCW; break; case 4: gc_block.modal.spindle = SPINDLE_ENABLE_CCW; break;
#endif
case 5: gc_block.modal.spindle = SPINDLE_DISABLE; break; case 5: gc_block.modal.spindle = SPINDLE_DISABLE; break;
} }
break; break;

View File

@ -23,7 +23,7 @@
// Grbl versioning system // Grbl versioning system
#define GRBL_VERSION "0.9i" #define GRBL_VERSION "0.9i"
#define GRBL_VERSION_BUILD "20150315" #define GRBL_VERSION_BUILD "20150327"
// Define standard libraries used by Grbl. // Define standard libraries used by Grbl.
#include <avr/io.h> #include <avr/io.h>

View File

@ -320,7 +320,7 @@ uint8_t plan_check_full_buffer()
// Adjust feed_rate value to mm/min depending on type of rate input (normal, inverse time, or rapids) // Adjust feed_rate value to mm/min depending on type of rate input (normal, inverse time, or rapids)
// TODO: Need to distinguish a rapids vs feed move for overrides. Some flag of some sort. // TODO: Need to distinguish a rapids vs feed move for overrides. Some flag of some sort.
if (feed_rate < 0) { feed_rate = SOME_LARGE_VALUE; } // Scaled down to absolute max/rapids rate later if (feed_rate < 0) { feed_rate = SOME_LARGE_VALUE; } // Scaled down to absolute max/rapids rate later
else if (invert_feed_rate) { feed_rate = block->millimeters/feed_rate; } else if (invert_feed_rate) { feed_rate *= block->millimeters; }
if (feed_rate < MINIMUM_FEED_RATE) { feed_rate = MINIMUM_FEED_RATE; } // Prevents step generation round-off condition. if (feed_rate < MINIMUM_FEED_RATE) { feed_rate = MINIMUM_FEED_RATE; } // Prevents step generation round-off condition.
// Calculate the unit vector of the line move and the block maximum feed rate and acceleration scaled // Calculate the unit vector of the line move and the block maximum feed rate and acceleration scaled

View File

@ -21,6 +21,11 @@
#include "grbl.h" #include "grbl.h"
// Define different comment types for pre-parsing.
#define COMMENT_NONE 0
#define COMMENT_TYPE_PARENTHESES 1
#define COMMENT_TYPE_SEMICOLON 2
static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated. static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
@ -33,6 +38,10 @@ static void protocol_execute_line(char *line)
protocol_execute_realtime(); // Runtime command check point. protocol_execute_realtime(); // Runtime command check point.
if (sys.abort) { return; } // Bail to calling function upon system abort if (sys.abort) { return; } // Bail to calling function upon system abort
#ifdef REPORT_ECHO_LINE_RECEIVED
report_echo_line_received(line);
#endif
if (line[0] == 0) { if (line[0] == 0) {
// Empty or comment line. Send status message for syncing purposes. // Empty or comment line. Send status message for syncing purposes.
report_status_message(STATUS_OK); report_status_message(STATUS_OK);
@ -82,7 +91,7 @@ void protocol_main_loop()
// Primary loop! Upon a system abort, this exits back to main() to reset the system. // Primary loop! Upon a system abort, this exits back to main() to reset the system.
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
uint8_t iscomment = false; uint8_t comment = COMMENT_NONE;
uint8_t char_counter = 0; uint8_t char_counter = 0;
uint8_t c; uint8_t c;
for (;;) { for (;;) {
@ -101,14 +110,14 @@ void protocol_main_loop()
if ((c == '\n') || (c == '\r')) { // End of line reached if ((c == '\n') || (c == '\r')) { // End of line reached
line[char_counter] = 0; // Set string termination character. line[char_counter] = 0; // Set string termination character.
protocol_execute_line(line); // Line is complete. Execute it! protocol_execute_line(line); // Line is complete. Execute it!
iscomment = false; comment = COMMENT_NONE;
char_counter = 0; char_counter = 0;
} else { } else {
if (iscomment) { if (comment != COMMENT_NONE) {
// Throw away all comment characters // Throw away all comment characters
if (c == ')') { if (c == ')') {
// End of comment. Resume line. // End of comment. Resume line. But, not if semicolon type comment.
iscomment = false; if (comment == COMMENT_TYPE_PARENTHESES) { comment = COMMENT_NONE; }
} }
} else { } else {
if (c <= ' ') { if (c <= ' ') {
@ -121,9 +130,10 @@ void protocol_main_loop()
// NOTE: This doesn't follow the NIST definition exactly, but is good enough for now. // NOTE: This doesn't follow the NIST definition exactly, but is good enough for now.
// In the future, we could simply remove the items within the comments, but retain the // In the future, we could simply remove the items within the comments, but retain the
// comment control characters, so that the g-code parser can error-check it. // comment control characters, so that the g-code parser can error-check it.
iscomment = true; comment = COMMENT_TYPE_PARENTHESES;
// } else if (c == ';') { } else if (c == ';') {
// Comment character to EOL NOT SUPPORTED. LinuxCNC definition. Not NIST. // NOTE: ';' comment to EOL is a LinuxCNC definition. Not NIST.
comment = COMMENT_TYPE_SEMICOLON;
// TODO: Install '%' feature // TODO: Install '%' feature
// } else if (c == '%') { // } else if (c == '%') {
@ -136,7 +146,7 @@ void protocol_main_loop()
} else if (char_counter >= (LINE_BUFFER_SIZE-1)) { } else if (char_counter >= (LINE_BUFFER_SIZE-1)) {
// Detect line buffer overflow. Report error and reset line buffer. // Detect line buffer overflow. Report error and reset line buffer.
report_status_message(STATUS_OVERFLOW); report_status_message(STATUS_OVERFLOW);
iscomment = false; comment = COMMENT_NONE;
char_counter = 0; char_counter = 0;
} else if (c >= 'a' && c <= 'z') { // Upcase lowercase } else if (c >= 'a' && c <= 'z') { // Upcase lowercase
line[char_counter++] = c-'a'+'A'; line[char_counter++] = c-'a'+'A';
@ -206,6 +216,8 @@ void protocol_execute_realtime()
// to do what is needed before resetting, like killing the incoming stream. The // to do what is needed before resetting, like killing the incoming stream. The
// same could be said about soft limits. While the position is not lost, the incoming // same could be said about soft limits. While the position is not lost, the incoming
// stream could be still engaged and cause a serious crash if it continues afterwards. // stream could be still engaged and cause a serious crash if it continues afterwards.
// TODO: Allow status reports during a critical alarm. Still need to think about implications of this.
// if (sys.rt_exec_state & EXEC_STATUS_REPORT) { // if (sys.rt_exec_state & EXEC_STATUS_REPORT) {
// report_realtime_status(); // report_realtime_status();
// bit_false_atomic(sys.rt_exec_state,EXEC_STATUS_REPORT); // bit_false_atomic(sys.rt_exec_state,EXEC_STATUS_REPORT);

View File

@ -400,6 +400,15 @@ void report_build_info(char *line)
} }
// Prints the character string line Grbl has received from the user, which has been pre-parsed,
// and has been sent into protocol_execute_line() routine to be executed by Grbl.
void report_echo_line_received(char *line)
{
printPgmString(PSTR("[echo: ")); printString(line);
printPgmString(PSTR("]\r\n"));
}
// Prints real-time data. This function grabs a real-time snapshot of the stepper subprogram // Prints real-time data. This function grabs a real-time snapshot of the stepper subprogram
// and the actual location of the CNC machine. Users may change the following function to their // and the actual location of the CNC machine. Users may change the following function to their
// specific needs, but the desired real-time data report must be as short as possible. This is // specific needs, but the desired real-time data report must be as short as possible. This is

View File

@ -87,6 +87,9 @@ void report_grbl_help();
// Prints Grbl global settings // Prints Grbl global settings
void report_grbl_settings(); void report_grbl_settings();
// Prints an echo of the pre-parsed line received right before execution.
void report_echo_line_received(char *line);
// Prints realtime status report // Prints realtime status report
void report_realtime_status(); void report_realtime_status();

View File

@ -24,16 +24,21 @@
void spindle_init() void spindle_init()
{ {
// On the Uno, spindle enable and PWM are shared. Other CPUs have seperate enable pin. // Configure variable spindle PWM and enable pin, if requried. On the Uno, PWM and enable are
// combined unless configured otherwise.
#ifdef VARIABLE_SPINDLE #ifdef VARIABLE_SPINDLE
SPINDLE_PWM_DDR |= (1<<SPINDLE_PWM_BIT); // Configure as PWM output pin. SPINDLE_PWM_DDR |= (1<<SPINDLE_PWM_BIT); // Configure as PWM output pin.
#ifndef CPU_MAP_ATMEGA328P #if defined(CPU_MAP_ATMEGA2560) || defined(USE_SPINDLE_DIR_AS_ENABLE_PIN)
SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin. SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
#endif #endif
// Configure no variable spindle and only enable pin.
#else #else
SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin. SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
#endif #endif
#ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin. SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.
#endif
spindle_stop(); spindle_stop();
} }
@ -43,7 +48,7 @@ void spindle_stop()
// On the Uno, spindle enable and PWM are shared. Other CPUs have seperate enable pin. // On the Uno, spindle enable and PWM are shared. Other CPUs have seperate enable pin.
#ifdef VARIABLE_SPINDLE #ifdef VARIABLE_SPINDLE
TCCRA_REGISTER &= ~(1<<COMB_BIT); // Disable PWM. Output voltage is zero. TCCRA_REGISTER &= ~(1<<COMB_BIT); // Disable PWM. Output voltage is zero.
#ifndef CPU_MAP_ATMEGA328P #if defined(CPU_MAP_ATMEGA2560) || defined(USE_SPINDLE_DIR_AS_ENABLE_PIN)
SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT); // Set pin to low. SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT); // Set pin to low.
#endif #endif
#else #else
@ -61,11 +66,13 @@ void spindle_set_state(uint8_t state, float rpm)
} else { } else {
#ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
if (state == SPINDLE_ENABLE_CW) { if (state == SPINDLE_ENABLE_CW) {
SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT); SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT);
} else { } else {
SPINDLE_DIRECTION_PORT |= (1<<SPINDLE_DIRECTION_BIT); SPINDLE_DIRECTION_PORT |= (1<<SPINDLE_DIRECTION_BIT);
} }
#endif
#ifdef VARIABLE_SPINDLE #ifdef VARIABLE_SPINDLE
// TODO: Install the optional capability for frequency-based output for servos. // TODO: Install the optional capability for frequency-based output for servos.
@ -92,9 +99,11 @@ void spindle_set_state(uint8_t state, float rpm)
#endif #endif
OCR_REGISTER = current_pwm; // Set PWM pin output OCR_REGISTER = current_pwm; // Set PWM pin output
#ifdef CPU_MAP_ATMEGA2560 // On the Uno, spindle enable and PWM are shared. // On the Uno, spindle enable and PWM are shared, unless otherwise specified.
#if defined(CPU_MAP_ATMEGA2560) || defined(USE_SPINDLE_DIR_AS_ENABLE_PIN)
SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT); SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
#endif #endif
#else #else
SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT); SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
#endif #endif