2009-01-28 23:48:21 +01:00
|
|
|
/*
|
2011-01-14 16:45:18 +01:00
|
|
|
stepper.c - stepper motor driver: executes motion plans using stepper motors
|
2009-01-28 23:48:21 +01:00
|
|
|
Part of Grbl
|
|
|
|
|
2012-01-29 04:41:08 +01:00
|
|
|
Copyright (c) 2011-2012 Sungeun K. Jeon
|
2012-12-08 23:00:58 +01:00
|
|
|
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
2011-09-24 15:46:41 +02:00
|
|
|
|
2009-01-28 23:48:21 +01:00
|
|
|
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/>.
|
|
|
|
*/
|
|
|
|
|
2009-01-29 09:58:29 +01:00
|
|
|
/* The timer calculations of this module informed by the 'RepRap cartesian firmware' by Zack Smith
|
2011-02-11 01:31:44 +01:00
|
|
|
and Philipp Tiefenbacher. */
|
2009-01-29 09:58:29 +01:00
|
|
|
|
New startup script setting. New dry run, check gcode switches. New system state variable. Lots of reorganizing.
(All v0.8 features installed. Still likely buggy, but now thourough
testing will need to start to squash them all. As soon as we're done,
this will be pushed to master and v0.9 development will be started.
Please report ANY issues to us so we can get this rolled out ASAP.)
- User startup script! A user can now save one (up to 5 as compile-time
option) block of g-code in EEPROM memory. This will be run everytime
Grbl resets. Mainly to be used as a way to set your preferences, like
G21, G54, etc.
- New dry run and check g-code switches. Dry run moves ALL motions at
rapids rate ignoring spindle, coolant, and dwell commands. For rapid
physical proofing of your code. The check g-code switch ignores all
motion and provides the user a way to check if there are any errors in
their program that Grbl may not like.
- Program restart! (sort of). Program restart is typically an advanced
feature that allows users to restart a program mid-stream. The check
g-code switch can perform this feature by enabling the switch at the
start of the program, and disabling it at the desired point with some
minimal changes.
- New system state variable. This state variable tracks all of the
different state processes that Grbl performs, i.e. cycle start, feed
hold, homing, etc. This is mainly for making managing of these task
easier and more clear.
- Position lost state variable. Only when homing is enabled, Grbl will
refuse to move until homing is completed and position is known. This is
mainly for safety. Otherwise, it will let users fend for themselves.
- Moved the default settings defines into config.h. The plan is to
eventually create a set of config.h's for particular as-built machines
to help users from doing it themselves.
- Moved around misc defines into .h files. And lots of other little
things.
2012-11-03 18:32:23 +01:00
|
|
|
#include <avr/interrupt.h>
|
2009-01-28 23:48:21 +01:00
|
|
|
#include "stepper.h"
|
2011-02-05 00:55:37 +01:00
|
|
|
#include "config.h"
|
2011-02-05 00:45:41 +01:00
|
|
|
#include "settings.h"
|
2011-02-11 00:34:53 +01:00
|
|
|
#include "planner.h"
|
2011-01-31 23:04:39 +01:00
|
|
|
|
2012-11-09 03:23:47 +01:00
|
|
|
// Some useful constants
|
|
|
|
#define TICKS_PER_MICROSECOND (F_CPU/1000000)
|
2012-12-08 23:00:58 +01:00
|
|
|
#define CRUISE_RAMP 0
|
|
|
|
#define ACCEL_RAMP 1
|
|
|
|
#define DECEL_RAMP 2
|
2011-02-04 22:09:09 +01:00
|
|
|
|
2011-12-09 02:47:48 +01:00
|
|
|
// Stepper state variable. Contains running data and trapezoid variables.
|
|
|
|
typedef struct {
|
|
|
|
// Used by the bresenham line algorithm
|
|
|
|
int32_t counter_x, // Counter variables for the bresenham line tracer
|
|
|
|
counter_y,
|
|
|
|
counter_z;
|
2012-12-08 23:00:58 +01:00
|
|
|
uint32_t event_count; // Total event count. Retained for feed holds.
|
|
|
|
uint32_t step_events_remaining; // Steps remaining in motion
|
|
|
|
|
|
|
|
// Used by Pramod Ranade inverse time algorithm
|
|
|
|
int32_t delta_d; // Ranade distance traveled per interrupt tick
|
|
|
|
int32_t d_counter; // Ranade distance traveled since last step event
|
2012-12-20 01:30:09 +01:00
|
|
|
uint8_t ramp_count; // Acceleration interrupt tick counter.
|
2012-12-08 23:00:58 +01:00
|
|
|
uint8_t ramp_type; // Ramp type variable.
|
|
|
|
uint8_t execute_step; // Flags step execution for each interrupt.
|
|
|
|
|
2012-01-06 18:10:41 +01:00
|
|
|
} stepper_t;
|
|
|
|
static stepper_t st;
|
2011-02-11 00:34:53 +01:00
|
|
|
static block_t *current_block; // A pointer to the block currently being traced
|
2010-12-20 14:01:38 +01:00
|
|
|
|
2011-12-09 02:47:48 +01:00
|
|
|
// Used by the stepper driver interrupt
|
|
|
|
static uint8_t step_pulse_time; // Step pulse reset time after step rise
|
2011-01-25 23:33:19 +01:00
|
|
|
static uint8_t out_bits; // The next stepping-bits to be output
|
2011-01-22 23:29:02 +01:00
|
|
|
|
2012-12-08 23:00:58 +01:00
|
|
|
// NOTE: If the main interrupt is guaranteed to be complete before the next interrupt, then
|
|
|
|
// this blocking variable is no longer needed. Only here for safety reasons.
|
|
|
|
static volatile uint8_t busy; // True when "Stepper Driver Interrupt" is being serviced. Used to avoid retriggering that handler.
|
2012-06-27 05:48:42 +02:00
|
|
|
|
2013-02-20 14:56:47 +01:00
|
|
|
|
2011-01-03 00:36:33 +01:00
|
|
|
// __________________________
|
|
|
|
// /| |\ _________________ ^
|
|
|
|
// / | | \ /| |\ |
|
|
|
|
// / | | \ / | | \ s
|
|
|
|
// / | | | | | \ p
|
|
|
|
// / | | | | | \ e
|
|
|
|
// +-----+------------------------+---+--+---------------+----+ e
|
|
|
|
// | BLOCK 1 | BLOCK 2 | d
|
|
|
|
//
|
|
|
|
// time ----->
|
|
|
|
//
|
2011-01-24 20:55:25 +01:00
|
|
|
// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates by block->rate_delta
|
2012-12-08 23:00:58 +01:00
|
|
|
// until reaching cruising speed block->nominal_rate, and/or until step_events_remaining reaches block->decelerate_after
|
|
|
|
// after which it decelerates until the block is completed. The driver uses constant acceleration, which is applied as
|
|
|
|
// +/- block->rate_delta velocity increments by the midpoint rule at each ACCELERATION_TICKS_PER_SECOND.
|
2011-01-31 23:04:39 +01:00
|
|
|
|
2012-11-01 16:37:27 +01:00
|
|
|
// 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()
|
2011-12-09 02:47:48 +01:00
|
|
|
{
|
2011-05-31 13:08:42 +02:00
|
|
|
// Enable steppers by resetting the stepper disable port
|
2012-11-01 16:37:27 +01:00
|
|
|
if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) {
|
|
|
|
STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT);
|
|
|
|
} else {
|
|
|
|
STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT);
|
|
|
|
}
|
New startup script setting. New dry run, check gcode switches. New system state variable. Lots of reorganizing.
(All v0.8 features installed. Still likely buggy, but now thourough
testing will need to start to squash them all. As soon as we're done,
this will be pushed to master and v0.9 development will be started.
Please report ANY issues to us so we can get this rolled out ASAP.)
- User startup script! A user can now save one (up to 5 as compile-time
option) block of g-code in EEPROM memory. This will be run everytime
Grbl resets. Mainly to be used as a way to set your preferences, like
G21, G54, etc.
- New dry run and check g-code switches. Dry run moves ALL motions at
rapids rate ignoring spindle, coolant, and dwell commands. For rapid
physical proofing of your code. The check g-code switch ignores all
motion and provides the user a way to check if there are any errors in
their program that Grbl may not like.
- Program restart! (sort of). Program restart is typically an advanced
feature that allows users to restart a program mid-stream. The check
g-code switch can perform this feature by enabling the switch at the
start of the program, and disabling it at the desired point with some
minimal changes.
- New system state variable. This state variable tracks all of the
different state processes that Grbl performs, i.e. cycle start, feed
hold, homing, etc. This is mainly for making managing of these task
easier and more clear.
- Position lost state variable. Only when homing is enabled, Grbl will
refuse to move until homing is completed and position is known. This is
mainly for safety. Otherwise, it will let users fend for themselves.
- Moved the default settings defines into config.h. The plan is to
eventually create a set of config.h's for particular as-built machines
to help users from doing it themselves.
- Moved around misc defines into .h files. And lots of other little
things.
2012-11-03 18:32:23 +01:00
|
|
|
if (sys.state == STATE_CYCLE) {
|
2012-11-01 16:37:27 +01:00
|
|
|
// Initialize stepper output bits
|
2012-12-08 23:00:58 +01:00
|
|
|
out_bits = settings.invert_mask;
|
|
|
|
// Initialize step pulse timing from settings.
|
|
|
|
step_pulse_time = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3);
|
2012-11-01 16:37:27 +01:00
|
|
|
// Enable stepper driver interrupt
|
2012-12-08 23:00:58 +01:00
|
|
|
st.execute_step = false;
|
|
|
|
TCNT2 = 0; // Clear Timer2
|
|
|
|
TIMSK2 |= (1<<OCIE2A); // Enable Timer2 Compare Match A interrupt
|
|
|
|
TCCR2B = (1<<CS21); // Begin Timer2. Full speed, 1/8 prescaler
|
2012-11-01 16:37:27 +01:00
|
|
|
}
|
2011-05-31 13:08:42 +02:00
|
|
|
}
|
|
|
|
|
2011-10-12 04:51:04 +02:00
|
|
|
// Stepper shutdown
|
2011-12-09 02:47:48 +01:00
|
|
|
void st_go_idle()
|
|
|
|
{
|
2012-12-11 02:50:18 +01:00
|
|
|
// Disable stepper driver interrupt. Allow Timer0 to finish. It will disable itself.
|
2012-12-08 23:00:58 +01:00
|
|
|
TIMSK2 &= ~(1<<OCIE2A); // Disable Timer2 interrupt
|
|
|
|
TCCR2B = 0; // Disable Timer2
|
|
|
|
|
2012-10-22 03:18:24 +02:00
|
|
|
// Disable steppers only upon system alarm activated or by user setting to not be kept enabled.
|
Hard limits, homing direction, pull-off limits after homing, status reports in mm or inches, system alarm, and more.
- Thank you statement added for Alden Hart of Synthetos.
- Hard limits option added, which also works with homing by pulling off
the switches to help prevent unintended triggering. Hard limits use a
interrupt to sense a falling edge pin change and immediately go into
alarm mode, which stops everything and forces the user to issue a reset
(Ctrl-x) or reboot.
- Auto cycle start now a configuration option.
- Alarm mode: A new method to kill all Grbl processes in the event of
something catastrophic or potentially catastropic. Just works with hard
limits for now, but will be expanded to include g-code errors (most
likely) and other events.
- Updated status reports to be configurable in inches or mm mode. Much
more to do here, but this is the first step.
- New settings: auto cycle start, hard limit enable, homing direction
mask (which works the same as the stepper mask), homing pulloff
distance (or distance traveled from homed machine zero to prevent
accidental limit trip).
- Minor memory liberation and calculation speed ups.
2012-10-17 05:29:45 +02:00
|
|
|
if ((settings.stepper_idle_lock_time != 0xff) || bit_istrue(sys.execute,EXEC_ALARM)) {
|
2012-11-01 16:37:27 +01:00
|
|
|
// 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);
|
|
|
|
}
|
2012-10-13 21:11:43 +02:00
|
|
|
}
|
2011-02-11 00:34:53 +01:00
|
|
|
}
|
|
|
|
|
2010-12-20 14:01:38 +01:00
|
|
|
|
2012-12-08 23:00:58 +01:00
|
|
|
// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse of Grbl. It is based
|
|
|
|
// on the Pramod Ranade inverse time stepper algorithm, where a timer ticks at a constant
|
|
|
|
// frequency and uses time-distance counters to track when its the approximate time for any
|
|
|
|
// step event. However, the Ranade algorithm, as described, is susceptible to numerical round-off,
|
|
|
|
// meaning that some axes steps may not execute for a given multi-axis motion.
|
|
|
|
// Grbl's algorithm slightly differs by using a single Ranade time-distance counter to manage
|
2012-12-11 02:50:18 +01:00
|
|
|
// a Bresenham line algorithm for multi-axis step events which ensures the number of steps for
|
2012-12-08 23:00:58 +01:00
|
|
|
// each axis are executed exactly. In other words, it uses a Bresenham within a Bresenham algorithm,
|
|
|
|
// where one tracks time(Ranade) and the other steps.
|
|
|
|
// This interrupt pops blocks from the block_buffer and executes them by pulsing the stepper pins
|
|
|
|
// appropriately. It is supported by The Stepper Port Reset Interrupt which it uses to reset the
|
|
|
|
// stepper port after each pulse. The bresenham line tracer algorithm controls all three stepper
|
|
|
|
// outputs simultaneously with these two interrupts.
|
|
|
|
//
|
|
|
|
// NOTE: Average time in this ISR is: 5 usec iterating timers only, 20-25 usec with step event, or
|
|
|
|
// 15 usec when popping a block. So, ensure Ranade frequency and step pulse times work with this.
|
|
|
|
ISR(TIMER2_COMPA_vect)
|
|
|
|
{
|
|
|
|
// SPINDLE_ENABLE_PORT ^= 1<<SPINDLE_ENABLE_BIT; // Debug: Used to time ISR
|
2011-12-09 02:47:48 +01:00
|
|
|
if (busy) { return; } // The busy-flag is used to avoid reentering this interrupt
|
2011-01-24 20:55:25 +01:00
|
|
|
|
2012-12-17 00:23:24 +01:00
|
|
|
// Pulse stepper port pins, if flagged. New block dir will always be set one timer tick
|
|
|
|
// before any step pulse due to algorithm design.
|
2012-12-08 23:00:58 +01:00
|
|
|
if (st.execute_step) {
|
|
|
|
st.execute_step = false;
|
|
|
|
STEPPING_PORT = ( STEPPING_PORT & ~(DIRECTION_MASK | STEP_MASK) ) | out_bits;
|
|
|
|
TCNT0 = step_pulse_time; // Reload Timer0 counter.
|
|
|
|
TCCR0B = (1<<CS21); // Begin Timer0. Full speed, 1/8 prescaler
|
|
|
|
}
|
|
|
|
|
2012-01-16 02:25:12 +01:00
|
|
|
busy = true;
|
2012-12-11 02:50:18 +01:00
|
|
|
sei(); // Re-enable interrupts. This ISR will still finish before returning to main program.
|
2012-01-16 02:25:12 +01:00
|
|
|
|
2011-01-03 00:36:33 +01:00
|
|
|
// If there is no current block, attempt to pop one from the buffer
|
|
|
|
if (current_block == NULL) {
|
2012-12-08 23:00:58 +01:00
|
|
|
|
2011-12-09 02:47:48 +01:00
|
|
|
// Anything in the buffer? If so, initialize next motion.
|
2011-02-06 23:52:12 +01:00
|
|
|
current_block = plan_get_current_block();
|
|
|
|
if (current_block != NULL) {
|
2012-12-08 23:00:58 +01:00
|
|
|
// By algorithm design, the loading of the next block never coincides with a step event,
|
|
|
|
// since there is always one Ranade timer tick before a step event occurs. This means
|
|
|
|
// that the Bresenham counter math never is performed at the same time as the loading
|
|
|
|
// of a block, hence helping minimize total time spent in this interrupt.
|
|
|
|
|
|
|
|
// Initialize direction bits for block
|
2012-12-17 00:23:24 +01:00
|
|
|
out_bits = current_block->direction_bits ^ settings.invert_mask;
|
|
|
|
st.execute_step = true; // Set flag to set direction bits.
|
|
|
|
|
2012-12-08 23:00:58 +01:00
|
|
|
// Initialize Bresenham variables
|
|
|
|
st.counter_x = (current_block->step_event_count >> 1);
|
2011-12-09 02:47:48 +01:00
|
|
|
st.counter_y = st.counter_x;
|
|
|
|
st.counter_z = st.counter_x;
|
|
|
|
st.event_count = current_block->step_event_count;
|
2012-12-08 23:00:58 +01:00
|
|
|
st.step_events_remaining = st.event_count;
|
|
|
|
|
|
|
|
// During feed hold, do not update Ranade counter, rate, or ramp type. Keep decelerating.
|
|
|
|
if (sys.state == STATE_CYCLE) {
|
|
|
|
// Initialize Ranade variables
|
|
|
|
st.d_counter = current_block->d_next;
|
|
|
|
st.delta_d = current_block->initial_rate;
|
2013-01-06 20:04:02 +01:00
|
|
|
st.ramp_count = ISR_TICKS_PER_ACCELERATION_TICK/2;
|
2012-12-08 23:00:58 +01:00
|
|
|
|
|
|
|
// Initialize ramp type.
|
|
|
|
if (st.step_events_remaining == current_block->decelerate_after) { st.ramp_type = DECEL_RAMP; }
|
2012-12-12 01:42:29 +01:00
|
|
|
else if (st.delta_d == current_block->nominal_rate) { st.ramp_type = CRUISE_RAMP; }
|
2012-12-08 23:00:58 +01:00
|
|
|
else { st.ramp_type = ACCEL_RAMP; }
|
|
|
|
}
|
|
|
|
|
2010-03-03 00:26:48 +01:00
|
|
|
} else {
|
2011-05-31 13:08:42 +02:00
|
|
|
st_go_idle();
|
2012-01-06 18:10:41 +01:00
|
|
|
bit_true(sys.execute,EXEC_CYCLE_STOP); // Flag main program for cycle end
|
2012-12-08 23:00:58 +01:00
|
|
|
busy = false;
|
|
|
|
return; // Nothing to do but exit.
|
|
|
|
}
|
2010-03-03 00:26:48 +01:00
|
|
|
}
|
2012-12-08 23:00:58 +01:00
|
|
|
|
|
|
|
// Adjust inverse time counter for ac/de-celerations
|
|
|
|
if (st.ramp_type) {
|
|
|
|
// Tick acceleration ramp counter
|
|
|
|
st.ramp_count--;
|
|
|
|
if (st.ramp_count == 0) {
|
2013-01-06 20:04:02 +01:00
|
|
|
st.ramp_count = ISR_TICKS_PER_ACCELERATION_TICK; // Reload ramp counter
|
2012-12-08 23:00:58 +01:00
|
|
|
if (st.ramp_type == ACCEL_RAMP) { // Adjust velocity for acceleration
|
|
|
|
st.delta_d += current_block->rate_delta;
|
|
|
|
if (st.delta_d >= current_block->nominal_rate) { // Reached cruise state.
|
|
|
|
st.ramp_type = CRUISE_RAMP;
|
|
|
|
st.delta_d = current_block->nominal_rate; // Set cruise velocity
|
|
|
|
}
|
|
|
|
} else if (st.ramp_type == DECEL_RAMP) { // Adjust velocity for deceleration
|
|
|
|
if (st.delta_d > current_block->rate_delta) {
|
|
|
|
st.delta_d -= current_block->rate_delta;
|
|
|
|
} else {
|
2012-12-17 00:23:24 +01:00
|
|
|
st.delta_d >>= 1; // Integer divide by 2 until complete. Also prevents overflow.
|
2012-12-08 23:00:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate Pramod Ranade inverse time counter. Triggers each Bresenham step event.
|
|
|
|
if (st.delta_d < MINIMUM_STEP_RATE) { st.d_counter -= MINIMUM_STEP_RATE; }
|
|
|
|
else { st.d_counter -= st.delta_d; }
|
|
|
|
|
|
|
|
// Execute Bresenham step event, when it's time to do so.
|
|
|
|
if (st.d_counter < 0) {
|
|
|
|
st.d_counter += current_block->d_next;
|
|
|
|
|
|
|
|
// Check for feed hold state and execute accordingly.
|
|
|
|
if (sys.state == STATE_HOLD) {
|
|
|
|
if (st.ramp_type != DECEL_RAMP) {
|
|
|
|
st.ramp_type = DECEL_RAMP;
|
2013-01-06 20:04:02 +01:00
|
|
|
st.ramp_count = ISR_TICKS_PER_ACCELERATION_TICK/2;
|
2012-12-08 23:00:58 +01:00
|
|
|
}
|
|
|
|
if (st.delta_d <= current_block->rate_delta) {
|
|
|
|
st_go_idle();
|
|
|
|
bit_true(sys.execute,EXEC_CYCLE_STOP);
|
|
|
|
busy = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Vary Bresenham resolution for smoother motions or enable faster step rates (>20kHz).
|
|
|
|
|
|
|
|
out_bits = current_block->direction_bits; // Reset out_bits and reload direction bits
|
|
|
|
st.execute_step = true;
|
|
|
|
|
|
|
|
// Execute step displacement profile by Bresenham line algorithm
|
|
|
|
st.counter_x -= current_block->steps_x;
|
|
|
|
if (st.counter_x < 0) {
|
2010-03-02 21:46:51 +01:00
|
|
|
out_bits |= (1<<X_STEP_BIT);
|
2012-12-08 23:00:58 +01:00
|
|
|
st.counter_x += st.event_count;
|
2012-01-06 18:10:41 +01:00
|
|
|
if (out_bits & (1<<X_DIRECTION_BIT)) { sys.position[X_AXIS]--; }
|
|
|
|
else { sys.position[X_AXIS]++; }
|
2010-03-02 21:46:51 +01:00
|
|
|
}
|
2012-12-08 23:00:58 +01:00
|
|
|
st.counter_y -= current_block->steps_y;
|
|
|
|
if (st.counter_y < 0) {
|
2010-03-02 21:46:51 +01:00
|
|
|
out_bits |= (1<<Y_STEP_BIT);
|
2012-12-08 23:00:58 +01:00
|
|
|
st.counter_y += st.event_count;
|
2012-01-06 18:10:41 +01:00
|
|
|
if (out_bits & (1<<Y_DIRECTION_BIT)) { sys.position[Y_AXIS]--; }
|
|
|
|
else { sys.position[Y_AXIS]++; }
|
2010-03-02 21:46:51 +01:00
|
|
|
}
|
2012-12-08 23:00:58 +01:00
|
|
|
st.counter_z -= current_block->steps_z;
|
|
|
|
if (st.counter_z < 0) {
|
2010-03-02 21:46:51 +01:00
|
|
|
out_bits |= (1<<Z_STEP_BIT);
|
2012-12-08 23:00:58 +01:00
|
|
|
st.counter_z += st.event_count;
|
2012-01-06 18:10:41 +01:00
|
|
|
if (out_bits & (1<<Z_DIRECTION_BIT)) { sys.position[Z_AXIS]--; }
|
|
|
|
else { sys.position[Z_AXIS]++; }
|
2010-03-02 21:46:51 +01:00
|
|
|
}
|
2011-09-24 15:46:41 +02:00
|
|
|
|
2012-12-08 23:00:58 +01:00
|
|
|
// Check step events for trapezoid change or end of block.
|
|
|
|
st.step_events_remaining--; // Decrement step events count
|
|
|
|
if (st.step_events_remaining) {
|
|
|
|
if (st.ramp_type != DECEL_RAMP) {
|
|
|
|
// Acceleration and cruise handled by ramping. Just check for deceleration.
|
|
|
|
if (st.step_events_remaining <= current_block->decelerate_after) {
|
|
|
|
st.ramp_type = DECEL_RAMP;
|
2012-12-17 00:23:24 +01:00
|
|
|
if (st.step_events_remaining == current_block->decelerate_after) {
|
|
|
|
if (st.delta_d == current_block->nominal_rate) {
|
2013-01-06 20:04:02 +01:00
|
|
|
st.ramp_count = ISR_TICKS_PER_ACCELERATION_TICK/2; // Set ramp counter for trapezoid
|
2012-12-17 00:23:24 +01:00
|
|
|
} else {
|
2013-01-06 20:04:02 +01:00
|
|
|
st.ramp_count = ISR_TICKS_PER_ACCELERATION_TICK-st.ramp_count; // Set ramp counter for triangle
|
2012-12-17 00:23:24 +01:00
|
|
|
}
|
|
|
|
}
|
2011-09-24 15:46:41 +02:00
|
|
|
}
|
2012-12-08 23:00:58 +01:00
|
|
|
}
|
|
|
|
} else {
|
2011-09-24 15:46:41 +02:00
|
|
|
// If current block is finished, reset pointer
|
2011-01-03 00:36:33 +01:00
|
|
|
current_block = NULL;
|
2011-02-06 23:52:12 +01:00
|
|
|
plan_discard_current_block();
|
2009-02-08 20:40:24 +01:00
|
|
|
}
|
2012-12-08 23:00:58 +01:00
|
|
|
|
|
|
|
out_bits ^= settings.invert_mask; // Apply step port invert mask
|
2011-10-12 04:51:04 +02:00
|
|
|
}
|
2011-12-09 02:47:48 +01:00
|
|
|
busy = false;
|
2012-12-08 23:00:58 +01:00
|
|
|
// SPINDLE_ENABLE_PORT ^= 1<<SPINDLE_ENABLE_BIT;
|
2009-01-28 23:48:21 +01:00
|
|
|
}
|
|
|
|
|
2012-12-08 23:00:58 +01:00
|
|
|
// 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
|
|
|
|
// finish, if Timer2 is disabled after completing a move.
|
|
|
|
ISR(TIMER0_OVF_vect)
|
2009-01-28 23:48:21 +01:00
|
|
|
{
|
2010-03-07 20:29:18 +01:00
|
|
|
STEPPING_PORT = (STEPPING_PORT & ~STEP_MASK) | (settings.invert_mask & STEP_MASK);
|
2012-12-17 00:23:24 +01:00
|
|
|
TCCR0B = 0; // Disable timer until needed.
|
2009-01-28 23:48:21 +01:00
|
|
|
}
|
|
|
|
|
2012-06-27 05:48:42 +02:00
|
|
|
|
2011-12-09 02:47:48 +01:00
|
|
|
// Reset and clear stepper subsystem variables
|
|
|
|
void st_reset()
|
|
|
|
{
|
|
|
|
memset(&st, 0, sizeof(st));
|
|
|
|
current_block = NULL;
|
|
|
|
busy = false;
|
|
|
|
}
|
|
|
|
|
2009-01-28 23:48:21 +01:00
|
|
|
// Initialize and start the stepper motor subsystem
|
|
|
|
void st_init()
|
|
|
|
{
|
2011-12-09 02:47:48 +01:00
|
|
|
// Configure directions of interface pins
|
|
|
|
STEPPING_DDR |= STEPPING_MASK;
|
2010-03-07 20:29:18 +01:00
|
|
|
STEPPING_PORT = (STEPPING_PORT & ~STEPPING_MASK) | settings.invert_mask;
|
2011-05-31 13:08:42 +02:00
|
|
|
STEPPERS_DISABLE_DDR |= 1<<STEPPERS_DISABLE_BIT;
|
2009-01-28 23:48:21 +01:00
|
|
|
|
2011-12-09 02:47:48 +01:00
|
|
|
// Configure Timer 2
|
2012-12-08 23:00:58 +01:00
|
|
|
TIMSK2 &= ~(1<<OCIE2A); // Disable Timer2 interrupt while configuring it
|
|
|
|
TCCR2B = 0; // Disable Timer2 until needed
|
|
|
|
TCNT2 = 0; // Clear Timer2 counter
|
|
|
|
TCCR2A = (1<<WGM21); // Set CTC mode
|
|
|
|
OCR2A = (F_CPU/ISR_TICKS_PER_SECOND)/8 - 1; // Set Timer2 CTC rate
|
|
|
|
|
|
|
|
// Configure Timer 0
|
|
|
|
TIMSK0 &= ~(1<<TOIE0);
|
|
|
|
TCCR0A = 0; // Normal operation
|
|
|
|
TCCR0B = 0; // Disable Timer0 until needed
|
|
|
|
TIMSK0 |= (1<<TOIE0); // Enable overflow interrupt
|
|
|
|
|
2012-11-01 16:37:27 +01:00
|
|
|
// Start in the idle state, but first wake up to check for keep steppers enabled option.
|
|
|
|
st_wake_up();
|
2011-05-31 13:08:42 +02:00
|
|
|
st_go_idle();
|
2009-01-28 23:48:21 +01:00
|
|
|
}
|
|
|
|
|
2010-06-28 23:29:58 +02:00
|
|
|
|
2011-12-09 02:47:48 +01:00
|
|
|
// Planner external interface to start stepper interrupt and execute the blocks in queue. Called
|
2012-01-06 18:10:41 +01:00
|
|
|
// by the main program functions: planner auto-start and run-time command execution.
|
2011-12-09 02:47:48 +01:00
|
|
|
void st_cycle_start()
|
2009-01-28 23:48:21 +01:00
|
|
|
{
|
New startup script setting. New dry run, check gcode switches. New system state variable. Lots of reorganizing.
(All v0.8 features installed. Still likely buggy, but now thourough
testing will need to start to squash them all. As soon as we're done,
this will be pushed to master and v0.9 development will be started.
Please report ANY issues to us so we can get this rolled out ASAP.)
- User startup script! A user can now save one (up to 5 as compile-time
option) block of g-code in EEPROM memory. This will be run everytime
Grbl resets. Mainly to be used as a way to set your preferences, like
G21, G54, etc.
- New dry run and check g-code switches. Dry run moves ALL motions at
rapids rate ignoring spindle, coolant, and dwell commands. For rapid
physical proofing of your code. The check g-code switch ignores all
motion and provides the user a way to check if there are any errors in
their program that Grbl may not like.
- Program restart! (sort of). Program restart is typically an advanced
feature that allows users to restart a program mid-stream. The check
g-code switch can perform this feature by enabling the switch at the
start of the program, and disabling it at the desired point with some
minimal changes.
- New system state variable. This state variable tracks all of the
different state processes that Grbl performs, i.e. cycle start, feed
hold, homing, etc. This is mainly for making managing of these task
easier and more clear.
- Position lost state variable. Only when homing is enabled, Grbl will
refuse to move until homing is completed and position is known. This is
mainly for safety. Otherwise, it will let users fend for themselves.
- Moved the default settings defines into config.h. The plan is to
eventually create a set of config.h's for particular as-built machines
to help users from doing it themselves.
- Moved around misc defines into .h files. And lots of other little
things.
2012-11-03 18:32:23 +01:00
|
|
|
if (sys.state == STATE_QUEUED) {
|
|
|
|
sys.state = STATE_CYCLE;
|
|
|
|
st_wake_up();
|
2011-12-09 02:47:48 +01:00
|
|
|
}
|
2009-01-28 23:48:21 +01:00
|
|
|
}
|
2011-10-12 04:51:04 +02:00
|
|
|
|
2011-12-09 02:47:48 +01:00
|
|
|
// Execute a feed hold with deceleration, only during cycle. Called by main program.
|
|
|
|
void st_feed_hold()
|
|
|
|
{
|
New startup script setting. New dry run, check gcode switches. New system state variable. Lots of reorganizing.
(All v0.8 features installed. Still likely buggy, but now thourough
testing will need to start to squash them all. As soon as we're done,
this will be pushed to master and v0.9 development will be started.
Please report ANY issues to us so we can get this rolled out ASAP.)
- User startup script! A user can now save one (up to 5 as compile-time
option) block of g-code in EEPROM memory. This will be run everytime
Grbl resets. Mainly to be used as a way to set your preferences, like
G21, G54, etc.
- New dry run and check g-code switches. Dry run moves ALL motions at
rapids rate ignoring spindle, coolant, and dwell commands. For rapid
physical proofing of your code. The check g-code switch ignores all
motion and provides the user a way to check if there are any errors in
their program that Grbl may not like.
- Program restart! (sort of). Program restart is typically an advanced
feature that allows users to restart a program mid-stream. The check
g-code switch can perform this feature by enabling the switch at the
start of the program, and disabling it at the desired point with some
minimal changes.
- New system state variable. This state variable tracks all of the
different state processes that Grbl performs, i.e. cycle start, feed
hold, homing, etc. This is mainly for making managing of these task
easier and more clear.
- Position lost state variable. Only when homing is enabled, Grbl will
refuse to move until homing is completed and position is known. This is
mainly for safety. Otherwise, it will let users fend for themselves.
- Moved the default settings defines into config.h. The plan is to
eventually create a set of config.h's for particular as-built machines
to help users from doing it themselves.
- Moved around misc defines into .h files. And lots of other little
things.
2012-11-03 18:32:23 +01:00
|
|
|
if (sys.state == STATE_CYCLE) {
|
|
|
|
sys.state = STATE_HOLD;
|
|
|
|
sys.auto_start = false; // Disable planner auto start upon feed hold.
|
2011-10-12 04:51:04 +02:00
|
|
|
}
|
|
|
|
}
|
2011-12-09 02:47:48 +01:00
|
|
|
|
|
|
|
// Reinitializes the cycle plan and stepper system after a feed hold for a resume. Called by
|
|
|
|
// runtime command execution in the main program, ensuring that the planner re-plans safely.
|
|
|
|
// NOTE: Bresenham algorithm variables are still maintained through both the planner and stepper
|
|
|
|
// cycle reinitializations. The stepper path should continue exactly as if nothing has happened.
|
|
|
|
// Only the planner de/ac-celerations profiles and stepper rates have been updated.
|
|
|
|
void st_cycle_reinitialize()
|
|
|
|
{
|
2012-01-06 18:10:41 +01:00
|
|
|
if (current_block != NULL) {
|
|
|
|
// Replan buffer from the feed hold stop location.
|
2012-12-08 23:00:58 +01:00
|
|
|
plan_cycle_reinitialize(st.step_events_remaining);
|
|
|
|
st.ramp_type = ACCEL_RAMP;
|
2013-01-06 20:04:02 +01:00
|
|
|
st.ramp_count = ISR_TICKS_PER_ACCELERATION_TICK/2;
|
2012-12-08 23:00:58 +01:00
|
|
|
st.delta_d = 0;
|
New startup script setting. New dry run, check gcode switches. New system state variable. Lots of reorganizing.
(All v0.8 features installed. Still likely buggy, but now thourough
testing will need to start to squash them all. As soon as we're done,
this will be pushed to master and v0.9 development will be started.
Please report ANY issues to us so we can get this rolled out ASAP.)
- User startup script! A user can now save one (up to 5 as compile-time
option) block of g-code in EEPROM memory. This will be run everytime
Grbl resets. Mainly to be used as a way to set your preferences, like
G21, G54, etc.
- New dry run and check g-code switches. Dry run moves ALL motions at
rapids rate ignoring spindle, coolant, and dwell commands. For rapid
physical proofing of your code. The check g-code switch ignores all
motion and provides the user a way to check if there are any errors in
their program that Grbl may not like.
- Program restart! (sort of). Program restart is typically an advanced
feature that allows users to restart a program mid-stream. The check
g-code switch can perform this feature by enabling the switch at the
start of the program, and disabling it at the desired point with some
minimal changes.
- New system state variable. This state variable tracks all of the
different state processes that Grbl performs, i.e. cycle start, feed
hold, homing, etc. This is mainly for making managing of these task
easier and more clear.
- Position lost state variable. Only when homing is enabled, Grbl will
refuse to move until homing is completed and position is known. This is
mainly for safety. Otherwise, it will let users fend for themselves.
- Moved the default settings defines into config.h. The plan is to
eventually create a set of config.h's for particular as-built machines
to help users from doing it themselves.
- Moved around misc defines into .h files. And lots of other little
things.
2012-11-03 18:32:23 +01:00
|
|
|
sys.state = STATE_QUEUED;
|
|
|
|
} else {
|
|
|
|
sys.state = STATE_IDLE;
|
2012-01-06 18:10:41 +01:00
|
|
|
}
|
2011-12-09 02:47:48 +01:00
|
|
|
}
|
2013-02-20 14:56:47 +01:00
|
|
|
|
|
|
|
uint8_t st_is_decelerating() {
|
|
|
|
return st.ramp_type == DECEL_RAMP;
|
|
|
|
}
|
|
|
|
|