2011-11-13 14:42:08 -05:00
/*
stepper . c - stepper motor driver : executes motion plans using stepper motors
Part of Grbl
Copyright ( c ) 2009 - 2011 Simen Svale Skogsrud
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/>.
*/
/* The timer calculations of this module informed by the 'RepRap cartesian firmware' by Zack Smith
and Philipp Tiefenbacher . */
# include "Marlin.h"
2011-12-22 08:55:45 -05:00
# include "stepper.h"
2011-11-13 14:42:08 -05:00
# include "planner.h"
# include "temperature.h"
# include "ultralcd.h"
2012-03-03 10:51:47 -05:00
# include "language.h"
2013-01-08 05:53:18 -05:00
# include "cardreader.h"
2011-11-13 14:42:08 -05:00
# include "speed_lookuptable.h"
2015-03-14 07:28:22 -04:00
# if HAS_DIGIPOTSS
# include <SPI.h>
2012-11-21 14:53:56 -05:00
# endif
2011-11-13 14:42:08 -05:00
//===========================================================================
2015-03-14 07:28:22 -04:00
//============================= public variables ============================
2011-11-13 14:42:08 -05:00
//===========================================================================
block_t * current_block ; // A pointer to the block currently being traced
//===========================================================================
2015-03-14 07:28:22 -04:00
//============================= private variables ===========================
2011-11-13 14:42:08 -05:00
//===========================================================================
2015-02-17 14:37:05 -05:00
//static makes it impossible to be called from outside of this file by extern.!
2011-11-13 14:42:08 -05:00
// Variables used by The Stepper Driver Interrupt
static unsigned char out_bits ; // The next stepping-bits to be output
2015-04-24 02:03:17 -04:00
static unsigned int cleaning_buffer_counter ;
2015-03-14 07:28:22 -04:00
2015-03-24 13:06:44 -04:00
# ifdef Z_DUAL_ENDSTOPS
static bool performing_homing = false ,
locked_z_motor = false ,
locked_z2_motor = false ;
# endif
2015-04-17 04:28:08 -04:00
// Counter variables for the Bresenham line tracer
2015-03-14 07:28:22 -04:00
static long counter_x , counter_y , counter_z , counter_e ;
2011-11-27 15:12:55 -05:00
volatile static unsigned long step_events_completed ; // The number of step events executed in the current block
2015-03-14 07:28:22 -04:00
2011-11-13 14:42:08 -05:00
# ifdef ADVANCE
static long advance_rate , advance , final_advance = 0 ;
2011-12-04 13:54:07 -05:00
static long old_advance = 0 ;
2015-01-23 17:13:06 -05:00
static long e_steps [ 4 ] ;
2011-11-13 14:42:08 -05:00
# endif
2015-03-14 07:28:22 -04:00
2011-11-13 14:42:08 -05:00
static long acceleration_time , deceleration_time ;
//static unsigned long accelerate_until, decelerate_after, acceleration_rate, initial_rate, final_rate, nominal_rate;
2015-04-17 04:28:08 -04:00
static unsigned short acc_step_rate ; // needed for deceleration start point
2011-11-13 14:42:08 -05:00
static char step_loops ;
2011-11-27 15:12:55 -05:00
static unsigned short OCR1A_nominal ;
2013-03-15 04:03:53 -04:00
static unsigned short step_loops_nominal ;
2011-11-13 14:42:08 -05:00
2015-03-14 07:28:22 -04:00
volatile long endstops_trigsteps [ 3 ] = { 0 } ;
volatile long endstops_stepsTotal , endstops_stepsDone ;
static volatile bool endstop_x_hit = false ;
static volatile bool endstop_y_hit = false ;
static volatile bool endstop_z_hit = false ;
2015-04-01 03:14:55 -04:00
static volatile bool endstop_z_probe_hit = false ; // Leaving this in even if Z_PROBE_ENDSTOP isn't defined, keeps code below cleaner. #ifdef it and usage below to save space.
2015-03-14 07:28:22 -04:00
2013-05-02 12:22:58 -04:00
# ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED
2015-03-14 07:28:22 -04:00
bool abort_on_endstop_hit = false ;
2013-05-02 12:22:58 -04:00
# endif
2015-03-14 07:28:22 -04:00
2014-01-06 05:05:02 -05:00
# ifdef MOTOR_CURRENT_PWM_XY_PIN
int motor_current_setting [ 3 ] = DEFAULT_PWM_MOTOR_CURRENT ;
# endif
2011-11-13 14:42:08 -05:00
2015-04-03 18:31:35 -04:00
# if HAS_X_MIN
2015-03-27 03:32:58 -04:00
static bool old_x_min_endstop = false ;
# endif
2015-04-03 18:31:35 -04:00
# if HAS_X_MAX
2015-03-27 03:32:58 -04:00
static bool old_x_max_endstop = false ;
# endif
2015-04-03 18:31:35 -04:00
# if HAS_Y_MIN
2015-03-27 03:32:58 -04:00
static bool old_y_min_endstop = false ;
# endif
2015-04-03 18:31:35 -04:00
# if HAS_Y_MAX
2015-03-27 03:32:58 -04:00
static bool old_y_max_endstop = false ;
# endif
2015-04-14 07:05:51 -04:00
2015-04-14 07:55:20 -04:00
static bool old_z_min_endstop = false ;
static bool old_z_max_endstop = false ;
2015-04-14 07:05:51 -04:00
# ifdef Z_DUAL_ENDSTOPS
static bool old_z2_min_endstop = false ;
static bool old_z2_max_endstop = false ;
2015-03-27 03:32:58 -04:00
# endif
2011-11-25 07:43:06 -05:00
2015-04-01 03:14:55 -04:00
# ifdef Z_PROBE_ENDSTOP // No need to check for valid pin, SanityCheck.h already does this.
2015-04-05 06:44:47 -04:00
static bool old_z_probe_endstop = false ;
2015-03-28 06:09:48 -04:00
# endif
2011-11-25 07:43:06 -05:00
2011-12-04 14:17:21 -05:00
static bool check_endstops = true ;
2015-03-14 07:28:22 -04:00
volatile long count_position [ NUM_AXIS ] = { 0 } ;
2015-03-20 08:45:05 -04:00
volatile signed char count_direction [ NUM_AXIS ] = { 1 , 1 , 1 , 1 } ;
2011-11-13 14:42:08 -05:00
2015-02-26 06:57:46 -05:00
2011-11-13 14:42:08 -05:00
//===========================================================================
2015-03-14 07:28:22 -04:00
//================================ functions ================================
2011-11-13 14:42:08 -05:00
//===========================================================================
2011-12-04 15:03:02 -05:00
2015-03-14 07:28:22 -04:00
# ifdef DUAL_X_CARRIAGE
# define X_APPLY_DIR(v,ALWAYS) \
if ( extruder_duplication_enabled | | ALWAYS ) { \
X_DIR_WRITE ( v ) ; \
X2_DIR_WRITE ( v ) ; \
} \
2015-03-21 19:43:47 -04:00
else { \
if ( current_block - > active_extruder ) X2_DIR_WRITE ( v ) ; else X_DIR_WRITE ( v ) ; \
2015-03-14 07:28:22 -04:00
}
# define X_APPLY_STEP(v,ALWAYS) \
if ( extruder_duplication_enabled | | ALWAYS ) { \
X_STEP_WRITE ( v ) ; \
X2_STEP_WRITE ( v ) ; \
} \
else { \
2015-03-21 19:43:47 -04:00
if ( current_block - > active_extruder ! = 0 ) X2_STEP_WRITE ( v ) ; else X_STEP_WRITE ( v ) ; \
2015-03-14 07:28:22 -04:00
}
# else
2015-03-14 21:31:25 -04:00
# define X_APPLY_DIR(v,Q) X_DIR_WRITE(v)
# define X_APPLY_STEP(v,Q) X_STEP_WRITE(v)
2015-03-14 07:28:22 -04:00
# endif
# ifdef Y_DUAL_STEPPER_DRIVERS
2015-03-21 19:43:47 -04:00
# define Y_APPLY_DIR(v,Q) { Y_DIR_WRITE(v); Y2_DIR_WRITE((v) != INVERT_Y2_VS_Y_DIR); }
# define Y_APPLY_STEP(v,Q) { Y_STEP_WRITE(v); Y2_STEP_WRITE(v); }
2015-03-14 07:28:22 -04:00
# else
2015-03-14 21:31:25 -04:00
# define Y_APPLY_DIR(v,Q) Y_DIR_WRITE(v)
# define Y_APPLY_STEP(v,Q) Y_STEP_WRITE(v)
2015-03-14 07:28:22 -04:00
# endif
# ifdef Z_DUAL_STEPPER_DRIVERS
2015-03-21 19:43:47 -04:00
# define Z_APPLY_DIR(v,Q) { Z_DIR_WRITE(v); Z2_DIR_WRITE(v); }
2015-03-24 13:06:44 -04:00
# ifdef Z_DUAL_ENDSTOPS
# define Z_APPLY_STEP(v,Q) \
if ( performing_homing ) { \
if ( Z_HOME_DIR > 0 ) { \
if ( ! ( old_z_max_endstop & & ( count_direction [ Z_AXIS ] > 0 ) ) & & ! locked_z_motor ) Z_STEP_WRITE ( v ) ; \
if ( ! ( old_z2_max_endstop & & ( count_direction [ Z_AXIS ] > 0 ) ) & & ! locked_z2_motor ) Z2_STEP_WRITE ( v ) ; \
} else { \
if ( ! ( old_z_min_endstop & & ( count_direction [ Z_AXIS ] < 0 ) ) & & ! locked_z_motor ) Z_STEP_WRITE ( v ) ; \
if ( ! ( old_z2_min_endstop & & ( count_direction [ Z_AXIS ] < 0 ) ) & & ! locked_z2_motor ) Z2_STEP_WRITE ( v ) ; \
} \
} else { \
Z_STEP_WRITE ( v ) ; \
Z2_STEP_WRITE ( v ) ; \
}
# else
2015-03-27 20:02:11 -04:00
# define Z_APPLY_STEP(v,Q) { Z_STEP_WRITE(v); Z2_STEP_WRITE(v); }
2015-03-24 13:06:44 -04:00
# endif
2015-03-14 07:28:22 -04:00
# else
2015-03-14 21:31:25 -04:00
# define Z_APPLY_DIR(v,Q) Z_DIR_WRITE(v)
# define Z_APPLY_STEP(v,Q) Z_STEP_WRITE(v)
2015-03-14 07:28:22 -04:00
# endif
2015-03-14 21:31:25 -04:00
# define E_APPLY_STEP(v,Q) E_STEP_WRITE(v)
2011-11-13 14:42:08 -05:00
// intRes = intIn1 * intIn2 >> 16
// uses:
// r26 to store 0
// r27 to store the byte 1 of the 24 bit result
# define MultiU16X8toH16(intRes, charIn1, intIn2) \
2015-03-14 07:28:22 -04:00
asm volatile ( \
" clr r26 \n \t " \
" mul %A1, %B2 \n \t " \
" movw %A0, r0 \n \t " \
" mul %A1, %A2 \n \t " \
" add %A0, r1 \n \t " \
" adc %B0, r26 \n \t " \
" lsr r0 \n \t " \
" adc %A0, r26 \n \t " \
" adc %B0, r26 \n \t " \
" clr r1 \n \t " \
: \
" =&r " ( intRes ) \
: \
" d " ( charIn1 ) , \
" d " ( intIn2 ) \
: \
" r26 " \
)
2011-11-13 14:42:08 -05:00
2015-04-16 18:04:38 -04:00
// intRes = longIn1 * longIn2 >> 24
// uses:
// r26 to store 0
// r27 to store bits 16-23 of the 48bit result. The top bit is used to round the two byte result.
// note that the lower two bytes and the upper byte of the 48bit result are not calculated.
// this can cause the result to be out by one as the lower bytes may cause carries into the upper ones.
// B0 A0 are bits 24-39 and are the returned value
// C1 B1 A1 is longIn1
// D2 C2 B2 A2 is longIn2
//
# define MultiU24X32toH16(intRes, longIn1, longIn2) \
2015-03-14 07:28:22 -04:00
asm volatile ( \
" clr r26 \n \t " \
" mul %A1, %B2 \n \t " \
" mov r27, r1 \n \t " \
" mul %B1, %C2 \n \t " \
" movw %A0, r0 \n \t " \
" mul %C1, %C2 \n \t " \
" add %B0, r0 \n \t " \
" mul %C1, %B2 \n \t " \
" add %A0, r0 \n \t " \
" adc %B0, r1 \n \t " \
" mul %A1, %C2 \n \t " \
" add r27, r0 \n \t " \
" adc %A0, r1 \n \t " \
" adc %B0, r26 \n \t " \
" mul %B1, %B2 \n \t " \
" add r27, r0 \n \t " \
" adc %A0, r1 \n \t " \
" adc %B0, r26 \n \t " \
" mul %C1, %A2 \n \t " \
" add r27, r0 \n \t " \
" adc %A0, r1 \n \t " \
" adc %B0, r26 \n \t " \
" mul %B1, %A2 \n \t " \
" add r27, r1 \n \t " \
" adc %A0, r26 \n \t " \
" adc %B0, r26 \n \t " \
" lsr r27 \n \t " \
" adc %A0, r26 \n \t " \
" adc %B0, r26 \n \t " \
2015-04-16 18:04:38 -04:00
" mul %D2, %A1 \n \t " \
" add %A0, r0 \n \t " \
" adc %B0, r1 \n \t " \
" mul %D2, %B1 \n \t " \
" add %B0, r0 \n \t " \
2015-03-14 07:28:22 -04:00
" clr r1 \n \t " \
: \
" =&r " ( intRes ) \
: \
" d " ( longIn1 ) , \
" d " ( longIn2 ) \
: \
" r26 " , " r27 " \
)
2011-11-13 14:42:08 -05:00
// Some useful constants
2015-03-14 07:28:22 -04:00
# define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= BIT(OCIE1A)
# define DISABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 &= ~BIT(OCIE1A)
2011-11-13 14:42:08 -05:00
2015-03-14 07:28:22 -04:00
void endstops_hit_on_purpose ( ) {
2015-04-01 03:14:55 -04:00
endstop_x_hit = endstop_y_hit = endstop_z_hit = endstop_z_probe_hit = false ; // #ifdef endstop_z_probe_hit = to save space if needed.
2011-11-13 14:46:44 -05:00
}
2011-11-13 14:42:08 -05:00
2015-03-14 07:28:22 -04:00
void checkHitEndstops ( ) {
2015-04-01 03:14:55 -04:00
if ( endstop_x_hit | | endstop_y_hit | | endstop_z_hit | | endstop_z_probe_hit ) { // #ifdef || endstop_z_probe_hit to save space if needed.
2015-03-14 07:28:22 -04:00
SERIAL_ECHO_START ;
SERIAL_ECHOPGM ( MSG_ENDSTOPS_HIT ) ;
if ( endstop_x_hit ) {
SERIAL_ECHOPAIR ( " X: " , ( float ) endstops_trigsteps [ X_AXIS ] / axis_steps_per_unit [ X_AXIS ] ) ;
LCD_MESSAGEPGM ( MSG_ENDSTOPS_HIT " X " ) ;
}
if ( endstop_y_hit ) {
SERIAL_ECHOPAIR ( " Y: " , ( float ) endstops_trigsteps [ Y_AXIS ] / axis_steps_per_unit [ Y_AXIS ] ) ;
LCD_MESSAGEPGM ( MSG_ENDSTOPS_HIT " Y " ) ;
}
if ( endstop_z_hit ) {
SERIAL_ECHOPAIR ( " Z: " , ( float ) endstops_trigsteps [ Z_AXIS ] / axis_steps_per_unit [ Z_AXIS ] ) ;
LCD_MESSAGEPGM ( MSG_ENDSTOPS_HIT " Z " ) ;
}
2015-04-01 03:14:55 -04:00
# ifdef Z_PROBE_ENDSTOP
2015-03-31 03:56:41 -04:00
if ( endstop_z_probe_hit ) {
2015-04-24 02:03:17 -04:00
SERIAL_ECHOPAIR ( " Z_PROBE: " , ( float ) endstops_trigsteps [ Z_AXIS ] / axis_steps_per_unit [ Z_AXIS ] ) ;
LCD_MESSAGEPGM ( MSG_ENDSTOPS_HIT " ZP " ) ;
2015-03-31 03:56:41 -04:00
}
2015-04-01 03:14:55 -04:00
# endif
2015-03-14 07:28:22 -04:00
SERIAL_EOL ;
endstops_hit_on_purpose ( ) ;
# if defined(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) && defined(SDSUPPORT)
if ( abort_on_endstop_hit ) {
card . sdprinting = false ;
card . closefile ( ) ;
quickStop ( ) ;
setTargetHotend0 ( 0 ) ;
setTargetHotend1 ( 0 ) ;
setTargetHotend2 ( 0 ) ;
setTargetHotend3 ( 0 ) ;
setTargetBed ( 0 ) ;
}
# endif
}
2011-12-04 14:17:21 -05:00
}
2015-03-14 07:28:22 -04:00
void enable_endstops ( bool check ) { check_endstops = check ; }
2011-11-13 14:42:08 -05:00
// __________________________
// /| |\ _________________ ^
// / | | \ /| |\ |
// / | | \ / | | \ s
// / | | | | | \ p
// / | | | | | \ e
// +-----+------------------------+---+--+---------------+----+ e
// | BLOCK 1 | BLOCK 2 | d
//
// time ----->
2013-08-01 09:06:39 -04:00
//
// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates
// first block->accelerate_until step_events_completed, then keeps going at constant speed until
2011-11-13 14:42:08 -05:00
// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset.
2015-04-16 18:04:38 -04:00
// The slope of acceleration is calculated using v = u + at where t is the accumulated timer values of the steps so far.
2011-11-13 14:42:08 -05:00
void st_wake_up ( ) {
// TCNT1 = 0;
2013-08-01 09:06:39 -04:00
ENABLE_STEPPER_DRIVER_INTERRUPT ( ) ;
2011-11-13 14:42:08 -05:00
}
2011-11-27 10:45:00 -05:00
FORCE_INLINE unsigned short calc_timer ( unsigned short step_rate ) {
2011-11-13 14:42:08 -05:00
unsigned short timer ;
2015-03-14 07:28:22 -04:00
if ( step_rate > MAX_STEP_FREQUENCY ) step_rate = MAX_STEP_FREQUENCY ;
2013-08-01 09:06:39 -04:00
2015-03-14 07:28:22 -04:00
if ( step_rate > 20000 ) { // If steprate > 20kHz >> step 4 times
step_rate = ( step_rate > > 2 ) & 0x3fff ;
2011-11-13 14:42:08 -05:00
step_loops = 4 ;
}
2015-03-14 07:28:22 -04:00
else if ( step_rate > 10000 ) { // If steprate > 10kHz >> step 2 times
step_rate = ( step_rate > > 1 ) & 0x7fff ;
2011-11-13 14:42:08 -05:00
step_loops = 2 ;
}
else {
step_loops = 1 ;
2013-08-01 09:06:39 -04:00
}
2015-03-14 07:28:22 -04:00
if ( step_rate < ( F_CPU / 500000 ) ) step_rate = ( F_CPU / 500000 ) ;
step_rate - = ( F_CPU / 500000 ) ; // Correct for minimal speed
if ( step_rate > = ( 8 * 256 ) ) { // higher step rate
2011-11-13 14:42:08 -05:00
unsigned short table_address = ( unsigned short ) & speed_lookuptable_fast [ ( unsigned char ) ( step_rate > > 8 ) ] [ 0 ] ;
unsigned char tmp_step_rate = ( step_rate & 0x00ff ) ;
unsigned short gain = ( unsigned short ) pgm_read_word_near ( table_address + 2 ) ;
MultiU16X8toH16 ( timer , tmp_step_rate , gain ) ;
timer = ( unsigned short ) pgm_read_word_near ( table_address ) - timer ;
}
else { // lower step rates
unsigned short table_address = ( unsigned short ) & speed_lookuptable_slow [ 0 ] [ 0 ] ;
table_address + = ( ( step_rate ) > > 1 ) & 0xfffc ;
timer = ( unsigned short ) pgm_read_word_near ( table_address ) ;
timer - = ( ( ( unsigned short ) pgm_read_word_near ( table_address + 2 ) * ( unsigned char ) ( step_rate & 0x0007 ) ) > > 3 ) ;
}
2015-03-14 07:28:22 -04:00
if ( timer < 100 ) { timer = 100 ; MYSERIAL . print ( MSG_STEPPER_TOO_HIGH ) ; MYSERIAL . println ( step_rate ) ; } //(20kHz this should never happen)
2011-11-13 14:42:08 -05:00
return timer ;
}
2013-08-01 09:06:39 -04:00
// Initializes the trapezoid generator from the current block. Called whenever a new
2011-11-13 14:42:08 -05:00
// block begins.
2011-11-27 10:45:00 -05:00
FORCE_INLINE void trapezoid_generator_reset ( ) {
2011-11-13 14:42:08 -05:00
# ifdef ADVANCE
advance = current_block - > initial_advance ;
final_advance = current_block - > final_advance ;
2011-12-04 13:54:07 -05:00
// Do E steps + advance steps
2011-12-12 13:34:37 -05:00
e_steps [ current_block - > active_extruder ] + = ( ( advance > > 8 ) - old_advance ) ;
2013-08-01 09:06:39 -04:00
old_advance = advance > > 8 ;
2011-11-13 14:42:08 -05:00
# endif
deceleration_time = 0 ;
// step_rate to timer interval
2012-06-11 11:33:42 -04:00
OCR1A_nominal = calc_timer ( current_block - > nominal_rate ) ;
2013-03-15 04:03:53 -04:00
// make a note of the number of step loops required at nominal speed
step_loops_nominal = step_loops ;
2011-11-13 14:42:08 -05:00
acc_step_rate = current_block - > initial_rate ;
acceleration_time = calc_timer ( acc_step_rate ) ;
OCR1A = acceleration_time ;
2013-08-01 09:06:39 -04:00
2015-03-14 07:28:22 -04:00
// SERIAL_ECHO_START;
// SERIAL_ECHOPGM("advance :");
// SERIAL_ECHO(current_block->advance/256.0);
// SERIAL_ECHOPGM("advance rate :");
// SERIAL_ECHO(current_block->advance_rate/256.0);
// SERIAL_ECHOPGM("initial advance :");
// SERIAL_ECHO(current_block->initial_advance/256.0);
// SERIAL_ECHOPGM("final advance :");
// SERIAL_ECHOLN(current_block->final_advance/256.0);
2011-11-13 14:42:08 -05:00
}
2013-08-01 09:06:39 -04:00
// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse.
// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately.
2015-03-14 07:28:22 -04:00
ISR ( TIMER1_COMPA_vect ) {
2015-03-19 13:16:18 -04:00
if ( cleaning_buffer_counter )
{
current_block = NULL ;
plan_discard_current_block ( ) ;
2015-03-31 02:31:48 -04:00
# ifdef SD_FINISHED_RELEASECOMMAND
2015-04-12 21:07:08 -04:00
if ( ( cleaning_buffer_counter = = 1 ) & & ( SD_FINISHED_STEPPERRELEASE ) ) enqueuecommands_P ( PSTR ( SD_FINISHED_RELEASECOMMAND ) ) ;
2015-03-31 02:31:48 -04:00
# endif
2015-03-19 13:16:18 -04:00
cleaning_buffer_counter - - ;
OCR1A = 200 ;
return ;
}
2015-04-24 02:03:17 -04:00
2011-11-13 14:42:08 -05:00
// If there is no current block, attempt to pop one from the buffer
2015-03-14 07:28:22 -04:00
if ( ! current_block ) {
2011-11-13 14:42:08 -05:00
// Anything in the buffer?
current_block = plan_get_current_block ( ) ;
2015-03-14 07:28:22 -04:00
if ( current_block ) {
2012-04-15 13:17:33 -04:00
current_block - > busy = true ;
2011-11-13 14:42:08 -05:00
trapezoid_generator_reset ( ) ;
counter_x = - ( current_block - > step_event_count > > 1 ) ;
2015-03-14 07:28:22 -04:00
counter_y = counter_z = counter_e = counter_x ;
2013-08-01 09:06:39 -04:00
step_events_completed = 0 ;
# ifdef Z_LATE_ENABLE
2015-03-20 23:42:49 -04:00
if ( current_block - > steps [ Z_AXIS ] > 0 ) {
2012-02-06 11:38:16 -05:00
enable_z ( ) ;
OCR1A = 2000 ; //1ms wait
return ;
}
# endif
2013-08-01 09:06:39 -04:00
2015-03-14 07:28:22 -04:00
// #ifdef ADVANCE
// e_steps[current_block->active_extruder] = 0;
// #endif
2013-08-01 09:06:39 -04:00
}
2011-11-13 14:42:08 -05:00
else {
2015-03-14 07:28:22 -04:00
OCR1A = 2000 ; // 1kHz.
2013-08-01 09:06:39 -04:00
}
}
2011-11-13 14:42:08 -05:00
if ( current_block ! = NULL ) {
// Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt
out_bits = current_block - > direction_bits ;
2013-06-09 07:10:06 -04:00
// Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY)
2015-03-14 07:28:22 -04:00
if ( TEST ( out_bits , X_AXIS ) ) {
2015-03-14 21:31:25 -04:00
X_APPLY_DIR ( INVERT_X_DIR , 0 ) ;
2015-03-14 07:28:22 -04:00
count_direction [ X_AXIS ] = - 1 ;
2013-06-09 07:10:06 -04:00
}
2015-03-14 07:28:22 -04:00
else {
2015-03-14 21:31:25 -04:00
X_APPLY_DIR ( ! INVERT_X_DIR , 0 ) ;
2015-03-14 07:28:22 -04:00
count_direction [ X_AXIS ] = 1 ;
2013-06-09 07:10:06 -04:00
}
2015-03-14 07:28:22 -04:00
if ( TEST ( out_bits , Y_AXIS ) ) {
2015-03-14 21:31:25 -04:00
Y_APPLY_DIR ( INVERT_Y_DIR , 0 ) ;
2015-03-14 07:28:22 -04:00
count_direction [ Y_AXIS ] = - 1 ;
2013-06-09 07:10:06 -04:00
}
2015-03-14 07:28:22 -04:00
else {
2015-03-14 21:31:25 -04:00
Y_APPLY_DIR ( ! INVERT_Y_DIR , 0 ) ;
2015-03-14 07:28:22 -04:00
count_direction [ Y_AXIS ] = 1 ;
2013-06-09 07:10:06 -04:00
}
2013-08-01 09:06:39 -04:00
2015-04-24 02:03:17 -04:00
# define _ENDSTOP(axis, minmax) axis ##_## minmax ##_endstop
# define _ENDSTOP_PIN(AXIS, MINMAX) AXIS ##_## MINMAX ##_PIN
# define _ENDSTOP_INVERTING(AXIS, MINMAX) AXIS ##_## MINMAX ##_ENDSTOP_INVERTING
# define _OLD_ENDSTOP(axis, minmax) old_## axis ##_## minmax ##_endstop
# define _AXIS(AXIS) AXIS ##_AXIS
# define _ENDSTOP_HIT(axis) endstop_## axis ##_hit
2015-03-14 07:28:22 -04:00
# define UPDATE_ENDSTOP(axis,AXIS,minmax,MINMAX) \
2015-04-24 02:03:17 -04:00
bool _ENDSTOP ( axis , minmax ) = ( READ ( _ENDSTOP_PIN ( AXIS , MINMAX ) ) ! = _ENDSTOP_INVERTING ( AXIS , MINMAX ) ) ; \
if ( _ENDSTOP ( axis , minmax ) & & _OLD_ENDSTOP ( axis , minmax ) & & ( current_block - > steps [ _AXIS ( AXIS ) ] > 0 ) ) { \
endstops_trigsteps [ _AXIS ( AXIS ) ] = count_position [ _AXIS ( AXIS ) ] ; \
_ENDSTOP_HIT ( axis ) = true ; \
2015-03-14 07:28:22 -04:00
step_events_completed = current_block - > step_event_count ; \
} \
2015-04-24 02:03:17 -04:00
_OLD_ENDSTOP ( axis , minmax ) = _ENDSTOP ( axis , minmax ) ;
2015-03-14 07:28:22 -04:00
// Check X and Y endstops
if ( check_endstops ) {
2015-03-20 23:42:49 -04:00
# ifdef COREXY
2015-03-14 07:28:22 -04:00
// Head direction in -X axis for CoreXY bots.
// If DeltaX == -DeltaY, the movement is only in Y axis
2015-03-29 19:42:35 -04:00
if ( ( current_block - > steps [ A_AXIS ] ! = current_block - > steps [ B_AXIS ] ) | | ( TEST ( out_bits , A_AXIS ) = = TEST ( out_bits , B_AXIS ) ) ) {
2015-03-20 23:42:49 -04:00
if ( TEST ( out_bits , X_HEAD ) )
2015-03-16 15:31:25 -04:00
# else
2015-04-17 04:28:08 -04:00
if ( TEST ( out_bits , X_AXIS ) ) // stepping along -X axis (regular Cartesian bot)
2015-03-20 23:42:49 -04:00
# endif
{ // -direction
# ifdef DUAL_X_CARRIAGE
// with 2 x-carriages, endstops are only checked in the homing direction for the active extruder
if ( ( current_block - > active_extruder = = 0 & & X_HOME_DIR = = - 1 ) | | ( current_block - > active_extruder ! = 0 & & X2_HOME_DIR = = - 1 ) )
2015-04-24 02:03:17 -04:00
# endif
2015-03-20 23:42:49 -04:00
{
2015-04-03 18:31:35 -04:00
# if HAS_X_MIN
2015-03-20 23:42:49 -04:00
UPDATE_ENDSTOP ( x , X , min , MIN ) ;
# endif
}
}
else { // +direction
# ifdef DUAL_X_CARRIAGE
// with 2 x-carriages, endstops are only checked in the homing direction for the active extruder
if ( ( current_block - > active_extruder = = 0 & & X_HOME_DIR = = 1 ) | | ( current_block - > active_extruder ! = 0 & & X2_HOME_DIR = = 1 ) )
# endif
{
2015-04-03 18:31:35 -04:00
# if HAS_X_MAX
2015-03-20 23:42:49 -04:00
UPDATE_ENDSTOP ( x , X , max , MAX ) ;
# endif
}
}
# ifdef COREXY
2015-03-29 19:42:35 -04:00
}
2015-03-16 15:31:25 -04:00
// Head direction in -Y axis for CoreXY bots.
// If DeltaX == DeltaY, the movement is only in X axis
2015-03-29 19:42:35 -04:00
if ( ( current_block - > steps [ A_AXIS ] ! = current_block - > steps [ B_AXIS ] ) | | ( TEST ( out_bits , A_AXIS ) ! = TEST ( out_bits , B_AXIS ) ) ) {
2015-03-20 23:42:49 -04:00
if ( TEST ( out_bits , Y_HEAD ) )
# else
if ( TEST ( out_bits , Y_AXIS ) ) // -direction
2015-03-16 15:31:25 -04:00
# endif
2015-03-20 23:42:49 -04:00
{ // -direction
2015-04-03 18:31:35 -04:00
# if HAS_Y_MIN
2015-03-20 23:42:49 -04:00
UPDATE_ENDSTOP ( y , Y , min , MIN ) ;
# endif
}
else { // +direction
2015-04-03 18:31:35 -04:00
# if HAS_Y_MAX
2015-03-20 23:42:49 -04:00
UPDATE_ENDSTOP ( y , Y , max , MAX ) ;
# endif
}
2015-03-29 19:42:35 -04:00
# ifdef COREXY
}
# endif
2011-11-13 14:42:08 -05:00
}
2013-06-09 07:10:06 -04:00
2015-03-14 07:28:22 -04:00
if ( TEST ( out_bits , Z_AXIS ) ) { // -direction
2015-03-30 02:16:12 -04:00
2015-03-24 13:06:44 -04:00
Z_APPLY_DIR ( INVERT_Z_DIR , 0 ) ;
2015-03-14 07:28:22 -04:00
count_direction [ Z_AXIS ] = - 1 ;
2015-03-30 02:16:12 -04:00
if ( check_endstops ) {
2015-04-03 18:31:35 -04:00
# if HAS_Z_MIN
2015-03-30 02:16:12 -04:00
# ifdef Z_DUAL_ENDSTOPS
bool z_min_endstop = READ ( Z_MIN_PIN ) ! = Z_MIN_ENDSTOP_INVERTING ,
z2_min_endstop =
2015-04-03 18:31:35 -04:00
# if HAS_Z2_MIN
2015-03-30 02:16:12 -04:00
READ ( Z2_MIN_PIN ) ! = Z2_MIN_ENDSTOP_INVERTING
# else
z_min_endstop
# endif
;
bool z_min_both = z_min_endstop & & old_z_min_endstop ,
z2_min_both = z2_min_endstop & & old_z2_min_endstop ;
if ( ( z_min_both | | z2_min_both ) & & current_block - > steps [ Z_AXIS ] > 0 ) {
2015-03-24 13:06:44 -04:00
endstops_trigsteps [ Z_AXIS ] = count_position [ Z_AXIS ] ;
2015-03-30 02:16:12 -04:00
endstop_z_hit = true ;
if ( ! performing_homing | | ( performing_homing & & z_min_both & & z2_min_both ) ) //if not performing home or if both endstops were trigged during homing...
2015-03-24 13:06:44 -04:00
step_events_completed = current_block - > step_event_count ;
}
old_z_min_endstop = z_min_endstop ;
old_z2_min_endstop = z2_min_endstop ;
2015-03-30 02:16:12 -04:00
# else // !Z_DUAL_ENDSTOPS
UPDATE_ENDSTOP ( z , Z , min , MIN ) ;
# endif // !Z_DUAL_ENDSTOPS
# endif // Z_MIN_PIN
2015-04-01 03:14:55 -04:00
# ifdef Z_PROBE_ENDSTOP
2015-03-28 05:31:51 -04:00
UPDATE_ENDSTOP ( z , Z , probe , PROBE ) ;
2015-03-31 02:06:01 -04:00
z_probe_endstop = ( READ ( Z_PROBE_PIN ) ! = Z_PROBE_ENDSTOP_INVERTING ) ;
2015-03-28 05:31:51 -04:00
if ( z_probe_endstop & & old_z_probe_endstop )
{
2015-04-24 02:03:17 -04:00
endstops_trigsteps [ Z_AXIS ] = count_position [ Z_AXIS ] ;
endstop_z_probe_hit = true ;
2015-03-28 05:31:51 -04:00
2015-04-24 02:03:17 -04:00
// if (z_probe_endstop && old_z_probe_endstop) SERIAL_ECHOLN("z_probe_endstop = true");
2015-03-28 05:31:51 -04:00
}
old_z_probe_endstop = z_probe_endstop ;
# endif
2015-04-24 02:03:17 -04:00
2015-03-30 02:16:12 -04:00
} // check_endstops
2011-11-13 14:42:08 -05:00
}
else { // +direction
2015-03-30 02:16:12 -04:00
2015-03-24 13:06:44 -04:00
Z_APPLY_DIR ( ! INVERT_Z_DIR , 0 ) ;
2015-03-14 07:28:22 -04:00
count_direction [ Z_AXIS ] = 1 ;
2015-03-30 02:16:12 -04:00
2015-03-14 07:28:22 -04:00
if ( check_endstops ) {
2015-03-30 02:16:12 -04:00
2015-04-03 18:31:35 -04:00
# if HAS_Z_MAX
2015-03-30 02:16:12 -04:00
# ifdef Z_DUAL_ENDSTOPS
bool z_max_endstop = READ ( Z_MAX_PIN ) ! = Z_MAX_ENDSTOP_INVERTING ,
z2_max_endstop =
2015-04-03 18:31:35 -04:00
# if HAS_Z2_MAX
2015-03-30 02:16:12 -04:00
READ ( Z2_MAX_PIN ) ! = Z2_MAX_ENDSTOP_INVERTING
# else
z_max_endstop
# endif
;
bool z_max_both = z_max_endstop & & old_z_max_endstop ,
z2_max_both = z2_max_endstop & & old_z2_max_endstop ;
if ( ( z_max_both | | z2_max_both ) & & current_block - > steps [ Z_AXIS ] > 0 ) {
2015-03-24 13:06:44 -04:00
endstops_trigsteps [ Z_AXIS ] = count_position [ Z_AXIS ] ;
2015-03-30 02:16:12 -04:00
endstop_z_hit = true ;
2015-03-24 13:06:44 -04:00
2015-03-30 02:16:12 -04:00
// if (z_max_both) SERIAL_ECHOLN("z_max_endstop = true");
// if (z2_max_both) SERIAL_ECHOLN("z2_max_endstop = true");
2015-03-24 13:06:44 -04:00
2015-03-30 02:16:12 -04:00
if ( ! performing_homing | | ( performing_homing & & z_max_both & & z2_max_both ) ) //if not performing home or if both endstops were trigged during homing...
2015-03-24 13:06:44 -04:00
step_events_completed = current_block - > step_event_count ;
}
old_z_max_endstop = z_max_endstop ;
old_z2_max_endstop = z2_max_endstop ;
2015-03-30 02:16:12 -04:00
# else // !Z_DUAL_ENDSTOPS
UPDATE_ENDSTOP ( z , Z , max , MAX ) ;
# endif // !Z_DUAL_ENDSTOPS
# endif // Z_MAX_PIN
2015-04-24 02:03:17 -04:00
2015-04-01 03:14:55 -04:00
# ifdef Z_PROBE_ENDSTOP
2015-03-28 05:31:51 -04:00
UPDATE_ENDSTOP ( z , Z , probe , PROBE ) ;
2015-03-31 02:06:01 -04:00
z_probe_endstop = ( READ ( Z_PROBE_PIN ) ! = Z_PROBE_ENDSTOP_INVERTING ) ;
2015-03-28 05:31:51 -04:00
if ( z_probe_endstop & & old_z_probe_endstop )
{
2015-04-24 02:03:17 -04:00
endstops_trigsteps [ Z_AXIS ] = count_position [ Z_AXIS ] ;
endstop_z_probe_hit = true ;
// if (z_probe_endstop && old_z_probe_endstop) SERIAL_ECHOLN("z_probe_endstop = true");
2015-03-28 05:31:51 -04:00
}
old_z_probe_endstop = z_probe_endstop ;
# endif
2015-03-30 02:16:12 -04:00
} // check_endstops
} // +direction
2011-11-13 14:42:08 -05:00
# ifndef ADVANCE
2015-03-14 07:28:22 -04:00
if ( TEST ( out_bits , E_AXIS ) ) { // -direction
2011-12-12 13:34:37 -05:00
REV_E_DIR ( ) ;
2015-03-30 02:16:12 -04:00
count_direction [ E_AXIS ] = - 1 ;
2011-11-20 08:50:08 -05:00
}
else { // +direction
2011-12-12 13:34:37 -05:00
NORM_E_DIR ( ) ;
2015-03-30 02:16:12 -04:00
count_direction [ E_AXIS ] = 1 ;
2011-11-20 08:50:08 -05:00
}
2011-11-13 14:42:08 -05:00
# endif //!ADVANCE
2011-12-04 13:54:07 -05:00
2015-03-14 07:28:22 -04:00
// Take multiple steps per interrupt (For high speed moves)
2015-03-30 02:16:12 -04:00
for ( int8_t i = 0 ; i < step_loops ; i + + ) {
2012-12-09 04:32:09 -05:00
# ifndef AT90USB
2015-03-14 07:28:22 -04:00
MSerial . checkRx ( ) ; // Check for serial chars.
2012-12-09 04:32:09 -05:00
# endif
2011-12-02 11:45:05 -05:00
# ifdef ADVANCE
2015-03-20 23:42:49 -04:00
counter_e + = current_block - > steps [ E_AXIS ] ;
2014-12-03 09:01:52 -05:00
if ( counter_e > 0 ) {
counter_e - = current_block - > step_event_count ;
2015-03-14 07:28:22 -04:00
e_steps [ current_block - > active_extruder ] + = TEST ( out_bits , E_AXIS ) ? - 1 : 1 ;
2012-07-14 07:43:19 -04:00
}
2015-03-14 07:28:22 -04:00
# endif //ADVANCE
2013-08-01 09:06:39 -04:00
2015-04-24 02:03:17 -04:00
# define _COUNTER(axis) counter_## axis
# define _WRITE_STEP(AXIS, HIGHLOW) AXIS ##_STEP_WRITE(HIGHLOW)
# define _APPLY_STEP(AXIS) AXIS ##_APPLY_STEP
# define _INVERT_STEP_PIN(AXIS) INVERT_## AXIS ##_STEP_PIN
2015-03-14 07:28:22 -04:00
# ifdef CONFIG_STEPPERS_TOSHIBA
/**
* The Toshiba stepper controller require much longer pulses .
* So we ' stage ' decompose the pulses between high and low
* instead of doing each in turn . The extra tests add enough
* lag to allow it work with without needing NOPs
*/
2015-03-20 23:42:49 -04:00
# define STEP_ADD(axis, AXIS) \
2015-04-24 02:03:17 -04:00
_COUNTER ( axis ) + = current_block - > steps [ _AXIS ( AXIS ) ] ; \
if ( _COUNTER ( axis ) > 0 ) { _WRITE_STEP ( AXIS , HIGH ) ; }
2015-03-20 23:42:49 -04:00
STEP_ADD ( x , X ) ;
STEP_ADD ( y , Y ) ;
STEP_ADD ( z , Z ) ;
2015-03-14 07:28:22 -04:00
# ifndef ADVANCE
2015-03-20 23:42:49 -04:00
STEP_ADD ( e , E ) ;
2015-03-14 07:28:22 -04:00
# endif
# define STEP_IF_COUNTER(axis, AXIS) \
2015-04-24 02:03:17 -04:00
if ( _COUNTER ( axis ) > 0 ) { \
_COUNTER ( axis ) - = current_block - > step_event_count ; \
count_position [ _AXIS ( AXIS ) ] + = count_direction [ _AXIS ( AXIS ) ] ; \
_WRITE_STEP ( AXIS , LOW ) ; \
2015-03-14 07:28:22 -04:00
}
2013-08-01 09:06:39 -04:00
2015-03-14 07:28:22 -04:00
STEP_IF_COUNTER ( x , X ) ;
STEP_IF_COUNTER ( y , Y ) ;
STEP_IF_COUNTER ( z , Z ) ;
# ifndef ADVANCE
STEP_IF_COUNTER ( e , E ) ;
2012-08-04 02:32:26 -04:00
# endif
2013-08-01 09:06:39 -04:00
2015-03-14 07:28:22 -04:00
# else // !CONFIG_STEPPERS_TOSHIBA
# define APPLY_MOVEMENT(axis, AXIS) \
2015-04-24 02:03:17 -04:00
_COUNTER ( axis ) + = current_block - > steps [ _AXIS ( AXIS ) ] ; \
if ( _COUNTER ( axis ) > 0 ) { \
_APPLY_STEP ( AXIS ) ( ! _INVERT_STEP_PIN ( AXIS ) , 0 ) ; \
_COUNTER ( axis ) - = current_block - > step_event_count ; \
count_position [ _AXIS ( AXIS ) ] + = count_direction [ _AXIS ( AXIS ) ] ; \
_APPLY_STEP ( AXIS ) ( _INVERT_STEP_PIN ( AXIS ) , 0 ) ; \
2015-03-14 07:28:22 -04:00
}
2015-03-07 01:14:34 -05:00
2015-03-14 07:28:22 -04:00
APPLY_MOVEMENT ( x , X ) ;
APPLY_MOVEMENT ( y , Y ) ;
APPLY_MOVEMENT ( z , Z ) ;
# ifndef ADVANCE
APPLY_MOVEMENT ( e , E ) ;
2012-08-04 02:32:26 -04:00
# endif
2011-11-13 14:42:08 -05:00
2015-03-14 07:28:22 -04:00
# endif // CONFIG_STEPPERS_TOSHIBA
step_events_completed + + ;
if ( step_events_completed > = current_block - > step_event_count ) break ;
2011-11-13 14:42:08 -05:00
}
2015-03-28 05:31:51 -04:00
// Calculate new timer value
2011-11-13 14:42:08 -05:00
unsigned short timer ;
unsigned short step_rate ;
2015-04-12 21:07:08 -04:00
if ( step_events_completed < = ( unsigned long ) current_block - > accelerate_until ) {
2013-08-01 09:06:39 -04:00
2015-04-16 18:04:38 -04:00
MultiU24X32toH16 ( acc_step_rate , acceleration_time , current_block - > acceleration_rate ) ;
2011-11-13 14:42:08 -05:00
acc_step_rate + = current_block - > initial_rate ;
2013-08-01 09:06:39 -04:00
2011-11-13 14:42:08 -05:00
// upper limit
2015-03-14 07:28:22 -04:00
if ( acc_step_rate > current_block - > nominal_rate )
2011-11-13 14:42:08 -05:00
acc_step_rate = current_block - > nominal_rate ;
// step_rate to timer interval
timer = calc_timer ( acc_step_rate ) ;
2011-11-25 09:32:50 -05:00
OCR1A = timer ;
acceleration_time + = timer ;
2011-11-13 14:42:08 -05:00
# ifdef ADVANCE
2011-12-02 11:45:05 -05:00
for ( int8_t i = 0 ; i < step_loops ; i + + ) {
advance + = advance_rate ;
}
2015-03-14 07:28:22 -04:00
//if (advance > current_block->advance) advance = current_block->advance;
2011-12-04 13:54:07 -05:00
// Do E steps + advance steps
2011-12-12 13:34:37 -05:00
e_steps [ current_block - > active_extruder ] + = ( ( advance > > 8 ) - old_advance ) ;
2013-08-01 09:06:39 -04:00
old_advance = advance > > 8 ;
2011-11-13 14:42:08 -05:00
# endif
2013-08-01 09:06:39 -04:00
}
2015-04-12 21:07:08 -04:00
else if ( step_events_completed > ( unsigned long ) current_block - > decelerate_after ) {
2015-04-16 18:04:38 -04:00
MultiU24X32toH16 ( step_rate , deceleration_time , current_block - > acceleration_rate ) ;
2013-08-01 09:06:39 -04:00
2015-03-14 07:28:22 -04:00
if ( step_rate > acc_step_rate ) { // Check step_rate stays positive
2011-11-13 14:42:08 -05:00
step_rate = current_block - > final_rate ;
}
else {
step_rate = acc_step_rate - step_rate ; // Decelerate from aceleration end point.
}
// lower limit
2015-03-14 07:28:22 -04:00
if ( step_rate < current_block - > final_rate )
2011-11-13 14:42:08 -05:00
step_rate = current_block - > final_rate ;
// step_rate to timer interval
timer = calc_timer ( step_rate ) ;
2011-11-25 09:32:50 -05:00
OCR1A = timer ;
deceleration_time + = timer ;
2011-11-13 14:42:08 -05:00
# ifdef ADVANCE
2011-12-02 11:45:05 -05:00
for ( int8_t i = 0 ; i < step_loops ; i + + ) {
advance - = advance_rate ;
}
2015-03-14 07:28:22 -04:00
if ( advance < final_advance ) advance = final_advance ;
2011-12-04 13:54:07 -05:00
// Do E steps + advance steps
2011-12-12 13:34:37 -05:00
e_steps [ current_block - > active_extruder ] + = ( ( advance > > 8 ) - old_advance ) ;
2013-08-01 09:06:39 -04:00
old_advance = advance > > 8 ;
2011-11-13 14:42:08 -05:00
# endif //ADVANCE
}
else {
2011-11-25 09:32:50 -05:00
OCR1A = OCR1A_nominal ;
2013-03-15 04:03:53 -04:00
// ensure we're running at the correct step rate, even if we just came off an acceleration
step_loops = step_loops_nominal ;
2011-11-13 14:42:08 -05:00
}
2011-12-02 11:45:05 -05:00
2013-08-01 09:06:39 -04:00
// If current block is finished, reset pointer
2011-11-13 14:42:08 -05:00
if ( step_events_completed > = current_block - > step_event_count ) {
current_block = NULL ;
plan_discard_current_block ( ) ;
2013-08-01 09:06:39 -04:00
}
}
2011-11-13 14:42:08 -05:00
}
# ifdef ADVANCE
unsigned char old_OCR0A ;
// Timer interrupt for E. e_steps is set in the main routine;
// Timer 0 is shared with millies
ISR ( TIMER0_COMPA_vect )
{
2011-12-04 13:54:07 -05:00
old_OCR0A + = 52 ; // ~10kHz interrupt (250000 / 26 = 9615kHz)
2011-12-02 11:45:05 -05:00
OCR0A = old_OCR0A ;
2011-11-13 14:42:08 -05:00
// Set E direction (Depends on E direction + advance)
2011-12-12 13:34:37 -05:00
for ( unsigned char i = 0 ; i < 4 ; i + + ) {
if ( e_steps [ 0 ] ! = 0 ) {
2015-03-14 07:28:22 -04:00
E0_STEP_WRITE ( INVERT_E_STEP_PIN ) ;
2011-12-12 13:34:37 -05:00
if ( e_steps [ 0 ] < 0 ) {
2015-02-23 10:12:35 -05:00
E0_DIR_WRITE ( INVERT_E0_DIR ) ;
2011-12-12 13:34:37 -05:00
e_steps [ 0 ] + + ;
2015-02-23 10:12:35 -05:00
E0_STEP_WRITE ( ! INVERT_E_STEP_PIN ) ;
2013-08-01 09:06:39 -04:00
}
2011-12-12 13:34:37 -05:00
else if ( e_steps [ 0 ] > 0 ) {
2015-02-23 10:12:35 -05:00
E0_DIR_WRITE ( ! INVERT_E0_DIR ) ;
2011-12-12 13:34:37 -05:00
e_steps [ 0 ] - - ;
2015-02-23 10:12:35 -05:00
E0_STEP_WRITE ( ! INVERT_E_STEP_PIN ) ;
2011-12-12 13:34:37 -05:00
}
}
# if EXTRUDERS > 1
if ( e_steps [ 1 ] ! = 0 ) {
2015-02-23 10:12:35 -05:00
E1_STEP_WRITE ( INVERT_E_STEP_PIN ) ;
2011-12-12 13:34:37 -05:00
if ( e_steps [ 1 ] < 0 ) {
2015-02-23 10:12:35 -05:00
E1_DIR_WRITE ( INVERT_E1_DIR ) ;
2011-12-12 13:34:37 -05:00
e_steps [ 1 ] + + ;
2015-02-23 10:12:35 -05:00
E1_STEP_WRITE ( ! INVERT_E_STEP_PIN ) ;
2013-08-01 09:06:39 -04:00
}
2011-12-12 13:34:37 -05:00
else if ( e_steps [ 1 ] > 0 ) {
2015-02-23 10:12:35 -05:00
E1_DIR_WRITE ( ! INVERT_E1_DIR ) ;
2011-12-12 13:34:37 -05:00
e_steps [ 1 ] - - ;
2015-02-23 10:12:35 -05:00
E1_STEP_WRITE ( ! INVERT_E_STEP_PIN ) ;
2011-12-12 13:34:37 -05:00
}
}
# endif
# if EXTRUDERS > 2
if ( e_steps [ 2 ] ! = 0 ) {
2015-02-23 10:12:35 -05:00
E2_STEP_WRITE ( INVERT_E_STEP_PIN ) ;
2011-12-12 13:34:37 -05:00
if ( e_steps [ 2 ] < 0 ) {
2015-02-23 10:12:35 -05:00
E2_DIR_WRITE ( INVERT_E2_DIR ) ;
2011-12-12 13:34:37 -05:00
e_steps [ 2 ] + + ;
2015-02-23 10:12:35 -05:00
E2_STEP_WRITE ( ! INVERT_E_STEP_PIN ) ;
2013-08-01 09:06:39 -04:00
}
2011-12-12 13:34:37 -05:00
else if ( e_steps [ 2 ] > 0 ) {
2015-02-23 10:12:35 -05:00
E2_DIR_WRITE ( ! INVERT_E2_DIR ) ;
2011-12-12 13:34:37 -05:00
e_steps [ 2 ] - - ;
2015-02-23 10:12:35 -05:00
E2_STEP_WRITE ( ! INVERT_E_STEP_PIN ) ;
2011-12-12 13:34:37 -05:00
}
2011-12-02 11:45:05 -05:00
}
2011-12-12 13:34:37 -05:00
# endif
2015-01-23 17:13:06 -05:00
# if EXTRUDERS > 3
if ( e_steps [ 3 ] ! = 0 ) {
2015-02-23 10:12:35 -05:00
E3_STEP_WRITE ( INVERT_E_STEP_PIN ) ;
2015-01-23 17:13:06 -05:00
if ( e_steps [ 3 ] < 0 ) {
2015-02-23 10:12:35 -05:00
E3_DIR_WRITE ( INVERT_E3_DIR ) ;
2015-01-23 17:13:06 -05:00
e_steps [ 3 ] + + ;
2015-02-23 10:12:35 -05:00
E3_STEP_WRITE ( ! INVERT_E_STEP_PIN ) ;
2015-01-23 17:13:06 -05:00
}
else if ( e_steps [ 3 ] > 0 ) {
2015-02-23 10:12:35 -05:00
E3_DIR_WRITE ( ! INVERT_E3_DIR ) ;
2015-01-23 17:13:06 -05:00
e_steps [ 3 ] - - ;
2015-02-23 10:12:35 -05:00
E3_STEP_WRITE ( ! INVERT_E_STEP_PIN ) ;
2015-01-23 17:13:06 -05:00
}
}
# endif
2011-11-13 14:42:08 -05:00
}
}
# endif // ADVANCE
2015-03-14 07:28:22 -04:00
void st_init ( ) {
2012-08-30 03:16:57 -04:00
digipot_init ( ) ; //Initialize Digipot Motor Current
microstep_init ( ) ; //Initialize Microstepping Pins
2013-08-01 09:06:39 -04:00
2015-02-23 11:45:29 -05:00
// initialise TMC Steppers
# ifdef HAVE_TMCDRIVER
2015-03-14 07:28:22 -04:00
tmc_init ( ) ;
2015-02-23 11:45:29 -05:00
# endif
2015-02-27 06:43:23 -05:00
// initialise L6470 Steppers
# ifdef HAVE_L6470DRIVER
2015-03-14 07:28:22 -04:00
L6470_init ( ) ;
2015-02-27 06:43:23 -05:00
# endif
2015-04-24 02:03:17 -04:00
2015-03-14 07:28:22 -04:00
// Initialize Dir Pins
2015-04-03 18:31:35 -04:00
# if HAS_X_DIR
2015-02-23 10:12:35 -05:00
X_DIR_INIT ;
2011-11-13 14:42:08 -05:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_X2_DIR
2015-02-23 10:12:35 -05:00
X2_DIR_INIT ;
2013-07-17 08:44:45 -04:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_Y_DIR
2015-02-23 10:12:35 -05:00
Y_DIR_INIT ;
2015-04-03 18:31:35 -04:00
# if defined(Y_DUAL_STEPPER_DRIVERS) && HAS_Y2_DIR
2015-03-14 07:28:22 -04:00
Y2_DIR_INIT ;
# endif
2011-11-13 14:42:08 -05:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_Z_DIR
2015-02-23 10:12:35 -05:00
Z_DIR_INIT ;
2015-04-03 18:31:35 -04:00
# if defined(Z_DUAL_STEPPER_DRIVERS) && HAS_Z2_DIR
2015-02-23 10:12:35 -05:00
Z2_DIR_INIT ;
2012-08-04 02:32:26 -04:00
# endif
2011-11-13 14:42:08 -05:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_E0_DIR
2015-02-23 10:12:35 -05:00
E0_DIR_INIT ;
2011-12-05 23:33:33 -05:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_E1_DIR
2015-02-23 10:12:35 -05:00
E1_DIR_INIT ;
2011-12-05 23:33:33 -05:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_E2_DIR
2015-02-23 10:12:35 -05:00
E2_DIR_INIT ;
2011-11-13 14:42:08 -05:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_E3_DIR
2015-02-23 10:12:35 -05:00
E3_DIR_INIT ;
2015-01-23 17:13:06 -05:00
# endif
2011-11-13 14:42:08 -05:00
//Initialize Enable Pins - steppers default to disabled.
2015-04-03 18:31:35 -04:00
# if HAS_X_ENABLE
2015-02-23 10:12:35 -05:00
X_ENABLE_INIT ;
2015-03-14 07:28:22 -04:00
if ( ! X_ENABLE_ON ) X_ENABLE_WRITE ( HIGH ) ;
2011-11-13 14:42:08 -05:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_X2_ENABLE
2015-02-23 10:12:35 -05:00
X2_ENABLE_INIT ;
2015-03-14 07:28:22 -04:00
if ( ! X_ENABLE_ON ) X2_ENABLE_WRITE ( HIGH ) ;
2013-07-17 08:44:45 -04:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_Y_ENABLE
2015-02-23 10:12:35 -05:00
Y_ENABLE_INIT ;
2015-03-14 07:28:22 -04:00
if ( ! Y_ENABLE_ON ) Y_ENABLE_WRITE ( HIGH ) ;
2015-04-24 02:03:17 -04:00
# if defined(Y_DUAL_STEPPER_DRIVERS) && HAS_Y2_ENABLE
Y2_ENABLE_INIT ;
if ( ! Y_ENABLE_ON ) Y2_ENABLE_WRITE ( HIGH ) ;
# endif
2011-11-13 14:42:08 -05:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_Z_ENABLE
2015-02-23 10:12:35 -05:00
Z_ENABLE_INIT ;
2015-03-14 07:28:22 -04:00
if ( ! Z_ENABLE_ON ) Z_ENABLE_WRITE ( HIGH ) ;
2013-08-01 09:06:39 -04:00
2015-04-03 18:31:35 -04:00
# if defined(Z_DUAL_STEPPER_DRIVERS) && HAS_Z2_ENABLE
2015-02-23 10:12:35 -05:00
Z2_ENABLE_INIT ;
2015-03-14 07:28:22 -04:00
if ( ! Z_ENABLE_ON ) Z2_ENABLE_WRITE ( HIGH ) ;
2012-08-04 02:32:26 -04:00
# endif
2011-11-13 14:42:08 -05:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_E0_ENABLE
2015-02-23 10:12:35 -05:00
E0_ENABLE_INIT ;
2015-03-14 07:28:22 -04:00
if ( ! E_ENABLE_ON ) E0_ENABLE_WRITE ( HIGH ) ;
2011-12-05 23:33:33 -05:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_E1_ENABLE
2015-02-23 10:12:35 -05:00
E1_ENABLE_INIT ;
2015-03-14 07:28:22 -04:00
if ( ! E_ENABLE_ON ) E1_ENABLE_WRITE ( HIGH ) ;
2011-12-05 23:33:33 -05:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_E2_ENABLE
2015-02-23 10:12:35 -05:00
E2_ENABLE_INIT ;
2015-03-14 07:28:22 -04:00
if ( ! E_ENABLE_ON ) E2_ENABLE_WRITE ( HIGH ) ;
2011-11-13 14:42:08 -05:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_E3_ENABLE
2015-02-23 10:12:35 -05:00
E3_ENABLE_INIT ;
2015-03-14 07:28:22 -04:00
if ( ! E_ENABLE_ON ) E3_ENABLE_WRITE ( HIGH ) ;
2015-01-23 17:13:06 -05:00
# endif
2011-11-13 14:42:08 -05:00
//endstops and pullups
2013-08-01 09:06:39 -04:00
2015-04-03 18:31:35 -04:00
# if HAS_X_MIN
2013-08-01 09:06:39 -04:00
SET_INPUT ( X_MIN_PIN ) ;
2012-06-02 07:47:50 -04:00
# ifdef ENDSTOPPULLUP_XMIN
2011-11-13 14:42:08 -05:00
WRITE ( X_MIN_PIN , HIGH ) ;
# endif
2012-06-02 07:47:50 -04:00
# endif
2013-08-01 09:06:39 -04:00
2015-04-03 18:31:35 -04:00
# if HAS_Y_MIN
2013-08-01 09:06:39 -04:00
SET_INPUT ( Y_MIN_PIN ) ;
2012-06-02 07:47:50 -04:00
# ifdef ENDSTOPPULLUP_YMIN
2011-11-13 14:42:08 -05:00
WRITE ( Y_MIN_PIN , HIGH ) ;
# endif
2012-06-02 07:47:50 -04:00
# endif
2013-08-01 09:06:39 -04:00
2015-04-03 18:31:35 -04:00
# if HAS_Z_MIN
2013-08-01 09:06:39 -04:00
SET_INPUT ( Z_MIN_PIN ) ;
2012-06-02 07:47:50 -04:00
# ifdef ENDSTOPPULLUP_ZMIN
2011-11-13 14:42:08 -05:00
WRITE ( Z_MIN_PIN , HIGH ) ;
# endif
2012-06-02 07:47:50 -04:00
# endif
2013-08-01 09:06:39 -04:00
2015-04-03 18:31:35 -04:00
# if HAS_X_MAX
2013-08-01 09:06:39 -04:00
SET_INPUT ( X_MAX_PIN ) ;
2012-06-02 07:47:50 -04:00
# ifdef ENDSTOPPULLUP_XMAX
WRITE ( X_MAX_PIN , HIGH ) ;
2011-11-13 14:42:08 -05:00
# endif
2012-06-02 07:47:50 -04:00
# endif
2013-08-01 09:06:39 -04:00
2015-04-03 18:31:35 -04:00
# if HAS_Y_MAX
2013-08-01 09:06:39 -04:00
SET_INPUT ( Y_MAX_PIN ) ;
2012-06-02 07:47:50 -04:00
# ifdef ENDSTOPPULLUP_YMAX
WRITE ( Y_MAX_PIN , HIGH ) ;
2011-11-13 14:42:08 -05:00
# endif
2012-06-02 07:47:50 -04:00
# endif
2013-08-01 09:06:39 -04:00
2015-04-03 18:31:35 -04:00
# if HAS_Z_MAX
2013-08-01 09:06:39 -04:00
SET_INPUT ( Z_MAX_PIN ) ;
2012-06-02 07:47:50 -04:00
# ifdef ENDSTOPPULLUP_ZMAX
WRITE ( Z_MAX_PIN , HIGH ) ;
2011-11-13 14:42:08 -05:00
# endif
2012-06-02 07:47:50 -04:00
# endif
2013-08-01 09:06:39 -04:00
2015-04-03 18:31:35 -04:00
# if HAS_Z2_MAX
2015-03-24 13:06:44 -04:00
SET_INPUT ( Z2_MAX_PIN ) ;
# ifdef ENDSTOPPULLUP_ZMAX
WRITE ( Z2_MAX_PIN , HIGH ) ;
# endif
2015-04-24 02:03:17 -04:00
# endif
2015-04-01 03:14:55 -04:00
# if (defined(Z_PROBE_PIN) && Z_PROBE_PIN >= 0) && defined(Z_PROBE_ENDSTOP) // Check for Z_PROBE_ENDSTOP so we don't pull a pin high unless it's to be used.
2015-03-28 05:31:51 -04:00
SET_INPUT ( Z_PROBE_PIN ) ;
# ifdef ENDSTOPPULLUP_ZPROBE
WRITE ( Z_PROBE_PIN , HIGH ) ;
# endif
# endif
2015-04-24 02:03:17 -04:00
# define _STEP_INIT(AXIS) AXIS ##_STEP_INIT
# define _DISABLE(axis) disable_## axis()
2015-03-14 07:28:22 -04:00
# define AXIS_INIT(axis, AXIS, PIN) \
2015-04-24 02:03:17 -04:00
_STEP_INIT ( AXIS ) ; \
_WRITE_STEP ( AXIS , _INVERT_STEP_PIN ( PIN ) ) ; \
_DISABLE ( axis )
2011-11-13 14:42:08 -05:00
2015-03-14 07:28:22 -04:00
# define E_AXIS_INIT(NUM) AXIS_INIT(e## NUM, E## NUM, E)
// Initialize Step Pins
2015-04-03 18:31:35 -04:00
# if HAS_X_STEP
2015-03-14 07:28:22 -04:00
AXIS_INIT ( x , X , X ) ;
2013-08-01 09:06:39 -04:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_X2_STEP
2015-03-14 07:28:22 -04:00
AXIS_INIT ( x , X2 , X ) ;
2013-08-01 09:06:39 -04:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_Y_STEP
# if defined(Y_DUAL_STEPPER_DRIVERS) && HAS_Y2_STEP
2015-02-23 10:12:35 -05:00
Y2_STEP_INIT ;
Y2_STEP_WRITE ( INVERT_Y_STEP_PIN ) ;
2013-09-17 14:19:20 -04:00
# endif
2015-03-14 07:28:22 -04:00
AXIS_INIT ( y , Y , Y ) ;
2013-08-01 09:06:39 -04:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_Z_STEP
# if defined(Z_DUAL_STEPPER_DRIVERS) && HAS_Z2_STEP
2015-02-23 10:12:35 -05:00
Z2_STEP_INIT ;
Z2_STEP_WRITE ( INVERT_Z_STEP_PIN ) ;
2012-08-04 02:32:26 -04:00
# endif
2015-03-14 07:28:22 -04:00
AXIS_INIT ( z , Z , Z ) ;
2013-08-01 09:06:39 -04:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_E0_STEP
2015-03-14 07:28:22 -04:00
E_AXIS_INIT ( 0 ) ;
2013-08-01 09:06:39 -04:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_E1_STEP
2015-03-14 07:28:22 -04:00
E_AXIS_INIT ( 1 ) ;
2013-08-01 09:06:39 -04:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_E2_STEP
2015-03-14 07:28:22 -04:00
E_AXIS_INIT ( 2 ) ;
2013-08-01 09:06:39 -04:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_E3_STEP
2015-03-14 07:28:22 -04:00
E_AXIS_INIT ( 3 ) ;
2015-01-23 17:13:06 -05:00
# endif
2011-11-13 14:42:08 -05:00
// waveform generation = 0100 = CTC
2015-03-14 07:28:22 -04:00
TCCR1B & = ~ BIT ( WGM13 ) ;
TCCR1B | = BIT ( WGM12 ) ;
TCCR1A & = ~ BIT ( WGM11 ) ;
TCCR1A & = ~ BIT ( WGM10 ) ;
2011-11-13 14:42:08 -05:00
// output mode = 00 (disconnected)
2013-08-01 09:06:39 -04:00
TCCR1A & = ~ ( 3 < < COM1A0 ) ;
TCCR1A & = ~ ( 3 < < COM1B0 ) ;
2012-03-07 17:58:35 -05:00
// Set the timer pre-scaler
// Generally we use a divider of 8, resulting in a 2MHz timer
// frequency on a 16MHz MCU. If you are going to change this, be
// sure to regenerate speed_lookuptable.h with
// create_speed_lookuptable.py
TCCR1B = ( TCCR1B & ~ ( 0x07 < < CS10 ) ) | ( 2 < < CS10 ) ;
2011-11-13 14:42:08 -05:00
OCR1A = 0x4000 ;
2011-11-18 12:59:17 -05:00
TCNT1 = 0 ;
2013-08-01 09:06:39 -04:00
ENABLE_STEPPER_DRIVER_INTERRUPT ( ) ;
2011-11-13 14:42:08 -05:00
# ifdef ADVANCE
2015-03-14 07:28:22 -04:00
# if defined(TCCR0A) && defined(WGM01)
TCCR0A & = ~ BIT ( WGM01 ) ;
TCCR0A & = ~ BIT ( WGM00 ) ;
# endif
2015-04-12 19:57:00 -04:00
e_steps [ 0 ] = e_steps [ 1 ] = e_steps [ 2 ] = e_steps [ 3 ] = 0 ;
2015-03-14 07:28:22 -04:00
TIMSK0 | = BIT ( OCIE0A ) ;
2011-11-13 14:42:08 -05:00
# endif //ADVANCE
2013-08-01 09:06:39 -04:00
2012-04-15 13:17:33 -04:00
enable_endstops ( true ) ; // Start with endstops active. After homing they can be disabled
2011-11-13 14:42:08 -05:00
sei ( ) ;
}
2011-12-09 06:32:31 -05:00
2011-11-13 14:42:08 -05:00
// Block until all buffered steps are executed
2015-03-14 07:28:22 -04:00
void st_synchronize ( ) {
while ( blocks_queued ( ) ) {
2011-11-13 14:42:08 -05:00
manage_heater ( ) ;
2012-08-21 08:48:29 -04:00
manage_inactivity ( ) ;
2012-12-03 06:52:00 -05:00
lcd_update ( ) ;
2011-12-09 06:32:31 -05:00
}
2011-11-13 14:46:44 -05:00
}
2011-11-20 08:50:08 -05:00
2015-03-14 07:28:22 -04:00
void st_set_position ( const long & x , const long & y , const long & z , const long & e ) {
2011-11-20 08:50:08 -05:00
CRITICAL_SECTION_START ;
count_position [ X_AXIS ] = x ;
count_position [ Y_AXIS ] = y ;
count_position [ Z_AXIS ] = z ;
count_position [ E_AXIS ] = e ;
CRITICAL_SECTION_END ;
}
2015-03-14 07:28:22 -04:00
void st_set_e_position ( const long & e ) {
2011-11-25 07:43:06 -05:00
CRITICAL_SECTION_START ;
count_position [ E_AXIS ] = e ;
CRITICAL_SECTION_END ;
}
2015-03-14 07:28:22 -04:00
long st_get_position ( uint8_t axis ) {
2011-11-20 08:50:08 -05:00
long count_pos ;
CRITICAL_SECTION_START ;
count_pos = count_position [ axis ] ;
CRITICAL_SECTION_END ;
return count_pos ;
}
2011-11-26 05:50:23 -05:00
2013-09-29 12:20:06 -04:00
# ifdef ENABLE_AUTO_BED_LEVELING
2015-03-14 07:28:22 -04:00
float st_get_position_mm ( uint8_t axis ) {
float steper_position_in_steps = st_get_position ( axis ) ;
return steper_position_in_steps / axis_steps_per_unit [ axis ] ;
}
2013-09-29 12:20:06 -04:00
# endif // ENABLE_AUTO_BED_LEVELING
2015-03-14 07:28:22 -04:00
void finishAndDisableSteppers ( ) {
2013-08-01 09:06:39 -04:00
st_synchronize ( ) ;
2015-04-03 22:25:22 -04:00
disable_all_steppers ( ) ;
2011-11-26 05:50:23 -05:00
}
2011-12-11 16:10:06 -05:00
2015-03-14 07:28:22 -04:00
void quickStop ( ) {
2015-03-19 13:16:18 -04:00
cleaning_buffer_counter = 5000 ;
2011-12-11 16:10:06 -05:00
DISABLE_STEPPER_DRIVER_INTERRUPT ( ) ;
2015-03-14 07:28:22 -04:00
while ( blocks_queued ( ) ) plan_discard_current_block ( ) ;
2012-03-03 14:40:46 -05:00
current_block = NULL ;
2011-12-11 16:10:06 -05:00
ENABLE_STEPPER_DRIVER_INTERRUPT ( ) ;
}
Add the socalled "Babystepping" feature.
It is a realtime control over the head position via the LCD menu system that works _while_ printing.
Using it, one can e.g. tune the z-position in realtime, while printing the first layer.
Also, lost steps can be manually added/removed, but thats not the prime feature.
Stuff is placed into the Tune->Babystep *
It is not possible to have realtime control via gcode sending due to the buffering, so I did not include a gcode yet. However, it could be added, but it movements will not be realtime then.
Historically, a very similar thing was implemented for the "Kaamermaker" project, while Joris was babysitting his offspring, hence the name.
say goodby to fuddling around with the z-axis.
2013-10-06 15:14:51 -04:00
# ifdef BABYSTEPPING
2015-03-14 07:28:22 -04:00
// MUST ONLY BE CALLED BY AN ISR,
// No other ISR should ever interrupt this!
void babystep ( const uint8_t axis , const bool direction ) {
2015-04-24 02:03:17 -04:00
# define _ENABLE(axis) enable_## axis()
# define _READ_DIR(AXIS) AXIS ##_DIR_READ
# define _INVERT_DIR(AXIS) INVERT_## AXIS ##_DIR
# define _APPLY_DIR(AXIS, INVERT) AXIS ##_APPLY_DIR(INVERT, true)
2015-03-14 07:28:22 -04:00
# define BABYSTEP_AXIS(axis, AXIS, INVERT) { \
2015-04-24 02:03:17 -04:00
_ENABLE ( axis ) ; \
uint8_t old_pin = _READ_DIR ( AXIS ) ; \
_APPLY_DIR ( AXIS , _INVERT_DIR ( AXIS ) ^ direction ^ INVERT ) ; \
_APPLY_STEP ( AXIS ) ( ! _INVERT_STEP_PIN ( AXIS ) , true ) ; \
2015-04-16 07:16:36 -04:00
delayMicroseconds ( 2 ) ; \
2015-04-24 02:03:17 -04:00
_APPLY_STEP ( AXIS ) ( _INVERT_STEP_PIN ( AXIS ) , true ) ; \
_APPLY_DIR ( AXIS , old_pin ) ; \
2015-03-14 07:28:22 -04:00
}
Add the socalled "Babystepping" feature.
It is a realtime control over the head position via the LCD menu system that works _while_ printing.
Using it, one can e.g. tune the z-position in realtime, while printing the first layer.
Also, lost steps can be manually added/removed, but thats not the prime feature.
Stuff is placed into the Tune->Babystep *
It is not possible to have realtime control via gcode sending due to the buffering, so I did not include a gcode yet. However, it could be added, but it movements will not be realtime then.
Historically, a very similar thing was implemented for the "Kaamermaker" project, while Joris was babysitting his offspring, hence the name.
say goodby to fuddling around with the z-axis.
2013-10-06 15:14:51 -04:00
2015-03-14 07:28:22 -04:00
switch ( axis ) {
Add the socalled "Babystepping" feature.
It is a realtime control over the head position via the LCD menu system that works _while_ printing.
Using it, one can e.g. tune the z-position in realtime, while printing the first layer.
Also, lost steps can be manually added/removed, but thats not the prime feature.
Stuff is placed into the Tune->Babystep *
It is not possible to have realtime control via gcode sending due to the buffering, so I did not include a gcode yet. However, it could be added, but it movements will not be realtime then.
Historically, a very similar thing was implemented for the "Kaamermaker" project, while Joris was babysitting his offspring, hence the name.
say goodby to fuddling around with the z-axis.
2013-10-06 15:14:51 -04:00
2015-03-14 07:28:22 -04:00
case X_AXIS :
BABYSTEP_AXIS ( x , X , false ) ;
break ;
Add the socalled "Babystepping" feature.
It is a realtime control over the head position via the LCD menu system that works _while_ printing.
Using it, one can e.g. tune the z-position in realtime, while printing the first layer.
Also, lost steps can be manually added/removed, but thats not the prime feature.
Stuff is placed into the Tune->Babystep *
It is not possible to have realtime control via gcode sending due to the buffering, so I did not include a gcode yet. However, it could be added, but it movements will not be realtime then.
Historically, a very similar thing was implemented for the "Kaamermaker" project, while Joris was babysitting his offspring, hence the name.
say goodby to fuddling around with the z-axis.
2013-10-06 15:14:51 -04:00
2015-03-14 07:28:22 -04:00
case Y_AXIS :
BABYSTEP_AXIS ( y , Y , false ) ;
break ;
2015-04-24 02:03:17 -04:00
2015-03-14 07:28:22 -04:00
case Z_AXIS : {
2015-01-23 06:24:45 -05:00
2015-03-14 07:28:22 -04:00
# ifndef DELTA
Add the socalled "Babystepping" feature.
It is a realtime control over the head position via the LCD menu system that works _while_ printing.
Using it, one can e.g. tune the z-position in realtime, while printing the first layer.
Also, lost steps can be manually added/removed, but thats not the prime feature.
Stuff is placed into the Tune->Babystep *
It is not possible to have realtime control via gcode sending due to the buffering, so I did not include a gcode yet. However, it could be added, but it movements will not be realtime then.
Historically, a very similar thing was implemented for the "Kaamermaker" project, while Joris was babysitting his offspring, hence the name.
say goodby to fuddling around with the z-axis.
2013-10-06 15:14:51 -04:00
2015-03-14 07:28:22 -04:00
BABYSTEP_AXIS ( z , Z , BABYSTEP_INVERT_Z ) ;
Add the socalled "Babystepping" feature.
It is a realtime control over the head position via the LCD menu system that works _while_ printing.
Using it, one can e.g. tune the z-position in realtime, while printing the first layer.
Also, lost steps can be manually added/removed, but thats not the prime feature.
Stuff is placed into the Tune->Babystep *
It is not possible to have realtime control via gcode sending due to the buffering, so I did not include a gcode yet. However, it could be added, but it movements will not be realtime then.
Historically, a very similar thing was implemented for the "Kaamermaker" project, while Joris was babysitting his offspring, hence the name.
say goodby to fuddling around with the z-axis.
2013-10-06 15:14:51 -04:00
2015-03-14 07:28:22 -04:00
# else // DELTA
2015-01-23 06:24:45 -05:00
2015-03-14 07:28:22 -04:00
bool z_direction = direction ^ BABYSTEP_INVERT_Z ;
2015-01-23 06:24:45 -05:00
2015-03-14 07:28:22 -04:00
enable_x ( ) ;
enable_y ( ) ;
enable_z ( ) ;
uint8_t old_x_dir_pin = X_DIR_READ ,
old_y_dir_pin = Y_DIR_READ ,
old_z_dir_pin = Z_DIR_READ ;
//setup new step
X_DIR_WRITE ( INVERT_X_DIR ^ z_direction ) ;
Y_DIR_WRITE ( INVERT_Y_DIR ^ z_direction ) ;
Z_DIR_WRITE ( INVERT_Z_DIR ^ z_direction ) ;
//perform step
X_STEP_WRITE ( ! INVERT_X_STEP_PIN ) ;
Y_STEP_WRITE ( ! INVERT_Y_STEP_PIN ) ;
Z_STEP_WRITE ( ! INVERT_Z_STEP_PIN ) ;
2015-04-16 07:16:36 -04:00
delayMicroseconds ( 2 ) ;
2015-03-14 07:28:22 -04:00
X_STEP_WRITE ( INVERT_X_STEP_PIN ) ;
Y_STEP_WRITE ( INVERT_Y_STEP_PIN ) ;
Z_STEP_WRITE ( INVERT_Z_STEP_PIN ) ;
//get old pin state back.
X_DIR_WRITE ( old_x_dir_pin ) ;
Y_DIR_WRITE ( old_y_dir_pin ) ;
Z_DIR_WRITE ( old_z_dir_pin ) ;
Add the socalled "Babystepping" feature.
It is a realtime control over the head position via the LCD menu system that works _while_ printing.
Using it, one can e.g. tune the z-position in realtime, while printing the first layer.
Also, lost steps can be manually added/removed, but thats not the prime feature.
Stuff is placed into the Tune->Babystep *
It is not possible to have realtime control via gcode sending due to the buffering, so I did not include a gcode yet. However, it could be added, but it movements will not be realtime then.
Historically, a very similar thing was implemented for the "Kaamermaker" project, while Joris was babysitting his offspring, hence the name.
say goodby to fuddling around with the z-axis.
2013-10-06 15:14:51 -04:00
2015-03-14 07:28:22 -04:00
# endif
Add the socalled "Babystepping" feature.
It is a realtime control over the head position via the LCD menu system that works _while_ printing.
Using it, one can e.g. tune the z-position in realtime, while printing the first layer.
Also, lost steps can be manually added/removed, but thats not the prime feature.
Stuff is placed into the Tune->Babystep *
It is not possible to have realtime control via gcode sending due to the buffering, so I did not include a gcode yet. However, it could be added, but it movements will not be realtime then.
Historically, a very similar thing was implemented for the "Kaamermaker" project, while Joris was babysitting his offspring, hence the name.
say goodby to fuddling around with the z-axis.
2013-10-06 15:14:51 -04:00
2015-03-14 07:28:22 -04:00
} break ;
2015-04-24 02:03:17 -04:00
2015-03-14 07:28:22 -04:00
default : break ;
}
Add the socalled "Babystepping" feature.
It is a realtime control over the head position via the LCD menu system that works _while_ printing.
Using it, one can e.g. tune the z-position in realtime, while printing the first layer.
Also, lost steps can be manually added/removed, but thats not the prime feature.
Stuff is placed into the Tune->Babystep *
It is not possible to have realtime control via gcode sending due to the buffering, so I did not include a gcode yet. However, it could be added, but it movements will not be realtime then.
Historically, a very similar thing was implemented for the "Kaamermaker" project, while Joris was babysitting his offspring, hence the name.
say goodby to fuddling around with the z-axis.
2013-10-06 15:14:51 -04:00
}
2013-10-07 03:14:04 -04:00
Add the socalled "Babystepping" feature.
It is a realtime control over the head position via the LCD menu system that works _while_ printing.
Using it, one can e.g. tune the z-position in realtime, while printing the first layer.
Also, lost steps can be manually added/removed, but thats not the prime feature.
Stuff is placed into the Tune->Babystep *
It is not possible to have realtime control via gcode sending due to the buffering, so I did not include a gcode yet. However, it could be added, but it movements will not be realtime then.
Historically, a very similar thing was implemented for the "Kaamermaker" project, while Joris was babysitting his offspring, hence the name.
say goodby to fuddling around with the z-axis.
2013-10-06 15:14:51 -04:00
# endif //BABYSTEPPING
2015-03-14 07:28:22 -04:00
// From Arduino DigitalPotControl example
void digitalPotWrite ( int address , int value ) {
# if HAS_DIGIPOTSS
2012-08-30 03:16:57 -04:00
digitalWrite ( DIGIPOTSS_PIN , LOW ) ; // take the SS pin low to select the chip
SPI . transfer ( address ) ; // send in the address and value via SPI:
SPI . transfer ( value ) ;
digitalWrite ( DIGIPOTSS_PIN , HIGH ) ; // take the SS pin high to de-select the chip:
//delay(10);
# endif
}
2015-03-14 07:28:22 -04:00
// Initialize Digipot Motor Current
void digipot_init ( ) {
# if HAS_DIGIPOTSS
2012-08-30 03:16:57 -04:00
const uint8_t digipot_motor_current [ ] = DIGIPOT_MOTOR_CURRENT ;
2013-08-01 09:06:39 -04:00
SPI . begin ( ) ;
pinMode ( DIGIPOTSS_PIN , OUTPUT ) ;
2015-03-14 07:28:22 -04:00
for ( int i = 0 ; i < = 4 ; i + + ) {
2012-08-30 03:16:57 -04:00
//digitalPotWrite(digipot_ch[i], digipot_motor_current[i]);
digipot_current ( i , digipot_motor_current [ i ] ) ;
2015-03-14 07:28:22 -04:00
}
2012-08-30 03:16:57 -04:00
# endif
2014-01-06 05:05:02 -05:00
# ifdef MOTOR_CURRENT_PWM_XY_PIN
pinMode ( MOTOR_CURRENT_PWM_XY_PIN , OUTPUT ) ;
pinMode ( MOTOR_CURRENT_PWM_Z_PIN , OUTPUT ) ;
pinMode ( MOTOR_CURRENT_PWM_E_PIN , OUTPUT ) ;
digipot_current ( 0 , motor_current_setting [ 0 ] ) ;
digipot_current ( 1 , motor_current_setting [ 1 ] ) ;
digipot_current ( 2 , motor_current_setting [ 2 ] ) ;
//Set timer5 to 31khz so the PWM of the motor power is as constant as possible. (removes a buzzing noise)
TCCR5B = ( TCCR5B & ~ ( _BV ( CS50 ) | _BV ( CS51 ) | _BV ( CS52 ) ) ) | _BV ( CS50 ) ;
# endif
2012-08-30 03:16:57 -04:00
}
2015-03-14 07:28:22 -04:00
void digipot_current ( uint8_t driver , int current ) {
# if HAS_DIGIPOTSS
2012-08-30 03:16:57 -04:00
const uint8_t digipot_ch [ ] = DIGIPOT_CHANNELS ;
digitalPotWrite ( digipot_ch [ driver ] , current ) ;
# endif
2014-01-06 05:05:02 -05:00
# ifdef MOTOR_CURRENT_PWM_XY_PIN
2015-03-14 07:28:22 -04:00
switch ( driver ) {
case 0 : analogWrite ( MOTOR_CURRENT_PWM_XY_PIN , 255L * current / MOTOR_CURRENT_PWM_RANGE ) ; break ;
case 1 : analogWrite ( MOTOR_CURRENT_PWM_Z_PIN , 255L * current / MOTOR_CURRENT_PWM_RANGE ) ; break ;
case 2 : analogWrite ( MOTOR_CURRENT_PWM_E_PIN , 255L * current / MOTOR_CURRENT_PWM_RANGE ) ; break ;
}
2014-01-06 05:05:02 -05:00
# endif
2012-08-30 03:16:57 -04:00
}
2015-03-14 07:28:22 -04:00
void microstep_init ( ) {
2015-04-03 18:31:35 -04:00
# if HAS_MICROSTEPS_E1
2015-03-14 07:28:22 -04:00
pinMode ( E1_MS1_PIN , OUTPUT ) ;
2015-04-03 18:31:35 -04:00
pinMode ( E1_MS2_PIN , OUTPUT ) ;
2014-04-25 00:57:11 -04:00
# endif
2015-04-03 18:31:35 -04:00
# if HAS_MICROSTEPS
2015-03-14 07:28:22 -04:00
pinMode ( X_MS1_PIN , OUTPUT ) ;
2015-04-24 02:03:17 -04:00
pinMode ( X_MS2_PIN , OUTPUT ) ;
2015-03-14 07:28:22 -04:00
pinMode ( Y_MS1_PIN , OUTPUT ) ;
pinMode ( Y_MS2_PIN , OUTPUT ) ;
pinMode ( Z_MS1_PIN , OUTPUT ) ;
pinMode ( Z_MS2_PIN , OUTPUT ) ;
pinMode ( E0_MS1_PIN , OUTPUT ) ;
pinMode ( E0_MS2_PIN , OUTPUT ) ;
2015-03-27 03:32:58 -04:00
const uint8_t microstep_modes [ ] = MICROSTEP_MODES ;
2015-03-28 23:33:21 -04:00
for ( uint16_t i = 0 ; i < sizeof ( microstep_modes ) / sizeof ( microstep_modes [ 0 ] ) ; i + + )
2015-03-27 03:32:58 -04:00
microstep_mode ( i , microstep_modes [ i ] ) ;
2012-08-30 03:16:57 -04:00
# endif
}
2015-03-14 07:28:22 -04:00
void microstep_ms ( uint8_t driver , int8_t ms1 , int8_t ms2 ) {
if ( ms1 > = 0 ) switch ( driver ) {
case 0 : digitalWrite ( X_MS1_PIN , ms1 ) ; break ;
case 1 : digitalWrite ( Y_MS1_PIN , ms1 ) ; break ;
case 2 : digitalWrite ( Z_MS1_PIN , ms1 ) ; break ;
case 3 : digitalWrite ( E0_MS1_PIN , ms1 ) ; break ;
2015-04-03 18:31:35 -04:00
# if HAS_MICROSTEPS_E1
2015-03-14 07:28:22 -04:00
case 4 : digitalWrite ( E1_MS1_PIN , ms1 ) ; break ;
2014-04-25 00:57:11 -04:00
# endif
2012-08-30 03:16:57 -04:00
}
2015-03-14 07:28:22 -04:00
if ( ms2 > = 0 ) switch ( driver ) {
case 0 : digitalWrite ( X_MS2_PIN , ms2 ) ; break ;
case 1 : digitalWrite ( Y_MS2_PIN , ms2 ) ; break ;
case 2 : digitalWrite ( Z_MS2_PIN , ms2 ) ; break ;
case 3 : digitalWrite ( E0_MS2_PIN , ms2 ) ; break ;
# if defined(E1_MS2_PIN) && E1_MS2_PIN >= 0
case 4 : digitalWrite ( E1_MS2_PIN , ms2 ) ; break ;
2014-04-25 00:57:11 -04:00
# endif
2012-08-30 03:16:57 -04:00
}
}
2015-03-14 07:28:22 -04:00
void microstep_mode ( uint8_t driver , uint8_t stepping_mode ) {
switch ( stepping_mode ) {
2012-08-30 03:16:57 -04:00
case 1 : microstep_ms ( driver , MICROSTEP1 ) ; break ;
case 2 : microstep_ms ( driver , MICROSTEP2 ) ; break ;
case 4 : microstep_ms ( driver , MICROSTEP4 ) ; break ;
case 8 : microstep_ms ( driver , MICROSTEP8 ) ; break ;
case 16 : microstep_ms ( driver , MICROSTEP16 ) ; break ;
}
}
2015-03-14 07:28:22 -04:00
void microstep_readings ( ) {
SERIAL_PROTOCOLPGM ( " MS1,MS2 Pins \n " ) ;
SERIAL_PROTOCOLPGM ( " X: " ) ;
SERIAL_PROTOCOL ( digitalRead ( X_MS1_PIN ) ) ;
SERIAL_PROTOCOLLN ( digitalRead ( X_MS2_PIN ) ) ;
SERIAL_PROTOCOLPGM ( " Y: " ) ;
SERIAL_PROTOCOL ( digitalRead ( Y_MS1_PIN ) ) ;
SERIAL_PROTOCOLLN ( digitalRead ( Y_MS2_PIN ) ) ;
SERIAL_PROTOCOLPGM ( " Z: " ) ;
SERIAL_PROTOCOL ( digitalRead ( Z_MS1_PIN ) ) ;
SERIAL_PROTOCOLLN ( digitalRead ( Z_MS2_PIN ) ) ;
SERIAL_PROTOCOLPGM ( " E0: " ) ;
SERIAL_PROTOCOL ( digitalRead ( E0_MS1_PIN ) ) ;
SERIAL_PROTOCOLLN ( digitalRead ( E0_MS2_PIN ) ) ;
2015-04-03 18:31:35 -04:00
# if HAS_MICROSTEPS_E1
2015-03-14 07:28:22 -04:00
SERIAL_PROTOCOLPGM ( " E1: " ) ;
SERIAL_PROTOCOL ( digitalRead ( E1_MS1_PIN ) ) ;
SERIAL_PROTOCOLLN ( digitalRead ( E1_MS2_PIN ) ) ;
# endif
2012-08-30 03:16:57 -04:00
}
2015-03-24 13:06:44 -04:00
# ifdef Z_DUAL_ENDSTOPS
void In_Homing_Process ( bool state ) { performing_homing = state ; }
void Lock_z_motor ( bool state ) { locked_z_motor = state ; }
void Lock_z2_motor ( bool state ) { locked_z2_motor = state ; }
# endif