Incomplete push but working. Lots more stuff. More to come.

- NEW! An active multi-axis step smoothing algorithm that automatically
adjusts dependent on step frequency. This solves the long standing
issue to aliasing when moving with multiple axes. Similar in scheme to
Smoothieware, but more advanced in ensuring a more consistent CPU
overhead throughout all frequencies while maintaining step exactness.

- Switched from Timer2 to Timer0 for the Step Port Reset Interrupt.
Mainly to free up hardware PWM pins.

- Seperated the direction and step pin assignments, so we can now move
them to seperate ports. This means that we can more easily support 4+
axes in the future.

- Added a setting for inverting the limit pins, as so many users have
request. Better late than never.

- Bug fix related to EEPROM calls when in cycle. The EEPROM would kill
the stepper motion. Now protocol mandates that the system be either in
IDLE or ALARM to access or change any settings.

- Bug fix related to resuming the cycle after a spindle or dwell
command if auto start has been disabled. This fix is somewhat temporary
or more of a patch. Doesn’t work with a straight call-response
streaming protocol, but works fine with serial buffer pre-filling
streaming that most clients use.

- Renamed the pin_map.h to cpu_map.h to more accurately describe what
the file is.

- Pushed an auto start bug fix upon re-initialization.

- Much more polishing to do!
This commit is contained in:
Sonny Jeon 2013-12-30 18:44:46 -07:00
parent 5ab2bb7767
commit 47cd40c8dc
14 changed files with 348 additions and 272 deletions

View File

@ -34,9 +34,9 @@
// Serial baud rate // Serial baud rate
#define BAUD_RATE 115200 #define BAUD_RATE 115200
// Default pin mappings. Grbl officially supports the Arduino Uno only. Other processor types // Default cpu mappings. Grbl officially supports the Arduino Uno only. Other processor types
// may exist from user-supplied templates or directly user-defined in pin_map.h // may exist from user-supplied templates or directly user-defined in cpu_map.h
#define PIN_MAP_ARDUINO_UNO #define CPU_MAP_ATMEGA328P // Arduino Uno CPU
// Define runtime command special characters. These characters are 'picked-off' directly from the // Define runtime command special characters. These characters are 'picked-off' directly from the
// serial read data stream and are not passed to the grbl line execution parser. Select characters // serial read data stream and are not passed to the grbl line execution parser. Select characters
@ -49,12 +49,6 @@
#define CMD_CYCLE_START '~' #define CMD_CYCLE_START '~'
#define CMD_RESET 0x18 // ctrl-x. #define CMD_RESET 0x18 // ctrl-x.
// Uncomment the following define if you are using hardware that drives high when your limits
// are reached. You will need to ensure that you have appropriate pull-down resistors on the
// limit switch input pins, or that your hardware drives the pins low when they are open (non-
// triggered).
// #define LIMIT_SWITCHES_ACTIVE_HIGH // Uncomment to enable
// If homing is enabled, homing init lock sets Grbl into an alarm state upon power up. This forces // If homing is enabled, homing init lock sets Grbl into an alarm state upon power up. This forces
// the user to perform the homing cycle (or override the locks) before doing anything else. This is // the user to perform the homing cycle (or override the locks) before doing anything else. This is
// mainly a safety feature to remind the user to home, since position is unknown to Grbl. // mainly a safety feature to remind the user to home, since position is unknown to Grbl.
@ -94,16 +88,8 @@
// set this only as high as needed. Approximate successful values can widely range from 50 to 200 or more. // set this only as high as needed. Approximate successful values can widely range from 50 to 200 or more.
#define ACCELERATION_TICKS_PER_SECOND 100 #define ACCELERATION_TICKS_PER_SECOND 100
// Creates a delay between the direction pin setting and corresponding step pulse by creating #define ACTIVE_MULTI_AXIS_STEP_SMOOTHING
// another interrupt (Timer2 compare) to manage it. The main Grbl interrupt (Timer1 compare) #define ENABLE_SOFTWARE_DEBOUNCE
// sets the direction pins, and does not immediately set the stepper pins, as it would in
// normal operation. The Timer2 compare fires next to set the stepper pins after the step
// pulse delay time, and Timer2 overflow will complete the step pulse, except now delayed
// by the step pulse time plus the step pulse delay. (Thanks langwadt for the idea!)
// NOTE: Uncomment to enable. The recommended delay must be > 3us, and, when added with the
// user-supplied step pulse time, the total time must not exceed 127us. Reported successful
// values for certain setups have ranged from 5 to 20us.
// #define STEP_PULSE_DELAY 10 // Step pulse delay in microseconds. Default disabled.
// 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
@ -127,6 +113,17 @@
// time step. Also, keep in mind that the Arduino delay timer is not very accurate for long delays. // time step. Also, keep in mind that the Arduino delay timer is not very accurate for long delays.
#define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds) #define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds)
// Creates a delay between the direction pin setting and corresponding step pulse by creating
// another interrupt (Timer2 compare) to manage it. The main Grbl interrupt (Timer1 compare)
// sets the direction pins, and does not immediately set the stepper pins, as it would in
// normal operation. The Timer2 compare fires next to set the stepper pins after the step
// pulse delay time, and Timer2 overflow will complete the step pulse, except now delayed
// by the step pulse time plus the step pulse delay. (Thanks langwadt for the idea!)
// NOTE: Uncomment to enable. The recommended delay must be > 3us, and, when added with the
// user-supplied step pulse time, the total time must not exceed 127us. Reported successful
// values for certain setups have ranged from 5 to 20us.
// #define STEP_PULSE_DELAY 10 // Step pulse delay in microseconds. Default disabled.
// The number of linear motions in the planner buffer to be planned at any give time. The vast // The number of linear motions in the planner buffer to be planned at any give time. The vast
// majority of RAM that Grbl uses is based on this buffer size. Only increase if there is extra // majority of RAM that Grbl uses is based on this buffer size. Only increase if there is extra
// available RAM, like when re-compiling for a Mega or Sanguino. Or decrease if the Arduino // available RAM, like when re-compiling for a Mega or Sanguino. Or decrease if the Arduino
@ -171,8 +168,6 @@
// case, please report any successes to grbl administrators! // case, please report any successes to grbl administrators!
// #define ENABLE_XONXOFF // Default disabled. Uncomment to enable. // #define ENABLE_XONXOFF // Default disabled. Uncomment to enable.
#define ENABLE_SOFTWARE_DEBOUNCE
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
// TODO: Install compile-time option to send numeric status codes rather than strings. // TODO: Install compile-time option to send numeric status codes rather than strings.

View File

@ -1,5 +1,5 @@
/* /*
pin_map.h - Pin mapping configuration file cpu_map.h - CPU and pin mapping configuration file
Part of Grbl Part of Grbl
Copyright (c) 2013 Sungeun K. Jeon Copyright (c) 2013 Sungeun K. Jeon
@ -18,14 +18,17 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>. along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* The pin_map.h file serves as a central pin mapping settings file for different processor /* The cpu_map.h file serves as a central pin mapping settings file for different processor
types, i.e. AVR 328p or AVR Mega 2560. Grbl officially supports the Arduino Uno, but the types, i.e. AVR 328p or AVR Mega 2560. Grbl officially supports the Arduino Uno, but the
other supplied pin mappings are supplied by users, so your results may vary. */ other supplied pin mappings are supplied by users, so your results may vary. */
#ifndef pin_map_h // NOTE: This is still a work in progress. We are still centralizing the configurations to
#define pin_map_h // this file, so your success may vary for other CPUs.
#ifdef PIN_MAP_ARDUINO_UNO // AVR 328p, Officially supported by Grbl. #ifndef cpu_map_h
#define cpu_map_h
#ifdef CPU_MAP_ATMEGA328P // (Arduino Uno) Officially supported by Grbl.
// Serial port pins // Serial port pins
#define SERIAL_RX USART_RX_vect #define SERIAL_RX USART_RX_vect
@ -37,12 +40,14 @@
#define X_STEP_BIT 2 // Uno Digital Pin 2 #define X_STEP_BIT 2 // Uno Digital Pin 2
#define Y_STEP_BIT 3 // Uno Digital Pin 3 #define Y_STEP_BIT 3 // Uno Digital Pin 3
#define Z_STEP_BIT 4 // Uno Digital Pin 4 #define Z_STEP_BIT 4 // Uno Digital Pin 4
#define STEP_MASK ((1<<X_STEP_BIT)|(1<<Y_STEP_BIT)|(1<<Z_STEP_BIT)) // All step bits
#define DIRECTION_DDR DDRD
#define DIRECTION_PORT PORTD
#define X_DIRECTION_BIT 5 // Uno Digital Pin 5 #define X_DIRECTION_BIT 5 // Uno Digital Pin 5
#define Y_DIRECTION_BIT 6 // Uno Digital Pin 6 #define Y_DIRECTION_BIT 6 // Uno Digital Pin 6
#define Z_DIRECTION_BIT 7 // Uno Digital Pin 7 #define Z_DIRECTION_BIT 7 // Uno Digital Pin 7
#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 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_DDR DDRB #define STEPPERS_DISABLE_DDR DDRB
#define STEPPERS_DISABLE_PORT PORTB #define STEPPERS_DISABLE_PORT PORTB
@ -82,7 +87,7 @@
#define COOLANT_MIST_BIT 4 // Uno Analog Pin 4 #define COOLANT_MIST_BIT 4 // Uno Analog Pin 4
#endif #endif
// NOTE: All pinouts pins must be on the same port // NOTE: All pinouts pins must be on the same port, but cannot be on same port as limit pins.
#define PINOUT_DDR DDRC #define PINOUT_DDR DDRC
#define PINOUT_PIN PINC #define PINOUT_PIN PINC
#define PINOUT_PORT PORTC #define PINOUT_PORT PORTC
@ -97,7 +102,7 @@
#endif #endif
#ifdef PIN_MAP_ARDUINO_MEGA_2560 // Working @EliteEng #ifdef CPU_MAP_ATMEGA2560 // (Arduino Mega 2560) Working @EliteEng
// Serial port pins // Serial port pins
#define SERIAL_RX USART0_RX_vect #define SERIAL_RX USART0_RX_vect
@ -109,19 +114,23 @@
#define BLOCK_BUFFER_SIZE 36 #define BLOCK_BUFFER_SIZE 36
#define LINE_BUFFER_SIZE 100 #define LINE_BUFFER_SIZE 100
// NOTE: All step bit and direction pins must be on the same port. // NOTE: All step pins must be on the same port.
#define STEPPING_DDR DDRA #define STEPPING_DDR DDRA
#define STEPPING_PORT PORTA #define STEPPING_PORT PORTA
#define STEPPING_PIN PINA #define STEPPING_PIN PINA
#define X_STEP_BIT 2 // MEGA2560 Digital Pin 24 #define X_STEP_BIT 2 // MEGA2560 Digital Pin 24
#define Y_STEP_BIT 3 // MEGA2560 Digital Pin 25 #define Y_STEP_BIT 3 // MEGA2560 Digital Pin 25
#define Z_STEP_BIT 4 // MEGA2560 Digital Pin 26 #define Z_STEP_BIT 4 // MEGA2560 Digital Pin 26
#define STEPPING_MASK ((1<<X_STEP_BIT)|(1<<Y_STEP_BIT)|(1<<Z_STEP_BIT)) // All step bits
// NOTE: All direction pins must be on the same port.
#define DIRECTION_DDR DDRA
#define DIRECTION_PORT PORTA
#define DIRECTION_PIN PINA
#define X_DIRECTION_BIT 5 // MEGA2560 Digital Pin 27 #define X_DIRECTION_BIT 5 // MEGA2560 Digital Pin 27
#define Y_DIRECTION_BIT 6 // MEGA2560 Digital Pin 28 #define Y_DIRECTION_BIT 6 // MEGA2560 Digital Pin 28
#define Z_DIRECTION_BIT 7 // MEGA2560 Digital Pin 29 #define Z_DIRECTION_BIT 7 // MEGA2560 Digital Pin 29
#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 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_DDR DDRB #define STEPPERS_DISABLE_DDR DDRB
#define STEPPERS_DISABLE_PORT PORTB #define STEPPERS_DISABLE_PORT PORTB
@ -159,7 +168,7 @@
#define COOLANT_MIST_BIT 3 // MEGA2560 Digital Pin 34 #define COOLANT_MIST_BIT 3 // MEGA2560 Digital Pin 34
#endif #endif
// NOTE: All pinouts pins must be on the same port // NOTE: All pinouts pins must be on the same port and cannot be on same port as limit pins.
#define PINOUT_DDR DDRK #define PINOUT_DDR DDRK
#define PINOUT_PIN PINK #define PINOUT_PIN PINK
#define PINOUT_PORT PORTK #define PINOUT_PORT PORTK
@ -174,8 +183,8 @@
#endif #endif
/* /*
#ifdef PIN_MAP_CUSTOM_PROC #ifdef CPU_MAP_CUSTOM_PROC
// For a custom pin map or different processor, copy and paste one of the default pin map // For a custom pin map or different processor, copy and paste one of the default cpu map
// settings above and modify it to your needs. Then, make sure the defined name is also // settings above and modify it to your needs. Then, make sure the defined name is also
// changed in the config.h file. // changed in the config.h file.
#endif #endif

View File

@ -43,7 +43,8 @@
#define DEFAULT_Z_MAX_TRAVEL 200.0 // mm #define DEFAULT_Z_MAX_TRAVEL 200.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10 #define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_FEEDRATE 250.0 // mm/min #define DEFAULT_FEEDRATE 250.0 // mm/min
#define DEFAULT_STEPPING_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) #define DEFAULT_STEPPING_INVERT_MASK 0
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT))
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled) #define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm #define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
#define DEFAULT_ARC_TOLERANCE 0.005 // mm #define DEFAULT_ARC_TOLERANCE 0.005 // mm
@ -51,6 +52,7 @@
#define DEFAULT_REPORT_INCHES 0 // false #define DEFAULT_REPORT_INCHES 0 // false
#define DEFAULT_AUTO_START 1 // true #define DEFAULT_AUTO_START 1 // true
#define DEFAULT_INVERT_ST_ENABLE 0 // false #define DEFAULT_INVERT_ST_ENABLE 0 // false
#define DEFAULT_INVERT_LIMIT_PINS 0 // false
#define DEFAULT_SOFT_LIMIT_ENABLE 0 // false #define DEFAULT_SOFT_LIMIT_ENABLE 0 // false
#define DEFAULT_HARD_LIMIT_ENABLE 0 // false #define DEFAULT_HARD_LIMIT_ENABLE 0 // false
#define DEFAULT_HOMING_ENABLE 0 // false #define DEFAULT_HOMING_ENABLE 0 // false
@ -81,7 +83,8 @@
#define DEFAULT_Z_MAX_TRAVEL 170.0 // mm #define DEFAULT_Z_MAX_TRAVEL 170.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10 #define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_FEEDRATE 254.0 // mm/min (10 ipm) #define DEFAULT_FEEDRATE 254.0 // mm/min (10 ipm)
#define DEFAULT_STEPPING_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) #define DEFAULT_STEPPING_INVERT_MASK 0
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT))
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled) #define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm #define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
#define DEFAULT_ARC_TOLERANCE 0.005 // mm #define DEFAULT_ARC_TOLERANCE 0.005 // mm
@ -89,6 +92,7 @@
#define DEFAULT_REPORT_INCHES 0 // true #define DEFAULT_REPORT_INCHES 0 // true
#define DEFAULT_AUTO_START 1 // true #define DEFAULT_AUTO_START 1 // true
#define DEFAULT_INVERT_ST_ENABLE 0 // false #define DEFAULT_INVERT_ST_ENABLE 0 // false
#define DEFAULT_INVERT_LIMIT_PINS 0 // false
#define DEFAULT_SOFT_LIMIT_ENABLE 0 // false #define DEFAULT_SOFT_LIMIT_ENABLE 0 // false
#define DEFAULT_HARD_LIMIT_ENABLE 0 // false #define DEFAULT_HARD_LIMIT_ENABLE 0 // false
#define DEFAULT_HOMING_ENABLE 0 // false #define DEFAULT_HOMING_ENABLE 0 // false
@ -122,7 +126,8 @@
#define DEFAULT_Z_MAX_TRAVEL 200.0 // mm #define DEFAULT_Z_MAX_TRAVEL 200.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10 #define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_FEEDRATE 250.0 #define DEFAULT_FEEDRATE 250.0
#define DEFAULT_STEPPING_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) #define DEFAULT_STEPPING_INVERT_MASK 0
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT))
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled) #define DEFAULT_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm #define DEFAULT_JUNCTION_DEVIATION 0.05 // mm
#define DEFAULT_ARC_TOLERANCE 0.005 // mm #define DEFAULT_ARC_TOLERANCE 0.005 // mm
@ -130,6 +135,7 @@
#define DEFAULT_REPORT_INCHES 0 // false #define DEFAULT_REPORT_INCHES 0 // false
#define DEFAULT_AUTO_START 1 // true #define DEFAULT_AUTO_START 1 // true
#define DEFAULT_INVERT_ST_ENABLE 0 // false #define DEFAULT_INVERT_ST_ENABLE 0 // false
#define DEFAULT_INVERT_LIMIT_PINS 0 // false
#define DEFAULT_SOFT_LIMIT_ENABLE 0 // false #define DEFAULT_SOFT_LIMIT_ENABLE 0 // false
#define DEFAULT_HARD_LIMIT_ENABLE 0 // false #define DEFAULT_HARD_LIMIT_ENABLE 0 // false
#define DEFAULT_HOMING_ENABLE 0 // false #define DEFAULT_HOMING_ENABLE 0 // false
@ -171,6 +177,7 @@
#define DEFAULT_REPORT_INCHES 0 // false #define DEFAULT_REPORT_INCHES 0 // false
#define DEFAULT_AUTO_START 1 // true #define DEFAULT_AUTO_START 1 // true
#define DEFAULT_INVERT_ST_ENABLE 0 // false #define DEFAULT_INVERT_ST_ENABLE 0 // false
#define DEFAULT_INVERT_LIMIT_PINS 0 // false
#define DEFAULT_SOFT_LIMIT_ENABLE 0 // false #define DEFAULT_SOFT_LIMIT_ENABLE 0 // false
#define DEFAULT_HARD_LIMIT_ENABLE 0 // false #define DEFAULT_HARD_LIMIT_ENABLE 0 // false
#define DEFAULT_HOMING_ENABLE 0 // false #define DEFAULT_HOMING_ENABLE 0 // false
@ -202,7 +209,8 @@
#define DEFAULT_Z_MAX_TRAVEL 150.0 // mm #define DEFAULT_Z_MAX_TRAVEL 150.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10 #define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_FEEDRATE 1000.0 // mm/min #define DEFAULT_FEEDRATE 1000.0 // mm/min
#define DEFAULT_STEPPING_INVERT_MASK ((1<<Y_DIRECTION_BIT)) #define DEFAULT_STEPPING_INVERT_MASK 0
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT))
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled) #define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm #define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
#define DEFAULT_ARC_TOLERANCE 0.005 // mm #define DEFAULT_ARC_TOLERANCE 0.005 // mm
@ -210,6 +218,7 @@
#define DEFAULT_REPORT_INCHES 0 // false #define DEFAULT_REPORT_INCHES 0 // false
#define DEFAULT_AUTO_START 1 // true #define DEFAULT_AUTO_START 1 // true
#define DEFAULT_INVERT_ST_ENABLE 0 // false #define DEFAULT_INVERT_ST_ENABLE 0 // false
#define DEFAULT_INVERT_LIMIT_PINS 0 // false
#define DEFAULT_SOFT_LIMIT_ENABLE 0 // false #define DEFAULT_SOFT_LIMIT_ENABLE 0 // false
#define DEFAULT_HARD_LIMIT_ENABLE 0 // false #define DEFAULT_HARD_LIMIT_ENABLE 0 // false
#define DEFAULT_HOMING_ENABLE 0 // false #define DEFAULT_HOMING_ENABLE 0 // false

View File

@ -39,11 +39,11 @@ void limits_init()
{ {
LIMIT_DDR &= ~(LIMIT_MASK); // Set as input pins LIMIT_DDR &= ~(LIMIT_MASK); // Set as input pins
#ifndef LIMIT_SWITCHES_ACTIVE_HIGH if (bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) {
LIMIT_PORT |= (LIMIT_MASK); // Enable internal pull-up resistors. Normal high operation.
#else
LIMIT_PORT &= ~(LIMIT_MASK); // Normal low operation. Requires external pull-down. LIMIT_PORT &= ~(LIMIT_MASK); // Normal low operation. Requires external pull-down.
#endif } else {
LIMIT_PORT |= (LIMIT_MASK); // Enable internal pull-up resistors. Normal high operation.
}
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) {
LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt
@ -123,13 +123,14 @@ void limits_disable()
// asynchronous stops are handled by a system level axis lock mask, which prevents the stepper // asynchronous stops are handled by a system level axis lock mask, which prevents the stepper
// algorithm from executing step pulses. // algorithm from executing step pulses.
// NOTE: Only the abort runtime command can interrupt this process. // NOTE: Only the abort runtime command can interrupt this process.
void limits_go_home(uint8_t cycle_mask, bool approach, bool invert_pin, float homing_rate) void limits_go_home(uint8_t cycle_mask, bool approach, float homing_rate)
{ {
if (sys.execute & EXEC_RESET) { return; } if (sys.execute & EXEC_RESET) { return; }
uint8_t limit_state;
#ifndef LIMIT_SWITCHES_ACTIVE_HIGH uint8_t invert_pin;
invert_pin = !invert_pin; if (bit_isfalse(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { invert_pin = approach; }
#endif else { invert_pin = !approach; }
// Determine travel distance to the furthest homing switch based on user max travel settings. // Determine travel distance to the furthest homing switch based on user max travel settings.
float max_travel = settings.max_travel[X_AXIS]; float max_travel = settings.max_travel[X_AXIS];
if (max_travel < settings.max_travel[Y_AXIS]) { max_travel = settings.max_travel[Y_AXIS]; } if (max_travel < settings.max_travel[Y_AXIS]) { max_travel = settings.max_travel[Y_AXIS]; }
@ -155,13 +156,14 @@ void limits_go_home(uint8_t cycle_mask, bool approach, bool invert_pin, float ho
homing_rate *= sqrt(n_active_axis); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate. homing_rate *= sqrt(n_active_axis); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate.
// Setup homing axis locks based on cycle mask. // Setup homing axis locks based on cycle mask.
uint8_t axislock = (STEPPING_MASK & ~STEP_MASK); uint8_t axislock = 0;
if (bit_istrue(cycle_mask,bit(X_AXIS))) { axislock |= (1<<X_STEP_BIT); } if (bit_istrue(cycle_mask,bit(X_AXIS))) { axislock |= (1<<X_STEP_BIT); }
if (bit_istrue(cycle_mask,bit(Y_AXIS))) { axislock |= (1<<Y_STEP_BIT); } if (bit_istrue(cycle_mask,bit(Y_AXIS))) { axislock |= (1<<Y_STEP_BIT); }
if (bit_istrue(cycle_mask,bit(Z_AXIS))) { axislock |= (1<<Z_STEP_BIT); } if (bit_istrue(cycle_mask,bit(Z_AXIS))) { axislock |= (1<<Z_STEP_BIT); }
sys.homing_axis_lock = axislock; sys.homing_axis_lock = axislock;
// Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle. // Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle.
uint8_t limit_state;
plan_buffer_line(target, homing_rate, false); // Bypass mc_line(). Directly plan homing motion. plan_buffer_line(target, homing_rate, false); // Bypass mc_line(). Directly plan homing motion.
st_prep_buffer(); // Prep first segment from newly planned block. st_prep_buffer(); // Prep first segment from newly planned block.
st_wake_up(); // Initiate motion st_wake_up(); // Initiate motion

View File

@ -28,7 +28,7 @@ void limits_init();
void limits_disable(); void limits_disable();
// Perform one portion of the homing cycle based on the input settings. // Perform one portion of the homing cycle based on the input settings.
void limits_go_home(uint8_t cycle_mask, bool approach, bool invert_pin, float homing_rate); void limits_go_home(uint8_t cycle_mask, bool approach, float homing_rate);
// Check for soft limit violations // Check for soft limit violations
void limits_soft_check(float *target); void limits_soft_check(float *target);

1
main.c
View File

@ -88,6 +88,7 @@ int main(void)
sys.abort = false; sys.abort = false;
sys.execute = 0; sys.execute = 0;
if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; } if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; }
else { sys.auto_start = false; }
// Check for and report alarm state after a reset, error, or an initial power up. // Check for and report alarm state after a reset, error, or an initial power up.
if (sys.state == STATE_ALARM) { if (sys.state == STATE_ALARM) {

View File

@ -224,12 +224,12 @@ void mc_homing_cycle()
// Perform homing routine. NOTE: Special motion case. Only system reset works. // Perform homing routine. NOTE: Special motion case. Only system reset works.
// Search to engage all axes limit switches at faster homing seek rate. // Search to engage all axes limit switches at faster homing seek rate.
limits_go_home(HOMING_SEARCH_CYCLE_0, true, false, settings.homing_seek_rate); // Search cycle 0 limits_go_home(HOMING_SEARCH_CYCLE_0, true, settings.homing_seek_rate); // Search cycle 0
#ifdef HOMING_SEARCH_CYCLE_1 #ifdef HOMING_SEARCH_CYCLE_1
limits_go_home(HOMING_SEARCH_CYCLE_1, true, false, settings.homing_seek_rate); // Search cycle 1 limits_go_home(HOMING_SEARCH_CYCLE_1, true, settings.homing_seek_rate); // Search cycle 1
#endif #endif
#ifdef HOMING_SEARCH_CYCLE_2 #ifdef HOMING_SEARCH_CYCLE_2
limits_go_home(HOMING_SEARCH_CYCLE_2, true, false, settings.homing_seek_rate); // Search cycle 2 limits_go_home(HOMING_SEARCH_CYCLE_2, true, settings.homing_seek_rate); // Search cycle 2
#endif #endif
// Now in proximity of all limits. Carefully leave and approach switches in multiple cycles // Now in proximity of all limits. Carefully leave and approach switches in multiple cycles
@ -237,11 +237,11 @@ void mc_homing_cycle()
int8_t n_cycle = N_HOMING_LOCATE_CYCLE; int8_t n_cycle = N_HOMING_LOCATE_CYCLE;
while (n_cycle--) { while (n_cycle--) {
// Leave all switches to release them. After cycles complete, this is machine zero. // Leave all switches to release them. After cycles complete, this is machine zero.
limits_go_home(HOMING_LOCATE_CYCLE, false, true, settings.homing_feed_rate); limits_go_home(HOMING_LOCATE_CYCLE, false, settings.homing_feed_rate);
if (n_cycle > 0) { if (n_cycle > 0) {
// Re-approach all switches to re-engage them. // Re-approach all switches to re-engage them.
limits_go_home(HOMING_LOCATE_CYCLE, true, false, settings.homing_feed_rate); limits_go_home(HOMING_LOCATE_CYCLE, true, settings.homing_feed_rate);
} }
} }
// ------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------
@ -291,15 +291,23 @@ void mc_homing_cycle()
} }
// Auto-cycle start is a user setting that automatically begins the cycle when a user enters // Auto-cycle start has two purposes: 1. Resumes a plan_synchronize() call from a function that
// a valid motion command either manually or by a streaming tool. This is intended as a beginners // requires the planner buffer to empty (spindle enable, dwell, etc.) 2. As a user setting that
// feature to help new users to understand g-code. It can be disabled. Otherwise, the normal // automatically begins the cycle when a user enters a valid motion command manually. This is
// operation of cycle start is manually issuing a cycle start command whenever the user is // intended as a beginners feature to help new users to understand g-code. It can be disabled
// ready and there is a valid motion command in the planner queue. // as a beginner tool, but (1.) still operates. If disabled, the operation of cycle start is
// manually issuing a cycle start command whenever the user is ready and there is a valid motion
// command in the planner queue.
// NOTE: This function is called from the main loop and mc_line() only and executes when one of // NOTE: This function is called from the main loop and mc_line() only and executes when one of
// two conditions exist respectively: There are no more blocks sent (i.e. streaming is finished, // two conditions exist respectively: There are no more blocks sent (i.e. streaming is finished,
// single commands), or the planner buffer is full and ready to go. // single commands), or the planner buffer is full and ready to go.
void mc_auto_cycle_start() { if (sys.auto_start) { st_cycle_start(); } } void mc_auto_cycle_start()
{
if (sys.auto_start) {
st_cycle_start();
if (bit_isfalse(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = false; } // Reset auto start per settings.
}
}
// Method to ready the system to reset by setting the runtime reset command and killing any // Method to ready the system to reset by setting the runtime reset command and killing any

View File

@ -27,7 +27,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "config.h" #include "config.h"
#include "defaults.h" #include "defaults.h"
#include "pin_map.h" #include "cpu_map.h"
#define false 0 #define false 0
#define true 1 #define true 1

View File

@ -255,6 +255,7 @@ uint8_t plan_check_full_buffer()
// during a synchronize call, if it should happen. Also, waits for clean cycle end. // during a synchronize call, if it should happen. Also, waits for clean cycle end.
void plan_synchronize() void plan_synchronize()
{ {
sys.auto_start = true; // Set auto start to resume cycle after synchronize and caller completes.
while (plan_get_current_block() || (sys.state == STATE_CYCLE)) { while (plan_get_current_block() || (sys.state == STATE_CYCLE)) {
protocol_execute_runtime(); // Check and execute run-time commands protocol_execute_runtime(); // Check and execute run-time commands
if (sys.abort) { return; } // Check for system abort if (sys.abort) { return; } // Check for system abort

View File

@ -192,16 +192,10 @@ uint8_t protocol_execute_line(char *line)
{ {
// Grbl internal command and parameter lines are of the form '$4=374.3' or '$' for help // Grbl internal command and parameter lines are of the form '$4=374.3' or '$' for help
if(line[0] == '$') { if(line[0] == '$') {
uint8_t char_counter = 1; uint8_t char_counter = 1;
uint8_t helper_var = 0; // Helper variable uint8_t helper_var = 0; // Helper variable
float parameter, value; float parameter, value;
switch( line[char_counter] ) { switch( line[char_counter] ) {
case 0 : report_grbl_help(); break;
case '$' : // Prints Grbl settings
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
else { report_grbl_settings(); }
break;
case '#' : // Print gcode parameters case '#' : // Print gcode parameters
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
else { report_gcode_parameters(); } else { report_gcode_parameters(); }
@ -210,37 +204,6 @@ uint8_t protocol_execute_line(char *line)
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
else { report_gcode_modes(); } else { report_gcode_modes(); }
break; break;
case 'C' : // Set check g-code mode
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
// Perform reset when toggling off. Check g-code mode should only work if Grbl
// is idle and ready, regardless of alarm locks. This is mainly to keep things
// simple and consistent.
if ( sys.state == STATE_CHECK_MODE ) {
mc_reset();
report_feedback_message(MESSAGE_DISABLED);
} else {
if (sys.state) { return(STATUS_IDLE_ERROR); }
sys.state = STATE_CHECK_MODE;
report_feedback_message(MESSAGE_ENABLED);
}
break;
case 'X' : // Disable alarm lock
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
if (sys.state == STATE_ALARM) {
report_feedback_message(MESSAGE_ALARM_UNLOCK);
sys.state = STATE_IDLE;
// Don't run startup script. Prevents stored moves in startup from causing accidents.
}
break;
case 'H' : // Perform homing cycle
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
// Only perform homing if Grbl is idle or lost.
if ( sys.state == STATE_IDLE || sys.state == STATE_ALARM ) {
mc_homing_cycle();
if (!sys.abort) { protocol_execute_startup(); } // Execute startup scripts after successful homing.
} else { return(STATUS_IDLE_ERROR); }
} else { return(STATUS_SETTING_DISABLED); }
break;
// case 'J' : break; // Jogging methods // case 'J' : break; // Jogging methods
// TODO: Here jogging can be placed for execution as a seperate subprogram. It does not need to be // 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 // susceptible to other runtime commands except for e-stop. The jogging function is intended to
@ -252,42 +215,81 @@ uint8_t protocol_execute_line(char *line)
// More controlled exact motions can be taken care of by inputting G0 or G1 commands, which are // 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 // 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 // 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. // on its own carefully. This approach could be effective and possibly size/memory efficient.
case 'N' : // Startup lines. default :
if ( line[++char_counter] == 0 ) { // Print startup lines // Block any system command that requires the state as IDLE/ALARM. (i.e. EEPROM, homing)
for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) { if ( !(sys.state == STATE_IDLE || sys.state == STATE_ALARM) ) { return(STATUS_IDLE_ERROR); }
if (!(settings_read_startup_line(helper_var, line))) { switch( line[char_counter] ) {
report_status_message(STATUS_SETTING_READ_FAIL); case 0 : report_grbl_help(); break;
case '$' : // Prints Grbl settings
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
else { report_grbl_settings(); }
break;
case 'C' : // Set check g-code mode
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
// Perform reset when toggling off. Check g-code mode should only work if Grbl
// is idle and ready, regardless of alarm locks. This is mainly to keep things
// simple and consistent.
if ( sys.state == STATE_CHECK_MODE ) {
mc_reset();
report_feedback_message(MESSAGE_DISABLED);
} else { } else {
report_startup_line(helper_var,line); if (sys.state) { return(STATUS_IDLE_ERROR); }
sys.state = STATE_CHECK_MODE;
report_feedback_message(MESSAGE_ENABLED);
} }
} break;
break; case 'X' : // Disable alarm lock
} else { // Store startup line if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
helper_var = true; // Set helper_var to flag storing method. if (sys.state == STATE_ALARM) {
// No break. Continues into default: to read remaining command characters. report_feedback_message(MESSAGE_ALARM_UNLOCK);
} sys.state = STATE_IDLE;
default : // Storing setting methods // Don't run startup script. Prevents stored moves in startup from causing accidents.
if(!read_float(line, &char_counter, &parameter)) { return(STATUS_BAD_NUMBER_FORMAT); } }
if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); } break;
if (helper_var) { // Store startup line case 'H' : // Perform homing cycle
// Prepare sending gcode block to gcode parser by shifting all characters if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
helper_var = char_counter; // Set helper variable as counter to start of gcode block // Only perform homing if Grbl is idle or lost.
do { mc_homing_cycle();
line[char_counter-helper_var] = line[char_counter]; if (!sys.abort) { protocol_execute_startup(); } // Execute startup scripts after successful homing.
} while (line[char_counter++] != 0); } else { return(STATUS_SETTING_DISABLED); }
// Execute gcode block to ensure block is valid. break;
helper_var = gc_execute_line(line); // Set helper_var to returned status code. case 'N' : // Startup lines.
if (helper_var) { return(helper_var); } if ( line[++char_counter] == 0 ) { // Print startup lines
else { for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) {
helper_var = trunc(parameter); // Set helper_var to int value of parameter if (!(settings_read_startup_line(helper_var, line))) {
settings_store_startup_line(helper_var,line); report_status_message(STATUS_SETTING_READ_FAIL);
} } else {
} else { // Store global setting. report_startup_line(helper_var,line);
if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); } }
if(line[char_counter] != 0) { return(STATUS_UNSUPPORTED_STATEMENT); } }
return(settings_store_global_setting(parameter, value)); break;
} } else { // Store startup line
helper_var = true; // Set helper_var to flag storing method.
// No break. Continues into default: to read remaining command characters.
}
default : // Storing setting methods
if(!read_float(line, &char_counter, &parameter)) { return(STATUS_BAD_NUMBER_FORMAT); }
if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); }
if (helper_var) { // Store startup line
// Prepare sending gcode block to gcode parser by shifting all characters
helper_var = char_counter; // Set helper variable as counter to start of gcode block
do {
line[char_counter-helper_var] = line[char_counter];
} while (line[char_counter++] != 0);
// Execute gcode block to ensure block is valid.
helper_var = gc_execute_line(line); // Set helper_var to returned status code.
if (helper_var) { return(helper_var); }
else {
helper_var = trunc(parameter); // Set helper_var to int value of parameter
settings_store_startup_line(helper_var,line);
}
} else { // Store global setting.
if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); }
if(line[char_counter] != 0) { return(STATUS_UNSUPPORTED_STATEMENT); }
return(settings_store_global_setting(parameter, value));
}
}
} }
return(STATUS_OK); // If '$' command makes it to here, then everything's ok. return(STATUS_OK); // If '$' command makes it to here, then everything's ok.

View File

@ -71,7 +71,7 @@ void report_status_message(uint8_t status_code)
case STATUS_SETTING_READ_FAIL: case STATUS_SETTING_READ_FAIL:
printPgmString(PSTR("EEPROM read fail. Using defaults")); break; printPgmString(PSTR("EEPROM read fail. Using defaults")); break;
case STATUS_IDLE_ERROR: case STATUS_IDLE_ERROR:
printPgmString(PSTR("Busy or queued")); break; printPgmString(PSTR("Not idle")); break;
case STATUS_ALARM_LOCK: case STATUS_ALARM_LOCK:
printPgmString(PSTR("Alarm lock")); break; printPgmString(PSTR("Alarm lock")); break;
case STATUS_SOFT_LIMIT_ERROR: case STATUS_SOFT_LIMIT_ERROR:
@ -162,24 +162,27 @@ void report_grbl_settings() {
printPgmString(PSTR(" (y max travel, mm)\r\n$11=")); printFloat(-settings.max_travel[Z_AXIS]); // Grbl internally store this as negative. printPgmString(PSTR(" (y max travel, mm)\r\n$11=")); printFloat(-settings.max_travel[Z_AXIS]); // Grbl internally store this as negative.
printPgmString(PSTR(" (z max travel, mm)\r\n$12=")); printInteger(settings.pulse_microseconds); printPgmString(PSTR(" (z max travel, mm)\r\n$12=")); printInteger(settings.pulse_microseconds);
printPgmString(PSTR(" (step pulse, usec)\r\n$13=")); printFloat(settings.default_feed_rate); printPgmString(PSTR(" (step pulse, usec)\r\n$13=")); printFloat(settings.default_feed_rate);
printPgmString(PSTR(" (default feed, mm/min)\r\n$14=")); printInteger(settings.invert_mask); printPgmString(PSTR(" (default feed, mm/min)\r\n$14=")); printInteger(settings.step_invert_mask);
printPgmString(PSTR(" (step port invert mask, int:")); print_uint8_base2(settings.invert_mask); printPgmString(PSTR(" (step port invert mask, int:")); print_uint8_base2(settings.step_invert_mask);
printPgmString(PSTR(")\r\n$15=")); printInteger(settings.stepper_idle_lock_time); printPgmString(PSTR(")\r\n$15=")); printInteger(settings.dir_invert_mask);
printPgmString(PSTR(" (step idle delay, msec)\r\n$16=")); printFloat(settings.junction_deviation); printPgmString(PSTR(" (dir port invert mask, int:")); print_uint8_base2(settings.dir_invert_mask);
printPgmString(PSTR(" (junction deviation, mm)\r\n$17=")); printFloat(settings.arc_tolerance); printPgmString(PSTR(")\r\n$16=")); printInteger(settings.stepper_idle_lock_time);
printPgmString(PSTR(" (arc tolerance, mm)\r\n$18=")); printInteger(settings.decimal_places); printPgmString(PSTR(" (step idle delay, msec)\r\n$17=")); printFloat(settings.junction_deviation);
printPgmString(PSTR(" (n-decimals, int)\r\n$19=")); printInteger(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)); printPgmString(PSTR(" (junction deviation, mm)\r\n$18=")); printFloat(settings.arc_tolerance);
printPgmString(PSTR(" (report inches, bool)\r\n$20=")); printInteger(bit_istrue(settings.flags,BITFLAG_AUTO_START)); printPgmString(PSTR(" (arc tolerance, mm)\r\n$19=")); printInteger(settings.decimal_places);
printPgmString(PSTR(" (auto start, bool)\r\n$21=")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)); printPgmString(PSTR(" (n-decimals, int)\r\n$20=")); printInteger(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES));
printPgmString(PSTR(" (invert step enable, bool)\r\n$22=")); printInteger(bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE)); printPgmString(PSTR(" (report inches, bool)\r\n$21=")); printInteger(bit_istrue(settings.flags,BITFLAG_AUTO_START));
printPgmString(PSTR(" (soft limits, bool)\r\n$23=")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)); printPgmString(PSTR(" (auto start, bool)\r\n$22=")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE));
printPgmString(PSTR(" (hard limits, bool)\r\n$24=")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)); printPgmString(PSTR(" (invert step enable, bool)\r\n$23=")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS));
printPgmString(PSTR(" (homing cycle, bool)\r\n$25=")); printInteger(settings.homing_dir_mask); printPgmString(PSTR(" (invert limit pins, bool)\r\n$24=")); printInteger(bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE));
printPgmString(PSTR(" (soft limits, bool)\r\n$25=")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE));
printPgmString(PSTR(" (hard limits, bool)\r\n$26=")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE));
printPgmString(PSTR(" (homing cycle, bool)\r\n$27=")); printInteger(settings.homing_dir_mask);
printPgmString(PSTR(" (homing dir invert mask, int:")); print_uint8_base2(settings.homing_dir_mask); printPgmString(PSTR(" (homing dir invert mask, int:")); print_uint8_base2(settings.homing_dir_mask);
printPgmString(PSTR(")\r\n$26=")); printFloat(settings.homing_feed_rate); printPgmString(PSTR(")\r\n$28=")); printFloat(settings.homing_feed_rate);
printPgmString(PSTR(" (homing feed, mm/min)\r\n$27=")); printFloat(settings.homing_seek_rate); printPgmString(PSTR(" (homing feed, mm/min)\r\n$29=")); printFloat(settings.homing_seek_rate);
printPgmString(PSTR(" (homing seek, mm/min)\r\n$28=")); printInteger(settings.homing_debounce_delay); printPgmString(PSTR(" (homing seek, mm/min)\r\n$30=")); printInteger(settings.homing_debounce_delay);
printPgmString(PSTR(" (homing debounce, msec)\r\n$29=")); printFloat(settings.homing_pulloff); printPgmString(PSTR(" (homing debounce, msec)\r\n$31=")); printFloat(settings.homing_pulloff);
printPgmString(PSTR(" (homing pull-off, mm)\r\n")); printPgmString(PSTR(" (homing pull-off, mm)\r\n"));
} }

View File

@ -80,7 +80,8 @@ void settings_reset(bool reset_all) {
settings.acceleration[Y_AXIS] = DEFAULT_Y_ACCELERATION; settings.acceleration[Y_AXIS] = DEFAULT_Y_ACCELERATION;
settings.acceleration[Z_AXIS] = DEFAULT_Z_ACCELERATION; settings.acceleration[Z_AXIS] = DEFAULT_Z_ACCELERATION;
settings.arc_tolerance = DEFAULT_ARC_TOLERANCE; settings.arc_tolerance = DEFAULT_ARC_TOLERANCE;
settings.invert_mask = DEFAULT_STEPPING_INVERT_MASK; settings.step_invert_mask = DEFAULT_STEPPING_INVERT_MASK;
settings.dir_invert_mask = DEFAULT_DIRECTION_INVERT_MASK;
settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION; settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION;
} }
// New settings since last version // New settings since last version
@ -88,6 +89,7 @@ void settings_reset(bool reset_all) {
if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; } if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; }
if (DEFAULT_AUTO_START) { settings.flags |= BITFLAG_AUTO_START; } if (DEFAULT_AUTO_START) { settings.flags |= BITFLAG_AUTO_START; }
if (DEFAULT_INVERT_ST_ENABLE) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; } if (DEFAULT_INVERT_ST_ENABLE) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
if (DEFAULT_INVERT_LIMIT_PINS) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; }
if (DEFAULT_SOFT_LIMIT_ENABLE) { settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE; } if (DEFAULT_SOFT_LIMIT_ENABLE) { settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE; }
if (DEFAULT_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; } if (DEFAULT_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
if (DEFAULT_HOMING_ENABLE) { settings.flags |= BITFLAG_HOMING_ENABLE; } if (DEFAULT_HOMING_ENABLE) { settings.flags |= BITFLAG_HOMING_ENABLE; }
@ -176,46 +178,51 @@ uint8_t settings_store_global_setting(int parameter, float value) {
if (value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); } if (value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); }
settings.pulse_microseconds = round(value); break; settings.pulse_microseconds = round(value); break;
case 13: settings.default_feed_rate = value; break; case 13: settings.default_feed_rate = value; break;
case 14: settings.invert_mask = trunc(value); break; case 14: settings.step_invert_mask = trunc(value); break;
case 15: settings.stepper_idle_lock_time = round(value); break; case 15: settings.dir_invert_mask = trunc(value); break;
case 16: settings.junction_deviation = fabs(value); break; case 16: settings.stepper_idle_lock_time = round(value); break;
case 17: settings.arc_tolerance = value; break; case 17: settings.junction_deviation = fabs(value); break;
case 18: settings.decimal_places = round(value); break; case 18: settings.arc_tolerance = value; break;
case 19: case 19: settings.decimal_places = round(value); break;
case 20:
if (value) { settings.flags |= BITFLAG_REPORT_INCHES; } if (value) { settings.flags |= BITFLAG_REPORT_INCHES; }
else { settings.flags &= ~BITFLAG_REPORT_INCHES; } else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
break; break;
case 20: // Reset to ensure change. Immediate re-init may cause problems. case 21: // Reset to ensure change. Immediate re-init may cause problems.
if (value) { settings.flags |= BITFLAG_AUTO_START; } if (value) { settings.flags |= BITFLAG_AUTO_START; }
else { settings.flags &= ~BITFLAG_AUTO_START; } else { settings.flags &= ~BITFLAG_AUTO_START; }
break; break;
case 21: // Reset to ensure change. Immediate re-init may cause problems. case 22: // Reset to ensure change. Immediate re-init may cause problems.
if (value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; } if (value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; } else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; }
break; break;
case 22: case 23: // Reset to ensure change. Immediate re-init may cause problems.
if (value) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; }
else { settings.flags &= ~BITFLAG_INVERT_LIMIT_PINS; }
break;
case 24:
if (value) { if (value) {
if (bit_isfalse(settings.flags, BITFLAG_HOMING_ENABLE)) { return(STATUS_SOFT_LIMIT_ERROR); } if (bit_isfalse(settings.flags, BITFLAG_HOMING_ENABLE)) { return(STATUS_SOFT_LIMIT_ERROR); }
settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE; settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE;
} else { settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; } } else { settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; }
break; break;
case 23: case 25:
if (value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; } if (value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; } else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; }
limits_init(); // Re-init to immediately change. NOTE: Nice to have but could be problematic later. limits_init(); // Re-init to immediately change. NOTE: Nice to have but could be problematic later.
break; break;
case 24: case 26:
if (value) { settings.flags |= BITFLAG_HOMING_ENABLE; } if (value) { settings.flags |= BITFLAG_HOMING_ENABLE; }
else { else {
settings.flags &= ~BITFLAG_HOMING_ENABLE; settings.flags &= ~BITFLAG_HOMING_ENABLE;
settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; // Force disable soft-limits.
} }
break; break;
case 25: settings.homing_dir_mask = trunc(value); break; case 27: settings.homing_dir_mask = trunc(value); break;
case 26: settings.homing_feed_rate = value; break; case 28: settings.homing_feed_rate = value; break;
case 27: settings.homing_seek_rate = value; break; case 29: settings.homing_seek_rate = value; break;
case 28: settings.homing_debounce_delay = round(value); break; case 30: settings.homing_debounce_delay = round(value); break;
case 29: settings.homing_pulloff = value; break; case 31: settings.homing_pulloff = value; break;
default: default:
return(STATUS_INVALID_STATEMENT); return(STATUS_INVALID_STATEMENT);
} }

View File

@ -30,7 +30,7 @@
// Version of the EEPROM data. Will be used to migrate existing data from older versions of Grbl // 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 // when firmware is upgraded. Always stored in byte 0 of eeprom
#define SETTINGS_VERSION 56 #define SETTINGS_VERSION 57
// Define bit flag masks for the boolean settings in settings.flag. // Define bit flag masks for the boolean settings in settings.flag.
#define BITFLAG_REPORT_INCHES bit(0) #define BITFLAG_REPORT_INCHES bit(0)
@ -39,6 +39,7 @@
#define BITFLAG_HARD_LIMIT_ENABLE bit(3) #define BITFLAG_HARD_LIMIT_ENABLE bit(3)
#define BITFLAG_HOMING_ENABLE bit(4) #define BITFLAG_HOMING_ENABLE bit(4)
#define BITFLAG_SOFT_LIMIT_ENABLE bit(5) #define BITFLAG_SOFT_LIMIT_ENABLE bit(5)
#define BITFLAG_INVERT_LIMIT_PINS bit(6)
// Define EEPROM memory address location values for Grbl settings and parameters // Define EEPROM memory address location values for Grbl settings and parameters
// NOTE: The Atmega328p has 1KB EEPROM. The upper half is reserved for parameters and // NOTE: The Atmega328p has 1KB EEPROM. The upper half is reserved for parameters and
@ -64,7 +65,8 @@ typedef struct {
float max_travel[N_AXIS]; float max_travel[N_AXIS];
uint8_t pulse_microseconds; uint8_t pulse_microseconds;
float default_feed_rate; float default_feed_rate;
uint8_t invert_mask; uint8_t step_invert_mask;
uint8_t dir_invert_mask;
uint8_t stepper_idle_lock_time; // If max value 255, steppers do not disable. uint8_t stepper_idle_lock_time; // If max value 255, steppers do not disable.
float junction_deviation; float junction_deviation;
float arc_tolerance; float arc_tolerance;

237
stepper.c
View File

@ -35,6 +35,12 @@
#define RAMP_DECEL 2 #define RAMP_DECEL 2
#define MAX_AMASS_LEVEL 3
#define AMASS_LEVEL1 (F_CPU/10000)
#define AMASS_LEVEL2 (F_CPU/5000)
#define AMASS_LEVEL3 (F_CPU/2500)
// Stores the planner block Bresenham algorithm execution data for the segments in the segment // Stores the planner block Bresenham algorithm execution data for the segments in the segment
// buffer. Normally, this buffer is partially in-use, but, for the worst case scenario, it will // buffer. Normally, this buffer is partially in-use, but, for the worst case scenario, it will
// never exceed the number of accessible stepper buffer segments (SEGMENT_BUFFER_SIZE-1). // never exceed the number of accessible stepper buffer segments (SEGMENT_BUFFER_SIZE-1).
@ -57,7 +63,7 @@ typedef struct {
uint16_t n_step; // Number of step events to be executed for this segment uint16_t n_step; // Number of step events to be executed for this segment
uint8_t st_block_index; // Stepper block data index. Uses this information to execute this segment. uint8_t st_block_index; // Stepper block data index. Uses this information to execute this segment.
uint16_t cycles_per_tick; // Step distance traveled per ISR tick, aka step rate. uint16_t cycles_per_tick; // Step distance traveled per ISR tick, aka step rate.
uint8_t prescaler; uint8_t amass_level;
} segment_t; } segment_t;
static segment_t segment_buffer[SEGMENT_BUFFER_SIZE]; static segment_t segment_buffer[SEGMENT_BUFFER_SIZE];
@ -65,17 +71,19 @@ static segment_t segment_buffer[SEGMENT_BUFFER_SIZE];
typedef struct { typedef struct {
// Used by the bresenham line algorithm // Used by the bresenham line algorithm
uint32_t counter_x, // Counter variables for the bresenham line tracer uint32_t counter_x, // Counter variables for the bresenham line tracer
counter_y, counter_y,
counter_z; counter_z;
#if STEP_PULSE_DELAY > 0 #ifdef STEP_PULSE_DELAY
uint8_t step_bits; // Stores out_bits output to complete the step pulse delay uint8_t step_bits; // Stores out_bits output to complete the step pulse delay
#endif #endif
// Used by the stepper driver interrupt // Used by the stepper driver interrupt
uint8_t execute_step; // Flags step execution for each interrupt. uint8_t execute_step; // Flags step execution for each interrupt.
uint8_t step_pulse_time; // Step pulse reset time after step rise uint8_t step_pulse_time; // Step pulse reset time after step rise
uint8_t out_bits; // The next stepping-bits to be output uint8_t step_outbits; // The next stepping-bits to be output
uint8_t dir_outbits;
uint32_t steps[N_AXIS];
uint16_t step_count; // Steps remaining in line segment motion uint16_t step_count; // Steps remaining in line segment motion
uint8_t exec_block_index; // Tracks the current st_block index. Change indicates new block. uint8_t exec_block_index; // Tracks the current st_block index. Change indicates new block.
@ -120,6 +128,8 @@ typedef struct {
static st_prep_t prep; static st_prep_t prep;
static void st_config_step_timer(uint32_t cycles);
/* BLOCK VELOCITY PROFILE DEFINITION /* BLOCK VELOCITY PROFILE DEFINITION
__________________________ __________________________
/| |\ _________________ ^ /| |\ _________________ ^
@ -158,6 +168,7 @@ static st_prep_t prep;
are shown and defined in the above illustration. are shown and defined in the above illustration.
*/ */
// Stepper state initialization. Cycle should only start if the st.cycle_start flag is // 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. // enabled. Startup init and limits call this function but shouldn't start the cycle.
void st_wake_up() void st_wake_up()
@ -170,20 +181,22 @@ void st_wake_up()
} }
if (sys.state & (STATE_CYCLE | STATE_HOMING)){ if (sys.state & (STATE_CYCLE | STATE_HOMING)){
// Initialize stepper output bits // Initialize stepper output bits
st.out_bits = settings.invert_mask; st.dir_outbits = settings.dir_invert_mask;
st.step_outbits = settings.step_invert_mask;
// Initialize step pulse timing from settings. Here to ensure updating after re-writing. // Initialize step pulse timing from settings. Here to ensure updating after re-writing.
#ifdef STEP_PULSE_DELAY #ifdef STEP_PULSE_DELAY
// Set total step pulse time after direction pin set. Ad hoc computation from oscilloscope. // Set total step pulse time after direction pin set. Ad hoc computation from oscilloscope.
st.step_pulse_time = -(((settings.pulse_microseconds+STEP_PULSE_DELAY-2)*TICKS_PER_MICROSECOND) >> 3); st.step_pulse_time = -(((settings.pulse_microseconds+STEP_PULSE_DELAY-2)*TICKS_PER_MICROSECOND) >> 3);
// Set delay between direction pin write and step command. // Set delay between direction pin write and step command.
OCR2A = -(((settings.pulse_microseconds)*TICKS_PER_MICROSECOND) >> 3); OCR0A = -(((settings.pulse_microseconds)*TICKS_PER_MICROSECOND) >> 3);
#else // Normal operation #else // Normal operation
// Set step pulse time. Ad hoc computation from oscilloscope. Uses two's complement. // Set step pulse time. Ad hoc computation from oscilloscope. Uses two's complement.
st.step_pulse_time = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3); st.step_pulse_time = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3);
#endif #endif
// Enable stepper driver interrupt // Enable Stepper Driver Interrupt
TCCR1B = (TCCR1B & ~(0x07<<CS10)) | (1<<CS10); // Set prescaler
TIMSK1 |= (1<<OCIE1A); TIMSK1 |= (1<<OCIE1A);
} }
} }
@ -192,10 +205,8 @@ void st_wake_up()
// Stepper shutdown // Stepper shutdown
void st_go_idle() void st_go_idle()
{ {
// Disable stepper driver interrupt. Allow Timer0 to finish. It will disable itself. // Disable Timer1 Stepper Driver Interrupt. Allow Timer0 to finish. It will disable itself.
TIMSK1 &= ~(1<<OCIE1A); TIMSK1 &= ~(1<<OCIE1A);
// TIMSK2 &= ~(1<<OCIE2A); // Disable Timer2 interrupt
// TCCR2B = 0; // Disable Timer2
busy = false; busy = false;
// Disable steppers only upon system alarm activated or by user setting to not be kept enabled. // Disable steppers only upon system alarm activated or by user setting to not be kept enabled.
@ -242,19 +253,20 @@ ISR(TIMER1_COMPA_vect)
if (busy) { return; } // The busy-flag is used to avoid reentering this interrupt if (busy) { return; } // The busy-flag is used to avoid reentering this interrupt
// Set the direction pins a couple of nanoseconds before we step the steppers // Set the direction pins a couple of nanoseconds before we step the steppers
STEPPING_PORT = (STEPPING_PORT & ~DIRECTION_MASK) | (st.out_bits & DIRECTION_MASK); DIRECTION_PORT = (DIRECTION_PORT & ~DIRECTION_MASK) | (st.dir_outbits & DIRECTION_MASK);
// Then pulse the stepping pins // Then pulse the stepping pins
#ifdef STEP_PULSE_DELAY #ifdef STEP_PULSE_DELAY
st.step_bits = (STEPPING_PORT & ~STEP_MASK) | st.out_bits; // Store out_bits to prevent overwriting. st.step_bits = (STEPPING_PORT & ~STEP_MASK) | st.step_outbits; // Store out_bits to prevent overwriting.
#else // Normal operation #else // Normal operation
STEPPING_PORT = (STEPPING_PORT & ~STEP_MASK) | st.out_bits; STEPPING_PORT = (STEPPING_PORT & ~STEP_MASK) | st.step_outbits;
#endif #endif
// Enable step pulse reset timer so that The Stepper Port Reset Interrupt can reset the signal after // Enable step pulse reset timer so that The Stepper Port Reset Interrupt can reset the signal after
// exactly settings.pulse_microseconds microseconds, independent of the main Timer1 prescaler. // exactly settings.pulse_microseconds microseconds, independent of the main Timer1 prescaler.
TCNT2 = st.step_pulse_time; // Reload timer counter TCNT0 = st.step_pulse_time; // Reload Timer0 counter
TCCR2B = (1<<CS21); // Begin timer2. Full speed, 1/8 prescaler TCCR0B = (1<<CS21); // Begin Timer0. Full speed, 1/8 prescaler
busy = true; busy = true;
sei(); // Re-enable interrupts to allow Stepper Port Reset Interrupt to fire on-time. sei(); // Re-enable interrupts to allow Stepper Port Reset Interrupt to fire on-time.
// NOTE: The remaining code in this ISR will finish before returning to main program. // NOTE: The remaining code in this ISR will finish before returning to main program.
@ -266,7 +278,7 @@ ISR(TIMER1_COMPA_vect)
// Initialize new step segment and load number of steps to execute // Initialize new step segment and load number of steps to execute
st.exec_segment = &segment_buffer[segment_buffer_tail]; st.exec_segment = &segment_buffer[segment_buffer_tail];
// Initialize step segment timing per step and load number of steps to execute. // Initialize step segment timing per step and load number of steps to execute.
TCCR1B = (TCCR1B & ~(0x07<<CS10)) | (st.exec_segment->prescaler<<CS10); // TCCR1B = (TCCR1B & ~(0x07<<CS10)) | (st.exec_segment->prescaler<<CS10);
OCR1A = st.exec_segment->cycles_per_tick; OCR1A = st.exec_segment->cycles_per_tick;
st.step_count = st.exec_segment->n_step; // NOTE: Can sometimes be zero when moving slow. st.step_count = st.exec_segment->n_step; // NOTE: Can sometimes be zero when moving slow.
// If the new segment starts a new planner block, initialize stepper variables and counters. // If the new segment starts a new planner block, initialize stepper variables and counters.
@ -274,11 +286,15 @@ ISR(TIMER1_COMPA_vect)
if ( st.exec_block_index != st.exec_segment->st_block_index ) { if ( st.exec_block_index != st.exec_segment->st_block_index ) {
st.exec_block_index = st.exec_segment->st_block_index; st.exec_block_index = st.exec_segment->st_block_index;
st.exec_block = &st_block_buffer[st.exec_block_index]; st.exec_block = &st_block_buffer[st.exec_block_index];
st.dir_outbits = st.exec_block->direction_bits ^ settings.dir_invert_mask;
// Initialize Bresenham line and distance counters // Initialize Bresenham line and distance counters
st.counter_x = (st.exec_block->step_event_count >> 1); st.counter_x = (st.exec_block->step_event_count >> 1);
st.counter_y = st.counter_x; st.counter_y = st.counter_x;
st.counter_z = st.counter_x; st.counter_z = st.counter_x;
} }
st.steps[X_AXIS] = st.exec_block->steps[X_AXIS] >> st.exec_segment->amass_level;
st.steps[Y_AXIS] = st.exec_block->steps[Y_AXIS] >> st.exec_segment->amass_level;
st.steps[Z_AXIS] = st.exec_block->steps[Z_AXIS] >> st.exec_segment->amass_level;
} else { } else {
// Segment buffer empty. Shutdown. // Segment buffer empty. Shutdown.
st_go_idle(); st_go_idle();
@ -287,46 +303,43 @@ ISR(TIMER1_COMPA_vect)
} }
} }
// Reset out_bits and reload direction bits // Reset step out bits.
st.out_bits = st.exec_block->direction_bits; st.step_outbits = 0;
// Execute step displacement profile by Bresenham line algorithm // Execute step displacement profile by Bresenham line algorithm
if (st.step_count > 0) { st.counter_x += st.steps[X_AXIS];
st.step_count--; // Decrement step events count if (st.counter_x > st.exec_block->step_event_count) {
st.step_outbits |= (1<<X_STEP_BIT);
st.counter_x -= st.exec_block->step_event_count;
if (st.exec_block->direction_bits & (1<<X_DIRECTION_BIT)) { sys.position[X_AXIS]--; }
else { sys.position[X_AXIS]++; }
}
st.counter_y += st.steps[Y_AXIS];
if (st.counter_y > st.exec_block->step_event_count) {
st.step_outbits |= (1<<Y_STEP_BIT);
st.counter_y -= st.exec_block->step_event_count;
if (st.exec_block->direction_bits & (1<<Y_DIRECTION_BIT)) { sys.position[Y_AXIS]--; }
else { sys.position[Y_AXIS]++; }
}
st.counter_z += st.steps[Z_AXIS];
if (st.counter_z > st.exec_block->step_event_count) {
st.step_outbits |= (1<<Z_STEP_BIT);
st.counter_z -= st.exec_block->step_event_count;
if (st.exec_block->direction_bits & (1<<Z_DIRECTION_BIT)) { sys.position[Z_AXIS]--; }
else { sys.position[Z_AXIS]++; }
}
st.counter_x += st.exec_block->steps[X_AXIS]; // During a homing cycle, lock out and prevent desired axes from moving.
if (st.counter_x > st.exec_block->step_event_count) { if (sys.state == STATE_HOMING) { st.step_outbits &= sys.homing_axis_lock; }
st.out_bits |= (1<<X_STEP_BIT);
st.counter_x -= st.exec_block->step_event_count;
if (st.out_bits & (1<<X_DIRECTION_BIT)) { sys.position[X_AXIS]--; }
else { sys.position[X_AXIS]++; }
}
st.counter_y += st.exec_block->steps[Y_AXIS];
if (st.counter_y > st.exec_block->step_event_count) {
st.out_bits |= (1<<Y_STEP_BIT);
st.counter_y -= st.exec_block->step_event_count;
if (st.out_bits & (1<<Y_DIRECTION_BIT)) { sys.position[Y_AXIS]--; }
else { sys.position[Y_AXIS]++; }
}
st.counter_z += st.exec_block->steps[Z_AXIS];
if (st.counter_z > st.exec_block->step_event_count) {
st.out_bits |= (1<<Z_STEP_BIT);
st.counter_z -= st.exec_block->step_event_count;
if (st.out_bits & (1<<Z_DIRECTION_BIT)) { sys.position[Z_AXIS]--; }
else { sys.position[Z_AXIS]++; }
}
// During a homing cycle, lock out and prevent desired axes from moving.
if (sys.state == STATE_HOMING) { st.out_bits &= sys.homing_axis_lock; }
}
st.step_count--; // Decrement step events count
if (st.step_count == 0) { if (st.step_count == 0) {
// Segment is complete. Discard current segment and advance segment indexing. // Segment is complete. Discard current segment and advance segment indexing.
st.exec_segment = NULL; st.exec_segment = NULL;
if ( ++segment_buffer_tail == SEGMENT_BUFFER_SIZE) { segment_buffer_tail = 0; } if ( ++segment_buffer_tail == SEGMENT_BUFFER_SIZE) { segment_buffer_tail = 0; }
} }
st.out_bits ^= settings.invert_mask; // Apply step port invert mask st.step_outbits ^= settings.step_invert_mask; // Apply step port invert mask
busy = false; busy = false;
// SPINDLE_ENABLE_PORT ^= 1<<SPINDLE_ENABLE_BIT; // SPINDLE_ENABLE_PORT ^= 1<<SPINDLE_ENABLE_BIT;
} }
@ -335,12 +348,6 @@ ISR(TIMER1_COMPA_vect)
/* The Stepper Port Reset Interrupt: Timer0 OVF interrupt handles the falling edge of the step /* The Stepper Port Reset Interrupt: Timer0 OVF interrupt handles the falling edge of the step
pulse. This should always trigger before the next Timer2 COMPA interrupt and independently pulse. This should always trigger before the next Timer2 COMPA interrupt and independently
finish, if Timer2 is disabled after completing a move. */ finish, if Timer2 is disabled after completing a move. */
// ISR(TIMER0_OVF_vect)
// {
// STEPPING_PORT = (STEPPING_PORT & ~STEP_MASK) | (settings.invert_mask & STEP_MASK);
// TCCR0B = 0; // Disable timer until needed.
// }
// This interrupt is set up by ISR_TIMER1_COMPAREA when it sets the motor port bits. It resets // This interrupt is set up by ISR_TIMER1_COMPAREA when it sets the motor port bits. It resets
// the motor port after a short period (settings.pulse_microseconds) completing one step cycle. // the motor port after a short period (settings.pulse_microseconds) completing one step cycle.
@ -348,11 +355,11 @@ ISR(TIMER1_COMPA_vect)
// a few microseconds, if they execute right before one another. Not a big deal, but can // a few microseconds, if they execute right before one another. Not a big deal, but can
// cause issues at high step rates if another high frequency asynchronous interrupt is // cause issues at high step rates if another high frequency asynchronous interrupt is
// added to Grbl. // added to Grbl.
ISR(TIMER2_OVF_vect) ISR(TIMER0_OVF_vect)
{ {
// Reset stepping pins (leave the direction pins) // Reset stepping pins (leave the direction pins)
STEPPING_PORT = (STEPPING_PORT & ~STEP_MASK) | (settings.invert_mask & STEP_MASK); STEPPING_PORT = (STEPPING_PORT & ~STEP_MASK) | (settings.step_invert_mask & STEP_MASK);
TCCR2B = 0; // Disable Timer2 to prevent re-entering this interrupt when it's not needed. TCCR0B = 0; // Disable Timer0 to prevent re-entering this interrupt when it's not needed.
} }
@ -362,7 +369,7 @@ ISR(TIMER2_OVF_vect)
// will then trigger after the appropriate settings.pulse_microseconds, as in normal operation. // will then trigger after the appropriate settings.pulse_microseconds, as in normal operation.
// The new timing between direction, step pulse, and step complete events are setup in the // The new timing between direction, step pulse, and step complete events are setup in the
// st_wake_up() routine. // st_wake_up() routine.
ISR(TIMER2_COMPA_vect) ISR(TIMER0_COMPA_vect)
{ {
STEPPING_PORT = st.step_bits; // Begin step pulse. STEPPING_PORT = st.step_bits; // Begin step pulse.
} }
@ -387,12 +394,14 @@ void st_reset()
// Initialize and start the stepper motor subsystem // Initialize and start the stepper motor subsystem
void st_init() void st_init()
{ {
// Configure directions of interface pins // Configure step and direction interface pins
STEPPING_DDR |= STEPPING_MASK; STEPPING_DDR |= STEP_MASK;
STEPPING_PORT = (STEPPING_PORT & ~STEPPING_MASK) | settings.invert_mask; STEPPING_PORT = (STEPPING_PORT & ~STEP_MASK) | settings.step_invert_mask;
STEPPERS_DISABLE_DDR |= 1<<STEPPERS_DISABLE_BIT; STEPPERS_DISABLE_DDR |= 1<<STEPPERS_DISABLE_BIT;
DIRECTION_DDR |= DIRECTION_MASK;
DIRECTION_PORT = (DIRECTION_PORT & ~DIRECTION_MASK) | settings.dir_invert_mask;
// Configure Timer 1 // Configure Timer 1: Stepper Driver Interrupt
TCCR1B &= ~(1<<WGM13); // waveform generation = 0100 = CTC TCCR1B &= ~(1<<WGM13); // waveform generation = 0100 = CTC
TCCR1B |= (1<<WGM12); TCCR1B |= (1<<WGM12);
TCCR1A &= ~(1<<WGM11); TCCR1A &= ~(1<<WGM11);
@ -401,12 +410,13 @@ void st_init()
TCCR1A &= ~(3<<COM1B0); TCCR1A &= ~(3<<COM1B0);
TCCR1B = (TCCR1B & ~(0x07<<CS10)) | (1<<CS10); TCCR1B = (TCCR1B & ~(0x07<<CS10)) | (1<<CS10);
// Configure Timer 2 // Configure Timer 0: Stepper Port Reset Interrupt
TCCR2A = 0; // Normal operation TIMSK0 &= ~(1<<TOIE0);
TCCR2B = 0; // Disable timer until needed. TCCR0A = 0; // Normal operation
TIMSK2 |= (1<<TOIE2); // Enable Timer2 Overflow interrupt TCCR0B = 0; // Disable Timer0 until needed
TIMSK0 |= (1<<TOIE0); // Enable Timer0 overflow interrupt
#ifdef STEP_PULSE_DELAY #ifdef STEP_PULSE_DELAY
TIMSK2 |= (1<<OCIE2A); // Enable Timer2 Compare Match A interrupt TIMSK0 |= (1<<OCIE0A); // Enable Timer0 Compare Match A interrupt
#endif #endif
// Start in the idle state, but first wake up to check for keep steppers enabled option. // Start in the idle state, but first wake up to check for keep steppers enabled option.
@ -510,10 +520,17 @@ void st_prep_buffer()
// when the segment buffer completes the planner block, it may be discarded immediately. // when the segment buffer completes the planner block, it may be discarded immediately.
st_prep_block = &st_block_buffer[prep.st_block_index]; st_prep_block = &st_block_buffer[prep.st_block_index];
st_prep_block->direction_bits = pl_block->direction_bits; st_prep_block->direction_bits = pl_block->direction_bits;
st_prep_block->steps[X_AXIS] = pl_block->steps[X_AXIS]; #ifdef ACTIVE_MULTI_AXIS_STEP_SMOOTHING
st_prep_block->steps[Y_AXIS] = pl_block->steps[Y_AXIS]; st_prep_block->steps[X_AXIS] = pl_block->steps[X_AXIS] << MAX_AMASS_LEVEL;
st_prep_block->steps[Z_AXIS] = pl_block->steps[Z_AXIS]; st_prep_block->steps[Y_AXIS] = pl_block->steps[Y_AXIS] << MAX_AMASS_LEVEL;
st_prep_block->step_event_count = pl_block->step_event_count; st_prep_block->steps[Z_AXIS] = pl_block->steps[Z_AXIS] << MAX_AMASS_LEVEL;
st_prep_block->step_event_count = pl_block->step_event_count << MAX_AMASS_LEVEL;
#else
st_prep_block->steps[X_AXIS] = pl_block->steps[X_AXIS];
st_prep_block->steps[Y_AXIS] = pl_block->steps[Y_AXIS];
st_prep_block->steps[Z_AXIS] = pl_block->steps[Z_AXIS];
st_prep_block->step_event_count = pl_block->step_event_count;
#endif
// Initialize segment buffer data for generating the segments. // Initialize segment buffer data for generating the segments.
prep.steps_remaining = pl_block->step_event_count; prep.steps_remaining = pl_block->step_event_count;
@ -678,11 +695,26 @@ void st_prep_buffer()
uint32_t cycles; uint32_t cycles;
float steps_remaining = prep.step_per_mm*mm_remaining; float steps_remaining = prep.step_per_mm*mm_remaining;
float inv_rate = dt/(prep.steps_remaining-steps_remaining);
cycles = ceil( (TICKS_PER_MICROSECOND*1000000*60)*inv_rate ); // (ftol_mult*step/isr_tic)
// Compute number of steps to execute and segment step phase correction. // Compute number of steps to execute and segment step phase correction.
prep_segment->n_step = ceil(prep.steps_remaining)-ceil(steps_remaining); prep_segment->n_step = ceil(prep.steps_remaining)-ceil(steps_remaining);
float inv_rate = dt/(prep.steps_remaining-steps_remaining);
cycles = ceil( (TICKS_PER_MICROSECOND*1000000*60)*inv_rate ); // (cycles/step)
#ifdef ACTIVE_MULTI_AXIS_STEP_SMOOTHING
// Compute step timing and multi-axis smoothing level.
// NOTE: Only one prescalar is required with AMASS enabled.
if (cycles > AMASS_LEVEL1) {
if (cycles > AMASS_LEVEL2) {
if (cycles > AMASS_LEVEL3) { prep_segment->amass_level = 3; }
else { prep_segment->amass_level = 2; }
} else { prep_segment->amass_level = 1; }
cycles >>= prep_segment->amass_level;
prep_segment->n_step <<= prep_segment->amass_level;
} else { prep_segment->amass_level = 0; }
if (cycles < (1UL << 16)) { prep_segment->cycles_per_tick = cycles; }
else { prep_segment->cycles_per_tick = 0xffff; } // Just set the slowest speed possible. (4.1ms @ 16MHz)
#endif
// Determine end of segment conditions. Setup initial conditions for next segment. // Determine end of segment conditions. Setup initial conditions for next segment.
if (mm_remaining > prep.mm_complete) { if (mm_remaining > prep.mm_complete) {
@ -715,29 +747,6 @@ void st_prep_buffer()
} }
} }
// TODO: Compile-time checks to what prescalers need to be compiled in.
if (cycles < (1UL << 16)) { // < 65536 (4.1ms @ 16MHz)
prep_segment->prescaler = 1; // prescaler: 0
prep_segment->cycles_per_tick = cycles;
} else {
prep_segment->prescaler = 2; // prescaler: 8
if (cycles < (1UL << 19)) { // < 524288 (32.8ms@16MHz)
prep_segment->cycles_per_tick = cycles >> 3;
// } else if (cycles < (1UL << 22)) { // < 4194304 (262ms@16MHz)
// prep_segment->prescaler = 3; // prescaler: 64
// prep_segment->cycles_per_tick = cycles >> 6;
// } else if (cycles < (1UL << 24)) { // < 16777216 (1.05sec@16MHz)
// prep_segment->prescaler = 4; // prescaler: 256
// prep_segment->cycles_per_tick = (cycles >> 8);
// } else {
// prep_segment->prescaler = 5; // prescaler: 1024
// if (cycles < (1UL << 26)) { // < 67108864 (4.19sec@16MHz)
// prep_segment->cycles_per_tick = (cycles >> 10);
} else { // Just set the slowest speed possible.
prep_segment->cycles_per_tick = 0xffff;
}
}
// New step segment initialization completed. Increment segment buffer indices. // New step segment initialization completed. Increment segment buffer indices.
segment_buffer_head = segment_next_head; segment_buffer_head = segment_next_head;
if ( ++segment_next_head == SEGMENT_BUFFER_SIZE ) { segment_next_head = 0; } if ( ++segment_next_head == SEGMENT_BUFFER_SIZE ) { segment_next_head = 0; }
@ -776,3 +785,31 @@ void st_prep_buffer()
we know when the plan is feasible in the context of what's already in the code and not we know when the plan is feasible in the context of what's already in the code and not
require too much more code? require too much more code?
*/ */
// static void st_config_step_timer(uint32_t cycles)
// {
// if (cycles < (1UL << 16)) { // < 65536 (4.1ms @ 16MHz)
// prep_segment->prescaler = 1; // prescaler: 0
// prep_segment->cycles_per_tick = cycles;
// } else {
// prep_segment->prescaler = 2; // prescaler: 8
// if (cycles < (1UL << 19)) { // < 524288 (32.8ms@16MHz)
// prep_segment->cycles_per_tick = cycles >> 3;
//
// // } else if (cycles < (1UL << 22)) { // < 4194304 (262ms@16MHz)
// // prep_segment->prescaler = 3; // prescaler: 64
// // prep_segment->cycles_per_tick = cycles >> 6;
// // } else if (cycles < (1UL << 24)) { // < 16777216 (1.05sec@16MHz)
// // prep_segment->prescaler = 4; // prescaler: 256
// // prep_segment->cycles_per_tick = (cycles >> 8);
// // } else {
// // prep_segment->prescaler = 5; // prescaler: 1024
// // if (cycles < (1UL << 26)) { // < 67108864 (4.19sec@16MHz)
// // prep_segment->cycles_per_tick = (cycles >> 10);
//
// } else { // Just set the slowest speed possible.
// prep_segment->cycles_per_tick = 0xffff;
// }
// printString("X");
// }
// }