/*
This file is part of Repetier-Firmware.
Repetier-Firmware 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.
Repetier-Firmware 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 Repetier-Firmware. If not, see .
This firmware is a nearly complete rewrite of the sprinter firmware
by kliment (https://github.com/kliment/Sprinter)
which based on Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware.
Main author: repetier
*/
/**
\mainpage Repetier-Firmware for Arduino based RepRaps
Copyright © 2011-2013 by repetier
\section Intro Introduction
\section GCodes Implemented GCodes
look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html
and http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes
Implemented Codes
- G0 -> G1
- G1 - Coordinated Movement X Y Z E
- G4 - Dwell S or P
- G20 - Units for G0/G1 are inches.
- G21 - Units for G0/G1 are mm.
- G28 - Home all axis or named axis.
- G90 - Use absolute coordinates
- G91 - Use relative coordinates
- G92 - Set current position to cordinates given
RepRap M Codes
- M104 - Set extruder target temp
- M105 - Read current temp
- M106 - Fan on
- M107 - Fan off
- M109 - Wait for extruder current temp to reach target temp.
- M114 - Display current position
Custom M Codes
- M80 - Turn on Power Supply
- M20 - List SD card
- M21 - Init SD card
- M22 - Release SD card
- M23 - Select SD file (M23 filename.g)
- M24 - Start/resume SD print
- M25 - Pause SD print
- M26 - Set SD position in bytes (M26 S12345)
- M27 - Report SD print status
- M28 - Start SD write (M28 filename.g)
- M29 - Stop SD write
- M30 - Delete file on sd card
- M32 create subdirectory
- M42 P S - Change output of pin P to S. Does not work on most important pins.
- M80 - Turn on power supply
- M81 - Turn off power supply
- M82 - Set E codes absolute (default)
- M83 - Set E codes relative while in Absolute Coordinates (G90) mode
- M84 - Disable steppers until next move,
or use S to specify an inactivity timeout, after which the steppers will be disabled. S0 to disable the timeout.
- M85 - Set inactivity shutdown timer with parameter S. To disable set zero (default)
- M92 - Set axis_steps_per_unit - same syntax as G92
- M112 - Emergency kill
- M115- Capabilities string
- M117 - Write message in status row on lcd
- M119 - Report endstop status
- M140 - Set bed target temp
- M190 - Wait for bed current temp to reach target temp.
- M201 - Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000)
- M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000)
- M203 - Set temperture monitor to Sx
- M204 - Set PID parameter X => Kp Y => Ki Z => Kd S Default is current extruder. NUM_EXTRUDER=Heated bed
- M205 - Output EEPROM settings
- M206 - Set EEPROM value
- M220 S - Increase/decrease given feedrate
- M221 S - Increase/decrease given flow rate
- M231 S X Y Z F - Set OPS parameter
- M232 - Read and reset max. advance values
- M233 X Y - Set temporary advance K-value to X and linear term advanceL to Y
- M251 Measure Z steps from homing stop (Delta printers). S0 - Reset, S1 - Print, S2 - Store to Z length (also EEPROM if enabled)
- M303 P S Autodetect pid values. Use P for heated bed.
- M350 S X Y Z E P : Set microstepping on RAMBO board
- M400 - Wait until move buffers empty.
- M401 - Store x, y and z position.
- M402 - Go to stored position. If X, Y or Z is specified, only these coordinates are used. F changes feedrate fo rthat move.
- M500 Store settings to EEPROM
- M501 Load settings from EEPROM
- M502 Reset settings to the one in configuration.h. Does not store values in EEPROM!
- M908 P S : Set stepper current for digipot (RAMBO board)
*/
#include "Reptier.h"
#include "Eeprom.h"
#include "pins_arduino.h"
#include "fastio.h"
#include "ui.h"
#include
#include
#if UI_DISPLAY_TYPE==4
//#include // Uncomment this if you are using liquid crystal library
#endif
// ================ Sanity checks ================
#ifndef STEP_DOUBLER_FREQUENCY
#error Please add new parameter STEP_DOUBLER_FREQUENCY to your configuration.
#else
#if STEP_DOUBLER_FREQUENCY<10000 || STEP_DOUBLER_FREQUENCY>20000
#error STEP_DOUBLER_FREQUENCY should be in range 10000-16000.
#endif
#endif
#ifdef EXTRUDER_SPEED
#error EXTRUDER_SPEED is not used any more. Values are now taken from extruder definition.
#endif
#if MAX_HALFSTEP_INTERVAL<=1900
#error MAX_HALFSTEP_INTERVAL must be greater then 1900
#endif
#ifdef ENDSTOPPULLUPS
#error ENDSTOPPULLUPS is now replaced by individual pullup configuration!
#endif
#ifdef EXT0_PID_PGAIN
#error The PID system has changed. Please use the new float number options!
#endif
// ####################################################################################
// # No configuration below this line - just some errorchecking #
// ####################################################################################
#ifdef SUPPORT_MAX6675
#if !defined SCK_PIN || !defined MOSI_PIN || !defined MISO_PIN
#error For MAX6675 support, you need to define SCK_PIN, MISO_PIN and MOSI_PIN in pins.h
#endif
#endif
#if X_STEP_PIN<0 || Y_STEP_PIN<0 || Z_STEP_PIN<0
#error One of the following pins is not assigned: X_STEP_PIN,Y_STEP_PIN,Z_STEP_PIN
#endif
#if EXT0_STEP_PIN<0 && NUM_EXTRUDER>0
#error EXT0_STEP_PIN not set to a pin number.
#endif
#if EXT0_DIR_PIN<0 && NUM_EXTRUDER>0
#error EXT0_DIR_PIN not set to a pin number.
#endif
#if MOVE_CACHE_SIZE<4
#error MOVE_CACHE_SIZE must be at least 5
#endif
#if DRIVE_SYSTEM==3
#define SIN_60 0.8660254037844386
#define COS_60 0.5
#define DELTA_DIAGONAL_ROD_STEPS (AXIS_STEPS_PER_MM * DELTA_DIAGONAL_ROD)
#define DELTA_DIAGONAL_ROD_STEPS_SQUARED (DELTA_DIAGONAL_ROD_STEPS * DELTA_DIAGONAL_ROD_STEPS)
#define DELTA_ZERO_OFFSET_STEPS (AXIS_STEPS_PER_MM * DELTA_ZERO_OFFSET)
#define DELTA_RADIUS_STEPS (AXIS_STEPS_PER_MM * DELTA_RADIUS)
#define DELTA_TOWER1_X_STEPS -SIN_60*DELTA_RADIUS_STEPS
#define DELTA_TOWER1_Y_STEPS -COS_60*DELTA_RADIUS_STEPS
#define DELTA_TOWER2_X_STEPS SIN_60*DELTA_RADIUS_STEPS
#define DELTA_TOWER2_Y_STEPS -COS_60*DELTA_RADIUS_STEPS
#define DELTA_TOWER3_X_STEPS 0.0
#define DELTA_TOWER3_Y_STEPS DELTA_RADIUS_STEPS
#define NUM_AXIS 4
#define X_AXIS 0
#define Y_AXIS 1
#define Z_AXIS 2
#define E_AXIS 3
#endif
#define OVERFLOW_PERIODICAL (int)(F_CPU/(TIMER0_PRESCALE*40))
// RAM usage of variables: Non RAMPS 114+MOVE_CACHE_SIZE*59+printer_state(32) = 382 Byte with MOVE_CACHE_SIZE=4
// RAM usage RAMPS adds: 96
// RAM usage SD Card:
byte unit_inches = 0; ///< 0 = Units are mm, 1 = units are inches.
//Stepper Movement Variables
float axis_steps_per_unit[4] = {XAXIS_STEPS_PER_MM,YAXIS_STEPS_PER_MM,ZAXIS_STEPS_PER_MM,1}; ///< Number of steps per mm needed.
float inv_axis_steps_per_unit[4]; ///< Inverse of axis_steps_per_unit for faster conversion
float max_feedrate[4] = {MAX_FEEDRATE_X, MAX_FEEDRATE_Y, MAX_FEEDRATE_Z}; ///< Maximum allowed feedrate.
float homing_feedrate[3] = {HOMING_FEEDRATE_X, HOMING_FEEDRATE_Y, HOMING_FEEDRATE_Z};
byte STEP_PIN[3] = {X_STEP_PIN, Y_STEP_PIN, Z_STEP_PIN};
#ifdef RAMP_ACCELERATION
// float max_start_speed_units_per_second[4] = MAX_START_SPEED_UNITS_PER_SECOND; ///< Speed we can use, without acceleration.
long max_acceleration_units_per_sq_second[4] = {MAX_ACCELERATION_UNITS_PER_SQ_SECOND_X,MAX_ACCELERATION_UNITS_PER_SQ_SECOND_Y,MAX_ACCELERATION_UNITS_PER_SQ_SECOND_Z}; ///< X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts
long max_travel_acceleration_units_per_sq_second[4] = {MAX_TRAVEL_ACCELERATION_UNITS_PER_SQ_SECOND_X,MAX_TRAVEL_ACCELERATION_UNITS_PER_SQ_SECOND_Y,MAX_TRAVEL_ACCELERATION_UNITS_PER_SQ_SECOND_Z}; ///< X, Y, Z max acceleration in mm/s^2 for travel moves
/** Acceleration in steps/s^3 in printing mode.*/
unsigned long axis_steps_per_sqr_second[4];
/** Acceleration in steps/s^2 in movement mode.*/
unsigned long axis_travel_steps_per_sqr_second[4];
#endif
#if DRIVE_SYSTEM==3
DeltaSegment segments[DELTA_CACHE_SIZE];
unsigned int delta_segment_write_pos = 0; // Position where we write the next cached delta move
volatile unsigned int delta_segment_count = 0; // Number of delta moves cached 0 = nothing in cache
byte lastMoveID = 0; // Last move ID
#endif
PrinterState printer_state;
byte relative_mode = false; ///< Determines absolute (false) or relative Coordinates (true).
byte relative_mode_e = false; ///< Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode.
byte debug_level = 6; ///< Bitfield defining debug output. 1 = echo, 2 = info, 4 = error, 8 = dry run., 16 = Only communication, 32 = No moves
//Inactivity shutdown variables
unsigned long previous_millis_cmd = 0;
unsigned long max_inactive_time = MAX_INACTIVE_TIME*1000L;
unsigned long stepper_inactive_time = STEPPER_INACTIVE_TIME*1000L;
PrintLine lines[MOVE_CACHE_SIZE]; ///< Cache for print moves.
PrintLine *cur = 0; ///< Current printing line
byte lines_write_pos=0; ///< Position where we write the next cached line move.
volatile byte lines_count=0; ///< Number of lines cached 0 = nothing to do.
byte lines_pos=0; ///< Position for executing line movement.
long baudrate = BAUDRATE; ///< Communication speed rate.
#ifdef USE_ADVANCE
#ifdef ENABLE_QUADRATIC_ADVANCE
int maxadv=0;
#endif
int maxadv2=0;
float maxadvspeed=0;
#endif
byte pwm_pos[NUM_EXTRUDER+3]; // 0-NUM_EXTRUDER = Heater 0-NUM_EXTRUDER of extruder, NUM_EXTRUDER = Heated bed, NUM_EXTRUDER+1 Board fan, NUM_EXTRUDER+2 = Fan
int waitRelax=0; // Delay filament relax at the end of print, could be a simple timeout
#ifdef USE_OPS
byte printmoveSeen=0;
#endif
#ifdef DEBUG_FREE_MEMORY
int lowest_ram=16384;
int lowest_send=16384;
void check_mem() {
BEGIN_INTERRUPT_PROTECTED
uint8_t * heapptr, * stackptr;
heapptr = (uint8_t *)malloc(4); // get heap pointer
free(heapptr); // free up the memory again (sets heapptr to 0)
stackptr = (uint8_t *)(SP); // save value of stack pointer
int newfree = (int)stackptr-(int)heapptr;
if(newfreelowest_ram) {
lowest_send = lowest_ram;
out.println_int_P(PSTR("Free RAM:"),lowest_ram);
}
}
#endif
void update_extruder_flags() {
printer_state.flag0 &= ~PRINTER_FLAG0_SEPERATE_EXTRUDER_INT;
#if USE_OPS==1
if(printer_state.opsMode!=0) {
printer_state.flag0 |= PRINTER_FLAG0_SEPERATE_EXTRUDER_INT;
}
#endif
#if defined(USE_ADVANCE)
for(byte i=0;ipin assignments
#if ANALYZER_CH0>=0
SET_OUTPUT(ANALYZER_CH0);
#endif
#if ANALYZER_CH1>=0
SET_OUTPUT(ANALYZER_CH1);
#endif
#if ANALYZER_CH2>=0
SET_OUTPUT(ANALYZER_CH2);
#endif
#if ANALYZER_CH3>=0
SET_OUTPUT(ANALYZER_CH3);
#endif
#if ANALYZER_CH4>=0
SET_OUTPUT(ANALYZER_CH4);
#endif
#if ANALYZER_CH5>=0
SET_OUTPUT(ANALYZER_CH5);
#endif
#if ANALYZER_CH6>=0
SET_OUTPUT(ANALYZER_CH6);
#endif
#if ANALYZER_CH7>=0
SET_OUTPUT(ANALYZER_CH7);
#endif
#endif
#if defined(ENABLE_POWER_ON_STARTUP) && PS_ON_PIN>-1
SET_OUTPUT(PS_ON_PIN); //GND
WRITE(PS_ON_PIN, LOW);
#endif
//Initialize Step Pins
SET_OUTPUT(X_STEP_PIN);
SET_OUTPUT(Y_STEP_PIN);
SET_OUTPUT(Z_STEP_PIN);
//Initialize Dir Pins
#if X_DIR_PIN>-1
SET_OUTPUT(X_DIR_PIN);
#endif
#if Y_DIR_PIN>-1
SET_OUTPUT(Y_DIR_PIN);
#endif
#if Z_DIR_PIN>-1
SET_OUTPUT(Z_DIR_PIN);
#endif
//Steppers default to disabled.
#if X_ENABLE_PIN > -1
if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH);
SET_OUTPUT(X_ENABLE_PIN);
#endif
#if Y_ENABLE_PIN > -1
if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH);
SET_OUTPUT(Y_ENABLE_PIN);
#endif
#if Z_ENABLE_PIN > -1
if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH);
SET_OUTPUT(Z_ENABLE_PIN);
#endif
//endstop pullups
#if X_MIN_PIN>-1 && MIN_HARDWARE_ENDSTOP_X
SET_INPUT(X_MIN_PIN);
#if ENDSTOP_PULLUP_X_MIN
WRITE(X_MIN_PIN,HIGH);
#endif
#endif
#if Y_MIN_PIN>-1 && MIN_HARDWARE_ENDSTOP_Y
SET_INPUT(Y_MIN_PIN);
#if ENDSTOP_PULLUP_Y_MIN
WRITE(Y_MIN_PIN,HIGH);
#endif
#endif
#if Z_MIN_PIN>-1 && MIN_HARDWARE_ENDSTOP_Z
SET_INPUT(Z_MIN_PIN);
#if ENDSTOP_PULLUP_Z_MIN
WRITE(Z_MIN_PIN,HIGH);
#endif
#endif
#if X_MAX_PIN>-1 && MAX_HARDWARE_ENDSTOP_X
SET_INPUT(X_MAX_PIN);
#if ENDSTOP_PULLUP_X_MAX
WRITE(X_MAX_PIN,HIGH);
#endif
#endif
#if Y_MAX_PIN>-1 && MAX_HARDWARE_ENDSTOP_Y
SET_INPUT(Y_MAX_PIN);
#if ENDSTOP_PULLUP_Y_MAX
WRITE(Y_MAX_PIN,HIGH);
#endif
#endif
#if Z_MAX_PIN>-1 && MAX_HARDWARE_ENDSTOP_Z
SET_INPUT(Z_MAX_PIN);
#if ENDSTOP_PULLUP_Z_MAX
WRITE(Z_MAX_PIN,HIGH);
#endif
#endif
#if FAN_PIN>-1
SET_OUTPUT(FAN_PIN);
WRITE(FAN_PIN,LOW);
#endif
#if FAN_BOARD_PIN>-1
SET_OUTPUT(FAN_BOARD_PIN);
WRITE(FAN_BOARD_PIN,LOW);
#endif
#if EXT0_HEATER_PIN>-1
SET_OUTPUT(EXT0_HEATER_PIN);
WRITE(EXT0_HEATER_PIN,LOW);
#endif
#if defined(EXT1_HEATER_PIN) && EXT1_HEATER_PIN>-1
SET_OUTPUT(EXT1_HEATER_PIN);
WRITE(EXT1_HEATER_PIN,LOW);
#endif
#if defined(EXT2_HEATER_PIN) && EXT2_HEATER_PIN>-1
SET_OUTPUT(EXT2_HEATER_PIN);
WRITE(EXT2_HEATER_PIN,LOW);
#endif
#if defined(EXT3_HEATER_PIN) && EXT3_HEATER_PIN>-1
SET_OUTPUT(EXT3_HEATER_PIN);
WRITE(EXT3_HEATER_PIN,LOW);
#endif
#if defined(EXT4_HEATER_PIN) && EXT4_HEATER_PIN>-1
SET_OUTPUT(EXT4_HEATER_PIN);
WRITE(EXT4_HEATER_PIN,LOW);
#endif
#if defined(EXT5_HEATER_PIN) && EXT5_HEATER_PIN>-1
SET_OUTPUT(EXT5_HEATER_PIN);
WRITE(EXT5_HEATER_PIN,LOW);
#endif
#ifdef XY_GANTRY
printer_state.motorX = 0;
printer_state.motorY = 0;
#endif
#if STEPPER_CURRENT_CONTROL!=CURRENT_CONTROL_MANUAL
current_control_init(); // Set current if it is firmware controlled
#endif
microstep_init();
#if USE_OPS==1
printer_state.opsMode = OPS_MODE;
printer_state.opsMinDistance = OPS_MIN_DISTANCE;
printer_state.opsRetractDistance = OPS_RETRACT_DISTANCE;
printer_state.opsRetractBacklash = OPS_RETRACT_BACKLASH;
printer_state.filamentRetracted = false;
#endif
printer_state.feedrate = 50; ///< Current feedrate in mm/s.
printer_state.feedrateMultiply = 100;
printer_state.extrudeMultiply = 100;
#ifdef USE_ADVANCE
#ifdef ENABLE_QUADRATIC_ADVANCE
printer_state.advance_executed = 0;
#endif
printer_state.advance_steps_set = 0;
printer_state.advance_lin_set = 0;
#endif
for(byte i=0;i max_inactive_time ) kill(false);
if(stepper_inactive_time!=0 && (curtime-previous_millis_cmd) > stepper_inactive_time ) { kill(true); }
#if defined(SDCARDDETECT) && SDCARDDETECT>-1 && defined(SDSUPPORT) && SDSUPPORT
sd.automount();
#endif
//void finishNextSegment();
DEBUG_MEMORY;
}
/**
Main processing loop. It checks perodically for new commands, checks temperatures
and executes new incoming commands.
*/
void loop()
{
gcode_read_serial();
GCode *code = gcode_next_command();
//UI_SLOW; // do longer timed user interface action
UI_MEDIUM; // do check encoder
if(code){
#if SDSUPPORT
if(sd.savetosd){
if(!(GCODE_HAS_M(code) && code->M==29)) { // still writing to file
sd.write_command(code);
} else {
sd.finishWrite();
}
#ifdef ECHO_ON_EXECUTE
if(DEBUG_ECHO) {
OUT_P("Echo:");
gcode_print_command(code);
out.println();
}
#endif
gcode_command_finished(code);
} else {
process_command(code,true);
}
#else
process_command(code,true);
#endif
}
defaultLoopActions();
}
/** \brief Optimized division
Normally the C compiler will compute a long/long division, which takes ~670 Ticks.
This version is optimized for a 16 bit dividend and recognises the special cases
of a 24 bit and 16 bit dividend, which offen, but not always occur in updating the
interval.
*/
inline long Div4U2U(unsigned long a,unsigned int b) {
#if CPU_ARCH==ARCH_AVR
// r14/r15 remainder
// r16 counter
__asm__ __volatile__ (
"clr r14 \n\t"
"sub r15,r15 \n\t"
"tst %D0 \n\t"
"brne do32%= \n\t"
"tst %C0 \n\t"
"breq donot24%= \n\t"
"rjmp do24%= \n\t"
"donot24%=:" "ldi r16,17 \n\t" // 16 Bit divide
"d16u_1%=:" "rol %A0 \n\t"
"rol %B0 \n\t"
"dec r16 \n\t"
"brne d16u_2%= \n\t"
"rjmp end%= \n\t"
"d16u_2%=:" "rol r14 \n\t"
"rol r15 \n\t"
"sub r14,%A2 \n\t"
"sbc r15,%B2 \n\t"
"brcc d16u_3%= \n\t"
"add r14,%A2 \n\t"
"adc r15,%B2 \n\t"
"clc \n\t"
"rjmp d16u_1%= \n\t"
"d16u_3%=:" "sec \n\t"
"rjmp d16u_1%= \n\t"
"do32%=:" // divide full 32 bit
"rjmp do32B%= \n\t"
"do24%=:" // divide 24 bit
"ldi r16,25 \n\t" // 24 Bit divide
"d24u_1%=:" "rol %A0 \n\t"
"rol %B0 \n\t"
"rol %C0 \n\t"
"dec r16 \n\t"
"brne d24u_2%= \n\t"
"rjmp end%= \n\t"
"d24u_2%=:" "rol r14 \n\t"
"rol r15 \n\t"
"sub r14,%A2 \n\t"
"sbc r15,%B2 \n\t"
"brcc d24u_3%= \n\t"
"add r14,%A2 \n\t"
"adc r15,%B2 \n\t"
"clc \n\t"
"rjmp d24u_1%= \n\t"
"d24u_3%=:" "sec \n\t"
"rjmp d24u_1%= \n\t"
"do32B%=:" // divide full 32 bit
"ldi r16,33 \n\t" // 32 Bit divide
"d32u_1%=:" "rol %A0 \n\t"
"rol %B0 \n\t"
"rol %C0 \n\t"
"rol %D0 \n\t"
"dec r16 \n\t"
"brne d32u_2%= \n\t"
"rjmp end%= \n\t"
"d32u_2%=:" "rol r14 \n\t"
"rol r15 \n\t"
"sub r14,%A2 \n\t"
"sbc r15,%B2 \n\t"
"brcc d32u_3%= \n\t"
"add r14,%A2 \n\t"
"adc r15,%B2 \n\t"
"clc \n\t"
"rjmp d32u_1%= \n\t"
"d32u_3%=:" "sec \n\t"
"rjmp d32u_1%= \n\t"
"end%=:" // end
:"=&r"(a)
:"0"(a),"r"(b)
:"r14","r15","r16"
);
return a;
#else
return a/b;
#endif
}
const uint16_t fast_div_lut[17] PROGMEM = {0,F_CPU/4096,F_CPU/8192,F_CPU/12288,F_CPU/16384,F_CPU/20480,F_CPU/24576,F_CPU/28672,F_CPU/32768,F_CPU/36864
,F_CPU/40960,F_CPU/45056,F_CPU/49152,F_CPU/53248,F_CPU/57344,F_CPU/61440,F_CPU/65536};
const uint16_t slow_div_lut[257] PROGMEM = {0,F_CPU/32,F_CPU/64,F_CPU/96,F_CPU/128,F_CPU/160,F_CPU/192,F_CPU/224,F_CPU/256,F_CPU/288,F_CPU/320,F_CPU/352
,F_CPU/384,F_CPU/416,F_CPU/448,F_CPU/480,F_CPU/512,F_CPU/544,F_CPU/576,F_CPU/608,F_CPU/640,F_CPU/672,F_CPU/704,F_CPU/736,F_CPU/768,F_CPU/800,F_CPU/832
,F_CPU/864,F_CPU/896,F_CPU/928,F_CPU/960,F_CPU/992,F_CPU/1024,F_CPU/1056,F_CPU/1088,F_CPU/1120,F_CPU/1152,F_CPU/1184,F_CPU/1216,F_CPU/1248,F_CPU/1280,F_CPU/1312
,F_CPU/1344,F_CPU/1376,F_CPU/1408,F_CPU/1440,F_CPU/1472,F_CPU/1504,F_CPU/1536,F_CPU/1568,F_CPU/1600,F_CPU/1632,F_CPU/1664,F_CPU/1696,F_CPU/1728,F_CPU/1760,F_CPU/1792
,F_CPU/1824,F_CPU/1856,F_CPU/1888,F_CPU/1920,F_CPU/1952,F_CPU/1984,F_CPU/2016
,F_CPU/2048,F_CPU/2080,F_CPU/2112,F_CPU/2144,F_CPU/2176,F_CPU/2208,F_CPU/2240,F_CPU/2272,F_CPU/2304,F_CPU/2336,F_CPU/2368,F_CPU/2400
,F_CPU/2432,F_CPU/2464,F_CPU/2496,F_CPU/2528,F_CPU/2560,F_CPU/2592,F_CPU/2624,F_CPU/2656,F_CPU/2688,F_CPU/2720,F_CPU/2752,F_CPU/2784,F_CPU/2816,F_CPU/2848,F_CPU/2880
,F_CPU/2912,F_CPU/2944,F_CPU/2976,F_CPU/3008,F_CPU/3040,F_CPU/3072,F_CPU/3104,F_CPU/3136,F_CPU/3168,F_CPU/3200,F_CPU/3232,F_CPU/3264,F_CPU/3296,F_CPU/3328,F_CPU/3360
,F_CPU/3392,F_CPU/3424,F_CPU/3456,F_CPU/3488,F_CPU/3520,F_CPU/3552,F_CPU/3584,F_CPU/3616,F_CPU/3648,F_CPU/3680,F_CPU/3712,F_CPU/3744,F_CPU/3776,F_CPU/3808,F_CPU/3840
,F_CPU/3872,F_CPU/3904,F_CPU/3936,F_CPU/3968,F_CPU/4000,F_CPU/4032,F_CPU/4064
,F_CPU/4096,F_CPU/4128,F_CPU/4160,F_CPU/4192,F_CPU/4224,F_CPU/4256,F_CPU/4288,F_CPU/4320,F_CPU/4352,F_CPU/4384,F_CPU/4416,F_CPU/4448,F_CPU/4480,F_CPU/4512,F_CPU/4544
,F_CPU/4576,F_CPU/4608,F_CPU/4640,F_CPU/4672,F_CPU/4704,F_CPU/4736,F_CPU/4768,F_CPU/4800,F_CPU/4832,F_CPU/4864,F_CPU/4896,F_CPU/4928,F_CPU/4960,F_CPU/4992,F_CPU/5024
,F_CPU/5056,F_CPU/5088,F_CPU/5120,F_CPU/5152,F_CPU/5184,F_CPU/5216,F_CPU/5248,F_CPU/5280,F_CPU/5312,F_CPU/5344,F_CPU/5376,F_CPU/5408,F_CPU/5440,F_CPU/5472,F_CPU/5504
,F_CPU/5536,F_CPU/5568,F_CPU/5600,F_CPU/5632,F_CPU/5664,F_CPU/5696,F_CPU/5728,F_CPU/5760,F_CPU/5792,F_CPU/5824,F_CPU/5856,F_CPU/5888,F_CPU/5920,F_CPU/5952,F_CPU/5984
,F_CPU/6016,F_CPU/6048,F_CPU/6080,F_CPU/6112,F_CPU/6144,F_CPU/6176,F_CPU/6208,F_CPU/6240,F_CPU/6272,F_CPU/6304,F_CPU/6336,F_CPU/6368,F_CPU/6400,F_CPU/6432,F_CPU/6464
,F_CPU/6496,F_CPU/6528,F_CPU/6560,F_CPU/6592,F_CPU/6624,F_CPU/6656,F_CPU/6688,F_CPU/6720,F_CPU/6752,F_CPU/6784,F_CPU/6816,F_CPU/6848,F_CPU/6880,F_CPU/6912,F_CPU/6944
,F_CPU/6976,F_CPU/7008,F_CPU/7040,F_CPU/7072,F_CPU/7104,F_CPU/7136,F_CPU/7168,F_CPU/7200,F_CPU/7232,F_CPU/7264,F_CPU/7296,F_CPU/7328,F_CPU/7360,F_CPU/7392,F_CPU/7424
,F_CPU/7456,F_CPU/7488,F_CPU/7520,F_CPU/7552,F_CPU/7584,F_CPU/7616,F_CPU/7648,F_CPU/7680,F_CPU/7712,F_CPU/7744,F_CPU/7776,F_CPU/7808,F_CPU/7840,F_CPU/7872,F_CPU/7904
,F_CPU/7936,F_CPU/7968,F_CPU/8000,F_CPU/8032,F_CPU/8064,F_CPU/8096,F_CPU/8128,F_CPU/8160,F_CPU/8192
};
/** \brief approximates division of F_CPU/divisor
In the stepper interrupt a division is needed, which is a slow operation.
The result is used for timer calculation where small errors are ok. This
function uses lookup tables to find a fast approximation of the result.
*/
long CPUDivU2(unsigned int divisor) {
#if CPU_ARCH==ARCH_AVR
long res;
unsigned short table;
if(divisor<8192) {
if(divisor<512) {
if(divisor<10) divisor = 10;
return Div4U2U(F_CPU,divisor); // These entries have overflows in lookuptable!
}
table = (unsigned short)&slow_div_lut[0];
__asm__ __volatile__( // needs 64 ticks neu 49 Ticks
"mov r18,%A1 \n\t"
"andi r18,31 \n\t" // divisor & 31 in r18
"lsr %B1 \n\t" // divisor >> 4
"ror %A1 \n\t"
"lsr %B1 \n\t"
"ror %A1 \n\t"
"lsr %B1 \n\t"
"ror %A1 \n\t"
"lsr %B1 \n\t"
"ror %A1 \n\t"
"andi %A1,254 \n\t"
"add %A2,%A1 \n\t" // table+divisor>>3
"adc %B2,%B1 \n\t"
"lpm %A0,Z+ \n\t" // y0 in res
"lpm %B0,Z+ \n\t" // %C0,%D0 are 0
"movw r4,%A0 \n\t" // y0 nach gain (r4-r5)
"lpm r0,Z+ \n\t" // gain = gain-y1
"sub r4,r0 \n\t"
"lpm r0,Z+ \n\t"
"sbc r5,r0 \n\t"
"mul r18,r4 \n\t" // gain*(divisor & 31)
"movw %A1,r0 \n\t" // divisor not needed any more, use for byte 0,1 of result
"mul r18,r5 \n\t"
"add %B1,r0 \n\t"
"mov %A2,r1 \n\t"
"lsl %A1 \n\t"
"rol %B1 \n\t"
"rol %A2 \n\t"
"lsl %A1 \n\t"
"rol %B1 \n\t"
"rol %A2 \n\t"
"lsl %A1 \n\t"
"rol %B1 \n\t"
"rol %A2 \n\t"
"sub %A0,%B1 \n\t"
"sbc %B0,%A2 \n\t"
"clr %C0 \n\t"
"clr %D0 \n\t"
"clr r1 \n\t"
: "=&r" (res),"=&d"(divisor),"=&z"(table) : "1"(divisor),"2"(table) : "r18","r4","r5");
return res;
/*unsigned short adr0 = (unsigned short)&slow_div_lut+(divisor>>4)&1022;
long y0= pgm_read_dword_near(adr0);
long gain = y0-pgm_read_dword_near(adr0+2);
return y0-((gain*(divisor & 31))>>5);*/
} else {
table = (unsigned short)&fast_div_lut[0];
__asm__ __volatile__( // needs 49 ticks
"movw r18,%A1 \n\t"
"andi r19,15 \n\t" // divisor & 4095 in r18,r19
"lsr %B1 \n\t" // divisor >> 3, then %B1 is 2*(divisor >> 12)
"lsr %B1 \n\t"
"lsr %B1 \n\t"
"andi %B1,254 \n\t"
"add %A2,%B1 \n\t" // table+divisor>>11
"adc %B2,r1 \n\t" //
"lpm %A0,Z+ \n\t" // y0 in res
"lpm %B0,Z+ \n\t"
"movw r4,%A0 \n\t" // y0 to gain (r4-r5)
"lpm r0,Z+ \n\t" // gain = gain-y1
"sub r4,r0 \n\t"
"lpm r0,Z+ \n\t"
"sbc r5,r0 \n\t" // finished - result has max. 16 bit
"mul r18,r4 \n\t" // gain*(divisor & 4095)
"movw %A1,r0 \n\t" // divisor not needed any more, use for byte 0,1 of result
"mul r19,r5 \n\t"
"mov %A2,r0 \n\t" // %A2 = byte 3 of result
"mul r18,r5 \n\t"
"add %B1,r0 \n\t"
"adc %A2,r1 \n\t"
"mul r19,r4 \n\t"
"add %B1,r0 \n\t"
"adc %A2,r1 \n\t"
"andi %B1,240 \n\t" // >> 12
"swap %B1 \n\t"
"swap %A2 \r\n"
"mov %A1,%A2 \r\n"
"andi %A1,240 \r\n"
"or %B1,%A1 \r\n"
"andi %A2,15 \r\n"
"sub %A0,%B1 \n\t"
"sbc %B0,%A2 \n\t"
"clr %C0 \n\t"
"clr %D0 \n\t"
"clr r1 \n\t"
: "=&r" (res),"=&d"(divisor),"=&z"(table) : "1"(divisor),"2"(table) : "r18","r19","r4","r5");
return res;
/*
// The asm mimics the following code
unsigned short adr0 = (unsigned short)&fast_div_lut+(divisor>>11)&254;
unsigned short y0= pgm_read_word_near(adr0);
unsigned short gain = y0-pgm_read_word_near(adr0+2);
return y0-(((long)gain*(divisor & 4095))>>12);*/
#else
return F_CPU/divisor;
#endif
}
}
/**
\brief Sets the destination coordinates to values stored in com.
For the computation of the destination, the following facts are considered:
- Are units inches or mm.
- Reltive or absolute positioning with special case only extruder relative.
- Offset in x and y direction for multiple extruder support.
*/
byte get_coordinates(GCode *com)
{
register long p;
register byte r=0;
if(lines_count==0) {
UI_STATUS(UI_TEXT_PRINTING);
}
if(GCODE_HAS_X(com)) {
r = 1;
if(unit_inches)
p = com->X*25.4*axis_steps_per_unit[0];
else
p = com->X*axis_steps_per_unit[0];
if(relative_mode)
printer_state.destinationSteps[0] = printer_state.currentPositionSteps[0]+p;
else
printer_state.destinationSteps[0] = p+printer_state.offsetX;
} else printer_state.destinationSteps[0] = printer_state.currentPositionSteps[0];
if(GCODE_HAS_Y(com)) {
r = 1;
if(unit_inches)
p = com->Y*25.4*axis_steps_per_unit[1];
else
p = com->Y*axis_steps_per_unit[1];
if(relative_mode)
printer_state.destinationSteps[1] = printer_state.currentPositionSteps[1]+p;
else
printer_state.destinationSteps[1] = p+printer_state.offsetY;
} else printer_state.destinationSteps[1] = printer_state.currentPositionSteps[1];
if(GCODE_HAS_Z(com)) {
r = 1;
if(unit_inches)
p = com->Z*25.4*axis_steps_per_unit[2];
else
p = com->Z*axis_steps_per_unit[2];
if(relative_mode) {
printer_state.destinationSteps[2] = printer_state.currentPositionSteps[2]+p;
} else {
printer_state.destinationSteps[2] = p;
}
} else printer_state.destinationSteps[2] = printer_state.currentPositionSteps[2];
if(GCODE_HAS_E(com) && !DEBUG_DRYRUN) {
if(unit_inches)
p = com->E*25.4*axis_steps_per_unit[3];
else
p = com->E*axis_steps_per_unit[3];
if(relative_mode || relative_mode_e)
printer_state.destinationSteps[3] = printer_state.currentPositionSteps[3]+p;
else
printer_state.destinationSteps[3] = p;
} else printer_state.destinationSteps[3] = printer_state.currentPositionSteps[3];
if(GCODE_HAS_F(com)) {
if(com->F < 1)
printer_state.feedrate = 1;
else
if(unit_inches)
printer_state.feedrate = com->F*0.0042333f*(float)printer_state.feedrateMultiply; // Factor is 25.5/60/100
else
printer_state.feedrate = com->F*(float)printer_state.feedrateMultiply*0.00016666666f;
}
return r || (GCODE_HAS_E(com) && printer_state.destinationSteps[3]!=printer_state.currentPositionSteps[3]); // ignore unproductive moves
}
inline unsigned int ComputeV(long timer,long accel) {
#if CPU_ARCH==ARCH_AVR
unsigned int res;
// 38 Ticks
__asm__ __volatile__ ( // 0 = res, 1 = timer, 2 = accel %D2=0 ,%A1 are unused is free
// Result LSB first: %A0, %B0, %A1
"mul %B1,%A2 \n\t"
"mov %A0,r1 \n\t"
"mul %B1,%C2 \n\t"
"mov %B0,r0 \n\t"
"mov %A1,r1 \n\t"
"mul %B1,%B2 \n\t"
"add %A0,r0 \n\t"
"adc %B0,r1 \n\t"
"adc %A1,%D2 \n\t"
"mul %C1,%A2 \n\t"
"add %A0,r0 \n\t"
"adc %B0,r1 \n\t"
"adc %A1,%D2 \n\t"
"mul %C1,%B2 \n\t"
"add %B0,r0 \n\t"
"adc %A1,r1 \n\t"
"mul %D1,%A2 \n\t"
"add %B0,r0 \n\t"
"adc %A1,r1 \n\t"
"mul %C1,%C2 \n\t"
"add %A1,r0 \n\t"
"mul %D1,%B2 \n\t"
"add %A1,r0 \n\t"
"lsr %A1 \n\t"
"ror %B0 \n\t"
"ror %A0 \n\t"
"lsr %A1 \n\t"
"ror %B0 \n\t"
"ror %A0 \n\t"
"clr r1 \n\t"
:"=&r"(res),"=r"(timer),"=r"(accel)
:"1"(timer),"2"(accel)
: );
// unsigned int v = ((timer>>8)*cur->accel)>>10;
return res;
#else
return ((timer>>8)*accel)>>10;
#endif
}
// Multiply two 16 bit values and return 32 bit result
inline unsigned long mulu6xu16to32(unsigned int a,unsigned int b) {
unsigned long res;
// 18 Ticks = 1.125 us
__asm__ __volatile__ ( // 0 = res, 1 = timer, 2 = accel %D2=0 ,%A1 are unused is free
// Result LSB first: %A0, %B0, %A1
"clr r18 \n\t"
"mul %B2,%B1 \n\t" // mul hig bytes
"movw %C0,r0 \n\t"
"mul %A1,%A2 \n\t" // mul low bytes
"movw %A0,r0 \n\t"
"mul %A1,%B2 \n\t"
"add %B0,r0 \n\t"
"adc %C0,r1 \n\t"
"adc %D0,r18 \n\t"
"mul %B1,%A2 \n\t"
"add %B0,r0 \n\t"
"adc %C0,r1 \n\t"
"adc %D0,r18 \n\t"
"clr r1 \n\t"
:"=&r"(res),"=r"(a),"=r"(b)
:"1"(a),"2"(b)
:"r18" );
// return (long)a*b;
return res;
}
// Multiply two 16 bit values and return 32 bit result
inline unsigned int mulu6xu16shift16(unsigned int a,unsigned int b) {
#if CPU_ARCH==ARCH_AVR
unsigned int res;
// 18 Ticks = 1.125 us
__asm__ __volatile__ ( // 0 = res, 1 = timer, 2 = accel %D2=0 ,%A1 are unused is free
// Result LSB first: %A0, %B0, %A1
"clr r18 \n\t"
"mul %B2,%B1 \n\t" // mul hig bytes
"movw %A0,r0 \n\t"
"mul %A1,%A2 \n\t" // mul low bytes
"mov r19,r1 \n\t"
"mul %A1,%B2 \n\t"
"add r19,r0 \n\t"
"adc %A0,r1 \n\t"
"adc %B0,r18 \n\t"
"mul %B1,%A2 \n\t"
"add r19,r0 \n\t"
"adc %A0,r1 \n\t"
"adc %B0,r18 \n\t"
"clr r1 \n\t"
:"=&r"(res),"=r"(a),"=r"(b)
:"1"(a),"2"(b)
:"r18","r19" );
return res;
#else
return ((long)a*b)>>16;
#endif
}
/**
Moves the stepper motors one step. If the last step is reached, the next movement is started.
The function must be called from a timer loop. It returns the time for the next call.
This is a modified version that implements a bresenham 'multi-step' algorithm where the dominant
cartesian axis steps may be less than the changing dominant delta axis.
*/
#if DRIVE_SYSTEM==3
int lastblk=-1;
long cur_errupd;
//#define DEBUG_DELTA_TIMER
// Current delta segment
DeltaSegment *curd;
// Current delta segment primary error increment
long curd_errupd, stepsPerSegRemaining;
inline long bresenham_step() {
if(cur == 0) {
sei();
cur = &lines[lines_pos];
if(cur->flags & FLAG_BLOCKED) { // This step is in computation - shouldn't happen
if(lastblk!=(int)cur) {
lastblk = (int)cur;
out.println_int_P(PSTR("BLK "),(unsigned int)lines_count);
}
cur = 0;
return 2000;
}
lastblk = -1;
#ifdef INCLUDE_DEBUG_NO_MOVE
if(DEBUG_NO_MOVES) { // simulate a move, but do nothing in reality
lines_pos++;
if(lines_pos>=MOVE_CACHE_SIZE) lines_pos=0;
cur = 0;
cli();
--lines_count;
return 1000;
}
#endif
if(cur->flags & FLAG_WARMUP) {
// This is a warmup move to initalize the path planner correctly. Just waste
// a bit of time to get the planning up to date.
#if USE_OPS==1
if(cur->joinFlags & FLAG_JOIN_END_RETRACT) { // Make sure filament is pushed back
if(printer_state.filamentRetracted) {
#ifdef DEBUG_OPS
//sei();
out.println_P(PSTR("DownW"));
cli();
#endif
printer_state.filamentRetracted = false;
printer_state.extruderStepsNeeded+=printer_state.opsPushbackSteps;
}
if(printer_state.extruderStepsNeeded) {
cur = 0;
return 2000; // wait, work is done in other interrupt
}
} else if(cur->joinFlags & FLAG_JOIN_START_RETRACT) {
if(!printer_state.filamentRetracted) {
#ifdef DEBUG_OPS
//sei();
out.println_P(PSTR("UpW"));
cli();
#endif
printer_state.filamentRetracted = true;
cli();
printer_state.extruderStepsNeeded-=printer_state.opsRetractSteps;
cur->joinFlags |= FLAG_JOIN_WAIT_EXTRUDER_UP;
}
if(printer_state.extruderStepsNeeded) {
cur = 0;
return 2000; // wait, work is done in other interrupt
}
}
#endif
if(lines_count<=cur->primaryAxis) { cur=0;return 2000;}
lines_pos++;
if(lines_pos>=MOVE_CACHE_SIZE) lines_pos=0;
long wait = cur->accelerationPrim;
cur = 0;
--lines_count;
return(wait); // waste some time for path optimization to fill up
} // End if WARMUP
if(cur->dir & 128) extruder_enable();
cur->joinFlags |= FLAG_JOIN_END_FIXED | FLAG_JOIN_START_FIXED; // don't touch this segment any more, just for safety
#if USE_OPS==1
if(printer_state.opsMode) { // Enabled?
if(cur->joinFlags & FLAG_JOIN_START_RETRACT) {
if(!printer_state.filamentRetracted) {
#ifdef DEBUG_OPS
out.println_P(PSTR("Up"));
#endif
printer_state.filamentRetracted = true;
cli();
printer_state.extruderStepsNeeded-=printer_state.opsRetractSteps;
sei();
cur->joinFlags |= FLAG_JOIN_WAIT_EXTRUDER_UP;
}
}
// If path optimizer ran out of samples, he might miss some retractions. Solve them before printing
else if((cur->joinFlags & FLAG_JOIN_NO_RETRACT)==0 && printmoveSeen) {
if((cur->dir & 136)==136) {
if(printer_state.filamentRetracted) { // Printmove and filament is still up!
#ifdef DEBUG_OPS
out.println_P(PSTR("DownA"));
#endif
printer_state.filamentRetracted = false;
cli();
printer_state.extruderStepsNeeded+=printer_state.opsPushbackSteps;
cur->joinFlags |= FLAG_JOIN_WAIT_EXTRUDER_DOWN;
}
} /*else if(!printer_state.filamentRetracted) {
#ifdef DEBUG_OPS
out.println_P(PSTR("UpA"));
#endif
printer_state.filamentRetracted = true;
cli();
printer_state.extruderStepsNeeded-=printer_state.opsRetractSteps;
cur->joinFlags |= FLAG_JOIN_WAIT_EXTRUDER_UP;
}*/
}
if(cur->joinFlags & FLAG_JOIN_WAIT_EXTRUDER_UP) { // Wait for filament pushback
cli();
if(printer_state.extruderStepsNeededjoinFlags & FLAG_JOIN_WAIT_EXTRUDER_DOWN) { // Wait for filament pushback
cli();
if(printer_state.extruderStepsNeeded) {
cur=0;
return 4000;
}
}
} // End if opsMode
#endif
sei(); // Allow interrupts
// Set up delta segments
if (cur->numDeltaSegments) {
// If there are delta segments point to them here
curd = &segments[cur->deltaSegmentReadPos++];
if (cur->deltaSegmentReadPos >= DELTA_CACHE_SIZE) cur->deltaSegmentReadPos=0;
// Enable axis - All axis are enabled since they will most probably all be involved in a move
// Since segments could involve different axis this reduces load when switching segments and
// makes disabling easier.
enable_x();enable_y();enable_z();
// Copy across movement into main direction flags so that endstops function correctly
cur->dir |= curd->dir;
// Initialize bresenham for the first segment
if (cur->halfstep) {
cur->error[0] = cur->error[1] = cur->error[2] = cur->numPrimaryStepPerSegment;
curd_errupd = cur->numPrimaryStepPerSegment = cur->numPrimaryStepPerSegment<<1;
} else {
cur->error[0] = cur->error[1] = cur->error[2] = cur->numPrimaryStepPerSegment>>1;
curd_errupd = cur->numPrimaryStepPerSegment;
}
stepsPerSegRemaining = cur->numPrimaryStepPerSegment;
#ifdef DEBUG_DELTA_TIMER
out.println_byte_P(PSTR("HS: "),cur->halfstep);
out.println_long_P(PSTR("Error: "),curd_errupd);
#endif
} else curd=0;
cur_errupd = (cur->halfstep ? cur->stepsRemaining << 1 : cur->stepsRemaining);
if(!(cur->joinFlags & FLAG_JOIN_STEPPARAMS_COMPUTED)) {// should never happen, but with bad timings???
out.println_int_P(PSTR("LATE "),(unsigned int)lines_count);
updateStepsParameter(cur/*,8*/);
}
printer_state.vMaxReached = cur->vStart;
printer_state.stepNumber=0;
printer_state.timer = 0;
cli();
//Determine direction of movement
if (curd) {
if(curd->dir & 1) {
WRITE(X_DIR_PIN,!INVERT_X_DIR);
} else {
WRITE(X_DIR_PIN,INVERT_X_DIR);
}
if(curd->dir & 2) {
WRITE(Y_DIR_PIN,!INVERT_Y_DIR);
} else {
WRITE(Y_DIR_PIN,INVERT_Y_DIR);
}
if(curd->dir & 4) {
WRITE(Z_DIR_PIN,!INVERT_Z_DIR);
} else {
WRITE(Z_DIR_PIN,INVERT_Z_DIR);
}
}
#if USE_OPS==1 || defined(USE_ADVANCE)
if((printer_state.flag0 & PRINTER_FLAG0_SEPERATE_EXTRUDER_INT)==0) // Set direction if no advance/OPS enabled
#endif
if(cur->dir & 8) {
extruder_set_direction(1);
} else {
extruder_set_direction(0);
}
#ifdef USE_ADVANCE
long h = mulu6xu16to32(cur->vStart,cur->advanceL);
int tred = ((
#ifdef ENABLE_QUADRATIC_ADVANCE
(printer_state.advance_executed = cur->advanceStart)+
#endif
h)>>16);
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
#endif
if(printer_state.waslasthalfstepping && cur->halfstep==0) { // Switch halfstepping -> full stepping
printer_state.waslasthalfstepping = 0;
return printer_state.interval*3; // Wait an other 150% from last half step to make the 100% full
} else if(!printer_state.waslasthalfstepping && cur->halfstep) { // Switch full to half stepping
printer_state.waslasthalfstepping = 1;
} else
return printer_state.interval; // Wait an other 50% from last step to make the 100% full
} // End cur=0
sei();
/* For halfstepping, we divide the actions into even and odd actions to split
time used per loop. */
byte do_even;
byte do_odd;
if(cur->halfstep) {
do_odd = cur->halfstep & 1;
do_even = cur->halfstep & 2;
cur->halfstep = 3-cur->halfstep;
} else {
do_even = 1;
do_odd = 1;
}
cli();
if(do_even) {
if((cur->flags & FLAG_CHECK_ENDSTOPS) && (curd != 0)) {
#if X_MAX_PIN>-1 && MAX_HARDWARE_ENDSTOP_X
if((curd->dir & 17)==17) if(READ(X_MAX_PIN) != ENDSTOP_X_MAX_INVERTING) {
curd->dir&=~16;
cur->dir&=~16;
}
#endif
#if Y_MAX_PIN>-1 && MAX_HARDWARE_ENDSTOP_Y
if((curd->dir & 34)==34) if(READ(Y_MAX_PIN) != ENDSTOP_Y_MAX_INVERTING) {
curd->dir&=~32;
cur->dir&=~32;
}
#endif
#if Z_MAX_PIN>-1 && MAX_HARDWARE_ENDSTOP_Z
if((curd->dir & 68)==68) if(READ(Z_MAX_PIN)!= ENDSTOP_Z_MAX_INVERTING) {
curd->dir&=~64;
cur->dir&=~64;
}
#endif
}
}
byte max_loops = (printer_state.stepper_loops<=cur->stepsRemaining ? printer_state.stepper_loops : cur->stepsRemaining);
if(cur->stepsRemaining>0) {
for(byte loop=0;loop0)
#if STEPPER_HIGH_DELAY>0
delayMicroseconds(STEPPER_HIGH_DELAY+DOUBLE_STEP_DELAY);
#else
delayMicroseconds(DOUBLE_STEP_DELAY);
#endif
if(cur->dir & 128) {
if((cur->error[3] -= cur->delta[3]) < 0) {
#if USE_OPS==1 || defined(USE_ADVANCE)
if((printer_state.flag0 & PRINTER_FLAG0_SEPERATE_EXTRUDER_INT)) { // Use interrupt for movement
if(cur->dir & 8)
printer_state.extruderStepsNeeded++;
else
printer_state.extruderStepsNeeded--;
} else {
#endif
extruder_step();
#if USE_OPS==1 || defined(USE_ADVANCE)
}
#endif
cur->error[3] += cur_errupd;
}
}
if (curd) {
// Take delta steps
if(curd->dir & 16) {
if((cur->error[0] -= curd->deltaSteps[0]) < 0) {
WRITE(X_STEP_PIN,HIGH);
cur->error[0] += curd_errupd;
#ifdef DEBUG_STEPCOUNT
cur->totalStepsRemaining--;
#endif
}
}
if(curd->dir & 32) {
if((cur->error[1] -= curd->deltaSteps[1]) < 0) {
WRITE(Y_STEP_PIN,HIGH);
cur->error[1] += curd_errupd;
#ifdef DEBUG_STEPCOUNT
cur->totalStepsRemaining--;
#endif
}
}
if(curd->dir & 64) {
if((cur->error[2] -= curd->deltaSteps[2]) < 0) {
WRITE(Z_STEP_PIN,HIGH);
printer_state.countZSteps += ( cur->dir & 4 ? 1 : -1 );
cur->error[2] += curd_errupd;
#ifdef DEBUG_STEPCOUNT
cur->totalStepsRemaining--;
#endif
}
}
#if STEPPER_HIGH_DELAY>0
delayMicroseconds(STEPPER_HIGH_DELAY);
#endif
WRITE(X_STEP_PIN,LOW);
WRITE(Y_STEP_PIN,LOW);
WRITE(Z_STEP_PIN,LOW);
stepsPerSegRemaining--;
if (!stepsPerSegRemaining) {
cur->numDeltaSegments--;
if (cur->numDeltaSegments) {
// Get the next delta segment
curd = &segments[cur->deltaSegmentReadPos++];
if (cur->deltaSegmentReadPos >= DELTA_CACHE_SIZE) cur->deltaSegmentReadPos=0;
delta_segment_count--;
// Initialize bresenham for this segment (numPrimaryStepPerSegment is already correct for the half step setting)
cur->error[0] = cur->error[1] = cur->error[2] = cur->numPrimaryStepPerSegment>>1;
// Reset the counter of the primary steps. This is initialized in the line
// generation so don't have to do this the first time.
stepsPerSegRemaining = cur->numPrimaryStepPerSegment;
// Change direction if necessary
if(curd->dir & 1) {
WRITE(X_DIR_PIN,!INVERT_X_DIR);
} else {
WRITE(X_DIR_PIN,INVERT_X_DIR);
}
if(curd->dir & 2) {
WRITE(Y_DIR_PIN,!INVERT_Y_DIR);
} else {
WRITE(Y_DIR_PIN,INVERT_Y_DIR);
}
if(curd->dir & 4) {
WRITE(Z_DIR_PIN,!INVERT_Z_DIR);
} else {
WRITE(Z_DIR_PIN,INVERT_Z_DIR);
}
} else {
// Release the last segment
delta_segment_count--;
curd=0;
}
}
}
#if USE_OPS==1 || defined(USE_ADVANCE)
if((printer_state.flag0 & PRINTER_FLAG0_SEPERATE_EXTRUDER_INT)==0) // Use interrupt for movement
#endif
extruder_unstep();
} // for loop
if(do_odd) {
sei(); // Allow interrupts for other types, timer1 is still disabled
#ifdef RAMP_ACCELERATION
//If acceleration is enabled on this move and we are in the acceleration segment, calculate the current interval
if (printer_state.stepNumber <= cur->accelSteps) { // we are accelerating
printer_state.vMaxReached = ComputeV(printer_state.timer,cur->facceleration)+cur->vStart;
if(printer_state.vMaxReached>cur->vMax) printer_state.vMaxReached = cur->vMax;
unsigned int v;
if(printer_state.vMaxReached>STEP_DOUBLER_FREQUENCY) {
#if ALLOW_QUADSTEPPING
if(printer_state.vMaxReached>STEP_DOUBLER_FREQUENCY*2) {
printer_state.stepper_loops = 4;
v = printer_state.vMaxReached>>2;
} else {
printer_state.stepper_loops = 2;
v = printer_state.vMaxReached>>1;
}
#else
printer_state.stepper_loops = 2;
v = printer_state.vMaxReached>>1;
#endif
} else {
printer_state.stepper_loops = 1;
v = printer_state.vMaxReached;
}
printer_state.interval = CPUDivU2(v);
printer_state.timer+=printer_state.interval;
#ifdef USE_ADVANCE
#ifdef ENABLE_QUADRATIC_ADVANCE
long advance_target =printer_state.advance_executed+cur->advanceRate;
for(byte loop=1;loopadvanceRate;
if(advance_target>cur->advanceFull)
advance_target = cur->advanceFull;
cli();
long h = mulu6xu16to32(printer_state.vMaxReached,cur->advanceL);
int tred = ((advance_target+h)>>16);
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
sei();
printer_state.advance_executed = advance_target;
#else
int tred = mulu6xu16shift16(printer_state.vMaxReached,cur->advanceL);
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
sei();
#endif
#endif
} else if (cur->stepsRemaining <= cur->decelSteps) { // time to slow down
if (!(cur->flags & FLAG_DECELERATING)) {
printer_state.timer = 0;
cur->flags |= FLAG_DECELERATING;
}
unsigned int v = ComputeV(printer_state.timer,cur->facceleration);
if (v > printer_state.vMaxReached) // if deceleration goes too far it can become too large
v = cur->vEnd;
else {
v=printer_state.vMaxReached-v;
if (vvEnd) v = cur->vEnd; // extra steps at the end of desceleration due to rounding erros
}
if(v>STEP_DOUBLER_FREQUENCY) {
#if ALLOW_QUADSTEPPING
if(v>STEP_DOUBLER_FREQUENCY*2) {
printer_state.stepper_loops = 4;
v = v>>2;
} else {
printer_state.stepper_loops = 2;
v = v>>1;
}
#else
printer_state.stepper_loops = 2;
v = v>>1;
#endif
} else {
printer_state.stepper_loops = 1;
}
printer_state.interval = CPUDivU2(v);
printer_state.timer+=printer_state.interval;
#ifdef USE_ADVANCE
#ifdef ENABLE_QUADRATIC_ADVANCE
long advance_target =printer_state.advance_executed-cur->advanceRate;
for(byte loop=1;loopadvanceRate;
if(advance_targetadvanceEnd)
advance_target = cur->advanceEnd;
long h=mulu6xu16to32(cur->advanceL,v);
int tred = ((advance_target+h)>>16);
cli();
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
sei();
printer_state.advance_executed = advance_target;
#else
int tred=mulu6xu16shift16(cur->advanceL,v);
cli();
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
sei();
#endif
#endif
} else {
// If we had acceleration, we need to use the latest vMaxReached and interval
// If we started full speed, we need to use cur->fullInterval and vMax
#ifdef USE_ADVANCE
unsigned int v;
if(!cur->accelSteps) {
v = cur->vMax;
} else {
v = printer_state.vMaxReached;
}
#ifdef ENABLE_QUADRATIC_ADVANCE
long h=mulu6xu16to32(cur->advanceL,v);
int tred = ((printer_state.advance_executed+h)>>16);
cli();
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
sei();
#else
int tred=mulu6xu16shift16(cur->advanceL,v);
cli();
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
sei();
#endif
#endif
if(!cur->accelSteps) {
if(cur->vMax>STEP_DOUBLER_FREQUENCY) {
#if ALLOW_QUADSTEPPING
if(cur->vMax>STEP_DOUBLER_FREQUENCY*2) {
printer_state.stepper_loops = 4;
printer_state.interval = cur->fullInterval>>2;
} else {
printer_state.stepper_loops = 2;
printer_state.interval = cur->fullInterval>>1;
}
#else
printer_state.stepper_loops = 2;
printer_state.interval = cur->fullInterval>>1;
#endif
} else {
printer_state.stepper_loops = 1;
printer_state.interval = cur->fullInterval;
}
}
}
#else
printer_state.interval = cur->fullInterval; // without RAMPS always use full speed
#endif
} // do_odd
if(do_even) {
printer_state.stepNumber+=max_loops;
cur->stepsRemaining-=max_loops;
}
#if USE_OPS==1
if(printer_state.opsMode==2 && (cur->joinFlags & FLAG_JOIN_END_RETRACT) && printer_state.filamentRetracted && cur->stepsRemaining<=cur->opsReverseSteps) {
#ifdef DEBUG_OPS
out.println_long_P(PSTR("DownX"),cur->stepsRemaining);
#endif
// Point for retraction reversal reached.
printer_state.filamentRetracted = false;
cli();
printer_state.extruderStepsNeeded+=printer_state.opsPushbackSteps;
#ifdef DEBUG_OPS
sei();
out.println_long_P(PSTR("N="),printer_state.extruderStepsNeeded);
#endif
}
#endif
} // stepsRemaining
long interval;
if(cur->halfstep)
interval = (printer_state.interval>>1); // time to come back
else
interval = printer_state.interval;
if(do_even) {
if(cur->stepsRemaining<=0 || (cur->dir & 240)==0) { // line finished
// out.println_int_P(PSTR("Line finished: "), (int) cur->numDeltaSegments);
// out.println_int_P(PSTR("DSC: "), (int) delta_segment_count);
// out.println_P(PSTR("F"));
// Release remaining delta segments
delta_segment_count -= cur->numDeltaSegments;
#ifdef DEBUG_STEPCOUNT
if(cur->totalStepsRemaining) {
out.println_long_P(PSTR("Missed steps:"), cur->totalStepsRemaining);
out.println_long_P(PSTR("Step/seg r:"), stepsPerSegRemaining);
out.println_int_P(PSTR("NDS:"), (int) cur->numDeltaSegments);
out.println_int_P(PSTR("HS:"), (int) cur->halfstep);
}
#endif
#if USE_OPS==1
if(cur->joinFlags & FLAG_JOIN_END_RETRACT) { // Make sure filament is pushed back
sei();
if(printer_state.filamentRetracted) {
#ifdef DEBUG_OPS
out.println_P(PSTR("Down"));
#endif
printer_state.filamentRetracted = false;
cli();
printer_state.extruderStepsNeeded+=printer_state.opsPushbackSteps;
}
cli();
if(printer_state.extruderStepsNeeded) {
#ifdef DEBUG_OPS
// sei();
// out.println_int_P(PSTR("W"),printer_state.extruderStepsNeeded);
#endif
return 4000; // wait, work is done in other interrupt
}
#ifdef DEBUG_OPS
sei();
#endif
}
#endif
cli();
lines_pos++;
if(lines_pos>=MOVE_CACHE_SIZE) lines_pos=0;
cur = 0;
--lines_count;
if(DISABLE_X) disable_x();
if(DISABLE_Y) disable_y();
if(DISABLE_Z) disable_z();
if(lines_count==0) UI_STATUS(UI_TEXT_IDLE);
interval = printer_state.interval = interval>>1; // 50% of time to next call to do cur=0
}
DEBUG_MEMORY;
} // Do even
return interval;
}
#else
/**
Moves the stepper motors one step. If the last step is reached, the next movement is started.
The function must be called from a timer loop. It returns the time for the next call.
Normal non delta algorithm
*/
int lastblk=-1;
long cur_errupd;
inline long bresenham_step() {
if(cur == 0) {
sei();
ANALYZER_ON(ANALYZER_CH0);
cur = &lines[lines_pos];
if(cur->flags & FLAG_BLOCKED) { // This step is in computation - shouldn't happen
if(lastblk!=(int)cur) {
lastblk = (int)cur;
out.println_int_P(PSTR("BLK "),(unsigned int)lines_count);
}
cur = 0;
return 2000;
}
lastblk = -1;
#ifdef INCLUDE_DEBUG_NO_MOVE
if(DEBUG_NO_MOVES) { // simulate a move, but do nothing in reality
NEXT_PLANNER_INDEX(lines_pos);
cur = 0;
cli();
--lines_count;
return 1000;
}
#endif
ANALYZER_OFF(ANALYZER_CH0);
if(cur->flags & FLAG_WARMUP) {
// This is a warmup move to initalize the path planner correctly. Just waste
// a bit of time to get the planning up to date.
#if USE_OPS==1
if(cur->joinFlags & FLAG_JOIN_END_RETRACT) { // Make sure filament is pushed back
if(printer_state.filamentRetracted) {
#ifdef DEBUG_OPS
//sei();
OUT_P_LN("DownW");
cli();
#endif
printer_state.filamentRetracted = false;
printer_state.extruderStepsNeeded+=printer_state.opsPushbackSteps;
}
if(printer_state.extruderStepsNeeded) {
cur = 0;
return 2000; // wait, work is done in other interrupt
}
} else if(cur->joinFlags & FLAG_JOIN_START_RETRACT) {
if(!printer_state.filamentRetracted) {
#ifdef DEBUG_OPS
OUT_P_LN("UpW");
cli();
#endif
printer_state.filamentRetracted = true;
cli();
printer_state.extruderStepsNeeded-=printer_state.opsRetractSteps;
cur->joinFlags |= FLAG_JOIN_WAIT_EXTRUDER_UP;
}
if(printer_state.extruderStepsNeeded) {
cur = 0;
return 2000; // wait, work is done in other interrupt
}
}
#endif
if(lines_count<=cur->primaryAxis) {
cur=0;
return 2000;
}
NEXT_PLANNER_INDEX(lines_pos);
long wait = cur->accelerationPrim;
cur = 0;
cli();
--lines_count;
return(wait); // waste some time for path optimization to fill up
} // End if WARMUP
/*if(DEBUG_ECHO) {
OUT_P_L_LN("MSteps:",cur->stepsRemaining);
//OUT_P_F("Ln:",cur->startSpeed);
//OUT_P_F_LN(":",cur->endSpeed);
}*/
//Only enable axis that are moving. If the axis doesn't need to move then it can stay disabled depending on configuration.
#ifdef XY_GANTRY
if(cur->dir & 48) {
enable_x();
enable_y();
}
#else
if(cur->dir & 16) enable_x();
if(cur->dir & 32) enable_y();
#endif
if(cur->dir & 64) {
enable_z();
}
if(cur->dir & 128) extruder_enable();
cur->joinFlags |= FLAG_JOIN_END_FIXED | FLAG_JOIN_START_FIXED; // don't touch this segment any more, just for safety
#if USE_OPS==1
if(printer_state.opsMode) { // Enabled?
if(cur->joinFlags & FLAG_JOIN_START_RETRACT) {
if(!printer_state.filamentRetracted) {
#ifdef DEBUG_OPS
OUT_P_LN("Up");
#endif
printer_state.filamentRetracted = true;
cli();
printer_state.extruderStepsNeeded-=printer_state.opsRetractSteps;
sei();
cur->joinFlags |= FLAG_JOIN_WAIT_EXTRUDER_UP;
}
}
// If path optimizer ran out of samples, he might miss some retractions. Solve them before printing
else if((cur->joinFlags & FLAG_JOIN_NO_RETRACT)==0 && printmoveSeen) {
if((cur->dir & 136)==136) {
if(printer_state.filamentRetracted) { // Printmove and filament is still up!
#ifdef DEBUG_OPS
OUT_P_LN("DownA");
#endif
printer_state.filamentRetracted = false;
cli();
printer_state.extruderStepsNeeded+=printer_state.opsPushbackSteps;
cur->joinFlags |= FLAG_JOIN_WAIT_EXTRUDER_DOWN;
}
} /*else if(!printer_state.filamentRetracted) {
#ifdef DEBUG_OPS
out.println_P(PSTR("UpA"));
#endif
printer_state.filamentRetracted = true;
cli();
printer_state.extruderStepsNeeded-=printer_state.opsRetractSteps;
cur->joinFlags |= FLAG_JOIN_WAIT_EXTRUDER_UP;
}*/
}
if(cur->joinFlags & FLAG_JOIN_WAIT_EXTRUDER_UP) { // Wait for filament pushback
cli();
if(printer_state.extruderStepsNeededjoinFlags & FLAG_JOIN_WAIT_EXTRUDER_DOWN) { // Wait for filament pushback
cli();
if(printer_state.extruderStepsNeeded) {
cur=0;
return 4000;
}
}
} // End if opsMode
#endif
sei(); // Allow interrupts
if(cur->halfstep) {
cur_errupd = cur->delta[cur->primaryAxis]<<1;
//printer_state.interval = CPUDivU2(cur->vStart);
} else
cur_errupd = cur->delta[cur->primaryAxis];
if(!(cur->joinFlags & FLAG_JOIN_STEPPARAMS_COMPUTED)) {// should never happen, but with bad timings???
updateStepsParameter(cur/*,8*/);
}
printer_state.vMaxReached = cur->vStart;
printer_state.stepNumber=0;
printer_state.timer = 0;
cli();
//Determine direction of movement,check if endstop was hit
#if !defined(XY_GANTRY)
if(cur->dir & 1) {
WRITE(X_DIR_PIN,!INVERT_X_DIR);
} else {
WRITE(X_DIR_PIN,INVERT_X_DIR);
}
if(cur->dir & 2) {
WRITE(Y_DIR_PIN,!INVERT_Y_DIR);
} else {
WRITE(Y_DIR_PIN,INVERT_Y_DIR);
}
#else
long gdx = (cur->dir & 1 ? cur->delta[0] : -cur->delta[0]); // Compute signed difference in steps
long gdy = (cur->dir & 2 ? cur->delta[1] : -cur->delta[1]);
#if DRIVE_SYSTEM==1
if(gdx+gdy>=0) {
WRITE(X_DIR_PIN,!INVERT_X_DIR);
ANALYZER_ON(ANALYZER_CH4);
} else {
WRITE(X_DIR_PIN,INVERT_X_DIR);
ANALYZER_OFF(ANALYZER_CH4);
}
if(gdx>gdy) {
WRITE(Y_DIR_PIN,!INVERT_Y_DIR);
ANALYZER_ON(ANALYZER_CH5);
} else {
WRITE(Y_DIR_PIN,INVERT_Y_DIR);
ANALYZER_OFF(ANALYZER_CH5);
}
#endif
#if DRIVE_SYSTEM==2
if(gdx+gdy>=0) {
WRITE(X_DIR_PIN,!INVERT_X_DIR);
} else {
WRITE(X_DIR_PIN,INVERT_X_DIR);
}
if(gdx<=gdy) {
WRITE(Y_DIR_PIN,!INVERT_Y_DIR);
} else {
WRITE(Y_DIR_PIN,INVERT_Y_DIR);
}
#endif
#endif
if(cur->dir & 4) {
WRITE(Z_DIR_PIN,!INVERT_Z_DIR);
} else {
WRITE(Z_DIR_PIN,INVERT_Z_DIR);
}
#if USE_OPS==1 || defined(USE_ADVANCE)
if((printer_state.flag0 & PRINTER_FLAG0_SEPERATE_EXTRUDER_INT)==0) // Set direction if no advance/OPS enabled
#endif
if(cur->dir & 8) {
extruder_set_direction(1);
} else {
extruder_set_direction(0);
}
#ifdef USE_ADVANCE
long h = mulu6xu16to32(cur->vStart,cur->advanceL);
int tred = ((
#ifdef ENABLE_QUADRATIC_ADVANCE
(printer_state.advance_executed = cur->advanceStart)+
#endif
h)>>16);
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
#endif
if(printer_state.waslasthalfstepping && cur->halfstep==0) { // Switch halfstepping -> full stepping
printer_state.waslasthalfstepping = 0;
return printer_state.interval*3; // Wait an other 150% from last half step to make the 100% full
} else if(!printer_state.waslasthalfstepping && cur->halfstep) { // Switch full to half stepping
printer_state.waslasthalfstepping = 1;
} else
return printer_state.interval; // Wait an other 50% from last step to make the 100% full
} // End cur=0
sei();
/* For halfstepping, we divide the actions into even and odd actions to split
time used per loop. */
byte do_even;
byte do_odd;
if(cur->halfstep) {
do_odd = cur->halfstep & 1;
do_even = cur->halfstep & 2;
cur->halfstep = 3-cur->halfstep;
} else {
do_even = 1;
do_odd = 1;
}
cli();
if(do_even) {
if(cur->flags & FLAG_CHECK_ENDSTOPS) {
#if X_MIN_PIN>-1 && MIN_HARDWARE_ENDSTOP_X
if((cur->dir & 17)==16) if(READ(X_MIN_PIN) != ENDSTOP_X_MIN_INVERTING) {
#if DRIVE_SYSTEM==0
cur->dir&=~16;
#else
cur->dir&=~48;
#endif
}
#endif
#if Y_MIN_PIN>-1 && MIN_HARDWARE_ENDSTOP_Y
if((cur->dir & 34)==32) if(READ(Y_MIN_PIN) != ENDSTOP_Y_MIN_INVERTING) {
#if DRIVE_SYSTEM==0
cur->dir&=~32;
#else
cur->dir&=~48;
#endif
}
#endif
#if X_MAX_PIN>-1 && MAX_HARDWARE_ENDSTOP_X
if((cur->dir & 17)==17) if(READ(X_MAX_PIN) != ENDSTOP_X_MAX_INVERTING) {
#if DRIVE_SYSTEM==0
cur->dir&=~16;
#else
cur->dir&=~48;
#endif
}
#endif
#if Y_MAX_PIN>-1 && MAX_HARDWARE_ENDSTOP_Y
if((cur->dir & 34)==34) if(READ(Y_MAX_PIN) != ENDSTOP_Y_MAX_INVERTING) {
#if DRIVE_SYSTEM==0
cur->dir&=~32;
#else
cur->dir&=~48;
#endif
}
#endif
}
// Test Z-Axis every step if necessary, otherwise it could easyly ruin your printer!
#if Z_MIN_PIN>-1 && MIN_HARDWARE_ENDSTOP_Z
if((cur->dir & 68)==64) if(READ(Z_MIN_PIN) != ENDSTOP_Z_MIN_INVERTING) {cur->dir&=~64;}
#endif
#if Z_MAX_PIN>-1 && MAX_HARDWARE_ENDSTOP_Z
if((cur->dir & 68)==68) if(READ(Z_MAX_PIN)!= ENDSTOP_Z_MAX_INVERTING) {cur->dir&=~64;}
#endif
}
byte max_loops = (printer_state.stepper_loops<=cur->stepsRemaining ? printer_state.stepper_loops : cur->stepsRemaining);
if(cur->stepsRemaining>0) {
for(byte loop=0;loop0)
#if STEPPER_HIGH_DELAY>0
delayMicroseconds(STEPPER_HIGH_DELAY+DOUBLE_STEP_DELAY);
#else
delayMicroseconds(DOUBLE_STEP_DELAY);
#endif
if(cur->dir & 128) {
if((cur->error[3] -= cur->delta[3]) < 0) {
#if USE_OPS==1 || defined(USE_ADVANCE)
if((printer_state.flag0 & PRINTER_FLAG0_SEPERATE_EXTRUDER_INT)) { // Use interrupt for movement
if(cur->dir & 8)
printer_state.extruderStepsNeeded++;
else
printer_state.extruderStepsNeeded--;
} else {
#endif
extruder_step();
#if USE_OPS==1 || defined(USE_ADVANCE)
}
#endif
cur->error[3] += cur_errupd;
}
}
#if defined(XY_GANTRY)
#endif
if(cur->dir & 16) {
if((cur->error[0] -= cur->delta[0]) < 0) {
ANALYZER_ON(ANALYZER_CH6);
#if DRIVE_SYSTEM==0 || !defined(XY_GANTRY)
ANALYZER_ON(ANALYZER_CH2);
WRITE(X_STEP_PIN,HIGH);
#else
#if DRIVE_SYSTEM==1
if(cur->dir & 1) {
printer_state.motorX++;
printer_state.motorY++;
} else {
printer_state.motorX--;
printer_state.motorY--;
}
#endif
#if DRIVE_SYSTEM==2
if(cur->dir & 1) {
printer_state.motorX++;
printer_state.motorY--;
} else {
printer_state.motorX--;
printer_state.motorY++;
}
#endif
#endif // XY_GANTRY
cur->error[0] += cur_errupd;
#ifdef DEBUG_STEPCOUNT
cur->totalStepsRemaining--;
#endif
}
}
if(cur->dir & 32) {
if((cur->error[1] -= cur->delta[1]) < 0) {
ANALYZER_ON(ANALYZER_CH7);
#if DRIVE_SYSTEM==0 || !defined(XY_GANTRY)
ANALYZER_ON(ANALYZER_CH3);
WRITE(Y_STEP_PIN,HIGH);
#else
#if DRIVE_SYSTEM==1
if(cur->dir & 2) {
printer_state.motorX++;
printer_state.motorY--;
} else {
printer_state.motorX--;
printer_state.motorY++;
}
#endif
#if DRIVE_SYSTEM==2
if(cur->dir & 2) {
printer_state.motorX++;
printer_state.motorY++;
} else {
printer_state.motorX--;
printer_state.motorY--;
}
#endif
#endif // XY_GANTRY
cur->error[1] += cur_errupd;
#ifdef DEBUG_STEPCOUNT
cur->totalStepsRemaining--;
#endif
}
}
#if defined(XY_GANTRY)
if(printer_state.motorX <= -2) {
ANALYZER_ON(ANALYZER_CH2);
WRITE(X_STEP_PIN,HIGH);
printer_state.motorX += 2;
} else if(printer_state.motorX >= 2) {
ANALYZER_ON(ANALYZER_CH2);
WRITE(X_STEP_PIN,HIGH);
printer_state.motorX -= 2;
}
if(printer_state.motorY <= -2) {
ANALYZER_ON(ANALYZER_CH3);
WRITE(Y_STEP_PIN,HIGH);
printer_state.motorY += 2;
} else if(printer_state.motorY >= 2) {
ANALYZER_ON(ANALYZER_CH3);
WRITE(Y_STEP_PIN,HIGH);
printer_state.motorY -= 2;
}
#endif
if(cur->dir & 64) {
if((cur->error[2] -= cur->delta[2]) < 0) {
WRITE(Z_STEP_PIN,HIGH);
cur->error[2] += cur_errupd;
#ifdef DEBUG_STEPCOUNT
cur->totalStepsRemaining--;
#endif
}
}
#if STEPPER_HIGH_DELAY>0
delayMicroseconds(STEPPER_HIGH_DELAY);
#endif
#if USE_OPS==1 || defined(USE_ADVANCE)
if((printer_state.flag0 & PRINTER_FLAG0_SEPERATE_EXTRUDER_INT)==0) // Use interrupt for movement
#endif
extruder_unstep();
WRITE(X_STEP_PIN,LOW);
WRITE(Y_STEP_PIN,LOW);
WRITE(Z_STEP_PIN,LOW);
ANALYZER_OFF(ANALYZER_CH1);
ANALYZER_OFF(ANALYZER_CH2);
ANALYZER_OFF(ANALYZER_CH3);
ANALYZER_OFF(ANALYZER_CH6);
ANALYZER_OFF(ANALYZER_CH7);
} // for loop
if(do_odd) {
sei(); // Allow interrupts for other types, timer1 is still disabled
#ifdef RAMP_ACCELERATION
//If acceleration is enabled on this move and we are in the acceleration segment, calculate the current interval
if (printer_state.stepNumber <= cur->accelSteps) { // we are accelerating
printer_state.vMaxReached = ComputeV(printer_state.timer,cur->facceleration)+cur->vStart;
if(printer_state.vMaxReached>cur->vMax) printer_state.vMaxReached = cur->vMax;
unsigned int v;
if(printer_state.vMaxReached>STEP_DOUBLER_FREQUENCY) {
#if ALLOW_QUADSTEPPING
if(printer_state.vMaxReached>STEP_DOUBLER_FREQUENCY*2) {
printer_state.stepper_loops = 4;
v = printer_state.vMaxReached>>2;
} else {
printer_state.stepper_loops = 2;
v = printer_state.vMaxReached>>1;
}
#else
printer_state.stepper_loops = 2;
v = printer_state.vMaxReached>>1;
#endif
} else {
printer_state.stepper_loops = 1;
v = printer_state.vMaxReached;
}
printer_state.interval = CPUDivU2(v);
printer_state.timer+=printer_state.interval;
#ifdef USE_ADVANCE
#ifdef ENABLE_QUADRATIC_ADVANCE
long advance_target =printer_state.advance_executed+cur->advanceRate;
for(byte loop=1;loopadvanceRate;
if(advance_target>cur->advanceFull)
advance_target = cur->advanceFull;
cli();
long h = mulu6xu16to32(printer_state.vMaxReached,cur->advanceL);
int tred = ((advance_target+h)>>16);
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
sei();
printer_state.advance_executed = advance_target;
#else
int tred = mulu6xu16shift16(printer_state.vMaxReached,cur->advanceL);
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
sei();
#endif
#endif
} else if (cur->stepsRemaining <= cur->decelSteps) { // time to slow down
if (!(cur->flags & FLAG_DECELERATING)) {
printer_state.timer = 0;
cur->flags |= FLAG_DECELERATING;
}
unsigned int v = ComputeV(printer_state.timer,cur->facceleration);
if (v > printer_state.vMaxReached) // if deceleration goes too far it can become too large
v = cur->vEnd;
else{
v=printer_state.vMaxReached-v;
if (vvEnd) v = cur->vEnd; // extra steps at the end of desceleration due to rounding erros
}
#ifdef USE_ADVANCE
unsigned int v0 = v;
#endif
if(v>STEP_DOUBLER_FREQUENCY) {
#if ALLOW_QUADSTEPPING
if(v>STEP_DOUBLER_FREQUENCY*2) {
printer_state.stepper_loops = 4;
v = v>>2;
} else {
printer_state.stepper_loops = 2;
v = v>>1;
}
#else
printer_state.stepper_loops = 2;
v = v>>1;
#endif
} else {
printer_state.stepper_loops = 1;
}
printer_state.interval = CPUDivU2(v);
printer_state.timer+=printer_state.interval;
#ifdef USE_ADVANCE
#ifdef ENABLE_QUADRATIC_ADVANCE
long advance_target =printer_state.advance_executed-cur->advanceRate;
for(byte loop=1;loopadvanceRate;
if(advance_targetadvanceEnd)
advance_target = cur->advanceEnd;
long h=mulu6xu16to32(cur->advanceL,v0);
int tred = ((advance_target+h)>>16);
cli();
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
sei();
printer_state.advance_executed = advance_target;
#else
int tred=mulu6xu16shift16(cur->advanceL,v0);
cli();
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
sei();
#endif
#endif
} else {
// If we had acceleration, we need to use the latest vMaxReached and interval
// If we started full speed, we need to use cur->fullInterval and vMax
#ifdef USE_ADVANCE
unsigned int v;
if(!cur->accelSteps) {
v = cur->vMax;
} else {
v = printer_state.vMaxReached;
}
#ifdef ENABLE_QUADRATIC_ADVANCE
long h=mulu6xu16to32(cur->advanceL,v);
int tred = ((printer_state.advance_executed+h)>>16);
cli();
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
sei();
#else
int tred=mulu6xu16shift16(cur->advanceL,v);
cli();
printer_state.extruderStepsNeeded+=tred-printer_state.advance_steps_set;
printer_state.advance_steps_set = tred;
sei();
#endif
#endif
if(!cur->accelSteps) {
if(cur->vMax>STEP_DOUBLER_FREQUENCY) {
#if ALLOW_QUADSTEPPING
if(cur->vMax>STEP_DOUBLER_FREQUENCY*2) {
printer_state.stepper_loops = 4;
printer_state.interval = cur->fullInterval>>2;
} else {
printer_state.stepper_loops = 2;
printer_state.interval = cur->fullInterval>>1;
}
#else
printer_state.stepper_loops = 2;
printer_state.interval = cur->fullInterval>>1;
#endif
} else {
printer_state.stepper_loops = 1;
printer_state.interval = cur->fullInterval;
}
}
}
#else
printer_state.interval = cur->fullInterval; // without RAMPS always use full speed
#endif
} // do_odd
if(do_even) {
printer_state.stepNumber+=max_loops;
cur->stepsRemaining-=max_loops;
}
#if USE_OPS==1
if(printer_state.opsMode==2 && (cur->joinFlags & FLAG_JOIN_END_RETRACT) && printer_state.filamentRetracted && cur->stepsRemaining<=cur->opsReverseSteps) {
#ifdef DEBUG_OPS
OUT_P_L_LN("DownX",cur->stepsRemaining);
#endif
// Point for retraction reversal reached.
printer_state.filamentRetracted = false;
cli();
printer_state.extruderStepsNeeded+=printer_state.opsPushbackSteps;
#ifdef DEBUG_OPS
sei();
OUT_P_L_LN("N=",printer_state.extruderStepsNeeded);
#endif
}
#endif
} // stepsRemaining
long interval;
if(cur->halfstep) interval = (printer_state.interval>>1); // time to come back
else interval = printer_state.interval;
if(do_even) {
if(cur->stepsRemaining<=0 || (cur->dir & 240)==0) { // line finished
#ifdef DEBUG_STEPCOUNT
if(cur->totalStepsRemaining)
OUT_P_L_LN("Missed steps:",cur->totalStepsRemaining);
#endif
#if USE_OPS==1
if(cur->joinFlags & FLAG_JOIN_END_RETRACT) { // Make sure filament is pushed back
sei();
if(printer_state.filamentRetracted) {
#ifdef DEBUG_OPS
out.println_P(PSTR("Down"));
#endif
printer_state.filamentRetracted = false;
cli();
printer_state.extruderStepsNeeded+=printer_state.opsPushbackSteps;
}
cli();
if(printer_state.extruderStepsNeeded) {
#ifdef DEBUG_OPS
// sei();
// out.println_int_P(PSTR("W"),printer_state.extruderStepsNeeded);
#endif
return 4000; // wait, work is done in other interrupt
}
#ifdef DEBUG_OPS
sei();
#endif
}
#endif
cli();
NEXT_PLANNER_INDEX(lines_pos);
cur = 0;
--lines_count;
#ifdef XY_GANTRY
if(DISABLE_X && DISABLE_Y) {
disable_x();
disable_y();
}
#else
if(DISABLE_X) disable_x();
if(DISABLE_Y) disable_y();
#endif
if(DISABLE_Z) disable_z();
if(lines_count==0) UI_STATUS(UI_TEXT_IDLE);
interval = printer_state.interval = interval>>1; // 50% of time to next call to do cur=0
}
DEBUG_MEMORY;
} // Do even
return interval;
}
#endif
void(* resetFunc) (void) = 0; //declare reset function @ address 0
/**
\brief Stop heater and stepper motors. Disable power,if possible.
*/
void kill(byte only_steppers)
{
if((printer_state.flag0 & PRINTER_FLAG0_STEPPER_DISABLED) && only_steppers) return;
printer_state.flag0 |=PRINTER_FLAG0_STEPPER_DISABLED;
disable_x();
disable_y();
disable_z();
extruder_disable();
if(!only_steppers) {
for(byte i=0;i-1
//pinMode(PS_ON_PIN,INPUT);
SET_OUTPUT(PS_ON_PIN); //GND
WRITE(PS_ON_PIN, HIGH);
#endif
} else UI_STATUS_UPD(UI_TEXT_STEPPER_DISABLED);
}
long stepperWait = 0;
/** \brief Sets the timer 1 compare value to delay ticks.
This function sets the OCR1A compare counter to get the next interrupt
at delay ticks measured from the last interrupt. delay must be << 2^24
*/
inline void setTimer(unsigned long delay)
{
__asm__ __volatile__ (
"cli \n\t"
"tst %C[delay] \n\t" //if(delay<65536) {
"brne else%= \n\t"
"cpi %B[delay],255 \n\t"
"breq else%= \n\t" // delay <65280
"sts stepperWait,r1 \n\t" // stepperWait = 0;
"sts stepperWait+1,r1 \n\t"
"sts stepperWait+2,r1 \n\t"
"lds %C[delay],%[time] \n\t" // Read TCNT1
"lds %D[delay],%[time]+1 \n\t"
"ldi r18,100 \n\t" // Add 100 to TCNT1
"add %C[delay],r18 \n\t"
"adc %D[delay],r1 \n\t"
"cp %A[delay],%C[delay] \n\t" // delay 65535
"lds r23,stepperWait+1 \n\t"
"tst r23 \n\t"
"brne last%= \n\t" // Still not 0, go ahead
"lds r22,stepperWait \n\t"
"breq end%= \n\t" // stepperWait is 0, do your work
"last%=: \n\t"
"sts %[ocr]+1,r23 \n\t" // OCR1A = stepper wait;
"sts %[ocr],r22 \n\t"
"sts stepperWait,r1 \n\t"
"sts stepperWait+1,r1 \n\t"
"rjmp end1%= \n\t"
"else%=: lds r22,stepperWait+1 \n\t" //} else { stepperWait = stepperWait-32768;
"subi r22, 0x80 \n\t"
"sbci r23, 0x00 \n\t"
"sts stepperWait+1,r22 \n\t" // ocr1a stays 32768
"sts stepperWait+2,r23 \n\t"
"end1%=: ldi %[ex],1 \n\t"
"end%=: \n\t"
:[ex]"=&d"(doExit):[ocr]"i" (_SFR_MEM_ADDR(OCR1A)):"r22","r23" );
if(doExit) return;
insideTimer1=1;
OCR1A=61000;
if(lines_count) {
setTimer(bresenham_step());
} else {
if(waitRelax==0) {
#if USE_OPS==1
// push filament in normal position if printings stops, so we have a defined starting position
if(printer_state.opsMode && printer_state.filamentRetracted) {
#ifdef DEBUG_OPS
out.println_P(PSTR("DownI"));
#endif
printer_state.extruderStepsNeeded+=printer_state.opsPushbackSteps;
printer_state.filamentRetracted = false;
}
printmoveSeen = 0;
#endif
#ifdef USE_ADVANCE
if(printer_state.advance_steps_set) {
printer_state.extruderStepsNeeded-=printer_state.advance_steps_set;
#ifdef ENABLE_QUADRATIC_ADVANCE
printer_state.advance_executed = 0;
#endif
printer_state.advance_steps_set = 0;
}
#endif
#if USE_OPS==1 || defined(USE_ADVANCE)
if(!printer_state.extruderStepsNeeded) if(DISABLE_E) extruder_disable();
#else
if(DISABLE_E) extruder_disable();
#endif
} else waitRelax--;
stepperWait = 0; // Importent becaus of optimization in asm at begin
OCR1A = 65500; // Wait for next move
}
DEBUG_MEMORY;
insideTimer1=0;
}
#if USE_OPS==1 || defined(USE_ADVANCE)
byte extruder_wait_dirchange=0; ///< Wait cycles, if direction changes. Prevents stepper from loosing steps.
char extruder_last_dir = 0;
byte extruder_speed = 0;
#endif
/** \brief Timer routine for extruder stepper.
Several methods need to move the extruder. To get a optima result,
all methods update the printer_state.extruderStepsNeeded with the
number of additional steps needed. During this interrupt, one step
is executed. This will keep the extruder moving, until the total
wanted movement is achieved. This will be done with the maximum
allowable speed for the extruder.
*/
ISR(EXTRUDER_TIMER_VECTOR)
{
#if USE_OPS==1 || defined(USE_ADVANCE)
if((printer_state.flag0 & PRINTER_FLAG0_SEPERATE_EXTRUDER_INT)==0) return; // currently no need
byte timer = EXTRUDER_OCR;
bool increasing = printer_state.extruderStepsNeeded>0;
if(printer_state.extruderStepsNeeded==0) {
extruder_last_dir = 0;
} else if((increasing>0 && extruder_last_dir<0) || (!increasing && extruder_last_dir>0)) {
EXTRUDER_OCR = timer+50; // Little delay to accomodate to reversed direction
extruder_set_direction(increasing ? 1 : 0);
extruder_last_dir = (increasing ? 1 : -1);
return;
} else {
if(extruder_last_dir==0) {
extruder_set_direction(increasing ? 1 : 0);
extruder_last_dir = (increasing ? 1 : -1);
}
extruder_step();
printer_state.extruderStepsNeeded-=extruder_last_dir;
#if STEPPER_HIGH_DELAY>0
delayMicroseconds(STEPPER_HIGH_DELAY);
#endif
extruder_unstep();
}
EXTRUDER_OCR = timer+printer_state.maxExtruderSpeed;
/* Version of 0.7 branch
static byte accdelay=10;
if(printer_state.extruderStepsNeeded==0) {
extruder_last_dir = 0;
} else if((increasing>0 && extruder_last_dir<0) || (!increasing && extruder_last_dir>0)) {
EXTRUDER_OCR = timer+50; // Little delay to accomodate to reversed direction
extruder_set_direction(increasing ? 1 : 0);
extruder_last_dir = (increasing ? 1 : -1);
return;
} else {
if(extruder_last_dir==0) {
extruder_set_direction(increasing ? 1 : 0);
extruder_last_dir = (increasing ? 1 : -1);
}
extruder_step();
printer_state.extruderStepsNeeded-=extruder_last_dir;
#if STEPPER_HIGH_DELAY>0
delayMicroseconds(STEPPER_HIGH_DELAY);
#endif
extruder_unstep();
}
EXTRUDER_OCR = timer+printer_state.maxExtruderSpeed;
}
*/
/*
EXTRUDER_OCR += printer_state.timer0Interval; // time to come back
// The stepper signals are in strategical positions for optimal timing. If you
// still have timing issues, add dummy commands between.
if(printer_state.extruderStepsNeeded) {
extruder_unstep();
if(printer_state.extruderStepsNeeded<0) { // Backward step
extruder_set_direction(0);
if(extruder_wait_dirchange && extruder_last_dir==-1) {
extruder_wait_dirchange--;
return;
}
extruder_last_dir = 1;
extruder_wait_dirchange=2;
printer_state.extruderStepsNeeded++;
} else { // Forward step
extruder_set_direction(1);
if(extruder_wait_dirchange && extruder_last_dir==1) {
extruder_wait_dirchange--;
return;
}
extruder_last_dir = -1;
extruder_wait_dirchange=2;
printer_state.extruderStepsNeeded--;
}
if(current_extruder->currentTemperatureC>=MIN_EXTRUDER_TEMP<-1
if((pwm_pos_set[0] = pwm_pos[0])>0) WRITE(EXT0_HEATER_PIN,1);
#if EXT0_EXTRUDER_COOLER_PIN>-1
if((pwm_cooler_pos_set[0] = extruder[0].coolerPWM)>0) WRITE(EXT0_EXTRUDER_COOLER_PIN,1);
#endif
#endif
#if defined(EXT1_HEATER_PIN) && EXT1_HEATER_PIN>-1
if((pwm_pos_set[1] = pwm_pos[1])>0) WRITE(EXT1_HEATER_PIN,1);
#if EXT1_EXTRUDER_COOLER_PIN>-1
if((pwm_cooler_pos_set[1] = extruder[1].coolerPWM)>0) WRITE(EXT1_EXTRUDER_COOLER_PIN,1);
#endif
#endif
#if defined(EXT2_HEATER_PIN) && EXT2_HEATER_PIN>-1
if((pwm_pos_set[2] = pwm_pos[2])>0) WRITE(EXT2_HEATER_PIN,1);
#if EXT2_EXTRUDER_COOLER_PIN>-1
if((pwm_cooler_pos_set[2] = extruder[2].coolerPWM)>0) WRITE(EXT2_EXTRUDER_COOLER_PIN,1);
#endif
#endif
#if defined(EXT3_HEATER_PIN) && EXT3_HEATER_PIN>-1
if((pwm_pos_set[3] = pwm_pos[3])>0) WRITE(EXT3_HEATER_PIN,1);
#if EXT3_EXTRUDER_COOLER_PIN>-1
if((pwm_cooler_pos_set[3] = extruder[3].coolerPWM)>0) WRITE(EXT3_EXTRUDER_COOLER_PIN,1);
#endif
#endif
#if defined(EXT4_HEATER_PIN) && EXT4_HEATER_PIN>-1
if((pwm_pos_set[4] = pwm_pos[4])>0) WRITE(EXT4_HEATER_PIN,1);
#if EXT4_EXTRUDER_COOLER_PIN>-1
if((pwm_cooler_pos_set[4] = pwm_pos[4].coolerPWM)>0) WRITE(EXT4_EXTRUDER_COOLER_PIN,1);
#endif
#endif
#if defined(EXT5_HEATER_PIN) && EXT5_HEATER_PIN>-1
if((pwm_pos_set[5] = pwm_pos[5])>0) WRITE(EXT5_HEATER_PIN,1);
#if EXT5_EXTRUDER_COOLER_PIN>-1
if((pwm_cooler_pos_set[5] = extruder[5].coolerPWM)>0) WRITE(EXT5_EXTRUDER_COOLER_PIN,1);
#endif
#endif
#if FAN_BOARD_PIN>-1
if((pwm_pos_set[NUM_EXTRUDER+1] = pwm_pos[NUM_EXTRUDER+1])>0) WRITE(FAN_BOARD_PIN,1);
#endif
#if FAN_PIN>-1 && FEATURE_FAN_CONTROL
if((pwm_pos_set[NUM_EXTRUDER+2] = pwm_pos[NUM_EXTRUDER+2])>0) WRITE(FAN_PIN,1);
#endif
#if HEATED_BED_HEATER_PIN>-1 && HAVE_HEATED_BED
if((pwm_pos_set[NUM_EXTRUDER] = pwm_pos[NUM_EXTRUDER])>0) WRITE(HEATED_BED_HEATER_PIN,1);
#endif
}
#if EXT0_HEATER_PIN>-1
if(pwm_pos_set[0] == pwm_count && pwm_pos_set[0]!=255) WRITE(EXT0_HEATER_PIN,0);
#if EXT0_EXTRUDER_COOLER_PIN>-1
if(pwm_cooler_pos_set[0] == pwm_count && pwm_cooler_pos_set[0]!=255) WRITE(EXT0_EXTRUDER_COOLER_PIN,0);
#endif
#endif
#if defined(EXT1_HEATER_PIN) && EXT1_HEATER_PIN>-1
if(pwm_pos_set[1] == pwm_count && pwm_pos_set[1]!=255) WRITE(EXT1_HEATER_PIN,0);
#if EXT1_EXTRUDER_COOLER_PIN>-1
if(pwm_cooler_pos_set[1] == pwm_count && pwm_cooler_pos_set[1]!=255) WRITE(EXT1_EXTRUDER_COOLER_PIN,0);
#endif
#endif
#if defined(EXT2_HEATER_PIN) && EXT2_HEATER_PIN>-1
if(pwm_pos_set[2] == pwm_count && pwm_pos_set[2]!=255) WRITE(EXT2_HEATER_PIN,0);
#if EXT2_EXTRUDER_COOLER_PIN>-1
if(pwm_cooler_pos_set[2] == pwm_count && pwm_cooler_pos_set[2]!=255) WRITE(EXT2_EXTRUDER_COOLER_PIN,0);
#endif
#endif
#if defined(EXT3_HEATER_PIN) && EXT3_HEATER_PIN>-1
if(pwm_pos_set[3] == pwm_count && pwm_pos_set[3]!=255) WRITE(EXT3_HEATER_PIN,0);
#if EXT3_EXTRUDER_COOLER_PIN>-1
if(pwm_cooler_pos_set[3] == pwm_count && pwm_cooler_pos_set[3]!=255) WRITE(EXT3_EXTRUDER_COOLER_PIN,0);
#endif
#endif
#if defined(EXT4_HEATER_PIN) && EXT4_HEATER_PIN>-1
if(pwm_pos_set[4] == pwm_count && pwm_pos_set[4]!=255) WRITE(EXT4_HEATER_PIN,0);
#if EXT4_EXTRUDER_COOLER_PIN>-1
if(pwm_cooler_pos_set[4] == pwm_count && pwm_cooler_pos_set[4]!=255) WRITE(EXT4_EXTRUDER_COOLER_PIN,0);
#endif
#endif
#if defined(EXT5_HEATER_PIN) && EXT5_HEATER_PIN>-1
if(pwm_pos_set[5] == pwm_count && pwm_pos_set[5]!=255) WRITE(EXT5_HEATER_PIN,0);
#if EXT5_EXTRUDER_COOLER_PIN>-1
if(pwm_cooler_pos_set[5] == pwm_count && pwm_cooler_pos_set[5]!=255) WRITE(EXT5_EXTRUDER_COOLER_PIN,0);
#endif
#endif
#if FAN_BOARD_PIN>-1
if(pwm_pos_set[NUM_EXTRUDER+2] == pwm_count && pwm_pos_set[NUM_EXTRUDER+2]!=255) WRITE(FAN_BOARD_PIN,0);
#endif
#if FAN_PIN>-1 && FEATURE_FAN_CONTROL
if(pwm_pos_set[NUM_EXTRUDER+2] == pwm_count && pwm_pos_set[NUM_EXTRUDER+2]!=255) WRITE(FAN_PIN,0);
#endif
#if HEATED_BED_HEATER_PIN>-1 && HAVE_HEATED_BED
if(pwm_pos_set[NUM_EXTRUDER] == pwm_count && pwm_pos_set[NUM_EXTRUDER]!=255) WRITE(HEATED_BED_HEATER_PIN,0);
#endif
sei();
counter_periodical++; // Appxoimate a 100ms timer
if(counter_periodical>=(int)(F_CPU/40960)) {
counter_periodical=0;
execute_periodical=1;
}
// read analog values
#if ANALOG_INPUTS>0
if((ADCSRA & _BV(ADSC))==0) { // Conversion finished?
osAnalogInputBuildup[osAnalogInputPos] += ADCW;
if(++osAnalogInputCounter[osAnalogInputPos]>=_BV(ANALOG_INPUT_SAMPLE)) {
#if ANALOG_INPUT_BITS+ANALOG_INPUT_SAMPLE<12
osAnalogInputValues[osAnalogInputPos] =
osAnalogInputBuildup[osAnalogInputPos] <<
(12-ANALOG_INPUT_BITS-ANALOG_INPUT_SAMPLE);
#endif
#if ANALOG_INPUT_BITS+ANALOG_INPUT_SAMPLE>12
osAnalogInputValues[osAnalogInputPos] =
osAnalogInputBuildup[osAnalogInputPos] >>
(ANALOG_INPUT_BITS+ANALOG_INPUT_SAMPLE-12);
#endif
#if ANALOG_INPUT_BITS+ANALOG_INPUT_SAMPLE==12
osAnalogInputValues[osAnalogInputPos] =
osAnalogInputBuildup[osAnalogInputPos];
#endif
osAnalogInputBuildup[osAnalogInputPos] = 0;
osAnalogInputCounter[osAnalogInputPos] = 0;
// Start next conversion
if(++osAnalogInputPos>=ANALOG_INPUTS) osAnalogInputPos = 0;
byte channel = pgm_read_byte(&osAnalogInputChannels[osAnalogInputPos]);
#if defined(ADCSRB) && defined(MUX5)
if(channel & 8) // Reading channel 0-7 or 8-15?
ADCSRB |= _BV(MUX5);
else
ADCSRB &= ~_BV(MUX5);
#endif
ADMUX = (ADMUX & ~(0x1F)) | (channel & 7);
}
ADCSRA |= _BV(ADSC); // start next conversion
}
#endif
UI_FAST; // Short timed user interface action
pwm_count++;
}