/* 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++; }