From 7907edf72e769ae181b69e743cb57ac990f695d8 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Mon, 22 Aug 2011 17:42:58 +0200 Subject: [PATCH 001/130] first compile using arduino22 --- Marlin/Configuration.h | 4 +- Marlin/Marlin.h | 104 ++++++++++++---------- Marlin/Marlin.pde | 14 ++- Marlin/pins.h | 75 +++++++++++++++- Marlin/speed_lookuptable.h | 8 +- Marlin/wiring.c | 176 ------------------------------------- Marlin/wiring_serial.c | 139 ----------------------------- 7 files changed, 147 insertions(+), 373 deletions(-) delete mode 100644 Marlin/wiring.c delete mode 100644 Marlin/wiring_serial.c diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 134dff961ac4..dd5d2fd3666d 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -5,7 +5,7 @@ //// The following define selects which electronics board you have. Please choose the one that matches your setup // Gen6 = 5, -#define MOTHERBOARD 5 +#define MOTHERBOARD 7 //// Thermistor settings: // 1 is 100k thermistor @@ -28,7 +28,7 @@ const bool ENDSTOPS_INVERTING = false; // set to true to invert the logic of the // For optos H21LOB set to true, for Mendel-Parts newer optos TCST2103 set to false // This determines the communication speed of the printer -#define BAUDRATE 250000 +#define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: //#define SDSUPPORT diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index f0c33965743e..8e9e90f4d551 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -1,9 +1,41 @@ +#ifndef __MARLINH +#define __MARLINH + +typedef struct { + // Fields used by the bresenham algorithm for tracing the line + long steps_x, steps_y, steps_z, steps_e; // Step count along each axis + long step_event_count; // The number of step events required to complete this block + volatile long accelerate_until; // The index of the step event on which to stop acceleration + volatile long decelerate_after; // The index of the step event on which to start decelerating + volatile long acceleration_rate; // The acceleration rate used for acceleration calculation + unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h) + + long advance_rate; + volatile long initial_advance; + volatile long final_advance; + float advance; + + // Fields used by the motion planner to manage acceleration + float speed_x, speed_y, speed_z, speed_e; // Nominal mm/minute for each axis + float nominal_speed; // The nominal speed for this block in mm/min + float millimeters; // The total travel of this block in mm + float entry_speed; + + // Settings for the trapezoid generator + long nominal_rate; // The nominal step rate for this block in step_events/sec + volatile long initial_rate; // The jerk-adjusted step rate at start of block + volatile long final_rate; // The minimal rate at exit + long acceleration; // acceleration mm/sec^2 + volatile char busy; +} block_t; + + // Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. // Licence: GPL #include #include "fastio.h" -extern "C" void __cxa_pure_virtual(); -void __cxa_pure_virtual(){}; +//extern "C" void __cxa_pure_virtual(); +//void __cxa_pure_virtual(){}; void get_command(); void process_commands(); @@ -12,6 +44,7 @@ void manage_inactivity(byte debug); void manage_heater(); int temp2analogu(int celsius, const short table[][2], int numtemps); float analog2tempu(int raw, const short table[][2], int numtemps); + #ifdef HEATER_USES_THERMISTOR #define HEATERSOURCE 1 #endif @@ -23,32 +56,35 @@ float analog2tempu(int raw, const short table[][2], int numtemps); #define analog2temp( c ) analog2tempu((c),temptable,NUMTEMPS) #if X_ENABLE_PIN > -1 -#define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) -#define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) + #define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) + #define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) #else -#define enable_x() ; -#define disable_x() ; + #define enable_x() ; + #define disable_x() ; #endif + #if Y_ENABLE_PIN > -1 -#define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) -#define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) + #define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) + #define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) #else -#define enable_y() ; -#define disable_y() ; + #define enable_y() ; + #define disable_y() ; #endif + #if Z_ENABLE_PIN > -1 -#define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) -#define disable_z() WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON) + #define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) + #define disable_z() WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON) #else -#define enable_z() ; -#define disable_z() ; + #define enable_z() ; + #define disable_z() ; #endif + #if E_ENABLE_PIN > -1 -#define enable_e() WRITE(E_ENABLE_PIN, E_ENABLE_ON) -#define disable_e() WRITE(E_ENABLE_PIN,!E_ENABLE_ON) + #define enable_e() WRITE(E_ENABLE_PIN, E_ENABLE_ON) + #define disable_e() WRITE(E_ENABLE_PIN,!E_ENABLE_ON) #else -#define enable_e() ; -#define disable_e() ; + #define enable_e() ; + #define disable_e() ; #endif #define X_AXIS 0 @@ -56,6 +92,8 @@ float analog2tempu(int raw, const short table[][2], int numtemps); #define Z_AXIS 2 #define E_AXIS 3 + + void FlushSerialRequestResend(); void ClearToSend(); @@ -65,35 +103,6 @@ void linear_move(unsigned long steps_remaining[]); void do_step(int axis); void kill(byte debug); -// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in -// the source g-code and may never actually be reached if acceleration management is active. -typedef struct { - // Fields used by the bresenham algorithm for tracing the line - long steps_x, steps_y, steps_z, steps_e; // Step count along each axis - long step_event_count; // The number of step events required to complete this block - volatile long accelerate_until; // The index of the step event on which to stop acceleration - volatile long decelerate_after; // The index of the step event on which to start decelerating - volatile long acceleration_rate; // The acceleration rate used for acceleration calculation - unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h) - - long advance_rate; - volatile long initial_advance; - volatile long final_advance; - float advance; - - // Fields used by the motion planner to manage acceleration - float speed_x, speed_y, speed_z, speed_e; // Nominal mm/minute for each axis - float nominal_speed; // The nominal speed for this block in mm/min - float millimeters; // The total travel of this block in mm - float entry_speed; - - // Settings for the trapezoid generator - long nominal_rate; // The nominal step rate for this block in step_events/sec - volatile long initial_rate; // The jerk-adjusted step rate at start of block - volatile long final_rate; // The minimal rate at exit - long acceleration; // acceleration mm/sec^2 - volatile char busy; -} block_t; void check_axes_activity(); void plan_init(); @@ -105,3 +114,4 @@ void st_wake_up(); void st_synchronize(); +#endif \ No newline at end of file diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index d1a98565edf5..1a1e65565c70 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1,3 +1,10 @@ +#include "Marlin.h" +// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in +// the source g-code and may never actually be reached if acceleration management is active. + + +#include "speed_lookuptable.h" + /* Reprap firmware based on Sprinter and grbl. Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm @@ -27,11 +34,11 @@ This firmware is optimized for gen6 electronics. */ + + #include "fastio.h" #include "Configuration.h" #include "pins.h" -#include "Marlin.h" -#include "speed_lookuptable.h" char version_string[] = "0.9.3"; @@ -220,6 +227,7 @@ void setup() for(int i = 0; i < BUFSIZE; i++){ fromsd[i] = false; } + //Initialize Dir Pins #if X_DIR_PIN > -1 @@ -1195,7 +1203,7 @@ void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit #ifdef ADVANCE block->initial_advance = initial_advance; block->final_advance = final_advance; -#endif ADVANCE +#endif //ADVANCE } CRITICAL_SECTION_END; } diff --git a/Marlin/pins.h b/Marlin/pins.h index 1bd670266cab..2472b8938438 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -485,10 +485,81 @@ #define SDPOWER -1 #define SDSS 31 -#ifndef KNOWN_BOARD -#error Unknown MOTHERBOARD value in configuration.h + + + + + + +#endif + + +#if MOTHERBOARD == 7 +#define KNOWN_BOARD +/***************************************************************** +* Ultimaker pin assignment +******************************************************************/ + +#ifndef __AVR_ATmega1280__ + #ifndef __AVR_ATmega2560__ + #error Oops! Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu. + #endif #endif +#define X_STEP_PIN 25 +#define X_DIR_PIN 23 +#define X_MIN_PIN 22 +#define X_MAX_PIN 24 +#define X_ENABLE_PIN 27 + +#define Y_STEP_PIN 31 +#define Y_DIR_PIN 33 +#define Y_MIN_PIN 26 +#define Y_MAX_PIN 28 +#define Y_ENABLE_PIN 29 + +#define Z_STEP_PIN 37 +#define Z_DIR_PIN 39 +#define Z_MIN_PIN 30 +#define Z_MAX_PIN 32 +#define Z_ENABLE_PIN 35 + +#define HEATER_1_PIN 4 +#define TEMP_1_PIN 11 + +#define EXTRUDER_0_STEP_PIN 43 +#define EXTRUDER_0_DIR_PIN 45 +#define EXTRUDER_0_ENABLE_PIN 41 +#define HEATER_0_PIN 2 +#define TEMP_0_PIN 8 + +#define EXTRUDER_1_STEP_PIN 49 +#define EXTRUDER_1_DIR_PIN 47 +#define EXTRUDER_1_ENABLE_PIN 51 +#define EXTRUDER_1_HEATER_PIN 3 +#define EXTRUDER_1_TEMPERATURE_PIN 10 + +#define LCD_PINS_RS 16 +#define LCD_PINS_ENABLE 5 +#define LCD_PINS_D4 6 +#define LCD_PINS_D5 21 +#define LCD_PINS_D6 20 +#define LCD_PINS_D7 19 + +#define E_STEP_PIN EXTRUDER_0_STEP_PIN +#define E_DIR_PIN EXTRUDER_0_DIR_PIN +#define E_ENABLE_PIN EXTRUDER_0_ENABLE_PIN + +#define SDPOWER -1 +#define SDSS 53 +#define LED_PIN 13 +#define FAN_PIN 7 +#define PS_ON_PIN 12 +#define KILL_PIN -1 #endif + +#ifndef KNOWN_BOARD +#error Unknown MOTHERBOARD value in configuration.h +#endif #endif diff --git a/Marlin/speed_lookuptable.h b/Marlin/speed_lookuptable.h index 5c54a08d1cd2..43ef89980d91 100644 --- a/Marlin/speed_lookuptable.h +++ b/Marlin/speed_lookuptable.h @@ -3,7 +3,7 @@ #include -uint16_t speed_lookuptable_fast[256][2] PROGMEM = { +uint16_t speed_lookuptable_fast[256][2] PROGMEM = {\ { 62500, 55556}, { 6944, 3268}, { 3676, 1176}, { 2500, 607}, { 1893, 369}, { 1524, 249}, { 1275, 179}, { 1096, 135}, { 961, 105}, { 856, 85}, { 771, 69}, { 702, 58}, { 644, 49}, { 595, 42}, { 553, 37}, { 516, 32}, { 484, 28}, { 456, 25}, { 431, 23}, { 408, 20}, { 388, 19}, { 369, 16}, { 353, 16}, { 337, 14}, @@ -35,9 +35,9 @@ uint16_t speed_lookuptable_fast[256][2] PROGMEM = { { 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 1}, { 33, 0}, { 33, 0}, { 33, 0}, { 33, 0}, { 33, 0}, { 33, 0}, { 33, 1}, { 32, 0}, { 32, 0}, { 32, 0}, { 32, 0}, { 32, 0}, { 32, 0}, { 32, 0}, { 32, 1}, { 31, 0}, { 31, 0}, { 31, 0}, -{ 31, 0}, { 31, 0}, { 31, 0}, { 31, 1}, { 30, 0}, { 30, 0}, { 30, 0}, { 30, 0}, +{ 31, 0}, { 31, 0}, { 31, 0}, { 31, 1}, { 30, 0}, { 30, 0}, { 30, 0}, { 30, 0} }; -uint16_t speed_lookuptable_slow[256][2] PROGMEM = { +uint16_t speed_lookuptable_slow[256][2] PROGMEM = {\ { 62500, 12500}, { 50000, 8334}, { 41666, 5952}, { 35714, 4464}, { 31250, 3473}, { 27777, 2777}, { 25000, 2273}, { 22727, 1894}, { 20833, 1603}, { 19230, 1373}, { 17857, 1191}, { 16666, 1041}, { 15625, 920}, { 14705, 817}, { 13888, 731}, { 13157, 657}, { 12500, 596}, { 11904, 541}, { 11363, 494}, { 10869, 453}, { 10416, 416}, { 10000, 385}, { 9615, 356}, { 9259, 331}, @@ -69,7 +69,7 @@ uint16_t speed_lookuptable_slow[256][2] PROGMEM = { { 1096, 5}, { 1091, 5}, { 1086, 4}, { 1082, 5}, { 1077, 5}, { 1072, 4}, { 1068, 5}, { 1063, 4}, { 1059, 5}, { 1054, 4}, { 1050, 4}, { 1046, 5}, { 1041, 4}, { 1037, 4}, { 1033, 5}, { 1028, 4}, { 1024, 4}, { 1020, 4}, { 1016, 4}, { 1012, 4}, { 1008, 4}, { 1004, 4}, { 1000, 4}, { 996, 4}, -{ 992, 4}, { 988, 4}, { 984, 4}, { 980, 4}, { 976, 4}, { 972, 4}, { 968, 3}, { 965, 3}, +{ 992, 4}, { 988, 4}, { 984, 4}, { 980, 4}, { 976, 4}, { 972, 4}, { 968, 3}, { 965, 3} }; #endif diff --git a/Marlin/wiring.c b/Marlin/wiring.c deleted file mode 100644 index adee6cbe44af..000000000000 --- a/Marlin/wiring.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - wiring.c - Partial implementation of the Wiring API for the ATmega8. - Part of Arduino - http://www.arduino.cc/ - - Copyright (c) 2005-2006 David A. Mellis - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with this library; if not, write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - $Id: wiring.c 388 2008-03-08 22:05:23Z mellis $ -*/ - -#include "wiring_private.h" - -volatile unsigned long timer0_millis = 0; - -SIGNAL(TIMER0_OVF_vect) -{ - // timer 0 prescale factor is 64 and the timer overflows at 256 - timer0_millis++; -} - -unsigned long millis() -{ - unsigned long m; - uint8_t oldSREG = SREG; - - // disable interrupts while we read timer0_millis or we might get an - // inconsistent value (e.g. in the middle of the timer0_millis++) - cli(); - m = timer0_millis; - SREG = oldSREG; - - return m; -} - -void delay(unsigned long ms) -{ - unsigned long start = millis(); - - while (millis() - start <= ms) - ; -} - -/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. - * Disables interrupts, which will disrupt the millis() function if used - * too frequently. */ -void delayMicroseconds(unsigned int us) -{ - uint8_t oldSREG; - - // calling avrlib's delay_us() function with low values (e.g. 1 or - // 2 microseconds) gives delays longer than desired. - //delay_us(us); - -#if F_CPU >= 16000000L - // for the 16 MHz clock on most Arduino boards - - // for a one-microsecond delay, simply return. the overhead - // of the function call yields a delay of approximately 1 1/8 us. - if (--us == 0) - return; - - // the following loop takes a quarter of a microsecond (4 cycles) - // per iteration, so execute it four times for each microsecond of - // delay requested. - us <<= 2; - - // account for the time taken in the preceeding commands. - us -= 2; -#else - // for the 8 MHz internal clock on the ATmega168 - - // for a one- or two-microsecond delay, simply return. the overhead of - // the function calls takes more than two microseconds. can't just - // subtract two, since us is unsigned; we'd overflow. - if (--us == 0) - return; - if (--us == 0) - return; - - // the following loop takes half of a microsecond (4 cycles) - // per iteration, so execute it twice for each microsecond of - // delay requested. - us <<= 1; - - // partially compensate for the time taken by the preceeding commands. - // we can't subtract any more than this or we'd overflow w/ small delays. - us--; -#endif - - // disable interrupts, otherwise the timer 0 overflow interrupt that - // tracks milliseconds will make us delay longer than we want. - oldSREG = SREG; - cli(); - - // busy wait - __asm__ __volatile__ ( - "1: sbiw %0,1" "\n\t" // 2 cycles - "brne 1b" : "=w" (us) : "0" (us) // 2 cycles - ); - - // reenable interrupts. - SREG = oldSREG; -} - -void init() -{ - // this needs to be called before setup() or some functions won't - // work there - sei(); - - // on the ATmega168, timer 0 is also used for fast hardware pwm - // (using phase-correct PWM would mean that timer 0 overflowed half as often - // resulting in different millis() behavior on the ATmega8 and ATmega168) - sbi(TCCR0A, WGM01); - sbi(TCCR0A, WGM00); - - // set timer 0 prescale factor to 64 - sbi(TCCR0B, CS01); - sbi(TCCR0B, CS00); - - // enable timer 0 overflow interrupt - sbi(TIMSK0, TOIE0); - - // timers 1 and 2 are used for phase-correct hardware pwm - // this is better for motors as it ensures an even waveform - // note, however, that fast pwm mode can achieve a frequency of up - // 8 MHz (with a 16 MHz clock) at 50% duty cycle -#if 0 - // set timer 1 prescale factor to 64 - sbi(TCCR1B, CS11); - sbi(TCCR1B, CS10); - - // put timer 1 in 8-bit phase correct pwm mode - sbi(TCCR1A, WGM10); - - // set timer 2 prescale factor to 64 - sbi(TCCR2B, CS22); - - // configure timer 2 for phase correct pwm (8-bit) - sbi(TCCR2A, WGM20); - - // set a2d prescale factor to 128 - // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range. - // XXX: this will not work properly for other clock speeds, and - // this code should use F_CPU to determine the prescale factor. - sbi(ADCSRA, ADPS2); - sbi(ADCSRA, ADPS1); - sbi(ADCSRA, ADPS0); - - // enable a2d conversions - sbi(ADCSRA, ADEN); - - // the bootloader connects pins 0 and 1 to the USART; disconnect them - // here so they can be used as normal digital i/o; they will be - // reconnected in Serial.begin() - UCSR0B = 0; - #if defined(__AVR_ATmega644P__) - //TODO: test to see if disabling this helps? - //UCSR1B = 0; - #endif -#endif -} diff --git a/Marlin/wiring_serial.c b/Marlin/wiring_serial.c deleted file mode 100644 index c027944c9030..000000000000 --- a/Marlin/wiring_serial.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - wiring_serial.c - serial functions. - Part of Arduino - http://www.arduino.cc/ - - Copyright (c) 2005-2006 David A. Mellis - Modified 29 January 2009, Marius Kintel for Sanguino - http://www.sanguino.cc/ - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with this library; if not, write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ -*/ - - -#include "wiring_private.h" - -// Define constants and variables for buffering incoming serial data. We're -// using a ring buffer (I think), in which rx_buffer_head is the index of the -// location to which to write the next incoming character and rx_buffer_tail -// is the index of the location from which to read. -#define RX_BUFFER_SIZE 128 -#define RX_BUFFER_MASK 0x7f - -#if defined(__AVR_ATmega644P__) -unsigned char rx_buffer[2][RX_BUFFER_SIZE]; -int rx_buffer_head[2] = {0, 0}; -int rx_buffer_tail[2] = {0, 0}; -#else -unsigned char rx_buffer[1][RX_BUFFER_SIZE]; -int rx_buffer_head[1] = {0}; -int rx_buffer_tail[1] = {0}; -#endif - - -#define BEGIN_SERIAL(uart_, baud_) \ -{ \ - UBRR##uart_##H = ((F_CPU / 16 + baud / 2) / baud - 1) >> 8; \ - UBRR##uart_##L = ((F_CPU / 16 + baud / 2) / baud - 1); \ - \ - /* reset config for UART */ \ - UCSR##uart_##A = 0; \ - UCSR##uart_##B = 0; \ - UCSR##uart_##C = 0; \ - \ - /* enable rx and tx */ \ - sbi(UCSR##uart_##B, RXEN##uart_);\ - sbi(UCSR##uart_##B, TXEN##uart_);\ - \ - /* enable interrupt on complete reception of a byte */ \ - sbi(UCSR##uart_##B, RXCIE##uart_); \ - UCSR##uart_##C = _BV(UCSZ##uart_##1)|_BV(UCSZ##uart_##0); \ - /* defaults to 8-bit, no parity, 1 stop bit */ \ -} - -void beginSerial(uint8_t uart, long baud) -{ - if (uart == 0) BEGIN_SERIAL(0, baud) -#if defined(__AVR_ATmega644P__) - else BEGIN_SERIAL(1, baud) -#endif -} - -#define SERIAL_WRITE(uart_, c_) \ - while (!(UCSR##uart_##A & (1 << UDRE##uart_))) \ - ; \ - UDR##uart_ = c - -void serialWrite(uint8_t uart, unsigned char c) -{ - if (uart == 0) { - SERIAL_WRITE(0, c); - } -#if defined(__AVR_ATmega644P__) - else { - SERIAL_WRITE(1, c); - } -#endif -} - -int serialAvailable(uint8_t uart) -{ - return (RX_BUFFER_SIZE + rx_buffer_head[uart] - rx_buffer_tail[uart]) & RX_BUFFER_MASK; -} - -int serialRead(uint8_t uart) -{ - // if the head isn't ahead of the tail, we don't have any characters - if (rx_buffer_head[uart] == rx_buffer_tail[uart]) { - return -1; - } else { - unsigned char c = rx_buffer[uart][rx_buffer_tail[uart]]; - rx_buffer_tail[uart] = (rx_buffer_tail[uart] + 1) & RX_BUFFER_MASK; - return c; - } -} - -void serialFlush(uint8_t uart) -{ - // don't reverse this or there may be problems if the RX interrupt - // occurs after reading the value of rx_buffer_head but before writing - // the value to rx_buffer_tail; the previous value of rx_buffer_head - // may be written to rx_buffer_tail, making it appear as if the buffer - // were full, not empty. - rx_buffer_head[uart] = rx_buffer_tail[uart]; -} - -#define UART_ISR(uart_) \ -ISR(USART##uart_##_RX_vect) \ -{ \ - unsigned char c = UDR##uart_; \ - \ - int i = (rx_buffer_head[uart_] + 1) & RX_BUFFER_MASK; \ - \ - /* if we should be storing the received character into the location \ - just before the tail (meaning that the head would advance to the \ - current location of the tail), we're about to overflow the buffer \ - and so we don't write the character or advance the head. */ \ - if (i != rx_buffer_tail[uart_]) { \ - rx_buffer[uart_][rx_buffer_head[uart_]] = c; \ - rx_buffer_head[uart_] = i; \ - } \ -} - -UART_ISR(0) -#if defined(__AVR_ATmega644P__) -UART_ISR(1) -#endif From 36d1c3f62ae922dfec8eb670ba6f1b89f522abfd Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Mon, 22 Aug 2011 17:47:46 +0200 Subject: [PATCH 002/130] better settings --- Marlin/Configuration.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index dd5d2fd3666d..cb3cf4e92ec1 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -16,7 +16,7 @@ //// Calibration variables // X, Y, Z, E steps per unit - Metric Mendel / Orca with V9 extruder: -float axis_steps_per_unit[] = {40, 40, 3333.92, 67}; +float axis_steps_per_unit[] = {79.87220447, 79.87220447, 200*8/3., 14}; // For E steps per unit = 67 for v9 with direct drive (needs finetuning) for other extruders this needs to be changed // Metric Prusa Mendel with Makergear geared stepper extruder: //float axis_steps_per_unit[] = {80,80,3200/1.25,1380}; @@ -24,7 +24,7 @@ float axis_steps_per_unit[] = {40, 40, 3333.92, 67}; //// Endstop Settings #define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors // The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins. -const bool ENDSTOPS_INVERTING = false; // set to true to invert the logic of the endstops. +const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the endstops. // For optos H21LOB set to true, for Mendel-Parts newer optos TCST2103 set to false // This determines the communication speed of the printer From 57d0011fb138d9020b54b04f550c5dea1b6fc4ab Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 23 Aug 2011 14:10:02 +0200 Subject: [PATCH 003/130] dis-funcional ad595 --- Marlin/Configuration.h | 280 +-- Marlin/Marlin.h | 16 +- Marlin/Marlin.pde | 4386 +++++++++++++++++++++------------------- 3 files changed, 2492 insertions(+), 2190 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index cb3cf4e92ec1..af5b16e0a18b 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -1,134 +1,146 @@ -#ifndef CONFIGURATION_H -#define CONFIGURATION_H - -// BASIC SETTINGS: select your board type, thermistor type, axis scaling, and endstop configuration - -//// The following define selects which electronics board you have. Please choose the one that matches your setup -// Gen6 = 5, -#define MOTHERBOARD 7 - -//// Thermistor settings: -// 1 is 100k thermistor -// 2 is 200k thermistor -// 3 is mendel-parts thermistor -#define THERMISTORHEATER 3 - - -//// Calibration variables -// X, Y, Z, E steps per unit - Metric Mendel / Orca with V9 extruder: -float axis_steps_per_unit[] = {79.87220447, 79.87220447, 200*8/3., 14}; -// For E steps per unit = 67 for v9 with direct drive (needs finetuning) for other extruders this needs to be changed -// Metric Prusa Mendel with Makergear geared stepper extruder: -//float axis_steps_per_unit[] = {80,80,3200/1.25,1380}; - -//// Endstop Settings -#define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors -// The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins. -const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the endstops. -// For optos H21LOB set to true, for Mendel-Parts newer optos TCST2103 set to false - -// This determines the communication speed of the printer -#define BAUDRATE 115200 - -// Comment out (using // at the start of the line) to disable SD support: -//#define SDSUPPORT - - -//// ADVANCED SETTINGS - to tweak parameters - -#include "thermistortables.h" - -// For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1 -#define X_ENABLE_ON 0 -#define Y_ENABLE_ON 0 -#define Z_ENABLE_ON 0 -#define E_ENABLE_ON 0 - -// Disables axis when it's not being used. -#define DISABLE_X false -#define DISABLE_Y false -#define DISABLE_Z true -#define DISABLE_E false - -// Inverting axis direction -#define INVERT_X_DIR true // for Mendel set to false, for Orca set to true -#define INVERT_Y_DIR false // for Mendel set to true, for Orca set to false -#define INVERT_Z_DIR true // for Mendel set to false, for Orca set to true -#define INVERT_E_DIR true // for direct drive extruder v9 set to true, for geared extruder set to false - -//// ENDSTOP SETTINGS: -// Sets direction of endstops when homing; 1=MAX, -1=MIN -#define X_HOME_DIR -1 -#define Y_HOME_DIR -1 -#define Z_HOME_DIR -1 - -#define min_software_endstops false //If true, axis won't move to coordinates less than zero. -#define max_software_endstops true //If true, axis won't move to coordinates greater than the defined lengths below. -#define X_MAX_LENGTH 200 -#define Y_MAX_LENGTH 200 -#define Z_MAX_LENGTH 100 - -//// MOVEMENT SETTINGS -#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {60000, 60000, 100, 500000}; // set the max speeds -float homing_feedrate[] = {2400, 2400, 80, 0}; // set the homing speeds -bool axis_relative_modes[] = {false, false, false, false}; - -//// Acceleration settings -// X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. -float acceleration = 2000; // Normal acceleration mm/s^2 -float retract_acceleration = 7000; // Normal acceleration mm/s^2 -float max_jerk = 20*60; -long max_acceleration_units_per_sq_second[] = {7000,7000,100,10000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts -// Not used long max_travel_acceleration_units_per_sq_second[] = {500,500,50,500}; // X, Y, Z max acceleration in mm/s^2 for travel moves - - -// The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature -// If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 -//#define WATCHPERIOD 5000 //5 seconds - -//// The minimal temperature defines the temperature below which the heater will not be enabled -#define MINTEMP 5 - - -// When temperature exceeds max temp, your heater will be switched off. -// This feature exists to protect your hotend from overheating accidentally, but *NOT* from thermistor short/failure! -// You should use MINTEMP for thermistor short/failure protection. -#define MAXTEMP 275 - - -/// PID settings: -// Uncomment the following line to enable PID support. -//#define PIDTEMP -#ifdef PIDTEMP -//#define PID_DEBUG 1 // Sends debug data to the serial port. -//#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % -#define PID_MAX 156 // limits current to nozzle -#define PID_INTEGRAL_DRIVE_MAX 156.0 -#define PID_dT 0.16 -double Kp = 20.0; -double Ki = 1.5*PID_dT; -double Kd = 80/PID_dT; -#endif // PIDTEMP - - -// extruder advance constant (s2/mm3) -// -// advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2 -// -// hooke's law says: force = k * distance -// bernoulli's priniciple says: v ^ 2 / 2 + g . h + pressure / density = constant -// so: v ^ 2 is proportional to number of steps we advance the extruder -//#define ADVANCE - -#ifdef ADVANCE -#define EXTRUDER_ADVANCE_K 0.02 - -#define D_FILAMENT 1.7 -#define STEPS_MM_E 65 -#define EXTRUTION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159) -#define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUTION_AREA) - -#endif // ADVANCE - -#endif +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +// BASIC SETTINGS: select your board type, thermistor type, axis scaling, and endstop configuration + +//// The following define selects which electronics board you have. Please choose the one that matches your setup +// Gen6 = 5, +#define MOTHERBOARD 7 + +//// Thermistor settings: +// 1 is 100k thermistor +// 2 is 200k thermistor +// 3 is mendel-parts thermistor +#define THERMISTORHEATER 2 +// Select one of these only to define how the nozzle temp is read. +//#define HEATER_USES_THERMISTOR +#define HEATER_USES_AD595 +//#define HEATER_USES_MAX6675 + +// Select one of these only to define how the bed temp is read. +//#define BED_USES_THERMISTOR +//#define BED_USES_AD595 + +#define HEATER_CHECK_INTERVAL 50 +#define BED_CHECK_INTERVAL 5000 +#define BNUMTEMPS NUMTEMPS +#define bedtemptable temptable + +//// Calibration variables +// X, Y, Z, E steps per unit - Metric Mendel / Orca with V9 extruder: +float axis_steps_per_unit[] = {79.87220447, 79.87220447, 200*8/3., 14}; +// For E steps per unit = 67 for v9 with direct drive (needs finetuning) for other extruders this needs to be changed +// Metric Prusa Mendel with Makergear geared stepper extruder: +//float axis_steps_per_unit[] = {80,80,3200/1.25,1380}; + +//// Endstop Settings +#define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors +// The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins. +const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the endstops. +// For optos H21LOB set to true, for Mendel-Parts newer optos TCST2103 set to false + +// This determines the communication speed of the printer +#define BAUDRATE 115200 + +// Comment out (using // at the start of the line) to disable SD support: +//#define SDSUPPORT + + +//// ADVANCED SETTINGS - to tweak parameters + +#include "thermistortables.h" + +// For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1 +#define X_ENABLE_ON 0 +#define Y_ENABLE_ON 0 +#define Z_ENABLE_ON 0 +#define E_ENABLE_ON 0 + +// Disables axis when it's not being used. +#define DISABLE_X false +#define DISABLE_Y false +#define DISABLE_Z true +#define DISABLE_E false + +// Inverting axis direction +#define INVERT_X_DIR true // for Mendel set to false, for Orca set to true +#define INVERT_Y_DIR false // for Mendel set to true, for Orca set to false +#define INVERT_Z_DIR true // for Mendel set to false, for Orca set to true +#define INVERT_E_DIR false // for direct drive extruder v9 set to true, for geared extruder set to false + +//// ENDSTOP SETTINGS: +// Sets direction of endstops when homing; 1=MAX, -1=MIN +#define X_HOME_DIR -1 +#define Y_HOME_DIR -1 +#define Z_HOME_DIR -1 + +#define min_software_endstops false //If true, axis won't move to coordinates less than zero. +#define max_software_endstops true //If true, axis won't move to coordinates greater than the defined lengths below. +#define X_MAX_LENGTH 200 +#define Y_MAX_LENGTH 200 +#define Z_MAX_LENGTH 100 + +//// MOVEMENT SETTINGS +#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E +float max_feedrate[] = {60000, 60000, 500, 500000}; // set the max speeds +float homing_feedrate[] = {2400, 2400, 150, 0}; // set the homing speeds +bool axis_relative_modes[] = {false, false, false, false}; + +//// Acceleration settings +// X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. +float acceleration = 2000; // Normal acceleration mm/s^2 +float retract_acceleration = 7000; // Normal acceleration mm/s^2 +float max_jerk = 20*60; +long max_acceleration_units_per_sq_second[] = {7000,7000,100,10000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts +// Not used long max_travel_acceleration_units_per_sq_second[] = {500,500,50,500}; // X, Y, Z max acceleration in mm/s^2 for travel moves + + +// The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature +// If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 +//#define WATCHPERIOD 5000 //5 seconds + +//// The minimal temperature defines the temperature below which the heater will not be enabled +#define MINTEMP 5 + + +// When temperature exceeds max temp, your heater will be switched off. +// This feature exists to protect your hotend from overheating accidentally, but *NOT* from thermistor short/failure! +// You should use MINTEMP for thermistor short/failure protection. +#define MAXTEMP 275 + + +/// PID settings: +// Uncomment the following line to enable PID support. +//#define PIDTEMP +#ifdef PIDTEMP +//#define PID_DEBUG 1 // Sends debug data to the serial port. +//#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % +#define PID_MAX 156 // limits current to nozzle +#define PID_INTEGRAL_DRIVE_MAX 156.0 +#define PID_dT 0.16 +double Kp = 20.0; +double Ki = 1.5*PID_dT; +double Kd = 80/PID_dT; +#endif // PIDTEMP + + +// extruder advance constant (s2/mm3) +// +// advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2 +// +// hooke's law says: force = k * distance +// bernoulli's priniciple says: v ^ 2 / 2 + g . h + pressure / density = constant +// so: v ^ 2 is proportional to number of steps we advance the extruder +//#define ADVANCE + +#ifdef ADVANCE +#define EXTRUDER_ADVANCE_K 0.02 + +#define D_FILAMENT 1.7 +#define STEPS_MM_E 65 +#define EXTRUTION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159) +#define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUTION_AREA) + +#endif // ADVANCE + +#endif diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 8e9e90f4d551..0f7ae7cc4e5b 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -42,8 +42,12 @@ void process_commands(); void manage_inactivity(byte debug); void manage_heater(); -int temp2analogu(int celsius, const short table[][2], int numtemps); -float analog2tempu(int raw, const short table[][2], int numtemps); +//int temp2analogu(int celsius, const short table[][2], int numtemps); +//float analog2tempu(int raw, const short table[][2], int numtemps); +float temp2analog(int celsius); +float temp2analogBed(int celsius); +float analog2temp(int raw); +float analog2tempBed(int raw); #ifdef HEATER_USES_THERMISTOR #define HEATERSOURCE 1 @@ -52,11 +56,11 @@ float analog2tempu(int raw, const short table[][2], int numtemps); #define BEDSOURCE 1 #endif -#define temp2analogh( c ) temp2analogu((c),temptable,NUMTEMPS) -#define analog2temp( c ) analog2tempu((c),temptable,NUMTEMPS) +//#define temp2analogh( c ) temp2analogu((c),temptable,NUMTEMPS) +//#define analog2temp( c ) analog2tempu((c),temptable,NUMTEMPS) #if X_ENABLE_PIN > -1 - #define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) + #define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) #define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) #else #define enable_x() ; @@ -114,4 +118,4 @@ void st_wake_up(); void st_synchronize(); -#endif \ No newline at end of file +#endif diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 1a1e65565c70..da93e8058547 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1,2050 +1,2336 @@ -#include "Marlin.h" -// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in -// the source g-code and may never actually be reached if acceleration management is active. - - -#include "speed_lookuptable.h" - -/* - Reprap firmware based on Sprinter and grbl. - Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm - - This program 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. - - This program 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 this program. If not, see . - */ - -/* - This firmware is a mashup between Sprinter and grbl. - (https://github.com/kliment/Sprinter) - (https://github.com/simen/grbl/tree) - - It has preliminary support for Matthew Roberts advance algorithm - http://reprap.org/pipermail/reprap-dev/2011-May/003323.html - - This firmware is optimized for gen6 electronics. - */ - - - -#include "fastio.h" -#include "Configuration.h" -#include "pins.h" - -char version_string[] = "0.9.3"; - -#ifdef SDSUPPORT -#include "SdFat.h" -#endif //SDSUPPORT - -#ifndef CRITICAL_SECTION_START -#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() -#define CRITICAL_SECTION_END SREG = _sreg -#endif //CRITICAL_SECTION_START - -// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html -// 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 -// G28 - Home all 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 -// 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 -// M115 - Capabilities string -// 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) -// M301 - Set PID parameters P I and D - -//Stepper Movement Variables - -char axis_codes[NUM_AXIS] = { - 'X', 'Y', 'Z', 'E'}; -float destination[NUM_AXIS] = { - 0.0, 0.0, 0.0, 0.0}; -float current_position[NUM_AXIS] = { - 0.0, 0.0, 0.0, 0.0}; -bool home_all_axis = true; -long feedrate = 1500, next_feedrate, saved_feedrate; -long gcode_N, gcode_LastN; -bool relative_mode = false; //Determines Absolute or Relative Coordinates -bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. -unsigned long axis_steps_per_sqr_second[NUM_AXIS]; - -// comm variables -#define MAX_CMD_SIZE 96 -#define BUFSIZE 8 -char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; -bool fromsd[BUFSIZE]; -int bufindr = 0; -int bufindw = 0; -int buflen = 0; -int i = 0; -char serial_char; -int serial_count = 0; -boolean comment_mode = false; -char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc - -// Manage heater variables. - -int target_raw = 0; -int current_raw = 0; -unsigned char temp_meas_ready = false; - -#ifdef PIDTEMP - double temp_iState = 0; - double temp_dState = 0; - double pTerm; - double iTerm; - double dTerm; - //int output; - double pid_error; - double temp_iState_min; - double temp_iState_max; - double pid_setpoint = 0.0; - double pid_input; - double pid_output; - bool pid_reset; -#endif //PIDTEMP - -#ifdef WATCHPERIOD -int watch_raw = -1000; -unsigned long watchmillis = 0; -#endif //WATCHPERIOD -#ifdef MINTEMP -int minttemp = temp2analogh(MINTEMP); -#endif //MINTEMP -#ifdef MAXTEMP -int maxttemp = temp2analogh(MAXTEMP); -#endif //MAXTEMP - -//Inactivity shutdown variables -unsigned long previous_millis_cmd = 0; -unsigned long max_inactive_time = 0; -unsigned long stepper_inactive_time = 0; - -#ifdef SDSUPPORT -Sd2Card card; -SdVolume volume; -SdFile root; -SdFile file; -uint32_t filesize = 0; -uint32_t sdpos = 0; -bool sdmode = false; -bool sdactive = false; -bool savetosd = false; -int16_t n; - -void initsd(){ - sdactive = false; -#if SDSS >- 1 - if(root.isOpen()) - root.close(); - if (!card.init(SPI_FULL_SPEED,SDSS)){ - //if (!card.init(SPI_HALF_SPEED,SDSS)) - Serial.println("SD init fail"); - } - else if (!volume.init(&card)) - Serial.println("volume.init failed"); - else if (!root.openRoot(&volume)) - Serial.println("openRoot failed"); - else - sdactive = true; -#endif //SDSS -} - -inline void write_command(char *buf){ - char* begin = buf; - char* npos = 0; - char* end = buf + strlen(buf) - 1; - - file.writeError = false; - if((npos = strchr(buf, 'N')) != NULL){ - begin = strchr(npos, ' ') + 1; - end = strchr(npos, '*') - 1; - } - end[1] = '\r'; - end[2] = '\n'; - end[3] = '\0'; - //Serial.println(begin); - file.write(begin); - if (file.writeError){ - Serial.println("error writing to file"); - } -} -#endif //SDSUPPORT - - -void setup() -{ - Serial.begin(BAUDRATE); - Serial.print("Marlin "); - Serial.println(version_string); - Serial.println("start"); - - for(int i = 0; i < BUFSIZE; i++){ - fromsd[i] = false; - } - - - //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 -#if E_DIR_PIN > -1 - SET_OUTPUT(E_DIR_PIN); -#endif - - //Initialize Enable Pins - steppers default to disabled. - -#if (X_ENABLE_PIN > -1) - SET_OUTPUT(X_ENABLE_PIN); - if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); -#endif -#if (Y_ENABLE_PIN > -1) - SET_OUTPUT(Y_ENABLE_PIN); - if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); -#endif -#if (Z_ENABLE_PIN > -1) - SET_OUTPUT(Z_ENABLE_PIN); - if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); -#endif -#if (E_ENABLE_PIN > -1) - SET_OUTPUT(E_ENABLE_PIN); - if(!E_ENABLE_ON) WRITE(E_ENABLE_PIN,HIGH); -#endif - - //endstops and pullups -#ifdef ENDSTOPPULLUPS -#if X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); - WRITE(X_MIN_PIN,HIGH); -#endif -#if X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); - WRITE(X_MAX_PIN,HIGH); -#endif -#if Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); - WRITE(Y_MIN_PIN,HIGH); -#endif -#if Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); - WRITE(Y_MAX_PIN,HIGH); -#endif -#if Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); - WRITE(Z_MIN_PIN,HIGH); -#endif -#if Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); - WRITE(Z_MAX_PIN,HIGH); -#endif -#else //ENDSTOPPULLUPS -#if X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); -#endif -#if X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); -#endif -#if Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); -#endif -#if Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); -#endif -#if Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); -#endif -#if Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); -#endif -#endif //ENDSTOPPULLUPS - -#if (HEATER_0_PIN > -1) - SET_OUTPUT(HEATER_0_PIN); -#endif -#if (HEATER_1_PIN > -1) - SET_OUTPUT(HEATER_1_PIN); -#endif - - //Initialize Step Pins -#if (X_STEP_PIN > -1) - SET_OUTPUT(X_STEP_PIN); -#endif -#if (Y_STEP_PIN > -1) - SET_OUTPUT(Y_STEP_PIN); -#endif -#if (Z_STEP_PIN > -1) - SET_OUTPUT(Z_STEP_PIN); -#endif -#if (E_STEP_PIN > -1) - SET_OUTPUT(E_STEP_PIN); -#endif - for(int i=0; i < NUM_AXIS; i++){ - axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; - } - -#ifdef PIDTEMP - temp_iState_min = 0.0; - temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; -#endif //PIDTEMP - -#ifdef SDSUPPORT - //power to SD reader -#if SDPOWER > -1 - SET_OUTPUT(SDPOWER); - WRITE(SDPOWER,HIGH); -#endif //SDPOWER - initsd(); - -#endif //SDSUPPORT - plan_init(); // Initialize planner; - st_init(); // Initialize stepper; - tp_init(); // Initialize temperature loop -} - - -void loop() -{ - if(buflen<3) - get_command(); - - if(buflen){ -#ifdef SDSUPPORT - if(savetosd){ - if(strstr(cmdbuffer[bufindr],"M29") == NULL){ - write_command(cmdbuffer[bufindr]); - Serial.println("ok"); - } - else{ - file.sync(); - file.close(); - savetosd = false; - Serial.println("Done saving file."); - } - } - else{ - process_commands(); - } -#else - process_commands(); -#endif //SDSUPPORT - buflen = (buflen-1); - bufindr = (bufindr + 1)%BUFSIZE; - } - //check heater every n milliseconds - manage_heater(); - manage_inactivity(1); -} - - -inline void get_command() -{ - while( Serial.available() > 0 && buflen < BUFSIZE) { - serial_char = Serial.read(); - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) - { - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = false; - if(strstr(cmdbuffer[bufindw], "N") != NULL) - { - strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); - gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); - if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { - Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); - Serial.println(gcode_LastN); - //Serial.println(gcode_N); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - if(strstr(cmdbuffer[bufindw], "*") != NULL) - { - byte checksum = 0; - byte count = 0; - while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; - strchr_pointer = strchr(cmdbuffer[bufindw], '*'); - - if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { - Serial.print("Error: checksum mismatch, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - //if no errors, continue parsing - } - else - { - Serial.print("Error: No Checksum with line number, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - gcode_LastN = gcode_N; - //if no errors, continue parsing - } - else // if we don't receive 'N' but still see '*' - { - if((strstr(cmdbuffer[bufindw], "*") != NULL)) - { - Serial.print("Error: No Line Number with checksum, Last Line:"); - Serial.println(gcode_LastN); - serial_count = 0; - return; - } - } - if((strstr(cmdbuffer[bufindw], "G") != NULL)){ - strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); - switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ - case 0: - case 1: -#ifdef SDSUPPORT - if(savetosd) - break; -#endif //SDSUPPORT - Serial.println("ok"); - break; - default: - break; - } - - } - bufindw = (bufindw + 1)%BUFSIZE; - buflen += 1; - - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } - } -#ifdef SDSUPPORT - if(!sdmode || serial_count!=0){ - return; - } - while( filesize > sdpos && buflen < BUFSIZE) { - n = file.read(); - serial_char = (char)n; - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) - { - sdpos = file.curPosition(); - if(sdpos >= filesize){ - sdmode = false; - Serial.println("Done printing file"); - } - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = true; - buflen += 1; - bufindw = (bufindw + 1)%BUFSIZE; - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } - } -#endif //SDSUPPORT - -} - - -inline float code_value() { - return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); -} -inline long code_value_long() { - return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); -} -inline bool code_seen(char code_string[]) { - return (strstr(cmdbuffer[bufindr], code_string) != NULL); -} //Return True if the string was found - -inline bool code_seen(char code) -{ - strchr_pointer = strchr(cmdbuffer[bufindr], code); - return (strchr_pointer != NULL); //Return True if a character was found -} - -inline void process_commands() -{ - unsigned long codenum; //throw away variable - char *starpos = NULL; - - if(code_seen('G')) - { - switch((int)code_value()) - { - case 0: // G0 -> G1 - case 1: // G1 - get_coordinates(); // For X Y Z E F - prepare_move(); - previous_millis_cmd = millis(); - //ClearToSend(); - return; - //break; - case 4: // G4 dwell - codenum = 0; - if(code_seen('P')) codenum = code_value(); // milliseconds to wait - if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait - codenum += millis(); // keep track of when we started waiting - while(millis() < codenum ){ - manage_heater(); - } - break; - case 28: //G28 Home all Axis one at a time - saved_feedrate = feedrate; - for(int i=0; i < NUM_AXIS; i++) { - destination[i] = current_position[i]; - } - feedrate = 0; - - home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); - - if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) { - if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){ - st_synchronize(); - current_position[X_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; - feedrate = homing_feedrate[X_AXIS]; - prepare_move(); - - st_synchronize(); - current_position[X_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = -5 * X_HOME_DIR; - prepare_move(); - - st_synchronize(); - destination[X_AXIS] = 10 * X_HOME_DIR; - feedrate = homing_feedrate[X_AXIS]/2 ; - prepare_move(); - st_synchronize(); - - current_position[X_AXIS] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = current_position[X_AXIS]; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { - if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){ - current_position[Y_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; - feedrate = homing_feedrate[Y_AXIS]; - prepare_move(); - st_synchronize(); - - current_position[Y_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = -5 * Y_HOME_DIR; - prepare_move(); - st_synchronize(); - - destination[Y_AXIS] = 10 * Y_HOME_DIR; - feedrate = homing_feedrate[Y_AXIS]/2; - prepare_move(); - st_synchronize(); - - current_position[Y_AXIS] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = current_position[Y_AXIS]; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { - if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){ - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; - feedrate = homing_feedrate[Z_AXIS]; - prepare_move(); - st_synchronize(); - - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = -2 * Z_HOME_DIR; - prepare_move(); - st_synchronize(); - - destination[Z_AXIS] = 3 * Z_HOME_DIR; - feedrate = homing_feedrate[Z_AXIS]/2; - prepare_move(); - st_synchronize(); - - current_position[Z_AXIS] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = current_position[Z_AXIS]; - feedrate = 0; - } - } - feedrate = saved_feedrate; - previous_millis_cmd = millis(); - break; - case 90: // G90 - relative_mode = false; - break; - case 91: // G91 - relative_mode = true; - break; - case 92: // G92 - if(!code_seen(axis_codes[E_AXIS])) - st_synchronize(); - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) current_position[i] = code_value(); - } - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - break; - - } - } - - else if(code_seen('M')) - { - - switch( (int)code_value() ) - { -#ifdef SDSUPPORT - - case 20: // M20 - list SD card - Serial.println("Begin file list"); - root.ls(); - Serial.println("End file list"); - break; - case 21: // M21 - init SD card - sdmode = false; - initsd(); - break; - case 22: //M22 - release SD card - sdmode = false; - sdactive = false; - break; - case 23: //M23 - Select file - if(sdactive){ - sdmode = false; - file.close(); - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos!=NULL) - *(starpos-1)='\0'; - if (file.open(&root, strchr_pointer + 4, O_READ)) { - Serial.print("File opened:"); - Serial.print(strchr_pointer + 4); - Serial.print(" Size:"); - Serial.println(file.fileSize()); - sdpos = 0; - filesize = file.fileSize(); - Serial.println("File selected"); - } - else{ - Serial.println("file.open failed"); - } - } - break; - case 24: //M24 - Start SD print - if(sdactive){ - sdmode = true; - } - break; - case 25: //M25 - Pause SD print - if(sdmode){ - sdmode = false; - } - break; - case 26: //M26 - Set SD index - if(sdactive && code_seen('S')){ - sdpos = code_value_long(); - file.seekSet(sdpos); - } - break; - case 27: //M27 - Get SD status - if(sdactive){ - Serial.print("SD printing byte "); - Serial.print(sdpos); - Serial.print("/"); - Serial.println(filesize); - } - else{ - Serial.println("Not SD printing"); - } - break; - case 28: //M28 - Start SD write - if(sdactive){ - char* npos = 0; - file.close(); - sdmode = false; - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos != NULL){ - npos = strchr(cmdbuffer[bufindr], 'N'); - strchr_pointer = strchr(npos,' ') + 1; - *(starpos-1) = '\0'; - } - if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) - { - Serial.print("open failed, File: "); - Serial.print(strchr_pointer + 4); - Serial.print("."); - } - else{ - savetosd = true; - Serial.print("Writing to file: "); - Serial.println(strchr_pointer + 4); - } - } - break; - case 29: //M29 - Stop SD write - //processed in write to file routine above - //savetosd = false; - break; -#endif //SDSUPPORT - case 104: // M104 -#ifdef PID_OPENLOOP - if (code_seen('S')) PidTemp_Output = code_value() * (PID_MAX/100.0); - if(pid_output > PID_MAX) pid_output = PID_MAX; - if(pid_output < 0) pid_output = 0; -#else //PID_OPENLOOP - if (code_seen('S')) { - target_raw = temp2analogh(code_value()); -#ifdef PIDTEMP - pid_setpoint = code_value(); -#endif //PIDTEMP - } -#ifdef WATCHPERIOD - if(target_raw > current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - } - else{ - watchmillis = 0; - } -#endif //WATCHPERIOD -#endif //PID_OPENLOOP - break; - case 105: // M105 - Serial.print("ok T:"); - Serial.println(analog2temp(current_raw)); - return; - //break; - case 109: // M109 - Wait for extruder heater to reach target. - if (code_seen('S')) { - target_raw = temp2analogh(code_value()); -#ifdef PIDTEMP - pid_setpoint = code_value(); -#endif //PIDTEMP - } -#ifdef WATCHPERIOD - if(target_raw>current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - } - else{ - watchmillis = 0; - } -#endif //WATCHERPERIOD - codenum = millis(); - while(current_raw < target_raw) { - if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - Serial.print("T:"); - Serial.println( analog2temp(current_raw)); - codenum = millis(); - } - manage_heater(); - } - break; - case 190: - break; - case 82: - axis_relative_modes[3] = false; - break; - case 83: - axis_relative_modes[3] = true; - break; - case 84: - if(code_seen('S')){ - stepper_inactive_time = code_value() * 1000; - } - else{ - st_synchronize(); - disable_x(); - disable_y(); - disable_z(); - disable_e(); - } - break; - case 85: // M85 - code_seen('S'); - max_inactive_time = code_value() * 1000; - break; - case 92: // M92 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); - } - - break; - case 115: // M115 - Serial.println("FIRMWARE_NAME:Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); - break; - case 114: // M114 - Serial.print("X:"); - Serial.print(current_position[X_AXIS]); - Serial.print("Y:"); - Serial.print(current_position[Y_AXIS]); - Serial.print("Z:"); - Serial.print(current_position[Z_AXIS]); - Serial.print("E:"); - Serial.println(current_position[E_AXIS]); - break; - case 119: // M119 -#if (X_MIN_PIN > -1) - Serial.print("x_min:"); - Serial.print((READ(X_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (X_MAX_PIN > -1) - Serial.print("x_max:"); - Serial.print((READ(X_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Y_MIN_PIN > -1) - Serial.print("y_min:"); - Serial.print((READ(Y_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Y_MAX_PIN > -1) - Serial.print("y_max:"); - Serial.print((READ(Y_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Z_MIN_PIN > -1) - Serial.print("z_min:"); - Serial.print((READ(Z_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Z_MAX_PIN > -1) - Serial.print("z_max:"); - Serial.print((READ(Z_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif - Serial.println(""); - break; - //TODO: update for all axis, use for loop - case 201: // M201 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; -#if 0 // Not used for Sprinter/grbl gen6 - case 202: // M202 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; -#endif -#ifdef PIDTEMP - case 301: // M301 - if(code_seen('P')) Kp = code_value(); - if(code_seen('I')) Ki = code_value()*PID_dT; - if(code_seen('D')) Kd = code_value()/PID_dT; - Serial.print("Kp ");Serial.println(Kp); - Serial.print("Ki ");Serial.println(Ki/PID_dT); - Serial.print("Kd ");Serial.println(Kd*PID_dT); - temp_iState_min = 0.0; - temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; - break; -#endif //PIDTEMP - } - } - else{ - Serial.println("Unknown command:"); - Serial.println(cmdbuffer[bufindr]); - } - - ClearToSend(); -} - -void FlushSerialRequestResend() -{ - //char cmdbuffer[bufindr][100]="Resend:"; - Serial.flush(); - Serial.print("Resend:"); - Serial.println(gcode_LastN + 1); - ClearToSend(); -} - -void ClearToSend() -{ - previous_millis_cmd = millis(); -#ifdef SDSUPPORT - if(fromsd[bufindr]) - return; -#endif //SDSUPPORT - Serial.println("ok"); -} - -inline void get_coordinates() -{ - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; - else destination[i] = current_position[i]; //Are these else lines really needed? - } - if(code_seen('F')) { - next_feedrate = code_value(); - if(next_feedrate > 0.0) feedrate = next_feedrate; - } -} - -void prepare_move() -{ - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60.0); - for(int i=0; i < NUM_AXIS; i++) { - current_position[i] = destination[i]; - } -} - -void manage_heater() -{ - float pid_input; - float pid_output; - if(temp_meas_ready != true) - return; - -CRITICAL_SECTION_START; - temp_meas_ready = false; -CRITICAL_SECTION_END; - -#ifdef PIDTEMP - pid_input = analog2temp(current_raw); - -#ifndef PID_OPENLOOP - pid_error = pid_setpoint - pid_input; - if(pid_error > 10){ - pid_output = PID_MAX; - pid_reset = true; - } - else if(pid_error < -10) { - pid_output = 0; - pid_reset = true; - } - else { - if(pid_reset == true) { - temp_iState = 0.0; - pid_reset = false; - } - pTerm = Kp * pid_error; - temp_iState += pid_error; - temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = Ki * temp_iState; - #define K1 0.8 - #define K2 (1.0-K1) - dTerm = (Kd * (pid_input - temp_dState))*K2 + (K1 * dTerm); - temp_dState = pid_input; - pid_output = constrain(pTerm + iTerm - dTerm, 0, PID_MAX); - } -#endif //PID_OPENLOOP -#ifdef PID_DEBUG - Serial.print(" Input "); - Serial.print(pid_input); - Serial.print(" Output "); - Serial.print(pid_output); - Serial.print(" pTerm "); - Serial.print(pTerm); - Serial.print(" iTerm "); - Serial.print(iTerm); - Serial.print(" dTerm "); - Serial.print(dTerm); - Serial.println(); -#endif //PID_DEBUG - OCR2B = pid_output; -#endif //PIDTEMP -} - - -int temp2analogu(int celsius, const short table[][2], int numtemps) { - int raw = 0; - byte i; - - for (i=1; i raw) { - celsius = (float)table[i-1][1] + - (float)(raw - table[i-1][0]) * - (float)(table[i][1] - table[i-1][1]) / - (float)(table[i][0] - table[i-1][0]); - - break; - } - } - // Overflow: Set to last value in the table - if (i == numtemps) celsius = table[i-1][1]; - - return celsius; -} - - -inline void kill() -{ - target_raw=0; -#ifdef PIDTEMP - pid_setpoint = 0.0; -#endif //PIDTEMP - OCR2B = 0; - WRITE(HEATER_0_PIN,LOW); - - disable_x(); - disable_y(); - disable_z(); - disable_e(); - -} - -inline void manage_inactivity(byte debug) { - if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); - if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { - disable_x(); - disable_y(); - disable_z(); - disable_e(); - } - check_axes_activity(); -} - -// Planner - -/* - Reasoning behind the mathematics in this module (in the key of 'Mathematica'): - - s == speed, a == acceleration, t == time, d == distance - - Basic definitions: - - Speed[s_, a_, t_] := s + (a*t) - Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t] - - Distance to reach a specific speed with a constant acceleration: - - Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t] - d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance() - - Speed after a given distance of travel with constant acceleration: - - Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t] - m -> Sqrt[2 a d + s^2] - - DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2] - - When to start braking (di) to reach a specified destionation speed (s2) after accelerating - from initial speed s1 without ever stopping at a plateau: - - Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di] - di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance() - - IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a) - */ - - -// The number of linear motions that can be in the plan at any give time -#define BLOCK_BUFFER_SIZE 16 -#define BLOCK_BUFFER_MASK 0x0f - -static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions -static volatile unsigned char block_buffer_head; // Index of the next block to be pushed -static volatile unsigned char block_buffer_tail; // Index of the block to process now - -// The current position of the tool in absolute steps -static long position[4]; - -#define ONE_MINUTE_OF_MICROSECONDS 60000000.0 - -// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the -// given acceleration: -inline long estimate_acceleration_distance(long initial_rate, long target_rate, long acceleration) { - return( - (target_rate*target_rate-initial_rate*initial_rate)/ - (2L*acceleration) - ); -} - -// This function gives you the point at which you must start braking (at the rate of -acceleration) if -// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after -// a total travel of distance. This can be used to compute the intersection point between acceleration and -// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) - -inline long intersection_distance(long initial_rate, long final_rate, long acceleration, long distance) { - return( - (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ - (4*acceleration) - ); -} - -// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. - -void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { - if(block->busy == true) return; // If block is busy then bail out. - float entry_factor = entry_speed / block->nominal_speed; - float exit_factor = exit_speed / block->nominal_speed; - long initial_rate = ceil(block->nominal_rate*entry_factor); - long final_rate = ceil(block->nominal_rate*exit_factor); - -#ifdef ADVANCE - long initial_advance = block->advance*entry_factor*entry_factor; - long final_advance = block->advance*exit_factor*exit_factor; -#endif // ADVANCE - - // Limit minimal step rate (Otherwise the timer will overflow.) - if(initial_rate <120) initial_rate=120; - if(final_rate < 120) final_rate=120; - - // Calculate the acceleration steps - long acceleration = block->acceleration; - long accelerate_steps = estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration); - long decelerate_steps = estimate_acceleration_distance(final_rate, block->nominal_rate, acceleration); - - // Calculate the size of Plateau of Nominal Rate. - long plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; - - // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will - // have to use intersection_distance() to calculate when to abort acceleration and start braking - // in order to reach the final_rate exactly at the end of this block. - if (plateau_steps < 0) { - accelerate_steps = intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count); - plateau_steps = 0; - } - - long decelerate_after = accelerate_steps+plateau_steps; - long acceleration_rate = (long)((float)acceleration * 8.388608); - - CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section - if(block->busy == false) { // Don't update variables if block is busy. - block->accelerate_until = accelerate_steps; - block->decelerate_after = decelerate_after; - block->acceleration_rate = acceleration_rate; - block->initial_rate = initial_rate; - block->final_rate = final_rate; -#ifdef ADVANCE - block->initial_advance = initial_advance; - block->final_advance = final_advance; -#endif //ADVANCE - } - CRITICAL_SECTION_END; -} - -// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the -// acceleration within the allotted distance. -inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { - return( - sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) - ); -} - -// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks. -// This method will calculate the junction jerk as the euclidean distance between the nominal -// velocities of the respective blocks. -inline float junction_jerk(block_t *before, block_t *after) { - return(sqrt( - pow((before->speed_x-after->speed_x), 2)+ - pow((before->speed_y-after->speed_y), 2)+ - pow((before->speed_z-after->speed_z)*axis_steps_per_unit[Z_AXIS]/axis_steps_per_unit[X_AXIS], 2))); -} - -// Return the safe speed which is max_jerk/2, e.g. the -// speed under which you cannot exceed max_jerk no matter what you do. -float safe_speed(block_t *block) { - float safe_speed; - safe_speed = max_jerk/2; - if (safe_speed > block->nominal_speed) safe_speed = block->nominal_speed; - return safe_speed; -} - -// The kernel called by planner_recalculate() when scanning the plan from last to first entry. -void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) { - if(!current) { - return; - } - - float entry_speed = current->nominal_speed; - float exit_factor; - float exit_speed; - if (next) { - exit_speed = next->entry_speed; - } - else { - exit_speed = safe_speed(current); - } - - // Calculate the entry_factor for the current block. - if (previous) { - // Reduce speed so that junction_jerk is within the maximum allowed - float jerk = junction_jerk(previous, current); - if((previous->steps_x == 0) && (previous->steps_y == 0)) { - entry_speed = safe_speed(current); - } - else if (jerk > max_jerk) { - entry_speed = (max_jerk/jerk) * entry_speed; - } - // If the required deceleration across the block is too rapid, reduce the entry_factor accordingly. - if (entry_speed > exit_speed) { - float max_entry_speed = max_allowable_speed(-acceleration,exit_speed, current->millimeters); - if (max_entry_speed < entry_speed) { - entry_speed = max_entry_speed; - } - } - } - else { - entry_speed = safe_speed(current); - } - // Store result - current->entry_speed = entry_speed; -} - -// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This -// implements the reverse pass. -void planner_reverse_pass() { - char block_index = block_buffer_head; - block_t *block[3] = { - NULL, NULL, NULL }; - while(block_index != block_buffer_tail) { - block_index--; - if(block_index < 0) { - block_index = BLOCK_BUFFER_SIZE-1; - } - block[2]= block[1]; - block[1]= block[0]; - block[0] = &block_buffer[block_index]; - planner_reverse_pass_kernel(block[0], block[1], block[2]); - } - planner_reverse_pass_kernel(NULL, block[0], block[1]); -} - -// The kernel called by planner_recalculate() when scanning the plan from first to last entry. -void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) { - if(!current) { - return; - } - if(previous) { - // If the previous block is an acceleration block, but it is not long enough to - // complete the full speed change within the block, we need to adjust out entry - // speed accordingly. Remember current->entry_factor equals the exit factor of - // the previous block. - if(previous->entry_speed < current->entry_speed) { - float max_entry_speed = max_allowable_speed(-acceleration, previous->entry_speed, previous->millimeters); - if (max_entry_speed < current->entry_speed) { - current->entry_speed = max_entry_speed; - } - } - } -} - -// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This -// implements the forward pass. -void planner_forward_pass() { - char block_index = block_buffer_tail; - block_t *block[3] = { - NULL, NULL, NULL }; - - while(block_index != block_buffer_head) { - block[0] = block[1]; - block[1] = block[2]; - block[2] = &block_buffer[block_index]; - planner_forward_pass_kernel(block[0],block[1],block[2]); - block_index = (block_index+1) & BLOCK_BUFFER_MASK; - } - planner_forward_pass_kernel(block[1], block[2], NULL); -} - -// Recalculates the trapezoid speed profiles for all blocks in the plan according to the -// entry_factor for each junction. Must be called by planner_recalculate() after -// updating the blocks. -void planner_recalculate_trapezoids() { - char block_index = block_buffer_tail; - block_t *current; - block_t *next = NULL; - while(block_index != block_buffer_head) { - current = next; - next = &block_buffer[block_index]; - if (current) { - calculate_trapezoid_for_block(current, current->entry_speed, next->entry_speed); - } - block_index = (block_index+1) & BLOCK_BUFFER_MASK; - } - calculate_trapezoid_for_block(next, next->entry_speed, safe_speed(next)); -} - -// Recalculates the motion plan according to the following algorithm: -// -// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) -// so that: -// a. The junction jerk is within the set limit -// b. No speed reduction within one block requires faster deceleration than the one, true constant -// acceleration. -// 2. Go over every block in chronological order and dial down junction speed reduction values if -// a. The speed increase within one block would require faster accelleration than the one, true -// constant acceleration. -// -// When these stages are complete all blocks have an entry_factor that will allow all speed changes to -// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than -// the set limit. Finally it will: -// -// 3. Recalculate trapezoids for all blocks. - -void planner_recalculate() { - planner_reverse_pass(); - planner_forward_pass(); - planner_recalculate_trapezoids(); -} - -void plan_init() { - block_buffer_head = 0; - block_buffer_tail = 0; - memset(position, 0, sizeof(position)); // clear position -} - - -inline void plan_discard_current_block() { - if (block_buffer_head != block_buffer_tail) { - block_buffer_tail = (block_buffer_tail + 1) & BLOCK_BUFFER_MASK; - } -} - -inline block_t *plan_get_current_block() { - if (block_buffer_head == block_buffer_tail) { - return(NULL); - } - block_t *block = &block_buffer[block_buffer_tail]; - block->busy = true; - return(block); -} - -void check_axes_activity() { - unsigned char x_active = 0; - unsigned char y_active = 0; - unsigned char z_active = 0; - unsigned char e_active = 0; - block_t *block; - - if(block_buffer_tail != block_buffer_head) { - char block_index = block_buffer_tail; - while(block_index != block_buffer_head) { - block = &block_buffer[block_index]; - if(block->steps_x != 0) x_active++; - if(block->steps_y != 0) y_active++; - if(block->steps_z != 0) z_active++; - if(block->steps_e != 0) e_active++; - block_index = (block_index+1) & BLOCK_BUFFER_MASK; - } - } - if((DISABLE_X) && (x_active == 0)) disable_x(); - if((DISABLE_Y) && (y_active == 0)) disable_y(); - if((DISABLE_Z) && (z_active == 0)) disable_z(); - if((DISABLE_E) && (e_active == 0)) disable_e(); -} - -// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in -// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration -// calculation the caller must also provide the physical length of the line in millimeters. -void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { - - // The target position of the tool in absolute steps - // Calculate target position in absolute steps - long target[4]; - target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); - target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); - target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); - target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); - - // Calculate the buffer head after we push this byte - int next_buffer_head = (block_buffer_head + 1) & BLOCK_BUFFER_MASK; - - // If the buffer is full: good! That means we are well ahead of the robot. - // Rest here until there is room in the buffer. - while(block_buffer_tail == next_buffer_head) { - manage_heater(); - manage_inactivity(1); - } - - // Prepare to set up new block - block_t *block = &block_buffer[block_buffer_head]; - - // Mark block as not busy (Not executed by the stepper interrupt) - block->busy = false; - - // Number of steps for each axis - block->steps_x = labs(target[X_AXIS]-position[X_AXIS]); - block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]); - block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); - block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); - block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); - - // Bail if this is a zero-length block - if (block->step_event_count == 0) { - return; - }; - - float delta_x_mm = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; - float delta_y_mm = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; - float delta_z_mm = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; - float delta_e_mm = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS]; - block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); - - unsigned long microseconds; - microseconds = lround((block->millimeters/feed_rate)*1000000); - - // Calculate speed in mm/minute for each axis - float multiplier = 60.0*1000000.0/microseconds; - block->speed_z = delta_z_mm * multiplier; - block->speed_x = delta_x_mm * multiplier; - block->speed_y = delta_y_mm * multiplier; - block->speed_e = delta_e_mm * multiplier; - - // Limit speed per axis - float speed_factor = 1; - float tmp_speed_factor; - if(abs(block->speed_x) > max_feedrate[X_AXIS]) { - speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); - } - if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ - tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ - tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_e) > max_feedrate[E_AXIS]){ - tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - multiplier = multiplier * speed_factor; - block->speed_z = delta_z_mm * multiplier; - block->speed_x = delta_x_mm * multiplier; - block->speed_y = delta_y_mm * multiplier; - block->speed_e = delta_e_mm * multiplier; - block->nominal_speed = block->millimeters * multiplier; - block->nominal_rate = ceil(block->step_event_count * multiplier / 60); - - if(block->nominal_rate < 120) block->nominal_rate = 120; - block->entry_speed = safe_speed(block); - - // Compute the acceleration rate for the trapezoid generator. - float travel_per_step = block->millimeters/block->step_event_count; - if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { - block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 - } - else { - block->acceleration = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 - // Limit acceleration per axis - if((block->acceleration * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) - block->acceleration = axis_steps_per_sqr_second[X_AXIS]; - if((block->acceleration * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) - block->acceleration = axis_steps_per_sqr_second[Y_AXIS]; - if((block->acceleration * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) - block->acceleration = axis_steps_per_sqr_second[E_AXIS]; - if((block->acceleration * block->steps_z / block->step_event_count) > axis_steps_per_sqr_second[Z_AXIS]) - block->acceleration = axis_steps_per_sqr_second[Z_AXIS]; - } - -#ifdef ADVANCE - // Calculate advance rate - if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { - block->advance_rate = 0; - block->advance = 0; - } - else { - long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration); - float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * - (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; - block->advance = advance; - if(acc_dist == 0) { - block->advance_rate = 0; - } - else { - block->advance_rate = advance / (float)acc_dist; - } - } - -#endif // ADVANCE - - // compute a preliminary conservative acceleration trapezoid - float safespeed = safe_speed(block); - calculate_trapezoid_for_block(block, safespeed, safespeed); - - // Compute direction bits for this block - block->direction_bits = 0; - if (target[X_AXIS] < position[X_AXIS]) { - block->direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<steps_x != 0) enable_x(); - if(block->steps_y != 0) enable_y(); - if(block->steps_z != 0) enable_z(); - if(block->steps_e != 0) enable_e(); - - // Move buffer head - block_buffer_head = next_buffer_head; - - // Update position - memcpy(position, target, sizeof(target)); // position[] = target[] - - planner_recalculate(); - st_wake_up(); -} - -void plan_set_position(float x, float y, float z, float e) -{ - position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); - position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); - position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); - position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); -} - -// Stepper - -// intRes = intIn1 * intIn2 >> 16 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 24 bit result -#define MultiU16X8toH16(intRes, charIn1, intIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %A1, %A2 \n\t" \ -"add %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r0 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (charIn1), \ -"d" (intIn2) \ -: \ -"r26" \ -) - -// intRes = longIn1 * longIn2 >> 24 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 48bit result -#define MultiU24X24toH16(intRes, longIn1, longIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"mov r27, r1 \n\t" \ -"mul %B1, %C2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %C1, %C2 \n\t" \ -"add %B0, r0 \n\t" \ -"mul %C1, %B2 \n\t" \ -"add %A0, r0 \n\t" \ -"adc %B0, r1 \n\t" \ -"mul %A1, %C2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %B2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %C1, %A2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %A2 \n\t" \ -"add r27, r1 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r27 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (longIn1), \ -"d" (longIn2) \ -: \ -"r26" , "r27" \ -) - -// Some useful constants - -#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1< -// -// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates -// first block->accelerate_until step_events_completed, then keeps going at constant speed until -// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. -// The slope of acceleration is calculated with the leib ramp alghorithm. - -void st_wake_up() { - // TCNT1 = 0; - ENABLE_STEPPER_DRIVER_INTERRUPT(); -} - -inline unsigned short calc_timer(unsigned short step_rate) { - unsigned short timer; - if(step_rate < 32) step_rate = 32; - step_rate -= 32; // Correct for minimal speed - if(step_rate >= (8*256)){ // higher step rate - unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; - unsigned char tmp_step_rate = (step_rate & 0x00ff); - unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); - MultiU16X8toH16(timer, tmp_step_rate, gain); - timer = (unsigned short)pgm_read_word_near(table_address) - timer; - } - else { // lower step rates - unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; - table_address += ((step_rate)>>1) & 0xfffc; - timer = (unsigned short)pgm_read_word_near(table_address); - timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); - } - if(timer < 100) timer = 100; - return timer; -} - -// Initializes the trapezoid generator from the current block. Called whenever a new -// block begins. -inline void trapezoid_generator_reset() { - accelerate_until = current_block->accelerate_until; - decelerate_after = current_block->decelerate_after; - acceleration_rate = current_block->acceleration_rate; - initial_rate = current_block->initial_rate; - final_rate = current_block->final_rate; - nominal_rate = current_block->nominal_rate; - advance = current_block->initial_advance; - final_advance = current_block->final_advance; - deceleration_time = 0; - advance_rate = current_block->advance_rate; - // step_rate to timer interval - acc_step_rate = initial_rate; - acceleration_time = calc_timer(acc_step_rate); - OCR1A = acceleration_time; -} - -// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. -// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. -ISR(TIMER1_COMPA_vect) -{ - if(busy){ /*Serial.println("BUSY")*/; - return; - } // The busy-flag is used to avoid reentering this interrupt - - busy = true; - sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) - - // If there is no current block, attempt to pop one from the buffer - if (current_block == NULL) { - // Anything in the buffer? - current_block = plan_get_current_block(); - if (current_block != NULL) { - trapezoid_generator_reset(); - counter_x = -(current_block->step_event_count >> 1); - counter_y = counter_x; - counter_z = counter_x; - counter_e = counter_x; - step_events_completed = 0; - e_steps = 0; - } - else { - DISABLE_STEPPER_DRIVER_INTERRUPT(); - } - } - - if (current_block != NULL) { - // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt - out_bits = current_block->direction_bits; - -#ifdef ADVANCE - // Calculate E early. - counter_e += current_block->steps_e; - if (counter_e > 0) { - counter_e -= current_block->step_event_count; - if ((out_bits & (1<> 16) - old_advance); - CRITICAL_SECTION_END; - old_advance = advance >> 16; -#endif //ADVANCE - - // Set direction en check limit switches - if ((out_bits & (1<step_event_count; - } - } - else // +direction - WRITE(X_DIR_PIN,!INVERT_X_DIR); - - if ((out_bits & (1<step_event_count; - } - } - else // +direction - WRITE(Y_DIR_PIN,!INVERT_Y_DIR); - - if ((out_bits & (1<step_event_count; - } - } - else // +direction - WRITE(Z_DIR_PIN,!INVERT_Z_DIR); - -#ifndef ADVANCE - if ((out_bits & (1<steps_x; - if (counter_x > 0) { - WRITE(X_STEP_PIN, HIGH); - counter_x -= current_block->step_event_count; - WRITE(X_STEP_PIN, LOW); - } - - counter_y += current_block->steps_y; - if (counter_y > 0) { - WRITE(Y_STEP_PIN, HIGH); - counter_y -= current_block->step_event_count; - WRITE(Y_STEP_PIN, LOW); - } - - counter_z += current_block->steps_z; - if (counter_z > 0) { - WRITE(Z_STEP_PIN, HIGH); - counter_z -= current_block->step_event_count; - WRITE(Z_STEP_PIN, LOW); - } - -#ifndef ADVANCE - counter_e += current_block->steps_e; - if (counter_e > 0) { - WRITE(E_STEP_PIN, HIGH); - counter_e -= current_block->step_event_count; - WRITE(E_STEP_PIN, LOW); - } -#endif //!ADVANCE - - // Calculare new timer value - unsigned short timer; - unsigned short step_rate; - if (step_events_completed < accelerate_until) { - MultiU24X24toH16(acc_step_rate, acceleration_time, acceleration_rate); - acc_step_rate += initial_rate; - - // upper limit - if(acc_step_rate > nominal_rate) - acc_step_rate = nominal_rate; - - // step_rate to timer interval - timer = calc_timer(acc_step_rate); - advance += advance_rate; - acceleration_time += timer; - OCR1A = timer; - } - else if (step_events_completed >= decelerate_after) { - MultiU24X24toH16(step_rate, deceleration_time, acceleration_rate); - - if(step_rate > acc_step_rate) { // Check step_rate stays positive - step_rate = final_rate; - } - else { - step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. - } - - // lower limit - if(step_rate < final_rate) - step_rate = final_rate; - - // step_rate to timer interval - timer = calc_timer(step_rate); -#ifdef ADVANCE - advance -= advance_rate; - if(advance < final_advance) - advance = final_advance; -#endif //ADVANCE - deceleration_time += timer; - OCR1A = timer; - } - // If current block is finished, reset pointer - step_events_completed += 1; - if (step_events_completed >= current_block->step_event_count) { - current_block = NULL; - plan_discard_current_block(); - } - } - busy=false; -} - -#ifdef ADVANCE - -unsigned char old_OCR0A; -// Timer interrupt for E. e_steps is set in the main routine; -// Timer 0 is shared with millies -ISR(TIMER0_COMPA_vect) -{ - // Critical section needed because Timer 1 interrupt has higher priority. - // The pin set functions are placed on trategic position to comply with the stepper driver timing. - WRITE(E_STEP_PIN, LOW); - // Set E direction (Depends on E direction + advance) - if (e_steps < 0) { - WRITE(E_DIR_PIN,INVERT_E_DIR); - e_steps++; - WRITE(E_STEP_PIN, HIGH); - } - if (e_steps > 0) { - WRITE(E_DIR_PIN,!INVERT_E_DIR); - e_steps--; - WRITE(E_STEP_PIN, HIGH); - } - old_OCR0A += 25; // 10kHz interrupt - OCR0A = old_OCR0A; -} -#endif // ADVANCE - -void st_init() -{ - // waveform generation = 0100 = CTC - TCCR1B &= ~(1<= 16) - { - current_raw = 16383 - raw_temp_value; - temp_meas_ready = true; - temp_count = 0; - raw_temp_value = 0; -#ifdef MAXTEMP - if(current_raw >= maxttemp) { - target_raw = 0; -#ifdef PIDTEMP - OCR2B = 0; -#else - WRITE(HEATER_0_PIN,LOW); -#endif //PIDTEMP - } -#endif //MAXTEMP -#ifdef MINTEMP - if(current_raw <= minttemp) { - target_raw = 0; -#ifdef PIDTEMP - OCR2B = 0; -#else - WRITE(HEATER_0_PIN,LOW); -#endif //PIDTEMP - } -#endif //MAXTEMP -#ifndef PIDTEMP - if(current_raw >= target_raw) - { - WRITE(HEATER_0_PIN,LOW); - } - else - { - WRITE(HEATER_0_PIN,HIGH); - } -#endif //PIDTEMP - } -} - - +#include "Marlin.h" +// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in +// the source g-code and may never actually be reached if acceleration management is active. + + +#include "speed_lookuptable.h" + +/* + Reprap firmware based on Sprinter and grbl. + Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + + This program 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. + + This program 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 this program. If not, see . + */ + +/* + This firmware is a mashup between Sprinter and grbl. + (https://github.com/kliment/Sprinter) + (https://github.com/simen/grbl/tree) + + It has preliminary support for Matthew Roberts advance algorithm + http://reprap.org/pipermail/reprap-dev/2011-May/003323.html + + This firmware is optimized for gen6 electronics. + */ + + + +#include "fastio.h" +#include "Configuration.h" +#include "pins.h" + +char version_string[] = "0.9.3"; + +#ifdef SDSUPPORT +#include "SdFat.h" +#endif //SDSUPPORT + +#ifndef CRITICAL_SECTION_START +#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() +#define CRITICAL_SECTION_END SREG = _sreg +#endif //CRITICAL_SECTION_START + +// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html +// 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 +// G28 - Home all 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 +// 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 +// M115 - Capabilities string +// 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) +// M301 - Set PID parameters P I and D + +//Stepper Movement Variables + +char axis_codes[NUM_AXIS] = { + 'X', 'Y', 'Z', 'E'}; +float destination[NUM_AXIS] = { + 0.0, 0.0, 0.0, 0.0}; +float current_position[NUM_AXIS] = { + 0.0, 0.0, 0.0, 0.0}; +bool home_all_axis = true; +long feedrate = 1500, next_feedrate, saved_feedrate; +long gcode_N, gcode_LastN; +unsigned long previous_millis_heater, previous_millis_bed_heater; +bool relative_mode = false; //Determines Absolute or Relative Coordinates +bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. +unsigned long axis_steps_per_sqr_second[NUM_AXIS]; + +// comm variables +#define MAX_CMD_SIZE 96 +#define BUFSIZE 8 +char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; +bool fromsd[BUFSIZE]; +int bufindr = 0; +int bufindw = 0; +int buflen = 0; +int i = 0; +char serial_char; +int serial_count = 0; +boolean comment_mode = false; +char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc + +// Manage heater variables. + +int target_bed_raw = 0; +int current_bed_raw = 0; + +int target_raw = 0; +int current_raw = 0; +unsigned char temp_meas_ready = false; + +#ifdef PIDTEMP + double temp_iState = 0; + double temp_dState = 0; + double pTerm; + double iTerm; + double dTerm; + //int output; + double pid_error; + double temp_iState_min; + double temp_iState_max; + double pid_setpoint = 0.0; + double pid_input; + double pid_output; + bool pid_reset; +#endif //PIDTEMP +float tt = 0, bt = 0; +#ifdef WATCHPERIOD +int watch_raw = -1000; +unsigned long watchmillis = 0; +#endif //WATCHPERIOD +#ifdef MINTEMP +int minttemp = temp2analog(MINTEMP); +#endif //MINTEMP +#ifdef MAXTEMP +int maxttemp = temp2analog(MAXTEMP); +#endif //MAXTEMP + +//Inactivity shutdown variables +unsigned long previous_millis_cmd = 0; +unsigned long max_inactive_time = 0; +unsigned long stepper_inactive_time = 0; + +#ifdef SDSUPPORT +Sd2Card card; +SdVolume volume; +SdFile root; +SdFile file; +uint32_t filesize = 0; +uint32_t sdpos = 0; +bool sdmode = false; +bool sdactive = false; +bool savetosd = false; +int16_t n; + +void initsd(){ + sdactive = false; +#if SDSS >- 1 + if(root.isOpen()) + root.close(); + if (!card.init(SPI_FULL_SPEED,SDSS)){ + //if (!card.init(SPI_HALF_SPEED,SDSS)) + Serial.println("SD init fail"); + } + else if (!volume.init(&card)) + Serial.println("volume.init failed"); + else if (!root.openRoot(&volume)) + Serial.println("openRoot failed"); + else + sdactive = true; +#endif //SDSS +} + +inline void write_command(char *buf){ + char* begin = buf; + char* npos = 0; + char* end = buf + strlen(buf) - 1; + + file.writeError = false; + if((npos = strchr(buf, 'N')) != NULL){ + begin = strchr(npos, ' ') + 1; + end = strchr(npos, '*') - 1; + } + end[1] = '\r'; + end[2] = '\n'; + end[3] = '\0'; + //Serial.println(begin); + file.write(begin); + if (file.writeError){ + Serial.println("error writing to file"); + } +} +#endif //SDSUPPORT + + +void setup() +{ + Serial.begin(BAUDRATE); + Serial.print("Marlin "); + Serial.println(version_string); + Serial.println("start"); + + for(int i = 0; i < BUFSIZE; i++){ + fromsd[i] = false; + } + + + //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 +#if E_DIR_PIN > -1 + SET_OUTPUT(E_DIR_PIN); +#endif + + //Initialize Enable Pins - steppers default to disabled. + +#if (X_ENABLE_PIN > -1) + SET_OUTPUT(X_ENABLE_PIN); + if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); +#endif +#if (Y_ENABLE_PIN > -1) + SET_OUTPUT(Y_ENABLE_PIN); + if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); +#endif +#if (Z_ENABLE_PIN > -1) + SET_OUTPUT(Z_ENABLE_PIN); + if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); +#endif +#if (E_ENABLE_PIN > -1) + SET_OUTPUT(E_ENABLE_PIN); + if(!E_ENABLE_ON) WRITE(E_ENABLE_PIN,HIGH); +#endif + + //endstops and pullups +#ifdef ENDSTOPPULLUPS +#if X_MIN_PIN > -1 + SET_INPUT(X_MIN_PIN); + WRITE(X_MIN_PIN,HIGH); +#endif +#if X_MAX_PIN > -1 + SET_INPUT(X_MAX_PIN); + WRITE(X_MAX_PIN,HIGH); +#endif +#if Y_MIN_PIN > -1 + SET_INPUT(Y_MIN_PIN); + WRITE(Y_MIN_PIN,HIGH); +#endif +#if Y_MAX_PIN > -1 + SET_INPUT(Y_MAX_PIN); + WRITE(Y_MAX_PIN,HIGH); +#endif +#if Z_MIN_PIN > -1 + SET_INPUT(Z_MIN_PIN); + WRITE(Z_MIN_PIN,HIGH); +#endif +#if Z_MAX_PIN > -1 + SET_INPUT(Z_MAX_PIN); + WRITE(Z_MAX_PIN,HIGH); +#endif +#else //ENDSTOPPULLUPS +#if X_MIN_PIN > -1 + SET_INPUT(X_MIN_PIN); +#endif +#if X_MAX_PIN > -1 + SET_INPUT(X_MAX_PIN); +#endif +#if Y_MIN_PIN > -1 + SET_INPUT(Y_MIN_PIN); +#endif +#if Y_MAX_PIN > -1 + SET_INPUT(Y_MAX_PIN); +#endif +#if Z_MIN_PIN > -1 + SET_INPUT(Z_MIN_PIN); +#endif +#if Z_MAX_PIN > -1 + SET_INPUT(Z_MAX_PIN); +#endif +#endif //ENDSTOPPULLUPS + +#if (HEATER_0_PIN > -1) + SET_OUTPUT(HEATER_0_PIN); +#endif +#if (HEATER_1_PIN > -1) + SET_OUTPUT(HEATER_1_PIN); +#endif + + //Initialize Step Pins +#if (X_STEP_PIN > -1) + SET_OUTPUT(X_STEP_PIN); +#endif +#if (Y_STEP_PIN > -1) + SET_OUTPUT(Y_STEP_PIN); +#endif +#if (Z_STEP_PIN > -1) + SET_OUTPUT(Z_STEP_PIN); +#endif +#if (E_STEP_PIN > -1) + SET_OUTPUT(E_STEP_PIN); +#endif + for(int i=0; i < NUM_AXIS; i++){ + axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; + } + +#ifdef PIDTEMP + temp_iState_min = 0.0; + temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; +#endif //PIDTEMP + +#ifdef SDSUPPORT + //power to SD reader +#if SDPOWER > -1 + SET_OUTPUT(SDPOWER); + WRITE(SDPOWER,HIGH); +#endif //SDPOWER + initsd(); + +#endif //SDSUPPORT + plan_init(); // Initialize planner; + st_init(); // Initialize stepper; +// tp_init(); // Initialize temperature loop +} + + +void loop() +{ + //check heater every n milliseconds + manage_heater(); + if(buflen<3) + get_command(); + + if(buflen){ +#ifdef SDSUPPORT + if(savetosd){ + if(strstr(cmdbuffer[bufindr],"M29") == NULL){ + write_command(cmdbuffer[bufindr]); + Serial.println("ok"); + } + else{ + file.sync(); + file.close(); + savetosd = false; + Serial.println("Done saving file."); + } + } + else{ + process_commands(); + } +#else + process_commands(); +#endif //SDSUPPORT + buflen = (buflen-1); + bufindr = (bufindr + 1)%BUFSIZE; + } + + manage_inactivity(1); +} + + +inline void get_command() +{ + while( Serial.available() > 0 && buflen < BUFSIZE) { + serial_char = Serial.read(); + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) + { + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = false; + if(strstr(cmdbuffer[bufindw], "N") != NULL) + { + strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); + gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); + if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { + Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); + Serial.println(gcode_LastN); + //Serial.println(gcode_N); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + if(strstr(cmdbuffer[bufindw], "*") != NULL) + { + byte checksum = 0; + byte count = 0; + while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; + strchr_pointer = strchr(cmdbuffer[bufindw], '*'); + + if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { + Serial.print("Error: checksum mismatch, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + //if no errors, continue parsing + } + else + { + Serial.print("Error: No Checksum with line number, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + gcode_LastN = gcode_N; + //if no errors, continue parsing + } + else // if we don't receive 'N' but still see '*' + { + if((strstr(cmdbuffer[bufindw], "*") != NULL)) + { + Serial.print("Error: No Line Number with checksum, Last Line:"); + Serial.println(gcode_LastN); + serial_count = 0; + return; + } + } + if((strstr(cmdbuffer[bufindw], "G") != NULL)){ + strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); + switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ + case 0: + case 1: +#ifdef SDSUPPORT + if(savetosd) + break; +#endif //SDSUPPORT + Serial.println("ok"); + break; + default: + break; + } + + } + bufindw = (bufindw + 1)%BUFSIZE; + buflen += 1; + + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } + } +#ifdef SDSUPPORT + if(!sdmode || serial_count!=0){ + return; + } + while( filesize > sdpos && buflen < BUFSIZE) { + n = file.read(); + serial_char = (char)n; + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) + { + sdpos = file.curPosition(); + if(sdpos >= filesize){ + sdmode = false; + Serial.println("Done printing file"); + } + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = true; + buflen += 1; + bufindw = (bufindw + 1)%BUFSIZE; + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } + } +#endif //SDSUPPORT + +} + + +inline float code_value() { + return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); +} +inline long code_value_long() { + return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); +} +inline bool code_seen(char code_string[]) { + return (strstr(cmdbuffer[bufindr], code_string) != NULL); +} //Return True if the string was found + +inline bool code_seen(char code) +{ + strchr_pointer = strchr(cmdbuffer[bufindr], code); + return (strchr_pointer != NULL); //Return True if a character was found +} + +inline void process_commands() +{ + unsigned long codenum; //throw away variable + char *starpos = NULL; + + if(code_seen('G')) + { + switch((int)code_value()) + { + case 0: // G0 -> G1 + case 1: // G1 + get_coordinates(); // For X Y Z E F + prepare_move(); + previous_millis_cmd = millis(); + //ClearToSend(); + return; + //break; + case 4: // G4 dwell + codenum = 0; + if(code_seen('P')) codenum = code_value(); // milliseconds to wait + if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait + codenum += millis(); // keep track of when we started waiting + while(millis() < codenum ){ + manage_heater(); + } + break; + case 28: //G28 Home all Axis one at a time + saved_feedrate = feedrate; + for(int i=0; i < NUM_AXIS; i++) { + destination[i] = current_position[i]; + } + feedrate = 0; + + home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); + + if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) { + if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){ + st_synchronize(); + current_position[X_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; + feedrate = homing_feedrate[X_AXIS]; + prepare_move(); + + st_synchronize(); + current_position[X_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = -5 * X_HOME_DIR; + prepare_move(); + + st_synchronize(); + destination[X_AXIS] = 10 * X_HOME_DIR; + feedrate = homing_feedrate[X_AXIS]/2 ; + prepare_move(); + st_synchronize(); + + current_position[X_AXIS] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = current_position[X_AXIS]; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { + if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){ + current_position[Y_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; + feedrate = homing_feedrate[Y_AXIS]; + prepare_move(); + st_synchronize(); + + current_position[Y_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = -5 * Y_HOME_DIR; + prepare_move(); + st_synchronize(); + + destination[Y_AXIS] = 10 * Y_HOME_DIR; + feedrate = homing_feedrate[Y_AXIS]/2; + prepare_move(); + st_synchronize(); + + current_position[Y_AXIS] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = current_position[Y_AXIS]; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { + if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){ + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; + feedrate = homing_feedrate[Z_AXIS]; + prepare_move(); + st_synchronize(); + + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = -2 * Z_HOME_DIR; + prepare_move(); + st_synchronize(); + + destination[Z_AXIS] = 3 * Z_HOME_DIR; + feedrate = homing_feedrate[Z_AXIS]/2; + prepare_move(); + st_synchronize(); + + current_position[Z_AXIS] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = current_position[Z_AXIS]; + feedrate = 0; + } + } + feedrate = saved_feedrate; + previous_millis_cmd = millis(); + break; + case 90: // G90 + relative_mode = false; + break; + case 91: // G91 + relative_mode = true; + break; + case 92: // G92 + if(!code_seen(axis_codes[E_AXIS])) + st_synchronize(); + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) current_position[i] = code_value(); + } + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + break; + + } + } + + else if(code_seen('M')) + { + + switch( (int)code_value() ) + { +#ifdef SDSUPPORT + + case 20: // M20 - list SD card + Serial.println("Begin file list"); + root.ls(); + Serial.println("End file list"); + break; + case 21: // M21 - init SD card + sdmode = false; + initsd(); + break; + case 22: //M22 - release SD card + sdmode = false; + sdactive = false; + break; + case 23: //M23 - Select file + if(sdactive){ + sdmode = false; + file.close(); + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos!=NULL) + *(starpos-1)='\0'; + if (file.open(&root, strchr_pointer + 4, O_READ)) { + Serial.print("File opened:"); + Serial.print(strchr_pointer + 4); + Serial.print(" Size:"); + Serial.println(file.fileSize()); + sdpos = 0; + filesize = file.fileSize(); + Serial.println("File selected"); + } + else{ + Serial.println("file.open failed"); + } + } + break; + case 24: //M24 - Start SD print + if(sdactive){ + sdmode = true; + } + break; + case 25: //M25 - Pause SD print + if(sdmode){ + sdmode = false; + } + break; + case 26: //M26 - Set SD index + if(sdactive && code_seen('S')){ + sdpos = code_value_long(); + file.seekSet(sdpos); + } + break; + case 27: //M27 - Get SD status + if(sdactive){ + Serial.print("SD printing byte "); + Serial.print(sdpos); + Serial.print("/"); + Serial.println(filesize); + } + else{ + Serial.println("Not SD printing"); + } + break; + case 28: //M28 - Start SD write + if(sdactive){ + char* npos = 0; + file.close(); + sdmode = false; + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos != NULL){ + npos = strchr(cmdbuffer[bufindr], 'N'); + strchr_pointer = strchr(npos,' ') + 1; + *(starpos-1) = '\0'; + } + if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) + { + Serial.print("open failed, File: "); + Serial.print(strchr_pointer + 4); + Serial.print("."); + } + else{ + savetosd = true; + Serial.print("Writing to file: "); + Serial.println(strchr_pointer + 4); + } + } + break; + case 29: //M29 - Stop SD write + //processed in write to file routine above + //savetosd = false; + break; +#endif //SDSUPPORT + case 104: // M104 + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw > current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + break; + case 140: // M140 set bed temp + if (code_seen('S')) target_bed_raw = temp2analogBed(code_value()); + break; + case 105: // M105 + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) + tt = analog2temp(current_raw); + #endif + #if TEMP_1_PIN > -1 + bt = analog2tempBed(current_bed_raw); + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) + Serial.print("ok T:"); + Serial.print(tt); + Serial.print(", raw:"); + Serial.print(current_raw); + #if TEMP_1_PIN > -1 + Serial.print(" B:"); + Serial.println(bt); + #else + Serial.println(); + #endif + #else + Serial.println("No thermistors - no temp"); + #endif + return; + //break; + case 109: // M109 - Wait for extruder heater to reach target. + //LCD_MESSAGE("Heating..."); + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw>current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + codenum = millis(); + while(current_raw < target_raw) { + if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + Serial.print("T:"); + Serial.println( analog2temp(current_raw) ); + // LCD_STATUS; + codenum = millis(); + } + manage_heater(); + } + break; + case 190: // M190 - Wait bed for heater to reach target. + #if TEMP_1_PIN > -1 + if (code_seen('S')) target_bed_raw = temp2analog(code_value()); + codenum = millis(); + while(current_bed_raw < target_bed_raw) { + if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + tt=analog2temp(current_raw); + Serial.print("T:"); + Serial.println( tt ); + Serial.print("ok T:"); + Serial.print( tt ); + Serial.print(" B:"); + Serial.println( analog2temp(current_bed_raw) ); + codenum = millis(); + } + manage_heater(); + } + #endif + break; + case 82: + axis_relative_modes[3] = false; + break; + case 83: + axis_relative_modes[3] = true; + break; + case 84: + if(code_seen('S')){ + stepper_inactive_time = code_value() * 1000; + } + else{ + st_synchronize(); + disable_x(); + disable_y(); + disable_z(); + disable_e(); + } + break; + case 85: // M85 + code_seen('S'); + max_inactive_time = code_value() * 1000; + break; + case 92: // M92 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); + } + + break; + case 115: // M115 + Serial.println("FIRMWARE_NAME:Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); + break; + case 114: // M114 + Serial.print("X:"); + Serial.print(current_position[X_AXIS]); + Serial.print("Y:"); + Serial.print(current_position[Y_AXIS]); + Serial.print("Z:"); + Serial.print(current_position[Z_AXIS]); + Serial.print("E:"); + Serial.println(current_position[E_AXIS]); + break; + case 119: // M119 +#if (X_MIN_PIN > -1) + Serial.print("x_min:"); + Serial.print((READ(X_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (X_MAX_PIN > -1) + Serial.print("x_max:"); + Serial.print((READ(X_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Y_MIN_PIN > -1) + Serial.print("y_min:"); + Serial.print((READ(Y_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Y_MAX_PIN > -1) + Serial.print("y_max:"); + Serial.print((READ(Y_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Z_MIN_PIN > -1) + Serial.print("z_min:"); + Serial.print((READ(Z_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Z_MAX_PIN > -1) + Serial.print("z_max:"); + Serial.print((READ(Z_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif + Serial.println(""); + break; + //TODO: update for all axis, use for loop + case 201: // M201 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; +#if 0 // Not used for Sprinter/grbl gen6 + case 202: // M202 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; +#endif +#ifdef PIDTEMP + case 301: // M301 + if(code_seen('P')) Kp = code_value(); + if(code_seen('I')) Ki = code_value()*PID_dT; + if(code_seen('D')) Kd = code_value()/PID_dT; + Serial.print("Kp ");Serial.println(Kp); + Serial.print("Ki ");Serial.println(Ki/PID_dT); + Serial.print("Kd ");Serial.println(Kd*PID_dT); + temp_iState_min = 0.0; + temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; + break; +#endif //PIDTEMP + } + } + else{ + Serial.println("Unknown command:"); + Serial.println(cmdbuffer[bufindr]); + } + + ClearToSend(); +} + +void FlushSerialRequestResend() +{ + //char cmdbuffer[bufindr][100]="Resend:"; + Serial.flush(); + Serial.print("Resend:"); + Serial.println(gcode_LastN + 1); + ClearToSend(); +} + +void ClearToSend() +{ + previous_millis_cmd = millis(); +#ifdef SDSUPPORT + if(fromsd[bufindr]) + return; +#endif //SDSUPPORT + Serial.println("ok"); +} + +inline void get_coordinates() +{ + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; + else destination[i] = current_position[i]; //Are these else lines really needed? + } + if(code_seen('F')) { + next_feedrate = code_value(); + if(next_feedrate > 0.0) feedrate = next_feedrate; + } +} + +void prepare_move() +{ + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60.0); + for(int i=0; i < NUM_AXIS; i++) { + current_position[i] = destination[i]; + } +} +/* +void manage_heater() +{ + float pid_input; + float pid_output; + if(temp_meas_ready != true) + return; + +CRITICAL_SECTION_START; + temp_meas_ready = false; +CRITICAL_SECTION_END; + +#ifdef PIDTEMP + pid_input = analog2temp(current_raw); + +#ifndef PID_OPENLOOP + pid_error = pid_setpoint - pid_input; + if(pid_error > 10){ + pid_output = PID_MAX; + pid_reset = true; + } + else if(pid_error < -10) { + pid_output = 0; + pid_reset = true; + } + else { + if(pid_reset == true) { + temp_iState = 0.0; + pid_reset = false; + } + pTerm = Kp * pid_error; + temp_iState += pid_error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = Ki * temp_iState; + #define K1 0.8 + #define K2 (1.0-K1) + dTerm = (Kd * (pid_input - temp_dState))*K2 + (K1 * dTerm); + temp_dState = pid_input; + pid_output = constrain(pTerm + iTerm - dTerm, 0, PID_MAX); + } +#endif //PID_OPENLOOP +#ifdef PID_DEBUG + Serial.print(" Input "); + Serial.print(pid_input); + Serial.print(" Output "); + Serial.print(pid_output); + Serial.print(" pTerm "); + Serial.print(pTerm); + Serial.print(" iTerm "); + Serial.print(iTerm); + Serial.print(" dTerm "); + Serial.print(dTerm); + Serial.println(); +#endif //PID_DEBUG + OCR2B = pid_output; +#endif //PIDTEMP +} +*/ + + +/* +int temp2analogu(int celsius, const short table[][2], int numtemps) { + int raw = 0; + byte i; + + for (i=1; i raw) { + celsius = (float)table[i-1][1] + + (float)(raw - table[i-1][0]) * + (float)(table[i][1] - table[i-1][1]) / + (float)(table[i][0] - table[i-1][0]); + + break; + } + } + // Overflow: Set to last value in the table + if (i == numtemps) celsius = table[i-1][1]; + + return celsius; +} + + +inline void kill() +{ + target_raw=0; +#ifdef PIDTEMP + pid_setpoint = 0.0; +#endif //PIDTEMP + OCR2B = 0; + WRITE(HEATER_0_PIN,LOW); + + disable_x(); + disable_y(); + disable_z(); + disable_e(); + +} +*/ + + + +//#################################################################################################################### +//#################################################################################################################### +void manage_heater() +{ +#ifdef USE_WATCHDOG + wd_reset(); +#endif + //there is noanalogRead FANCY_LCD here, because this routine is called within moves, and delays them. one could loose steps. + + if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) + return; + previous_millis_heater = millis(); + #ifdef HEATER_USES_THERMISTOR + current_raw = analogRead(TEMP_0_PIN); + // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_raw = 1023 - current_raw; + #elif defined HEATER_USES_AD595 + current_raw = analogRead(TEMP_0_PIN); + #elif defined HEATER_USES_MAX6675 + current_raw = read_max6675(); + #endif + #ifdef SMOOTHING + nma = (nma + current_raw) - (nma / SMOOTHFACTOR); + current_raw = nma / SMOOTHFACTOR; + #endif + #ifdef WATCHPERIOD + if(watchmillis && millis() - watchmillis > WATCHPERIOD){ + if(watch_raw + 1 >= current_raw){ + target_raw = 0; + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + }else{ + watchmillis = 0; + } + } + #endif + #ifdef MINTEMP + if(current_raw <= minttemp) + target_raw = 0; + #endif + #ifdef MAXTEMP + if(current_raw >= maxttemp) { + target_raw = 0; + } + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) + #ifdef PIDTEMP + error = target_raw - current_raw; + pTerm = (PID_PGAIN * error) / 100; + temp_iState += error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = (PID_IGAIN * temp_iState) / 100; + dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; + temp_dState = current_raw; + analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); + #else + if(current_raw >= target_raw) + { + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + } + else + { + digitalWrite(HEATER_0_PIN,HIGH); + digitalWrite(LED_PIN,HIGH); + } + #endif + #endif + + if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) + return; + previous_millis_bed_heater = millis(); + + #ifdef BED_USES_THERMISTOR + + current_bed_raw = analogRead(TEMP_1_PIN); + + // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_bed_raw = 1023 - current_bed_raw; + #elif defined BED_USES_AD595 + current_bed_raw = analogRead(TEMP_1_PIN); + + #endif + + + #if TEMP_1_PIN > -1 + if(current_bed_raw >= target_bed_raw) + { + digitalWrite(HEATER_1_PIN,LOW); + } + else + { + digitalWrite(HEATER_1_PIN,HIGH); + } + #endif +} + +// Takes hot end temperature value as input and returns corresponding raw value. +// For a thermistor, it uses the RepRap thermistor temp table. +// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value. +// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware. +float temp2analog(int celsius) { + #ifdef HEATER_USES_THERMISTOR + int raw = 0; + byte i; + + for (i=1; i raw) + { + celsius = temptable[i-1][1] + + (raw - temptable[i-1][0]) * + (temptable[i][1] - temptable[i-1][1]) / + (temptable[i][0] - temptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = temptable[i-1][1]; + + return celsius; + #elif defined HEATER_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #elif defined HEATER_USES_MAX6675 + return raw * 0.25; + #endif +} + +// Derived from RepRap FiveD extruder::getTemperature() +// For bed temperature measurement. +float analog2tempBed(int raw) { + #ifdef BED_USES_THERMISTOR + int celsius = 0; + byte i; + + raw = 1023 - raw; + + for (i=1; i raw) + { + celsius = bedtemptable[i-1][1] + + (raw - bedtemptable[i-1][0]) * + (bedtemptable[i][1] - bedtemptable[i-1][1]) / + (bedtemptable[i][0] - bedtemptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = bedtemptable[i-1][1]; + + return celsius; + + #elif defined BED_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #endif +} + +inline void kill() +{ + #if TEMP_0_PIN > -1 + target_raw=0; + digitalWrite(HEATER_0_PIN,LOW); + #endif + #if TEMP_1_PIN > -1 + target_bed_raw=0; + if(HEATER_1_PIN > -1) digitalWrite(HEATER_1_PIN,LOW); + #endif + disable_x(); + disable_y(); + disable_z(); + disable_e(); + + if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); + +} + + + + + + +//####################################################################################################################### + +inline void manage_inactivity(byte debug) { + if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); + if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { + disable_x(); + disable_y(); + disable_z(); + disable_e(); + } + check_axes_activity(); +} + +// Planner + +/* + Reasoning behind the mathematics in this module (in the key of 'Mathematica'): + + s == speed, a == acceleration, t == time, d == distance + + Basic definitions: + + Speed[s_, a_, t_] := s + (a*t) + Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t] + + Distance to reach a specific speed with a constant acceleration: + + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t] + d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance() + + Speed after a given distance of travel with constant acceleration: + + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t] + m -> Sqrt[2 a d + s^2] + + DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2] + + When to start braking (di) to reach a specified destionation speed (s2) after accelerating + from initial speed s1 without ever stopping at a plateau: + + Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di] + di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance() + + IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a) + */ + + +// The number of linear motions that can be in the plan at any give time +#define BLOCK_BUFFER_SIZE 16 +#define BLOCK_BUFFER_MASK 0x0f + +static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions +static volatile unsigned char block_buffer_head; // Index of the next block to be pushed +static volatile unsigned char block_buffer_tail; // Index of the block to process now + +// The current position of the tool in absolute steps +static long position[4]; + +#define ONE_MINUTE_OF_MICROSECONDS 60000000.0 + +// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the +// given acceleration: +inline long estimate_acceleration_distance(long initial_rate, long target_rate, long acceleration) { + return( + (target_rate*target_rate-initial_rate*initial_rate)/ + (2L*acceleration) + ); +} + +// This function gives you the point at which you must start braking (at the rate of -acceleration) if +// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after +// a total travel of distance. This can be used to compute the intersection point between acceleration and +// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) + +inline long intersection_distance(long initial_rate, long final_rate, long acceleration, long distance) { + return( + (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ + (4*acceleration) + ); +} + +// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. + +void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { + if(block->busy == true) return; // If block is busy then bail out. + float entry_factor = entry_speed / block->nominal_speed; + float exit_factor = exit_speed / block->nominal_speed; + long initial_rate = ceil(block->nominal_rate*entry_factor); + long final_rate = ceil(block->nominal_rate*exit_factor); + +#ifdef ADVANCE + long initial_advance = block->advance*entry_factor*entry_factor; + long final_advance = block->advance*exit_factor*exit_factor; +#endif // ADVANCE + + // Limit minimal step rate (Otherwise the timer will overflow.) + if(initial_rate <120) initial_rate=120; + if(final_rate < 120) final_rate=120; + + // Calculate the acceleration steps + long acceleration = block->acceleration; + long accelerate_steps = estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration); + long decelerate_steps = estimate_acceleration_distance(final_rate, block->nominal_rate, acceleration); + + // Calculate the size of Plateau of Nominal Rate. + long plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; + + // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will + // have to use intersection_distance() to calculate when to abort acceleration and start braking + // in order to reach the final_rate exactly at the end of this block. + if (plateau_steps < 0) { + accelerate_steps = intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count); + plateau_steps = 0; + } + + long decelerate_after = accelerate_steps+plateau_steps; + long acceleration_rate = (long)((float)acceleration * 8.388608); + + CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section + if(block->busy == false) { // Don't update variables if block is busy. + block->accelerate_until = accelerate_steps; + block->decelerate_after = decelerate_after; + block->acceleration_rate = acceleration_rate; + block->initial_rate = initial_rate; + block->final_rate = final_rate; +#ifdef ADVANCE + block->initial_advance = initial_advance; + block->final_advance = final_advance; +#endif //ADVANCE + } + CRITICAL_SECTION_END; +} + +// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the +// acceleration within the allotted distance. +inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { + return( + sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) + ); +} + +// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks. +// This method will calculate the junction jerk as the euclidean distance between the nominal +// velocities of the respective blocks. +inline float junction_jerk(block_t *before, block_t *after) { + return(sqrt( + pow((before->speed_x-after->speed_x), 2)+ + pow((before->speed_y-after->speed_y), 2)+ + pow((before->speed_z-after->speed_z)*axis_steps_per_unit[Z_AXIS]/axis_steps_per_unit[X_AXIS], 2))); +} + +// Return the safe speed which is max_jerk/2, e.g. the +// speed under which you cannot exceed max_jerk no matter what you do. +float safe_speed(block_t *block) { + float safe_speed; + safe_speed = max_jerk/2; + if (safe_speed > block->nominal_speed) safe_speed = block->nominal_speed; + return safe_speed; +} + +// The kernel called by planner_recalculate() when scanning the plan from last to first entry. +void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) { + if(!current) { + return; + } + + float entry_speed = current->nominal_speed; + float exit_factor; + float exit_speed; + if (next) { + exit_speed = next->entry_speed; + } + else { + exit_speed = safe_speed(current); + } + + // Calculate the entry_factor for the current block. + if (previous) { + // Reduce speed so that junction_jerk is within the maximum allowed + float jerk = junction_jerk(previous, current); + if((previous->steps_x == 0) && (previous->steps_y == 0)) { + entry_speed = safe_speed(current); + } + else if (jerk > max_jerk) { + entry_speed = (max_jerk/jerk) * entry_speed; + } + // If the required deceleration across the block is too rapid, reduce the entry_factor accordingly. + if (entry_speed > exit_speed) { + float max_entry_speed = max_allowable_speed(-acceleration,exit_speed, current->millimeters); + if (max_entry_speed < entry_speed) { + entry_speed = max_entry_speed; + } + } + } + else { + entry_speed = safe_speed(current); + } + // Store result + current->entry_speed = entry_speed; +} + +// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This +// implements the reverse pass. +void planner_reverse_pass() { + char block_index = block_buffer_head; + block_t *block[3] = { + NULL, NULL, NULL }; + while(block_index != block_buffer_tail) { + block_index--; + if(block_index < 0) { + block_index = BLOCK_BUFFER_SIZE-1; + } + block[2]= block[1]; + block[1]= block[0]; + block[0] = &block_buffer[block_index]; + planner_reverse_pass_kernel(block[0], block[1], block[2]); + } + planner_reverse_pass_kernel(NULL, block[0], block[1]); +} + +// The kernel called by planner_recalculate() when scanning the plan from first to last entry. +void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) { + if(!current) { + return; + } + if(previous) { + // If the previous block is an acceleration block, but it is not long enough to + // complete the full speed change within the block, we need to adjust out entry + // speed accordingly. Remember current->entry_factor equals the exit factor of + // the previous block. + if(previous->entry_speed < current->entry_speed) { + float max_entry_speed = max_allowable_speed(-acceleration, previous->entry_speed, previous->millimeters); + if (max_entry_speed < current->entry_speed) { + current->entry_speed = max_entry_speed; + } + } + } +} + +// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This +// implements the forward pass. +void planner_forward_pass() { + char block_index = block_buffer_tail; + block_t *block[3] = { + NULL, NULL, NULL }; + + while(block_index != block_buffer_head) { + block[0] = block[1]; + block[1] = block[2]; + block[2] = &block_buffer[block_index]; + planner_forward_pass_kernel(block[0],block[1],block[2]); + block_index = (block_index+1) & BLOCK_BUFFER_MASK; + } + planner_forward_pass_kernel(block[1], block[2], NULL); +} + +// Recalculates the trapezoid speed profiles for all blocks in the plan according to the +// entry_factor for each junction. Must be called by planner_recalculate() after +// updating the blocks. +void planner_recalculate_trapezoids() { + char block_index = block_buffer_tail; + block_t *current; + block_t *next = NULL; + while(block_index != block_buffer_head) { + current = next; + next = &block_buffer[block_index]; + if (current) { + calculate_trapezoid_for_block(current, current->entry_speed, next->entry_speed); + } + block_index = (block_index+1) & BLOCK_BUFFER_MASK; + } + calculate_trapezoid_for_block(next, next->entry_speed, safe_speed(next)); +} + +// Recalculates the motion plan according to the following algorithm: +// +// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) +// so that: +// a. The junction jerk is within the set limit +// b. No speed reduction within one block requires faster deceleration than the one, true constant +// acceleration. +// 2. Go over every block in chronological order and dial down junction speed reduction values if +// a. The speed increase within one block would require faster accelleration than the one, true +// constant acceleration. +// +// When these stages are complete all blocks have an entry_factor that will allow all speed changes to +// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than +// the set limit. Finally it will: +// +// 3. Recalculate trapezoids for all blocks. + +void planner_recalculate() { + planner_reverse_pass(); + planner_forward_pass(); + planner_recalculate_trapezoids(); +} + +void plan_init() { + block_buffer_head = 0; + block_buffer_tail = 0; + memset(position, 0, sizeof(position)); // clear position +} + + +inline void plan_discard_current_block() { + if (block_buffer_head != block_buffer_tail) { + block_buffer_tail = (block_buffer_tail + 1) & BLOCK_BUFFER_MASK; + } +} + +inline block_t *plan_get_current_block() { + if (block_buffer_head == block_buffer_tail) { + return(NULL); + } + block_t *block = &block_buffer[block_buffer_tail]; + block->busy = true; + return(block); +} + +void check_axes_activity() { + unsigned char x_active = 0; + unsigned char y_active = 0; + unsigned char z_active = 0; + unsigned char e_active = 0; + block_t *block; + + if(block_buffer_tail != block_buffer_head) { + char block_index = block_buffer_tail; + while(block_index != block_buffer_head) { + block = &block_buffer[block_index]; + if(block->steps_x != 0) x_active++; + if(block->steps_y != 0) y_active++; + if(block->steps_z != 0) z_active++; + if(block->steps_e != 0) e_active++; + block_index = (block_index+1) & BLOCK_BUFFER_MASK; + } + } + if((DISABLE_X) && (x_active == 0)) disable_x(); + if((DISABLE_Y) && (y_active == 0)) disable_y(); + if((DISABLE_Z) && (z_active == 0)) disable_z(); + if((DISABLE_E) && (e_active == 0)) disable_e(); +} + +// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in +// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration +// calculation the caller must also provide the physical length of the line in millimeters. +void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { + + // The target position of the tool in absolute steps + // Calculate target position in absolute steps + long target[4]; + target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); + target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); + target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); + target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); + + // Calculate the buffer head after we push this byte + int next_buffer_head = (block_buffer_head + 1) & BLOCK_BUFFER_MASK; + + // If the buffer is full: good! That means we are well ahead of the robot. + // Rest here until there is room in the buffer. + while(block_buffer_tail == next_buffer_head) { + manage_heater(); + manage_inactivity(1); + } + + // Prepare to set up new block + block_t *block = &block_buffer[block_buffer_head]; + + // Mark block as not busy (Not executed by the stepper interrupt) + block->busy = false; + + // Number of steps for each axis + block->steps_x = labs(target[X_AXIS]-position[X_AXIS]); + block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]); + block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); + block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); + block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); + + // Bail if this is a zero-length block + if (block->step_event_count == 0) { + return; + }; + + float delta_x_mm = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; + float delta_y_mm = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; + float delta_z_mm = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; + float delta_e_mm = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS]; + block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); + + unsigned long microseconds; + microseconds = lround((block->millimeters/feed_rate)*1000000); + + // Calculate speed in mm/minute for each axis + float multiplier = 60.0*1000000.0/microseconds; + block->speed_z = delta_z_mm * multiplier; + block->speed_x = delta_x_mm * multiplier; + block->speed_y = delta_y_mm * multiplier; + block->speed_e = delta_e_mm * multiplier; + + // Limit speed per axis + float speed_factor = 1; + float tmp_speed_factor; + if(abs(block->speed_x) > max_feedrate[X_AXIS]) { + speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + } + if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ + tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ + tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_e) > max_feedrate[E_AXIS]){ + tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + multiplier = multiplier * speed_factor; + block->speed_z = delta_z_mm * multiplier; + block->speed_x = delta_x_mm * multiplier; + block->speed_y = delta_y_mm * multiplier; + block->speed_e = delta_e_mm * multiplier; + block->nominal_speed = block->millimeters * multiplier; + block->nominal_rate = ceil(block->step_event_count * multiplier / 60); + + if(block->nominal_rate < 120) block->nominal_rate = 120; + block->entry_speed = safe_speed(block); + + // Compute the acceleration rate for the trapezoid generator. + float travel_per_step = block->millimeters/block->step_event_count; + if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { + block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + } + else { + block->acceleration = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + // Limit acceleration per axis + if((block->acceleration * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) + block->acceleration = axis_steps_per_sqr_second[X_AXIS]; + if((block->acceleration * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) + block->acceleration = axis_steps_per_sqr_second[Y_AXIS]; + if((block->acceleration * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) + block->acceleration = axis_steps_per_sqr_second[E_AXIS]; + if((block->acceleration * block->steps_z / block->step_event_count) > axis_steps_per_sqr_second[Z_AXIS]) + block->acceleration = axis_steps_per_sqr_second[Z_AXIS]; + } + +#ifdef ADVANCE + // Calculate advance rate + if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { + block->advance_rate = 0; + block->advance = 0; + } + else { + long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration); + float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * + (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; + block->advance = advance; + if(acc_dist == 0) { + block->advance_rate = 0; + } + else { + block->advance_rate = advance / (float)acc_dist; + } + } + +#endif // ADVANCE + + // compute a preliminary conservative acceleration trapezoid + float safespeed = safe_speed(block); + calculate_trapezoid_for_block(block, safespeed, safespeed); + + // Compute direction bits for this block + block->direction_bits = 0; + if (target[X_AXIS] < position[X_AXIS]) { + block->direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<steps_x != 0) enable_x(); + if(block->steps_y != 0) enable_y(); + if(block->steps_z != 0) enable_z(); + if(block->steps_e != 0) enable_e(); + + // Move buffer head + block_buffer_head = next_buffer_head; + + // Update position + memcpy(position, target, sizeof(target)); // position[] = target[] + + planner_recalculate(); + st_wake_up(); +} + +void plan_set_position(float x, float y, float z, float e) +{ + position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); + position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); + position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); + position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); +} + +// Stepper + +// intRes = intIn1 * intIn2 >> 16 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 24 bit result +#define MultiU16X8toH16(intRes, charIn1, intIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %A1, %A2 \n\t" \ +"add %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r0 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (charIn1), \ +"d" (intIn2) \ +: \ +"r26" \ +) + +// intRes = longIn1 * longIn2 >> 24 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 48bit result +#define MultiU24X24toH16(intRes, longIn1, longIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"mov r27, r1 \n\t" \ +"mul %B1, %C2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %C1, %C2 \n\t" \ +"add %B0, r0 \n\t" \ +"mul %C1, %B2 \n\t" \ +"add %A0, r0 \n\t" \ +"adc %B0, r1 \n\t" \ +"mul %A1, %C2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %B2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %C1, %A2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %A2 \n\t" \ +"add r27, r1 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r27 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (longIn1), \ +"d" (longIn2) \ +: \ +"r26" , "r27" \ +) + +// Some useful constants + +#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1< +// +// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates +// first block->accelerate_until step_events_completed, then keeps going at constant speed until +// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. +// The slope of acceleration is calculated with the leib ramp alghorithm. + +void st_wake_up() { + // TCNT1 = 0; + ENABLE_STEPPER_DRIVER_INTERRUPT(); +} + +inline unsigned short calc_timer(unsigned short step_rate) { + unsigned short timer; + if(step_rate < 32) step_rate = 32; + step_rate -= 32; // Correct for minimal speed + if(step_rate >= (8*256)){ // higher step rate + unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; + unsigned char tmp_step_rate = (step_rate & 0x00ff); + unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); + MultiU16X8toH16(timer, tmp_step_rate, gain); + timer = (unsigned short)pgm_read_word_near(table_address) - timer; + } + else { // lower step rates + unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; + table_address += ((step_rate)>>1) & 0xfffc; + timer = (unsigned short)pgm_read_word_near(table_address); + timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); + } + if(timer < 100) timer = 100; + return timer; +} + +// Initializes the trapezoid generator from the current block. Called whenever a new +// block begins. +inline void trapezoid_generator_reset() { + accelerate_until = current_block->accelerate_until; + decelerate_after = current_block->decelerate_after; + acceleration_rate = current_block->acceleration_rate; + initial_rate = current_block->initial_rate; + final_rate = current_block->final_rate; + nominal_rate = current_block->nominal_rate; + advance = current_block->initial_advance; + final_advance = current_block->final_advance; + deceleration_time = 0; + advance_rate = current_block->advance_rate; + // step_rate to timer interval + acc_step_rate = initial_rate; + acceleration_time = calc_timer(acc_step_rate); + OCR1A = acceleration_time; +} + +// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. +// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. +ISR(TIMER1_COMPA_vect) +{ + if(busy){ /*Serial.println("BUSY")*/; + return; + } // The busy-flag is used to avoid reentering this interrupt + + busy = true; + sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) + + // If there is no current block, attempt to pop one from the buffer + if (current_block == NULL) { + // Anything in the buffer? + current_block = plan_get_current_block(); + if (current_block != NULL) { + trapezoid_generator_reset(); + counter_x = -(current_block->step_event_count >> 1); + counter_y = counter_x; + counter_z = counter_x; + counter_e = counter_x; + step_events_completed = 0; + e_steps = 0; + } + else { + DISABLE_STEPPER_DRIVER_INTERRUPT(); + } + } + + if (current_block != NULL) { + // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt + out_bits = current_block->direction_bits; + +#ifdef ADVANCE + // Calculate E early. + counter_e += current_block->steps_e; + if (counter_e > 0) { + counter_e -= current_block->step_event_count; + if ((out_bits & (1<> 16) - old_advance); + CRITICAL_SECTION_END; + old_advance = advance >> 16; +#endif //ADVANCE + + // Set direction en check limit switches + if ((out_bits & (1<step_event_count; + } + } + else // +direction + WRITE(X_DIR_PIN,!INVERT_X_DIR); + + if ((out_bits & (1<step_event_count; + } + } + else // +direction + WRITE(Y_DIR_PIN,!INVERT_Y_DIR); + + if ((out_bits & (1<step_event_count; + } + } + else // +direction + WRITE(Z_DIR_PIN,!INVERT_Z_DIR); + +#ifndef ADVANCE + if ((out_bits & (1<steps_x; + if (counter_x > 0) { + WRITE(X_STEP_PIN, HIGH); + counter_x -= current_block->step_event_count; + WRITE(X_STEP_PIN, LOW); + } + + counter_y += current_block->steps_y; + if (counter_y > 0) { + WRITE(Y_STEP_PIN, HIGH); + counter_y -= current_block->step_event_count; + WRITE(Y_STEP_PIN, LOW); + } + + counter_z += current_block->steps_z; + if (counter_z > 0) { + WRITE(Z_STEP_PIN, HIGH); + counter_z -= current_block->step_event_count; + WRITE(Z_STEP_PIN, LOW); + } + +#ifndef ADVANCE + counter_e += current_block->steps_e; + if (counter_e > 0) { + WRITE(E_STEP_PIN, HIGH); + counter_e -= current_block->step_event_count; + WRITE(E_STEP_PIN, LOW); + } +#endif //!ADVANCE + + // Calculare new timer value + unsigned short timer; + unsigned short step_rate; + if (step_events_completed < accelerate_until) { + MultiU24X24toH16(acc_step_rate, acceleration_time, acceleration_rate); + acc_step_rate += initial_rate; + + // upper limit + if(acc_step_rate > nominal_rate) + acc_step_rate = nominal_rate; + + // step_rate to timer interval + timer = calc_timer(acc_step_rate); + advance += advance_rate; + acceleration_time += timer; + OCR1A = timer; + } + else if (step_events_completed >= decelerate_after) { + MultiU24X24toH16(step_rate, deceleration_time, acceleration_rate); + + if(step_rate > acc_step_rate) { // Check step_rate stays positive + step_rate = final_rate; + } + else { + step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. + } + + // lower limit + if(step_rate < final_rate) + step_rate = final_rate; + + // step_rate to timer interval + timer = calc_timer(step_rate); +#ifdef ADVANCE + advance -= advance_rate; + if(advance < final_advance) + advance = final_advance; +#endif //ADVANCE + deceleration_time += timer; + OCR1A = timer; + } + // If current block is finished, reset pointer + step_events_completed += 1; + if (step_events_completed >= current_block->step_event_count) { + current_block = NULL; + plan_discard_current_block(); + } + } + busy=false; +} + +#ifdef ADVANCE + +unsigned char old_OCR0A; +// Timer interrupt for E. e_steps is set in the main routine; +// Timer 0 is shared with millies +ISR(TIMER0_COMPA_vect) +{ + // Critical section needed because Timer 1 interrupt has higher priority. + // The pin set functions are placed on trategic position to comply with the stepper driver timing. + WRITE(E_STEP_PIN, LOW); + // Set E direction (Depends on E direction + advance) + if (e_steps < 0) { + WRITE(E_DIR_PIN,INVERT_E_DIR); + e_steps++; + WRITE(E_STEP_PIN, HIGH); + } + if (e_steps > 0) { + WRITE(E_DIR_PIN,!INVERT_E_DIR); + e_steps--; + WRITE(E_STEP_PIN, HIGH); + } + old_OCR0A += 25; // 10kHz interrupt + OCR0A = old_OCR0A; +} +#endif // ADVANCE + +void st_init() +{ + // waveform generation = 0100 = CTC + TCCR1B &= ~(1<= 16) + { + current_raw = 16383 - raw_temp_value; + temp_meas_ready = true; + temp_count = 0; + raw_temp_value = 0; +#ifdef MAXTEMP + if(current_raw >= maxttemp) { + target_raw = 0; +#ifdef PIDTEMP + OCR2B = 0; +#else + WRITE(HEATER_0_PIN,LOW); +#endif //PIDTEMP + } +#endif //MAXTEMP +#ifdef MINTEMP + if(current_raw <= minttemp) { + target_raw = 0; +#ifdef PIDTEMP + OCR2B = 0; +#else + WRITE(HEATER_0_PIN,LOW); +#endif //PIDTEMP + } +#endif //MAXTEMP +#ifndef PIDTEMP + if(current_raw >= target_raw) + { + WRITE(HEATER_0_PIN,LOW); + } + else + { + WRITE(HEATER_0_PIN,HIGH); + } +#endif //PIDTEMP + } +} + +*/ From 5b93020e6c24d6a393092ef1e5d90781ca961560 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 23 Aug 2011 16:21:59 +0200 Subject: [PATCH 004/130] unworking temp reading still, added lcd support --- Marlin/Configuration.h | 19 +- Marlin/Marlin.pde | 35 ++- Marlin/buttons.h | 60 +++++ Marlin/buttons.pde | 96 ++++++++ Marlin/lcd.h | 32 +++ Marlin/lcd.pde | 539 +++++++++++++++++++++++++++++++++++++++++ Marlin/menu_base.h | 105 ++++++++ Marlin/menu_base.pde | 65 +++++ Marlin/wiring.pde | 176 ++++++++++++++ 9 files changed, 1110 insertions(+), 17 deletions(-) create mode 100644 Marlin/buttons.h create mode 100644 Marlin/buttons.pde create mode 100644 Marlin/lcd.h create mode 100644 Marlin/lcd.pde create mode 100644 Marlin/menu_base.h create mode 100644 Marlin/menu_base.pde create mode 100644 Marlin/wiring.pde diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index af5b16e0a18b..583de16f564b 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -18,7 +18,7 @@ //#define HEATER_USES_MAX6675 // Select one of these only to define how the bed temp is read. -//#define BED_USES_THERMISTOR +#define BED_USES_THERMISTOR //#define BED_USES_AD595 #define HEATER_CHECK_INTERVAL 50 @@ -43,7 +43,10 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -//#define SDSUPPORT +#define SDSUPPORT +#define FANCY_LCD +#define LCD_UPDATE_INTERVAL 400 + //// ADVANCED SETTINGS - to tweak parameters @@ -83,15 +86,15 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the //// MOVEMENT SETTINGS #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E float max_feedrate[] = {60000, 60000, 500, 500000}; // set the max speeds -float homing_feedrate[] = {2400, 2400, 150, 0}; // set the homing speeds +float homing_feedrate[] = {2400, 2400, 200, 0}; // set the homing speeds bool axis_relative_modes[] = {false, false, false, false}; //// Acceleration settings // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. -float acceleration = 2000; // Normal acceleration mm/s^2 +float acceleration = 3000; // Normal acceleration mm/s^2 float retract_acceleration = 7000; // Normal acceleration mm/s^2 float max_jerk = 20*60; -long max_acceleration_units_per_sq_second[] = {7000,7000,100,10000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts +long max_acceleration_units_per_sq_second[] = {7000,7000,200,10000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts // Not used long max_travel_acceleration_units_per_sq_second[] = {500,500,50,500}; // X, Y, Z max acceleration in mm/s^2 for travel moves @@ -136,11 +139,11 @@ double Kd = 80/PID_dT; #ifdef ADVANCE #define EXTRUDER_ADVANCE_K 0.02 -#define D_FILAMENT 1.7 -#define STEPS_MM_E 65 +#define D_FILAMENT 2.75 +#define STEPS_MM_E 600 #define EXTRUTION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159) #define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUTION_AREA) #endif // ADVANCE -#endif +#endif \ No newline at end of file diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index da93e8058547..6dbca501b370 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -39,6 +39,8 @@ #include "fastio.h" #include "Configuration.h" #include "pins.h" +#include "lcd.h" +//extern LiquidCrystal lcd; char version_string[] = "0.9.3"; @@ -227,7 +229,9 @@ void setup() Serial.print("Marlin "); Serial.println(version_string); Serial.println("start"); - +#ifdef FANCY_LCD + lcd_init(); +#endif for(int i = 0; i < BUFSIZE; i++){ fromsd[i] = false; } @@ -359,8 +363,6 @@ void setup() void loop() { - //check heater every n milliseconds - manage_heater(); if(buflen<3) get_command(); @@ -387,8 +389,10 @@ void loop() buflen = (buflen-1); bufindr = (bufindr + 1)%BUFSIZE; } - + //check heater every n milliseconds + manage_heater(); manage_inactivity(1); + LCD_STATUS; } @@ -805,7 +809,7 @@ inline void process_commands() return; //break; case 109: // M109 - Wait for extruder heater to reach target. - //LCD_MESSAGE("Heating..."); + LCD_MESSAGE("Heating..."); if (code_seen('S')) target_raw = temp2analog(code_value()); #ifdef WATCHPERIOD if(target_raw>current_raw){ @@ -821,7 +825,7 @@ inline void process_commands() { Serial.print("T:"); Serial.println( analog2temp(current_raw) ); - // LCD_STATUS; + LCD_STATUS; codenum = millis(); } manage_heater(); @@ -847,6 +851,20 @@ inline void process_commands() } #endif break; + case 106: //M106 Fan On + if (code_seen('S')){ + digitalWrite(FAN_PIN, HIGH); + analogWrite(FAN_PIN, constrain(code_value(),0,255) ); + } + else + digitalWrite(FAN_PIN, HIGH); + break; + case 107: //M107 Fan Off + analogWrite(FAN_PIN, 0); + + digitalWrite(FAN_PIN, LOW); + break; + case 82: axis_relative_modes[3] = false; break; @@ -1117,8 +1135,7 @@ void manage_heater() #ifdef USE_WATCHDOG wd_reset(); #endif - //there is noanalogRead FANCY_LCD here, because this routine is called within moves, and delays them. one could loose steps. - + if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) return; previous_millis_heater = millis(); @@ -2333,4 +2350,4 @@ ISR(TIMER2_OVF_vect) } } -*/ +*/ \ No newline at end of file diff --git a/Marlin/buttons.h b/Marlin/buttons.h new file mode 100644 index 000000000000..8472491db1b6 --- /dev/null +++ b/Marlin/buttons.h @@ -0,0 +1,60 @@ + +#define BUTTONS_HAVEENCODER + +extern volatile char buttons; +extern volatile int encoderpos; + +//buttons are attached to a shift register +#define SHIFT_CLK 38 +#define SHIFT_LD 42 +#define SHIFT_OUT 40 +#define SHIFT_EN 17 + +// blocking time for recognizing a new keypress of one key, ms +#define blocktime 1000 + + +//bits in the shift register that carry the buttons for: +// left up center down right red +#define BL_LE 7 +#define BL_UP 6 +#define BL_MI 5 +#define BL_DW 4 +#define BL_RI 3 +#define BL_ST 2 + +//if there is a rotary encoder, its two bits are at the shift register byte position: +#ifdef BUTTONS_HAVEENCODER + + #define BLEN_B 1 + #define BLEN_A 0 + + //encoder rotation values + #define encrot0 0 + #define encrot1 2 + #define encrot2 3 + #define encrot3 1 + +#endif //BUTONS_HAVEENCODER + + +//atomatic, do not change +#define B_LE (1< + extern LiquidCrystal lcd; + + //lcd display size + #define LCD_WIDTH 20 + #define LCD_HEIGHT 4 + + //arduino pin witch triggers an piezzo beeper + #define BEEPER 18 + + void lcd_status(); + void lcd_init(); + void lcd_status(const char* message); + void beep(); + + + + #define LCD_MESSAGE(x) lcd_status(x); + #define LCD_STATUS lcd_status() +#else + #define LCD_STATUS + #define LCD_MESSAGE(x) +#endif + +#endif diff --git a/Marlin/lcd.pde b/Marlin/lcd.pde new file mode 100644 index 000000000000..93b64571132f --- /dev/null +++ b/Marlin/lcd.pde @@ -0,0 +1,539 @@ +#include "lcd.h" +#include "pins.h" + +#ifdef FANCY_LCD + +#include +LiquidCrystal lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5,LCD_PINS_D6,LCD_PINS_D7); //RS,Enable,D4,D5,D6,D7 + +unsigned long previous_millis_lcd=0; + +#include "buttons.h" + +#include "menu_base.h" + +char messagetext[20]=""; + + + +bool force_lcd_update=false; + + +extern LiquidCrystal lcd; + +//return for string conversion routines +char conv[8]; + +/// convert float to string with +123.4 format +char *ftostr31(const float &x) +{ + //sprintf(conv,"%5.1f",x); + int xx=x*10; + conv[0]=(xx>=0)?'+':'-'; + xx=abs(xx); + conv[1]=(xx/1000)%10+'0'; + conv[2]=(xx/100)%10+'0'; + conv[3]=(xx/10)%10+'0'; + conv[4]='.'; + conv[5]=(xx)%10+'0'; + conv[6]=0; + return conv; +} + +/// convert float to string with +1234.5 format +char *ftostr51(const float &x) +{ + int xx=x*10; + conv[0]=(xx>=0)?'+':'-'; + xx=abs(xx); + conv[1]=(xx/10000)%10+'0'; + conv[2]=(xx/1000)%10+'0'; + conv[3]=(xx/100)%10+'0'; + conv[4]=(xx/10)%10+'0'; + conv[5]='.'; + conv[6]=(xx)%10+'0'; + conv[7]=0; + return conv; +} + +char *fillto(int8_t n,char *c) +{ + static char ret[25]; + bool endfound=false; + for(int8_t i=0;i0); + + if(1&&print) + { + lcd.print(fillto(20,cline2)); + } + if(LCD_HEIGHT>2) + { + lcd.setCursor(0, 2); + strncpy(cline2,cmdbuffer[(abs(bufindr-2))%BUFSIZE],LCD_WIDTH-1); //the last processed line + cline2[LCD_WIDTH-1]=0; + bool print=(strlen(cline2)>0); + + if(1&&print) + { + lcd.print(fillto(20,cline2)); + } + lcd.setCursor(0,3); + lcd.print(fillto(20,messagetext)); + + } + +#endif + fillline(); +} + + + +class PageMove:public MenuPage +{ +public: + PageMove(); + + virtual void activate(); + virtual void update(); +}; + +//extern float current_x, current_y , current_z , current_e ; +extern float current_position[NUM_AXIS]; +float target_x,target_y,target_z,target_e; + + + +PageMove::PageMove() +{ + xshift=10;items=4; +} + +int lastline=-1; +int lastencoder=0; +int step=2; +void PageMove::update() +{ + + if(line!=lastline) + { + lastencoder=encoderpos; + target_x=current_position[X_AXIS]; + target_y=current_position[Y_AXIS]; + target_z=current_position[Z_AXIS]; + target_e=current_position[E_AXIS]; + } + else //update on the same selected line + if(lastencoder!=encoderpos) //change in encoder + { + int d=encoderpos-lastencoder; + char c=';'; + float cur=0; + if(line==4) + { + step+=d; + if(step<1) step=1; + } + else + { + switch(line) + { + case 0:c='X';cur=target_x+=step*d/10.;break; + case 1:c='Y';cur=target_y+=step*d/10.;break; + case 2:c='Z';cur=target_z+=step*d/10.;break; + case 3:c='E';cur=target_e+=step*d/10.;break; + } + char com[20]; + sprintf(com,"G1 %c%i.%i",c,int(cur),int(fabs(cur*10))%10); + enquecommand(com); + } + lastencoder=encoderpos; + } + else + { + //Serial.print("encoder: ");Serial.println(encoderpos); + } + lastline=line; + activate(); +} + +void PageMove::activate() +{ + lcd.setCursor(0,0); + lcd.print("Manual Move "); + lcd.setCursor(0,1); + lcd.print(" X");lcd.print(ftostr31(current_position[X_AXIS]));lcd.print(" E");lcd.print(ftostr51(current_position[E_AXIS])); + lcd.setCursor(0,2); + lcd.print(" Y");lcd.print(ftostr31(current_position[Y_AXIS]));lcd.print(" St");lcd.print(ftostr31(step/10.));lcd.print(" "); + lcd.setCursor(0,3); + lcd.print(" Z");lcd.print(ftostr31(current_position[Z_AXIS]));lcd.print(" "); + fillline(); +} + +class PageHome:public MenuPage +{ +public: + PageHome(); + + virtual void activate(); + virtual void update(); +}; + + +PageHome::PageHome() +{ + xshift=10;items=5; +} + +void PageHome::update() +{ + if(buttons&B_MI) + { + blocking[BL_MI]=millis()+blocktime; + switch(line) + { + case 0:enquecommand("G28 X");break; + case 1:enquecommand("G28 Y");break; + case 2:enquecommand("G28 Z");break; + case 3:enquecommand("G92 X0");break; + case 4:enquecommand("G92 Y0");break; + case 5:enquecommand("G92 Z0");break; + default: + ; + } + } + activate(); +} + +void PageHome::activate() +{ + lcd.setCursor(0,0); + lcd.print(fillto(20,"Home")); + lcd.setCursor(0,1); + lcd.print(fillto(20," X ZERO")); + lcd.setCursor(0,2); + lcd.print(fillto(20," Y ZERO")); + lcd.setCursor(0,3); + lcd.print(fillto(20," Z ZERO")); + fillline(); +} + +#ifdef SDSUPPORT +#include "SdFat.h" + +class PageSd:public MenuPage +{ +public: + PageSd(); + + virtual void activate(); + virtual void update(); +}; + +PageSd::PageSd() +{ + xshift=10;items=7;firstline=0; +} + +void PageSd::update() +{ + if(buttons&B_MI) + { + blocking[BL_MI]=millis()+blocktime; + + dir_t p; + + root.rewind(); + char filename[11]; + int cnt=0; + while (root.readDir(p) > 0) + { + // done if past last used entry + if (p.name[0] == DIR_NAME_FREE) break; + + // skip deleted entry and entries for . and .. + if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue; + + // only list subdirectories and files + if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; + + uint8_t writepos=0; + for (uint8_t i = 0; i < 11; i++) { + + if (p.name[i] == ' ') continue; + if (i == 8) { + filename[writepos++]='.'; + } + filename[writepos++]=p.name[i]; + } + filename[writepos++]=0; + if(cnt==line) + break; + cnt++; + + } + char cmd[50]; + for(int i=0;i 0) + { + // done if past last used entry + if (p.name[0] == DIR_NAME_FREE) break; + + // skip deleted entry and entries for . and .. + if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue; + + // only list subdirectories and files + if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; + + + uint8_t writepos=0; + for (uint8_t i = 0; i < 11; i++) { + + if (p.name[i] == ' ') continue; + if (i == 8) { + filename[writepos++]='.'; + } + filename[writepos++]=p.name[i]; + } + filename[writepos++]=0; + if(cnt>8) + break; + lcd.setCursor(0+10*(cnt/4),cnt%4); + lcd.print(" "); + lcd.print(fillto(9,filename)); + cnt++; + + } + fillline(); +} + +PageSd pagesd; + +#endif + + + +PageWatch pagewatch; +PageMove pagemove; +PageHome pagehome; + + +void lcd_status(const char* message) +{ +// if(LCD_HEIGHT>3) +// lcd.setCursor(0,3); +// else +// lcd.setCursor(0,0); +// lcd.print(message); +// int missing=(LCD_WIDTH-strlen(message)); +// if(missing>0) +// for(int i=0;i0) + { + lcd.setCursor((line/(4-firstline))*xshift,firstline+line%(4-firstline)); + lcd.print(" "); + } + }; + inline void fillline() + { + if(items>0) + { + lcd.setCursor((line/(4-firstline))*xshift,firstline+line%(4-firstline)); + lcd.print("~"); + } + }; +}; + +#define MAXPAGES 10 + + +class MenuBase +{ +public: + MenuBase(); + ~MenuBase(); + + + void addMenuPage(MenuPage *_newpage); + + + inline void pageUp() + { + //if(pages[curPage!=0]) + // pages[curPage]->deactivate(); + curPage++; + if(curPage>=maxPage) + { + curPage=0; + } + if(pages[curPage]!=0) + pages[curPage]->activate(); + + }; + + inline void pageDown() + { + //if(pages[curPage!=0]) + // pages[curPage]->deactivate(); + curPage--; + if(curPage<0) + { + curPage=maxPage-1; + } + if(pages[curPage]!=0) + pages[curPage]->activate(); + }; + + inline void lineUp() + { + if(pages[curPage]!=0) + pages[curPage]->lineUp(); + }; + + inline void lineDown() + { + if(pages[curPage]!=0) + pages[curPage]->lineDown(); + }; + + inline void update() + { + pages[curPage]->update(); + }; + +public: + //short int curLine; + short int curPage; + short int maxPage; + MenuPage *pages[MAXPAGES]; +}; + + +#endif + + + diff --git a/Marlin/menu_base.pde b/Marlin/menu_base.pde new file mode 100644 index 000000000000..3bdec26365f5 --- /dev/null +++ b/Marlin/menu_base.pde @@ -0,0 +1,65 @@ +#include "menu_base.h" +//#include +//extern LiquidCrystal lcd; +extern "C" { + void __cxa_pure_virtual() + { + // put error handling here + } +} + +MenuBase::MenuBase() +{ +//lcd=_lcd; + curPage=0; + //curLine=0; + maxPage=0; + for(int i=0;iactivate(); + } + maxPage++; + } +} + + +MenuPage::MenuPage() +{ + line=0; + firstline=1; +} + +void MenuPage::lineUp() +{ + emptyline(); + if(line==0) + line=items; + else + line--; + fillline(); +} + +void MenuPage::lineDown() +{ + emptyline(); + if(line==items) + line=0; + else + line++; + fillline(); +} + diff --git a/Marlin/wiring.pde b/Marlin/wiring.pde new file mode 100644 index 000000000000..adee6cbe44af --- /dev/null +++ b/Marlin/wiring.pde @@ -0,0 +1,176 @@ +/* + wiring.c - Partial implementation of the Wiring API for the ATmega8. + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.c 388 2008-03-08 22:05:23Z mellis $ +*/ + +#include "wiring_private.h" + +volatile unsigned long timer0_millis = 0; + +SIGNAL(TIMER0_OVF_vect) +{ + // timer 0 prescale factor is 64 and the timer overflows at 256 + timer0_millis++; +} + +unsigned long millis() +{ + unsigned long m; + uint8_t oldSREG = SREG; + + // disable interrupts while we read timer0_millis or we might get an + // inconsistent value (e.g. in the middle of the timer0_millis++) + cli(); + m = timer0_millis; + SREG = oldSREG; + + return m; +} + +void delay(unsigned long ms) +{ + unsigned long start = millis(); + + while (millis() - start <= ms) + ; +} + +/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. + * Disables interrupts, which will disrupt the millis() function if used + * too frequently. */ +void delayMicroseconds(unsigned int us) +{ + uint8_t oldSREG; + + // calling avrlib's delay_us() function with low values (e.g. 1 or + // 2 microseconds) gives delays longer than desired. + //delay_us(us); + +#if F_CPU >= 16000000L + // for the 16 MHz clock on most Arduino boards + + // for a one-microsecond delay, simply return. the overhead + // of the function call yields a delay of approximately 1 1/8 us. + if (--us == 0) + return; + + // the following loop takes a quarter of a microsecond (4 cycles) + // per iteration, so execute it four times for each microsecond of + // delay requested. + us <<= 2; + + // account for the time taken in the preceeding commands. + us -= 2; +#else + // for the 8 MHz internal clock on the ATmega168 + + // for a one- or two-microsecond delay, simply return. the overhead of + // the function calls takes more than two microseconds. can't just + // subtract two, since us is unsigned; we'd overflow. + if (--us == 0) + return; + if (--us == 0) + return; + + // the following loop takes half of a microsecond (4 cycles) + // per iteration, so execute it twice for each microsecond of + // delay requested. + us <<= 1; + + // partially compensate for the time taken by the preceeding commands. + // we can't subtract any more than this or we'd overflow w/ small delays. + us--; +#endif + + // disable interrupts, otherwise the timer 0 overflow interrupt that + // tracks milliseconds will make us delay longer than we want. + oldSREG = SREG; + cli(); + + // busy wait + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" // 2 cycles + "brne 1b" : "=w" (us) : "0" (us) // 2 cycles + ); + + // reenable interrupts. + SREG = oldSREG; +} + +void init() +{ + // this needs to be called before setup() or some functions won't + // work there + sei(); + + // on the ATmega168, timer 0 is also used for fast hardware pwm + // (using phase-correct PWM would mean that timer 0 overflowed half as often + // resulting in different millis() behavior on the ATmega8 and ATmega168) + sbi(TCCR0A, WGM01); + sbi(TCCR0A, WGM00); + + // set timer 0 prescale factor to 64 + sbi(TCCR0B, CS01); + sbi(TCCR0B, CS00); + + // enable timer 0 overflow interrupt + sbi(TIMSK0, TOIE0); + + // timers 1 and 2 are used for phase-correct hardware pwm + // this is better for motors as it ensures an even waveform + // note, however, that fast pwm mode can achieve a frequency of up + // 8 MHz (with a 16 MHz clock) at 50% duty cycle +#if 0 + // set timer 1 prescale factor to 64 + sbi(TCCR1B, CS11); + sbi(TCCR1B, CS10); + + // put timer 1 in 8-bit phase correct pwm mode + sbi(TCCR1A, WGM10); + + // set timer 2 prescale factor to 64 + sbi(TCCR2B, CS22); + + // configure timer 2 for phase correct pwm (8-bit) + sbi(TCCR2A, WGM20); + + // set a2d prescale factor to 128 + // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range. + // XXX: this will not work properly for other clock speeds, and + // this code should use F_CPU to determine the prescale factor. + sbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + + // enable a2d conversions + sbi(ADCSRA, ADEN); + + // the bootloader connects pins 0 and 1 to the USART; disconnect them + // here so they can be used as normal digital i/o; they will be + // reconnected in Serial.begin() + UCSR0B = 0; + #if defined(__AVR_ATmega644P__) + //TODO: test to see if disabling this helps? + //UCSR1B = 0; + #endif +#endif +} From 4fd12ae6f52105a5f56e14cb42d294b2211c7ba4 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 23 Aug 2011 16:33:56 +0200 Subject: [PATCH 005/130] ah wirking f** it up --- Marlin/Configuration.h | 2 +- Marlin/Marlin.pde | 4689 ++++++++++++++++++++-------------------- Marlin/wiring.pde | 176 -- 3 files changed, 2346 insertions(+), 2521 deletions(-) delete mode 100644 Marlin/wiring.pde diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 583de16f564b..5451439083ce 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -44,7 +44,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the // Comment out (using // at the start of the line) to disable SD support: #define SDSUPPORT -#define FANCY_LCD +//#define FANCY_LCD #define LCD_UPDATE_INTERVAL 400 diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 6dbca501b370..6d23dc2eeca1 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1,2353 +1,2354 @@ -#include "Marlin.h" -// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in -// the source g-code and may never actually be reached if acceleration management is active. - - -#include "speed_lookuptable.h" - -/* - Reprap firmware based on Sprinter and grbl. - Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm - - This program 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. - - This program 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 this program. If not, see . - */ - -/* - This firmware is a mashup between Sprinter and grbl. - (https://github.com/kliment/Sprinter) - (https://github.com/simen/grbl/tree) - - It has preliminary support for Matthew Roberts advance algorithm - http://reprap.org/pipermail/reprap-dev/2011-May/003323.html - - This firmware is optimized for gen6 electronics. - */ - - - -#include "fastio.h" -#include "Configuration.h" -#include "pins.h" +#include "Marlin.h" +// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in +// the source g-code and may never actually be reached if acceleration management is active. + + +#include "speed_lookuptable.h" + +/* + Reprap firmware based on Sprinter and grbl. + Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + + This program 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. + + This program 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 this program. If not, see . + */ + +/* + This firmware is a mashup between Sprinter and grbl. + (https://github.com/kliment/Sprinter) + (https://github.com/simen/grbl/tree) + + It has preliminary support for Matthew Roberts advance algorithm + http://reprap.org/pipermail/reprap-dev/2011-May/003323.html + + This firmware is optimized for gen6 electronics. + */ + + + +#include "fastio.h" +#include "Configuration.h" +#include "pins.h" #include "lcd.h" //extern LiquidCrystal lcd; - -char version_string[] = "0.9.3"; - -#ifdef SDSUPPORT -#include "SdFat.h" -#endif //SDSUPPORT - -#ifndef CRITICAL_SECTION_START -#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() -#define CRITICAL_SECTION_END SREG = _sreg -#endif //CRITICAL_SECTION_START - -// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html -// 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 -// G28 - Home all 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 -// 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 -// M115 - Capabilities string -// 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) -// M301 - Set PID parameters P I and D - -//Stepper Movement Variables - -char axis_codes[NUM_AXIS] = { - 'X', 'Y', 'Z', 'E'}; -float destination[NUM_AXIS] = { - 0.0, 0.0, 0.0, 0.0}; -float current_position[NUM_AXIS] = { - 0.0, 0.0, 0.0, 0.0}; -bool home_all_axis = true; -long feedrate = 1500, next_feedrate, saved_feedrate; -long gcode_N, gcode_LastN; -unsigned long previous_millis_heater, previous_millis_bed_heater; -bool relative_mode = false; //Determines Absolute or Relative Coordinates -bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. -unsigned long axis_steps_per_sqr_second[NUM_AXIS]; - -// comm variables -#define MAX_CMD_SIZE 96 -#define BUFSIZE 8 -char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; -bool fromsd[BUFSIZE]; -int bufindr = 0; -int bufindw = 0; -int buflen = 0; -int i = 0; -char serial_char; -int serial_count = 0; -boolean comment_mode = false; -char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc - -// Manage heater variables. - -int target_bed_raw = 0; -int current_bed_raw = 0; - -int target_raw = 0; -int current_raw = 0; -unsigned char temp_meas_ready = false; - -#ifdef PIDTEMP - double temp_iState = 0; - double temp_dState = 0; - double pTerm; - double iTerm; - double dTerm; - //int output; - double pid_error; - double temp_iState_min; - double temp_iState_max; - double pid_setpoint = 0.0; - double pid_input; - double pid_output; - bool pid_reset; -#endif //PIDTEMP -float tt = 0, bt = 0; -#ifdef WATCHPERIOD -int watch_raw = -1000; -unsigned long watchmillis = 0; -#endif //WATCHPERIOD -#ifdef MINTEMP -int minttemp = temp2analog(MINTEMP); -#endif //MINTEMP -#ifdef MAXTEMP -int maxttemp = temp2analog(MAXTEMP); -#endif //MAXTEMP - -//Inactivity shutdown variables -unsigned long previous_millis_cmd = 0; -unsigned long max_inactive_time = 0; -unsigned long stepper_inactive_time = 0; - -#ifdef SDSUPPORT -Sd2Card card; -SdVolume volume; -SdFile root; -SdFile file; -uint32_t filesize = 0; -uint32_t sdpos = 0; -bool sdmode = false; -bool sdactive = false; -bool savetosd = false; -int16_t n; - -void initsd(){ - sdactive = false; -#if SDSS >- 1 - if(root.isOpen()) - root.close(); - if (!card.init(SPI_FULL_SPEED,SDSS)){ - //if (!card.init(SPI_HALF_SPEED,SDSS)) - Serial.println("SD init fail"); - } - else if (!volume.init(&card)) - Serial.println("volume.init failed"); - else if (!root.openRoot(&volume)) - Serial.println("openRoot failed"); - else - sdactive = true; -#endif //SDSS -} - -inline void write_command(char *buf){ - char* begin = buf; - char* npos = 0; - char* end = buf + strlen(buf) - 1; - - file.writeError = false; - if((npos = strchr(buf, 'N')) != NULL){ - begin = strchr(npos, ' ') + 1; - end = strchr(npos, '*') - 1; - } - end[1] = '\r'; - end[2] = '\n'; - end[3] = '\0'; - //Serial.println(begin); - file.write(begin); - if (file.writeError){ - Serial.println("error writing to file"); - } -} -#endif //SDSUPPORT - - -void setup() -{ - Serial.begin(BAUDRATE); - Serial.print("Marlin "); - Serial.println(version_string); - Serial.println("start"); + +char version_string[] = "0.9.3"; + +#ifdef SDSUPPORT +#include "SdFat.h" +#endif //SDSUPPORT + +#ifndef CRITICAL_SECTION_START +#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() +#define CRITICAL_SECTION_END SREG = _sreg +#endif //CRITICAL_SECTION_START + +// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html +// 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 +// G28 - Home all 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 +// 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 +// M115 - Capabilities string +// 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) +// M301 - Set PID parameters P I and D + +//Stepper Movement Variables + +char axis_codes[NUM_AXIS] = { + 'X', 'Y', 'Z', 'E'}; +float destination[NUM_AXIS] = { + 0.0, 0.0, 0.0, 0.0}; +float current_position[NUM_AXIS] = { + 0.0, 0.0, 0.0, 0.0}; +bool home_all_axis = true; +long feedrate = 1500, next_feedrate, saved_feedrate; +long gcode_N, gcode_LastN; +unsigned long previous_millis_heater, previous_millis_bed_heater; +bool relative_mode = false; //Determines Absolute or Relative Coordinates +bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. +unsigned long axis_steps_per_sqr_second[NUM_AXIS]; + +// comm variables +#define MAX_CMD_SIZE 96 +#define BUFSIZE 8 +char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; +bool fromsd[BUFSIZE]; +int bufindr = 0; +int bufindw = 0; +int buflen = 0; +int i = 0; +char serial_char; +int serial_count = 0; +boolean comment_mode = false; +char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc + +// Manage heater variables. + +int target_bed_raw = 0; +int current_bed_raw = 0; + +int target_raw = 0; +int current_raw = 0; +unsigned char temp_meas_ready = false; + +#ifdef PIDTEMP + double temp_iState = 0; + double temp_dState = 0; + double pTerm; + double iTerm; + double dTerm; + //int output; + double pid_error; + double temp_iState_min; + double temp_iState_max; + double pid_setpoint = 0.0; + double pid_input; + double pid_output; + bool pid_reset; +#endif //PIDTEMP +float tt = 0, bt = 0; +#ifdef WATCHPERIOD +int watch_raw = -1000; +unsigned long watchmillis = 0; +#endif //WATCHPERIOD +#ifdef MINTEMP +int minttemp = temp2analog(MINTEMP); +#endif //MINTEMP +#ifdef MAXTEMP +int maxttemp = temp2analog(MAXTEMP); +#endif //MAXTEMP + +//Inactivity shutdown variables +unsigned long previous_millis_cmd = 0; +unsigned long max_inactive_time = 0; +unsigned long stepper_inactive_time = 0; + +#ifdef SDSUPPORT +Sd2Card card; +SdVolume volume; +SdFile root; +SdFile file; +uint32_t filesize = 0; +uint32_t sdpos = 0; +bool sdmode = false; +bool sdactive = false; +bool savetosd = false; +int16_t n; + +void initsd(){ + sdactive = false; +#if SDSS >- 1 + if(root.isOpen()) + root.close(); + if (!card.init(SPI_FULL_SPEED,SDSS)){ + //if (!card.init(SPI_HALF_SPEED,SDSS)) + Serial.println("SD init fail"); + } + else if (!volume.init(&card)) + Serial.println("volume.init failed"); + else if (!root.openRoot(&volume)) + Serial.println("openRoot failed"); + else + sdactive = true; +#endif //SDSS +} + +inline void write_command(char *buf){ + char* begin = buf; + char* npos = 0; + char* end = buf + strlen(buf) - 1; + + file.writeError = false; + if((npos = strchr(buf, 'N')) != NULL){ + begin = strchr(npos, ' ') + 1; + end = strchr(npos, '*') - 1; + } + end[1] = '\r'; + end[2] = '\n'; + end[3] = '\0'; + //Serial.println(begin); + file.write(begin); + if (file.writeError){ + Serial.println("error writing to file"); + } +} +#endif //SDSUPPORT + + +void setup() +{ + Serial.begin(BAUDRATE); + Serial.print("Marlin "); + Serial.println(version_string); + Serial.println("start"); #ifdef FANCY_LCD lcd_init(); #endif - for(int i = 0; i < BUFSIZE; i++){ - fromsd[i] = false; - } - - - //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 -#if E_DIR_PIN > -1 - SET_OUTPUT(E_DIR_PIN); -#endif - - //Initialize Enable Pins - steppers default to disabled. - -#if (X_ENABLE_PIN > -1) - SET_OUTPUT(X_ENABLE_PIN); - if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); -#endif -#if (Y_ENABLE_PIN > -1) - SET_OUTPUT(Y_ENABLE_PIN); - if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); -#endif -#if (Z_ENABLE_PIN > -1) - SET_OUTPUT(Z_ENABLE_PIN); - if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); -#endif -#if (E_ENABLE_PIN > -1) - SET_OUTPUT(E_ENABLE_PIN); - if(!E_ENABLE_ON) WRITE(E_ENABLE_PIN,HIGH); -#endif - - //endstops and pullups -#ifdef ENDSTOPPULLUPS -#if X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); - WRITE(X_MIN_PIN,HIGH); -#endif -#if X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); - WRITE(X_MAX_PIN,HIGH); -#endif -#if Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); - WRITE(Y_MIN_PIN,HIGH); -#endif -#if Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); - WRITE(Y_MAX_PIN,HIGH); -#endif -#if Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); - WRITE(Z_MIN_PIN,HIGH); -#endif -#if Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); - WRITE(Z_MAX_PIN,HIGH); -#endif -#else //ENDSTOPPULLUPS -#if X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); -#endif -#if X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); -#endif -#if Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); -#endif -#if Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); -#endif -#if Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); -#endif -#if Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); -#endif -#endif //ENDSTOPPULLUPS - -#if (HEATER_0_PIN > -1) - SET_OUTPUT(HEATER_0_PIN); -#endif -#if (HEATER_1_PIN > -1) - SET_OUTPUT(HEATER_1_PIN); -#endif - - //Initialize Step Pins -#if (X_STEP_PIN > -1) - SET_OUTPUT(X_STEP_PIN); -#endif -#if (Y_STEP_PIN > -1) - SET_OUTPUT(Y_STEP_PIN); -#endif -#if (Z_STEP_PIN > -1) - SET_OUTPUT(Z_STEP_PIN); -#endif -#if (E_STEP_PIN > -1) - SET_OUTPUT(E_STEP_PIN); -#endif - for(int i=0; i < NUM_AXIS; i++){ - axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; - } - -#ifdef PIDTEMP - temp_iState_min = 0.0; - temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; -#endif //PIDTEMP - -#ifdef SDSUPPORT - //power to SD reader -#if SDPOWER > -1 - SET_OUTPUT(SDPOWER); - WRITE(SDPOWER,HIGH); -#endif //SDPOWER - initsd(); - -#endif //SDSUPPORT - plan_init(); // Initialize planner; - st_init(); // Initialize stepper; -// tp_init(); // Initialize temperature loop -} - - -void loop() -{ - if(buflen<3) - get_command(); - - if(buflen){ -#ifdef SDSUPPORT - if(savetosd){ - if(strstr(cmdbuffer[bufindr],"M29") == NULL){ - write_command(cmdbuffer[bufindr]); - Serial.println("ok"); - } - else{ - file.sync(); - file.close(); - savetosd = false; - Serial.println("Done saving file."); - } - } - else{ - process_commands(); - } -#else - process_commands(); -#endif //SDSUPPORT - buflen = (buflen-1); - bufindr = (bufindr + 1)%BUFSIZE; - } - //check heater every n milliseconds - manage_heater(); - manage_inactivity(1); + for(int i = 0; i < BUFSIZE; i++){ + fromsd[i] = false; + } + + + //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 +#if E_DIR_PIN > -1 + SET_OUTPUT(E_DIR_PIN); +#endif + + //Initialize Enable Pins - steppers default to disabled. + +#if (X_ENABLE_PIN > -1) + SET_OUTPUT(X_ENABLE_PIN); + if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); +#endif +#if (Y_ENABLE_PIN > -1) + SET_OUTPUT(Y_ENABLE_PIN); + if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); +#endif +#if (Z_ENABLE_PIN > -1) + SET_OUTPUT(Z_ENABLE_PIN); + if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); +#endif +#if (E_ENABLE_PIN > -1) + SET_OUTPUT(E_ENABLE_PIN); + if(!E_ENABLE_ON) WRITE(E_ENABLE_PIN,HIGH); +#endif + + //endstops and pullups +#ifdef ENDSTOPPULLUPS +#if X_MIN_PIN > -1 + SET_INPUT(X_MIN_PIN); + WRITE(X_MIN_PIN,HIGH); +#endif +#if X_MAX_PIN > -1 + SET_INPUT(X_MAX_PIN); + WRITE(X_MAX_PIN,HIGH); +#endif +#if Y_MIN_PIN > -1 + SET_INPUT(Y_MIN_PIN); + WRITE(Y_MIN_PIN,HIGH); +#endif +#if Y_MAX_PIN > -1 + SET_INPUT(Y_MAX_PIN); + WRITE(Y_MAX_PIN,HIGH); +#endif +#if Z_MIN_PIN > -1 + SET_INPUT(Z_MIN_PIN); + WRITE(Z_MIN_PIN,HIGH); +#endif +#if Z_MAX_PIN > -1 + SET_INPUT(Z_MAX_PIN); + WRITE(Z_MAX_PIN,HIGH); +#endif +#else //ENDSTOPPULLUPS +#if X_MIN_PIN > -1 + SET_INPUT(X_MIN_PIN); +#endif +#if X_MAX_PIN > -1 + SET_INPUT(X_MAX_PIN); +#endif +#if Y_MIN_PIN > -1 + SET_INPUT(Y_MIN_PIN); +#endif +#if Y_MAX_PIN > -1 + SET_INPUT(Y_MAX_PIN); +#endif +#if Z_MIN_PIN > -1 + SET_INPUT(Z_MIN_PIN); +#endif +#if Z_MAX_PIN > -1 + SET_INPUT(Z_MAX_PIN); +#endif +#endif //ENDSTOPPULLUPS + +#if (HEATER_0_PIN > -1) + SET_OUTPUT(HEATER_0_PIN); +#endif +#if (HEATER_1_PIN > -1) + SET_OUTPUT(HEATER_1_PIN); +#endif + + //Initialize Step Pins +#if (X_STEP_PIN > -1) + SET_OUTPUT(X_STEP_PIN); +#endif +#if (Y_STEP_PIN > -1) + SET_OUTPUT(Y_STEP_PIN); +#endif +#if (Z_STEP_PIN > -1) + SET_OUTPUT(Z_STEP_PIN); +#endif +#if (E_STEP_PIN > -1) + SET_OUTPUT(E_STEP_PIN); +#endif + for(int i=0; i < NUM_AXIS; i++){ + axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; + } + +#ifdef PIDTEMP + temp_iState_min = 0.0; + temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; +#endif //PIDTEMP + +#ifdef SDSUPPORT + //power to SD reader +#if SDPOWER > -1 + SET_OUTPUT(SDPOWER); + WRITE(SDPOWER,HIGH); +#endif //SDPOWER + initsd(); + +#endif //SDSUPPORT + plan_init(); // Initialize planner; + st_init(); // Initialize stepper; +// tp_init(); // Initialize temperature loop +} + + +void loop() +{ + if(buflen<3) + get_command(); + + if(buflen){ +#ifdef SDSUPPORT + if(savetosd){ + if(strstr(cmdbuffer[bufindr],"M29") == NULL){ + write_command(cmdbuffer[bufindr]); + Serial.println("ok"); + } + else{ + file.sync(); + file.close(); + savetosd = false; + Serial.println("Done saving file."); + } + } + else{ + process_commands(); + } +#else + process_commands(); +#endif //SDSUPPORT + buflen = (buflen-1); + bufindr = (bufindr + 1)%BUFSIZE; + } + //check heater every n milliseconds + manage_heater(); + manage_inactivity(1); LCD_STATUS; -} - - -inline void get_command() -{ - while( Serial.available() > 0 && buflen < BUFSIZE) { - serial_char = Serial.read(); - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) - { - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = false; - if(strstr(cmdbuffer[bufindw], "N") != NULL) - { - strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); - gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); - if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { - Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); - Serial.println(gcode_LastN); - //Serial.println(gcode_N); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - if(strstr(cmdbuffer[bufindw], "*") != NULL) - { - byte checksum = 0; - byte count = 0; - while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; - strchr_pointer = strchr(cmdbuffer[bufindw], '*'); - - if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { - Serial.print("Error: checksum mismatch, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - //if no errors, continue parsing - } - else - { - Serial.print("Error: No Checksum with line number, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - gcode_LastN = gcode_N; - //if no errors, continue parsing - } - else // if we don't receive 'N' but still see '*' - { - if((strstr(cmdbuffer[bufindw], "*") != NULL)) - { - Serial.print("Error: No Line Number with checksum, Last Line:"); - Serial.println(gcode_LastN); - serial_count = 0; - return; - } - } - if((strstr(cmdbuffer[bufindw], "G") != NULL)){ - strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); - switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ - case 0: - case 1: -#ifdef SDSUPPORT - if(savetosd) - break; -#endif //SDSUPPORT - Serial.println("ok"); - break; - default: - break; - } - - } - bufindw = (bufindw + 1)%BUFSIZE; - buflen += 1; - - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } - } -#ifdef SDSUPPORT - if(!sdmode || serial_count!=0){ - return; - } - while( filesize > sdpos && buflen < BUFSIZE) { - n = file.read(); - serial_char = (char)n; - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) - { - sdpos = file.curPosition(); - if(sdpos >= filesize){ - sdmode = false; - Serial.println("Done printing file"); - } - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = true; - buflen += 1; - bufindw = (bufindw + 1)%BUFSIZE; - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } - } -#endif //SDSUPPORT - -} - - -inline float code_value() { - return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); -} -inline long code_value_long() { - return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); -} -inline bool code_seen(char code_string[]) { - return (strstr(cmdbuffer[bufindr], code_string) != NULL); -} //Return True if the string was found - -inline bool code_seen(char code) -{ - strchr_pointer = strchr(cmdbuffer[bufindr], code); - return (strchr_pointer != NULL); //Return True if a character was found -} - -inline void process_commands() -{ - unsigned long codenum; //throw away variable - char *starpos = NULL; - - if(code_seen('G')) - { - switch((int)code_value()) - { - case 0: // G0 -> G1 - case 1: // G1 - get_coordinates(); // For X Y Z E F - prepare_move(); - previous_millis_cmd = millis(); - //ClearToSend(); - return; - //break; - case 4: // G4 dwell - codenum = 0; - if(code_seen('P')) codenum = code_value(); // milliseconds to wait - if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait - codenum += millis(); // keep track of when we started waiting - while(millis() < codenum ){ - manage_heater(); - } - break; - case 28: //G28 Home all Axis one at a time - saved_feedrate = feedrate; - for(int i=0; i < NUM_AXIS; i++) { - destination[i] = current_position[i]; - } - feedrate = 0; - - home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); - - if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) { - if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){ - st_synchronize(); - current_position[X_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; - feedrate = homing_feedrate[X_AXIS]; - prepare_move(); - - st_synchronize(); - current_position[X_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = -5 * X_HOME_DIR; - prepare_move(); - - st_synchronize(); - destination[X_AXIS] = 10 * X_HOME_DIR; - feedrate = homing_feedrate[X_AXIS]/2 ; - prepare_move(); - st_synchronize(); - - current_position[X_AXIS] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = current_position[X_AXIS]; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { - if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){ - current_position[Y_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; - feedrate = homing_feedrate[Y_AXIS]; - prepare_move(); - st_synchronize(); - - current_position[Y_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = -5 * Y_HOME_DIR; - prepare_move(); - st_synchronize(); - - destination[Y_AXIS] = 10 * Y_HOME_DIR; - feedrate = homing_feedrate[Y_AXIS]/2; - prepare_move(); - st_synchronize(); - - current_position[Y_AXIS] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = current_position[Y_AXIS]; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { - if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){ - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; - feedrate = homing_feedrate[Z_AXIS]; - prepare_move(); - st_synchronize(); - - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = -2 * Z_HOME_DIR; - prepare_move(); - st_synchronize(); - - destination[Z_AXIS] = 3 * Z_HOME_DIR; - feedrate = homing_feedrate[Z_AXIS]/2; - prepare_move(); - st_synchronize(); - - current_position[Z_AXIS] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = current_position[Z_AXIS]; - feedrate = 0; - } - } - feedrate = saved_feedrate; - previous_millis_cmd = millis(); - break; - case 90: // G90 - relative_mode = false; - break; - case 91: // G91 - relative_mode = true; - break; - case 92: // G92 - if(!code_seen(axis_codes[E_AXIS])) - st_synchronize(); - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) current_position[i] = code_value(); - } - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - break; - - } - } - - else if(code_seen('M')) - { - - switch( (int)code_value() ) - { -#ifdef SDSUPPORT - - case 20: // M20 - list SD card - Serial.println("Begin file list"); - root.ls(); - Serial.println("End file list"); - break; - case 21: // M21 - init SD card - sdmode = false; - initsd(); - break; - case 22: //M22 - release SD card - sdmode = false; - sdactive = false; - break; - case 23: //M23 - Select file - if(sdactive){ - sdmode = false; - file.close(); - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos!=NULL) - *(starpos-1)='\0'; - if (file.open(&root, strchr_pointer + 4, O_READ)) { - Serial.print("File opened:"); - Serial.print(strchr_pointer + 4); - Serial.print(" Size:"); - Serial.println(file.fileSize()); - sdpos = 0; - filesize = file.fileSize(); - Serial.println("File selected"); - } - else{ - Serial.println("file.open failed"); - } - } - break; - case 24: //M24 - Start SD print - if(sdactive){ - sdmode = true; - } - break; - case 25: //M25 - Pause SD print - if(sdmode){ - sdmode = false; - } - break; - case 26: //M26 - Set SD index - if(sdactive && code_seen('S')){ - sdpos = code_value_long(); - file.seekSet(sdpos); - } - break; - case 27: //M27 - Get SD status - if(sdactive){ - Serial.print("SD printing byte "); - Serial.print(sdpos); - Serial.print("/"); - Serial.println(filesize); - } - else{ - Serial.println("Not SD printing"); - } - break; - case 28: //M28 - Start SD write - if(sdactive){ - char* npos = 0; - file.close(); - sdmode = false; - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos != NULL){ - npos = strchr(cmdbuffer[bufindr], 'N'); - strchr_pointer = strchr(npos,' ') + 1; - *(starpos-1) = '\0'; - } - if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) - { - Serial.print("open failed, File: "); - Serial.print(strchr_pointer + 4); - Serial.print("."); - } - else{ - savetosd = true; - Serial.print("Writing to file: "); - Serial.println(strchr_pointer + 4); - } - } - break; - case 29: //M29 - Stop SD write - //processed in write to file routine above - //savetosd = false; - break; -#endif //SDSUPPORT - case 104: // M104 - if (code_seen('S')) target_raw = temp2analog(code_value()); - #ifdef WATCHPERIOD - if(target_raw > current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - }else{ - watchmillis = 0; - } - #endif - break; - case 140: // M140 set bed temp - if (code_seen('S')) target_bed_raw = temp2analogBed(code_value()); - break; - case 105: // M105 - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) - tt = analog2temp(current_raw); - #endif - #if TEMP_1_PIN > -1 - bt = analog2tempBed(current_bed_raw); - #endif - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) - Serial.print("ok T:"); - Serial.print(tt); - Serial.print(", raw:"); - Serial.print(current_raw); - #if TEMP_1_PIN > -1 - Serial.print(" B:"); - Serial.println(bt); - #else - Serial.println(); - #endif - #else - Serial.println("No thermistors - no temp"); - #endif - return; - //break; - case 109: // M109 - Wait for extruder heater to reach target. +} + + +inline void get_command() +{ + while( Serial.available() > 0 && buflen < BUFSIZE) { + serial_char = Serial.read(); + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) + { + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = false; + if(strstr(cmdbuffer[bufindw], "N") != NULL) + { + strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); + gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); + if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { + Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); + Serial.println(gcode_LastN); + //Serial.println(gcode_N); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + if(strstr(cmdbuffer[bufindw], "*") != NULL) + { + byte checksum = 0; + byte count = 0; + while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; + strchr_pointer = strchr(cmdbuffer[bufindw], '*'); + + if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { + Serial.print("Error: checksum mismatch, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + //if no errors, continue parsing + } + else + { + Serial.print("Error: No Checksum with line number, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + gcode_LastN = gcode_N; + //if no errors, continue parsing + } + else // if we don't receive 'N' but still see '*' + { + if((strstr(cmdbuffer[bufindw], "*") != NULL)) + { + Serial.print("Error: No Line Number with checksum, Last Line:"); + Serial.println(gcode_LastN); + serial_count = 0; + return; + } + } + if((strstr(cmdbuffer[bufindw], "G") != NULL)){ + strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); + switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ + case 0: + case 1: +#ifdef SDSUPPORT + if(savetosd) + break; +#endif //SDSUPPORT + Serial.println("ok"); + break; + default: + break; + } + + } + bufindw = (bufindw + 1)%BUFSIZE; + buflen += 1; + + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } + } +#ifdef SDSUPPORT + if(!sdmode || serial_count!=0){ + return; + } + while( filesize > sdpos && buflen < BUFSIZE) { + n = file.read(); + serial_char = (char)n; + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) + { + sdpos = file.curPosition(); + if(sdpos >= filesize){ + sdmode = false; + Serial.println("Done printing file"); + } + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = true; + buflen += 1; + bufindw = (bufindw + 1)%BUFSIZE; + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } + } +#endif //SDSUPPORT + +} + + +inline float code_value() { + return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); +} +inline long code_value_long() { + return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); +} +inline bool code_seen(char code_string[]) { + return (strstr(cmdbuffer[bufindr], code_string) != NULL); +} //Return True if the string was found + +inline bool code_seen(char code) +{ + strchr_pointer = strchr(cmdbuffer[bufindr], code); + return (strchr_pointer != NULL); //Return True if a character was found +} + +inline void process_commands() +{ + unsigned long codenum; //throw away variable + char *starpos = NULL; + + if(code_seen('G')) + { + switch((int)code_value()) + { + case 0: // G0 -> G1 + case 1: // G1 + get_coordinates(); // For X Y Z E F + prepare_move(); + previous_millis_cmd = millis(); + //ClearToSend(); + return; + //break; + case 4: // G4 dwell + codenum = 0; + if(code_seen('P')) codenum = code_value(); // milliseconds to wait + if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait + codenum += millis(); // keep track of when we started waiting + while(millis() < codenum ){ + manage_heater(); + } + break; + case 28: //G28 Home all Axis one at a time + saved_feedrate = feedrate; + for(int i=0; i < NUM_AXIS; i++) { + destination[i] = current_position[i]; + } + feedrate = 0; + + home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); + + if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) { + if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){ + st_synchronize(); + current_position[X_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; + feedrate = homing_feedrate[X_AXIS]; + prepare_move(); + + st_synchronize(); + current_position[X_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = -5 * X_HOME_DIR; + prepare_move(); + + st_synchronize(); + destination[X_AXIS] = 10 * X_HOME_DIR; + feedrate = homing_feedrate[X_AXIS]/2 ; + prepare_move(); + st_synchronize(); + + current_position[X_AXIS] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = current_position[X_AXIS]; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { + if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){ + current_position[Y_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; + feedrate = homing_feedrate[Y_AXIS]; + prepare_move(); + st_synchronize(); + + current_position[Y_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = -5 * Y_HOME_DIR; + prepare_move(); + st_synchronize(); + + destination[Y_AXIS] = 10 * Y_HOME_DIR; + feedrate = homing_feedrate[Y_AXIS]/2; + prepare_move(); + st_synchronize(); + + current_position[Y_AXIS] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = current_position[Y_AXIS]; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { + if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){ + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; + feedrate = homing_feedrate[Z_AXIS]; + prepare_move(); + st_synchronize(); + + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = -2 * Z_HOME_DIR; + prepare_move(); + st_synchronize(); + + destination[Z_AXIS] = 3 * Z_HOME_DIR; + feedrate = homing_feedrate[Z_AXIS]/2; + prepare_move(); + st_synchronize(); + + current_position[Z_AXIS] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = current_position[Z_AXIS]; + feedrate = 0; + } + } + feedrate = saved_feedrate; + previous_millis_cmd = millis(); + break; + case 90: // G90 + relative_mode = false; + break; + case 91: // G91 + relative_mode = true; + break; + case 92: // G92 + if(!code_seen(axis_codes[E_AXIS])) + st_synchronize(); + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) current_position[i] = code_value(); + } + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + break; + + } + } + + else if(code_seen('M')) + { + + switch( (int)code_value() ) + { +#ifdef SDSUPPORT + + case 20: // M20 - list SD card + Serial.println("Begin file list"); + root.ls(); + Serial.println("End file list"); + break; + case 21: // M21 - init SD card + sdmode = false; + initsd(); + break; + case 22: //M22 - release SD card + sdmode = false; + sdactive = false; + break; + case 23: //M23 - Select file + if(sdactive){ + sdmode = false; + file.close(); + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos!=NULL) + *(starpos-1)='\0'; + if (file.open(&root, strchr_pointer + 4, O_READ)) { + Serial.print("File opened:"); + Serial.print(strchr_pointer + 4); + Serial.print(" Size:"); + Serial.println(file.fileSize()); + sdpos = 0; + filesize = file.fileSize(); + Serial.println("File selected"); + } + else{ + Serial.println("file.open failed"); + } + } + break; + case 24: //M24 - Start SD print + if(sdactive){ + sdmode = true; + } + break; + case 25: //M25 - Pause SD print + if(sdmode){ + sdmode = false; + } + break; + case 26: //M26 - Set SD index + if(sdactive && code_seen('S')){ + sdpos = code_value_long(); + file.seekSet(sdpos); + } + break; + case 27: //M27 - Get SD status + if(sdactive){ + Serial.print("SD printing byte "); + Serial.print(sdpos); + Serial.print("/"); + Serial.println(filesize); + } + else{ + Serial.println("Not SD printing"); + } + break; + case 28: //M28 - Start SD write + if(sdactive){ + char* npos = 0; + file.close(); + sdmode = false; + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos != NULL){ + npos = strchr(cmdbuffer[bufindr], 'N'); + strchr_pointer = strchr(npos,' ') + 1; + *(starpos-1) = '\0'; + } + if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) + { + Serial.print("open failed, File: "); + Serial.print(strchr_pointer + 4); + Serial.print("."); + } + else{ + savetosd = true; + Serial.print("Writing to file: "); + Serial.println(strchr_pointer + 4); + } + } + break; + case 29: //M29 - Stop SD write + //processed in write to file routine above + //savetosd = false; + break; +#endif //SDSUPPORT + case 104: // M104 + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw > current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + break; + case 140: // M140 set bed temp + if (code_seen('S')) target_bed_raw = temp2analogBed(code_value()); + break; + case 105: // M105 + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) + tt = analog2temp(current_raw); + #endif + #if TEMP_1_PIN > -1 + bt = analog2tempBed(current_bed_raw); + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) + Serial.print("ok T:"); + Serial.print(tt); + Serial.print(", raw:"); + Serial.print(current_raw); + #if TEMP_1_PIN > -1 + Serial.print(" B:"); + Serial.println(bt); + #else + Serial.println(); + #endif + #else + Serial.println("No thermistors - no temp"); + #endif + return; + //break; + case 109: // M109 - Wait for extruder heater to reach target. LCD_MESSAGE("Heating..."); - if (code_seen('S')) target_raw = temp2analog(code_value()); - #ifdef WATCHPERIOD - if(target_raw>current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - }else{ - watchmillis = 0; - } - #endif - codenum = millis(); - while(current_raw < target_raw) { - if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - Serial.print("T:"); - Serial.println( analog2temp(current_raw) ); + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw>current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + codenum = millis(); + while(current_raw < target_raw) { + if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + Serial.print("T:"); + Serial.println( analog2temp(current_raw) ); LCD_STATUS; - codenum = millis(); - } - manage_heater(); - } - break; - case 190: // M190 - Wait bed for heater to reach target. - #if TEMP_1_PIN > -1 - if (code_seen('S')) target_bed_raw = temp2analog(code_value()); - codenum = millis(); - while(current_bed_raw < target_bed_raw) { - if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - tt=analog2temp(current_raw); - Serial.print("T:"); - Serial.println( tt ); - Serial.print("ok T:"); - Serial.print( tt ); - Serial.print(" B:"); - Serial.println( analog2temp(current_bed_raw) ); - codenum = millis(); - } - manage_heater(); - } - #endif - break; - case 106: //M106 Fan On - if (code_seen('S')){ - digitalWrite(FAN_PIN, HIGH); - analogWrite(FAN_PIN, constrain(code_value(),0,255) ); - } - else - digitalWrite(FAN_PIN, HIGH); - break; - case 107: //M107 Fan Off - analogWrite(FAN_PIN, 0); - - digitalWrite(FAN_PIN, LOW); - break; - - case 82: - axis_relative_modes[3] = false; - break; - case 83: - axis_relative_modes[3] = true; - break; - case 84: - if(code_seen('S')){ - stepper_inactive_time = code_value() * 1000; - } - else{ - st_synchronize(); - disable_x(); - disable_y(); - disable_z(); - disable_e(); - } - break; - case 85: // M85 - code_seen('S'); - max_inactive_time = code_value() * 1000; - break; - case 92: // M92 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); - } - - break; - case 115: // M115 - Serial.println("FIRMWARE_NAME:Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); - break; - case 114: // M114 - Serial.print("X:"); - Serial.print(current_position[X_AXIS]); - Serial.print("Y:"); - Serial.print(current_position[Y_AXIS]); - Serial.print("Z:"); - Serial.print(current_position[Z_AXIS]); - Serial.print("E:"); - Serial.println(current_position[E_AXIS]); - break; - case 119: // M119 -#if (X_MIN_PIN > -1) - Serial.print("x_min:"); - Serial.print((READ(X_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (X_MAX_PIN > -1) - Serial.print("x_max:"); - Serial.print((READ(X_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Y_MIN_PIN > -1) - Serial.print("y_min:"); - Serial.print((READ(Y_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Y_MAX_PIN > -1) - Serial.print("y_max:"); - Serial.print((READ(Y_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Z_MIN_PIN > -1) - Serial.print("z_min:"); - Serial.print((READ(Z_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Z_MAX_PIN > -1) - Serial.print("z_max:"); - Serial.print((READ(Z_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif - Serial.println(""); - break; - //TODO: update for all axis, use for loop - case 201: // M201 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; -#if 0 // Not used for Sprinter/grbl gen6 - case 202: // M202 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; -#endif -#ifdef PIDTEMP - case 301: // M301 - if(code_seen('P')) Kp = code_value(); - if(code_seen('I')) Ki = code_value()*PID_dT; - if(code_seen('D')) Kd = code_value()/PID_dT; - Serial.print("Kp ");Serial.println(Kp); - Serial.print("Ki ");Serial.println(Ki/PID_dT); - Serial.print("Kd ");Serial.println(Kd*PID_dT); - temp_iState_min = 0.0; - temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; - break; -#endif //PIDTEMP - } - } - else{ - Serial.println("Unknown command:"); - Serial.println(cmdbuffer[bufindr]); - } - - ClearToSend(); -} - -void FlushSerialRequestResend() -{ - //char cmdbuffer[bufindr][100]="Resend:"; - Serial.flush(); - Serial.print("Resend:"); - Serial.println(gcode_LastN + 1); - ClearToSend(); -} - -void ClearToSend() -{ - previous_millis_cmd = millis(); -#ifdef SDSUPPORT - if(fromsd[bufindr]) - return; -#endif //SDSUPPORT - Serial.println("ok"); -} - -inline void get_coordinates() -{ - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; - else destination[i] = current_position[i]; //Are these else lines really needed? - } - if(code_seen('F')) { - next_feedrate = code_value(); - if(next_feedrate > 0.0) feedrate = next_feedrate; - } -} - -void prepare_move() -{ - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60.0); - for(int i=0; i < NUM_AXIS; i++) { - current_position[i] = destination[i]; - } -} -/* -void manage_heater() -{ - float pid_input; - float pid_output; - if(temp_meas_ready != true) - return; - -CRITICAL_SECTION_START; - temp_meas_ready = false; -CRITICAL_SECTION_END; - -#ifdef PIDTEMP - pid_input = analog2temp(current_raw); - -#ifndef PID_OPENLOOP - pid_error = pid_setpoint - pid_input; - if(pid_error > 10){ - pid_output = PID_MAX; - pid_reset = true; - } - else if(pid_error < -10) { - pid_output = 0; - pid_reset = true; - } - else { - if(pid_reset == true) { - temp_iState = 0.0; - pid_reset = false; - } - pTerm = Kp * pid_error; - temp_iState += pid_error; - temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = Ki * temp_iState; - #define K1 0.8 - #define K2 (1.0-K1) - dTerm = (Kd * (pid_input - temp_dState))*K2 + (K1 * dTerm); - temp_dState = pid_input; - pid_output = constrain(pTerm + iTerm - dTerm, 0, PID_MAX); - } -#endif //PID_OPENLOOP -#ifdef PID_DEBUG - Serial.print(" Input "); - Serial.print(pid_input); - Serial.print(" Output "); - Serial.print(pid_output); - Serial.print(" pTerm "); - Serial.print(pTerm); - Serial.print(" iTerm "); - Serial.print(iTerm); - Serial.print(" dTerm "); - Serial.print(dTerm); - Serial.println(); -#endif //PID_DEBUG - OCR2B = pid_output; -#endif //PIDTEMP -} -*/ - - -/* -int temp2analogu(int celsius, const short table[][2], int numtemps) { - int raw = 0; - byte i; - - for (i=1; i raw) { - celsius = (float)table[i-1][1] + - (float)(raw - table[i-1][0]) * - (float)(table[i][1] - table[i-1][1]) / - (float)(table[i][0] - table[i-1][0]); - - break; - } - } - // Overflow: Set to last value in the table - if (i == numtemps) celsius = table[i-1][1]; - - return celsius; -} - - -inline void kill() -{ - target_raw=0; -#ifdef PIDTEMP - pid_setpoint = 0.0; -#endif //PIDTEMP - OCR2B = 0; - WRITE(HEATER_0_PIN,LOW); - - disable_x(); - disable_y(); - disable_z(); - disable_e(); - -} -*/ - - - -//#################################################################################################################### -//#################################################################################################################### -void manage_heater() -{ -#ifdef USE_WATCHDOG - wd_reset(); -#endif - - if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) - return; - previous_millis_heater = millis(); - #ifdef HEATER_USES_THERMISTOR - current_raw = analogRead(TEMP_0_PIN); - // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, - // this switches it up so that the reading appears lower than target for the control logic. - current_raw = 1023 - current_raw; - #elif defined HEATER_USES_AD595 - current_raw = analogRead(TEMP_0_PIN); - #elif defined HEATER_USES_MAX6675 - current_raw = read_max6675(); - #endif - #ifdef SMOOTHING - nma = (nma + current_raw) - (nma / SMOOTHFACTOR); - current_raw = nma / SMOOTHFACTOR; - #endif - #ifdef WATCHPERIOD - if(watchmillis && millis() - watchmillis > WATCHPERIOD){ - if(watch_raw + 1 >= current_raw){ - target_raw = 0; - digitalWrite(HEATER_0_PIN,LOW); - digitalWrite(LED_PIN,LOW); - }else{ - watchmillis = 0; - } - } - #endif - #ifdef MINTEMP - if(current_raw <= minttemp) - target_raw = 0; - #endif - #ifdef MAXTEMP - if(current_raw >= maxttemp) { - target_raw = 0; - } - #endif - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) - #ifdef PIDTEMP - error = target_raw - current_raw; - pTerm = (PID_PGAIN * error) / 100; - temp_iState += error; - temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = (PID_IGAIN * temp_iState) / 100; - dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; - temp_dState = current_raw; - analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); - #else - if(current_raw >= target_raw) - { - digitalWrite(HEATER_0_PIN,LOW); - digitalWrite(LED_PIN,LOW); - } - else - { - digitalWrite(HEATER_0_PIN,HIGH); - digitalWrite(LED_PIN,HIGH); - } - #endif - #endif - - if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) - return; - previous_millis_bed_heater = millis(); - - #ifdef BED_USES_THERMISTOR - - current_bed_raw = analogRead(TEMP_1_PIN); - - // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, - // this switches it up so that the reading appears lower than target for the control logic. - current_bed_raw = 1023 - current_bed_raw; - #elif defined BED_USES_AD595 - current_bed_raw = analogRead(TEMP_1_PIN); - - #endif - - - #if TEMP_1_PIN > -1 - if(current_bed_raw >= target_bed_raw) - { - digitalWrite(HEATER_1_PIN,LOW); - } - else - { - digitalWrite(HEATER_1_PIN,HIGH); - } - #endif -} - -// Takes hot end temperature value as input and returns corresponding raw value. -// For a thermistor, it uses the RepRap thermistor temp table. -// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value. -// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware. -float temp2analog(int celsius) { - #ifdef HEATER_USES_THERMISTOR - int raw = 0; - byte i; - - for (i=1; i raw) - { - celsius = temptable[i-1][1] + - (raw - temptable[i-1][0]) * - (temptable[i][1] - temptable[i-1][1]) / - (temptable[i][0] - temptable[i-1][0]); - - break; - } - } - - // Overflow: Set to last value in the table - if (i == NUMTEMPS) celsius = temptable[i-1][1]; - - return celsius; - #elif defined HEATER_USES_AD595 - return raw * ((5.0 * 100.0) / 1024.0); - #elif defined HEATER_USES_MAX6675 - return raw * 0.25; - #endif -} - -// Derived from RepRap FiveD extruder::getTemperature() -// For bed temperature measurement. -float analog2tempBed(int raw) { - #ifdef BED_USES_THERMISTOR - int celsius = 0; - byte i; - - raw = 1023 - raw; - - for (i=1; i raw) - { - celsius = bedtemptable[i-1][1] + - (raw - bedtemptable[i-1][0]) * - (bedtemptable[i][1] - bedtemptable[i-1][1]) / - (bedtemptable[i][0] - bedtemptable[i-1][0]); - - break; - } - } - - // Overflow: Set to last value in the table - if (i == NUMTEMPS) celsius = bedtemptable[i-1][1]; - - return celsius; - - #elif defined BED_USES_AD595 - return raw * ((5.0 * 100.0) / 1024.0); - #endif -} - -inline void kill() -{ - #if TEMP_0_PIN > -1 - target_raw=0; - digitalWrite(HEATER_0_PIN,LOW); - #endif - #if TEMP_1_PIN > -1 - target_bed_raw=0; - if(HEATER_1_PIN > -1) digitalWrite(HEATER_1_PIN,LOW); - #endif - disable_x(); - disable_y(); - disable_z(); - disable_e(); - - if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); - -} - - - - - - -//####################################################################################################################### - -inline void manage_inactivity(byte debug) { - if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); - if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { - disable_x(); - disable_y(); - disable_z(); - disable_e(); - } - check_axes_activity(); -} - -// Planner - -/* - Reasoning behind the mathematics in this module (in the key of 'Mathematica'): - - s == speed, a == acceleration, t == time, d == distance - - Basic definitions: - - Speed[s_, a_, t_] := s + (a*t) - Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t] - - Distance to reach a specific speed with a constant acceleration: - - Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t] - d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance() - - Speed after a given distance of travel with constant acceleration: - - Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t] - m -> Sqrt[2 a d + s^2] - - DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2] - - When to start braking (di) to reach a specified destionation speed (s2) after accelerating - from initial speed s1 without ever stopping at a plateau: - - Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di] - di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance() - - IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a) - */ - - -// The number of linear motions that can be in the plan at any give time -#define BLOCK_BUFFER_SIZE 16 -#define BLOCK_BUFFER_MASK 0x0f - -static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions -static volatile unsigned char block_buffer_head; // Index of the next block to be pushed -static volatile unsigned char block_buffer_tail; // Index of the block to process now - -// The current position of the tool in absolute steps -static long position[4]; - -#define ONE_MINUTE_OF_MICROSECONDS 60000000.0 - -// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the -// given acceleration: -inline long estimate_acceleration_distance(long initial_rate, long target_rate, long acceleration) { - return( - (target_rate*target_rate-initial_rate*initial_rate)/ - (2L*acceleration) - ); -} - -// This function gives you the point at which you must start braking (at the rate of -acceleration) if -// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after -// a total travel of distance. This can be used to compute the intersection point between acceleration and -// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) - -inline long intersection_distance(long initial_rate, long final_rate, long acceleration, long distance) { - return( - (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ - (4*acceleration) - ); -} - -// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. - -void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { - if(block->busy == true) return; // If block is busy then bail out. - float entry_factor = entry_speed / block->nominal_speed; - float exit_factor = exit_speed / block->nominal_speed; - long initial_rate = ceil(block->nominal_rate*entry_factor); - long final_rate = ceil(block->nominal_rate*exit_factor); - -#ifdef ADVANCE - long initial_advance = block->advance*entry_factor*entry_factor; - long final_advance = block->advance*exit_factor*exit_factor; -#endif // ADVANCE - - // Limit minimal step rate (Otherwise the timer will overflow.) - if(initial_rate <120) initial_rate=120; - if(final_rate < 120) final_rate=120; - - // Calculate the acceleration steps - long acceleration = block->acceleration; - long accelerate_steps = estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration); - long decelerate_steps = estimate_acceleration_distance(final_rate, block->nominal_rate, acceleration); - - // Calculate the size of Plateau of Nominal Rate. - long plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; - - // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will - // have to use intersection_distance() to calculate when to abort acceleration and start braking - // in order to reach the final_rate exactly at the end of this block. - if (plateau_steps < 0) { - accelerate_steps = intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count); - plateau_steps = 0; - } - - long decelerate_after = accelerate_steps+plateau_steps; - long acceleration_rate = (long)((float)acceleration * 8.388608); - - CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section - if(block->busy == false) { // Don't update variables if block is busy. - block->accelerate_until = accelerate_steps; - block->decelerate_after = decelerate_after; - block->acceleration_rate = acceleration_rate; - block->initial_rate = initial_rate; - block->final_rate = final_rate; -#ifdef ADVANCE - block->initial_advance = initial_advance; - block->final_advance = final_advance; -#endif //ADVANCE - } - CRITICAL_SECTION_END; -} - -// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the -// acceleration within the allotted distance. -inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { - return( - sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) - ); -} - -// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks. -// This method will calculate the junction jerk as the euclidean distance between the nominal -// velocities of the respective blocks. -inline float junction_jerk(block_t *before, block_t *after) { - return(sqrt( - pow((before->speed_x-after->speed_x), 2)+ - pow((before->speed_y-after->speed_y), 2)+ - pow((before->speed_z-after->speed_z)*axis_steps_per_unit[Z_AXIS]/axis_steps_per_unit[X_AXIS], 2))); -} - -// Return the safe speed which is max_jerk/2, e.g. the -// speed under which you cannot exceed max_jerk no matter what you do. -float safe_speed(block_t *block) { - float safe_speed; - safe_speed = max_jerk/2; - if (safe_speed > block->nominal_speed) safe_speed = block->nominal_speed; - return safe_speed; -} - -// The kernel called by planner_recalculate() when scanning the plan from last to first entry. -void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) { - if(!current) { - return; - } - - float entry_speed = current->nominal_speed; - float exit_factor; - float exit_speed; - if (next) { - exit_speed = next->entry_speed; - } - else { - exit_speed = safe_speed(current); - } - - // Calculate the entry_factor for the current block. - if (previous) { - // Reduce speed so that junction_jerk is within the maximum allowed - float jerk = junction_jerk(previous, current); - if((previous->steps_x == 0) && (previous->steps_y == 0)) { - entry_speed = safe_speed(current); - } - else if (jerk > max_jerk) { - entry_speed = (max_jerk/jerk) * entry_speed; - } - // If the required deceleration across the block is too rapid, reduce the entry_factor accordingly. - if (entry_speed > exit_speed) { - float max_entry_speed = max_allowable_speed(-acceleration,exit_speed, current->millimeters); - if (max_entry_speed < entry_speed) { - entry_speed = max_entry_speed; - } - } - } - else { - entry_speed = safe_speed(current); - } - // Store result - current->entry_speed = entry_speed; -} - -// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This -// implements the reverse pass. -void planner_reverse_pass() { - char block_index = block_buffer_head; - block_t *block[3] = { - NULL, NULL, NULL }; - while(block_index != block_buffer_tail) { - block_index--; - if(block_index < 0) { - block_index = BLOCK_BUFFER_SIZE-1; - } - block[2]= block[1]; - block[1]= block[0]; - block[0] = &block_buffer[block_index]; - planner_reverse_pass_kernel(block[0], block[1], block[2]); - } - planner_reverse_pass_kernel(NULL, block[0], block[1]); -} - -// The kernel called by planner_recalculate() when scanning the plan from first to last entry. -void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) { - if(!current) { - return; - } - if(previous) { - // If the previous block is an acceleration block, but it is not long enough to - // complete the full speed change within the block, we need to adjust out entry - // speed accordingly. Remember current->entry_factor equals the exit factor of - // the previous block. - if(previous->entry_speed < current->entry_speed) { - float max_entry_speed = max_allowable_speed(-acceleration, previous->entry_speed, previous->millimeters); - if (max_entry_speed < current->entry_speed) { - current->entry_speed = max_entry_speed; - } - } - } -} - -// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This -// implements the forward pass. -void planner_forward_pass() { - char block_index = block_buffer_tail; - block_t *block[3] = { - NULL, NULL, NULL }; - - while(block_index != block_buffer_head) { - block[0] = block[1]; - block[1] = block[2]; - block[2] = &block_buffer[block_index]; - planner_forward_pass_kernel(block[0],block[1],block[2]); - block_index = (block_index+1) & BLOCK_BUFFER_MASK; - } - planner_forward_pass_kernel(block[1], block[2], NULL); -} - -// Recalculates the trapezoid speed profiles for all blocks in the plan according to the -// entry_factor for each junction. Must be called by planner_recalculate() after -// updating the blocks. -void planner_recalculate_trapezoids() { - char block_index = block_buffer_tail; - block_t *current; - block_t *next = NULL; - while(block_index != block_buffer_head) { - current = next; - next = &block_buffer[block_index]; - if (current) { - calculate_trapezoid_for_block(current, current->entry_speed, next->entry_speed); - } - block_index = (block_index+1) & BLOCK_BUFFER_MASK; - } - calculate_trapezoid_for_block(next, next->entry_speed, safe_speed(next)); -} - -// Recalculates the motion plan according to the following algorithm: -// -// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) -// so that: -// a. The junction jerk is within the set limit -// b. No speed reduction within one block requires faster deceleration than the one, true constant -// acceleration. -// 2. Go over every block in chronological order and dial down junction speed reduction values if -// a. The speed increase within one block would require faster accelleration than the one, true -// constant acceleration. -// -// When these stages are complete all blocks have an entry_factor that will allow all speed changes to -// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than -// the set limit. Finally it will: -// -// 3. Recalculate trapezoids for all blocks. - -void planner_recalculate() { - planner_reverse_pass(); - planner_forward_pass(); - planner_recalculate_trapezoids(); -} - -void plan_init() { - block_buffer_head = 0; - block_buffer_tail = 0; - memset(position, 0, sizeof(position)); // clear position -} - - -inline void plan_discard_current_block() { - if (block_buffer_head != block_buffer_tail) { - block_buffer_tail = (block_buffer_tail + 1) & BLOCK_BUFFER_MASK; - } -} - -inline block_t *plan_get_current_block() { - if (block_buffer_head == block_buffer_tail) { - return(NULL); - } - block_t *block = &block_buffer[block_buffer_tail]; - block->busy = true; - return(block); -} - -void check_axes_activity() { - unsigned char x_active = 0; - unsigned char y_active = 0; - unsigned char z_active = 0; - unsigned char e_active = 0; - block_t *block; - - if(block_buffer_tail != block_buffer_head) { - char block_index = block_buffer_tail; - while(block_index != block_buffer_head) { - block = &block_buffer[block_index]; - if(block->steps_x != 0) x_active++; - if(block->steps_y != 0) y_active++; - if(block->steps_z != 0) z_active++; - if(block->steps_e != 0) e_active++; - block_index = (block_index+1) & BLOCK_BUFFER_MASK; - } - } - if((DISABLE_X) && (x_active == 0)) disable_x(); - if((DISABLE_Y) && (y_active == 0)) disable_y(); - if((DISABLE_Z) && (z_active == 0)) disable_z(); - if((DISABLE_E) && (e_active == 0)) disable_e(); -} - -// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in -// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration -// calculation the caller must also provide the physical length of the line in millimeters. -void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { - - // The target position of the tool in absolute steps - // Calculate target position in absolute steps - long target[4]; - target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); - target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); - target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); - target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); - - // Calculate the buffer head after we push this byte - int next_buffer_head = (block_buffer_head + 1) & BLOCK_BUFFER_MASK; - - // If the buffer is full: good! That means we are well ahead of the robot. - // Rest here until there is room in the buffer. - while(block_buffer_tail == next_buffer_head) { - manage_heater(); - manage_inactivity(1); - } - - // Prepare to set up new block - block_t *block = &block_buffer[block_buffer_head]; - - // Mark block as not busy (Not executed by the stepper interrupt) - block->busy = false; - - // Number of steps for each axis - block->steps_x = labs(target[X_AXIS]-position[X_AXIS]); - block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]); - block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); - block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); - block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); - - // Bail if this is a zero-length block - if (block->step_event_count == 0) { - return; - }; - - float delta_x_mm = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; - float delta_y_mm = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; - float delta_z_mm = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; - float delta_e_mm = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS]; - block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); - - unsigned long microseconds; - microseconds = lround((block->millimeters/feed_rate)*1000000); - - // Calculate speed in mm/minute for each axis - float multiplier = 60.0*1000000.0/microseconds; - block->speed_z = delta_z_mm * multiplier; - block->speed_x = delta_x_mm * multiplier; - block->speed_y = delta_y_mm * multiplier; - block->speed_e = delta_e_mm * multiplier; - - // Limit speed per axis - float speed_factor = 1; - float tmp_speed_factor; - if(abs(block->speed_x) > max_feedrate[X_AXIS]) { - speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); - } - if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ - tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ - tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_e) > max_feedrate[E_AXIS]){ - tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - multiplier = multiplier * speed_factor; - block->speed_z = delta_z_mm * multiplier; - block->speed_x = delta_x_mm * multiplier; - block->speed_y = delta_y_mm * multiplier; - block->speed_e = delta_e_mm * multiplier; - block->nominal_speed = block->millimeters * multiplier; - block->nominal_rate = ceil(block->step_event_count * multiplier / 60); - - if(block->nominal_rate < 120) block->nominal_rate = 120; - block->entry_speed = safe_speed(block); - - // Compute the acceleration rate for the trapezoid generator. - float travel_per_step = block->millimeters/block->step_event_count; - if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { - block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 - } - else { - block->acceleration = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 - // Limit acceleration per axis - if((block->acceleration * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) - block->acceleration = axis_steps_per_sqr_second[X_AXIS]; - if((block->acceleration * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) - block->acceleration = axis_steps_per_sqr_second[Y_AXIS]; - if((block->acceleration * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) - block->acceleration = axis_steps_per_sqr_second[E_AXIS]; - if((block->acceleration * block->steps_z / block->step_event_count) > axis_steps_per_sqr_second[Z_AXIS]) - block->acceleration = axis_steps_per_sqr_second[Z_AXIS]; - } - -#ifdef ADVANCE - // Calculate advance rate - if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { - block->advance_rate = 0; - block->advance = 0; - } - else { - long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration); - float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * - (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; - block->advance = advance; - if(acc_dist == 0) { - block->advance_rate = 0; - } - else { - block->advance_rate = advance / (float)acc_dist; - } - } - -#endif // ADVANCE - - // compute a preliminary conservative acceleration trapezoid - float safespeed = safe_speed(block); - calculate_trapezoid_for_block(block, safespeed, safespeed); - - // Compute direction bits for this block - block->direction_bits = 0; - if (target[X_AXIS] < position[X_AXIS]) { - block->direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<steps_x != 0) enable_x(); - if(block->steps_y != 0) enable_y(); - if(block->steps_z != 0) enable_z(); - if(block->steps_e != 0) enable_e(); - - // Move buffer head - block_buffer_head = next_buffer_head; - - // Update position - memcpy(position, target, sizeof(target)); // position[] = target[] - - planner_recalculate(); - st_wake_up(); -} - -void plan_set_position(float x, float y, float z, float e) -{ - position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); - position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); - position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); - position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); -} - -// Stepper - -// intRes = intIn1 * intIn2 >> 16 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 24 bit result -#define MultiU16X8toH16(intRes, charIn1, intIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %A1, %A2 \n\t" \ -"add %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r0 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (charIn1), \ -"d" (intIn2) \ -: \ -"r26" \ -) - -// intRes = longIn1 * longIn2 >> 24 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 48bit result -#define MultiU24X24toH16(intRes, longIn1, longIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"mov r27, r1 \n\t" \ -"mul %B1, %C2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %C1, %C2 \n\t" \ -"add %B0, r0 \n\t" \ -"mul %C1, %B2 \n\t" \ -"add %A0, r0 \n\t" \ -"adc %B0, r1 \n\t" \ -"mul %A1, %C2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %B2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %C1, %A2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %A2 \n\t" \ -"add r27, r1 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r27 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (longIn1), \ -"d" (longIn2) \ -: \ -"r26" , "r27" \ -) - -// Some useful constants - -#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1< -// -// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates -// first block->accelerate_until step_events_completed, then keeps going at constant speed until -// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. -// The slope of acceleration is calculated with the leib ramp alghorithm. - -void st_wake_up() { - // TCNT1 = 0; - ENABLE_STEPPER_DRIVER_INTERRUPT(); -} - -inline unsigned short calc_timer(unsigned short step_rate) { - unsigned short timer; - if(step_rate < 32) step_rate = 32; - step_rate -= 32; // Correct for minimal speed - if(step_rate >= (8*256)){ // higher step rate - unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; - unsigned char tmp_step_rate = (step_rate & 0x00ff); - unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); - MultiU16X8toH16(timer, tmp_step_rate, gain); - timer = (unsigned short)pgm_read_word_near(table_address) - timer; - } - else { // lower step rates - unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; - table_address += ((step_rate)>>1) & 0xfffc; - timer = (unsigned short)pgm_read_word_near(table_address); - timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); - } - if(timer < 100) timer = 100; - return timer; -} - -// Initializes the trapezoid generator from the current block. Called whenever a new -// block begins. -inline void trapezoid_generator_reset() { - accelerate_until = current_block->accelerate_until; - decelerate_after = current_block->decelerate_after; - acceleration_rate = current_block->acceleration_rate; - initial_rate = current_block->initial_rate; - final_rate = current_block->final_rate; - nominal_rate = current_block->nominal_rate; - advance = current_block->initial_advance; - final_advance = current_block->final_advance; - deceleration_time = 0; - advance_rate = current_block->advance_rate; - // step_rate to timer interval - acc_step_rate = initial_rate; - acceleration_time = calc_timer(acc_step_rate); - OCR1A = acceleration_time; -} - -// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. -// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. -ISR(TIMER1_COMPA_vect) -{ - if(busy){ /*Serial.println("BUSY")*/; - return; - } // The busy-flag is used to avoid reentering this interrupt - - busy = true; - sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) - - // If there is no current block, attempt to pop one from the buffer - if (current_block == NULL) { - // Anything in the buffer? - current_block = plan_get_current_block(); - if (current_block != NULL) { - trapezoid_generator_reset(); - counter_x = -(current_block->step_event_count >> 1); - counter_y = counter_x; - counter_z = counter_x; - counter_e = counter_x; - step_events_completed = 0; - e_steps = 0; - } - else { - DISABLE_STEPPER_DRIVER_INTERRUPT(); - } - } - - if (current_block != NULL) { - // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt - out_bits = current_block->direction_bits; - -#ifdef ADVANCE - // Calculate E early. - counter_e += current_block->steps_e; - if (counter_e > 0) { - counter_e -= current_block->step_event_count; - if ((out_bits & (1<> 16) - old_advance); - CRITICAL_SECTION_END; - old_advance = advance >> 16; -#endif //ADVANCE - - // Set direction en check limit switches - if ((out_bits & (1<step_event_count; - } - } - else // +direction - WRITE(X_DIR_PIN,!INVERT_X_DIR); - - if ((out_bits & (1<step_event_count; - } - } - else // +direction - WRITE(Y_DIR_PIN,!INVERT_Y_DIR); - - if ((out_bits & (1<step_event_count; - } - } - else // +direction - WRITE(Z_DIR_PIN,!INVERT_Z_DIR); - -#ifndef ADVANCE - if ((out_bits & (1<steps_x; - if (counter_x > 0) { - WRITE(X_STEP_PIN, HIGH); - counter_x -= current_block->step_event_count; - WRITE(X_STEP_PIN, LOW); - } - - counter_y += current_block->steps_y; - if (counter_y > 0) { - WRITE(Y_STEP_PIN, HIGH); - counter_y -= current_block->step_event_count; - WRITE(Y_STEP_PIN, LOW); - } - - counter_z += current_block->steps_z; - if (counter_z > 0) { - WRITE(Z_STEP_PIN, HIGH); - counter_z -= current_block->step_event_count; - WRITE(Z_STEP_PIN, LOW); - } - -#ifndef ADVANCE - counter_e += current_block->steps_e; - if (counter_e > 0) { - WRITE(E_STEP_PIN, HIGH); - counter_e -= current_block->step_event_count; - WRITE(E_STEP_PIN, LOW); - } -#endif //!ADVANCE - - // Calculare new timer value - unsigned short timer; - unsigned short step_rate; - if (step_events_completed < accelerate_until) { - MultiU24X24toH16(acc_step_rate, acceleration_time, acceleration_rate); - acc_step_rate += initial_rate; - - // upper limit - if(acc_step_rate > nominal_rate) - acc_step_rate = nominal_rate; - - // step_rate to timer interval - timer = calc_timer(acc_step_rate); - advance += advance_rate; - acceleration_time += timer; - OCR1A = timer; - } - else if (step_events_completed >= decelerate_after) { - MultiU24X24toH16(step_rate, deceleration_time, acceleration_rate); - - if(step_rate > acc_step_rate) { // Check step_rate stays positive - step_rate = final_rate; - } - else { - step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. - } - - // lower limit - if(step_rate < final_rate) - step_rate = final_rate; - - // step_rate to timer interval - timer = calc_timer(step_rate); -#ifdef ADVANCE - advance -= advance_rate; - if(advance < final_advance) - advance = final_advance; -#endif //ADVANCE - deceleration_time += timer; - OCR1A = timer; - } - // If current block is finished, reset pointer - step_events_completed += 1; - if (step_events_completed >= current_block->step_event_count) { - current_block = NULL; - plan_discard_current_block(); - } - } - busy=false; -} - -#ifdef ADVANCE - -unsigned char old_OCR0A; -// Timer interrupt for E. e_steps is set in the main routine; -// Timer 0 is shared with millies -ISR(TIMER0_COMPA_vect) -{ - // Critical section needed because Timer 1 interrupt has higher priority. - // The pin set functions are placed on trategic position to comply with the stepper driver timing. - WRITE(E_STEP_PIN, LOW); - // Set E direction (Depends on E direction + advance) - if (e_steps < 0) { - WRITE(E_DIR_PIN,INVERT_E_DIR); - e_steps++; - WRITE(E_STEP_PIN, HIGH); - } - if (e_steps > 0) { - WRITE(E_DIR_PIN,!INVERT_E_DIR); - e_steps--; - WRITE(E_STEP_PIN, HIGH); - } - old_OCR0A += 25; // 10kHz interrupt - OCR0A = old_OCR0A; -} -#endif // ADVANCE - -void st_init() -{ - // waveform generation = 0100 = CTC - TCCR1B &= ~(1<= 16) - { - current_raw = 16383 - raw_temp_value; - temp_meas_ready = true; - temp_count = 0; - raw_temp_value = 0; -#ifdef MAXTEMP - if(current_raw >= maxttemp) { - target_raw = 0; -#ifdef PIDTEMP - OCR2B = 0; -#else - WRITE(HEATER_0_PIN,LOW); -#endif //PIDTEMP - } -#endif //MAXTEMP -#ifdef MINTEMP - if(current_raw <= minttemp) { - target_raw = 0; -#ifdef PIDTEMP - OCR2B = 0; -#else - WRITE(HEATER_0_PIN,LOW); -#endif //PIDTEMP - } -#endif //MAXTEMP -#ifndef PIDTEMP - if(current_raw >= target_raw) - { - WRITE(HEATER_0_PIN,LOW); - } - else - { - WRITE(HEATER_0_PIN,HIGH); - } -#endif //PIDTEMP - } -} - + codenum = millis(); + } + manage_heater(); + } + break; + case 190: // M190 - Wait bed for heater to reach target. + #if TEMP_1_PIN > -1 + if (code_seen('S')) target_bed_raw = temp2analog(code_value()); + codenum = millis(); + while(current_bed_raw < target_bed_raw) { + if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + tt=analog2temp(current_raw); + Serial.print("T:"); + Serial.println( tt ); + Serial.print("ok T:"); + Serial.print( tt ); + Serial.print(" B:"); + Serial.println( analog2temp(current_bed_raw) ); + codenum = millis(); + } + manage_heater(); + } + #endif + break; + case 106: //M106 Fan On + if (code_seen('S')){ + digitalWrite(FAN_PIN, HIGH); + analogWrite(FAN_PIN, constrain(code_value(),0,255) ); + } + else + digitalWrite(FAN_PIN, HIGH); + break; + case 107: //M107 Fan Off + analogWrite(FAN_PIN, 0); + + digitalWrite(FAN_PIN, LOW); + break; + + case 82: + axis_relative_modes[3] = false; + break; + case 83: + axis_relative_modes[3] = true; + break; + case 84: + if(code_seen('S')){ + stepper_inactive_time = code_value() * 1000; + } + else{ + st_synchronize(); + disable_x(); + disable_y(); + disable_z(); + disable_e(); + } + break; + case 85: // M85 + code_seen('S'); + max_inactive_time = code_value() * 1000; + break; + case 92: // M92 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); + } + + break; + case 115: // M115 + Serial.println("FIRMWARE_NAME:Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); + break; + case 114: // M114 + Serial.print("X:"); + Serial.print(current_position[X_AXIS]); + Serial.print("Y:"); + Serial.print(current_position[Y_AXIS]); + Serial.print("Z:"); + Serial.print(current_position[Z_AXIS]); + Serial.print("E:"); + Serial.println(current_position[E_AXIS]); + break; + case 119: // M119 +#if (X_MIN_PIN > -1) + Serial.print("x_min:"); + Serial.print((READ(X_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (X_MAX_PIN > -1) + Serial.print("x_max:"); + Serial.print((READ(X_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Y_MIN_PIN > -1) + Serial.print("y_min:"); + Serial.print((READ(Y_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Y_MAX_PIN > -1) + Serial.print("y_max:"); + Serial.print((READ(Y_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Z_MIN_PIN > -1) + Serial.print("z_min:"); + Serial.print((READ(Z_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Z_MAX_PIN > -1) + Serial.print("z_max:"); + Serial.print((READ(Z_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif + Serial.println(""); + break; + //TODO: update for all axis, use for loop + case 201: // M201 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; +#if 0 // Not used for Sprinter/grbl gen6 + case 202: // M202 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; +#endif +#ifdef PIDTEMP + case 301: // M301 + if(code_seen('P')) Kp = code_value(); + if(code_seen('I')) Ki = code_value()*PID_dT; + if(code_seen('D')) Kd = code_value()/PID_dT; + Serial.print("Kp ");Serial.println(Kp); + Serial.print("Ki ");Serial.println(Ki/PID_dT); + Serial.print("Kd ");Serial.println(Kd*PID_dT); + temp_iState_min = 0.0; + temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; + break; +#endif //PIDTEMP + } + } + else{ + Serial.println("Unknown command:"); + Serial.println(cmdbuffer[bufindr]); + } + + ClearToSend(); +} + +void FlushSerialRequestResend() +{ + //char cmdbuffer[bufindr][100]="Resend:"; + Serial.flush(); + Serial.print("Resend:"); + Serial.println(gcode_LastN + 1); + ClearToSend(); +} + +void ClearToSend() +{ + previous_millis_cmd = millis(); +#ifdef SDSUPPORT + if(fromsd[bufindr]) + return; +#endif //SDSUPPORT + Serial.println("ok"); +} + +inline void get_coordinates() +{ + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; + else destination[i] = current_position[i]; //Are these else lines really needed? + } + if(code_seen('F')) { + next_feedrate = code_value(); + if(next_feedrate > 0.0) feedrate = next_feedrate; + } +} + +void prepare_move() +{ + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60.0); + for(int i=0; i < NUM_AXIS; i++) { + current_position[i] = destination[i]; + } +} +/* +void manage_heater() +{ + float pid_input; + float pid_output; + if(temp_meas_ready != true) + return; + +CRITICAL_SECTION_START; + temp_meas_ready = false; +CRITICAL_SECTION_END; + +#ifdef PIDTEMP + pid_input = analog2temp(current_raw); + +#ifndef PID_OPENLOOP + pid_error = pid_setpoint - pid_input; + if(pid_error > 10){ + pid_output = PID_MAX; + pid_reset = true; + } + else if(pid_error < -10) { + pid_output = 0; + pid_reset = true; + } + else { + if(pid_reset == true) { + temp_iState = 0.0; + pid_reset = false; + } + pTerm = Kp * pid_error; + temp_iState += pid_error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = Ki * temp_iState; + #define K1 0.8 + #define K2 (1.0-K1) + dTerm = (Kd * (pid_input - temp_dState))*K2 + (K1 * dTerm); + temp_dState = pid_input; + pid_output = constrain(pTerm + iTerm - dTerm, 0, PID_MAX); + } +#endif //PID_OPENLOOP +#ifdef PID_DEBUG + Serial.print(" Input "); + Serial.print(pid_input); + Serial.print(" Output "); + Serial.print(pid_output); + Serial.print(" pTerm "); + Serial.print(pTerm); + Serial.print(" iTerm "); + Serial.print(iTerm); + Serial.print(" dTerm "); + Serial.print(dTerm); + Serial.println(); +#endif //PID_DEBUG + OCR2B = pid_output; +#endif //PIDTEMP +} +*/ + + +/* +int temp2analogu(int celsius, const short table[][2], int numtemps) { + int raw = 0; + byte i; + + for (i=1; i raw) { + celsius = (float)table[i-1][1] + + (float)(raw - table[i-1][0]) * + (float)(table[i][1] - table[i-1][1]) / + (float)(table[i][0] - table[i-1][0]); + + break; + } + } + // Overflow: Set to last value in the table + if (i == numtemps) celsius = table[i-1][1]; + + return celsius; +} + + +inline void kill() +{ + target_raw=0; +#ifdef PIDTEMP + pid_setpoint = 0.0; +#endif //PIDTEMP + OCR2B = 0; + WRITE(HEATER_0_PIN,LOW); + + disable_x(); + disable_y(); + disable_z(); + disable_e(); + +} +*/ + + + +//#################################################################################################################### +//#################################################################################################################### +void manage_heater() +{ +#ifdef USE_WATCHDOG + wd_reset(); +#endif + //there is no FANCY_LCD here, because this routine is called within moves, and delays them. one could loose steps. + + if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) + return; + previous_millis_heater = millis(); + #ifdef HEATER_USES_THERMISTOR + current_raw = analogRead(TEMP_0_PIN); + // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_raw = 1023 - current_raw; + #elif defined HEATER_USES_AD595 + current_raw = analogRead(TEMP_0_PIN); + #elif defined HEATER_USES_MAX6675 + current_raw = read_max6675(); + #endif + #ifdef SMOOTHING + nma = (nma + current_raw) - (nma / SMOOTHFACTOR); + current_raw = nma / SMOOTHFACTOR; + #endif + #ifdef WATCHPERIOD + if(watchmillis && millis() - watchmillis > WATCHPERIOD){ + if(watch_raw + 1 >= current_raw){ + target_raw = 0; + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + }else{ + watchmillis = 0; + } + } + #endif + #ifdef MINTEMP + if(current_raw <= minttemp) + target_raw = 0; + #endif + #ifdef MAXTEMP + if(current_raw >= maxttemp) { + target_raw = 0; + } + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) + #ifdef PIDTEMP + error = target_raw - current_raw; + pTerm = (PID_PGAIN * error) / 100; + temp_iState += error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = (PID_IGAIN * temp_iState) / 100; + dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; + temp_dState = current_raw; + analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); + #else + if(current_raw >= target_raw) + { + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + } + else + { + digitalWrite(HEATER_0_PIN,HIGH); + digitalWrite(LED_PIN,HIGH); + } + #endif + #endif + + if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) + return; + previous_millis_bed_heater = millis(); + + #ifdef BED_USES_THERMISTOR + + current_bed_raw = analogRead(TEMP_1_PIN); + + // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_bed_raw = 1023 - current_bed_raw; + #elif defined BED_USES_AD595 + current_bed_raw = analogRead(TEMP_1_PIN); + + #endif + + + #if TEMP_1_PIN > -1 + if(current_bed_raw >= target_bed_raw) + { + digitalWrite(HEATER_1_PIN,LOW); + } + else + { + digitalWrite(HEATER_1_PIN,HIGH); + } + #endif +} + +// Takes hot end temperature value as input and returns corresponding raw value. +// For a thermistor, it uses the RepRap thermistor temp table. +// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value. +// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware. +float temp2analog(int celsius) { + #ifdef HEATER_USES_THERMISTOR + int raw = 0; + byte i; + + for (i=1; i raw) + { + celsius = temptable[i-1][1] + + (raw - temptable[i-1][0]) * + (temptable[i][1] - temptable[i-1][1]) / + (temptable[i][0] - temptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = temptable[i-1][1]; + + return celsius; + #elif defined HEATER_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #elif defined HEATER_USES_MAX6675 + return raw * 0.25; + #endif +} + +// Derived from RepRap FiveD extruder::getTemperature() +// For bed temperature measurement. +float analog2tempBed(int raw) { + #ifdef BED_USES_THERMISTOR + int celsius = 0; + byte i; + + raw = 1023 - raw; + + for (i=1; i raw) + { + celsius = bedtemptable[i-1][1] + + (raw - bedtemptable[i-1][0]) * + (bedtemptable[i][1] - bedtemptable[i-1][1]) / + (bedtemptable[i][0] - bedtemptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = bedtemptable[i-1][1]; + + return celsius; + + #elif defined BED_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #endif +} + +inline void kill() +{ + #if TEMP_0_PIN > -1 + target_raw=0; + digitalWrite(HEATER_0_PIN,LOW); + #endif + #if TEMP_1_PIN > -1 + target_bed_raw=0; + if(HEATER_1_PIN > -1) digitalWrite(HEATER_1_PIN,LOW); + #endif + disable_x(); + disable_y(); + disable_z(); + disable_e(); + + if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); + +} + + + + + + +//####################################################################################################################### + +inline void manage_inactivity(byte debug) { + if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); + if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { + disable_x(); + disable_y(); + disable_z(); + disable_e(); + } + check_axes_activity(); +} + +// Planner + +/* + Reasoning behind the mathematics in this module (in the key of 'Mathematica'): + + s == speed, a == acceleration, t == time, d == distance + + Basic definitions: + + Speed[s_, a_, t_] := s + (a*t) + Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t] + + Distance to reach a specific speed with a constant acceleration: + + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t] + d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance() + + Speed after a given distance of travel with constant acceleration: + + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t] + m -> Sqrt[2 a d + s^2] + + DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2] + + When to start braking (di) to reach a specified destionation speed (s2) after accelerating + from initial speed s1 without ever stopping at a plateau: + + Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di] + di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance() + + IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a) + */ + + +// The number of linear motions that can be in the plan at any give time +#define BLOCK_BUFFER_SIZE 16 +#define BLOCK_BUFFER_MASK 0x0f + +static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions +static volatile unsigned char block_buffer_head; // Index of the next block to be pushed +static volatile unsigned char block_buffer_tail; // Index of the block to process now + +// The current position of the tool in absolute steps +static long position[4]; + +#define ONE_MINUTE_OF_MICROSECONDS 60000000.0 + +// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the +// given acceleration: +inline long estimate_acceleration_distance(long initial_rate, long target_rate, long acceleration) { + return( + (target_rate*target_rate-initial_rate*initial_rate)/ + (2L*acceleration) + ); +} + +// This function gives you the point at which you must start braking (at the rate of -acceleration) if +// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after +// a total travel of distance. This can be used to compute the intersection point between acceleration and +// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) + +inline long intersection_distance(long initial_rate, long final_rate, long acceleration, long distance) { + return( + (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ + (4*acceleration) + ); +} + +// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. + +void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { + if(block->busy == true) return; // If block is busy then bail out. + float entry_factor = entry_speed / block->nominal_speed; + float exit_factor = exit_speed / block->nominal_speed; + long initial_rate = ceil(block->nominal_rate*entry_factor); + long final_rate = ceil(block->nominal_rate*exit_factor); + +#ifdef ADVANCE + long initial_advance = block->advance*entry_factor*entry_factor; + long final_advance = block->advance*exit_factor*exit_factor; +#endif // ADVANCE + + // Limit minimal step rate (Otherwise the timer will overflow.) + if(initial_rate <120) initial_rate=120; + if(final_rate < 120) final_rate=120; + + // Calculate the acceleration steps + long acceleration = block->acceleration; + long accelerate_steps = estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration); + long decelerate_steps = estimate_acceleration_distance(final_rate, block->nominal_rate, acceleration); + + // Calculate the size of Plateau of Nominal Rate. + long plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; + + // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will + // have to use intersection_distance() to calculate when to abort acceleration and start braking + // in order to reach the final_rate exactly at the end of this block. + if (plateau_steps < 0) { + accelerate_steps = intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count); + plateau_steps = 0; + } + + long decelerate_after = accelerate_steps+plateau_steps; + long acceleration_rate = (long)((float)acceleration * 8.388608); + + CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section + if(block->busy == false) { // Don't update variables if block is busy. + block->accelerate_until = accelerate_steps; + block->decelerate_after = decelerate_after; + block->acceleration_rate = acceleration_rate; + block->initial_rate = initial_rate; + block->final_rate = final_rate; +#ifdef ADVANCE + block->initial_advance = initial_advance; + block->final_advance = final_advance; +#endif //ADVANCE + } + CRITICAL_SECTION_END; +} + +// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the +// acceleration within the allotted distance. +inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { + return( + sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) + ); +} + +// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks. +// This method will calculate the junction jerk as the euclidean distance between the nominal +// velocities of the respective blocks. +inline float junction_jerk(block_t *before, block_t *after) { + return(sqrt( + pow((before->speed_x-after->speed_x), 2)+ + pow((before->speed_y-after->speed_y), 2)+ + pow((before->speed_z-after->speed_z)*axis_steps_per_unit[Z_AXIS]/axis_steps_per_unit[X_AXIS], 2))); +} + +// Return the safe speed which is max_jerk/2, e.g. the +// speed under which you cannot exceed max_jerk no matter what you do. +float safe_speed(block_t *block) { + float safe_speed; + safe_speed = max_jerk/2; + if (safe_speed > block->nominal_speed) safe_speed = block->nominal_speed; + return safe_speed; +} + +// The kernel called by planner_recalculate() when scanning the plan from last to first entry. +void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) { + if(!current) { + return; + } + + float entry_speed = current->nominal_speed; + float exit_factor; + float exit_speed; + if (next) { + exit_speed = next->entry_speed; + } + else { + exit_speed = safe_speed(current); + } + + // Calculate the entry_factor for the current block. + if (previous) { + // Reduce speed so that junction_jerk is within the maximum allowed + float jerk = junction_jerk(previous, current); + if((previous->steps_x == 0) && (previous->steps_y == 0)) { + entry_speed = safe_speed(current); + } + else if (jerk > max_jerk) { + entry_speed = (max_jerk/jerk) * entry_speed; + } + // If the required deceleration across the block is too rapid, reduce the entry_factor accordingly. + if (entry_speed > exit_speed) { + float max_entry_speed = max_allowable_speed(-acceleration,exit_speed, current->millimeters); + if (max_entry_speed < entry_speed) { + entry_speed = max_entry_speed; + } + } + } + else { + entry_speed = safe_speed(current); + } + // Store result + current->entry_speed = entry_speed; +} + +// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This +// implements the reverse pass. +void planner_reverse_pass() { + char block_index = block_buffer_head; + block_t *block[3] = { + NULL, NULL, NULL }; + while(block_index != block_buffer_tail) { + block_index--; + if(block_index < 0) { + block_index = BLOCK_BUFFER_SIZE-1; + } + block[2]= block[1]; + block[1]= block[0]; + block[0] = &block_buffer[block_index]; + planner_reverse_pass_kernel(block[0], block[1], block[2]); + } + planner_reverse_pass_kernel(NULL, block[0], block[1]); +} + +// The kernel called by planner_recalculate() when scanning the plan from first to last entry. +void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) { + if(!current) { + return; + } + if(previous) { + // If the previous block is an acceleration block, but it is not long enough to + // complete the full speed change within the block, we need to adjust out entry + // speed accordingly. Remember current->entry_factor equals the exit factor of + // the previous block. + if(previous->entry_speed < current->entry_speed) { + float max_entry_speed = max_allowable_speed(-acceleration, previous->entry_speed, previous->millimeters); + if (max_entry_speed < current->entry_speed) { + current->entry_speed = max_entry_speed; + } + } + } +} + +// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This +// implements the forward pass. +void planner_forward_pass() { + char block_index = block_buffer_tail; + block_t *block[3] = { + NULL, NULL, NULL }; + + while(block_index != block_buffer_head) { + block[0] = block[1]; + block[1] = block[2]; + block[2] = &block_buffer[block_index]; + planner_forward_pass_kernel(block[0],block[1],block[2]); + block_index = (block_index+1) & BLOCK_BUFFER_MASK; + } + planner_forward_pass_kernel(block[1], block[2], NULL); +} + +// Recalculates the trapezoid speed profiles for all blocks in the plan according to the +// entry_factor for each junction. Must be called by planner_recalculate() after +// updating the blocks. +void planner_recalculate_trapezoids() { + char block_index = block_buffer_tail; + block_t *current; + block_t *next = NULL; + while(block_index != block_buffer_head) { + current = next; + next = &block_buffer[block_index]; + if (current) { + calculate_trapezoid_for_block(current, current->entry_speed, next->entry_speed); + } + block_index = (block_index+1) & BLOCK_BUFFER_MASK; + } + calculate_trapezoid_for_block(next, next->entry_speed, safe_speed(next)); +} + +// Recalculates the motion plan according to the following algorithm: +// +// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) +// so that: +// a. The junction jerk is within the set limit +// b. No speed reduction within one block requires faster deceleration than the one, true constant +// acceleration. +// 2. Go over every block in chronological order and dial down junction speed reduction values if +// a. The speed increase within one block would require faster accelleration than the one, true +// constant acceleration. +// +// When these stages are complete all blocks have an entry_factor that will allow all speed changes to +// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than +// the set limit. Finally it will: +// +// 3. Recalculate trapezoids for all blocks. + +void planner_recalculate() { + planner_reverse_pass(); + planner_forward_pass(); + planner_recalculate_trapezoids(); +} + +void plan_init() { + block_buffer_head = 0; + block_buffer_tail = 0; + memset(position, 0, sizeof(position)); // clear position +} + + +inline void plan_discard_current_block() { + if (block_buffer_head != block_buffer_tail) { + block_buffer_tail = (block_buffer_tail + 1) & BLOCK_BUFFER_MASK; + } +} + +inline block_t *plan_get_current_block() { + if (block_buffer_head == block_buffer_tail) { + return(NULL); + } + block_t *block = &block_buffer[block_buffer_tail]; + block->busy = true; + return(block); +} + +void check_axes_activity() { + unsigned char x_active = 0; + unsigned char y_active = 0; + unsigned char z_active = 0; + unsigned char e_active = 0; + block_t *block; + + if(block_buffer_tail != block_buffer_head) { + char block_index = block_buffer_tail; + while(block_index != block_buffer_head) { + block = &block_buffer[block_index]; + if(block->steps_x != 0) x_active++; + if(block->steps_y != 0) y_active++; + if(block->steps_z != 0) z_active++; + if(block->steps_e != 0) e_active++; + block_index = (block_index+1) & BLOCK_BUFFER_MASK; + } + } + if((DISABLE_X) && (x_active == 0)) disable_x(); + if((DISABLE_Y) && (y_active == 0)) disable_y(); + if((DISABLE_Z) && (z_active == 0)) disable_z(); + if((DISABLE_E) && (e_active == 0)) disable_e(); +} + +// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in +// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration +// calculation the caller must also provide the physical length of the line in millimeters. +void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { + + // The target position of the tool in absolute steps + // Calculate target position in absolute steps + long target[4]; + target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); + target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); + target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); + target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); + + // Calculate the buffer head after we push this byte + int next_buffer_head = (block_buffer_head + 1) & BLOCK_BUFFER_MASK; + + // If the buffer is full: good! That means we are well ahead of the robot. + // Rest here until there is room in the buffer. + while(block_buffer_tail == next_buffer_head) { + manage_heater(); + manage_inactivity(1); + } + + // Prepare to set up new block + block_t *block = &block_buffer[block_buffer_head]; + + // Mark block as not busy (Not executed by the stepper interrupt) + block->busy = false; + + // Number of steps for each axis + block->steps_x = labs(target[X_AXIS]-position[X_AXIS]); + block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]); + block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); + block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); + block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); + + // Bail if this is a zero-length block + if (block->step_event_count == 0) { + return; + }; + + float delta_x_mm = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; + float delta_y_mm = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; + float delta_z_mm = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; + float delta_e_mm = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS]; + block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); + + unsigned long microseconds; + microseconds = lround((block->millimeters/feed_rate)*1000000); + + // Calculate speed in mm/minute for each axis + float multiplier = 60.0*1000000.0/microseconds; + block->speed_z = delta_z_mm * multiplier; + block->speed_x = delta_x_mm * multiplier; + block->speed_y = delta_y_mm * multiplier; + block->speed_e = delta_e_mm * multiplier; + + // Limit speed per axis + float speed_factor = 1; + float tmp_speed_factor; + if(abs(block->speed_x) > max_feedrate[X_AXIS]) { + speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + } + if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ + tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ + tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_e) > max_feedrate[E_AXIS]){ + tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + multiplier = multiplier * speed_factor; + block->speed_z = delta_z_mm * multiplier; + block->speed_x = delta_x_mm * multiplier; + block->speed_y = delta_y_mm * multiplier; + block->speed_e = delta_e_mm * multiplier; + block->nominal_speed = block->millimeters * multiplier; + block->nominal_rate = ceil(block->step_event_count * multiplier / 60); + + if(block->nominal_rate < 120) block->nominal_rate = 120; + block->entry_speed = safe_speed(block); + + // Compute the acceleration rate for the trapezoid generator. + float travel_per_step = block->millimeters/block->step_event_count; + if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { + block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + } + else { + block->acceleration = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + // Limit acceleration per axis + if((block->acceleration * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) + block->acceleration = axis_steps_per_sqr_second[X_AXIS]; + if((block->acceleration * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) + block->acceleration = axis_steps_per_sqr_second[Y_AXIS]; + if((block->acceleration * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) + block->acceleration = axis_steps_per_sqr_second[E_AXIS]; + if((block->acceleration * block->steps_z / block->step_event_count) > axis_steps_per_sqr_second[Z_AXIS]) + block->acceleration = axis_steps_per_sqr_second[Z_AXIS]; + } + +#ifdef ADVANCE + // Calculate advance rate + if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { + block->advance_rate = 0; + block->advance = 0; + } + else { + long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration); + float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * + (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; + block->advance = advance; + if(acc_dist == 0) { + block->advance_rate = 0; + } + else { + block->advance_rate = advance / (float)acc_dist; + } + } + +#endif // ADVANCE + + // compute a preliminary conservative acceleration trapezoid + float safespeed = safe_speed(block); + calculate_trapezoid_for_block(block, safespeed, safespeed); + + // Compute direction bits for this block + block->direction_bits = 0; + if (target[X_AXIS] < position[X_AXIS]) { + block->direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<steps_x != 0) enable_x(); + if(block->steps_y != 0) enable_y(); + if(block->steps_z != 0) enable_z(); + if(block->steps_e != 0) enable_e(); + + // Move buffer head + block_buffer_head = next_buffer_head; + + // Update position + memcpy(position, target, sizeof(target)); // position[] = target[] + + planner_recalculate(); + st_wake_up(); +} + +void plan_set_position(float x, float y, float z, float e) +{ + position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); + position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); + position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); + position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); +} + +// Stepper + +// intRes = intIn1 * intIn2 >> 16 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 24 bit result +#define MultiU16X8toH16(intRes, charIn1, intIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %A1, %A2 \n\t" \ +"add %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r0 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (charIn1), \ +"d" (intIn2) \ +: \ +"r26" \ +) + +// intRes = longIn1 * longIn2 >> 24 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 48bit result +#define MultiU24X24toH16(intRes, longIn1, longIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"mov r27, r1 \n\t" \ +"mul %B1, %C2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %C1, %C2 \n\t" \ +"add %B0, r0 \n\t" \ +"mul %C1, %B2 \n\t" \ +"add %A0, r0 \n\t" \ +"adc %B0, r1 \n\t" \ +"mul %A1, %C2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %B2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %C1, %A2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %A2 \n\t" \ +"add r27, r1 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r27 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (longIn1), \ +"d" (longIn2) \ +: \ +"r26" , "r27" \ +) + +// Some useful constants + +#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1< +// +// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates +// first block->accelerate_until step_events_completed, then keeps going at constant speed until +// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. +// The slope of acceleration is calculated with the leib ramp alghorithm. + +void st_wake_up() { + // TCNT1 = 0; + ENABLE_STEPPER_DRIVER_INTERRUPT(); +} + +inline unsigned short calc_timer(unsigned short step_rate) { + unsigned short timer; + if(step_rate < 32) step_rate = 32; + step_rate -= 32; // Correct for minimal speed + if(step_rate >= (8*256)){ // higher step rate + unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; + unsigned char tmp_step_rate = (step_rate & 0x00ff); + unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); + MultiU16X8toH16(timer, tmp_step_rate, gain); + timer = (unsigned short)pgm_read_word_near(table_address) - timer; + } + else { // lower step rates + unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; + table_address += ((step_rate)>>1) & 0xfffc; + timer = (unsigned short)pgm_read_word_near(table_address); + timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); + } + if(timer < 100) timer = 100; + return timer; +} + +// Initializes the trapezoid generator from the current block. Called whenever a new +// block begins. +inline void trapezoid_generator_reset() { + accelerate_until = current_block->accelerate_until; + decelerate_after = current_block->decelerate_after; + acceleration_rate = current_block->acceleration_rate; + initial_rate = current_block->initial_rate; + final_rate = current_block->final_rate; + nominal_rate = current_block->nominal_rate; + advance = current_block->initial_advance; + final_advance = current_block->final_advance; + deceleration_time = 0; + advance_rate = current_block->advance_rate; + // step_rate to timer interval + acc_step_rate = initial_rate; + acceleration_time = calc_timer(acc_step_rate); + OCR1A = acceleration_time; +} + +// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. +// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. +ISR(TIMER1_COMPA_vect) +{ + if(busy){ /*Serial.println("BUSY")*/; + return; + } // The busy-flag is used to avoid reentering this interrupt + + busy = true; + sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) + + // If there is no current block, attempt to pop one from the buffer + if (current_block == NULL) { + // Anything in the buffer? + current_block = plan_get_current_block(); + if (current_block != NULL) { + trapezoid_generator_reset(); + counter_x = -(current_block->step_event_count >> 1); + counter_y = counter_x; + counter_z = counter_x; + counter_e = counter_x; + step_events_completed = 0; + e_steps = 0; + } + else { + DISABLE_STEPPER_DRIVER_INTERRUPT(); + } + } + + if (current_block != NULL) { + // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt + out_bits = current_block->direction_bits; + +#ifdef ADVANCE + // Calculate E early. + counter_e += current_block->steps_e; + if (counter_e > 0) { + counter_e -= current_block->step_event_count; + if ((out_bits & (1<> 16) - old_advance); + CRITICAL_SECTION_END; + old_advance = advance >> 16; +#endif //ADVANCE + + // Set direction en check limit switches + if ((out_bits & (1<step_event_count; + } + } + else // +direction + WRITE(X_DIR_PIN,!INVERT_X_DIR); + + if ((out_bits & (1<step_event_count; + } + } + else // +direction + WRITE(Y_DIR_PIN,!INVERT_Y_DIR); + + if ((out_bits & (1<step_event_count; + } + } + else // +direction + WRITE(Z_DIR_PIN,!INVERT_Z_DIR); + +#ifndef ADVANCE + if ((out_bits & (1<steps_x; + if (counter_x > 0) { + WRITE(X_STEP_PIN, HIGH); + counter_x -= current_block->step_event_count; + WRITE(X_STEP_PIN, LOW); + } + + counter_y += current_block->steps_y; + if (counter_y > 0) { + WRITE(Y_STEP_PIN, HIGH); + counter_y -= current_block->step_event_count; + WRITE(Y_STEP_PIN, LOW); + } + + counter_z += current_block->steps_z; + if (counter_z > 0) { + WRITE(Z_STEP_PIN, HIGH); + counter_z -= current_block->step_event_count; + WRITE(Z_STEP_PIN, LOW); + } + +#ifndef ADVANCE + counter_e += current_block->steps_e; + if (counter_e > 0) { + WRITE(E_STEP_PIN, HIGH); + counter_e -= current_block->step_event_count; + WRITE(E_STEP_PIN, LOW); + } +#endif //!ADVANCE + + // Calculare new timer value + unsigned short timer; + unsigned short step_rate; + if (step_events_completed < accelerate_until) { + MultiU24X24toH16(acc_step_rate, acceleration_time, acceleration_rate); + acc_step_rate += initial_rate; + + // upper limit + if(acc_step_rate > nominal_rate) + acc_step_rate = nominal_rate; + + // step_rate to timer interval + timer = calc_timer(acc_step_rate); + advance += advance_rate; + acceleration_time += timer; + OCR1A = timer; + } + else if (step_events_completed >= decelerate_after) { + MultiU24X24toH16(step_rate, deceleration_time, acceleration_rate); + + if(step_rate > acc_step_rate) { // Check step_rate stays positive + step_rate = final_rate; + } + else { + step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. + } + + // lower limit + if(step_rate < final_rate) + step_rate = final_rate; + + // step_rate to timer interval + timer = calc_timer(step_rate); +#ifdef ADVANCE + advance -= advance_rate; + if(advance < final_advance) + advance = final_advance; +#endif //ADVANCE + deceleration_time += timer; + OCR1A = timer; + } + // If current block is finished, reset pointer + step_events_completed += 1; + if (step_events_completed >= current_block->step_event_count) { + current_block = NULL; + plan_discard_current_block(); + } + } + busy=false; +} + +#ifdef ADVANCE + +unsigned char old_OCR0A; +// Timer interrupt for E. e_steps is set in the main routine; +// Timer 0 is shared with millies +ISR(TIMER0_COMPA_vect) +{ + // Critical section needed because Timer 1 interrupt has higher priority. + // The pin set functions are placed on trategic position to comply with the stepper driver timing. + WRITE(E_STEP_PIN, LOW); + // Set E direction (Depends on E direction + advance) + if (e_steps < 0) { + WRITE(E_DIR_PIN,INVERT_E_DIR); + e_steps++; + WRITE(E_STEP_PIN, HIGH); + } + if (e_steps > 0) { + WRITE(E_DIR_PIN,!INVERT_E_DIR); + e_steps--; + WRITE(E_STEP_PIN, HIGH); + } + old_OCR0A += 25; // 10kHz interrupt + OCR0A = old_OCR0A; +} +#endif // ADVANCE + +void st_init() +{ + // waveform generation = 0100 = CTC + TCCR1B &= ~(1<= 16) + { + current_raw = 16383 - raw_temp_value; + temp_meas_ready = true; + temp_count = 0; + raw_temp_value = 0; +#ifdef MAXTEMP + if(current_raw >= maxttemp) { + target_raw = 0; +#ifdef PIDTEMP + OCR2B = 0; +#else + WRITE(HEATER_0_PIN,LOW); +#endif //PIDTEMP + } +#endif //MAXTEMP +#ifdef MINTEMP + if(current_raw <= minttemp) { + target_raw = 0; +#ifdef PIDTEMP + OCR2B = 0; +#else + WRITE(HEATER_0_PIN,LOW); +#endif //PIDTEMP + } +#endif //MAXTEMP +#ifndef PIDTEMP + if(current_raw >= target_raw) + { + WRITE(HEATER_0_PIN,LOW); + } + else + { + WRITE(HEATER_0_PIN,HIGH); + } +#endif //PIDTEMP + } +} + */ \ No newline at end of file diff --git a/Marlin/wiring.pde b/Marlin/wiring.pde deleted file mode 100644 index adee6cbe44af..000000000000 --- a/Marlin/wiring.pde +++ /dev/null @@ -1,176 +0,0 @@ -/* - wiring.c - Partial implementation of the Wiring API for the ATmega8. - Part of Arduino - http://www.arduino.cc/ - - Copyright (c) 2005-2006 David A. Mellis - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with this library; if not, write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - $Id: wiring.c 388 2008-03-08 22:05:23Z mellis $ -*/ - -#include "wiring_private.h" - -volatile unsigned long timer0_millis = 0; - -SIGNAL(TIMER0_OVF_vect) -{ - // timer 0 prescale factor is 64 and the timer overflows at 256 - timer0_millis++; -} - -unsigned long millis() -{ - unsigned long m; - uint8_t oldSREG = SREG; - - // disable interrupts while we read timer0_millis or we might get an - // inconsistent value (e.g. in the middle of the timer0_millis++) - cli(); - m = timer0_millis; - SREG = oldSREG; - - return m; -} - -void delay(unsigned long ms) -{ - unsigned long start = millis(); - - while (millis() - start <= ms) - ; -} - -/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. - * Disables interrupts, which will disrupt the millis() function if used - * too frequently. */ -void delayMicroseconds(unsigned int us) -{ - uint8_t oldSREG; - - // calling avrlib's delay_us() function with low values (e.g. 1 or - // 2 microseconds) gives delays longer than desired. - //delay_us(us); - -#if F_CPU >= 16000000L - // for the 16 MHz clock on most Arduino boards - - // for a one-microsecond delay, simply return. the overhead - // of the function call yields a delay of approximately 1 1/8 us. - if (--us == 0) - return; - - // the following loop takes a quarter of a microsecond (4 cycles) - // per iteration, so execute it four times for each microsecond of - // delay requested. - us <<= 2; - - // account for the time taken in the preceeding commands. - us -= 2; -#else - // for the 8 MHz internal clock on the ATmega168 - - // for a one- or two-microsecond delay, simply return. the overhead of - // the function calls takes more than two microseconds. can't just - // subtract two, since us is unsigned; we'd overflow. - if (--us == 0) - return; - if (--us == 0) - return; - - // the following loop takes half of a microsecond (4 cycles) - // per iteration, so execute it twice for each microsecond of - // delay requested. - us <<= 1; - - // partially compensate for the time taken by the preceeding commands. - // we can't subtract any more than this or we'd overflow w/ small delays. - us--; -#endif - - // disable interrupts, otherwise the timer 0 overflow interrupt that - // tracks milliseconds will make us delay longer than we want. - oldSREG = SREG; - cli(); - - // busy wait - __asm__ __volatile__ ( - "1: sbiw %0,1" "\n\t" // 2 cycles - "brne 1b" : "=w" (us) : "0" (us) // 2 cycles - ); - - // reenable interrupts. - SREG = oldSREG; -} - -void init() -{ - // this needs to be called before setup() or some functions won't - // work there - sei(); - - // on the ATmega168, timer 0 is also used for fast hardware pwm - // (using phase-correct PWM would mean that timer 0 overflowed half as often - // resulting in different millis() behavior on the ATmega8 and ATmega168) - sbi(TCCR0A, WGM01); - sbi(TCCR0A, WGM00); - - // set timer 0 prescale factor to 64 - sbi(TCCR0B, CS01); - sbi(TCCR0B, CS00); - - // enable timer 0 overflow interrupt - sbi(TIMSK0, TOIE0); - - // timers 1 and 2 are used for phase-correct hardware pwm - // this is better for motors as it ensures an even waveform - // note, however, that fast pwm mode can achieve a frequency of up - // 8 MHz (with a 16 MHz clock) at 50% duty cycle -#if 0 - // set timer 1 prescale factor to 64 - sbi(TCCR1B, CS11); - sbi(TCCR1B, CS10); - - // put timer 1 in 8-bit phase correct pwm mode - sbi(TCCR1A, WGM10); - - // set timer 2 prescale factor to 64 - sbi(TCCR2B, CS22); - - // configure timer 2 for phase correct pwm (8-bit) - sbi(TCCR2A, WGM20); - - // set a2d prescale factor to 128 - // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range. - // XXX: this will not work properly for other clock speeds, and - // this code should use F_CPU to determine the prescale factor. - sbi(ADCSRA, ADPS2); - sbi(ADCSRA, ADPS1); - sbi(ADCSRA, ADPS0); - - // enable a2d conversions - sbi(ADCSRA, ADEN); - - // the bootloader connects pins 0 and 1 to the USART; disconnect them - // here so they can be used as normal digital i/o; they will be - // reconnected in Serial.begin() - UCSR0B = 0; - #if defined(__AVR_ATmega644P__) - //TODO: test to see if disabling this helps? - //UCSR1B = 0; - #endif -#endif -} From 4630b163364b40bc0ae0403b177e8890ee064d47 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 23 Aug 2011 16:40:19 +0200 Subject: [PATCH 006/130] ok, now it seems to work with the temperatures --- Marlin/Configuration.h | 7 +++---- Marlin/lcd.h | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 5451439083ce..48b2090f8f95 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -18,7 +18,7 @@ //#define HEATER_USES_MAX6675 // Select one of these only to define how the bed temp is read. -#define BED_USES_THERMISTOR +//#define BED_USES_THERMISTOR //#define BED_USES_AD595 #define HEATER_CHECK_INTERVAL 50 @@ -45,7 +45,6 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the // Comment out (using // at the start of the line) to disable SD support: #define SDSUPPORT //#define FANCY_LCD -#define LCD_UPDATE_INTERVAL 400 @@ -91,10 +90,10 @@ bool axis_relative_modes[] = {false, false, false, false}; //// Acceleration settings // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. -float acceleration = 3000; // Normal acceleration mm/s^2 +float acceleration = 6000; // Normal acceleration mm/s^2 float retract_acceleration = 7000; // Normal acceleration mm/s^2 float max_jerk = 20*60; -long max_acceleration_units_per_sq_second[] = {7000,7000,200,10000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts +long max_acceleration_units_per_sq_second[] = {15000,15000,15000,15000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts // Not used long max_travel_acceleration_units_per_sq_second[] = {500,500,50,500}; // X, Y, Z max acceleration in mm/s^2 for travel moves diff --git a/Marlin/lcd.h b/Marlin/lcd.h index d15e4cb0775a..d852fd21c7a0 100644 --- a/Marlin/lcd.h +++ b/Marlin/lcd.h @@ -2,6 +2,7 @@ #define __LCDH #ifdef FANCY_LCD + #define LCD_UPDATE_INTERVAL 400 #include "Configuration.h" From b84f6e160105833bf0713992e40168438c4d6bff Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 23 Aug 2011 17:42:31 +0200 Subject: [PATCH 007/130] tuned configuration --- Marlin/Configuration.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 48b2090f8f95..8383c36deb74 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -61,7 +61,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the // Disables axis when it's not being used. #define DISABLE_X false #define DISABLE_Y false -#define DISABLE_Z true +#define DISABLE_Z false #define DISABLE_E false // Inverting axis direction @@ -84,16 +84,16 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the //// MOVEMENT SETTINGS #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {60000, 60000, 500, 500000}; // set the max speeds +float max_feedrate[] = {60000, 60000, 50000, 500000}; // set the max speeds float homing_feedrate[] = {2400, 2400, 200, 0}; // set the homing speeds bool axis_relative_modes[] = {false, false, false, false}; //// Acceleration settings // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. -float acceleration = 6000; // Normal acceleration mm/s^2 -float retract_acceleration = 7000; // Normal acceleration mm/s^2 +float acceleration = 4000; // Normal acceleration mm/s^2 +float retract_acceleration = 10000; // Normal acceleration mm/s^2 float max_jerk = 20*60; -long max_acceleration_units_per_sq_second[] = {15000,15000,15000,15000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts +long max_acceleration_units_per_sq_second[] = {15000,15000,150000,15000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts // Not used long max_travel_acceleration_units_per_sq_second[] = {500,500,50,500}; // X, Y, Z max acceleration in mm/s^2 for travel moves From d471651fe67ff40c3e56992593e62165eba12afc Mon Sep 17 00:00:00 2001 From: bradleyf Date: Wed, 24 Aug 2011 07:07:43 -0400 Subject: [PATCH 008/130] Fixes to allow simple LCD display. Added FANCY_BUTTONS define to allow Bernhard's console to function as well --- Marlin/Configuration.h | 5 +++-- Marlin/lcd.h | 9 +++++++-- Marlin/lcd.pde | 30 ++++++++++++++++++------------ 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 8383c36deb74..6b2df0195391 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -43,8 +43,9 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -#define SDSUPPORT -//#define FANCY_LCD +//#define SDSUPPORT +#define FANCY_LCD +//#define FANCY_BUTTONS diff --git a/Marlin/lcd.h b/Marlin/lcd.h index d852fd21c7a0..24f93720e50c 100644 --- a/Marlin/lcd.h +++ b/Marlin/lcd.h @@ -10,8 +10,13 @@ extern LiquidCrystal lcd; //lcd display size - #define LCD_WIDTH 20 - #define LCD_HEIGHT 4 + #ifdef FANCY_BUTTONS + #define LCD_WIDTH 20 + #define LCD_HEIGHT 4 + #else + #define LCD_WIDTH 16 + #define LCD_HEIGHT 2 + #endif //arduino pin witch triggers an piezzo beeper #define BEEPER 18 diff --git a/Marlin/lcd.pde b/Marlin/lcd.pde index 93b64571132f..4a9c9a56e212 100644 --- a/Marlin/lcd.pde +++ b/Marlin/lcd.pde @@ -12,7 +12,7 @@ unsigned long previous_millis_lcd=0; #include "menu_base.h" -char messagetext[20]=""; +char messagetext[LCD_WIDTH]=""; @@ -114,7 +114,7 @@ void PageWatch::activate() (!digitalRead(Z_MAX_PIN))? 'Z':' '); lcd.setCursor(0,0); - lcd.print(fillto(20,line1)); + lcd.print(fillto(LCD_WIDTH,line1)); #if 0 lcd.setCursor(0, 1); //copy last printed gcode line from the buffer onto the lcd @@ -126,7 +126,7 @@ void PageWatch::activate() if(1&&print) { - lcd.print(fillto(20,cline2)); + lcd.print(fillto(LCD_WIDTH,cline2)); } if(LCD_HEIGHT>2) { @@ -137,10 +137,10 @@ void PageWatch::activate() if(1&&print) { - lcd.print(fillto(20,cline2)); + lcd.print(fillto(LCD_WIDTH,cline2)); } lcd.setCursor(0,3); - lcd.print(fillto(20,messagetext)); + lcd.print(fillto(LCD_WIDTH,messagetext)); } @@ -269,13 +269,13 @@ void PageHome::update() void PageHome::activate() { lcd.setCursor(0,0); - lcd.print(fillto(20,"Home")); + lcd.print(fillto(LCD_WIDTH,"Home")); lcd.setCursor(0,1); - lcd.print(fillto(20," X ZERO")); + lcd.print(fillto(LCD_WIDTH," X ZERO")); lcd.setCursor(0,2); - lcd.print(fillto(20," Y ZERO")); + lcd.print(fillto(LCD_WIDTH," Y ZERO")); lcd.setCursor(0,3); - lcd.print(fillto(20," Z ZERO")); + lcd.print(fillto(LCD_WIDTH," Z ZERO")); fillline(); } @@ -407,7 +407,7 @@ void lcd_status(const char* message) // if(missing>0) // for(int i=0;i Date: Wed, 24 Aug 2011 12:00:16 -0400 Subject: [PATCH 009/130] Implemented Max Endstops for X,Y,Z axis --- Marlin/Marlin.pde | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 6d23dc2eeca1..3aa8ea029aa2 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -2106,12 +2106,16 @@ ISR(TIMER1_COMPA_vect) // Set direction en check limit switches if ((out_bits & (1<step_event_count; } } - else // +direction - WRITE(X_DIR_PIN,!INVERT_X_DIR); + else { // +direction + WRITE(X_DIR_PIN,!INVERT_X_DIR); + if(READ(X_MAX_PIN) != ENDSTOPS_INVERTING){ + step_events_completed = current_block->step_event_count; + } + } if ((out_bits & (1<step_event_count; } } - else // +direction + else { // +direction WRITE(Y_DIR_PIN,!INVERT_Y_DIR); + if(READ(Y_MAX_PIN) != ENDSTOPS_INVERTING){ + step_events_completed = current_block->step_event_count; + } + } if ((out_bits & (1<step_event_count; } } - else // +direction - WRITE(Z_DIR_PIN,!INVERT_Z_DIR); + else { // +direction + WRITE(Z_DIR_PIN,!INVERT_Z_DIR); + if(READ(Z_MAX_PIN) != ENDSTOPS_INVERTING){ + step_events_completed = current_block->step_event_count; + } + } #ifndef ADVANCE if ((out_bits & (1< Date: Wed, 24 Aug 2011 12:14:07 -0400 Subject: [PATCH 010/130] Updated Readme for this fork --- README | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/README b/README index daf03db52dd4..d31bda7c8642 100644 --- a/README +++ b/README @@ -2,6 +2,10 @@ This firmware is a mashup between Sprinter, grbl and many original parts. (https://github.com/kliment/Sprinter) (https://github.com/simen/grbl/tree) +It has been adapted to the Ultimaker Printer by: + Bernhard Kubicek, Bradley Feldman, and others + + Features: - Interrupt based movement with real linear acceleration - High steprate @@ -9,48 +13,52 @@ Features: - Interrupt based temperature protection - preliminary support for Matthew Roberts advance algorithm For more info see: http://reprap.org/pipermail/reprap-dev/2011-May/003323.html + - Full endstop support + - Simple LCD support (16x2) + - SD Card support + - Provisions for Bernhard Kubicek's new hardware control console and 20x4 lcd + +This firmware is optimized for Ultimaker's gen6 electronics (including the Ultimaker 1.5.x daughterboard and Arduino Mega 2560). -This firmware is optimized for gen6 electronics. +The default baudrate is 115200. -The default baudrate is 250000. -This gives less communication errors then regular baudrates. ======================================================================================== Configuring and compilation -Install the arduino software version 0018 +Install the latest arduino software IDE/toolset (currently 0022) http://www.arduino.cc/en/Main/Software Install the sanguino software, version 0018 http://sanguino.cc/useit -Install pronterface - https://github.com/kliment/Printrun +Install Ultimaker's RepG 25 build + http://software.ultimaker.com +(or alternatively install Kliment's printrun/pronterface https://github.com/kliment/Printrun_) -Copy the Marlin firmware +Copy the Ultimaker Marlin firmware https:/github.com/ErikZalm/Marlin (Use the download button) Start the arduino IDE. -Select Tools -> Board -> Sanguino +Select Tools -> Board -> Arduino Mega 2560 Select the correct serial port in Tools ->Serial Port Open Marlin.pde -Change the printer specific setting in Configuration.h to the correct values. - -The following values are the most important: - - float axis_steps_per_unit[].... // Set the correct steps / mm in the corresponding field - - const bool ENDSTOPS_INVERTING = false; // Change if only positive moves are executed - - #define INVERT_x_DIR true // Change if the motor direction is wrong +Click the Verify/Compile button Click the Upload button If all goes well the firmware is uploading -Start pronterface +Start Ultimaker's Custom RepG 25 +Make sure Show Experimental Profiles is enabled in Preferences +Select Sprinter as the Driver -Select the correct Serial Port. Type 250000 in the baudrate field. Press the Connect button. +KNOWN ISSUES: RepG will display: Unknown: marlin x.y.z + +That's ok. Enjoy Silky Smooth Printing. From f1a7c8bc807a11f7420d375f75a9db9777181d60 Mon Sep 17 00:00:00 2001 From: bradleyf Date: Wed, 24 Aug 2011 12:16:12 -0400 Subject: [PATCH 011/130] Updated Readme typos --- README | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README b/README index d31bda7c8642..71215d8e16a6 100644 --- a/README +++ b/README @@ -1,9 +1,9 @@ -This firmware is a mashup between Sprinter, grbl and many original parts. +This RepRap firmware is a mashup between Sprinter, grbl and many original parts. (https://github.com/kliment/Sprinter) (https://github.com/simen/grbl/tree) It has been adapted to the Ultimaker Printer by: - Bernhard Kubicek, Bradley Feldman, and others + Bernhard Kubicek, Bradley Feldman, and others... Features: @@ -31,9 +31,6 @@ Configuring and compilation Install the latest arduino software IDE/toolset (currently 0022) http://www.arduino.cc/en/Main/Software -Install the sanguino software, version 0018 - http://sanguino.cc/useit - Install Ultimaker's RepG 25 build http://software.ultimaker.com (or alternatively install Kliment's printrun/pronterface https://github.com/kliment/Printrun_) From 3d0ce296d4696fb7e089d1fb87a52add471e291f Mon Sep 17 00:00:00 2001 From: bradleyf Date: Wed, 24 Aug 2011 12:17:27 -0400 Subject: [PATCH 012/130] Corrected one more readme typo --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 71215d8e16a6..7567e23a44c7 100644 --- a/README +++ b/README @@ -36,7 +36,7 @@ Install Ultimaker's RepG 25 build (or alternatively install Kliment's printrun/pronterface https://github.com/kliment/Printrun_) Copy the Ultimaker Marlin firmware - https:/github.com/ErikZalm/Marlin + https:/github.com/bkubicek/Marlin (Use the download button) Start the arduino IDE. From 6416e2080b1707d2114e3331b5b4d4249207622b Mon Sep 17 00:00:00 2001 From: bradleyf Date: Wed, 24 Aug 2011 16:00:54 -0400 Subject: [PATCH 013/130] Fixed max endstops locking other axis' movements --- Marlin/Marlin.pde | 4714 ++++++++++++++++++++++----------------------- 1 file changed, 2357 insertions(+), 2357 deletions(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 3aa8ea029aa2..7ff9889797d7 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1,2366 +1,2366 @@ -#include "Marlin.h" -// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in -// the source g-code and may never actually be reached if acceleration management is active. - - -#include "speed_lookuptable.h" - -/* - Reprap firmware based on Sprinter and grbl. - Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm - - This program 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. - - This program 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 this program. If not, see . - */ - -/* - This firmware is a mashup between Sprinter and grbl. - (https://github.com/kliment/Sprinter) - (https://github.com/simen/grbl/tree) - - It has preliminary support for Matthew Roberts advance algorithm - http://reprap.org/pipermail/reprap-dev/2011-May/003323.html - - This firmware is optimized for gen6 electronics. - */ - - - -#include "fastio.h" -#include "Configuration.h" -#include "pins.h" +#include "Marlin.h" +// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in +// the source g-code and may never actually be reached if acceleration management is active. + + +#include "speed_lookuptable.h" + +/* + Reprap firmware based on Sprinter and grbl. + Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + + This program 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. + + This program 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 this program. If not, see . + */ + +/* + This firmware is a mashup between Sprinter and grbl. + (https://github.com/kliment/Sprinter) + (https://github.com/simen/grbl/tree) + + It has preliminary support for Matthew Roberts advance algorithm + http://reprap.org/pipermail/reprap-dev/2011-May/003323.html + + This firmware is optimized for gen6 electronics. + */ + + + +#include "fastio.h" +#include "Configuration.h" +#include "pins.h" #include "lcd.h" //extern LiquidCrystal lcd; - -char version_string[] = "0.9.3"; - -#ifdef SDSUPPORT -#include "SdFat.h" -#endif //SDSUPPORT - -#ifndef CRITICAL_SECTION_START -#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() -#define CRITICAL_SECTION_END SREG = _sreg -#endif //CRITICAL_SECTION_START - -// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html -// 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 -// G28 - Home all 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 -// 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 -// M115 - Capabilities string -// 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) -// M301 - Set PID parameters P I and D - -//Stepper Movement Variables - -char axis_codes[NUM_AXIS] = { - 'X', 'Y', 'Z', 'E'}; -float destination[NUM_AXIS] = { - 0.0, 0.0, 0.0, 0.0}; -float current_position[NUM_AXIS] = { - 0.0, 0.0, 0.0, 0.0}; -bool home_all_axis = true; -long feedrate = 1500, next_feedrate, saved_feedrate; -long gcode_N, gcode_LastN; -unsigned long previous_millis_heater, previous_millis_bed_heater; -bool relative_mode = false; //Determines Absolute or Relative Coordinates -bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. -unsigned long axis_steps_per_sqr_second[NUM_AXIS]; - -// comm variables -#define MAX_CMD_SIZE 96 -#define BUFSIZE 8 -char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; -bool fromsd[BUFSIZE]; -int bufindr = 0; -int bufindw = 0; -int buflen = 0; -int i = 0; -char serial_char; -int serial_count = 0; -boolean comment_mode = false; -char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc - -// Manage heater variables. - -int target_bed_raw = 0; -int current_bed_raw = 0; - -int target_raw = 0; -int current_raw = 0; -unsigned char temp_meas_ready = false; - -#ifdef PIDTEMP - double temp_iState = 0; - double temp_dState = 0; - double pTerm; - double iTerm; - double dTerm; - //int output; - double pid_error; - double temp_iState_min; - double temp_iState_max; - double pid_setpoint = 0.0; - double pid_input; - double pid_output; - bool pid_reset; -#endif //PIDTEMP -float tt = 0, bt = 0; -#ifdef WATCHPERIOD -int watch_raw = -1000; -unsigned long watchmillis = 0; -#endif //WATCHPERIOD -#ifdef MINTEMP -int minttemp = temp2analog(MINTEMP); -#endif //MINTEMP -#ifdef MAXTEMP -int maxttemp = temp2analog(MAXTEMP); -#endif //MAXTEMP - -//Inactivity shutdown variables -unsigned long previous_millis_cmd = 0; -unsigned long max_inactive_time = 0; -unsigned long stepper_inactive_time = 0; - -#ifdef SDSUPPORT -Sd2Card card; -SdVolume volume; -SdFile root; -SdFile file; -uint32_t filesize = 0; -uint32_t sdpos = 0; -bool sdmode = false; -bool sdactive = false; -bool savetosd = false; -int16_t n; - -void initsd(){ - sdactive = false; -#if SDSS >- 1 - if(root.isOpen()) - root.close(); - if (!card.init(SPI_FULL_SPEED,SDSS)){ - //if (!card.init(SPI_HALF_SPEED,SDSS)) - Serial.println("SD init fail"); - } - else if (!volume.init(&card)) - Serial.println("volume.init failed"); - else if (!root.openRoot(&volume)) - Serial.println("openRoot failed"); - else - sdactive = true; -#endif //SDSS -} - -inline void write_command(char *buf){ - char* begin = buf; - char* npos = 0; - char* end = buf + strlen(buf) - 1; - - file.writeError = false; - if((npos = strchr(buf, 'N')) != NULL){ - begin = strchr(npos, ' ') + 1; - end = strchr(npos, '*') - 1; - } - end[1] = '\r'; - end[2] = '\n'; - end[3] = '\0'; - //Serial.println(begin); - file.write(begin); - if (file.writeError){ - Serial.println("error writing to file"); - } -} -#endif //SDSUPPORT - - -void setup() -{ - Serial.begin(BAUDRATE); - Serial.print("Marlin "); - Serial.println(version_string); - Serial.println("start"); + +char version_string[] = "0.9.3"; + +#ifdef SDSUPPORT +#include "SdFat.h" +#endif //SDSUPPORT + +#ifndef CRITICAL_SECTION_START +#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() +#define CRITICAL_SECTION_END SREG = _sreg +#endif //CRITICAL_SECTION_START + +// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html +// 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 +// G28 - Home all 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 +// 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 +// M115 - Capabilities string +// 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) +// M301 - Set PID parameters P I and D + +//Stepper Movement Variables + +char axis_codes[NUM_AXIS] = { + 'X', 'Y', 'Z', 'E'}; +float destination[NUM_AXIS] = { + 0.0, 0.0, 0.0, 0.0}; +float current_position[NUM_AXIS] = { + 0.0, 0.0, 0.0, 0.0}; +bool home_all_axis = true; +long feedrate = 1500, next_feedrate, saved_feedrate; +long gcode_N, gcode_LastN; +unsigned long previous_millis_heater, previous_millis_bed_heater; +bool relative_mode = false; //Determines Absolute or Relative Coordinates +bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. +unsigned long axis_steps_per_sqr_second[NUM_AXIS]; + +// comm variables +#define MAX_CMD_SIZE 96 +#define BUFSIZE 8 +char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; +bool fromsd[BUFSIZE]; +int bufindr = 0; +int bufindw = 0; +int buflen = 0; +int i = 0; +char serial_char; +int serial_count = 0; +boolean comment_mode = false; +char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc + +// Manage heater variables. + +int target_bed_raw = 0; +int current_bed_raw = 0; + +int target_raw = 0; +int current_raw = 0; +unsigned char temp_meas_ready = false; + +#ifdef PIDTEMP + double temp_iState = 0; + double temp_dState = 0; + double pTerm; + double iTerm; + double dTerm; + //int output; + double pid_error; + double temp_iState_min; + double temp_iState_max; + double pid_setpoint = 0.0; + double pid_input; + double pid_output; + bool pid_reset; +#endif //PIDTEMP +float tt = 0, bt = 0; +#ifdef WATCHPERIOD +int watch_raw = -1000; +unsigned long watchmillis = 0; +#endif //WATCHPERIOD +#ifdef MINTEMP +int minttemp = temp2analog(MINTEMP); +#endif //MINTEMP +#ifdef MAXTEMP +int maxttemp = temp2analog(MAXTEMP); +#endif //MAXTEMP + +//Inactivity shutdown variables +unsigned long previous_millis_cmd = 0; +unsigned long max_inactive_time = 0; +unsigned long stepper_inactive_time = 0; + +#ifdef SDSUPPORT +Sd2Card card; +SdVolume volume; +SdFile root; +SdFile file; +uint32_t filesize = 0; +uint32_t sdpos = 0; +bool sdmode = false; +bool sdactive = false; +bool savetosd = false; +int16_t n; + +void initsd(){ + sdactive = false; +#if SDSS >- 1 + if(root.isOpen()) + root.close(); + if (!card.init(SPI_FULL_SPEED,SDSS)){ + //if (!card.init(SPI_HALF_SPEED,SDSS)) + Serial.println("SD init fail"); + } + else if (!volume.init(&card)) + Serial.println("volume.init failed"); + else if (!root.openRoot(&volume)) + Serial.println("openRoot failed"); + else + sdactive = true; +#endif //SDSS +} + +inline void write_command(char *buf){ + char* begin = buf; + char* npos = 0; + char* end = buf + strlen(buf) - 1; + + file.writeError = false; + if((npos = strchr(buf, 'N')) != NULL){ + begin = strchr(npos, ' ') + 1; + end = strchr(npos, '*') - 1; + } + end[1] = '\r'; + end[2] = '\n'; + end[3] = '\0'; + //Serial.println(begin); + file.write(begin); + if (file.writeError){ + Serial.println("error writing to file"); + } +} +#endif //SDSUPPORT + + +void setup() +{ + Serial.begin(BAUDRATE); + Serial.print("Marlin "); + Serial.println(version_string); + Serial.println("start"); #ifdef FANCY_LCD lcd_init(); #endif - for(int i = 0; i < BUFSIZE; i++){ - fromsd[i] = false; - } - - - //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 -#if E_DIR_PIN > -1 - SET_OUTPUT(E_DIR_PIN); -#endif - - //Initialize Enable Pins - steppers default to disabled. - -#if (X_ENABLE_PIN > -1) - SET_OUTPUT(X_ENABLE_PIN); - if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); -#endif -#if (Y_ENABLE_PIN > -1) - SET_OUTPUT(Y_ENABLE_PIN); - if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); -#endif -#if (Z_ENABLE_PIN > -1) - SET_OUTPUT(Z_ENABLE_PIN); - if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); -#endif -#if (E_ENABLE_PIN > -1) - SET_OUTPUT(E_ENABLE_PIN); - if(!E_ENABLE_ON) WRITE(E_ENABLE_PIN,HIGH); -#endif - - //endstops and pullups -#ifdef ENDSTOPPULLUPS -#if X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); - WRITE(X_MIN_PIN,HIGH); -#endif -#if X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); - WRITE(X_MAX_PIN,HIGH); -#endif -#if Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); - WRITE(Y_MIN_PIN,HIGH); -#endif -#if Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); - WRITE(Y_MAX_PIN,HIGH); -#endif -#if Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); - WRITE(Z_MIN_PIN,HIGH); -#endif -#if Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); - WRITE(Z_MAX_PIN,HIGH); -#endif -#else //ENDSTOPPULLUPS -#if X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); -#endif -#if X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); -#endif -#if Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); -#endif -#if Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); -#endif -#if Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); -#endif -#if Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); -#endif -#endif //ENDSTOPPULLUPS - -#if (HEATER_0_PIN > -1) - SET_OUTPUT(HEATER_0_PIN); -#endif -#if (HEATER_1_PIN > -1) - SET_OUTPUT(HEATER_1_PIN); -#endif - - //Initialize Step Pins -#if (X_STEP_PIN > -1) - SET_OUTPUT(X_STEP_PIN); -#endif -#if (Y_STEP_PIN > -1) - SET_OUTPUT(Y_STEP_PIN); -#endif -#if (Z_STEP_PIN > -1) - SET_OUTPUT(Z_STEP_PIN); -#endif -#if (E_STEP_PIN > -1) - SET_OUTPUT(E_STEP_PIN); -#endif - for(int i=0; i < NUM_AXIS; i++){ - axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; - } - -#ifdef PIDTEMP - temp_iState_min = 0.0; - temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; -#endif //PIDTEMP - -#ifdef SDSUPPORT - //power to SD reader -#if SDPOWER > -1 - SET_OUTPUT(SDPOWER); - WRITE(SDPOWER,HIGH); -#endif //SDPOWER - initsd(); - -#endif //SDSUPPORT - plan_init(); // Initialize planner; - st_init(); // Initialize stepper; -// tp_init(); // Initialize temperature loop -} - - -void loop() -{ - if(buflen<3) - get_command(); - - if(buflen){ -#ifdef SDSUPPORT - if(savetosd){ - if(strstr(cmdbuffer[bufindr],"M29") == NULL){ - write_command(cmdbuffer[bufindr]); - Serial.println("ok"); - } - else{ - file.sync(); - file.close(); - savetosd = false; - Serial.println("Done saving file."); - } - } - else{ - process_commands(); - } -#else - process_commands(); -#endif //SDSUPPORT - buflen = (buflen-1); - bufindr = (bufindr + 1)%BUFSIZE; - } - //check heater every n milliseconds - manage_heater(); - manage_inactivity(1); + for(int i = 0; i < BUFSIZE; i++){ + fromsd[i] = false; + } + + + //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 +#if E_DIR_PIN > -1 + SET_OUTPUT(E_DIR_PIN); +#endif + + //Initialize Enable Pins - steppers default to disabled. + +#if (X_ENABLE_PIN > -1) + SET_OUTPUT(X_ENABLE_PIN); + if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); +#endif +#if (Y_ENABLE_PIN > -1) + SET_OUTPUT(Y_ENABLE_PIN); + if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); +#endif +#if (Z_ENABLE_PIN > -1) + SET_OUTPUT(Z_ENABLE_PIN); + if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); +#endif +#if (E_ENABLE_PIN > -1) + SET_OUTPUT(E_ENABLE_PIN); + if(!E_ENABLE_ON) WRITE(E_ENABLE_PIN,HIGH); +#endif + + //endstops and pullups +#ifdef ENDSTOPPULLUPS +#if X_MIN_PIN > -1 + SET_INPUT(X_MIN_PIN); + WRITE(X_MIN_PIN,HIGH); +#endif +#if X_MAX_PIN > -1 + SET_INPUT(X_MAX_PIN); + WRITE(X_MAX_PIN,HIGH); +#endif +#if Y_MIN_PIN > -1 + SET_INPUT(Y_MIN_PIN); + WRITE(Y_MIN_PIN,HIGH); +#endif +#if Y_MAX_PIN > -1 + SET_INPUT(Y_MAX_PIN); + WRITE(Y_MAX_PIN,HIGH); +#endif +#if Z_MIN_PIN > -1 + SET_INPUT(Z_MIN_PIN); + WRITE(Z_MIN_PIN,HIGH); +#endif +#if Z_MAX_PIN > -1 + SET_INPUT(Z_MAX_PIN); + WRITE(Z_MAX_PIN,HIGH); +#endif +#else //ENDSTOPPULLUPS +#if X_MIN_PIN > -1 + SET_INPUT(X_MIN_PIN); +#endif +#if X_MAX_PIN > -1 + SET_INPUT(X_MAX_PIN); +#endif +#if Y_MIN_PIN > -1 + SET_INPUT(Y_MIN_PIN); +#endif +#if Y_MAX_PIN > -1 + SET_INPUT(Y_MAX_PIN); +#endif +#if Z_MIN_PIN > -1 + SET_INPUT(Z_MIN_PIN); +#endif +#if Z_MAX_PIN > -1 + SET_INPUT(Z_MAX_PIN); +#endif +#endif //ENDSTOPPULLUPS + +#if (HEATER_0_PIN > -1) + SET_OUTPUT(HEATER_0_PIN); +#endif +#if (HEATER_1_PIN > -1) + SET_OUTPUT(HEATER_1_PIN); +#endif + + //Initialize Step Pins +#if (X_STEP_PIN > -1) + SET_OUTPUT(X_STEP_PIN); +#endif +#if (Y_STEP_PIN > -1) + SET_OUTPUT(Y_STEP_PIN); +#endif +#if (Z_STEP_PIN > -1) + SET_OUTPUT(Z_STEP_PIN); +#endif +#if (E_STEP_PIN > -1) + SET_OUTPUT(E_STEP_PIN); +#endif + for(int i=0; i < NUM_AXIS; i++){ + axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; + } + +#ifdef PIDTEMP + temp_iState_min = 0.0; + temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; +#endif //PIDTEMP + +#ifdef SDSUPPORT + //power to SD reader +#if SDPOWER > -1 + SET_OUTPUT(SDPOWER); + WRITE(SDPOWER,HIGH); +#endif //SDPOWER + initsd(); + +#endif //SDSUPPORT + plan_init(); // Initialize planner; + st_init(); // Initialize stepper; +// tp_init(); // Initialize temperature loop +} + + +void loop() +{ + if(buflen<3) + get_command(); + + if(buflen){ +#ifdef SDSUPPORT + if(savetosd){ + if(strstr(cmdbuffer[bufindr],"M29") == NULL){ + write_command(cmdbuffer[bufindr]); + Serial.println("ok"); + } + else{ + file.sync(); + file.close(); + savetosd = false; + Serial.println("Done saving file."); + } + } + else{ + process_commands(); + } +#else + process_commands(); +#endif //SDSUPPORT + buflen = (buflen-1); + bufindr = (bufindr + 1)%BUFSIZE; + } + //check heater every n milliseconds + manage_heater(); + manage_inactivity(1); LCD_STATUS; -} - - -inline void get_command() -{ - while( Serial.available() > 0 && buflen < BUFSIZE) { - serial_char = Serial.read(); - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) - { - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = false; - if(strstr(cmdbuffer[bufindw], "N") != NULL) - { - strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); - gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); - if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { - Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); - Serial.println(gcode_LastN); - //Serial.println(gcode_N); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - if(strstr(cmdbuffer[bufindw], "*") != NULL) - { - byte checksum = 0; - byte count = 0; - while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; - strchr_pointer = strchr(cmdbuffer[bufindw], '*'); - - if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { - Serial.print("Error: checksum mismatch, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - //if no errors, continue parsing - } - else - { - Serial.print("Error: No Checksum with line number, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - gcode_LastN = gcode_N; - //if no errors, continue parsing - } - else // if we don't receive 'N' but still see '*' - { - if((strstr(cmdbuffer[bufindw], "*") != NULL)) - { - Serial.print("Error: No Line Number with checksum, Last Line:"); - Serial.println(gcode_LastN); - serial_count = 0; - return; - } - } - if((strstr(cmdbuffer[bufindw], "G") != NULL)){ - strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); - switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ - case 0: - case 1: -#ifdef SDSUPPORT - if(savetosd) - break; -#endif //SDSUPPORT - Serial.println("ok"); - break; - default: - break; - } - - } - bufindw = (bufindw + 1)%BUFSIZE; - buflen += 1; - - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } - } -#ifdef SDSUPPORT - if(!sdmode || serial_count!=0){ - return; - } - while( filesize > sdpos && buflen < BUFSIZE) { - n = file.read(); - serial_char = (char)n; - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) - { - sdpos = file.curPosition(); - if(sdpos >= filesize){ - sdmode = false; - Serial.println("Done printing file"); - } - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = true; - buflen += 1; - bufindw = (bufindw + 1)%BUFSIZE; - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } - } -#endif //SDSUPPORT - -} - - -inline float code_value() { - return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); -} -inline long code_value_long() { - return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); -} -inline bool code_seen(char code_string[]) { - return (strstr(cmdbuffer[bufindr], code_string) != NULL); -} //Return True if the string was found - -inline bool code_seen(char code) -{ - strchr_pointer = strchr(cmdbuffer[bufindr], code); - return (strchr_pointer != NULL); //Return True if a character was found -} - -inline void process_commands() -{ - unsigned long codenum; //throw away variable - char *starpos = NULL; - - if(code_seen('G')) - { - switch((int)code_value()) - { - case 0: // G0 -> G1 - case 1: // G1 - get_coordinates(); // For X Y Z E F - prepare_move(); - previous_millis_cmd = millis(); - //ClearToSend(); - return; - //break; - case 4: // G4 dwell - codenum = 0; - if(code_seen('P')) codenum = code_value(); // milliseconds to wait - if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait - codenum += millis(); // keep track of when we started waiting - while(millis() < codenum ){ - manage_heater(); - } - break; - case 28: //G28 Home all Axis one at a time - saved_feedrate = feedrate; - for(int i=0; i < NUM_AXIS; i++) { - destination[i] = current_position[i]; - } - feedrate = 0; - - home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); - - if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) { - if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){ - st_synchronize(); - current_position[X_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; - feedrate = homing_feedrate[X_AXIS]; - prepare_move(); - - st_synchronize(); - current_position[X_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = -5 * X_HOME_DIR; - prepare_move(); - - st_synchronize(); - destination[X_AXIS] = 10 * X_HOME_DIR; - feedrate = homing_feedrate[X_AXIS]/2 ; - prepare_move(); - st_synchronize(); - - current_position[X_AXIS] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = current_position[X_AXIS]; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { - if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){ - current_position[Y_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; - feedrate = homing_feedrate[Y_AXIS]; - prepare_move(); - st_synchronize(); - - current_position[Y_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = -5 * Y_HOME_DIR; - prepare_move(); - st_synchronize(); - - destination[Y_AXIS] = 10 * Y_HOME_DIR; - feedrate = homing_feedrate[Y_AXIS]/2; - prepare_move(); - st_synchronize(); - - current_position[Y_AXIS] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = current_position[Y_AXIS]; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { - if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){ - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; - feedrate = homing_feedrate[Z_AXIS]; - prepare_move(); - st_synchronize(); - - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = -2 * Z_HOME_DIR; - prepare_move(); - st_synchronize(); - - destination[Z_AXIS] = 3 * Z_HOME_DIR; - feedrate = homing_feedrate[Z_AXIS]/2; - prepare_move(); - st_synchronize(); - - current_position[Z_AXIS] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = current_position[Z_AXIS]; - feedrate = 0; - } - } - feedrate = saved_feedrate; - previous_millis_cmd = millis(); - break; - case 90: // G90 - relative_mode = false; - break; - case 91: // G91 - relative_mode = true; - break; - case 92: // G92 - if(!code_seen(axis_codes[E_AXIS])) - st_synchronize(); - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) current_position[i] = code_value(); - } - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - break; - - } - } - - else if(code_seen('M')) - { - - switch( (int)code_value() ) - { -#ifdef SDSUPPORT - - case 20: // M20 - list SD card - Serial.println("Begin file list"); - root.ls(); - Serial.println("End file list"); - break; - case 21: // M21 - init SD card - sdmode = false; - initsd(); - break; - case 22: //M22 - release SD card - sdmode = false; - sdactive = false; - break; - case 23: //M23 - Select file - if(sdactive){ - sdmode = false; - file.close(); - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos!=NULL) - *(starpos-1)='\0'; - if (file.open(&root, strchr_pointer + 4, O_READ)) { - Serial.print("File opened:"); - Serial.print(strchr_pointer + 4); - Serial.print(" Size:"); - Serial.println(file.fileSize()); - sdpos = 0; - filesize = file.fileSize(); - Serial.println("File selected"); - } - else{ - Serial.println("file.open failed"); - } - } - break; - case 24: //M24 - Start SD print - if(sdactive){ - sdmode = true; - } - break; - case 25: //M25 - Pause SD print - if(sdmode){ - sdmode = false; - } - break; - case 26: //M26 - Set SD index - if(sdactive && code_seen('S')){ - sdpos = code_value_long(); - file.seekSet(sdpos); - } - break; - case 27: //M27 - Get SD status - if(sdactive){ - Serial.print("SD printing byte "); - Serial.print(sdpos); - Serial.print("/"); - Serial.println(filesize); - } - else{ - Serial.println("Not SD printing"); - } - break; - case 28: //M28 - Start SD write - if(sdactive){ - char* npos = 0; - file.close(); - sdmode = false; - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos != NULL){ - npos = strchr(cmdbuffer[bufindr], 'N'); - strchr_pointer = strchr(npos,' ') + 1; - *(starpos-1) = '\0'; - } - if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) - { - Serial.print("open failed, File: "); - Serial.print(strchr_pointer + 4); - Serial.print("."); - } - else{ - savetosd = true; - Serial.print("Writing to file: "); - Serial.println(strchr_pointer + 4); - } - } - break; - case 29: //M29 - Stop SD write - //processed in write to file routine above - //savetosd = false; - break; -#endif //SDSUPPORT - case 104: // M104 - if (code_seen('S')) target_raw = temp2analog(code_value()); - #ifdef WATCHPERIOD - if(target_raw > current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - }else{ - watchmillis = 0; - } - #endif - break; - case 140: // M140 set bed temp - if (code_seen('S')) target_bed_raw = temp2analogBed(code_value()); - break; - case 105: // M105 - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) - tt = analog2temp(current_raw); - #endif - #if TEMP_1_PIN > -1 - bt = analog2tempBed(current_bed_raw); - #endif - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) - Serial.print("ok T:"); - Serial.print(tt); - Serial.print(", raw:"); - Serial.print(current_raw); - #if TEMP_1_PIN > -1 - Serial.print(" B:"); - Serial.println(bt); - #else - Serial.println(); - #endif - #else - Serial.println("No thermistors - no temp"); - #endif - return; - //break; - case 109: // M109 - Wait for extruder heater to reach target. +} + + +inline void get_command() +{ + while( Serial.available() > 0 && buflen < BUFSIZE) { + serial_char = Serial.read(); + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) + { + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = false; + if(strstr(cmdbuffer[bufindw], "N") != NULL) + { + strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); + gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); + if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { + Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); + Serial.println(gcode_LastN); + //Serial.println(gcode_N); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + if(strstr(cmdbuffer[bufindw], "*") != NULL) + { + byte checksum = 0; + byte count = 0; + while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; + strchr_pointer = strchr(cmdbuffer[bufindw], '*'); + + if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { + Serial.print("Error: checksum mismatch, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + //if no errors, continue parsing + } + else + { + Serial.print("Error: No Checksum with line number, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + gcode_LastN = gcode_N; + //if no errors, continue parsing + } + else // if we don't receive 'N' but still see '*' + { + if((strstr(cmdbuffer[bufindw], "*") != NULL)) + { + Serial.print("Error: No Line Number with checksum, Last Line:"); + Serial.println(gcode_LastN); + serial_count = 0; + return; + } + } + if((strstr(cmdbuffer[bufindw], "G") != NULL)){ + strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); + switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ + case 0: + case 1: +#ifdef SDSUPPORT + if(savetosd) + break; +#endif //SDSUPPORT + Serial.println("ok"); + break; + default: + break; + } + + } + bufindw = (bufindw + 1)%BUFSIZE; + buflen += 1; + + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } + } +#ifdef SDSUPPORT + if(!sdmode || serial_count!=0){ + return; + } + while( filesize > sdpos && buflen < BUFSIZE) { + n = file.read(); + serial_char = (char)n; + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) + { + sdpos = file.curPosition(); + if(sdpos >= filesize){ + sdmode = false; + Serial.println("Done printing file"); + } + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = true; + buflen += 1; + bufindw = (bufindw + 1)%BUFSIZE; + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } + } +#endif //SDSUPPORT + +} + + +inline float code_value() { + return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); +} +inline long code_value_long() { + return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); +} +inline bool code_seen(char code_string[]) { + return (strstr(cmdbuffer[bufindr], code_string) != NULL); +} //Return True if the string was found + +inline bool code_seen(char code) +{ + strchr_pointer = strchr(cmdbuffer[bufindr], code); + return (strchr_pointer != NULL); //Return True if a character was found +} + +inline void process_commands() +{ + unsigned long codenum; //throw away variable + char *starpos = NULL; + + if(code_seen('G')) + { + switch((int)code_value()) + { + case 0: // G0 -> G1 + case 1: // G1 + get_coordinates(); // For X Y Z E F + prepare_move(); + previous_millis_cmd = millis(); + //ClearToSend(); + return; + //break; + case 4: // G4 dwell + codenum = 0; + if(code_seen('P')) codenum = code_value(); // milliseconds to wait + if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait + codenum += millis(); // keep track of when we started waiting + while(millis() < codenum ){ + manage_heater(); + } + break; + case 28: //G28 Home all Axis one at a time + saved_feedrate = feedrate; + for(int i=0; i < NUM_AXIS; i++) { + destination[i] = current_position[i]; + } + feedrate = 0; + + home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); + + if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) { + if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){ + st_synchronize(); + current_position[X_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; + feedrate = homing_feedrate[X_AXIS]; + prepare_move(); + + st_synchronize(); + current_position[X_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = -5 * X_HOME_DIR; + prepare_move(); + + st_synchronize(); + destination[X_AXIS] = 10 * X_HOME_DIR; + feedrate = homing_feedrate[X_AXIS]/2 ; + prepare_move(); + st_synchronize(); + + current_position[X_AXIS] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = current_position[X_AXIS]; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { + if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){ + current_position[Y_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; + feedrate = homing_feedrate[Y_AXIS]; + prepare_move(); + st_synchronize(); + + current_position[Y_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = -5 * Y_HOME_DIR; + prepare_move(); + st_synchronize(); + + destination[Y_AXIS] = 10 * Y_HOME_DIR; + feedrate = homing_feedrate[Y_AXIS]/2; + prepare_move(); + st_synchronize(); + + current_position[Y_AXIS] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = current_position[Y_AXIS]; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { + if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){ + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; + feedrate = homing_feedrate[Z_AXIS]; + prepare_move(); + st_synchronize(); + + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = -2 * Z_HOME_DIR; + prepare_move(); + st_synchronize(); + + destination[Z_AXIS] = 3 * Z_HOME_DIR; + feedrate = homing_feedrate[Z_AXIS]/2; + prepare_move(); + st_synchronize(); + + current_position[Z_AXIS] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = current_position[Z_AXIS]; + feedrate = 0; + } + } + feedrate = saved_feedrate; + previous_millis_cmd = millis(); + break; + case 90: // G90 + relative_mode = false; + break; + case 91: // G91 + relative_mode = true; + break; + case 92: // G92 + if(!code_seen(axis_codes[E_AXIS])) + st_synchronize(); + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) current_position[i] = code_value(); + } + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + break; + + } + } + + else if(code_seen('M')) + { + + switch( (int)code_value() ) + { +#ifdef SDSUPPORT + + case 20: // M20 - list SD card + Serial.println("Begin file list"); + root.ls(); + Serial.println("End file list"); + break; + case 21: // M21 - init SD card + sdmode = false; + initsd(); + break; + case 22: //M22 - release SD card + sdmode = false; + sdactive = false; + break; + case 23: //M23 - Select file + if(sdactive){ + sdmode = false; + file.close(); + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos!=NULL) + *(starpos-1)='\0'; + if (file.open(&root, strchr_pointer + 4, O_READ)) { + Serial.print("File opened:"); + Serial.print(strchr_pointer + 4); + Serial.print(" Size:"); + Serial.println(file.fileSize()); + sdpos = 0; + filesize = file.fileSize(); + Serial.println("File selected"); + } + else{ + Serial.println("file.open failed"); + } + } + break; + case 24: //M24 - Start SD print + if(sdactive){ + sdmode = true; + } + break; + case 25: //M25 - Pause SD print + if(sdmode){ + sdmode = false; + } + break; + case 26: //M26 - Set SD index + if(sdactive && code_seen('S')){ + sdpos = code_value_long(); + file.seekSet(sdpos); + } + break; + case 27: //M27 - Get SD status + if(sdactive){ + Serial.print("SD printing byte "); + Serial.print(sdpos); + Serial.print("/"); + Serial.println(filesize); + } + else{ + Serial.println("Not SD printing"); + } + break; + case 28: //M28 - Start SD write + if(sdactive){ + char* npos = 0; + file.close(); + sdmode = false; + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos != NULL){ + npos = strchr(cmdbuffer[bufindr], 'N'); + strchr_pointer = strchr(npos,' ') + 1; + *(starpos-1) = '\0'; + } + if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) + { + Serial.print("open failed, File: "); + Serial.print(strchr_pointer + 4); + Serial.print("."); + } + else{ + savetosd = true; + Serial.print("Writing to file: "); + Serial.println(strchr_pointer + 4); + } + } + break; + case 29: //M29 - Stop SD write + //processed in write to file routine above + //savetosd = false; + break; +#endif //SDSUPPORT + case 104: // M104 + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw > current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + break; + case 140: // M140 set bed temp + if (code_seen('S')) target_bed_raw = temp2analogBed(code_value()); + break; + case 105: // M105 + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) + tt = analog2temp(current_raw); + #endif + #if TEMP_1_PIN > -1 + bt = analog2tempBed(current_bed_raw); + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) + Serial.print("ok T:"); + Serial.print(tt); + Serial.print(", raw:"); + Serial.print(current_raw); + #if TEMP_1_PIN > -1 + Serial.print(" B:"); + Serial.println(bt); + #else + Serial.println(); + #endif + #else + Serial.println("No thermistors - no temp"); + #endif + return; + //break; + case 109: // M109 - Wait for extruder heater to reach target. LCD_MESSAGE("Heating..."); - if (code_seen('S')) target_raw = temp2analog(code_value()); - #ifdef WATCHPERIOD - if(target_raw>current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - }else{ - watchmillis = 0; - } - #endif - codenum = millis(); - while(current_raw < target_raw) { - if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - Serial.print("T:"); - Serial.println( analog2temp(current_raw) ); + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw>current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + codenum = millis(); + while(current_raw < target_raw) { + if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + Serial.print("T:"); + Serial.println( analog2temp(current_raw) ); LCD_STATUS; - codenum = millis(); - } - manage_heater(); - } - break; - case 190: // M190 - Wait bed for heater to reach target. - #if TEMP_1_PIN > -1 - if (code_seen('S')) target_bed_raw = temp2analog(code_value()); - codenum = millis(); - while(current_bed_raw < target_bed_raw) { - if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - tt=analog2temp(current_raw); - Serial.print("T:"); - Serial.println( tt ); - Serial.print("ok T:"); - Serial.print( tt ); - Serial.print(" B:"); - Serial.println( analog2temp(current_bed_raw) ); - codenum = millis(); - } - manage_heater(); - } - #endif - break; - case 106: //M106 Fan On - if (code_seen('S')){ - digitalWrite(FAN_PIN, HIGH); - analogWrite(FAN_PIN, constrain(code_value(),0,255) ); - } - else - digitalWrite(FAN_PIN, HIGH); - break; - case 107: //M107 Fan Off - analogWrite(FAN_PIN, 0); - - digitalWrite(FAN_PIN, LOW); - break; - - case 82: - axis_relative_modes[3] = false; - break; - case 83: - axis_relative_modes[3] = true; - break; - case 84: - if(code_seen('S')){ - stepper_inactive_time = code_value() * 1000; - } - else{ - st_synchronize(); - disable_x(); - disable_y(); - disable_z(); - disable_e(); - } - break; - case 85: // M85 - code_seen('S'); - max_inactive_time = code_value() * 1000; - break; - case 92: // M92 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); - } - - break; - case 115: // M115 - Serial.println("FIRMWARE_NAME:Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); - break; - case 114: // M114 - Serial.print("X:"); - Serial.print(current_position[X_AXIS]); - Serial.print("Y:"); - Serial.print(current_position[Y_AXIS]); - Serial.print("Z:"); - Serial.print(current_position[Z_AXIS]); - Serial.print("E:"); - Serial.println(current_position[E_AXIS]); - break; - case 119: // M119 -#if (X_MIN_PIN > -1) - Serial.print("x_min:"); - Serial.print((READ(X_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (X_MAX_PIN > -1) - Serial.print("x_max:"); - Serial.print((READ(X_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Y_MIN_PIN > -1) - Serial.print("y_min:"); - Serial.print((READ(Y_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Y_MAX_PIN > -1) - Serial.print("y_max:"); - Serial.print((READ(Y_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Z_MIN_PIN > -1) - Serial.print("z_min:"); - Serial.print((READ(Z_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Z_MAX_PIN > -1) - Serial.print("z_max:"); - Serial.print((READ(Z_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif - Serial.println(""); - break; - //TODO: update for all axis, use for loop - case 201: // M201 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; -#if 0 // Not used for Sprinter/grbl gen6 - case 202: // M202 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; -#endif -#ifdef PIDTEMP - case 301: // M301 - if(code_seen('P')) Kp = code_value(); - if(code_seen('I')) Ki = code_value()*PID_dT; - if(code_seen('D')) Kd = code_value()/PID_dT; - Serial.print("Kp ");Serial.println(Kp); - Serial.print("Ki ");Serial.println(Ki/PID_dT); - Serial.print("Kd ");Serial.println(Kd*PID_dT); - temp_iState_min = 0.0; - temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; - break; -#endif //PIDTEMP - } - } - else{ - Serial.println("Unknown command:"); - Serial.println(cmdbuffer[bufindr]); - } - - ClearToSend(); -} - -void FlushSerialRequestResend() -{ - //char cmdbuffer[bufindr][100]="Resend:"; - Serial.flush(); - Serial.print("Resend:"); - Serial.println(gcode_LastN + 1); - ClearToSend(); -} - -void ClearToSend() -{ - previous_millis_cmd = millis(); -#ifdef SDSUPPORT - if(fromsd[bufindr]) - return; -#endif //SDSUPPORT - Serial.println("ok"); -} - -inline void get_coordinates() -{ - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; - else destination[i] = current_position[i]; //Are these else lines really needed? - } - if(code_seen('F')) { - next_feedrate = code_value(); - if(next_feedrate > 0.0) feedrate = next_feedrate; - } -} - -void prepare_move() -{ - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60.0); - for(int i=0; i < NUM_AXIS; i++) { - current_position[i] = destination[i]; - } -} -/* -void manage_heater() -{ - float pid_input; - float pid_output; - if(temp_meas_ready != true) - return; - -CRITICAL_SECTION_START; - temp_meas_ready = false; -CRITICAL_SECTION_END; - -#ifdef PIDTEMP - pid_input = analog2temp(current_raw); - -#ifndef PID_OPENLOOP - pid_error = pid_setpoint - pid_input; - if(pid_error > 10){ - pid_output = PID_MAX; - pid_reset = true; - } - else if(pid_error < -10) { - pid_output = 0; - pid_reset = true; - } - else { - if(pid_reset == true) { - temp_iState = 0.0; - pid_reset = false; - } - pTerm = Kp * pid_error; - temp_iState += pid_error; - temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = Ki * temp_iState; - #define K1 0.8 - #define K2 (1.0-K1) - dTerm = (Kd * (pid_input - temp_dState))*K2 + (K1 * dTerm); - temp_dState = pid_input; - pid_output = constrain(pTerm + iTerm - dTerm, 0, PID_MAX); - } -#endif //PID_OPENLOOP -#ifdef PID_DEBUG - Serial.print(" Input "); - Serial.print(pid_input); - Serial.print(" Output "); - Serial.print(pid_output); - Serial.print(" pTerm "); - Serial.print(pTerm); - Serial.print(" iTerm "); - Serial.print(iTerm); - Serial.print(" dTerm "); - Serial.print(dTerm); - Serial.println(); -#endif //PID_DEBUG - OCR2B = pid_output; -#endif //PIDTEMP -} -*/ - - -/* -int temp2analogu(int celsius, const short table[][2], int numtemps) { - int raw = 0; - byte i; - - for (i=1; i raw) { - celsius = (float)table[i-1][1] + - (float)(raw - table[i-1][0]) * - (float)(table[i][1] - table[i-1][1]) / - (float)(table[i][0] - table[i-1][0]); - - break; - } - } - // Overflow: Set to last value in the table - if (i == numtemps) celsius = table[i-1][1]; - - return celsius; -} - - -inline void kill() -{ - target_raw=0; -#ifdef PIDTEMP - pid_setpoint = 0.0; -#endif //PIDTEMP - OCR2B = 0; - WRITE(HEATER_0_PIN,LOW); - - disable_x(); - disable_y(); - disable_z(); - disable_e(); - -} -*/ - - - -//#################################################################################################################### -//#################################################################################################################### -void manage_heater() -{ -#ifdef USE_WATCHDOG - wd_reset(); -#endif - //there is no FANCY_LCD here, because this routine is called within moves, and delays them. one could loose steps. - - if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) - return; - previous_millis_heater = millis(); - #ifdef HEATER_USES_THERMISTOR - current_raw = analogRead(TEMP_0_PIN); - // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, - // this switches it up so that the reading appears lower than target for the control logic. - current_raw = 1023 - current_raw; - #elif defined HEATER_USES_AD595 - current_raw = analogRead(TEMP_0_PIN); - #elif defined HEATER_USES_MAX6675 - current_raw = read_max6675(); - #endif - #ifdef SMOOTHING - nma = (nma + current_raw) - (nma / SMOOTHFACTOR); - current_raw = nma / SMOOTHFACTOR; - #endif - #ifdef WATCHPERIOD - if(watchmillis && millis() - watchmillis > WATCHPERIOD){ - if(watch_raw + 1 >= current_raw){ - target_raw = 0; - digitalWrite(HEATER_0_PIN,LOW); - digitalWrite(LED_PIN,LOW); - }else{ - watchmillis = 0; - } - } - #endif - #ifdef MINTEMP - if(current_raw <= minttemp) - target_raw = 0; - #endif - #ifdef MAXTEMP - if(current_raw >= maxttemp) { - target_raw = 0; - } - #endif - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) - #ifdef PIDTEMP - error = target_raw - current_raw; - pTerm = (PID_PGAIN * error) / 100; - temp_iState += error; - temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = (PID_IGAIN * temp_iState) / 100; - dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; - temp_dState = current_raw; - analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); - #else - if(current_raw >= target_raw) - { - digitalWrite(HEATER_0_PIN,LOW); - digitalWrite(LED_PIN,LOW); - } - else - { - digitalWrite(HEATER_0_PIN,HIGH); - digitalWrite(LED_PIN,HIGH); - } - #endif - #endif - - if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) - return; - previous_millis_bed_heater = millis(); - - #ifdef BED_USES_THERMISTOR - - current_bed_raw = analogRead(TEMP_1_PIN); - - // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, - // this switches it up so that the reading appears lower than target for the control logic. - current_bed_raw = 1023 - current_bed_raw; - #elif defined BED_USES_AD595 - current_bed_raw = analogRead(TEMP_1_PIN); - - #endif - - - #if TEMP_1_PIN > -1 - if(current_bed_raw >= target_bed_raw) - { - digitalWrite(HEATER_1_PIN,LOW); - } - else - { - digitalWrite(HEATER_1_PIN,HIGH); - } - #endif -} - -// Takes hot end temperature value as input and returns corresponding raw value. -// For a thermistor, it uses the RepRap thermistor temp table. -// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value. -// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware. -float temp2analog(int celsius) { - #ifdef HEATER_USES_THERMISTOR - int raw = 0; - byte i; - - for (i=1; i raw) - { - celsius = temptable[i-1][1] + - (raw - temptable[i-1][0]) * - (temptable[i][1] - temptable[i-1][1]) / - (temptable[i][0] - temptable[i-1][0]); - - break; - } - } - - // Overflow: Set to last value in the table - if (i == NUMTEMPS) celsius = temptable[i-1][1]; - - return celsius; - #elif defined HEATER_USES_AD595 - return raw * ((5.0 * 100.0) / 1024.0); - #elif defined HEATER_USES_MAX6675 - return raw * 0.25; - #endif -} - -// Derived from RepRap FiveD extruder::getTemperature() -// For bed temperature measurement. -float analog2tempBed(int raw) { - #ifdef BED_USES_THERMISTOR - int celsius = 0; - byte i; - - raw = 1023 - raw; - - for (i=1; i raw) - { - celsius = bedtemptable[i-1][1] + - (raw - bedtemptable[i-1][0]) * - (bedtemptable[i][1] - bedtemptable[i-1][1]) / - (bedtemptable[i][0] - bedtemptable[i-1][0]); - - break; - } - } - - // Overflow: Set to last value in the table - if (i == NUMTEMPS) celsius = bedtemptable[i-1][1]; - - return celsius; - - #elif defined BED_USES_AD595 - return raw * ((5.0 * 100.0) / 1024.0); - #endif -} - -inline void kill() -{ - #if TEMP_0_PIN > -1 - target_raw=0; - digitalWrite(HEATER_0_PIN,LOW); - #endif - #if TEMP_1_PIN > -1 - target_bed_raw=0; - if(HEATER_1_PIN > -1) digitalWrite(HEATER_1_PIN,LOW); - #endif - disable_x(); - disable_y(); - disable_z(); - disable_e(); - - if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); - -} - - - - - - -//####################################################################################################################### - -inline void manage_inactivity(byte debug) { - if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); - if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { - disable_x(); - disable_y(); - disable_z(); - disable_e(); - } - check_axes_activity(); -} - -// Planner - -/* - Reasoning behind the mathematics in this module (in the key of 'Mathematica'): - - s == speed, a == acceleration, t == time, d == distance - - Basic definitions: - - Speed[s_, a_, t_] := s + (a*t) - Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t] - - Distance to reach a specific speed with a constant acceleration: - - Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t] - d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance() - - Speed after a given distance of travel with constant acceleration: - - Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t] - m -> Sqrt[2 a d + s^2] - - DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2] - - When to start braking (di) to reach a specified destionation speed (s2) after accelerating - from initial speed s1 without ever stopping at a plateau: - - Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di] - di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance() - - IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a) - */ - - -// The number of linear motions that can be in the plan at any give time -#define BLOCK_BUFFER_SIZE 16 -#define BLOCK_BUFFER_MASK 0x0f - -static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions -static volatile unsigned char block_buffer_head; // Index of the next block to be pushed -static volatile unsigned char block_buffer_tail; // Index of the block to process now - -// The current position of the tool in absolute steps -static long position[4]; - -#define ONE_MINUTE_OF_MICROSECONDS 60000000.0 - -// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the -// given acceleration: -inline long estimate_acceleration_distance(long initial_rate, long target_rate, long acceleration) { - return( - (target_rate*target_rate-initial_rate*initial_rate)/ - (2L*acceleration) - ); -} - -// This function gives you the point at which you must start braking (at the rate of -acceleration) if -// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after -// a total travel of distance. This can be used to compute the intersection point between acceleration and -// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) - -inline long intersection_distance(long initial_rate, long final_rate, long acceleration, long distance) { - return( - (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ - (4*acceleration) - ); -} - -// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. - -void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { - if(block->busy == true) return; // If block is busy then bail out. - float entry_factor = entry_speed / block->nominal_speed; - float exit_factor = exit_speed / block->nominal_speed; - long initial_rate = ceil(block->nominal_rate*entry_factor); - long final_rate = ceil(block->nominal_rate*exit_factor); - -#ifdef ADVANCE - long initial_advance = block->advance*entry_factor*entry_factor; - long final_advance = block->advance*exit_factor*exit_factor; -#endif // ADVANCE - - // Limit minimal step rate (Otherwise the timer will overflow.) - if(initial_rate <120) initial_rate=120; - if(final_rate < 120) final_rate=120; - - // Calculate the acceleration steps - long acceleration = block->acceleration; - long accelerate_steps = estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration); - long decelerate_steps = estimate_acceleration_distance(final_rate, block->nominal_rate, acceleration); - - // Calculate the size of Plateau of Nominal Rate. - long plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; - - // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will - // have to use intersection_distance() to calculate when to abort acceleration and start braking - // in order to reach the final_rate exactly at the end of this block. - if (plateau_steps < 0) { - accelerate_steps = intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count); - plateau_steps = 0; - } - - long decelerate_after = accelerate_steps+plateau_steps; - long acceleration_rate = (long)((float)acceleration * 8.388608); - - CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section - if(block->busy == false) { // Don't update variables if block is busy. - block->accelerate_until = accelerate_steps; - block->decelerate_after = decelerate_after; - block->acceleration_rate = acceleration_rate; - block->initial_rate = initial_rate; - block->final_rate = final_rate; -#ifdef ADVANCE - block->initial_advance = initial_advance; - block->final_advance = final_advance; -#endif //ADVANCE - } - CRITICAL_SECTION_END; -} - -// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the -// acceleration within the allotted distance. -inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { - return( - sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) - ); -} - -// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks. -// This method will calculate the junction jerk as the euclidean distance between the nominal -// velocities of the respective blocks. -inline float junction_jerk(block_t *before, block_t *after) { - return(sqrt( - pow((before->speed_x-after->speed_x), 2)+ - pow((before->speed_y-after->speed_y), 2)+ - pow((before->speed_z-after->speed_z)*axis_steps_per_unit[Z_AXIS]/axis_steps_per_unit[X_AXIS], 2))); -} - -// Return the safe speed which is max_jerk/2, e.g. the -// speed under which you cannot exceed max_jerk no matter what you do. -float safe_speed(block_t *block) { - float safe_speed; - safe_speed = max_jerk/2; - if (safe_speed > block->nominal_speed) safe_speed = block->nominal_speed; - return safe_speed; -} - -// The kernel called by planner_recalculate() when scanning the plan from last to first entry. -void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) { - if(!current) { - return; - } - - float entry_speed = current->nominal_speed; - float exit_factor; - float exit_speed; - if (next) { - exit_speed = next->entry_speed; - } - else { - exit_speed = safe_speed(current); - } - - // Calculate the entry_factor for the current block. - if (previous) { - // Reduce speed so that junction_jerk is within the maximum allowed - float jerk = junction_jerk(previous, current); - if((previous->steps_x == 0) && (previous->steps_y == 0)) { - entry_speed = safe_speed(current); - } - else if (jerk > max_jerk) { - entry_speed = (max_jerk/jerk) * entry_speed; - } - // If the required deceleration across the block is too rapid, reduce the entry_factor accordingly. - if (entry_speed > exit_speed) { - float max_entry_speed = max_allowable_speed(-acceleration,exit_speed, current->millimeters); - if (max_entry_speed < entry_speed) { - entry_speed = max_entry_speed; - } - } - } - else { - entry_speed = safe_speed(current); - } - // Store result - current->entry_speed = entry_speed; -} - -// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This -// implements the reverse pass. -void planner_reverse_pass() { - char block_index = block_buffer_head; - block_t *block[3] = { - NULL, NULL, NULL }; - while(block_index != block_buffer_tail) { - block_index--; - if(block_index < 0) { - block_index = BLOCK_BUFFER_SIZE-1; - } - block[2]= block[1]; - block[1]= block[0]; - block[0] = &block_buffer[block_index]; - planner_reverse_pass_kernel(block[0], block[1], block[2]); - } - planner_reverse_pass_kernel(NULL, block[0], block[1]); -} - -// The kernel called by planner_recalculate() when scanning the plan from first to last entry. -void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) { - if(!current) { - return; - } - if(previous) { - // If the previous block is an acceleration block, but it is not long enough to - // complete the full speed change within the block, we need to adjust out entry - // speed accordingly. Remember current->entry_factor equals the exit factor of - // the previous block. - if(previous->entry_speed < current->entry_speed) { - float max_entry_speed = max_allowable_speed(-acceleration, previous->entry_speed, previous->millimeters); - if (max_entry_speed < current->entry_speed) { - current->entry_speed = max_entry_speed; - } - } - } -} - -// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This -// implements the forward pass. -void planner_forward_pass() { - char block_index = block_buffer_tail; - block_t *block[3] = { - NULL, NULL, NULL }; - - while(block_index != block_buffer_head) { - block[0] = block[1]; - block[1] = block[2]; - block[2] = &block_buffer[block_index]; - planner_forward_pass_kernel(block[0],block[1],block[2]); - block_index = (block_index+1) & BLOCK_BUFFER_MASK; - } - planner_forward_pass_kernel(block[1], block[2], NULL); -} - -// Recalculates the trapezoid speed profiles for all blocks in the plan according to the -// entry_factor for each junction. Must be called by planner_recalculate() after -// updating the blocks. -void planner_recalculate_trapezoids() { - char block_index = block_buffer_tail; - block_t *current; - block_t *next = NULL; - while(block_index != block_buffer_head) { - current = next; - next = &block_buffer[block_index]; - if (current) { - calculate_trapezoid_for_block(current, current->entry_speed, next->entry_speed); - } - block_index = (block_index+1) & BLOCK_BUFFER_MASK; - } - calculate_trapezoid_for_block(next, next->entry_speed, safe_speed(next)); -} - -// Recalculates the motion plan according to the following algorithm: -// -// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) -// so that: -// a. The junction jerk is within the set limit -// b. No speed reduction within one block requires faster deceleration than the one, true constant -// acceleration. -// 2. Go over every block in chronological order and dial down junction speed reduction values if -// a. The speed increase within one block would require faster accelleration than the one, true -// constant acceleration. -// -// When these stages are complete all blocks have an entry_factor that will allow all speed changes to -// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than -// the set limit. Finally it will: -// -// 3. Recalculate trapezoids for all blocks. - -void planner_recalculate() { - planner_reverse_pass(); - planner_forward_pass(); - planner_recalculate_trapezoids(); -} - -void plan_init() { - block_buffer_head = 0; - block_buffer_tail = 0; - memset(position, 0, sizeof(position)); // clear position -} - - -inline void plan_discard_current_block() { - if (block_buffer_head != block_buffer_tail) { - block_buffer_tail = (block_buffer_tail + 1) & BLOCK_BUFFER_MASK; - } -} - -inline block_t *plan_get_current_block() { - if (block_buffer_head == block_buffer_tail) { - return(NULL); - } - block_t *block = &block_buffer[block_buffer_tail]; - block->busy = true; - return(block); -} - -void check_axes_activity() { - unsigned char x_active = 0; - unsigned char y_active = 0; - unsigned char z_active = 0; - unsigned char e_active = 0; - block_t *block; - - if(block_buffer_tail != block_buffer_head) { - char block_index = block_buffer_tail; - while(block_index != block_buffer_head) { - block = &block_buffer[block_index]; - if(block->steps_x != 0) x_active++; - if(block->steps_y != 0) y_active++; - if(block->steps_z != 0) z_active++; - if(block->steps_e != 0) e_active++; - block_index = (block_index+1) & BLOCK_BUFFER_MASK; - } - } - if((DISABLE_X) && (x_active == 0)) disable_x(); - if((DISABLE_Y) && (y_active == 0)) disable_y(); - if((DISABLE_Z) && (z_active == 0)) disable_z(); - if((DISABLE_E) && (e_active == 0)) disable_e(); -} - -// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in -// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration -// calculation the caller must also provide the physical length of the line in millimeters. -void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { - - // The target position of the tool in absolute steps - // Calculate target position in absolute steps - long target[4]; - target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); - target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); - target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); - target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); - - // Calculate the buffer head after we push this byte - int next_buffer_head = (block_buffer_head + 1) & BLOCK_BUFFER_MASK; - - // If the buffer is full: good! That means we are well ahead of the robot. - // Rest here until there is room in the buffer. - while(block_buffer_tail == next_buffer_head) { - manage_heater(); - manage_inactivity(1); - } - - // Prepare to set up new block - block_t *block = &block_buffer[block_buffer_head]; - - // Mark block as not busy (Not executed by the stepper interrupt) - block->busy = false; - - // Number of steps for each axis - block->steps_x = labs(target[X_AXIS]-position[X_AXIS]); - block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]); - block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); - block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); - block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); - - // Bail if this is a zero-length block - if (block->step_event_count == 0) { - return; - }; - - float delta_x_mm = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; - float delta_y_mm = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; - float delta_z_mm = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; - float delta_e_mm = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS]; - block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); - - unsigned long microseconds; - microseconds = lround((block->millimeters/feed_rate)*1000000); - - // Calculate speed in mm/minute for each axis - float multiplier = 60.0*1000000.0/microseconds; - block->speed_z = delta_z_mm * multiplier; - block->speed_x = delta_x_mm * multiplier; - block->speed_y = delta_y_mm * multiplier; - block->speed_e = delta_e_mm * multiplier; - - // Limit speed per axis - float speed_factor = 1; - float tmp_speed_factor; - if(abs(block->speed_x) > max_feedrate[X_AXIS]) { - speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); - } - if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ - tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ - tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_e) > max_feedrate[E_AXIS]){ - tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - multiplier = multiplier * speed_factor; - block->speed_z = delta_z_mm * multiplier; - block->speed_x = delta_x_mm * multiplier; - block->speed_y = delta_y_mm * multiplier; - block->speed_e = delta_e_mm * multiplier; - block->nominal_speed = block->millimeters * multiplier; - block->nominal_rate = ceil(block->step_event_count * multiplier / 60); - - if(block->nominal_rate < 120) block->nominal_rate = 120; - block->entry_speed = safe_speed(block); - - // Compute the acceleration rate for the trapezoid generator. - float travel_per_step = block->millimeters/block->step_event_count; - if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { - block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 - } - else { - block->acceleration = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 - // Limit acceleration per axis - if((block->acceleration * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) - block->acceleration = axis_steps_per_sqr_second[X_AXIS]; - if((block->acceleration * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) - block->acceleration = axis_steps_per_sqr_second[Y_AXIS]; - if((block->acceleration * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) - block->acceleration = axis_steps_per_sqr_second[E_AXIS]; - if((block->acceleration * block->steps_z / block->step_event_count) > axis_steps_per_sqr_second[Z_AXIS]) - block->acceleration = axis_steps_per_sqr_second[Z_AXIS]; - } - -#ifdef ADVANCE - // Calculate advance rate - if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { - block->advance_rate = 0; - block->advance = 0; - } - else { - long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration); - float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * - (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; - block->advance = advance; - if(acc_dist == 0) { - block->advance_rate = 0; - } - else { - block->advance_rate = advance / (float)acc_dist; - } - } - -#endif // ADVANCE - - // compute a preliminary conservative acceleration trapezoid - float safespeed = safe_speed(block); - calculate_trapezoid_for_block(block, safespeed, safespeed); - - // Compute direction bits for this block - block->direction_bits = 0; - if (target[X_AXIS] < position[X_AXIS]) { - block->direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<steps_x != 0) enable_x(); - if(block->steps_y != 0) enable_y(); - if(block->steps_z != 0) enable_z(); - if(block->steps_e != 0) enable_e(); - - // Move buffer head - block_buffer_head = next_buffer_head; - - // Update position - memcpy(position, target, sizeof(target)); // position[] = target[] - - planner_recalculate(); - st_wake_up(); -} - -void plan_set_position(float x, float y, float z, float e) -{ - position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); - position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); - position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); - position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); -} - -// Stepper - -// intRes = intIn1 * intIn2 >> 16 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 24 bit result -#define MultiU16X8toH16(intRes, charIn1, intIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %A1, %A2 \n\t" \ -"add %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r0 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (charIn1), \ -"d" (intIn2) \ -: \ -"r26" \ -) - -// intRes = longIn1 * longIn2 >> 24 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 48bit result -#define MultiU24X24toH16(intRes, longIn1, longIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"mov r27, r1 \n\t" \ -"mul %B1, %C2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %C1, %C2 \n\t" \ -"add %B0, r0 \n\t" \ -"mul %C1, %B2 \n\t" \ -"add %A0, r0 \n\t" \ -"adc %B0, r1 \n\t" \ -"mul %A1, %C2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %B2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %C1, %A2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %A2 \n\t" \ -"add r27, r1 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r27 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (longIn1), \ -"d" (longIn2) \ -: \ -"r26" , "r27" \ -) - -// Some useful constants - -#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1< -// -// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates -// first block->accelerate_until step_events_completed, then keeps going at constant speed until -// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. -// The slope of acceleration is calculated with the leib ramp alghorithm. - -void st_wake_up() { - // TCNT1 = 0; - ENABLE_STEPPER_DRIVER_INTERRUPT(); -} - -inline unsigned short calc_timer(unsigned short step_rate) { - unsigned short timer; - if(step_rate < 32) step_rate = 32; - step_rate -= 32; // Correct for minimal speed - if(step_rate >= (8*256)){ // higher step rate - unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; - unsigned char tmp_step_rate = (step_rate & 0x00ff); - unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); - MultiU16X8toH16(timer, tmp_step_rate, gain); - timer = (unsigned short)pgm_read_word_near(table_address) - timer; - } - else { // lower step rates - unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; - table_address += ((step_rate)>>1) & 0xfffc; - timer = (unsigned short)pgm_read_word_near(table_address); - timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); - } - if(timer < 100) timer = 100; - return timer; -} - -// Initializes the trapezoid generator from the current block. Called whenever a new -// block begins. -inline void trapezoid_generator_reset() { - accelerate_until = current_block->accelerate_until; - decelerate_after = current_block->decelerate_after; - acceleration_rate = current_block->acceleration_rate; - initial_rate = current_block->initial_rate; - final_rate = current_block->final_rate; - nominal_rate = current_block->nominal_rate; - advance = current_block->initial_advance; - final_advance = current_block->final_advance; - deceleration_time = 0; - advance_rate = current_block->advance_rate; - // step_rate to timer interval - acc_step_rate = initial_rate; - acceleration_time = calc_timer(acc_step_rate); - OCR1A = acceleration_time; -} - -// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. -// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. -ISR(TIMER1_COMPA_vect) -{ - if(busy){ /*Serial.println("BUSY")*/; - return; - } // The busy-flag is used to avoid reentering this interrupt - - busy = true; - sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) - - // If there is no current block, attempt to pop one from the buffer - if (current_block == NULL) { - // Anything in the buffer? - current_block = plan_get_current_block(); - if (current_block != NULL) { - trapezoid_generator_reset(); - counter_x = -(current_block->step_event_count >> 1); - counter_y = counter_x; - counter_z = counter_x; - counter_e = counter_x; - step_events_completed = 0; - e_steps = 0; - } - else { - DISABLE_STEPPER_DRIVER_INTERRUPT(); - } - } - - if (current_block != NULL) { - // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt - out_bits = current_block->direction_bits; - -#ifdef ADVANCE - // Calculate E early. - counter_e += current_block->steps_e; - if (counter_e > 0) { - counter_e -= current_block->step_event_count; - if ((out_bits & (1<> 16) - old_advance); - CRITICAL_SECTION_END; - old_advance = advance >> 16; -#endif //ADVANCE - - // Set direction en check limit switches - if ((out_bits & (1<step_event_count; - } - } - else { // +direction - WRITE(X_DIR_PIN,!INVERT_X_DIR); - if(READ(X_MAX_PIN) != ENDSTOPS_INVERTING){ - step_events_completed = current_block->step_event_count; - } - } - - if ((out_bits & (1<step_event_count; - } - } - else { // +direction - WRITE(Y_DIR_PIN,!INVERT_Y_DIR); - if(READ(Y_MAX_PIN) != ENDSTOPS_INVERTING){ - step_events_completed = current_block->step_event_count; - } - } - - if ((out_bits & (1<step_event_count; - } - } - else { // +direction - WRITE(Z_DIR_PIN,!INVERT_Z_DIR); - if(READ(Z_MAX_PIN) != ENDSTOPS_INVERTING){ - step_events_completed = current_block->step_event_count; - } - } - -#ifndef ADVANCE - if ((out_bits & (1<steps_x; - if (counter_x > 0) { - WRITE(X_STEP_PIN, HIGH); - counter_x -= current_block->step_event_count; - WRITE(X_STEP_PIN, LOW); - } - - counter_y += current_block->steps_y; - if (counter_y > 0) { - WRITE(Y_STEP_PIN, HIGH); - counter_y -= current_block->step_event_count; - WRITE(Y_STEP_PIN, LOW); - } - - counter_z += current_block->steps_z; - if (counter_z > 0) { - WRITE(Z_STEP_PIN, HIGH); - counter_z -= current_block->step_event_count; - WRITE(Z_STEP_PIN, LOW); - } - -#ifndef ADVANCE - counter_e += current_block->steps_e; - if (counter_e > 0) { - WRITE(E_STEP_PIN, HIGH); - counter_e -= current_block->step_event_count; - WRITE(E_STEP_PIN, LOW); - } -#endif //!ADVANCE - - // Calculare new timer value - unsigned short timer; - unsigned short step_rate; - if (step_events_completed < accelerate_until) { - MultiU24X24toH16(acc_step_rate, acceleration_time, acceleration_rate); - acc_step_rate += initial_rate; - - // upper limit - if(acc_step_rate > nominal_rate) - acc_step_rate = nominal_rate; - - // step_rate to timer interval - timer = calc_timer(acc_step_rate); - advance += advance_rate; - acceleration_time += timer; - OCR1A = timer; - } - else if (step_events_completed >= decelerate_after) { - MultiU24X24toH16(step_rate, deceleration_time, acceleration_rate); - - if(step_rate > acc_step_rate) { // Check step_rate stays positive - step_rate = final_rate; - } - else { - step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. - } - - // lower limit - if(step_rate < final_rate) - step_rate = final_rate; - - // step_rate to timer interval - timer = calc_timer(step_rate); -#ifdef ADVANCE - advance -= advance_rate; - if(advance < final_advance) - advance = final_advance; -#endif //ADVANCE - deceleration_time += timer; - OCR1A = timer; - } - // If current block is finished, reset pointer - step_events_completed += 1; - if (step_events_completed >= current_block->step_event_count) { - current_block = NULL; - plan_discard_current_block(); - } - } - busy=false; -} - -#ifdef ADVANCE - -unsigned char old_OCR0A; -// Timer interrupt for E. e_steps is set in the main routine; -// Timer 0 is shared with millies -ISR(TIMER0_COMPA_vect) -{ - // Critical section needed because Timer 1 interrupt has higher priority. - // The pin set functions are placed on trategic position to comply with the stepper driver timing. - WRITE(E_STEP_PIN, LOW); - // Set E direction (Depends on E direction + advance) - if (e_steps < 0) { - WRITE(E_DIR_PIN,INVERT_E_DIR); - e_steps++; - WRITE(E_STEP_PIN, HIGH); - } - if (e_steps > 0) { - WRITE(E_DIR_PIN,!INVERT_E_DIR); - e_steps--; - WRITE(E_STEP_PIN, HIGH); - } - old_OCR0A += 25; // 10kHz interrupt - OCR0A = old_OCR0A; -} -#endif // ADVANCE - -void st_init() -{ - // waveform generation = 0100 = CTC - TCCR1B &= ~(1<= 16) - { - current_raw = 16383 - raw_temp_value; - temp_meas_ready = true; - temp_count = 0; - raw_temp_value = 0; -#ifdef MAXTEMP - if(current_raw >= maxttemp) { - target_raw = 0; -#ifdef PIDTEMP - OCR2B = 0; -#else - WRITE(HEATER_0_PIN,LOW); -#endif //PIDTEMP - } -#endif //MAXTEMP -#ifdef MINTEMP - if(current_raw <= minttemp) { - target_raw = 0; -#ifdef PIDTEMP - OCR2B = 0; -#else - WRITE(HEATER_0_PIN,LOW); -#endif //PIDTEMP - } -#endif //MAXTEMP -#ifndef PIDTEMP - if(current_raw >= target_raw) - { - WRITE(HEATER_0_PIN,LOW); - } - else - { - WRITE(HEATER_0_PIN,HIGH); - } -#endif //PIDTEMP - } -} - + codenum = millis(); + } + manage_heater(); + } + break; + case 190: // M190 - Wait bed for heater to reach target. + #if TEMP_1_PIN > -1 + if (code_seen('S')) target_bed_raw = temp2analog(code_value()); + codenum = millis(); + while(current_bed_raw < target_bed_raw) { + if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + tt=analog2temp(current_raw); + Serial.print("T:"); + Serial.println( tt ); + Serial.print("ok T:"); + Serial.print( tt ); + Serial.print(" B:"); + Serial.println( analog2temp(current_bed_raw) ); + codenum = millis(); + } + manage_heater(); + } + #endif + break; + case 106: //M106 Fan On + if (code_seen('S')){ + digitalWrite(FAN_PIN, HIGH); + analogWrite(FAN_PIN, constrain(code_value(),0,255) ); + } + else + digitalWrite(FAN_PIN, HIGH); + break; + case 107: //M107 Fan Off + analogWrite(FAN_PIN, 0); + + digitalWrite(FAN_PIN, LOW); + break; + + case 82: + axis_relative_modes[3] = false; + break; + case 83: + axis_relative_modes[3] = true; + break; + case 84: + if(code_seen('S')){ + stepper_inactive_time = code_value() * 1000; + } + else{ + st_synchronize(); + disable_x(); + disable_y(); + disable_z(); + disable_e(); + } + break; + case 85: // M85 + code_seen('S'); + max_inactive_time = code_value() * 1000; + break; + case 92: // M92 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); + } + + break; + case 115: // M115 + Serial.println("FIRMWARE_NAME:Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); + break; + case 114: // M114 + Serial.print("X:"); + Serial.print(current_position[X_AXIS]); + Serial.print("Y:"); + Serial.print(current_position[Y_AXIS]); + Serial.print("Z:"); + Serial.print(current_position[Z_AXIS]); + Serial.print("E:"); + Serial.println(current_position[E_AXIS]); + break; + case 119: // M119 +#if (X_MIN_PIN > -1) + Serial.print("x_min:"); + Serial.print((READ(X_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (X_MAX_PIN > -1) + Serial.print("x_max:"); + Serial.print((READ(X_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Y_MIN_PIN > -1) + Serial.print("y_min:"); + Serial.print((READ(Y_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Y_MAX_PIN > -1) + Serial.print("y_max:"); + Serial.print((READ(Y_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Z_MIN_PIN > -1) + Serial.print("z_min:"); + Serial.print((READ(Z_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Z_MAX_PIN > -1) + Serial.print("z_max:"); + Serial.print((READ(Z_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif + Serial.println(""); + break; + //TODO: update for all axis, use for loop + case 201: // M201 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; +#if 0 // Not used for Sprinter/grbl gen6 + case 202: // M202 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; +#endif +#ifdef PIDTEMP + case 301: // M301 + if(code_seen('P')) Kp = code_value(); + if(code_seen('I')) Ki = code_value()*PID_dT; + if(code_seen('D')) Kd = code_value()/PID_dT; + Serial.print("Kp ");Serial.println(Kp); + Serial.print("Ki ");Serial.println(Ki/PID_dT); + Serial.print("Kd ");Serial.println(Kd*PID_dT); + temp_iState_min = 0.0; + temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; + break; +#endif //PIDTEMP + } + } + else{ + Serial.println("Unknown command:"); + Serial.println(cmdbuffer[bufindr]); + } + + ClearToSend(); +} + +void FlushSerialRequestResend() +{ + //char cmdbuffer[bufindr][100]="Resend:"; + Serial.flush(); + Serial.print("Resend:"); + Serial.println(gcode_LastN + 1); + ClearToSend(); +} + +void ClearToSend() +{ + previous_millis_cmd = millis(); +#ifdef SDSUPPORT + if(fromsd[bufindr]) + return; +#endif //SDSUPPORT + Serial.println("ok"); +} + +inline void get_coordinates() +{ + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; + else destination[i] = current_position[i]; //Are these else lines really needed? + } + if(code_seen('F')) { + next_feedrate = code_value(); + if(next_feedrate > 0.0) feedrate = next_feedrate; + } +} + +void prepare_move() +{ + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60.0); + for(int i=0; i < NUM_AXIS; i++) { + current_position[i] = destination[i]; + } +} +/* +void manage_heater() +{ + float pid_input; + float pid_output; + if(temp_meas_ready != true) + return; + +CRITICAL_SECTION_START; + temp_meas_ready = false; +CRITICAL_SECTION_END; + +#ifdef PIDTEMP + pid_input = analog2temp(current_raw); + +#ifndef PID_OPENLOOP + pid_error = pid_setpoint - pid_input; + if(pid_error > 10){ + pid_output = PID_MAX; + pid_reset = true; + } + else if(pid_error < -10) { + pid_output = 0; + pid_reset = true; + } + else { + if(pid_reset == true) { + temp_iState = 0.0; + pid_reset = false; + } + pTerm = Kp * pid_error; + temp_iState += pid_error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = Ki * temp_iState; + #define K1 0.8 + #define K2 (1.0-K1) + dTerm = (Kd * (pid_input - temp_dState))*K2 + (K1 * dTerm); + temp_dState = pid_input; + pid_output = constrain(pTerm + iTerm - dTerm, 0, PID_MAX); + } +#endif //PID_OPENLOOP +#ifdef PID_DEBUG + Serial.print(" Input "); + Serial.print(pid_input); + Serial.print(" Output "); + Serial.print(pid_output); + Serial.print(" pTerm "); + Serial.print(pTerm); + Serial.print(" iTerm "); + Serial.print(iTerm); + Serial.print(" dTerm "); + Serial.print(dTerm); + Serial.println(); +#endif //PID_DEBUG + OCR2B = pid_output; +#endif //PIDTEMP +} +*/ + + +/* +int temp2analogu(int celsius, const short table[][2], int numtemps) { + int raw = 0; + byte i; + + for (i=1; i raw) { + celsius = (float)table[i-1][1] + + (float)(raw - table[i-1][0]) * + (float)(table[i][1] - table[i-1][1]) / + (float)(table[i][0] - table[i-1][0]); + + break; + } + } + // Overflow: Set to last value in the table + if (i == numtemps) celsius = table[i-1][1]; + + return celsius; +} + + +inline void kill() +{ + target_raw=0; +#ifdef PIDTEMP + pid_setpoint = 0.0; +#endif //PIDTEMP + OCR2B = 0; + WRITE(HEATER_0_PIN,LOW); + + disable_x(); + disable_y(); + disable_z(); + disable_e(); + +} +*/ + + + +//#################################################################################################################### +//#################################################################################################################### +void manage_heater() +{ +#ifdef USE_WATCHDOG + wd_reset(); +#endif + //there is no FANCY_LCD here, because this routine is called within moves, and delays them. one could loose steps. + + if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) + return; + previous_millis_heater = millis(); + #ifdef HEATER_USES_THERMISTOR + current_raw = analogRead(TEMP_0_PIN); + // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_raw = 1023 - current_raw; + #elif defined HEATER_USES_AD595 + current_raw = analogRead(TEMP_0_PIN); + #elif defined HEATER_USES_MAX6675 + current_raw = read_max6675(); + #endif + #ifdef SMOOTHING + nma = (nma + current_raw) - (nma / SMOOTHFACTOR); + current_raw = nma / SMOOTHFACTOR; + #endif + #ifdef WATCHPERIOD + if(watchmillis && millis() - watchmillis > WATCHPERIOD){ + if(watch_raw + 1 >= current_raw){ + target_raw = 0; + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + }else{ + watchmillis = 0; + } + } + #endif + #ifdef MINTEMP + if(current_raw <= minttemp) + target_raw = 0; + #endif + #ifdef MAXTEMP + if(current_raw >= maxttemp) { + target_raw = 0; + } + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) + #ifdef PIDTEMP + error = target_raw - current_raw; + pTerm = (PID_PGAIN * error) / 100; + temp_iState += error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = (PID_IGAIN * temp_iState) / 100; + dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; + temp_dState = current_raw; + analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); + #else + if(current_raw >= target_raw) + { + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + } + else + { + digitalWrite(HEATER_0_PIN,HIGH); + digitalWrite(LED_PIN,HIGH); + } + #endif + #endif + + if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) + return; + previous_millis_bed_heater = millis(); + + #ifdef BED_USES_THERMISTOR + + current_bed_raw = analogRead(TEMP_1_PIN); + + // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_bed_raw = 1023 - current_bed_raw; + #elif defined BED_USES_AD595 + current_bed_raw = analogRead(TEMP_1_PIN); + + #endif + + + #if TEMP_1_PIN > -1 + if(current_bed_raw >= target_bed_raw) + { + digitalWrite(HEATER_1_PIN,LOW); + } + else + { + digitalWrite(HEATER_1_PIN,HIGH); + } + #endif +} + +// Takes hot end temperature value as input and returns corresponding raw value. +// For a thermistor, it uses the RepRap thermistor temp table. +// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value. +// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware. +float temp2analog(int celsius) { + #ifdef HEATER_USES_THERMISTOR + int raw = 0; + byte i; + + for (i=1; i raw) + { + celsius = temptable[i-1][1] + + (raw - temptable[i-1][0]) * + (temptable[i][1] - temptable[i-1][1]) / + (temptable[i][0] - temptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = temptable[i-1][1]; + + return celsius; + #elif defined HEATER_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #elif defined HEATER_USES_MAX6675 + return raw * 0.25; + #endif +} + +// Derived from RepRap FiveD extruder::getTemperature() +// For bed temperature measurement. +float analog2tempBed(int raw) { + #ifdef BED_USES_THERMISTOR + int celsius = 0; + byte i; + + raw = 1023 - raw; + + for (i=1; i raw) + { + celsius = bedtemptable[i-1][1] + + (raw - bedtemptable[i-1][0]) * + (bedtemptable[i][1] - bedtemptable[i-1][1]) / + (bedtemptable[i][0] - bedtemptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = bedtemptable[i-1][1]; + + return celsius; + + #elif defined BED_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #endif +} + +inline void kill() +{ + #if TEMP_0_PIN > -1 + target_raw=0; + digitalWrite(HEATER_0_PIN,LOW); + #endif + #if TEMP_1_PIN > -1 + target_bed_raw=0; + if(HEATER_1_PIN > -1) digitalWrite(HEATER_1_PIN,LOW); + #endif + disable_x(); + disable_y(); + disable_z(); + disable_e(); + + if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); + +} + + + + + + +//####################################################################################################################### + +inline void manage_inactivity(byte debug) { + if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); + if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { + disable_x(); + disable_y(); + disable_z(); + disable_e(); + } + check_axes_activity(); +} + +// Planner + +/* + Reasoning behind the mathematics in this module (in the key of 'Mathematica'): + + s == speed, a == acceleration, t == time, d == distance + + Basic definitions: + + Speed[s_, a_, t_] := s + (a*t) + Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t] + + Distance to reach a specific speed with a constant acceleration: + + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t] + d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance() + + Speed after a given distance of travel with constant acceleration: + + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t] + m -> Sqrt[2 a d + s^2] + + DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2] + + When to start braking (di) to reach a specified destionation speed (s2) after accelerating + from initial speed s1 without ever stopping at a plateau: + + Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di] + di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance() + + IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a) + */ + + +// The number of linear motions that can be in the plan at any give time +#define BLOCK_BUFFER_SIZE 16 +#define BLOCK_BUFFER_MASK 0x0f + +static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions +static volatile unsigned char block_buffer_head; // Index of the next block to be pushed +static volatile unsigned char block_buffer_tail; // Index of the block to process now + +// The current position of the tool in absolute steps +static long position[4]; + +#define ONE_MINUTE_OF_MICROSECONDS 60000000.0 + +// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the +// given acceleration: +inline long estimate_acceleration_distance(long initial_rate, long target_rate, long acceleration) { + return( + (target_rate*target_rate-initial_rate*initial_rate)/ + (2L*acceleration) + ); +} + +// This function gives you the point at which you must start braking (at the rate of -acceleration) if +// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after +// a total travel of distance. This can be used to compute the intersection point between acceleration and +// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) + +inline long intersection_distance(long initial_rate, long final_rate, long acceleration, long distance) { + return( + (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ + (4*acceleration) + ); +} + +// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. + +void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { + if(block->busy == true) return; // If block is busy then bail out. + float entry_factor = entry_speed / block->nominal_speed; + float exit_factor = exit_speed / block->nominal_speed; + long initial_rate = ceil(block->nominal_rate*entry_factor); + long final_rate = ceil(block->nominal_rate*exit_factor); + +#ifdef ADVANCE + long initial_advance = block->advance*entry_factor*entry_factor; + long final_advance = block->advance*exit_factor*exit_factor; +#endif // ADVANCE + + // Limit minimal step rate (Otherwise the timer will overflow.) + if(initial_rate <120) initial_rate=120; + if(final_rate < 120) final_rate=120; + + // Calculate the acceleration steps + long acceleration = block->acceleration; + long accelerate_steps = estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration); + long decelerate_steps = estimate_acceleration_distance(final_rate, block->nominal_rate, acceleration); + + // Calculate the size of Plateau of Nominal Rate. + long plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; + + // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will + // have to use intersection_distance() to calculate when to abort acceleration and start braking + // in order to reach the final_rate exactly at the end of this block. + if (plateau_steps < 0) { + accelerate_steps = intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count); + plateau_steps = 0; + } + + long decelerate_after = accelerate_steps+plateau_steps; + long acceleration_rate = (long)((float)acceleration * 8.388608); + + CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section + if(block->busy == false) { // Don't update variables if block is busy. + block->accelerate_until = accelerate_steps; + block->decelerate_after = decelerate_after; + block->acceleration_rate = acceleration_rate; + block->initial_rate = initial_rate; + block->final_rate = final_rate; +#ifdef ADVANCE + block->initial_advance = initial_advance; + block->final_advance = final_advance; +#endif //ADVANCE + } + CRITICAL_SECTION_END; +} + +// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the +// acceleration within the allotted distance. +inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { + return( + sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) + ); +} + +// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks. +// This method will calculate the junction jerk as the euclidean distance between the nominal +// velocities of the respective blocks. +inline float junction_jerk(block_t *before, block_t *after) { + return(sqrt( + pow((before->speed_x-after->speed_x), 2)+ + pow((before->speed_y-after->speed_y), 2)+ + pow((before->speed_z-after->speed_z)*axis_steps_per_unit[Z_AXIS]/axis_steps_per_unit[X_AXIS], 2))); +} + +// Return the safe speed which is max_jerk/2, e.g. the +// speed under which you cannot exceed max_jerk no matter what you do. +float safe_speed(block_t *block) { + float safe_speed; + safe_speed = max_jerk/2; + if (safe_speed > block->nominal_speed) safe_speed = block->nominal_speed; + return safe_speed; +} + +// The kernel called by planner_recalculate() when scanning the plan from last to first entry. +void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) { + if(!current) { + return; + } + + float entry_speed = current->nominal_speed; + float exit_factor; + float exit_speed; + if (next) { + exit_speed = next->entry_speed; + } + else { + exit_speed = safe_speed(current); + } + + // Calculate the entry_factor for the current block. + if (previous) { + // Reduce speed so that junction_jerk is within the maximum allowed + float jerk = junction_jerk(previous, current); + if((previous->steps_x == 0) && (previous->steps_y == 0)) { + entry_speed = safe_speed(current); + } + else if (jerk > max_jerk) { + entry_speed = (max_jerk/jerk) * entry_speed; + } + // If the required deceleration across the block is too rapid, reduce the entry_factor accordingly. + if (entry_speed > exit_speed) { + float max_entry_speed = max_allowable_speed(-acceleration,exit_speed, current->millimeters); + if (max_entry_speed < entry_speed) { + entry_speed = max_entry_speed; + } + } + } + else { + entry_speed = safe_speed(current); + } + // Store result + current->entry_speed = entry_speed; +} + +// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This +// implements the reverse pass. +void planner_reverse_pass() { + char block_index = block_buffer_head; + block_t *block[3] = { + NULL, NULL, NULL }; + while(block_index != block_buffer_tail) { + block_index--; + if(block_index < 0) { + block_index = BLOCK_BUFFER_SIZE-1; + } + block[2]= block[1]; + block[1]= block[0]; + block[0] = &block_buffer[block_index]; + planner_reverse_pass_kernel(block[0], block[1], block[2]); + } + planner_reverse_pass_kernel(NULL, block[0], block[1]); +} + +// The kernel called by planner_recalculate() when scanning the plan from first to last entry. +void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) { + if(!current) { + return; + } + if(previous) { + // If the previous block is an acceleration block, but it is not long enough to + // complete the full speed change within the block, we need to adjust out entry + // speed accordingly. Remember current->entry_factor equals the exit factor of + // the previous block. + if(previous->entry_speed < current->entry_speed) { + float max_entry_speed = max_allowable_speed(-acceleration, previous->entry_speed, previous->millimeters); + if (max_entry_speed < current->entry_speed) { + current->entry_speed = max_entry_speed; + } + } + } +} + +// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This +// implements the forward pass. +void planner_forward_pass() { + char block_index = block_buffer_tail; + block_t *block[3] = { + NULL, NULL, NULL }; + + while(block_index != block_buffer_head) { + block[0] = block[1]; + block[1] = block[2]; + block[2] = &block_buffer[block_index]; + planner_forward_pass_kernel(block[0],block[1],block[2]); + block_index = (block_index+1) & BLOCK_BUFFER_MASK; + } + planner_forward_pass_kernel(block[1], block[2], NULL); +} + +// Recalculates the trapezoid speed profiles for all blocks in the plan according to the +// entry_factor for each junction. Must be called by planner_recalculate() after +// updating the blocks. +void planner_recalculate_trapezoids() { + char block_index = block_buffer_tail; + block_t *current; + block_t *next = NULL; + while(block_index != block_buffer_head) { + current = next; + next = &block_buffer[block_index]; + if (current) { + calculate_trapezoid_for_block(current, current->entry_speed, next->entry_speed); + } + block_index = (block_index+1) & BLOCK_BUFFER_MASK; + } + calculate_trapezoid_for_block(next, next->entry_speed, safe_speed(next)); +} + +// Recalculates the motion plan according to the following algorithm: +// +// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) +// so that: +// a. The junction jerk is within the set limit +// b. No speed reduction within one block requires faster deceleration than the one, true constant +// acceleration. +// 2. Go over every block in chronological order and dial down junction speed reduction values if +// a. The speed increase within one block would require faster accelleration than the one, true +// constant acceleration. +// +// When these stages are complete all blocks have an entry_factor that will allow all speed changes to +// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than +// the set limit. Finally it will: +// +// 3. Recalculate trapezoids for all blocks. + +void planner_recalculate() { + planner_reverse_pass(); + planner_forward_pass(); + planner_recalculate_trapezoids(); +} + +void plan_init() { + block_buffer_head = 0; + block_buffer_tail = 0; + memset(position, 0, sizeof(position)); // clear position +} + + +inline void plan_discard_current_block() { + if (block_buffer_head != block_buffer_tail) { + block_buffer_tail = (block_buffer_tail + 1) & BLOCK_BUFFER_MASK; + } +} + +inline block_t *plan_get_current_block() { + if (block_buffer_head == block_buffer_tail) { + return(NULL); + } + block_t *block = &block_buffer[block_buffer_tail]; + block->busy = true; + return(block); +} + +void check_axes_activity() { + unsigned char x_active = 0; + unsigned char y_active = 0; + unsigned char z_active = 0; + unsigned char e_active = 0; + block_t *block; + + if(block_buffer_tail != block_buffer_head) { + char block_index = block_buffer_tail; + while(block_index != block_buffer_head) { + block = &block_buffer[block_index]; + if(block->steps_x != 0) x_active++; + if(block->steps_y != 0) y_active++; + if(block->steps_z != 0) z_active++; + if(block->steps_e != 0) e_active++; + block_index = (block_index+1) & BLOCK_BUFFER_MASK; + } + } + if((DISABLE_X) && (x_active == 0)) disable_x(); + if((DISABLE_Y) && (y_active == 0)) disable_y(); + if((DISABLE_Z) && (z_active == 0)) disable_z(); + if((DISABLE_E) && (e_active == 0)) disable_e(); +} + +// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in +// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration +// calculation the caller must also provide the physical length of the line in millimeters. +void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { + + // The target position of the tool in absolute steps + // Calculate target position in absolute steps + long target[4]; + target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); + target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); + target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); + target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); + + // Calculate the buffer head after we push this byte + int next_buffer_head = (block_buffer_head + 1) & BLOCK_BUFFER_MASK; + + // If the buffer is full: good! That means we are well ahead of the robot. + // Rest here until there is room in the buffer. + while(block_buffer_tail == next_buffer_head) { + manage_heater(); + manage_inactivity(1); + } + + // Prepare to set up new block + block_t *block = &block_buffer[block_buffer_head]; + + // Mark block as not busy (Not executed by the stepper interrupt) + block->busy = false; + + // Number of steps for each axis + block->steps_x = labs(target[X_AXIS]-position[X_AXIS]); + block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]); + block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); + block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); + block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); + + // Bail if this is a zero-length block + if (block->step_event_count == 0) { + return; + }; + + float delta_x_mm = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; + float delta_y_mm = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; + float delta_z_mm = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; + float delta_e_mm = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS]; + block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); + + unsigned long microseconds; + microseconds = lround((block->millimeters/feed_rate)*1000000); + + // Calculate speed in mm/minute for each axis + float multiplier = 60.0*1000000.0/microseconds; + block->speed_z = delta_z_mm * multiplier; + block->speed_x = delta_x_mm * multiplier; + block->speed_y = delta_y_mm * multiplier; + block->speed_e = delta_e_mm * multiplier; + + // Limit speed per axis + float speed_factor = 1; + float tmp_speed_factor; + if(abs(block->speed_x) > max_feedrate[X_AXIS]) { + speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + } + if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ + tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ + tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_e) > max_feedrate[E_AXIS]){ + tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + multiplier = multiplier * speed_factor; + block->speed_z = delta_z_mm * multiplier; + block->speed_x = delta_x_mm * multiplier; + block->speed_y = delta_y_mm * multiplier; + block->speed_e = delta_e_mm * multiplier; + block->nominal_speed = block->millimeters * multiplier; + block->nominal_rate = ceil(block->step_event_count * multiplier / 60); + + if(block->nominal_rate < 120) block->nominal_rate = 120; + block->entry_speed = safe_speed(block); + + // Compute the acceleration rate for the trapezoid generator. + float travel_per_step = block->millimeters/block->step_event_count; + if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { + block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + } + else { + block->acceleration = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + // Limit acceleration per axis + if((block->acceleration * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) + block->acceleration = axis_steps_per_sqr_second[X_AXIS]; + if((block->acceleration * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) + block->acceleration = axis_steps_per_sqr_second[Y_AXIS]; + if((block->acceleration * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) + block->acceleration = axis_steps_per_sqr_second[E_AXIS]; + if((block->acceleration * block->steps_z / block->step_event_count) > axis_steps_per_sqr_second[Z_AXIS]) + block->acceleration = axis_steps_per_sqr_second[Z_AXIS]; + } + +#ifdef ADVANCE + // Calculate advance rate + if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { + block->advance_rate = 0; + block->advance = 0; + } + else { + long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration); + float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * + (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; + block->advance = advance; + if(acc_dist == 0) { + block->advance_rate = 0; + } + else { + block->advance_rate = advance / (float)acc_dist; + } + } + +#endif // ADVANCE + + // compute a preliminary conservative acceleration trapezoid + float safespeed = safe_speed(block); + calculate_trapezoid_for_block(block, safespeed, safespeed); + + // Compute direction bits for this block + block->direction_bits = 0; + if (target[X_AXIS] < position[X_AXIS]) { + block->direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<steps_x != 0) enable_x(); + if(block->steps_y != 0) enable_y(); + if(block->steps_z != 0) enable_z(); + if(block->steps_e != 0) enable_e(); + + // Move buffer head + block_buffer_head = next_buffer_head; + + // Update position + memcpy(position, target, sizeof(target)); // position[] = target[] + + planner_recalculate(); + st_wake_up(); +} + +void plan_set_position(float x, float y, float z, float e) +{ + position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); + position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); + position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); + position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); +} + +// Stepper + +// intRes = intIn1 * intIn2 >> 16 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 24 bit result +#define MultiU16X8toH16(intRes, charIn1, intIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %A1, %A2 \n\t" \ +"add %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r0 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (charIn1), \ +"d" (intIn2) \ +: \ +"r26" \ +) + +// intRes = longIn1 * longIn2 >> 24 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 48bit result +#define MultiU24X24toH16(intRes, longIn1, longIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"mov r27, r1 \n\t" \ +"mul %B1, %C2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %C1, %C2 \n\t" \ +"add %B0, r0 \n\t" \ +"mul %C1, %B2 \n\t" \ +"add %A0, r0 \n\t" \ +"adc %B0, r1 \n\t" \ +"mul %A1, %C2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %B2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %C1, %A2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %A2 \n\t" \ +"add r27, r1 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r27 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (longIn1), \ +"d" (longIn2) \ +: \ +"r26" , "r27" \ +) + +// Some useful constants + +#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1< +// +// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates +// first block->accelerate_until step_events_completed, then keeps going at constant speed until +// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. +// The slope of acceleration is calculated with the leib ramp alghorithm. + +void st_wake_up() { + // TCNT1 = 0; + ENABLE_STEPPER_DRIVER_INTERRUPT(); +} + +inline unsigned short calc_timer(unsigned short step_rate) { + unsigned short timer; + if(step_rate < 32) step_rate = 32; + step_rate -= 32; // Correct for minimal speed + if(step_rate >= (8*256)){ // higher step rate + unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; + unsigned char tmp_step_rate = (step_rate & 0x00ff); + unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); + MultiU16X8toH16(timer, tmp_step_rate, gain); + timer = (unsigned short)pgm_read_word_near(table_address) - timer; + } + else { // lower step rates + unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; + table_address += ((step_rate)>>1) & 0xfffc; + timer = (unsigned short)pgm_read_word_near(table_address); + timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); + } + if(timer < 100) timer = 100; + return timer; +} + +// Initializes the trapezoid generator from the current block. Called whenever a new +// block begins. +inline void trapezoid_generator_reset() { + accelerate_until = current_block->accelerate_until; + decelerate_after = current_block->decelerate_after; + acceleration_rate = current_block->acceleration_rate; + initial_rate = current_block->initial_rate; + final_rate = current_block->final_rate; + nominal_rate = current_block->nominal_rate; + advance = current_block->initial_advance; + final_advance = current_block->final_advance; + deceleration_time = 0; + advance_rate = current_block->advance_rate; + // step_rate to timer interval + acc_step_rate = initial_rate; + acceleration_time = calc_timer(acc_step_rate); + OCR1A = acceleration_time; +} + +// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. +// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. +ISR(TIMER1_COMPA_vect) +{ + if(busy){ /*Serial.println("BUSY")*/; + return; + } // The busy-flag is used to avoid reentering this interrupt + + busy = true; + sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) + + // If there is no current block, attempt to pop one from the buffer + if (current_block == NULL) { + // Anything in the buffer? + current_block = plan_get_current_block(); + if (current_block != NULL) { + trapezoid_generator_reset(); + counter_x = -(current_block->step_event_count >> 1); + counter_y = counter_x; + counter_z = counter_x; + counter_e = counter_x; + step_events_completed = 0; + e_steps = 0; + } + else { + DISABLE_STEPPER_DRIVER_INTERRUPT(); + } + } + + if (current_block != NULL) { + // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt + out_bits = current_block->direction_bits; + +#ifdef ADVANCE + // Calculate E early. + counter_e += current_block->steps_e; + if (counter_e > 0) { + counter_e -= current_block->step_event_count; + if ((out_bits & (1<> 16) - old_advance); + CRITICAL_SECTION_END; + old_advance = advance >> 16; +#endif //ADVANCE + + // Set direction en check limit switches + if ((out_bits & (1<step_event_count; + } + } + else { // +direction + WRITE(X_DIR_PIN,!INVERT_X_DIR); + if((READ(X_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_x >0)){ + step_events_completed = current_block->step_event_count; + } + } + + if ((out_bits & (1<step_event_count; + } + } + else { // +direction + WRITE(Y_DIR_PIN,!INVERT_Y_DIR); + if((READ(Y_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_y >0)){ + step_events_completed = current_block->step_event_count; + } + } + + if ((out_bits & (1<step_event_count; + } + } + else { // +direction + WRITE(Z_DIR_PIN,!INVERT_Z_DIR); + if((READ(Z_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_z >0)){ + step_events_completed = current_block->step_event_count; + } + } + +#ifndef ADVANCE + if ((out_bits & (1<steps_x; + if (counter_x > 0) { + WRITE(X_STEP_PIN, HIGH); + counter_x -= current_block->step_event_count; + WRITE(X_STEP_PIN, LOW); + } + + counter_y += current_block->steps_y; + if (counter_y > 0) { + WRITE(Y_STEP_PIN, HIGH); + counter_y -= current_block->step_event_count; + WRITE(Y_STEP_PIN, LOW); + } + + counter_z += current_block->steps_z; + if (counter_z > 0) { + WRITE(Z_STEP_PIN, HIGH); + counter_z -= current_block->step_event_count; + WRITE(Z_STEP_PIN, LOW); + } + +#ifndef ADVANCE + counter_e += current_block->steps_e; + if (counter_e > 0) { + WRITE(E_STEP_PIN, HIGH); + counter_e -= current_block->step_event_count; + WRITE(E_STEP_PIN, LOW); + } +#endif //!ADVANCE + + // Calculare new timer value + unsigned short timer; + unsigned short step_rate; + if (step_events_completed < accelerate_until) { + MultiU24X24toH16(acc_step_rate, acceleration_time, acceleration_rate); + acc_step_rate += initial_rate; + + // upper limit + if(acc_step_rate > nominal_rate) + acc_step_rate = nominal_rate; + + // step_rate to timer interval + timer = calc_timer(acc_step_rate); + advance += advance_rate; + acceleration_time += timer; + OCR1A = timer; + } + else if (step_events_completed >= decelerate_after) { + MultiU24X24toH16(step_rate, deceleration_time, acceleration_rate); + + if(step_rate > acc_step_rate) { // Check step_rate stays positive + step_rate = final_rate; + } + else { + step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. + } + + // lower limit + if(step_rate < final_rate) + step_rate = final_rate; + + // step_rate to timer interval + timer = calc_timer(step_rate); +#ifdef ADVANCE + advance -= advance_rate; + if(advance < final_advance) + advance = final_advance; +#endif //ADVANCE + deceleration_time += timer; + OCR1A = timer; + } + // If current block is finished, reset pointer + step_events_completed += 1; + if (step_events_completed >= current_block->step_event_count) { + current_block = NULL; + plan_discard_current_block(); + } + } + busy=false; +} + +#ifdef ADVANCE + +unsigned char old_OCR0A; +// Timer interrupt for E. e_steps is set in the main routine; +// Timer 0 is shared with millies +ISR(TIMER0_COMPA_vect) +{ + // Critical section needed because Timer 1 interrupt has higher priority. + // The pin set functions are placed on trategic position to comply with the stepper driver timing. + WRITE(E_STEP_PIN, LOW); + // Set E direction (Depends on E direction + advance) + if (e_steps < 0) { + WRITE(E_DIR_PIN,INVERT_E_DIR); + e_steps++; + WRITE(E_STEP_PIN, HIGH); + } + if (e_steps > 0) { + WRITE(E_DIR_PIN,!INVERT_E_DIR); + e_steps--; + WRITE(E_STEP_PIN, HIGH); + } + old_OCR0A += 25; // 10kHz interrupt + OCR0A = old_OCR0A; +} +#endif // ADVANCE + +void st_init() +{ + // waveform generation = 0100 = CTC + TCCR1B &= ~(1<= 16) + { + current_raw = 16383 - raw_temp_value; + temp_meas_ready = true; + temp_count = 0; + raw_temp_value = 0; +#ifdef MAXTEMP + if(current_raw >= maxttemp) { + target_raw = 0; +#ifdef PIDTEMP + OCR2B = 0; +#else + WRITE(HEATER_0_PIN,LOW); +#endif //PIDTEMP + } +#endif //MAXTEMP +#ifdef MINTEMP + if(current_raw <= minttemp) { + target_raw = 0; +#ifdef PIDTEMP + OCR2B = 0; +#else + WRITE(HEATER_0_PIN,LOW); +#endif //PIDTEMP + } +#endif //MAXTEMP +#ifndef PIDTEMP + if(current_raw >= target_raw) + { + WRITE(HEATER_0_PIN,LOW); + } + else + { + WRITE(HEATER_0_PIN,HIGH); + } +#endif //PIDTEMP + } +} + */ \ No newline at end of file From 7d7ad0848646a1ba5926ce39f5f61275977712d8 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Fri, 26 Aug 2011 00:20:41 +0300 Subject: [PATCH 014/130] Credits.. --- README | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README b/README index 7567e23a44c7..a86b0653bd27 100644 --- a/README +++ b/README @@ -2,8 +2,10 @@ This RepRap firmware is a mashup between Sprinter, grbl and many original parts. (https://github.com/kliment/Sprinter) (https://github.com/simen/grbl/tree) +Derived from Sprinter by Erik Zalm. +Sprinters lead developers are Kliment and caru. It has been adapted to the Ultimaker Printer by: - Bernhard Kubicek, Bradley Feldman, and others... +Bernhard Kubicek, Lampmaker, Bradley Feldman, and others... Features: From b203697b474206835f7ac2ae35cef7061a07bf5c Mon Sep 17 00:00:00 2001 From: lampmaker Date: Fri, 26 Aug 2011 08:54:03 +0300 Subject: [PATCH 015/130] Let me introduce myself :-) --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index a86b0653bd27..380d91901889 100644 --- a/README +++ b/README @@ -5,7 +5,7 @@ This RepRap firmware is a mashup between Sprinter, grbl and many original parts. Derived from Sprinter by Erik Zalm. Sprinters lead developers are Kliment and caru. It has been adapted to the Ultimaker Printer by: -Bernhard Kubicek, Lampmaker, Bradley Feldman, and others... +Bernhard Kubicek, Matthijs Keuper, Bradley Feldman, and others... Features: From 535506ab3c4f273344951a4b57e676277d9b40b5 Mon Sep 17 00:00:00 2001 From: ErikZalm Date: Fri, 26 Aug 2011 21:11:23 +0300 Subject: [PATCH 016/130] Edited README via GitHub --- README | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README b/README index 380d91901889..ecaa62129c40 100644 --- a/README +++ b/README @@ -2,8 +2,9 @@ This RepRap firmware is a mashup between Sprinter, grbl and many original parts. (https://github.com/kliment/Sprinter) (https://github.com/simen/grbl/tree) -Derived from Sprinter by Erik Zalm. +Derived from Sprinter and Grbl by Erik van der Zalm. Sprinters lead developers are Kliment and caru. +Grbls lead developer is Simen Svale Skogsrud. It has been adapted to the Ultimaker Printer by: Bernhard Kubicek, Matthijs Keuper, Bradley Feldman, and others... From 461e267a66bd5eb9bb5edf1b5ac7908de0f6afa6 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sun, 28 Aug 2011 15:35:47 +0200 Subject: [PATCH 017/130] pre-update --- Marlin/Configuration.h | 296 ++++++++++++++++++++--------------------- Marlin/Marlin.h | 240 ++++++++++++++++----------------- 2 files changed, 268 insertions(+), 268 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 8383c36deb74..ed2a84e05818 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -1,148 +1,148 @@ -#ifndef CONFIGURATION_H -#define CONFIGURATION_H - -// BASIC SETTINGS: select your board type, thermistor type, axis scaling, and endstop configuration - -//// The following define selects which electronics board you have. Please choose the one that matches your setup -// Gen6 = 5, -#define MOTHERBOARD 7 - -//// Thermistor settings: -// 1 is 100k thermistor -// 2 is 200k thermistor -// 3 is mendel-parts thermistor -#define THERMISTORHEATER 2 -// Select one of these only to define how the nozzle temp is read. -//#define HEATER_USES_THERMISTOR -#define HEATER_USES_AD595 -//#define HEATER_USES_MAX6675 - -// Select one of these only to define how the bed temp is read. -//#define BED_USES_THERMISTOR -//#define BED_USES_AD595 - -#define HEATER_CHECK_INTERVAL 50 -#define BED_CHECK_INTERVAL 5000 -#define BNUMTEMPS NUMTEMPS -#define bedtemptable temptable - -//// Calibration variables -// X, Y, Z, E steps per unit - Metric Mendel / Orca with V9 extruder: -float axis_steps_per_unit[] = {79.87220447, 79.87220447, 200*8/3., 14}; -// For E steps per unit = 67 for v9 with direct drive (needs finetuning) for other extruders this needs to be changed -// Metric Prusa Mendel with Makergear geared stepper extruder: -//float axis_steps_per_unit[] = {80,80,3200/1.25,1380}; - -//// Endstop Settings -#define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors -// The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins. -const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the endstops. -// For optos H21LOB set to true, for Mendel-Parts newer optos TCST2103 set to false - -// This determines the communication speed of the printer -#define BAUDRATE 115200 - -// Comment out (using // at the start of the line) to disable SD support: -#define SDSUPPORT -//#define FANCY_LCD - - - -//// ADVANCED SETTINGS - to tweak parameters - -#include "thermistortables.h" - -// For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1 -#define X_ENABLE_ON 0 -#define Y_ENABLE_ON 0 -#define Z_ENABLE_ON 0 -#define E_ENABLE_ON 0 - -// Disables axis when it's not being used. -#define DISABLE_X false -#define DISABLE_Y false -#define DISABLE_Z false -#define DISABLE_E false - -// Inverting axis direction -#define INVERT_X_DIR true // for Mendel set to false, for Orca set to true -#define INVERT_Y_DIR false // for Mendel set to true, for Orca set to false -#define INVERT_Z_DIR true // for Mendel set to false, for Orca set to true -#define INVERT_E_DIR false // for direct drive extruder v9 set to true, for geared extruder set to false - -//// ENDSTOP SETTINGS: -// Sets direction of endstops when homing; 1=MAX, -1=MIN -#define X_HOME_DIR -1 -#define Y_HOME_DIR -1 -#define Z_HOME_DIR -1 - -#define min_software_endstops false //If true, axis won't move to coordinates less than zero. -#define max_software_endstops true //If true, axis won't move to coordinates greater than the defined lengths below. -#define X_MAX_LENGTH 200 -#define Y_MAX_LENGTH 200 -#define Z_MAX_LENGTH 100 - -//// MOVEMENT SETTINGS -#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {60000, 60000, 50000, 500000}; // set the max speeds -float homing_feedrate[] = {2400, 2400, 200, 0}; // set the homing speeds -bool axis_relative_modes[] = {false, false, false, false}; - -//// Acceleration settings -// X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. -float acceleration = 4000; // Normal acceleration mm/s^2 -float retract_acceleration = 10000; // Normal acceleration mm/s^2 -float max_jerk = 20*60; -long max_acceleration_units_per_sq_second[] = {15000,15000,150000,15000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts -// Not used long max_travel_acceleration_units_per_sq_second[] = {500,500,50,500}; // X, Y, Z max acceleration in mm/s^2 for travel moves - - -// The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature -// If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 -//#define WATCHPERIOD 5000 //5 seconds - -//// The minimal temperature defines the temperature below which the heater will not be enabled -#define MINTEMP 5 - - -// When temperature exceeds max temp, your heater will be switched off. -// This feature exists to protect your hotend from overheating accidentally, but *NOT* from thermistor short/failure! -// You should use MINTEMP for thermistor short/failure protection. -#define MAXTEMP 275 - - -/// PID settings: -// Uncomment the following line to enable PID support. -//#define PIDTEMP -#ifdef PIDTEMP -//#define PID_DEBUG 1 // Sends debug data to the serial port. -//#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % -#define PID_MAX 156 // limits current to nozzle -#define PID_INTEGRAL_DRIVE_MAX 156.0 -#define PID_dT 0.16 -double Kp = 20.0; -double Ki = 1.5*PID_dT; -double Kd = 80/PID_dT; -#endif // PIDTEMP - - -// extruder advance constant (s2/mm3) -// -// advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2 -// -// hooke's law says: force = k * distance -// bernoulli's priniciple says: v ^ 2 / 2 + g . h + pressure / density = constant -// so: v ^ 2 is proportional to number of steps we advance the extruder -//#define ADVANCE - -#ifdef ADVANCE -#define EXTRUDER_ADVANCE_K 0.02 - -#define D_FILAMENT 2.75 -#define STEPS_MM_E 600 -#define EXTRUTION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159) -#define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUTION_AREA) - -#endif // ADVANCE - -#endif \ No newline at end of file +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +// BASIC SETTINGS: select your board type, thermistor type, axis scaling, and endstop configuration + +//// The following define selects which electronics board you have. Please choose the one that matches your setup +// Gen6 = 5, +#define MOTHERBOARD 7 + +//// Thermistor settings: +// 1 is 100k thermistor +// 2 is 200k thermistor +// 3 is mendel-parts thermistor +#define THERMISTORHEATER 2 +// Select one of these only to define how the nozzle temp is read. +//#define HEATER_USES_THERMISTOR +#define HEATER_USES_AD595 +//#define HEATER_USES_MAX6675 + +// Select one of these only to define how the bed temp is read. +//#define BED_USES_THERMISTOR +//#define BED_USES_AD595 + +#define HEATER_CHECK_INTERVAL 50 +#define BED_CHECK_INTERVAL 5000 +#define BNUMTEMPS NUMTEMPS +#define bedtemptable temptable + +//// Calibration variables +// X, Y, Z, E steps per unit - Metric Mendel / Orca with V9 extruder: +float axis_steps_per_unit[] = {79.87220447, 79.87220447, 200*8/3., 14}; +// For E steps per unit = 67 for v9 with direct drive (needs finetuning) for other extruders this needs to be changed +// Metric Prusa Mendel with Makergear geared stepper extruder: +//float axis_steps_per_unit[] = {80,80,3200/1.25,1380}; + +//// Endstop Settings +#define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors +// The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins. +const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the endstops. +// For optos H21LOB set to true, for Mendel-Parts newer optos TCST2103 set to false + +// This determines the communication speed of the printer +#define BAUDRATE 115200 + +// Comment out (using // at the start of the line) to disable SD support: +#define SDSUPPORT +#define FANCY_LCD + + + +//// ADVANCED SETTINGS - to tweak parameters + +#include "thermistortables.h" + +// For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1 +#define X_ENABLE_ON 0 +#define Y_ENABLE_ON 0 +#define Z_ENABLE_ON 0 +#define E_ENABLE_ON 0 + +// Disables axis when it's not being used. +#define DISABLE_X false +#define DISABLE_Y false +#define DISABLE_Z false +#define DISABLE_E false + +// Inverting axis direction +#define INVERT_X_DIR true // for Mendel set to false, for Orca set to true +#define INVERT_Y_DIR false // for Mendel set to true, for Orca set to false +#define INVERT_Z_DIR true // for Mendel set to false, for Orca set to true +#define INVERT_E_DIR false // for direct drive extruder v9 set to true, for geared extruder set to false + +//// ENDSTOP SETTINGS: +// Sets direction of endstops when homing; 1=MAX, -1=MIN +#define X_HOME_DIR -1 +#define Y_HOME_DIR -1 +#define Z_HOME_DIR -1 + +#define min_software_endstops false //If true, axis won't move to coordinates less than zero. +#define max_software_endstops true //If true, axis won't move to coordinates greater than the defined lengths below. +#define X_MAX_LENGTH 200 +#define Y_MAX_LENGTH 200 +#define Z_MAX_LENGTH 100 + +//// MOVEMENT SETTINGS +#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E +float max_feedrate[] = {60000, 60000, 50000, 500000}; // set the max speeds +float homing_feedrate[] = {2400, 2400, 200, 0}; // set the homing speeds +bool axis_relative_modes[] = {false, false, false, false}; + +//// Acceleration settings +// X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. +float acceleration = 4000; // Normal acceleration mm/s^2 +float retract_acceleration = 10000; // Normal acceleration mm/s^2 +float max_jerk = 20*60; +long max_acceleration_units_per_sq_second[] = {15000,15000,150000,15000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts +// Not used long max_travel_acceleration_units_per_sq_second[] = {500,500,50,500}; // X, Y, Z max acceleration in mm/s^2 for travel moves + + +// The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature +// If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 +//#define WATCHPERIOD 5000 //5 seconds + +//// The minimal temperature defines the temperature below which the heater will not be enabled +#define MINTEMP 5 + + +// When temperature exceeds max temp, your heater will be switched off. +// This feature exists to protect your hotend from overheating accidentally, but *NOT* from thermistor short/failure! +// You should use MINTEMP for thermistor short/failure protection. +#define MAXTEMP 275 + + +/// PID settings: +// Uncomment the following line to enable PID support. +//#define PIDTEMP +#ifdef PIDTEMP +//#define PID_DEBUG 1 // Sends debug data to the serial port. +//#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % +#define PID_MAX 156 // limits current to nozzle +#define PID_INTEGRAL_DRIVE_MAX 156.0 +#define PID_dT 0.16 +double Kp = 20.0; +double Ki = 1.5*PID_dT; +double Kd = 80/PID_dT; +#endif // PIDTEMP + + +// extruder advance constant (s2/mm3) +// +// advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2 +// +// hooke's law says: force = k * distance +// bernoulli's priniciple says: v ^ 2 / 2 + g . h + pressure / density = constant +// so: v ^ 2 is proportional to number of steps we advance the extruder +//#define ADVANCE + +#ifdef ADVANCE +#define EXTRUDER_ADVANCE_K 0.02 + +#define D_FILAMENT 2.75 +#define STEPS_MM_E 600 +#define EXTRUTION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159) +#define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUTION_AREA) + +#endif // ADVANCE + +#endif diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 0f7ae7cc4e5b..9ff0f51532cd 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -1,121 +1,121 @@ -#ifndef __MARLINH -#define __MARLINH - -typedef struct { - // Fields used by the bresenham algorithm for tracing the line - long steps_x, steps_y, steps_z, steps_e; // Step count along each axis - long step_event_count; // The number of step events required to complete this block - volatile long accelerate_until; // The index of the step event on which to stop acceleration - volatile long decelerate_after; // The index of the step event on which to start decelerating - volatile long acceleration_rate; // The acceleration rate used for acceleration calculation - unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h) - - long advance_rate; - volatile long initial_advance; - volatile long final_advance; - float advance; - - // Fields used by the motion planner to manage acceleration - float speed_x, speed_y, speed_z, speed_e; // Nominal mm/minute for each axis - float nominal_speed; // The nominal speed for this block in mm/min - float millimeters; // The total travel of this block in mm - float entry_speed; - - // Settings for the trapezoid generator - long nominal_rate; // The nominal step rate for this block in step_events/sec - volatile long initial_rate; // The jerk-adjusted step rate at start of block - volatile long final_rate; // The minimal rate at exit - long acceleration; // acceleration mm/sec^2 - volatile char busy; -} block_t; - - -// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. -// Licence: GPL -#include -#include "fastio.h" -//extern "C" void __cxa_pure_virtual(); -//void __cxa_pure_virtual(){}; -void get_command(); -void process_commands(); - -void manage_inactivity(byte debug); - -void manage_heater(); -//int temp2analogu(int celsius, const short table[][2], int numtemps); -//float analog2tempu(int raw, const short table[][2], int numtemps); -float temp2analog(int celsius); -float temp2analogBed(int celsius); -float analog2temp(int raw); -float analog2tempBed(int raw); - -#ifdef HEATER_USES_THERMISTOR - #define HEATERSOURCE 1 -#endif -#ifdef BED_USES_THERMISTOR - #define BEDSOURCE 1 -#endif - -//#define temp2analogh( c ) temp2analogu((c),temptable,NUMTEMPS) -//#define analog2temp( c ) analog2tempu((c),temptable,NUMTEMPS) - -#if X_ENABLE_PIN > -1 - #define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) - #define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) -#else - #define enable_x() ; - #define disable_x() ; -#endif - -#if Y_ENABLE_PIN > -1 - #define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) - #define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) -#else - #define enable_y() ; - #define disable_y() ; -#endif - -#if Z_ENABLE_PIN > -1 - #define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) - #define disable_z() WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON) -#else - #define enable_z() ; - #define disable_z() ; -#endif - -#if E_ENABLE_PIN > -1 - #define enable_e() WRITE(E_ENABLE_PIN, E_ENABLE_ON) - #define disable_e() WRITE(E_ENABLE_PIN,!E_ENABLE_ON) -#else - #define enable_e() ; - #define disable_e() ; -#endif - -#define X_AXIS 0 -#define Y_AXIS 1 -#define Z_AXIS 2 -#define E_AXIS 3 - - - -void FlushSerialRequestResend(); -void ClearToSend(); - -void get_coordinates(); -void prepare_move(); -void linear_move(unsigned long steps_remaining[]); -void do_step(int axis); -void kill(byte debug); - - -void check_axes_activity(); -void plan_init(); -void st_init(); -void tp_init(); -void plan_buffer_line(float x, float y, float z, float e, float feed_rate); -void plan_set_position(float x, float y, float z, float e); -void st_wake_up(); -void st_synchronize(); - - +#ifndef __MARLINH +#define __MARLINH + +typedef struct { + // Fields used by the bresenham algorithm for tracing the line + long steps_x, steps_y, steps_z, steps_e; // Step count along each axis + long step_event_count; // The number of step events required to complete this block + volatile long accelerate_until; // The index of the step event on which to stop acceleration + volatile long decelerate_after; // The index of the step event on which to start decelerating + volatile long acceleration_rate; // The acceleration rate used for acceleration calculation + unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h) + + long advance_rate; + volatile long initial_advance; + volatile long final_advance; + float advance; + + // Fields used by the motion planner to manage acceleration + float speed_x, speed_y, speed_z, speed_e; // Nominal mm/minute for each axis + float nominal_speed; // The nominal speed for this block in mm/min + float millimeters; // The total travel of this block in mm + float entry_speed; + + // Settings for the trapezoid generator + long nominal_rate; // The nominal step rate for this block in step_events/sec + volatile long initial_rate; // The jerk-adjusted step rate at start of block + volatile long final_rate; // The minimal rate at exit + long acceleration; // acceleration mm/sec^2 + volatile char busy; +} block_t; + + +// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. +// Licence: GPL +#include +#include "fastio.h" +//extern "C" void __cxa_pure_virtual(); +//void __cxa_pure_virtual(){}; +void get_command(); +void process_commands(); + +void manage_inactivity(byte debug); + +void manage_heater(); +//int temp2analogu(int celsius, const short table[][2], int numtemps); +//float analog2tempu(int raw, const short table[][2], int numtemps); +float temp2analog(int celsius); +float temp2analogBed(int celsius); +float analog2temp(int raw); +float analog2tempBed(int raw); + +#ifdef HEATER_USES_THERMISTOR + #define HEATERSOURCE 1 +#endif +#ifdef BED_USES_THERMISTOR + #define BEDSOURCE 1 +#endif + +//#define temp2analogh( c ) temp2analogu((c),temptable,NUMTEMPS) +//#define analog2temp( c ) analog2tempu((c),temptable,NUMTEMPS) + +#if X_ENABLE_PIN > -1 + #define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) + #define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) +#else + #define enable_x() ; + #define disable_x() ; +#endif + +#if Y_ENABLE_PIN > -1 + #define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) + #define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) +#else + #define enable_y() ; + #define disable_y() ; +#endif + +#if Z_ENABLE_PIN > -1 + #define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) + #define disable_z() WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON) +#else + #define enable_z() ; + #define disable_z() ; +#endif + +#if E_ENABLE_PIN > -1 + #define enable_e() WRITE(E_ENABLE_PIN, E_ENABLE_ON) + #define disable_e() WRITE(E_ENABLE_PIN,E_ENABLE_ON) +#else + #define enable_e() ; + #define disable_e() ; +#endif + +#define X_AXIS 0 +#define Y_AXIS 1 +#define Z_AXIS 2 +#define E_AXIS 3 + + + +void FlushSerialRequestResend(); +void ClearToSend(); + +void get_coordinates(); +void prepare_move(); +void linear_move(unsigned long steps_remaining[]); +void do_step(int axis); +void kill(byte debug); + + +void check_axes_activity(); +void plan_init(); +void st_init(); +void tp_init(); +void plan_buffer_line(float x, float y, float z, float e, float feed_rate); +void plan_set_position(float x, float y, float z, float e); +void st_wake_up(); +void st_synchronize(); + + #endif From e7e7b35e7b9d7a10e23774a9909bf64026301b01 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sun, 28 Aug 2011 18:54:02 +0200 Subject: [PATCH 018/130] lcd improvement, real speed override for lcd/sd printing, config.h back to linux eol, addidional gcode for disable steppers. --- Marlin/Configuration.h | 296 ++++++++++++++++++++--------------------- Marlin/Marlin.pde | 31 ++--- Marlin/buttons.h | 2 +- Marlin/lcd.h | 9 +- Marlin/lcd.pde | 203 ++++++++++++++++++---------- 5 files changed, 296 insertions(+), 245 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 0a07715a92ac..4f15a3dba75c 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -1,149 +1,149 @@ -#ifndef CONFIGURATION_H -#define CONFIGURATION_H - -// BASIC SETTINGS: select your board type, thermistor type, axis scaling, and endstop configuration - -//// The following define selects which electronics board you have. Please choose the one that matches your setup -// Gen6 = 5, -#define MOTHERBOARD 7 - -//// Thermistor settings: -// 1 is 100k thermistor -// 2 is 200k thermistor -// 3 is mendel-parts thermistor -#define THERMISTORHEATER 2 -// Select one of these only to define how the nozzle temp is read. -//#define HEATER_USES_THERMISTOR -#define HEATER_USES_AD595 -//#define HEATER_USES_MAX6675 - -// Select one of these only to define how the bed temp is read. -//#define BED_USES_THERMISTOR -//#define BED_USES_AD595 - -#define HEATER_CHECK_INTERVAL 50 -#define BED_CHECK_INTERVAL 5000 -#define BNUMTEMPS NUMTEMPS -#define bedtemptable temptable - -//// Calibration variables -// X, Y, Z, E steps per unit - Metric Mendel / Orca with V9 extruder: -float axis_steps_per_unit[] = {79.87220447, 79.87220447, 200*8/3., 14}; -// For E steps per unit = 67 for v9 with direct drive (needs finetuning) for other extruders this needs to be changed -// Metric Prusa Mendel with Makergear geared stepper extruder: -//float axis_steps_per_unit[] = {80,80,3200/1.25,1380}; - -//// Endstop Settings -#define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors -// The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins. -const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the endstops. -// For optos H21LOB set to true, for Mendel-Parts newer optos TCST2103 set to false - -// This determines the communication speed of the printer -#define BAUDRATE 115200 - -// Comment out (using // at the start of the line) to disable SD support: -//#define SDSUPPORT -#define FANCY_LCD -//#define FANCY_BUTTONS - - - -//// ADVANCED SETTINGS - to tweak parameters - -#include "thermistortables.h" - -// For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1 -#define X_ENABLE_ON 0 -#define Y_ENABLE_ON 0 -#define Z_ENABLE_ON 0 -#define E_ENABLE_ON 0 - -// Disables axis when it's not being used. -#define DISABLE_X false -#define DISABLE_Y false -#define DISABLE_Z false -#define DISABLE_E false - -// Inverting axis direction -#define INVERT_X_DIR true // for Mendel set to false, for Orca set to true -#define INVERT_Y_DIR false // for Mendel set to true, for Orca set to false -#define INVERT_Z_DIR true // for Mendel set to false, for Orca set to true -#define INVERT_E_DIR false // for direct drive extruder v9 set to true, for geared extruder set to false - -//// ENDSTOP SETTINGS: -// Sets direction of endstops when homing; 1=MAX, -1=MIN -#define X_HOME_DIR -1 -#define Y_HOME_DIR -1 -#define Z_HOME_DIR -1 - -#define min_software_endstops false //If true, axis won't move to coordinates less than zero. -#define max_software_endstops true //If true, axis won't move to coordinates greater than the defined lengths below. -#define X_MAX_LENGTH 200 -#define Y_MAX_LENGTH 200 -#define Z_MAX_LENGTH 100 - -//// MOVEMENT SETTINGS -#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {60000, 60000, 50000, 500000}; // set the max speeds -float homing_feedrate[] = {2400, 2400, 200, 0}; // set the homing speeds -bool axis_relative_modes[] = {false, false, false, false}; - -//// Acceleration settings -// X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. -float acceleration = 4000; // Normal acceleration mm/s^2 -float retract_acceleration = 10000; // Normal acceleration mm/s^2 -float max_jerk = 20*60; -long max_acceleration_units_per_sq_second[] = {15000,15000,150000,15000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts -// Not used long max_travel_acceleration_units_per_sq_second[] = {500,500,50,500}; // X, Y, Z max acceleration in mm/s^2 for travel moves - - -// The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature -// If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 -//#define WATCHPERIOD 5000 //5 seconds - -//// The minimal temperature defines the temperature below which the heater will not be enabled -#define MINTEMP 5 - - -// When temperature exceeds max temp, your heater will be switched off. -// This feature exists to protect your hotend from overheating accidentally, but *NOT* from thermistor short/failure! -// You should use MINTEMP for thermistor short/failure protection. -#define MAXTEMP 275 - - -/// PID settings: -// Uncomment the following line to enable PID support. -//#define PIDTEMP -#ifdef PIDTEMP -//#define PID_DEBUG 1 // Sends debug data to the serial port. -//#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % -#define PID_MAX 156 // limits current to nozzle -#define PID_INTEGRAL_DRIVE_MAX 156.0 -#define PID_dT 0.16 -double Kp = 20.0; -double Ki = 1.5*PID_dT; -double Kd = 80/PID_dT; -#endif // PIDTEMP - - -// extruder advance constant (s2/mm3) -// -// advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2 -// -// hooke's law says: force = k * distance -// bernoulli's priniciple says: v ^ 2 / 2 + g . h + pressure / density = constant -// so: v ^ 2 is proportional to number of steps we advance the extruder -//#define ADVANCE - -#ifdef ADVANCE -#define EXTRUDER_ADVANCE_K 0.02 - -#define D_FILAMENT 2.75 -#define STEPS_MM_E 600 -#define EXTRUTION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159) -#define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUTION_AREA) - -#endif // ADVANCE - +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +// BASIC SETTINGS: select your board type, thermistor type, axis scaling, and endstop configuration + +//// The following define selects which electronics board you have. Please choose the one that matches your setup +// Gen6 = 5, +#define MOTHERBOARD 7 + +//// Thermistor settings: +// 1 is 100k thermistor +// 2 is 200k thermistor +// 3 is mendel-parts thermistor +#define THERMISTORHEATER 2 +// Select one of these only to define how the nozzle temp is read. +//#define HEATER_USES_THERMISTOR +#define HEATER_USES_AD595 +//#define HEATER_USES_MAX6675 + +// Select one of these only to define how the bed temp is read. +//#define BED_USES_THERMISTOR +//#define BED_USES_AD595 + +#define HEATER_CHECK_INTERVAL 50 +#define BED_CHECK_INTERVAL 5000 +#define BNUMTEMPS NUMTEMPS +#define bedtemptable temptable + +//// Calibration variables +// X, Y, Z, E steps per unit - Metric Mendel / Orca with V9 extruder: +float axis_steps_per_unit[] = {79.87220447, 79.87220447, 200*8/3., 14}; +// For E steps per unit = 67 for v9 with direct drive (needs finetuning) for other extruders this needs to be changed +// Metric Prusa Mendel with Makergear geared stepper extruder: +//float axis_steps_per_unit[] = {80,80,3200/1.25,1380}; + +//// Endstop Settings +#define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors +// The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins. +const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the endstops. +// For optos H21LOB set to true, for Mendel-Parts newer optos TCST2103 set to false + +// This determines the communication speed of the printer +#define BAUDRATE 115200 + +// Comment out (using // at the start of the line) to disable SD support: +#define SDSUPPORT +//#define FANCY_LCD +//#define FANCY_BUTTONS + + + +//// ADVANCED SETTINGS - to tweak parameters + +#include "thermistortables.h" + +// For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1 +#define X_ENABLE_ON 0 +#define Y_ENABLE_ON 0 +#define Z_ENABLE_ON 0 +#define E_ENABLE_ON 0 + +// Disables axis when it's not being used. +#define DISABLE_X false +#define DISABLE_Y false +#define DISABLE_Z false +#define DISABLE_E false + +// Inverting axis direction +#define INVERT_X_DIR true // for Mendel set to false, for Orca set to true +#define INVERT_Y_DIR false // for Mendel set to true, for Orca set to false +#define INVERT_Z_DIR true // for Mendel set to false, for Orca set to true +#define INVERT_E_DIR false // for direct drive extruder v9 set to true, for geared extruder set to false + +//// ENDSTOP SETTINGS: +// Sets direction of endstops when homing; 1=MAX, -1=MIN +#define X_HOME_DIR -1 +#define Y_HOME_DIR -1 +#define Z_HOME_DIR -1 + +#define min_software_endstops false //If true, axis won't move to coordinates less than zero. +#define max_software_endstops true //If true, axis won't move to coordinates greater than the defined lengths below. +#define X_MAX_LENGTH 200 +#define Y_MAX_LENGTH 200 +#define Z_MAX_LENGTH 100 + +//// MOVEMENT SETTINGS +#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E +float max_feedrate[] = {60000, 60000, 300, 500000}; // set the max speeds +float homing_feedrate[] = {2400, 2400, 200, 0}; // set the homing speeds +bool axis_relative_modes[] = {false, false, false, false}; + +//// Acceleration settings +// X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. +float acceleration = 4000; // Normal acceleration mm/s^2 +float retract_acceleration = 10000; // Normal acceleration mm/s^2 +float max_jerk = 20*60; +long max_acceleration_units_per_sq_second[] = {15000,15000,150000,15000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts +// Not used long max_travel_acceleration_units_per_sq_second[] = {500,500,50,500}; // X, Y, Z max acceleration in mm/s^2 for travel moves + + +// The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature +// If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 +//#define WATCHPERIOD 5000 //5 seconds + +//// The minimal temperature defines the temperature below which the heater will not be enabled +#define MINTEMP 5 + + +// When temperature exceeds max temp, your heater will be switched off. +// This feature exists to protect your hotend from overheating accidentally, but *NOT* from thermistor short/failure! +// You should use MINTEMP for thermistor short/failure protection. +#define MAXTEMP 275 + + +/// PID settings: +// Uncomment the following line to enable PID support. +//#define PIDTEMP +#ifdef PIDTEMP +//#define PID_DEBUG 1 // Sends debug data to the serial port. +//#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % +#define PID_MAX 156 // limits current to nozzle +#define PID_INTEGRAL_DRIVE_MAX 156.0 +#define PID_dT 0.16 +double Kp = 20.0; +double Ki = 1.5*PID_dT; +double Kd = 80/PID_dT; +#endif // PIDTEMP + + +// extruder advance constant (s2/mm3) +// +// advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2 +// +// hooke's law says: force = k * distance +// bernoulli's priniciple says: v ^ 2 / 2 + g . h + pressure / density = constant +// so: v ^ 2 is proportional to number of steps we advance the extruder +#define ADVANCE + +#ifdef ADVANCE +#define EXTRUDER_ADVANCE_K 0.02 + +#define D_FILAMENT 2.75 +//#define STEPS_MM_E 600 //this seems uncessesary +#define EXTRUTION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159) +#define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUTION_AREA) + +#endif // ADVANCE + #endif diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 7ff9889797d7..84f851aea841 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -116,6 +116,7 @@ bool relative_mode = false; //Determines Absolute or Relative Coordinates bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. unsigned long axis_steps_per_sqr_second[NUM_AXIS]; +volatile int feedmultiply=100; //100->1 200->2 // comm variables #define MAX_CMD_SIZE 96 #define BUFSIZE 8 @@ -825,9 +826,10 @@ inline void process_commands() { Serial.print("T:"); Serial.println( analog2temp(current_raw) ); - LCD_STATUS; + codenum = millis(); } + LCD_STATUS; manage_heater(); } break; @@ -871,6 +873,7 @@ inline void process_commands() case 83: axis_relative_modes[3] = true; break; + case 18: case 84: if(code_seen('S')){ stepper_inactive_time = code_value() * 1000; @@ -1001,7 +1004,7 @@ inline void get_coordinates() void prepare_move() { - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60.0); + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60.0/100.); for(int i=0; i < NUM_AXIS; i++) { current_position[i] = destination[i]; } @@ -2106,16 +2109,12 @@ ISR(TIMER1_COMPA_vect) // Set direction en check limit switches if ((out_bits & (1<step_event_count; } } - else { // +direction - WRITE(X_DIR_PIN,!INVERT_X_DIR); - if((READ(X_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_x >0)){ - step_events_completed = current_block->step_event_count; - } - } + else // +direction + WRITE(X_DIR_PIN,!INVERT_X_DIR); if ((out_bits & (1<step_event_count; } } - else { // +direction + else // +direction WRITE(Y_DIR_PIN,!INVERT_Y_DIR); - if((READ(Y_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_y >0)){ - step_events_completed = current_block->step_event_count; - } - } if ((out_bits & (1<step_event_count; } } - else { // +direction - WRITE(Z_DIR_PIN,!INVERT_Z_DIR); - if((READ(Z_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_z >0)){ - step_events_completed = current_block->step_event_count; - } - } + else // +direction + WRITE(Z_DIR_PIN,!INVERT_Z_DIR); #ifndef ADVANCE if ((out_bits & (1< LiquidCrystal lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5,LCD_PINS_D6,LCD_PINS_D7); //RS,Enable,D4,D5,D6,D7 @@ -87,6 +88,7 @@ public: virtual void activate(); virtual void update(); + int lastencoder; }; PageWatch::PageWatch() @@ -96,12 +98,27 @@ PageWatch::PageWatch() void PageWatch::update() { - activate(); -} - -void PageWatch::activate() -{ - char line1[25]; + if(messagetext[0]) + { + lcd.setCursor(0,1); + lcd.print(fillto(LCD_WIDTH,messagetext)); + messagetext[0]=0; + } + if(encoderpos!=lastencoder) + { + lcd.setCursor(0,2); + lcd.print("Speed: "); + if(encoderpos<5) encoderpos=5; + if(encoderpos>600) encoderpos=600; + feedmultiply=encoderpos; + lcd.print(encoderpos); + lcd.print(" "); + lastencoder=encoderpos; + } + static int n=0; + if(n++%4) + return; //slower updates + char line1[25]; static char blink=0; sprintf(line1,"%c%3i/%3i\1%c%c%c%c%c%c", ((blink++)%2==0)? (char)2:' ', int(analog2temp(current_raw)), @@ -115,6 +132,14 @@ void PageWatch::activate() lcd.setCursor(0,0); lcd.print(fillto(LCD_WIDTH,line1)); + +} + +void PageWatch::activate() +{ + encoderpos=feedmultiply; + lcd.setCursor(0,0); + lcd.print(fillto(LCD_WIDTH," ")); #if 0 lcd.setCursor(0, 1); //copy last printed gcode line from the buffer onto the lcd @@ -143,9 +168,13 @@ void PageWatch::activate() lcd.print(fillto(LCD_WIDTH,messagetext)); } - +#else + lcd.setCursor(0,1);lcd.print(fillto(LCD_WIDTH," ")); + lcd.setCursor(0,2);lcd.print(fillto(LCD_WIDTH," ")); + lcd.setCursor(0,3);lcd.print(fillto(LCD_WIDTH," ")); #endif fillline(); + update(); } @@ -269,13 +298,13 @@ void PageHome::update() void PageHome::activate() { lcd.setCursor(0,0); - lcd.print(fillto(LCD_WIDTH,"Home")); + lcd.print(fillto(20,"Home")); lcd.setCursor(0,1); - lcd.print(fillto(LCD_WIDTH," X ZERO")); + lcd.print(fillto(20," X ZERO")); lcd.setCursor(0,2); - lcd.print(fillto(LCD_WIDTH," Y ZERO")); + lcd.print(fillto(20," Y ZERO")); lcd.setCursor(0,3); - lcd.print(fillto(LCD_WIDTH," Z ZERO")); + lcd.print(fillto(20," Z ZERO")); fillline(); } @@ -289,58 +318,72 @@ public: virtual void activate(); virtual void update(); + int fileoffset,nrfiles; }; PageSd::PageSd() { xshift=10;items=7;firstline=0; + fileoffset=0; + nrfiles=0; } void PageSd::update() { - if(buttons&B_MI) + if(encoderpos!=lastencoder) //scoll through files + { + fileoffset=encoderpos%nrfiles; + if(fileoffset>nrfiles-8) fileoffset=nrfiles-8; + if(fileoffset<0) fileoffset=0; + activate(); + lastencoder=encoderpos; + + } + if(buttons&B_MI) //start print { blocking[BL_MI]=millis()+blocktime; dir_t p; - root.rewind(); - char filename[11]; - int cnt=0; - while (root.readDir(p) > 0) - { - // done if past last used entry - if (p.name[0] == DIR_NAME_FREE) break; + root.rewind(); + char filename[11]; + int cnt=0; + lastencoder=encoderpos; + while (root.readDir(p) > 0) + { + // done if past last used entry + if (p.name[0] == DIR_NAME_FREE) break; - // skip deleted entry and entries for . and .. - if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue; + // skip deleted entry and entries for . and .. + if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue; - // only list subdirectories and files - if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; + // only list subdirectories and files + if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; - uint8_t writepos=0; - for (uint8_t i = 0; i < 11; i++) { - - if (p.name[i] == ' ') continue; - if (i == 8) { - filename[writepos++]='.'; - } - filename[writepos++]=p.name[i]; - } - filename[writepos++]=0; - if(cnt==line) - break; - cnt++; + uint8_t writepos=0; + for (uint8_t i = 0; i < 11; i++) { - } - char cmd[50]; - for(int i=0;i 0) + { + // done if past last used entry + if (p.name[0] == DIR_NAME_FREE) break; + + // skip deleted entry and entries for . and .. + if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue; + + // only list subdirectories and files + if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; + nrfiles++; + } + root.rewind(); + cnt=0; + int precount=0; while (root.readDir(p) > 0) { // done if past last used entry @@ -362,26 +422,35 @@ void PageSd::activate() // only list subdirectories and files if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; - - - uint8_t writepos=0; - for (uint8_t i = 0; i < 11; i++) { - - if (p.name[i] == ' ') continue; - if (i == 8) { - filename[writepos++]='.'; - } - filename[writepos++]=p.name[i]; - } - filename[writepos++]=0; + if(precount++8) break; lcd.setCursor(0+10*(cnt/4),cnt%4); lcd.print(" "); - lcd.print(fillto(9,filename)); - cnt++; + lcd.print(fillto(9,filename));cnt++; + + } + for(;cnt<9;cnt++) + { + lcd.setCursor(0+10*(cnt/4),cnt%4); + lcd.print(fillto(9," ")); + } + fillline(); } @@ -407,7 +476,7 @@ void lcd_status(const char* message) // if(missing>0) // for(int i=0;i Date: Mon, 29 Aug 2011 20:33:32 +0300 Subject: [PATCH 019/130] Version number --- Marlin/Marlin.pde | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 84f851aea841..94fae4a3129f 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -42,7 +42,7 @@ #include "lcd.h" //extern LiquidCrystal lcd; -char version_string[] = "0.9.3"; +char version_string[] = "U0.9.3.1"; #ifdef SDSUPPORT #include "SdFat.h" From 0156fda38a88880b6b30c3679a8201b036b946b0 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Mon, 29 Aug 2011 23:31:14 +0200 Subject: [PATCH 020/130] buttons improvement, actual measures --- Marlin/Configuration.h | 6 +++--- Marlin/Marlin.pde | 5 +++++ Marlin/buttons.h | 2 ++ Marlin/buttons.pde | 13 ++++++++++--- Marlin/lcd.pde | 4 ++++ 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 4f15a3dba75c..835f20247c28 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -79,9 +79,9 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define min_software_endstops false //If true, axis won't move to coordinates less than zero. #define max_software_endstops true //If true, axis won't move to coordinates greater than the defined lengths below. -#define X_MAX_LENGTH 200 -#define Y_MAX_LENGTH 200 -#define Z_MAX_LENGTH 100 +#define X_MAX_LENGTH 210 +#define Y_MAX_LENGTH 210 +#define Z_MAX_LENGTH 210 //// MOVEMENT SETTINGS #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 94fae4a3129f..b4b1ebaa16fe 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -2060,6 +2060,11 @@ ISR(TIMER1_COMPA_vect) busy = true; sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) +#ifdef FANCY_BUTTONS + static int breakdown=0; + if((breakdown++)%1000==0) + buttons_check(); +#endif // If there is no current block, attempt to pop one from the buffer if (current_block == NULL) { diff --git a/Marlin/buttons.h b/Marlin/buttons.h index 9cc14a7911ef..9e0dee3d2b14 100644 --- a/Marlin/buttons.h +++ b/Marlin/buttons.h @@ -1,3 +1,4 @@ +#ifdef FANCY_BUTTONS #define BUTTONS_HAVEENCODER @@ -58,3 +59,4 @@ void buttons_init(); void buttons_check(); +#endif \ No newline at end of file diff --git a/Marlin/buttons.pde b/Marlin/buttons.pde index fe449808c041..67707a7f7612 100644 --- a/Marlin/buttons.pde +++ b/Marlin/buttons.pde @@ -1,4 +1,6 @@ #include "buttons.h" +#ifdef FANCY_BUTTONS + long blocking[8]={ 0,0,0,0,0,0,0,0}; @@ -13,13 +15,16 @@ extern bool force_lcd_update; void buttons_check() { //read it from the shift register + volatile static bool busy=false; + if(busy) return; + busy=true; digitalWrite(SHIFT_LD,LOW); delayMicroseconds(20); digitalWrite(SHIFT_LD,HIGH); buttons=0; + long ms=millis(); for(short i=0;i<8;i++) - { - long ms=millis(); + { if((blocking[i] Date: Mon, 29 Aug 2011 23:59:39 +0200 Subject: [PATCH 021/130] trying to add redbutton sd-reset, so that moving to the file page does not stop sd printing --- Marlin/lcd.pde | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Marlin/lcd.pde b/Marlin/lcd.pde index 5914ffafd84d..f35d026e998f 100644 --- a/Marlin/lcd.pde +++ b/Marlin/lcd.pde @@ -330,6 +330,12 @@ PageSd::PageSd() void PageSd::update() { + if(buttons&B_ST) //reset sd card + { + sdactive = false; + sdmode = false; + initsd(); + } if(encoderpos!=lastencoder) //scoll through files { fileoffset=encoderpos%nrfiles; @@ -390,11 +396,7 @@ void PageSd::update() void PageSd::activate() { - dir_t p; - sdactive = false; - sdmode = false; - initsd(); - + dir_t p; root.rewind(); char filename[11]; @@ -559,9 +561,9 @@ void buttons_process() if(buttons&B_ST) { - Serial.println("Red"); + //Serial.println("Red"); blocking[BL_ST]=millis()+blocktime; - enquecommand("M115\n"); + //enquecommand("M115\n"); } if(buttons&B_LE) { From f231c9e9db6d7999e96064bb91665127d1fa7b4e Mon Sep 17 00:00:00 2001 From: bradleyf Date: Sun, 4 Sep 2011 14:46:11 -0400 Subject: [PATCH 022/130] Reapply code for implementing max endstops for X,Y,Z axis and fixing max endstops locking other axis' movements that was overwritten by Berhnard's last commits --- Marlin/Marlin.pde | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index b4b1ebaa16fe..d9619a4a7cc3 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -2118,8 +2118,12 @@ ISR(TIMER1_COMPA_vect) step_events_completed = current_block->step_event_count; } } - else // +direction - WRITE(X_DIR_PIN,!INVERT_X_DIR); + else { // +direction + WRITE(X_DIR_PIN,!INVERT_X_DIR); + if((READ(X_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_x >0)){ + step_events_completed = current_block->step_event_count; + } + } if ((out_bits & (1<step_event_count; } } - else // +direction + else { // +direction WRITE(Y_DIR_PIN,!INVERT_Y_DIR); + if((READ(Y_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_y >0)){ + step_events_completed = current_block->step_event_count; + } + } if ((out_bits & (1<step_event_count; } } - else // +direction - WRITE(Z_DIR_PIN,!INVERT_Z_DIR); + else { // +direction + WRITE(Z_DIR_PIN,!INVERT_Z_DIR); + if((READ(Z_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_z >0)){ + step_events_completed = current_block->step_event_count; + } + } #ifndef ADVANCE if ((out_bits & (1< Date: Fri, 9 Sep 2011 20:50:22 +0200 Subject: [PATCH 023/130] protospace: Analog fan --- Marlin/Configuration.h | 6 +++--- Marlin/Marlin.pde | 12 +++++++----- Marlin/lcd.pde | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 835f20247c28..b2ab89a3fbb2 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -44,8 +44,8 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the // Comment out (using // at the start of the line) to disable SD support: #define SDSUPPORT -//#define FANCY_LCD -//#define FANCY_BUTTONS +#define FANCY_LCD +#define FANCY_BUTTONS @@ -85,7 +85,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the //// MOVEMENT SETTINGS #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {60000, 60000, 300, 500000}; // set the max speeds +float max_feedrate[] = {120*60, 120*60, 200*60, 500000}; // set the max speeds float homing_feedrate[] = {2400, 2400, 200, 0}; // set the homing speeds bool axis_relative_modes[] = {false, false, false, false}; diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index d9619a4a7cc3..dca1584017ca 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -855,16 +855,18 @@ inline void process_commands() break; case 106: //M106 Fan On if (code_seen('S')){ - digitalWrite(FAN_PIN, HIGH); + digitalWrite(FAN_PIN,HIGH); analogWrite(FAN_PIN, constrain(code_value(),0,255) ); } else - digitalWrite(FAN_PIN, HIGH); + { + digitalWrite(FAN_PIN,HIGH); + analogWrite(FAN_PIN, 255); + } break; case 107: //M107 Fan Off + digitalWrite(FAN_PIN,LOW); analogWrite(FAN_PIN, 0); - - digitalWrite(FAN_PIN, LOW); break; case 82: @@ -2062,7 +2064,7 @@ ISR(TIMER1_COMPA_vect) sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) #ifdef FANCY_BUTTONS static int breakdown=0; - if((breakdown++)%1000==0) + if((breakdown++)%100==0) buttons_check(); #endif diff --git a/Marlin/lcd.pde b/Marlin/lcd.pde index f35d026e998f..08de4429578f 100644 --- a/Marlin/lcd.pde +++ b/Marlin/lcd.pde @@ -539,7 +539,7 @@ void lcd_init() //lcd.print(fillto(20,"booting!")); //lcd.setCursor(0, 1); //lcd.print("lets Marlin!"); - LCD_MESSAGE(fillto(LCD_WIDTH,"Marlin ready.")); + LCD_MESSAGE(fillto(LCD_WIDTH,"UltiMarlin ready.")); #endif menu.addMenuPage(&pagewatch); menu.addMenuPage(&pagemove); From 05a816dedc8a040169f036f1e504847d892445b6 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Fri, 9 Sep 2011 22:13:04 +0200 Subject: [PATCH 024/130] solved problem with floating buttons, limit of maximum velocity. --- Marlin/Configuration.h | 2 +- Marlin/buttons.pde | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index b2ab89a3fbb2..a597bdac4678 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -134,7 +134,7 @@ double Kd = 80/PID_dT; // hooke's law says: force = k * distance // bernoulli's priniciple says: v ^ 2 / 2 + g . h + pressure / density = constant // so: v ^ 2 is proportional to number of steps we advance the extruder -#define ADVANCE +//#define ADVANCE #ifdef ADVANCE #define EXTRUDER_ADVANCE_K 0.02 diff --git a/Marlin/buttons.pde b/Marlin/buttons.pde index 67707a7f7612..be1e60840caa 100644 --- a/Marlin/buttons.pde +++ b/Marlin/buttons.pde @@ -94,6 +94,7 @@ void buttons_init() pinMode(SHIFT_LD,OUTPUT); pinMode(SHIFT_EN,OUTPUT); pinMode(SHIFT_OUT,INPUT); + digitalWrite(SHIFT_OUT,HIGH); digitalWrite(SHIFT_LD,HIGH); //load has inverse logic digitalWrite(SHIFT_EN,LOW); //low active } From 083ff50b484660373a97d9a03f9677cd49673436 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Fri, 9 Sep 2011 22:49:28 +0200 Subject: [PATCH 025/130] timer --- Marlin/Marlin.pde | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index dca1584017ca..afbf741d449a 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -172,6 +172,8 @@ unsigned long previous_millis_cmd = 0; unsigned long max_inactive_time = 0; unsigned long stepper_inactive_time = 0; +unsigned long starttime=0; +unsigned long stoptime=0; #ifdef SDSUPPORT Sd2Card card; SdVolume volume; @@ -500,6 +502,15 @@ inline void get_command() if(sdpos >= filesize){ sdmode = false; Serial.println("Done printing file"); + stoptime=millis(); + char time[30]; + unsigned long t=(stoptime-starttime)/1000; + int sec,min; + min=t/60; + sec=t%60; + sprintf(time,"Time: %i:%i ",min,sec); + Serial.println(time); + LCD_MESSAGE(time); } if(!serial_count) return; //if empty line cmdbuffer[bufindw][serial_count] = 0; //terminate string @@ -719,6 +730,7 @@ inline void process_commands() case 24: //M24 - Start SD print if(sdactive){ sdmode = true; + starttime=millis(); } break; case 25: //M25 - Pause SD print From 7d753d2cf6dc3e187a23a41cfe7b75b7de7c9cab Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 10 Sep 2011 00:01:10 +0200 Subject: [PATCH 026/130] autostart debugging --- Marlin/Marlin.pde | 57 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index afbf741d449a..318aa8d80e51 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -228,6 +228,7 @@ inline void write_command(char *buf){ void setup() { + Serial.begin(BAUDRATE); Serial.print("Marlin "); Serial.println(version_string); @@ -361,8 +362,61 @@ void setup() plan_init(); // Initialize planner; st_init(); // Initialize stepper; // tp_init(); // Initialize temperature loop + checkautostart(); } +#ifdef SDSUPPORT +void checkautostart() +{ + if(!sdactive) + return; + static int lastnr=0; + char autoname[30]; + sprintf(autoname,"auto%i.g",lastnr); + for(int i=0;i 0) + { + for(int i=0;i Date: Sat, 10 Sep 2011 00:03:41 +0200 Subject: [PATCH 027/130] back to default config --- Marlin/Configuration.h | 6 +++--- Marlin/Marlin.pde | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index a597bdac4678..986fa39ef1d2 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -43,9 +43,9 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -#define SDSUPPORT -#define FANCY_LCD -#define FANCY_BUTTONS +//#define SDSUPPORT +//#define FANCY_LCD +//#define FANCY_BUTTONS diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 318aa8d80e51..7023bec8e0f0 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -225,7 +225,6 @@ inline void write_command(char *buf){ } #endif //SDSUPPORT - void setup() { From a9f2c95e0a200c3502bb36b4b747e62ab05fe816 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 10 Sep 2011 04:21:13 +0200 Subject: [PATCH 028/130] added minute counting for no-sdcard printing --- Marlin/Configuration.h | 6 +++--- Marlin/Marlin.pde | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 986fa39ef1d2..a597bdac4678 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -43,9 +43,9 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -//#define SDSUPPORT -//#define FANCY_LCD -//#define FANCY_BUTTONS +#define SDSUPPORT +#define FANCY_LCD +#define FANCY_BUTTONS diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 7023bec8e0f0..b1a983e6e67e 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -837,6 +837,19 @@ inline void process_commands() //processed in write to file routine above //savetosd = false; break; + case 30: + { + stoptime=millis(); + char time[30]; + unsigned long t=(stoptime-starttime)/1000; + int sec,min; + min=t/60; + sec=t%60; + sprintf(time,"%i min, %i sec",min,sec); + Serial.println(time); + LCD_MESSAGE(time); + } + break; #endif //SDSUPPORT case 104: // M104 if (code_seen('S')) target_raw = temp2analog(code_value()); @@ -887,6 +900,7 @@ inline void process_commands() } #endif codenum = millis(); + starttime=millis(); while(current_raw < target_raw) { if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. { From 07d19621865b5f5f55e91d74ed1c57c02d0d6130 Mon Sep 17 00:00:00 2001 From: bradleyf Date: Tue, 13 Sep 2011 00:04:06 -0400 Subject: [PATCH 029/130] Keep floating point math pure -- to attempt to prevent rounding errors and skewing --- Marlin/Marlin.pde | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index b1a983e6e67e..999de3da70aa 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1601,7 +1601,7 @@ void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit // acceleration within the allotted distance. inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { return( - sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) + sqrt(target_velocity*target_velocity-2*acceleration*60.0*60.0*distance) ); } @@ -1855,7 +1855,7 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); unsigned long microseconds; - microseconds = lround((block->millimeters/feed_rate)*1000000); + microseconds = lround((block->millimeters/feed_rate)*1000000.0); // Calculate speed in mm/minute for each axis float multiplier = 60.0*1000000.0/microseconds; @@ -1865,7 +1865,7 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->speed_e = delta_e_mm * multiplier; // Limit speed per axis - float speed_factor = 1; + float speed_factor = 1.0; float tmp_speed_factor; if(abs(block->speed_x) > max_feedrate[X_AXIS]) { speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); @@ -1888,9 +1888,9 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->speed_y = delta_y_mm * multiplier; block->speed_e = delta_e_mm * multiplier; block->nominal_speed = block->millimeters * multiplier; - block->nominal_rate = ceil(block->step_event_count * multiplier / 60); + block->nominal_rate = ceil(block->step_event_count * multiplier / 60.0); - if(block->nominal_rate < 120) block->nominal_rate = 120; + if(block->nominal_rate < 120.0) block->nominal_rate = 120.0; block->entry_speed = safe_speed(block); // Compute the acceleration rate for the trapezoid generator. @@ -1914,16 +1914,16 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { #ifdef ADVANCE // Calculate advance rate if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { - block->advance_rate = 0; - block->advance = 0; + block->advance_rate = 0.0; + block->advance = 0.0; } else { long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration); float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * - (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; + (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536.0; block->advance = advance; if(acc_dist == 0) { - block->advance_rate = 0; + block->advance_rate = 0.0; } else { block->advance_rate = advance / (float)acc_dist; From c8f734db73d60a5c23bb5b3100787ea4a4aba2b0 Mon Sep 17 00:00:00 2001 From: bradleyf Date: Tue, 13 Sep 2011 00:17:08 -0400 Subject: [PATCH 030/130] Disable SDSUPPORT by default so that folks can use RepG to connect --- Marlin/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index a597bdac4678..f097ce319e76 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -43,7 +43,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -#define SDSUPPORT +//#define SDSUPPORT #define FANCY_LCD #define FANCY_BUTTONS From 659f607dd86eab305db9919d80b0b6e78157a5fb Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 13 Sep 2011 19:29:47 +0200 Subject: [PATCH 031/130] step debugging --- Marlin/Marlin.pde | 34 ++++++++++++++++++++++++++++++++++ Marlin/lcd.pde | 33 +++++++++------------------------ 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index b1a983e6e67e..a79dddd44509 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1,6 +1,7 @@ #include "Marlin.h" // This struct is used when buffering the setup for each linear movement "nominal" values are as specified in // the source g-code and may never actually be reached if acceleration management is active. +#define DEBUG_STEPS #include "speed_lookuptable.h" @@ -53,6 +54,10 @@ char version_string[] = "U0.9.3.1"; #define CRITICAL_SECTION_END SREG = _sreg #endif //CRITICAL_SECTION_START + +#ifdef DEBUG_STEPS +volatile long stepstaken[4]; +#endif // look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html // http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes @@ -1843,6 +1848,15 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); +#ifdef DEBUG_STEPS + Serial.print("(Planned: "); + Serial.print(abs(block->steps_x));Serial.print(" "); + Serial.print(abs(block->steps_y));Serial.print(" "); + Serial.print(abs(block->steps_z));Serial.print(" "); + Serial.print(abs(block->steps_e));Serial.print(" "); + Serial.println(); + +#endif // Bail if this is a zero-length block if (block->step_event_count == 0) { return; @@ -2132,6 +2146,7 @@ inline void trapezoid_generator_reset() { OCR1A = acceleration_time; } + // "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. // It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. ISR(TIMER1_COMPA_vect) @@ -2160,6 +2175,9 @@ ISR(TIMER1_COMPA_vect) counter_e = counter_x; step_events_completed = 0; e_steps = 0; +#ifdef DEBUG_STEPS + stepstaken[0]=0;stepstaken[1]=0;stepstaken[2]=0;stepstaken[3]=0; +#endif } else { DISABLE_STEPPER_DRIVER_INTERRUPT(); @@ -2245,6 +2263,9 @@ ISR(TIMER1_COMPA_vect) WRITE(X_STEP_PIN, HIGH); counter_x -= current_block->step_event_count; WRITE(X_STEP_PIN, LOW); + #ifdef DEBUG_STEPS + stepstaken[0]++; + #endif } counter_y += current_block->steps_y; @@ -2252,6 +2273,9 @@ ISR(TIMER1_COMPA_vect) WRITE(Y_STEP_PIN, HIGH); counter_y -= current_block->step_event_count; WRITE(Y_STEP_PIN, LOW); + #ifdef DEBUG_STEPS + stepstaken[1]++; + #endif } counter_z += current_block->steps_z; @@ -2259,6 +2283,9 @@ ISR(TIMER1_COMPA_vect) WRITE(Z_STEP_PIN, HIGH); counter_z -= current_block->step_event_count; WRITE(Z_STEP_PIN, LOW); + #ifdef DEBUG_STEPS + stepstaken[2]++; + #endif } #ifndef ADVANCE @@ -2316,9 +2343,16 @@ ISR(TIMER1_COMPA_vect) if (step_events_completed >= current_block->step_event_count) { current_block = NULL; plan_discard_current_block(); +#ifdef DEBUG_STEPS + Serial.print("(Steps done: "); + Serial.print(stepstaken[0]);Serial.print(" "); + Serial.print(stepstaken[1]);Serial.print(" "); + Serial.print(stepstaken[2]);Serial.println(" "); +#endif } } busy=false; + } #ifdef ADVANCE diff --git a/Marlin/lcd.pde b/Marlin/lcd.pde index 08de4429578f..6c3d596f1c16 100644 --- a/Marlin/lcd.pde +++ b/Marlin/lcd.pde @@ -22,6 +22,7 @@ bool force_lcd_update=false; extern LiquidCrystal lcd; + //return for string conversion routines char conv[8]; @@ -321,6 +322,7 @@ public: int fileoffset,nrfiles; }; +#define FILTERSD if (p.name[0] == DIR_NAME_FREE) break;if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;if(p.name[8]!='G') continue;if(p.name[9]=='~') continue; PageSd::PageSd() { xshift=10;items=7;firstline=0; @@ -357,15 +359,7 @@ void PageSd::update() lastencoder=encoderpos; while (root.readDir(p) > 0) { - // done if past last used entry - if (p.name[0] == DIR_NAME_FREE) break; - - // skip deleted entry and entries for . and .. - if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue; - - // only list subdirectories and files - if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; - + FILTERSD uint8_t writepos=0; for (uint8_t i = 0; i < 11; i++) { @@ -406,13 +400,11 @@ void PageSd::activate() while (root.readDir(p) > 0) { // done if past last used entry - if (p.name[0] == DIR_NAME_FREE) break; - - // skip deleted entry and entries for . and .. - if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue; - - // only list subdirectories and files - if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; + FILTERSD + Serial.println((char*)p.name); + Serial.println(strlen((char*)p.name)); + Serial.println((char)p.name[strlen((char*)p.name)-1]); + nrfiles++; } root.rewind(); @@ -420,14 +412,7 @@ void PageSd::activate() int precount=0; while (root.readDir(p) > 0) { - // done if past last used entry - if (p.name[0] == DIR_NAME_FREE) break; - - // skip deleted entry and entries for . and .. - if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue; - - // only list subdirectories and files - if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; + FILTERSD if(precount++ Date: Wed, 14 Sep 2011 13:20:18 +0300 Subject: [PATCH 032/130] disabled the step debugging for default users --- Marlin/Marlin.pde | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 2cf224431465..a3ca83983553 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1,7 +1,8 @@ #include "Marlin.h" // This struct is used when buffering the setup for each linear movement "nominal" values are as specified in // the source g-code and may never actually be reached if acceleration management is active. -#define DEBUG_STEPS + +//#define DEBUG_STEPS #include "speed_lookuptable.h" From 309774a51ec73c1b7c3674864096fc1d8eebfe73 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Wed, 14 Sep 2011 13:21:35 +0300 Subject: [PATCH 033/130] larger speed limits --- Marlin/Configuration.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index f097ce319e76..0c7c11137989 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -44,8 +44,8 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the // Comment out (using // at the start of the line) to disable SD support: //#define SDSUPPORT -#define FANCY_LCD -#define FANCY_BUTTONS +//#define FANCY_LCD +//#define FANCY_BUTTONS @@ -85,7 +85,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the //// MOVEMENT SETTINGS #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {120*60, 120*60, 200*60, 500000}; // set the max speeds +float max_feedrate[] = {240*60, 240*60, 350*60, 500000}; // set the max speeds float homing_feedrate[] = {2400, 2400, 200, 0}; // set the homing speeds bool axis_relative_modes[] = {false, false, false, false}; From 87eb94101985a80dc40a07dc2e25ef0cfb9d5f53 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Wed, 14 Sep 2011 20:01:24 +0200 Subject: [PATCH 034/130] leftovers --- Marlin/Configuration.h | 2 +- Marlin/Marlin.pde | 38 ++++++++++++++++++-------------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index f097ce319e76..a597bdac4678 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -43,7 +43,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -//#define SDSUPPORT +#define SDSUPPORT #define FANCY_LCD #define FANCY_BUTTONS diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 2cf224431465..3dffc0c62e9c 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1,7 +1,7 @@ #include "Marlin.h" // This struct is used when buffering the setup for each linear movement "nominal" values are as specified in // the source g-code and may never actually be reached if acceleration management is active. -#define DEBUG_STEPS +//#define DEBUG_STEPS #include "speed_lookuptable.h" @@ -56,7 +56,7 @@ char version_string[] = "U0.9.3.1"; #ifdef DEBUG_STEPS -volatile long stepstaken[4]; +long stepstaken[4]; #endif // look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html // http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes @@ -1606,7 +1606,7 @@ void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit // acceleration within the allotted distance. inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { return( - sqrt(target_velocity*target_velocity-2*acceleration*60.0*60.0*distance) + sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) ); } @@ -1848,15 +1848,7 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); -#ifdef DEBUG_STEPS - Serial.print("(Planned: "); - Serial.print(abs(block->steps_x));Serial.print(" "); - Serial.print(abs(block->steps_y));Serial.print(" "); - Serial.print(abs(block->steps_z));Serial.print(" "); - Serial.print(abs(block->steps_e));Serial.print(" "); - Serial.println(); - -#endif + // Bail if this is a zero-length block if (block->step_event_count == 0) { return; @@ -1869,7 +1861,7 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); unsigned long microseconds; - microseconds = lround((block->millimeters/feed_rate)*1000000.0); + microseconds = lround((block->millimeters/feed_rate)*1000000); // Calculate speed in mm/minute for each axis float multiplier = 60.0*1000000.0/microseconds; @@ -1879,7 +1871,7 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->speed_e = delta_e_mm * multiplier; // Limit speed per axis - float speed_factor = 1.0; + float speed_factor = 1; float tmp_speed_factor; if(abs(block->speed_x) > max_feedrate[X_AXIS]) { speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); @@ -1902,9 +1894,9 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->speed_y = delta_y_mm * multiplier; block->speed_e = delta_e_mm * multiplier; block->nominal_speed = block->millimeters * multiplier; - block->nominal_rate = ceil(block->step_event_count * multiplier / 60.0); + block->nominal_rate = ceil(block->step_event_count * multiplier / 60); - if(block->nominal_rate < 120.0) block->nominal_rate = 120.0; + if(block->nominal_rate < 120) block->nominal_rate = 120; block->entry_speed = safe_speed(block); // Compute the acceleration rate for the trapezoid generator. @@ -1928,16 +1920,16 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { #ifdef ADVANCE // Calculate advance rate if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { - block->advance_rate = 0.0; - block->advance = 0.0; + block->advance_rate = 0; + block->advance = 0; } else { long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration); float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * - (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536.0; + (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; block->advance = advance; if(acc_dist == 0) { - block->advance_rate = 0.0; + block->advance_rate = 0; } else { block->advance_rate = advance / (float)acc_dist; @@ -2177,6 +2169,12 @@ ISR(TIMER1_COMPA_vect) e_steps = 0; #ifdef DEBUG_STEPS stepstaken[0]=0;stepstaken[1]=0;stepstaken[2]=0;stepstaken[3]=0; + Serial.print("(Planned: "); + Serial.print(abs(current_block->steps_x));Serial.print(" "); + Serial.print(abs(current_block->steps_y));Serial.print(" "); + Serial.print(abs(current_block->steps_z));Serial.print(" "); + //Serial.print(abs(current_block->steps_e));Serial.print(" "); + Serial.println(); #endif } else { From c4b330cb32d870f3cf970a6432cd5648445dc832 Mon Sep 17 00:00:00 2001 From: bradleyf Date: Wed, 14 Sep 2011 15:17:37 -0400 Subject: [PATCH 035/130] Extruder Stepper now properly disables as necessary --- Marlin/Marlin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 9ff0f51532cd..f1b2f35e0d21 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -85,7 +85,7 @@ float analog2tempBed(int raw); #if E_ENABLE_PIN > -1 #define enable_e() WRITE(E_ENABLE_PIN, E_ENABLE_ON) - #define disable_e() WRITE(E_ENABLE_PIN,E_ENABLE_ON) + #define disable_e() WRITE(E_ENABLE_PIN,!E_ENABLE_ON) #else #define enable_e() ; #define disable_e() ; From a6de9cf1e7dfb9eee83c337a88107e02c2dc28e6 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 17 Sep 2011 00:55:51 +0200 Subject: [PATCH 036/130] added a lot of corrections --- Marlin/Configuration.h | 23 +-- Marlin/Makefile | 447 ++++++++++++++++++++++------------------- Marlin/Marlin.h | 60 +++--- Marlin/Marlin.pde | 139 +++++++------ Marlin/lcd.pde | 7 +- 5 files changed, 364 insertions(+), 312 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 221d6764ff9d..36efc7ad7ddd 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -43,9 +43,9 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -#define SDSUPPORT -#define FANCY_LCD -#define FANCY_BUTTONS +//#define SDSUPPORT +//#define FANCY_LCD +//#define FANCY_BUTTONS @@ -86,18 +86,17 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the //// MOVEMENT SETTINGS #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {240*60, 240*60, 350*60, 500000}; // set the max speeds -float homing_feedrate[] = {2400, 2400, 200, 0}; // set the homing speeds +float max_feedrate[] = {240*60, 240*60, 500*60, 500000}; // set the max speeds +float homing_feedrate[] = {3400, 3400, 60*500, 0}; // set the homing speeds bool axis_relative_modes[] = {false, false, false, false}; //// Acceleration settings // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. float acceleration = 4000; // Normal acceleration mm/s^2 -float retract_acceleration = 10000; // Normal acceleration mm/s^2 -float max_jerk = 20*60; -long max_acceleration_units_per_sq_second[] = {15000,15000,150000,15000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts -// Not used long max_travel_acceleration_units_per_sq_second[] = {500,500,50,500}; // X, Y, Z max acceleration in mm/s^2 for travel moves - +float retract_acceleration = 7000; // Normal acceleration mm/s^2 +float max_xy_jerk = 20.0*60; +float max_z_jerk = 0.4*60; +long max_acceleration_units_per_sq_second[] = {7000,7000,15000,10000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts // The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature // If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 @@ -140,8 +139,8 @@ double Kd = 80/PID_dT; #ifdef ADVANCE #define EXTRUDER_ADVANCE_K 0.02 -#define D_FILAMENT 2.75 -//#define STEPS_MM_E 600 //this seems uncessesary +#define D_FILAMENT 1.7 +#define STEPS_MM_E 65 #define EXTRUTION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159) #define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUTION_AREA) diff --git a/Marlin/Makefile b/Marlin/Makefile index 06e643d4aa57..6fafba13b070 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -1,247 +1,274 @@ -# Marlin Arduino Project Makefile -# -# Makefile Based on: -# Arduino 0011 Makefile -# Arduino adaptation by mellis, eighthave, oli.keller # -# This has been tested with Arduino 0022. -# -# This makefile allows you to build sketches from the command line -# without the Arduino environment (or Java). +# Arduino 0022 Makefile +# Uno with DOGS102 Shield # -# Detailed instructions for using the makefile: +# written by olikraus@gmail.com # -# 1. Modify the line containg "INSTALL_DIR" to point to the directory that -# contains the Arduino installation (for example, under Mac OS X, this -# might be /Applications/arduino-0012). +# Features: +# - boards.txt is used to derive parameters +# - All intermediate files are put into a separate directory (TMPDIRNAME) +# - Simple use: Copy Makefile into the same directory of the .pde file # -# 2. Modify the line containing "PORT" to refer to the filename -# representing the USB or serial connection to your Arduino board -# (e.g. PORT = /dev/tty.USB0). If the exact name of this file -# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.usb*). +# Limitations: +# - requires UNIX environment +# - TMPDIRNAME must be subdirectory of the current directory. # -# 3. Set the line containing "MCU" to match your board's processor. -# Older one's are atmega8 based, newer ones like Arduino Mini, Bluetooth -# or Diecimila have the atmega168. If you're using a LilyPad Arduino, -# change F_CPU to 8000000. +# Targets +# all build everything +# upload build and upload to arduino +# clean remove all temporary files (includes final hex file) # -# 4. Type "make" and press enter to compile/verify your program. +# History +# 001 28 Apr 2010 first release +# 002 05 Oct 2010 added 'uno' # -# 5. Type "make upload", reset your Arduino board, and press enter to -# upload your program to the Arduino board. -# -# $Id$ - -TARGET = Marlin -INSTALL_DIR = ../../Desktop/arduino-0018/ -UPLOAD_RATE = 38400 -AVRDUDE_PROGRAMMER = stk500v1 -PORT = /dev/ttyUSB0 -#MCU = atmega2560 -#For "old" Arduino Mega -#MCU = atmega1280 -#For Sanguinololu -MCU = atmega644p -F_CPU = 16000000 - - -############################################################################ -# Below here nothing should be changed... - -ARDUINO = $(INSTALL_DIR)/hardware/Sanguino/cores/arduino -AVR_TOOLS_PATH = $(INSTALL_DIR)/hardware/tools/avr/bin -SRC = $(ARDUINO)/pins_arduino.c wiring.c wiring_serial.c \ -$(ARDUINO)/wiring_analog.c $(ARDUINO)/wiring_digital.c \ -$(ARDUINO)/wiring_pulse.c \ -$(ARDUINO)/wiring_shift.c $(ARDUINO)/WInterrupts.c -CXXSRC = $(ARDUINO)/HardwareSerial.cpp $(ARDUINO)/WMath.cpp \ -$(ARDUINO)/Print.cpp ./SdFile.cpp ./SdVolume.cpp ./Sd2Card.cpp -FORMAT = ihex - - -# Name of this Makefile (used for "make depend"). -MAKEFILE = Makefile - -# Debugging format. -# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. -# AVR (extended) COFF requires stabs, plus an avr-objcopy run. -DEBUG = stabs - -OPT = s - -# Place -D or -U options here -CDEFS = -DF_CPU=$(F_CPU) -CXXDEFS = -DF_CPU=$(F_CPU) - -# Place -I options here -CINCS = -I$(ARDUINO) -CXXINCS = -I$(ARDUINO) - -# Compiler flag to set the C Standard level. -# c89 - "ANSI" C -# gnu89 - c89 plus GCC extensions -# c99 - ISO C99 standard (not yet fully implemented) -# gnu99 - c99 plus GCC extensions -#CSTANDARD = -std=gnu99 -CDEBUG = -g$(DEBUG) -CWARN = -Wall -Wunused-variable -CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -w -ffunction-sections -fdata-sections -DARDUINO=22 -#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) - -CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CEXTRA) $(CTUNING) -CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT) -Wall $(CEXTRA) $(CTUNING) -#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs -LDFLAGS = -lm - - -# Programming support using avrdude. Settings and variables. -AVRDUDE_PORT = $(PORT) -AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex:i -AVRDUDE_FLAGS = -D -C $(INSTALL_DIR)/hardware/tools/avrdude.conf \ --p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ --b $(UPLOAD_RATE) - -# Program settings -CC = $(AVR_TOOLS_PATH)/avr-gcc -CXX = $(AVR_TOOLS_PATH)/avr-g++ -OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy -OBJDUMP = $(AVR_TOOLS_PATH)/avr-objdump -AR = $(AVR_TOOLS_PATH)/avr-ar -SIZE = $(AVR_TOOLS_PATH)/avr-size -NM = $(AVR_TOOLS_PATH)/avr-nm -AVRDUDE = $(INSTALL_DIR)/hardware/tools/avrdude -REMOVE = rm -f -MV = mv -f - -# Define all object files. -OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) - -# Define all listing files. -LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) - -# Combine all necessary flags and optional flags. -# Add target processor to flags. -ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) -ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) -ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) - - -# Default target. -all: applet_files_ez build sizeafter - -build: elf hex - -applet_files_ez: $(TARGET).pde - # Here is the "preprocessing". - # It creates a .cpp file based with the same name as the .pde file. - # On top of the new .cpp file comes the WProgram.h header. - # At the end there is a generic main() function attached. - # Then the .cpp file will be compiled. Errors during compile will - # refer to this new, automatically generated, file. - # Not the original .pde file you actually edit... - test -d applet || mkdir applet - echo '#include "WProgram.h"' > applet/$(TARGET).cpp - cat $(TARGET).pde >> applet/$(TARGET).cpp - cat $(ARDUINO)/main.cpp >> applet/$(TARGET).cpp - -elf: applet/$(TARGET).elf -hex: applet/$(TARGET).hex -eep: applet/$(TARGET).eep -lss: applet/$(TARGET).lss -sym: applet/$(TARGET).sym -# Program the device. -upload: applet/$(TARGET).hex - $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) +#=== user configuration === +# All ...PATH variables must have a '/' at the end +# Board (and prozessor) information: see $(ARDUINO_PATH)hardware/arduino/boards.txt +# Some examples: +# BOARD DESCRIPTION +# uno Arduino Uno +# atmega328 Arduino Duemilanove or Nano w/ ATmega328 +# diecimila Arduino Diecimila, Duemilanove, or Nano w/ ATmega168 +# mega Arduino Mega +# mini Arduino Mini +# lilypad328 LilyPad Arduino w/ ATmega328 +BOARD:=mega - # Display size of file. -HEXSIZE = $(SIZE) --target=$(FORMAT) applet/$(TARGET).hex -ELFSIZE = $(SIZE) applet/$(TARGET).elf -sizebefore: - @if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(HEXSIZE); echo; fi +# additional (comma separated) defines +# -DDOGM128_HW board is connected to DOGM128 display +# -DDOGM132_HW board is connected to DOGM132 display +# -DDOGS102_HW board is connected to DOGS102 display +# -DDOG_REVERSE 180 degree rotation +# -DDOG_SPI_SW_ARDUINO force SW shiftOut +DEFS=-DDOGS102_HW -DDOG_DOUBLE_MEMORY -DDOG_SPI_SW_ARDUINO -sizeafter: - @if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(HEXSIZE); echo; fi +# The location where the avr tools (e.g. avr-gcc) are located. Requires a '/' at the end. +# Can be empty if all tools are accessable through the search path +AVR_TOOLS_PATH:=/usr/bin/ + +# Install path of the arduino software. Requires a '/' at the end. +ARDUINO_PATH:=/home/bkubicek/software/arduino-0022/ + +# Install path for avrdude. Requires a '/' at the end. Can be empty if avrdude is in the search path. +AVRDUDE_PATH:= + +# The unix device where we can reach the arduino board +# Uno: /dev/ttyACM0 +# Duemilanove: /dev/ttyUSB0 +AVRDUDE_PORT:=/dev/ttyACM0 + +# List of all libaries which should be included. +#EXTRA_DIRS=$(ARDUINO_PATH)libraries/LiquidCrystal/ +#EXTRA_DIRS+=$(ARDUINO_PATH)libraries/Dogm/ +#EXTRA_DIRS+=/home/kraus/src/arduino/dogm128/hg/libraries/Dogm/ + +#=== fetch parameter from boards.txt processor parameter === +# the basic idea is to get most of the information from boards.txt +BOARDS_TXT:=$(ARDUINO_PATH)hardware/arduino/boards.txt + +# get the MCU value from the $(BOARD).build.mcu variable. For the atmega328 board this is atmega328p +MCU:=$(shell sed -n -e "s/$(BOARD).build.mcu=\(.*\)/\1/p" $(BOARDS_TXT)) +# get the F_CPU value from the $(BOARD).build.f_cpu variable. For the atmega328 board this is 16000000 +F_CPU:=$(shell sed -n -e "s/$(BOARD).build.f_cpu=\(.*\)/\1/p" $(BOARDS_TXT)) -# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. -COFFCONVERT=$(OBJCOPY) --debugging \ ---change-section-address .data-0x800000 \ ---change-section-address .bss-0x800000 \ ---change-section-address .noinit-0x800000 \ ---change-section-address .eeprom-0x810000 +# avrdude +# get the AVRDUDE_UPLOAD_RATE value from the $(BOARD).upload.speed variable. For the atmega328 board this is 57600 +AVRDUDE_UPLOAD_RATE:=$(shell sed -n -e "s/$(BOARD).upload.speed=\(.*\)/\1/p" $(BOARDS_TXT)) +# get the AVRDUDE_PROGRAMMER value from the $(BOARD).upload.protocol variable. For the atmega328 board this is stk500 +# AVRDUDE_PROGRAMMER:=$(shell sed -n -e "s/$(BOARD).upload.protocol=\(.*\)/\1/p" $(BOARDS_TXT)) +# use stk500v1, because stk500 will default to stk500v2 +AVRDUDE_PROGRAMMER:=stk500v1 +#=== identify user files === +PDESRC:=$(shell ls *.pde) +TARGETNAME=$(basename $(PDESRC)) -coff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf $(TARGET).cof +CDIRS:=$(EXTRA_DIRS) $(addsuffix utility/,$(EXTRA_DIRS)) +CDIRS:=*.c utility/*.c $(addsuffix *.c,$(CDIRS)) $(ARDUINO_PATH)hardware/arduino/cores/arduino/*.c +CSRC:=$(shell ls $(CDIRS) 2>/dev/null) +CCSRC:=$(shell ls *.cc 2>/dev/null) -extcoff: $(TARGET).elf - $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf $(TARGET).cof +CPPDIRS:=$(EXTRA_DIRS) $(addsuffix utility/,$(EXTRA_DIRS)) +CPPDIRS:=*.cpp utility/*.cpp $(addsuffix *.cpp,$(CPPDIRS)) $(ARDUINO_PATH)hardware/arduino/cores/arduino/*.cpp +CPPSRC:=$(shell ls $(CPPDIRS) 2>/dev/null) +#=== build internal variables === -.SUFFIXES: .elf .hex .eep .lss .sym +# the name of the subdirectory where everything is stored +TMPDIRNAME:=tmp +TMPDIRPATH:=$(TMPDIRNAME)/ + +AVRTOOLSPATH:=$(AVR_TOOLS_PATH) + +OBJCOPY:=$(AVRTOOLSPATH)avr-objcopy +OBJDUMP:=$(AVRTOOLSPATH)avr-objdump +SIZE:=$(AVRTOOLSPATH)avr-size + +CPPSRC:=$(addprefix $(TMPDIRPATH),$(PDESRC:.pde=.cpp)) $(CPPSRC) + +COBJ:=$(CSRC:.c=.o) +CCOBJ:=$(CCSRC:.cc=.o) +CPPOBJ:=$(CPPSRC:.cpp=.o) + +OBJFILES:=$(COBJ) $(CCOBJ) $(CPPOBJ) +DIRS:= $(dir $(OBJFILES)) + +DEPFILES:=$(OBJFILES:.o=.d) +# assembler files from avr-gcc -S +ASSFILES:=$(OBJFILES:.o=.s) +# disassembled object files with avr-objdump -S +DISFILES:=$(OBJFILES:.o=.dis) -.elf.hex: - $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ -.elf.eep: - -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ - --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ +LIBNAME:=$(TMPDIRPATH)$(TARGETNAME).a +ELFNAME:=$(TMPDIRPATH)$(TARGETNAME).elf +HEXNAME:=$(TMPDIRPATH)$(TARGETNAME).hex -# Create extended listing file from ELF output file. -.elf.lss: - $(OBJDUMP) -h -S $< > $@ +AVRDUDE_FLAGS = -V -F +AVRDUDE_FLAGS += -C $(ARDUINO_PATH)/hardware/tools/avrdude.conf +AVRDUDE_FLAGS += -p $(MCU) +AVRDUDE_FLAGS += -P $(AVRDUDE_PORT) +AVRDUDE_FLAGS += -c $(AVRDUDE_PROGRAMMER) +AVRDUDE_FLAGS += -b $(AVRDUDE_UPLOAD_RATE) +AVRDUDE_FLAGS += -U flash:w:$(HEXNAME) -# Create a symbol table from ELF output file. -.elf.sym: - $(NM) -n $< > $@ +AVRDUDE = avrdude - # Link: create ELF output file from library. -applet/$(TARGET).elf: $(TARGET).pde applet/core.a - $(CC) $(ALL_CFLAGS) -Wl,--gc-sections -o $@ applet/$(TARGET).cpp -L. applet/core.a $(LDFLAGS) +#=== predefined variable override === +# use "make -p -f/dev/null" to see the default rules and definitions -applet/core.a: $(OBJ) - @for i in $(OBJ); do echo $(AR) rcs applet/core.a $$i; $(AR) rcs applet/core.a $$i; done +# Build C and C++ flags. Include path information must be placed here +COMMON_FLAGS = -DF_CPU=$(F_CPU) -mmcu=$(MCU) $(DEFS) +# COMMON_FLAGS += -gdwarf-2 +COMMON_FLAGS += -Os +COMMON_FLAGS += -Wall -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +COMMON_FLAGS += -I. +COMMON_FLAGS += -I$(ARDUINO_PATH)hardware/arduino/cores/arduino +COMMON_FLAGS += $(addprefix -I,$(EXTRA_DIRS)) +COMMON_FLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections +COMMON_FLAGS += -Wl,--relax +COMMON_FLAGS += -mcall-prologues +CFLAGS = $(COMMON_FLAGS) -std=gnu99 -Wstrict-prototypes +CXXFLAGS = $(COMMON_FLAGS) +# Replace standard build tools by avr tools +CC = $(AVRTOOLSPATH)avr-gcc +CXX = $(AVRTOOLSPATH)avr-g++ +AR = @$(AVRTOOLSPATH)avr-ar -# Compile: create object files from C++ source files. -.cpp.o: - $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ -# Compile: create object files from C source files. -.c.o: - $(CC) -c $(ALL_CFLAGS) $< -o $@ +# "rm" must be able to delete a directory tree +RM = rm -rf +#=== rules === -# Compile: create assembler files from C source files. -.c.s: - $(CC) -S $(ALL_CFLAGS) $< -o $@ +# add rules for the C/C++ files where the .o file is placed in the TMPDIRPATH +# reuse existing variables as far as possible +$(TMPDIRPATH)%.o: %.c + @echo compile $< + @$(COMPILE.c) $(OUTPUT_OPTION) $< + +$(TMPDIRPATH)%.o: %.cc + @echo compile $< + @$(COMPILE.cc) $(OUTPUT_OPTION) $< + +$(TMPDIRPATH)%.o: %.cpp + @echo compile $< + @$(COMPILE.cpp) $(OUTPUT_OPTION) $< + +$(TMPDIRPATH)%.s: %.c + @$(COMPILE.c) $(OUTPUT_OPTION) -S $< + +$(TMPDIRPATH)%.s: %.cc + @$(COMPILE.cc) $(OUTPUT_OPTION) -S $< + +$(TMPDIRPATH)%.s: %.cpp + @$(COMPILE.cpp) $(OUTPUT_OPTION) -S $< + +$(TMPDIRPATH)%.dis: $(TMPDIRPATH)%.o + @$(OBJDUMP) -S $< > $@ + +.SUFFIXES: .elf .hex .pde + +.elf.hex: + @$(OBJCOPY) -O ihex -R .eeprom $< $@ + +$(TMPDIRPATH)%.cpp: %.pde + @cat $(ARDUINO_PATH)hardware/arduino/cores/arduino/main.cpp > $@ + @cat $< >> $@ + @echo >> $@ + @echo 'extern "C" void __cxa_pure_virtual() { while (1); }' >> $@ -# Assemble: create object files from assembler source files. -.S.o: - $(CC) -c $(ALL_ASFLAGS) $< -o $@ +.PHONY: all +all: tmpdir $(HEXNAME) assemblersource showsize + ls -al $(HEXNAME) $(ELFNAME) +$(ELFNAME): $(LIBNAME)($(addprefix $(TMPDIRPATH),$(OBJFILES))) + $(LINK.o) $(COMMON_FLAGS) $(LIBNAME) $(LOADLIBES) $(LDLIBS) -o $@ -# Target: clean project. +$(LIBNAME)(): $(addprefix $(TMPDIRPATH),$(OBJFILES)) + +#=== create temp directory === +# not really required, because it will be also created during the dependency handling +.PHONY: tmpdir +tmpdir: + @test -d $(TMPDIRPATH) || mkdir $(TMPDIRPATH) + +#=== create assembler files for each C/C++ file === +.PHONY: assemblersource +assemblersource: $(addprefix $(TMPDIRPATH),$(ASSFILES)) $(addprefix $(TMPDIRPATH),$(DISFILES)) + + +#=== show the section sizes of the ELF file === +.PHONY: showsize +showsize: $(ELFNAME) + $(SIZE) $< + +#=== clean up target === +# this is simple: the TMPDIRPATH is removed +.PHONY: clean clean: - $(REMOVE) applet/$(TARGET).hex applet/$(TARGET).eep applet/$(TARGET).cof applet/$(TARGET).elf \ - applet/$(TARGET).map applet/$(TARGET).sym applet/$(TARGET).lss applet/core.a \ - $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) - -depend: - if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ - then \ - sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ - $(MAKEFILE).$$$$ && \ - $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ - fi - echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ - >> $(MAKEFILE); \ - $(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE) - -.PHONY: all build elf hex eep lss sym program coff extcoff clean depend applet_files sizebefore sizeafter + $(RM) $(TMPDIRPATH) + +# Program the device. +# step 1: reset the arduino board with the stty command +# step 2: user avrdude to upload the software +.PHONY: upload +upload: $(HEXNAME) + stty -F $(AVRDUDE_PORT) hupcl + $(AVRDUDE) $(AVRDUDE_FLAGS) + + +# === dependency handling === +# From the gnu make manual (section 4.14, Generating Prerequisites Automatically) +# Additionally (because this will be the first executed rule) TMPDIRPATH is created here. +# Instead of "sed" the "echo" command is used +# cd $(TMPDIRPATH); mkdir -p $(DIRS) 2> /dev/null; cd .. +DEPACTION=test -d $(TMPDIRPATH) || mkdir $(TMPDIRPATH);\ +mkdir -p $(addprefix $(TMPDIRPATH),$(DIRS));\ +set -e; echo -n $@ $(dir $@) > $@; $(CC) -MM $(COMMON_FLAGS) $< >> $@ + + +$(TMPDIRPATH)%.d: %.c + @$(DEPACTION) + +$(TMPDIRPATH)%.d: %.cc + @$(DEPACTION) + + +$(TMPDIRPATH)%.d: %.cpp + @$(DEPACTION) + +# Include dependency files. If a .d file is missing, a warning is created and the .d file is created +# This warning is not a problem (gnu make manual, section 3.3 Including Other Makefiles) +-include $(addprefix $(TMPDIRPATH),$(DEPFILES)) + + diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 9ff0f51532cd..7dfe7512dde8 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -1,7 +1,15 @@ #ifndef __MARLINH #define __MARLINH -typedef struct { +// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. +// Licence: GPL +#include +#include "fastio.h" + + +// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in +// the source g-code and may never actually be reached if acceleration management is active. +typedef struct { // Fields used by the bresenham algorithm for tracing the line long steps_x, steps_y, steps_z, steps_e; // Step count along each axis long step_event_count; // The number of step events required to complete this block @@ -20,22 +28,17 @@ typedef struct { float nominal_speed; // The nominal speed for this block in mm/min float millimeters; // The total travel of this block in mm float entry_speed; + float acceleration; // acceleration mm/sec^2 // Settings for the trapezoid generator long nominal_rate; // The nominal step rate for this block in step_events/sec - volatile long initial_rate; // The jerk-adjusted step rate at start of block - volatile long final_rate; // The minimal rate at exit - long acceleration; // acceleration mm/sec^2 + volatile long initial_rate; // The jerk-adjusted step rate at start of block + volatile long final_rate; // The minimal rate at exit + long acceleration_st; // acceleration steps/sec^2 volatile char busy; } block_t; -// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. -// Licence: GPL -#include -#include "fastio.h" -//extern "C" void __cxa_pure_virtual(); -//void __cxa_pure_virtual(){}; void get_command(); void process_commands(); @@ -60,35 +63,33 @@ float analog2tempBed(int raw); //#define analog2temp( c ) analog2tempu((c),temptable,NUMTEMPS) #if X_ENABLE_PIN > -1 - #define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) - #define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) +#define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) +#define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) #else - #define enable_x() ; - #define disable_x() ; +#define enable_x() ; +#define disable_x() ; #endif - #if Y_ENABLE_PIN > -1 - #define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) - #define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) +#define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) +#define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) #else - #define enable_y() ; - #define disable_y() ; +#define enable_y() ; +#define disable_y() ; #endif - #if Z_ENABLE_PIN > -1 - #define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) - #define disable_z() WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON) +#define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) +#define disable_z() WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON) #else - #define enable_z() ; - #define disable_z() ; +#define enable_z() ; +#define disable_z() ; #endif #if E_ENABLE_PIN > -1 - #define enable_e() WRITE(E_ENABLE_PIN, E_ENABLE_ON) - #define disable_e() WRITE(E_ENABLE_PIN,E_ENABLE_ON) +#define enable_e() WRITE(E_ENABLE_PIN, E_ENABLE_ON) + #define disable_e() WRITE(E_ENABLE_PIN,E_ENABLE_ON) #else - #define enable_e() ; - #define disable_e() ; +#define enable_e() ; +#define disable_e() ; #endif #define X_AXIS 0 @@ -96,8 +97,6 @@ float analog2tempBed(int raw); #define Z_AXIS 2 #define E_AXIS 3 - - void FlushSerialRequestResend(); void ClearToSend(); @@ -108,6 +107,7 @@ void do_step(int axis); void kill(byte debug); + void check_axes_activity(); void plan_init(); void st_init(); diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 6e96e85cc114..f57508f396ca 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -41,10 +41,11 @@ #include "fastio.h" #include "Configuration.h" #include "pins.h" +#include "Marlin.h" +#include "speed_lookuptable.h" #include "lcd.h" -//extern LiquidCrystal lcd; -char version_string[] = "U0.9.3.1"; +char version_string[] = "U0.9.3.2"; #ifdef SDSUPPORT #include "SdFat.h" @@ -923,10 +924,11 @@ inline void process_commands() #if TEMP_1_PIN > -1 if (code_seen('S')) target_bed_raw = temp2analog(code_value()); codenum = millis(); - while(current_bed_raw < target_bed_raw) { + while(current_bed_raw < target_bed_raw) + { if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. { - tt=analog2temp(current_raw); + float tt=analog2temp(current_raw); Serial.print("T:"); Serial.println( tt ); Serial.print("ok T:"); @@ -1570,10 +1572,9 @@ void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit if(final_rate < 120) final_rate=120; // Calculate the acceleration steps - long acceleration = block->acceleration; + long acceleration = block->acceleration_st; long accelerate_steps = estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration); long decelerate_steps = estimate_acceleration_distance(final_rate, block->nominal_rate, acceleration); - // Calculate the size of Plateau of Nominal Rate. long plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; @@ -1617,15 +1618,15 @@ inline float max_allowable_speed(float acceleration, float target_velocity, floa inline float junction_jerk(block_t *before, block_t *after) { return(sqrt( pow((before->speed_x-after->speed_x), 2)+ - pow((before->speed_y-after->speed_y), 2)+ - pow((before->speed_z-after->speed_z)*axis_steps_per_unit[Z_AXIS]/axis_steps_per_unit[X_AXIS], 2))); + pow((before->speed_y-after->speed_y), 2))); } // Return the safe speed which is max_jerk/2, e.g. the // speed under which you cannot exceed max_jerk no matter what you do. float safe_speed(block_t *block) { float safe_speed; - safe_speed = max_jerk/2; + safe_speed = max_xy_jerk/2; + if(abs(block->speed_z) > max_z_jerk/2) safe_speed = max_z_jerk/2; if (safe_speed > block->nominal_speed) safe_speed = block->nominal_speed; return safe_speed; } @@ -1653,12 +1654,15 @@ void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *n if((previous->steps_x == 0) && (previous->steps_y == 0)) { entry_speed = safe_speed(current); } - else if (jerk > max_jerk) { - entry_speed = (max_jerk/jerk) * entry_speed; + else if (jerk > max_xy_jerk) { + entry_speed = (max_xy_jerk/jerk) * entry_speed; + } + if(abs(previous->speed_z - current->speed_z) > max_z_jerk) { + entry_speed = (max_z_jerk/abs(previous->speed_z - current->speed_z)) * entry_speed; } // If the required deceleration across the block is too rapid, reduce the entry_factor accordingly. if (entry_speed > exit_speed) { - float max_entry_speed = max_allowable_speed(-acceleration,exit_speed, current->millimeters); + float max_entry_speed = max_allowable_speed(-current->acceleration,exit_speed, current->millimeters); if (max_entry_speed < entry_speed) { entry_speed = max_entry_speed; } @@ -1678,16 +1682,16 @@ void planner_reverse_pass() { block_t *block[3] = { NULL, NULL, NULL }; while(block_index != block_buffer_tail) { - block_index--; - if(block_index < 0) { - block_index = BLOCK_BUFFER_SIZE-1; - } block[2]= block[1]; block[1]= block[0]; block[0] = &block_buffer[block_index]; planner_reverse_pass_kernel(block[0], block[1], block[2]); + block_index--; + if(block_index < 0) { + block_index = BLOCK_BUFFER_SIZE-1; + } } - planner_reverse_pass_kernel(NULL, block[0], block[1]); +// planner_reverse_pass_kernel(NULL, block[0], block[1]); } // The kernel called by planner_recalculate() when scanning the plan from first to last entry. @@ -1701,7 +1705,7 @@ void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *n // speed accordingly. Remember current->entry_factor equals the exit factor of // the previous block. if(previous->entry_speed < current->entry_speed) { - float max_entry_speed = max_allowable_speed(-acceleration, previous->entry_speed, previous->millimeters); + float max_entry_speed = max_allowable_speed(-previous->acceleration, previous->entry_speed, previous->millimeters); if (max_entry_speed < current->entry_speed) { current->entry_speed = max_entry_speed; } @@ -1849,12 +1853,17 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); - // Bail if this is a zero-length block if (block->step_event_count == 0) { return; }; + //enable active axes + if(block->steps_x != 0) enable_x(); + if(block->steps_y != 0) enable_y(); + if(block->steps_z != 0) enable_z(); + if(block->steps_e != 0) enable_e(); + float delta_x_mm = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; float delta_y_mm = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; float delta_z_mm = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; @@ -1863,6 +1872,14 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { unsigned long microseconds; microseconds = lround((block->millimeters/feed_rate)*1000000); + //added my lampmaker to slow down rather than wait at the corner for a buffer refill + // turns corner blobs into more dissapated blobs + int blockcount=block_buffer_head-block_buffer_tail; + //blockcount=8; + while(blockcount<0) blockcount+=BLOCK_BUFFER_SIZE; + if ((blockcount<=2)&&(microseconds<50000)) microseconds=50000; + else if ((blockcount<=4)&&(microseconds<20000)) microseconds=20000; + else if ((blockcount<=8)&&(microseconds<10000)) microseconds=10000; // Calculate speed in mm/minute for each axis float multiplier = 60.0*1000000.0/microseconds; @@ -1875,7 +1892,10 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { float speed_factor = 1; float tmp_speed_factor; if(abs(block->speed_x) > max_feedrate[X_AXIS]) { - speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + //// [ErikDeBruijn] IS THIS THE BUG WE'RE LOOING FOR???? + // it used to be just this line: speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + tmp_speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; } if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); @@ -1906,17 +1926,18 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 } else { - block->acceleration = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + block->acceleration_st = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 // Limit acceleration per axis - if((block->acceleration * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) - block->acceleration = axis_steps_per_sqr_second[X_AXIS]; - if((block->acceleration * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) - block->acceleration = axis_steps_per_sqr_second[Y_AXIS]; - if((block->acceleration * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) - block->acceleration = axis_steps_per_sqr_second[E_AXIS]; - if((block->acceleration * block->steps_z / block->step_event_count) > axis_steps_per_sqr_second[Z_AXIS]) - block->acceleration = axis_steps_per_sqr_second[Z_AXIS]; + if((block->acceleration_st * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[X_AXIS]; + if((block->acceleration_st * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS]; + if((block->acceleration_st * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[E_AXIS]; + if(((block->acceleration_st / block->step_event_count) * block->steps_z ) > axis_steps_per_sqr_second[Z_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS]; } + block->acceleration = block->acceleration_st * travel_per_step; #ifdef ADVANCE // Calculate advance rate @@ -1925,7 +1946,7 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->advance = 0; } else { - long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration); + long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st); float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; block->advance = advance; @@ -1958,12 +1979,6 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->direction_bits |= (1<steps_x != 0) enable_x(); - if(block->steps_y != 0) enable_y(); - if(block->steps_z != 0) enable_z(); - if(block->steps_e != 0) enable_e(); - // Move buffer head block_buffer_head = next_buffer_head; @@ -2139,7 +2154,6 @@ inline void trapezoid_generator_reset() { OCR1A = acceleration_time; } - // "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. // It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. ISR(TIMER1_COMPA_vect) @@ -2154,6 +2168,14 @@ ISR(TIMER1_COMPA_vect) static int breakdown=0; if((breakdown++)%100==0) buttons_check(); +/* [ErikDeBruijn] Perhaps it would be nice to use a piece of code like this (adapted from process_g_code), to create a nice progress bar! + if(sdactive){ + sprintf("SD printing byte %i%",(int) (sdpos/filesize*100)); // perhaps a fraction of a percent is also nice, 0.03%, progress bar even better. + Serial.print(sdpos); + Serial.print("/"); + Serial.println(filesize); + } +*/ #endif // If there is no current block, attempt to pop one from the buffer @@ -2169,13 +2191,13 @@ ISR(TIMER1_COMPA_vect) step_events_completed = 0; e_steps = 0; #ifdef DEBUG_STEPS - stepstaken[0]=0;stepstaken[1]=0;stepstaken[2]=0;stepstaken[3]=0; - Serial.print("(Planned: "); - Serial.print(abs(current_block->steps_x));Serial.print(" "); - Serial.print(abs(current_block->steps_y));Serial.print(" "); - Serial.print(abs(current_block->steps_z));Serial.print(" "); - //Serial.print(abs(current_block->steps_e));Serial.print(" "); - Serial.println(); + stepstaken[0]=0;stepstaken[1]=0;stepstaken[2]=0;stepstaken[3]=0; + Serial.print("(Planned: "); + Serial.print(abs(current_block->steps_x));Serial.print(" "); + Serial.print(abs(current_block->steps_y));Serial.print(" "); + Serial.print(abs(current_block->steps_z));Serial.print(" "); + //Serial.print(abs(current_block->steps_e));Serial.print(" "); + Serial.println(); #endif } else { @@ -2262,9 +2284,9 @@ ISR(TIMER1_COMPA_vect) WRITE(X_STEP_PIN, HIGH); counter_x -= current_block->step_event_count; WRITE(X_STEP_PIN, LOW); - #ifdef DEBUG_STEPS - stepstaken[0]++; - #endif + #ifdef DEBUG_STEPS + stepstaken[0]++; + #endif } counter_y += current_block->steps_y; @@ -2272,9 +2294,9 @@ ISR(TIMER1_COMPA_vect) WRITE(Y_STEP_PIN, HIGH); counter_y -= current_block->step_event_count; WRITE(Y_STEP_PIN, LOW); - #ifdef DEBUG_STEPS - stepstaken[1]++; - #endif + #ifdef DEBUG_STEPS + stepstaken[1]++; + #endif } counter_z += current_block->steps_z; @@ -2282,9 +2304,9 @@ ISR(TIMER1_COMPA_vect) WRITE(Z_STEP_PIN, HIGH); counter_z -= current_block->step_event_count; WRITE(Z_STEP_PIN, LOW); - #ifdef DEBUG_STEPS - stepstaken[2]++; - #endif + #ifdef DEBUG_STEPS + stepstaken[2]++; + #endif } #ifndef ADVANCE @@ -2343,15 +2365,14 @@ ISR(TIMER1_COMPA_vect) current_block = NULL; plan_discard_current_block(); #ifdef DEBUG_STEPS - Serial.print("(Steps done: "); - Serial.print(stepstaken[0]);Serial.print(" "); - Serial.print(stepstaken[1]);Serial.print(" "); - Serial.print(stepstaken[2]);Serial.println(" "); + Serial.print("(Steps done: "); + Serial.print(stepstaken[0]);Serial.print(" "); + Serial.print(stepstaken[1]);Serial.print(" "); + Serial.print(stepstaken[2]);Serial.println(" "); #endif } } busy=false; - } #ifdef ADVANCE @@ -2486,4 +2507,4 @@ ISR(TIMER2_OVF_vect) } } -*/ \ No newline at end of file +*/ diff --git a/Marlin/lcd.pde b/Marlin/lcd.pde index 6c3d596f1c16..8b52bd6a41cf 100644 --- a/Marlin/lcd.pde +++ b/Marlin/lcd.pde @@ -589,9 +589,14 @@ void enquecommand(const char *cmd) void beep() { + // [ErikDeBruijn] changed to two short beeps, more friendly pinMode(BEEPER,OUTPUT); digitalWrite(BEEPER,HIGH); - delay(1000); + delay(200); + digitalWrite(BEEPER,LOW); + delay(200); + digitalWrite(BEEPER,HIGH); + delay(200); digitalWrite(BEEPER,LOW); } From 6c11c3df00ffd6b53c5fee73e32b3ee8a4ae00b1 Mon Sep 17 00:00:00 2001 From: mkeuper Date: Sat, 17 Sep 2011 10:45:29 +0200 Subject: [PATCH 037/130] Added a MIN_SEGMENT_TIME option in configuration.h. this sets the minimum time a motion segment should take if the buffer is empty. Increased the Block_buffer size to 40, only if LCD, SD, Buttons are turned off. Not sure how much RAM each of those take. Increasing the buffer is probably not required for SD anyway. Changed the debug_steps section so M114 can be used to compare the two methods of determining the position. Hope we won't need this anymore. --- Marlin/Configuration.h | 4 + Marlin/Marlin.pde | 5040 ++++++++++++++++++++-------------------- 2 files changed, 2535 insertions(+), 2509 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 36efc7ad7ddd..b11780bdea72 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -112,6 +112,10 @@ long max_acceleration_units_per_sq_second[] = {7000,7000,15000,10000}; // X, Y, #define MAXTEMP 275 +// minimum time in microseconds that a movement needs to take if the buffer is emptied. Increase this number if you see blobs while printing high speed & high detail. It will slowdown on the detailed stuff. +#define MIN_SEGMENT_TIME 50000 + + /// PID settings: // Uncomment the following line to enable PID support. //#define PIDTEMP diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index f57508f396ca..2af3beddc76f 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1,2510 +1,2532 @@ -#include "Marlin.h" -// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in -// the source g-code and may never actually be reached if acceleration management is active. - -//#define DEBUG_STEPS - - -#include "speed_lookuptable.h" - -/* - Reprap firmware based on Sprinter and grbl. - Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm - - This program 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. - - This program 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 this program. If not, see . - */ - -/* - This firmware is a mashup between Sprinter and grbl. - (https://github.com/kliment/Sprinter) - (https://github.com/simen/grbl/tree) - - It has preliminary support for Matthew Roberts advance algorithm - http://reprap.org/pipermail/reprap-dev/2011-May/003323.html - - This firmware is optimized for gen6 electronics. - */ - - - -#include "fastio.h" -#include "Configuration.h" -#include "pins.h" -#include "Marlin.h" -#include "speed_lookuptable.h" -#include "lcd.h" - -char version_string[] = "U0.9.3.2"; - -#ifdef SDSUPPORT -#include "SdFat.h" -#endif //SDSUPPORT - -#ifndef CRITICAL_SECTION_START -#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() -#define CRITICAL_SECTION_END SREG = _sreg -#endif //CRITICAL_SECTION_START - - -#ifdef DEBUG_STEPS -long stepstaken[4]; -#endif -// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html -// 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 -// G28 - Home all 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 -// 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 -// M115 - Capabilities string -// 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) -// M301 - Set PID parameters P I and D - -//Stepper Movement Variables - -char axis_codes[NUM_AXIS] = { - 'X', 'Y', 'Z', 'E'}; -float destination[NUM_AXIS] = { - 0.0, 0.0, 0.0, 0.0}; -float current_position[NUM_AXIS] = { - 0.0, 0.0, 0.0, 0.0}; -bool home_all_axis = true; -long feedrate = 1500, next_feedrate, saved_feedrate; -long gcode_N, gcode_LastN; -unsigned long previous_millis_heater, previous_millis_bed_heater; -bool relative_mode = false; //Determines Absolute or Relative Coordinates -bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. -unsigned long axis_steps_per_sqr_second[NUM_AXIS]; - -volatile int feedmultiply=100; //100->1 200->2 -// comm variables -#define MAX_CMD_SIZE 96 -#define BUFSIZE 8 -char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; -bool fromsd[BUFSIZE]; -int bufindr = 0; -int bufindw = 0; -int buflen = 0; -int i = 0; -char serial_char; -int serial_count = 0; -boolean comment_mode = false; -char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc - -// Manage heater variables. - -int target_bed_raw = 0; -int current_bed_raw = 0; - -int target_raw = 0; -int current_raw = 0; -unsigned char temp_meas_ready = false; - -#ifdef PIDTEMP - double temp_iState = 0; - double temp_dState = 0; - double pTerm; - double iTerm; - double dTerm; - //int output; - double pid_error; - double temp_iState_min; - double temp_iState_max; - double pid_setpoint = 0.0; - double pid_input; - double pid_output; - bool pid_reset; -#endif //PIDTEMP -float tt = 0, bt = 0; -#ifdef WATCHPERIOD -int watch_raw = -1000; -unsigned long watchmillis = 0; -#endif //WATCHPERIOD -#ifdef MINTEMP -int minttemp = temp2analog(MINTEMP); -#endif //MINTEMP -#ifdef MAXTEMP -int maxttemp = temp2analog(MAXTEMP); -#endif //MAXTEMP - -//Inactivity shutdown variables -unsigned long previous_millis_cmd = 0; -unsigned long max_inactive_time = 0; -unsigned long stepper_inactive_time = 0; - -unsigned long starttime=0; -unsigned long stoptime=0; -#ifdef SDSUPPORT -Sd2Card card; -SdVolume volume; -SdFile root; -SdFile file; -uint32_t filesize = 0; -uint32_t sdpos = 0; -bool sdmode = false; -bool sdactive = false; -bool savetosd = false; -int16_t n; - -void initsd(){ - sdactive = false; -#if SDSS >- 1 - if(root.isOpen()) - root.close(); - if (!card.init(SPI_FULL_SPEED,SDSS)){ - //if (!card.init(SPI_HALF_SPEED,SDSS)) - Serial.println("SD init fail"); - } - else if (!volume.init(&card)) - Serial.println("volume.init failed"); - else if (!root.openRoot(&volume)) - Serial.println("openRoot failed"); - else - sdactive = true; -#endif //SDSS -} - -inline void write_command(char *buf){ - char* begin = buf; - char* npos = 0; - char* end = buf + strlen(buf) - 1; - - file.writeError = false; - if((npos = strchr(buf, 'N')) != NULL){ - begin = strchr(npos, ' ') + 1; - end = strchr(npos, '*') - 1; - } - end[1] = '\r'; - end[2] = '\n'; - end[3] = '\0'; - //Serial.println(begin); - file.write(begin); - if (file.writeError){ - Serial.println("error writing to file"); - } -} -#endif //SDSUPPORT - -void setup() -{ - - Serial.begin(BAUDRATE); - Serial.print("Marlin "); - Serial.println(version_string); - Serial.println("start"); -#ifdef FANCY_LCD - lcd_init(); -#endif - for(int i = 0; i < BUFSIZE; i++){ - fromsd[i] = false; - } - - - //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 -#if E_DIR_PIN > -1 - SET_OUTPUT(E_DIR_PIN); -#endif - - //Initialize Enable Pins - steppers default to disabled. - -#if (X_ENABLE_PIN > -1) - SET_OUTPUT(X_ENABLE_PIN); - if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); -#endif -#if (Y_ENABLE_PIN > -1) - SET_OUTPUT(Y_ENABLE_PIN); - if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); -#endif -#if (Z_ENABLE_PIN > -1) - SET_OUTPUT(Z_ENABLE_PIN); - if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); -#endif -#if (E_ENABLE_PIN > -1) - SET_OUTPUT(E_ENABLE_PIN); - if(!E_ENABLE_ON) WRITE(E_ENABLE_PIN,HIGH); -#endif - - //endstops and pullups -#ifdef ENDSTOPPULLUPS -#if X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); - WRITE(X_MIN_PIN,HIGH); -#endif -#if X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); - WRITE(X_MAX_PIN,HIGH); -#endif -#if Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); - WRITE(Y_MIN_PIN,HIGH); -#endif -#if Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); - WRITE(Y_MAX_PIN,HIGH); -#endif -#if Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); - WRITE(Z_MIN_PIN,HIGH); -#endif -#if Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); - WRITE(Z_MAX_PIN,HIGH); -#endif -#else //ENDSTOPPULLUPS -#if X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); -#endif -#if X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); -#endif -#if Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); -#endif -#if Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); -#endif -#if Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); -#endif -#if Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); -#endif -#endif //ENDSTOPPULLUPS - -#if (HEATER_0_PIN > -1) - SET_OUTPUT(HEATER_0_PIN); -#endif -#if (HEATER_1_PIN > -1) - SET_OUTPUT(HEATER_1_PIN); -#endif - - //Initialize Step Pins -#if (X_STEP_PIN > -1) - SET_OUTPUT(X_STEP_PIN); -#endif -#if (Y_STEP_PIN > -1) - SET_OUTPUT(Y_STEP_PIN); -#endif -#if (Z_STEP_PIN > -1) - SET_OUTPUT(Z_STEP_PIN); -#endif -#if (E_STEP_PIN > -1) - SET_OUTPUT(E_STEP_PIN); -#endif - for(int i=0; i < NUM_AXIS; i++){ - axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; - } - -#ifdef PIDTEMP - temp_iState_min = 0.0; - temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; -#endif //PIDTEMP - -#ifdef SDSUPPORT - //power to SD reader -#if SDPOWER > -1 - SET_OUTPUT(SDPOWER); - WRITE(SDPOWER,HIGH); -#endif //SDPOWER - initsd(); - -#endif //SDSUPPORT - plan_init(); // Initialize planner; - st_init(); // Initialize stepper; -// tp_init(); // Initialize temperature loop - checkautostart(); -} - -#ifdef SDSUPPORT -void checkautostart() -{ - if(!sdactive) - return; - static int lastnr=0; - char autoname[30]; - sprintf(autoname,"auto%i.g",lastnr); - for(int i=0;i 0) - { - for(int i=0;i 0 && buflen < BUFSIZE) { - serial_char = Serial.read(); - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) - { - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = false; - if(strstr(cmdbuffer[bufindw], "N") != NULL) - { - strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); - gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); - if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { - Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); - Serial.println(gcode_LastN); - //Serial.println(gcode_N); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - if(strstr(cmdbuffer[bufindw], "*") != NULL) - { - byte checksum = 0; - byte count = 0; - while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; - strchr_pointer = strchr(cmdbuffer[bufindw], '*'); - - if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { - Serial.print("Error: checksum mismatch, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - //if no errors, continue parsing - } - else - { - Serial.print("Error: No Checksum with line number, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - gcode_LastN = gcode_N; - //if no errors, continue parsing - } - else // if we don't receive 'N' but still see '*' - { - if((strstr(cmdbuffer[bufindw], "*") != NULL)) - { - Serial.print("Error: No Line Number with checksum, Last Line:"); - Serial.println(gcode_LastN); - serial_count = 0; - return; - } - } - if((strstr(cmdbuffer[bufindw], "G") != NULL)){ - strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); - switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ - case 0: - case 1: -#ifdef SDSUPPORT - if(savetosd) - break; -#endif //SDSUPPORT - Serial.println("ok"); - break; - default: - break; - } - - } - bufindw = (bufindw + 1)%BUFSIZE; - buflen += 1; - - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } - } -#ifdef SDSUPPORT - if(!sdmode || serial_count!=0){ - return; - } - while( filesize > sdpos && buflen < BUFSIZE) { - n = file.read(); - serial_char = (char)n; - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) - { - sdpos = file.curPosition(); - if(sdpos >= filesize){ - sdmode = false; - Serial.println("Done printing file"); - stoptime=millis(); - char time[30]; - unsigned long t=(stoptime-starttime)/1000; - int sec,min; - min=t/60; - sec=t%60; - sprintf(time,"%i min, %i sec",min,sec); - Serial.println(time); - LCD_MESSAGE(time); - checkautostart(); - } - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = true; - buflen += 1; - bufindw = (bufindw + 1)%BUFSIZE; - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } - } -#endif //SDSUPPORT - -} - - -inline float code_value() { - return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); -} -inline long code_value_long() { - return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); -} -inline bool code_seen(char code_string[]) { - return (strstr(cmdbuffer[bufindr], code_string) != NULL); -} //Return True if the string was found - -inline bool code_seen(char code) -{ - strchr_pointer = strchr(cmdbuffer[bufindr], code); - return (strchr_pointer != NULL); //Return True if a character was found -} - -inline void process_commands() -{ - unsigned long codenum; //throw away variable - char *starpos = NULL; - - if(code_seen('G')) - { - switch((int)code_value()) - { - case 0: // G0 -> G1 - case 1: // G1 - get_coordinates(); // For X Y Z E F - prepare_move(); - previous_millis_cmd = millis(); - //ClearToSend(); - return; - //break; - case 4: // G4 dwell - codenum = 0; - if(code_seen('P')) codenum = code_value(); // milliseconds to wait - if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait - codenum += millis(); // keep track of when we started waiting - while(millis() < codenum ){ - manage_heater(); - } - break; - case 28: //G28 Home all Axis one at a time - saved_feedrate = feedrate; - for(int i=0; i < NUM_AXIS; i++) { - destination[i] = current_position[i]; - } - feedrate = 0; - - home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); - - if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) { - if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){ - st_synchronize(); - current_position[X_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; - feedrate = homing_feedrate[X_AXIS]; - prepare_move(); - - st_synchronize(); - current_position[X_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = -5 * X_HOME_DIR; - prepare_move(); - - st_synchronize(); - destination[X_AXIS] = 10 * X_HOME_DIR; - feedrate = homing_feedrate[X_AXIS]/2 ; - prepare_move(); - st_synchronize(); - - current_position[X_AXIS] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = current_position[X_AXIS]; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { - if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){ - current_position[Y_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; - feedrate = homing_feedrate[Y_AXIS]; - prepare_move(); - st_synchronize(); - - current_position[Y_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = -5 * Y_HOME_DIR; - prepare_move(); - st_synchronize(); - - destination[Y_AXIS] = 10 * Y_HOME_DIR; - feedrate = homing_feedrate[Y_AXIS]/2; - prepare_move(); - st_synchronize(); - - current_position[Y_AXIS] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = current_position[Y_AXIS]; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { - if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){ - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; - feedrate = homing_feedrate[Z_AXIS]; - prepare_move(); - st_synchronize(); - - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = -2 * Z_HOME_DIR; - prepare_move(); - st_synchronize(); - - destination[Z_AXIS] = 3 * Z_HOME_DIR; - feedrate = homing_feedrate[Z_AXIS]/2; - prepare_move(); - st_synchronize(); - - current_position[Z_AXIS] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = current_position[Z_AXIS]; - feedrate = 0; - } - } - feedrate = saved_feedrate; - previous_millis_cmd = millis(); - break; - case 90: // G90 - relative_mode = false; - break; - case 91: // G91 - relative_mode = true; - break; - case 92: // G92 - if(!code_seen(axis_codes[E_AXIS])) - st_synchronize(); - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) current_position[i] = code_value(); - } - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - break; - - } - } - - else if(code_seen('M')) - { - - switch( (int)code_value() ) - { -#ifdef SDSUPPORT - - case 20: // M20 - list SD card - Serial.println("Begin file list"); - root.ls(); - Serial.println("End file list"); - break; - case 21: // M21 - init SD card - sdmode = false; - initsd(); - break; - case 22: //M22 - release SD card - sdmode = false; - sdactive = false; - break; - case 23: //M23 - Select file - if(sdactive){ - sdmode = false; - file.close(); - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos!=NULL) - *(starpos-1)='\0'; - if (file.open(&root, strchr_pointer + 4, O_READ)) { - Serial.print("File opened:"); - Serial.print(strchr_pointer + 4); - Serial.print(" Size:"); - Serial.println(file.fileSize()); - sdpos = 0; - filesize = file.fileSize(); - Serial.println("File selected"); - } - else{ - Serial.println("file.open failed"); - } - } - break; - case 24: //M24 - Start SD print - if(sdactive){ - sdmode = true; - starttime=millis(); - } - break; - case 25: //M25 - Pause SD print - if(sdmode){ - sdmode = false; - } - break; - case 26: //M26 - Set SD index - if(sdactive && code_seen('S')){ - sdpos = code_value_long(); - file.seekSet(sdpos); - } - break; - case 27: //M27 - Get SD status - if(sdactive){ - Serial.print("SD printing byte "); - Serial.print(sdpos); - Serial.print("/"); - Serial.println(filesize); - } - else{ - Serial.println("Not SD printing"); - } - break; - case 28: //M28 - Start SD write - if(sdactive){ - char* npos = 0; - file.close(); - sdmode = false; - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos != NULL){ - npos = strchr(cmdbuffer[bufindr], 'N'); - strchr_pointer = strchr(npos,' ') + 1; - *(starpos-1) = '\0'; - } - if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) - { - Serial.print("open failed, File: "); - Serial.print(strchr_pointer + 4); - Serial.print("."); - } - else{ - savetosd = true; - Serial.print("Writing to file: "); - Serial.println(strchr_pointer + 4); - } - } - break; - case 29: //M29 - Stop SD write - //processed in write to file routine above - //savetosd = false; - break; - case 30: - { - stoptime=millis(); - char time[30]; - unsigned long t=(stoptime-starttime)/1000; - int sec,min; - min=t/60; - sec=t%60; - sprintf(time,"%i min, %i sec",min,sec); - Serial.println(time); - LCD_MESSAGE(time); - } - break; -#endif //SDSUPPORT - case 104: // M104 - if (code_seen('S')) target_raw = temp2analog(code_value()); - #ifdef WATCHPERIOD - if(target_raw > current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - }else{ - watchmillis = 0; - } - #endif - break; - case 140: // M140 set bed temp - if (code_seen('S')) target_bed_raw = temp2analogBed(code_value()); - break; - case 105: // M105 - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) - tt = analog2temp(current_raw); - #endif - #if TEMP_1_PIN > -1 - bt = analog2tempBed(current_bed_raw); - #endif - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) - Serial.print("ok T:"); - Serial.print(tt); - Serial.print(", raw:"); - Serial.print(current_raw); - #if TEMP_1_PIN > -1 - Serial.print(" B:"); - Serial.println(bt); - #else - Serial.println(); - #endif - #else - Serial.println("No thermistors - no temp"); - #endif - return; - //break; - case 109: // M109 - Wait for extruder heater to reach target. - LCD_MESSAGE("Heating..."); - if (code_seen('S')) target_raw = temp2analog(code_value()); - #ifdef WATCHPERIOD - if(target_raw>current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - }else{ - watchmillis = 0; - } - #endif - codenum = millis(); - starttime=millis(); - while(current_raw < target_raw) { - if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - Serial.print("T:"); - Serial.println( analog2temp(current_raw) ); - - codenum = millis(); - } - LCD_STATUS; - manage_heater(); - } - break; - case 190: // M190 - Wait bed for heater to reach target. - #if TEMP_1_PIN > -1 - if (code_seen('S')) target_bed_raw = temp2analog(code_value()); - codenum = millis(); - while(current_bed_raw < target_bed_raw) - { - if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - float tt=analog2temp(current_raw); - Serial.print("T:"); - Serial.println( tt ); - Serial.print("ok T:"); - Serial.print( tt ); - Serial.print(" B:"); - Serial.println( analog2temp(current_bed_raw) ); - codenum = millis(); - } - manage_heater(); - } - #endif - break; - case 106: //M106 Fan On - if (code_seen('S')){ - digitalWrite(FAN_PIN,HIGH); - analogWrite(FAN_PIN, constrain(code_value(),0,255) ); - } - else - { - digitalWrite(FAN_PIN,HIGH); - analogWrite(FAN_PIN, 255); - } - break; - case 107: //M107 Fan Off - digitalWrite(FAN_PIN,LOW); - analogWrite(FAN_PIN, 0); - break; - - case 82: - axis_relative_modes[3] = false; - break; - case 83: - axis_relative_modes[3] = true; - break; - case 18: - case 84: - if(code_seen('S')){ - stepper_inactive_time = code_value() * 1000; - } - else{ - st_synchronize(); - disable_x(); - disable_y(); - disable_z(); - disable_e(); - } - break; - case 85: // M85 - code_seen('S'); - max_inactive_time = code_value() * 1000; - break; - case 92: // M92 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); - } - - break; - case 115: // M115 - Serial.println("FIRMWARE_NAME:Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); - break; - case 114: // M114 - Serial.print("X:"); - Serial.print(current_position[X_AXIS]); - Serial.print("Y:"); - Serial.print(current_position[Y_AXIS]); - Serial.print("Z:"); - Serial.print(current_position[Z_AXIS]); - Serial.print("E:"); - Serial.println(current_position[E_AXIS]); - break; - case 119: // M119 -#if (X_MIN_PIN > -1) - Serial.print("x_min:"); - Serial.print((READ(X_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (X_MAX_PIN > -1) - Serial.print("x_max:"); - Serial.print((READ(X_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Y_MIN_PIN > -1) - Serial.print("y_min:"); - Serial.print((READ(Y_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Y_MAX_PIN > -1) - Serial.print("y_max:"); - Serial.print((READ(Y_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Z_MIN_PIN > -1) - Serial.print("z_min:"); - Serial.print((READ(Z_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Z_MAX_PIN > -1) - Serial.print("z_max:"); - Serial.print((READ(Z_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif - Serial.println(""); - break; - //TODO: update for all axis, use for loop - case 201: // M201 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; -#if 0 // Not used for Sprinter/grbl gen6 - case 202: // M202 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; -#endif -#ifdef PIDTEMP - case 301: // M301 - if(code_seen('P')) Kp = code_value(); - if(code_seen('I')) Ki = code_value()*PID_dT; - if(code_seen('D')) Kd = code_value()/PID_dT; - Serial.print("Kp ");Serial.println(Kp); - Serial.print("Ki ");Serial.println(Ki/PID_dT); - Serial.print("Kd ");Serial.println(Kd*PID_dT); - temp_iState_min = 0.0; - temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; - break; -#endif //PIDTEMP - } - } - else{ - Serial.println("Unknown command:"); - Serial.println(cmdbuffer[bufindr]); - } - - ClearToSend(); -} - -void FlushSerialRequestResend() -{ - //char cmdbuffer[bufindr][100]="Resend:"; - Serial.flush(); - Serial.print("Resend:"); - Serial.println(gcode_LastN + 1); - ClearToSend(); -} - -void ClearToSend() -{ - previous_millis_cmd = millis(); -#ifdef SDSUPPORT - if(fromsd[bufindr]) - return; -#endif //SDSUPPORT - Serial.println("ok"); -} - -inline void get_coordinates() -{ - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; - else destination[i] = current_position[i]; //Are these else lines really needed? - } - if(code_seen('F')) { - next_feedrate = code_value(); - if(next_feedrate > 0.0) feedrate = next_feedrate; - } -} - -void prepare_move() -{ - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60.0/100.); - for(int i=0; i < NUM_AXIS; i++) { - current_position[i] = destination[i]; - } -} -/* -void manage_heater() -{ - float pid_input; - float pid_output; - if(temp_meas_ready != true) - return; - -CRITICAL_SECTION_START; - temp_meas_ready = false; -CRITICAL_SECTION_END; - -#ifdef PIDTEMP - pid_input = analog2temp(current_raw); - -#ifndef PID_OPENLOOP - pid_error = pid_setpoint - pid_input; - if(pid_error > 10){ - pid_output = PID_MAX; - pid_reset = true; - } - else if(pid_error < -10) { - pid_output = 0; - pid_reset = true; - } - else { - if(pid_reset == true) { - temp_iState = 0.0; - pid_reset = false; - } - pTerm = Kp * pid_error; - temp_iState += pid_error; - temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = Ki * temp_iState; - #define K1 0.8 - #define K2 (1.0-K1) - dTerm = (Kd * (pid_input - temp_dState))*K2 + (K1 * dTerm); - temp_dState = pid_input; - pid_output = constrain(pTerm + iTerm - dTerm, 0, PID_MAX); - } -#endif //PID_OPENLOOP -#ifdef PID_DEBUG - Serial.print(" Input "); - Serial.print(pid_input); - Serial.print(" Output "); - Serial.print(pid_output); - Serial.print(" pTerm "); - Serial.print(pTerm); - Serial.print(" iTerm "); - Serial.print(iTerm); - Serial.print(" dTerm "); - Serial.print(dTerm); - Serial.println(); -#endif //PID_DEBUG - OCR2B = pid_output; -#endif //PIDTEMP -} -*/ - - -/* -int temp2analogu(int celsius, const short table[][2], int numtemps) { - int raw = 0; - byte i; - - for (i=1; i raw) { - celsius = (float)table[i-1][1] + - (float)(raw - table[i-1][0]) * - (float)(table[i][1] - table[i-1][1]) / - (float)(table[i][0] - table[i-1][0]); - - break; - } - } - // Overflow: Set to last value in the table - if (i == numtemps) celsius = table[i-1][1]; - - return celsius; -} - - -inline void kill() -{ - target_raw=0; -#ifdef PIDTEMP - pid_setpoint = 0.0; -#endif //PIDTEMP - OCR2B = 0; - WRITE(HEATER_0_PIN,LOW); - - disable_x(); - disable_y(); - disable_z(); - disable_e(); - -} -*/ - - - -//#################################################################################################################### -//#################################################################################################################### -void manage_heater() -{ -#ifdef USE_WATCHDOG - wd_reset(); -#endif - //there is no FANCY_LCD here, because this routine is called within moves, and delays them. one could loose steps. - - if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) - return; - previous_millis_heater = millis(); - #ifdef HEATER_USES_THERMISTOR - current_raw = analogRead(TEMP_0_PIN); - // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, - // this switches it up so that the reading appears lower than target for the control logic. - current_raw = 1023 - current_raw; - #elif defined HEATER_USES_AD595 - current_raw = analogRead(TEMP_0_PIN); - #elif defined HEATER_USES_MAX6675 - current_raw = read_max6675(); - #endif - #ifdef SMOOTHING - nma = (nma + current_raw) - (nma / SMOOTHFACTOR); - current_raw = nma / SMOOTHFACTOR; - #endif - #ifdef WATCHPERIOD - if(watchmillis && millis() - watchmillis > WATCHPERIOD){ - if(watch_raw + 1 >= current_raw){ - target_raw = 0; - digitalWrite(HEATER_0_PIN,LOW); - digitalWrite(LED_PIN,LOW); - }else{ - watchmillis = 0; - } - } - #endif - #ifdef MINTEMP - if(current_raw <= minttemp) - target_raw = 0; - #endif - #ifdef MAXTEMP - if(current_raw >= maxttemp) { - target_raw = 0; - } - #endif - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) - #ifdef PIDTEMP - error = target_raw - current_raw; - pTerm = (PID_PGAIN * error) / 100; - temp_iState += error; - temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = (PID_IGAIN * temp_iState) / 100; - dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; - temp_dState = current_raw; - analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); - #else - if(current_raw >= target_raw) - { - digitalWrite(HEATER_0_PIN,LOW); - digitalWrite(LED_PIN,LOW); - } - else - { - digitalWrite(HEATER_0_PIN,HIGH); - digitalWrite(LED_PIN,HIGH); - } - #endif - #endif - - if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) - return; - previous_millis_bed_heater = millis(); - - #ifdef BED_USES_THERMISTOR - - current_bed_raw = analogRead(TEMP_1_PIN); - - // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, - // this switches it up so that the reading appears lower than target for the control logic. - current_bed_raw = 1023 - current_bed_raw; - #elif defined BED_USES_AD595 - current_bed_raw = analogRead(TEMP_1_PIN); - - #endif - - - #if TEMP_1_PIN > -1 - if(current_bed_raw >= target_bed_raw) - { - digitalWrite(HEATER_1_PIN,LOW); - } - else - { - digitalWrite(HEATER_1_PIN,HIGH); - } - #endif -} - -// Takes hot end temperature value as input and returns corresponding raw value. -// For a thermistor, it uses the RepRap thermistor temp table. -// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value. -// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware. -float temp2analog(int celsius) { - #ifdef HEATER_USES_THERMISTOR - int raw = 0; - byte i; - - for (i=1; i raw) - { - celsius = temptable[i-1][1] + - (raw - temptable[i-1][0]) * - (temptable[i][1] - temptable[i-1][1]) / - (temptable[i][0] - temptable[i-1][0]); - - break; - } - } - - // Overflow: Set to last value in the table - if (i == NUMTEMPS) celsius = temptable[i-1][1]; - - return celsius; - #elif defined HEATER_USES_AD595 - return raw * ((5.0 * 100.0) / 1024.0); - #elif defined HEATER_USES_MAX6675 - return raw * 0.25; - #endif -} - -// Derived from RepRap FiveD extruder::getTemperature() -// For bed temperature measurement. -float analog2tempBed(int raw) { - #ifdef BED_USES_THERMISTOR - int celsius = 0; - byte i; - - raw = 1023 - raw; - - for (i=1; i raw) - { - celsius = bedtemptable[i-1][1] + - (raw - bedtemptable[i-1][0]) * - (bedtemptable[i][1] - bedtemptable[i-1][1]) / - (bedtemptable[i][0] - bedtemptable[i-1][0]); - - break; - } - } - - // Overflow: Set to last value in the table - if (i == NUMTEMPS) celsius = bedtemptable[i-1][1]; - - return celsius; - - #elif defined BED_USES_AD595 - return raw * ((5.0 * 100.0) / 1024.0); - #endif -} - -inline void kill() -{ - #if TEMP_0_PIN > -1 - target_raw=0; - digitalWrite(HEATER_0_PIN,LOW); - #endif - #if TEMP_1_PIN > -1 - target_bed_raw=0; - if(HEATER_1_PIN > -1) digitalWrite(HEATER_1_PIN,LOW); - #endif - disable_x(); - disable_y(); - disable_z(); - disable_e(); - - if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); - -} - - - - - - -//####################################################################################################################### - -inline void manage_inactivity(byte debug) { - if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); - if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { - disable_x(); - disable_y(); - disable_z(); - disable_e(); - } - check_axes_activity(); -} - -// Planner - -/* - Reasoning behind the mathematics in this module (in the key of 'Mathematica'): - - s == speed, a == acceleration, t == time, d == distance - - Basic definitions: - - Speed[s_, a_, t_] := s + (a*t) - Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t] - - Distance to reach a specific speed with a constant acceleration: - - Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t] - d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance() - - Speed after a given distance of travel with constant acceleration: - - Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t] - m -> Sqrt[2 a d + s^2] - - DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2] - - When to start braking (di) to reach a specified destionation speed (s2) after accelerating - from initial speed s1 without ever stopping at a plateau: - - Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di] - di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance() - - IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a) - */ - - -// The number of linear motions that can be in the plan at any give time -#define BLOCK_BUFFER_SIZE 16 -#define BLOCK_BUFFER_MASK 0x0f - -static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions -static volatile unsigned char block_buffer_head; // Index of the next block to be pushed -static volatile unsigned char block_buffer_tail; // Index of the block to process now - -// The current position of the tool in absolute steps -static long position[4]; - -#define ONE_MINUTE_OF_MICROSECONDS 60000000.0 - -// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the -// given acceleration: -inline long estimate_acceleration_distance(long initial_rate, long target_rate, long acceleration) { - return( - (target_rate*target_rate-initial_rate*initial_rate)/ - (2L*acceleration) - ); -} - -// This function gives you the point at which you must start braking (at the rate of -acceleration) if -// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after -// a total travel of distance. This can be used to compute the intersection point between acceleration and -// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) - -inline long intersection_distance(long initial_rate, long final_rate, long acceleration, long distance) { - return( - (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ - (4*acceleration) - ); -} - -// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. - -void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { - if(block->busy == true) return; // If block is busy then bail out. - float entry_factor = entry_speed / block->nominal_speed; - float exit_factor = exit_speed / block->nominal_speed; - long initial_rate = ceil(block->nominal_rate*entry_factor); - long final_rate = ceil(block->nominal_rate*exit_factor); - -#ifdef ADVANCE - long initial_advance = block->advance*entry_factor*entry_factor; - long final_advance = block->advance*exit_factor*exit_factor; -#endif // ADVANCE - - // Limit minimal step rate (Otherwise the timer will overflow.) - if(initial_rate <120) initial_rate=120; - if(final_rate < 120) final_rate=120; - - // Calculate the acceleration steps - long acceleration = block->acceleration_st; - long accelerate_steps = estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration); - long decelerate_steps = estimate_acceleration_distance(final_rate, block->nominal_rate, acceleration); - // Calculate the size of Plateau of Nominal Rate. - long plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; - - // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will - // have to use intersection_distance() to calculate when to abort acceleration and start braking - // in order to reach the final_rate exactly at the end of this block. - if (plateau_steps < 0) { - accelerate_steps = intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count); - plateau_steps = 0; - } - - long decelerate_after = accelerate_steps+plateau_steps; - long acceleration_rate = (long)((float)acceleration * 8.388608); - - CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section - if(block->busy == false) { // Don't update variables if block is busy. - block->accelerate_until = accelerate_steps; - block->decelerate_after = decelerate_after; - block->acceleration_rate = acceleration_rate; - block->initial_rate = initial_rate; - block->final_rate = final_rate; -#ifdef ADVANCE - block->initial_advance = initial_advance; - block->final_advance = final_advance; -#endif //ADVANCE - } - CRITICAL_SECTION_END; -} - -// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the -// acceleration within the allotted distance. -inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { - return( - sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) - ); -} - -// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks. -// This method will calculate the junction jerk as the euclidean distance between the nominal -// velocities of the respective blocks. -inline float junction_jerk(block_t *before, block_t *after) { - return(sqrt( - pow((before->speed_x-after->speed_x), 2)+ - pow((before->speed_y-after->speed_y), 2))); -} - -// Return the safe speed which is max_jerk/2, e.g. the -// speed under which you cannot exceed max_jerk no matter what you do. -float safe_speed(block_t *block) { - float safe_speed; - safe_speed = max_xy_jerk/2; - if(abs(block->speed_z) > max_z_jerk/2) safe_speed = max_z_jerk/2; - if (safe_speed > block->nominal_speed) safe_speed = block->nominal_speed; - return safe_speed; -} - -// The kernel called by planner_recalculate() when scanning the plan from last to first entry. -void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) { - if(!current) { - return; - } - - float entry_speed = current->nominal_speed; - float exit_factor; - float exit_speed; - if (next) { - exit_speed = next->entry_speed; - } - else { - exit_speed = safe_speed(current); - } - - // Calculate the entry_factor for the current block. - if (previous) { - // Reduce speed so that junction_jerk is within the maximum allowed - float jerk = junction_jerk(previous, current); - if((previous->steps_x == 0) && (previous->steps_y == 0)) { - entry_speed = safe_speed(current); - } - else if (jerk > max_xy_jerk) { - entry_speed = (max_xy_jerk/jerk) * entry_speed; - } - if(abs(previous->speed_z - current->speed_z) > max_z_jerk) { - entry_speed = (max_z_jerk/abs(previous->speed_z - current->speed_z)) * entry_speed; - } - // If the required deceleration across the block is too rapid, reduce the entry_factor accordingly. - if (entry_speed > exit_speed) { - float max_entry_speed = max_allowable_speed(-current->acceleration,exit_speed, current->millimeters); - if (max_entry_speed < entry_speed) { - entry_speed = max_entry_speed; - } - } - } - else { - entry_speed = safe_speed(current); - } - // Store result - current->entry_speed = entry_speed; -} - -// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This -// implements the reverse pass. -void planner_reverse_pass() { - char block_index = block_buffer_head; - block_t *block[3] = { - NULL, NULL, NULL }; - while(block_index != block_buffer_tail) { - block[2]= block[1]; - block[1]= block[0]; - block[0] = &block_buffer[block_index]; - planner_reverse_pass_kernel(block[0], block[1], block[2]); - block_index--; - if(block_index < 0) { - block_index = BLOCK_BUFFER_SIZE-1; - } - } -// planner_reverse_pass_kernel(NULL, block[0], block[1]); -} - -// The kernel called by planner_recalculate() when scanning the plan from first to last entry. -void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) { - if(!current) { - return; - } - if(previous) { - // If the previous block is an acceleration block, but it is not long enough to - // complete the full speed change within the block, we need to adjust out entry - // speed accordingly. Remember current->entry_factor equals the exit factor of - // the previous block. - if(previous->entry_speed < current->entry_speed) { - float max_entry_speed = max_allowable_speed(-previous->acceleration, previous->entry_speed, previous->millimeters); - if (max_entry_speed < current->entry_speed) { - current->entry_speed = max_entry_speed; - } - } - } -} - -// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This -// implements the forward pass. -void planner_forward_pass() { - char block_index = block_buffer_tail; - block_t *block[3] = { - NULL, NULL, NULL }; - - while(block_index != block_buffer_head) { - block[0] = block[1]; - block[1] = block[2]; - block[2] = &block_buffer[block_index]; - planner_forward_pass_kernel(block[0],block[1],block[2]); - block_index = (block_index+1) & BLOCK_BUFFER_MASK; - } - planner_forward_pass_kernel(block[1], block[2], NULL); -} - -// Recalculates the trapezoid speed profiles for all blocks in the plan according to the -// entry_factor for each junction. Must be called by planner_recalculate() after -// updating the blocks. -void planner_recalculate_trapezoids() { - char block_index = block_buffer_tail; - block_t *current; - block_t *next = NULL; - while(block_index != block_buffer_head) { - current = next; - next = &block_buffer[block_index]; - if (current) { - calculate_trapezoid_for_block(current, current->entry_speed, next->entry_speed); - } - block_index = (block_index+1) & BLOCK_BUFFER_MASK; - } - calculate_trapezoid_for_block(next, next->entry_speed, safe_speed(next)); -} - -// Recalculates the motion plan according to the following algorithm: -// -// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) -// so that: -// a. The junction jerk is within the set limit -// b. No speed reduction within one block requires faster deceleration than the one, true constant -// acceleration. -// 2. Go over every block in chronological order and dial down junction speed reduction values if -// a. The speed increase within one block would require faster accelleration than the one, true -// constant acceleration. -// -// When these stages are complete all blocks have an entry_factor that will allow all speed changes to -// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than -// the set limit. Finally it will: -// -// 3. Recalculate trapezoids for all blocks. - -void planner_recalculate() { - planner_reverse_pass(); - planner_forward_pass(); - planner_recalculate_trapezoids(); -} - -void plan_init() { - block_buffer_head = 0; - block_buffer_tail = 0; - memset(position, 0, sizeof(position)); // clear position -} - - -inline void plan_discard_current_block() { - if (block_buffer_head != block_buffer_tail) { - block_buffer_tail = (block_buffer_tail + 1) & BLOCK_BUFFER_MASK; - } -} - -inline block_t *plan_get_current_block() { - if (block_buffer_head == block_buffer_tail) { - return(NULL); - } - block_t *block = &block_buffer[block_buffer_tail]; - block->busy = true; - return(block); -} - -void check_axes_activity() { - unsigned char x_active = 0; - unsigned char y_active = 0; - unsigned char z_active = 0; - unsigned char e_active = 0; - block_t *block; - - if(block_buffer_tail != block_buffer_head) { - char block_index = block_buffer_tail; - while(block_index != block_buffer_head) { - block = &block_buffer[block_index]; - if(block->steps_x != 0) x_active++; - if(block->steps_y != 0) y_active++; - if(block->steps_z != 0) z_active++; - if(block->steps_e != 0) e_active++; - block_index = (block_index+1) & BLOCK_BUFFER_MASK; - } - } - if((DISABLE_X) && (x_active == 0)) disable_x(); - if((DISABLE_Y) && (y_active == 0)) disable_y(); - if((DISABLE_Z) && (z_active == 0)) disable_z(); - if((DISABLE_E) && (e_active == 0)) disable_e(); -} - -// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in -// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration -// calculation the caller must also provide the physical length of the line in millimeters. -void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { - - // The target position of the tool in absolute steps - // Calculate target position in absolute steps - long target[4]; - target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); - target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); - target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); - target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); - - // Calculate the buffer head after we push this byte - int next_buffer_head = (block_buffer_head + 1) & BLOCK_BUFFER_MASK; - - // If the buffer is full: good! That means we are well ahead of the robot. - // Rest here until there is room in the buffer. - while(block_buffer_tail == next_buffer_head) { - manage_heater(); - manage_inactivity(1); - } - - // Prepare to set up new block - block_t *block = &block_buffer[block_buffer_head]; - - // Mark block as not busy (Not executed by the stepper interrupt) - block->busy = false; - - // Number of steps for each axis - block->steps_x = labs(target[X_AXIS]-position[X_AXIS]); - block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]); - block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); - block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); - block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); - - // Bail if this is a zero-length block - if (block->step_event_count == 0) { - return; - }; - - //enable active axes - if(block->steps_x != 0) enable_x(); - if(block->steps_y != 0) enable_y(); - if(block->steps_z != 0) enable_z(); - if(block->steps_e != 0) enable_e(); - - float delta_x_mm = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; - float delta_y_mm = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; - float delta_z_mm = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; - float delta_e_mm = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS]; - block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); - - unsigned long microseconds; - microseconds = lround((block->millimeters/feed_rate)*1000000); - //added my lampmaker to slow down rather than wait at the corner for a buffer refill - // turns corner blobs into more dissapated blobs - int blockcount=block_buffer_head-block_buffer_tail; - //blockcount=8; - while(blockcount<0) blockcount+=BLOCK_BUFFER_SIZE; - if ((blockcount<=2)&&(microseconds<50000)) microseconds=50000; - else if ((blockcount<=4)&&(microseconds<20000)) microseconds=20000; - else if ((blockcount<=8)&&(microseconds<10000)) microseconds=10000; - - // Calculate speed in mm/minute for each axis - float multiplier = 60.0*1000000.0/microseconds; - block->speed_z = delta_z_mm * multiplier; - block->speed_x = delta_x_mm * multiplier; - block->speed_y = delta_y_mm * multiplier; - block->speed_e = delta_e_mm * multiplier; - - // Limit speed per axis - float speed_factor = 1; - float tmp_speed_factor; - if(abs(block->speed_x) > max_feedrate[X_AXIS]) { - //// [ErikDeBruijn] IS THIS THE BUG WE'RE LOOING FOR???? - // it used to be just this line: speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); - tmp_speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ - tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ - tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_e) > max_feedrate[E_AXIS]){ - tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - multiplier = multiplier * speed_factor; - block->speed_z = delta_z_mm * multiplier; - block->speed_x = delta_x_mm * multiplier; - block->speed_y = delta_y_mm * multiplier; - block->speed_e = delta_e_mm * multiplier; - block->nominal_speed = block->millimeters * multiplier; - block->nominal_rate = ceil(block->step_event_count * multiplier / 60); - - if(block->nominal_rate < 120) block->nominal_rate = 120; - block->entry_speed = safe_speed(block); - - // Compute the acceleration rate for the trapezoid generator. - float travel_per_step = block->millimeters/block->step_event_count; - if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { - block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 - } - else { - block->acceleration_st = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 - // Limit acceleration per axis - if((block->acceleration_st * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) - block->acceleration_st = axis_steps_per_sqr_second[X_AXIS]; - if((block->acceleration_st * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) - block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS]; - if((block->acceleration_st * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) - block->acceleration_st = axis_steps_per_sqr_second[E_AXIS]; - if(((block->acceleration_st / block->step_event_count) * block->steps_z ) > axis_steps_per_sqr_second[Z_AXIS]) - block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS]; - } - block->acceleration = block->acceleration_st * travel_per_step; - -#ifdef ADVANCE - // Calculate advance rate - if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { - block->advance_rate = 0; - block->advance = 0; - } - else { - long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st); - float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * - (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; - block->advance = advance; - if(acc_dist == 0) { - block->advance_rate = 0; - } - else { - block->advance_rate = advance / (float)acc_dist; - } - } - -#endif // ADVANCE - - // compute a preliminary conservative acceleration trapezoid - float safespeed = safe_speed(block); - calculate_trapezoid_for_block(block, safespeed, safespeed); - - // Compute direction bits for this block - block->direction_bits = 0; - if (target[X_AXIS] < position[X_AXIS]) { - block->direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<> 16 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 24 bit result -#define MultiU16X8toH16(intRes, charIn1, intIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %A1, %A2 \n\t" \ -"add %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r0 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (charIn1), \ -"d" (intIn2) \ -: \ -"r26" \ -) - -// intRes = longIn1 * longIn2 >> 24 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 48bit result -#define MultiU24X24toH16(intRes, longIn1, longIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"mov r27, r1 \n\t" \ -"mul %B1, %C2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %C1, %C2 \n\t" \ -"add %B0, r0 \n\t" \ -"mul %C1, %B2 \n\t" \ -"add %A0, r0 \n\t" \ -"adc %B0, r1 \n\t" \ -"mul %A1, %C2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %B2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %C1, %A2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %A2 \n\t" \ -"add r27, r1 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r27 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (longIn1), \ -"d" (longIn2) \ -: \ -"r26" , "r27" \ -) - -// Some useful constants - -#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1< -// -// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates -// first block->accelerate_until step_events_completed, then keeps going at constant speed until -// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. -// The slope of acceleration is calculated with the leib ramp alghorithm. - -void st_wake_up() { - // TCNT1 = 0; - ENABLE_STEPPER_DRIVER_INTERRUPT(); -} - -inline unsigned short calc_timer(unsigned short step_rate) { - unsigned short timer; - if(step_rate < 32) step_rate = 32; - step_rate -= 32; // Correct for minimal speed - if(step_rate >= (8*256)){ // higher step rate - unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; - unsigned char tmp_step_rate = (step_rate & 0x00ff); - unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); - MultiU16X8toH16(timer, tmp_step_rate, gain); - timer = (unsigned short)pgm_read_word_near(table_address) - timer; - } - else { // lower step rates - unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; - table_address += ((step_rate)>>1) & 0xfffc; - timer = (unsigned short)pgm_read_word_near(table_address); - timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); - } - if(timer < 100) timer = 100; - return timer; -} - -// Initializes the trapezoid generator from the current block. Called whenever a new -// block begins. -inline void trapezoid_generator_reset() { - accelerate_until = current_block->accelerate_until; - decelerate_after = current_block->decelerate_after; - acceleration_rate = current_block->acceleration_rate; - initial_rate = current_block->initial_rate; - final_rate = current_block->final_rate; - nominal_rate = current_block->nominal_rate; - advance = current_block->initial_advance; - final_advance = current_block->final_advance; - deceleration_time = 0; - advance_rate = current_block->advance_rate; - // step_rate to timer interval - acc_step_rate = initial_rate; - acceleration_time = calc_timer(acc_step_rate); - OCR1A = acceleration_time; -} - -// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. -// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. -ISR(TIMER1_COMPA_vect) -{ - if(busy){ /*Serial.println("BUSY")*/; - return; - } // The busy-flag is used to avoid reentering this interrupt - - busy = true; - sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) -#ifdef FANCY_BUTTONS - static int breakdown=0; - if((breakdown++)%100==0) - buttons_check(); -/* [ErikDeBruijn] Perhaps it would be nice to use a piece of code like this (adapted from process_g_code), to create a nice progress bar! - if(sdactive){ - sprintf("SD printing byte %i%",(int) (sdpos/filesize*100)); // perhaps a fraction of a percent is also nice, 0.03%, progress bar even better. - Serial.print(sdpos); - Serial.print("/"); - Serial.println(filesize); - } -*/ -#endif - - // If there is no current block, attempt to pop one from the buffer - if (current_block == NULL) { - // Anything in the buffer? - current_block = plan_get_current_block(); - if (current_block != NULL) { - trapezoid_generator_reset(); - counter_x = -(current_block->step_event_count >> 1); - counter_y = counter_x; - counter_z = counter_x; - counter_e = counter_x; - step_events_completed = 0; - e_steps = 0; -#ifdef DEBUG_STEPS - stepstaken[0]=0;stepstaken[1]=0;stepstaken[2]=0;stepstaken[3]=0; - Serial.print("(Planned: "); - Serial.print(abs(current_block->steps_x));Serial.print(" "); - Serial.print(abs(current_block->steps_y));Serial.print(" "); - Serial.print(abs(current_block->steps_z));Serial.print(" "); - //Serial.print(abs(current_block->steps_e));Serial.print(" "); - Serial.println(); -#endif - } - else { - DISABLE_STEPPER_DRIVER_INTERRUPT(); - } - } - - if (current_block != NULL) { - // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt - out_bits = current_block->direction_bits; - -#ifdef ADVANCE - // Calculate E early. - counter_e += current_block->steps_e; - if (counter_e > 0) { - counter_e -= current_block->step_event_count; - if ((out_bits & (1<> 16) - old_advance); - CRITICAL_SECTION_END; - old_advance = advance >> 16; -#endif //ADVANCE - - // Set direction en check limit switches - if ((out_bits & (1<step_event_count; - } - } - else { // +direction - WRITE(X_DIR_PIN,!INVERT_X_DIR); - if((READ(X_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_x >0)){ - step_events_completed = current_block->step_event_count; - } - } - - if ((out_bits & (1<step_event_count; - } - } - else { // +direction - WRITE(Y_DIR_PIN,!INVERT_Y_DIR); - if((READ(Y_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_y >0)){ - step_events_completed = current_block->step_event_count; - } - } - - if ((out_bits & (1<step_event_count; - } - } - else { // +direction - WRITE(Z_DIR_PIN,!INVERT_Z_DIR); - if((READ(Z_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_z >0)){ - step_events_completed = current_block->step_event_count; - } - } - -#ifndef ADVANCE - if ((out_bits & (1<steps_x; - if (counter_x > 0) { - WRITE(X_STEP_PIN, HIGH); - counter_x -= current_block->step_event_count; - WRITE(X_STEP_PIN, LOW); - #ifdef DEBUG_STEPS - stepstaken[0]++; - #endif - } - - counter_y += current_block->steps_y; - if (counter_y > 0) { - WRITE(Y_STEP_PIN, HIGH); - counter_y -= current_block->step_event_count; - WRITE(Y_STEP_PIN, LOW); - #ifdef DEBUG_STEPS - stepstaken[1]++; - #endif - } - - counter_z += current_block->steps_z; - if (counter_z > 0) { - WRITE(Z_STEP_PIN, HIGH); - counter_z -= current_block->step_event_count; - WRITE(Z_STEP_PIN, LOW); - #ifdef DEBUG_STEPS - stepstaken[2]++; - #endif - } - -#ifndef ADVANCE - counter_e += current_block->steps_e; - if (counter_e > 0) { - WRITE(E_STEP_PIN, HIGH); - counter_e -= current_block->step_event_count; - WRITE(E_STEP_PIN, LOW); - } -#endif //!ADVANCE - - // Calculare new timer value - unsigned short timer; - unsigned short step_rate; - if (step_events_completed < accelerate_until) { - MultiU24X24toH16(acc_step_rate, acceleration_time, acceleration_rate); - acc_step_rate += initial_rate; - - // upper limit - if(acc_step_rate > nominal_rate) - acc_step_rate = nominal_rate; - - // step_rate to timer interval - timer = calc_timer(acc_step_rate); - advance += advance_rate; - acceleration_time += timer; - OCR1A = timer; - } - else if (step_events_completed >= decelerate_after) { - MultiU24X24toH16(step_rate, deceleration_time, acceleration_rate); - - if(step_rate > acc_step_rate) { // Check step_rate stays positive - step_rate = final_rate; - } - else { - step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. - } - - // lower limit - if(step_rate < final_rate) - step_rate = final_rate; - - // step_rate to timer interval - timer = calc_timer(step_rate); -#ifdef ADVANCE - advance -= advance_rate; - if(advance < final_advance) - advance = final_advance; -#endif //ADVANCE - deceleration_time += timer; - OCR1A = timer; - } - // If current block is finished, reset pointer - step_events_completed += 1; - if (step_events_completed >= current_block->step_event_count) { - current_block = NULL; - plan_discard_current_block(); -#ifdef DEBUG_STEPS - Serial.print("(Steps done: "); - Serial.print(stepstaken[0]);Serial.print(" "); - Serial.print(stepstaken[1]);Serial.print(" "); - Serial.print(stepstaken[2]);Serial.println(" "); -#endif - } - } - busy=false; -} - -#ifdef ADVANCE - -unsigned char old_OCR0A; -// Timer interrupt for E. e_steps is set in the main routine; -// Timer 0 is shared with millies -ISR(TIMER0_COMPA_vect) -{ - // Critical section needed because Timer 1 interrupt has higher priority. - // The pin set functions are placed on trategic position to comply with the stepper driver timing. - WRITE(E_STEP_PIN, LOW); - // Set E direction (Depends on E direction + advance) - if (e_steps < 0) { - WRITE(E_DIR_PIN,INVERT_E_DIR); - e_steps++; - WRITE(E_STEP_PIN, HIGH); - } - if (e_steps > 0) { - WRITE(E_DIR_PIN,!INVERT_E_DIR); - e_steps--; - WRITE(E_STEP_PIN, HIGH); - } - old_OCR0A += 25; // 10kHz interrupt - OCR0A = old_OCR0A; -} -#endif // ADVANCE - -void st_init() -{ - // waveform generation = 0100 = CTC - TCCR1B &= ~(1<= 16) - { - current_raw = 16383 - raw_temp_value; - temp_meas_ready = true; - temp_count = 0; - raw_temp_value = 0; -#ifdef MAXTEMP - if(current_raw >= maxttemp) { - target_raw = 0; -#ifdef PIDTEMP - OCR2B = 0; -#else - WRITE(HEATER_0_PIN,LOW); -#endif //PIDTEMP - } -#endif //MAXTEMP -#ifdef MINTEMP - if(current_raw <= minttemp) { - target_raw = 0; -#ifdef PIDTEMP - OCR2B = 0; -#else - WRITE(HEATER_0_PIN,LOW); -#endif //PIDTEMP - } -#endif //MAXTEMP -#ifndef PIDTEMP - if(current_raw >= target_raw) - { - WRITE(HEATER_0_PIN,LOW); - } - else - { - WRITE(HEATER_0_PIN,HIGH); - } -#endif //PIDTEMP - } -} - +#include "Marlin.h" +// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in +// the source g-code and may never actually be reached if acceleration management is active. + +//#define DEBUG_STEPS + + +#include "speed_lookuptable.h" + +/* + Reprap firmware based on Sprinter and grbl. + Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + + This program 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. + + This program 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 this program. If not, see . + */ + +/* + This firmware is a mashup between Sprinter and grbl. + (https://github.com/kliment/Sprinter) + (https://github.com/simen/grbl/tree) + + It has preliminary support for Matthew Roberts advance algorithm + http://reprap.org/pipermail/reprap-dev/2011-May/003323.html + + This firmware is optimized for gen6 electronics. + */ + + + +#include "fastio.h" +#include "Configuration.h" +#include "pins.h" +#include "Marlin.h" +#include "speed_lookuptable.h" +#include "lcd.h" + +char version_string[] = "U0.9.3.2"; + +#ifdef SDSUPPORT +#include "SdFat.h" +#endif //SDSUPPORT + +#ifndef CRITICAL_SECTION_START +#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() +#define CRITICAL_SECTION_END SREG = _sreg +#endif //CRITICAL_SECTION_START + + +#if defined SDSUPPORT || defined FANCY_LCD || defined FANCY_BUTTONS +// The number of linear motions that can be in the plan at any give time. + #define BLOCK_BUFFER_SIZE 16 // SD,LCD,Buttons take more memory, block buffer needs to be smaller +#else + #define BLOCK_BUFFER_SIZE 40 // maximize block buffer +#endif + + +// if DEBUG_STEPS is enabled, M114 can be used to compare two methods of determining the X,Y,Z position of the printer. +// for debugging purposes only, should be disabled by default +#ifdef DEBUG_STEPS +volatile long count_position[NUM_AXIS] = { 0, 0, 0, 0}; +volatile int count_direction[NUM_AXIS] = { 1, 1, 1, 1}; +#endif +// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html +// 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 +// G28 - Home all 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 +// 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 +// M115 - Capabilities string +// 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) +// M301 - Set PID parameters P I and D + +//Stepper Movement Variables + +char axis_codes[NUM_AXIS] = { + 'X', 'Y', 'Z', 'E'}; +float destination[NUM_AXIS] = { + 0.0, 0.0, 0.0, 0.0}; +float current_position[NUM_AXIS] = { + 0.0, 0.0, 0.0, 0.0}; +bool home_all_axis = true; +long feedrate = 1500, next_feedrate, saved_feedrate; +long gcode_N, gcode_LastN; +unsigned long previous_millis_heater, previous_millis_bed_heater; +bool relative_mode = false; //Determines Absolute or Relative Coordinates +bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. +unsigned long axis_steps_per_sqr_second[NUM_AXIS]; + +volatile int feedmultiply=100; //100->1 200->2 +// comm variables +#define MAX_CMD_SIZE 96 +#define BUFSIZE 8 +char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; +bool fromsd[BUFSIZE]; +int bufindr = 0; +int bufindw = 0; +int buflen = 0; +int i = 0; +char serial_char; +int serial_count = 0; +boolean comment_mode = false; +char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc + +// Manage heater variables. + +int target_bed_raw = 0; +int current_bed_raw = 0; + +int target_raw = 0; +int current_raw = 0; +unsigned char temp_meas_ready = false; + +#ifdef PIDTEMP + double temp_iState = 0; + double temp_dState = 0; + double pTerm; + double iTerm; + double dTerm; + //int output; + double pid_error; + double temp_iState_min; + double temp_iState_max; + double pid_setpoint = 0.0; + double pid_input; + double pid_output; + bool pid_reset; +#endif //PIDTEMP +float tt = 0, bt = 0; +#ifdef WATCHPERIOD +int watch_raw = -1000; +unsigned long watchmillis = 0; +#endif //WATCHPERIOD +#ifdef MINTEMP +int minttemp = temp2analog(MINTEMP); +#endif //MINTEMP +#ifdef MAXTEMP +int maxttemp = temp2analog(MAXTEMP); +#endif //MAXTEMP + +//Inactivity shutdown variables +unsigned long previous_millis_cmd = 0; +unsigned long max_inactive_time = 0; +unsigned long stepper_inactive_time = 0; + +unsigned long starttime=0; +unsigned long stoptime=0; +#ifdef SDSUPPORT +Sd2Card card; +SdVolume volume; +SdFile root; +SdFile file; +uint32_t filesize = 0; +uint32_t sdpos = 0; +bool sdmode = false; +bool sdactive = false; +bool savetosd = false; +int16_t n; + +void initsd(){ + sdactive = false; +#if SDSS >- 1 + if(root.isOpen()) + root.close(); + if (!card.init(SPI_FULL_SPEED,SDSS)){ + //if (!card.init(SPI_HALF_SPEED,SDSS)) + Serial.println("SD init fail"); + } + else if (!volume.init(&card)) + Serial.println("volume.init failed"); + else if (!root.openRoot(&volume)) + Serial.println("openRoot failed"); + else + sdactive = true; +#endif //SDSS +} + +inline void write_command(char *buf){ + char* begin = buf; + char* npos = 0; + char* end = buf + strlen(buf) - 1; + + file.writeError = false; + if((npos = strchr(buf, 'N')) != NULL){ + begin = strchr(npos, ' ') + 1; + end = strchr(npos, '*') - 1; + } + end[1] = '\r'; + end[2] = '\n'; + end[3] = '\0'; + //Serial.println(begin); + file.write(begin); + if (file.writeError){ + Serial.println("error writing to file"); + } +} +#endif //SDSUPPORT + +void setup() +{ + + Serial.begin(BAUDRATE); + Serial.print("Marlin "); + Serial.println(version_string); + Serial.println("start"); +#ifdef FANCY_LCD + lcd_init(); +#endif + for(int i = 0; i < BUFSIZE; i++){ + fromsd[i] = false; + } + + + //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 +#if E_DIR_PIN > -1 + SET_OUTPUT(E_DIR_PIN); +#endif + + //Initialize Enable Pins - steppers default to disabled. + +#if (X_ENABLE_PIN > -1) + SET_OUTPUT(X_ENABLE_PIN); + if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); +#endif +#if (Y_ENABLE_PIN > -1) + SET_OUTPUT(Y_ENABLE_PIN); + if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); +#endif +#if (Z_ENABLE_PIN > -1) + SET_OUTPUT(Z_ENABLE_PIN); + if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); +#endif +#if (E_ENABLE_PIN > -1) + SET_OUTPUT(E_ENABLE_PIN); + if(!E_ENABLE_ON) WRITE(E_ENABLE_PIN,HIGH); +#endif + + //endstops and pullups +#ifdef ENDSTOPPULLUPS +#if X_MIN_PIN > -1 + SET_INPUT(X_MIN_PIN); + WRITE(X_MIN_PIN,HIGH); +#endif +#if X_MAX_PIN > -1 + SET_INPUT(X_MAX_PIN); + WRITE(X_MAX_PIN,HIGH); +#endif +#if Y_MIN_PIN > -1 + SET_INPUT(Y_MIN_PIN); + WRITE(Y_MIN_PIN,HIGH); +#endif +#if Y_MAX_PIN > -1 + SET_INPUT(Y_MAX_PIN); + WRITE(Y_MAX_PIN,HIGH); +#endif +#if Z_MIN_PIN > -1 + SET_INPUT(Z_MIN_PIN); + WRITE(Z_MIN_PIN,HIGH); +#endif +#if Z_MAX_PIN > -1 + SET_INPUT(Z_MAX_PIN); + WRITE(Z_MAX_PIN,HIGH); +#endif +#else //ENDSTOPPULLUPS +#if X_MIN_PIN > -1 + SET_INPUT(X_MIN_PIN); +#endif +#if X_MAX_PIN > -1 + SET_INPUT(X_MAX_PIN); +#endif +#if Y_MIN_PIN > -1 + SET_INPUT(Y_MIN_PIN); +#endif +#if Y_MAX_PIN > -1 + SET_INPUT(Y_MAX_PIN); +#endif +#if Z_MIN_PIN > -1 + SET_INPUT(Z_MIN_PIN); +#endif +#if Z_MAX_PIN > -1 + SET_INPUT(Z_MAX_PIN); +#endif +#endif //ENDSTOPPULLUPS + +#if (HEATER_0_PIN > -1) + SET_OUTPUT(HEATER_0_PIN); +#endif +#if (HEATER_1_PIN > -1) + SET_OUTPUT(HEATER_1_PIN); +#endif + + //Initialize Step Pins +#if (X_STEP_PIN > -1) + SET_OUTPUT(X_STEP_PIN); +#endif +#if (Y_STEP_PIN > -1) + SET_OUTPUT(Y_STEP_PIN); +#endif +#if (Z_STEP_PIN > -1) + SET_OUTPUT(Z_STEP_PIN); +#endif +#if (E_STEP_PIN > -1) + SET_OUTPUT(E_STEP_PIN); +#endif + for(int i=0; i < NUM_AXIS; i++){ + axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; + } + +#ifdef PIDTEMP + temp_iState_min = 0.0; + temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; +#endif //PIDTEMP + +#ifdef SDSUPPORT + //power to SD reader +#if SDPOWER > -1 + SET_OUTPUT(SDPOWER); + WRITE(SDPOWER,HIGH); +#endif //SDPOWER + initsd(); + +#endif //SDSUPPORT + plan_init(); // Initialize planner; + st_init(); // Initialize stepper; +// tp_init(); // Initialize temperature loop + checkautostart(); +} + +#ifdef SDSUPPORT +void checkautostart() +{ + if(!sdactive) + return; + static int lastnr=0; + char autoname[30]; + sprintf(autoname,"auto%i.g",lastnr); + for(int i=0;i 0) + { + for(int i=0;i 0 && buflen < BUFSIZE) { + serial_char = Serial.read(); + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) + { + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = false; + if(strstr(cmdbuffer[bufindw], "N") != NULL) + { + strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); + gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); + if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { + Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); + Serial.println(gcode_LastN); + //Serial.println(gcode_N); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + if(strstr(cmdbuffer[bufindw], "*") != NULL) + { + byte checksum = 0; + byte count = 0; + while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; + strchr_pointer = strchr(cmdbuffer[bufindw], '*'); + + if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { + Serial.print("Error: checksum mismatch, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + //if no errors, continue parsing + } + else + { + Serial.print("Error: No Checksum with line number, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + gcode_LastN = gcode_N; + //if no errors, continue parsing + } + else // if we don't receive 'N' but still see '*' + { + if((strstr(cmdbuffer[bufindw], "*") != NULL)) + { + Serial.print("Error: No Line Number with checksum, Last Line:"); + Serial.println(gcode_LastN); + serial_count = 0; + return; + } + } + if((strstr(cmdbuffer[bufindw], "G") != NULL)){ + strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); + switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ + case 0: + case 1: +#ifdef SDSUPPORT + if(savetosd) + break; +#endif //SDSUPPORT + Serial.println("ok"); + break; + default: + break; + } + + } + bufindw = (bufindw + 1)%BUFSIZE; + buflen += 1; + + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } + } +#ifdef SDSUPPORT + if(!sdmode || serial_count!=0){ + return; + } + while( filesize > sdpos && buflen < BUFSIZE) { + n = file.read(); + serial_char = (char)n; + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) + { + sdpos = file.curPosition(); + if(sdpos >= filesize){ + sdmode = false; + Serial.println("Done printing file"); + stoptime=millis(); + char time[30]; + unsigned long t=(stoptime-starttime)/1000; + int sec,min; + min=t/60; + sec=t%60; + sprintf(time,"%i min, %i sec",min,sec); + Serial.println(time); + LCD_MESSAGE(time); + checkautostart(); + } + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = true; + buflen += 1; + bufindw = (bufindw + 1)%BUFSIZE; + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } + } +#endif //SDSUPPORT + +} + + +inline float code_value() { + return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); +} +inline long code_value_long() { + return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); +} +inline bool code_seen(char code_string[]) { + return (strstr(cmdbuffer[bufindr], code_string) != NULL); +} //Return True if the string was found + +inline bool code_seen(char code) +{ + strchr_pointer = strchr(cmdbuffer[bufindr], code); + return (strchr_pointer != NULL); //Return True if a character was found +} + +inline void process_commands() +{ + unsigned long codenum; //throw away variable + char *starpos = NULL; + + if(code_seen('G')) + { + switch((int)code_value()) + { + case 0: // G0 -> G1 + case 1: // G1 + get_coordinates(); // For X Y Z E F + prepare_move(); + previous_millis_cmd = millis(); + //ClearToSend(); + return; + //break; + case 4: // G4 dwell + codenum = 0; + if(code_seen('P')) codenum = code_value(); // milliseconds to wait + if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait + codenum += millis(); // keep track of when we started waiting + while(millis() < codenum ){ + manage_heater(); + } + break; + case 28: //G28 Home all Axis one at a time + saved_feedrate = feedrate; + for(int i=0; i < NUM_AXIS; i++) { + destination[i] = current_position[i]; + } + feedrate = 0; + + home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); + + if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) { + if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){ + st_synchronize(); + current_position[X_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; + feedrate = homing_feedrate[X_AXIS]; + prepare_move(); + + st_synchronize(); + current_position[X_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = -5 * X_HOME_DIR; + prepare_move(); + + st_synchronize(); + destination[X_AXIS] = 10 * X_HOME_DIR; + feedrate = homing_feedrate[X_AXIS]/2 ; + prepare_move(); + st_synchronize(); + + current_position[X_AXIS] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = current_position[X_AXIS]; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { + if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){ + current_position[Y_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; + feedrate = homing_feedrate[Y_AXIS]; + prepare_move(); + st_synchronize(); + + current_position[Y_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = -5 * Y_HOME_DIR; + prepare_move(); + st_synchronize(); + + destination[Y_AXIS] = 10 * Y_HOME_DIR; + feedrate = homing_feedrate[Y_AXIS]/2; + prepare_move(); + st_synchronize(); + + current_position[Y_AXIS] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = current_position[Y_AXIS]; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { + if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){ + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; + feedrate = homing_feedrate[Z_AXIS]; + prepare_move(); + st_synchronize(); + + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = -2 * Z_HOME_DIR; + prepare_move(); + st_synchronize(); + + destination[Z_AXIS] = 3 * Z_HOME_DIR; + feedrate = homing_feedrate[Z_AXIS]/2; + prepare_move(); + st_synchronize(); + + current_position[Z_AXIS] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = current_position[Z_AXIS]; + feedrate = 0; + } + } + feedrate = saved_feedrate; + previous_millis_cmd = millis(); + break; + case 90: // G90 + relative_mode = false; + break; + case 91: // G91 + relative_mode = true; + break; + case 92: // G92 + if(!code_seen(axis_codes[E_AXIS])) + st_synchronize(); + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) current_position[i] = code_value(); + } + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + break; + + } + } + + else if(code_seen('M')) + { + + switch( (int)code_value() ) + { +#ifdef SDSUPPORT + + case 20: // M20 - list SD card + Serial.println("Begin file list"); + root.ls(); + Serial.println("End file list"); + break; + case 21: // M21 - init SD card + sdmode = false; + initsd(); + break; + case 22: //M22 - release SD card + sdmode = false; + sdactive = false; + break; + case 23: //M23 - Select file + if(sdactive){ + sdmode = false; + file.close(); + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos!=NULL) + *(starpos-1)='\0'; + if (file.open(&root, strchr_pointer + 4, O_READ)) { + Serial.print("File opened:"); + Serial.print(strchr_pointer + 4); + Serial.print(" Size:"); + Serial.println(file.fileSize()); + sdpos = 0; + filesize = file.fileSize(); + Serial.println("File selected"); + } + else{ + Serial.println("file.open failed"); + } + } + break; + case 24: //M24 - Start SD print + if(sdactive){ + sdmode = true; + starttime=millis(); + } + break; + case 25: //M25 - Pause SD print + if(sdmode){ + sdmode = false; + } + break; + case 26: //M26 - Set SD index + if(sdactive && code_seen('S')){ + sdpos = code_value_long(); + file.seekSet(sdpos); + } + break; + case 27: //M27 - Get SD status + if(sdactive){ + Serial.print("SD printing byte "); + Serial.print(sdpos); + Serial.print("/"); + Serial.println(filesize); + } + else{ + Serial.println("Not SD printing"); + } + break; + case 28: //M28 - Start SD write + if(sdactive){ + char* npos = 0; + file.close(); + sdmode = false; + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos != NULL){ + npos = strchr(cmdbuffer[bufindr], 'N'); + strchr_pointer = strchr(npos,' ') + 1; + *(starpos-1) = '\0'; + } + if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) + { + Serial.print("open failed, File: "); + Serial.print(strchr_pointer + 4); + Serial.print("."); + } + else{ + savetosd = true; + Serial.print("Writing to file: "); + Serial.println(strchr_pointer + 4); + } + } + break; + case 29: //M29 - Stop SD write + //processed in write to file routine above + //savetosd = false; + break; + case 30: + { + stoptime=millis(); + char time[30]; + unsigned long t=(stoptime-starttime)/1000; + int sec,min; + min=t/60; + sec=t%60; + sprintf(time,"%i min, %i sec",min,sec); + Serial.println(time); + LCD_MESSAGE(time); + } + break; +#endif //SDSUPPORT + case 104: // M104 + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw > current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + break; + case 140: // M140 set bed temp + if (code_seen('S')) target_bed_raw = temp2analogBed(code_value()); + break; + case 105: // M105 + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) + tt = analog2temp(current_raw); + #endif + #if TEMP_1_PIN > -1 + bt = analog2tempBed(current_bed_raw); + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) + Serial.print("ok T:"); + Serial.print(tt); + Serial.print(", raw:"); + Serial.print(current_raw); + #if TEMP_1_PIN > -1 + Serial.print(" B:"); + Serial.println(bt); + #else + Serial.println(); + #endif + #else + Serial.println("No thermistors - no temp"); + #endif + return; + //break; + case 109: // M109 - Wait for extruder heater to reach target. + LCD_MESSAGE("Heating..."); + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw>current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + codenum = millis(); + starttime=millis(); + while(current_raw < target_raw) { + if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + Serial.print("T:"); + Serial.println( analog2temp(current_raw) ); + + codenum = millis(); + } + LCD_STATUS; + manage_heater(); + } + break; + case 190: // M190 - Wait bed for heater to reach target. + #if TEMP_1_PIN > -1 + if (code_seen('S')) target_bed_raw = temp2analog(code_value()); + codenum = millis(); + while(current_bed_raw < target_bed_raw) + { + if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + float tt=analog2temp(current_raw); + Serial.print("T:"); + Serial.println( tt ); + Serial.print("ok T:"); + Serial.print( tt ); + Serial.print(" B:"); + Serial.println( analog2temp(current_bed_raw) ); + codenum = millis(); + } + manage_heater(); + } + #endif + break; + case 106: //M106 Fan On + if (code_seen('S')){ + digitalWrite(FAN_PIN,HIGH); + analogWrite(FAN_PIN, constrain(code_value(),0,255) ); + } + else + { + digitalWrite(FAN_PIN,HIGH); + analogWrite(FAN_PIN, 255); + } + break; + case 107: //M107 Fan Off + digitalWrite(FAN_PIN,LOW); + analogWrite(FAN_PIN, 0); + break; + + case 82: + axis_relative_modes[3] = false; + break; + case 83: + axis_relative_modes[3] = true; + break; + case 18: + case 84: + if(code_seen('S')){ + stepper_inactive_time = code_value() * 1000; + } + else{ + st_synchronize(); + disable_x(); + disable_y(); + disable_z(); + disable_e(); + } + break; + case 85: // M85 + code_seen('S'); + max_inactive_time = code_value() * 1000; + break; + case 92: // M92 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); + } + + break; + case 115: // M115 + Serial.println("FIRMWARE_NAME:Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); + break; + case 114: // M114 + Serial.print("X:"); + Serial.print(current_position[X_AXIS]); + Serial.print("Y:"); + Serial.print(current_position[Y_AXIS]); + Serial.print("Z:"); + Serial.print(current_position[Z_AXIS]); + Serial.print("E:"); + Serial.print(current_position[E_AXIS]); + #ifdef DEBUG_STEPS + Serial.print(" Count X:"); + Serial.print(float(count_position[X_AXIS])/axis_steps_per_unit[X_AXIS]); + Serial.print("Y:"); + Serial.print(float(count_position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]); + Serial.print("Z:"); + Serial.println(float(count_position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]); + #endif + Serial.println(""); + break; + case 119: // M119 +#if (X_MIN_PIN > -1) + Serial.print("x_min:"); + Serial.print((READ(X_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (X_MAX_PIN > -1) + Serial.print("x_max:"); + Serial.print((READ(X_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Y_MIN_PIN > -1) + Serial.print("y_min:"); + Serial.print((READ(Y_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Y_MAX_PIN > -1) + Serial.print("y_max:"); + Serial.print((READ(Y_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Z_MIN_PIN > -1) + Serial.print("z_min:"); + Serial.print((READ(Z_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Z_MAX_PIN > -1) + Serial.print("z_max:"); + Serial.print((READ(Z_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif + Serial.println(""); + break; + //TODO: update for all axis, use for loop + case 201: // M201 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; +#if 0 // Not used for Sprinter/grbl gen6 + case 202: // M202 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; +#endif +#ifdef PIDTEMP + case 301: // M301 + if(code_seen('P')) Kp = code_value(); + if(code_seen('I')) Ki = code_value()*PID_dT; + if(code_seen('D')) Kd = code_value()/PID_dT; + Serial.print("Kp ");Serial.println(Kp); + Serial.print("Ki ");Serial.println(Ki/PID_dT); + Serial.print("Kd ");Serial.println(Kd*PID_dT); + temp_iState_min = 0.0; + temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; + break; +#endif //PIDTEMP + } + } + else{ + Serial.println("Unknown command:"); + Serial.println(cmdbuffer[bufindr]); + } + + ClearToSend(); +} + +void FlushSerialRequestResend() +{ + //char cmdbuffer[bufindr][100]="Resend:"; + Serial.flush(); + Serial.print("Resend:"); + Serial.println(gcode_LastN + 1); + ClearToSend(); +} + +void ClearToSend() +{ + previous_millis_cmd = millis(); +#ifdef SDSUPPORT + if(fromsd[bufindr]) + return; +#endif //SDSUPPORT + Serial.println("ok"); +} + +inline void get_coordinates() +{ + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; + else destination[i] = current_position[i]; //Are these else lines really needed? + } + if(code_seen('F')) { + next_feedrate = code_value(); + if(next_feedrate > 0.0) feedrate = next_feedrate; + } +} + +void prepare_move() +{ + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60.0/100.); + for(int i=0; i < NUM_AXIS; i++) { + current_position[i] = destination[i]; + } +} +/* +void manage_heater() +{ + float pid_input; + float pid_output; + if(temp_meas_ready != true) + return; + +CRITICAL_SECTION_START; + temp_meas_ready = false; +CRITICAL_SECTION_END; + +#ifdef PIDTEMP + pid_input = analog2temp(current_raw); + +#ifndef PID_OPENLOOP + pid_error = pid_setpoint - pid_input; + if(pid_error > 10){ + pid_output = PID_MAX; + pid_reset = true; + } + else if(pid_error < -10) { + pid_output = 0; + pid_reset = true; + } + else { + if(pid_reset == true) { + temp_iState = 0.0; + pid_reset = false; + } + pTerm = Kp * pid_error; + temp_iState += pid_error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = Ki * temp_iState; + #define K1 0.8 + #define K2 (1.0-K1) + dTerm = (Kd * (pid_input - temp_dState))*K2 + (K1 * dTerm); + temp_dState = pid_input; + pid_output = constrain(pTerm + iTerm - dTerm, 0, PID_MAX); + } +#endif //PID_OPENLOOP +#ifdef PID_DEBUG + Serial.print(" Input "); + Serial.print(pid_input); + Serial.print(" Output "); + Serial.print(pid_output); + Serial.print(" pTerm "); + Serial.print(pTerm); + Serial.print(" iTerm "); + Serial.print(iTerm); + Serial.print(" dTerm "); + Serial.print(dTerm); + Serial.println(); +#endif //PID_DEBUG + OCR2B = pid_output; +#endif //PIDTEMP +} +*/ + + +/* +int temp2analogu(int celsius, const short table[][2], int numtemps) { + int raw = 0; + byte i; + + for (i=1; i raw) { + celsius = (float)table[i-1][1] + + (float)(raw - table[i-1][0]) * + (float)(table[i][1] - table[i-1][1]) / + (float)(table[i][0] - table[i-1][0]); + + break; + } + } + // Overflow: Set to last value in the table + if (i == numtemps) celsius = table[i-1][1]; + + return celsius; +} + + +inline void kill() +{ + target_raw=0; +#ifdef PIDTEMP + pid_setpoint = 0.0; +#endif //PIDTEMP + OCR2B = 0; + WRITE(HEATER_0_PIN,LOW); + + disable_x(); + disable_y(); + disable_z(); + disable_e(); + +} +*/ + + + +//#################################################################################################################### +//#################################################################################################################### +void manage_heater() +{ +#ifdef USE_WATCHDOG + wd_reset(); +#endif + //there is no FANCY_LCD here, because this routine is called within moves, and delays them. one could loose steps. + + if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) + return; + previous_millis_heater = millis(); + #ifdef HEATER_USES_THERMISTOR + current_raw = analogRead(TEMP_0_PIN); + // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_raw = 1023 - current_raw; + #elif defined HEATER_USES_AD595 + current_raw = analogRead(TEMP_0_PIN); + #elif defined HEATER_USES_MAX6675 + current_raw = read_max6675(); + #endif + #ifdef SMOOTHING + nma = (nma + current_raw) - (nma / SMOOTHFACTOR); + current_raw = nma / SMOOTHFACTOR; + #endif + #ifdef WATCHPERIOD + if(watchmillis && millis() - watchmillis > WATCHPERIOD){ + if(watch_raw + 1 >= current_raw){ + target_raw = 0; + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + }else{ + watchmillis = 0; + } + } + #endif + #ifdef MINTEMP + if(current_raw <= minttemp) + target_raw = 0; + #endif + #ifdef MAXTEMP + if(current_raw >= maxttemp) { + target_raw = 0; + } + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) + #ifdef PIDTEMP + error = target_raw - current_raw; + pTerm = (PID_PGAIN * error) / 100; + temp_iState += error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = (PID_IGAIN * temp_iState) / 100; + dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; + temp_dState = current_raw; + analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); + #else + if(current_raw >= target_raw) + { + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + } + else + { + digitalWrite(HEATER_0_PIN,HIGH); + digitalWrite(LED_PIN,HIGH); + } + #endif + #endif + + if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) + return; + previous_millis_bed_heater = millis(); + + #ifdef BED_USES_THERMISTOR + + current_bed_raw = analogRead(TEMP_1_PIN); + + // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_bed_raw = 1023 - current_bed_raw; + #elif defined BED_USES_AD595 + current_bed_raw = analogRead(TEMP_1_PIN); + + #endif + + + #if TEMP_1_PIN > -1 + if(current_bed_raw >= target_bed_raw) + { + digitalWrite(HEATER_1_PIN,LOW); + } + else + { + digitalWrite(HEATER_1_PIN,HIGH); + } + #endif +} + +// Takes hot end temperature value as input and returns corresponding raw value. +// For a thermistor, it uses the RepRap thermistor temp table. +// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value. +// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware. +float temp2analog(int celsius) { + #ifdef HEATER_USES_THERMISTOR + int raw = 0; + byte i; + + for (i=1; i raw) + { + celsius = temptable[i-1][1] + + (raw - temptable[i-1][0]) * + (temptable[i][1] - temptable[i-1][1]) / + (temptable[i][0] - temptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = temptable[i-1][1]; + + return celsius; + #elif defined HEATER_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #elif defined HEATER_USES_MAX6675 + return raw * 0.25; + #endif +} + +// Derived from RepRap FiveD extruder::getTemperature() +// For bed temperature measurement. +float analog2tempBed(int raw) { + #ifdef BED_USES_THERMISTOR + int celsius = 0; + byte i; + + raw = 1023 - raw; + + for (i=1; i raw) + { + celsius = bedtemptable[i-1][1] + + (raw - bedtemptable[i-1][0]) * + (bedtemptable[i][1] - bedtemptable[i-1][1]) / + (bedtemptable[i][0] - bedtemptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = bedtemptable[i-1][1]; + + return celsius; + + #elif defined BED_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #endif +} + +inline void kill() +{ + #if TEMP_0_PIN > -1 + target_raw=0; + digitalWrite(HEATER_0_PIN,LOW); + #endif + #if TEMP_1_PIN > -1 + target_bed_raw=0; + if(HEATER_1_PIN > -1) digitalWrite(HEATER_1_PIN,LOW); + #endif + disable_x(); + disable_y(); + disable_z(); + disable_e(); + + if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); + +} + + + + + + +//####################################################################################################################### + +inline void manage_inactivity(byte debug) { + if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); + if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { + disable_x(); + disable_y(); + disable_z(); + disable_e(); + } + check_axes_activity(); +} + +// Planner + +/* + Reasoning behind the mathematics in this module (in the key of 'Mathematica'): + + s == speed, a == acceleration, t == time, d == distance + + Basic definitions: + + Speed[s_, a_, t_] := s + (a*t) + Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t] + + Distance to reach a specific speed with a constant acceleration: + + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t] + d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance() + + Speed after a given distance of travel with constant acceleration: + + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t] + m -> Sqrt[2 a d + s^2] + + DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2] + + When to start braking (di) to reach a specified destionation speed (s2) after accelerating + from initial speed s1 without ever stopping at a plateau: + + Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di] + di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance() + + IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a) + */ + + + + +static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions +static volatile unsigned char block_buffer_head; // Index of the next block to be pushed +static volatile unsigned char block_buffer_tail; // Index of the block to process now + +// The current position of the tool in absolute steps +static long position[4]; + +#define ONE_MINUTE_OF_MICROSECONDS 60000000.0 + +// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the +// given acceleration: +inline long estimate_acceleration_distance(long initial_rate, long target_rate, long acceleration) { + return( + (target_rate*target_rate-initial_rate*initial_rate)/ + (2L*acceleration) + ); +} + +// This function gives you the point at which you must start braking (at the rate of -acceleration) if +// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after +// a total travel of distance. This can be used to compute the intersection point between acceleration and +// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) + +inline long intersection_distance(long initial_rate, long final_rate, long acceleration, long distance) { + return( + (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ + (4*acceleration) + ); +} + +// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. + +void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { + if(block->busy == true) return; // If block is busy then bail out. + float entry_factor = entry_speed / block->nominal_speed; + float exit_factor = exit_speed / block->nominal_speed; + long initial_rate = ceil(block->nominal_rate*entry_factor); + long final_rate = ceil(block->nominal_rate*exit_factor); + +#ifdef ADVANCE + long initial_advance = block->advance*entry_factor*entry_factor; + long final_advance = block->advance*exit_factor*exit_factor; +#endif // ADVANCE + + // Limit minimal step rate (Otherwise the timer will overflow.) + if(initial_rate <120) initial_rate=120; + if(final_rate < 120) final_rate=120; + + // Calculate the acceleration steps + long acceleration = block->acceleration_st; + long accelerate_steps = estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration); + long decelerate_steps = estimate_acceleration_distance(final_rate, block->nominal_rate, acceleration); + // Calculate the size of Plateau of Nominal Rate. + long plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; + + // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will + // have to use intersection_distance() to calculate when to abort acceleration and start braking + // in order to reach the final_rate exactly at the end of this block. + if (plateau_steps < 0) { + accelerate_steps = intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count); + plateau_steps = 0; + } + + long decelerate_after = accelerate_steps+plateau_steps; + long acceleration_rate = (long)((float)acceleration * 8.388608); + + CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section + if(block->busy == false) { // Don't update variables if block is busy. + block->accelerate_until = accelerate_steps; + block->decelerate_after = decelerate_after; + block->acceleration_rate = acceleration_rate; + block->initial_rate = initial_rate; + block->final_rate = final_rate; +#ifdef ADVANCE + block->initial_advance = initial_advance; + block->final_advance = final_advance; +#endif //ADVANCE + } + CRITICAL_SECTION_END; +} + +// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the +// acceleration within the allotted distance. +inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { + return( + sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) + ); +} + +// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks. +// This method will calculate the junction jerk as the euclidean distance between the nominal +// velocities of the respective blocks. +inline float junction_jerk(block_t *before, block_t *after) { + return(sqrt( + pow((before->speed_x-after->speed_x), 2)+ + pow((before->speed_y-after->speed_y), 2))); +} + +// Return the safe speed which is max_jerk/2, e.g. the +// speed under which you cannot exceed max_jerk no matter what you do. +float safe_speed(block_t *block) { + float safe_speed; + safe_speed = max_xy_jerk/2; + if(abs(block->speed_z) > max_z_jerk/2) safe_speed = max_z_jerk/2; + if (safe_speed > block->nominal_speed) safe_speed = block->nominal_speed; + return safe_speed; +} + +// The kernel called by planner_recalculate() when scanning the plan from last to first entry. +void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) { + if(!current) { + return; + } + + float entry_speed = current->nominal_speed; + float exit_factor; + float exit_speed; + if (next) { + exit_speed = next->entry_speed; + } + else { + exit_speed = safe_speed(current); + } + + // Calculate the entry_factor for the current block. + if (previous) { + // Reduce speed so that junction_jerk is within the maximum allowed + float jerk = junction_jerk(previous, current); + if((previous->steps_x == 0) && (previous->steps_y == 0)) { + entry_speed = safe_speed(current); + } + else if (jerk > max_xy_jerk) { + entry_speed = (max_xy_jerk/jerk) * entry_speed; + } + if(abs(previous->speed_z - current->speed_z) > max_z_jerk) { + entry_speed = (max_z_jerk/abs(previous->speed_z - current->speed_z)) * entry_speed; + } + // If the required deceleration across the block is too rapid, reduce the entry_factor accordingly. + if (entry_speed > exit_speed) { + float max_entry_speed = max_allowable_speed(-current->acceleration,exit_speed, current->millimeters); + if (max_entry_speed < entry_speed) { + entry_speed = max_entry_speed; + } + } + } + else { + entry_speed = safe_speed(current); + } + // Store result + current->entry_speed = entry_speed; +} + +// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This +// implements the reverse pass. +void planner_reverse_pass() { + char block_index = block_buffer_head; + block_t *block[3] = { + NULL, NULL, NULL }; + while(block_index != block_buffer_tail) { + block[2]= block[1]; + block[1]= block[0]; + block[0] = &block_buffer[block_index]; + planner_reverse_pass_kernel(block[0], block[1], block[2]); + block_index--; + if(block_index < 0) { + block_index = BLOCK_BUFFER_SIZE-1; + } + } +// planner_reverse_pass_kernel(NULL, block[0], block[1]); +} + +// The kernel called by planner_recalculate() when scanning the plan from first to last entry. +void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) { + if(!current) { + return; + } + if(previous) { + // If the previous block is an acceleration block, but it is not long enough to + // complete the full speed change within the block, we need to adjust out entry + // speed accordingly. Remember current->entry_factor equals the exit factor of + // the previous block. + if(previous->entry_speed < current->entry_speed) { + float max_entry_speed = max_allowable_speed(-previous->acceleration, previous->entry_speed, previous->millimeters); + if (max_entry_speed < current->entry_speed) { + current->entry_speed = max_entry_speed; + } + } + } +} + +// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This +// implements the forward pass. +void planner_forward_pass() { + char block_index = block_buffer_tail; + block_t *block[3] = { + NULL, NULL, NULL }; + + while(block_index != block_buffer_head) { + block[0] = block[1]; + block[1] = block[2]; + block[2] = &block_buffer[block_index]; + planner_forward_pass_kernel(block[0],block[1],block[2]); + block_index = (block_index+1) %BLOCK_BUFFER_SIZE; + } + planner_forward_pass_kernel(block[1], block[2], NULL); +} + +// Recalculates the trapezoid speed profiles for all blocks in the plan according to the +// entry_factor for each junction. Must be called by planner_recalculate() after +// updating the blocks. +void planner_recalculate_trapezoids() { + char block_index = block_buffer_tail; + block_t *current; + block_t *next = NULL; + while(block_index != block_buffer_head) { + current = next; + next = &block_buffer[block_index]; + if (current) { + calculate_trapezoid_for_block(current, current->entry_speed, next->entry_speed); + } + block_index = (block_index+1) %BLOCK_BUFFER_SIZE; + } + calculate_trapezoid_for_block(next, next->entry_speed, safe_speed(next)); +} + +// Recalculates the motion plan according to the following algorithm: +// +// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) +// so that: +// a. The junction jerk is within the set limit +// b. No speed reduction within one block requires faster deceleration than the one, true constant +// acceleration. +// 2. Go over every block in chronological order and dial down junction speed reduction values if +// a. The speed increase within one block would require faster accelleration than the one, true +// constant acceleration. +// +// When these stages are complete all blocks have an entry_factor that will allow all speed changes to +// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than +// the set limit. Finally it will: +// +// 3. Recalculate trapezoids for all blocks. + +void planner_recalculate() { + planner_reverse_pass(); + planner_forward_pass(); + planner_recalculate_trapezoids(); +} + +void plan_init() { + block_buffer_head = 0; + block_buffer_tail = 0; + memset(position, 0, sizeof(position)); // clear position +} + + +inline void plan_discard_current_block() { + if (block_buffer_head != block_buffer_tail) { + block_buffer_tail = (block_buffer_tail + 1) %BLOCK_BUFFER_SIZE; + } +} + +inline block_t *plan_get_current_block() { + if (block_buffer_head == block_buffer_tail) { + return(NULL); + } + block_t *block = &block_buffer[block_buffer_tail]; + block->busy = true; + return(block); +} + +void check_axes_activity() { + unsigned char x_active = 0; + unsigned char y_active = 0; + unsigned char z_active = 0; + unsigned char e_active = 0; + block_t *block; + + if(block_buffer_tail != block_buffer_head) { + char block_index = block_buffer_tail; + while(block_index != block_buffer_head) { + block = &block_buffer[block_index]; + if(block->steps_x != 0) x_active++; + if(block->steps_y != 0) y_active++; + if(block->steps_z != 0) z_active++; + if(block->steps_e != 0) e_active++; + block_index = (block_index+1) %BLOCK_BUFFER_SIZE; + } + } + if((DISABLE_X) && (x_active == 0)) disable_x(); + if((DISABLE_Y) && (y_active == 0)) disable_y(); + if((DISABLE_Z) && (z_active == 0)) disable_z(); + if((DISABLE_E) && (e_active == 0)) disable_e(); +} + +// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in +// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration +// calculation the caller must also provide the physical length of the line in millimeters. +void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { + + // The target position of the tool in absolute steps + // Calculate target position in absolute steps + long target[4]; + target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); + target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); + target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); + target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); + + // Calculate the buffer head after we push this byte + int next_buffer_head = (block_buffer_head + 1) %BLOCK_BUFFER_SIZE; + + // If the buffer is full: good! That means we are well ahead of the robot. + // Rest here until there is room in the buffer. + while(block_buffer_tail == next_buffer_head) { + manage_heater(); + manage_inactivity(1); + } + + // Prepare to set up new block + block_t *block = &block_buffer[block_buffer_head]; + + // Mark block as not busy (Not executed by the stepper interrupt) + block->busy = false; + + // Number of steps for each axis + block->steps_x = labs(target[X_AXIS]-position[X_AXIS]); + block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]); + block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); + block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); + block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); + + // Bail if this is a zero-length block + if (block->step_event_count == 0) { + return; + }; + + //enable active axes + if(block->steps_x != 0) enable_x(); + if(block->steps_y != 0) enable_y(); + if(block->steps_z != 0) enable_z(); + if(block->steps_e != 0) enable_e(); + + float delta_x_mm = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; + float delta_y_mm = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; + float delta_z_mm = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; + float delta_e_mm = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS]; + block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); + + unsigned long microseconds; + microseconds = lround((block->millimeters/feed_rate)*1000000); + + // added by lampmaker to slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill + // reduces/removes corner blobs as the machine won't come to a full stop. + int blockcount=block_buffer_head-block_buffer_tail; + //blockcount=8; + while(blockcount<0) blockcount+=BLOCK_BUFFER_SIZE; + if ((blockcount<=2)&&(microseconds<(MIN_SEGMENT_TIME))) microseconds=MIN_SEGMENT_TIME; + else if ((blockcount<=4)&&(microseconds<(MIN_SEGMENT_TIME/2))) microseconds=MIN_SEGMENT_TIME/2; + else if ((blockcount<=8)&&(microseconds<(MIN_SEGMENT_TIME/5))) microseconds=MIN_SEGMENT_TIME/5; + + // Calculate speed in mm/minute for each axis + float multiplier = 60.0*1000000.0/microseconds; + block->speed_z = delta_z_mm * multiplier; + block->speed_x = delta_x_mm * multiplier; + block->speed_y = delta_y_mm * multiplier; + block->speed_e = delta_e_mm * multiplier; + + // Limit speed per axis + float speed_factor = 1; + float tmp_speed_factor; + if(abs(block->speed_x) > max_feedrate[X_AXIS]) { + //// [ErikDeBruijn] IS THIS THE BUG WE'RE LOOING FOR???? + // it used to be just this line: speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + tmp_speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ + tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ + tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_e) > max_feedrate[E_AXIS]){ + tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + multiplier = multiplier * speed_factor; + block->speed_z = delta_z_mm * multiplier; + block->speed_x = delta_x_mm * multiplier; + block->speed_y = delta_y_mm * multiplier; + block->speed_e = delta_e_mm * multiplier; + block->nominal_speed = block->millimeters * multiplier; + block->nominal_rate = ceil(block->step_event_count * multiplier / 60); + + if(block->nominal_rate < 120) block->nominal_rate = 120; + block->entry_speed = safe_speed(block); + + // Compute the acceleration rate for the trapezoid generator. + float travel_per_step = block->millimeters/block->step_event_count; + if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { + block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + } + else { + block->acceleration_st = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + // Limit acceleration per axis + if((block->acceleration_st * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[X_AXIS]; + if((block->acceleration_st * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS]; + if((block->acceleration_st * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[E_AXIS]; + if(((block->acceleration_st / block->step_event_count) * block->steps_z ) > axis_steps_per_sqr_second[Z_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS]; + } + block->acceleration = block->acceleration_st * travel_per_step; + +#ifdef ADVANCE + // Calculate advance rate + if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { + block->advance_rate = 0; + block->advance = 0; + } + else { + long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st); + float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * + (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; + block->advance = advance; + if(acc_dist == 0) { + block->advance_rate = 0; + } + else { + block->advance_rate = advance / (float)acc_dist; + } + } + +#endif // ADVANCE + + // compute a preliminary conservative acceleration trapezoid + float safespeed = safe_speed(block); + calculate_trapezoid_for_block(block, safespeed, safespeed); + + // Compute direction bits for this block + block->direction_bits = 0; + if (target[X_AXIS] < position[X_AXIS]) { + block->direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<> 16 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 24 bit result +#define MultiU16X8toH16(intRes, charIn1, intIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %A1, %A2 \n\t" \ +"add %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r0 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (charIn1), \ +"d" (intIn2) \ +: \ +"r26" \ +) + +// intRes = longIn1 * longIn2 >> 24 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 48bit result +#define MultiU24X24toH16(intRes, longIn1, longIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"mov r27, r1 \n\t" \ +"mul %B1, %C2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %C1, %C2 \n\t" \ +"add %B0, r0 \n\t" \ +"mul %C1, %B2 \n\t" \ +"add %A0, r0 \n\t" \ +"adc %B0, r1 \n\t" \ +"mul %A1, %C2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %B2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %C1, %A2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %A2 \n\t" \ +"add r27, r1 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r27 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (longIn1), \ +"d" (longIn2) \ +: \ +"r26" , "r27" \ +) + +// Some useful constants + +#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1< +// +// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates +// first block->accelerate_until step_events_completed, then keeps going at constant speed until +// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. +// The slope of acceleration is calculated with the leib ramp alghorithm. + +void st_wake_up() { + // TCNT1 = 0; + ENABLE_STEPPER_DRIVER_INTERRUPT(); +} + +inline unsigned short calc_timer(unsigned short step_rate) { + unsigned short timer; + if(step_rate < 32) step_rate = 32; + step_rate -= 32; // Correct for minimal speed + if(step_rate >= (8*256)){ // higher step rate + unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; + unsigned char tmp_step_rate = (step_rate & 0x00ff); + unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); + MultiU16X8toH16(timer, tmp_step_rate, gain); + timer = (unsigned short)pgm_read_word_near(table_address) - timer; + } + else { // lower step rates + unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; + table_address += ((step_rate)>>1) & 0xfffc; + timer = (unsigned short)pgm_read_word_near(table_address); + timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); + } + if(timer < 100) timer = 100; + return timer; +} + +// Initializes the trapezoid generator from the current block. Called whenever a new +// block begins. +inline void trapezoid_generator_reset() { + accelerate_until = current_block->accelerate_until; + decelerate_after = current_block->decelerate_after; + acceleration_rate = current_block->acceleration_rate; + initial_rate = current_block->initial_rate; + final_rate = current_block->final_rate; + nominal_rate = current_block->nominal_rate; + advance = current_block->initial_advance; + final_advance = current_block->final_advance; + deceleration_time = 0; + advance_rate = current_block->advance_rate; + // step_rate to timer interval + acc_step_rate = initial_rate; + acceleration_time = calc_timer(acc_step_rate); + OCR1A = acceleration_time; +} + +// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. +// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. +ISR(TIMER1_COMPA_vect) +{ + if(busy){ /*Serial.println("BUSY")*/; + return; + } // The busy-flag is used to avoid reentering this interrupt + + busy = true; + sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) +#ifdef FANCY_BUTTONS + static int breakdown=0; + if((breakdown++)%100==0) + buttons_check(); +/* [ErikDeBruijn] Perhaps it would be nice to use a piece of code like this (adapted from process_g_code), to create a nice progress bar! + if(sdactive){ + sprintf("SD printing byte %i%",(int) (sdpos/filesize*100)); // perhaps a fraction of a percent is also nice, 0.03%, progress bar even better. + Serial.print(sdpos); + Serial.print("/"); + Serial.println(filesize); + } +*/ +#endif + + // If there is no current block, attempt to pop one from the buffer + if (current_block == NULL) { + // Anything in the buffer? + current_block = plan_get_current_block(); + if (current_block != NULL) { + trapezoid_generator_reset(); + counter_x = -(current_block->step_event_count >> 1); + counter_y = counter_x; + counter_z = counter_x; + counter_e = counter_x; + step_events_completed = 0; + e_steps = 0; + } + else { + DISABLE_STEPPER_DRIVER_INTERRUPT(); + } + } + + if (current_block != NULL) { + // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt + out_bits = current_block->direction_bits; + +#ifdef ADVANCE + // Calculate E early. + counter_e += current_block->steps_e; + if (counter_e > 0) { + counter_e -= current_block->step_event_count; + if ((out_bits & (1<> 16) - old_advance); + CRITICAL_SECTION_END; + old_advance = advance >> 16; +#endif //ADVANCE + + // Set direction en check limit switches +if ((out_bits & (1<step_event_count; + } + } + else { // +direction + WRITE(X_DIR_PIN,!INVERT_X_DIR); + #ifdef DEBUG_STEPS + count_direction[X_AXIS]=1; + #endif + if((READ(X_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_x >0)){ + step_events_completed = current_block->step_event_count; + } + } + + if ((out_bits & (1<step_event_count; + } + } + else { // +direction + WRITE(Y_DIR_PIN,!INVERT_Y_DIR); + #ifdef DEBUG_STEPS + count_direction[Y_AXIS]=1; + #endif + if((READ(Y_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_y >0)){ + step_events_completed = current_block->step_event_count; + } + } + + if ((out_bits & (1<step_event_count; + } + } + else { // +direction + WRITE(Z_DIR_PIN,!INVERT_Z_DIR); + #ifdef DEBUG_STEPS + count_direction[Z_AXIS]=1; + #endif + if((READ(Z_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_z >0)){ + step_events_completed = current_block->step_event_count; + } + } + +#ifndef ADVANCE + if ((out_bits & (1<steps_x; + if (counter_x > 0) { + WRITE(X_STEP_PIN, HIGH); + counter_x -= current_block->step_event_count; + WRITE(X_STEP_PIN, LOW); + #ifdef DEBUG_STEPS + count_position[X_AXIS]+=count_direction[X_AXIS]; + #endif + } + + counter_y += current_block->steps_y; + if (counter_y > 0) { + WRITE(Y_STEP_PIN, HIGH); + counter_y -= current_block->step_event_count; + WRITE(Y_STEP_PIN, LOW); + #ifdef DEBUG_STEPS + count_position[Y_AXIS]+=count_direction[Y_AXIS]; + #endif + } + + counter_z += current_block->steps_z; + if (counter_z > 0) { + WRITE(Z_STEP_PIN, HIGH); + counter_z -= current_block->step_event_count; + WRITE(Z_STEP_PIN, LOW); + #ifdef DEBUG_STEPS + count_position[Z_AXIS]+=count_direction[Z_AXIS]; + #endif + } + +#ifndef ADVANCE + counter_e += current_block->steps_e; + if (counter_e > 0) { + WRITE(E_STEP_PIN, HIGH); + counter_e -= current_block->step_event_count; + WRITE(E_STEP_PIN, LOW); + } +#endif //!ADVANCE + + // Calculare new timer value + unsigned short timer; + unsigned short step_rate; + if (step_events_completed < accelerate_until) { + MultiU24X24toH16(acc_step_rate, acceleration_time, acceleration_rate); + acc_step_rate += initial_rate; + + // upper limit + if(acc_step_rate > nominal_rate) + acc_step_rate = nominal_rate; + + // step_rate to timer interval + timer = calc_timer(acc_step_rate); + advance += advance_rate; + acceleration_time += timer; + OCR1A = timer; + } + else if (step_events_completed >= decelerate_after) { + MultiU24X24toH16(step_rate, deceleration_time, acceleration_rate); + + if(step_rate > acc_step_rate) { // Check step_rate stays positive + step_rate = final_rate; + } + else { + step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. + } + + // lower limit + if(step_rate < final_rate) + step_rate = final_rate; + + // step_rate to timer interval + timer = calc_timer(step_rate); +#ifdef ADVANCE + advance -= advance_rate; + if(advance < final_advance) + advance = final_advance; +#endif //ADVANCE + deceleration_time += timer; + OCR1A = timer; + } + // If current block is finished, reset pointer + step_events_completed += 1; + if (step_events_completed >= current_block->step_event_count) { + current_block = NULL; + plan_discard_current_block(); + } + } + busy=false; +} + +#ifdef ADVANCE + +unsigned char old_OCR0A; +// Timer interrupt for E. e_steps is set in the main routine; +// Timer 0 is shared with millies +ISR(TIMER0_COMPA_vect) +{ + // Critical section needed because Timer 1 interrupt has higher priority. + // The pin set functions are placed on trategic position to comply with the stepper driver timing. + WRITE(E_STEP_PIN, LOW); + // Set E direction (Depends on E direction + advance) + if (e_steps < 0) { + WRITE(E_DIR_PIN,INVERT_E_DIR); + e_steps++; + WRITE(E_STEP_PIN, HIGH); + } + if (e_steps > 0) { + WRITE(E_DIR_PIN,!INVERT_E_DIR); + e_steps--; + WRITE(E_STEP_PIN, HIGH); + } + old_OCR0A += 25; // 10kHz interrupt + OCR0A = old_OCR0A; +} +#endif // ADVANCE + +void st_init() +{ + // waveform generation = 0100 = CTC + TCCR1B &= ~(1<= 16) + { + current_raw = 16383 - raw_temp_value; + temp_meas_ready = true; + temp_count = 0; + raw_temp_value = 0; +#ifdef MAXTEMP + if(current_raw >= maxttemp) { + target_raw = 0; +#ifdef PIDTEMP + OCR2B = 0; +#else + WRITE(HEATER_0_PIN,LOW); +#endif //PIDTEMP + } +#endif //MAXTEMP +#ifdef MINTEMP + if(current_raw <= minttemp) { + target_raw = 0; +#ifdef PIDTEMP + OCR2B = 0; +#else + WRITE(HEATER_0_PIN,LOW); +#endif //PIDTEMP + } +#endif //MAXTEMP +#ifndef PIDTEMP + if(current_raw >= target_raw) + { + WRITE(HEATER_0_PIN,LOW); + } + else + { + WRITE(HEATER_0_PIN,HIGH); + } +#endif //PIDTEMP + } +} + */ From c6e6a78e2370902027220ac8f59734ce5659afa6 Mon Sep 17 00:00:00 2001 From: bradleyf Date: Sat, 17 Sep 2011 19:08:13 -0400 Subject: [PATCH 038/130] Changed defines for SIMPLE or FANCY LCD (removing FANCY_BUTTONS). It was too confusing. Simple LCD is a 16x2 for temp monitoring only. Fancy LCD is for 20x4 multipage LCD console with buttons and encoders and, optionally, SD Card support (through SDSUPPORT define). SIMPLE_LCD is enabled by support in synch with the Ultimaker version of Marlin. Bumped up version to 9.3.3-BK to distinguish between the Ultimaker version and the BKubicek version. --- Marlin/Configuration.h | 8 +++----- Marlin/Marlin.pde | 11 +++++++---- Marlin/buttons.h | 4 ++-- Marlin/buttons.pde | 2 +- Marlin/lcd.h | 11 ++++++++--- Marlin/lcd.pde | 45 ++++++++++++++++++++++++------------------ 6 files changed, 47 insertions(+), 34 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index b11780bdea72..b3b6a8d6d34d 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -43,11 +43,9 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -//#define SDSUPPORT -//#define FANCY_LCD -//#define FANCY_BUTTONS - - +//#define SDSUPPORT // Enable SD Card Support in Hardware Console +//#define FANCY_LCD // Hardware Console with 20x4 multipage LCD +#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) //// ADVANCED SETTINGS - to tweak parameters diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 2af3beddc76f..75a25caa0998 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -45,7 +45,7 @@ #include "speed_lookuptable.h" #include "lcd.h" -char version_string[] = "U0.9.3.2"; +char version_string[] = "U0.9.3.3-BK"; #ifdef SDSUPPORT #include "SdFat.h" @@ -57,13 +57,16 @@ char version_string[] = "U0.9.3.2"; #endif //CRITICAL_SECTION_START -#if defined SDSUPPORT || defined FANCY_LCD || defined FANCY_BUTTONS +#if defined SDSUPPORT || defined FANCY_LCD // The number of linear motions that can be in the plan at any give time. #define BLOCK_BUFFER_SIZE 16 // SD,LCD,Buttons take more memory, block buffer needs to be smaller #else #define BLOCK_BUFFER_SIZE 40 // maximize block buffer #endif +#ifdef SIMPLE_LCD + #define BLOCK_BUFFER_SIZE 32 // A little less buffer for just a simple LCD +#endif // if DEBUG_STEPS is enabled, M114 can be used to compare two methods of determining the X,Y,Z position of the printer. // for debugging purposes only, should be disabled by default @@ -250,7 +253,7 @@ void setup() Serial.print("Marlin "); Serial.println(version_string); Serial.println("start"); -#ifdef FANCY_LCD +#if defined FANCY_LCD || defined SIMPLE_LCD lcd_init(); #endif for(int i = 0; i < BUFSIZE; i++){ @@ -2183,7 +2186,7 @@ ISR(TIMER1_COMPA_vect) busy = true; sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) -#ifdef FANCY_BUTTONS +#ifdef FANCY_LCD static int breakdown=0; if((breakdown++)%100==0) buttons_check(); diff --git a/Marlin/buttons.h b/Marlin/buttons.h index 9e0dee3d2b14..ea4de00caa0a 100644 --- a/Marlin/buttons.h +++ b/Marlin/buttons.h @@ -1,4 +1,4 @@ -#ifdef FANCY_BUTTONS +#ifdef FANCY_LCD #define BUTTONS_HAVEENCODER @@ -59,4 +59,4 @@ void buttons_init(); void buttons_check(); -#endif \ No newline at end of file +#endif diff --git a/Marlin/buttons.pde b/Marlin/buttons.pde index be1e60840caa..5a0dddc612f8 100644 --- a/Marlin/buttons.pde +++ b/Marlin/buttons.pde @@ -1,5 +1,5 @@ #include "buttons.h" -#ifdef FANCY_BUTTONS +#ifdef FANCY_LCD long blocking[8]={ diff --git a/Marlin/lcd.h b/Marlin/lcd.h index d852fd21c7a0..7cddcc93cce7 100644 --- a/Marlin/lcd.h +++ b/Marlin/lcd.h @@ -1,7 +1,7 @@ #ifndef __LCDH #define __LCDH -#ifdef FANCY_LCD +#if defined FANCY_LCD || defined SIMPLE_LCD #define LCD_UPDATE_INTERVAL 400 #include "Configuration.h" @@ -10,8 +10,13 @@ extern LiquidCrystal lcd; //lcd display size - #define LCD_WIDTH 20 - #define LCD_HEIGHT 4 + #ifdef FANCY_LCD + #define LCD_WIDTH 20 + #define LCD_HEIGHT 4 + #else + #define LCD_WIDTH 16 + #define LCD_HEIGHT 2 + #endif //arduino pin witch triggers an piezzo beeper #define BEEPER 18 diff --git a/Marlin/lcd.pde b/Marlin/lcd.pde index 8b52bd6a41cf..bcc4944e3001 100644 --- a/Marlin/lcd.pde +++ b/Marlin/lcd.pde @@ -1,7 +1,7 @@ #include "lcd.h" #include "pins.h" -#ifdef FANCY_LCD +#if defined FANCY_LCD || defined SIMPLE_LCD extern volatile int feedmultiply; #include @@ -9,7 +9,10 @@ LiquidCrystal lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5,LCD_PIN unsigned long previous_millis_lcd=0; + +#ifdef FANCY_LCD #include "buttons.h" +#endif //FANCY_LCD #include "menu_base.h" @@ -79,6 +82,7 @@ char *fillto(int8_t n,char *c) } + #include "menu_base.h" MenuBase menu; @@ -105,6 +109,7 @@ void PageWatch::update() lcd.print(fillto(LCD_WIDTH,messagetext)); messagetext[0]=0; } +#ifdef FANCY_LCD if(encoderpos!=lastencoder) { lcd.setCursor(0,2); @@ -116,6 +121,7 @@ void PageWatch::update() lcd.print(" "); lastencoder=encoderpos; } +#endif FANCY_LCD static int n=0; if(n++%4) return; //slower updates @@ -138,7 +144,9 @@ void PageWatch::update() void PageWatch::activate() { +#ifdef FANCY_LCD encoderpos=feedmultiply; +#endif lcd.setCursor(0,0); lcd.print(fillto(LCD_WIDTH," ")); #if 0 @@ -178,6 +186,7 @@ void PageWatch::activate() update(); } +#ifdef FANCY_LCD class PageMove:public MenuPage @@ -447,13 +456,12 @@ void PageSd::activate() PageSd pagesd; -#endif - - - -PageWatch pagewatch; +#endif // SD_SUPPORT PageMove pagemove; PageHome pagehome; +#endif // FANCY_LCD +PageWatch pagewatch; + void lcd_status(const char* message) @@ -467,7 +475,7 @@ void lcd_status(const char* message) // if(missing>0) // for(int i=0;i Date: Sun, 18 Sep 2011 11:02:25 +0300 Subject: [PATCH 039/130] No lcd should be enabled by default, IMHO, in the current all lcd stuff could cause a tiny bit of layer-pausing. --- Marlin/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index b3b6a8d6d34d..d81c4f9d9434 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -45,7 +45,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the // Comment out (using // at the start of the line) to disable SD support: //#define SDSUPPORT // Enable SD Card Support in Hardware Console //#define FANCY_LCD // Hardware Console with 20x4 multipage LCD -#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) +//#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) //// ADVANCED SETTINGS - to tweak parameters From 58b0fb838e58ef1e86e03b0cf8f33a729458fb25 Mon Sep 17 00:00:00 2001 From: lampmaker Date: Sun, 18 Sep 2011 17:31:12 +0300 Subject: [PATCH 040/130] Modified step counter to follow plan_set_position's input. --- Marlin/Marlin.pde | 5071 +++++++++++++++++++++++---------------------- 1 file changed, 2537 insertions(+), 2534 deletions(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 75a25caa0998..3af3717e6426 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1,2535 +1,2538 @@ -#include "Marlin.h" -// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in -// the source g-code and may never actually be reached if acceleration management is active. - -//#define DEBUG_STEPS - - -#include "speed_lookuptable.h" - -/* - Reprap firmware based on Sprinter and grbl. - Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm - - This program 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. - - This program 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 this program. If not, see . - */ - -/* - This firmware is a mashup between Sprinter and grbl. - (https://github.com/kliment/Sprinter) - (https://github.com/simen/grbl/tree) - - It has preliminary support for Matthew Roberts advance algorithm - http://reprap.org/pipermail/reprap-dev/2011-May/003323.html - - This firmware is optimized for gen6 electronics. - */ - - - -#include "fastio.h" -#include "Configuration.h" -#include "pins.h" -#include "Marlin.h" -#include "speed_lookuptable.h" -#include "lcd.h" - -char version_string[] = "U0.9.3.3-BK"; - -#ifdef SDSUPPORT -#include "SdFat.h" -#endif //SDSUPPORT - -#ifndef CRITICAL_SECTION_START -#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() -#define CRITICAL_SECTION_END SREG = _sreg -#endif //CRITICAL_SECTION_START - - -#if defined SDSUPPORT || defined FANCY_LCD -// The number of linear motions that can be in the plan at any give time. - #define BLOCK_BUFFER_SIZE 16 // SD,LCD,Buttons take more memory, block buffer needs to be smaller -#else - #define BLOCK_BUFFER_SIZE 40 // maximize block buffer -#endif - -#ifdef SIMPLE_LCD - #define BLOCK_BUFFER_SIZE 32 // A little less buffer for just a simple LCD -#endif - -// if DEBUG_STEPS is enabled, M114 can be used to compare two methods of determining the X,Y,Z position of the printer. -// for debugging purposes only, should be disabled by default -#ifdef DEBUG_STEPS -volatile long count_position[NUM_AXIS] = { 0, 0, 0, 0}; -volatile int count_direction[NUM_AXIS] = { 1, 1, 1, 1}; -#endif -// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html -// 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 -// G28 - Home all 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 -// 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 -// M115 - Capabilities string -// 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) -// M301 - Set PID parameters P I and D - -//Stepper Movement Variables - -char axis_codes[NUM_AXIS] = { - 'X', 'Y', 'Z', 'E'}; -float destination[NUM_AXIS] = { - 0.0, 0.0, 0.0, 0.0}; -float current_position[NUM_AXIS] = { - 0.0, 0.0, 0.0, 0.0}; -bool home_all_axis = true; -long feedrate = 1500, next_feedrate, saved_feedrate; -long gcode_N, gcode_LastN; -unsigned long previous_millis_heater, previous_millis_bed_heater; -bool relative_mode = false; //Determines Absolute or Relative Coordinates -bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. -unsigned long axis_steps_per_sqr_second[NUM_AXIS]; - -volatile int feedmultiply=100; //100->1 200->2 -// comm variables -#define MAX_CMD_SIZE 96 -#define BUFSIZE 8 -char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; -bool fromsd[BUFSIZE]; -int bufindr = 0; -int bufindw = 0; -int buflen = 0; -int i = 0; -char serial_char; -int serial_count = 0; -boolean comment_mode = false; -char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc - -// Manage heater variables. - -int target_bed_raw = 0; -int current_bed_raw = 0; - -int target_raw = 0; -int current_raw = 0; -unsigned char temp_meas_ready = false; - -#ifdef PIDTEMP - double temp_iState = 0; - double temp_dState = 0; - double pTerm; - double iTerm; - double dTerm; - //int output; - double pid_error; - double temp_iState_min; - double temp_iState_max; - double pid_setpoint = 0.0; - double pid_input; - double pid_output; - bool pid_reset; -#endif //PIDTEMP -float tt = 0, bt = 0; -#ifdef WATCHPERIOD -int watch_raw = -1000; -unsigned long watchmillis = 0; -#endif //WATCHPERIOD -#ifdef MINTEMP -int minttemp = temp2analog(MINTEMP); -#endif //MINTEMP -#ifdef MAXTEMP -int maxttemp = temp2analog(MAXTEMP); -#endif //MAXTEMP - -//Inactivity shutdown variables -unsigned long previous_millis_cmd = 0; -unsigned long max_inactive_time = 0; -unsigned long stepper_inactive_time = 0; - -unsigned long starttime=0; -unsigned long stoptime=0; -#ifdef SDSUPPORT -Sd2Card card; -SdVolume volume; -SdFile root; -SdFile file; -uint32_t filesize = 0; -uint32_t sdpos = 0; -bool sdmode = false; -bool sdactive = false; -bool savetosd = false; -int16_t n; - -void initsd(){ - sdactive = false; -#if SDSS >- 1 - if(root.isOpen()) - root.close(); - if (!card.init(SPI_FULL_SPEED,SDSS)){ - //if (!card.init(SPI_HALF_SPEED,SDSS)) - Serial.println("SD init fail"); - } - else if (!volume.init(&card)) - Serial.println("volume.init failed"); - else if (!root.openRoot(&volume)) - Serial.println("openRoot failed"); - else - sdactive = true; -#endif //SDSS -} - -inline void write_command(char *buf){ - char* begin = buf; - char* npos = 0; - char* end = buf + strlen(buf) - 1; - - file.writeError = false; - if((npos = strchr(buf, 'N')) != NULL){ - begin = strchr(npos, ' ') + 1; - end = strchr(npos, '*') - 1; - } - end[1] = '\r'; - end[2] = '\n'; - end[3] = '\0'; - //Serial.println(begin); - file.write(begin); - if (file.writeError){ - Serial.println("error writing to file"); - } -} -#endif //SDSUPPORT - -void setup() -{ - - Serial.begin(BAUDRATE); - Serial.print("Marlin "); - Serial.println(version_string); - Serial.println("start"); -#if defined FANCY_LCD || defined SIMPLE_LCD - lcd_init(); -#endif - for(int i = 0; i < BUFSIZE; i++){ - fromsd[i] = false; - } - - - //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 -#if E_DIR_PIN > -1 - SET_OUTPUT(E_DIR_PIN); -#endif - - //Initialize Enable Pins - steppers default to disabled. - -#if (X_ENABLE_PIN > -1) - SET_OUTPUT(X_ENABLE_PIN); - if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); -#endif -#if (Y_ENABLE_PIN > -1) - SET_OUTPUT(Y_ENABLE_PIN); - if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); -#endif -#if (Z_ENABLE_PIN > -1) - SET_OUTPUT(Z_ENABLE_PIN); - if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); -#endif -#if (E_ENABLE_PIN > -1) - SET_OUTPUT(E_ENABLE_PIN); - if(!E_ENABLE_ON) WRITE(E_ENABLE_PIN,HIGH); -#endif - - //endstops and pullups -#ifdef ENDSTOPPULLUPS -#if X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); - WRITE(X_MIN_PIN,HIGH); -#endif -#if X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); - WRITE(X_MAX_PIN,HIGH); -#endif -#if Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); - WRITE(Y_MIN_PIN,HIGH); -#endif -#if Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); - WRITE(Y_MAX_PIN,HIGH); -#endif -#if Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); - WRITE(Z_MIN_PIN,HIGH); -#endif -#if Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); - WRITE(Z_MAX_PIN,HIGH); -#endif -#else //ENDSTOPPULLUPS -#if X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); -#endif -#if X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); -#endif -#if Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); -#endif -#if Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); -#endif -#if Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); -#endif -#if Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); -#endif -#endif //ENDSTOPPULLUPS - -#if (HEATER_0_PIN > -1) - SET_OUTPUT(HEATER_0_PIN); -#endif -#if (HEATER_1_PIN > -1) - SET_OUTPUT(HEATER_1_PIN); -#endif - - //Initialize Step Pins -#if (X_STEP_PIN > -1) - SET_OUTPUT(X_STEP_PIN); -#endif -#if (Y_STEP_PIN > -1) - SET_OUTPUT(Y_STEP_PIN); -#endif -#if (Z_STEP_PIN > -1) - SET_OUTPUT(Z_STEP_PIN); -#endif -#if (E_STEP_PIN > -1) - SET_OUTPUT(E_STEP_PIN); -#endif - for(int i=0; i < NUM_AXIS; i++){ - axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; - } - -#ifdef PIDTEMP - temp_iState_min = 0.0; - temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; -#endif //PIDTEMP - -#ifdef SDSUPPORT - //power to SD reader -#if SDPOWER > -1 - SET_OUTPUT(SDPOWER); - WRITE(SDPOWER,HIGH); -#endif //SDPOWER - initsd(); - -#endif //SDSUPPORT - plan_init(); // Initialize planner; - st_init(); // Initialize stepper; -// tp_init(); // Initialize temperature loop - checkautostart(); -} - -#ifdef SDSUPPORT -void checkautostart() -{ - if(!sdactive) - return; - static int lastnr=0; - char autoname[30]; - sprintf(autoname,"auto%i.g",lastnr); - for(int i=0;i 0) - { - for(int i=0;i 0 && buflen < BUFSIZE) { - serial_char = Serial.read(); - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) - { - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = false; - if(strstr(cmdbuffer[bufindw], "N") != NULL) - { - strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); - gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); - if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { - Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); - Serial.println(gcode_LastN); - //Serial.println(gcode_N); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - if(strstr(cmdbuffer[bufindw], "*") != NULL) - { - byte checksum = 0; - byte count = 0; - while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; - strchr_pointer = strchr(cmdbuffer[bufindw], '*'); - - if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { - Serial.print("Error: checksum mismatch, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - //if no errors, continue parsing - } - else - { - Serial.print("Error: No Checksum with line number, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - gcode_LastN = gcode_N; - //if no errors, continue parsing - } - else // if we don't receive 'N' but still see '*' - { - if((strstr(cmdbuffer[bufindw], "*") != NULL)) - { - Serial.print("Error: No Line Number with checksum, Last Line:"); - Serial.println(gcode_LastN); - serial_count = 0; - return; - } - } - if((strstr(cmdbuffer[bufindw], "G") != NULL)){ - strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); - switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ - case 0: - case 1: -#ifdef SDSUPPORT - if(savetosd) - break; -#endif //SDSUPPORT - Serial.println("ok"); - break; - default: - break; - } - - } - bufindw = (bufindw + 1)%BUFSIZE; - buflen += 1; - - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } - } -#ifdef SDSUPPORT - if(!sdmode || serial_count!=0){ - return; - } - while( filesize > sdpos && buflen < BUFSIZE) { - n = file.read(); - serial_char = (char)n; - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) - { - sdpos = file.curPosition(); - if(sdpos >= filesize){ - sdmode = false; - Serial.println("Done printing file"); - stoptime=millis(); - char time[30]; - unsigned long t=(stoptime-starttime)/1000; - int sec,min; - min=t/60; - sec=t%60; - sprintf(time,"%i min, %i sec",min,sec); - Serial.println(time); - LCD_MESSAGE(time); - checkautostart(); - } - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = true; - buflen += 1; - bufindw = (bufindw + 1)%BUFSIZE; - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } - } -#endif //SDSUPPORT - -} - - -inline float code_value() { - return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); -} -inline long code_value_long() { - return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); -} -inline bool code_seen(char code_string[]) { - return (strstr(cmdbuffer[bufindr], code_string) != NULL); -} //Return True if the string was found - -inline bool code_seen(char code) -{ - strchr_pointer = strchr(cmdbuffer[bufindr], code); - return (strchr_pointer != NULL); //Return True if a character was found -} - -inline void process_commands() -{ - unsigned long codenum; //throw away variable - char *starpos = NULL; - - if(code_seen('G')) - { - switch((int)code_value()) - { - case 0: // G0 -> G1 - case 1: // G1 - get_coordinates(); // For X Y Z E F - prepare_move(); - previous_millis_cmd = millis(); - //ClearToSend(); - return; - //break; - case 4: // G4 dwell - codenum = 0; - if(code_seen('P')) codenum = code_value(); // milliseconds to wait - if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait - codenum += millis(); // keep track of when we started waiting - while(millis() < codenum ){ - manage_heater(); - } - break; - case 28: //G28 Home all Axis one at a time - saved_feedrate = feedrate; - for(int i=0; i < NUM_AXIS; i++) { - destination[i] = current_position[i]; - } - feedrate = 0; - - home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); - - if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) { - if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){ - st_synchronize(); - current_position[X_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; - feedrate = homing_feedrate[X_AXIS]; - prepare_move(); - - st_synchronize(); - current_position[X_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = -5 * X_HOME_DIR; - prepare_move(); - - st_synchronize(); - destination[X_AXIS] = 10 * X_HOME_DIR; - feedrate = homing_feedrate[X_AXIS]/2 ; - prepare_move(); - st_synchronize(); - - current_position[X_AXIS] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = current_position[X_AXIS]; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { - if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){ - current_position[Y_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; - feedrate = homing_feedrate[Y_AXIS]; - prepare_move(); - st_synchronize(); - - current_position[Y_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = -5 * Y_HOME_DIR; - prepare_move(); - st_synchronize(); - - destination[Y_AXIS] = 10 * Y_HOME_DIR; - feedrate = homing_feedrate[Y_AXIS]/2; - prepare_move(); - st_synchronize(); - - current_position[Y_AXIS] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = current_position[Y_AXIS]; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { - if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){ - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; - feedrate = homing_feedrate[Z_AXIS]; - prepare_move(); - st_synchronize(); - - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = -2 * Z_HOME_DIR; - prepare_move(); - st_synchronize(); - - destination[Z_AXIS] = 3 * Z_HOME_DIR; - feedrate = homing_feedrate[Z_AXIS]/2; - prepare_move(); - st_synchronize(); - - current_position[Z_AXIS] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = current_position[Z_AXIS]; - feedrate = 0; - } - } - feedrate = saved_feedrate; - previous_millis_cmd = millis(); - break; - case 90: // G90 - relative_mode = false; - break; - case 91: // G91 - relative_mode = true; - break; - case 92: // G92 - if(!code_seen(axis_codes[E_AXIS])) - st_synchronize(); - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) current_position[i] = code_value(); - } - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - break; - - } - } - - else if(code_seen('M')) - { - - switch( (int)code_value() ) - { -#ifdef SDSUPPORT - - case 20: // M20 - list SD card - Serial.println("Begin file list"); - root.ls(); - Serial.println("End file list"); - break; - case 21: // M21 - init SD card - sdmode = false; - initsd(); - break; - case 22: //M22 - release SD card - sdmode = false; - sdactive = false; - break; - case 23: //M23 - Select file - if(sdactive){ - sdmode = false; - file.close(); - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos!=NULL) - *(starpos-1)='\0'; - if (file.open(&root, strchr_pointer + 4, O_READ)) { - Serial.print("File opened:"); - Serial.print(strchr_pointer + 4); - Serial.print(" Size:"); - Serial.println(file.fileSize()); - sdpos = 0; - filesize = file.fileSize(); - Serial.println("File selected"); - } - else{ - Serial.println("file.open failed"); - } - } - break; - case 24: //M24 - Start SD print - if(sdactive){ - sdmode = true; - starttime=millis(); - } - break; - case 25: //M25 - Pause SD print - if(sdmode){ - sdmode = false; - } - break; - case 26: //M26 - Set SD index - if(sdactive && code_seen('S')){ - sdpos = code_value_long(); - file.seekSet(sdpos); - } - break; - case 27: //M27 - Get SD status - if(sdactive){ - Serial.print("SD printing byte "); - Serial.print(sdpos); - Serial.print("/"); - Serial.println(filesize); - } - else{ - Serial.println("Not SD printing"); - } - break; - case 28: //M28 - Start SD write - if(sdactive){ - char* npos = 0; - file.close(); - sdmode = false; - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos != NULL){ - npos = strchr(cmdbuffer[bufindr], 'N'); - strchr_pointer = strchr(npos,' ') + 1; - *(starpos-1) = '\0'; - } - if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) - { - Serial.print("open failed, File: "); - Serial.print(strchr_pointer + 4); - Serial.print("."); - } - else{ - savetosd = true; - Serial.print("Writing to file: "); - Serial.println(strchr_pointer + 4); - } - } - break; - case 29: //M29 - Stop SD write - //processed in write to file routine above - //savetosd = false; - break; - case 30: - { - stoptime=millis(); - char time[30]; - unsigned long t=(stoptime-starttime)/1000; - int sec,min; - min=t/60; - sec=t%60; - sprintf(time,"%i min, %i sec",min,sec); - Serial.println(time); - LCD_MESSAGE(time); - } - break; -#endif //SDSUPPORT - case 104: // M104 - if (code_seen('S')) target_raw = temp2analog(code_value()); - #ifdef WATCHPERIOD - if(target_raw > current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - }else{ - watchmillis = 0; - } - #endif - break; - case 140: // M140 set bed temp - if (code_seen('S')) target_bed_raw = temp2analogBed(code_value()); - break; - case 105: // M105 - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) - tt = analog2temp(current_raw); - #endif - #if TEMP_1_PIN > -1 - bt = analog2tempBed(current_bed_raw); - #endif - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) - Serial.print("ok T:"); - Serial.print(tt); - Serial.print(", raw:"); - Serial.print(current_raw); - #if TEMP_1_PIN > -1 - Serial.print(" B:"); - Serial.println(bt); - #else - Serial.println(); - #endif - #else - Serial.println("No thermistors - no temp"); - #endif - return; - //break; - case 109: // M109 - Wait for extruder heater to reach target. - LCD_MESSAGE("Heating..."); - if (code_seen('S')) target_raw = temp2analog(code_value()); - #ifdef WATCHPERIOD - if(target_raw>current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - }else{ - watchmillis = 0; - } - #endif - codenum = millis(); - starttime=millis(); - while(current_raw < target_raw) { - if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - Serial.print("T:"); - Serial.println( analog2temp(current_raw) ); - - codenum = millis(); - } - LCD_STATUS; - manage_heater(); - } - break; - case 190: // M190 - Wait bed for heater to reach target. - #if TEMP_1_PIN > -1 - if (code_seen('S')) target_bed_raw = temp2analog(code_value()); - codenum = millis(); - while(current_bed_raw < target_bed_raw) - { - if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - float tt=analog2temp(current_raw); - Serial.print("T:"); - Serial.println( tt ); - Serial.print("ok T:"); - Serial.print( tt ); - Serial.print(" B:"); - Serial.println( analog2temp(current_bed_raw) ); - codenum = millis(); - } - manage_heater(); - } - #endif - break; - case 106: //M106 Fan On - if (code_seen('S')){ - digitalWrite(FAN_PIN,HIGH); - analogWrite(FAN_PIN, constrain(code_value(),0,255) ); - } - else - { - digitalWrite(FAN_PIN,HIGH); - analogWrite(FAN_PIN, 255); - } - break; - case 107: //M107 Fan Off - digitalWrite(FAN_PIN,LOW); - analogWrite(FAN_PIN, 0); - break; - - case 82: - axis_relative_modes[3] = false; - break; - case 83: - axis_relative_modes[3] = true; - break; - case 18: - case 84: - if(code_seen('S')){ - stepper_inactive_time = code_value() * 1000; - } - else{ - st_synchronize(); - disable_x(); - disable_y(); - disable_z(); - disable_e(); - } - break; - case 85: // M85 - code_seen('S'); - max_inactive_time = code_value() * 1000; - break; - case 92: // M92 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); - } - - break; - case 115: // M115 - Serial.println("FIRMWARE_NAME:Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); - break; - case 114: // M114 - Serial.print("X:"); - Serial.print(current_position[X_AXIS]); - Serial.print("Y:"); - Serial.print(current_position[Y_AXIS]); - Serial.print("Z:"); - Serial.print(current_position[Z_AXIS]); - Serial.print("E:"); - Serial.print(current_position[E_AXIS]); - #ifdef DEBUG_STEPS - Serial.print(" Count X:"); - Serial.print(float(count_position[X_AXIS])/axis_steps_per_unit[X_AXIS]); - Serial.print("Y:"); - Serial.print(float(count_position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]); - Serial.print("Z:"); - Serial.println(float(count_position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]); - #endif - Serial.println(""); - break; - case 119: // M119 -#if (X_MIN_PIN > -1) - Serial.print("x_min:"); - Serial.print((READ(X_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (X_MAX_PIN > -1) - Serial.print("x_max:"); - Serial.print((READ(X_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Y_MIN_PIN > -1) - Serial.print("y_min:"); - Serial.print((READ(Y_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Y_MAX_PIN > -1) - Serial.print("y_max:"); - Serial.print((READ(Y_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Z_MIN_PIN > -1) - Serial.print("z_min:"); - Serial.print((READ(Z_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Z_MAX_PIN > -1) - Serial.print("z_max:"); - Serial.print((READ(Z_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif - Serial.println(""); - break; - //TODO: update for all axis, use for loop - case 201: // M201 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; -#if 0 // Not used for Sprinter/grbl gen6 - case 202: // M202 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; -#endif -#ifdef PIDTEMP - case 301: // M301 - if(code_seen('P')) Kp = code_value(); - if(code_seen('I')) Ki = code_value()*PID_dT; - if(code_seen('D')) Kd = code_value()/PID_dT; - Serial.print("Kp ");Serial.println(Kp); - Serial.print("Ki ");Serial.println(Ki/PID_dT); - Serial.print("Kd ");Serial.println(Kd*PID_dT); - temp_iState_min = 0.0; - temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; - break; -#endif //PIDTEMP - } - } - else{ - Serial.println("Unknown command:"); - Serial.println(cmdbuffer[bufindr]); - } - - ClearToSend(); -} - -void FlushSerialRequestResend() -{ - //char cmdbuffer[bufindr][100]="Resend:"; - Serial.flush(); - Serial.print("Resend:"); - Serial.println(gcode_LastN + 1); - ClearToSend(); -} - -void ClearToSend() -{ - previous_millis_cmd = millis(); -#ifdef SDSUPPORT - if(fromsd[bufindr]) - return; -#endif //SDSUPPORT - Serial.println("ok"); -} - -inline void get_coordinates() -{ - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; - else destination[i] = current_position[i]; //Are these else lines really needed? - } - if(code_seen('F')) { - next_feedrate = code_value(); - if(next_feedrate > 0.0) feedrate = next_feedrate; - } -} - -void prepare_move() -{ - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60.0/100.); - for(int i=0; i < NUM_AXIS; i++) { - current_position[i] = destination[i]; - } -} -/* -void manage_heater() -{ - float pid_input; - float pid_output; - if(temp_meas_ready != true) - return; - -CRITICAL_SECTION_START; - temp_meas_ready = false; -CRITICAL_SECTION_END; - -#ifdef PIDTEMP - pid_input = analog2temp(current_raw); - -#ifndef PID_OPENLOOP - pid_error = pid_setpoint - pid_input; - if(pid_error > 10){ - pid_output = PID_MAX; - pid_reset = true; - } - else if(pid_error < -10) { - pid_output = 0; - pid_reset = true; - } - else { - if(pid_reset == true) { - temp_iState = 0.0; - pid_reset = false; - } - pTerm = Kp * pid_error; - temp_iState += pid_error; - temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = Ki * temp_iState; - #define K1 0.8 - #define K2 (1.0-K1) - dTerm = (Kd * (pid_input - temp_dState))*K2 + (K1 * dTerm); - temp_dState = pid_input; - pid_output = constrain(pTerm + iTerm - dTerm, 0, PID_MAX); - } -#endif //PID_OPENLOOP -#ifdef PID_DEBUG - Serial.print(" Input "); - Serial.print(pid_input); - Serial.print(" Output "); - Serial.print(pid_output); - Serial.print(" pTerm "); - Serial.print(pTerm); - Serial.print(" iTerm "); - Serial.print(iTerm); - Serial.print(" dTerm "); - Serial.print(dTerm); - Serial.println(); -#endif //PID_DEBUG - OCR2B = pid_output; -#endif //PIDTEMP -} -*/ - - -/* -int temp2analogu(int celsius, const short table[][2], int numtemps) { - int raw = 0; - byte i; - - for (i=1; i raw) { - celsius = (float)table[i-1][1] + - (float)(raw - table[i-1][0]) * - (float)(table[i][1] - table[i-1][1]) / - (float)(table[i][0] - table[i-1][0]); - - break; - } - } - // Overflow: Set to last value in the table - if (i == numtemps) celsius = table[i-1][1]; - - return celsius; -} - - -inline void kill() -{ - target_raw=0; -#ifdef PIDTEMP - pid_setpoint = 0.0; -#endif //PIDTEMP - OCR2B = 0; - WRITE(HEATER_0_PIN,LOW); - - disable_x(); - disable_y(); - disable_z(); - disable_e(); - -} -*/ - - - -//#################################################################################################################### -//#################################################################################################################### -void manage_heater() -{ -#ifdef USE_WATCHDOG - wd_reset(); -#endif - //there is no FANCY_LCD here, because this routine is called within moves, and delays them. one could loose steps. - - if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) - return; - previous_millis_heater = millis(); - #ifdef HEATER_USES_THERMISTOR - current_raw = analogRead(TEMP_0_PIN); - // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, - // this switches it up so that the reading appears lower than target for the control logic. - current_raw = 1023 - current_raw; - #elif defined HEATER_USES_AD595 - current_raw = analogRead(TEMP_0_PIN); - #elif defined HEATER_USES_MAX6675 - current_raw = read_max6675(); - #endif - #ifdef SMOOTHING - nma = (nma + current_raw) - (nma / SMOOTHFACTOR); - current_raw = nma / SMOOTHFACTOR; - #endif - #ifdef WATCHPERIOD - if(watchmillis && millis() - watchmillis > WATCHPERIOD){ - if(watch_raw + 1 >= current_raw){ - target_raw = 0; - digitalWrite(HEATER_0_PIN,LOW); - digitalWrite(LED_PIN,LOW); - }else{ - watchmillis = 0; - } - } - #endif - #ifdef MINTEMP - if(current_raw <= minttemp) - target_raw = 0; - #endif - #ifdef MAXTEMP - if(current_raw >= maxttemp) { - target_raw = 0; - } - #endif - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) - #ifdef PIDTEMP - error = target_raw - current_raw; - pTerm = (PID_PGAIN * error) / 100; - temp_iState += error; - temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = (PID_IGAIN * temp_iState) / 100; - dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; - temp_dState = current_raw; - analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); - #else - if(current_raw >= target_raw) - { - digitalWrite(HEATER_0_PIN,LOW); - digitalWrite(LED_PIN,LOW); - } - else - { - digitalWrite(HEATER_0_PIN,HIGH); - digitalWrite(LED_PIN,HIGH); - } - #endif - #endif - - if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) - return; - previous_millis_bed_heater = millis(); - - #ifdef BED_USES_THERMISTOR - - current_bed_raw = analogRead(TEMP_1_PIN); - - // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, - // this switches it up so that the reading appears lower than target for the control logic. - current_bed_raw = 1023 - current_bed_raw; - #elif defined BED_USES_AD595 - current_bed_raw = analogRead(TEMP_1_PIN); - - #endif - - - #if TEMP_1_PIN > -1 - if(current_bed_raw >= target_bed_raw) - { - digitalWrite(HEATER_1_PIN,LOW); - } - else - { - digitalWrite(HEATER_1_PIN,HIGH); - } - #endif -} - -// Takes hot end temperature value as input and returns corresponding raw value. -// For a thermistor, it uses the RepRap thermistor temp table. -// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value. -// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware. -float temp2analog(int celsius) { - #ifdef HEATER_USES_THERMISTOR - int raw = 0; - byte i; - - for (i=1; i raw) - { - celsius = temptable[i-1][1] + - (raw - temptable[i-1][0]) * - (temptable[i][1] - temptable[i-1][1]) / - (temptable[i][0] - temptable[i-1][0]); - - break; - } - } - - // Overflow: Set to last value in the table - if (i == NUMTEMPS) celsius = temptable[i-1][1]; - - return celsius; - #elif defined HEATER_USES_AD595 - return raw * ((5.0 * 100.0) / 1024.0); - #elif defined HEATER_USES_MAX6675 - return raw * 0.25; - #endif -} - -// Derived from RepRap FiveD extruder::getTemperature() -// For bed temperature measurement. -float analog2tempBed(int raw) { - #ifdef BED_USES_THERMISTOR - int celsius = 0; - byte i; - - raw = 1023 - raw; - - for (i=1; i raw) - { - celsius = bedtemptable[i-1][1] + - (raw - bedtemptable[i-1][0]) * - (bedtemptable[i][1] - bedtemptable[i-1][1]) / - (bedtemptable[i][0] - bedtemptable[i-1][0]); - - break; - } - } - - // Overflow: Set to last value in the table - if (i == NUMTEMPS) celsius = bedtemptable[i-1][1]; - - return celsius; - - #elif defined BED_USES_AD595 - return raw * ((5.0 * 100.0) / 1024.0); - #endif -} - -inline void kill() -{ - #if TEMP_0_PIN > -1 - target_raw=0; - digitalWrite(HEATER_0_PIN,LOW); - #endif - #if TEMP_1_PIN > -1 - target_bed_raw=0; - if(HEATER_1_PIN > -1) digitalWrite(HEATER_1_PIN,LOW); - #endif - disable_x(); - disable_y(); - disable_z(); - disable_e(); - - if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); - -} - - - - - - -//####################################################################################################################### - -inline void manage_inactivity(byte debug) { - if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); - if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { - disable_x(); - disable_y(); - disable_z(); - disable_e(); - } - check_axes_activity(); -} - -// Planner - -/* - Reasoning behind the mathematics in this module (in the key of 'Mathematica'): - - s == speed, a == acceleration, t == time, d == distance - - Basic definitions: - - Speed[s_, a_, t_] := s + (a*t) - Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t] - - Distance to reach a specific speed with a constant acceleration: - - Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t] - d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance() - - Speed after a given distance of travel with constant acceleration: - - Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t] - m -> Sqrt[2 a d + s^2] - - DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2] - - When to start braking (di) to reach a specified destionation speed (s2) after accelerating - from initial speed s1 without ever stopping at a plateau: - - Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di] - di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance() - - IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a) - */ - - - - -static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions -static volatile unsigned char block_buffer_head; // Index of the next block to be pushed -static volatile unsigned char block_buffer_tail; // Index of the block to process now - -// The current position of the tool in absolute steps -static long position[4]; - -#define ONE_MINUTE_OF_MICROSECONDS 60000000.0 - -// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the -// given acceleration: -inline long estimate_acceleration_distance(long initial_rate, long target_rate, long acceleration) { - return( - (target_rate*target_rate-initial_rate*initial_rate)/ - (2L*acceleration) - ); -} - -// This function gives you the point at which you must start braking (at the rate of -acceleration) if -// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after -// a total travel of distance. This can be used to compute the intersection point between acceleration and -// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) - -inline long intersection_distance(long initial_rate, long final_rate, long acceleration, long distance) { - return( - (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ - (4*acceleration) - ); -} - -// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. - -void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { - if(block->busy == true) return; // If block is busy then bail out. - float entry_factor = entry_speed / block->nominal_speed; - float exit_factor = exit_speed / block->nominal_speed; - long initial_rate = ceil(block->nominal_rate*entry_factor); - long final_rate = ceil(block->nominal_rate*exit_factor); - -#ifdef ADVANCE - long initial_advance = block->advance*entry_factor*entry_factor; - long final_advance = block->advance*exit_factor*exit_factor; -#endif // ADVANCE - - // Limit minimal step rate (Otherwise the timer will overflow.) - if(initial_rate <120) initial_rate=120; - if(final_rate < 120) final_rate=120; - - // Calculate the acceleration steps - long acceleration = block->acceleration_st; - long accelerate_steps = estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration); - long decelerate_steps = estimate_acceleration_distance(final_rate, block->nominal_rate, acceleration); - // Calculate the size of Plateau of Nominal Rate. - long plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; - - // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will - // have to use intersection_distance() to calculate when to abort acceleration and start braking - // in order to reach the final_rate exactly at the end of this block. - if (plateau_steps < 0) { - accelerate_steps = intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count); - plateau_steps = 0; - } - - long decelerate_after = accelerate_steps+plateau_steps; - long acceleration_rate = (long)((float)acceleration * 8.388608); - - CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section - if(block->busy == false) { // Don't update variables if block is busy. - block->accelerate_until = accelerate_steps; - block->decelerate_after = decelerate_after; - block->acceleration_rate = acceleration_rate; - block->initial_rate = initial_rate; - block->final_rate = final_rate; -#ifdef ADVANCE - block->initial_advance = initial_advance; - block->final_advance = final_advance; -#endif //ADVANCE - } - CRITICAL_SECTION_END; -} - -// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the -// acceleration within the allotted distance. -inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { - return( - sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) - ); -} - -// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks. -// This method will calculate the junction jerk as the euclidean distance between the nominal -// velocities of the respective blocks. -inline float junction_jerk(block_t *before, block_t *after) { - return(sqrt( - pow((before->speed_x-after->speed_x), 2)+ - pow((before->speed_y-after->speed_y), 2))); -} - -// Return the safe speed which is max_jerk/2, e.g. the -// speed under which you cannot exceed max_jerk no matter what you do. -float safe_speed(block_t *block) { - float safe_speed; - safe_speed = max_xy_jerk/2; - if(abs(block->speed_z) > max_z_jerk/2) safe_speed = max_z_jerk/2; - if (safe_speed > block->nominal_speed) safe_speed = block->nominal_speed; - return safe_speed; -} - -// The kernel called by planner_recalculate() when scanning the plan from last to first entry. -void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) { - if(!current) { - return; - } - - float entry_speed = current->nominal_speed; - float exit_factor; - float exit_speed; - if (next) { - exit_speed = next->entry_speed; - } - else { - exit_speed = safe_speed(current); - } - - // Calculate the entry_factor for the current block. - if (previous) { - // Reduce speed so that junction_jerk is within the maximum allowed - float jerk = junction_jerk(previous, current); - if((previous->steps_x == 0) && (previous->steps_y == 0)) { - entry_speed = safe_speed(current); - } - else if (jerk > max_xy_jerk) { - entry_speed = (max_xy_jerk/jerk) * entry_speed; - } - if(abs(previous->speed_z - current->speed_z) > max_z_jerk) { - entry_speed = (max_z_jerk/abs(previous->speed_z - current->speed_z)) * entry_speed; - } - // If the required deceleration across the block is too rapid, reduce the entry_factor accordingly. - if (entry_speed > exit_speed) { - float max_entry_speed = max_allowable_speed(-current->acceleration,exit_speed, current->millimeters); - if (max_entry_speed < entry_speed) { - entry_speed = max_entry_speed; - } - } - } - else { - entry_speed = safe_speed(current); - } - // Store result - current->entry_speed = entry_speed; -} - -// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This -// implements the reverse pass. -void planner_reverse_pass() { - char block_index = block_buffer_head; - block_t *block[3] = { - NULL, NULL, NULL }; - while(block_index != block_buffer_tail) { - block[2]= block[1]; - block[1]= block[0]; - block[0] = &block_buffer[block_index]; - planner_reverse_pass_kernel(block[0], block[1], block[2]); - block_index--; - if(block_index < 0) { - block_index = BLOCK_BUFFER_SIZE-1; - } - } -// planner_reverse_pass_kernel(NULL, block[0], block[1]); -} - -// The kernel called by planner_recalculate() when scanning the plan from first to last entry. -void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) { - if(!current) { - return; - } - if(previous) { - // If the previous block is an acceleration block, but it is not long enough to - // complete the full speed change within the block, we need to adjust out entry - // speed accordingly. Remember current->entry_factor equals the exit factor of - // the previous block. - if(previous->entry_speed < current->entry_speed) { - float max_entry_speed = max_allowable_speed(-previous->acceleration, previous->entry_speed, previous->millimeters); - if (max_entry_speed < current->entry_speed) { - current->entry_speed = max_entry_speed; - } - } - } -} - -// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This -// implements the forward pass. -void planner_forward_pass() { - char block_index = block_buffer_tail; - block_t *block[3] = { - NULL, NULL, NULL }; - - while(block_index != block_buffer_head) { - block[0] = block[1]; - block[1] = block[2]; - block[2] = &block_buffer[block_index]; - planner_forward_pass_kernel(block[0],block[1],block[2]); - block_index = (block_index+1) %BLOCK_BUFFER_SIZE; - } - planner_forward_pass_kernel(block[1], block[2], NULL); -} - -// Recalculates the trapezoid speed profiles for all blocks in the plan according to the -// entry_factor for each junction. Must be called by planner_recalculate() after -// updating the blocks. -void planner_recalculate_trapezoids() { - char block_index = block_buffer_tail; - block_t *current; - block_t *next = NULL; - while(block_index != block_buffer_head) { - current = next; - next = &block_buffer[block_index]; - if (current) { - calculate_trapezoid_for_block(current, current->entry_speed, next->entry_speed); - } - block_index = (block_index+1) %BLOCK_BUFFER_SIZE; - } - calculate_trapezoid_for_block(next, next->entry_speed, safe_speed(next)); -} - -// Recalculates the motion plan according to the following algorithm: -// -// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) -// so that: -// a. The junction jerk is within the set limit -// b. No speed reduction within one block requires faster deceleration than the one, true constant -// acceleration. -// 2. Go over every block in chronological order and dial down junction speed reduction values if -// a. The speed increase within one block would require faster accelleration than the one, true -// constant acceleration. -// -// When these stages are complete all blocks have an entry_factor that will allow all speed changes to -// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than -// the set limit. Finally it will: -// -// 3. Recalculate trapezoids for all blocks. - -void planner_recalculate() { - planner_reverse_pass(); - planner_forward_pass(); - planner_recalculate_trapezoids(); -} - -void plan_init() { - block_buffer_head = 0; - block_buffer_tail = 0; - memset(position, 0, sizeof(position)); // clear position -} - - -inline void plan_discard_current_block() { - if (block_buffer_head != block_buffer_tail) { - block_buffer_tail = (block_buffer_tail + 1) %BLOCK_BUFFER_SIZE; - } -} - -inline block_t *plan_get_current_block() { - if (block_buffer_head == block_buffer_tail) { - return(NULL); - } - block_t *block = &block_buffer[block_buffer_tail]; - block->busy = true; - return(block); -} - -void check_axes_activity() { - unsigned char x_active = 0; - unsigned char y_active = 0; - unsigned char z_active = 0; - unsigned char e_active = 0; - block_t *block; - - if(block_buffer_tail != block_buffer_head) { - char block_index = block_buffer_tail; - while(block_index != block_buffer_head) { - block = &block_buffer[block_index]; - if(block->steps_x != 0) x_active++; - if(block->steps_y != 0) y_active++; - if(block->steps_z != 0) z_active++; - if(block->steps_e != 0) e_active++; - block_index = (block_index+1) %BLOCK_BUFFER_SIZE; - } - } - if((DISABLE_X) && (x_active == 0)) disable_x(); - if((DISABLE_Y) && (y_active == 0)) disable_y(); - if((DISABLE_Z) && (z_active == 0)) disable_z(); - if((DISABLE_E) && (e_active == 0)) disable_e(); -} - -// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in -// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration -// calculation the caller must also provide the physical length of the line in millimeters. -void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { - - // The target position of the tool in absolute steps - // Calculate target position in absolute steps - long target[4]; - target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); - target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); - target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); - target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); - - // Calculate the buffer head after we push this byte - int next_buffer_head = (block_buffer_head + 1) %BLOCK_BUFFER_SIZE; - - // If the buffer is full: good! That means we are well ahead of the robot. - // Rest here until there is room in the buffer. - while(block_buffer_tail == next_buffer_head) { - manage_heater(); - manage_inactivity(1); - } - - // Prepare to set up new block - block_t *block = &block_buffer[block_buffer_head]; - - // Mark block as not busy (Not executed by the stepper interrupt) - block->busy = false; - - // Number of steps for each axis - block->steps_x = labs(target[X_AXIS]-position[X_AXIS]); - block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]); - block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); - block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); - block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); - - // Bail if this is a zero-length block - if (block->step_event_count == 0) { - return; - }; - - //enable active axes - if(block->steps_x != 0) enable_x(); - if(block->steps_y != 0) enable_y(); - if(block->steps_z != 0) enable_z(); - if(block->steps_e != 0) enable_e(); - - float delta_x_mm = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; - float delta_y_mm = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; - float delta_z_mm = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; - float delta_e_mm = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS]; - block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); - - unsigned long microseconds; - microseconds = lround((block->millimeters/feed_rate)*1000000); - - // added by lampmaker to slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill - // reduces/removes corner blobs as the machine won't come to a full stop. - int blockcount=block_buffer_head-block_buffer_tail; - //blockcount=8; - while(blockcount<0) blockcount+=BLOCK_BUFFER_SIZE; - if ((blockcount<=2)&&(microseconds<(MIN_SEGMENT_TIME))) microseconds=MIN_SEGMENT_TIME; - else if ((blockcount<=4)&&(microseconds<(MIN_SEGMENT_TIME/2))) microseconds=MIN_SEGMENT_TIME/2; - else if ((blockcount<=8)&&(microseconds<(MIN_SEGMENT_TIME/5))) microseconds=MIN_SEGMENT_TIME/5; - - // Calculate speed in mm/minute for each axis - float multiplier = 60.0*1000000.0/microseconds; - block->speed_z = delta_z_mm * multiplier; - block->speed_x = delta_x_mm * multiplier; - block->speed_y = delta_y_mm * multiplier; - block->speed_e = delta_e_mm * multiplier; - - // Limit speed per axis - float speed_factor = 1; - float tmp_speed_factor; - if(abs(block->speed_x) > max_feedrate[X_AXIS]) { - //// [ErikDeBruijn] IS THIS THE BUG WE'RE LOOING FOR???? - // it used to be just this line: speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); - tmp_speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ - tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ - tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_e) > max_feedrate[E_AXIS]){ - tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - multiplier = multiplier * speed_factor; - block->speed_z = delta_z_mm * multiplier; - block->speed_x = delta_x_mm * multiplier; - block->speed_y = delta_y_mm * multiplier; - block->speed_e = delta_e_mm * multiplier; - block->nominal_speed = block->millimeters * multiplier; - block->nominal_rate = ceil(block->step_event_count * multiplier / 60); - - if(block->nominal_rate < 120) block->nominal_rate = 120; - block->entry_speed = safe_speed(block); - - // Compute the acceleration rate for the trapezoid generator. - float travel_per_step = block->millimeters/block->step_event_count; - if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { - block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 - } - else { - block->acceleration_st = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 - // Limit acceleration per axis - if((block->acceleration_st * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) - block->acceleration_st = axis_steps_per_sqr_second[X_AXIS]; - if((block->acceleration_st * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) - block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS]; - if((block->acceleration_st * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) - block->acceleration_st = axis_steps_per_sqr_second[E_AXIS]; - if(((block->acceleration_st / block->step_event_count) * block->steps_z ) > axis_steps_per_sqr_second[Z_AXIS]) - block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS]; - } - block->acceleration = block->acceleration_st * travel_per_step; - -#ifdef ADVANCE - // Calculate advance rate - if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { - block->advance_rate = 0; - block->advance = 0; - } - else { - long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st); - float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * - (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; - block->advance = advance; - if(acc_dist == 0) { - block->advance_rate = 0; - } - else { - block->advance_rate = advance / (float)acc_dist; - } - } - -#endif // ADVANCE - - // compute a preliminary conservative acceleration trapezoid - float safespeed = safe_speed(block); - calculate_trapezoid_for_block(block, safespeed, safespeed); - - // Compute direction bits for this block - block->direction_bits = 0; - if (target[X_AXIS] < position[X_AXIS]) { - block->direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<> 16 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 24 bit result -#define MultiU16X8toH16(intRes, charIn1, intIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %A1, %A2 \n\t" \ -"add %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r0 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (charIn1), \ -"d" (intIn2) \ -: \ -"r26" \ -) - -// intRes = longIn1 * longIn2 >> 24 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 48bit result -#define MultiU24X24toH16(intRes, longIn1, longIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"mov r27, r1 \n\t" \ -"mul %B1, %C2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %C1, %C2 \n\t" \ -"add %B0, r0 \n\t" \ -"mul %C1, %B2 \n\t" \ -"add %A0, r0 \n\t" \ -"adc %B0, r1 \n\t" \ -"mul %A1, %C2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %B2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %C1, %A2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %A2 \n\t" \ -"add r27, r1 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r27 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (longIn1), \ -"d" (longIn2) \ -: \ -"r26" , "r27" \ -) - -// Some useful constants - -#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1< -// -// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates -// first block->accelerate_until step_events_completed, then keeps going at constant speed until -// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. -// The slope of acceleration is calculated with the leib ramp alghorithm. - -void st_wake_up() { - // TCNT1 = 0; - ENABLE_STEPPER_DRIVER_INTERRUPT(); -} - -inline unsigned short calc_timer(unsigned short step_rate) { - unsigned short timer; - if(step_rate < 32) step_rate = 32; - step_rate -= 32; // Correct for minimal speed - if(step_rate >= (8*256)){ // higher step rate - unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; - unsigned char tmp_step_rate = (step_rate & 0x00ff); - unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); - MultiU16X8toH16(timer, tmp_step_rate, gain); - timer = (unsigned short)pgm_read_word_near(table_address) - timer; - } - else { // lower step rates - unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; - table_address += ((step_rate)>>1) & 0xfffc; - timer = (unsigned short)pgm_read_word_near(table_address); - timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); - } - if(timer < 100) timer = 100; - return timer; -} - -// Initializes the trapezoid generator from the current block. Called whenever a new -// block begins. -inline void trapezoid_generator_reset() { - accelerate_until = current_block->accelerate_until; - decelerate_after = current_block->decelerate_after; - acceleration_rate = current_block->acceleration_rate; - initial_rate = current_block->initial_rate; - final_rate = current_block->final_rate; - nominal_rate = current_block->nominal_rate; - advance = current_block->initial_advance; - final_advance = current_block->final_advance; - deceleration_time = 0; - advance_rate = current_block->advance_rate; - // step_rate to timer interval - acc_step_rate = initial_rate; - acceleration_time = calc_timer(acc_step_rate); - OCR1A = acceleration_time; -} - -// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. -// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. -ISR(TIMER1_COMPA_vect) -{ - if(busy){ /*Serial.println("BUSY")*/; - return; - } // The busy-flag is used to avoid reentering this interrupt - - busy = true; - sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) -#ifdef FANCY_LCD - static int breakdown=0; - if((breakdown++)%100==0) - buttons_check(); -/* [ErikDeBruijn] Perhaps it would be nice to use a piece of code like this (adapted from process_g_code), to create a nice progress bar! - if(sdactive){ - sprintf("SD printing byte %i%",(int) (sdpos/filesize*100)); // perhaps a fraction of a percent is also nice, 0.03%, progress bar even better. - Serial.print(sdpos); - Serial.print("/"); - Serial.println(filesize); - } -*/ -#endif - - // If there is no current block, attempt to pop one from the buffer - if (current_block == NULL) { - // Anything in the buffer? - current_block = plan_get_current_block(); - if (current_block != NULL) { - trapezoid_generator_reset(); - counter_x = -(current_block->step_event_count >> 1); - counter_y = counter_x; - counter_z = counter_x; - counter_e = counter_x; - step_events_completed = 0; - e_steps = 0; - } - else { - DISABLE_STEPPER_DRIVER_INTERRUPT(); - } - } - - if (current_block != NULL) { - // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt - out_bits = current_block->direction_bits; - -#ifdef ADVANCE - // Calculate E early. - counter_e += current_block->steps_e; - if (counter_e > 0) { - counter_e -= current_block->step_event_count; - if ((out_bits & (1<> 16) - old_advance); - CRITICAL_SECTION_END; - old_advance = advance >> 16; -#endif //ADVANCE - - // Set direction en check limit switches -if ((out_bits & (1<step_event_count; - } - } - else { // +direction - WRITE(X_DIR_PIN,!INVERT_X_DIR); - #ifdef DEBUG_STEPS - count_direction[X_AXIS]=1; - #endif - if((READ(X_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_x >0)){ - step_events_completed = current_block->step_event_count; - } - } - - if ((out_bits & (1<step_event_count; - } - } - else { // +direction - WRITE(Y_DIR_PIN,!INVERT_Y_DIR); - #ifdef DEBUG_STEPS - count_direction[Y_AXIS]=1; - #endif - if((READ(Y_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_y >0)){ - step_events_completed = current_block->step_event_count; - } - } - - if ((out_bits & (1<step_event_count; - } - } - else { // +direction - WRITE(Z_DIR_PIN,!INVERT_Z_DIR); - #ifdef DEBUG_STEPS - count_direction[Z_AXIS]=1; - #endif - if((READ(Z_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_z >0)){ - step_events_completed = current_block->step_event_count; - } - } - -#ifndef ADVANCE - if ((out_bits & (1<steps_x; - if (counter_x > 0) { - WRITE(X_STEP_PIN, HIGH); - counter_x -= current_block->step_event_count; - WRITE(X_STEP_PIN, LOW); - #ifdef DEBUG_STEPS - count_position[X_AXIS]+=count_direction[X_AXIS]; - #endif - } - - counter_y += current_block->steps_y; - if (counter_y > 0) { - WRITE(Y_STEP_PIN, HIGH); - counter_y -= current_block->step_event_count; - WRITE(Y_STEP_PIN, LOW); - #ifdef DEBUG_STEPS - count_position[Y_AXIS]+=count_direction[Y_AXIS]; - #endif - } - - counter_z += current_block->steps_z; - if (counter_z > 0) { - WRITE(Z_STEP_PIN, HIGH); - counter_z -= current_block->step_event_count; - WRITE(Z_STEP_PIN, LOW); - #ifdef DEBUG_STEPS - count_position[Z_AXIS]+=count_direction[Z_AXIS]; - #endif - } - -#ifndef ADVANCE - counter_e += current_block->steps_e; - if (counter_e > 0) { - WRITE(E_STEP_PIN, HIGH); - counter_e -= current_block->step_event_count; - WRITE(E_STEP_PIN, LOW); - } -#endif //!ADVANCE - - // Calculare new timer value - unsigned short timer; - unsigned short step_rate; - if (step_events_completed < accelerate_until) { - MultiU24X24toH16(acc_step_rate, acceleration_time, acceleration_rate); - acc_step_rate += initial_rate; - - // upper limit - if(acc_step_rate > nominal_rate) - acc_step_rate = nominal_rate; - - // step_rate to timer interval - timer = calc_timer(acc_step_rate); - advance += advance_rate; - acceleration_time += timer; - OCR1A = timer; - } - else if (step_events_completed >= decelerate_after) { - MultiU24X24toH16(step_rate, deceleration_time, acceleration_rate); - - if(step_rate > acc_step_rate) { // Check step_rate stays positive - step_rate = final_rate; - } - else { - step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. - } - - // lower limit - if(step_rate < final_rate) - step_rate = final_rate; - - // step_rate to timer interval - timer = calc_timer(step_rate); -#ifdef ADVANCE - advance -= advance_rate; - if(advance < final_advance) - advance = final_advance; -#endif //ADVANCE - deceleration_time += timer; - OCR1A = timer; - } - // If current block is finished, reset pointer - step_events_completed += 1; - if (step_events_completed >= current_block->step_event_count) { - current_block = NULL; - plan_discard_current_block(); - } - } - busy=false; -} - -#ifdef ADVANCE - -unsigned char old_OCR0A; -// Timer interrupt for E. e_steps is set in the main routine; -// Timer 0 is shared with millies -ISR(TIMER0_COMPA_vect) -{ - // Critical section needed because Timer 1 interrupt has higher priority. - // The pin set functions are placed on trategic position to comply with the stepper driver timing. - WRITE(E_STEP_PIN, LOW); - // Set E direction (Depends on E direction + advance) - if (e_steps < 0) { - WRITE(E_DIR_PIN,INVERT_E_DIR); - e_steps++; - WRITE(E_STEP_PIN, HIGH); - } - if (e_steps > 0) { - WRITE(E_DIR_PIN,!INVERT_E_DIR); - e_steps--; - WRITE(E_STEP_PIN, HIGH); - } - old_OCR0A += 25; // 10kHz interrupt - OCR0A = old_OCR0A; -} -#endif // ADVANCE - -void st_init() -{ - // waveform generation = 0100 = CTC - TCCR1B &= ~(1<= 16) - { - current_raw = 16383 - raw_temp_value; - temp_meas_ready = true; - temp_count = 0; - raw_temp_value = 0; -#ifdef MAXTEMP - if(current_raw >= maxttemp) { - target_raw = 0; -#ifdef PIDTEMP - OCR2B = 0; -#else - WRITE(HEATER_0_PIN,LOW); -#endif //PIDTEMP - } -#endif //MAXTEMP -#ifdef MINTEMP - if(current_raw <= minttemp) { - target_raw = 0; -#ifdef PIDTEMP - OCR2B = 0; -#else - WRITE(HEATER_0_PIN,LOW); -#endif //PIDTEMP - } -#endif //MAXTEMP -#ifndef PIDTEMP - if(current_raw >= target_raw) - { - WRITE(HEATER_0_PIN,LOW); - } - else - { - WRITE(HEATER_0_PIN,HIGH); - } -#endif //PIDTEMP - } -} - +#include "Marlin.h" +// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in +// the source g-code and may never actually be reached if acceleration management is active. + +//#define DEBUG_STEPS + + +#include "speed_lookuptable.h" + +/* + Reprap firmware based on Sprinter and grbl. + Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + + This program 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. + + This program 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 this program. If not, see . + */ + +/* + This firmware is a mashup between Sprinter and grbl. + (https://github.com/kliment/Sprinter) + (https://github.com/simen/grbl/tree) + + It has preliminary support for Matthew Roberts advance algorithm + http://reprap.org/pipermail/reprap-dev/2011-May/003323.html + + This firmware is optimized for gen6 electronics. + */ + + + +#include "fastio.h" +#include "Configuration.h" +#include "pins.h" +#include "Marlin.h" +#include "speed_lookuptable.h" +#include "lcd.h" + +char version_string[] = "U0.9.3.3-BK"; + +#ifdef SDSUPPORT +#include "SdFat.h" +#endif //SDSUPPORT + +#ifndef CRITICAL_SECTION_START +#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() +#define CRITICAL_SECTION_END SREG = _sreg +#endif //CRITICAL_SECTION_START + + +#if defined SDSUPPORT || defined FANCY_LCD +// The number of linear motions that can be in the plan at any give time. + #define BLOCK_BUFFER_SIZE 16 // SD,LCD,Buttons take more memory, block buffer needs to be smaller +#else + #define BLOCK_BUFFER_SIZE 40 // maximize block buffer +#endif + +#ifdef SIMPLE_LCD + #define BLOCK_BUFFER_SIZE 32 // A little less buffer for just a simple LCD +#endif + +// if DEBUG_STEPS is enabled, M114 can be used to compare two methods of determining the X,Y,Z position of the printer. +// for debugging purposes only, should be disabled by default +#ifdef DEBUG_STEPS +volatile long count_position[NUM_AXIS] = { 0, 0, 0, 0}; +volatile int count_direction[NUM_AXIS] = { 1, 1, 1, 1}; +#endif +// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html +// 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 +// G28 - Home all 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 +// 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 +// M115 - Capabilities string +// 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) +// M301 - Set PID parameters P I and D + +//Stepper Movement Variables + +char axis_codes[NUM_AXIS] = { + 'X', 'Y', 'Z', 'E'}; +float destination[NUM_AXIS] = { + 0.0, 0.0, 0.0, 0.0}; +float current_position[NUM_AXIS] = { + 0.0, 0.0, 0.0, 0.0}; +bool home_all_axis = true; +long feedrate = 1500, next_feedrate, saved_feedrate; +long gcode_N, gcode_LastN; +unsigned long previous_millis_heater, previous_millis_bed_heater; +bool relative_mode = false; //Determines Absolute or Relative Coordinates +bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. +unsigned long axis_steps_per_sqr_second[NUM_AXIS]; + +volatile int feedmultiply=100; //100->1 200->2 +// comm variables +#define MAX_CMD_SIZE 96 +#define BUFSIZE 8 +char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; +bool fromsd[BUFSIZE]; +int bufindr = 0; +int bufindw = 0; +int buflen = 0; +int i = 0; +char serial_char; +int serial_count = 0; +boolean comment_mode = false; +char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc + +// Manage heater variables. + +int target_bed_raw = 0; +int current_bed_raw = 0; + +int target_raw = 0; +int current_raw = 0; +unsigned char temp_meas_ready = false; + +#ifdef PIDTEMP + double temp_iState = 0; + double temp_dState = 0; + double pTerm; + double iTerm; + double dTerm; + //int output; + double pid_error; + double temp_iState_min; + double temp_iState_max; + double pid_setpoint = 0.0; + double pid_input; + double pid_output; + bool pid_reset; +#endif //PIDTEMP +float tt = 0, bt = 0; +#ifdef WATCHPERIOD +int watch_raw = -1000; +unsigned long watchmillis = 0; +#endif //WATCHPERIOD +#ifdef MINTEMP +int minttemp = temp2analog(MINTEMP); +#endif //MINTEMP +#ifdef MAXTEMP +int maxttemp = temp2analog(MAXTEMP); +#endif //MAXTEMP + +//Inactivity shutdown variables +unsigned long previous_millis_cmd = 0; +unsigned long max_inactive_time = 0; +unsigned long stepper_inactive_time = 0; + +unsigned long starttime=0; +unsigned long stoptime=0; +#ifdef SDSUPPORT +Sd2Card card; +SdVolume volume; +SdFile root; +SdFile file; +uint32_t filesize = 0; +uint32_t sdpos = 0; +bool sdmode = false; +bool sdactive = false; +bool savetosd = false; +int16_t n; + +void initsd(){ + sdactive = false; +#if SDSS >- 1 + if(root.isOpen()) + root.close(); + if (!card.init(SPI_FULL_SPEED,SDSS)){ + //if (!card.init(SPI_HALF_SPEED,SDSS)) + Serial.println("SD init fail"); + } + else if (!volume.init(&card)) + Serial.println("volume.init failed"); + else if (!root.openRoot(&volume)) + Serial.println("openRoot failed"); + else + sdactive = true; +#endif //SDSS +} + +inline void write_command(char *buf){ + char* begin = buf; + char* npos = 0; + char* end = buf + strlen(buf) - 1; + + file.writeError = false; + if((npos = strchr(buf, 'N')) != NULL){ + begin = strchr(npos, ' ') + 1; + end = strchr(npos, '*') - 1; + } + end[1] = '\r'; + end[2] = '\n'; + end[3] = '\0'; + //Serial.println(begin); + file.write(begin); + if (file.writeError){ + Serial.println("error writing to file"); + } +} +#endif //SDSUPPORT + +void setup() +{ + + Serial.begin(BAUDRATE); + Serial.print("Marlin "); + Serial.println(version_string); + Serial.println("start"); +#if defined FANCY_LCD || defined SIMPLE_LCD + lcd_init(); +#endif + for(int i = 0; i < BUFSIZE; i++){ + fromsd[i] = false; + } + + + //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 +#if E_DIR_PIN > -1 + SET_OUTPUT(E_DIR_PIN); +#endif + + //Initialize Enable Pins - steppers default to disabled. + +#if (X_ENABLE_PIN > -1) + SET_OUTPUT(X_ENABLE_PIN); + if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); +#endif +#if (Y_ENABLE_PIN > -1) + SET_OUTPUT(Y_ENABLE_PIN); + if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); +#endif +#if (Z_ENABLE_PIN > -1) + SET_OUTPUT(Z_ENABLE_PIN); + if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); +#endif +#if (E_ENABLE_PIN > -1) + SET_OUTPUT(E_ENABLE_PIN); + if(!E_ENABLE_ON) WRITE(E_ENABLE_PIN,HIGH); +#endif + + //endstops and pullups +#ifdef ENDSTOPPULLUPS +#if X_MIN_PIN > -1 + SET_INPUT(X_MIN_PIN); + WRITE(X_MIN_PIN,HIGH); +#endif +#if X_MAX_PIN > -1 + SET_INPUT(X_MAX_PIN); + WRITE(X_MAX_PIN,HIGH); +#endif +#if Y_MIN_PIN > -1 + SET_INPUT(Y_MIN_PIN); + WRITE(Y_MIN_PIN,HIGH); +#endif +#if Y_MAX_PIN > -1 + SET_INPUT(Y_MAX_PIN); + WRITE(Y_MAX_PIN,HIGH); +#endif +#if Z_MIN_PIN > -1 + SET_INPUT(Z_MIN_PIN); + WRITE(Z_MIN_PIN,HIGH); +#endif +#if Z_MAX_PIN > -1 + SET_INPUT(Z_MAX_PIN); + WRITE(Z_MAX_PIN,HIGH); +#endif +#else //ENDSTOPPULLUPS +#if X_MIN_PIN > -1 + SET_INPUT(X_MIN_PIN); +#endif +#if X_MAX_PIN > -1 + SET_INPUT(X_MAX_PIN); +#endif +#if Y_MIN_PIN > -1 + SET_INPUT(Y_MIN_PIN); +#endif +#if Y_MAX_PIN > -1 + SET_INPUT(Y_MAX_PIN); +#endif +#if Z_MIN_PIN > -1 + SET_INPUT(Z_MIN_PIN); +#endif +#if Z_MAX_PIN > -1 + SET_INPUT(Z_MAX_PIN); +#endif +#endif //ENDSTOPPULLUPS + +#if (HEATER_0_PIN > -1) + SET_OUTPUT(HEATER_0_PIN); +#endif +#if (HEATER_1_PIN > -1) + SET_OUTPUT(HEATER_1_PIN); +#endif + + //Initialize Step Pins +#if (X_STEP_PIN > -1) + SET_OUTPUT(X_STEP_PIN); +#endif +#if (Y_STEP_PIN > -1) + SET_OUTPUT(Y_STEP_PIN); +#endif +#if (Z_STEP_PIN > -1) + SET_OUTPUT(Z_STEP_PIN); +#endif +#if (E_STEP_PIN > -1) + SET_OUTPUT(E_STEP_PIN); +#endif + for(int i=0; i < NUM_AXIS; i++){ + axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; + } + +#ifdef PIDTEMP + temp_iState_min = 0.0; + temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; +#endif //PIDTEMP + +#ifdef SDSUPPORT + //power to SD reader +#if SDPOWER > -1 + SET_OUTPUT(SDPOWER); + WRITE(SDPOWER,HIGH); +#endif //SDPOWER + initsd(); + +#endif //SDSUPPORT + plan_init(); // Initialize planner; + st_init(); // Initialize stepper; +// tp_init(); // Initialize temperature loop + checkautostart(); +} + +#ifdef SDSUPPORT +void checkautostart() +{ + if(!sdactive) + return; + static int lastnr=0; + char autoname[30]; + sprintf(autoname,"auto%i.g",lastnr); + for(int i=0;i 0) + { + for(int i=0;i 0 && buflen < BUFSIZE) { + serial_char = Serial.read(); + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) + { + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = false; + if(strstr(cmdbuffer[bufindw], "N") != NULL) + { + strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); + gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); + if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { + Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); + Serial.println(gcode_LastN); + //Serial.println(gcode_N); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + if(strstr(cmdbuffer[bufindw], "*") != NULL) + { + byte checksum = 0; + byte count = 0; + while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; + strchr_pointer = strchr(cmdbuffer[bufindw], '*'); + + if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { + Serial.print("Error: checksum mismatch, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + //if no errors, continue parsing + } + else + { + Serial.print("Error: No Checksum with line number, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + gcode_LastN = gcode_N; + //if no errors, continue parsing + } + else // if we don't receive 'N' but still see '*' + { + if((strstr(cmdbuffer[bufindw], "*") != NULL)) + { + Serial.print("Error: No Line Number with checksum, Last Line:"); + Serial.println(gcode_LastN); + serial_count = 0; + return; + } + } + if((strstr(cmdbuffer[bufindw], "G") != NULL)){ + strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); + switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ + case 0: + case 1: +#ifdef SDSUPPORT + if(savetosd) + break; +#endif //SDSUPPORT + Serial.println("ok"); + break; + default: + break; + } + + } + bufindw = (bufindw + 1)%BUFSIZE; + buflen += 1; + + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } + } +#ifdef SDSUPPORT + if(!sdmode || serial_count!=0){ + return; + } + while( filesize > sdpos && buflen < BUFSIZE) { + n = file.read(); + serial_char = (char)n; + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) + { + sdpos = file.curPosition(); + if(sdpos >= filesize){ + sdmode = false; + Serial.println("Done printing file"); + stoptime=millis(); + char time[30]; + unsigned long t=(stoptime-starttime)/1000; + int sec,min; + min=t/60; + sec=t%60; + sprintf(time,"%i min, %i sec",min,sec); + Serial.println(time); + LCD_MESSAGE(time); + checkautostart(); + } + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = true; + buflen += 1; + bufindw = (bufindw + 1)%BUFSIZE; + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } + } +#endif //SDSUPPORT + +} + + +inline float code_value() { + return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); +} +inline long code_value_long() { + return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); +} +inline bool code_seen(char code_string[]) { + return (strstr(cmdbuffer[bufindr], code_string) != NULL); +} //Return True if the string was found + +inline bool code_seen(char code) +{ + strchr_pointer = strchr(cmdbuffer[bufindr], code); + return (strchr_pointer != NULL); //Return True if a character was found +} + +inline void process_commands() +{ + unsigned long codenum; //throw away variable + char *starpos = NULL; + + if(code_seen('G')) + { + switch((int)code_value()) + { + case 0: // G0 -> G1 + case 1: // G1 + get_coordinates(); // For X Y Z E F + prepare_move(); + previous_millis_cmd = millis(); + //ClearToSend(); + return; + //break; + case 4: // G4 dwell + codenum = 0; + if(code_seen('P')) codenum = code_value(); // milliseconds to wait + if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait + codenum += millis(); // keep track of when we started waiting + while(millis() < codenum ){ + manage_heater(); + } + break; + case 28: //G28 Home all Axis one at a time + saved_feedrate = feedrate; + for(int i=0; i < NUM_AXIS; i++) { + destination[i] = current_position[i]; + } + feedrate = 0; + + home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); + + if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) { + if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){ + st_synchronize(); + current_position[X_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; + feedrate = homing_feedrate[X_AXIS]; + prepare_move(); + + st_synchronize(); + current_position[X_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = -5 * X_HOME_DIR; + prepare_move(); + + st_synchronize(); + destination[X_AXIS] = 10 * X_HOME_DIR; + feedrate = homing_feedrate[X_AXIS]/2 ; + prepare_move(); + st_synchronize(); + + current_position[X_AXIS] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = current_position[X_AXIS]; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { + if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){ + current_position[Y_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; + feedrate = homing_feedrate[Y_AXIS]; + prepare_move(); + st_synchronize(); + + current_position[Y_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = -5 * Y_HOME_DIR; + prepare_move(); + st_synchronize(); + + destination[Y_AXIS] = 10 * Y_HOME_DIR; + feedrate = homing_feedrate[Y_AXIS]/2; + prepare_move(); + st_synchronize(); + + current_position[Y_AXIS] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = current_position[Y_AXIS]; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { + if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){ + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; + feedrate = homing_feedrate[Z_AXIS]; + prepare_move(); + st_synchronize(); + + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = -2 * Z_HOME_DIR; + prepare_move(); + st_synchronize(); + + destination[Z_AXIS] = 3 * Z_HOME_DIR; + feedrate = homing_feedrate[Z_AXIS]/2; + prepare_move(); + st_synchronize(); + + current_position[Z_AXIS] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = current_position[Z_AXIS]; + feedrate = 0; + } + } + feedrate = saved_feedrate; + previous_millis_cmd = millis(); + break; + case 90: // G90 + relative_mode = false; + break; + case 91: // G91 + relative_mode = true; + break; + case 92: // G92 + if(!code_seen(axis_codes[E_AXIS])) + st_synchronize(); + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) current_position[i] = code_value(); + } + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + break; + + } + } + + else if(code_seen('M')) + { + + switch( (int)code_value() ) + { +#ifdef SDSUPPORT + + case 20: // M20 - list SD card + Serial.println("Begin file list"); + root.ls(); + Serial.println("End file list"); + break; + case 21: // M21 - init SD card + sdmode = false; + initsd(); + break; + case 22: //M22 - release SD card + sdmode = false; + sdactive = false; + break; + case 23: //M23 - Select file + if(sdactive){ + sdmode = false; + file.close(); + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos!=NULL) + *(starpos-1)='\0'; + if (file.open(&root, strchr_pointer + 4, O_READ)) { + Serial.print("File opened:"); + Serial.print(strchr_pointer + 4); + Serial.print(" Size:"); + Serial.println(file.fileSize()); + sdpos = 0; + filesize = file.fileSize(); + Serial.println("File selected"); + } + else{ + Serial.println("file.open failed"); + } + } + break; + case 24: //M24 - Start SD print + if(sdactive){ + sdmode = true; + starttime=millis(); + } + break; + case 25: //M25 - Pause SD print + if(sdmode){ + sdmode = false; + } + break; + case 26: //M26 - Set SD index + if(sdactive && code_seen('S')){ + sdpos = code_value_long(); + file.seekSet(sdpos); + } + break; + case 27: //M27 - Get SD status + if(sdactive){ + Serial.print("SD printing byte "); + Serial.print(sdpos); + Serial.print("/"); + Serial.println(filesize); + } + else{ + Serial.println("Not SD printing"); + } + break; + case 28: //M28 - Start SD write + if(sdactive){ + char* npos = 0; + file.close(); + sdmode = false; + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos != NULL){ + npos = strchr(cmdbuffer[bufindr], 'N'); + strchr_pointer = strchr(npos,' ') + 1; + *(starpos-1) = '\0'; + } + if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) + { + Serial.print("open failed, File: "); + Serial.print(strchr_pointer + 4); + Serial.print("."); + } + else{ + savetosd = true; + Serial.print("Writing to file: "); + Serial.println(strchr_pointer + 4); + } + } + break; + case 29: //M29 - Stop SD write + //processed in write to file routine above + //savetosd = false; + break; + case 30: + { + stoptime=millis(); + char time[30]; + unsigned long t=(stoptime-starttime)/1000; + int sec,min; + min=t/60; + sec=t%60; + sprintf(time,"%i min, %i sec",min,sec); + Serial.println(time); + LCD_MESSAGE(time); + } + break; +#endif //SDSUPPORT + case 104: // M104 + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw > current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + break; + case 140: // M140 set bed temp + if (code_seen('S')) target_bed_raw = temp2analogBed(code_value()); + break; + case 105: // M105 + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) + tt = analog2temp(current_raw); + #endif + #if TEMP_1_PIN > -1 + bt = analog2tempBed(current_bed_raw); + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) + Serial.print("ok T:"); + Serial.print(tt); + Serial.print(", raw:"); + Serial.print(current_raw); + #if TEMP_1_PIN > -1 + Serial.print(" B:"); + Serial.println(bt); + #else + Serial.println(); + #endif + #else + Serial.println("No thermistors - no temp"); + #endif + return; + //break; + case 109: // M109 - Wait for extruder heater to reach target. + LCD_MESSAGE("Heating..."); + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw>current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + codenum = millis(); + starttime=millis(); + while(current_raw < target_raw) { + if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + Serial.print("T:"); + Serial.println( analog2temp(current_raw) ); + + codenum = millis(); + } + LCD_STATUS; + manage_heater(); + } + break; + case 190: // M190 - Wait bed for heater to reach target. + #if TEMP_1_PIN > -1 + if (code_seen('S')) target_bed_raw = temp2analog(code_value()); + codenum = millis(); + while(current_bed_raw < target_bed_raw) + { + if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + float tt=analog2temp(current_raw); + Serial.print("T:"); + Serial.println( tt ); + Serial.print("ok T:"); + Serial.print( tt ); + Serial.print(" B:"); + Serial.println( analog2temp(current_bed_raw) ); + codenum = millis(); + } + manage_heater(); + } + #endif + break; + case 106: //M106 Fan On + if (code_seen('S')){ + digitalWrite(FAN_PIN,HIGH); + analogWrite(FAN_PIN, constrain(code_value(),0,255) ); + } + else + { + digitalWrite(FAN_PIN,HIGH); + analogWrite(FAN_PIN, 255); + } + break; + case 107: //M107 Fan Off + digitalWrite(FAN_PIN,LOW); + analogWrite(FAN_PIN, 0); + break; + + case 82: + axis_relative_modes[3] = false; + break; + case 83: + axis_relative_modes[3] = true; + break; + case 18: + case 84: + if(code_seen('S')){ + stepper_inactive_time = code_value() * 1000; + } + else{ + st_synchronize(); + disable_x(); + disable_y(); + disable_z(); + disable_e(); + } + break; + case 85: // M85 + code_seen('S'); + max_inactive_time = code_value() * 1000; + break; + case 92: // M92 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); + } + + break; + case 115: // M115 + Serial.println("FIRMWARE_NAME:Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); + break; + case 114: // M114 + Serial.print("X:"); + Serial.print(current_position[X_AXIS]); + Serial.print("Y:"); + Serial.print(current_position[Y_AXIS]); + Serial.print("Z:"); + Serial.print(current_position[Z_AXIS]); + Serial.print("E:"); + Serial.print(current_position[E_AXIS]); + #ifdef DEBUG_STEPS + Serial.print(" Count X:"); + Serial.print(float(count_position[X_AXIS])/axis_steps_per_unit[X_AXIS]); + Serial.print("Y:"); + Serial.print(float(count_position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]); + Serial.print("Z:"); + Serial.println(float(count_position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]); + #endif + Serial.println(""); + break; + case 119: // M119 +#if (X_MIN_PIN > -1) + Serial.print("x_min:"); + Serial.print((READ(X_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (X_MAX_PIN > -1) + Serial.print("x_max:"); + Serial.print((READ(X_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Y_MIN_PIN > -1) + Serial.print("y_min:"); + Serial.print((READ(Y_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Y_MAX_PIN > -1) + Serial.print("y_max:"); + Serial.print((READ(Y_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Z_MIN_PIN > -1) + Serial.print("z_min:"); + Serial.print((READ(Z_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Z_MAX_PIN > -1) + Serial.print("z_max:"); + Serial.print((READ(Z_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif + Serial.println(""); + break; + //TODO: update for all axis, use for loop + case 201: // M201 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; +#if 0 // Not used for Sprinter/grbl gen6 + case 202: // M202 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; +#endif +#ifdef PIDTEMP + case 301: // M301 + if(code_seen('P')) Kp = code_value(); + if(code_seen('I')) Ki = code_value()*PID_dT; + if(code_seen('D')) Kd = code_value()/PID_dT; + Serial.print("Kp ");Serial.println(Kp); + Serial.print("Ki ");Serial.println(Ki/PID_dT); + Serial.print("Kd ");Serial.println(Kd*PID_dT); + temp_iState_min = 0.0; + temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; + break; +#endif //PIDTEMP + } + } + else{ + Serial.println("Unknown command:"); + Serial.println(cmdbuffer[bufindr]); + } + + ClearToSend(); +} + +void FlushSerialRequestResend() +{ + //char cmdbuffer[bufindr][100]="Resend:"; + Serial.flush(); + Serial.print("Resend:"); + Serial.println(gcode_LastN + 1); + ClearToSend(); +} + +void ClearToSend() +{ + previous_millis_cmd = millis(); +#ifdef SDSUPPORT + if(fromsd[bufindr]) + return; +#endif //SDSUPPORT + Serial.println("ok"); +} + +inline void get_coordinates() +{ + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; + else destination[i] = current_position[i]; //Are these else lines really needed? + } + if(code_seen('F')) { + next_feedrate = code_value(); + if(next_feedrate > 0.0) feedrate = next_feedrate; + } +} + +void prepare_move() +{ + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60.0/100.); + for(int i=0; i < NUM_AXIS; i++) { + current_position[i] = destination[i]; + } +} +/* +void manage_heater() +{ + float pid_input; + float pid_output; + if(temp_meas_ready != true) + return; + +CRITICAL_SECTION_START; + temp_meas_ready = false; +CRITICAL_SECTION_END; + +#ifdef PIDTEMP + pid_input = analog2temp(current_raw); + +#ifndef PID_OPENLOOP + pid_error = pid_setpoint - pid_input; + if(pid_error > 10){ + pid_output = PID_MAX; + pid_reset = true; + } + else if(pid_error < -10) { + pid_output = 0; + pid_reset = true; + } + else { + if(pid_reset == true) { + temp_iState = 0.0; + pid_reset = false; + } + pTerm = Kp * pid_error; + temp_iState += pid_error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = Ki * temp_iState; + #define K1 0.8 + #define K2 (1.0-K1) + dTerm = (Kd * (pid_input - temp_dState))*K2 + (K1 * dTerm); + temp_dState = pid_input; + pid_output = constrain(pTerm + iTerm - dTerm, 0, PID_MAX); + } +#endif //PID_OPENLOOP +#ifdef PID_DEBUG + Serial.print(" Input "); + Serial.print(pid_input); + Serial.print(" Output "); + Serial.print(pid_output); + Serial.print(" pTerm "); + Serial.print(pTerm); + Serial.print(" iTerm "); + Serial.print(iTerm); + Serial.print(" dTerm "); + Serial.print(dTerm); + Serial.println(); +#endif //PID_DEBUG + OCR2B = pid_output; +#endif //PIDTEMP +} +*/ + + +/* +int temp2analogu(int celsius, const short table[][2], int numtemps) { + int raw = 0; + byte i; + + for (i=1; i raw) { + celsius = (float)table[i-1][1] + + (float)(raw - table[i-1][0]) * + (float)(table[i][1] - table[i-1][1]) / + (float)(table[i][0] - table[i-1][0]); + + break; + } + } + // Overflow: Set to last value in the table + if (i == numtemps) celsius = table[i-1][1]; + + return celsius; +} + + +inline void kill() +{ + target_raw=0; +#ifdef PIDTEMP + pid_setpoint = 0.0; +#endif //PIDTEMP + OCR2B = 0; + WRITE(HEATER_0_PIN,LOW); + + disable_x(); + disable_y(); + disable_z(); + disable_e(); + +} +*/ + + + +//#################################################################################################################### +//#################################################################################################################### +void manage_heater() +{ +#ifdef USE_WATCHDOG + wd_reset(); +#endif + //there is no FANCY_LCD here, because this routine is called within moves, and delays them. one could loose steps. + + if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) + return; + previous_millis_heater = millis(); + #ifdef HEATER_USES_THERMISTOR + current_raw = analogRead(TEMP_0_PIN); + // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_raw = 1023 - current_raw; + #elif defined HEATER_USES_AD595 + current_raw = analogRead(TEMP_0_PIN); + #elif defined HEATER_USES_MAX6675 + current_raw = read_max6675(); + #endif + #ifdef SMOOTHING + nma = (nma + current_raw) - (nma / SMOOTHFACTOR); + current_raw = nma / SMOOTHFACTOR; + #endif + #ifdef WATCHPERIOD + if(watchmillis && millis() - watchmillis > WATCHPERIOD){ + if(watch_raw + 1 >= current_raw){ + target_raw = 0; + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + }else{ + watchmillis = 0; + } + } + #endif + #ifdef MINTEMP + if(current_raw <= minttemp) + target_raw = 0; + #endif + #ifdef MAXTEMP + if(current_raw >= maxttemp) { + target_raw = 0; + } + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) + #ifdef PIDTEMP + error = target_raw - current_raw; + pTerm = (PID_PGAIN * error) / 100; + temp_iState += error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = (PID_IGAIN * temp_iState) / 100; + dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; + temp_dState = current_raw; + analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); + #else + if(current_raw >= target_raw) + { + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + } + else + { + digitalWrite(HEATER_0_PIN,HIGH); + digitalWrite(LED_PIN,HIGH); + } + #endif + #endif + + if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) + return; + previous_millis_bed_heater = millis(); + + #ifdef BED_USES_THERMISTOR + + current_bed_raw = analogRead(TEMP_1_PIN); + + // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_bed_raw = 1023 - current_bed_raw; + #elif defined BED_USES_AD595 + current_bed_raw = analogRead(TEMP_1_PIN); + + #endif + + + #if TEMP_1_PIN > -1 + if(current_bed_raw >= target_bed_raw) + { + digitalWrite(HEATER_1_PIN,LOW); + } + else + { + digitalWrite(HEATER_1_PIN,HIGH); + } + #endif +} + +// Takes hot end temperature value as input and returns corresponding raw value. +// For a thermistor, it uses the RepRap thermistor temp table. +// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value. +// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware. +float temp2analog(int celsius) { + #ifdef HEATER_USES_THERMISTOR + int raw = 0; + byte i; + + for (i=1; i raw) + { + celsius = temptable[i-1][1] + + (raw - temptable[i-1][0]) * + (temptable[i][1] - temptable[i-1][1]) / + (temptable[i][0] - temptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = temptable[i-1][1]; + + return celsius; + #elif defined HEATER_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #elif defined HEATER_USES_MAX6675 + return raw * 0.25; + #endif +} + +// Derived from RepRap FiveD extruder::getTemperature() +// For bed temperature measurement. +float analog2tempBed(int raw) { + #ifdef BED_USES_THERMISTOR + int celsius = 0; + byte i; + + raw = 1023 - raw; + + for (i=1; i raw) + { + celsius = bedtemptable[i-1][1] + + (raw - bedtemptable[i-1][0]) * + (bedtemptable[i][1] - bedtemptable[i-1][1]) / + (bedtemptable[i][0] - bedtemptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = bedtemptable[i-1][1]; + + return celsius; + + #elif defined BED_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #endif +} + +inline void kill() +{ + #if TEMP_0_PIN > -1 + target_raw=0; + digitalWrite(HEATER_0_PIN,LOW); + #endif + #if TEMP_1_PIN > -1 + target_bed_raw=0; + if(HEATER_1_PIN > -1) digitalWrite(HEATER_1_PIN,LOW); + #endif + disable_x(); + disable_y(); + disable_z(); + disable_e(); + + if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); + +} + + + + + + +//####################################################################################################################### + +inline void manage_inactivity(byte debug) { + if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); + if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { + disable_x(); + disable_y(); + disable_z(); + disable_e(); + } + check_axes_activity(); +} + +// Planner + +/* + Reasoning behind the mathematics in this module (in the key of 'Mathematica'): + + s == speed, a == acceleration, t == time, d == distance + + Basic definitions: + + Speed[s_, a_, t_] := s + (a*t) + Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t] + + Distance to reach a specific speed with a constant acceleration: + + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t] + d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance() + + Speed after a given distance of travel with constant acceleration: + + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t] + m -> Sqrt[2 a d + s^2] + + DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2] + + When to start braking (di) to reach a specified destionation speed (s2) after accelerating + from initial speed s1 without ever stopping at a plateau: + + Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di] + di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance() + + IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a) + */ + + + + +static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions +static volatile unsigned char block_buffer_head; // Index of the next block to be pushed +static volatile unsigned char block_buffer_tail; // Index of the block to process now + +// The current position of the tool in absolute steps +static long position[4]; + +#define ONE_MINUTE_OF_MICROSECONDS 60000000.0 + +// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the +// given acceleration: +inline long estimate_acceleration_distance(long initial_rate, long target_rate, long acceleration) { + return( + (target_rate*target_rate-initial_rate*initial_rate)/ + (2L*acceleration) + ); +} + +// This function gives you the point at which you must start braking (at the rate of -acceleration) if +// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after +// a total travel of distance. This can be used to compute the intersection point between acceleration and +// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) + +inline long intersection_distance(long initial_rate, long final_rate, long acceleration, long distance) { + return( + (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ + (4*acceleration) + ); +} + +// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. + +void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { + if(block->busy == true) return; // If block is busy then bail out. + float entry_factor = entry_speed / block->nominal_speed; + float exit_factor = exit_speed / block->nominal_speed; + long initial_rate = ceil(block->nominal_rate*entry_factor); + long final_rate = ceil(block->nominal_rate*exit_factor); + +#ifdef ADVANCE + long initial_advance = block->advance*entry_factor*entry_factor; + long final_advance = block->advance*exit_factor*exit_factor; +#endif // ADVANCE + + // Limit minimal step rate (Otherwise the timer will overflow.) + if(initial_rate <120) initial_rate=120; + if(final_rate < 120) final_rate=120; + + // Calculate the acceleration steps + long acceleration = block->acceleration_st; + long accelerate_steps = estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration); + long decelerate_steps = estimate_acceleration_distance(final_rate, block->nominal_rate, acceleration); + // Calculate the size of Plateau of Nominal Rate. + long plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; + + // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will + // have to use intersection_distance() to calculate when to abort acceleration and start braking + // in order to reach the final_rate exactly at the end of this block. + if (plateau_steps < 0) { + accelerate_steps = intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count); + plateau_steps = 0; + } + + long decelerate_after = accelerate_steps+plateau_steps; + long acceleration_rate = (long)((float)acceleration * 8.388608); + + CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section + if(block->busy == false) { // Don't update variables if block is busy. + block->accelerate_until = accelerate_steps; + block->decelerate_after = decelerate_after; + block->acceleration_rate = acceleration_rate; + block->initial_rate = initial_rate; + block->final_rate = final_rate; +#ifdef ADVANCE + block->initial_advance = initial_advance; + block->final_advance = final_advance; +#endif //ADVANCE + } + CRITICAL_SECTION_END; +} + +// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the +// acceleration within the allotted distance. +inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { + return( + sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) + ); +} + +// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks. +// This method will calculate the junction jerk as the euclidean distance between the nominal +// velocities of the respective blocks. +inline float junction_jerk(block_t *before, block_t *after) { + return(sqrt( + pow((before->speed_x-after->speed_x), 2)+ + pow((before->speed_y-after->speed_y), 2))); +} + +// Return the safe speed which is max_jerk/2, e.g. the +// speed under which you cannot exceed max_jerk no matter what you do. +float safe_speed(block_t *block) { + float safe_speed; + safe_speed = max_xy_jerk/2; + if(abs(block->speed_z) > max_z_jerk/2) safe_speed = max_z_jerk/2; + if (safe_speed > block->nominal_speed) safe_speed = block->nominal_speed; + return safe_speed; +} + +// The kernel called by planner_recalculate() when scanning the plan from last to first entry. +void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) { + if(!current) { + return; + } + + float entry_speed = current->nominal_speed; + float exit_factor; + float exit_speed; + if (next) { + exit_speed = next->entry_speed; + } + else { + exit_speed = safe_speed(current); + } + + // Calculate the entry_factor for the current block. + if (previous) { + // Reduce speed so that junction_jerk is within the maximum allowed + float jerk = junction_jerk(previous, current); + if((previous->steps_x == 0) && (previous->steps_y == 0)) { + entry_speed = safe_speed(current); + } + else if (jerk > max_xy_jerk) { + entry_speed = (max_xy_jerk/jerk) * entry_speed; + } + if(abs(previous->speed_z - current->speed_z) > max_z_jerk) { + entry_speed = (max_z_jerk/abs(previous->speed_z - current->speed_z)) * entry_speed; + } + // If the required deceleration across the block is too rapid, reduce the entry_factor accordingly. + if (entry_speed > exit_speed) { + float max_entry_speed = max_allowable_speed(-current->acceleration,exit_speed, current->millimeters); + if (max_entry_speed < entry_speed) { + entry_speed = max_entry_speed; + } + } + } + else { + entry_speed = safe_speed(current); + } + // Store result + current->entry_speed = entry_speed; +} + +// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This +// implements the reverse pass. +void planner_reverse_pass() { + char block_index = block_buffer_head; + block_t *block[3] = { + NULL, NULL, NULL }; + while(block_index != block_buffer_tail) { + block[2]= block[1]; + block[1]= block[0]; + block[0] = &block_buffer[block_index]; + planner_reverse_pass_kernel(block[0], block[1], block[2]); + block_index--; + if(block_index < 0) { + block_index = BLOCK_BUFFER_SIZE-1; + } + } +// planner_reverse_pass_kernel(NULL, block[0], block[1]); +} + +// The kernel called by planner_recalculate() when scanning the plan from first to last entry. +void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) { + if(!current) { + return; + } + if(previous) { + // If the previous block is an acceleration block, but it is not long enough to + // complete the full speed change within the block, we need to adjust out entry + // speed accordingly. Remember current->entry_factor equals the exit factor of + // the previous block. + if(previous->entry_speed < current->entry_speed) { + float max_entry_speed = max_allowable_speed(-previous->acceleration, previous->entry_speed, previous->millimeters); + if (max_entry_speed < current->entry_speed) { + current->entry_speed = max_entry_speed; + } + } + } +} + +// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This +// implements the forward pass. +void planner_forward_pass() { + char block_index = block_buffer_tail; + block_t *block[3] = { + NULL, NULL, NULL }; + + while(block_index != block_buffer_head) { + block[0] = block[1]; + block[1] = block[2]; + block[2] = &block_buffer[block_index]; + planner_forward_pass_kernel(block[0],block[1],block[2]); + block_index = (block_index+1) %BLOCK_BUFFER_SIZE; + } + planner_forward_pass_kernel(block[1], block[2], NULL); +} + +// Recalculates the trapezoid speed profiles for all blocks in the plan according to the +// entry_factor for each junction. Must be called by planner_recalculate() after +// updating the blocks. +void planner_recalculate_trapezoids() { + char block_index = block_buffer_tail; + block_t *current; + block_t *next = NULL; + while(block_index != block_buffer_head) { + current = next; + next = &block_buffer[block_index]; + if (current) { + calculate_trapezoid_for_block(current, current->entry_speed, next->entry_speed); + } + block_index = (block_index+1) %BLOCK_BUFFER_SIZE; + } + calculate_trapezoid_for_block(next, next->entry_speed, safe_speed(next)); +} + +// Recalculates the motion plan according to the following algorithm: +// +// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) +// so that: +// a. The junction jerk is within the set limit +// b. No speed reduction within one block requires faster deceleration than the one, true constant +// acceleration. +// 2. Go over every block in chronological order and dial down junction speed reduction values if +// a. The speed increase within one block would require faster accelleration than the one, true +// constant acceleration. +// +// When these stages are complete all blocks have an entry_factor that will allow all speed changes to +// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than +// the set limit. Finally it will: +// +// 3. Recalculate trapezoids for all blocks. + +void planner_recalculate() { + planner_reverse_pass(); + planner_forward_pass(); + planner_recalculate_trapezoids(); +} + +void plan_init() { + block_buffer_head = 0; + block_buffer_tail = 0; + memset(position, 0, sizeof(position)); // clear position +} + + +inline void plan_discard_current_block() { + if (block_buffer_head != block_buffer_tail) { + block_buffer_tail = (block_buffer_tail + 1) %BLOCK_BUFFER_SIZE; + } +} + +inline block_t *plan_get_current_block() { + if (block_buffer_head == block_buffer_tail) { + return(NULL); + } + block_t *block = &block_buffer[block_buffer_tail]; + block->busy = true; + return(block); +} + +void check_axes_activity() { + unsigned char x_active = 0; + unsigned char y_active = 0; + unsigned char z_active = 0; + unsigned char e_active = 0; + block_t *block; + + if(block_buffer_tail != block_buffer_head) { + char block_index = block_buffer_tail; + while(block_index != block_buffer_head) { + block = &block_buffer[block_index]; + if(block->steps_x != 0) x_active++; + if(block->steps_y != 0) y_active++; + if(block->steps_z != 0) z_active++; + if(block->steps_e != 0) e_active++; + block_index = (block_index+1) %BLOCK_BUFFER_SIZE; + } + } + if((DISABLE_X) && (x_active == 0)) disable_x(); + if((DISABLE_Y) && (y_active == 0)) disable_y(); + if((DISABLE_Z) && (z_active == 0)) disable_z(); + if((DISABLE_E) && (e_active == 0)) disable_e(); +} + +// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in +// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration +// calculation the caller must also provide the physical length of the line in millimeters. +void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { + + // The target position of the tool in absolute steps + // Calculate target position in absolute steps + long target[4]; + target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); + target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); + target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); + target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); + + // Calculate the buffer head after we push this byte + int next_buffer_head = (block_buffer_head + 1) %BLOCK_BUFFER_SIZE; + + // If the buffer is full: good! That means we are well ahead of the robot. + // Rest here until there is room in the buffer. + while(block_buffer_tail == next_buffer_head) { + manage_heater(); + manage_inactivity(1); + } + + // Prepare to set up new block + block_t *block = &block_buffer[block_buffer_head]; + + // Mark block as not busy (Not executed by the stepper interrupt) + block->busy = false; + + // Number of steps for each axis + block->steps_x = labs(target[X_AXIS]-position[X_AXIS]); + block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]); + block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); + block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); + block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); + + // Bail if this is a zero-length block + if (block->step_event_count == 0) { + return; + }; + + //enable active axes + if(block->steps_x != 0) enable_x(); + if(block->steps_y != 0) enable_y(); + if(block->steps_z != 0) enable_z(); + if(block->steps_e != 0) enable_e(); + + float delta_x_mm = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; + float delta_y_mm = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; + float delta_z_mm = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; + float delta_e_mm = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS]; + block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); + + unsigned long microseconds; + microseconds = lround((block->millimeters/feed_rate)*1000000); + + // added by lampmaker to slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill + // reduces/removes corner blobs as the machine won't come to a full stop. + int blockcount=block_buffer_head-block_buffer_tail; + //blockcount=8; + while(blockcount<0) blockcount+=BLOCK_BUFFER_SIZE; + if ((blockcount<=2)&&(microseconds<(MIN_SEGMENT_TIME))) microseconds=MIN_SEGMENT_TIME; + else if ((blockcount<=4)&&(microseconds<(MIN_SEGMENT_TIME/2))) microseconds=MIN_SEGMENT_TIME/2; + else if ((blockcount<=8)&&(microseconds<(MIN_SEGMENT_TIME/5))) microseconds=MIN_SEGMENT_TIME/5; + + // Calculate speed in mm/minute for each axis + float multiplier = 60.0*1000000.0/microseconds; + block->speed_z = delta_z_mm * multiplier; + block->speed_x = delta_x_mm * multiplier; + block->speed_y = delta_y_mm * multiplier; + block->speed_e = delta_e_mm * multiplier; + + // Limit speed per axis + float speed_factor = 1; + float tmp_speed_factor; + if(abs(block->speed_x) > max_feedrate[X_AXIS]) { + //// [ErikDeBruijn] IS THIS THE BUG WE'RE LOOING FOR???? + // it used to be just this line: speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + tmp_speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ + tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ + tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_e) > max_feedrate[E_AXIS]){ + tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + multiplier = multiplier * speed_factor; + block->speed_z = delta_z_mm * multiplier; + block->speed_x = delta_x_mm * multiplier; + block->speed_y = delta_y_mm * multiplier; + block->speed_e = delta_e_mm * multiplier; + block->nominal_speed = block->millimeters * multiplier; + block->nominal_rate = ceil(block->step_event_count * multiplier / 60); + + if(block->nominal_rate < 120) block->nominal_rate = 120; + block->entry_speed = safe_speed(block); + + // Compute the acceleration rate for the trapezoid generator. + float travel_per_step = block->millimeters/block->step_event_count; + if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { + block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + } + else { + block->acceleration_st = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + // Limit acceleration per axis + if((block->acceleration_st * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[X_AXIS]; + if((block->acceleration_st * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS]; + if((block->acceleration_st * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[E_AXIS]; + if(((block->acceleration_st / block->step_event_count) * block->steps_z ) > axis_steps_per_sqr_second[Z_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS]; + } + block->acceleration = block->acceleration_st * travel_per_step; + +#ifdef ADVANCE + // Calculate advance rate + if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { + block->advance_rate = 0; + block->advance = 0; + } + else { + long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st); + float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * + (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; + block->advance = advance; + if(acc_dist == 0) { + block->advance_rate = 0; + } + else { + block->advance_rate = advance / (float)acc_dist; + } + } + +#endif // ADVANCE + + // compute a preliminary conservative acceleration trapezoid + float safespeed = safe_speed(block); + calculate_trapezoid_for_block(block, safespeed, safespeed); + + // Compute direction bits for this block + block->direction_bits = 0; + if (target[X_AXIS] < position[X_AXIS]) { + block->direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<> 16 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 24 bit result +#define MultiU16X8toH16(intRes, charIn1, intIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %A1, %A2 \n\t" \ +"add %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r0 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (charIn1), \ +"d" (intIn2) \ +: \ +"r26" \ +) + +// intRes = longIn1 * longIn2 >> 24 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 48bit result +#define MultiU24X24toH16(intRes, longIn1, longIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"mov r27, r1 \n\t" \ +"mul %B1, %C2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %C1, %C2 \n\t" \ +"add %B0, r0 \n\t" \ +"mul %C1, %B2 \n\t" \ +"add %A0, r0 \n\t" \ +"adc %B0, r1 \n\t" \ +"mul %A1, %C2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %B2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %C1, %A2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %A2 \n\t" \ +"add r27, r1 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r27 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (longIn1), \ +"d" (longIn2) \ +: \ +"r26" , "r27" \ +) + +// Some useful constants + +#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1< +// +// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates +// first block->accelerate_until step_events_completed, then keeps going at constant speed until +// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. +// The slope of acceleration is calculated with the leib ramp alghorithm. + +void st_wake_up() { + // TCNT1 = 0; + ENABLE_STEPPER_DRIVER_INTERRUPT(); +} + +inline unsigned short calc_timer(unsigned short step_rate) { + unsigned short timer; + if(step_rate < 32) step_rate = 32; + step_rate -= 32; // Correct for minimal speed + if(step_rate >= (8*256)){ // higher step rate + unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; + unsigned char tmp_step_rate = (step_rate & 0x00ff); + unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); + MultiU16X8toH16(timer, tmp_step_rate, gain); + timer = (unsigned short)pgm_read_word_near(table_address) - timer; + } + else { // lower step rates + unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; + table_address += ((step_rate)>>1) & 0xfffc; + timer = (unsigned short)pgm_read_word_near(table_address); + timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); + } + if(timer < 100) timer = 100; + return timer; +} + +// Initializes the trapezoid generator from the current block. Called whenever a new +// block begins. +inline void trapezoid_generator_reset() { + accelerate_until = current_block->accelerate_until; + decelerate_after = current_block->decelerate_after; + acceleration_rate = current_block->acceleration_rate; + initial_rate = current_block->initial_rate; + final_rate = current_block->final_rate; + nominal_rate = current_block->nominal_rate; + advance = current_block->initial_advance; + final_advance = current_block->final_advance; + deceleration_time = 0; + advance_rate = current_block->advance_rate; + // step_rate to timer interval + acc_step_rate = initial_rate; + acceleration_time = calc_timer(acc_step_rate); + OCR1A = acceleration_time; +} + +// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. +// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. +ISR(TIMER1_COMPA_vect) +{ + if(busy){ /*Serial.println("BUSY")*/; + return; + } // The busy-flag is used to avoid reentering this interrupt + + busy = true; + sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) +#ifdef FANCY_LCD + static int breakdown=0; + if((breakdown++)%100==0) + buttons_check(); +/* [ErikDeBruijn] Perhaps it would be nice to use a piece of code like this (adapted from process_g_code), to create a nice progress bar! + if(sdactive){ + sprintf("SD printing byte %i%",(int) (sdpos/filesize*100)); // perhaps a fraction of a percent is also nice, 0.03%, progress bar even better. + Serial.print(sdpos); + Serial.print("/"); + Serial.println(filesize); + } +*/ +#endif + + // If there is no current block, attempt to pop one from the buffer + if (current_block == NULL) { + // Anything in the buffer? + current_block = plan_get_current_block(); + if (current_block != NULL) { + trapezoid_generator_reset(); + counter_x = -(current_block->step_event_count >> 1); + counter_y = counter_x; + counter_z = counter_x; + counter_e = counter_x; + step_events_completed = 0; + e_steps = 0; + } + else { + DISABLE_STEPPER_DRIVER_INTERRUPT(); + } + } + + if (current_block != NULL) { + // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt + out_bits = current_block->direction_bits; + +#ifdef ADVANCE + // Calculate E early. + counter_e += current_block->steps_e; + if (counter_e > 0) { + counter_e -= current_block->step_event_count; + if ((out_bits & (1<> 16) - old_advance); + CRITICAL_SECTION_END; + old_advance = advance >> 16; +#endif //ADVANCE + + // Set direction en check limit switches +if ((out_bits & (1<step_event_count; + } + } + else { // +direction + WRITE(X_DIR_PIN,!INVERT_X_DIR); + #ifdef DEBUG_STEPS + count_direction[X_AXIS]=1; + #endif + if((READ(X_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_x >0)){ + step_events_completed = current_block->step_event_count; + } + } + + if ((out_bits & (1<step_event_count; + } + } + else { // +direction + WRITE(Y_DIR_PIN,!INVERT_Y_DIR); + #ifdef DEBUG_STEPS + count_direction[Y_AXIS]=1; + #endif + if((READ(Y_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_y >0)){ + step_events_completed = current_block->step_event_count; + } + } + + if ((out_bits & (1<step_event_count; + } + } + else { // +direction + WRITE(Z_DIR_PIN,!INVERT_Z_DIR); + #ifdef DEBUG_STEPS + count_direction[Z_AXIS]=1; + #endif + if((READ(Z_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_z >0)){ + step_events_completed = current_block->step_event_count; + } + } + +#ifndef ADVANCE + if ((out_bits & (1<steps_x; + if (counter_x > 0) { + WRITE(X_STEP_PIN, HIGH); + counter_x -= current_block->step_event_count; + WRITE(X_STEP_PIN, LOW); + #ifdef DEBUG_STEPS + count_position[X_AXIS]+=count_direction[X_AXIS]; + #endif + } + + counter_y += current_block->steps_y; + if (counter_y > 0) { + WRITE(Y_STEP_PIN, HIGH); + counter_y -= current_block->step_event_count; + WRITE(Y_STEP_PIN, LOW); + #ifdef DEBUG_STEPS + count_position[Y_AXIS]+=count_direction[Y_AXIS]; + #endif + } + + counter_z += current_block->steps_z; + if (counter_z > 0) { + WRITE(Z_STEP_PIN, HIGH); + counter_z -= current_block->step_event_count; + WRITE(Z_STEP_PIN, LOW); + #ifdef DEBUG_STEPS + count_position[Z_AXIS]+=count_direction[Z_AXIS]; + #endif + } + +#ifndef ADVANCE + counter_e += current_block->steps_e; + if (counter_e > 0) { + WRITE(E_STEP_PIN, HIGH); + counter_e -= current_block->step_event_count; + WRITE(E_STEP_PIN, LOW); + } +#endif //!ADVANCE + + // Calculare new timer value + unsigned short timer; + unsigned short step_rate; + if (step_events_completed < accelerate_until) { + MultiU24X24toH16(acc_step_rate, acceleration_time, acceleration_rate); + acc_step_rate += initial_rate; + + // upper limit + if(acc_step_rate > nominal_rate) + acc_step_rate = nominal_rate; + + // step_rate to timer interval + timer = calc_timer(acc_step_rate); + advance += advance_rate; + acceleration_time += timer; + OCR1A = timer; + } + else if (step_events_completed >= decelerate_after) { + MultiU24X24toH16(step_rate, deceleration_time, acceleration_rate); + + if(step_rate > acc_step_rate) { // Check step_rate stays positive + step_rate = final_rate; + } + else { + step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. + } + + // lower limit + if(step_rate < final_rate) + step_rate = final_rate; + + // step_rate to timer interval + timer = calc_timer(step_rate); +#ifdef ADVANCE + advance -= advance_rate; + if(advance < final_advance) + advance = final_advance; +#endif //ADVANCE + deceleration_time += timer; + OCR1A = timer; + } + // If current block is finished, reset pointer + step_events_completed += 1; + if (step_events_completed >= current_block->step_event_count) { + current_block = NULL; + plan_discard_current_block(); + } + } + busy=false; +} + +#ifdef ADVANCE + +unsigned char old_OCR0A; +// Timer interrupt for E. e_steps is set in the main routine; +// Timer 0 is shared with millies +ISR(TIMER0_COMPA_vect) +{ + // Critical section needed because Timer 1 interrupt has higher priority. + // The pin set functions are placed on trategic position to comply with the stepper driver timing. + WRITE(E_STEP_PIN, LOW); + // Set E direction (Depends on E direction + advance) + if (e_steps < 0) { + WRITE(E_DIR_PIN,INVERT_E_DIR); + e_steps++; + WRITE(E_STEP_PIN, HIGH); + } + if (e_steps > 0) { + WRITE(E_DIR_PIN,!INVERT_E_DIR); + e_steps--; + WRITE(E_STEP_PIN, HIGH); + } + old_OCR0A += 25; // 10kHz interrupt + OCR0A = old_OCR0A; +} +#endif // ADVANCE + +void st_init() +{ + // waveform generation = 0100 = CTC + TCCR1B &= ~(1<= 16) + { + current_raw = 16383 - raw_temp_value; + temp_meas_ready = true; + temp_count = 0; + raw_temp_value = 0; +#ifdef MAXTEMP + if(current_raw >= maxttemp) { + target_raw = 0; +#ifdef PIDTEMP + OCR2B = 0; +#else + WRITE(HEATER_0_PIN,LOW); +#endif //PIDTEMP + } +#endif //MAXTEMP +#ifdef MINTEMP + if(current_raw <= minttemp) { + target_raw = 0; +#ifdef PIDTEMP + OCR2B = 0; +#else + WRITE(HEATER_0_PIN,LOW); +#endif //PIDTEMP + } +#endif //MAXTEMP +#ifndef PIDTEMP + if(current_raw >= target_raw) + { + WRITE(HEATER_0_PIN,LOW); + } + else + { + WRITE(HEATER_0_PIN,HIGH); + } +#endif //PIDTEMP + } +} + */ From 3dae132436ff46ca4378ef79eafa2d81002ba865 Mon Sep 17 00:00:00 2001 From: lampmaker Date: Sun, 18 Sep 2011 17:35:47 +0300 Subject: [PATCH 041/130] Wrapped prev commit in #ifdef DEBUG_STEPS --- Marlin/Marlin.pde | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 3af3717e6426..3c3f202abb20 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -2016,10 +2016,12 @@ void plan_set_position(float x, float y, float z, float e) position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); - position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); + position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); +#ifdef DEBUG_STEPS count_position[X_AXIS]= position[X_AXIS]; count_position[Y_AXIS]= position[Y_AXIS]; count_position[Z_AXIS]= position[Z_AXIS]; +#endif } // Stepper From d6f6bdc532f3b120015131da994e5cbfab282308 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 20 Sep 2011 13:37:31 +0200 Subject: [PATCH 042/130] making acceleration and max speeds value changeable by gcode. M203 M204 additional comments --- Marlin/Configuration.h | 17 +++++++++++------ Marlin/Marlin.pde | 41 ++++++++++++++++++++++++++++++----------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index d81c4f9d9434..8b5913caae5b 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -84,17 +84,22 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the //// MOVEMENT SETTINGS #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {240*60, 240*60, 500*60, 500000}; // set the max speeds -float homing_feedrate[] = {3400, 3400, 60*500, 0}; // set the homing speeds +float max_feedrate[] = {200*60, 200*60, 500*60, 500000}; // set the max speeds +float homing_feedrate[] = {70*60, 70*60, 500*60, 0}; // set the homing speeds +//the followint checks if an extrusion is existent in the move. if _not_, the speed of the move is set to the maximum speed. +//!!!!!!Use only if you know that your printer works at the maximum declared speeds. +// works around the skeinforge cool-bug. There all moves are slowed to have a minimum layer time. However slow travel moves= ooze +//#define TRAVELING_AT_MAXSPEED bool axis_relative_modes[] = {false, false, false, false}; //// Acceleration settings // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. -float acceleration = 4000; // Normal acceleration mm/s^2 -float retract_acceleration = 7000; // Normal acceleration mm/s^2 -float max_xy_jerk = 20.0*60; +float acceleration = 4000; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX +float retract_acceleration = 7000; // mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX +float max_xy_jerk = 50.0*60; //speed than can be stopped at once, if i understand correctly. float max_z_jerk = 0.4*60; -long max_acceleration_units_per_sq_second[] = {7000,7000,15000,10000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts +// X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts +long max_acceleration_units_per_sq_second[] = {9000,9000,15000,10000}; // Use M201 to override by software // The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature // If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 75a25caa0998..d9a9730c135c 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -118,7 +118,9 @@ volatile int count_direction[NUM_AXIS] = { 1, 1, 1, 1}; // 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) +// M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) Unused in Marlin!! +// M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec +// M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 // M301 - Set PID parameters P I and D //Stepper Movement Variables @@ -1062,6 +1064,17 @@ inline void process_commands() } break; #endif + case 203: // M203 max feedrate mm/sec + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) max_feedrate[i] = code_value()*60 ; + } + break; + case 204: // M204 acclereration S normal moves T filmanent only moves + { + if(code_seen('S') acceleration = code_value() ; + if(code_seen('T') acceleration_retract = code_value() ; + } + break; #ifdef PIDTEMP case 301: // M301 if(code_seen('P')) Kp = code_value(); @@ -1893,7 +1906,12 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { unsigned long microseconds; microseconds = lround((block->millimeters/feed_rate)*1000000); - +#ifdef TRAVELING_AT_MAXSPEED + if(delta_e_mm==0) //no extrusion + { + microseconds*=0.001; // speed limits then should get working + } +#endif // added by lampmaker to slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill // reduces/removes corner blobs as the machine won't come to a full stop. int blockcount=block_buffer_head-block_buffer_tail; @@ -1910,25 +1928,26 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->speed_y = delta_y_mm * multiplier; block->speed_e = delta_e_mm * multiplier; + // Limit speed per axis - float speed_factor = 1; - float tmp_speed_factor; + float speed_factor = 1; //factor <=1 do decrease speed if(abs(block->speed_x) > max_feedrate[X_AXIS]) { //// [ErikDeBruijn] IS THIS THE BUG WE'RE LOOING FOR???? - // it used to be just this line: speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); - tmp_speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + //// [bernhard] No its not, according to Zalm. + //// the if would always be true, since tmp_speedfactor <=0 due the inial if, so its safe to set. the next lines actually compare. + speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + //if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; } if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ - tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); + float tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; } if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ - tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); + float tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; } if(abs(block->speed_e) > max_feedrate[E_AXIS]){ - tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); + float tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; } multiplier = multiplier * speed_factor; @@ -2532,4 +2551,4 @@ ISR(TIMER2_OVF_vect) } } -*/ +*/ From 063e7c7d7df3ac8b7400473d8e166c9f85a93393 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 20 Sep 2011 13:45:36 +0200 Subject: [PATCH 043/130] unix end of line --- Marlin/Marlin.pde | 5080 ++++++++++++++++++++++----------------------- 1 file changed, 2540 insertions(+), 2540 deletions(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 3c3f202abb20..095e90024c35 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1,2540 +1,2540 @@ -#include "Marlin.h" -// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in -// the source g-code and may never actually be reached if acceleration management is active. - -//#define DEBUG_STEPS - - -#include "speed_lookuptable.h" - -/* - Reprap firmware based on Sprinter and grbl. - Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm - - This program 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. - - This program 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 this program. If not, see . - */ - -/* - This firmware is a mashup between Sprinter and grbl. - (https://github.com/kliment/Sprinter) - (https://github.com/simen/grbl/tree) - - It has preliminary support for Matthew Roberts advance algorithm - http://reprap.org/pipermail/reprap-dev/2011-May/003323.html - - This firmware is optimized for gen6 electronics. - */ - - - -#include "fastio.h" -#include "Configuration.h" -#include "pins.h" -#include "Marlin.h" -#include "speed_lookuptable.h" -#include "lcd.h" - -char version_string[] = "U0.9.3.3-BK"; - -#ifdef SDSUPPORT -#include "SdFat.h" -#endif //SDSUPPORT - -#ifndef CRITICAL_SECTION_START -#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() -#define CRITICAL_SECTION_END SREG = _sreg -#endif //CRITICAL_SECTION_START - - -#if defined SDSUPPORT || defined FANCY_LCD -// The number of linear motions that can be in the plan at any give time. - #define BLOCK_BUFFER_SIZE 16 // SD,LCD,Buttons take more memory, block buffer needs to be smaller -#else - #define BLOCK_BUFFER_SIZE 40 // maximize block buffer -#endif - -#ifdef SIMPLE_LCD - #define BLOCK_BUFFER_SIZE 32 // A little less buffer for just a simple LCD -#endif - -// if DEBUG_STEPS is enabled, M114 can be used to compare two methods of determining the X,Y,Z position of the printer. -// for debugging purposes only, should be disabled by default -#ifdef DEBUG_STEPS -volatile long count_position[NUM_AXIS] = { 0, 0, 0, 0}; -volatile int count_direction[NUM_AXIS] = { 1, 1, 1, 1}; -#endif -// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html -// 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 -// G28 - Home all 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 -// 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 -// M115 - Capabilities string -// 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) -// M301 - Set PID parameters P I and D - -//Stepper Movement Variables - -char axis_codes[NUM_AXIS] = { - 'X', 'Y', 'Z', 'E'}; -float destination[NUM_AXIS] = { - 0.0, 0.0, 0.0, 0.0}; -float current_position[NUM_AXIS] = { - 0.0, 0.0, 0.0, 0.0}; -bool home_all_axis = true; -long feedrate = 1500, next_feedrate, saved_feedrate; -long gcode_N, gcode_LastN; -unsigned long previous_millis_heater, previous_millis_bed_heater; -bool relative_mode = false; //Determines Absolute or Relative Coordinates -bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. -unsigned long axis_steps_per_sqr_second[NUM_AXIS]; - -volatile int feedmultiply=100; //100->1 200->2 -// comm variables -#define MAX_CMD_SIZE 96 -#define BUFSIZE 8 -char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; -bool fromsd[BUFSIZE]; -int bufindr = 0; -int bufindw = 0; -int buflen = 0; -int i = 0; -char serial_char; -int serial_count = 0; -boolean comment_mode = false; -char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc - -// Manage heater variables. - -int target_bed_raw = 0; -int current_bed_raw = 0; - -int target_raw = 0; -int current_raw = 0; -unsigned char temp_meas_ready = false; - -#ifdef PIDTEMP - double temp_iState = 0; - double temp_dState = 0; - double pTerm; - double iTerm; - double dTerm; - //int output; - double pid_error; - double temp_iState_min; - double temp_iState_max; - double pid_setpoint = 0.0; - double pid_input; - double pid_output; - bool pid_reset; -#endif //PIDTEMP -float tt = 0, bt = 0; -#ifdef WATCHPERIOD -int watch_raw = -1000; -unsigned long watchmillis = 0; -#endif //WATCHPERIOD -#ifdef MINTEMP -int minttemp = temp2analog(MINTEMP); -#endif //MINTEMP -#ifdef MAXTEMP -int maxttemp = temp2analog(MAXTEMP); -#endif //MAXTEMP - -//Inactivity shutdown variables -unsigned long previous_millis_cmd = 0; -unsigned long max_inactive_time = 0; -unsigned long stepper_inactive_time = 0; - -unsigned long starttime=0; -unsigned long stoptime=0; -#ifdef SDSUPPORT -Sd2Card card; -SdVolume volume; -SdFile root; -SdFile file; -uint32_t filesize = 0; -uint32_t sdpos = 0; -bool sdmode = false; -bool sdactive = false; -bool savetosd = false; -int16_t n; - -void initsd(){ - sdactive = false; -#if SDSS >- 1 - if(root.isOpen()) - root.close(); - if (!card.init(SPI_FULL_SPEED,SDSS)){ - //if (!card.init(SPI_HALF_SPEED,SDSS)) - Serial.println("SD init fail"); - } - else if (!volume.init(&card)) - Serial.println("volume.init failed"); - else if (!root.openRoot(&volume)) - Serial.println("openRoot failed"); - else - sdactive = true; -#endif //SDSS -} - -inline void write_command(char *buf){ - char* begin = buf; - char* npos = 0; - char* end = buf + strlen(buf) - 1; - - file.writeError = false; - if((npos = strchr(buf, 'N')) != NULL){ - begin = strchr(npos, ' ') + 1; - end = strchr(npos, '*') - 1; - } - end[1] = '\r'; - end[2] = '\n'; - end[3] = '\0'; - //Serial.println(begin); - file.write(begin); - if (file.writeError){ - Serial.println("error writing to file"); - } -} -#endif //SDSUPPORT - -void setup() -{ - - Serial.begin(BAUDRATE); - Serial.print("Marlin "); - Serial.println(version_string); - Serial.println("start"); -#if defined FANCY_LCD || defined SIMPLE_LCD - lcd_init(); -#endif - for(int i = 0; i < BUFSIZE; i++){ - fromsd[i] = false; - } - - - //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 -#if E_DIR_PIN > -1 - SET_OUTPUT(E_DIR_PIN); -#endif - - //Initialize Enable Pins - steppers default to disabled. - -#if (X_ENABLE_PIN > -1) - SET_OUTPUT(X_ENABLE_PIN); - if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); -#endif -#if (Y_ENABLE_PIN > -1) - SET_OUTPUT(Y_ENABLE_PIN); - if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); -#endif -#if (Z_ENABLE_PIN > -1) - SET_OUTPUT(Z_ENABLE_PIN); - if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); -#endif -#if (E_ENABLE_PIN > -1) - SET_OUTPUT(E_ENABLE_PIN); - if(!E_ENABLE_ON) WRITE(E_ENABLE_PIN,HIGH); -#endif - - //endstops and pullups -#ifdef ENDSTOPPULLUPS -#if X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); - WRITE(X_MIN_PIN,HIGH); -#endif -#if X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); - WRITE(X_MAX_PIN,HIGH); -#endif -#if Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); - WRITE(Y_MIN_PIN,HIGH); -#endif -#if Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); - WRITE(Y_MAX_PIN,HIGH); -#endif -#if Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); - WRITE(Z_MIN_PIN,HIGH); -#endif -#if Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); - WRITE(Z_MAX_PIN,HIGH); -#endif -#else //ENDSTOPPULLUPS -#if X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); -#endif -#if X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); -#endif -#if Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); -#endif -#if Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); -#endif -#if Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); -#endif -#if Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); -#endif -#endif //ENDSTOPPULLUPS - -#if (HEATER_0_PIN > -1) - SET_OUTPUT(HEATER_0_PIN); -#endif -#if (HEATER_1_PIN > -1) - SET_OUTPUT(HEATER_1_PIN); -#endif - - //Initialize Step Pins -#if (X_STEP_PIN > -1) - SET_OUTPUT(X_STEP_PIN); -#endif -#if (Y_STEP_PIN > -1) - SET_OUTPUT(Y_STEP_PIN); -#endif -#if (Z_STEP_PIN > -1) - SET_OUTPUT(Z_STEP_PIN); -#endif -#if (E_STEP_PIN > -1) - SET_OUTPUT(E_STEP_PIN); -#endif - for(int i=0; i < NUM_AXIS; i++){ - axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; - } - -#ifdef PIDTEMP - temp_iState_min = 0.0; - temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; -#endif //PIDTEMP - -#ifdef SDSUPPORT - //power to SD reader -#if SDPOWER > -1 - SET_OUTPUT(SDPOWER); - WRITE(SDPOWER,HIGH); -#endif //SDPOWER - initsd(); - -#endif //SDSUPPORT - plan_init(); // Initialize planner; - st_init(); // Initialize stepper; -// tp_init(); // Initialize temperature loop - checkautostart(); -} - -#ifdef SDSUPPORT -void checkautostart() -{ - if(!sdactive) - return; - static int lastnr=0; - char autoname[30]; - sprintf(autoname,"auto%i.g",lastnr); - for(int i=0;i 0) - { - for(int i=0;i 0 && buflen < BUFSIZE) { - serial_char = Serial.read(); - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) - { - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = false; - if(strstr(cmdbuffer[bufindw], "N") != NULL) - { - strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); - gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); - if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { - Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); - Serial.println(gcode_LastN); - //Serial.println(gcode_N); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - if(strstr(cmdbuffer[bufindw], "*") != NULL) - { - byte checksum = 0; - byte count = 0; - while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; - strchr_pointer = strchr(cmdbuffer[bufindw], '*'); - - if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { - Serial.print("Error: checksum mismatch, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - //if no errors, continue parsing - } - else - { - Serial.print("Error: No Checksum with line number, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - gcode_LastN = gcode_N; - //if no errors, continue parsing - } - else // if we don't receive 'N' but still see '*' - { - if((strstr(cmdbuffer[bufindw], "*") != NULL)) - { - Serial.print("Error: No Line Number with checksum, Last Line:"); - Serial.println(gcode_LastN); - serial_count = 0; - return; - } - } - if((strstr(cmdbuffer[bufindw], "G") != NULL)){ - strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); - switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ - case 0: - case 1: -#ifdef SDSUPPORT - if(savetosd) - break; -#endif //SDSUPPORT - Serial.println("ok"); - break; - default: - break; - } - - } - bufindw = (bufindw + 1)%BUFSIZE; - buflen += 1; - - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } - } -#ifdef SDSUPPORT - if(!sdmode || serial_count!=0){ - return; - } - while( filesize > sdpos && buflen < BUFSIZE) { - n = file.read(); - serial_char = (char)n; - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) - { - sdpos = file.curPosition(); - if(sdpos >= filesize){ - sdmode = false; - Serial.println("Done printing file"); - stoptime=millis(); - char time[30]; - unsigned long t=(stoptime-starttime)/1000; - int sec,min; - min=t/60; - sec=t%60; - sprintf(time,"%i min, %i sec",min,sec); - Serial.println(time); - LCD_MESSAGE(time); - checkautostart(); - } - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = true; - buflen += 1; - bufindw = (bufindw + 1)%BUFSIZE; - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } - } -#endif //SDSUPPORT - -} - - -inline float code_value() { - return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); -} -inline long code_value_long() { - return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); -} -inline bool code_seen(char code_string[]) { - return (strstr(cmdbuffer[bufindr], code_string) != NULL); -} //Return True if the string was found - -inline bool code_seen(char code) -{ - strchr_pointer = strchr(cmdbuffer[bufindr], code); - return (strchr_pointer != NULL); //Return True if a character was found -} - -inline void process_commands() -{ - unsigned long codenum; //throw away variable - char *starpos = NULL; - - if(code_seen('G')) - { - switch((int)code_value()) - { - case 0: // G0 -> G1 - case 1: // G1 - get_coordinates(); // For X Y Z E F - prepare_move(); - previous_millis_cmd = millis(); - //ClearToSend(); - return; - //break; - case 4: // G4 dwell - codenum = 0; - if(code_seen('P')) codenum = code_value(); // milliseconds to wait - if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait - codenum += millis(); // keep track of when we started waiting - while(millis() < codenum ){ - manage_heater(); - } - break; - case 28: //G28 Home all Axis one at a time - saved_feedrate = feedrate; - for(int i=0; i < NUM_AXIS; i++) { - destination[i] = current_position[i]; - } - feedrate = 0; - - home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); - - if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) { - if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){ - st_synchronize(); - current_position[X_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; - feedrate = homing_feedrate[X_AXIS]; - prepare_move(); - - st_synchronize(); - current_position[X_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = -5 * X_HOME_DIR; - prepare_move(); - - st_synchronize(); - destination[X_AXIS] = 10 * X_HOME_DIR; - feedrate = homing_feedrate[X_AXIS]/2 ; - prepare_move(); - st_synchronize(); - - current_position[X_AXIS] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[X_AXIS] = current_position[X_AXIS]; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { - if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){ - current_position[Y_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; - feedrate = homing_feedrate[Y_AXIS]; - prepare_move(); - st_synchronize(); - - current_position[Y_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = -5 * Y_HOME_DIR; - prepare_move(); - st_synchronize(); - - destination[Y_AXIS] = 10 * Y_HOME_DIR; - feedrate = homing_feedrate[Y_AXIS]/2; - prepare_move(); - st_synchronize(); - - current_position[Y_AXIS] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Y_AXIS] = current_position[Y_AXIS]; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { - if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){ - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; - feedrate = homing_feedrate[Z_AXIS]; - prepare_move(); - st_synchronize(); - - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = -2 * Z_HOME_DIR; - prepare_move(); - st_synchronize(); - - destination[Z_AXIS] = 3 * Z_HOME_DIR; - feedrate = homing_feedrate[Z_AXIS]/2; - prepare_move(); - st_synchronize(); - - current_position[Z_AXIS] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[Z_AXIS] = current_position[Z_AXIS]; - feedrate = 0; - } - } - feedrate = saved_feedrate; - previous_millis_cmd = millis(); - break; - case 90: // G90 - relative_mode = false; - break; - case 91: // G91 - relative_mode = true; - break; - case 92: // G92 - if(!code_seen(axis_codes[E_AXIS])) - st_synchronize(); - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) current_position[i] = code_value(); - } - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - break; - - } - } - - else if(code_seen('M')) - { - - switch( (int)code_value() ) - { -#ifdef SDSUPPORT - - case 20: // M20 - list SD card - Serial.println("Begin file list"); - root.ls(); - Serial.println("End file list"); - break; - case 21: // M21 - init SD card - sdmode = false; - initsd(); - break; - case 22: //M22 - release SD card - sdmode = false; - sdactive = false; - break; - case 23: //M23 - Select file - if(sdactive){ - sdmode = false; - file.close(); - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos!=NULL) - *(starpos-1)='\0'; - if (file.open(&root, strchr_pointer + 4, O_READ)) { - Serial.print("File opened:"); - Serial.print(strchr_pointer + 4); - Serial.print(" Size:"); - Serial.println(file.fileSize()); - sdpos = 0; - filesize = file.fileSize(); - Serial.println("File selected"); - } - else{ - Serial.println("file.open failed"); - } - } - break; - case 24: //M24 - Start SD print - if(sdactive){ - sdmode = true; - starttime=millis(); - } - break; - case 25: //M25 - Pause SD print - if(sdmode){ - sdmode = false; - } - break; - case 26: //M26 - Set SD index - if(sdactive && code_seen('S')){ - sdpos = code_value_long(); - file.seekSet(sdpos); - } - break; - case 27: //M27 - Get SD status - if(sdactive){ - Serial.print("SD printing byte "); - Serial.print(sdpos); - Serial.print("/"); - Serial.println(filesize); - } - else{ - Serial.println("Not SD printing"); - } - break; - case 28: //M28 - Start SD write - if(sdactive){ - char* npos = 0; - file.close(); - sdmode = false; - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos != NULL){ - npos = strchr(cmdbuffer[bufindr], 'N'); - strchr_pointer = strchr(npos,' ') + 1; - *(starpos-1) = '\0'; - } - if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) - { - Serial.print("open failed, File: "); - Serial.print(strchr_pointer + 4); - Serial.print("."); - } - else{ - savetosd = true; - Serial.print("Writing to file: "); - Serial.println(strchr_pointer + 4); - } - } - break; - case 29: //M29 - Stop SD write - //processed in write to file routine above - //savetosd = false; - break; - case 30: - { - stoptime=millis(); - char time[30]; - unsigned long t=(stoptime-starttime)/1000; - int sec,min; - min=t/60; - sec=t%60; - sprintf(time,"%i min, %i sec",min,sec); - Serial.println(time); - LCD_MESSAGE(time); - } - break; -#endif //SDSUPPORT - case 104: // M104 - if (code_seen('S')) target_raw = temp2analog(code_value()); - #ifdef WATCHPERIOD - if(target_raw > current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - }else{ - watchmillis = 0; - } - #endif - break; - case 140: // M140 set bed temp - if (code_seen('S')) target_bed_raw = temp2analogBed(code_value()); - break; - case 105: // M105 - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) - tt = analog2temp(current_raw); - #endif - #if TEMP_1_PIN > -1 - bt = analog2tempBed(current_bed_raw); - #endif - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) - Serial.print("ok T:"); - Serial.print(tt); - Serial.print(", raw:"); - Serial.print(current_raw); - #if TEMP_1_PIN > -1 - Serial.print(" B:"); - Serial.println(bt); - #else - Serial.println(); - #endif - #else - Serial.println("No thermistors - no temp"); - #endif - return; - //break; - case 109: // M109 - Wait for extruder heater to reach target. - LCD_MESSAGE("Heating..."); - if (code_seen('S')) target_raw = temp2analog(code_value()); - #ifdef WATCHPERIOD - if(target_raw>current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - }else{ - watchmillis = 0; - } - #endif - codenum = millis(); - starttime=millis(); - while(current_raw < target_raw) { - if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - Serial.print("T:"); - Serial.println( analog2temp(current_raw) ); - - codenum = millis(); - } - LCD_STATUS; - manage_heater(); - } - break; - case 190: // M190 - Wait bed for heater to reach target. - #if TEMP_1_PIN > -1 - if (code_seen('S')) target_bed_raw = temp2analog(code_value()); - codenum = millis(); - while(current_bed_raw < target_bed_raw) - { - if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - float tt=analog2temp(current_raw); - Serial.print("T:"); - Serial.println( tt ); - Serial.print("ok T:"); - Serial.print( tt ); - Serial.print(" B:"); - Serial.println( analog2temp(current_bed_raw) ); - codenum = millis(); - } - manage_heater(); - } - #endif - break; - case 106: //M106 Fan On - if (code_seen('S')){ - digitalWrite(FAN_PIN,HIGH); - analogWrite(FAN_PIN, constrain(code_value(),0,255) ); - } - else - { - digitalWrite(FAN_PIN,HIGH); - analogWrite(FAN_PIN, 255); - } - break; - case 107: //M107 Fan Off - digitalWrite(FAN_PIN,LOW); - analogWrite(FAN_PIN, 0); - break; - - case 82: - axis_relative_modes[3] = false; - break; - case 83: - axis_relative_modes[3] = true; - break; - case 18: - case 84: - if(code_seen('S')){ - stepper_inactive_time = code_value() * 1000; - } - else{ - st_synchronize(); - disable_x(); - disable_y(); - disable_z(); - disable_e(); - } - break; - case 85: // M85 - code_seen('S'); - max_inactive_time = code_value() * 1000; - break; - case 92: // M92 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); - } - - break; - case 115: // M115 - Serial.println("FIRMWARE_NAME:Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); - break; - case 114: // M114 - Serial.print("X:"); - Serial.print(current_position[X_AXIS]); - Serial.print("Y:"); - Serial.print(current_position[Y_AXIS]); - Serial.print("Z:"); - Serial.print(current_position[Z_AXIS]); - Serial.print("E:"); - Serial.print(current_position[E_AXIS]); - #ifdef DEBUG_STEPS - Serial.print(" Count X:"); - Serial.print(float(count_position[X_AXIS])/axis_steps_per_unit[X_AXIS]); - Serial.print("Y:"); - Serial.print(float(count_position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]); - Serial.print("Z:"); - Serial.println(float(count_position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]); - #endif - Serial.println(""); - break; - case 119: // M119 -#if (X_MIN_PIN > -1) - Serial.print("x_min:"); - Serial.print((READ(X_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (X_MAX_PIN > -1) - Serial.print("x_max:"); - Serial.print((READ(X_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Y_MIN_PIN > -1) - Serial.print("y_min:"); - Serial.print((READ(Y_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Y_MAX_PIN > -1) - Serial.print("y_max:"); - Serial.print((READ(Y_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Z_MIN_PIN > -1) - Serial.print("z_min:"); - Serial.print((READ(Z_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif -#if (Z_MAX_PIN > -1) - Serial.print("z_max:"); - Serial.print((READ(Z_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); -#endif - Serial.println(""); - break; - //TODO: update for all axis, use for loop - case 201: // M201 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; -#if 0 // Not used for Sprinter/grbl gen6 - case 202: // M202 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; -#endif -#ifdef PIDTEMP - case 301: // M301 - if(code_seen('P')) Kp = code_value(); - if(code_seen('I')) Ki = code_value()*PID_dT; - if(code_seen('D')) Kd = code_value()/PID_dT; - Serial.print("Kp ");Serial.println(Kp); - Serial.print("Ki ");Serial.println(Ki/PID_dT); - Serial.print("Kd ");Serial.println(Kd*PID_dT); - temp_iState_min = 0.0; - temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; - break; -#endif //PIDTEMP - } - } - else{ - Serial.println("Unknown command:"); - Serial.println(cmdbuffer[bufindr]); - } - - ClearToSend(); -} - -void FlushSerialRequestResend() -{ - //char cmdbuffer[bufindr][100]="Resend:"; - Serial.flush(); - Serial.print("Resend:"); - Serial.println(gcode_LastN + 1); - ClearToSend(); -} - -void ClearToSend() -{ - previous_millis_cmd = millis(); -#ifdef SDSUPPORT - if(fromsd[bufindr]) - return; -#endif //SDSUPPORT - Serial.println("ok"); -} - -inline void get_coordinates() -{ - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; - else destination[i] = current_position[i]; //Are these else lines really needed? - } - if(code_seen('F')) { - next_feedrate = code_value(); - if(next_feedrate > 0.0) feedrate = next_feedrate; - } -} - -void prepare_move() -{ - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60.0/100.); - for(int i=0; i < NUM_AXIS; i++) { - current_position[i] = destination[i]; - } -} -/* -void manage_heater() -{ - float pid_input; - float pid_output; - if(temp_meas_ready != true) - return; - -CRITICAL_SECTION_START; - temp_meas_ready = false; -CRITICAL_SECTION_END; - -#ifdef PIDTEMP - pid_input = analog2temp(current_raw); - -#ifndef PID_OPENLOOP - pid_error = pid_setpoint - pid_input; - if(pid_error > 10){ - pid_output = PID_MAX; - pid_reset = true; - } - else if(pid_error < -10) { - pid_output = 0; - pid_reset = true; - } - else { - if(pid_reset == true) { - temp_iState = 0.0; - pid_reset = false; - } - pTerm = Kp * pid_error; - temp_iState += pid_error; - temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = Ki * temp_iState; - #define K1 0.8 - #define K2 (1.0-K1) - dTerm = (Kd * (pid_input - temp_dState))*K2 + (K1 * dTerm); - temp_dState = pid_input; - pid_output = constrain(pTerm + iTerm - dTerm, 0, PID_MAX); - } -#endif //PID_OPENLOOP -#ifdef PID_DEBUG - Serial.print(" Input "); - Serial.print(pid_input); - Serial.print(" Output "); - Serial.print(pid_output); - Serial.print(" pTerm "); - Serial.print(pTerm); - Serial.print(" iTerm "); - Serial.print(iTerm); - Serial.print(" dTerm "); - Serial.print(dTerm); - Serial.println(); -#endif //PID_DEBUG - OCR2B = pid_output; -#endif //PIDTEMP -} -*/ - - -/* -int temp2analogu(int celsius, const short table[][2], int numtemps) { - int raw = 0; - byte i; - - for (i=1; i raw) { - celsius = (float)table[i-1][1] + - (float)(raw - table[i-1][0]) * - (float)(table[i][1] - table[i-1][1]) / - (float)(table[i][0] - table[i-1][0]); - - break; - } - } - // Overflow: Set to last value in the table - if (i == numtemps) celsius = table[i-1][1]; - - return celsius; -} - - -inline void kill() -{ - target_raw=0; -#ifdef PIDTEMP - pid_setpoint = 0.0; -#endif //PIDTEMP - OCR2B = 0; - WRITE(HEATER_0_PIN,LOW); - - disable_x(); - disable_y(); - disable_z(); - disable_e(); - -} -*/ - - - -//#################################################################################################################### -//#################################################################################################################### -void manage_heater() -{ -#ifdef USE_WATCHDOG - wd_reset(); -#endif - //there is no FANCY_LCD here, because this routine is called within moves, and delays them. one could loose steps. - - if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) - return; - previous_millis_heater = millis(); - #ifdef HEATER_USES_THERMISTOR - current_raw = analogRead(TEMP_0_PIN); - // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, - // this switches it up so that the reading appears lower than target for the control logic. - current_raw = 1023 - current_raw; - #elif defined HEATER_USES_AD595 - current_raw = analogRead(TEMP_0_PIN); - #elif defined HEATER_USES_MAX6675 - current_raw = read_max6675(); - #endif - #ifdef SMOOTHING - nma = (nma + current_raw) - (nma / SMOOTHFACTOR); - current_raw = nma / SMOOTHFACTOR; - #endif - #ifdef WATCHPERIOD - if(watchmillis && millis() - watchmillis > WATCHPERIOD){ - if(watch_raw + 1 >= current_raw){ - target_raw = 0; - digitalWrite(HEATER_0_PIN,LOW); - digitalWrite(LED_PIN,LOW); - }else{ - watchmillis = 0; - } - } - #endif - #ifdef MINTEMP - if(current_raw <= minttemp) - target_raw = 0; - #endif - #ifdef MAXTEMP - if(current_raw >= maxttemp) { - target_raw = 0; - } - #endif - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) - #ifdef PIDTEMP - error = target_raw - current_raw; - pTerm = (PID_PGAIN * error) / 100; - temp_iState += error; - temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = (PID_IGAIN * temp_iState) / 100; - dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; - temp_dState = current_raw; - analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); - #else - if(current_raw >= target_raw) - { - digitalWrite(HEATER_0_PIN,LOW); - digitalWrite(LED_PIN,LOW); - } - else - { - digitalWrite(HEATER_0_PIN,HIGH); - digitalWrite(LED_PIN,HIGH); - } - #endif - #endif - - if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) - return; - previous_millis_bed_heater = millis(); - - #ifdef BED_USES_THERMISTOR - - current_bed_raw = analogRead(TEMP_1_PIN); - - // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, - // this switches it up so that the reading appears lower than target for the control logic. - current_bed_raw = 1023 - current_bed_raw; - #elif defined BED_USES_AD595 - current_bed_raw = analogRead(TEMP_1_PIN); - - #endif - - - #if TEMP_1_PIN > -1 - if(current_bed_raw >= target_bed_raw) - { - digitalWrite(HEATER_1_PIN,LOW); - } - else - { - digitalWrite(HEATER_1_PIN,HIGH); - } - #endif -} - -// Takes hot end temperature value as input and returns corresponding raw value. -// For a thermistor, it uses the RepRap thermistor temp table. -// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value. -// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware. -float temp2analog(int celsius) { - #ifdef HEATER_USES_THERMISTOR - int raw = 0; - byte i; - - for (i=1; i raw) - { - celsius = temptable[i-1][1] + - (raw - temptable[i-1][0]) * - (temptable[i][1] - temptable[i-1][1]) / - (temptable[i][0] - temptable[i-1][0]); - - break; - } - } - - // Overflow: Set to last value in the table - if (i == NUMTEMPS) celsius = temptable[i-1][1]; - - return celsius; - #elif defined HEATER_USES_AD595 - return raw * ((5.0 * 100.0) / 1024.0); - #elif defined HEATER_USES_MAX6675 - return raw * 0.25; - #endif -} - -// Derived from RepRap FiveD extruder::getTemperature() -// For bed temperature measurement. -float analog2tempBed(int raw) { - #ifdef BED_USES_THERMISTOR - int celsius = 0; - byte i; - - raw = 1023 - raw; - - for (i=1; i raw) - { - celsius = bedtemptable[i-1][1] + - (raw - bedtemptable[i-1][0]) * - (bedtemptable[i][1] - bedtemptable[i-1][1]) / - (bedtemptable[i][0] - bedtemptable[i-1][0]); - - break; - } - } - - // Overflow: Set to last value in the table - if (i == NUMTEMPS) celsius = bedtemptable[i-1][1]; - - return celsius; - - #elif defined BED_USES_AD595 - return raw * ((5.0 * 100.0) / 1024.0); - #endif -} - -inline void kill() -{ - #if TEMP_0_PIN > -1 - target_raw=0; - digitalWrite(HEATER_0_PIN,LOW); - #endif - #if TEMP_1_PIN > -1 - target_bed_raw=0; - if(HEATER_1_PIN > -1) digitalWrite(HEATER_1_PIN,LOW); - #endif - disable_x(); - disable_y(); - disable_z(); - disable_e(); - - if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); - -} - - - - - - -//####################################################################################################################### - -inline void manage_inactivity(byte debug) { - if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); - if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { - disable_x(); - disable_y(); - disable_z(); - disable_e(); - } - check_axes_activity(); -} - -// Planner - -/* - Reasoning behind the mathematics in this module (in the key of 'Mathematica'): - - s == speed, a == acceleration, t == time, d == distance - - Basic definitions: - - Speed[s_, a_, t_] := s + (a*t) - Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t] - - Distance to reach a specific speed with a constant acceleration: - - Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t] - d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance() - - Speed after a given distance of travel with constant acceleration: - - Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t] - m -> Sqrt[2 a d + s^2] - - DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2] - - When to start braking (di) to reach a specified destionation speed (s2) after accelerating - from initial speed s1 without ever stopping at a plateau: - - Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di] - di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance() - - IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a) - */ - - - - -static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions -static volatile unsigned char block_buffer_head; // Index of the next block to be pushed -static volatile unsigned char block_buffer_tail; // Index of the block to process now - -// The current position of the tool in absolute steps -static long position[4]; - -#define ONE_MINUTE_OF_MICROSECONDS 60000000.0 - -// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the -// given acceleration: -inline long estimate_acceleration_distance(long initial_rate, long target_rate, long acceleration) { - return( - (target_rate*target_rate-initial_rate*initial_rate)/ - (2L*acceleration) - ); -} - -// This function gives you the point at which you must start braking (at the rate of -acceleration) if -// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after -// a total travel of distance. This can be used to compute the intersection point between acceleration and -// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) - -inline long intersection_distance(long initial_rate, long final_rate, long acceleration, long distance) { - return( - (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ - (4*acceleration) - ); -} - -// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. - -void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { - if(block->busy == true) return; // If block is busy then bail out. - float entry_factor = entry_speed / block->nominal_speed; - float exit_factor = exit_speed / block->nominal_speed; - long initial_rate = ceil(block->nominal_rate*entry_factor); - long final_rate = ceil(block->nominal_rate*exit_factor); - -#ifdef ADVANCE - long initial_advance = block->advance*entry_factor*entry_factor; - long final_advance = block->advance*exit_factor*exit_factor; -#endif // ADVANCE - - // Limit minimal step rate (Otherwise the timer will overflow.) - if(initial_rate <120) initial_rate=120; - if(final_rate < 120) final_rate=120; - - // Calculate the acceleration steps - long acceleration = block->acceleration_st; - long accelerate_steps = estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration); - long decelerate_steps = estimate_acceleration_distance(final_rate, block->nominal_rate, acceleration); - // Calculate the size of Plateau of Nominal Rate. - long plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; - - // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will - // have to use intersection_distance() to calculate when to abort acceleration and start braking - // in order to reach the final_rate exactly at the end of this block. - if (plateau_steps < 0) { - accelerate_steps = intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count); - plateau_steps = 0; - } - - long decelerate_after = accelerate_steps+plateau_steps; - long acceleration_rate = (long)((float)acceleration * 8.388608); - - CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section - if(block->busy == false) { // Don't update variables if block is busy. - block->accelerate_until = accelerate_steps; - block->decelerate_after = decelerate_after; - block->acceleration_rate = acceleration_rate; - block->initial_rate = initial_rate; - block->final_rate = final_rate; -#ifdef ADVANCE - block->initial_advance = initial_advance; - block->final_advance = final_advance; -#endif //ADVANCE - } - CRITICAL_SECTION_END; -} - -// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the -// acceleration within the allotted distance. -inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { - return( - sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) - ); -} - -// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks. -// This method will calculate the junction jerk as the euclidean distance between the nominal -// velocities of the respective blocks. -inline float junction_jerk(block_t *before, block_t *after) { - return(sqrt( - pow((before->speed_x-after->speed_x), 2)+ - pow((before->speed_y-after->speed_y), 2))); -} - -// Return the safe speed which is max_jerk/2, e.g. the -// speed under which you cannot exceed max_jerk no matter what you do. -float safe_speed(block_t *block) { - float safe_speed; - safe_speed = max_xy_jerk/2; - if(abs(block->speed_z) > max_z_jerk/2) safe_speed = max_z_jerk/2; - if (safe_speed > block->nominal_speed) safe_speed = block->nominal_speed; - return safe_speed; -} - -// The kernel called by planner_recalculate() when scanning the plan from last to first entry. -void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) { - if(!current) { - return; - } - - float entry_speed = current->nominal_speed; - float exit_factor; - float exit_speed; - if (next) { - exit_speed = next->entry_speed; - } - else { - exit_speed = safe_speed(current); - } - - // Calculate the entry_factor for the current block. - if (previous) { - // Reduce speed so that junction_jerk is within the maximum allowed - float jerk = junction_jerk(previous, current); - if((previous->steps_x == 0) && (previous->steps_y == 0)) { - entry_speed = safe_speed(current); - } - else if (jerk > max_xy_jerk) { - entry_speed = (max_xy_jerk/jerk) * entry_speed; - } - if(abs(previous->speed_z - current->speed_z) > max_z_jerk) { - entry_speed = (max_z_jerk/abs(previous->speed_z - current->speed_z)) * entry_speed; - } - // If the required deceleration across the block is too rapid, reduce the entry_factor accordingly. - if (entry_speed > exit_speed) { - float max_entry_speed = max_allowable_speed(-current->acceleration,exit_speed, current->millimeters); - if (max_entry_speed < entry_speed) { - entry_speed = max_entry_speed; - } - } - } - else { - entry_speed = safe_speed(current); - } - // Store result - current->entry_speed = entry_speed; -} - -// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This -// implements the reverse pass. -void planner_reverse_pass() { - char block_index = block_buffer_head; - block_t *block[3] = { - NULL, NULL, NULL }; - while(block_index != block_buffer_tail) { - block[2]= block[1]; - block[1]= block[0]; - block[0] = &block_buffer[block_index]; - planner_reverse_pass_kernel(block[0], block[1], block[2]); - block_index--; - if(block_index < 0) { - block_index = BLOCK_BUFFER_SIZE-1; - } - } -// planner_reverse_pass_kernel(NULL, block[0], block[1]); -} - -// The kernel called by planner_recalculate() when scanning the plan from first to last entry. -void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) { - if(!current) { - return; - } - if(previous) { - // If the previous block is an acceleration block, but it is not long enough to - // complete the full speed change within the block, we need to adjust out entry - // speed accordingly. Remember current->entry_factor equals the exit factor of - // the previous block. - if(previous->entry_speed < current->entry_speed) { - float max_entry_speed = max_allowable_speed(-previous->acceleration, previous->entry_speed, previous->millimeters); - if (max_entry_speed < current->entry_speed) { - current->entry_speed = max_entry_speed; - } - } - } -} - -// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This -// implements the forward pass. -void planner_forward_pass() { - char block_index = block_buffer_tail; - block_t *block[3] = { - NULL, NULL, NULL }; - - while(block_index != block_buffer_head) { - block[0] = block[1]; - block[1] = block[2]; - block[2] = &block_buffer[block_index]; - planner_forward_pass_kernel(block[0],block[1],block[2]); - block_index = (block_index+1) %BLOCK_BUFFER_SIZE; - } - planner_forward_pass_kernel(block[1], block[2], NULL); -} - -// Recalculates the trapezoid speed profiles for all blocks in the plan according to the -// entry_factor for each junction. Must be called by planner_recalculate() after -// updating the blocks. -void planner_recalculate_trapezoids() { - char block_index = block_buffer_tail; - block_t *current; - block_t *next = NULL; - while(block_index != block_buffer_head) { - current = next; - next = &block_buffer[block_index]; - if (current) { - calculate_trapezoid_for_block(current, current->entry_speed, next->entry_speed); - } - block_index = (block_index+1) %BLOCK_BUFFER_SIZE; - } - calculate_trapezoid_for_block(next, next->entry_speed, safe_speed(next)); -} - -// Recalculates the motion plan according to the following algorithm: -// -// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) -// so that: -// a. The junction jerk is within the set limit -// b. No speed reduction within one block requires faster deceleration than the one, true constant -// acceleration. -// 2. Go over every block in chronological order and dial down junction speed reduction values if -// a. The speed increase within one block would require faster accelleration than the one, true -// constant acceleration. -// -// When these stages are complete all blocks have an entry_factor that will allow all speed changes to -// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than -// the set limit. Finally it will: -// -// 3. Recalculate trapezoids for all blocks. - -void planner_recalculate() { - planner_reverse_pass(); - planner_forward_pass(); - planner_recalculate_trapezoids(); -} - -void plan_init() { - block_buffer_head = 0; - block_buffer_tail = 0; - memset(position, 0, sizeof(position)); // clear position -} - - -inline void plan_discard_current_block() { - if (block_buffer_head != block_buffer_tail) { - block_buffer_tail = (block_buffer_tail + 1) %BLOCK_BUFFER_SIZE; - } -} - -inline block_t *plan_get_current_block() { - if (block_buffer_head == block_buffer_tail) { - return(NULL); - } - block_t *block = &block_buffer[block_buffer_tail]; - block->busy = true; - return(block); -} - -void check_axes_activity() { - unsigned char x_active = 0; - unsigned char y_active = 0; - unsigned char z_active = 0; - unsigned char e_active = 0; - block_t *block; - - if(block_buffer_tail != block_buffer_head) { - char block_index = block_buffer_tail; - while(block_index != block_buffer_head) { - block = &block_buffer[block_index]; - if(block->steps_x != 0) x_active++; - if(block->steps_y != 0) y_active++; - if(block->steps_z != 0) z_active++; - if(block->steps_e != 0) e_active++; - block_index = (block_index+1) %BLOCK_BUFFER_SIZE; - } - } - if((DISABLE_X) && (x_active == 0)) disable_x(); - if((DISABLE_Y) && (y_active == 0)) disable_y(); - if((DISABLE_Z) && (z_active == 0)) disable_z(); - if((DISABLE_E) && (e_active == 0)) disable_e(); -} - -// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in -// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration -// calculation the caller must also provide the physical length of the line in millimeters. -void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { - - // The target position of the tool in absolute steps - // Calculate target position in absolute steps - long target[4]; - target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); - target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); - target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); - target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); - - // Calculate the buffer head after we push this byte - int next_buffer_head = (block_buffer_head + 1) %BLOCK_BUFFER_SIZE; - - // If the buffer is full: good! That means we are well ahead of the robot. - // Rest here until there is room in the buffer. - while(block_buffer_tail == next_buffer_head) { - manage_heater(); - manage_inactivity(1); - } - - // Prepare to set up new block - block_t *block = &block_buffer[block_buffer_head]; - - // Mark block as not busy (Not executed by the stepper interrupt) - block->busy = false; - - // Number of steps for each axis - block->steps_x = labs(target[X_AXIS]-position[X_AXIS]); - block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]); - block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); - block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); - block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); - - // Bail if this is a zero-length block - if (block->step_event_count == 0) { - return; - }; - - //enable active axes - if(block->steps_x != 0) enable_x(); - if(block->steps_y != 0) enable_y(); - if(block->steps_z != 0) enable_z(); - if(block->steps_e != 0) enable_e(); - - float delta_x_mm = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; - float delta_y_mm = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; - float delta_z_mm = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; - float delta_e_mm = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS]; - block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); - - unsigned long microseconds; - microseconds = lround((block->millimeters/feed_rate)*1000000); - - // added by lampmaker to slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill - // reduces/removes corner blobs as the machine won't come to a full stop. - int blockcount=block_buffer_head-block_buffer_tail; - //blockcount=8; - while(blockcount<0) blockcount+=BLOCK_BUFFER_SIZE; - if ((blockcount<=2)&&(microseconds<(MIN_SEGMENT_TIME))) microseconds=MIN_SEGMENT_TIME; - else if ((blockcount<=4)&&(microseconds<(MIN_SEGMENT_TIME/2))) microseconds=MIN_SEGMENT_TIME/2; - else if ((blockcount<=8)&&(microseconds<(MIN_SEGMENT_TIME/5))) microseconds=MIN_SEGMENT_TIME/5; - - // Calculate speed in mm/minute for each axis - float multiplier = 60.0*1000000.0/microseconds; - block->speed_z = delta_z_mm * multiplier; - block->speed_x = delta_x_mm * multiplier; - block->speed_y = delta_y_mm * multiplier; - block->speed_e = delta_e_mm * multiplier; - - // Limit speed per axis - float speed_factor = 1; - float tmp_speed_factor; - if(abs(block->speed_x) > max_feedrate[X_AXIS]) { - //// [ErikDeBruijn] IS THIS THE BUG WE'RE LOOING FOR???? - // it used to be just this line: speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); - tmp_speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ - tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ - tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - if(abs(block->speed_e) > max_feedrate[E_AXIS]){ - tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; - } - multiplier = multiplier * speed_factor; - block->speed_z = delta_z_mm * multiplier; - block->speed_x = delta_x_mm * multiplier; - block->speed_y = delta_y_mm * multiplier; - block->speed_e = delta_e_mm * multiplier; - block->nominal_speed = block->millimeters * multiplier; - block->nominal_rate = ceil(block->step_event_count * multiplier / 60); - - if(block->nominal_rate < 120) block->nominal_rate = 120; - block->entry_speed = safe_speed(block); - - // Compute the acceleration rate for the trapezoid generator. - float travel_per_step = block->millimeters/block->step_event_count; - if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { - block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 - } - else { - block->acceleration_st = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 - // Limit acceleration per axis - if((block->acceleration_st * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) - block->acceleration_st = axis_steps_per_sqr_second[X_AXIS]; - if((block->acceleration_st * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) - block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS]; - if((block->acceleration_st * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) - block->acceleration_st = axis_steps_per_sqr_second[E_AXIS]; - if(((block->acceleration_st / block->step_event_count) * block->steps_z ) > axis_steps_per_sqr_second[Z_AXIS]) - block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS]; - } - block->acceleration = block->acceleration_st * travel_per_step; - -#ifdef ADVANCE - // Calculate advance rate - if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { - block->advance_rate = 0; - block->advance = 0; - } - else { - long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st); - float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * - (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; - block->advance = advance; - if(acc_dist == 0) { - block->advance_rate = 0; - } - else { - block->advance_rate = advance / (float)acc_dist; - } - } - -#endif // ADVANCE - - // compute a preliminary conservative acceleration trapezoid - float safespeed = safe_speed(block); - calculate_trapezoid_for_block(block, safespeed, safespeed); - - // Compute direction bits for this block - block->direction_bits = 0; - if (target[X_AXIS] < position[X_AXIS]) { - block->direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<> 16 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 24 bit result -#define MultiU16X8toH16(intRes, charIn1, intIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %A1, %A2 \n\t" \ -"add %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r0 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (charIn1), \ -"d" (intIn2) \ -: \ -"r26" \ -) - -// intRes = longIn1 * longIn2 >> 24 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 48bit result -#define MultiU24X24toH16(intRes, longIn1, longIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"mov r27, r1 \n\t" \ -"mul %B1, %C2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %C1, %C2 \n\t" \ -"add %B0, r0 \n\t" \ -"mul %C1, %B2 \n\t" \ -"add %A0, r0 \n\t" \ -"adc %B0, r1 \n\t" \ -"mul %A1, %C2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %B2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %C1, %A2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %A2 \n\t" \ -"add r27, r1 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r27 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (longIn1), \ -"d" (longIn2) \ -: \ -"r26" , "r27" \ -) - -// Some useful constants - -#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1< -// -// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates -// first block->accelerate_until step_events_completed, then keeps going at constant speed until -// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. -// The slope of acceleration is calculated with the leib ramp alghorithm. - -void st_wake_up() { - // TCNT1 = 0; - ENABLE_STEPPER_DRIVER_INTERRUPT(); -} - -inline unsigned short calc_timer(unsigned short step_rate) { - unsigned short timer; - if(step_rate < 32) step_rate = 32; - step_rate -= 32; // Correct for minimal speed - if(step_rate >= (8*256)){ // higher step rate - unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; - unsigned char tmp_step_rate = (step_rate & 0x00ff); - unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); - MultiU16X8toH16(timer, tmp_step_rate, gain); - timer = (unsigned short)pgm_read_word_near(table_address) - timer; - } - else { // lower step rates - unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; - table_address += ((step_rate)>>1) & 0xfffc; - timer = (unsigned short)pgm_read_word_near(table_address); - timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); - } - if(timer < 100) timer = 100; - return timer; -} - -// Initializes the trapezoid generator from the current block. Called whenever a new -// block begins. -inline void trapezoid_generator_reset() { - accelerate_until = current_block->accelerate_until; - decelerate_after = current_block->decelerate_after; - acceleration_rate = current_block->acceleration_rate; - initial_rate = current_block->initial_rate; - final_rate = current_block->final_rate; - nominal_rate = current_block->nominal_rate; - advance = current_block->initial_advance; - final_advance = current_block->final_advance; - deceleration_time = 0; - advance_rate = current_block->advance_rate; - // step_rate to timer interval - acc_step_rate = initial_rate; - acceleration_time = calc_timer(acc_step_rate); - OCR1A = acceleration_time; -} - -// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. -// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. -ISR(TIMER1_COMPA_vect) -{ - if(busy){ /*Serial.println("BUSY")*/; - return; - } // The busy-flag is used to avoid reentering this interrupt - - busy = true; - sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) -#ifdef FANCY_LCD - static int breakdown=0; - if((breakdown++)%100==0) - buttons_check(); -/* [ErikDeBruijn] Perhaps it would be nice to use a piece of code like this (adapted from process_g_code), to create a nice progress bar! - if(sdactive){ - sprintf("SD printing byte %i%",(int) (sdpos/filesize*100)); // perhaps a fraction of a percent is also nice, 0.03%, progress bar even better. - Serial.print(sdpos); - Serial.print("/"); - Serial.println(filesize); - } -*/ -#endif - - // If there is no current block, attempt to pop one from the buffer - if (current_block == NULL) { - // Anything in the buffer? - current_block = plan_get_current_block(); - if (current_block != NULL) { - trapezoid_generator_reset(); - counter_x = -(current_block->step_event_count >> 1); - counter_y = counter_x; - counter_z = counter_x; - counter_e = counter_x; - step_events_completed = 0; - e_steps = 0; - } - else { - DISABLE_STEPPER_DRIVER_INTERRUPT(); - } - } - - if (current_block != NULL) { - // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt - out_bits = current_block->direction_bits; - -#ifdef ADVANCE - // Calculate E early. - counter_e += current_block->steps_e; - if (counter_e > 0) { - counter_e -= current_block->step_event_count; - if ((out_bits & (1<> 16) - old_advance); - CRITICAL_SECTION_END; - old_advance = advance >> 16; -#endif //ADVANCE - - // Set direction en check limit switches -if ((out_bits & (1<step_event_count; - } - } - else { // +direction - WRITE(X_DIR_PIN,!INVERT_X_DIR); - #ifdef DEBUG_STEPS - count_direction[X_AXIS]=1; - #endif - if((READ(X_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_x >0)){ - step_events_completed = current_block->step_event_count; - } - } - - if ((out_bits & (1<step_event_count; - } - } - else { // +direction - WRITE(Y_DIR_PIN,!INVERT_Y_DIR); - #ifdef DEBUG_STEPS - count_direction[Y_AXIS]=1; - #endif - if((READ(Y_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_y >0)){ - step_events_completed = current_block->step_event_count; - } - } - - if ((out_bits & (1<step_event_count; - } - } - else { // +direction - WRITE(Z_DIR_PIN,!INVERT_Z_DIR); - #ifdef DEBUG_STEPS - count_direction[Z_AXIS]=1; - #endif - if((READ(Z_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_z >0)){ - step_events_completed = current_block->step_event_count; - } - } - -#ifndef ADVANCE - if ((out_bits & (1<steps_x; - if (counter_x > 0) { - WRITE(X_STEP_PIN, HIGH); - counter_x -= current_block->step_event_count; - WRITE(X_STEP_PIN, LOW); - #ifdef DEBUG_STEPS - count_position[X_AXIS]+=count_direction[X_AXIS]; - #endif - } - - counter_y += current_block->steps_y; - if (counter_y > 0) { - WRITE(Y_STEP_PIN, HIGH); - counter_y -= current_block->step_event_count; - WRITE(Y_STEP_PIN, LOW); - #ifdef DEBUG_STEPS - count_position[Y_AXIS]+=count_direction[Y_AXIS]; - #endif - } - - counter_z += current_block->steps_z; - if (counter_z > 0) { - WRITE(Z_STEP_PIN, HIGH); - counter_z -= current_block->step_event_count; - WRITE(Z_STEP_PIN, LOW); - #ifdef DEBUG_STEPS - count_position[Z_AXIS]+=count_direction[Z_AXIS]; - #endif - } - -#ifndef ADVANCE - counter_e += current_block->steps_e; - if (counter_e > 0) { - WRITE(E_STEP_PIN, HIGH); - counter_e -= current_block->step_event_count; - WRITE(E_STEP_PIN, LOW); - } -#endif //!ADVANCE - - // Calculare new timer value - unsigned short timer; - unsigned short step_rate; - if (step_events_completed < accelerate_until) { - MultiU24X24toH16(acc_step_rate, acceleration_time, acceleration_rate); - acc_step_rate += initial_rate; - - // upper limit - if(acc_step_rate > nominal_rate) - acc_step_rate = nominal_rate; - - // step_rate to timer interval - timer = calc_timer(acc_step_rate); - advance += advance_rate; - acceleration_time += timer; - OCR1A = timer; - } - else if (step_events_completed >= decelerate_after) { - MultiU24X24toH16(step_rate, deceleration_time, acceleration_rate); - - if(step_rate > acc_step_rate) { // Check step_rate stays positive - step_rate = final_rate; - } - else { - step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. - } - - // lower limit - if(step_rate < final_rate) - step_rate = final_rate; - - // step_rate to timer interval - timer = calc_timer(step_rate); -#ifdef ADVANCE - advance -= advance_rate; - if(advance < final_advance) - advance = final_advance; -#endif //ADVANCE - deceleration_time += timer; - OCR1A = timer; - } - // If current block is finished, reset pointer - step_events_completed += 1; - if (step_events_completed >= current_block->step_event_count) { - current_block = NULL; - plan_discard_current_block(); - } - } - busy=false; -} - -#ifdef ADVANCE - -unsigned char old_OCR0A; -// Timer interrupt for E. e_steps is set in the main routine; -// Timer 0 is shared with millies -ISR(TIMER0_COMPA_vect) -{ - // Critical section needed because Timer 1 interrupt has higher priority. - // The pin set functions are placed on trategic position to comply with the stepper driver timing. - WRITE(E_STEP_PIN, LOW); - // Set E direction (Depends on E direction + advance) - if (e_steps < 0) { - WRITE(E_DIR_PIN,INVERT_E_DIR); - e_steps++; - WRITE(E_STEP_PIN, HIGH); - } - if (e_steps > 0) { - WRITE(E_DIR_PIN,!INVERT_E_DIR); - e_steps--; - WRITE(E_STEP_PIN, HIGH); - } - old_OCR0A += 25; // 10kHz interrupt - OCR0A = old_OCR0A; -} -#endif // ADVANCE - -void st_init() -{ - // waveform generation = 0100 = CTC - TCCR1B &= ~(1<= 16) - { - current_raw = 16383 - raw_temp_value; - temp_meas_ready = true; - temp_count = 0; - raw_temp_value = 0; -#ifdef MAXTEMP - if(current_raw >= maxttemp) { - target_raw = 0; -#ifdef PIDTEMP - OCR2B = 0; -#else - WRITE(HEATER_0_PIN,LOW); -#endif //PIDTEMP - } -#endif //MAXTEMP -#ifdef MINTEMP - if(current_raw <= minttemp) { - target_raw = 0; -#ifdef PIDTEMP - OCR2B = 0; -#else - WRITE(HEATER_0_PIN,LOW); -#endif //PIDTEMP - } -#endif //MAXTEMP -#ifndef PIDTEMP - if(current_raw >= target_raw) - { - WRITE(HEATER_0_PIN,LOW); - } - else - { - WRITE(HEATER_0_PIN,HIGH); - } -#endif //PIDTEMP - } -} - -*/ +#include "Marlin.h" +// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in +// the source g-code and may never actually be reached if acceleration management is active. + +//#define DEBUG_STEPS + + +#include "speed_lookuptable.h" + +/* + Reprap firmware based on Sprinter and grbl. + Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + + This program 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. + + This program 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 this program. If not, see . + */ + +/* + This firmware is a mashup between Sprinter and grbl. + (https://github.com/kliment/Sprinter) + (https://github.com/simen/grbl/tree) + + It has preliminary support for Matthew Roberts advance algorithm + http://reprap.org/pipermail/reprap-dev/2011-May/003323.html + + This firmware is optimized for gen6 electronics. + */ + + + +#include "fastio.h" +#include "Configuration.h" +#include "pins.h" +#include "Marlin.h" +#include "speed_lookuptable.h" +#include "lcd.h" + +char version_string[] = "U0.9.3.3-BK"; + +#ifdef SDSUPPORT +#include "SdFat.h" +#endif //SDSUPPORT + +#ifndef CRITICAL_SECTION_START +#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() +#define CRITICAL_SECTION_END SREG = _sreg +#endif //CRITICAL_SECTION_START + + +#if defined SDSUPPORT || defined FANCY_LCD +// The number of linear motions that can be in the plan at any give time. + #define BLOCK_BUFFER_SIZE 16 // SD,LCD,Buttons take more memory, block buffer needs to be smaller +#else + #define BLOCK_BUFFER_SIZE 40 // maximize block buffer +#endif + +#ifdef SIMPLE_LCD + #define BLOCK_BUFFER_SIZE 32 // A little less buffer for just a simple LCD +#endif + +// if DEBUG_STEPS is enabled, M114 can be used to compare two methods of determining the X,Y,Z position of the printer. +// for debugging purposes only, should be disabled by default +#ifdef DEBUG_STEPS +volatile long count_position[NUM_AXIS] = { 0, 0, 0, 0}; +volatile int count_direction[NUM_AXIS] = { 1, 1, 1, 1}; +#endif +// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html +// 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 +// G28 - Home all 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 +// 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 +// M115 - Capabilities string +// 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) +// M301 - Set PID parameters P I and D + +//Stepper Movement Variables + +char axis_codes[NUM_AXIS] = { + 'X', 'Y', 'Z', 'E'}; +float destination[NUM_AXIS] = { + 0.0, 0.0, 0.0, 0.0}; +float current_position[NUM_AXIS] = { + 0.0, 0.0, 0.0, 0.0}; +bool home_all_axis = true; +long feedrate = 1500, next_feedrate, saved_feedrate; +long gcode_N, gcode_LastN; +unsigned long previous_millis_heater, previous_millis_bed_heater; +bool relative_mode = false; //Determines Absolute or Relative Coordinates +bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. +unsigned long axis_steps_per_sqr_second[NUM_AXIS]; + +volatile int feedmultiply=100; //100->1 200->2 +// comm variables +#define MAX_CMD_SIZE 96 +#define BUFSIZE 8 +char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; +bool fromsd[BUFSIZE]; +int bufindr = 0; +int bufindw = 0; +int buflen = 0; +int i = 0; +char serial_char; +int serial_count = 0; +boolean comment_mode = false; +char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc + +// Manage heater variables. + +int target_bed_raw = 0; +int current_bed_raw = 0; + +int target_raw = 0; +int current_raw = 0; +unsigned char temp_meas_ready = false; + +#ifdef PIDTEMP + double temp_iState = 0; + double temp_dState = 0; + double pTerm; + double iTerm; + double dTerm; + //int output; + double pid_error; + double temp_iState_min; + double temp_iState_max; + double pid_setpoint = 0.0; + double pid_input; + double pid_output; + bool pid_reset; +#endif //PIDTEMP +float tt = 0, bt = 0; +#ifdef WATCHPERIOD +int watch_raw = -1000; +unsigned long watchmillis = 0; +#endif //WATCHPERIOD +#ifdef MINTEMP +int minttemp = temp2analog(MINTEMP); +#endif //MINTEMP +#ifdef MAXTEMP +int maxttemp = temp2analog(MAXTEMP); +#endif //MAXTEMP + +//Inactivity shutdown variables +unsigned long previous_millis_cmd = 0; +unsigned long max_inactive_time = 0; +unsigned long stepper_inactive_time = 0; + +unsigned long starttime=0; +unsigned long stoptime=0; +#ifdef SDSUPPORT +Sd2Card card; +SdVolume volume; +SdFile root; +SdFile file; +uint32_t filesize = 0; +uint32_t sdpos = 0; +bool sdmode = false; +bool sdactive = false; +bool savetosd = false; +int16_t n; + +void initsd(){ + sdactive = false; +#if SDSS >- 1 + if(root.isOpen()) + root.close(); + if (!card.init(SPI_FULL_SPEED,SDSS)){ + //if (!card.init(SPI_HALF_SPEED,SDSS)) + Serial.println("SD init fail"); + } + else if (!volume.init(&card)) + Serial.println("volume.init failed"); + else if (!root.openRoot(&volume)) + Serial.println("openRoot failed"); + else + sdactive = true; +#endif //SDSS +} + +inline void write_command(char *buf){ + char* begin = buf; + char* npos = 0; + char* end = buf + strlen(buf) - 1; + + file.writeError = false; + if((npos = strchr(buf, 'N')) != NULL){ + begin = strchr(npos, ' ') + 1; + end = strchr(npos, '*') - 1; + } + end[1] = '\r'; + end[2] = '\n'; + end[3] = '\0'; + //Serial.println(begin); + file.write(begin); + if (file.writeError){ + Serial.println("error writing to file"); + } +} +#endif //SDSUPPORT + +void setup() +{ + + Serial.begin(BAUDRATE); + Serial.print("Marlin "); + Serial.println(version_string); + Serial.println("start"); +#if defined FANCY_LCD || defined SIMPLE_LCD + lcd_init(); +#endif + for(int i = 0; i < BUFSIZE; i++){ + fromsd[i] = false; + } + + + //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 +#if E_DIR_PIN > -1 + SET_OUTPUT(E_DIR_PIN); +#endif + + //Initialize Enable Pins - steppers default to disabled. + +#if (X_ENABLE_PIN > -1) + SET_OUTPUT(X_ENABLE_PIN); + if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); +#endif +#if (Y_ENABLE_PIN > -1) + SET_OUTPUT(Y_ENABLE_PIN); + if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); +#endif +#if (Z_ENABLE_PIN > -1) + SET_OUTPUT(Z_ENABLE_PIN); + if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); +#endif +#if (E_ENABLE_PIN > -1) + SET_OUTPUT(E_ENABLE_PIN); + if(!E_ENABLE_ON) WRITE(E_ENABLE_PIN,HIGH); +#endif + + //endstops and pullups +#ifdef ENDSTOPPULLUPS +#if X_MIN_PIN > -1 + SET_INPUT(X_MIN_PIN); + WRITE(X_MIN_PIN,HIGH); +#endif +#if X_MAX_PIN > -1 + SET_INPUT(X_MAX_PIN); + WRITE(X_MAX_PIN,HIGH); +#endif +#if Y_MIN_PIN > -1 + SET_INPUT(Y_MIN_PIN); + WRITE(Y_MIN_PIN,HIGH); +#endif +#if Y_MAX_PIN > -1 + SET_INPUT(Y_MAX_PIN); + WRITE(Y_MAX_PIN,HIGH); +#endif +#if Z_MIN_PIN > -1 + SET_INPUT(Z_MIN_PIN); + WRITE(Z_MIN_PIN,HIGH); +#endif +#if Z_MAX_PIN > -1 + SET_INPUT(Z_MAX_PIN); + WRITE(Z_MAX_PIN,HIGH); +#endif +#else //ENDSTOPPULLUPS +#if X_MIN_PIN > -1 + SET_INPUT(X_MIN_PIN); +#endif +#if X_MAX_PIN > -1 + SET_INPUT(X_MAX_PIN); +#endif +#if Y_MIN_PIN > -1 + SET_INPUT(Y_MIN_PIN); +#endif +#if Y_MAX_PIN > -1 + SET_INPUT(Y_MAX_PIN); +#endif +#if Z_MIN_PIN > -1 + SET_INPUT(Z_MIN_PIN); +#endif +#if Z_MAX_PIN > -1 + SET_INPUT(Z_MAX_PIN); +#endif +#endif //ENDSTOPPULLUPS + +#if (HEATER_0_PIN > -1) + SET_OUTPUT(HEATER_0_PIN); +#endif +#if (HEATER_1_PIN > -1) + SET_OUTPUT(HEATER_1_PIN); +#endif + + //Initialize Step Pins +#if (X_STEP_PIN > -1) + SET_OUTPUT(X_STEP_PIN); +#endif +#if (Y_STEP_PIN > -1) + SET_OUTPUT(Y_STEP_PIN); +#endif +#if (Z_STEP_PIN > -1) + SET_OUTPUT(Z_STEP_PIN); +#endif +#if (E_STEP_PIN > -1) + SET_OUTPUT(E_STEP_PIN); +#endif + for(int i=0; i < NUM_AXIS; i++){ + axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; + } + +#ifdef PIDTEMP + temp_iState_min = 0.0; + temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; +#endif //PIDTEMP + +#ifdef SDSUPPORT + //power to SD reader +#if SDPOWER > -1 + SET_OUTPUT(SDPOWER); + WRITE(SDPOWER,HIGH); +#endif //SDPOWER + initsd(); + +#endif //SDSUPPORT + plan_init(); // Initialize planner; + st_init(); // Initialize stepper; +// tp_init(); // Initialize temperature loop + checkautostart(); +} + +#ifdef SDSUPPORT +void checkautostart() +{ + if(!sdactive) + return; + static int lastnr=0; + char autoname[30]; + sprintf(autoname,"auto%i.g",lastnr); + for(int i=0;i 0) + { + for(int i=0;i 0 && buflen < BUFSIZE) { + serial_char = Serial.read(); + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) + { + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = false; + if(strstr(cmdbuffer[bufindw], "N") != NULL) + { + strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); + gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); + if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { + Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); + Serial.println(gcode_LastN); + //Serial.println(gcode_N); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + if(strstr(cmdbuffer[bufindw], "*") != NULL) + { + byte checksum = 0; + byte count = 0; + while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; + strchr_pointer = strchr(cmdbuffer[bufindw], '*'); + + if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { + Serial.print("Error: checksum mismatch, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + //if no errors, continue parsing + } + else + { + Serial.print("Error: No Checksum with line number, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + gcode_LastN = gcode_N; + //if no errors, continue parsing + } + else // if we don't receive 'N' but still see '*' + { + if((strstr(cmdbuffer[bufindw], "*") != NULL)) + { + Serial.print("Error: No Line Number with checksum, Last Line:"); + Serial.println(gcode_LastN); + serial_count = 0; + return; + } + } + if((strstr(cmdbuffer[bufindw], "G") != NULL)){ + strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); + switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ + case 0: + case 1: +#ifdef SDSUPPORT + if(savetosd) + break; +#endif //SDSUPPORT + Serial.println("ok"); + break; + default: + break; + } + + } + bufindw = (bufindw + 1)%BUFSIZE; + buflen += 1; + + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } + } +#ifdef SDSUPPORT + if(!sdmode || serial_count!=0){ + return; + } + while( filesize > sdpos && buflen < BUFSIZE) { + n = file.read(); + serial_char = (char)n; + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) + { + sdpos = file.curPosition(); + if(sdpos >= filesize){ + sdmode = false; + Serial.println("Done printing file"); + stoptime=millis(); + char time[30]; + unsigned long t=(stoptime-starttime)/1000; + int sec,min; + min=t/60; + sec=t%60; + sprintf(time,"%i min, %i sec",min,sec); + Serial.println(time); + LCD_MESSAGE(time); + checkautostart(); + } + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = true; + buflen += 1; + bufindw = (bufindw + 1)%BUFSIZE; + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } + } +#endif //SDSUPPORT + +} + + +inline float code_value() { + return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); +} +inline long code_value_long() { + return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); +} +inline bool code_seen(char code_string[]) { + return (strstr(cmdbuffer[bufindr], code_string) != NULL); +} //Return True if the string was found + +inline bool code_seen(char code) +{ + strchr_pointer = strchr(cmdbuffer[bufindr], code); + return (strchr_pointer != NULL); //Return True if a character was found +} + +inline void process_commands() +{ + unsigned long codenum; //throw away variable + char *starpos = NULL; + + if(code_seen('G')) + { + switch((int)code_value()) + { + case 0: // G0 -> G1 + case 1: // G1 + get_coordinates(); // For X Y Z E F + prepare_move(); + previous_millis_cmd = millis(); + //ClearToSend(); + return; + //break; + case 4: // G4 dwell + codenum = 0; + if(code_seen('P')) codenum = code_value(); // milliseconds to wait + if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait + codenum += millis(); // keep track of when we started waiting + while(millis() < codenum ){ + manage_heater(); + } + break; + case 28: //G28 Home all Axis one at a time + saved_feedrate = feedrate; + for(int i=0; i < NUM_AXIS; i++) { + destination[i] = current_position[i]; + } + feedrate = 0; + + home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); + + if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) { + if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){ + st_synchronize(); + current_position[X_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; + feedrate = homing_feedrate[X_AXIS]; + prepare_move(); + + st_synchronize(); + current_position[X_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = -5 * X_HOME_DIR; + prepare_move(); + + st_synchronize(); + destination[X_AXIS] = 10 * X_HOME_DIR; + feedrate = homing_feedrate[X_AXIS]/2 ; + prepare_move(); + st_synchronize(); + + current_position[X_AXIS] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = current_position[X_AXIS]; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { + if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){ + current_position[Y_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; + feedrate = homing_feedrate[Y_AXIS]; + prepare_move(); + st_synchronize(); + + current_position[Y_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = -5 * Y_HOME_DIR; + prepare_move(); + st_synchronize(); + + destination[Y_AXIS] = 10 * Y_HOME_DIR; + feedrate = homing_feedrate[Y_AXIS]/2; + prepare_move(); + st_synchronize(); + + current_position[Y_AXIS] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = current_position[Y_AXIS]; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { + if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){ + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; + feedrate = homing_feedrate[Z_AXIS]; + prepare_move(); + st_synchronize(); + + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = -2 * Z_HOME_DIR; + prepare_move(); + st_synchronize(); + + destination[Z_AXIS] = 3 * Z_HOME_DIR; + feedrate = homing_feedrate[Z_AXIS]/2; + prepare_move(); + st_synchronize(); + + current_position[Z_AXIS] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = current_position[Z_AXIS]; + feedrate = 0; + } + } + feedrate = saved_feedrate; + previous_millis_cmd = millis(); + break; + case 90: // G90 + relative_mode = false; + break; + case 91: // G91 + relative_mode = true; + break; + case 92: // G92 + if(!code_seen(axis_codes[E_AXIS])) + st_synchronize(); + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) current_position[i] = code_value(); + } + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + break; + + } + } + + else if(code_seen('M')) + { + + switch( (int)code_value() ) + { +#ifdef SDSUPPORT + + case 20: // M20 - list SD card + Serial.println("Begin file list"); + root.ls(); + Serial.println("End file list"); + break; + case 21: // M21 - init SD card + sdmode = false; + initsd(); + break; + case 22: //M22 - release SD card + sdmode = false; + sdactive = false; + break; + case 23: //M23 - Select file + if(sdactive){ + sdmode = false; + file.close(); + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos!=NULL) + *(starpos-1)='\0'; + if (file.open(&root, strchr_pointer + 4, O_READ)) { + Serial.print("File opened:"); + Serial.print(strchr_pointer + 4); + Serial.print(" Size:"); + Serial.println(file.fileSize()); + sdpos = 0; + filesize = file.fileSize(); + Serial.println("File selected"); + } + else{ + Serial.println("file.open failed"); + } + } + break; + case 24: //M24 - Start SD print + if(sdactive){ + sdmode = true; + starttime=millis(); + } + break; + case 25: //M25 - Pause SD print + if(sdmode){ + sdmode = false; + } + break; + case 26: //M26 - Set SD index + if(sdactive && code_seen('S')){ + sdpos = code_value_long(); + file.seekSet(sdpos); + } + break; + case 27: //M27 - Get SD status + if(sdactive){ + Serial.print("SD printing byte "); + Serial.print(sdpos); + Serial.print("/"); + Serial.println(filesize); + } + else{ + Serial.println("Not SD printing"); + } + break; + case 28: //M28 - Start SD write + if(sdactive){ + char* npos = 0; + file.close(); + sdmode = false; + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos != NULL){ + npos = strchr(cmdbuffer[bufindr], 'N'); + strchr_pointer = strchr(npos,' ') + 1; + *(starpos-1) = '\0'; + } + if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) + { + Serial.print("open failed, File: "); + Serial.print(strchr_pointer + 4); + Serial.print("."); + } + else{ + savetosd = true; + Serial.print("Writing to file: "); + Serial.println(strchr_pointer + 4); + } + } + break; + case 29: //M29 - Stop SD write + //processed in write to file routine above + //savetosd = false; + break; + case 30: + { + stoptime=millis(); + char time[30]; + unsigned long t=(stoptime-starttime)/1000; + int sec,min; + min=t/60; + sec=t%60; + sprintf(time,"%i min, %i sec",min,sec); + Serial.println(time); + LCD_MESSAGE(time); + } + break; +#endif //SDSUPPORT + case 104: // M104 + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw > current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + break; + case 140: // M140 set bed temp + if (code_seen('S')) target_bed_raw = temp2analogBed(code_value()); + break; + case 105: // M105 + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) + tt = analog2temp(current_raw); + #endif + #if TEMP_1_PIN > -1 + bt = analog2tempBed(current_bed_raw); + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) + Serial.print("ok T:"); + Serial.print(tt); + Serial.print(", raw:"); + Serial.print(current_raw); + #if TEMP_1_PIN > -1 + Serial.print(" B:"); + Serial.println(bt); + #else + Serial.println(); + #endif + #else + Serial.println("No thermistors - no temp"); + #endif + return; + //break; + case 109: // M109 - Wait for extruder heater to reach target. + LCD_MESSAGE("Heating..."); + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw>current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + codenum = millis(); + starttime=millis(); + while(current_raw < target_raw) { + if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + Serial.print("T:"); + Serial.println( analog2temp(current_raw) ); + + codenum = millis(); + } + LCD_STATUS; + manage_heater(); + } + break; + case 190: // M190 - Wait bed for heater to reach target. + #if TEMP_1_PIN > -1 + if (code_seen('S')) target_bed_raw = temp2analog(code_value()); + codenum = millis(); + while(current_bed_raw < target_bed_raw) + { + if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + float tt=analog2temp(current_raw); + Serial.print("T:"); + Serial.println( tt ); + Serial.print("ok T:"); + Serial.print( tt ); + Serial.print(" B:"); + Serial.println( analog2temp(current_bed_raw) ); + codenum = millis(); + } + manage_heater(); + } + #endif + break; + case 106: //M106 Fan On + if (code_seen('S')){ + digitalWrite(FAN_PIN,HIGH); + analogWrite(FAN_PIN, constrain(code_value(),0,255) ); + } + else + { + digitalWrite(FAN_PIN,HIGH); + analogWrite(FAN_PIN, 255); + } + break; + case 107: //M107 Fan Off + digitalWrite(FAN_PIN,LOW); + analogWrite(FAN_PIN, 0); + break; + + case 82: + axis_relative_modes[3] = false; + break; + case 83: + axis_relative_modes[3] = true; + break; + case 18: + case 84: + if(code_seen('S')){ + stepper_inactive_time = code_value() * 1000; + } + else{ + st_synchronize(); + disable_x(); + disable_y(); + disable_z(); + disable_e(); + } + break; + case 85: // M85 + code_seen('S'); + max_inactive_time = code_value() * 1000; + break; + case 92: // M92 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); + } + + break; + case 115: // M115 + Serial.println("FIRMWARE_NAME:Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); + break; + case 114: // M114 + Serial.print("X:"); + Serial.print(current_position[X_AXIS]); + Serial.print("Y:"); + Serial.print(current_position[Y_AXIS]); + Serial.print("Z:"); + Serial.print(current_position[Z_AXIS]); + Serial.print("E:"); + Serial.print(current_position[E_AXIS]); + #ifdef DEBUG_STEPS + Serial.print(" Count X:"); + Serial.print(float(count_position[X_AXIS])/axis_steps_per_unit[X_AXIS]); + Serial.print("Y:"); + Serial.print(float(count_position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]); + Serial.print("Z:"); + Serial.println(float(count_position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]); + #endif + Serial.println(""); + break; + case 119: // M119 +#if (X_MIN_PIN > -1) + Serial.print("x_min:"); + Serial.print((READ(X_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (X_MAX_PIN > -1) + Serial.print("x_max:"); + Serial.print((READ(X_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Y_MIN_PIN > -1) + Serial.print("y_min:"); + Serial.print((READ(Y_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Y_MAX_PIN > -1) + Serial.print("y_max:"); + Serial.print((READ(Y_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Z_MIN_PIN > -1) + Serial.print("z_min:"); + Serial.print((READ(Z_MIN_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif +#if (Z_MAX_PIN > -1) + Serial.print("z_max:"); + Serial.print((READ(Z_MAX_PIN)^ENDSTOPS_INVERTING)?"H ":"L "); +#endif + Serial.println(""); + break; + //TODO: update for all axis, use for loop + case 201: // M201 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; +#if 0 // Not used for Sprinter/grbl gen6 + case 202: // M202 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; +#endif +#ifdef PIDTEMP + case 301: // M301 + if(code_seen('P')) Kp = code_value(); + if(code_seen('I')) Ki = code_value()*PID_dT; + if(code_seen('D')) Kd = code_value()/PID_dT; + Serial.print("Kp ");Serial.println(Kp); + Serial.print("Ki ");Serial.println(Ki/PID_dT); + Serial.print("Kd ");Serial.println(Kd*PID_dT); + temp_iState_min = 0.0; + temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; + break; +#endif //PIDTEMP + } + } + else{ + Serial.println("Unknown command:"); + Serial.println(cmdbuffer[bufindr]); + } + + ClearToSend(); +} + +void FlushSerialRequestResend() +{ + //char cmdbuffer[bufindr][100]="Resend:"; + Serial.flush(); + Serial.print("Resend:"); + Serial.println(gcode_LastN + 1); + ClearToSend(); +} + +void ClearToSend() +{ + previous_millis_cmd = millis(); +#ifdef SDSUPPORT + if(fromsd[bufindr]) + return; +#endif //SDSUPPORT + Serial.println("ok"); +} + +inline void get_coordinates() +{ + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; + else destination[i] = current_position[i]; //Are these else lines really needed? + } + if(code_seen('F')) { + next_feedrate = code_value(); + if(next_feedrate > 0.0) feedrate = next_feedrate; + } +} + +void prepare_move() +{ + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60.0/100.); + for(int i=0; i < NUM_AXIS; i++) { + current_position[i] = destination[i]; + } +} +/* +void manage_heater() +{ + float pid_input; + float pid_output; + if(temp_meas_ready != true) + return; + +CRITICAL_SECTION_START; + temp_meas_ready = false; +CRITICAL_SECTION_END; + +#ifdef PIDTEMP + pid_input = analog2temp(current_raw); + +#ifndef PID_OPENLOOP + pid_error = pid_setpoint - pid_input; + if(pid_error > 10){ + pid_output = PID_MAX; + pid_reset = true; + } + else if(pid_error < -10) { + pid_output = 0; + pid_reset = true; + } + else { + if(pid_reset == true) { + temp_iState = 0.0; + pid_reset = false; + } + pTerm = Kp * pid_error; + temp_iState += pid_error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = Ki * temp_iState; + #define K1 0.8 + #define K2 (1.0-K1) + dTerm = (Kd * (pid_input - temp_dState))*K2 + (K1 * dTerm); + temp_dState = pid_input; + pid_output = constrain(pTerm + iTerm - dTerm, 0, PID_MAX); + } +#endif //PID_OPENLOOP +#ifdef PID_DEBUG + Serial.print(" Input "); + Serial.print(pid_input); + Serial.print(" Output "); + Serial.print(pid_output); + Serial.print(" pTerm "); + Serial.print(pTerm); + Serial.print(" iTerm "); + Serial.print(iTerm); + Serial.print(" dTerm "); + Serial.print(dTerm); + Serial.println(); +#endif //PID_DEBUG + OCR2B = pid_output; +#endif //PIDTEMP +} +*/ + + +/* +int temp2analogu(int celsius, const short table[][2], int numtemps) { + int raw = 0; + byte i; + + for (i=1; i raw) { + celsius = (float)table[i-1][1] + + (float)(raw - table[i-1][0]) * + (float)(table[i][1] - table[i-1][1]) / + (float)(table[i][0] - table[i-1][0]); + + break; + } + } + // Overflow: Set to last value in the table + if (i == numtemps) celsius = table[i-1][1]; + + return celsius; +} + + +inline void kill() +{ + target_raw=0; +#ifdef PIDTEMP + pid_setpoint = 0.0; +#endif //PIDTEMP + OCR2B = 0; + WRITE(HEATER_0_PIN,LOW); + + disable_x(); + disable_y(); + disable_z(); + disable_e(); + +} +*/ + + + +//#################################################################################################################### +//#################################################################################################################### +void manage_heater() +{ +#ifdef USE_WATCHDOG + wd_reset(); +#endif + //there is no FANCY_LCD here, because this routine is called within moves, and delays them. one could loose steps. + + if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) + return; + previous_millis_heater = millis(); + #ifdef HEATER_USES_THERMISTOR + current_raw = analogRead(TEMP_0_PIN); + // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_raw = 1023 - current_raw; + #elif defined HEATER_USES_AD595 + current_raw = analogRead(TEMP_0_PIN); + #elif defined HEATER_USES_MAX6675 + current_raw = read_max6675(); + #endif + #ifdef SMOOTHING + nma = (nma + current_raw) - (nma / SMOOTHFACTOR); + current_raw = nma / SMOOTHFACTOR; + #endif + #ifdef WATCHPERIOD + if(watchmillis && millis() - watchmillis > WATCHPERIOD){ + if(watch_raw + 1 >= current_raw){ + target_raw = 0; + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + }else{ + watchmillis = 0; + } + } + #endif + #ifdef MINTEMP + if(current_raw <= minttemp) + target_raw = 0; + #endif + #ifdef MAXTEMP + if(current_raw >= maxttemp) { + target_raw = 0; + } + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) + #ifdef PIDTEMP + error = target_raw - current_raw; + pTerm = (PID_PGAIN * error) / 100; + temp_iState += error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = (PID_IGAIN * temp_iState) / 100; + dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; + temp_dState = current_raw; + analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); + #else + if(current_raw >= target_raw) + { + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + } + else + { + digitalWrite(HEATER_0_PIN,HIGH); + digitalWrite(LED_PIN,HIGH); + } + #endif + #endif + + if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) + return; + previous_millis_bed_heater = millis(); + + #ifdef BED_USES_THERMISTOR + + current_bed_raw = analogRead(TEMP_1_PIN); + + // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_bed_raw = 1023 - current_bed_raw; + #elif defined BED_USES_AD595 + current_bed_raw = analogRead(TEMP_1_PIN); + + #endif + + + #if TEMP_1_PIN > -1 + if(current_bed_raw >= target_bed_raw) + { + digitalWrite(HEATER_1_PIN,LOW); + } + else + { + digitalWrite(HEATER_1_PIN,HIGH); + } + #endif +} + +// Takes hot end temperature value as input and returns corresponding raw value. +// For a thermistor, it uses the RepRap thermistor temp table. +// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value. +// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware. +float temp2analog(int celsius) { + #ifdef HEATER_USES_THERMISTOR + int raw = 0; + byte i; + + for (i=1; i raw) + { + celsius = temptable[i-1][1] + + (raw - temptable[i-1][0]) * + (temptable[i][1] - temptable[i-1][1]) / + (temptable[i][0] - temptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = temptable[i-1][1]; + + return celsius; + #elif defined HEATER_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #elif defined HEATER_USES_MAX6675 + return raw * 0.25; + #endif +} + +// Derived from RepRap FiveD extruder::getTemperature() +// For bed temperature measurement. +float analog2tempBed(int raw) { + #ifdef BED_USES_THERMISTOR + int celsius = 0; + byte i; + + raw = 1023 - raw; + + for (i=1; i raw) + { + celsius = bedtemptable[i-1][1] + + (raw - bedtemptable[i-1][0]) * + (bedtemptable[i][1] - bedtemptable[i-1][1]) / + (bedtemptable[i][0] - bedtemptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = bedtemptable[i-1][1]; + + return celsius; + + #elif defined BED_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #endif +} + +inline void kill() +{ + #if TEMP_0_PIN > -1 + target_raw=0; + digitalWrite(HEATER_0_PIN,LOW); + #endif + #if TEMP_1_PIN > -1 + target_bed_raw=0; + if(HEATER_1_PIN > -1) digitalWrite(HEATER_1_PIN,LOW); + #endif + disable_x(); + disable_y(); + disable_z(); + disable_e(); + + if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); + +} + + + + + + +//####################################################################################################################### + +inline void manage_inactivity(byte debug) { + if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); + if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { + disable_x(); + disable_y(); + disable_z(); + disable_e(); + } + check_axes_activity(); +} + +// Planner + +/* + Reasoning behind the mathematics in this module (in the key of 'Mathematica'): + + s == speed, a == acceleration, t == time, d == distance + + Basic definitions: + + Speed[s_, a_, t_] := s + (a*t) + Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t] + + Distance to reach a specific speed with a constant acceleration: + + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t] + d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance() + + Speed after a given distance of travel with constant acceleration: + + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t] + m -> Sqrt[2 a d + s^2] + + DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2] + + When to start braking (di) to reach a specified destionation speed (s2) after accelerating + from initial speed s1 without ever stopping at a plateau: + + Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di] + di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance() + + IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a) + */ + + + + +static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions +static volatile unsigned char block_buffer_head; // Index of the next block to be pushed +static volatile unsigned char block_buffer_tail; // Index of the block to process now + +// The current position of the tool in absolute steps +static long position[4]; + +#define ONE_MINUTE_OF_MICROSECONDS 60000000.0 + +// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the +// given acceleration: +inline long estimate_acceleration_distance(long initial_rate, long target_rate, long acceleration) { + return( + (target_rate*target_rate-initial_rate*initial_rate)/ + (2L*acceleration) + ); +} + +// This function gives you the point at which you must start braking (at the rate of -acceleration) if +// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after +// a total travel of distance. This can be used to compute the intersection point between acceleration and +// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) + +inline long intersection_distance(long initial_rate, long final_rate, long acceleration, long distance) { + return( + (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ + (4*acceleration) + ); +} + +// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. + +void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { + if(block->busy == true) return; // If block is busy then bail out. + float entry_factor = entry_speed / block->nominal_speed; + float exit_factor = exit_speed / block->nominal_speed; + long initial_rate = ceil(block->nominal_rate*entry_factor); + long final_rate = ceil(block->nominal_rate*exit_factor); + +#ifdef ADVANCE + long initial_advance = block->advance*entry_factor*entry_factor; + long final_advance = block->advance*exit_factor*exit_factor; +#endif // ADVANCE + + // Limit minimal step rate (Otherwise the timer will overflow.) + if(initial_rate <120) initial_rate=120; + if(final_rate < 120) final_rate=120; + + // Calculate the acceleration steps + long acceleration = block->acceleration_st; + long accelerate_steps = estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration); + long decelerate_steps = estimate_acceleration_distance(final_rate, block->nominal_rate, acceleration); + // Calculate the size of Plateau of Nominal Rate. + long plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; + + // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will + // have to use intersection_distance() to calculate when to abort acceleration and start braking + // in order to reach the final_rate exactly at the end of this block. + if (plateau_steps < 0) { + accelerate_steps = intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count); + plateau_steps = 0; + } + + long decelerate_after = accelerate_steps+plateau_steps; + long acceleration_rate = (long)((float)acceleration * 8.388608); + + CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section + if(block->busy == false) { // Don't update variables if block is busy. + block->accelerate_until = accelerate_steps; + block->decelerate_after = decelerate_after; + block->acceleration_rate = acceleration_rate; + block->initial_rate = initial_rate; + block->final_rate = final_rate; +#ifdef ADVANCE + block->initial_advance = initial_advance; + block->final_advance = final_advance; +#endif //ADVANCE + } + CRITICAL_SECTION_END; +} + +// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the +// acceleration within the allotted distance. +inline float max_allowable_speed(float acceleration, float target_velocity, float distance) { + return( + sqrt(target_velocity*target_velocity-2*acceleration*60*60*distance) + ); +} + +// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks. +// This method will calculate the junction jerk as the euclidean distance between the nominal +// velocities of the respective blocks. +inline float junction_jerk(block_t *before, block_t *after) { + return(sqrt( + pow((before->speed_x-after->speed_x), 2)+ + pow((before->speed_y-after->speed_y), 2))); +} + +// Return the safe speed which is max_jerk/2, e.g. the +// speed under which you cannot exceed max_jerk no matter what you do. +float safe_speed(block_t *block) { + float safe_speed; + safe_speed = max_xy_jerk/2; + if(abs(block->speed_z) > max_z_jerk/2) safe_speed = max_z_jerk/2; + if (safe_speed > block->nominal_speed) safe_speed = block->nominal_speed; + return safe_speed; +} + +// The kernel called by planner_recalculate() when scanning the plan from last to first entry. +void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) { + if(!current) { + return; + } + + float entry_speed = current->nominal_speed; + float exit_factor; + float exit_speed; + if (next) { + exit_speed = next->entry_speed; + } + else { + exit_speed = safe_speed(current); + } + + // Calculate the entry_factor for the current block. + if (previous) { + // Reduce speed so that junction_jerk is within the maximum allowed + float jerk = junction_jerk(previous, current); + if((previous->steps_x == 0) && (previous->steps_y == 0)) { + entry_speed = safe_speed(current); + } + else if (jerk > max_xy_jerk) { + entry_speed = (max_xy_jerk/jerk) * entry_speed; + } + if(abs(previous->speed_z - current->speed_z) > max_z_jerk) { + entry_speed = (max_z_jerk/abs(previous->speed_z - current->speed_z)) * entry_speed; + } + // If the required deceleration across the block is too rapid, reduce the entry_factor accordingly. + if (entry_speed > exit_speed) { + float max_entry_speed = max_allowable_speed(-current->acceleration,exit_speed, current->millimeters); + if (max_entry_speed < entry_speed) { + entry_speed = max_entry_speed; + } + } + } + else { + entry_speed = safe_speed(current); + } + // Store result + current->entry_speed = entry_speed; +} + +// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This +// implements the reverse pass. +void planner_reverse_pass() { + char block_index = block_buffer_head; + block_t *block[3] = { + NULL, NULL, NULL }; + while(block_index != block_buffer_tail) { + block[2]= block[1]; + block[1]= block[0]; + block[0] = &block_buffer[block_index]; + planner_reverse_pass_kernel(block[0], block[1], block[2]); + block_index--; + if(block_index < 0) { + block_index = BLOCK_BUFFER_SIZE-1; + } + } +// planner_reverse_pass_kernel(NULL, block[0], block[1]); +} + +// The kernel called by planner_recalculate() when scanning the plan from first to last entry. +void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) { + if(!current) { + return; + } + if(previous) { + // If the previous block is an acceleration block, but it is not long enough to + // complete the full speed change within the block, we need to adjust out entry + // speed accordingly. Remember current->entry_factor equals the exit factor of + // the previous block. + if(previous->entry_speed < current->entry_speed) { + float max_entry_speed = max_allowable_speed(-previous->acceleration, previous->entry_speed, previous->millimeters); + if (max_entry_speed < current->entry_speed) { + current->entry_speed = max_entry_speed; + } + } + } +} + +// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This +// implements the forward pass. +void planner_forward_pass() { + char block_index = block_buffer_tail; + block_t *block[3] = { + NULL, NULL, NULL }; + + while(block_index != block_buffer_head) { + block[0] = block[1]; + block[1] = block[2]; + block[2] = &block_buffer[block_index]; + planner_forward_pass_kernel(block[0],block[1],block[2]); + block_index = (block_index+1) %BLOCK_BUFFER_SIZE; + } + planner_forward_pass_kernel(block[1], block[2], NULL); +} + +// Recalculates the trapezoid speed profiles for all blocks in the plan according to the +// entry_factor for each junction. Must be called by planner_recalculate() after +// updating the blocks. +void planner_recalculate_trapezoids() { + char block_index = block_buffer_tail; + block_t *current; + block_t *next = NULL; + while(block_index != block_buffer_head) { + current = next; + next = &block_buffer[block_index]; + if (current) { + calculate_trapezoid_for_block(current, current->entry_speed, next->entry_speed); + } + block_index = (block_index+1) %BLOCK_BUFFER_SIZE; + } + calculate_trapezoid_for_block(next, next->entry_speed, safe_speed(next)); +} + +// Recalculates the motion plan according to the following algorithm: +// +// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) +// so that: +// a. The junction jerk is within the set limit +// b. No speed reduction within one block requires faster deceleration than the one, true constant +// acceleration. +// 2. Go over every block in chronological order and dial down junction speed reduction values if +// a. The speed increase within one block would require faster accelleration than the one, true +// constant acceleration. +// +// When these stages are complete all blocks have an entry_factor that will allow all speed changes to +// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than +// the set limit. Finally it will: +// +// 3. Recalculate trapezoids for all blocks. + +void planner_recalculate() { + planner_reverse_pass(); + planner_forward_pass(); + planner_recalculate_trapezoids(); +} + +void plan_init() { + block_buffer_head = 0; + block_buffer_tail = 0; + memset(position, 0, sizeof(position)); // clear position +} + + +inline void plan_discard_current_block() { + if (block_buffer_head != block_buffer_tail) { + block_buffer_tail = (block_buffer_tail + 1) %BLOCK_BUFFER_SIZE; + } +} + +inline block_t *plan_get_current_block() { + if (block_buffer_head == block_buffer_tail) { + return(NULL); + } + block_t *block = &block_buffer[block_buffer_tail]; + block->busy = true; + return(block); +} + +void check_axes_activity() { + unsigned char x_active = 0; + unsigned char y_active = 0; + unsigned char z_active = 0; + unsigned char e_active = 0; + block_t *block; + + if(block_buffer_tail != block_buffer_head) { + char block_index = block_buffer_tail; + while(block_index != block_buffer_head) { + block = &block_buffer[block_index]; + if(block->steps_x != 0) x_active++; + if(block->steps_y != 0) y_active++; + if(block->steps_z != 0) z_active++; + if(block->steps_e != 0) e_active++; + block_index = (block_index+1) %BLOCK_BUFFER_SIZE; + } + } + if((DISABLE_X) && (x_active == 0)) disable_x(); + if((DISABLE_Y) && (y_active == 0)) disable_y(); + if((DISABLE_Z) && (z_active == 0)) disable_z(); + if((DISABLE_E) && (e_active == 0)) disable_e(); +} + +// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in +// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration +// calculation the caller must also provide the physical length of the line in millimeters. +void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { + + // The target position of the tool in absolute steps + // Calculate target position in absolute steps + long target[4]; + target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); + target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); + target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); + target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); + + // Calculate the buffer head after we push this byte + int next_buffer_head = (block_buffer_head + 1) %BLOCK_BUFFER_SIZE; + + // If the buffer is full: good! That means we are well ahead of the robot. + // Rest here until there is room in the buffer. + while(block_buffer_tail == next_buffer_head) { + manage_heater(); + manage_inactivity(1); + } + + // Prepare to set up new block + block_t *block = &block_buffer[block_buffer_head]; + + // Mark block as not busy (Not executed by the stepper interrupt) + block->busy = false; + + // Number of steps for each axis + block->steps_x = labs(target[X_AXIS]-position[X_AXIS]); + block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]); + block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); + block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); + block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); + + // Bail if this is a zero-length block + if (block->step_event_count == 0) { + return; + }; + + //enable active axes + if(block->steps_x != 0) enable_x(); + if(block->steps_y != 0) enable_y(); + if(block->steps_z != 0) enable_z(); + if(block->steps_e != 0) enable_e(); + + float delta_x_mm = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; + float delta_y_mm = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; + float delta_z_mm = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; + float delta_e_mm = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS]; + block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); + + unsigned long microseconds; + microseconds = lround((block->millimeters/feed_rate)*1000000); + + // added by lampmaker to slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill + // reduces/removes corner blobs as the machine won't come to a full stop. + int blockcount=block_buffer_head-block_buffer_tail; + //blockcount=8; + while(blockcount<0) blockcount+=BLOCK_BUFFER_SIZE; + if ((blockcount<=2)&&(microseconds<(MIN_SEGMENT_TIME))) microseconds=MIN_SEGMENT_TIME; + else if ((blockcount<=4)&&(microseconds<(MIN_SEGMENT_TIME/2))) microseconds=MIN_SEGMENT_TIME/2; + else if ((blockcount<=8)&&(microseconds<(MIN_SEGMENT_TIME/5))) microseconds=MIN_SEGMENT_TIME/5; + + // Calculate speed in mm/minute for each axis + float multiplier = 60.0*1000000.0/microseconds; + block->speed_z = delta_z_mm * multiplier; + block->speed_x = delta_x_mm * multiplier; + block->speed_y = delta_y_mm * multiplier; + block->speed_e = delta_e_mm * multiplier; + + // Limit speed per axis + float speed_factor = 1; + float tmp_speed_factor; + if(abs(block->speed_x) > max_feedrate[X_AXIS]) { + //// [ErikDeBruijn] IS THIS THE BUG WE'RE LOOING FOR???? + // it used to be just this line: speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + tmp_speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ + tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ + tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + if(abs(block->speed_e) > max_feedrate[E_AXIS]){ + tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); + if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + } + multiplier = multiplier * speed_factor; + block->speed_z = delta_z_mm * multiplier; + block->speed_x = delta_x_mm * multiplier; + block->speed_y = delta_y_mm * multiplier; + block->speed_e = delta_e_mm * multiplier; + block->nominal_speed = block->millimeters * multiplier; + block->nominal_rate = ceil(block->step_event_count * multiplier / 60); + + if(block->nominal_rate < 120) block->nominal_rate = 120; + block->entry_speed = safe_speed(block); + + // Compute the acceleration rate for the trapezoid generator. + float travel_per_step = block->millimeters/block->step_event_count; + if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { + block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + } + else { + block->acceleration_st = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + // Limit acceleration per axis + if((block->acceleration_st * block->steps_x / block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[X_AXIS]; + if((block->acceleration_st * block->steps_y / block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS]; + if((block->acceleration_st * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[E_AXIS]; + if(((block->acceleration_st / block->step_event_count) * block->steps_z ) > axis_steps_per_sqr_second[Z_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS]; + } + block->acceleration = block->acceleration_st * travel_per_step; + +#ifdef ADVANCE + // Calculate advance rate + if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) { + block->advance_rate = 0; + block->advance = 0; + } + else { + long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st); + float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * + (block->speed_e * block->speed_e * EXTRUTION_AREA * EXTRUTION_AREA / 3600.0)*65536; + block->advance = advance; + if(acc_dist == 0) { + block->advance_rate = 0; + } + else { + block->advance_rate = advance / (float)acc_dist; + } + } + +#endif // ADVANCE + + // compute a preliminary conservative acceleration trapezoid + float safespeed = safe_speed(block); + calculate_trapezoid_for_block(block, safespeed, safespeed); + + // Compute direction bits for this block + block->direction_bits = 0; + if (target[X_AXIS] < position[X_AXIS]) { + block->direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<> 16 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 24 bit result +#define MultiU16X8toH16(intRes, charIn1, intIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %A1, %A2 \n\t" \ +"add %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r0 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (charIn1), \ +"d" (intIn2) \ +: \ +"r26" \ +) + +// intRes = longIn1 * longIn2 >> 24 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 48bit result +#define MultiU24X24toH16(intRes, longIn1, longIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"mov r27, r1 \n\t" \ +"mul %B1, %C2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %C1, %C2 \n\t" \ +"add %B0, r0 \n\t" \ +"mul %C1, %B2 \n\t" \ +"add %A0, r0 \n\t" \ +"adc %B0, r1 \n\t" \ +"mul %A1, %C2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %B2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %C1, %A2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %A2 \n\t" \ +"add r27, r1 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r27 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (longIn1), \ +"d" (longIn2) \ +: \ +"r26" , "r27" \ +) + +// Some useful constants + +#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1< +// +// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates +// first block->accelerate_until step_events_completed, then keeps going at constant speed until +// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. +// The slope of acceleration is calculated with the leib ramp alghorithm. + +void st_wake_up() { + // TCNT1 = 0; + ENABLE_STEPPER_DRIVER_INTERRUPT(); +} + +inline unsigned short calc_timer(unsigned short step_rate) { + unsigned short timer; + if(step_rate < 32) step_rate = 32; + step_rate -= 32; // Correct for minimal speed + if(step_rate >= (8*256)){ // higher step rate + unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; + unsigned char tmp_step_rate = (step_rate & 0x00ff); + unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); + MultiU16X8toH16(timer, tmp_step_rate, gain); + timer = (unsigned short)pgm_read_word_near(table_address) - timer; + } + else { // lower step rates + unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; + table_address += ((step_rate)>>1) & 0xfffc; + timer = (unsigned short)pgm_read_word_near(table_address); + timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); + } + if(timer < 100) timer = 100; + return timer; +} + +// Initializes the trapezoid generator from the current block. Called whenever a new +// block begins. +inline void trapezoid_generator_reset() { + accelerate_until = current_block->accelerate_until; + decelerate_after = current_block->decelerate_after; + acceleration_rate = current_block->acceleration_rate; + initial_rate = current_block->initial_rate; + final_rate = current_block->final_rate; + nominal_rate = current_block->nominal_rate; + advance = current_block->initial_advance; + final_advance = current_block->final_advance; + deceleration_time = 0; + advance_rate = current_block->advance_rate; + // step_rate to timer interval + acc_step_rate = initial_rate; + acceleration_time = calc_timer(acc_step_rate); + OCR1A = acceleration_time; +} + +// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. +// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. +ISR(TIMER1_COMPA_vect) +{ + if(busy){ /*Serial.println("BUSY")*/; + return; + } // The busy-flag is used to avoid reentering this interrupt + + busy = true; + sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) +#ifdef FANCY_LCD + static int breakdown=0; + if((breakdown++)%100==0) + buttons_check(); +/* [ErikDeBruijn] Perhaps it would be nice to use a piece of code like this (adapted from process_g_code), to create a nice progress bar! + if(sdactive){ + sprintf("SD printing byte %i%",(int) (sdpos/filesize*100)); // perhaps a fraction of a percent is also nice, 0.03%, progress bar even better. + Serial.print(sdpos); + Serial.print("/"); + Serial.println(filesize); + } +*/ +#endif + + // If there is no current block, attempt to pop one from the buffer + if (current_block == NULL) { + // Anything in the buffer? + current_block = plan_get_current_block(); + if (current_block != NULL) { + trapezoid_generator_reset(); + counter_x = -(current_block->step_event_count >> 1); + counter_y = counter_x; + counter_z = counter_x; + counter_e = counter_x; + step_events_completed = 0; + e_steps = 0; + } + else { + DISABLE_STEPPER_DRIVER_INTERRUPT(); + } + } + + if (current_block != NULL) { + // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt + out_bits = current_block->direction_bits; + +#ifdef ADVANCE + // Calculate E early. + counter_e += current_block->steps_e; + if (counter_e > 0) { + counter_e -= current_block->step_event_count; + if ((out_bits & (1<> 16) - old_advance); + CRITICAL_SECTION_END; + old_advance = advance >> 16; +#endif //ADVANCE + + // Set direction en check limit switches +if ((out_bits & (1<step_event_count; + } + } + else { // +direction + WRITE(X_DIR_PIN,!INVERT_X_DIR); + #ifdef DEBUG_STEPS + count_direction[X_AXIS]=1; + #endif + if((READ(X_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_x >0)){ + step_events_completed = current_block->step_event_count; + } + } + + if ((out_bits & (1<step_event_count; + } + } + else { // +direction + WRITE(Y_DIR_PIN,!INVERT_Y_DIR); + #ifdef DEBUG_STEPS + count_direction[Y_AXIS]=1; + #endif + if((READ(Y_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_y >0)){ + step_events_completed = current_block->step_event_count; + } + } + + if ((out_bits & (1<step_event_count; + } + } + else { // +direction + WRITE(Z_DIR_PIN,!INVERT_Z_DIR); + #ifdef DEBUG_STEPS + count_direction[Z_AXIS]=1; + #endif + if((READ(Z_MAX_PIN) != ENDSTOPS_INVERTING) && (current_block->steps_z >0)){ + step_events_completed = current_block->step_event_count; + } + } + +#ifndef ADVANCE + if ((out_bits & (1<steps_x; + if (counter_x > 0) { + WRITE(X_STEP_PIN, HIGH); + counter_x -= current_block->step_event_count; + WRITE(X_STEP_PIN, LOW); + #ifdef DEBUG_STEPS + count_position[X_AXIS]+=count_direction[X_AXIS]; + #endif + } + + counter_y += current_block->steps_y; + if (counter_y > 0) { + WRITE(Y_STEP_PIN, HIGH); + counter_y -= current_block->step_event_count; + WRITE(Y_STEP_PIN, LOW); + #ifdef DEBUG_STEPS + count_position[Y_AXIS]+=count_direction[Y_AXIS]; + #endif + } + + counter_z += current_block->steps_z; + if (counter_z > 0) { + WRITE(Z_STEP_PIN, HIGH); + counter_z -= current_block->step_event_count; + WRITE(Z_STEP_PIN, LOW); + #ifdef DEBUG_STEPS + count_position[Z_AXIS]+=count_direction[Z_AXIS]; + #endif + } + +#ifndef ADVANCE + counter_e += current_block->steps_e; + if (counter_e > 0) { + WRITE(E_STEP_PIN, HIGH); + counter_e -= current_block->step_event_count; + WRITE(E_STEP_PIN, LOW); + } +#endif //!ADVANCE + + // Calculare new timer value + unsigned short timer; + unsigned short step_rate; + if (step_events_completed < accelerate_until) { + MultiU24X24toH16(acc_step_rate, acceleration_time, acceleration_rate); + acc_step_rate += initial_rate; + + // upper limit + if(acc_step_rate > nominal_rate) + acc_step_rate = nominal_rate; + + // step_rate to timer interval + timer = calc_timer(acc_step_rate); + advance += advance_rate; + acceleration_time += timer; + OCR1A = timer; + } + else if (step_events_completed >= decelerate_after) { + MultiU24X24toH16(step_rate, deceleration_time, acceleration_rate); + + if(step_rate > acc_step_rate) { // Check step_rate stays positive + step_rate = final_rate; + } + else { + step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. + } + + // lower limit + if(step_rate < final_rate) + step_rate = final_rate; + + // step_rate to timer interval + timer = calc_timer(step_rate); +#ifdef ADVANCE + advance -= advance_rate; + if(advance < final_advance) + advance = final_advance; +#endif //ADVANCE + deceleration_time += timer; + OCR1A = timer; + } + // If current block is finished, reset pointer + step_events_completed += 1; + if (step_events_completed >= current_block->step_event_count) { + current_block = NULL; + plan_discard_current_block(); + } + } + busy=false; +} + +#ifdef ADVANCE + +unsigned char old_OCR0A; +// Timer interrupt for E. e_steps is set in the main routine; +// Timer 0 is shared with millies +ISR(TIMER0_COMPA_vect) +{ + // Critical section needed because Timer 1 interrupt has higher priority. + // The pin set functions are placed on trategic position to comply with the stepper driver timing. + WRITE(E_STEP_PIN, LOW); + // Set E direction (Depends on E direction + advance) + if (e_steps < 0) { + WRITE(E_DIR_PIN,INVERT_E_DIR); + e_steps++; + WRITE(E_STEP_PIN, HIGH); + } + if (e_steps > 0) { + WRITE(E_DIR_PIN,!INVERT_E_DIR); + e_steps--; + WRITE(E_STEP_PIN, HIGH); + } + old_OCR0A += 25; // 10kHz interrupt + OCR0A = old_OCR0A; +} +#endif // ADVANCE + +void st_init() +{ + // waveform generation = 0100 = CTC + TCCR1B &= ~(1<= 16) + { + current_raw = 16383 - raw_temp_value; + temp_meas_ready = true; + temp_count = 0; + raw_temp_value = 0; +#ifdef MAXTEMP + if(current_raw >= maxttemp) { + target_raw = 0; +#ifdef PIDTEMP + OCR2B = 0; +#else + WRITE(HEATER_0_PIN,LOW); +#endif //PIDTEMP + } +#endif //MAXTEMP +#ifdef MINTEMP + if(current_raw <= minttemp) { + target_raw = 0; +#ifdef PIDTEMP + OCR2B = 0; +#else + WRITE(HEATER_0_PIN,LOW); +#endif //PIDTEMP + } +#endif //MAXTEMP +#ifndef PIDTEMP + if(current_raw >= target_raw) + { + WRITE(HEATER_0_PIN,LOW); + } + else + { + WRITE(HEATER_0_PIN,HIGH); + } +#endif //PIDTEMP + } +} + +*/ From 712ca8d3eb3aaaf18d9f2b44a8a28636c9675a6f Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 20 Sep 2011 13:49:52 +0200 Subject: [PATCH 044/130] made acceration and feedrate limits software-configurable. M203 M204 added more comments to configuration TRAVELING_AT_MAXSPEED can be uncommented: it checks if an extrusion is existent in the move. if _not_, the speed of the move is set to the maximum speed. Use only if you know that your printer works at the maximum declared speeds. It is a workaround for the skeinforge cool-bug. There, all moves are slowed to have a minimum layer time. However slow travel moves= ooze --- Marlin/Configuration.h | 17 ++++++++++------ Marlin/Marlin.pde | 46 +++++++++++++++++++++++++++--------------- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index d81c4f9d9434..8b5913caae5b 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -84,17 +84,22 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the //// MOVEMENT SETTINGS #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {240*60, 240*60, 500*60, 500000}; // set the max speeds -float homing_feedrate[] = {3400, 3400, 60*500, 0}; // set the homing speeds +float max_feedrate[] = {200*60, 200*60, 500*60, 500000}; // set the max speeds +float homing_feedrate[] = {70*60, 70*60, 500*60, 0}; // set the homing speeds +//the followint checks if an extrusion is existent in the move. if _not_, the speed of the move is set to the maximum speed. +//!!!!!!Use only if you know that your printer works at the maximum declared speeds. +// works around the skeinforge cool-bug. There all moves are slowed to have a minimum layer time. However slow travel moves= ooze +//#define TRAVELING_AT_MAXSPEED bool axis_relative_modes[] = {false, false, false, false}; //// Acceleration settings // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. -float acceleration = 4000; // Normal acceleration mm/s^2 -float retract_acceleration = 7000; // Normal acceleration mm/s^2 -float max_xy_jerk = 20.0*60; +float acceleration = 4000; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX +float retract_acceleration = 7000; // mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX +float max_xy_jerk = 50.0*60; //speed than can be stopped at once, if i understand correctly. float max_z_jerk = 0.4*60; -long max_acceleration_units_per_sq_second[] = {7000,7000,15000,10000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts +// X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts +long max_acceleration_units_per_sq_second[] = {9000,9000,15000,10000}; // Use M201 to override by software // The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature // If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 095e90024c35..d9a9730c135c 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -118,7 +118,9 @@ volatile int count_direction[NUM_AXIS] = { 1, 1, 1, 1}; // 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) +// M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) Unused in Marlin!! +// M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec +// M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 // M301 - Set PID parameters P I and D //Stepper Movement Variables @@ -1062,6 +1064,17 @@ inline void process_commands() } break; #endif + case 203: // M203 max feedrate mm/sec + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) max_feedrate[i] = code_value()*60 ; + } + break; + case 204: // M204 acclereration S normal moves T filmanent only moves + { + if(code_seen('S') acceleration = code_value() ; + if(code_seen('T') acceleration_retract = code_value() ; + } + break; #ifdef PIDTEMP case 301: // M301 if(code_seen('P')) Kp = code_value(); @@ -1893,7 +1906,12 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { unsigned long microseconds; microseconds = lround((block->millimeters/feed_rate)*1000000); - +#ifdef TRAVELING_AT_MAXSPEED + if(delta_e_mm==0) //no extrusion + { + microseconds*=0.001; // speed limits then should get working + } +#endif // added by lampmaker to slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill // reduces/removes corner blobs as the machine won't come to a full stop. int blockcount=block_buffer_head-block_buffer_tail; @@ -1910,25 +1928,26 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->speed_y = delta_y_mm * multiplier; block->speed_e = delta_e_mm * multiplier; + // Limit speed per axis - float speed_factor = 1; - float tmp_speed_factor; + float speed_factor = 1; //factor <=1 do decrease speed if(abs(block->speed_x) > max_feedrate[X_AXIS]) { //// [ErikDeBruijn] IS THIS THE BUG WE'RE LOOING FOR???? - // it used to be just this line: speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); - tmp_speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); - if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; + //// [bernhard] No its not, according to Zalm. + //// the if would always be true, since tmp_speedfactor <=0 due the inial if, so its safe to set. the next lines actually compare. + speed_factor = max_feedrate[X_AXIS] / abs(block->speed_x); + //if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; } if(abs(block->speed_y) > max_feedrate[Y_AXIS]){ - tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); + float tmp_speed_factor = max_feedrate[Y_AXIS] / abs(block->speed_y); if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; } if(abs(block->speed_z) > max_feedrate[Z_AXIS]){ - tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); + float tmp_speed_factor = max_feedrate[Z_AXIS] / abs(block->speed_z); if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; } if(abs(block->speed_e) > max_feedrate[E_AXIS]){ - tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); + float tmp_speed_factor = max_feedrate[E_AXIS] / abs(block->speed_e); if(speed_factor > tmp_speed_factor) speed_factor = tmp_speed_factor; } multiplier = multiplier * speed_factor; @@ -2016,12 +2035,7 @@ void plan_set_position(float x, float y, float z, float e) position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); - position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); -#ifdef DEBUG_STEPS - count_position[X_AXIS]= position[X_AXIS]; - count_position[Y_AXIS]= position[Y_AXIS]; - count_position[Z_AXIS]= position[Z_AXIS]; -#endif + position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); } // Stepper From 03757512b3e421b4f3c22c1e123b8567dd681d81 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 20 Sep 2011 13:56:29 +0200 Subject: [PATCH 045/130] typos, stupid me --- Marlin/Marlin.pde | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index d9a9730c135c..8e625e82f383 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1071,8 +1071,8 @@ inline void process_commands() break; case 204: // M204 acclereration S normal moves T filmanent only moves { - if(code_seen('S') acceleration = code_value() ; - if(code_seen('T') acceleration_retract = code_value() ; + if(code_seen('S')) acceleration = code_value() ; + if(code_seen('T')) retract_acceleration = code_value() ; } break; #ifdef PIDTEMP From 849a0217629c8e8129f1e5bba8a298f2b6f75a57 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 20 Sep 2011 15:02:12 +0200 Subject: [PATCH 046/130] removed enquecommand lcd dependency, its also used for sd Before this commit, if sd was enabled and no sd card present, the device would need so long to boot that some host software had a timeout. so i try to delay the sd card initialisation to the first use. Hence also the autostart should be delayed. untested --- Marlin/Marlin.h | 1 + Marlin/Marlin.pde | 45 ++++++++++++++++++++++++++++++++++++++++----- Marlin/lcd.pde | 26 ++++++++++---------------- 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index b877be57e6d2..10f1377bbff1 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -118,6 +118,7 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate); void plan_set_position(float x, float y, float z, float e); void st_wake_up(); void st_synchronize(); +void enquecommand(const char *cmd); #endif diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 8e625e82f383..ac4ff42cfdb5 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -208,6 +208,7 @@ bool sdmode = false; bool sdactive = false; bool savetosd = false; int16_t n; +long autostart_atmillis=0; void initsd(){ sdactive = false; @@ -227,6 +228,11 @@ void initsd(){ #endif //SDSS } +void quickinitsd(){ + sdactive=false; + autostart_atmillis=millis()+3000; +} + inline void write_command(char *buf){ char* begin = buf; char* npos = 0; @@ -248,6 +254,20 @@ inline void write_command(char *buf){ } #endif //SDSUPPORT + +///adds an command to the main command buffer +void enquecommand(const char *cmd) +{ + if(buflen < BUFSIZE) + { + //this is dangerous if a mixing of serial and this happsens + strcpy(&(cmdbuffer[bufindw][0]),cmd); + Serial.print("en:");Serial.println(cmdbuffer[bufindw]); + bufindw= (bufindw + 1)%BUFSIZE; + buflen += 1; + } +} + void setup() { @@ -378,20 +398,33 @@ void setup() SET_OUTPUT(SDPOWER); WRITE(SDPOWER,HIGH); #endif //SDPOWER - initsd(); + quickinitsd(); #endif //SDSUPPORT plan_init(); // Initialize planner; st_init(); // Initialize stepper; // tp_init(); // Initialize temperature loop - checkautostart(); + //checkautostart(); } #ifdef SDSUPPORT +bool autostart_stilltocheck=true; + void checkautostart() { + //this is to delay autostart and hence the initialisaiton of the sd card to some seconds after the normal init, so the device is available quick after a reset + if(!autostart_stilltocheck) + return; + if(autostart_atmillis Date: Wed, 21 Sep 2011 12:51:47 -0400 Subject: [PATCH 047/130] Decreased command buffer size for SIMPLE_LCD. Added boot-up message. Cleared "Heating.." message after pre-heat completes --- Marlin/Configuration.h | 2 +- Marlin/Marlin.pde | 5 +++-- Marlin/lcd.pde | 38 +++++++++++++++++++++----------------- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 8b5913caae5b..efdb2f6270ab 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -45,7 +45,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the // Comment out (using // at the start of the line) to disable SD support: //#define SDSUPPORT // Enable SD Card Support in Hardware Console //#define FANCY_LCD // Hardware Console with 20x4 multipage LCD -//#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) +#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) //// ADVANCED SETTINGS - to tweak parameters diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index ac4ff42cfdb5..64bd0b1b0f98 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -65,7 +65,7 @@ char version_string[] = "U0.9.3.3-BK"; #endif #ifdef SIMPLE_LCD - #define BLOCK_BUFFER_SIZE 32 // A little less buffer for just a simple LCD + #define BLOCK_BUFFER_SIZE 24 // A little less buffer for just a simple LCD #endif // if DEBUG_STEPS is enabled, M114 can be used to compare two methods of determining the X,Y,Z position of the printer. @@ -947,7 +947,7 @@ inline void process_commands() return; //break; case 109: // M109 - Wait for extruder heater to reach target. - LCD_MESSAGE("Heating..."); + LCD_MESSAGE("Heating..."); if (code_seen('S')) target_raw = temp2analog(code_value()); #ifdef WATCHPERIOD if(target_raw>current_raw){ @@ -970,6 +970,7 @@ inline void process_commands() LCD_STATUS; manage_heater(); } + LCD_MESSAGE("UltiMarlin ready."); break; case 190: // M190 - Wait bed for heater to reach target. #if TEMP_1_PIN > -1 diff --git a/Marlin/lcd.pde b/Marlin/lcd.pde index 55d2625d6889..6bd5d811e3af 100644 --- a/Marlin/lcd.pde +++ b/Marlin/lcd.pde @@ -127,19 +127,27 @@ void PageWatch::update() return; //slower updates char line1[25]; static char blink=0; - sprintf(line1,"%c%3i/%3i\1%c%c%c%c%c%c", ((blink++)%2==0)? (char)2:' ', - int(analog2temp(current_raw)), - int(analog2temp(target_raw)), - (!digitalRead(X_MIN_PIN))? 'x':' ', - (!digitalRead(X_MAX_PIN))? 'X':' ', - (!digitalRead(Y_MIN_PIN))? 'y':' ', - (!digitalRead(Y_MAX_PIN))? 'Y':' ', - (!digitalRead(Z_MIN_PIN))? 'z':' ', - (!digitalRead(Z_MAX_PIN))? 'Z':' '); - - lcd.setCursor(0,0); - lcd.print(fillto(LCD_WIDTH,line1)); - + if (blink == 0) + { + lcd.setCursor(0,0); + lcd.print(fillto(LCD_WIDTH,"booting...")); + blink++; + } + else + { + sprintf(line1,"%c%3i/%3i\1%c%c%c%c%c%c", ((blink++)%2==0)? (char)2:' ', + int(analog2temp(current_raw)), + int(analog2temp(target_raw)), + (!digitalRead(X_MIN_PIN))? 'x':' ', + (!digitalRead(X_MAX_PIN))? 'X':' ', + (!digitalRead(Y_MIN_PIN))? 'y':' ', + (!digitalRead(Y_MAX_PIN))? 'Y':' ', + (!digitalRead(Z_MIN_PIN))? 'z':' ', + (!digitalRead(Z_MAX_PIN))? 'Z':' '); + + lcd.setCursor(0,0); + lcd.print(fillto(LCD_WIDTH,line1)); + } } void PageWatch::activate() @@ -532,10 +540,6 @@ void lcd_init() lcd.begin(LCD_WIDTH, LCD_HEIGHT); lcd.createChar(1,Degree); lcd.createChar(2,Thermometer); - lcd.clear(); - lcd.print(fillto(LCD_WIDTH,"booting!")); - //lcd.setCursor(0, 1); - //lcd.print("lets Marlin!"); LCD_MESSAGE(fillto(LCD_WIDTH,"UltiMarlin ready.")); menu.addMenuPage(&pagewatch); #ifdef FANCY_LCD From afad7d075814035a164a052d20985d69df5594c7 Mon Sep 17 00:00:00 2001 From: bradleyf Date: Wed, 21 Sep 2011 12:53:36 -0400 Subject: [PATCH 048/130] Whoops! Disable SIMPLE_LCD by default --- Marlin/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index efdb2f6270ab..8b5913caae5b 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -45,7 +45,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the // Comment out (using // at the start of the line) to disable SD support: //#define SDSUPPORT // Enable SD Card Support in Hardware Console //#define FANCY_LCD // Hardware Console with 20x4 multipage LCD -#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) +//#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) //// ADVANCED SETTINGS - to tweak parameters From 2ce018c9d75389503956259af8cfcec2a4c643fa Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Wed, 21 Sep 2011 20:53:36 +0200 Subject: [PATCH 049/130] prefetch --- Marlin/Configuration.h | 9 +++++---- Marlin/Marlin.pde | 6 ++++-- Marlin/lcd.pde | 19 ++++++++++--------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 8b5913caae5b..aaf7d527344f 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -43,8 +43,8 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -//#define SDSUPPORT // Enable SD Card Support in Hardware Console -//#define FANCY_LCD // Hardware Console with 20x4 multipage LCD +#define SDSUPPORT // Enable SD Card Support in Hardware Console +#define FANCY_LCD // Hardware Console with 20x4 multipage LCD //#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) @@ -85,7 +85,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the //// MOVEMENT SETTINGS #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E float max_feedrate[] = {200*60, 200*60, 500*60, 500000}; // set the max speeds -float homing_feedrate[] = {70*60, 70*60, 500*60, 0}; // set the homing speeds +float homing_feedrate[] = {70*60, 70*60, 100*60, 0}; // set the homing speeds //the followint checks if an extrusion is existent in the move. if _not_, the speed of the move is set to the maximum speed. //!!!!!!Use only if you know that your printer works at the maximum declared speeds. // works around the skeinforge cool-bug. There all moves are slowed to have a minimum layer time. However slow travel moves= ooze @@ -95,11 +95,12 @@ bool axis_relative_modes[] = {false, false, false, false}; //// Acceleration settings // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. float acceleration = 4000; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX +#define INSTANTZ float retract_acceleration = 7000; // mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX float max_xy_jerk = 50.0*60; //speed than can be stopped at once, if i understand correctly. float max_z_jerk = 0.4*60; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts -long max_acceleration_units_per_sq_second[] = {9000,9000,15000,10000}; // Use M201 to override by software +long max_acceleration_units_per_sq_second[] = {9000,9000,2000,10000}; // Use M201 to override by software // The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature // If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index ac4ff42cfdb5..c28a75d809d0 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -230,7 +230,7 @@ void initsd(){ void quickinitsd(){ sdactive=false; - autostart_atmillis=millis()+3000; + autostart_atmillis=millis()+5000; } inline void write_command(char *buf){ @@ -417,6 +417,7 @@ void checkautostart() return; if(autostart_atmillismillimeters/feed_rate)*1000000); + #ifdef TRAVELING_AT_MAXSPEED if(delta_e_mm==0) //no extrusion { diff --git a/Marlin/lcd.pde b/Marlin/lcd.pde index 55d2625d6889..2f607e2365f0 100644 --- a/Marlin/lcd.pde +++ b/Marlin/lcd.pde @@ -188,6 +188,10 @@ void PageWatch::activate() #ifdef FANCY_LCD +int lastline=-1; +int lastencoder=0; +int step=2; + #ifdef PAGEMOVE class PageMove:public MenuPage { @@ -209,9 +213,7 @@ PageMove::PageMove() xshift=10;items=4; } -int lastline=-1; -int lastencoder=0; -int step=2; + void PageMove::update() { @@ -593,14 +595,13 @@ void beep() { // [ErikDeBruijn] changed to two short beeps, more friendly pinMode(BEEPER,OUTPUT); + for(int i=0;i<20;i++){ digitalWrite(BEEPER,HIGH); - delay(200); - digitalWrite(BEEPER,LOW); - delay(200); - digitalWrite(BEEPER,HIGH); - delay(200); + delay(5); digitalWrite(BEEPER,LOW); - + delay(5); + } + } #endif From 72936b071d45300829ffc455b7b8d1d3fd5717e7 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Thu, 22 Sep 2011 00:12:25 +0200 Subject: [PATCH 050/130] tuned config. traveling_at_maxspeed increases travel speed,to workaround skeinforge cool slowdown bug of slowing also travel moves. Now, it is only done if the buffer is sufficiently full. solved bug with rounding eror at z accelleration calculation. --- Marlin/Configuration.h | 20 +++++++------- Marlin/Marlin.pde | 60 ++++++++++++++++++++++++++---------------- 2 files changed, 48 insertions(+), 32 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index aaf7d527344f..9026afd0b624 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -46,7 +46,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define SDSUPPORT // Enable SD Card Support in Hardware Console #define FANCY_LCD // Hardware Console with 20x4 multipage LCD //#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) - +const int dropsegments=2; //everything with this number of steps will be ignored as move //// ADVANCED SETTINGS - to tweak parameters @@ -84,23 +84,23 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the //// MOVEMENT SETTINGS #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {200*60, 200*60, 500*60, 500000}; // set the max speeds -float homing_feedrate[] = {70*60, 70*60, 100*60, 0}; // set the homing speeds +float max_feedrate[] = {200*60, 200*60, 12*60, 500000}; // set the max speeds +//note: on bernhards ultimaker 200 200 12 are working well. +float homing_feedrate[] = {70*60, 70*60, 12*60, 0}; // set the homing speeds //the followint checks if an extrusion is existent in the move. if _not_, the speed of the move is set to the maximum speed. //!!!!!!Use only if you know that your printer works at the maximum declared speeds. // works around the skeinforge cool-bug. There all moves are slowed to have a minimum layer time. However slow travel moves= ooze -//#define TRAVELING_AT_MAXSPEED +#define TRAVELING_AT_MAXSPEED bool axis_relative_modes[] = {false, false, false, false}; //// Acceleration settings // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. -float acceleration = 4000; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX -#define INSTANTZ +float acceleration = 4600; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX float retract_acceleration = 7000; // mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX -float max_xy_jerk = 50.0*60; //speed than can be stopped at once, if i understand correctly. -float max_z_jerk = 0.4*60; +float max_xy_jerk = 5.0*60; //speed than can be stopped at once, if i understand correctly. +float max_z_jerk = 1*60; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts -long max_acceleration_units_per_sq_second[] = {9000,9000,2000,10000}; // Use M201 to override by software +long max_acceleration_units_per_sq_second[] = {9000,9000,150,10000}; // Use M201 to override by software // The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature // If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 @@ -117,7 +117,7 @@ long max_acceleration_units_per_sq_second[] = {9000,9000,2000,10000}; // Use M20 // minimum time in microseconds that a movement needs to take if the buffer is emptied. Increase this number if you see blobs while printing high speed & high detail. It will slowdown on the detailed stuff. -#define MIN_SEGMENT_TIME 50000 +#define MIN_SEGMENT_TIME 60000 /// PID settings: diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 7a5459c15e11..decbecd577d9 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -224,7 +224,10 @@ void initsd(){ else if (!root.openRoot(&volume)) Serial.println("openRoot failed"); else + { sdactive = true; + Serial.println("SD card ok"); + } #endif //SDSS } @@ -410,16 +413,18 @@ void setup() #ifdef SDSUPPORT bool autostart_stilltocheck=true; -void checkautostart() +void checkautostart(bool force=false); //f*** u preprocessor +void checkautostart(bool force) { //this is to delay autostart and hence the initialisaiton of the sd card to some seconds after the normal init, so the device is available quick after a reset - if(!autostart_stilltocheck) - return; - if(autostart_atmillisstep_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); // Bail if this is a zero-length block - if (block->step_event_count == 0) { + if (block->step_event_count <=dropsegments) { return; }; @@ -1944,20 +1949,31 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { unsigned long microseconds; microseconds = lround((block->millimeters/feed_rate)*1000000); -#ifdef TRAVELING_AT_MAXSPEED - if(delta_e_mm==0) //no extrusion - { - microseconds*=0.001; // speed limits then should get working - } -#endif + // added by lampmaker to slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill // reduces/removes corner blobs as the machine won't come to a full stop. int blockcount=block_buffer_head-block_buffer_tail; //blockcount=8; while(blockcount<0) blockcount+=BLOCK_BUFFER_SIZE; - if ((blockcount<=2)&&(microseconds<(MIN_SEGMENT_TIME))) microseconds=MIN_SEGMENT_TIME; - else if ((blockcount<=4)&&(microseconds<(MIN_SEGMENT_TIME/2))) microseconds=MIN_SEGMENT_TIME/2; - else if ((blockcount<=8)&&(microseconds<(MIN_SEGMENT_TIME/5))) microseconds=MIN_SEGMENT_TIME/5; + if ((blockcount<=2)&&(microseconds<(MIN_SEGMENT_TIME))) + microseconds=MIN_SEGMENT_TIME; + else + if ((blockcount<=4)&&(microseconds<(MIN_SEGMENT_TIME/2))) + microseconds=MIN_SEGMENT_TIME/2; + else + if ((blockcount<=8)&&(microseconds<(MIN_SEGMENT_TIME/5))) + microseconds=MIN_SEGMENT_TIME/5; + else + { +#ifdef TRAVELING_AT_MAXSPEED + //only do this if the buffer is actually full enough. Otherwise, a smallsegmented crop-travel move causes a lot of buffer underruns and jerking + if(delta_e_mm==0) //if no extrusion + { + microseconds*=0.5; // speed limits then should get working + } +#endif + + } // Calculate speed in mm/minute for each axis float multiplier = 60.0*1000000.0/microseconds; @@ -2013,7 +2029,7 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS]; if((block->acceleration_st * block->steps_e / block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) block->acceleration_st = axis_steps_per_sqr_second[E_AXIS]; - if(((block->acceleration_st / block->step_event_count) * block->steps_z ) > axis_steps_per_sqr_second[Z_AXIS]) + if((block->acceleration_st * block->steps_z / block->step_event_count) > axis_steps_per_sqr_second[Z_AXIS]) block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS]; } block->acceleration = block->acceleration_st * travel_per_step; From 152e7f454385407cb7944f1d4aad4384bf022854 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Thu, 22 Sep 2011 01:13:54 +0300 Subject: [PATCH 051/130] sane config for average users. If you survive the homeing, your build should be good. --- Marlin/Configuration.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 9026afd0b624..399df3041521 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -43,8 +43,8 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -#define SDSUPPORT // Enable SD Card Support in Hardware Console -#define FANCY_LCD // Hardware Console with 20x4 multipage LCD +//#define SDSUPPORT // Enable SD Card Support in Hardware Console +//#define FANCY_LCD // Hardware Console with 20x4 multipage LCD //#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) const int dropsegments=2; //everything with this number of steps will be ignored as move From 7c6b0f9f5458c16647572cfe02bec676f67f59d9 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Thu, 22 Sep 2011 01:17:34 +0300 Subject: [PATCH 052/130] Decreased the max speeds so average users can use this firmware --- Marlin/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 399df3041521..17cf02d057ac 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -84,7 +84,7 @@ const int dropsegments=2; //everything with this number of steps will be ignore //// MOVEMENT SETTINGS #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {200*60, 200*60, 12*60, 500000}; // set the max speeds +float max_feedrate[] = {190*60, 190*60, 10*60, 500000}; // set the max speeds //note: on bernhards ultimaker 200 200 12 are working well. float homing_feedrate[] = {70*60, 70*60, 12*60, 0}; // set the homing speeds //the followint checks if an extrusion is existent in the move. if _not_, the speed of the move is set to the maximum speed. From 5da29eb30f031cc7df0c86737b15ea044b6c1838 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Thu, 22 Sep 2011 00:19:39 +0200 Subject: [PATCH 053/130] checkautostart caused a compile error. --- Marlin/Marlin.pde | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index decbecd577d9..be85ffe5417d 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -413,7 +413,7 @@ void setup() #ifdef SDSUPPORT bool autostart_stilltocheck=true; -void checkautostart(bool force=false); //f*** u preprocessor + void checkautostart(bool force) { //this is to delay autostart and hence the initialisaiton of the sd card to some seconds after the normal init, so the device is available quick after a reset @@ -484,7 +484,7 @@ void loop() { if(buflen<3) get_command(); - checkautostart(); + checkautostart(false); if(buflen) { #ifdef SDSUPPORT From 405e7ed1b10bb2189cf93f6e84eff3014db9051b Mon Sep 17 00:00:00 2001 From: lampmaker Date: Fri, 23 Sep 2011 17:22:01 +0200 Subject: [PATCH 054/130] Branch to test alternative method of slowing down. MIN_SEGMENT_TIME is the amount of time a segment need to take in order for the buffer refill to keep up. This value can now be set using the M204 Sxxx Tyyy Bzzz command; where ZZZ is the time in microseconds (default 20000) This method -still in testing phase- showed a more smooth slowdown / ramp up when buffer underruns occur. When a segment duration (microseconds) is shorter than the MIN_SEGMENT_TIME, the buffer will start to drain. To prevent this, the duration is increased by an amount that increases as the buffer is emptied further. --- Marlin/Configuration.h | 10 +++++----- Marlin/Marlin.pde | 15 ++++++--------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 17cf02d057ac..4e87dccc7691 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -28,7 +28,8 @@ //// Calibration variables // X, Y, Z, E steps per unit - Metric Mendel / Orca with V9 extruder: -float axis_steps_per_unit[] = {79.87220447, 79.87220447, 200*8/3., 14}; +//float axis_steps_per_unit[] = {79.87220447, 79.87220447, 200*8/3., 14}; +float axis_steps_per_unit[] = {40,40,200*8/3,310}; // For E steps per unit = 67 for v9 with direct drive (needs finetuning) for other extruders this needs to be changed // Metric Prusa Mendel with Makergear geared stepper extruder: //float axis_steps_per_unit[] = {80,80,3200/1.25,1380}; @@ -90,7 +91,7 @@ float homing_feedrate[] = {70*60, 70*60, 12*60, 0}; // set the homing speeds //the followint checks if an extrusion is existent in the move. if _not_, the speed of the move is set to the maximum speed. //!!!!!!Use only if you know that your printer works at the maximum declared speeds. // works around the skeinforge cool-bug. There all moves are slowed to have a minimum layer time. However slow travel moves= ooze -#define TRAVELING_AT_MAXSPEED +//#define TRAVELING_AT_MAXSPEED bool axis_relative_modes[] = {false, false, false, false}; //// Acceleration settings @@ -116,9 +117,8 @@ long max_acceleration_units_per_sq_second[] = {9000,9000,150,10000}; // Use M201 #define MAXTEMP 275 -// minimum time in microseconds that a movement needs to take if the buffer is emptied. Increase this number if you see blobs while printing high speed & high detail. It will slowdown on the detailed stuff. -#define MIN_SEGMENT_TIME 60000 - +// minimum time in microseconds that a movement needs to take to prevent the buffer from being emptied. Higher baudrates might reduce this number. +#define MIN_SEGMENT_TIME 20000 /// PID settings: // Uncomment the following line to enable PID support. diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index be85ffe5417d..6435002db0a1 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -153,6 +153,7 @@ char serial_char; int serial_count = 0; boolean comment_mode = false; char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc +unsigned long minsegmenttime=MIN_SEGMENT_TIME; // Manage heater variables. @@ -1115,6 +1116,7 @@ inline void process_commands() { if(code_seen('S')) acceleration = code_value() ; if(code_seen('T')) retract_acceleration = code_value() ; + if(code_seen('B')) minsegmenttime = code_value() ; } break; #ifdef PIDTEMP @@ -1953,16 +1955,11 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { // added by lampmaker to slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill // reduces/removes corner blobs as the machine won't come to a full stop. int blockcount=block_buffer_head-block_buffer_tail; - //blockcount=8; while(blockcount<0) blockcount+=BLOCK_BUFFER_SIZE; - if ((blockcount<=2)&&(microseconds<(MIN_SEGMENT_TIME))) - microseconds=MIN_SEGMENT_TIME; - else - if ((blockcount<=4)&&(microseconds<(MIN_SEGMENT_TIME/2))) - microseconds=MIN_SEGMENT_TIME/2; - else - if ((blockcount<=8)&&(microseconds<(MIN_SEGMENT_TIME/5))) - microseconds=MIN_SEGMENT_TIME/5; + + if (microseconds Date: Sun, 25 Sep 2011 13:21:55 +0200 Subject: [PATCH 055/130] Prevent div by 0 in case blockcount==0 --- Marlin/Marlin.pde | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 6435002db0a1..d42e064ad994 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1956,11 +1956,11 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { // reduces/removes corner blobs as the machine won't come to a full stop. int blockcount=block_buffer_head-block_buffer_tail; while(blockcount<0) blockcount+=BLOCK_BUFFER_SIZE; - + if (blockcount>0) { if (microsecondsspeed_z = delta_z_mm * multiplier; From dee0da7937a8fbfed3eece54d0d3bb94da261093 Mon Sep 17 00:00:00 2001 From: lampmaker Date: Thu, 29 Sep 2011 17:35:23 +0300 Subject: [PATCH 056/130] Fixed error when extruding only --- Marlin/Marlin.pde | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index be85ffe5417d..4cfa80f91ffd 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -2018,7 +2018,7 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { // Compute the acceleration rate for the trapezoid generator. float travel_per_step = block->millimeters/block->step_event_count; if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { - block->acceleration = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 + block->acceleration_st = ceil( (retract_acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 } else { block->acceleration_st = ceil( (acceleration)/travel_per_step); // convert to: acceleration steps/sec^2 From a3d9721c1528da9c9797bba7bd210ea0341123be Mon Sep 17 00:00:00 2001 From: bkubicek Date: Sat, 1 Oct 2011 12:09:56 +0300 Subject: [PATCH 057/130] Edited README via GitHub --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index ecaa62129c40..c5b4d98734f6 100644 --- a/README +++ b/README @@ -62,3 +62,4 @@ KNOWN ISSUES: RepG will display: Unknown: marlin x.y.z That's ok. Enjoy Silky Smooth Printing. +[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=bkubicek&url=https://github.com/bkubicek/Marlin&title=Marlin&language=en_GB&tags=github&category=software) \ No newline at end of file From 91e0025d7e236ed1d1bddead671f622ee19de174 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Sat, 1 Oct 2011 12:10:36 +0300 Subject: [PATCH 058/130] Edited README via GitHub --- README | 1 - 1 file changed, 1 deletion(-) diff --git a/README b/README index c5b4d98734f6..ecaa62129c40 100644 --- a/README +++ b/README @@ -62,4 +62,3 @@ KNOWN ISSUES: RepG will display: Unknown: marlin x.y.z That's ok. Enjoy Silky Smooth Printing. -[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=bkubicek&url=https://github.com/bkubicek/Marlin&title=Marlin&language=en_GB&tags=github&category=software) \ No newline at end of file From 994f4d783972d33451f251ee5fc2a6119c4af335 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 1 Oct 2011 11:53:14 +0200 Subject: [PATCH 059/130] minimum feedrate --- Marlin/Configuration.h | 7 ++++--- Marlin/Marlin.pde | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 17cf02d057ac..7862e2e50886 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -43,8 +43,8 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -//#define SDSUPPORT // Enable SD Card Support in Hardware Console -//#define FANCY_LCD // Hardware Console with 20x4 multipage LCD +#define SDSUPPORT // Enable SD Card Support in Hardware Console +#define FANCY_LCD // Hardware Console with 20x4 multipage LCD //#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) const int dropsegments=2; //everything with this number of steps will be ignored as move @@ -101,6 +101,7 @@ float max_xy_jerk = 5.0*60; //speed than can be stopped at once, if i understand float max_z_jerk = 1*60; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts long max_acceleration_units_per_sq_second[] = {9000,9000,150,10000}; // Use M201 to override by software +float minimumfeedrate=20; // The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature // If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 @@ -145,7 +146,7 @@ double Kd = 80/PID_dT; //#define ADVANCE #ifdef ADVANCE -#define EXTRUDER_ADVANCE_K 0.02 +#define EXTRUDER_ADVANCE_K .3 #define D_FILAMENT 1.7 #define STEPS_MM_E 65 diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index be85ffe5417d..6832e2b6a98b 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1947,6 +1947,8 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); unsigned long microseconds; + if(feedratemillimeters/feed_rate)*1000000); From cb56af52736d85e9906b68629f776931315f413b Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 1 Oct 2011 11:55:58 +0200 Subject: [PATCH 060/130] add flattr button to github --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000000..1db2ea7b031e --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=bkubicek&url=https://github.com/bkubicek/Marlin&title=Marlin&language=en_GB&tags=github&category=software) From bea1c7cddeb93d351bedee44519d630c2bcec644 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 1 Oct 2011 11:56:59 +0200 Subject: [PATCH 061/130] sane public config --- Marlin/Configuration.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 7862e2e50886..373698d47510 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -43,8 +43,8 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -#define SDSUPPORT // Enable SD Card Support in Hardware Console -#define FANCY_LCD // Hardware Console with 20x4 multipage LCD +//#define SDSUPPORT // Enable SD Card Support in Hardware Console +//#define FANCY_LCD // Hardware Console with 20x4 multipage LCD //#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) const int dropsegments=2; //everything with this number of steps will be ignored as move From 478f68a6a5cddf1a6a6b26dc0fa945bde27505c8 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 1 Oct 2011 11:58:01 +0200 Subject: [PATCH 062/130] corrected readme --- README.md | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/README.md b/README.md index 1db2ea7b031e..ee21d963121c 100644 --- a/README.md +++ b/README.md @@ -1 +1,67 @@ [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=bkubicek&url=https://github.com/bkubicek/Marlin&title=Marlin&language=en_GB&tags=github&category=software) +This RepRap firmware is a mashup between Sprinter, grbl and many original parts. + (https://github.com/kliment/Sprinter) + (https://github.com/simen/grbl/tree) + +Derived from Sprinter and Grbl by Erik van der Zalm. +Sprinters lead developers are Kliment and caru. +Grbls lead developer is Simen Svale Skogsrud. +It has been adapted to the Ultimaker Printer by: +Bernhard Kubicek, Matthijs Keuper, Bradley Feldman, and others... + + +Features: + - Interrupt based movement with real linear acceleration + - High steprate + - Look ahead (Keep the speed high when possible. High cornering speed) + - Interrupt based temperature protection + - preliminary support for Matthew Roberts advance algorithm + For more info see: http://reprap.org/pipermail/reprap-dev/2011-May/003323.html + - Full endstop support + - Simple LCD support (16x2) + - SD Card support + - Provisions for Bernhard Kubicek's new hardware control console and 20x4 lcd + +This firmware is optimized for Ultimaker's gen6 electronics (including the Ultimaker 1.5.x daughterboard and Arduino Mega 2560). + +The default baudrate is 115200. + + +======================================================================================== + +Configuring and compilation + + +Install the latest arduino software IDE/toolset (currently 0022) + http://www.arduino.cc/en/Main/Software + +Install Ultimaker's RepG 25 build + http://software.ultimaker.com +(or alternatively install Kliment's printrun/pronterface https://github.com/kliment/Printrun_) + +Copy the Ultimaker Marlin firmware + https:/github.com/bkubicek/Marlin + (Use the download button) + +Start the arduino IDE. +Select Tools -> Board -> Arduino Mega 2560 +Select the correct serial port in Tools ->Serial Port +Open Marlin.pde + +Click the Verify/Compile button + +Click the Upload button +If all goes well the firmware is uploading + +Start Ultimaker's Custom RepG 25 +Make sure Show Experimental Profiles is enabled in Preferences +Select Sprinter as the Driver + +Press the Connect button. + +KNOWN ISSUES: RepG will display: Unknown: marlin x.y.z + +That's ok. Enjoy Silky Smooth Printing. + + + From 48517b8876995599ec337c4f97665c1cb745c1e0 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Sat, 1 Oct 2011 13:30:22 +0300 Subject: [PATCH 063/130] Edited README.md via GitHub --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ee21d963121c..b1e154e26d77 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ +Donate via: [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=bkubicek&url=https://github.com/bkubicek/Marlin&title=Marlin&language=en_GB&tags=github&category=software) -This RepRap firmware is a mashup between Sprinter, grbl and many original parts. - (https://github.com/kliment/Sprinter) - (https://github.com/simen/grbl/tree) +or Paypal + +This RepRap firmware is a mashup between Sprinter, grbl and many original parts. Derived from Sprinter and Grbl by Erik van der Zalm. Sprinters lead developers are Kliment and caru. From c884af293bbda4af63c01f227fcec65f7584df46 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Sat, 1 Oct 2011 13:45:46 +0300 Subject: [PATCH 064/130] Edited README.md via GitHub --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b1e154e26d77..35178b1850be 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -Donate via: +Donate to this reposotiroy maintainer: [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=bkubicek&url=https://github.com/bkubicek/Marlin&title=Marlin&language=en_GB&tags=github&category=software) or Paypal +Donate to the reprap foundation + This RepRap firmware is a mashup between Sprinter, grbl and many original parts. Derived from Sprinter and Grbl by Erik van der Zalm. From 61b665c35ff92d32957234160a8feebfab95ba77 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Sat, 1 Oct 2011 14:36:53 +0300 Subject: [PATCH 065/130] Edited README.md via GitHub --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 35178b1850be..621b03c301fa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Donate to this reposotiroy maintainer: +Donate to this repository maintainer: [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=bkubicek&url=https://github.com/bkubicek/Marlin&title=Marlin&language=en_GB&tags=github&category=software) or Paypal From e3b53eb32ac321135e7101cebe5881fb3b0dc7ed Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 1 Oct 2011 15:36:03 +0200 Subject: [PATCH 066/130] remove old menu --- Marlin/menu_base.h | 105 ------------------------------------------- Marlin/menu_base.pde | 65 --------------------------- 2 files changed, 170 deletions(-) delete mode 100644 Marlin/menu_base.h delete mode 100644 Marlin/menu_base.pde diff --git a/Marlin/menu_base.h b/Marlin/menu_base.h deleted file mode 100644 index 5cdef3fd1c51..000000000000 --- a/Marlin/menu_base.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef __MENU_BASE -#define __MENU_BASE -#include "LiquidCrystal.h" -extern LiquidCrystal lcd; -class MenuPage -{ -public: - MenuPage(); - void lineUp(); - void lineDown(); - virtual void activate()=0; - virtual void update()=0; - - int8_t line; - int8_t items; - int8_t xshift; - int8_t firstline; - - inline void emptyline() - { - if(items>0) - { - lcd.setCursor((line/(4-firstline))*xshift,firstline+line%(4-firstline)); - lcd.print(" "); - } - }; - inline void fillline() - { - if(items>0) - { - lcd.setCursor((line/(4-firstline))*xshift,firstline+line%(4-firstline)); - lcd.print("~"); - } - }; -}; - -#define MAXPAGES 10 - - -class MenuBase -{ -public: - MenuBase(); - ~MenuBase(); - - - void addMenuPage(MenuPage *_newpage); - - - inline void pageUp() - { - //if(pages[curPage!=0]) - // pages[curPage]->deactivate(); - curPage++; - if(curPage>=maxPage) - { - curPage=0; - } - if(pages[curPage]!=0) - pages[curPage]->activate(); - - }; - - inline void pageDown() - { - //if(pages[curPage!=0]) - // pages[curPage]->deactivate(); - curPage--; - if(curPage<0) - { - curPage=maxPage-1; - } - if(pages[curPage]!=0) - pages[curPage]->activate(); - }; - - inline void lineUp() - { - if(pages[curPage]!=0) - pages[curPage]->lineUp(); - }; - - inline void lineDown() - { - if(pages[curPage]!=0) - pages[curPage]->lineDown(); - }; - - inline void update() - { - pages[curPage]->update(); - }; - -public: - //short int curLine; - short int curPage; - short int maxPage; - MenuPage *pages[MAXPAGES]; -}; - - -#endif - - - diff --git a/Marlin/menu_base.pde b/Marlin/menu_base.pde deleted file mode 100644 index 3bdec26365f5..000000000000 --- a/Marlin/menu_base.pde +++ /dev/null @@ -1,65 +0,0 @@ -#include "menu_base.h" -//#include -//extern LiquidCrystal lcd; -extern "C" { - void __cxa_pure_virtual() - { - // put error handling here - } -} - -MenuBase::MenuBase() -{ -//lcd=_lcd; - curPage=0; - //curLine=0; - maxPage=0; - for(int i=0;iactivate(); - } - maxPage++; - } -} - - -MenuPage::MenuPage() -{ - line=0; - firstline=1; -} - -void MenuPage::lineUp() -{ - emptyline(); - if(line==0) - line=items; - else - line--; - fillline(); -} - -void MenuPage::lineDown() -{ - emptyline(); - if(line==items) - line=0; - else - line++; - fillline(); -} - From bb0402d3f82c5574c447e760289aee6afd49d234 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 1 Oct 2011 15:45:10 +0200 Subject: [PATCH 067/130] cleanup --- Marlin/Configuration.h | 1 + Marlin/lcd.h | 2 +- Marlin/lcd.pde | 415 +---------------------------------------- 3 files changed, 4 insertions(+), 414 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 373698d47510..025b60d3782c 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -46,6 +46,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the //#define SDSUPPORT // Enable SD Card Support in Hardware Console //#define FANCY_LCD // Hardware Console with 20x4 multipage LCD //#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) +#define ULTRA_LCD //improved 3 button or clickencoder interface const int dropsegments=2; //everything with this number of steps will be ignored as move //// ADVANCED SETTINGS - to tweak parameters diff --git a/Marlin/lcd.h b/Marlin/lcd.h index 7cddcc93cce7..dedd42fc49a2 100644 --- a/Marlin/lcd.h +++ b/Marlin/lcd.h @@ -1,7 +1,7 @@ #ifndef __LCDH #define __LCDH -#if defined FANCY_LCD || defined SIMPLE_LCD +#ifdef ULTRA_LCD #define LCD_UPDATE_INTERVAL 400 #include "Configuration.h" diff --git a/Marlin/lcd.pde b/Marlin/lcd.pde index 39cf0c73845c..d97fc3e7919c 100644 --- a/Marlin/lcd.pde +++ b/Marlin/lcd.pde @@ -1,7 +1,7 @@ #include "lcd.h" #include "pins.h" -#if defined FANCY_LCD || defined SIMPLE_LCD +#ifdef ULTRA_LCD extern volatile int feedmultiply; #include @@ -10,9 +10,8 @@ LiquidCrystal lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5,LCD_PIN unsigned long previous_millis_lcd=0; -#ifdef FANCY_LCD + #include "buttons.h" -#endif //FANCY_LCD #include "menu_base.h" @@ -23,7 +22,6 @@ char messagetext[LCD_WIDTH]=""; bool force_lcd_update=false; -extern LiquidCrystal lcd; //return for string conversion routines @@ -86,408 +84,11 @@ char *fillto(int8_t n,char *c) #include "menu_base.h" MenuBase menu; -class PageWatch:public MenuPage -{ -public: - PageWatch(); - - virtual void activate(); - virtual void update(); - int lastencoder; -}; - -PageWatch::PageWatch() -{ - xshift=10;items=0; -} - -void PageWatch::update() -{ - if(messagetext[0]) - { - lcd.setCursor(0,1); - lcd.print(fillto(LCD_WIDTH,messagetext)); - messagetext[0]=0; - } -#ifdef FANCY_LCD - if(encoderpos!=lastencoder) - { - lcd.setCursor(0,2); - lcd.print("Speed: "); - if(encoderpos<5) encoderpos=5; - if(encoderpos>600) encoderpos=600; - feedmultiply=encoderpos; - lcd.print(encoderpos); - lcd.print(" "); - lastencoder=encoderpos; - } -#endif FANCY_LCD - static int n=0; - if(n++%4) - return; //slower updates - char line1[25]; - static char blink=0; - if (blink == 0) - { - lcd.setCursor(0,0); - lcd.print(fillto(LCD_WIDTH,"booting...")); - blink++; - } - else - { - sprintf(line1,"%c%3i/%3i\1%c%c%c%c%c%c", ((blink++)%2==0)? (char)2:' ', - int(analog2temp(current_raw)), - int(analog2temp(target_raw)), - (!digitalRead(X_MIN_PIN))? 'x':' ', - (!digitalRead(X_MAX_PIN))? 'X':' ', - (!digitalRead(Y_MIN_PIN))? 'y':' ', - (!digitalRead(Y_MAX_PIN))? 'Y':' ', - (!digitalRead(Z_MIN_PIN))? 'z':' ', - (!digitalRead(Z_MAX_PIN))? 'Z':' '); - - lcd.setCursor(0,0); - lcd.print(fillto(LCD_WIDTH,line1)); - } -} - -void PageWatch::activate() -{ -#ifdef FANCY_LCD - encoderpos=feedmultiply; -#endif - lcd.setCursor(0,0); - lcd.print(fillto(LCD_WIDTH," ")); -#if 0 - lcd.setCursor(0, 1); - //copy last printed gcode line from the buffer onto the lcd - char cline2[LCD_WIDTH]; - memset(cline2,0,LCD_WIDTH); - strncpy(cline2,cmdbuffer[(abs(bufindr-1))%BUFSIZE],LCD_WIDTH-1); //the last processed line - cline2[LCD_WIDTH-1]=0; - bool print=(strlen(cline2)>0); - - if(1&&print) - { - lcd.print(fillto(LCD_WIDTH,cline2)); - } - if(LCD_HEIGHT>2) - { - lcd.setCursor(0, 2); - strncpy(cline2,cmdbuffer[(abs(bufindr-2))%BUFSIZE],LCD_WIDTH-1); //the last processed line - cline2[LCD_WIDTH-1]=0; - bool print=(strlen(cline2)>0); - - if(1&&print) - { - lcd.print(fillto(LCD_WIDTH,cline2)); - } - lcd.setCursor(0,3); - lcd.print(fillto(LCD_WIDTH,messagetext)); - - } -#else - lcd.setCursor(0,1);lcd.print(fillto(LCD_WIDTH," ")); - lcd.setCursor(0,2);lcd.print(fillto(LCD_WIDTH," ")); - lcd.setCursor(0,3);lcd.print(fillto(LCD_WIDTH," ")); -#endif - fillline(); - update(); -} - -#ifdef FANCY_LCD - -int lastline=-1; -int lastencoder=0; -int step=2; - -#ifdef PAGEMOVE -class PageMove:public MenuPage -{ -public: - PageMove(); - - virtual void activate(); - virtual void update(); -}; - -//extern float current_x, current_y , current_z , current_e ; -extern float current_position[NUM_AXIS]; -float target_x,target_y,target_z,target_e; - - - -PageMove::PageMove() -{ - xshift=10;items=4; -} - - -void PageMove::update() -{ - - if(line!=lastline) - { - lastencoder=encoderpos; - target_x=current_position[X_AXIS]; - target_y=current_position[Y_AXIS]; - target_z=current_position[Z_AXIS]; - target_e=current_position[E_AXIS]; - } - else //update on the same selected line - if(lastencoder!=encoderpos) //change in encoder - { - int d=encoderpos-lastencoder; - char c=';'; - float cur=0; - if(line==4) - { - step+=d; - if(step<1) step=1; - } - else - { - switch(line) - { - case 0:c='X';cur=target_x+=step*d/10.;break; - case 1:c='Y';cur=target_y+=step*d/10.;break; - case 2:c='Z';cur=target_z+=step*d/10.;break; - case 3:c='E';cur=target_e+=step*d/10.;break; - } - char com[20]; - sprintf(com,"G1 %c%i.%i",c,int(cur),int(fabs(cur*10))%10); - enquecommand(com); - } - lastencoder=encoderpos; - } - else - { - //Serial.print("encoder: ");Serial.println(encoderpos); - } - lastline=line; - activate(); -} - -void PageMove::activate() -{ - lcd.setCursor(0,0); - lcd.print("Manual Move "); - lcd.setCursor(0,1); - lcd.print(" X");lcd.print(ftostr31(current_position[X_AXIS]));lcd.print(" E");lcd.print(ftostr51(current_position[E_AXIS])); - lcd.setCursor(0,2); - lcd.print(" Y");lcd.print(ftostr31(current_position[Y_AXIS]));lcd.print(" St");lcd.print(ftostr31(step/10.));lcd.print(" "); - lcd.setCursor(0,3); - lcd.print(" Z");lcd.print(ftostr31(current_position[Z_AXIS]));lcd.print(" "); - fillline(); -} -#endif -class PageHome:public MenuPage -{ -public: - PageHome(); - - virtual void activate(); - virtual void update(); -}; - - -PageHome::PageHome() -{ - xshift=10;items=5; -} - -void PageHome::update() -{ - if(buttons&B_MI) - { - blocking[BL_MI]=millis()+blocktime; - switch(line) - { - case 0:enquecommand("G28 X");break; - case 1:enquecommand("G28 Y");break; - case 2:enquecommand("G28 Z");break; - case 3:enquecommand("G92 X0");break; - case 4:enquecommand("G92 Y0");break; - case 5:enquecommand("G92 Z0");break; - default: - ; - } - } - activate(); -} - -void PageHome::activate() -{ - lcd.setCursor(0,0); - lcd.print(fillto(20,"Home")); - lcd.setCursor(0,1); - lcd.print(fillto(20," X ZERO")); - lcd.setCursor(0,2); - lcd.print(fillto(20," Y ZERO")); - lcd.setCursor(0,3); - lcd.print(fillto(20," Z ZERO")); - fillline(); -} - -#ifdef SDSUPPORT -#include "SdFat.h" - -class PageSd:public MenuPage -{ -public: - PageSd(); - - virtual void activate(); - virtual void update(); - int fileoffset,nrfiles; -}; - -#define FILTERSD if (p.name[0] == DIR_NAME_FREE) break;if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;if(p.name[8]!='G') continue;if(p.name[9]=='~') continue; -PageSd::PageSd() -{ - xshift=10;items=7;firstline=0; - fileoffset=0; - nrfiles=0; -} - -void PageSd::update() -{ - if(buttons&B_ST) //reset sd card - { - sdactive = false; - sdmode = false; - initsd(); - } - if(encoderpos!=lastencoder) //scoll through files - { - fileoffset=encoderpos%nrfiles; - if(fileoffset>nrfiles-8) fileoffset=nrfiles-8; - if(fileoffset<0) fileoffset=0; - activate(); - lastencoder=encoderpos; - - } - if(buttons&B_MI) //start print - { - blocking[BL_MI]=millis()+blocktime; - - dir_t p; - - root.rewind(); - char filename[11]; - int cnt=0; - lastencoder=encoderpos; - while (root.readDir(p) > 0) - { - FILTERSD - uint8_t writepos=0; - for (uint8_t i = 0; i < 11; i++) { - - if (p.name[i] == ' ') continue; - if (i == 8) { - filename[writepos++]='.'; - } - filename[writepos++]=p.name[i]; - } - filename[writepos++]=0; - if(cnt==line) - break; - cnt++; - - } - char cmd[50]; - for(int i=0;i 0) - { - // done if past last used entry - FILTERSD - Serial.println((char*)p.name); - Serial.println(strlen((char*)p.name)); - Serial.println((char)p.name[strlen((char*)p.name)-1]); - - nrfiles++; - } - root.rewind(); - cnt=0; - int precount=0; - while (root.readDir(p) > 0) - { - FILTERSD - if(precount++8) - break; - lcd.setCursor(0+10*(cnt/4),cnt%4); - lcd.print(" "); - lcd.print(fillto(9,filename));cnt++; - - - - } - for(;cnt<9;cnt++) - { - lcd.setCursor(0+10*(cnt/4),cnt%4); - lcd.print(fillto(9," ")); - } - - fillline(); -} - -PageSd pagesd; -#endif // SD_SUPPORT - -#ifdef PAGEMOVE -PageMove pagemove; -#endif - -PageHome pagehome; -#endif // FANCY_LCD -PageWatch pagewatch; void lcd_status(const char* message) { -// if(LCD_HEIGHT>3) -// lcd.setCursor(0,3); -// else -// lcd.setCursor(0,0); -// lcd.print(message); -// int missing=(LCD_WIDTH-strlen(message)); -// if(missing>0) -// for(int i=0;i Date: Sat, 1 Oct 2011 23:10:18 +0200 Subject: [PATCH 068/130] no test --- Marlin/lcd.pde | 117 -------------------------- Marlin/ultralcd.h | 68 +++++++++++++++ Marlin/ultralcd.pde | 201 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 269 insertions(+), 117 deletions(-) create mode 100644 Marlin/ultralcd.h create mode 100644 Marlin/ultralcd.pde diff --git a/Marlin/lcd.pde b/Marlin/lcd.pde index d97fc3e7919c..c5c41330f3c6 100644 --- a/Marlin/lcd.pde +++ b/Marlin/lcd.pde @@ -13,8 +13,6 @@ unsigned long previous_millis_lcd=0; #include "buttons.h" -#include "menu_base.h" - char messagetext[LCD_WIDTH]=""; @@ -24,67 +22,6 @@ bool force_lcd_update=false; -//return for string conversion routines -char conv[8]; - -/// convert float to string with +123.4 format -char *ftostr31(const float &x) -{ - //sprintf(conv,"%5.1f",x); - int xx=x*10; - conv[0]=(xx>=0)?'+':'-'; - xx=abs(xx); - conv[1]=(xx/1000)%10+'0'; - conv[2]=(xx/100)%10+'0'; - conv[3]=(xx/10)%10+'0'; - conv[4]='.'; - conv[5]=(xx)%10+'0'; - conv[6]=0; - return conv; -} - -/// convert float to string with +1234.5 format -char *ftostr51(const float &x) -{ - int xx=x*10; - conv[0]=(xx>=0)?'+':'-'; - xx=abs(xx); - conv[1]=(xx/10000)%10+'0'; - conv[2]=(xx/1000)%10+'0'; - conv[3]=(xx/100)%10+'0'; - conv[4]=(xx/10)%10+'0'; - conv[5]='.'; - conv[6]=(xx)%10+'0'; - conv[7]=0; - return conv; -} - -char *fillto(int8_t n,char *c) -{ - static char ret[25]; - bool endfound=false; - for(int8_t i=0;i=0)?'+':'-'; + xx=abs(xx); + conv[1]=(xx/1000)%10+'0'; + conv[2]=(xx/100)%10+'0'; + conv[3]=(xx/10)%10+'0'; + conv[4]='.'; + conv[5]=(xx)%10+'0'; + conv[6]=0; + return conv; +} + +/// convert float to string with +1234.5 format +char *ftostr51(const float &x) +{ + int xx=x*10; + conv[0]=(xx>=0)?'+':'-'; + xx=abs(xx); + conv[1]=(xx/10000)%10+'0'; + conv[2]=(xx/1000)%10+'0'; + conv[3]=(xx/100)%10+'0'; + conv[4]=(xx/10)%10+'0'; + conv[5]='.'; + conv[6]=(xx)%10+'0'; + conv[7]=0; + return conv; +} + +char *fillto(int8_t n,char *c) +{ + static char ret[25]; + bool endfound=false; + for(int8_t i=0;i Date: Sun, 2 Oct 2011 21:02:19 +0200 Subject: [PATCH 069/130] pretestingextruder --- Marlin/Configuration.h | 5 +- Marlin/Marlin.pde | 2 +- Marlin/lcd.h | 28 -------- Marlin/lcd.pde | 83 ---------------------- Marlin/ultralcd.h | 153 ++++++++++++++++++++++++----------------- Marlin/ultralcd.pde | 135 +++++++++++++++++++++++++++++++++--- 6 files changed, 218 insertions(+), 188 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 025b60d3782c..9bf271576aec 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -43,9 +43,8 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -//#define SDSUPPORT // Enable SD Card Support in Hardware Console -//#define FANCY_LCD // Hardware Console with 20x4 multipage LCD -//#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) +#define SDSUPPORT // Enable SD Card Support in Hardware Console + #define ULTRA_LCD //improved 3 button or clickencoder interface const int dropsegments=2; //everything with this number of steps will be ignored as move diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 557be0f789a8..f58cd9c19727 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -43,7 +43,7 @@ #include "pins.h" #include "Marlin.h" #include "speed_lookuptable.h" -#include "lcd.h" +#include "ultralcd.h" char version_string[] = "U0.9.3.3-BK"; diff --git a/Marlin/lcd.h b/Marlin/lcd.h index dedd42fc49a2..74057ddde12e 100644 --- a/Marlin/lcd.h +++ b/Marlin/lcd.h @@ -1,38 +1,10 @@ #ifndef __LCDH #define __LCDH -#ifdef ULTRA_LCD - #define LCD_UPDATE_INTERVAL 400 - #include "Configuration.h" - #include - extern LiquidCrystal lcd; - //lcd display size - #ifdef FANCY_LCD - #define LCD_WIDTH 20 - #define LCD_HEIGHT 4 - #else - #define LCD_WIDTH 16 - #define LCD_HEIGHT 2 - #endif - //arduino pin witch triggers an piezzo beeper - #define BEEPER 18 - void lcd_status(); - void lcd_init(); - void lcd_status(const char* message); - void beep(); - - - - #define LCD_MESSAGE(x) lcd_status(x); - #define LCD_STATUS lcd_status() -#else - #define LCD_STATUS - #define LCD_MESSAGE(x) -#endif #endif diff --git a/Marlin/lcd.pde b/Marlin/lcd.pde index c5c41330f3c6..8b137891791f 100644 --- a/Marlin/lcd.pde +++ b/Marlin/lcd.pde @@ -1,84 +1 @@ -#include "lcd.h" -#include "pins.h" - -#ifdef ULTRA_LCD -extern volatile int feedmultiply; - -#include -LiquidCrystal lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5,LCD_PINS_D6,LCD_PINS_D7); //RS,Enable,D4,D5,D6,D7 - -unsigned long previous_millis_lcd=0; - - - -#include "buttons.h" - -char messagetext[LCD_WIDTH]=""; - - - -bool force_lcd_update=false; - - - - - - -void lcd_status(const char* message) -{ - strncpy(messagetext,message,LCD_WIDTH); -} - -long previous_millis_buttons=0; - -void lcd_init() -{ -#ifdef FANCY_LCD - buttons_init(); - beep(); -#endif //FANCY LCD - byte Degree[8] = - { - B01100, - B10010, - B10010, - B01100, - B00000, - B00000, - B00000, - B00000 - }; - byte Thermometer[8] = - { - B00100, - B01010, - B01010, - B01010, - B01010, - B10001, - B10001, - B01110 - }; - - lcd.begin(LCD_WIDTH, LCD_HEIGHT); - lcd.createChar(1,Degree); - lcd.createChar(2,Thermometer); - LCD_MESSAGE(fillto(LCD_WIDTH,"UltiMarlin ready.")); -} - - -void beep() -{ - // [ErikDeBruijn] changed to two short beeps, more friendly - pinMode(BEEPER,OUTPUT); - for(int i=0;i<20;i++){ - digitalWrite(BEEPER,HIGH); - delay(5); - digitalWrite(BEEPER,LOW); - delay(5); - } - -} - -#endif diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h index 70cab16e1235..3c047b292278 100644 --- a/Marlin/ultralcd.h +++ b/Marlin/ultralcd.h @@ -1,68 +1,97 @@ #ifndef __ULTRALCDH #define __ULTRALCDH -const int nrSubmenus=5; -const bool statusRight=true; - -//buttons are attached to a shift register -#define SHIFT_CLK 38 -#define SHIFT_LD 42 -#define SHIFT_OUT 40 -#define SHIFT_EN 17 - -// blocking time for recognizing a new keypress of one key, ms -#define blocktime 500 - - -//bits in the shift register that carry the buttons for: -// left up center down right red -#define BL_LE 7 -#define BL_UP 6 -#define BL_MI 5 -#define BL_DW 4 -#define BL_RI 3 -#define BL_ST 2 - -#define BLEN_B 1 -#define BLEN_A 0 - -//encoder rotation values -#define encrot0 0 -#define encrot1 2 -#define encrot2 3 -#define encrot3 1 - -//atomatic, do not change -#define B_LE (1< + extern LiquidCrystal lcd; + + //lcd display size + #define LCD_WIDTH 20 + #define LCD_HEIGHT 4 + + //arduino pin witch triggers an piezzo beeper + #define BEEPER 18 + + //buttons are attached to a shift register + #define SHIFT_CLK 38 + #define SHIFT_LD 42 + #define SHIFT_OUT 40 + #define SHIFT_EN 17 + + // blocking time for recognizing a new keypress of one key, ms + #define blocktime 500 + + + //bits in the shift register that carry the buttons for: + // left up center down right red + #define BL_LE 7 + #define BL_UP 6 + #define BL_MI 5 + #define BL_DW 4 + #define BL_RI 3 + #define BL_ST 2 + + #define BLEN_B 1 + #define BLEN_A 0 + + //encoder rotation values + #define encrot0 0 + #define encrot1 2 + #define encrot2 3 + #define encrot3 1 + + //atomatic, do not change + #define B_LE (1< +LiquidCrystal lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5,LCD_PINS_D6,LCD_PINS_D7); //RS,Enable,D4,D5,D6,D7 + +unsigned long previous_millis_lcd=0; + + + volatile char buttons=0; //the last checked buttons in a bit array. int encoderpos=0; short lastenc=0; @@ -7,6 +19,60 @@ long blocking[8]={ 0,0,0,0,0,0,0,0}; MainMenu menu; +void lcd_status(const char* message) +{ + strncpy(messagetext,message,LCD_WIDTH); +} + +long previous_millis_buttons=0; + +void lcd_init() +{ + beep(); + byte Degree[8] = + { + B01100, + B10010, + B10010, + B01100, + B00000, + B00000, + B00000, + B00000 + }; + byte Thermometer[8] = + { + B00100, + B01010, + B01010, + B01010, + B01010, + B10001, + B10001, + B01110 + }; + + lcd.begin(LCD_WIDTH, LCD_HEIGHT); + lcd.createChar(1,Degree); + lcd.createChar(2,Thermometer); + LCD_MESSAGE(fillto(LCD_WIDTH,"UltiMarlin ready.")); +} + + +void beep() +{ + // [ErikDeBruijn] changed to two short beeps, more friendly + pinMode(BEEPER,OUTPUT); + for(int i=0;i<20;i++){ + digitalWrite(BEEPER,HIGH); + delay(5); + digitalWrite(BEEPER,LOW); + delay(5); + } + +} +bool force_lcd_update=false; + void lcd_status() { static long previous_millis_buttons=0; @@ -109,24 +175,69 @@ MainMenu::MainMenu() activemenu=0; subactive=false; displayStartingRow=0; - buttons_init(); + buttonlcd_inits_init(); + lcd_init(); } -void MainMenu::update() +void MainMenu::showStatusRight() +{ +#ifdef LCDSTATUSRIGHT + static int oldcurrentraw=-1; + static int oldtargetraw=-1; + if(current_raw!=oldcurrentraw) + { + lcd.setCursor(LCD_WIDTH-4,0); + lcd.print('H'); + lcd.print(ftostr3(analog2temp(current_raw))); + oldcurrentraw=current_raw; + } + if(target_raw!=oldtargetraw) + { + lcd.setCursor(LCD_WIDTH-4,1); + lcd.print('T'); + lcd.print(ftostr3(analog2temp(target_raw))); + oldtargetraw=target_raw; + } +#endif +} +void MainMenu::showSubTemperature() { - if(statusRight) +} +void MainMenu::showSubTune() +{ + +} +void MainMenu::update() +{ + showStatusRight(); + if(!subactive) + { + + for(short line=0;line Date: Tue, 4 Oct 2011 11:05:14 +0200 Subject: [PATCH 070/130] Added possibility to store data in EEPROM M500 stores data in EEPROM M501 retreives stored data M501 reverts data to 'factory defaults' Data stored: all data set by M92, M201, M203, M204, M205 commands; Also: M205 stores advanced settings: S=min feedrate, T=min travel feedrate, X=max XY jerk, Z=max Z jerk, B=min segment time Removed the 'travel at maxspeed' compiler switch; if M205 T0 is used, there is no lower limit Moved all speed, acceleration, etc variable definitions to marlin.PDE. Configuration.h now only contains default values prevented div/0 errors when acceleration is set to 0 --- Marlin/Configuration.h | 38 ++++++------- Marlin/EEPROM.h | 119 +++++++++++++++++++++++++++++++++++++++++ Marlin/Marlin.pde | 92 ++++++++++++++++++++++++------- 3 files changed, 207 insertions(+), 42 deletions(-) create mode 100644 Marlin/EEPROM.h diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index f2c84f235f93..526c3fa02184 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -26,13 +26,6 @@ #define BNUMTEMPS NUMTEMPS #define bedtemptable temptable -//// Calibration variables -// X, Y, Z, E steps per unit - Metric Mendel / Orca with V9 extruder: -//float axis_steps_per_unit[] = {79.87220447, 79.87220447, 200*8/3., 14}; -float axis_steps_per_unit[] = {40,40,200*8/3,310}; -// For E steps per unit = 67 for v9 with direct drive (needs finetuning) for other extruders this needs to be changed -// Metric Prusa Mendel with Makergear geared stepper extruder: -//float axis_steps_per_unit[] = {80,80,3200/1.25,1380}; //// Endstop Settings #define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors @@ -85,24 +78,26 @@ const int dropsegments=2; //everything with this number of steps will be ignore //// MOVEMENT SETTINGS #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {190*60, 190*60, 10*60, 500000}; // set the max speeds //note: on bernhards ultimaker 200 200 12 are working well. float homing_feedrate[] = {70*60, 70*60, 12*60, 0}; // set the homing speeds -//the followint checks if an extrusion is existent in the move. if _not_, the speed of the move is set to the maximum speed. -//!!!!!!Use only if you know that your printer works at the maximum declared speeds. -// works around the skeinforge cool-bug. There all moves are slowed to have a minimum layer time. However slow travel moves= ooze -//#define TRAVELING_AT_MAXSPEED bool axis_relative_modes[] = {false, false, false, false}; -//// Acceleration settings -// X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. -float acceleration = 4600; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX -float retract_acceleration = 7000; // mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX -float max_xy_jerk = 5.0*60; //speed than can be stopped at once, if i understand correctly. -float max_z_jerk = 1*60; -// X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts -long max_acceleration_units_per_sq_second[] = {9000,9000,150,10000}; // Use M201 to override by software -float minimumfeedrate=20; + +// default settings + +#define DEFAULT_AXIS_STEPS_PER_UNIT {80,80,200*8/3,14}; // default steps per unit for ultimaker +#define DEFAULT_MAX_FEEDRATE {190*60, 190*60, 10*60, 500000} +#define DEFAULT_MAX_ACCELERATION {9000,9000,150,10000} // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. + +#define DEFAULT_ACCELERATION 4600; // X, Y, Z and E max acceleration in mm/s^2 for printing moves +#define DEFAULT_RETRACT_ACCELERATION 7000; // X, Y, Z and E max acceleration in mm/s^2 for r retracts + +#define DEFAULT_MINIMUMFEEDRATE 20*60; // minimum feedrate +#define DEFAULT_MINTRAVELFEEDRATE 20*60; +#define DEFAULT_MINSEGMENTTIME 20000; // minimum segmenttime to prevent buffer underruns +#define DEFAULT_XYJERK 5.0*60; +#define DEFAULT_ZJERK 1.0*60; + // The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature // If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 @@ -119,7 +114,6 @@ float minimumfeedrate=20; // minimum time in microseconds that a movement needs to take to prevent the buffer from being emptied. Higher baudrates might reduce this number. -#define MIN_SEGMENT_TIME 20000 /// PID settings: // Uncomment the following line to enable PID support. diff --git a/Marlin/EEPROM.h b/Marlin/EEPROM.h new file mode 100644 index 000000000000..02914ea1c7f5 --- /dev/null +++ b/Marlin/EEPROM.h @@ -0,0 +1,119 @@ +//====================================================================================== +template int EEPROM_writeAnything(int &ee, const T& value) +{ + const byte* p = (const byte*)(const void*)&value; + int i; + for (i = 0; i < sizeof(value); i++) + EEPROM.write(ee++, *p++); + return i; +} +//====================================================================================== +template int EEPROM_readAnything(int &ee, T& value) +{ + byte* p = (byte*)(void*)&value; + int i; + for (i = 0; i < sizeof(value); i++) + *p++ = EEPROM.read(ee++); + return i; +} +//====================================================================================== + + +#define EEPROM_OFFSET 100 + +#define EEPROM_VERSION "V03" // IMPORTANT: Whenever there are changes made to the variables stored in EEPROM + // in the functions below, also increment the version number. This makes sure that + // the default values are used whenever there is a change to the data, to prevent + // wrong data being written to the variables. + // ALSO: always make sure the variables in the Store and retrieve sections are in the same order. +void StoreSettings() { + char ver[4]= "000"; + int i=EEPROM_OFFSET; + EEPROM_writeAnything(i,ver); // invalidate data first + EEPROM_writeAnything(i,axis_steps_per_unit); + EEPROM_writeAnything(i,max_feedrate); + EEPROM_writeAnything(i,max_acceleration_units_per_sq_second); + EEPROM_writeAnything(i,acceleration); + EEPROM_writeAnything(i,retract_acceleration); + EEPROM_writeAnything(i,minimumfeedrate); + EEPROM_writeAnything(i,mintravelfeedrate); + EEPROM_writeAnything(i,minsegmenttime); + EEPROM_writeAnything(i,max_xy_jerk); + EEPROM_writeAnything(i,max_z_jerk); + char ver2[4]=EEPROM_VERSION; + i=EEPROM_OFFSET; + EEPROM_writeAnything(i,ver2); // validate data + Serial.println("Settings Stored"); + +} + +void RetrieveSettings(bool def=false){ // if def=true, the default values will be used + int i=EEPROM_OFFSET; + char stored_ver[4]; + char ver[4]=EEPROM_VERSION; + EEPROM_readAnything(i,stored_ver); //read stored version + Serial.print("Version: [");Serial.print(ver);Serial.print("] Stored version: [");Serial.print(stored_ver);Serial.println("]"); + if ((!def)&&(strncmp(ver,stored_ver,3)==0)) { // version number match + EEPROM_readAnything(i,axis_steps_per_unit); + EEPROM_readAnything(i,max_feedrate); + EEPROM_readAnything(i,max_acceleration_units_per_sq_second); + EEPROM_readAnything(i,acceleration); + EEPROM_readAnything(i,retract_acceleration); + EEPROM_readAnything(i,minimumfeedrate); + EEPROM_readAnything(i,mintravelfeedrate); + EEPROM_readAnything(i,minsegmenttime); + EEPROM_readAnything(i,max_xy_jerk); + EEPROM_readAnything(i,max_z_jerk); + Serial.println("Stored settings retreived:"); + } + else { + float tmp1[]=DEFAULT_AXIS_STEPS_PER_UNIT; + float tmp2[]=DEFAULT_MAX_FEEDRATE; + long tmp3[]=DEFAULT_MAX_ACCELERATION; + for (int i=0;i<4;i++) { + axis_steps_per_unit[i]=tmp1[i]; + max_feedrate[i]=tmp2[i]; + max_acceleration_units_per_sq_second[i]=tmp3[i]; + } + acceleration=DEFAULT_ACCELERATION; + retract_acceleration=DEFAULT_RETRACT_ACCELERATION; + minimumfeedrate=DEFAULT_MINIMUMFEEDRATE + minsegmenttime=DEFAULT_MINSEGMENTTIME; + mintravelfeedrate=DEFAULT_MINTRAVELFEEDRATE + max_xy_jerk=DEFAULT_XYJERK; + max_z_jerk=DEFAULT_ZJERK; + Serial.println("Using Default settings:"); + } + Serial.println("Steps per unit:"); + Serial.print(" M92"); + Serial.print(" X");Serial.print(axis_steps_per_unit[0]); + Serial.print(" Y");Serial.print(axis_steps_per_unit[1]); + Serial.print(" Z");Serial.print(axis_steps_per_unit[2]); + Serial.print(" E");Serial.println(axis_steps_per_unit[3]); + Serial.println("Maximum feedrates (mm/s):"); + Serial.print (" M203"); + Serial.print(" X");Serial.print(max_feedrate[0]/60); + Serial.print(" Y");Serial.print(max_feedrate[1]/60); + Serial.print(" Z");Serial.print(max_feedrate[2]/60); + Serial.print(" E");Serial.println(max_feedrate[3]/60); + Serial.println("Maximum Acceleration (mm/s2):"); + Serial.print(" M201"); + Serial.print(" X");Serial.print(max_acceleration_units_per_sq_second[0]); + Serial.print(" Y");Serial.print(max_acceleration_units_per_sq_second[1]); + Serial.print(" Z");Serial.print(max_acceleration_units_per_sq_second[2]); + Serial.print(" E");Serial.println(max_acceleration_units_per_sq_second[3]); + Serial.println("Acceleration: S=acceleration, T=retract acceleration"); + Serial.print(" M204"); + Serial.print(" S");Serial.print(acceleration); + Serial.print(" T");Serial.println(retract_acceleration); + Serial.println("Advanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum xY jerk (mm/s), Z=maximum Z jerk (mm/s)"); + Serial.print(" M205"); + Serial.print(" S");Serial.print(minimumfeedrate/60); + Serial.print(" T");Serial.print(mintravelfeedrate/60); + Serial.print(" B");Serial.print(minsegmenttime); + Serial.print(" X");Serial.print(max_xy_jerk/60); + Serial.print(" Z");Serial.println(max_z_jerk/60); + +} + + diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 883fe597f7a5..8a60ec744c87 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -37,7 +37,7 @@ */ - +#include #include "fastio.h" #include "Configuration.h" #include "pins.h" @@ -45,6 +45,7 @@ #include "speed_lookuptable.h" #include "lcd.h" + char version_string[] = "U0.9.3.3-BK"; #ifdef SDSUPPORT @@ -120,8 +121,12 @@ volatile int count_direction[NUM_AXIS] = { 1, 1, 1, 1}; // 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) Unused in Marlin!! // M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec -// M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 +// M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 also sets minimum segment time in ms (B20000) to prevent buffer underruns and M20 minimum feedrate +// M205 - advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk // M301 - Set PID parameters P I and D +// M500 - stores paramters in EEPROM +// M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily). D +// M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to. //Stepper Movement Variables @@ -153,10 +158,24 @@ char serial_char; int serial_count = 0; boolean comment_mode = false; char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc -unsigned long minsegmenttime=MIN_SEGMENT_TIME; + +unsigned long minsegmenttime; +float max_feedrate[4]; // set the max speeds +float axis_steps_per_unit[4]; +long max_acceleration_units_per_sq_second[4]; // Use M201 to override by software +float minimumfeedrate; +float acceleration; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX +float retract_acceleration; // mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX +float max_xy_jerk; //speed than can be stopped at once, if i understand correctly. +float max_z_jerk; +float mintravelfeedrate; // Manage heater variables. +#include "EEPROM.h" + + + int target_bed_raw = 0; int current_bed_raw = 0; @@ -286,6 +305,7 @@ void setup() fromsd[i] = false; } + RetrieveSettings(); // loads data from EEPROM if available //Initialize Dir Pins #if X_DIR_PIN > -1 @@ -1116,7 +1136,15 @@ inline void process_commands() { if(code_seen('S')) acceleration = code_value() ; if(code_seen('T')) retract_acceleration = code_value() ; + } + break; + case 205: //M205 advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk + { + if(code_seen('S')) minimumfeedrate = code_value()*60 ; + if(code_seen('T')) mintravelfeedrate = code_value()*60 ; if(code_seen('B')) minsegmenttime = code_value() ; + if(code_seen('X')) max_xy_jerk = code_value()*60 ; + if(code_seen('Z')) max_z_jerk = code_value()*60 ; } break; #ifdef PIDTEMP @@ -1131,6 +1159,22 @@ inline void process_commands() temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; break; #endif //PIDTEMP + case 500: // Store settings in EEPROM + { + StoreSettings(); + } + break; + case 501: // Read settings from EEPROM + { + RetrieveSettings(); + } + break; + case 502: // Revert to default settings + { + RetrieveSettings(true); + } + break; + } } else{ @@ -1613,10 +1657,15 @@ static long position[4]; // Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the // given acceleration: inline long estimate_acceleration_distance(long initial_rate, long target_rate, long acceleration) { + if (acceleration!=0) { return( (target_rate*target_rate-initial_rate*initial_rate)/ (2L*acceleration) ); + } + else { + return 0; // acceleration was 0, set acceleration distance to 0 + } } // This function gives you the point at which you must start braking (at the rate of -acceleration) if @@ -1625,10 +1674,15 @@ inline long estimate_acceleration_distance(long initial_rate, long target_rate, // deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) inline long intersection_distance(long initial_rate, long final_rate, long acceleration, long distance) { + if (acceleration!=0) { return( (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ (4*acceleration) ); + } + else { + return 0; // acceleration was 0, set intersection distance to 0 + } } // Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. @@ -1949,34 +2003,32 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { block->millimeters = sqrt(square(delta_x_mm) + square(delta_y_mm) + square(delta_z_mm) + square(delta_e_mm)); unsigned long microseconds; - if(feedratemillimeters/feed_rate)*1000000); - - // added by lampmaker to slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill + // slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill // reduces/removes corner blobs as the machine won't come to a full stop. int blockcount=block_buffer_head-block_buffer_tail; while(blockcount<0) blockcount+=BLOCK_BUFFER_SIZE; + if (blockcount>0) { - if (microsecondsspeed_z = delta_z_mm * multiplier; From a43fe1a9f83e8ddfc43b0387ef1f4494648add4d Mon Sep 17 00:00:00 2001 From: lampmaker Date: Tue, 4 Oct 2011 15:07:12 +0200 Subject: [PATCH 071/130] Set default minimum feedrates to 0 Use M205 Sxxx Txxx to set minimum feedrates to a higher number --- Marlin/Configuration.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 526c3fa02184..7fa8a7f932ce 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -92,8 +92,8 @@ bool axis_relative_modes[] = {false, false, false, false}; #define DEFAULT_ACCELERATION 4600; // X, Y, Z and E max acceleration in mm/s^2 for printing moves #define DEFAULT_RETRACT_ACCELERATION 7000; // X, Y, Z and E max acceleration in mm/s^2 for r retracts -#define DEFAULT_MINIMUMFEEDRATE 20*60; // minimum feedrate -#define DEFAULT_MINTRAVELFEEDRATE 20*60; +#define DEFAULT_MINIMUMFEEDRATE 00*60; // minimum feedrate +#define DEFAULT_MINTRAVELFEEDRATE 00*60; #define DEFAULT_MINSEGMENTTIME 20000; // minimum segmenttime to prevent buffer underruns #define DEFAULT_XYJERK 5.0*60; #define DEFAULT_ZJERK 1.0*60; From fde9550aab98f5985b660f76b8c7e68db6f84044 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 8 Oct 2011 17:10:28 +0200 Subject: [PATCH 072/130] main menu and status seem ok --- Marlin/ultralcd.h | 22 ++-- Marlin/ultralcd.pde | 258 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 231 insertions(+), 49 deletions(-) diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h index 3c047b292278..fa7d1fce26cb 100644 --- a/Marlin/ultralcd.h +++ b/Marlin/ultralcd.h @@ -10,7 +10,8 @@ void beep(); #define LCDSTATUSRIGHT - #define LCD_UPDATE_INTERVAL 400 + #define LCD_UPDATE_INTERVAL 100 + #define STATUSTIMEOUT 15000 #include "Configuration.h" @@ -61,22 +62,29 @@ #define B_ST (1<999) + curfeedmultiply=999; + feedmultiply=curfeedmultiply; + encoderpos=curfeedmultiply; + } + if((curfeedmultiply!=oldfeedmultiply)||force_lcd_update) + { + oldfeedmultiply=curfeedmultiply; + lcd.setCursor(0,2); + lcd.print(itostr3(curfeedmultiply));lcd.print("% "); + } + if(messagetext[0]!='\0') + { + lcd.setCursor(0,3); + lcd.print(messagetext); + messagetext[0]='\0'; + } + } -void MainMenu::showSubTemperature() + +void MainMenu::showPrepare() +{ + lcd.setCursor(0,0);lcd.print("Prepare"); + lineoffset=0; + return; + uint8_t line=0; + for(uint8_t i=lineoffset;i'); + } + + +} +void MainMenu::update() +{ + static MainStatus oldstatus=Main_Menu; //init automatically causes foce_lcd_update=true + if(status!=oldstatus) + { + lcd.clear(); + force_lcd_update=true; + lineoffset=0; + + oldstatus=status; + } + static long timeoutToStatus=0; + switch(status) + { + case Main_Status: + showStatus(); + if(CLICKED) + { + status=Main_Menu; + timeoutToStatus=millis()+STATUSTIMEOUT; + } + break; + case Main_Menu: + showMainMenu(); + break; + case Main_Prepare: showPrepare(); break; + case Main_Control: showControl(); break; + case Main_SD: showSD(); break; + } + if(timeoutToStatus=0)?'+':'-'; + conv[1]=(xx/1000)%10+'0'; + conv[2]=(xx/100)%10+'0'; + conv[3]=(xx/10)%10+'0'; + conv[4]='.'; + conv[5]=(xx)%10+'0'; + conv[6]=0; + return conv; +} +char *itostr3(const int &xx) +{ + conv[0]=(xx/100)%10+'0'; + conv[1]=(xx/10)%10+'0'; + conv[2]=(xx)%10+'0'; + conv[3]=0; + return conv; +} + /// convert float to string with +1234.5 format char *ftostr51(const float &x) { From c651bbdcdd9283cc9fbc0abf5f23d6dfae514311 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 8 Oct 2011 17:28:11 +0200 Subject: [PATCH 073/130] prepare menu start --- Marlin/ultralcd.pde | 65 +++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index daa224c8b8f6..688a41c44bec 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -268,9 +268,9 @@ void MainMenu::showStatus() void MainMenu::showPrepare() { - lcd.setCursor(0,0);lcd.print("Prepare"); + //lcd.setCursor(0,0);lcd.print("Prepare"); lineoffset=0; - return; + //return; uint8_t line=0; for(uint8_t i=lineoffset;i'); + } for(short line=0;line<3;line++) { switch(line) { case 0: + { if(force_lcd_update) {lcd.setCursor(0,0);lcd.print(" Prepare \x7E");} - if(CLICKED) + if((activeline==line)&&CLICKED) status=Main_Prepare; - break; + } break; + case 1: + { if(force_lcd_update) {lcd.setCursor(0,1);lcd.print(" Control \x7E");} - if(CLICKED) + if((activeline==line)&&CLICKED) status=Main_Control; - break; + }break; case 2: + { if(force_lcd_update) {lcd.setCursor(0,2);lcd.print(" File \x7E");} - if(CLICKED) + if((activeline==line)&&CLICKED) status=Main_SD; - break; - default: break; + }break; + default: + break; } } - if(encoderpos!=lastencoderpos) - { - lcd.setCursor(0,activeline);lcd.print(' '); - activeline=encoderpos%3; - lastencoderpos=encoderpos; - lcd.setCursor(0,activeline);lcd.print('>'); - } + } @@ -356,29 +362,42 @@ void MainMenu::update() static MainStatus oldstatus=Main_Menu; //init automatically causes foce_lcd_update=true if(status!=oldstatus) { + Serial.println(status); lcd.clear(); force_lcd_update=true; lineoffset=0; oldstatus=status; } + static long timeoutToStatus=0; switch(status) { case Main_Status: + { showStatus(); if(CLICKED) { status=Main_Menu; timeoutToStatus=millis()+STATUSTIMEOUT; } - break; + }break; case Main_Menu: + { showMainMenu(); - break; - case Main_Prepare: showPrepare(); break; - case Main_Control: showControl(); break; - case Main_SD: showSD(); break; + }break; + case Main_Prepare: + { + showPrepare(); + }break; + case Main_Control: + { + showControl(); + }break; + case Main_SD: + { + showSD(); + }break; } if(timeoutToStatus Date: Sat, 8 Oct 2011 22:06:11 +0200 Subject: [PATCH 074/130] menu filled, missing changeable number system --- Marlin/buttons.pde | 5 + Marlin/ultralcd.h | 6 +- Marlin/ultralcd.pde | 376 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 362 insertions(+), 25 deletions(-) diff --git a/Marlin/buttons.pde b/Marlin/buttons.pde index 5a0dddc612f8..b97c2353c868 100644 --- a/Marlin/buttons.pde +++ b/Marlin/buttons.pde @@ -84,6 +84,11 @@ void buttons_check() } lastenc=enc; #endif + if(CLICKED) + { + blocking[BL_MI]=ms+blocktime; + blocking[BL_ST]=ms+blocktime; + } busy=false; } diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h index fa7d1fce26cb..62349f1ff103 100644 --- a/Marlin/ultralcd.h +++ b/Marlin/ultralcd.h @@ -11,7 +11,7 @@ #define LCDSTATUSRIGHT #define LCD_UPDATE_INTERVAL 100 - #define STATUSTIMEOUT 15000 + #define STATUSTIMEOUT 5000 #include "Configuration.h" @@ -33,6 +33,7 @@ // blocking time for recognizing a new keypress of one key, ms #define blocktime 500 + #define lcdslow 4 //bits in the shift register that carry the buttons for: @@ -84,7 +85,8 @@ void showSD(); bool force_lcd_update; int lastencoderpos; - uint8_t lineoffset; + int8_t lineoffset; + int8_t lastlineoffset; }; char *fillto(int8_t n,char *c); diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 688a41c44bec..102dc8166e7d 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -241,7 +241,7 @@ void MainMenu::showStatus() } static int oldfeedmultiply=0; int curfeedmultiply=feedmultiply; - if((encoderpos!=curfeedmultiply)||force_lcd_update) + if(encoderpos!=curfeedmultiply) { curfeedmultiply=encoderpos; if(curfeedmultiply<10) @@ -268,61 +268,380 @@ void MainMenu::showStatus() void MainMenu::showPrepare() { - //lcd.setCursor(0,0);lcd.print("Prepare"); - lineoffset=0; - //return; uint8_t line=0; + if(lastlineoffset!=lineoffset) + { + force_lcd_update=true; + lcd.clear(); + } for(uint8_t i=lineoffset;i3) + { + lineoffset++; + encoderpos=3*lcdslow; + if(lineoffset>(5+1-LCD_HEIGHT)) + lineoffset=5+1-LCD_HEIGHT; + force_lcd_update=true; + } + //encoderpos=encoderpos%LCD_HEIGHT; + lastencoderpos=encoderpos; + activeline=encoderpos/lcdslow; + lcd.setCursor(0,activeline);lcd.print('>'); + } } void MainMenu::showControl() { - status=Main_Menu; + uint8_t line=0; + if(lastlineoffset!=lineoffset) + { + force_lcd_update=true; + lcd.clear(); + } + for(uint8_t i=lineoffset;i3) + { + lineoffset++; + encoderpos=3; + if(lineoffset>(12+1-LCD_HEIGHT)) + lineoffset=12+1-LCD_HEIGHT; + force_lcd_update=true; + } + //encoderpos=encoderpos%LCD_HEIGHT; + lastencoderpos=encoderpos; + activeline=encoderpos/lcdslow; + lcd.setCursor(0,activeline);lcd.print('>'); + } } void MainMenu::showSD() { - status=Main_Menu; + uint8_t line=0; + if(lastlineoffset!=lineoffset) + { + force_lcd_update=true; + lcd.clear(); + } + for(uint8_t i=lineoffset;i3) + { + lineoffset++; + encoderpos=3*lcdslow; + if(lineoffset>(2+1-LCD_HEIGHT)) + lineoffset=2+1-LCD_HEIGHT; + force_lcd_update=true; + lineoffset=0; + } + //encoderpos=encoderpos%LCD_HEIGHT; + lastencoderpos=encoderpos; + activeline=encoderpos; + lcd.setCursor(0,activeline);lcd.print('>'); + } } void MainMenu::showMainMenu() { - - if(encoderpos!=lastencoderpos) - { - lcd.setCursor(0,activeline);lcd.print(' '); - activeline=encoderpos%3; - lastencoderpos=encoderpos; - lcd.setCursor(0,activeline);lcd.print('>'); - } - for(short line=0;line<3;line++) { switch(line) @@ -351,7 +670,13 @@ void MainMenu::showMainMenu() } } - + if((encoderpos!=lastencoderpos)||force_lcd_update) + { + lcd.setCursor(0,activeline);lcd.print(' '); + activeline=abs(encoderpos/lcdslow)%3; + lastencoderpos=encoderpos; + lcd.setCursor(0,activeline);lcd.print('>'); + } @@ -360,17 +685,21 @@ void MainMenu::showMainMenu() void MainMenu::update() { static MainStatus oldstatus=Main_Menu; //init automatically causes foce_lcd_update=true + static long timeoutToStatus=0; + if(status!=oldstatus) { Serial.println(status); lcd.clear(); force_lcd_update=true; + encoderpos=0; lineoffset=0; oldstatus=status; } - - static long timeoutToStatus=0; + if( (encoderpos!=lastencoderpos) || CLICKED) + timeoutToStatus=millis()+STATUSTIMEOUT; + switch(status) { case Main_Status: @@ -399,6 +728,7 @@ void MainMenu::update() showSD(); }break; } + if(timeoutToStatus Date: Sat, 8 Oct 2011 22:12:10 +0200 Subject: [PATCH 075/130] found error --- Marlin/ultralcd.pde | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 102dc8166e7d..434f49402f12 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -560,7 +560,7 @@ void MainMenu::showControl() if(encoderpos/lcdslow>3) { lineoffset++; - encoderpos=3; + encoderpos=3*lcdslow; if(lineoffset>(12+1-LCD_HEIGHT)) lineoffset=12+1-LCD_HEIGHT; force_lcd_update=true; @@ -624,7 +624,7 @@ void MainMenu::showSD() encoderpos=0; force_lcd_update=true; } - if(encoderpos>3) + if(encoderpos/lcdslow>3) { lineoffset++; encoderpos=3*lcdslow; From 9d196b5bdeae67d3fa79e9e203466363e5fc17fc Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sun, 9 Oct 2011 21:19:53 +0200 Subject: [PATCH 076/130] sd menu/printing seems to work --- Marlin/ultralcd.h | 5 +- Marlin/ultralcd.pde | 156 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 145 insertions(+), 16 deletions(-) diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h index 62349f1ff103..1c5d836b1f49 100644 --- a/Marlin/ultralcd.h +++ b/Marlin/ultralcd.h @@ -65,7 +65,7 @@ #define EN_A (1<3)||force_lcd_update) { lcd.setCursor(1,0); lcd.print(ftostr3(analog2temp(current_raw))); @@ -225,14 +237,20 @@ void MainMenu::showStatus() } #endif //starttime=2; + static uint16_t oldtime=0; if(starttime!=0) { lcd.setCursor(0,1); uint16_t time=millis()/60000-starttime/60000; - lcd.print(itostr2(time/60));lcd.print("h ");lcd.print(itostr2(time%60));lcd.print("m"); + + if(starttime!=oldtime) + { + lcd.print(itostr2(time/60));lcd.print("h ");lcd.print(itostr2(time%60));lcd.print("m"); + oldtime=time; + } } static int oldzpos=0; - int currentz=current_position[3]*10; + int currentz=current_position[2]*10; if((currentz!=oldzpos)||force_lcd_update) { lcd.setCursor(10,1); @@ -287,6 +305,7 @@ void MainMenu::showPrepare() } if((activeline==line) && CLICKED) { + BLOCK status=Main_Menu; } }break; @@ -298,7 +317,9 @@ void MainMenu::showPrepare() } if((activeline==line) && CLICKED) { + BLOCK enquecommand("G28 X-105 Y-105 Z0"); + smallbeep(); } }break; case 2: @@ -310,7 +331,9 @@ void MainMenu::showPrepare() } if((activeline==line) && CLICKED) { + BLOCK enquecommand("G92 X0 Y0 Z0"); + smallbeep(); } }break; case 3: @@ -321,7 +344,9 @@ void MainMenu::showPrepare() } if((activeline==line) && CLICKED) { + BLOCK target_raw = temp2analog(170); + smallbeep(); } }break; case 4: @@ -332,8 +357,10 @@ void MainMenu::showPrepare() } if((activeline==line) && CLICKED) { + BLOCK enquecommand("G92 E0"); enquecommand("G1 F700 E50"); + smallbeep(); } }break; case 5: @@ -344,7 +371,9 @@ void MainMenu::showPrepare() } if((activeline==line) && CLICKED) { + BLOCK enquecommand("M84"); + smallbeep(); } }break; default: @@ -382,7 +411,7 @@ void MainMenu::showPrepare() } void MainMenu::showControl() { - uint8_t line=0; + uint8_t line=0; if(lastlineoffset!=lineoffset) { force_lcd_update=true; @@ -400,6 +429,7 @@ void MainMenu::showControl() } if((activeline==line) && CLICKED) { + BLOCK status=Main_Menu; } }break; @@ -411,6 +441,7 @@ void MainMenu::showControl() } if((activeline==line) && CLICKED) { + BLOCK } }break; case 2: @@ -422,7 +453,7 @@ void MainMenu::showControl() } if((activeline==line) && CLICKED) { - enquecommand("G92 X0 Y0 Z0"); + enquecommand("G92 X0 Y0 Z0");smallbeep(); } }break; case 3: @@ -568,10 +599,58 @@ void MainMenu::showControl() //encoderpos=encoderpos%LCD_HEIGHT; lastencoderpos=encoderpos; activeline=encoderpos/lcdslow; + if(activeline>3) activeline=3; lcd.setCursor(0,activeline);lcd.print('>'); } } +#include "SdFat.h" + +void MainMenu::getfilename(const uint8_t nr) +{ + dir_t p; + root.rewind(); + uint8_t cnt=0; + filename[0]='\0'; + while (root.readDir(p) > 0) + { + if (p.name[0] == DIR_NAME_FREE) break; + if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue; + if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; + if(p.name[8]!='G') continue; + if(p.name[9]=='~') continue; + if(cnt++!=nr) continue; + //Serial.println((char*)p.name); + uint8_t writepos=0; + for (uint8_t i = 0; i < 11; i++) + { + if (p.name[i] == ' ') continue; + if (i == 8) { + filename[writepos++]='.'; + } + filename[writepos++]=p.name[i]; + } + filename[writepos++]=0; + } +} + +uint8_t getnrfilenames() +{ + dir_t p; + root.rewind(); + uint8_t cnt=0; + while (root.readDir(p) > 0) + { + if (p.name[0] == DIR_NAME_FREE) break; + if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue; + if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; + if(p.name[8]!='G') continue; + if(p.name[9]=='~') continue; + cnt++; + } + return cnt; +} + void MainMenu::showSD() { uint8_t line=0; @@ -580,6 +659,13 @@ void MainMenu::showSD() force_lcd_update=true; lcd.clear(); } + static uint8_t nrfiles; + if(force_lcd_update) + { + nrfiles=getnrfilenames(); + //Serial.print("Nr files:"); Serial.println((int)nrfiles); + } + for(uint8_t i=lineoffset;i(2+1-LCD_HEIGHT)) - lineoffset=2+1-LCD_HEIGHT; + //Serial.println((int)lineoffset); + //Serial.println((int)(2+nrfiles+1-LCD_HEIGHT)); + if(lineoffset>(2+nrfiles+1-LCD_HEIGHT)) + lineoffset=2+nrfiles+1-LCD_HEIGHT; force_lcd_update=true; - lineoffset=0; + } //encoderpos=encoderpos%LCD_HEIGHT; lastencoderpos=encoderpos; activeline=encoderpos; + if(activeline>3) activeline=3; + if(activeline<0) activeline=0; lcd.setCursor(0,activeline);lcd.print('>'); - } + } + } void MainMenu::showMainMenu() @@ -650,20 +768,29 @@ void MainMenu::showMainMenu() { if(force_lcd_update) {lcd.setCursor(0,0);lcd.print(" Prepare \x7E");} if((activeline==line)&&CLICKED) + { + BLOCK status=Main_Prepare; + } } break; case 1: { if(force_lcd_update) {lcd.setCursor(0,1);lcd.print(" Control \x7E");} if((activeline==line)&&CLICKED) + { + BLOCK status=Main_Control; + } }break; case 2: { if(force_lcd_update) {lcd.setCursor(0,2);lcd.print(" File \x7E");} if((activeline==line)&&CLICKED) + { + BLOCK status=Main_SD; + } }break; default: break; @@ -689,7 +816,7 @@ void MainMenu::update() if(status!=oldstatus) { - Serial.println(status); + //Serial.println(status); lcd.clear(); force_lcd_update=true; encoderpos=0; @@ -707,6 +834,7 @@ void MainMenu::update() showStatus(); if(CLICKED) { + BLOCK status=Main_Menu; timeoutToStatus=millis()+STATUSTIMEOUT; } From 2b2bb3a54615834109a24119fe9b26639f730a36 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Mon, 10 Oct 2011 21:59:52 +0200 Subject: [PATCH 077/130] file error --- Marlin/ultralcd.h | 1 + Marlin/ultralcd.pde | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h index 1c5d836b1f49..ed685e3acb03 100644 --- a/Marlin/ultralcd.h +++ b/Marlin/ultralcd.h @@ -88,6 +88,7 @@ int8_t lineoffset; int8_t lastlineoffset; char filename[11]; + bool linechanging; }; char *fillto(int8_t n,char *c); diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 4cef6117a200..e75e7d3fe991 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -189,6 +189,7 @@ MainMenu::MainMenu() force_lcd_update=true; buttons_init(); lcd_init(); + linechanging=false; } void clearLcd() { @@ -441,7 +442,8 @@ void MainMenu::showControl() } if((activeline==line) && CLICKED) { - BLOCK + BLOCK; + } }break; case 2: @@ -575,7 +577,8 @@ void MainMenu::showControl() line++; } lastlineoffset=lineoffset; - if((encoderpos/lcdslow!=lastencoderpos/lcdslow)||force_lcd_update) + + if(!linechanging && ((encoderpos/lcdslow!=lastencoderpos/lcdslow)||force_lcd_update)) { lcd.setCursor(0,activeline);lcd.print(' '); @@ -743,8 +746,8 @@ void MainMenu::showSD() encoderpos=3*lcdslow; //Serial.println((int)lineoffset); //Serial.println((int)(2+nrfiles+1-LCD_HEIGHT)); - if(lineoffset>(2+nrfiles+1-LCD_HEIGHT)) - lineoffset=2+nrfiles+1-LCD_HEIGHT; + if(lineoffset>(1+nrfiles+1-LCD_HEIGHT)) + lineoffset=1+nrfiles+1-LCD_HEIGHT; force_lcd_update=true; } From 1cc85eac21f9adb15bfb964344483493c6b41fa0 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Mon, 10 Oct 2011 23:26:12 +0200 Subject: [PATCH 078/130] whoa, amazing. the control menu seems to work, and the xyjerk now has an actualy usual value. --- Marlin/Configuration.h | 4 +- Marlin/ultralcd.pde | 276 ++++++++++++++++++++++++++++++----------- 2 files changed, 207 insertions(+), 73 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 9bf271576aec..0d58435c832b 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -95,9 +95,9 @@ bool axis_relative_modes[] = {false, false, false, false}; //// Acceleration settings // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. -float acceleration = 4600; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX +float acceleration = 4500; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX float retract_acceleration = 7000; // mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX -float max_xy_jerk = 5.0*60; //speed than can be stopped at once, if i understand correctly. +float max_xy_jerk = 30*60; //speed than can be stopped at once, if i understand correctly. float max_z_jerk = 1*60; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts long max_acceleration_units_per_sq_second[] = {9000,9000,150,10000}; // Use M201 to override by software diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index e75e7d3fe991..43fb394cf1bd 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -438,118 +438,251 @@ void MainMenu::showControl() { if(force_lcd_update) { - lcd.setCursor(0,line);lcd.print(" Nozzle:"); + lcd.setCursor(0,line);lcd.print(" \002Nozzle:"); + lcd.setCursor(13,line);lcd.print(ftostr3(analog2temp(target_raw))); } - if((activeline==line) && CLICKED) + + if((activeline==line) ) { - BLOCK; - + if(CLICKED) + { + linechanging=!linechanging; + if(linechanging) + { + encoderpos=(int)analog2temp(target_raw); + } + else + { + target_raw = temp2analog(encoderpos); + encoderpos=activeline*lcdslow; + + } + BLOCK; + } + if(linechanging) + { + if(encoderpos<0) encoderpos=0; + if(encoderpos>260) encoderpos=260; + lcd.setCursor(13,line);lcd.print(itostr3(encoderpos)); + } } }break; case 2: - { - if(force_lcd_update) + { + if(force_lcd_update) { - lcd.setCursor(0,line);lcd.print(" a:"); - + lcd.setCursor(0,line);lcd.print(" Acc:"); + lcd.setCursor(13,line);lcd.print(itostr3(acceleration/100));lcd.print("00"); } - if((activeline==line) && CLICKED) + + if((activeline==line) ) { - enquecommand("G92 X0 Y0 Z0");smallbeep(); + if(CLICKED) + { + linechanging=!linechanging; + if(linechanging) + { + encoderpos=(int)acceleration/100; + } + else + { + acceleration= encoderpos*100; + encoderpos=activeline*lcdslow; + + } + BLOCK; + } + if(linechanging) + { + if(encoderpos<5) encoderpos=5; + if(encoderpos>990) encoderpos=990; + lcd.setCursor(13,line);lcd.print(itostr3(encoderpos));lcd.print("00"); + } } }break; - case 3: + case 3: //max_xy_jerk { - if(force_lcd_update) + if(force_lcd_update) { - lcd.setCursor(0,line);lcd.print(" v-max x:"); + lcd.setCursor(0,line);lcd.print(" Vxy-jerk: "); + lcd.setCursor(13,line);lcd.print(itostr3(max_xy_jerk/60)); } - if((activeline==line) && CLICKED) + + if((activeline==line) ) { - //target_raw = temp2analog(170); + if(CLICKED) + { + linechanging=!linechanging; + if(linechanging) + { + encoderpos=(int)max_xy_jerk/60; + } + else + { + max_xy_jerk= encoderpos*60; + encoderpos=activeline*lcdslow; + + } + BLOCK; + } + if(linechanging) + { + if(encoderpos<1) encoderpos=1; + if(encoderpos>990) encoderpos=990; + lcd.setCursor(13,line);lcd.print(itostr3(encoderpos)); + } } }break; case 4: - { - if(force_lcd_update) - { - lcd.setCursor(0,line);lcd.print(" v-max y:"); - } - if((activeline==line) && CLICKED) - { - //enquecommand("G92 E0"); - //enquecommand("G1 F700 E50"); - } - }break; case 5: - { - if(force_lcd_update) - { - lcd.setCursor(0,line);lcd.print(" v-max z:"); - } - if((activeline==line) && CLICKED) - { - //enquecommand("M84"); - } - }break; case 6: + case 7: { - if(force_lcd_update) + if(force_lcd_update) { - lcd.setCursor(0,line);lcd.print(" v-max e:"); + lcd.setCursor(0,line);lcd.print(" Vmax "); + if(i==4)lcd.print("x:"); + if(i==5)lcd.print("y:"); + if(i==6)lcd.print("z:"); + if(i==7)lcd.print("e:"); + lcd.setCursor(13,line);lcd.print(itostr3(max_feedrate[i-3]/60)); } - if((activeline==line) && CLICKED) + + if((activeline==line) ) { - //enquecommand("M84"); + if(CLICKED) + { + linechanging=!linechanging; + if(linechanging) + { + encoderpos=(int)max_feedrate[i-3]/60; + } + else + { + max_feedrate[i-3]= encoderpos*60; + encoderpos=activeline*lcdslow; + + } + BLOCK; + } + if(linechanging) + { + if(encoderpos<1) encoderpos=1; + if(encoderpos>990) encoderpos=990; + lcd.setCursor(13,line);lcd.print(itostr3(encoderpos)); + } } }break; - case 7: + case 8: { if(force_lcd_update) - { - lcd.setCursor(0,line);lcd.print(" v-min:"); - } - if((activeline==line) && CLICKED) - { - //enquecommand("M84"); - } - }break; - case 8: - { - if(force_lcd_update) { - lcd.setCursor(0,line);lcd.print(" a-max x:"); + lcd.setCursor(0,line);lcd.print(" Vmin:"); + lcd.setCursor(13,line);lcd.print(itostr3(minimumfeedrate/60)); } - if((activeline==line) && CLICKED) + + if((activeline==line) ) { - //target_raw = temp2analog(170); + if(CLICKED) + { + linechanging=!linechanging; + if(linechanging) + { + encoderpos=(int)minimumfeedrate/60; + } + else + { + minimumfeedrate= encoderpos*60; + encoderpos=activeline*lcdslow; + + } + BLOCK; + } + if(linechanging) + { + if(encoderpos<0) encoderpos=0; + if(encoderpos>990) encoderpos=990; + lcd.setCursor(13,line);lcd.print(itostr3(encoderpos)); + } } }break; - case 9: - { - if(force_lcd_update) + + case 9: + case 10: + case 11: + case 12: + { + if(force_lcd_update) { - lcd.setCursor(0,line);lcd.print(" a-max y:"); + lcd.setCursor(0,line);lcd.print(" Amax "); + if(i==9)lcd.print("x:"); + if(i==10)lcd.print("y:"); + if(i==11)lcd.print("z:"); + if(i==12)lcd.print("e:"); + lcd.setCursor(13,line);lcd.print(itostr3(max_acceleration_units_per_sq_second[i-8]/100));lcd.print("00"); } - if((activeline==line) && CLICKED) + + if((activeline==line) ) { - //enquecommand("G92 E0"); - //enquecommand("G1 F700 E50"); + if(CLICKED) + { + linechanging=!linechanging; + if(linechanging) + { + encoderpos=(int)max_acceleration_units_per_sq_second[i-8]/100; + } + else + { + max_acceleration_units_per_sq_second[i-8]= encoderpos*100; + encoderpos=activeline*lcdslow; + + } + BLOCK; + } + if(linechanging) + { + if(encoderpos<1) encoderpos=1; + if(encoderpos>990) encoderpos=990; + lcd.setCursor(13,line);lcd.print(itostr3(encoderpos));lcd.print("00"); + } } }break; - case 10: - { + case 13://float retract_acceleration = 7000; + { if(force_lcd_update) { - lcd.setCursor(0,line);lcd.print(" a-max z:"); + lcd.setCursor(0,line);lcd.print(" Aretra:"); + lcd.setCursor(13,line);lcd.print(ftostr3(retract_acceleration/100));lcd.print("00"); } - if((activeline==line) && CLICKED) + + if((activeline==line) ) { - //enquecommand("M84"); + if(CLICKED) + { + linechanging=!linechanging; + if(linechanging) + { + encoderpos=(int)retract_acceleration/100; + } + else + { + retract_acceleration= encoderpos*100; + encoderpos=activeline*lcdslow; + + } + BLOCK; + } + if(linechanging) + { + if(encoderpos<10) encoderpos=10; + if(encoderpos>990) encoderpos=990; + lcd.setCursor(13,line);lcd.print(itostr3(encoderpos));lcd.print("00"); + } } }break; - case 11: + + case 14: { if(force_lcd_update) { @@ -560,7 +693,7 @@ void MainMenu::showControl() //enquecommand("M84"); } }break; - case 12: + case 15: { if(force_lcd_update) { @@ -595,8 +728,8 @@ void MainMenu::showControl() { lineoffset++; encoderpos=3*lcdslow; - if(lineoffset>(12+1-LCD_HEIGHT)) - lineoffset=12+1-LCD_HEIGHT; + if(lineoffset>(13+1-LCD_HEIGHT)) + lineoffset=13+1-LCD_HEIGHT; force_lcd_update=true; } //encoderpos=encoderpos%LCD_HEIGHT; @@ -863,6 +996,7 @@ void MainMenu::update() if(timeoutToStatus Date: Tue, 11 Oct 2011 01:27:24 +0300 Subject: [PATCH 079/130] wow, xy_jerk higher makes a big difference in print quality --- Marlin/Configuration.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 373698d47510..2f7d32fc853d 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -97,8 +97,8 @@ bool axis_relative_modes[] = {false, false, false, false}; // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. float acceleration = 4600; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX float retract_acceleration = 7000; // mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX -float max_xy_jerk = 5.0*60; //speed than can be stopped at once, if i understand correctly. -float max_z_jerk = 1*60; +float max_xy_jerk = 25.0*60; //speed than can be stopped at once, if i understand correctly. +float max_z_jerk = 10*60; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts long max_acceleration_units_per_sq_second[] = {9000,9000,150,10000}; // Use M201 to override by software float minimumfeedrate=20; From 9ac43c926f83289871b81a09c7fb3d8d126d23e9 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 11 Oct 2011 00:43:43 +0200 Subject: [PATCH 080/130] joris found a bug --- Marlin/ultralcd.pde | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 43fb394cf1bd..260a7c43fce6 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -545,7 +545,7 @@ void MainMenu::showControl() if(i==5)lcd.print("y:"); if(i==6)lcd.print("z:"); if(i==7)lcd.print("e:"); - lcd.setCursor(13,line);lcd.print(itostr3(max_feedrate[i-3]/60)); + lcd.setCursor(13,line);lcd.print(itostr3(max_feedrate[i-4]/60)); } if((activeline==line) ) @@ -555,11 +555,11 @@ void MainMenu::showControl() linechanging=!linechanging; if(linechanging) { - encoderpos=(int)max_feedrate[i-3]/60; + encoderpos=(int)max_feedrate[i-4]/60; } else { - max_feedrate[i-3]= encoderpos*60; + max_feedrate[i-4]= encoderpos*60; encoderpos=activeline*lcdslow; } @@ -620,7 +620,7 @@ void MainMenu::showControl() if(i==10)lcd.print("y:"); if(i==11)lcd.print("z:"); if(i==12)lcd.print("e:"); - lcd.setCursor(13,line);lcd.print(itostr3(max_acceleration_units_per_sq_second[i-8]/100));lcd.print("00"); + lcd.setCursor(13,line);lcd.print(itostr3(max_acceleration_units_per_sq_second[i-9]/100));lcd.print("00"); } if((activeline==line) ) @@ -630,11 +630,11 @@ void MainMenu::showControl() linechanging=!linechanging; if(linechanging) { - encoderpos=(int)max_acceleration_units_per_sq_second[i-8]/100; + encoderpos=(int)max_acceleration_units_per_sq_second[i-9]/100; } else { - max_acceleration_units_per_sq_second[i-8]= encoderpos*100; + max_acceleration_units_per_sq_second[i-9]= encoderpos*100; encoderpos=activeline*lcdslow; } From 376507537218321320405d461d41bd8e7e655bec Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 11 Oct 2011 01:06:06 +0200 Subject: [PATCH 081/130] maybe remove trapping in submenus --- Marlin/ultralcd.pde | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 260a7c43fce6..fee6c4d8e009 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -970,6 +970,7 @@ void MainMenu::update() showStatus(); if(CLICKED) { + linechanging=false; BLOCK status=Main_Menu; timeoutToStatus=millis()+STATUSTIMEOUT; @@ -977,7 +978,8 @@ void MainMenu::update() }break; case Main_Menu: { - showMainMenu(); + showMainMenu(); + linechanging=false; }break; case Main_Prepare: { From 0bbe1dcaa8b3f8cc36c23ba86313af6802f22a16 Mon Sep 17 00:00:00 2001 From: lampmaker Date: Tue, 11 Oct 2011 08:56:15 +0300 Subject: [PATCH 082/130] increased default xy and z-jerk --- Marlin/Configuration.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 7fa8a7f932ce..5ef689502cc6 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -95,8 +95,8 @@ bool axis_relative_modes[] = {false, false, false, false}; #define DEFAULT_MINIMUMFEEDRATE 00*60; // minimum feedrate #define DEFAULT_MINTRAVELFEEDRATE 00*60; #define DEFAULT_MINSEGMENTTIME 20000; // minimum segmenttime to prevent buffer underruns -#define DEFAULT_XYJERK 5.0*60; -#define DEFAULT_ZJERK 1.0*60; +#define DEFAULT_XYJERK 25.0*60; +#define DEFAULT_ZJERK 10.0*60; // The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature From 78c631e95abc9891ffe7e650ff03d6432bfdee0d Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 11 Oct 2011 19:06:33 +0200 Subject: [PATCH 083/130] menu to enum. --- Marlin/Configuration.h | 4 +- Marlin/ultralcd.pde | 234 +++++++++++++++++++++++++++-------------- 2 files changed, 159 insertions(+), 79 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 0d58435c832b..970cda585de2 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -84,7 +84,7 @@ const int dropsegments=2; //everything with this number of steps will be ignore //// MOVEMENT SETTINGS #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {190*60, 190*60, 10*60, 500000}; // set the max speeds +float max_feedrate[] = {190*60, 190*60, 10*60, 100*60}; // set the max speeds //note: on bernhards ultimaker 200 200 12 are working well. float homing_feedrate[] = {70*60, 70*60, 12*60, 0}; // set the homing speeds //the followint checks if an extrusion is existent in the move. if _not_, the speed of the move is set to the maximum speed. @@ -98,7 +98,7 @@ bool axis_relative_modes[] = {false, false, false, false}; float acceleration = 4500; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX float retract_acceleration = 7000; // mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX float max_xy_jerk = 30*60; //speed than can be stopped at once, if i understand correctly. -float max_z_jerk = 1*60; +float max_z_jerk = 5*60; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts long max_acceleration_units_per_sq_second[] = {9000,9000,150,10000}; // Use M201 to override by software float minimumfeedrate=20; diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index fee6c4d8e009..88e902f62f94 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -51,10 +51,11 @@ void lcd_init() B10001, B01110 }; - + byte uplevel[8]={0x04, 0x0e, 0x1f, 0x04, 0x1c, 0x00, 0x00, 0x00}; lcd.begin(LCD_WIDTH, LCD_HEIGHT); lcd.createChar(1,Degree); lcd.createChar(2,Thermometer); + lcd.createChar(3,uplevel); LCD_MESSAGE(fillto(LCD_WIDTH,"UltiMarlin ready.")); } @@ -71,7 +72,7 @@ void beep() } } -void smallbeep() +void beepshort() { // [ErikDeBruijn] changed to two short beeps, more friendly pinMode(BEEPER,OUTPUT); @@ -86,7 +87,7 @@ void smallbeep() void lcd_status() { static long previous_millis_buttons=0; - if(millis() - previous_millis_buttons<5) + if(millis() - previous_millis_buttons<3) return; buttons_check(); previous_millis_buttons=millis(); @@ -279,12 +280,14 @@ void MainMenu::showStatus() if(messagetext[0]!='\0') { lcd.setCursor(0,3); - lcd.print(messagetext); + lcd.print(fillto(LCD_WIDTH,messagetext)); messagetext[0]='\0'; } } +enum {ItemP_exit, ItemP_home, ItemP_origin, ItemP_preheat, ItemP_extrude, ItemP_disstep}; + void MainMenu::showPrepare() { uint8_t line=0; @@ -298,19 +301,20 @@ void MainMenu::showPrepare() //Serial.println((int)(line-lineoffset)); switch(i) { - case 0: + case ItemP_exit: { if(force_lcd_update) { - lcd.setCursor(0,line);lcd.print(" Exit \"Prepare\""); + lcd.setCursor(0,line);lcd.print(" Prepare"); } if((activeline==line) && CLICKED) { BLOCK status=Main_Menu; + beepshort(); } }break; - case 1: + case ItemP_home: { if(force_lcd_update) { @@ -320,10 +324,10 @@ void MainMenu::showPrepare() { BLOCK enquecommand("G28 X-105 Y-105 Z0"); - smallbeep(); + beepshort(); } }break; - case 2: + case ItemP_origin: { if(force_lcd_update) { @@ -334,10 +338,10 @@ void MainMenu::showPrepare() { BLOCK enquecommand("G92 X0 Y0 Z0"); - smallbeep(); + beepshort(); } }break; - case 3: + case ItemP_preheat: { if(force_lcd_update) { @@ -347,10 +351,10 @@ void MainMenu::showPrepare() { BLOCK target_raw = temp2analog(170); - smallbeep(); + beepshort(); } }break; - case 4: + case ItemP_extrude: { if(force_lcd_update) { @@ -361,10 +365,10 @@ void MainMenu::showPrepare() BLOCK enquecommand("G92 E0"); enquecommand("G1 F700 E50"); - smallbeep(); + beepshort(); } }break; - case 5: + case ItemP_disstep: { if(force_lcd_update) { @@ -374,7 +378,7 @@ void MainMenu::showPrepare() { BLOCK enquecommand("M84"); - smallbeep(); + beepshort(); } }break; default: @@ -386,7 +390,7 @@ void MainMenu::showPrepare() if((encoderpos/lcdslow!=lastencoderpos/lcdslow)||force_lcd_update) { - lcd.setCursor(0,activeline);lcd.print(' '); + lcd.setCursor(0,activeline);lcd.print((activeline+lineoffset)?' ':' '); if(encoderpos<0) { @@ -400,16 +404,24 @@ void MainMenu::showPrepare() { lineoffset++; encoderpos=3*lcdslow; - if(lineoffset>(5+1-LCD_HEIGHT)) - lineoffset=5+1-LCD_HEIGHT; + if(lineoffset>(ItemP_disstep+1-LCD_HEIGHT)) + lineoffset=ItemP_disstep+1-LCD_HEIGHT; force_lcd_update=true; } //encoderpos=encoderpos%LCD_HEIGHT; lastencoderpos=encoderpos; activeline=encoderpos/lcdslow; - lcd.setCursor(0,activeline);lcd.print('>'); + lcd.setCursor(0,activeline);lcd.print((activeline+lineoffset)?'>':'\003'); } } +enum { + ItemC_exit, ItemC_nozzle, ItemC_acc, ItemC_xyjerk, + ItemC_vmaxx, ItemC_vmaxy, ItemC_vmaxz, ItemC_vmaxe, + ItemC_vmin, + ItemC_amaxx, ItemC_amaxy, ItemC_amaxz, ItemC_amaxe, + ItemC_aret,ItemC_esteps, ItemC_store, ItemC_load +}; + void MainMenu::showControl() { uint8_t line=0; @@ -422,19 +434,20 @@ void MainMenu::showControl() { switch(i) { - case 0: + case ItemC_exit: { if(force_lcd_update) { - lcd.setCursor(0,line);lcd.print(" Exit \"Control\""); + lcd.setCursor(0,line);lcd.print(" Control"); } if((activeline==line) && CLICKED) { BLOCK status=Main_Menu; + beepshort(); } }break; - case 1: + case ItemC_nozzle: { if(force_lcd_update) { @@ -455,7 +468,7 @@ void MainMenu::showControl() { target_raw = temp2analog(encoderpos); encoderpos=activeline*lcdslow; - + beepshort(); } BLOCK; } @@ -467,7 +480,7 @@ void MainMenu::showControl() } } }break; - case 2: + case ItemC_acc: { if(force_lcd_update) { @@ -488,9 +501,9 @@ void MainMenu::showControl() { acceleration= encoderpos*100; encoderpos=activeline*lcdslow; - } BLOCK; + beepshort(); } if(linechanging) { @@ -500,7 +513,7 @@ void MainMenu::showControl() } } }break; - case 3: //max_xy_jerk + case ItemC_xyjerk: //max_xy_jerk { if(force_lcd_update) { @@ -524,6 +537,7 @@ void MainMenu::showControl() } BLOCK; + beepshort(); } if(linechanging) { @@ -533,19 +547,19 @@ void MainMenu::showControl() } } }break; - case 4: - case 5: - case 6: - case 7: + case ItemC_vmaxx: + case ItemC_vmaxy: + case ItemC_vmaxz: + case ItemC_vmaxe: { if(force_lcd_update) { lcd.setCursor(0,line);lcd.print(" Vmax "); - if(i==4)lcd.print("x:"); - if(i==5)lcd.print("y:"); - if(i==6)lcd.print("z:"); - if(i==7)lcd.print("e:"); - lcd.setCursor(13,line);lcd.print(itostr3(max_feedrate[i-4]/60)); + if(i==ItemC_vmaxx)lcd.print("x:"); + if(i==ItemC_vmaxy)lcd.print("y:"); + if(i==ItemC_vmaxz)lcd.print("z:"); + if(i==ItemC_vmaxe)lcd.print("e:"); + lcd.setCursor(13,line);lcd.print(itostr3(max_feedrate[i-ItemC_vmaxx]/60)); } if((activeline==line) ) @@ -555,15 +569,16 @@ void MainMenu::showControl() linechanging=!linechanging; if(linechanging) { - encoderpos=(int)max_feedrate[i-4]/60; + encoderpos=(int)max_feedrate[i-ItemC_vmaxx]/60; } else { - max_feedrate[i-4]= encoderpos*60; + max_feedrate[i-ItemC_vmaxx]= encoderpos*60; encoderpos=activeline*lcdslow; } BLOCK; + beepshort(); } if(linechanging) { @@ -574,7 +589,7 @@ void MainMenu::showControl() } }break; - case 8: + case ItemC_vmin: { if(force_lcd_update) { @@ -598,6 +613,7 @@ void MainMenu::showControl() } BLOCK; + beepshort(); } if(linechanging) { @@ -608,19 +624,19 @@ void MainMenu::showControl() } }break; - case 9: - case 10: - case 11: - case 12: + case ItemC_amaxx: + case ItemC_amaxy: + case ItemC_amaxz: + case ItemC_amaxe: { if(force_lcd_update) { lcd.setCursor(0,line);lcd.print(" Amax "); - if(i==9)lcd.print("x:"); - if(i==10)lcd.print("y:"); - if(i==11)lcd.print("z:"); - if(i==12)lcd.print("e:"); - lcd.setCursor(13,line);lcd.print(itostr3(max_acceleration_units_per_sq_second[i-9]/100));lcd.print("00"); + if(i==ItemC_amaxx)lcd.print("x:"); + if(i==ItemC_amaxy)lcd.print("y:"); + if(i==ItemC_amaxz)lcd.print("z:"); + if(i==ItemC_amaxe)lcd.print("e:"); + lcd.setCursor(13,line);lcd.print(itostr3(max_acceleration_units_per_sq_second[i-ItemC_amaxx]/100));lcd.print("00"); } if((activeline==line) ) @@ -630,15 +646,15 @@ void MainMenu::showControl() linechanging=!linechanging; if(linechanging) { - encoderpos=(int)max_acceleration_units_per_sq_second[i-9]/100; + encoderpos=(int)max_acceleration_units_per_sq_second[i-ItemC_amaxx]/100; } else { - max_acceleration_units_per_sq_second[i-9]= encoderpos*100; + max_acceleration_units_per_sq_second[i-ItemC_amaxx]= encoderpos*100; encoderpos=activeline*lcdslow; - } BLOCK; + beepshort(); } if(linechanging) { @@ -648,11 +664,11 @@ void MainMenu::showControl() } } }break; - case 13://float retract_acceleration = 7000; + case ItemC_aret://float retract_acceleration = 7000; { if(force_lcd_update) { - lcd.setCursor(0,line);lcd.print(" Aretra:"); + lcd.setCursor(0,line);lcd.print(" A-retract:"); lcd.setCursor(13,line);lcd.print(ftostr3(retract_acceleration/100));lcd.print("00"); } @@ -672,6 +688,7 @@ void MainMenu::showControl() } BLOCK; + beepshort(); } if(linechanging) { @@ -681,8 +698,41 @@ void MainMenu::showControl() } } }break; - - case 14: + case ItemC_esteps://axis_steps_per_unit[i] = code_value(); + { + if(force_lcd_update) + { + lcd.setCursor(0,line);lcd.print(" Esteps/mm:"); + lcd.setCursor(13,line);lcd.print(itostr3(axis_steps_per_unit[3])); + } + + if((activeline==line) ) + { + if(CLICKED) + { + linechanging=!linechanging; + if(linechanging) + { + encoderpos=(int)axis_steps_per_unit[3]; + } + else + { + axis_steps_per_unit[3]= encoderpos; + encoderpos=activeline*lcdslow; + + } + BLOCK; + beepshort(); + } + if(linechanging) + { + if(encoderpos<5) encoderpos=5; + if(encoderpos>990) encoderpos=990; + lcd.setCursor(13,line);lcd.print(itostr3(encoderpos)); + } + } + }break; + case ItemC_store: { if(force_lcd_update) { @@ -691,9 +741,10 @@ void MainMenu::showControl() if((activeline==line) && CLICKED) { //enquecommand("M84"); + beepshort(); } }break; - case 15: + case ItemC_load: { if(force_lcd_update) { @@ -702,6 +753,7 @@ void MainMenu::showControl() if((activeline==line) && CLICKED) { //enquecommand("M84"); + beepshort(); } }break; default: @@ -714,7 +766,7 @@ void MainMenu::showControl() if(!linechanging && ((encoderpos/lcdslow!=lastencoderpos/lcdslow)||force_lcd_update)) { - lcd.setCursor(0,activeline);lcd.print(' '); + lcd.setCursor(0,activeline);lcd.print((activeline+lineoffset)?' ':' '); if(encoderpos<0) { @@ -728,15 +780,15 @@ void MainMenu::showControl() { lineoffset++; encoderpos=3*lcdslow; - if(lineoffset>(13+1-LCD_HEIGHT)) - lineoffset=13+1-LCD_HEIGHT; + if(lineoffset>(ItemC_esteps+1-LCD_HEIGHT)) + lineoffset=ItemC_esteps+1-LCD_HEIGHT; force_lcd_update=true; } //encoderpos=encoderpos%LCD_HEIGHT; lastencoderpos=encoderpos; activeline=encoderpos/lcdslow; if(activeline>3) activeline=3; - lcd.setCursor(0,activeline);lcd.print('>'); + lcd.setCursor(0,activeline);lcd.print((activeline+lineoffset)?'>':'\003'); } } @@ -810,12 +862,13 @@ void MainMenu::showSD() { if(force_lcd_update) { - lcd.setCursor(0,line);lcd.print(" Exit \"File\""); + lcd.setCursor(0,line);lcd.print(" File"); } if((activeline==line) && CLICKED) { BLOCK status=Main_Menu; + beepshort(); } }break; case 1: @@ -826,7 +879,8 @@ void MainMenu::showSD() } if((activeline==line) && CLICKED) { - BLOCK + BLOCK; + beepshort(); } }break; default: @@ -863,7 +917,7 @@ void MainMenu::showSD() if((encoderpos!=lastencoderpos)||force_lcd_update) { - lcd.setCursor(0,activeline);lcd.print(' '); + lcd.setCursor(0,activeline);lcd.print((activeline+lineoffset)?' ':' '); if(encoderpos<0) { @@ -889,43 +943,67 @@ void MainMenu::showSD() activeline=encoderpos; if(activeline>3) activeline=3; if(activeline<0) activeline=0; - lcd.setCursor(0,activeline);lcd.print('>'); + lcd.setCursor(0,activeline);lcd.print((activeline+lineoffset)?'>':'\003'); } } +enum {ItemM_watch, ItemM_prepare, ItemM_control, ItemM_file }; void MainMenu::showMainMenu() { - for(short line=0;line<3;line++) + for(short line=0;line<4;line++) { switch(line) { - case 0: + case ItemM_watch: { - if(force_lcd_update) {lcd.setCursor(0,0);lcd.print(" Prepare \x7E");} + if(force_lcd_update) {lcd.setCursor(0,line);lcd.print(" Watch \x7E");} if((activeline==line)&&CLICKED) { - BLOCK + BLOCK; + beepshort(); + status=Main_Status; + } + } break; + case ItemM_prepare: + { + if(force_lcd_update) {lcd.setCursor(0,line);lcd.print(" Prepare \x7E");} + if((activeline==line)&&CLICKED) + { + BLOCK; status=Main_Prepare; + beepshort(); } } break; - case 1: + case ItemM_control: { - if(force_lcd_update) {lcd.setCursor(0,1);lcd.print(" Control \x7E");} + if(force_lcd_update) {lcd.setCursor(0,line);lcd.print(" Control \x7E");} if((activeline==line)&&CLICKED) { - BLOCK + BLOCK; status=Main_Control; + beepshort(); } }break; - case 2: + case ItemM_file: { - if(force_lcd_update) {lcd.setCursor(0,2);lcd.print(" File \x7E");} + if(force_lcd_update) + { + lcd.setCursor(0,line); + if(sdmode) + lcd.print(" Stop \x7E"); + else + lcd.print(" Card \x7E"); + + } if((activeline==line)&&CLICKED) { - BLOCK + sdmode = false; + + BLOCK; status=Main_SD; + beepshort(); } }break; default: @@ -935,10 +1013,12 @@ void MainMenu::showMainMenu() if((encoderpos!=lastencoderpos)||force_lcd_update) { - lcd.setCursor(0,activeline);lcd.print(' '); - activeline=abs(encoderpos/lcdslow)%3; + lcd.setCursor(0,activeline);lcd.print(activeline?' ':' '); + if(encoderpos<0) encoderpos=0; + activeline=abs(encoderpos/lcdslow)%4; + lastencoderpos=encoderpos; - lcd.setCursor(0,activeline);lcd.print('>'); + lcd.setCursor(0,activeline);lcd.print(activeline?'>':'\003'); } From 0d1cb1cf2378d3e9e43269e1638ca163f524a7d9 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Wed, 12 Oct 2011 19:54:07 +0200 Subject: [PATCH 084/130] sd card refresh working --- Marlin/ultralcd.pde | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 88e902f62f94..926feb6ececb 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -847,14 +847,22 @@ void MainMenu::showSD() force_lcd_update=true; lcd.clear(); } - static uint8_t nrfiles; + static uint8_t nrfiles=0; if(force_lcd_update) { - nrfiles=getnrfilenames(); + if(sdactive) + { + nrfiles=getnrfilenames(); + } + else + { + nrfiles=0; + lineoffset=0; + } //Serial.print("Nr files:"); Serial.println((int)nrfiles); } - for(uint8_t i=lineoffset;i3) activeline=3; if(activeline<0) activeline=0; + if(activeline>1+nrfiles) activeline=1+nrfiles; + if(lineoffset>1+nrfiles) lineoffset=1+nrfiles; lcd.setCursor(0,activeline);lcd.print((activeline+lineoffset)?'>':'\003'); + } } From 77791a6db29de5fb33939bd008dd0abcec2fc2c2 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Wed, 12 Oct 2011 20:50:21 +0200 Subject: [PATCH 085/130] added disable for ultipanel --- Marlin/Configuration.h | 1 + Marlin/buttons.h | 62 ----------------------- Marlin/buttons.pde | 109 ----------------------------------------- Marlin/ultralcd.h | 9 +++- Marlin/ultralcd.pde | 24 ++++++--- 5 files changed, 26 insertions(+), 179 deletions(-) delete mode 100644 Marlin/buttons.h delete mode 100644 Marlin/buttons.pde diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index c1f203280099..b48d1a9ba236 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -40,6 +40,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define SDSUPPORT // Enable SD Card Support in Hardware Console #define ULTRA_LCD //improved 3 button or clickencoder interface +#define ULTIPANEL const int dropsegments=2; //everything with this number of steps will be ignored as move //// ADVANCED SETTINGS - to tweak parameters diff --git a/Marlin/buttons.h b/Marlin/buttons.h deleted file mode 100644 index ea4de00caa0a..000000000000 --- a/Marlin/buttons.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifdef FANCY_LCD - -#define BUTTONS_HAVEENCODER - -extern volatile char buttons; -extern volatile int encoderpos; - -//buttons are attached to a shift register -#define SHIFT_CLK 38 -#define SHIFT_LD 42 -#define SHIFT_OUT 40 -#define SHIFT_EN 17 - -// blocking time for recognizing a new keypress of one key, ms -#define blocktime 500 - - -//bits in the shift register that carry the buttons for: -// left up center down right red -#define BL_LE 7 -#define BL_UP 6 -#define BL_MI 5 -#define BL_DW 4 -#define BL_RI 3 -#define BL_ST 2 - -//if there is a rotary encoder, its two bits are at the shift register byte position: -#ifdef BUTTONS_HAVEENCODER - - #define BLEN_B 1 - #define BLEN_A 0 - - //encoder rotation values - #define encrot0 0 - #define encrot1 2 - #define encrot2 3 - #define encrot3 1 - -#endif //BUTONS_HAVEENCODER - - -//atomatic, do not change -#define B_LE (1< Date: Wed, 12 Oct 2011 21:32:29 +0200 Subject: [PATCH 086/130] encoder updates more often --- Marlin/Marlin.pde | 2 +- Marlin/ultralcd.pde | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 7f4f71d59c10..bb0e6bae6e5d 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -2313,7 +2313,7 @@ ISR(TIMER1_COMPA_vect) busy = true; sei(); // Re enable interrupts (normally disabled while inside an interrupt handler) -#ifdef FANCY_LCD +#ifdef ULTIPANEL static int breakdown=0; if((breakdown++)%100==0) buttons_check(); diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index ce55be7a3940..98529d9e7f1b 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -1041,6 +1041,7 @@ void MainMenu::showMainMenu() { lcd.setCursor(0,activeline);lcd.print(activeline?' ':' '); if(encoderpos<0) encoderpos=0; + if(encoderpos>4*lcdslow) encoderpos=4*lcdslow; activeline=abs(encoderpos/lcdslow)%4; lastencoderpos=encoderpos; From f0cba289f5dce7ff7321eca4209b9961bc45af88 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Wed, 12 Oct 2011 22:55:07 +0200 Subject: [PATCH 087/130] fixed thermistor tables and sane config for average user --- Marlin/Configuration.h | 12 +-- Marlin/thermistortables.h | 221 +++++++++++++++++++------------------- Marlin/ultralcd.pde | 24 ++++- 3 files changed, 138 insertions(+), 119 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index b48d1a9ba236..a991c45dce68 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -37,10 +37,10 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -#define SDSUPPORT // Enable SD Card Support in Hardware Console +//#define SDSUPPORT // Enable SD Card Support in Hardware Console -#define ULTRA_LCD //improved 3 button or clickencoder interface -#define ULTIPANEL +//#define ULTRA_LCD //improved 3 button or clickencoder interface +//#define ULTIPANEL const int dropsegments=2; //everything with this number of steps will be ignored as move //// ADVANCED SETTINGS - to tweak parameters @@ -90,8 +90,8 @@ bool axis_relative_modes[] = {false, false, false, false}; // default settings -#define DEFAULT_AXIS_STEPS_PER_UNIT {80,80,200*8/3,14}; // default steps per unit for ultimaker -#define DEFAULT_MAX_FEEDRATE {190*60, 190*60, 10*60, 500000} +#define DEFAULT_AXIS_STEPS_PER_UNIT {79.87220447,79.87220447,200*8/3,14}; // default steps per unit for ultimaker +#define DEFAULT_MAX_FEEDRATE {160*60, 160*60, 10*60, 500000} #define DEFAULT_MAX_ACCELERATION {9000,9000,150,10000} // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. #define DEFAULT_ACCELERATION 4600; // X, Y, Z and E max acceleration in mm/s^2 for printing moves @@ -100,7 +100,7 @@ bool axis_relative_modes[] = {false, false, false, false}; #define DEFAULT_MINIMUMFEEDRATE 00*60; // minimum feedrate #define DEFAULT_MINTRAVELFEEDRATE 00*60; #define DEFAULT_MINSEGMENTTIME 20000; // minimum segmenttime to prevent buffer underruns -#define DEFAULT_XYJERK 25.0*60; +#define DEFAULT_XYJERK 30.0*60; #define DEFAULT_ZJERK 10.0*60; diff --git a/Marlin/thermistortables.h b/Marlin/thermistortables.h index 1c780020b02e..32a2500ebd26 100644 --- a/Marlin/thermistortables.h +++ b/Marlin/thermistortables.h @@ -1,132 +1,133 @@ #ifndef THERMISTORTABLES_H_ #define THERMISTORTABLES_H_ +#define OVERSAMPLENR 1 #if (THERMISTORHEATER == 1) || (THERMISTORBED == 1) //100k bed thermistor #define NUMTEMPS_1 61 const short temptable_1[NUMTEMPS_1][2] = { -{ (23*16) , 300 }, -{ (25*16) , 295 }, -{ (27*16) , 290 }, -{ (28*16) , 285 }, -{ (31*16) , 280 }, -{ (33*16) , 275 }, -{ (35*16) , 270 }, -{ (38*16) , 265 }, -{ (41*16) , 260 }, -{ (44*16) , 255 }, -{ (48*16) , 250 }, -{ (52*16) , 245 }, -{ (56*16) , 240 }, -{ (61*16) , 235 }, -{ (66*16) , 230 }, -{ (71*16) , 225 }, -{ (78*16) , 220 }, -{ (84*16) , 215 }, -{ (92*16) , 210 }, -{ (100*16), 205 }, -{ (109*16), 200 }, -{ (120*16), 195 }, -{ (131*16), 190 }, -{ (143*16), 185 }, -{ (156*16), 180 }, -{ (171*16), 175 }, -{ (187*16), 170 }, -{ (205*16), 165 }, -{ (224*16), 160 }, -{ (245*16), 155 }, -{ (268*16), 150 }, -{ (293*16), 145 }, -{ (320*16), 140 }, -{ (348*16), 135 }, -{ (379*16), 130 }, -{ (411*16), 125 }, -{ (445*16), 120 }, -{ (480*16), 115 }, -{ (516*16), 110 }, -{ (553*16), 105 }, -{ (591*16), 100 }, -{ (628*16), 95 }, -{ (665*16), 90 }, -{ (702*16), 85 }, -{ (737*16), 80 }, -{ (770*16), 75 }, -{ (801*16), 70 }, -{ (830*16), 65 }, -{ (857*16), 60 }, -{ (881*16), 55 }, -{ (903*16), 50 }, -{ (922*16), 45 }, -{ (939*16), 40 }, -{ (954*16), 35 }, -{ (966*16), 30 }, -{ (977*16), 25 }, -{ (985*16), 20 }, -{ (993*16), 15 }, -{ (999*16), 10 }, -{ (1004*16), 5 }, -{ (1008*16), 0 } //safety +{ (23*OVERSAMPLENR) , 300 }, +{ (25*OVERSAMPLENR) , 295 }, +{ (27*OVERSAMPLENR) , 290 }, +{ (28*OVERSAMPLENR) , 285 }, +{ (31*OVERSAMPLENR) , 280 }, +{ (33*OVERSAMPLENR) , 275 }, +{ (35*OVERSAMPLENR) , 270 }, +{ (38*OVERSAMPLENR) , 265 }, +{ (41*OVERSAMPLENR) , 260 }, +{ (44*OVERSAMPLENR) , 255 }, +{ (48*OVERSAMPLENR) , 250 }, +{ (52*OVERSAMPLENR) , 245 }, +{ (56*OVERSAMPLENR) , 240 }, +{ (61*OVERSAMPLENR) , 235 }, +{ (66*OVERSAMPLENR) , 230 }, +{ (71*OVERSAMPLENR) , 225 }, +{ (78*OVERSAMPLENR) , 220 }, +{ (84*OVERSAMPLENR) , 215 }, +{ (92*OVERSAMPLENR) , 210 }, +{ (100*OVERSAMPLENR), 205 }, +{ (109*OVERSAMPLENR), 200 }, +{ (120*OVERSAMPLENR), 195 }, +{ (131*OVERSAMPLENR), 190 }, +{ (143*OVERSAMPLENR), 185 }, +{ (156*OVERSAMPLENR), 180 }, +{ (171*OVERSAMPLENR), 175 }, +{ (187*OVERSAMPLENR), 170 }, +{ (205*OVERSAMPLENR), 165 }, +{ (224*OVERSAMPLENR), 160 }, +{ (245*OVERSAMPLENR), 155 }, +{ (268*OVERSAMPLENR), 150 }, +{ (293*OVERSAMPLENR), 145 }, +{ (320*OVERSAMPLENR), 140 }, +{ (348*OVERSAMPLENR), 135 }, +{ (379*OVERSAMPLENR), 130 }, +{ (411*OVERSAMPLENR), 125 }, +{ (445*OVERSAMPLENR), 120 }, +{ (480*OVERSAMPLENR), 115 }, +{ (516*OVERSAMPLENR), 110 }, +{ (553*OVERSAMPLENR), 105 }, +{ (591*OVERSAMPLENR), 100 }, +{ (628*OVERSAMPLENR), 95 }, +{ (665*OVERSAMPLENR), 90 }, +{ (702*OVERSAMPLENR), 85 }, +{ (737*OVERSAMPLENR), 80 }, +{ (770*OVERSAMPLENR), 75 }, +{ (801*OVERSAMPLENR), 70 }, +{ (830*OVERSAMPLENR), 65 }, +{ (857*OVERSAMPLENR), 60 }, +{ (881*OVERSAMPLENR), 55 }, +{ (903*OVERSAMPLENR), 50 }, +{ (922*OVERSAMPLENR), 45 }, +{ (939*OVERSAMPLENR), 40 }, +{ (954*OVERSAMPLENR), 35 }, +{ (966*OVERSAMPLENR), 30 }, +{ (977*OVERSAMPLENR), 25 }, +{ (985*OVERSAMPLENR), 20 }, +{ (993*OVERSAMPLENR), 15 }, +{ (999*OVERSAMPLENR), 10 }, +{ (1004*OVERSAMPLENR), 5 }, +{ (1008*OVERSAMPLENR), 0 } //safety }; #endif #if (THERMISTORHEATER == 2) || (THERMISTORBED == 2) //200k bed thermistor #define NUMTEMPS_2 21 const short temptable_2[NUMTEMPS_2][2] = { - {(1*16), 848}, - {(54*16), 275}, - {(107*16), 228}, - {(160*16), 202}, - {(213*16), 185}, - {(266*16), 171}, - {(319*16), 160}, - {(372*16), 150}, - {(425*16), 141}, - {(478*16), 133}, - {(531*16), 125}, - {(584*16), 118}, - {(637*16), 110}, - {(690*16), 103}, - {(743*16), 95}, - {(796*16), 86}, - {(849*16), 77}, - {(902*16), 65}, - {(955*16), 49}, - {(1008*16), 17}, - {(1020*16), 0} //safety + {(1*OVERSAMPLENR), 848}, + {(54*OVERSAMPLENR), 275}, + {(107*OVERSAMPLENR), 228}, + {(160*OVERSAMPLENR), 202}, + {(213*OVERSAMPLENR), 185}, + {(266*OVERSAMPLENR), 171}, + {(319*OVERSAMPLENR), 160}, + {(372*OVERSAMPLENR), 150}, + {(425*OVERSAMPLENR), 141}, + {(478*OVERSAMPLENR), 133}, + {(531*OVERSAMPLENR), 125}, + {(584*OVERSAMPLENR), 118}, + {(637*OVERSAMPLENR), 110}, + {(690*OVERSAMPLENR), 103}, + {(743*OVERSAMPLENR), 95}, + {(796*OVERSAMPLENR), 86}, + {(849*OVERSAMPLENR), 77}, + {(902*OVERSAMPLENR), 65}, + {(955*OVERSAMPLENR), 49}, + {(1008*OVERSAMPLENR), 17}, + {(1020*OVERSAMPLENR), 0} //safety }; #endif #if (THERMISTORHEATER == 3) || (THERMISTORBED == 3) //mendel-parts #define NUMTEMPS_3 28 const short temptable_3[NUMTEMPS_3][2] = { - {(1*16),864}, - {(21*16),300}, - {(25*16),290}, - {(29*16),280}, - {(33*16),270}, - {(39*16),260}, - {(46*16),250}, - {(54*16),240}, - {(64*16),230}, - {(75*16),220}, - {(90*16),210}, - {(107*16),200}, - {(128*16),190}, - {(154*16),180}, - {(184*16),170}, - {(221*16),160}, - {(265*16),150}, - {(316*16),140}, - {(375*16),130}, - {(441*16),120}, - {(513*16),110}, - {(588*16),100}, - {(734*16),80}, - {(856*16),60}, - {(938*16),40}, - {(986*16),20}, - {(1008*16),0}, - {(1018*16),-20} + {(1*OVERSAMPLENR),864}, + {(21*OVERSAMPLENR),300}, + {(25*OVERSAMPLENR),290}, + {(29*OVERSAMPLENR),280}, + {(33*OVERSAMPLENR),270}, + {(39*OVERSAMPLENR),260}, + {(46*OVERSAMPLENR),250}, + {(54*OVERSAMPLENR),240}, + {(64*OVERSAMPLENR),230}, + {(75*OVERSAMPLENR),220}, + {(90*OVERSAMPLENR),210}, + {(107*OVERSAMPLENR),200}, + {(128*OVERSAMPLENR),190}, + {(154*OVERSAMPLENR),180}, + {(184*OVERSAMPLENR),170}, + {(221*OVERSAMPLENR),160}, + {(265*OVERSAMPLENR),150}, + {(316*OVERSAMPLENR),140}, + {(375*OVERSAMPLENR),130}, + {(441*OVERSAMPLENR),120}, + {(513*OVERSAMPLENR),110}, + {(588*OVERSAMPLENR),100}, + {(734*OVERSAMPLENR),80}, + {(856*OVERSAMPLENR),60}, + {(938*OVERSAMPLENR),40}, + {(986*OVERSAMPLENR),20}, + {(1008*OVERSAMPLENR),0}, + {(1018*OVERSAMPLENR),-20} }; #endif diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 98529d9e7f1b..60315fea4bf8 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -429,7 +429,7 @@ enum { ItemC_vmaxx, ItemC_vmaxy, ItemC_vmaxz, ItemC_vmaxe, ItemC_vmin, ItemC_amaxx, ItemC_amaxy, ItemC_amaxz, ItemC_amaxe, - ItemC_aret,ItemC_esteps, ItemC_store, ItemC_load + ItemC_aret,ItemC_esteps, ItemC_store, ItemC_load,ItemC_failsafe }; void MainMenu::showControl() @@ -752,9 +752,25 @@ void MainMenu::showControl() { //enquecommand("M84"); beepshort(); + BLOCK; + StoreSettings(); } }break; case ItemC_load: + { + if(force_lcd_update) + { + lcd.setCursor(0,line);lcd.print(" Load EPROM"); + } + if((activeline==line) && CLICKED) + { + //enquecommand("M84"); + beepshort(); + BLOCK; + RetrieveSettings(); + } + }break; + case ItemC_failsafe: { if(force_lcd_update) { @@ -764,6 +780,8 @@ void MainMenu::showControl() { //enquecommand("M84"); beepshort(); + BLOCK; + RetrieveSettings(true); } }break; default: @@ -790,8 +808,8 @@ void MainMenu::showControl() { lineoffset++; encoderpos=3*lcdslow; - if(lineoffset>(ItemC_esteps+1-LCD_HEIGHT)) - lineoffset=ItemC_esteps+1-LCD_HEIGHT; + if(lineoffset>(ItemC_failsafe+1-LCD_HEIGHT)) + lineoffset=ItemC_failsafe+1-LCD_HEIGHT; force_lcd_update=true; } //encoderpos=encoderpos%LCD_HEIGHT; From 12e6bfb6866f6e6b4bb1432bb7dfb22e91555f25 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Wed, 12 Oct 2011 23:57:52 +0200 Subject: [PATCH 088/130] for joris. --- Marlin/Configuration.h | 6 +++--- Marlin/Marlin.pde | 5 +++-- Marlin/ultralcd.pde | 11 ++++++++--- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index a991c45dce68..3e23503a1662 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -37,10 +37,10 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -//#define SDSUPPORT // Enable SD Card Support in Hardware Console +#define SDSUPPORT // Enable SD Card Support in Hardware Console -//#define ULTRA_LCD //improved 3 button or clickencoder interface -//#define ULTIPANEL +#define ULTRA_LCD //improved 3 button or clickencoder interface +#define ULTIPANEL const int dropsegments=2; //everything with this number of steps will be ignored as move //// ADVANCED SETTINGS - to tweak parameters diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index bb0e6bae6e5d..72dee51701c0 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1352,10 +1352,11 @@ void manage_heater() #ifdef USE_WATCHDOG wd_reset(); #endif - //there is no FANCY_LCD here, because this routine is called within moves, and delays them. one could loose steps. - + + lcd_status(); if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) return; + previous_millis_heater = millis(); #ifdef HEATER_USES_THERMISTOR current_raw = analogRead(TEMP_0_PIN); diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 60315fea4bf8..5e983492a8de 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -91,7 +91,7 @@ void lcd_status() #ifdef ULTIPANEL static long previous_millis_buttons=0; buttons_check(); - previous_millis_buttons=millis(); + //previous_millis_buttons=millis(); static uint8_t oldbuttons=0; if((buttons==oldbuttons) && ((millis() - previous_millis_lcd) < LCD_UPDATE_INTERVAL) ) return; @@ -869,6 +869,7 @@ uint8_t getnrfilenames() void MainMenu::showSD() { +#ifdef SDSUPPORT uint8_t line=0; if(lastlineoffset!=lineoffset) { @@ -989,12 +990,14 @@ void MainMenu::showSD() lcd.setCursor(0,activeline);lcd.print((activeline+lineoffset)?'>':'\003'); } - +#endif } enum {ItemM_watch, ItemM_prepare, ItemM_control, ItemM_file }; void MainMenu::showMainMenu() { + if(encoderpos/lcdslow!=lastencoderpos/lcdslow) + force_lcd_update=true; for(short line=0;line<4;line++) { switch(line) @@ -1030,6 +1033,7 @@ void MainMenu::showMainMenu() beepshort(); } }break; +#ifdef SDSUPPORT case ItemM_file: { if(force_lcd_update) @@ -1050,6 +1054,7 @@ void MainMenu::showMainMenu() beepshort(); } }break; +#endif default: break; } @@ -1059,7 +1064,7 @@ void MainMenu::showMainMenu() { lcd.setCursor(0,activeline);lcd.print(activeline?' ':' '); if(encoderpos<0) encoderpos=0; - if(encoderpos>4*lcdslow) encoderpos=4*lcdslow; + if(encoderpos>3*lcdslow) encoderpos=3*lcdslow; activeline=abs(encoderpos/lcdslow)%4; lastencoderpos=encoderpos; From b958fd585de90be5ebf7ee7bb02f9da32dfab0cf Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Wed, 12 Oct 2011 23:59:11 +0200 Subject: [PATCH 089/130] sane config for everybody --- Marlin/Configuration.h | 6 +++--- Marlin/ultralcd.pde | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 3e23503a1662..a991c45dce68 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -37,10 +37,10 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -#define SDSUPPORT // Enable SD Card Support in Hardware Console +//#define SDSUPPORT // Enable SD Card Support in Hardware Console -#define ULTRA_LCD //improved 3 button or clickencoder interface -#define ULTIPANEL +//#define ULTRA_LCD //improved 3 button or clickencoder interface +//#define ULTIPANEL const int dropsegments=2; //everything with this number of steps will be ignored as move //// ADVANCED SETTINGS - to tweak parameters diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 5e983492a8de..f0e125185493 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -1231,4 +1231,7 @@ char *fillto(int8_t n,char *c) } -#endif \ No newline at end of file +#else +inline void lcd_status() {}; +#endif + From 4589ab3f860cfc4c22060412e86434b49f9ff533 Mon Sep 17 00:00:00 2001 From: bradleyf Date: Wed, 12 Oct 2011 18:02:14 -0400 Subject: [PATCH 090/130] Added back Simple LCD functionality that was obliterated by Berhnard's checkins. Thanks for doing this for the fourth time! --- Marlin/Configuration.h | 3 +- Marlin/Marlin.pde | 8 +- Marlin/Simplelcd.h | 29 +++++++ Marlin/Simplelcd.pde | 183 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 219 insertions(+), 4 deletions(-) create mode 100644 Marlin/Simplelcd.h create mode 100644 Marlin/Simplelcd.pde diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index a991c45dce68..0af11436248e 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -38,9 +38,10 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the // Comment out (using // at the start of the line) to disable SD support: //#define SDSUPPORT // Enable SD Card Support in Hardware Console - //#define ULTRA_LCD //improved 3 button or clickencoder interface //#define ULTIPANEL +//#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) + const int dropsegments=2; //everything with this number of steps will be ignored as move //// ADVANCED SETTINGS - to tweak parameters diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index bb0e6bae6e5d..54a305ac5fe4 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -44,7 +44,9 @@ #include "Marlin.h" #include "speed_lookuptable.h" #include "ultralcd.h" - +#ifdef SIMPLE_LCD + #include "Simplelcd.h" +#endif char version_string[] = "U0.9.3.3-BK"; @@ -58,7 +60,7 @@ char version_string[] = "U0.9.3.3-BK"; #endif //CRITICAL_SECTION_START -#if defined SDSUPPORT || defined FANCY_LCD +#if defined SDSUPPORT // The number of linear motions that can be in the plan at any give time. #define BLOCK_BUFFER_SIZE 16 // SD,LCD,Buttons take more memory, block buffer needs to be smaller #else @@ -66,7 +68,7 @@ char version_string[] = "U0.9.3.3-BK"; #endif #ifdef SIMPLE_LCD - #define BLOCK_BUFFER_SIZE 24 // A little less buffer for just a simple LCD + #define BLOCK_BUFFER_SIZE 30 // A little less buffer for just a simple LCD #endif // if DEBUG_STEPS is enabled, M114 can be used to compare two methods of determining the X,Y,Z position of the printer. diff --git a/Marlin/Simplelcd.h b/Marlin/Simplelcd.h new file mode 100644 index 000000000000..ad38fa6765ac --- /dev/null +++ b/Marlin/Simplelcd.h @@ -0,0 +1,29 @@ +#ifndef __LCDH +#define __LCDH + +#ifdef SIMPLE_LCD + #define LCD_UPDATE_INTERVAL 400 + + #include "Configuration.h" + #include + extern LiquidCrystal lcd; + + //lcd display size + #define LCD_WIDTH 16 + #define LCD_HEIGHT 2 + + void lcd_status(); + void lcd_status(const char* message); + void lcd_init(); + void lcd_activate(); + void lcd_update(); + + + #define LCD_MESSAGE(x) lcd_status(x); + #define LCD_STATUS lcd_status() +#else + #define LCD_STATUS + #define LCD_MESSAGE(x) +#endif +#endif + diff --git a/Marlin/Simplelcd.pde b/Marlin/Simplelcd.pde new file mode 100644 index 000000000000..a258819375ea --- /dev/null +++ b/Marlin/Simplelcd.pde @@ -0,0 +1,183 @@ +#ifdef SIMPLE_LCD + +extern volatile int feedmultiply; + +#include +#include "Simplelcd.h" + +LiquidCrystal lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5,LCD_PINS_D6,LCD_PINS_D7); //RS,Enable,D4,D5,D6,D7 + +unsigned long previous_millis_lcd=0; + +char messagetext[LCD_WIDTH]=""; +bool force_lcd_update=false; +extern LiquidCrystal lcd; + + +//return for string conversion routines +char conv[8]; + +/// convert float to string with +123.4 format +char *ftostr31(const float &x) +{ + //sprintf(conv,"%5.1f",x); + int xx=x*10; + conv[0]=(xx>=0)?'+':'-'; + xx=abs(xx); + conv[1]=(xx/1000)%10+'0'; + conv[2]=(xx/100)%10+'0'; + conv[3]=(xx/10)%10+'0'; + conv[4]='.'; + conv[5]=(xx)%10+'0'; + conv[6]=0; + return conv; +} + +/// convert float to string with +1234.5 format +char *ftostr51(const float &x) +{ + int xx=x*10; + conv[0]=(xx>=0)?'+':'-'; + xx=abs(xx); + conv[1]=(xx/10000)%10+'0'; + conv[2]=(xx/1000)%10+'0'; + conv[3]=(xx/100)%10+'0'; + conv[4]=(xx/10)%10+'0'; + conv[5]='.'; + conv[6]=(xx)%10+'0'; + conv[7]=0; + return conv; +} + +char *fillto(int8_t n,char *c) +{ + static char ret[25]; + bool endfound=false; + for(int8_t i=0;i3) +// lcd.setCursor(0,3); +// else +// lcd.setCursor(0,0); +// lcd.print(message); +// int missing=(LCD_WIDTH-strlen(message)); +// if(missing>0) +// for(int i=0;i Date: Thu, 13 Oct 2011 00:46:06 +0200 Subject: [PATCH 091/130] added support for smaller lcd in a useful, compatible way if lcd_height<4, just temperature is given --- Marlin/Configuration.h | 19 ++++- Marlin/Simplelcd.h | 29 ------- Marlin/Simplelcd.pde | 183 ----------------------------------------- Marlin/ultralcd.h | 5 +- Marlin/ultralcd.pde | 46 +++++++++-- 5 files changed, 57 insertions(+), 225 deletions(-) delete mode 100644 Marlin/Simplelcd.h delete mode 100644 Marlin/Simplelcd.pde diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 0af11436248e..d73400828278 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -37,10 +37,23 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define BAUDRATE 115200 // Comment out (using // at the start of the line) to disable SD support: -//#define SDSUPPORT // Enable SD Card Support in Hardware Console -//#define ULTRA_LCD //improved 3 button or clickencoder interface + +//#define ULTRA_LCD //any lcd +#define LCD_WIDTH 20 +#define LCD_HEIGHT 4 + //#define ULTIPANEL -//#define SIMPLE_LCD // 16x2 Simple LCD Display (Bootup, Temp Monitoring only) +#ifdef ULTIPANEL + #define SDSUPPORT + #define ULTRA_LCD + #define LCD_WIDTH 20 +#define LCD_HEIGHT 4 +#endif + + +//#define SDSUPPORT // Enable SD Card Support in Hardware Console + + const int dropsegments=2; //everything with this number of steps will be ignored as move diff --git a/Marlin/Simplelcd.h b/Marlin/Simplelcd.h deleted file mode 100644 index ad38fa6765ac..000000000000 --- a/Marlin/Simplelcd.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __LCDH -#define __LCDH - -#ifdef SIMPLE_LCD - #define LCD_UPDATE_INTERVAL 400 - - #include "Configuration.h" - #include - extern LiquidCrystal lcd; - - //lcd display size - #define LCD_WIDTH 16 - #define LCD_HEIGHT 2 - - void lcd_status(); - void lcd_status(const char* message); - void lcd_init(); - void lcd_activate(); - void lcd_update(); - - - #define LCD_MESSAGE(x) lcd_status(x); - #define LCD_STATUS lcd_status() -#else - #define LCD_STATUS - #define LCD_MESSAGE(x) -#endif -#endif - diff --git a/Marlin/Simplelcd.pde b/Marlin/Simplelcd.pde deleted file mode 100644 index a258819375ea..000000000000 --- a/Marlin/Simplelcd.pde +++ /dev/null @@ -1,183 +0,0 @@ -#ifdef SIMPLE_LCD - -extern volatile int feedmultiply; - -#include -#include "Simplelcd.h" - -LiquidCrystal lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5,LCD_PINS_D6,LCD_PINS_D7); //RS,Enable,D4,D5,D6,D7 - -unsigned long previous_millis_lcd=0; - -char messagetext[LCD_WIDTH]=""; -bool force_lcd_update=false; -extern LiquidCrystal lcd; - - -//return for string conversion routines -char conv[8]; - -/// convert float to string with +123.4 format -char *ftostr31(const float &x) -{ - //sprintf(conv,"%5.1f",x); - int xx=x*10; - conv[0]=(xx>=0)?'+':'-'; - xx=abs(xx); - conv[1]=(xx/1000)%10+'0'; - conv[2]=(xx/100)%10+'0'; - conv[3]=(xx/10)%10+'0'; - conv[4]='.'; - conv[5]=(xx)%10+'0'; - conv[6]=0; - return conv; -} - -/// convert float to string with +1234.5 format -char *ftostr51(const float &x) -{ - int xx=x*10; - conv[0]=(xx>=0)?'+':'-'; - xx=abs(xx); - conv[1]=(xx/10000)%10+'0'; - conv[2]=(xx/1000)%10+'0'; - conv[3]=(xx/100)%10+'0'; - conv[4]=(xx/10)%10+'0'; - conv[5]='.'; - conv[6]=(xx)%10+'0'; - conv[7]=0; - return conv; -} - -char *fillto(int8_t n,char *c) -{ - static char ret[25]; - bool endfound=false; - for(int8_t i=0;i3) -// lcd.setCursor(0,3); -// else -// lcd.setCursor(0,0); -// lcd.print(message); -// int missing=(LCD_WIDTH-strlen(message)); -// if(missing>0) -// for(int i=0;i3)||force_lcd_update) + { + lcd.setCursor(1,0); + lcd.print(ftostr3(analog2temp(current_raw))); + oldcurrentraw=current_raw; + } + if((target_raw!=oldtargetraw)||force_lcd_update) + { + lcd.setCursor(5,0); + lcd.print(ftostr3(analog2temp(target_raw))); + oldtargetraw=target_raw; + } + +#endif } enum {ItemP_exit, ItemP_home, ItemP_origin, ItemP_preheat, ItemP_extrude, ItemP_disstep}; @@ -998,7 +1027,10 @@ void MainMenu::showMainMenu() { if(encoderpos/lcdslow!=lastencoderpos/lcdslow) force_lcd_update=true; - for(short line=0;line<4;line++) +#ifndef ULTIPANEL + force_lcd_update=false; +#endif + for(short line=0;line3*lcdslow) encoderpos=3*lcdslow; - activeline=abs(encoderpos/lcdslow)%4; + activeline=abs(encoderpos/lcdslow)%LCD_HEIGHT; lastencoderpos=encoderpos; lcd.setCursor(0,activeline);lcd.print(activeline?'>':'\003'); From 1a8ef677caee201597509276c44ee24099b6d79e Mon Sep 17 00:00:00 2001 From: bradleyf Date: Wed, 12 Oct 2011 23:17:14 -0400 Subject: [PATCH 092/130] Allow ULTRA_LCD (any lcd) to compile without SDSUPPORT --- Marlin/Configuration.h | 6 +++--- Marlin/ultralcd.pde | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index d73400828278..54c0e01b17c5 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -38,9 +38,9 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the // Comment out (using // at the start of the line) to disable SD support: -//#define ULTRA_LCD //any lcd -#define LCD_WIDTH 20 -#define LCD_HEIGHT 4 +// #define ULTRA_LCD //any lcd +#define LCD_WIDTH 16 +#define LCD_HEIGHT 2 //#define ULTIPANEL #ifdef ULTIPANEL diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 38c9e9758479..ad312f0f6920 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -853,6 +853,7 @@ void MainMenu::showControl() void MainMenu::getfilename(const uint8_t nr) { +#ifdef SDSUPPORT dir_t p; root.rewind(); uint8_t cnt=0; @@ -877,10 +878,12 @@ void MainMenu::getfilename(const uint8_t nr) } filename[writepos++]=0; } +#endif } uint8_t getnrfilenames() { +#ifdef SDSUPPORT dir_t p; root.rewind(); uint8_t cnt=0; @@ -894,6 +897,7 @@ uint8_t getnrfilenames() cnt++; } return cnt; +#endif } void MainMenu::showSD() From e7cc585bb1b54515567912439cda7df54ed81781 Mon Sep 17 00:00:00 2001 From: bradleyf Date: Wed, 12 Oct 2011 23:25:01 -0400 Subject: [PATCH 093/130] Allow non-Ultipanel lcd's to display message text on bottom line --- Marlin/ultralcd.pde | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index ad312f0f6920..5961f16e4ff6 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -292,7 +292,7 @@ void MainMenu::showStatus() } if(messagetext[0]!='\0') { - lcd.setCursor(0,3); + lcd.setCursor(0,LCD_HEIGHT-1); lcd.print(fillto(LCD_WIDTH,messagetext)); messagetext[0]='\0'; } @@ -322,6 +322,13 @@ void MainMenu::showStatus() oldtargetraw=target_raw; } + if(messagetext[0]!='\0') + { + lcd.setCursor(0,LCD_HEIGHT-1); + lcd.print(fillto(LCD_WIDTH,messagetext)); + messagetext[0]='\0'; + } + #endif } From bac956e1ff16e15f3086291fc88ace821d562190 Mon Sep 17 00:00:00 2001 From: lampmaker Date: Fri, 14 Oct 2011 10:24:32 +0200 Subject: [PATCH 094/130] Enabled PID. EXPERIMENTAL! PID paramters set to P=1000; I=0; D=0 by default. This results in a behavior pretty similar to the standard on/off mode. Output power to the heater (0-255) is displayed as the bed temperature in the Skeinforge graph M105 returns heter temperatrure and output power. --- Marlin/Configuration.h | 10 +++++----- Marlin/Marlin.pde | 17 +++++++++++------ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 5ef689502cc6..01c349faf9ee 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -117,16 +117,16 @@ bool axis_relative_modes[] = {false, false, false, false}; /// PID settings: // Uncomment the following line to enable PID support. -//#define PIDTEMP +#define PIDTEMP #ifdef PIDTEMP //#define PID_DEBUG 1 // Sends debug data to the serial port. //#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % -#define PID_MAX 156 // limits current to nozzle +#define PID_MAX 255 // limits current to nozzle #define PID_INTEGRAL_DRIVE_MAX 156.0 #define PID_dT 0.16 -double Kp = 20.0; -double Ki = 1.5*PID_dT; -double Kd = 80/PID_dT; +double Kp = 1000; //20.0; +double Ki = 0; //1.5*PID_dT; +double Kd = 0; //80/PID_dT; #endif // PIDTEMP diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 8a60ec744c87..dffa3abf17b9 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -197,6 +197,7 @@ unsigned char temp_meas_ready = false; double pid_input; double pid_output; bool pid_reset; + float HeaterPower; #endif //PIDTEMP float tt = 0, bt = 0; #ifdef WATCHPERIOD @@ -964,7 +965,7 @@ inline void process_commands() Serial.print(current_raw); #if TEMP_1_PIN > -1 Serial.print(" B:"); - Serial.println(bt); + Serial.println(HeaterPower); #else Serial.println(); #endif @@ -1156,7 +1157,10 @@ inline void process_commands() Serial.print("Ki ");Serial.println(Ki/PID_dT); Serial.print("Kd ");Serial.println(Kd*PID_dT); temp_iState_min = 0.0; + if (Ki!=0) { temp_iState_max = PID_INTEGRAL_DRIVE_MAX / Ki; + } + else temp_iState_max = 1.0e10; break; #endif //PIDTEMP case 500: // Store settings in EEPROM @@ -1393,14 +1397,15 @@ void manage_heater() #endif #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) #ifdef PIDTEMP - error = target_raw - current_raw; - pTerm = (PID_PGAIN * error) / 100; + float error = target_raw - current_raw; + pTerm = (Kp * error) / 100; temp_iState += error; temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = (PID_IGAIN * temp_iState) / 100; - dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; + iTerm = (Ki * temp_iState) / 100; + dTerm = (Kd * (current_raw - temp_dState)) / 100; temp_dState = current_raw; - analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); + HeaterPower= constrain(pTerm + iTerm - dTerm, 0, PID_MAX); + analogWrite(HEATER_0_PIN,HeaterPower); #else if(current_raw >= target_raw) { From 2942d3ab67cd86d2a66c0cb22ee726e4a5f5a219 Mon Sep 17 00:00:00 2001 From: lampmaker Date: Fri, 14 Oct 2011 10:48:46 +0200 Subject: [PATCH 095/130] Changed PID parameters: max integral limit --- Marlin/Configuration.h | 2 +- Marlin/Marlin.pde | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 01c349faf9ee..cc55e4a1db28 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -122,7 +122,7 @@ bool axis_relative_modes[] = {false, false, false, false}; //#define PID_DEBUG 1 // Sends debug data to the serial port. //#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % #define PID_MAX 255 // limits current to nozzle -#define PID_INTEGRAL_DRIVE_MAX 156.0 +#define PID_INTEGRAL_DRIVE_MAX 255 #define PID_dT 0.16 double Kp = 1000; //20.0; double Ki = 0; //1.5*PID_dT; diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index dffa3abf17b9..82d991fa6b4e 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1401,7 +1401,7 @@ void manage_heater() pTerm = (Kp * error) / 100; temp_iState += error; temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = (Ki * temp_iState) / 100; + iTerm = (Ki * temp_iState); dTerm = (Kd * (current_raw - temp_dState)) / 100; temp_dState = current_raw; HeaterPower= constrain(pTerm + iTerm - dTerm, 0, PID_MAX); From 8766972e07efb8ba27e17605df061c3265b28a90 Mon Sep 17 00:00:00 2001 From: lampmaker Date: Fri, 14 Oct 2011 14:50:23 +0200 Subject: [PATCH 096/130] Some modifications to PID: - smoothing - Disable PID when temp is 15 degC above target Method for tuning PID: set heater output directly using a negative value for KP - if kP <0, the kp value is the heater setting (0-255) e.g. M301 P-128 will set the heater at 50% (volts) it's an ugly hack but a quick one. --- Marlin/Configuration.h | 4 ++++ Marlin/Marlin.pde | 28 ++++++++++++++++++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index cc55e4a1db28..8d59513cc391 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -117,6 +117,10 @@ bool axis_relative_modes[] = {false, false, false, false}; /// PID settings: // Uncomment the following line to enable PID support. +#define SMOOTHING +#define SMOOTHFACTOR 5.0 +float current_raw_average=0; + #define PIDTEMP #ifdef PIDTEMP //#define PID_DEBUG 1 // Sends debug data to the serial port. diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 82d991fa6b4e..925f030e0e4f 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1372,12 +1372,13 @@ void manage_heater() current_raw = read_max6675(); #endif #ifdef SMOOTHING - nma = (nma + current_raw) - (nma / SMOOTHFACTOR); - current_raw = nma / SMOOTHFACTOR; + + current_raw_average=(current_raw_average*(SMOOTHFACTOR-1)+current_raw)/SMOOTHFACTOR; + #endif #ifdef WATCHPERIOD if(watchmillis && millis() - watchmillis > WATCHPERIOD){ - if(watch_raw + 1 >= current_raw){ + if(watch_raw + 1 >= current_raw_average){ target_raw = 0; digitalWrite(HEATER_0_PIN,LOW); digitalWrite(LED_PIN,LOW); @@ -1396,18 +1397,25 @@ void manage_heater() } #endif #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) + #ifdef PIDTEMP - float error = target_raw - current_raw; - pTerm = (Kp * error) / 100; + HeaterPower=0; + if (current_raw_average=0) { + float error = target_raw - current_raw_average; + pTerm = (Kp * error) / 100.0; temp_iState += error; temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); iTerm = (Ki * temp_iState); - dTerm = (Kd * (current_raw - temp_dState)) / 100; - temp_dState = current_raw; - HeaterPower= constrain(pTerm + iTerm - dTerm, 0, PID_MAX); - analogWrite(HEATER_0_PIN,HeaterPower); + dTerm = (Kd * (current_raw_average - temp_dState)) / 100.0; + temp_dState = current_raw_average; + HeaterPower= constrain(pTerm + iTerm - dTerm, 0, PID_MAX); + } + else HeaterPower= constrain(-Kp,0, 255); // + } + analogWrite(HEATER_0_PIN,HeaterPower); #else - if(current_raw >= target_raw) + if(current_raw_average >= target_raw) { digitalWrite(HEATER_0_PIN,LOW); digitalWrite(LED_PIN,LOW); From 1f3c0e5f6dfb833ff4a6e6c79b135e6b1a25ff94 Mon Sep 17 00:00:00 2001 From: lampmaker Date: Fri, 14 Oct 2011 15:05:14 +0200 Subject: [PATCH 097/130] EEPROM now stores & retreives PID settings --- Marlin/EEPROM.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Marlin/EEPROM.h b/Marlin/EEPROM.h index 02914ea1c7f5..9ce5bf2e9f68 100644 --- a/Marlin/EEPROM.h +++ b/Marlin/EEPROM.h @@ -21,7 +21,7 @@ template int EEPROM_readAnything(int &ee, T& value) #define EEPROM_OFFSET 100 -#define EEPROM_VERSION "V03" // IMPORTANT: Whenever there are changes made to the variables stored in EEPROM +#define EEPROM_VERSION "V04" // IMPORTANT: Whenever there are changes made to the variables stored in EEPROM // in the functions below, also increment the version number. This makes sure that // the default values are used whenever there is a change to the data, to prevent // wrong data being written to the variables. @@ -40,6 +40,9 @@ void StoreSettings() { EEPROM_writeAnything(i,minsegmenttime); EEPROM_writeAnything(i,max_xy_jerk); EEPROM_writeAnything(i,max_z_jerk); + EEPROM_writeAnything(i,Kp); + EEPROM_writeAnything(i,Ki); + EEPROM_writeAnything(i,Kd); char ver2[4]=EEPROM_VERSION; i=EEPROM_OFFSET; EEPROM_writeAnything(i,ver2); // validate data @@ -64,6 +67,9 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will EEPROM_readAnything(i,minsegmenttime); EEPROM_readAnything(i,max_xy_jerk); EEPROM_readAnything(i,max_z_jerk); + EEPROM_readAnything(i,Kp); + EEPROM_readAnything(i,Ki); + EEPROM_readAnything(i,Kd); Serial.println("Stored settings retreived:"); } else { @@ -113,6 +119,11 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will Serial.print(" B");Serial.print(minsegmenttime); Serial.print(" X");Serial.print(max_xy_jerk/60); Serial.print(" Z");Serial.println(max_z_jerk/60); + Serial.println("PID settings:"); + Serial.print(" M301"); + Serial.print(" P");Serial.print(Kp); + Serial.print(" I");Serial.print(Ki); + Serial.print(" D");Serial.println(Kd); } From 1fc8fa329b0370bc662c98342d7a3c53393f4dd5 Mon Sep 17 00:00:00 2001 From: lampmaker Date: Sat, 15 Oct 2011 11:31:47 +0300 Subject: [PATCH 098/130] Disabled EEPROM info sent to serial --- Marlin/EEPROM.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Marlin/EEPROM.h b/Marlin/EEPROM.h index 02914ea1c7f5..dca1230b1049 100644 --- a/Marlin/EEPROM.h +++ b/Marlin/EEPROM.h @@ -43,7 +43,7 @@ void StoreSettings() { char ver2[4]=EEPROM_VERSION; i=EEPROM_OFFSET; EEPROM_writeAnything(i,ver2); // validate data - Serial.println("Settings Stored"); + // Serial.println("Settings Stored"); } @@ -64,7 +64,7 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will EEPROM_readAnything(i,minsegmenttime); EEPROM_readAnything(i,max_xy_jerk); EEPROM_readAnything(i,max_z_jerk); - Serial.println("Stored settings retreived:"); + // Serial.println("Stored settings retreived:"); } else { float tmp1[]=DEFAULT_AXIS_STEPS_PER_UNIT; @@ -82,8 +82,9 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will mintravelfeedrate=DEFAULT_MINTRAVELFEEDRATE max_xy_jerk=DEFAULT_XYJERK; max_z_jerk=DEFAULT_ZJERK; - Serial.println("Using Default settings:"); + // Serial.println("Using Default settings:"); } + /* Serial.println("Steps per unit:"); Serial.print(" M92"); Serial.print(" X");Serial.print(axis_steps_per_unit[0]); @@ -113,7 +114,7 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will Serial.print(" B");Serial.print(minsegmenttime); Serial.print(" X");Serial.print(max_xy_jerk/60); Serial.print(" Z");Serial.println(max_z_jerk/60); - + */ } From 3e3e8dd9880ee7872cc226386789873ac5a1405b Mon Sep 17 00:00:00 2001 From: lampmaker Date: Sat, 15 Oct 2011 18:46:44 +0300 Subject: [PATCH 099/130] removed more info sent to serial --- Marlin/EEPROM.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/EEPROM.h b/Marlin/EEPROM.h index dca1230b1049..2a66b38bdd49 100644 --- a/Marlin/EEPROM.h +++ b/Marlin/EEPROM.h @@ -52,7 +52,7 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will char stored_ver[4]; char ver[4]=EEPROM_VERSION; EEPROM_readAnything(i,stored_ver); //read stored version - Serial.print("Version: [");Serial.print(ver);Serial.print("] Stored version: [");Serial.print(stored_ver);Serial.println("]"); +// Serial.print("Version: [");Serial.print(ver);Serial.print("] Stored version: [");Serial.print(stored_ver);Serial.println("]"); if ((!def)&&(strncmp(ver,stored_ver,3)==0)) { // version number match EEPROM_readAnything(i,axis_steps_per_unit); EEPROM_readAnything(i,max_feedrate); From b3f5d1eccbb6f270af024adca6612e3707fa0dfb Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 15 Oct 2011 19:02:04 +0200 Subject: [PATCH 100/130] strange lcd problem with newpanel --- Marlin/Configuration.h | 4 +-- Marlin/EEPROM.h | 66 +++++++++++++++++++++--------------------- Marlin/pins.h | 7 +---- Marlin/ultralcd.h | 59 ++++++++++++++++++++++++++++++------- Marlin/ultralcd.pde | 58 ++++++++++++++++++++++++++++++------- 5 files changed, 133 insertions(+), 61 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 54c0e01b17c5..0ff086c4fc43 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -42,7 +42,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define LCD_WIDTH 16 #define LCD_HEIGHT 2 -//#define ULTIPANEL +#define ULTIPANEL #ifdef ULTIPANEL #define SDSUPPORT #define ULTRA_LCD @@ -51,7 +51,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #endif -//#define SDSUPPORT // Enable SD Card Support in Hardware Console +#define SDSUPPORT // Enable SD Card Support in Hardware Console diff --git a/Marlin/EEPROM.h b/Marlin/EEPROM.h index 02914ea1c7f5..54867ab0c261 100644 --- a/Marlin/EEPROM.h +++ b/Marlin/EEPROM.h @@ -52,7 +52,7 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will char stored_ver[4]; char ver[4]=EEPROM_VERSION; EEPROM_readAnything(i,stored_ver); //read stored version - Serial.print("Version: [");Serial.print(ver);Serial.print("] Stored version: [");Serial.print(stored_ver);Serial.println("]"); + //Serial.print("Version: [");Serial.print(ver);Serial.print("] Stored version: [");Serial.print(stored_ver);Serial.println("]"); if ((!def)&&(strncmp(ver,stored_ver,3)==0)) { // version number match EEPROM_readAnything(i,axis_steps_per_unit); EEPROM_readAnything(i,max_feedrate); @@ -64,7 +64,7 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will EEPROM_readAnything(i,minsegmenttime); EEPROM_readAnything(i,max_xy_jerk); EEPROM_readAnything(i,max_z_jerk); - Serial.println("Stored settings retreived:"); + //Serial.println("Stored settings retreived:"); } else { float tmp1[]=DEFAULT_AXIS_STEPS_PER_UNIT; @@ -82,38 +82,38 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will mintravelfeedrate=DEFAULT_MINTRAVELFEEDRATE max_xy_jerk=DEFAULT_XYJERK; max_z_jerk=DEFAULT_ZJERK; - Serial.println("Using Default settings:"); + //Serial.println("Using Default settings:"); } - Serial.println("Steps per unit:"); - Serial.print(" M92"); - Serial.print(" X");Serial.print(axis_steps_per_unit[0]); - Serial.print(" Y");Serial.print(axis_steps_per_unit[1]); - Serial.print(" Z");Serial.print(axis_steps_per_unit[2]); - Serial.print(" E");Serial.println(axis_steps_per_unit[3]); - Serial.println("Maximum feedrates (mm/s):"); - Serial.print (" M203"); - Serial.print(" X");Serial.print(max_feedrate[0]/60); - Serial.print(" Y");Serial.print(max_feedrate[1]/60); - Serial.print(" Z");Serial.print(max_feedrate[2]/60); - Serial.print(" E");Serial.println(max_feedrate[3]/60); - Serial.println("Maximum Acceleration (mm/s2):"); - Serial.print(" M201"); - Serial.print(" X");Serial.print(max_acceleration_units_per_sq_second[0]); - Serial.print(" Y");Serial.print(max_acceleration_units_per_sq_second[1]); - Serial.print(" Z");Serial.print(max_acceleration_units_per_sq_second[2]); - Serial.print(" E");Serial.println(max_acceleration_units_per_sq_second[3]); - Serial.println("Acceleration: S=acceleration, T=retract acceleration"); - Serial.print(" M204"); - Serial.print(" S");Serial.print(acceleration); - Serial.print(" T");Serial.println(retract_acceleration); - Serial.println("Advanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum xY jerk (mm/s), Z=maximum Z jerk (mm/s)"); - Serial.print(" M205"); - Serial.print(" S");Serial.print(minimumfeedrate/60); - Serial.print(" T");Serial.print(mintravelfeedrate/60); - Serial.print(" B");Serial.print(minsegmenttime); - Serial.print(" X");Serial.print(max_xy_jerk/60); - Serial.print(" Z");Serial.println(max_z_jerk/60); - + //Serial.println("Steps per unit:"); + //Serial.print(" M92"); + //Serial.print(" X");Serial.print(axis_steps_per_unit[0]); + //Serial.print(" Y");Serial.print(axis_steps_per_unit[1]); + //Serial.print(" Z");Serial.print(axis_steps_per_unit[2]); + //Serial.print(" E");Serial.println(axis_steps_per_unit[3]); + //Serial.println("Maximum feedrates (mm/s):"); + //Serial.print (" M203"); +// Serial.print(" X");Serial.print(max_feedrate[0]/60); +// Serial.print(" Y");Serial.print(max_feedrate[1]/60); +// Serial.print(" Z");Serial.print(max_feedrate[2]/60); +// Serial.print(" E");Serial.println(max_feedrate[3]/60); +// Serial.println("Maximum Acceleration (mm/s2):"); +// Serial.print(" M201"); +// Serial.print(" X");Serial.print(max_acceleration_units_per_sq_second[0]); +// Serial.print(" Y");Serial.print(max_acceleration_units_per_sq_second[1]); +// Serial.print(" Z");Serial.print(max_acceleration_units_per_sq_second[2]); +// Serial.print(" E");Serial.println(max_acceleration_units_per_sq_second[3]); +// Serial.println("Acceleration: S=acceleration, T=retract acceleration"); +// Serial.print(" M204"); +// Serial.print(" S");Serial.print(acceleration); +// Serial.print(" T");Serial.println(retract_acceleration); +// Serial.println("Advanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum xY jerk (mm/s), Z=maximum Z jerk (mm/s)"); +// Serial.print(" M205"); +// Serial.print(" S");Serial.print(minimumfeedrate/60); +// Serial.print(" T");Serial.print(mintravelfeedrate/60); +// Serial.print(" B");Serial.print(minsegmenttime); +// Serial.print(" X");Serial.print(max_xy_jerk/60); +// Serial.print(" Z");Serial.println(max_z_jerk/60); +// } diff --git a/Marlin/pins.h b/Marlin/pins.h index 2472b8938438..04026c14a20b 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -539,12 +539,7 @@ #define EXTRUDER_1_HEATER_PIN 3 #define EXTRUDER_1_TEMPERATURE_PIN 10 -#define LCD_PINS_RS 16 -#define LCD_PINS_ENABLE 5 -#define LCD_PINS_D4 6 -#define LCD_PINS_D5 21 -#define LCD_PINS_D6 20 -#define LCD_PINS_D7 19 + #define E_STEP_PIN EXTRUDER_0_STEP_PIN #define E_DIR_PIN EXTRUDER_0_DIR_PIN diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h index 106586a86fcb..193d2badcdde 100644 --- a/Marlin/ultralcd.h +++ b/Marlin/ultralcd.h @@ -1,5 +1,6 @@ #ifndef __ULTRALCDH #define __ULTRALCDH +//#define NEWPANEL #ifdef ULTRA_LCD @@ -20,7 +21,40 @@ //lcd display size +#ifdef NEWPANEL + //arduino pin witch triggers an piezzo beeper + #define BEEPER 18 + #define LCD_PINS_RS 20 +#define LCD_PINS_ENABLE 17 +#define LCD_PINS_D4 16 +#define LCD_PINS_D5 21 +#define LCD_PINS_D6 5 +#define LCD_PINS_D7 6 + + //buttons are directly attached + #define BTN_EN1 40 + #define BTN_EN2 42 + #define BTN_ENC 19 //the click + + #define BLEN_C 2 + #define BLEN_B 1 + #define BLEN_A 0 + + #define EN_C (1< Date: Sat, 15 Oct 2011 20:02:46 +0200 Subject: [PATCH 101/130] sane config --- Marlin/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 0ff086c4fc43..10ed197c9831 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -42,7 +42,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define LCD_WIDTH 16 #define LCD_HEIGHT 2 -#define ULTIPANEL +//#define ULTIPANEL #ifdef ULTIPANEL #define SDSUPPORT #define ULTRA_LCD From c96c076c1892ba80565ff2f7b821f8d3a9a5ea0b Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 15 Oct 2011 20:05:52 +0200 Subject: [PATCH 102/130] better default values --- Marlin/Configuration.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 10ed197c9831..2d9d856d80e9 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -111,8 +111,8 @@ bool axis_relative_modes[] = {false, false, false, false}; #define DEFAULT_ACCELERATION 4600; // X, Y, Z and E max acceleration in mm/s^2 for printing moves #define DEFAULT_RETRACT_ACCELERATION 7000; // X, Y, Z and E max acceleration in mm/s^2 for r retracts -#define DEFAULT_MINIMUMFEEDRATE 00*60; // minimum feedrate -#define DEFAULT_MINTRAVELFEEDRATE 00*60; +#define DEFAULT_MINIMUMFEEDRATE 10*60; // minimum feedrate +#define DEFAULT_MINTRAVELFEEDRATE 140*60; #define DEFAULT_MINSEGMENTTIME 20000; // minimum segmenttime to prevent buffer underruns #define DEFAULT_XYJERK 30.0*60; #define DEFAULT_ZJERK 10.0*60; From 0c7a39f12742a05232be367c2d234b30eadb388d Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sun, 16 Oct 2011 16:22:34 +0300 Subject: [PATCH 103/130] Some minor mistakes found by action68 --- Marlin/Configuration.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 2d9d856d80e9..044fbefd7ebc 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -55,7 +55,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the -const int dropsegments=2; //everything with this number of steps will be ignored as move +const int dropsegments=5; //everything with this number of steps will be ignored as move //// ADVANCED SETTINGS - to tweak parameters @@ -104,18 +104,20 @@ bool axis_relative_modes[] = {false, false, false, false}; // default settings -#define DEFAULT_AXIS_STEPS_PER_UNIT {79.87220447,79.87220447,200*8/3,14}; // default steps per unit for ultimaker +#define DEFAULT_AXIS_STEPS_PER_UNIT {79.87220447,79.87220447,200*8/3,14} // default steps per unit for ultimaker #define DEFAULT_MAX_FEEDRATE {160*60, 160*60, 10*60, 500000} #define DEFAULT_MAX_ACCELERATION {9000,9000,150,10000} // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. -#define DEFAULT_ACCELERATION 4600; // X, Y, Z and E max acceleration in mm/s^2 for printing moves -#define DEFAULT_RETRACT_ACCELERATION 7000; // X, Y, Z and E max acceleration in mm/s^2 for r retracts +#define DEFAULT_ACCELERATION 4600 // X, Y, Z and E max acceleration in mm/s^2 for printing moves +#define DEFAULT_RETRACT_ACCELERATION 7000 // X, Y, Z and E max acceleration in mm/s^2 for r retracts -#define DEFAULT_MINIMUMFEEDRATE 10*60; // minimum feedrate -#define DEFAULT_MINTRAVELFEEDRATE 140*60; -#define DEFAULT_MINSEGMENTTIME 20000; // minimum segmenttime to prevent buffer underruns -#define DEFAULT_XYJERK 30.0*60; -#define DEFAULT_ZJERK 10.0*60; +#define DEFAULT_MINIMUMFEEDRATE 10*60 // minimum feedrate +#define DEFAULT_MINTRAVELFEEDRATE 140*60 + +// minimum time in microseconds that a movement needs to take if the buffer is emptied. Increase this number if you see blobs while printing high speed & high detail. It will slowdown on the detailed stuff. +#define DEFAULT_MINSEGMENTTIME 20000 +#define DEFAULT_XYJERK 30.0*60 +#define DEFAULT_ZJERK 10.0*60 // The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature @@ -132,9 +134,7 @@ bool axis_relative_modes[] = {false, false, false, false}; #define MAXTEMP 275 -// minimum time in microseconds that a movement needs to take to prevent the buffer from being emptied. Higher baudrates might reduce this number. -// minimum time in microseconds that a movement needs to take if the buffer is emptied. Increase this number if you see blobs while printing high speed & high detail. It will slowdown on the detailed stuff. -#define MIN_SEGMENT_TIME 60000 + /// PID settings: From 9f57cdd6b4983b7357450b8f8da954ee57f73d4a Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sun, 16 Oct 2011 17:14:49 +0300 Subject: [PATCH 104/130] ; fixed --- Marlin/EEPROM.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/EEPROM.h b/Marlin/EEPROM.h index bd75d3bb97ad..7e1dc33c825d 100644 --- a/Marlin/EEPROM.h +++ b/Marlin/EEPROM.h @@ -77,9 +77,9 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will } acceleration=DEFAULT_ACCELERATION; retract_acceleration=DEFAULT_RETRACT_ACCELERATION; - minimumfeedrate=DEFAULT_MINIMUMFEEDRATE + minimumfeedrate=DEFAULT_MINIMUMFEEDRATE; minsegmenttime=DEFAULT_MINSEGMENTTIME; - mintravelfeedrate=DEFAULT_MINTRAVELFEEDRATE + mintravelfeedrate=DEFAULT_MINTRAVELFEEDRATE; max_xy_jerk=DEFAULT_XYJERK; max_z_jerk=DEFAULT_ZJERK; // Serial.println("Using Default settings:"); From d72e485be2a352e99f3493c33e22b3b9f458408a Mon Sep 17 00:00:00 2001 From: lampmaker Date: Tue, 18 Oct 2011 10:03:47 +0200 Subject: [PATCH 105/130] Included Streaming lib; added ECHO ECHO outputs serial data with "echo:" attached in front of it. This allows you to send data to replicatorg witout causing error messages. Debugging level needs to be set to "INFO" in repg. Using the streaming lib, messages can be sent like this: ECHO ("Maximum feedrate "<<_FLOAT(max_feedrate,2)) will output "echo: Maximum feedrate 300.00" ECHOLN(x) is the same as ECHO, but adds a linebreak after. --- Marlin/Configuration.h | 2 + Marlin/EEPROM.h | 59 ++++++++++------------------- Marlin/Marlin.pde | 10 ++--- Marlin/streaming.h | 84 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 46 deletions(-) create mode 100644 Marlin/streaming.h diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 8d59513cc391..d95006b21b90 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -1,3 +1,5 @@ + + #ifndef CONFIGURATION_H #define CONFIGURATION_H diff --git a/Marlin/EEPROM.h b/Marlin/EEPROM.h index 9ce5bf2e9f68..e36179939b08 100644 --- a/Marlin/EEPROM.h +++ b/Marlin/EEPROM.h @@ -1,3 +1,6 @@ +#define ECHO(x) Serial << "echo: " << x; +#define ECHOLN(x) Serial << "echo: "< int EEPROM_writeAnything(int &ee, const T& value) { @@ -18,7 +21,6 @@ template int EEPROM_readAnything(int &ee, T& value) } //====================================================================================== - #define EEPROM_OFFSET 100 #define EEPROM_VERSION "V04" // IMPORTANT: Whenever there are changes made to the variables stored in EEPROM @@ -46,7 +48,7 @@ void StoreSettings() { char ver2[4]=EEPROM_VERSION; i=EEPROM_OFFSET; EEPROM_writeAnything(i,ver2); // validate data - Serial.println("Settings Stored"); + ECHOLN("Settings Stored"); } @@ -55,7 +57,7 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will char stored_ver[4]; char ver[4]=EEPROM_VERSION; EEPROM_readAnything(i,stored_ver); //read stored version - Serial.print("Version: [");Serial.print(ver);Serial.print("] Stored version: [");Serial.print(stored_ver);Serial.println("]"); +// ECHOLN("Version: [" << ver << "] Stored version: [" << stored_ver << "]"); if ((!def)&&(strncmp(ver,stored_ver,3)==0)) { // version number match EEPROM_readAnything(i,axis_steps_per_unit); EEPROM_readAnything(i,max_feedrate); @@ -70,7 +72,7 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will EEPROM_readAnything(i,Kp); EEPROM_readAnything(i,Ki); EEPROM_readAnything(i,Kd); - Serial.println("Stored settings retreived:"); + ECHOLN("Stored settings retreived:"); } else { float tmp1[]=DEFAULT_AXIS_STEPS_PER_UNIT; @@ -88,43 +90,20 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will mintravelfeedrate=DEFAULT_MINTRAVELFEEDRATE max_xy_jerk=DEFAULT_XYJERK; max_z_jerk=DEFAULT_ZJERK; - Serial.println("Using Default settings:"); + ECHOLN("Using Default settings:"); } - Serial.println("Steps per unit:"); - Serial.print(" M92"); - Serial.print(" X");Serial.print(axis_steps_per_unit[0]); - Serial.print(" Y");Serial.print(axis_steps_per_unit[1]); - Serial.print(" Z");Serial.print(axis_steps_per_unit[2]); - Serial.print(" E");Serial.println(axis_steps_per_unit[3]); - Serial.println("Maximum feedrates (mm/s):"); - Serial.print (" M203"); - Serial.print(" X");Serial.print(max_feedrate[0]/60); - Serial.print(" Y");Serial.print(max_feedrate[1]/60); - Serial.print(" Z");Serial.print(max_feedrate[2]/60); - Serial.print(" E");Serial.println(max_feedrate[3]/60); - Serial.println("Maximum Acceleration (mm/s2):"); - Serial.print(" M201"); - Serial.print(" X");Serial.print(max_acceleration_units_per_sq_second[0]); - Serial.print(" Y");Serial.print(max_acceleration_units_per_sq_second[1]); - Serial.print(" Z");Serial.print(max_acceleration_units_per_sq_second[2]); - Serial.print(" E");Serial.println(max_acceleration_units_per_sq_second[3]); - Serial.println("Acceleration: S=acceleration, T=retract acceleration"); - Serial.print(" M204"); - Serial.print(" S");Serial.print(acceleration); - Serial.print(" T");Serial.println(retract_acceleration); - Serial.println("Advanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum xY jerk (mm/s), Z=maximum Z jerk (mm/s)"); - Serial.print(" M205"); - Serial.print(" S");Serial.print(minimumfeedrate/60); - Serial.print(" T");Serial.print(mintravelfeedrate/60); - Serial.print(" B");Serial.print(minsegmenttime); - Serial.print(" X");Serial.print(max_xy_jerk/60); - Serial.print(" Z");Serial.println(max_z_jerk/60); - Serial.println("PID settings:"); - Serial.print(" M301"); - Serial.print(" P");Serial.print(Kp); - Serial.print(" I");Serial.print(Ki); - Serial.print(" D");Serial.println(Kd); - + ECHOLN("Steps per unit:"); + ECHOLN(" M92 X" <<_FLOAT(axis_steps_per_unit[0],3) << " Y" << _FLOAT(axis_steps_per_unit[1],3) << " Z" << _FLOAT(axis_steps_per_unit[2],3) << " E" << _FLOAT(axis_steps_per_unit[3],3)); + ECHOLN("Maximum feedrates (mm/s):"); + ECHOLN(" M203 X" <<_FLOAT(max_feedrate[0]/60,2)<<" Y" << _FLOAT(max_feedrate[1]/60,2) << " Z" << _FLOAT(max_feedrate[2]/60,2) << " E" << _FLOAT(max_feedrate[3]/60,2)); + ECHOLN("Maximum Acceleration (mm/s2):"); + ECHOLN(" M201 X" <<_FLOAT(max_acceleration_units_per_sq_second[0],0) << " Y" << _FLOAT(max_acceleration_units_per_sq_second[1],0) << " Z" << _FLOAT(max_acceleration_units_per_sq_second[2],0) << " E" << _FLOAT(max_acceleration_units_per_sq_second[3],0)); + ECHOLN("Acceleration: S=acceleration, T=retract acceleration"); + ECHOLN(" M204 S" <<_FLOAT(acceleration,2) << " T" << _FLOAT(retract_acceleration,2)); + ECHOLN("Advanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum xY jerk (mm/s), Z=maximum Z jerk (mm/s)"); + ECHOLN(" M205 S" <<_FLOAT(minimumfeedrate/60,2) << " T" << _FLOAT(mintravelfeedrate/60,2) << " B" << _FLOAT(minsegmenttime,2) << " X" << _FLOAT(max_xy_jerk/60,2) << " Z" << _FLOAT(max_z_jerk/60,2)); + ECHOLN("PID settings:"); + ECHOLN(" M301 P" << _FLOAT(Kp,3) << " I" <<_ FLOAT(Ki,3) << " D" << _FLOAT(Kd,3)); } diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 925f030e0e4f..0652e1195156 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -36,7 +36,6 @@ This firmware is optimized for gen6 electronics. */ - #include #include "fastio.h" #include "Configuration.h" @@ -44,7 +43,7 @@ #include "Marlin.h" #include "speed_lookuptable.h" #include "lcd.h" - +#include "streaming.h" char version_string[] = "U0.9.3.3-BK"; @@ -296,8 +295,7 @@ void setup() { Serial.begin(BAUDRATE); - Serial.print("Marlin "); - Serial.println(version_string); + ECHOLN("Marlin "< + +#define STREAMING_LIBRARY_VERSION 4 + +// Generic template +template +inline Print &operator <<(Print &stream, T arg) +{ stream.print(arg); return stream; } + +struct _BASED +{ + long val; + int base; + _BASED(long v, int b): val(v), base(b) + {} +}; + +#define _HEX(a) _BASED(a, HEX) +#define _DEC(a) _BASED(a, DEC) +#define _OCT(a) _BASED(a, OCT) +#define _BIN(a) _BASED(a, BIN) +#define _BYTE(a) _BASED(a, BYTE) + +// Specialization for class _BASED +// Thanks to Arduino forum user Ben Combee who suggested this +// clever technique to allow for expressions like +// Serial << _HEX(a); + +inline Print &operator <<(Print &obj, const _BASED &arg) +{ obj.print(arg.val, arg.base); return obj; } + +#if ARDUINO >= 18 +// Specialization for class _FLOAT +// Thanks to Michael Margolis for suggesting a way +// to accommodate Arduino 0018's floating point precision +// feature like this: +// Serial << _FLOAT(gps_latitude, 6); // 6 digits of precision + +struct _FLOAT +{ + float val; + int digits; + _FLOAT(double v, int d): val(v), digits(d) + {} +}; + +inline Print &operator <<(Print &obj, const _FLOAT &arg) +{ obj.print(arg.val, arg.digits); return obj; } +#endif + +// Specialization for enum _EndLineCode +// Thanks to Arduino forum user Paul V. who suggested this +// clever technique to allow for expressions like +// Serial << "Hello!" << endl; + +enum _EndLineCode { endl }; + +inline Print &operator <<(Print &obj, _EndLineCode arg) +{ obj.println(); return obj; } + +#endif + From 300549de7ba466b6d1d97086be1d8b13bc324e48 Mon Sep 17 00:00:00 2001 From: lampmaker Date: Tue, 18 Oct 2011 10:19:01 +0200 Subject: [PATCH 106/130] fixed typo --- Marlin/EEPROM.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Marlin/EEPROM.h b/Marlin/EEPROM.h index e36179939b08..bc68458bc066 100644 --- a/Marlin/EEPROM.h +++ b/Marlin/EEPROM.h @@ -1,5 +1,3 @@ -#define ECHO(x) Serial << "echo: " << x; -#define ECHOLN(x) Serial << "echo: "< int EEPROM_writeAnything(int &ee, const T& value) @@ -103,7 +101,7 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will ECHOLN("Advanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum xY jerk (mm/s), Z=maximum Z jerk (mm/s)"); ECHOLN(" M205 S" <<_FLOAT(minimumfeedrate/60,2) << " T" << _FLOAT(mintravelfeedrate/60,2) << " B" << _FLOAT(minsegmenttime,2) << " X" << _FLOAT(max_xy_jerk/60,2) << " Z" << _FLOAT(max_z_jerk/60,2)); ECHOLN("PID settings:"); - ECHOLN(" M301 P" << _FLOAT(Kp,3) << " I" <<_ FLOAT(Ki,3) << " D" << _FLOAT(Kd,3)); + ECHOLN(" M301 P" << _FLOAT(Kp,3) << " I" << _FLOAT(Ki,3) << " D" << _FLOAT(Kd,3)); } From f3358265cfb68358913ea49629dbd7963c60a5ef Mon Sep 17 00:00:00 2001 From: lampmaker Date: Tue, 18 Oct 2011 10:19:01 +0200 Subject: [PATCH 107/130] Echo PID settings --- Marlin/EEPROM.h | 4 +- Marlin/Marlin.h | 250 +++++++++++++++++++++++----------------------- Marlin/Marlin.pde | 7 +- 3 files changed, 132 insertions(+), 129 deletions(-) diff --git a/Marlin/EEPROM.h b/Marlin/EEPROM.h index e36179939b08..bc68458bc066 100644 --- a/Marlin/EEPROM.h +++ b/Marlin/EEPROM.h @@ -1,5 +1,3 @@ -#define ECHO(x) Serial << "echo: " << x; -#define ECHOLN(x) Serial << "echo: "< int EEPROM_writeAnything(int &ee, const T& value) @@ -103,7 +101,7 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will ECHOLN("Advanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum xY jerk (mm/s), Z=maximum Z jerk (mm/s)"); ECHOLN(" M205 S" <<_FLOAT(minimumfeedrate/60,2) << " T" << _FLOAT(mintravelfeedrate/60,2) << " B" << _FLOAT(minsegmenttime,2) << " X" << _FLOAT(max_xy_jerk/60,2) << " Z" << _FLOAT(max_z_jerk/60,2)); ECHOLN("PID settings:"); - ECHOLN(" M301 P" << _FLOAT(Kp,3) << " I" <<_ FLOAT(Ki,3) << " D" << _FLOAT(Kd,3)); + ECHOLN(" M301 P" << _FLOAT(Kp,3) << " I" << _FLOAT(Ki,3) << " D" << _FLOAT(Kd,3)); } diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 10f1377bbff1..05de3e66dd56 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -1,124 +1,128 @@ -#ifndef __MARLINH -#define __MARLINH - -// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. -// Licence: GPL -#include -#include "fastio.h" - - -// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in -// the source g-code and may never actually be reached if acceleration management is active. -typedef struct { - // Fields used by the bresenham algorithm for tracing the line - long steps_x, steps_y, steps_z, steps_e; // Step count along each axis - long step_event_count; // The number of step events required to complete this block - volatile long accelerate_until; // The index of the step event on which to stop acceleration - volatile long decelerate_after; // The index of the step event on which to start decelerating - volatile long acceleration_rate; // The acceleration rate used for acceleration calculation - unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h) - - long advance_rate; - volatile long initial_advance; - volatile long final_advance; - float advance; - - // Fields used by the motion planner to manage acceleration - float speed_x, speed_y, speed_z, speed_e; // Nominal mm/minute for each axis - float nominal_speed; // The nominal speed for this block in mm/min - float millimeters; // The total travel of this block in mm - float entry_speed; - float acceleration; // acceleration mm/sec^2 - - // Settings for the trapezoid generator - long nominal_rate; // The nominal step rate for this block in step_events/sec - volatile long initial_rate; // The jerk-adjusted step rate at start of block - volatile long final_rate; // The minimal rate at exit - long acceleration_st; // acceleration steps/sec^2 - volatile char busy; -} block_t; - - -void get_command(); -void process_commands(); - -void manage_inactivity(byte debug); - -void manage_heater(); -//int temp2analogu(int celsius, const short table[][2], int numtemps); -//float analog2tempu(int raw, const short table[][2], int numtemps); -float temp2analog(int celsius); -float temp2analogBed(int celsius); -float analog2temp(int raw); -float analog2tempBed(int raw); - -#ifdef HEATER_USES_THERMISTOR - #define HEATERSOURCE 1 -#endif -#ifdef BED_USES_THERMISTOR - #define BEDSOURCE 1 -#endif - -//#define temp2analogh( c ) temp2analogu((c),temptable,NUMTEMPS) -//#define analog2temp( c ) analog2tempu((c),temptable,NUMTEMPS) - -#if X_ENABLE_PIN > -1 -#define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) -#define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) -#else -#define enable_x() ; -#define disable_x() ; -#endif -#if Y_ENABLE_PIN > -1 -#define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) -#define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) -#else -#define enable_y() ; -#define disable_y() ; -#endif -#if Z_ENABLE_PIN > -1 -#define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) -#define disable_z() WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON) -#else -#define enable_z() ; -#define disable_z() ; -#endif - -#if E_ENABLE_PIN > -1 - - #define enable_e() WRITE(E_ENABLE_PIN, E_ENABLE_ON) - #define disable_e() WRITE(E_ENABLE_PIN,!E_ENABLE_ON) - -#else -#define enable_e() ; -#define disable_e() ; -#endif - -#define X_AXIS 0 -#define Y_AXIS 1 -#define Z_AXIS 2 -#define E_AXIS 3 - -void FlushSerialRequestResend(); -void ClearToSend(); - -void get_coordinates(); -void prepare_move(); -void linear_move(unsigned long steps_remaining[]); -void do_step(int axis); -void kill(byte debug); - - - -void check_axes_activity(); -void plan_init(); -void st_init(); -void tp_init(); -void plan_buffer_line(float x, float y, float z, float e, float feed_rate); -void plan_set_position(float x, float y, float z, float e); -void st_wake_up(); -void st_synchronize(); -void enquecommand(const char *cmd); - - +#ifndef __MARLINH +#define __MARLINH + +// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. +// Licence: GPL +#include +#include "fastio.h" + + +#define ECHO(x) Serial << "echo: " << x; +#define ECHOLN(x) Serial << "echo: "< -1 +#define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) +#define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) +#else +#define enable_x() ; +#define disable_x() ; +#endif +#if Y_ENABLE_PIN > -1 +#define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) +#define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) +#else +#define enable_y() ; +#define disable_y() ; +#endif +#if Z_ENABLE_PIN > -1 +#define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) +#define disable_z() WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON) +#else +#define enable_z() ; +#define disable_z() ; +#endif + +#if E_ENABLE_PIN > -1 + + #define enable_e() WRITE(E_ENABLE_PIN, E_ENABLE_ON) + #define disable_e() WRITE(E_ENABLE_PIN,!E_ENABLE_ON) + +#else +#define enable_e() ; +#define disable_e() ; +#endif + +#define X_AXIS 0 +#define Y_AXIS 1 +#define Z_AXIS 2 +#define E_AXIS 3 + +void FlushSerialRequestResend(); +void ClearToSend(); + +void get_coordinates(); +void prepare_move(); +void linear_move(unsigned long steps_remaining[]); +void do_step(int axis); +void kill(byte debug); + + + +void check_axes_activity(); +void plan_init(); +void st_init(); +void tp_init(); +void plan_buffer_line(float x, float y, float z, float e, float feed_rate); +void plan_set_position(float x, float y, float z, float e); +void st_wake_up(); +void st_synchronize(); +void enquecommand(const char *cmd); + + #endif diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 0652e1195156..6d854a303703 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1151,9 +1151,10 @@ inline void process_commands() if(code_seen('P')) Kp = code_value(); if(code_seen('I')) Ki = code_value()*PID_dT; if(code_seen('D')) Kd = code_value()/PID_dT; - Serial.print("Kp ");Serial.println(Kp); - Serial.print("Ki ");Serial.println(Ki/PID_dT); - Serial.print("Kd ");Serial.println(Kd*PID_dT); + ECHOLN("Kp "<<_FLOAT(Kp,2)); + ECHOLN("Ki "<<_FLOAT(Ki/PID_dT,2)); + ECHOLN("Kd "<<_FLOAT(Kd*PID_dT,2)); + temp_iState_min = 0.0; if (Ki!=0) { temp_iState_max = PID_INTEGRAL_DRIVE_MAX / (Ki/100.0); From e4ff5e5d8fd9a66690021ada68aa4b9875442d71 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Fri, 21 Oct 2011 22:36:04 +0200 Subject: [PATCH 108/130] found the bug in the new panels. Pullup on output pins instead of input pins on switch/encoder stuff. --- Marlin/ultralcd.h | 28 ++++++++-------- Marlin/ultralcd.pde | 79 ++++++++++++++++++++++----------------------- 2 files changed, 53 insertions(+), 54 deletions(-) diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h index 193d2badcdde..4edf8e670782 100644 --- a/Marlin/ultralcd.h +++ b/Marlin/ultralcd.h @@ -1,7 +1,6 @@ #ifndef __ULTRALCDH #define __ULTRALCDH -//#define NEWPANEL - +#include "Configuration.h" #ifdef ULTRA_LCD @@ -26,11 +25,11 @@ #define BEEPER 18 #define LCD_PINS_RS 20 -#define LCD_PINS_ENABLE 17 -#define LCD_PINS_D4 16 -#define LCD_PINS_D5 21 -#define LCD_PINS_D6 5 -#define LCD_PINS_D7 6 + #define LCD_PINS_ENABLE 17 + #define LCD_PINS_D4 16 + #define LCD_PINS_D5 21 + #define LCD_PINS_D6 5 + #define LCD_PINS_D7 6 //buttons are directly attached #define BTN_EN1 40 @@ -50,8 +49,9 @@ #define encrot1 2 #define encrot2 3 #define encrot3 1 - #define CLICKED (buttons&EN_C) - #define BLOCK {blocking=millis()+blocktime;} + + #define CLICKED (buttons&EN_C) + #define BLOCK {blocking=millis()+blocktime;} #else @@ -65,11 +65,11 @@ #define SHIFT_EN 17 #define LCD_PINS_RS 16 -#define LCD_PINS_ENABLE 5 -#define LCD_PINS_D4 6 -#define LCD_PINS_D5 21 -#define LCD_PINS_D6 20 -#define LCD_PINS_D7 19 + #define LCD_PINS_ENABLE 5 + #define LCD_PINS_D4 6 + #define LCD_PINS_D5 21 + #define LCD_PINS_D6 20 + #define LCD_PINS_D7 19 //bits in the shift register that carry the buttons for: // left up center down right red diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index f5826052f59f..a8bd12ee86f5 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -16,11 +16,9 @@ volatile char buttons=0; //the last checked buttons in a bit array. int encoderpos=0; short lastenc=0; #ifdef NEWPANEL - -long blocking=0; + long blocking=0; #else -long blocking[8]={ - 0,0,0,0,0,0,0,0}; + long blocking[8]={0,0,0,0,0,0,0,0}; #endif MainMenu menu; @@ -33,7 +31,9 @@ void clear() { //lcd.setCursor(0,0); lcd.clear(); - delay(1); + //delay(1); + // lcd.begin(LCD_WIDTH,LCD_HEIGHT); + //lcd_init(); } long previous_millis_buttons=0; @@ -77,27 +77,26 @@ void beep() { return; #ifdef ULTIPANEL - // [ErikDeBruijn] changed to two short beeps, more friendly pinMode(BEEPER,OUTPUT); for(int i=0;i<20;i++){ - digitalWrite(BEEPER,HIGH); - delay(5); - digitalWrite(BEEPER,LOW); - delay(5); + digitalWrite(BEEPER,HIGH); + delay(5); + digitalWrite(BEEPER,LOW); + delay(5); } #endif } + void beepshort() { - return; + return; #ifdef ULTIPANEL - // [ErikDeBruijn] changed to two short beeps, more friendly pinMode(BEEPER,OUTPUT); for(int i=0;i<10;i++){ - digitalWrite(BEEPER,HIGH); - delay(3); - digitalWrite(BEEPER,LOW); - delay(3); + digitalWrite(BEEPER,HIGH); + delay(3); + digitalWrite(BEEPER,LOW); + delay(3); } #endif } @@ -125,26 +124,31 @@ void lcd_status() void buttons_init() { #ifdef NEWPANEL - pinMode(BTN_EN1,OUTPUT); - pinMode(BTN_EN2,OUTPUT); - pinMode(BTN_ENC,OUTPUT); + pinMode(BTN_EN1,INPUT); + pinMode(BTN_EN2,INPUT); + pinMode(BTN_ENC,INPUT); digitalWrite(BTN_EN1,HIGH); digitalWrite(BTN_EN2,HIGH); digitalWrite(BTN_ENC,HIGH); #else - pinMode(SHIFT_CLK,OUTPUT); + pinMode(SHIFT_CLK,OUTPUT); pinMode(SHIFT_LD,OUTPUT); pinMode(SHIFT_EN,OUTPUT); pinMode(SHIFT_OUT,INPUT); digitalWrite(SHIFT_OUT,HIGH); - digitalWrite(SHIFT_LD,HIGH); //load has inverse logic - digitalWrite(SHIFT_EN,LOW); //low active + digitalWrite(SHIFT_LD,HIGH); + digitalWrite(SHIFT_EN,LOW); #endif } void buttons_check() { + volatile static bool busy=false; + if(busy) + return; + busy=true; + #ifdef NEWPANEL uint8_t newbutton=0; if(digitalRead(BTN_EN1)==0) newbutton|=EN_A; @@ -152,13 +156,8 @@ void buttons_check() if((blocking=LCD_HEIGHT) activeline=LCD_HEIGHT-1; if((encoderpos!=lastencoderpos)||force_lcd_update) { lcd.setCursor(0,activeline);lcd.print(activeline?' ':' '); if(encoderpos<0) encoderpos=0; if(encoderpos>3*lcdslow) encoderpos=3*lcdslow; activeline=abs(encoderpos/lcdslow)%LCD_HEIGHT; - + if(activeline<0) activeline=0; + if(activeline>=LCD_HEIGHT) activeline=LCD_HEIGHT-1; lastencoderpos=encoderpos; lcd.setCursor(0,activeline);lcd.print(activeline?'>':'\003'); } @@ -1163,8 +1163,7 @@ void MainMenu::update() if(status!=oldstatus) { //Serial.println(status); - clear(); - delay(1); + //clear(); force_lcd_update=true; encoderpos=0; lineoffset=0; From 67c63c1657970a587fb8e024255fdd969cefc61b Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Fri, 21 Oct 2011 23:22:14 +0200 Subject: [PATCH 109/130] SD card autodetect added. --- Marlin/Configuration.h | 1 + Marlin/ultralcd.h | 7 ++-- Marlin/ultralcd.pde | 80 ++++++++++++++++++++++++++++++++++-------- 3 files changed, 72 insertions(+), 16 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 044fbefd7ebc..64efffd7bf37 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -44,6 +44,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the //#define ULTIPANEL #ifdef ULTIPANEL + #define NEWPANEL //enable this if you have a click-encoder panel #define SDSUPPORT #define ULTRA_LCD #define LCD_WIDTH 20 diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h index 4edf8e670782..b9775cef9f28 100644 --- a/Marlin/ultralcd.h +++ b/Marlin/ultralcd.h @@ -11,7 +11,7 @@ #define LCDSTATUSRIGHT #define LCD_UPDATE_INTERVAL 100 - #define STATUSTIMEOUT 5000 + #define STATUSTIMEOUT 15000 #include "Configuration.h" @@ -40,6 +40,8 @@ #define BLEN_B 1 #define BLEN_A 0 + #define SDCARDDETECT 38 + #define EN_C (1<(1+nrfiles+1-LCD_HEIGHT)) lineoffset=1+nrfiles+1-LCD_HEIGHT; force_lcd_update=true; } - //encoderpos=encoderpos%LCD_HEIGHT; lastencoderpos=encoderpos; activeline=encoderpos; - if(activeline>3) activeline=3; - if(activeline<0) activeline=0; + if(activeline>3) + { + activeline=3; + } + if(activeline<0) + { + activeline=0; + } if(activeline>1+nrfiles) activeline=1+nrfiles; if(lineoffset>1+nrfiles) lineoffset=1+nrfiles; lcd.setCursor(0,activeline);lcd.print((activeline+lineoffset)?'>':'\003'); @@ -1116,16 +1136,28 @@ void MainMenu::showMainMenu() if(force_lcd_update) { lcd.setCursor(0,line); - if(sdmode) - lcd.print(" Stop \x7E"); +#ifdef CARDINSERTED + if(CARDINSERTED) +#else + if(true) +#endif + { + if(sdmode) + lcd.print(" Stop Print \x7E"); + else + lcd.print(" Card Menu \x7E"); + } else - lcd.print(" Card \x7E"); - + { + lcd.print(" No Card"); + } } + #ifdef CARDINSERTED + if(CARDINSERTED) + #endif if((activeline==line)&&CLICKED) { sdmode = false; - BLOCK; status=Main_SD; beepshort(); @@ -1159,7 +1191,27 @@ void MainMenu::update() { static MainStatus oldstatus=Main_Menu; //init automatically causes foce_lcd_update=true static long timeoutToStatus=0; - + static bool oldcardstatus=false; +#ifdef CARDINSERTED + if((CARDINSERTED != oldcardstatus)) + { + force_lcd_update=true; + oldcardstatus=CARDINSERTED; + //Serial.println("SD CHANGE"); + if(CARDINSERTED) + { + initsd(); + lcd_status("Card inserted"); + } + else + { + sdactive=false; + lcd_status("Card removed"); + + } + } +#endif + if(status!=oldstatus) { //Serial.println(status); From cf397cacf8c431736fa7cc5e2c5bd689cb318027 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 22 Oct 2011 00:17:43 +0200 Subject: [PATCH 110/130] enable beep again --- Marlin/ultralcd.pde | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 5332a7d41685..094789290b37 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -75,7 +75,7 @@ void lcd_init() void beep() { - return; + //return; #ifdef ULTIPANEL pinMode(BEEPER,OUTPUT); for(int i=0;i<20;i++){ @@ -89,7 +89,7 @@ void beep() void beepshort() { - return; + //return; #ifdef ULTIPANEL pinMode(BEEPER,OUTPUT); for(int i=0;i<10;i++){ @@ -105,6 +105,7 @@ void lcd_status() #ifdef ULTIPANEL static uint8_t oldbuttons=0; static long previous_millis_buttons=0; + static long previous_lcdinit=0; buttons_check(); //previous_millis_buttons=millis(); @@ -116,7 +117,7 @@ void lcd_status() if(((millis() - previous_millis_lcd) < LCD_UPDATE_INTERVAL) ) return; #endif - + previous_millis_lcd=millis(); menu.update(); } From 73d5bd5bbcab33252f3078af6b812ad408633db3 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 22 Oct 2011 01:04:07 +0200 Subject: [PATCH 111/130] minimize offset temperature in pid --- Marlin/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 778a560394a9..a8495b70ba24 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -153,7 +153,7 @@ float current_raw_average=0; #define PID_MAX 255 // limits current to nozzle #define PID_INTEGRAL_DRIVE_MAX 255 #define PID_dT 0.16 -double Kp = 1000; //20.0; +double Kp = 3000; //20.0; double Ki = 0; //1.5*PID_dT; double Kd = 0; //80/PID_dT; #endif // PIDTEMP From ad4ae7c7f8e5c44e36e34de83387e76cbbe658fb Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 22 Oct 2011 01:12:54 +0200 Subject: [PATCH 112/130] make pid possible to be disabled --- Marlin/EEPROM.h | 12 ++++++++++++ Marlin/Marlin.pde | 4 +++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Marlin/EEPROM.h b/Marlin/EEPROM.h index 00f69a2f9ae3..4dd56b88ac3f 100644 --- a/Marlin/EEPROM.h +++ b/Marlin/EEPROM.h @@ -40,9 +40,15 @@ void StoreSettings() { EEPROM_writeAnything(i,minsegmenttime); EEPROM_writeAnything(i,max_xy_jerk); EEPROM_writeAnything(i,max_z_jerk); + #ifdef PIDTEMP EEPROM_writeAnything(i,Kp); EEPROM_writeAnything(i,Ki); EEPROM_writeAnything(i,Kd); +#else + EEPROM_writeAnything(i,3000); + EEPROM_writeAnything(i,0); + EEPROM_writeAnything(i,0); +#endif char ver2[4]=EEPROM_VERSION; i=EEPROM_OFFSET; EEPROM_writeAnything(i,ver2); // validate data @@ -67,9 +73,13 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will EEPROM_readAnything(i,minsegmenttime); EEPROM_readAnything(i,max_xy_jerk); EEPROM_readAnything(i,max_z_jerk); +#ifndef PIDTEMP + float Kp,Ki,Kd; +#endif EEPROM_readAnything(i,Kp); EEPROM_readAnything(i,Ki); EEPROM_readAnything(i,Kd); + ECHOLN("Stored settings retreived:"); } else { @@ -100,8 +110,10 @@ void RetrieveSettings(bool def=false){ // if def=true, the default values will ECHOLN(" M204 S" <<_FLOAT(acceleration,2) << " T" << _FLOAT(retract_acceleration,2)); ECHOLN("Advanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum xY jerk (mm/s), Z=maximum Z jerk (mm/s)"); ECHOLN(" M205 S" <<_FLOAT(minimumfeedrate/60,2) << " T" << _FLOAT(mintravelfeedrate/60,2) << " B" << _FLOAT(minsegmenttime,2) << " X" << _FLOAT(max_xy_jerk/60,2) << " Z" << _FLOAT(max_z_jerk/60,2)); +#ifdef PIDTEMP ECHOLN("PID settings:"); ECHOLN(" M301 P" << _FLOAT(Kp,3) << " I" << _FLOAT(Ki,3) << " D" << _FLOAT(Kd,3)); +#endif } diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 7b4bc5e431a3..343f8e8a9298 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -964,9 +964,11 @@ inline void process_commands() Serial.print(tt); Serial.print(", raw:"); Serial.print(current_raw); - #if TEMP_1_PIN > -1 + #if TEMP_1_PIN > -1 +#ifdef PIDTEMP Serial.print(" B:"); Serial.println(HeaterPower); +#endif #else Serial.println(); #endif From 743f775a030f7e0592bade915a53f81b84174e74 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sat, 22 Oct 2011 01:23:34 +0200 Subject: [PATCH 113/130] added fan control into menu --- Marlin/Configuration.h | 2 +- Marlin/Marlin.pde | 7 +++++-- Marlin/ultralcd.pde | 40 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index a8495b70ba24..f33904a9a306 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -146,7 +146,7 @@ bool axis_relative_modes[] = {false, false, false, false}; #define SMOOTHFACTOR 5.0 float current_raw_average=0; -#define PIDTEMP +//#define PIDTEMP #ifdef PIDTEMP //#define PID_DEBUG 1 // Sends debug data to the serial port. //#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 343f8e8a9298..9cc54718e239 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -145,6 +145,7 @@ unsigned long previous_millis_heater, previous_millis_bed_heater; bool relative_mode = false; //Determines Absolute or Relative Coordinates bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. unsigned long axis_steps_per_sqr_second[NUM_AXIS]; +uint8_t fanpwm=0; volatile int feedmultiply=100; //100->1 200->2 // comm variables @@ -1027,12 +1028,14 @@ inline void process_commands() case 106: //M106 Fan On if (code_seen('S')){ digitalWrite(FAN_PIN,HIGH); - analogWrite(FAN_PIN, constrain(code_value(),0,255) ); + fanpwm=constrain(code_value(),0,255); + analogWrite(FAN_PIN, fanpwm); } else { digitalWrite(FAN_PIN,HIGH); - analogWrite(FAN_PIN, 255); + fanpwm=255; + analogWrite(FAN_PIN, fanpwm); } break; case 107: //M107 Fan Off diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 094789290b37..2c8a61bb05eb 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -495,7 +495,7 @@ void MainMenu::showPrepare() } } enum { - ItemC_exit, ItemC_nozzle, ItemC_acc, ItemC_xyjerk, + ItemC_exit, ItemC_nozzle, ItemC_fan, ItemC_acc, ItemC_xyjerk, ItemC_vmaxx, ItemC_vmaxy, ItemC_vmaxz, ItemC_vmaxe, ItemC_vmin, ItemC_amaxx, ItemC_amaxy, ItemC_amaxz, ItemC_amaxe, @@ -560,6 +560,44 @@ void MainMenu::showControl() } } }break; + + case ItemC_fan: + { + if(force_lcd_update) + { + lcd.setCursor(0,line);lcd.print(" Fan speed:"); + lcd.setCursor(13,line);lcd.print(ftostr3(fanpwm)); + } + + if((activeline==line) ) + { + if(CLICKED) //nalogWrite(FAN_PIN, fanpwm); + { + linechanging=!linechanging; + if(linechanging) + { + encoderpos=fanpwm; + } + else + { + fanpwm = constrain(encoderpos,0,255); + encoderpos=fanpwm; + analogWrite(FAN_PIN, fanpwm); + + beepshort(); + } + BLOCK; + } + if(linechanging) + { + if(encoderpos<0) encoderpos=0; + if(encoderpos>255) encoderpos=255; + fanpwm=encoderpos; + analogWrite(FAN_PIN, fanpwm); + lcd.setCursor(13,line);lcd.print(itostr3(encoderpos)); + } + } + }break; case ItemC_acc: { if(force_lcd_update) From 1aa236fd51e1417b7191867af30dde348a91fd07 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Sun, 23 Oct 2011 23:12:38 +0200 Subject: [PATCH 114/130] updates full for lcd --- Marlin/ultralcd.pde | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 2c8a61bb05eb..83e41c1aecf6 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -371,7 +371,7 @@ enum {ItemP_exit, ItemP_home, ItemP_origin, ItemP_preheat, ItemP_extrude, ItemP_ void MainMenu::showPrepare() { uint8_t line=0; - if(lastlineoffset!=lineoffset) + if((lastlineoffset!=lineoffset) || force_lcd_update) { force_lcd_update=true; clear(); @@ -505,7 +505,7 @@ enum { void MainMenu::showControl() { uint8_t line=0; - if(lastlineoffset!=lineoffset) + if((lastlineoffset!=lineoffset)||force_lcd_update) { force_lcd_update=true; clear(); @@ -940,7 +940,7 @@ void MainMenu::getfilename(const uint8_t nr) while (root.readDir(p) > 0) { if (p.name[0] == DIR_NAME_FREE) break; - if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue; + if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.'|| p.name[0] == '_') continue; if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; if(p.name[8]!='G') continue; if(p.name[9]=='~') continue; @@ -969,7 +969,7 @@ uint8_t getnrfilenames() while (root.readDir(p) > 0) { if (p.name[0] == DIR_NAME_FREE) break; - if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue; + if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.'|| p.name[0] == '_') continue; if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue; if(p.name[8]!='G') continue; if(p.name[9]=='~') continue; From 0ad9779a69238de59597d532390c97203c59f7b1 Mon Sep 17 00:00:00 2001 From: lampmaker Date: Mon, 24 Oct 2011 11:15:55 +0300 Subject: [PATCH 115/130] Fixed bug in M105 processing when PID is disabled. --- Marlin/Marlin.pde | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 9cc54718e239..fbfb0fba0366 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -969,6 +969,8 @@ inline void process_commands() #ifdef PIDTEMP Serial.print(" B:"); Serial.println(HeaterPower); +#else + Serial.println(); #endif #else Serial.println(); From 062da6552734144f328119c50ea1e50912b3aa9d Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Wed, 26 Oct 2011 17:47:44 +0200 Subject: [PATCH 116/130] fix minimum feedrate --- Marlin/Configuration.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index f33904a9a306..73f83c140614 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -46,7 +46,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the //#define ULTIPANEL #ifdef ULTIPANEL - //#define NEWPANEL //enable this if you have a click-encoder panel + #define NEWPANEL //enable this if you have a click-encoder panel #define SDSUPPORT #define ULTRA_LCD #define LCD_WIDTH 20 @@ -114,7 +114,7 @@ bool axis_relative_modes[] = {false, false, false, false}; #define DEFAULT_ACCELERATION 4600 // X, Y, Z and E max acceleration in mm/s^2 for printing moves #define DEFAULT_RETRACT_ACCELERATION 7000 // X, Y, Z and E max acceleration in mm/s^2 for r retracts -#define DEFAULT_MINIMUMFEEDRATE 10*60 // minimum feedrate +#define DEFAULT_MINIMUMFEEDRATE 0*60 // minimum feedrate #define DEFAULT_MINTRAVELFEEDRATE 140*60 // minimum time in microseconds that a movement needs to take if the buffer is emptied. Increase this number if you see blobs while printing high speed & high detail. It will slowdown on the detailed stuff. From 328a5dddac844e4fb4781d63d4571a8a34c2a666 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Wed, 26 Oct 2011 18:25:07 +0200 Subject: [PATCH 117/130] smaller memory footprint of without advance. --- Marlin/Configuration.h | 1 - Marlin/Marlin.h | 6 +++--- Marlin/Marlin.pde | 5 +++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 73f83c140614..afbfd025d4ab 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -158,7 +158,6 @@ double Ki = 0; //1.5*PID_dT; double Kd = 0; //80/PID_dT; #endif // PIDTEMP - // extruder advance constant (s2/mm3) // // advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2 diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 05de3e66dd56..153a0a907e94 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -10,7 +10,6 @@ #define ECHO(x) Serial << "echo: " << x; #define ECHOLN(x) Serial << "echo: "<initial_rate; final_rate = current_block->final_rate; nominal_rate = current_block->nominal_rate; +#ifdef ADVANCE advance = current_block->initial_advance; final_advance = current_block->final_advance; +#endif + deceleration_time = 0; +#ifdef ADVANCE advance_rate = current_block->advance_rate; +#endif // step_rate to timer interval acc_step_rate = initial_rate; acceleration_time = calc_timer(acc_step_rate); From 6d559672fcf7ee20f9229490af8b5ebb2c6533a1 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Wed, 26 Oct 2011 23:37:38 +0200 Subject: [PATCH 118/130] enable watchdog with manual reset (still untested, but doing at least no harm) and adding some reasonable pid settings. Tested without actually printing. --- Marlin/Configuration.h | 17 +++++++++++----- Marlin/Marlin.pde | 44 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index afbfd025d4ab..42ee026a565f 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -122,8 +122,15 @@ bool axis_relative_modes[] = {false, false, false, false}; #define DEFAULT_XYJERK 30.0*60 #define DEFAULT_ZJERK 10.0*60 - // The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature +//this enables the watchdog interrupt. +#define USE_WATCHDOG +//you cannot reboot on a mega2560 due to a bug in he bootloader. Hence, you have to reset manually, and this is done hereby: +#define RESET_MANUAL + +#define WATCHDOG_TIMEOUT 4 + + // If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109 //#define WATCHPERIOD 5000 //5 seconds @@ -146,15 +153,15 @@ bool axis_relative_modes[] = {false, false, false, false}; #define SMOOTHFACTOR 5.0 float current_raw_average=0; -//#define PIDTEMP +#define PIDTEMP #ifdef PIDTEMP //#define PID_DEBUG 1 // Sends debug data to the serial port. //#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % #define PID_MAX 255 // limits current to nozzle #define PID_INTEGRAL_DRIVE_MAX 255 -#define PID_dT 0.16 -double Kp = 3000; //20.0; -double Ki = 0; //1.5*PID_dT; +#define PID_dT 0.05 +double Kp = 750; //20.0; +double Ki =10*PID_dT; //1.5*PID_dT; double Kd = 0; //80/PID_dT; #endif // PIDTEMP diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 133f8ace6daf..8a8e67dd3a65 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1356,7 +1356,48 @@ inline void kill() } */ +#ifdef USE_WATCHDOG + +#include +#include + +volatile uint8_t timeout_seconds=0; + +void(* ctrlaltdelete) (void) = 0; + +ISR(WDT_vect) { //Watchdog timer interrupt, called if main program blocks >1sec + if(timeout_seconds++ >= WATCHDOG_TIMEOUT) + { + kill(); +#ifdef RESET_MANUAL + LCD_MESSAGE("Please Reset!"); + ECHOLN("echo_: Something is wrong, please turn off the printer."); +#else + LCD_MESSAGE("Timeout, resetting!"); +#endif + //disable watchdog, it will survife reboot. + WDTCSR |= (1< Date: Sun, 30 Oct 2011 22:00:56 +0100 Subject: [PATCH 119/130] Disabled PID because its not working while in print.. --- Marlin/Configuration.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 42ee026a565f..3f6847cb8615 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -1,5 +1,4 @@ - #ifndef CONFIGURATION_H #define CONFIGURATION_H @@ -153,7 +152,7 @@ bool axis_relative_modes[] = {false, false, false, false}; #define SMOOTHFACTOR 5.0 float current_raw_average=0; -#define PIDTEMP +//#define PIDTEMP #ifdef PIDTEMP //#define PID_DEBUG 1 // Sends debug data to the serial port. //#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % From b65970e0adeeda71adce35c4c7f25b7ece2f1210 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 1 Nov 2011 19:44:00 +0100 Subject: [PATCH 120/130] better PID values. added M220 Svelocity factor override --- Marlin/Configuration.h | 12 +++++++----- Marlin/Marlin.pde | 10 ++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 42ee026a565f..f279a6d01e25 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -44,9 +44,9 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define LCD_WIDTH 16 #define LCD_HEIGHT 2 -//#define ULTIPANEL +#define ULTIPANEL #ifdef ULTIPANEL - #define NEWPANEL //enable this if you have a click-encoder panel + //#define NEWPANEL //enable this if you have a click-encoder panel #define SDSUPPORT #define ULTRA_LCD #define LCD_WIDTH 20 @@ -153,6 +153,7 @@ bool axis_relative_modes[] = {false, false, false, false}; #define SMOOTHFACTOR 5.0 float current_raw_average=0; +#define GRACETEMP 0 //temperature which already counts as reached for M109 #define PIDTEMP #ifdef PIDTEMP //#define PID_DEBUG 1 // Sends debug data to the serial port. @@ -160,8 +161,9 @@ float current_raw_average=0; #define PID_MAX 255 // limits current to nozzle #define PID_INTEGRAL_DRIVE_MAX 255 #define PID_dT 0.05 -double Kp = 750; //20.0; -double Ki =10*PID_dT; //1.5*PID_dT; + +double Kp = 1000; //20.0; +double Ki =100*PID_dT; //1.5*PID_dT; double Kd = 0; //80/PID_dT; #endif // PIDTEMP @@ -177,7 +179,7 @@ double Kd = 0; //80/PID_dT; #ifdef ADVANCE #define EXTRUDER_ADVANCE_K .3 -#define D_FILAMENT 1.7 +#define D_FILAMENT 2.8 #define STEPS_MM_E 65 #define EXTRUTION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159) #define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUTION_AREA) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 8a8e67dd3a65..c15beec62ea7 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -125,6 +125,7 @@ volatile int count_direction[NUM_AXIS] = { 1, 1, 1, 1}; // M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec // M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 also sets minimum segment time in ms (B20000) to prevent buffer underruns and M20 minimum feedrate // M205 - advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk +// M220 - set speed factor override percentage S:factor in percent // M301 - Set PID parameters P I and D // M500 - stores paramters in EEPROM // M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily). D @@ -993,7 +994,7 @@ inline void process_commands() #endif codenum = millis(); starttime=millis(); - while(current_raw < target_raw) { + while(analog2temp(current_raw)< analog2temp(target_raw)-GRACETEMP) { if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. { Serial.print("T:"); @@ -1156,6 +1157,11 @@ inline void process_commands() if(code_seen('Z')) max_z_jerk = code_value()*60 ; } break; + case 220: // M220 S- set speed factor override percentage + { + if(code_seen('S')) feedmultiply = code_value() ; + } + break; #ifdef PIDTEMP case 301: // M301 if(code_seen('P')) Kp = code_value(); @@ -1457,7 +1463,7 @@ void manage_heater() pTerm = (Kp * error) / 100.0; temp_iState += error; //temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - temp_iState = constrain(temp_iState, -1000, 1000); + temp_iState = constrain(temp_iState, -2000, 2000); iTerm = (Ki * temp_iState)/100.0; dTerm = (Kd * (current_raw_average - temp_dState)) / 100.0; temp_dState = current_raw_average; From 742fb2e835ad6c76b83085e823b42c798f3013e5 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 1 Nov 2011 19:53:52 +0100 Subject: [PATCH 121/130] disabled lcd for most users --- Marlin/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 181f44cb9e7e..b0ab7e527c6f 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -43,7 +43,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the #define LCD_WIDTH 16 #define LCD_HEIGHT 2 -#define ULTIPANEL +//#define ULTIPANEL #ifdef ULTIPANEL //#define NEWPANEL //enable this if you have a click-encoder panel #define SDSUPPORT From 5877a0fbbe19288f37a1fe5029919aa4ade5b440 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 1 Nov 2011 22:40:51 +0100 Subject: [PATCH 122/130] circumvent the display from overwriting the speed-factor --- Marlin/Marlin.pde | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index c15beec62ea7..a59c22327a1d 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1160,6 +1160,12 @@ inline void process_commands() case 220: // M220 S- set speed factor override percentage { if(code_seen('S')) feedmultiply = code_value() ; +#ifdef ULTRALCD + if(menu.status==Main_Status) + { + encoderpos=feedmultiply; + } +#endif } break; #ifdef PIDTEMP From e1e0abdfcca21a7ae8508c97433468d8a74de6cc Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 1 Nov 2011 23:12:39 +0100 Subject: [PATCH 123/130] next try. --- Marlin/Marlin.pde | 9 ++++----- Marlin/ultralcd.pde | 5 ++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index a59c22327a1d..2f99a43f3c37 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -149,6 +149,7 @@ unsigned long axis_steps_per_sqr_second[NUM_AXIS]; uint8_t fanpwm=0; volatile int feedmultiply=100; //100->1 200->2 +volatile bool feedmultiplychanged=false; // comm variables #define MAX_CMD_SIZE 96 #define BUFSIZE 8 @@ -1159,13 +1160,11 @@ inline void process_commands() break; case 220: // M220 S- set speed factor override percentage { - if(code_seen('S')) feedmultiply = code_value() ; -#ifdef ULTRALCD - if(menu.status==Main_Status) + if(code_seen('S')) { - encoderpos=feedmultiply; + feedmultiply = code_value() ; + feedmultiplychanged=true; } -#endif } break; #ifdef PIDTEMP diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 83e41c1aecf6..d79ee2e78495 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -240,14 +240,17 @@ MainMenu::MainMenu() linechanging=false; } +extern volatile bool feedmultiplychanged; + void MainMenu::showStatus() { #if LCD_HEIGHT==4 static int oldcurrentraw=-1; static int oldtargetraw=-1; //force_lcd_update=true; - if(force_lcd_update) //initial display of content + if(force_lcd_update||feedmultiplychanged) //initial display of content { + feedmultiplychanged=false; encoderpos=feedmultiply; clear(); lcd.setCursor(0,0);lcd.print("\002123/567\001 "); From c896db5f506e861bff7176fdcb0a6671416bc053 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Tue, 1 Nov 2011 23:33:35 +0100 Subject: [PATCH 124/130] display update bug --- Marlin/ultralcd.pde | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index d79ee2e78495..88432f512e8a 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -311,7 +311,7 @@ void MainMenu::showStatus() } static int oldfeedmultiply=0; int curfeedmultiply=feedmultiply; - if(encoderpos!=curfeedmultiply) + if(encoderpos!=curfeedmultiply||force_lcd_update) { curfeedmultiply=encoderpos; if(curfeedmultiply<10) From 786b83d2f4b01d8e04c30fe086fdea45e93e1485 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Wed, 2 Nov 2011 20:37:09 +0100 Subject: [PATCH 125/130] PID now working. Actually, its more than pid, lets call it PIDC. Additionnally to the P, I, and D term I use a term that is proportional to the extruder motor speed. If its running faster, one expects that more heat is needed, due to the additional melting. --- Marlin/Configuration.h | 26 ++++--- Marlin/Marlin.pde | 5 +- Marlin/ultralcd.pde | 154 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 173 insertions(+), 12 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index b0ab7e527c6f..1c223b74acfa 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -45,7 +45,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the //#define ULTIPANEL #ifdef ULTIPANEL - //#define NEWPANEL //enable this if you have a click-encoder panel + #define NEWPANEL //enable this if you have a click-encoder panel #define SDSUPPORT #define ULTRA_LCD #define LCD_WIDTH 20 @@ -155,16 +155,22 @@ float current_raw_average=0; #define GRACETEMP 0 //temperature which already counts as reached for M109 #define PIDTEMP + #ifdef PIDTEMP -//#define PID_DEBUG 1 // Sends debug data to the serial port. -//#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % -#define PID_MAX 255 // limits current to nozzle -#define PID_INTEGRAL_DRIVE_MAX 255 -#define PID_dT 0.05 - -double Kp = 1000; //20.0; -double Ki =100*PID_dT; //1.5*PID_dT; -double Kd = 0; //80/PID_dT; + //#define PID_DEBUG 1 // Sends debug data to the serial port. + //#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in % + #define PID_MAX 255 // limits current to nozzle + #define PID_INTEGRAL_DRIVE_MAX 255 + #define PID_dT 0.05 + //machine with red silicon: 1950:45 second ; with fan fully blowin 3000:47 + + #define PID_CRITIAL_GAIN 2800 + #define PID_SWING_AT_CRITIAL 45 //seconds + + double Kp = 0.6*PID_CRITIAL_GAIN; //20.0; + double Ki =2*Kp/PID_SWING_AT_CRITIAL*PID_dT; //1.5*PID_dT; + double Kd = Kp*PID_SWING_AT_CRITIAL/8./PID_dT; //80/PID_dT; + double Kc = 9; //heatingpower=Kc*(e_speed) #endif // PIDTEMP // extruder advance constant (s2/mm3) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 2f99a43f3c37..61b506a2bc0f 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -180,6 +180,7 @@ float mintravelfeedrate; #include "EEPROM.h" +static block_t *current_block; // A pointer to the block currently being traced int target_bed_raw = 0; int current_bed_raw = 0; @@ -1472,6 +1473,8 @@ void manage_heater() iTerm = (Ki * temp_iState)/100.0; dTerm = (Kd * (current_raw_average - temp_dState)) / 100.0; temp_dState = current_raw_average; + pTerm+=Kc*current_block->speed_e; //additional heating if extrusion speed is high + HeaterPower= constrain(pTerm + iTerm - dTerm, 0, PID_MAX); } else HeaterPower= constrain(-Kp,0, 255); // @@ -2299,7 +2302,7 @@ asm volatile ( \ #define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1<9990/5) encoderpos=9990/5; + lcd.setCursor(13,line);lcd.print(itostr4(encoderpos*5)); + } + } + }break; + case ItemC_PID_I: + { + if(force_lcd_update) + { + lcd.setCursor(0,line);lcd.print(" PID-I: "); + lcd.setCursor(13,line);lcd.print(itostr4(Ki)); + } + + if((activeline==line) ) + { + if(CLICKED) + { + linechanging=!linechanging; + if(linechanging) + { + encoderpos=(int)Ki/5; + } + else + { + Ki= encoderpos*5; + encoderpos=activeline*lcdslow; + + } + BLOCK; + beepshort(); + } + if(linechanging) + { + if(encoderpos<0) encoderpos=0; + if(encoderpos>9990/5) encoderpos=9990/5; + lcd.setCursor(13,line);lcd.print(itostr4(encoderpos*5)); + } + } + }break; + case ItemC_PID_D: + { + if(force_lcd_update) + { + lcd.setCursor(0,line);lcd.print(" PID-D: "); + lcd.setCursor(13,line);lcd.print(itostr4(Kd)); + } + + if((activeline==line) ) + { + if(CLICKED) + { + linechanging=!linechanging; + if(linechanging) + { + encoderpos=(int)Kd/5; + } + else + { + Kd= encoderpos*5; + encoderpos=activeline*lcdslow; + + } + BLOCK; + beepshort(); + } + if(linechanging) + { + if(encoderpos<0) encoderpos=0; + if(encoderpos>9990/5) encoderpos=9990/5; + lcd.setCursor(13,line);lcd.print(itostr4(encoderpos*5)); + } + } + }break; + + + + case ItemC_PID_C: + { + if(force_lcd_update) + { + lcd.setCursor(0,line);lcd.print(" PID-C: "); + lcd.setCursor(13,line);lcd.print(itostr3(Kc)); + } + + if((activeline==line) ) + { + if(CLICKED) + { + linechanging=!linechanging; + if(linechanging) + { + encoderpos=(int)Kc; + } + else + { + Kc= encoderpos; + encoderpos=activeline*lcdslow; + + } + BLOCK; + beepshort(); + } + if(linechanging) + { + if(encoderpos<0) encoderpos=0; + if(encoderpos>990) encoderpos=990; + lcd.setCursor(13,line);lcd.print(itostr3(encoderpos)); + } + } + }break; case ItemC_vmaxx: case ItemC_vmaxy: case ItemC_vmaxz: @@ -1368,6 +1510,16 @@ char *itostr3(const int &xx) return conv; } +char *itostr4(const int &xx) +{ + conv[0]=(xx/1000)%10+'0'; + conv[1]=(xx/100)%10+'0'; + conv[2]=(xx/10)%10+'0'; + conv[3]=(xx)%10+'0'; + conv[4]=0; + return conv; +} + /// convert float to string with +1234.5 format char *ftostr51(const float &x) { From 1353ab3b92b21bca73511ee85828cf624cd8fb3b Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Wed, 2 Nov 2011 21:03:58 +0100 Subject: [PATCH 126/130] a bit higher even. --- Marlin/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 1c223b74acfa..6b80d1e43f7b 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -164,7 +164,7 @@ float current_raw_average=0; #define PID_dT 0.05 //machine with red silicon: 1950:45 second ; with fan fully blowin 3000:47 - #define PID_CRITIAL_GAIN 2800 + #define PID_CRITIAL_GAIN 3000 #define PID_SWING_AT_CRITIAL 45 //seconds double Kp = 0.6*PID_CRITIAL_GAIN; //20.0; From 566ed1fbca6341d40c57f8ad0509fe5b512efb6b Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Wed, 2 Nov 2011 21:30:54 +0100 Subject: [PATCH 127/130] PID-I was a bit too low. --- Marlin/Configuration.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 6b80d1e43f7b..f2ec6653fe33 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -166,9 +166,10 @@ float current_raw_average=0; #define PID_CRITIAL_GAIN 3000 #define PID_SWING_AT_CRITIAL 45 //seconds + #define PIDIADD 5 double Kp = 0.6*PID_CRITIAL_GAIN; //20.0; - double Ki =2*Kp/PID_SWING_AT_CRITIAL*PID_dT; //1.5*PID_dT; + double Ki =PIDIADD+2*Kp/PID_SWING_AT_CRITIAL*PID_dT; //1.5*PID_dT; double Kd = Kp*PID_SWING_AT_CRITIAL/8./PID_dT; //80/PID_dT; double Kc = 9; //heatingpower=Kc*(e_speed) #endif // PIDTEMP From 3a49a0d81be372ab7bc3bb5e8575ff02056c0786 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Thu, 3 Nov 2011 09:47:13 +0100 Subject: [PATCH 128/130] float should be sufficient. --- Marlin/Configuration.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index f2ec6653fe33..44fdd7943517 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -168,10 +168,10 @@ float current_raw_average=0; #define PID_SWING_AT_CRITIAL 45 //seconds #define PIDIADD 5 - double Kp = 0.6*PID_CRITIAL_GAIN; //20.0; - double Ki =PIDIADD+2*Kp/PID_SWING_AT_CRITIAL*PID_dT; //1.5*PID_dT; - double Kd = Kp*PID_SWING_AT_CRITIAL/8./PID_dT; //80/PID_dT; - double Kc = 9; //heatingpower=Kc*(e_speed) + float Kp = 0.6*PID_CRITIAL_GAIN; //20.0; + float Ki =PIDIADD+2*Kp/PID_SWING_AT_CRITIAL*PID_dT; //1.5*PID_dT; + float Kd = Kp*PID_SWING_AT_CRITIAL/8./PID_dT; //80/PID_dT; + float Kc = 9; //heatingpower=Kc*(e_speed) #endif // PIDTEMP // extruder advance constant (s2/mm3) From 259a5aca94d893675a8bf2b6c2991544f2cde42e Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Thu, 3 Nov 2011 09:49:19 +0100 Subject: [PATCH 129/130] trying just PI instead of PID --- Marlin/Configuration.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 44fdd7943517..e22801698a64 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -167,10 +167,16 @@ float current_raw_average=0; #define PID_CRITIAL_GAIN 3000 #define PID_SWING_AT_CRITIAL 45 //seconds #define PIDIADD 5 - - float Kp = 0.6*PID_CRITIAL_GAIN; //20.0; - float Ki =PIDIADD+2*Kp/PID_SWING_AT_CRITIAL*PID_dT; //1.5*PID_dT; - float Kd = Kp*PID_SWING_AT_CRITIAL/8./PID_dT; //80/PID_dT; +/* + //PID according to Ziegler-Nichols method + float Kp = 0.6*PID_CRITIAL_GAIN; + float Ki =PIDIADD+2*Kp/PID_SWING_AT_CRITIAL*PID_dT; + float Kd = Kp*PID_SWING_AT_CRITIAL/8./PID_dT; +*/ + //PI according to Ziegler-Nichols method + float Kp = PID_CRITIAL_GAIN/2.2; + float Ki =1.2*Kp/PID_SWING_AT_CRITIAL*PID_dT; + float Kd = 0; float Kc = 9; //heatingpower=Kc*(e_speed) #endif // PIDTEMP From 81202a8d303a848fc99c29a1f817a727f84450b1 Mon Sep 17 00:00:00 2001 From: Bernhard Kubicek Date: Thu, 3 Nov 2011 20:02:04 +0100 Subject: [PATCH 130/130] made it possible to have an intermediate M92 command without the extruder motor running wild. --- Marlin/Marlin.pde | 26 ++++++++++++-------- Marlin/ultralcd.pde | 59 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 64 insertions(+), 21 deletions(-) diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 61b506a2bc0f..a514c57daf05 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -178,6 +178,7 @@ float mintravelfeedrate; // Manage heater variables. #include "EEPROM.h" +static long position[4]; //in steps static block_t *current_block; // A pointer to the block currently being traced @@ -1073,7 +1074,12 @@ inline void process_commands() break; case 92: // M92 for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); + if(code_seen(axis_codes[i])) + { + float factor=float(code_value())/float(axis_steps_per_unit[3]); + position[E_AXIS]=lround(position[E_AXIS]*factor); + axis_steps_per_unit[i] = code_value(); + } } break; @@ -1729,7 +1735,6 @@ static volatile unsigned char block_buffer_head; // Index of the next static volatile unsigned char block_buffer_tail; // Index of the block to process now // The current position of the tool in absolute steps -static long position[4]; #define ONE_MINUTE_OF_MICROSECONDS 60000000.0 @@ -2032,14 +2037,7 @@ void check_axes_activity() { // mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration // calculation the caller must also provide the physical length of the line in millimeters. void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { - - // The target position of the tool in absolute steps - // Calculate target position in absolute steps - long target[4]; - target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); - target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); - target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); - target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); + // Calculate the buffer head after we push this byte int next_buffer_head = (block_buffer_head + 1) %BLOCK_BUFFER_SIZE; @@ -2051,6 +2049,14 @@ void plan_buffer_line(float x, float y, float z, float e, float feed_rate) { manage_inactivity(1); } + // The target position of the tool in absolute steps + // Calculate target position in absolute steps + long target[4]; + target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); + target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); + target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); + target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); + // Prepare to set up new block block_t *block = &block_buffer[block_buffer_head]; diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index 61e25b1c1414..1eeb2af0b299 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -503,7 +503,7 @@ enum { ItemC_fan, ItemC_acc, ItemC_xyjerk, ItemC_vmaxx, ItemC_vmaxy, ItemC_vmaxz, ItemC_vmaxe, - ItemC_vmin, + ItemC_vtravmin,ItemC_vmin, ItemC_amaxx, ItemC_amaxy, ItemC_amaxz, ItemC_amaxe, ItemC_aret,ItemC_esteps, ItemC_store, ItemC_load,ItemC_failsafe }; @@ -710,7 +710,7 @@ void MainMenu::showControl() if(force_lcd_update) { lcd.setCursor(0,line);lcd.print(" PID-I: "); - lcd.setCursor(13,line);lcd.print(itostr4(Ki)); + lcd.setCursor(13,line);lcd.print(ftostr51(Ki)); } if((activeline==line) ) @@ -720,11 +720,11 @@ void MainMenu::showControl() linechanging=!linechanging; if(linechanging) { - encoderpos=(int)Ki/5; + encoderpos=(int)(Ki*10); } else { - Ki= encoderpos*5; + Ki= encoderpos/10.; encoderpos=activeline*lcdslow; } @@ -734,8 +734,8 @@ void MainMenu::showControl() if(linechanging) { if(encoderpos<0) encoderpos=0; - if(encoderpos>9990/5) encoderpos=9990/5; - lcd.setCursor(13,line);lcd.print(itostr4(encoderpos*5)); + if(encoderpos>9990) encoderpos=9990; + lcd.setCursor(13,line);lcd.print(ftostr51(encoderpos/10.)); } } }break; @@ -867,7 +867,7 @@ void MainMenu::showControl() linechanging=!linechanging; if(linechanging) { - encoderpos=(int)minimumfeedrate/60; + encoderpos=(int)(minimumfeedrate/60.); } else { @@ -886,6 +886,40 @@ void MainMenu::showControl() } } }break; + case ItemC_vtravmin: + { + if(force_lcd_update) + { + lcd.setCursor(0,line);lcd.print(" VTrav min:"); + lcd.setCursor(13,line);lcd.print(itostr3(mintravelfeedrate/60)); + } + + if((activeline==line) ) + { + if(CLICKED) + { + linechanging=!linechanging; + if(linechanging) + { + encoderpos=(int)mintravelfeedrate/60; + } + else + { + mintravelfeedrate= encoderpos*60; + encoderpos=activeline*lcdslow; + + } + BLOCK; + beepshort(); + } + if(linechanging) + { + if(encoderpos<0) encoderpos=0; + if(encoderpos>990) encoderpos=990; + lcd.setCursor(13,line);lcd.print(itostr3(encoderpos)); + } + } + }break; case ItemC_amaxx: case ItemC_amaxy: @@ -966,7 +1000,7 @@ void MainMenu::showControl() if(force_lcd_update) { lcd.setCursor(0,line);lcd.print(" Esteps/mm:"); - lcd.setCursor(13,line);lcd.print(itostr3(axis_steps_per_unit[3])); + lcd.setCursor(13,line);lcd.print(itostr4(axis_steps_per_unit[3])); } if((activeline==line) ) @@ -980,7 +1014,10 @@ void MainMenu::showControl() } else { - axis_steps_per_unit[3]= encoderpos; + float factor=float(encoderpos)/float(axis_steps_per_unit[3]); + position[E_AXIS]=lround(position[E_AXIS]*factor); + //current_position[3]*=factor; + axis_steps_per_unit[E_AXIS]= encoderpos; encoderpos=activeline*lcdslow; } @@ -990,8 +1027,8 @@ void MainMenu::showControl() if(linechanging) { if(encoderpos<5) encoderpos=5; - if(encoderpos>990) encoderpos=990; - lcd.setCursor(13,line);lcd.print(itostr3(encoderpos)); + if(encoderpos>9999) encoderpos=9999; + lcd.setCursor(13,line);lcd.print(itostr4(encoderpos)); } } }break;