New report module. 6 persistent work coordinates. New G-codes and settings. README and minor bug updates

(NOTE: This push is likely buggy so proceed with caution. Just
uploading to let people know where we're going.)

- New report.c module. Moved all feedback functions into this module to
centralize these processes. Includes realtime status reports, status
messages, feedback messages.

- Official support 6 work coordinate systems (G54-G59), which are
persistently held in EEPROM memory.

- New g-code support: G28.1, G30.1 stores current machine position as a
home position into EEPROM. G10 L20 Px stores current machine position
into work coordinates without needing to explicitly send XYZ words.

- Homing performed with '$H' command. G28/G30 no longer start the
homing cycle. This is how it's supposed to be.

- New settings: Stepper enable invert and n_arc correction installed.

- Updated and changed up some limits and homing functionality. Pull-off
travel will now move after the homing cycle regardless of hard limits
enabled. Fixed direction of pull-off travel (went wrong way).

- Started on designing an internal Grbl command protocol based on the
'$' settings letter. Commands with non numeric characters after '$'
will perform switch commands, homing cycle, jogging, printing
paramters, etc. Much more to do here.

- Updated README to reflect all of the new features.
This commit is contained in:
Sonny Jeon 2012-11-01 09:37:27 -06:00
parent 5d8c3dcbd7
commit e0a9054e32
17 changed files with 847 additions and 621 deletions

View File

@ -1,6 +1,7 @@
# Part of Grbl
#
# Copyright (c) 2009-2011 Simen Svale Skogsrud
# Copyright (c) 2012 Sungeun K. Jeon
#
# Grbl is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -31,7 +32,8 @@ DEVICE ?= atmega328p
CLOCK = 16000000
PROGRAMMER ?= -c avrisp2 -P usb
OBJECTS = main.o motion_control.o gcode.o spindle_control.o coolant_control.o serial.o \
protocol.o stepper.o eeprom.o settings.o planner.o nuts_bolts.o limits.o print.o
protocol.o stepper.o eeprom.o settings.o planner.o nuts_bolts.o limits.o \
print.o report.o
# FUSES = -U hfuse:w:0xd9:m -U lfuse:w:0x24:m
FUSES = -U hfuse:w:0xd2:m -U lfuse:w:0xff:m
# update that line with this when programmer is back up:

View File

@ -80,10 +80,6 @@
#define CMD_CYCLE_START '~'
#define CMD_RESET 0x18 // ctrl-x
// Specifies the number of work coordinate systems grbl will support (G54 - G59).
// This parameter must be one or greater, currently supporting up to a value of 6.
#define N_COORDINATE_SYSTEM 1
// The temporal resolution of the acceleration management subsystem. Higher number give smoother
// acceleration but may impact performance.
// NOTE: Increasing this parameter will help any resolution related issues, especially with machines
@ -106,13 +102,6 @@
// never reach its target. This parameter should always be greater than zero.
#define MINIMUM_STEPS_PER_MINUTE 800 // (steps/min) - Integer value only
// Number of arc generation iterations by small angle approximation before exact arc trajectory
// correction. This parameter maybe decreased if there are issues with the accuracy of the arc
// generations. In general, the default value is more than enough for the intended CNC applications
// of grbl, and should be on the order or greater than the size of the buffer to help with the
// computational efficiency of generating arcs.
#define N_ARC_CORRECTION 25 // Integer (1-255)
// Time delay increments performed during a dwell. The default value is set at 50ms, which provides
// a maximum time delay of roughly 55 minutes, more than enough for most any application. Increasing
// this delay will increase the maximum dwell time linearly, but also reduces the responsiveness of
@ -172,5 +161,17 @@
// words, the steppers never disable for users that require this.
// -> NOW INSTALLED IN SETTINGS #define STEPPER_IDLE_LOCK_TIME 25 // (milliseconds) - Integer > 0
// Number of arc generation iterations by small angle approximation before exact arc trajectory
// correction. This parameter maybe decreased if there are issues with the accuracy of the arc
// generations. In general, the default value is more than enough for the intended CNC applications
// of grbl, and should be on the order or greater than the size of the buffer to help with the
// computational efficiency of generating arcs.
// -> NOW INSTALLED IN SETTINGS #define N_ARC_CORRECTION 25 // Integer (1-255)
// Specifies the number of work coordinate systems grbl will support (G54 - G59).
// This parameter must be one or greater, currently supporting up to a value of 6.
// -> NOW CODED INTO SETTINGS.C #define N_COORDINATE_SYSTEM 6
// TODO: Install compile-time option to send numeric status codes rather than strings.
#endif

90
gcode.c
View File

@ -32,6 +32,7 @@
#include "coolant_control.h"
#include "errno.h"
#include "protocol.h"
#include "report.h"
// Define modal group internal numbers for checking multiple command violations and tracking the
// type of command that is called in the block. A modal group is a group of g-code commands that are
@ -64,9 +65,12 @@
#define NON_MODAL_NONE 0
#define NON_MODAL_DWELL 1 // G4
#define NON_MODAL_SET_COORDINATE_DATA 2 // G10
#define NON_MODAL_GO_HOME 3 // G28,G30
#define NON_MODAL_SET_COORDINATE_OFFSET 4 // G92
#define NON_MODAL_RESET_COORDINATE_OFFSET 5 //G92.1
#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_SET_COORDINATE_OFFSET 7 // G92
#define NON_MODAL_RESET_COORDINATE_OFFSET 8 //G92.1
typedef struct {
uint8_t status_code; // Parser status for current block
@ -182,22 +186,20 @@ uint8_t gc_execute_line(char *line)
case 19: select_plane(Y_AXIS, Z_AXIS, X_AXIS); break;
case 20: gc.inches_mode = true; break;
case 21: gc.inches_mode = false; break;
// NOTE: G28.1, G30.1 sets home position parameters. Not currently supported.
case 28: case 30:
// NOTE: G28.1, G30.1 sets home position parameters. Not currently supported.
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
non_modal_action = NON_MODAL_GO_HOME;
} else {
FAIL(STATUS_SETTING_DISABLED);
int_value = trunc(10*value); // Multiply by 10 to pick up G92.1
switch(int_value) {
case 280: non_modal_action = NON_MODAL_GO_HOME_0; break;
case 281: non_modal_action = NON_MODAL_SET_HOME_0; break;
case 300: non_modal_action = NON_MODAL_GO_HOME_1; break;
case 301: non_modal_action = NON_MODAL_SET_HOME_1; break;
default: FAIL(STATUS_UNSUPPORTED_STATEMENT);
}
break;
case 53: absolute_override = true; break;
case 54: case 55: case 56: case 57: case 58: case 59:
int_value -= 54; // Compute coordinate system row index (0=G54,1=G55,...)
if (int_value < N_COORDINATE_SYSTEM) {
sys.coord_select = int_value;
} else {
FAIL(STATUS_UNSUPPORTED_STATEMENT);
}
sys.coord_select = int_value-54;
break;
case 80: gc.motion_mode = MOTION_MODE_CANCEL; break;
case 90: gc.absolute_mode = true; break;
@ -307,6 +309,13 @@ uint8_t gc_execute_line(char *line)
// [*M7,M8,M9]: Update coolant state
coolant_run(gc.coolant_mode);
// [G54,G55,...,G59]: Coordinate system selection
if ( bit_istrue(modal_group_words,bit(MODAL_GROUP_12)) ) { // Check if called in block
float coord_data[N_AXIS];
if (!(settings_read_coord_data(sys.coord_select,coord_data))) { return(STATUS_SETTING_READ_FAIL); }
memcpy(sys.coord_system,coord_data,sizeof(coord_data));
}
// [G4,G10,G28,G30,G92,G92.1]: Perform dwell, set coordinate system data, homing, or set axis offsets.
// NOTE: These commands are in the same modal group, hence are mutually exclusive. G53 is in this
// modal group and do not effect these actions.
@ -320,30 +329,41 @@ uint8_t gc_execute_line(char *line)
break;
case NON_MODAL_SET_COORDINATE_DATA:
int_value = trunc(p); // Convert p value to int.
if (l != 2 || (int_value < 1 || int_value > N_COORDINATE_SYSTEM)) { // L2 only. P1=G54, P2=G55, ...
if ((l != 2 && l != 20) || (int_value < 1 || int_value > N_COORDINATE_SYSTEM)) { // L2 and L20. P1=G54, P2=G55, ...
FAIL(STATUS_UNSUPPORTED_STATEMENT);
} else if (!axis_words) { // No axis words.
} else if (!axis_words && l==2) { // No axis words.
FAIL(STATUS_INVALID_STATEMENT);
} else {
int_value--; // Adjust p to be inline with row array index.
// Update axes defined only in block. Always in machine coordinates. Can change non-active system.
uint8_t i;
for (i=0; i<=2; i++) { // Axes indices are consistent, so loop may be used.
if ( bit_istrue(axis_words,bit(i)) ) { sys.coord_system[int_value][i] = target[i]; }
int_value--; // Adjust P index to EEPROM coordinate data indexing.
if (l == 20) {
settings_write_coord_data(int_value,gc.position);
// Update system coordinate system if currently active.
if (sys.coord_select == int_value) { memcpy(sys.coord_system,gc.position,sizeof(gc.position)); }
} else {
float coord_data[N_AXIS];
if (!settings_read_coord_data(int_value,coord_data)) { return(STATUS_SETTING_READ_FAIL); }
// Update axes defined only in block. Always in machine coordinates. Can change non-active system.
uint8_t i;
for (i=0; i<N_AXIS; i++) { // Axes indices are consistent, so loop may be used.
if ( bit_istrue(axis_words,bit(i)) ) { coord_data[i] = target[i]; }
}
settings_write_coord_data(int_value,coord_data);
// Update system coordinate system if currently active.
if (sys.coord_select == int_value) { memcpy(sys.coord_system,coord_data,sizeof(coord_data)); }
}
}
axis_words = 0; // Axis words used. Lock out from motion modes by clearing flags.
break;
case NON_MODAL_GO_HOME:
case NON_MODAL_GO_HOME_0: case NON_MODAL_GO_HOME_1:
// Move to intermediate position before going home. Obeys current coordinate system and offsets
// and absolute and incremental modes.
if (axis_words) {
// Apply absolute mode coordinate offsets or incremental mode offsets.
uint8_t i;
for (i=0; i<=2; i++) { // Axes indices are consistent, so loop may be used.
for (i=0; i<N_AXIS; i++) { // Axes indices are consistent, so loop may be used.
if ( bit_istrue(axis_words,bit(i)) ) {
if (gc.absolute_mode) {
target[i] += sys.coord_system[sys.coord_select][i] + sys.coord_offset[i];
target[i] += sys.coord_system[i] + sys.coord_offset[i];
} else {
target[i] += gc.position[i];
}
@ -353,9 +373,19 @@ uint8_t gc_execute_line(char *line)
}
mc_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], settings.default_seek_rate, false);
}
mc_go_home();
// Retreive G28/30 go-home position data (in machine coordinates) from EEPROM
float coord_data[N_AXIS];
uint8_t home_select = SETTING_INDEX_G28;
if (non_modal_action == NON_MODAL_GO_HOME_1) { home_select = SETTING_INDEX_G30; }
if (!settings_read_coord_data(home_select,coord_data)) { return(STATUS_SETTING_READ_FAIL); }
mc_line(coord_data[X_AXIS], coord_data[Y_AXIS], coord_data[Z_AXIS], settings.default_seek_rate, false);
axis_words = 0; // Axis words used. Lock out from motion modes by clearing flags.
break;
case NON_MODAL_SET_HOME_0: case NON_MODAL_SET_HOME_1:
home_select = SETTING_INDEX_G28;
if (non_modal_action == NON_MODAL_SET_HOME_1) { home_select = SETTING_INDEX_G30; }
settings_write_coord_data(home_select,gc.position);
break;
case NON_MODAL_SET_COORDINATE_OFFSET:
if (!axis_words) { // No axis words
FAIL(STATUS_INVALID_STATEMENT);
@ -365,7 +395,7 @@ uint8_t gc_execute_line(char *line)
uint8_t i;
for (i=0; i<=2; i++) { // Axes indices are consistent, so loop may be used.
if (bit_istrue(axis_words,bit(i)) ) {
sys.coord_offset[i] = gc.position[i]-sys.coord_system[sys.coord_select][i]-target[i];
sys.coord_offset[i] = gc.position[i]-sys.coord_system[i]-target[i];
}
}
}
@ -402,7 +432,7 @@ uint8_t gc_execute_line(char *line)
if ( bit_istrue(axis_words,bit(i)) ) {
if (!absolute_override) { // Do not update target in absolute override mode
if (gc.absolute_mode) {
target[i] += sys.coord_system[sys.coord_select][i] + sys.coord_offset[i]; // Absolute mode
target[i] += sys.coord_system[i] + sys.coord_offset[i]; // Absolute mode
} else {
target[i] += gc.position[i]; // Incremental mode
}
@ -421,6 +451,10 @@ uint8_t gc_execute_line(char *line)
else { mc_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], settings.default_seek_rate, false); }
break;
case MOTION_MODE_LINEAR:
// TODO: Inverse time requires F-word with each statement. Need to do a check. Also need
// to check for initial F-word upon startup. Maybe just set to zero upon initialization
// and after an inverse time move and then check for non-zero feed rate each time. This
// should be efficient and effective.
if (!axis_words) { FAIL(STATUS_INVALID_STATEMENT);}
else { mc_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS],
(gc.inverse_feed_rate_mode) ? inverse_feed_rate : gc.feed_rate, gc.inverse_feed_rate_mode); }
@ -546,7 +580,7 @@ uint8_t gc_execute_line(char *line)
// 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.position, target, sizeof(float)*3); // gc.position[] = target[];
memcpy(gc.position, target, sizeof(target)); // gc.position[] = target[];
}
// M0,M1,M2,M30: Perform non-running program flow actions. During a program pause, the buffer may

View File

@ -31,6 +31,7 @@
#include "planner.h"
#include "protocol.h"
#include "limits.h"
#include "report.h"
#define MICROSECONDS_PER_ACCELERATION_TICK (1000000/ACCELERATION_TICKS_PER_SECOND)
@ -50,6 +51,11 @@ void limits_init()
// homing cycles and will not respond correctly. Upon user request or need, there may be a
// special pinout for an e-stop, but it is generally recommended to just directly connect
// your e-stop switch to the Arduino reset pin, since it is the most correct way to do this.
// TODO: This interrupt may be used to manage the homing cycle directly with the main stepper
// interrupt without adding too much to it. All it would need is some way to stop one axis
// when its limit is triggered and continue the others. This may reduce some of the code, but
// would make Grbl a little harder to read and understand down road. Holding off on this until
// we move on to new hardware or flash space becomes an issue. If it ain't broke, don't fix it.
ISR(LIMIT_INT_vect)
{
// Only enter if the system alarm is not active.
@ -57,13 +63,8 @@ ISR(LIMIT_INT_vect)
// Kill all processes upon hard limit event.
if ((LIMIT_PIN & LIMIT_MASK) ^ LIMIT_MASK) {
mc_alarm(); // Initiate system kill.
protocol_status_message(STATUS_HARD_LIMIT); // Print ok in interrupt since system killed.
report_status_message(STATUS_HARD_LIMIT); // Print ok in interrupt since system killed.
}
// else {
// TODO: When leaving a switch, this interrupt can be activated upon detecting a pin
// change to high. If so, need to start a countdown timer to check the pin again after
// a debounce period to not falsely re-engage the alarm. Not essential, but *could* be
// a minor annoyance.
}
}
@ -190,7 +191,8 @@ static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
void limits_go_home()
{
STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT); // Enable steppers, but not the cycle.
// Enable only the steppers, not the cycle. Cycle should be complete.
st_wake_up();
// Jog all axes toward home to engage their limit switches at faster homing seek rate.
homing_cycle(false, false, true, true, false, settings.homing_seek_rate); // First jog the z axis

7
main.c
View File

@ -35,6 +35,7 @@
#include "gcode.h"
#include "protocol.h"
#include "limits.h"
#include "report.h"
#include "settings.h"
#include "serial.h"
@ -68,9 +69,8 @@ int main(void)
// releases will auto-reset the machine position back to [0,0,0] if an abort is used while
// grbl is moving the machine.
int32_t last_position[3];
float last_coord_system[N_COORDINATE_SYSTEM][3];
memcpy(last_position, sys.position, sizeof(sys.position)); // last_position[] = sys.position[]
memcpy(last_coord_system, sys.coord_system, sizeof(sys.coord_system)); // last_coord_system[] = sys.coord_system[]
// TODO: Last coordinate system method.
// Reset system.
memset(&sys, 0, sizeof(sys)); // Clear all system variables
@ -86,7 +86,6 @@ int main(void)
// Reload last known machine position and work systems. G92 coordinate offsets are reset.
memcpy(sys.position, last_position, sizeof(last_position)); // sys.position[] = last_position[]
memcpy(sys.coord_system, last_coord_system, sizeof(last_coord_system)); // sys.coord_system[] = last_coord_system[]
gc_set_current_position(last_position[X_AXIS],last_position[Y_AXIS],last_position[Z_AXIS]);
plan_set_current_position(last_position[X_AXIS],last_position[Y_AXIS],last_position[Z_AXIS]);
@ -97,6 +96,8 @@ int main(void)
sys.auto_start = true;
}
// TODO: Install G20/G21 unit default into settings and load appropriate settings.
report_init_message();
}
protocol_execute_runtime();

View File

@ -110,7 +110,7 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
float linear_per_segment = linear_travel/segments;
/* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector,
and phi is the angle of rotation. Based on the solution approach by Jens Geisler.
and phi is the angle of rotation. Solution approach by Jens Geisler.
r_T = [cos(phi) -sin(phi);
sin(phi) cos(phi] * r ;
@ -150,14 +150,14 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
for (i = 1; i<segments; i++) { // Increment (segments-1)
if (count < N_ARC_CORRECTION) {
if (count < settings.n_arc_correction) {
// Apply vector rotation matrix
r_axisi = r_axis0*sin_T + r_axis1*cos_T;
r_axis0 = r_axis0*cos_T - r_axis1*sin_T;
r_axis1 = r_axisi;
count++;
} else {
// Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments.
// Arc correction to radius vector. Computed only every n_arc_correction increments.
// Compute exact location by applying transformation matrix from initial radius vector(=-offset).
cos_Ti = cos(i*theta_per_segment);
sin_Ti = sin(i*theta_per_segment);
@ -200,30 +200,33 @@ void mc_go_home()
{
plan_synchronize(); // Empty all motions in buffer before homing.
PCICR &= ~(1 << LIMIT_INT); // Disable hard limits pin change interrupt
plan_clear_position();
limits_go_home(); // Perform homing routine.
// Upon completion, reset all internal position vectors (g-code parser, planner, system)
gc_clear_position();
// The machine should now be homed and machine zero has been located. Upon completion,
// reset planner and system internal position vectors, but not gcode parser position yet.
plan_clear_position();
clear_vector_float(sys.position);
// If hard limits enabled, move all axes off limit switches before enabling the hard limit
// pin change interrupt. This should help prevent the switches from falsely tripping.
// NOTE: G-code parser was circumvented so its position needs to be updated explicitly.
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) {
int8_t x_dir, y_dir, z_dir;
x_dir = y_dir = z_dir = 1;
if (bit_istrue(settings.homing_dir_mask,bit(X_DIRECTION_BIT))) { x_dir = -1; }
if (bit_istrue(settings.homing_dir_mask,bit(Y_DIRECTION_BIT))) { y_dir = -1; }
if (bit_istrue(settings.homing_dir_mask,bit(Z_DIRECTION_BIT))) { z_dir = -1; }
mc_line(x_dir*settings.homing_pulloff, y_dir*settings.homing_pulloff,
z_dir*settings.homing_pulloff, settings.homing_feed_rate, false);
st_cycle_start(); // Move it. Nothing should be in the buffer except this motion.
plan_synchronize(); // Make sure the motion completes.
gc_set_current_position(sys.position[X_AXIS],sys.position[Y_AXIS],sys.position[Z_AXIS]);
PCICR |= (1 << LIMIT_INT); // Re-enable hard limits.
}
// Pull-off all axes from limit switches before continuing motion. This provides some initial
// clearance off the switches and should also help prevent them from falsely tripping when
// hard limits are enabled.
int8_t x_dir, y_dir, z_dir;
x_dir = y_dir = z_dir = -1;
if (bit_istrue(settings.homing_dir_mask,bit(X_DIRECTION_BIT))) { x_dir = 1; }
if (bit_istrue(settings.homing_dir_mask,bit(Y_DIRECTION_BIT))) { y_dir = 1; }
if (bit_istrue(settings.homing_dir_mask,bit(Z_DIRECTION_BIT))) { z_dir = 1; }
mc_line(x_dir*settings.homing_pulloff, y_dir*settings.homing_pulloff,
z_dir*settings.homing_pulloff, settings.homing_feed_rate, false);
st_cycle_start(); // Move it. Nothing should be in the buffer except this motion.
plan_synchronize(); // Make sure the motion completes.
// Explicitly update the gcode parser position since it was circumvented by the pull-off maneuver.
gc_set_current_position(sys.position[X_AXIS],sys.position[Y_AXIS],sys.position[Z_AXIS]);
// If hard limits feature enabled, re-enable hard limits interrupt after homing cycle.
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { PCICR |= (1 << LIMIT_INT); }
}
@ -234,12 +237,8 @@ void mc_alarm()
// Only this function can set the system alarm. This is done to prevent multiple kill calls
// by different processes.
if (bit_isfalse(sys.execute, EXEC_ALARM)) {
sys.execute |= EXEC_ALARM; // Set alarm to allow subsystem disable for certain settings.
sys.auto_start = false; // Disable auto cycle start.
// TODO: When Grbl system status is installed, set position lost state if the cycle is active.
// if (sys.cycle_start) { POSITION LOST }
// Set system alarm flag.
sys.execute |= EXEC_ALARM;
// Immediately force stepper, spindle, and coolant to stop.
st_go_idle();
spindle_stop();

View File

@ -30,7 +30,8 @@
#define false 0
#define true 1
#define X_AXIS 0
#define N_AXIS 3 // Number of axes
#define X_AXIS 0 // Axis indexing value
#define Y_AXIS 1
#define Z_AXIS 2
@ -39,7 +40,7 @@
// Useful macros
#define clear_vector(a) memset(a, 0, sizeof(a))
#define clear_vector_float(a) memset(a, 0.0, sizeof(a))
#define clear_vector_float(a) memset(a, 0.0, sizeof(float)*3)
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
@ -75,6 +76,11 @@
// #define bit(6)
// #define bit(7)
// Define Grbl system states for sys.state
// Define position lost in states?
// Define global system variables
typedef struct {
uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
@ -86,10 +92,9 @@ typedef struct {
// NOTE: This may need to be a volatile variable, if problems arise.
uint8_t coord_select; // Active work coordinate system number. Default: 0=G54.
float coord_system[N_COORDINATE_SYSTEM][3]; // Work coordinate systems (G54+). Stores offset from
// absolute machine position in mm.
// Rows: Work system number (0=G54,1=G55,...5=G59), Columns: XYZ Offsets
float coord_offset[3]; // Retains the G92 coordinate offset (work coordinates) relative to
float coord_system[N_AXIS]; // Current work coordinate system (G54+). Stores offset from absolute machine
// position in mm. Loaded from EEPROM when called.
float coord_offset[N_AXIS]; // Retains the G92 coordinate offset (work coordinates) relative to
// machine zero in mm.
volatile uint8_t cycle_start; // Cycle start flag. Set by stepper subsystem or main program.

View File

@ -31,124 +31,16 @@
#include <avr/pgmspace.h>
#include "stepper.h"
#include "planner.h"
#include "report.h"
#include "motion_control.h"
static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
static uint8_t char_counter; // Last character counter in line variable.
static uint8_t iscomment; // Comment/block delete flag for processor to ignore comment characters.
// Method to handle status messages, from an 'ok' to report any 'error' that has occurred.
// Errors can originate from the g-code parser, settings module, or a critical error, such
// as a triggered hard limit.
void protocol_status_message(uint8_t status_code)
{
// TODO: Compile time option to only return numeric codes for GUIs.
if (status_code == 0) { // STATUS_OK
printPgmString(PSTR("ok\r\n"));
} else {
printPgmString(PSTR("error: "));
switch(status_code) {
case STATUS_BAD_NUMBER_FORMAT:
printPgmString(PSTR("Bad number format")); break;
case STATUS_EXPECTED_COMMAND_LETTER:
printPgmString(PSTR("Expected command letter")); break;
case STATUS_UNSUPPORTED_STATEMENT:
printPgmString(PSTR("Unsupported statement")); break;
case STATUS_FLOATING_POINT_ERROR:
printPgmString(PSTR("Floating point error")); break;
case STATUS_MODAL_GROUP_VIOLATION:
printPgmString(PSTR("Modal group violation")); break;
case STATUS_INVALID_STATEMENT:
printPgmString(PSTR("Invalid statement")); break;
case STATUS_HARD_LIMIT:
printPgmString(PSTR("Limit triggered")); break;
case STATUS_SETTING_DISABLED:
printPgmString(PSTR("Grbl setting disabled")); break;
case STATUS_SETTING_STEPS_NEG:
printPgmString(PSTR("Steps/mm must be > 0.0")); break;
case STATUS_SETTING_STEP_PULSE_MIN:
printPgmString(PSTR("Step pulse must be >= 3 microseconds")); break;
case STATUS_SETTING_READ_FAIL:
printPgmString(PSTR("Failed to read EEPROM settings. Using defaults")); break;
}
printPgmString(PSTR("\r\n"));
}
}
// Prints miscellaneous messages. This serves as a centralized method to provide additional
// user feedback for things that do not pass through the protocol_execute_line() function
// and are not errors or confirmations, such as setup warnings and how to exit alarms.
void protocol_misc_message(uint8_t message_code)
{
// TODO: Install silence misc messages option in settings
switch(message_code) {
case MESSAGE_SYSTEM_ALARM:
printPgmString(PSTR("<ALARM: Reset to continue>")); break;
case MESSAGE_HOMING_ENABLE:
printPgmString(PSTR("warning: Install all axes limit switches before use")); break;
}
printPgmString(PSTR("\r\n"));
}
void protocol_status_report()
{
// TODO: Status report data is written to the user here. This function should be able to grab a
// real-time snapshot of the stepper subprogram and the actual location of the CNC machine. At a
// minimum, status report should return real-time location information. Other important information
// may be distance to go on block, processed block id, and feed rate. A secondary, non-critical
// status report may include g-code state, i.e. inch mode, plane mode, absolute mode, etc.
// The report generated must be as short as possible, yet still provide the user easily readable
// information, i.e. '[0.23,120.4,2.4]'. This is necessary as it minimizes the computational
// overhead and allows grbl to keep running smoothly, especially with g-code programs with fast,
// short line segments and interface setups that require real-time status reports (5-20Hz).
// **Under construction** Bare-bones status report. Provides real-time machine position relative to
// the system power on location (0,0,0) and work coordinate position (G54 and G92 applied).
// The following are still needed: user setting of output units (mm|inch), compressed (non-human
// readable) data for interfaces?, save last known position in EEPROM?, code optimizations, solidify
// the reporting schemes, move to a separate .c file for easy user accessibility, and setting the
// home position by the user (likely through '$' setting interface).
// Successfully tested at a query rate of 10-20Hz while running a gauntlet of programs at various
// speeds.
uint8_t i;
int32_t current_position[3]; // Copy current state of the system position variable
memcpy(current_position,sys.position,sizeof(sys.position));
float print_position[3];
// Report machine position
printPgmString(PSTR("MPos:["));
for (i=0; i<= 2; i++) {
print_position[i] = current_position[i]/settings.steps_per_mm[i];
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { print_position[i] *= INCH_PER_MM; }
printFloat(print_position[i]);
if (i < 2) { printPgmString(PSTR(",")); }
else { printPgmString(PSTR("]")); }
}
// Report work position
printPgmString(PSTR(",WPos:["));
for (i=0; i<= 2; i++) {
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
print_position[i] -= (sys.coord_system[sys.coord_select][i]+sys.coord_offset[i])*INCH_PER_MM;
} else {
print_position[i] -= sys.coord_system[sys.coord_select][i]+sys.coord_offset[i];
}
printFloat(print_position[i]);
if (i < 2) { printPgmString(PSTR(",")); }
else { printPgmString(PSTR("]")); }
}
printPgmString(PSTR("\r\n"));
}
void protocol_init()
{
// Print grbl initialization message
printPgmString(PSTR("\r\nGrbl " GRBL_VERSION));
printPgmString(PSTR("\r\n'$' to dump current settings\r\n"));
char_counter = 0; // Reset line input
iscomment = false;
}
@ -160,29 +52,43 @@ void protocol_init()
// This is a way to execute runtime commands asynchronously (aka multitasking) with grbl's g-code
// parsing and planning functions. This function also serves as an interface for the interrupts to
// set the system runtime flags, where only the main program handles them, removing the need to
// define more computationally-expensive volatile variables.
// NOTE: The sys.execute variable flags are set by the serial read subprogram, except where noted.
// define more computationally-expensive volatile variables. This also provides a controlled way to
// execute certain tasks without having two or more instances of the same task, such as the planner
// recalculating the buffer upon a feedhold or override.
// NOTE: The sys.execute variable flags are set by the serial read subprogram, except where noted,
// but may be set by any process, such as a switch pin change interrupt when pinouts are installed.
void protocol_execute_runtime()
{
if (sys.execute) { // Enter only if any bit flag is true
uint8_t rt_exec = sys.execute; // Avoid calling volatile multiple times
// System alarm. Something has gone wrong. Disable everything until system reset.
// System alarm. Something has gone wrong. Disable everything by entering an infinite
// loop until system reset/abort.
if (rt_exec & EXEC_ALARM) {
if (bit_isfalse(sys.execute,EXEC_RESET)) { protocol_misc_message(MESSAGE_SYSTEM_ALARM); }
while (bit_isfalse(sys.execute,EXEC_RESET)) { sleep_mode(); }
if (bit_isfalse(rt_exec,EXEC_RESET)) { // Ignore loop if reset is already issued
report_feedback_message(MESSAGE_SYSTEM_ALARM);
while (bit_isfalse(sys.execute,EXEC_RESET)) { sleep_mode(); }
}
bit_false(sys.execute,EXEC_ALARM);
}
// System abort. Steppers have already been force stopped.
if (rt_exec & EXEC_RESET) {
sys.abort = true;
// If the cycle is active before killing the motion, the event will likely caused a loss
// of position since there is no controlled deceleration(feed hold) to a stop.
// TODO: Add force home option upon position lost. Need to verify that cycle start isn't
// set false by anything but the stepper module. Also, need to look at a better place for
// this. Main.c?
// if (sys.cycle_start) { protocol_feedback_message(MESSAGE_POSITION_LOST); }
return; // Nothing else to do but exit.
}
// Execute and serial print status
if (rt_exec & EXEC_STATUS_REPORT) {
protocol_status_report();
report_realtime_status();
bit_false(sys.execute,EXEC_STATUS_REPORT);
}
@ -207,40 +113,94 @@ void protocol_execute_runtime()
bit_false(sys.execute,EXEC_CYCLE_START);
}
}
// Overrides flag byte (sys.override) and execution should be installed here, since they
// are runtime and require a direct and controlled interface to the main stepper program.
}
// Executes one line of input according to protocol
// Directs and executes one line of formatted input from protocol_process. While mostly
// incoming streaming g-code blocks, this also executes Grbl internal commands, such as
// settings, initiating the homing cycle, and toggling switch states. This differs from
// the runtime command module by being susceptible to when Grbl is ready to execute the
// next line during a cycle, so for switches like block delete, the switch only effects
// the lines that are processed afterward, not necessarily real-time during a cycle,
// since there are motions already stored in the buffer. However, this 'lag' should not
// be an issue, since these commands are not typically used during a cycle.
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] == '$') {
// TODO: Re-write this '$' as a way to change runtime settings without having to reset, i.e.
// auto-starting, status query output formatting and type, jog mode (axes, direction, and
// nominal feedrate), toggle block delete, etc. This differs from the EEPROM settings, as they
// are considered defaults and loaded upon startup/reset.
// This use is envisioned where '$' itself dumps settings and help. Defined characters
// proceeding the '$' may be used to setup modes, such as jog mode with a '$J=X100' for X-axis
// motion with a nominal feedrate of 100mm/min. Writing EEPROM settings will likely stay the
// same or similar. Should be worked out in upcoming releases.
return(settings_execute_line(line)); // Delegate lines starting with '$' to the settings module
// } else if {
//
// JOG MODE
//
// 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
// be a basic toggle on/off with controlled acceleration and deceleration to prevent skipped
// steps. The user would supply the desired feedrate, axis to move, and direction. Toggle on would
// start motion and toggle off would initiate a deceleration to stop. One could 'feather' the
// motion by repeatedly toggling to slow the motion to the desired location. Location data would
// need to be updated real-time and supplied to the user through status queries.
// 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.
uint8_t char_counter = 1;
float parameter, value;
switch( line[char_counter] ) {
case 0 :
report_grbl_help();
return(STATUS_OK);
break;
// case '#' :
// if ( line[++char_counter] == 0 ) {
// // Print all parameters
// return(STATUS_OK);
// } else {
// return(STATUS_UNSUPPORTED_STATEMENT);
// }
// case 'G' : // Start up blocks
// if(!read_float(line, &char_counter, &parameter)) { return(STATUS_BAD_NUMBER_FORMAT); }
// if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); }
// // Extract startup block, execute, and store.
// for (char_counter = 0; char_counter < LINE_BUFFER_SIZE-3; char_counter++) {
// line[char_counter] = line[char_counter+3];
// }
// uint8_t status = gc_execute_line(line);
// if (status) { return(status); }
// else { settings_store_startup_block(line); }
// break;
case 'H' : // Perform homing cycle
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
mc_go_home();
return(STATUS_OK);
} 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
// // be a basic toggle on/off with controlled acceleration and deceleration to prevent skipped
// // steps. The user would supply the desired feedrate, axis to move, and direction. Toggle on would
// // start motion and toggle off would initiate a deceleration to stop. One could 'feather' the
// // motion by repeatedly toggling to slow the motion to the desired location. Location data would
// // need to be updated real-time and supplied to the user through status queries.
// // 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 'P' : // Print g-code parameters and parser state
// if(line[char_counter] != 0) { return(STATUS_UNSUPPORTED_STATEMENT); }
//
// break;
// case 'S' : // Switch methods
// // Opt stop and block delete are referred to as switches.
// // How to store home position and work offsets real-time??
// break;
// // Parse $parameter=value settings
default :
if(!read_float(line, &char_counter, &parameter)) {
return(STATUS_BAD_NUMBER_FORMAT);
}
if(line[char_counter++] != '=') {
return(STATUS_UNSUPPORTED_STATEMENT);
}
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));
}
} else {
return(gc_execute_line(line)); // Everything else is gcode
// TODO: Install option to set system alarm upon any error code received back from the
@ -250,7 +210,8 @@ uint8_t protocol_execute_line(char *line)
}
// Process one line of incoming serial data. Remove unneeded characters and capitalize.
// Process and report status one line of incoming serial data. Performs an initial filtering
// by removing spaces and comments and capitalizing all letters.
void protocol_process()
{
uint8_t c;
@ -265,10 +226,10 @@ void protocol_process()
if (char_counter > 0) {// Line is complete. Then execute!
line[char_counter] = 0; // Terminate string
protocol_status_message(protocol_execute_line(line));
report_status_message(protocol_execute_line(line));
} else {
// Empty or comment line. Skip block.
protocol_status_message(STATUS_OK); // Send status message for syncing purposes.
report_status_message(STATUS_OK); // Send status message for syncing purposes.
}
char_counter = 0; // Reset line buffer index
iscomment = false; // Reset comment flag

View File

@ -29,25 +29,6 @@
// buffer.
#define LINE_BUFFER_SIZE 50
// Define Grbl status codes.
#define STATUS_OK 0
#define STATUS_BAD_NUMBER_FORMAT 1
#define STATUS_EXPECTED_COMMAND_LETTER 2
#define STATUS_UNSUPPORTED_STATEMENT 3
#define STATUS_FLOATING_POINT_ERROR 4
#define STATUS_MODAL_GROUP_VIOLATION 5
#define STATUS_INVALID_STATEMENT 6
#define STATUS_HARD_LIMIT 7
#define STATUS_SETTING_DISABLED 8
#define STATUS_SETTING_STEPS_NEG 9
#define STATUS_SETTING_STEP_PULSE_MIN 10
#define STATUS_SETTING_READ_FAIL 11
// Define Grbl misc message codes
#define MESSAGE_SYSTEM_ALARM 0
#define MESSAGE_HOMING_ENABLE 1
// Initialize the serial protocol
void protocol_init();
@ -61,10 +42,4 @@ uint8_t protocol_execute_line(char *line);
// Checks and executes a runtime command at various stop points in main program
void protocol_execute_runtime();
// Prints Grbl's status messages.
void protocol_status_message(uint8_t status_code);
// Prints any misc messages.
void protocol_misc_message(uint8_t message_code);
#endif

View File

@ -9,19 +9,24 @@ It accepts standards-compliant G-code and has been tested with the output of sev
Grbl includes full acceleration management with look ahead. That means the controller will look up to 18 motions into the future and plan its velocities ahead to deliver smooth acceleration and jerk-free cornering.
*Changelog for v0.8 from v0.7:*
- *ALPHA status: _Under heavy development. Code state may significantly change with each push as new features are integrated._*
- *BETA status: _Under development. Code state may significantly change with each push as new features are integrated._*
- Major structural overhaul to allow for multi-tasking events and new feature sets
- New run-time command control: Feed hold (pause), Cycle start (resume), Reset (abort), Status reporting
- Controlled feed hold with deceleration to ensure no skipped steps and loss of location.
- After feed hold, cycle accelerations are re-planned and may be resumed.
- Advanced homing cycle with direction and speed configuration options. (Requires limit switches.)
- Limit pins are held normal high with an internal pull-up resister. Wiring only requires a normally-open switch connected to ground. (For both ends of an axis, simply wire two in parallel into the same pin.)
- Hard limits option and plays nice with homing cycle, so switches can be used for both homing and hard limits.
- Re-factored g-code parser with robust error-checking.
- Work coordinate system (G54), offsets(G92), and machine coordinate system support. G10 work coordinate settings support. (Up to 6 work coordinate systems(G54-G59) available as a compile-time option.)
- 6 work coordinate systems (G54-G59), offsets(G92), and machine coordinate system support. Work systems are stored in EEPROM and persistent.
- G10 L2 and L20 work coordinate settings support. L2 sets one or more axes values. L20 sets the current machine position to the specified work origin.
- Program stop(M0,M1*,M2,M30) initial support. Optional stop to do.
- Coolant control(M7*,M8,M9) support. (M7 is a compile-time option).
- System reset re-initializes grbl without resetting the Arduino and retains machine/home position and work coordinates.
- Restructured planner and stepper modules to become independent and ready for future features.
- Reduced serial read buffer to 128 characters and increased write buffer to 64 characters.
- Settings re-factoring to allow configuration without compiling of most features. (Still in progress).
- Misc bug fixes and removed deprecated acceleration enabled code.
- Planned features: Jog mode, full-featured status reporting, runtime settings such as toggling block delete.
- Planned features: Axis acceleration and max speed individual settings, full-featured status reporting, runtime settings such as toggling block delete.
- Advanced compile-time options: Up to 6 work coordinate systems(G54-G59), XON/XOFF flow control (limited support), direction and step pulse time delay.

211
report.c Normal file
View File

@ -0,0 +1,211 @@
/*
report.c - reporting and messaging methods
Part of Grbl
Copyright (c) 2012 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This file functions as the primary feedback interface for Grbl. Any outgoing data, such
as the protocol status messages, feedback messages, and status reports, are stored here.
For the most part, these functions primarily are called from protocol.c methods. If a
different style feedback is desired (i.e. JSON), then a user can change these following
methods to accomodate their needs.
*/
#include <avr/io.h>
#include "print.h"
#include "settings.h"
#include <math.h>
#include "nuts_bolts.h"
#include <avr/pgmspace.h>
#include "report.h"
#include "protocol.h"
// Handles the primary confirmation protocol response for streaming interfaces and human-feedback.
// For every incoming line, this method responds with an 'ok' for a successful command or an
// 'error:' to indicate some error event with the line or some critical system error during
// operation. Errors events can originate from the g-code parser, settings module, or asynchronously
// from a critical error, such as a triggered hard limit. Interface should always monitor for these
// responses.
// NOTE: In silent mode, all error codes are greater than zero.
// TODO: Install silent mode to return only numeric values, primarily for GUIs.
void report_status_message(uint8_t status_code)
{
if (status_code == 0) { // STATUS_OK
printPgmString(PSTR("ok\r\n"));
} else {
printPgmString(PSTR("error: "));
switch(status_code) {
case STATUS_BAD_NUMBER_FORMAT:
printPgmString(PSTR("Bad number format")); break;
case STATUS_EXPECTED_COMMAND_LETTER:
printPgmString(PSTR("Expected command letter")); break;
case STATUS_UNSUPPORTED_STATEMENT:
printPgmString(PSTR("Unsupported statement")); break;
case STATUS_FLOATING_POINT_ERROR:
printPgmString(PSTR("Floating point error")); break;
case STATUS_MODAL_GROUP_VIOLATION:
printPgmString(PSTR("Modal group violation")); break;
case STATUS_INVALID_STATEMENT:
printPgmString(PSTR("Invalid statement")); break;
case STATUS_HARD_LIMIT:
printPgmString(PSTR("Limit triggered")); break;
case STATUS_SETTING_DISABLED:
printPgmString(PSTR("Grbl setting disabled")); break;
case STATUS_SETTING_VALUE_NEG:
printPgmString(PSTR("Set value must be > 0.0")); break;
case STATUS_SETTING_STEP_PULSE_MIN:
printPgmString(PSTR("Step pulse must be >= 3 microseconds")); break;
case STATUS_SETTING_READ_FAIL:
printPgmString(PSTR("Failed to read EEPROM settings. Using defaults")); break;
}
printPgmString(PSTR("\r\n"));
}
}
// Prints feedback messages. This serves as a centralized method to provide additional
// user feedback for things that are not of the status message response protocol. These
// are messages such as setup warnings and how to exit alarms.
// NOTE: For interfaces, messages are always placed within parentheses. And if silent mode
// is installed, the message codes are less than zero.
// TODO: Install silence feedback messages option in settings
void report_feedback_message(int8_t message_code)
{
printPgmString(PSTR("("));
switch(message_code) {
case MESSAGE_SYSTEM_ALARM:
printPgmString(PSTR("ALARM: Check and reset Grbl")); break;
case MESSAGE_POSITION_LOST:
printPgmString(PSTR("warning: Position may be lost")); break;
case MESSAGE_HOMING_ENABLE:
printPgmString(PSTR("'$H' to home. Ensure all limit switches are installed")); break;
}
printPgmString(PSTR(")\r\n"));
}
// Welcome message
void report_init_message()
{
// Print grbl initialization message
printPgmString(PSTR("\r\nGrbl " GRBL_VERSION));
printPgmString(PSTR("\r\n'$' for help and to view settings\r\n"));
}
void report_grbl_help() {
printPgmString(PSTR("$0 = ")); printFloat(settings.steps_per_mm[X_AXIS]);
printPgmString(PSTR(" (x axis, steps/mm)\r\n$1 = ")); printFloat(settings.steps_per_mm[Y_AXIS]);
printPgmString(PSTR(" (y axis, steps/mm)\r\n$2 = ")); printFloat(settings.steps_per_mm[Z_AXIS]);
printPgmString(PSTR(" (z axis, steps/mm)\r\n$3 = ")); printInteger(settings.pulse_microseconds);
printPgmString(PSTR(" (step pulse, usec)\r\n$4 = ")); printFloat(settings.default_feed_rate);
printPgmString(PSTR(" (default feed rate, mm/min)\r\n$5 = ")); printFloat(settings.default_seek_rate);
printPgmString(PSTR(" (default seek rate, mm/min)\r\n$6 = ")); printFloat(settings.mm_per_arc_segment);
printPgmString(PSTR(" (arc resolution, mm/segment)\r\n$7 = ")); printInteger(settings.invert_mask);
printPgmString(PSTR(" (step port invert mask, int:binary = ")); print_uint8_base2(settings.invert_mask);
printPgmString(PSTR(")\r\n$8 = ")); printFloat(settings.acceleration/(60*60)); // Convert from mm/min^2 for human readability
printPgmString(PSTR(" (acceleration, mm/sec^2)\r\n$9 = ")); printFloat(settings.junction_deviation);
printPgmString(PSTR(" (cornering junction deviation, mm)\r\n$10 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES));
printPgmString(PSTR(" (status report inches, bool)\r\n$11 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_AUTO_START));
printPgmString(PSTR(" (auto start enable, bool)\r\n$12 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE));
printPgmString(PSTR(" (invert stepper enable, bool)\r\n$13 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE));
printPgmString(PSTR(" (hard limit enable, bool)\r\n$14 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE));
printPgmString(PSTR(" (homing enable, bool)\r\n$15 = ")); printInteger(settings.homing_dir_mask);
printPgmString(PSTR(" (homing direction mask, int:binary = ")); print_uint8_base2(settings.homing_dir_mask);
printPgmString(PSTR(")\r\n$16 = ")); printFloat(settings.homing_feed_rate);
printPgmString(PSTR(" (homing feed rate, mm/min)\r\n$17 = ")); printFloat(settings.homing_seek_rate);
printPgmString(PSTR(" (homing seek rate, mm/min)\r\n$18 = ")); printInteger(settings.homing_debounce_delay);
printPgmString(PSTR(" (homing debounce delay, msec)\r\n$19 = ")); printFloat(settings.homing_pulloff);
printPgmString(PSTR(" (homing pull-off travel, mm)\r\n$20 = ")); printInteger(settings.stepper_idle_lock_time);
printPgmString(PSTR(" (stepper idle lock time, msec)\r\n$21 = ")); printInteger(settings.decimal_places);
printPgmString(PSTR(" (decimal places, int)\r\n$22 = ")); printInteger(settings.n_arc_correction);
// char st_line[LINE_BUFFER_SIZE];
// printPgmString(PSTR("\r\n\r\n Startup\r\n$100 = ")); printString(settings_read_startup(st_line,0));
// printPgmString(PSTR("\r\n$101 = ")); printString(settings_read_startup(st_line,1));
// char buf[4];
// settings_startup_string((char *)buf);
// printPgmString(PSTR("\r\n Startup: ")); printString(buf);
printPgmString(PSTR("\r\n'$x=value' to store setting"));
// printPgmString(PSTR("\r\n'$Sx' to toggle switch\r\n"));
}
// void report_gcode_status()
// {
// // Print gcode parser state
// }
//
// void report_gcode_parameters()
// {
// // Print gcode work coordinate offsets?
// }
void report_realtime_status()
{
// TODO: Status report data is written to the user here. This function should be able to grab a
// real-time snapshot of the stepper subprogram and the actual location of the CNC machine. At a
// minimum, status report should return real-time location information. Other important information
// may be distance to go on block, processed block id, and feed rate. A secondary, non-critical
// status report may include g-code state, i.e. inch mode, plane mode, absolute mode, etc.
// The report generated must be as short as possible, yet still provide the user easily readable
// information, i.e. '[0.23,120.4,2.4]'. This is necessary as it minimizes the computational
// overhead and allows grbl to keep running smoothly, especially with g-code programs with fast,
// short line segments and interface setups that require real-time status reports (5-20Hz).
// **Under construction** Bare-bones status report. Provides real-time machine position relative to
// the system power on location (0,0,0) and work coordinate position (G54 and G92 applied).
// The following are still needed: user setting of output units (mm|inch), compressed (non-human
// readable) data for interfaces?, save last known position in EEPROM?, code optimizations, solidify
// the reporting schemes, move to a separate .c file for easy user accessibility, and setting the
// home position by the user (likely through '$' setting interface).
// Successfully tested at a query rate of 10-20Hz while running a gauntlet of programs at various
// speeds.
uint8_t i;
int32_t current_position[3]; // Copy current state of the system position variable
memcpy(current_position,sys.position,sizeof(sys.position));
float print_position[3];
// Report machine position
printPgmString(PSTR("MPos:["));
for (i=0; i<= 2; i++) {
print_position[i] = current_position[i]/settings.steps_per_mm[i];
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { print_position[i] *= INCH_PER_MM; }
printFloat(print_position[i]);
if (i < 2) { printPgmString(PSTR(",")); }
else { printPgmString(PSTR("]")); }
}
// Report work position
printPgmString(PSTR(",WPos:["));
for (i=0; i<= 2; i++) {
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
print_position[i] -= (sys.coord_system[i]+sys.coord_offset[i])*INCH_PER_MM;
} else {
print_position[i] -= sys.coord_system[i]+sys.coord_offset[i];
}
printFloat(print_position[i]);
if (i < 2) { printPgmString(PSTR(",")); }
else { printPgmString(PSTR("]")); }
}
printPgmString(PSTR("\r\n"));
}

59
report.h Normal file
View File

@ -0,0 +1,59 @@
/*
report.h - reporting and messaging methods
Part of Grbl
Copyright (c) 2012 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef report_h
#define report_h
// Define Grbl status codes.
#define STATUS_OK 0
#define STATUS_BAD_NUMBER_FORMAT 1
#define STATUS_EXPECTED_COMMAND_LETTER 2
#define STATUS_UNSUPPORTED_STATEMENT 3
#define STATUS_FLOATING_POINT_ERROR 4
#define STATUS_MODAL_GROUP_VIOLATION 5
#define STATUS_INVALID_STATEMENT 6
#define STATUS_HARD_LIMIT 7
#define STATUS_SETTING_DISABLED 8
#define STATUS_SETTING_VALUE_NEG 9
#define STATUS_SETTING_STEP_PULSE_MIN 10
#define STATUS_SETTING_READ_FAIL 11
// Define Grbl feedback message codes. Less than zero to distinguish message from error.
#define MESSAGE_SYSTEM_ALARM -1
#define MESSAGE_POSITION_LOST -2
#define MESSAGE_HOMING_ENABLE -3
// Prints system status messages.
void report_status_message(uint8_t status_code);
// Prints miscellaneous feedback messages.
void report_feedback_message(int8_t message_code);
// Prints welcome message
void report_init_message();
// Prints Grbl help and current global settings
void report_grbl_help();
// Prints realtime status report
void report_realtime_status();
#endif

View File

@ -166,7 +166,7 @@ ISR(USART_RX_vect)
case CMD_FEED_HOLD: sys.execute |= EXEC_FEED_HOLD; break; // Set as true
case CMD_RESET:
// Immediately force stepper and spindle subsystem idle at an interrupt level.
if (!(sys.execute & EXEC_RESET)) { mc_alarm(); } // Stop only first time.
mc_alarm();
sys.execute |= EXEC_RESET; // Set as true
break;
default: // Write character to buffer

207
settings.c Executable file → Normal file
View File

@ -28,21 +28,11 @@
#include <avr/pgmspace.h>
#include "protocol.h"
#include "config.h"
#include "report.h"
settings_t settings;
// Version 1 outdated settings record
typedef struct {
float steps_per_mm[3];
uint8_t microsteps;
uint8_t pulse_microseconds;
float default_feed_rate;
float default_seek_rate;
uint8_t invert_mask;
float mm_per_arc_segment;
} settings_v1_t;
// Version 2,3,4 outdated settings record
// Version 4 outdated settings record
typedef struct {
float steps_per_mm[3];
uint8_t microsteps;
@ -53,7 +43,7 @@ typedef struct {
float mm_per_arc_segment;
float acceleration;
float junction_deviation;
} settings_v2_v4_t;
} settings_v4_t;
// Default settings (used when resetting eeprom-settings)
#define MICROSTEPS 8
@ -71,6 +61,7 @@ typedef struct {
// Developmental default settings
#define DEFAULT_REPORT_INCHES 0 // false
#define DEFAULT_AUTO_START 1 // true
#define DEFAULT_INVERT_ST_ENABLE 0 // false
#define DEFAULT_HARD_LIMIT_ENABLE 0 // false
#define DEFAULT_HOMING_ENABLE 0 // false
#define DEFAULT_HOMING_DIR_MASK 0 // move positive dir
@ -80,6 +71,22 @@ typedef struct {
#define DEFAULT_HOMING_PULLOFF 1 // mm
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-255)
#define DEFAULT_DECIMAL_PLACES 3
#define DEFAULT_N_ARC_CORRECTION 25
void settings_write_coord_data(uint8_t coord_select, float *coord_data)
{
uint16_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
memcpy_to_eeprom_with_checksum(addr,(char*)coord_data, sizeof(float)*N_AXIS);
}
void write_global_settings()
{
eeprom_put_char(0, SETTINGS_VERSION);
memcpy_to_eeprom_with_checksum(EEPROM_ADDR_GLOBAL, (char*)&settings, sizeof(settings_t));
}
void settings_reset(bool reset_all) {
// Reset all settings or only the migration settings to the new version.
@ -97,7 +104,9 @@ void settings_reset(bool reset_all) {
}
// New settings since last version
settings.flags = 0;
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_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
if (DEFAULT_HOMING_ENABLE) { settings.flags |= BITFLAG_HOMING_ENABLE; }
settings.homing_dir_mask = DEFAULT_HOMING_DIR_MASK;
@ -107,138 +116,56 @@ void settings_reset(bool reset_all) {
settings.homing_pulloff = DEFAULT_HOMING_PULLOFF;
settings.stepper_idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME;
settings.decimal_places = DEFAULT_DECIMAL_PLACES;
settings.n_arc_correction = DEFAULT_N_ARC_CORRECTION;
write_global_settings();
// Zero all coordinate parameter data.
float coord_data[N_AXIS];
clear_vector_float(coord_data);
uint8_t i = 0;
for (i=0; i<=SETTING_INDEX_NCOORD; i++) {
settings_write_coord_data(i,coord_data);
}
}
// static void settings_startup_string(char *buf) {
// memcpy_from_eeprom_with_checksum((char*)buf,512, 4);
// }
void settings_dump() {
printPgmString(PSTR("$0 = ")); printFloat(settings.steps_per_mm[X_AXIS]);
printPgmString(PSTR(" (x axis, steps/mm)\r\n$1 = ")); printFloat(settings.steps_per_mm[Y_AXIS]);
printPgmString(PSTR(" (y axis, steps/mm)\r\n$2 = ")); printFloat(settings.steps_per_mm[Z_AXIS]);
printPgmString(PSTR(" (z axis, steps/mm)\r\n$3 = ")); printInteger(settings.pulse_microseconds);
printPgmString(PSTR(" (step pulse, usec)\r\n$4 = ")); printFloat(settings.default_feed_rate);
printPgmString(PSTR(" (default feed rate, mm/min)\r\n$5 = ")); printFloat(settings.default_seek_rate);
printPgmString(PSTR(" (default seek rate, mm/min)\r\n$6 = ")); printFloat(settings.mm_per_arc_segment);
printPgmString(PSTR(" (arc resolution, mm/segment)\r\n$7 = ")); printInteger(settings.invert_mask);
printPgmString(PSTR(" (step port invert mask, int:binary = ")); print_uint8_base2(settings.invert_mask);
printPgmString(PSTR(")\r\n$8 = ")); printFloat(settings.acceleration/(60*60)); // Convert from mm/min^2 for human readability
printPgmString(PSTR(" (acceleration, mm/sec^2)\r\n$9 = ")); printFloat(settings.junction_deviation);
printPgmString(PSTR(" (cornering junction deviation, mm)\r\n$10 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES));
printPgmString(PSTR(" (status report inches, bool)\r\n$11 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_AUTO_START));
printPgmString(PSTR(" (auto start enable, bool)\r\n$12 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE));
printPgmString(PSTR(" (hard limit enable, bool)\r\n$13 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE));
printPgmString(PSTR(" (homing enable, bool)\r\n$14 = ")); printInteger(settings.homing_dir_mask);
printPgmString(PSTR(" (homing direction mask, int:binary = ")); print_uint8_base2(settings.homing_dir_mask);
printPgmString(PSTR(")\r\n$15 = ")); printFloat(settings.homing_feed_rate);
printPgmString(PSTR(" (homing feed rate, mm/min)\r\n$16 = ")); printFloat(settings.homing_seek_rate);
printPgmString(PSTR(" (homing seek rate, mm/min)\r\n$17 = ")); printInteger(settings.homing_debounce_delay);
printPgmString(PSTR(" (homing debounce delay, msec)\r\n$18 = ")); printFloat(settings.homing_pulloff);
printPgmString(PSTR(" (homing pull-off travel, mm)\r\n$19 = ")); printInteger(settings.stepper_idle_lock_time);
printPgmString(PSTR(" (stepper idle lock time, msec)\r\n$20 = ")); printInteger(settings.decimal_places);
printPgmString(PSTR(" (decimal places, int)"));
// char buf[4];
// settings_startup_string((char *)buf);
// printPgmString(PSTR("\r\n Startup: ")); printString(buf);
printPgmString(PSTR("\r\n'$x=value' to set parameter or just '$' to dump current settings\r\n"));
// Read selected coordinate data from EEPROM. Updates pointed coord_data value.
uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data)
{
uint16_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
if ((!memcpy_from_eeprom_with_checksum((char*)coord_data, addr, sizeof(float)*N_AXIS))) {
clear_vector_float(coord_data); // Default zero vector
settings_write_coord_data(coord_select,coord_data);
return(false);
} else {
return(true);
}
}
// Parameter lines are on the form '$4=374.3' or '$' to dump current settings
// NOTE: Assumes '$' already exists in line[0], which is checked by protocol.c.
uint8_t settings_execute_line(char *line) {
uint8_t char_counter = 1;
// unsigned char letter;
float parameter, value;
if(line[char_counter] == 0) {
settings_dump(); return(STATUS_OK);
}
// if(line[char_counter] >= 'A' || line[char_counter] <= 'Z') {
// letter = line[char_counter++];
// if(line[char_counter++] != '=') {
// return(STATUS_UNSUPPORTED_STATEMENT);
// }
// for (char_counter = 0; char_counter < LINE_BUFFER_SIZE-3; char_counter++) {
// line[char_counter] = line[char_counter+3];
// }
// uint8_t status = gc_execute_line(line);
// if (status) { return(status); }
// else { settings_store_startup_line(line); }
//
//
// // Opt stop and block delete are referred to as switches.
// // How to store home position and work offsets real-time??
//
// } else {
if(!read_float(line, &char_counter, &parameter)) {
return(STATUS_BAD_NUMBER_FORMAT);
}
if(line[char_counter++] != '=') {
return(STATUS_UNSUPPORTED_STATEMENT);
}
if(!read_float(line, &char_counter, &value)) {
return(STATUS_BAD_NUMBER_FORMAT);
}
if(line[char_counter] != 0) {
return(STATUS_UNSUPPORTED_STATEMENT);
}
return(settings_store_setting(parameter, value));
// }
}
void write_settings() {
eeprom_put_char(0, SETTINGS_VERSION);
memcpy_to_eeprom_with_checksum(1, (char*)&settings, sizeof(settings_t));
//
// char buf[4]; buf[0] = 'G'; buf[1] = '2'; buf[2] = '0'; buf[3] = 0;
// memcpy_to_eeprom_with_checksum(512, (char*)buf, 4);
//
}
int read_settings() {
uint8_t read_global_settings() {
// Check version-byte of eeprom
uint8_t version = eeprom_get_char(0);
if (version == SETTINGS_VERSION) {
// Read settings-record and check checksum
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_t)))) {
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t)))) {
return(false);
}
} else {
// Incrementally update the old versions until up-to-date.
if (version == 1) {
// Migrate from settings version 1 to version 4.
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v1_t)))) {
return(false);
}
settings.acceleration = DEFAULT_ACCELERATION;
settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION;
} else if ((version == 2) || (version == 3)) {
// Migrate from settings version 2 and 3 to version 4.
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v2_v4_t)))) {
return(false);
}
if (version == 2) { settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION; }
settings.acceleration *= 3600; // Convert to mm/min^2 from mm/sec^2
}
if (version <= 4) {
// Migrate from settings version 4 to current version.
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v2_v4_t)))) {
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v4_t)))) {
return(false);
}
settings_reset(false);
write_settings();
} else if (version >= 50) {
// Developmental settings. Version numbers greater than or equal to 50 are temporary.
// Currently, this will update the user settings to v4 and the remainder of the settings
// should be re-written to the default value, if the developmental version number changed.
// Grab settings regardless of error.
memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_t));
memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v4_t));
settings_reset(false);
write_settings();
} else {
return(false);
}
@ -246,11 +173,12 @@ int read_settings() {
return(true);
}
// A helper method to set settings from command line
uint8_t settings_store_setting(int parameter, float value) {
uint8_t settings_store_global_setting(int parameter, float value) {
switch(parameter) {
case 0: case 1: case 2:
if (value <= 0.0) { return(STATUS_SETTING_STEPS_NEG); }
if (value <= 0.0) { return(STATUS_SETTING_VALUE_NEG); }
settings.steps_per_mm[parameter] = value; break;
case 3:
if (value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); }
@ -267,45 +195,52 @@ uint8_t settings_store_setting(int parameter, float value) {
} else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
break;
case 11:
if (value) {
if (value) {
settings.flags |= BITFLAG_AUTO_START;
} else { settings.flags &= ~BITFLAG_AUTO_START; }
break;
case 12:
if (value) {
settings.flags |= BITFLAG_INVERT_ST_ENABLE;
} else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; }
break;
case 13:
if (value) {
settings.flags |= BITFLAG_HARD_LIMIT_ENABLE;
} else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; }
break;
case 13:
case 14:
if (value) {
settings.flags |= BITFLAG_HOMING_ENABLE;
protocol_misc_message(MESSAGE_HOMING_ENABLE);
report_feedback_message(MESSAGE_HOMING_ENABLE);
} else { settings.flags &= ~BITFLAG_HOMING_ENABLE; }
break;
case 14: settings.homing_dir_mask = trunc(value); break;
case 15: settings.homing_feed_rate = value; break;
case 16: settings.homing_seek_rate = value; break;
case 17: settings.homing_debounce_delay = round(value); break;
case 18: settings.homing_pulloff = value; break;
case 15: settings.homing_dir_mask = trunc(value); break;
case 16: settings.homing_feed_rate = value; break;
case 17: settings.homing_seek_rate = value; break;
case 18: settings.homing_debounce_delay = round(value); break;
case 19:
if (value <= 0.0) { return(STATUS_SETTING_VALUE_NEG); }
settings.homing_pulloff = value; break;
case 20:
settings.stepper_idle_lock_time = round(value);
// TODO: Immediately check and toggle steppers from always enable or disable?
break;
case 20: settings.decimal_places = round(value); break;
case 21: settings.decimal_places = round(value); break;
case 22: settings.n_arc_correction = round(value); break;
default:
return(STATUS_INVALID_STATEMENT);
}
write_settings();
write_global_settings();
return(STATUS_OK);
}
// Initialize the config subsystem
void settings_init() {
if(!read_settings()) {
protocol_status_message(STATUS_SETTING_READ_FAIL);
if(!read_global_settings()) {
report_status_message(STATUS_SETTING_READ_FAIL);
settings_reset(true);
write_settings();
settings_dump();
report_grbl_help();
}
}

View File

@ -24,20 +24,35 @@
#include <math.h>
#include <inttypes.h>
#include "nuts_bolts.h"
#define GRBL_VERSION "0.8b"
// 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 55
#define SETTINGS_VERSION 56
// Define bit flag masks for the boolean settings in settings.flag.
#define BITFLAG_REPORT_INCHES bit(0)
#define BITFLAG_AUTO_START bit(1)
#define BITFLAG_HARD_LIMIT_ENABLE bit(2)
#define BITFLAG_HOMING_ENABLE bit(3)
#define BITFLAG_INVERT_ST_ENABLE bit(2)
#define BITFLAG_HARD_LIMIT_ENABLE bit(3)
#define BITFLAG_HOMING_ENABLE bit(4)
// Current global settings (persisted in EEPROM from byte 1 onwards)
// Define EEPROM memory address location values for on-demand settings and parameters
#define EEPROM_ADDR_GLOBAL 1
#define EEPROM_ADDR_PARAMETERS 512
#define EEPROM_ADDR_STARTUP_SCRIPT 768
// Define EEPROM address indexing for coordinate parameters
#define N_COORDINATE_SYSTEM 6 // Number of supported work coordinate systems (from index 1)
#define SETTING_INDEX_NCOORD N_COORDINATE_SYSTEM+2 // Total number of system stored (from index 0)
// NOTE: Work coordinate indices are (0=G54, 1=G55, ... , 6=G59)
#define SETTING_INDEX_G28 N_COORDINATE_SYSTEM // Home position 1
#define SETTING_INDEX_G30 N_COORDINATE_SYSTEM+1 // Home position 2
#define SETTING_INDEX_G92 N_COORDINATE_SYSTEM+2 // Coordinate offset
// Global persistent settings (Stored from byte EEPROM_ADDR_GLOBAL onwards)
typedef struct {
float steps_per_mm[3];
uint8_t microsteps;
@ -56,20 +71,21 @@ typedef struct {
float homing_pulloff;
uint8_t stepper_idle_lock_time; // If max value 255, steppers do not disable.
uint8_t decimal_places;
uint8_t n_arc_correction;
} settings_t;
extern settings_t settings;
// Initialize the configuration subsystem (load settings from EEPROM)
void settings_init();
// Print current settings
void settings_dump();
// Handle settings command
uint8_t settings_execute_line(char *line);
// A helper method to set new settings from command line
uint8_t settings_store_setting(int parameter, float value);
uint8_t settings_store_global_setting(int parameter, float value);
// Writes selected coordinate data to EEPROM
void settings_write_coord_data(uint8_t coord_select, float *coord_data);
// Reads selected coordinate data from EEPROM
uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data);
// int8_t settings_execute_startup();

View File

@ -84,25 +84,32 @@ static volatile uint8_t busy; // True when SIG_OUTPUT_COMPARE1A is being servi
static void set_step_events_per_minute(uint32_t steps_per_minute);
// Stepper state initialization
static void st_wake_up()
// 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()
{
// Initialize stepper output bits
out_bits = (0) ^ (settings.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.
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);
#else // Normal operation
// Set step pulse time. Ad hoc computation from oscilloscope. Uses two's complement.
step_pulse_time = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3);
#endif
// Enable steppers by resetting the stepper disable port
STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT);
// Enable stepper driver interrupt
TIMSK1 |= (1<<OCIE1A);
if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) {
STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT);
} else {
STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT);
}
if (sys.cycle_start) {
// Initialize stepper output bits
out_bits = (0) ^ (settings.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.
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);
#else // Normal operation
// Set step pulse time. Ad hoc computation from oscilloscope. Uses two's complement.
step_pulse_time = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3);
#endif
// Enable stepper driver interrupt
TIMSK1 |= (1<<OCIE1A);
}
}
// Stepper shutdown
@ -110,12 +117,16 @@ void st_go_idle()
{
// Disable stepper driver interrupt
TIMSK1 &= ~(1<<OCIE1A);
// Force stepper dwell to lock axes for a defined amount of time to ensure the axes come to a complete
// stop and not drift from residual inertial forces at the end of the last movement.
delay_ms(settings.stepper_idle_lock_time);
// Disable steppers only upon system alarm activated or by user setting to not be kept enabled.
if ((settings.stepper_idle_lock_time != 0xff) || bit_istrue(sys.execute,EXEC_ALARM)) {
STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT);
// Force stepper dwell to lock axes for a defined amount of time to ensure the axes come to a complete
// stop and not drift from residual inertial forces at the end of the last movement.
delay_ms(settings.stepper_idle_lock_time);
if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) {
STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT);
} else {
STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT);
}
}
}
@ -362,7 +373,8 @@ void st_init()
TIMSK2 |= (1<<OCIE2A); // Enable Timer2 Compare Match A interrupt
#endif
// Start in the idle state
// Start in the idle state, but first wake up to check for keep steppers enabled option.
st_wake_up();
st_go_idle();
}
@ -414,12 +426,16 @@ static void set_step_events_per_minute(uint32_t steps_per_minute)
// Planner external interface to start stepper interrupt and execute the blocks in queue. Called
// by the main program functions: planner auto-start and run-time command execution.
// TODO: Update sys.cycle_start and feed_hold variables to a sys.state variable. This state
// variable will manage all of Grbl's processes and keep them separate.
void st_cycle_start()
{
if (!sys.cycle_start) {
if (!sys.feed_hold) {
sys.cycle_start = true;
st_wake_up();
if (bit_isfalse(sys.execute,EXEC_ALARM)) {
sys.cycle_start = true; // Only place this variable is set true.
st_wake_up();
}
}
}
}

View File

@ -29,10 +29,14 @@
#define STEP_MASK ((1<<X_STEP_BIT)|(1<<Y_STEP_BIT)|(1<<Z_STEP_BIT)) // All step bits
#define DIRECTION_MASK ((1<<X_DIRECTION_BIT)|(1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) // All direction bits
#define STEPPING_MASK (STEP_MASK | DIRECTION_MASK) // All stepping-related bits (step/direction)
#define STEPPERS_DISABLE_MASK (1<<STEPPERS_DISABLE_BIT)
// Initialize and setup the stepper motor subsystem
void st_init();
// Enable steppers, but cycle does not start unless called by motion control or runtime command.
void st_wake_up();
// Immediately disables steppers
void st_go_idle();