diff options
-rw-r--r-- | README | 8 | ||||
-rw-r--r-- | Sprinter/Configuration.h | 203 | ||||
-rw-r--r-- | Sprinter/Makefile | 2 | ||||
-rw-r--r-- | Sprinter/SdFat.h | 4 | ||||
-rw-r--r-- | Sprinter/SdFatUtil.h | 2 | ||||
-rw-r--r-- | Sprinter/SdFile.cpp | 33 | ||||
-rw-r--r-- | Sprinter/Sprinter.h | 134 | ||||
-rw-r--r-- | Sprinter/Sprinter.pde | 3243 | ||||
-rw-r--r-- | Sprinter/arc_func.cpp | 147 | ||||
-rw-r--r-- | Sprinter/arc_func.h | 32 | ||||
-rw-r--r-- | Sprinter/heater.cpp | 591 | ||||
-rw-r--r-- | Sprinter/heater.h | 119 | ||||
-rw-r--r-- | Sprinter/pins.h | 60 | ||||
-rw-r--r-- | Sprinter/speed_lookuptable.h | 151 | ||||
-rw-r--r-- | Sprinter/store_eeprom.cpp | 213 | ||||
-rw-r--r-- | Sprinter/store_eeprom.h | 49 | ||||
-rw-r--r-- | Sprinter/thermistortables.h | 2 |
17 files changed, 3960 insertions, 1033 deletions
@@ -40,8 +40,8 @@ Software installation 1. Install the required packages (gcc-avr, avr-libc, etc.)
sudo apt-get install arduino-core
-2. Get the arduino software version 0018 (0023 works for RAMPS), uncompress it in a directory
-Arduino software v1 DOES NOT work with Sprinter yet!
+2. Get the arduino software version 0018 (0023 works for RAMPS), uncompress it in a directory.
+Arduino software v1 has not been tested much, but is known to work with some boards.
http://www.arduino.cc/en/Main/Software
3. Get the sanguino software, version 0018
@@ -95,6 +95,10 @@ also for the mentioned hardware setup 13. Click on "the arrow going to the right" button to upload (you had done steps 7,8,9 before, right ?).
If everything goes well you should see the message "Done uploading".
+if GEN7 with 20 Mhz is in use set the Fuses for Bootloader to
+lfuse= 0xF7 hfuse = 0xD4 efuse = FD
+Brownout must be 2,7 V
+
Congratulations, you have just upgraded the firmware of your RepRap !
You can use pronterface.py to do some manual verifications by moving the printer's tip along
diff --git a/Sprinter/Configuration.h b/Sprinter/Configuration.h index d594094..212b44e 100644 --- a/Sprinter/Configuration.h +++ b/Sprinter/Configuration.h @@ -1,4 +1,4 @@ -#ifndef CONFIGURATION_H +#ifndef CONFIGURATION_H #define CONFIGURATION_H // BASIC SETTINGS: select your board type, thermistor type, axis scaling, and endstop configuration @@ -9,11 +9,14 @@ // Gen6 = 5, // Sanguinololu up to 1.1 = 6 // Sanguinololu 1.2 and above = 62 +// Gen 7 @ 16MHZ only= 7 +// Gen 7 @ 20MHZ only= 71 // Teensylu (at90usb) = 8 +// Printrboard Rev. B (ATMEGA90USB1286) = 9 // Gen 3 Plus = 21 // gen 3 Monolithic Electronics = 22 // Gen3 PLUS for TechZone Gen3 Remix Motherboard = 23 -#define MOTHERBOARD 3 +#define MOTHERBOARD 3 //// Thermistor settings: // 1 is 100k thermistor @@ -28,12 +31,13 @@ //// Calibration variables // X, Y, Z, E steps per unit - Metric Prusa Mendel with Wade extruder: -float axis_steps_per_unit[] = {80, 80, 3200/1.25,700}; +#define _AXIS_STEP_PER_UNIT {80, 80, 3200/1.25,700} // Metric Prusa Mendel with Makergear geared stepper extruder: -//float axis_steps_per_unit[] = {80,80,3200/1.25,1380}; +//#define _AXIS_STEP_PER_UNIT {80,80,3200/1.25,1380} // MakerGear Hybrid Prusa Mendel: // Z axis value is for .9 stepper(if you have 1.8 steppers for Z, you need to use 2272.7272) -//float axis_steps_per_unit[] = {104.987, 104.987, 4545.4544, 1487}; +//#define _AXIS_STEP_PER_UNIT {104.987, 104.987, 4545.4544, 1487} + //// Endstop Settings #define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors @@ -46,52 +50,112 @@ const bool Z_ENDSTOP_INVERT = false; // This determines the communication speed of the printer #define BAUDRATE 115200 +//#define BAUDRATE 250000 // Comment out (using // at the start of the line) to disable SD support: #define SDSUPPORT -// Uncomment to make Sprinter run init.g from SD on boot -//#define SDINITFILE +// Uncomment to make run init.g from SD on boot +//#define SDINITFILE +//Only work with Atmega1284 you need +1 kb ram +//#define SD_FAST_XFER_AKTIV + +//----------------------------------------------------------------------- +//// STORE SETTINGS TO EEPROM +//----------------------------------------------------------------------- +// the microcontroller can store settings in the EEPROM +// M500 - stores paramters in EEPROM +// M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily). +// M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to. +// M503 - Print settings +// define this to enable eeprom support +//#define USE_EEPROM_SETTINGS + +// to disable EEPROM Serial responses and decrease program space by ~1000 byte: comment this out: +// please keep turned on if you can. +//#define PRINT_EEPROM_SETTING + +//----------------------------------------------------------------------- +//// ARC Function (G2/G3 Command) +//----------------------------------------------------------------------- +//Uncomment to aktivate the arc (circle) function (G2/G3 Command) +//Without SD function an ARC function the used Flash is smaller 31 kb +#define USE_ARC_FUNCTION + +//----------------------------------------------------------------------- //// ADVANCED SETTINGS - to tweak parameters +//----------------------------------------------------------------------- -#include "thermistortables.h" +#ifdef SDSUPPORT + #ifdef SD_FAST_XFER_AKTIV + //Fast transfer chunk size (> 1024 is unstable, change at your own risk). + #define SD_FAST_XFER_CHUNK_SIZE 1024 + #endif +#endif +//----------------------------------------------------------------------- // 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 +//Uncomment if you have problems with a stepper driver enabeling too late, this will also set how many microseconds delay there will be after enabeling the driver +//#define DELAY_ENABLE 15 + +//----------------------------------------------------------------------- // Disables axis when it's not being used. +//----------------------------------------------------------------------- const bool DISABLE_X = false; const bool DISABLE_Y = false; const bool DISABLE_Z = true; const bool DISABLE_E = false; +//----------------------------------------------------------------------- // Inverting axis direction +//----------------------------------------------------------------------- const bool INVERT_X_DIR = false; const bool INVERT_Y_DIR = false; const bool INVERT_Z_DIR = true; const bool INVERT_E_DIR = 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 ENDSTOPS_ONLY_FOR_HOMING // If defined the endstops will only be used for homing + const bool min_software_endstops = false; //If true, axis won't move to coordinates less than zero. -const bool max_software_endstops = true; //If true, axis won't move to coordinates greater than the defined lengths below. +const bool max_software_endstops = true; //If true, axis won't move to coordinates greater than the defined lengths below. + + +//----------------------------------------------------------------------- +//Max Length for Prusa Mendel, check the ways of your axis and set this Values +//----------------------------------------------------------------------- const int X_MAX_LENGTH = 200; const int Y_MAX_LENGTH = 200; const int Z_MAX_LENGTH = 100; +//----------------------------------------------------------------------- //// MOVEMENT SETTINGS +//----------------------------------------------------------------------- const int NUM_AXIS = 4; // The axis order in all axis related arrays is X, Y, Z, E -float max_feedrate[] = {200000, 200000, 240, 500000}; -float homing_feedrate[] = {1500,1500,120}; -bool axis_relative_modes[] = {false, false, false, false}; +#define _MAX_FEEDRATE {400, 400, 2, 45} // (mm/sec) +#define _HOMING_FEEDRATE {1500,1500,120} // (mm/min) !! +#define _AXIS_RELATIVE_MODES {false, false, false, false} + +#define MAX_STEP_FREQUENCY 30000 // Max step frequency + + +//----------------------------------------------------------------------- +//// Not used at the Moment +//----------------------------------------------------------------------- // Min step delay in microseconds. If you are experiencing missing steps, try to raise the delay microseconds, but be aware this // If you enable this, make sure STEP_DELAY_RATIO is disabled. @@ -101,35 +165,111 @@ bool axis_relative_modes[] = {false, false, false, false}; // If you enable this, make sure STEP_DELAY_MICROS is disabled. (except for Gen6: both need to be enabled.) //#define STEP_DELAY_RATIO 0.25 -// Comment this to disable ramp acceleration -#define RAMP_ACCELERATION +///Oscillation reduction. Forces x,y,or z axis to be stationary for ## ms before allowing axis to switch direcitons. Alternative method to prevent skipping steps. Uncomment the line below to activate. +//#define RAPID_OSCILLATION_REDUCTION +#ifdef RAPID_OSCILLATION_REDUCTION +long min_time_before_dir_change = 30; //milliseconds +#endif +//----------------------------------------------------------------------- //// Acceleration settings -#ifdef RAMP_ACCELERATION +//----------------------------------------------------------------------- // 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 max_start_speed_units_per_second[] = {25.0,25.0,0.2,10.0}; -long max_acceleration_units_per_sq_second[] = {1000,1000,50,10000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts -long max_travel_acceleration_units_per_sq_second[] = {500,500,50,500}; // X, Y, Z max acceleration in mm/s^2 for travel moves -#endif +#define _ACCELERATION 1000 // Axis Normal acceleration mm/s^2 +#define _RETRACT_ACCELERATION 2000 // Extruder Normal acceleration mm/s^2 +#define _MAX_XY_JERK 20.0 +#define _MAX_Z_JERK 0.4 +//#define _MAX_START_SPEED_UNITS_PER_SECOND {25.0,25.0,0.2,10.0} +#define _MAX_ACCELERATION_UNITS_PER_SQ_SECOND {5000,5000,50,5000} // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts + + +// Minimum planner junction speed. Sets the default minimum speed the planner plans for at the end +// of the buffer and all stops. This should not be much greater than zero and should only be changed +// if unwanted behavior is observed on a user's machine when running at very slow speeds. +#define MINIMUM_PLANNER_SPEED 2.0 // (mm/sec) + +#define DEFAULT_MINIMUMFEEDRATE 0.0 // minimum feedrate +#define DEFAULT_MINTRAVELFEEDRATE 0.0 +// If defined the movements slow down when the look ahead buffer is only half full +#define SLOWDOWN + + +const int dropsegments=5; //everything with less than this number of steps will be ignored as move and joined with the next movement + +//----------------------------------------------------------------------- // Machine UUID +//----------------------------------------------------------------------- // This may be useful if you have multiple machines and wish to identify them by using the M115 command. // By default we set it to zeros. -char uuid[] = "00000000-0000-0000-0000-000000000000"; - +#define _DEF_CHAR_UUID "00000000-0000-0000-0000-000000000000" + + + +//----------------------------------------------------------------------- +//// Planner buffer Size +//----------------------------------------------------------------------- + +// The number of linear motions that can be in the plan at any give time +// if the SD Card need to much memory reduce the Values for Plannerpuffer (base of 2) +#ifdef SDSUPPORT + #define BLOCK_BUFFER_SIZE 16 + #define BLOCK_BUFFER_MASK 0x0f +#else + #define BLOCK_BUFFER_SIZE 16 + #define BLOCK_BUFFER_MASK 0x0f +#endif + +//----------------------------------------------------------------------- +//// SETTINGS FOR ARC FUNCTION (Command G2/G2) +//----------------------------------------------------------------------- + +// Arc interpretation settings: +//Step to split a cirrcle in small Lines +#define MM_PER_ARC_SEGMENT 1 +//After this count of steps a new SIN / COS caluclation is startet to correct the circle interpolation +#define N_ARC_CORRECTION 25 + +//----------------------------------------------------------------------- +//// HEATERCONTROL AND PID PARAMETERS +//----------------------------------------------------------------------- + +//Testfunction to adjust the Hotend temperatur in case of Printingspeed +//If the Printer print slow the Temp is going to AUTO_TEMP_MIN +//At the moment this Value dont change the targettemp from the Hotend +//The result of this function is only send with the Temperaturerequest to the host +//#define AUTOTEMP +#ifdef AUTOTEMP + #define AUTO_TEMP_MAX 240 + #define AUTO_TEMP_MIN 205 + #define AUTO_TEMP_FACTOR 0.025 + #define AUTOTEMP_OLDWEIGHT 0.98 +#endif //// AD595 THERMOCOUPLE SUPPORT UNTESTED... USE WITH CAUTION!!!! //// PID settings: // Uncomment the following line to enable PID support. This is untested and could be disastrous. Be careful. -//#define PIDTEMP 1 +#define PIDTEMP 1 #ifdef PIDTEMP +//Sanguinololu 1.2 and above, the PWM Output Hotend Timer 1 is used for the Hardware PWM +//but in this Software use Timer1 for the Stepperfunction so it is not possible to use the "analogWrite" function. +//This Soft PWM use Timer 2 with 400 Hz to drive the PWM for the hotend +#define PID_SOFT_PWM + +//Measure the MIN/MAX Value of the Hotend Temp and show it with +//Command M601 / Command M602 Reset the MIN/MAX Value +//#define DEBUG_HEATER_TEMP + +//PID Controler Settings #define PID_INTEGRAL_DRIVE_MAX 80 // too big, and heater will lag after changing temperature, too small and it might not compensate enough for long-term errors #define PID_PGAIN 2560 //256 is 1.0 // value of X means that error of 1 degree is changing PWM duty by X, probably no need to go over 25 #define PID_IGAIN 64 //256 is 1.0 // value of X (e.g 0.25) means that each degree error over 1 sec (2 measurements) changes duty cycle by 2X (=0.5) units (verify?) #define PID_DGAIN 4096 //256 is 1.0 // value of X means that around reached setpoint, each degree change over one measurement (half second) adjusts PWM by X units to compensate + // magic formula 1, to get approximate "zero error" PWM duty. Take few measurements with low PWM duty and make linear fit to get the formula -#define HEATER_DUTY_FOR_SETPOINT(setpoint) ((int)((187L*(long)setpoint)>>8)-27) // for my makergear hot-end: linear fit {50,10},{60,20},{80,30},{105,50},{176,100},{128,64},{208,128} +// for my makergear hot-end: linear fit {50,10},{60,20},{80,30},{105,50},{176,100},{128,64},{208,128} +#define HEATER_DUTY_FOR_SETPOINT(setpoint) ((int)((187L*(long)setpoint)>>8)-27) // magic formula 2, to make led brightness approximately linear #define LED_PWM_FOR_BRIGHTNESS(brightness) ((64*brightness-1384)/(300-brightness)) #endif @@ -140,12 +280,14 @@ char uuid[] = "00000000-0000-0000-0000-000000000000"; // How often should the heater check for new temp readings, in milliseconds #define HEATER_CHECK_INTERVAL 500 #define BED_CHECK_INTERVAL 5000 + // Comment the following line to enable heat management during acceleration #define DISABLE_CHECK_DURING_ACC #ifndef DISABLE_CHECK_DURING_ACC // Uncomment the following line to disable heat management during moves //#define DISABLE_CHECK_DURING_MOVE #endif + // Uncomment the following line to disable heat management during travel moves (and extruder-only moves, eg: retracts), strongly recommended if you are missing steps mid print. // Probably this should remain commented if are using PID. // It also defines the max milliseconds interval after which a travel move is not considered so for the sake of this feature. @@ -155,6 +297,7 @@ char uuid[] = "00000000-0000-0000-0000-000000000000"; //#define SMOOTHING //#define SMOOTHFACTOR 16 //best to use a power of two here - determines how many values are averaged together by the smoothing algorithm + //// Experimental watchdog and minimal temp // 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 @@ -188,13 +331,21 @@ char uuid[] = "00000000-0000-0000-0000-000000000000"; //#define CONTROLLERFAN_PIN 23 //Pin used for the fan to cool controller, comment out to disable this function #define CONTROLLERFAN_SEC 60 //How many seconds, after all motors were disabled, the fan should run + +//----------------------------------------------------------------------- +// DEBUGING +//----------------------------------------------------------------------- + + +//Uncomment this to see on the host if a wrong or unknown Command is recived +//Only for Testing !!! +//#define SEND_WRONG_CMD_INFO + // Uncomment the following line to enable debugging. You can better control debugging below the following line //#define DEBUG #ifdef DEBUG //#define DEBUG_PREPARE_MOVE //Enable this to debug prepare_move() function - //#define DEBUG_BRESENHAM //Enable this to debug the Bresenham algorithm - //#define DEBUG_RAMP_ACCELERATION //Enable this to debug all constant acceleration info - //#define DEBUG_MOVE_TIME //Enable this to time each move and print the result + //#define DEBUG_MOVE_TIME //Enable this to time each move and print the result //#define DEBUG_HEAT_MGMT //Enable this to debug heat management. WARNING, this will cause axes to jitter! //#define DEBUG_DISABLE_CHECK_DURING_TRAVEL //Debug the namesake feature, see above in this file #endif diff --git a/Sprinter/Makefile b/Sprinter/Makefile index de3223d..6b873bb 100644 --- a/Sprinter/Makefile +++ b/Sprinter/Makefile @@ -55,7 +55,7 @@ $(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)/WString.cpp\ -$(ARDUINO)/Print.cpp ./SdFile.cpp ./SdVolume.cpp ./Sd2Card.cpp +$(ARDUINO)/Print.cpp ./SdFile.cpp ./SdVolume.cpp ./Sd2Card.cpp ./heater.cpp ./arc_func.cpp ./store_eeprom.cpp FORMAT = ihex diff --git a/Sprinter/SdFat.h b/Sprinter/SdFat.h index 048fa71..7a11bba 100644 --- a/Sprinter/SdFat.h +++ b/Sprinter/SdFat.h @@ -283,7 +283,11 @@ class SdFile : public Print { }
/** \return SdVolume that contains this file. */
SdVolume* volume(void) const {return vol_;}
+#if ARDUINO >= 100
+ size_t write(uint8_t b);
+#else
void write(uint8_t b);
+#endif
int16_t write(const void* buf, uint16_t nbyte);
void write(const char* str);
void write_P(PGM_P str);
diff --git a/Sprinter/SdFatUtil.h b/Sprinter/SdFatUtil.h index 8bf9048..de3fee3 100644 --- a/Sprinter/SdFatUtil.h +++ b/Sprinter/SdFatUtil.h @@ -55,7 +55,7 @@ static int FreeRam(void) { * \param[in] str Pointer to string stored in flash memory.
*/
static NOINLINE void SerialPrint_P(PGM_P str) {
- for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.print(c);
+ for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.print(char(c));
}
//------------------------------------------------------------------------------
/**
diff --git a/Sprinter/SdFile.cpp b/Sprinter/SdFile.cpp index 0a27159..13f4c6a 100644 --- a/Sprinter/SdFile.cpp +++ b/Sprinter/SdFile.cpp @@ -213,7 +213,7 @@ void SdFile::ls(uint8_t flags, uint8_t indent) { if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; // print any indent spaces - for (int8_t i = 0; i < indent; i++) Serial.print(' '); + for (int8_t i = 0; i < indent; i++) Serial.print(char(' ')); // print file name with possible blank fill printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0); @@ -221,12 +221,12 @@ void SdFile::ls(uint8_t flags, uint8_t indent) { // print modify date/time if requested if (flags & LS_DATE) { printFatDate(p->lastWriteDate); - Serial.print(' '); + Serial.print(char(' ')); printFatTime(p->lastWriteTime); } // print size if requested if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) { - Serial.print(' '); + Serial.print(char(' ')); Serial.print(p->fileSize); } Serial.println(); @@ -587,18 +587,18 @@ void SdFile::printDirName(const dir_t& dir, uint8_t width) { for (uint8_t i = 0; i < 11; i++) { if (dir.name[i] == ' ')continue; if (i == 8) { - Serial.print('.'); + Serial.print(char('.')); w++; } - Serial.print(dir.name[i]); + Serial.print(char(dir.name[i])); w++; } if (DIR_IS_SUBDIR(&dir)) { - Serial.print('/'); + Serial.print(char('/')); w++; } while (w < width) { - Serial.print(' '); + Serial.print(char(' ')); w++; } } @@ -611,9 +611,9 @@ void SdFile::printDirName(const dir_t& dir, uint8_t width) { */ void SdFile::printFatDate(uint16_t fatDate) { Serial.print(FAT_YEAR(fatDate)); - Serial.print('-'); + Serial.print(char('-')); printTwoDigits(FAT_MONTH(fatDate)); - Serial.print('-'); + Serial.print(char('-')); printTwoDigits(FAT_DAY(fatDate)); } //------------------------------------------------------------------------------ @@ -625,9 +625,9 @@ void SdFile::printFatDate(uint16_t fatDate) { */ void SdFile::printFatTime(uint16_t fatTime) { printTwoDigits(FAT_HOUR(fatTime)); - Serial.print(':'); + Serial.print(char(':')); printTwoDigits(FAT_MINUTE(fatTime)); - Serial.print(':'); + Serial.print(char(':')); printTwoDigits(FAT_SECOND(fatTime)); } //------------------------------------------------------------------------------ @@ -1219,8 +1219,17 @@ int16_t SdFile::write(const void* buf, uint16_t nbyte) { * * Use SdFile::writeError to check for errors. */ -void SdFile::write(uint8_t b) { +#if ARDUINO >= 100 +size_t SdFile::write(uint8_t b) +#else +void SdFile::write(uint8_t b) +#endif +{ +#if ARDUINO >= 100 + return (size_t) write(&b, 1); +#else write(&b, 1); +#endif } //------------------------------------------------------------------------------ /** diff --git a/Sprinter/Sprinter.h b/Sprinter/Sprinter.h index 2ac9163..9873843 100644 --- a/Sprinter/Sprinter.h +++ b/Sprinter/Sprinter.h @@ -1,53 +1,18 @@ // Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. // Licence: GPL -#include <WProgram.h> -#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 setup_acceleration(); - -void manage_heater(); - -#if defined HEATER_USES_THERMISTOR -#define temp2analogh( c ) temp2analog_thermistor(c,temptable,NUMTEMPS) -#define analog2temp( c ) analog2temp_thermistor(c,temptable,NUMTEMPS) -#elif defined HEATER_USES_AD595 -#define temp2analogh( c ) temp2analog_ad595(c) -#define analog2temp( c ) analog2temp_ad595(c) -#elif defined HEATER_USES_MAX6675 -#define temp2analogh( c ) temp2analog_max6675(c) -#define analog2temp( c ) analog2temp_max6675(c) -#endif -#if defined BED_USES_THERMISTOR -#define temp2analogBed( c ) temp2analog_thermistor((c),bedtemptable,BNUMTEMPS) -#define analog2tempBed( c ) analog2temp_thermistor((c),bedtemptable,BNUMTEMPS) -#elif defined BED_USES_AD595 -#define temp2analogBed( c ) temp2analog_ad595(c) -#define analog2tempBed( c ) analog2temp_ad595(c) -#elif defined BED_USES_MAX6675 -#define temp2analogBed( c ) temp2analog_max6675(c) -#define analog2tempBed( c ) analog2temp_max6675(c) +//Check Version of Arduino and then include the right libraries +#if defined(ARDUINO) && ARDUINO >= 100 + #include "Arduino.h" +#else + #include <WProgram.h> #endif -#if defined (HEATER_USES_THERMISTOR) || defined (BED_USES_THERMISTOR) -int temp2analog_thermistor(int celsius, const short table[][2], int numtemps); -int analog2temp_thermistor(int raw,const short table[][2], int numtemps); -#endif +#include "fastio.h" -#if defined (HEATER_USES_AD595) || defined (BED_USES_AD595) -int temp2analog_ad595(int celsius); -int analog2temp_ad595(int raw); -#endif +extern "C" void __cxa_pure_virtual(); -#if defined (HEATER_USES_MAX6675) || defined (BED_USES_MAX6675) -int temp2analog_max6675(int celsius); -int analog2temp_max6675(int raw); -#endif +#define FORCE_INLINE __attribute__((always_inline)) inline #if X_ENABLE_PIN > -1 #define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) @@ -78,12 +43,91 @@ int analog2temp_max6675(int raw); #define disable_e() ; #endif +#define X_AXIS 0 +#define Y_AXIS 1 +#define Z_AXIS 2 +#define E_AXIS 3 + + +// 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 + + unsigned long step_event_count; // The number of step events required to complete this block + long accelerate_until; // The index of the step event on which to stop acceleration + long decelerate_after; // The index of the step event on which to start decelerating + 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) + + #ifdef ADVANCE + long advance_rate; + volatile long initial_advance; + volatile long final_advance; + float advance; + #endif + + // 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 entry_speed; // Entry speed at previous-current junction in mm/min + float max_entry_speed; // Maximum allowable junction entry speed in mm/min + float millimeters; // The total travel of this block in mm + float acceleration; // acceleration mm/sec^2 + unsigned char recalculate_flag; // Planner flag to recalculate trapezoids on entry junction + unsigned char nominal_length_flag; // Planner flag for nominal speed always reached + + + // Settings for the trapezoid generator + long nominal_rate; // The nominal step rate for this block in step_events/sec + long initial_rate; // The jerk-adjusted step rate at start of block + long final_rate; // The minimal rate at exit + long acceleration_st; // acceleration steps/sec^2 + volatile char busy; +} block_t; + + void FlushSerialRequestResend(); void ClearToSend(); +void showString (PGM_P s); + +void manage_inactivity(byte debug); + +void get_command(); void get_coordinates(); void prepare_move(); -void linear_move(unsigned long steps_remaining[]); -void do_step(int axis); +void prepare_arc_move(char isclockwise); +FORCE_INLINE void process_commands(); +#ifdef USE_ARC_FUNCTION + FORCE_INLINE void get_arc_coordinates(); +#endif + 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 st_set_position(const long &x, const long &y, const long &z, const long &e); + +void check_buffer_while_arc(); + +#ifdef SDSUPPORT +void print_disk_info(void); +#endif //SDSUPPORT + +#ifdef DEBUG +void log_message(char* message); +void log_bool(char* message, bool value); +void log_int(char* message, int value); +void log_long(char* message, long value); +void log_float(char* message, float value); +void log_uint(char* message, unsigned int value); +void log_ulong(char* message, unsigned long value); +#endif diff --git a/Sprinter/Sprinter.pde b/Sprinter/Sprinter.pde index c35258a..706910f 100644 --- a/Sprinter/Sprinter.pde +++ b/Sprinter/Sprinter.pde @@ -1,15 +1,134 @@ - // Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. -// Licence: GPL +/* + Reprap firmware based on Sprinter + Optimize for Sanguinololu 1.2 and above, RAMPS + + 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 <http://www.gnu.org/licenses/>. */ + +/* + This firmware is a mashup between Sprinter,grbl and parts from marlin. + (https://github.com/kliment/Sprinter) + + Changes by Doppler Michael (midopple) + + Planner is from Simen Svale Skogsrud + https://github.com/simen/grbl + + Parts of Marlin Firmware from ErikZalm + https://github.com/ErikZalm/Marlin-non-gen6 + + Sprinter Changelog + - Look forward function --> calculate 16 Steps forward, get from Firmaware Marlin and Grbl + - Stepper control with Timer 1 (Interrupt) + - Extruder heating with PID use a Softpwm (Timer 2) with 500 hz to free Timer1 für Steppercontrol + - command M220 Sxxx --> tune Printing speed online (+/- 50 %) + - G2 / G3 command --> circle funktion + - Baudrate set to 250 kbaud + - Testet on Sanguinololu Board + - M30 Command can delete files on SD Card + - move string to flash to free RAM vor forward planner + - M203 Temperature monitor for Repetier + + Version 1.3.04T + - Implement Plannercode from Marlin V1 big thanks to Erik + - Stepper interrupt with Step loops + - Stepperfrequenz 30 Khz + - New Command + * M202 - 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 + * M205 - advanced settings: minimum travel speed S=while printing T=travel only, X= maximum xy jerk, Z=maximum Z jerk + - Remove unused Variables + - Check Uart Puffer while circle processing (CMD: G2 / G3) + - Fast Xfer Function --> move Text to Flash + - Option to deaktivate ARC (G2/G3) function (save flash) + - Removed modulo (%) operator, which uses an expensive divide + + Version 1.3.05T + - changed homing function to not conflict with min_software_endstops/max_software_endstops (thanks rGlory) + - Changed check in arc_func + - Corrected distance calculation. (thanks jv4779) + - MAX Feed Rate for Z-Axis reduced to 2 mm/s some Printers had problems with 4 mm/s + + Version 1.3.06T + - the microcontroller can store settings in the EEPROM + - M500 - stores paramters in EEPROM + - M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily). + - M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to. + - M503 - Print settings + + Version 1.3.07T + - Optimize Variable Size (faster Code) + - Remove unused Code from Interrupt --> faster ~ 22 us per step + - Replace abs with fabs --> Faster and smaler + - Add "store_eeprom.cpp" to makefile + + Version 1.3.08T + - If a line starts with ';', it is ignored but comment_mode is reset. + A ';' inside a line ignores just the portion following the ';' character. + The beginning of the line is still interpreted. + + - Same fix for SD Card, testet and work + + Version 1.3.09T + - Move SLOWDOWN Function up + + Version 1.3.10T +- Add info to GEN7 Pins +- Update pins.h for gen7, working setup for 20MHz +- calculate feedrate without extrude before planner block is set +- New Board --> GEN7 @ 20 Mhz … +- ENDSTOPS_ONLY_FOR_HOMING Option ignore Endstop always --> fault is cleared + + Version 1.3.11T +- fix for broken include in store_eeprom.cpp --> Thanks to kmeehl (issue #145) +- Make fastio & Arduino pin numbering consistent for AT90USB128x. --> Thanks to lincomatic +- Select Speedtable with F_CPU +- Use same Values for Speedtables as Marlin +- + + + +*/ + +#include <avr/pgmspace.h> +#include <math.h> #include "fastio.h" #include "Configuration.h" #include "pins.h" #include "Sprinter.h" +#include "speed_lookuptable.h" +#include "heater.h" + +#ifdef USE_ARC_FUNCTION + #include "arc_func.h" +#endif #ifdef SDSUPPORT -#include "SdFat.h" + #include "SdFat.h" +#endif + +#ifdef USE_EEPROM_SETTINGS + #include "store_eeprom.h" #endif +#ifndef CRITICAL_SECTION_START +#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() +#define CRITICAL_SECTION_END SREG = _sreg +#endif //CRITICAL_SECTION_START + +void __cxa_pure_virtual(){}; + // look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html // http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes @@ -17,6 +136,8 @@ //------------------- // G0 -> G1 // G1 - Coordinated Movement X Y Z E +// G2 - CW ARC +// G3 - CCW ARC // G4 - Dwell S<seconds> or P<milliseconds> // G28 - Home all Axis // G90 - Use Absolute Coordinates @@ -32,7 +153,6 @@ // M114 - Display current position //Custom M Codes -// M80 - Turn on Power Supply // M20 - List SD card // M21 - Init SD card // M22 - Release SD card @@ -43,7 +163,9 @@ // M27 - Report SD print status // M28 - Start SD write (M28 filename.g) // M29 - Stop SD write -// M42 - Set output on free pins, on a non pwm pin (over pin 13 on an arduino mega) use S255 to turn it on and S0 to turn it off. Use P to decide the pin (M42 P23 S255) would turn pin 23 on +// - <filename> - Delete file on sd card +// M42 - Set output on free pins, on a non pwm pin (over pin 13 on an arduino mega) use S255 to turn it on and S0 to turn it off. Use P to decide the pin (M42 P23 S255) would turn pin 23 on +// M80 - Turn on Power Supply // M81 - Turn off Power Supply // M82 - Set E codes absolute (default) // M83 - Set E codes relative while in Absolute Coordinates (G90) mode @@ -52,105 +174,142 @@ // M85 - Set inactivity shutdown timer with parameter S<seconds>. To disable set zero (default) // M92 - Set axis_steps_per_unit - same syntax as G92 // M115 - Capabilities string +// M119 - Show Endstopper State // 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) +// M201 - Set maximum acceleration in units/s^2 for print moves (M201 X1000 Y1000) +// M202 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec +// M203 - Set temperture monitor to Sx +// M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 +// M205 - advanced settings: minimum travel speed S=while printing T=travel only, X= maximum xy jerk, Z=maximum Z jerk +// M220 - set speed factor override percentage S:factor in percent -//Stepper Movement Variables +// M500 - stores paramters in EEPROM +// M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily). +// M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to. +// M503 - Print settings + +// Debug feature / Testing the PID for Hotend +// M601 - Show Temp jitter from Extruder (min / max value from Hotend Temperatur while printing) +// M602 - Reset Temp jitter from Extruder (min / max val) --> Dont use it while Printing +// M603 - Show Free Ram + +#define _VERSION_TEXT "1.3.11T / 19.03.2012" + +//Stepper Movement Variables char axis_codes[NUM_AXIS] = {'X', 'Y', 'Z', 'E'}; -bool move_direction[NUM_AXIS]; -unsigned long axis_previous_micros[NUM_AXIS]; -unsigned long previous_micros = 0, previous_millis_heater, previous_millis_bed_heater; -unsigned long move_steps_to_take[NUM_AXIS]; -#ifdef RAMP_ACCELERATION -unsigned long axis_max_interval[NUM_AXIS]; +float axis_steps_per_unit[4] = _AXIS_STEP_PER_UNIT; + +float max_feedrate[4] = _MAX_FEEDRATE; +float homing_feedrate[] = _HOMING_FEEDRATE; +bool axis_relative_modes[] = _AXIS_RELATIVE_MODES; + +float move_acceleration = _ACCELERATION; // Normal acceleration mm/s^2 +float retract_acceleration = _RETRACT_ACCELERATION; // Normal acceleration mm/s^2 +float max_xy_jerk = _MAX_XY_JERK; +float max_z_jerk = _MAX_Z_JERK; + +long max_acceleration_units_per_sq_second[4] = _MAX_ACCELERATION_UNITS_PER_SQ_SECOND; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts + +//float max_start_speed_units_per_second[] = _MAX_START_SPEED_UNITS_PER_SECOND; +//long max_travel_acceleration_units_per_sq_second[] = _MAX_TRAVEL_ACCELERATION_UNITS_PER_SQ_SECOND; // X, Y, Z max acceleration in mm/s^2 for travel moves + +float mintravelfeedrate = DEFAULT_MINTRAVELFEEDRATE; +float minimumfeedrate = DEFAULT_MINIMUMFEEDRATE; + unsigned long axis_steps_per_sqr_second[NUM_AXIS]; -unsigned long axis_travel_steps_per_sqr_second[NUM_AXIS]; -unsigned long max_interval; -unsigned long steps_per_sqr_second, plateau_steps; -#endif -boolean acceleration_enabled = false, accelerating = false; -unsigned long interval; +unsigned long plateau_steps; + +//unsigned long axis_max_interval[NUM_AXIS]; +//unsigned long axis_travel_steps_per_sqr_second[NUM_AXIS]; +//unsigned long max_interval; +//unsigned long steps_per_sqr_second; + + +//adjustable feed faktor for online tuning printerspeed +volatile int feedmultiply=100; //100->original / 200-> Faktor 2 / 50 -> Faktor 0.5 +int saved_feedmultiply; +volatile bool feedmultiplychanged=false; + +//boolean acceleration_enabled = false, accelerating = false; +//unsigned long interval; 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}; -unsigned long steps_taken[NUM_AXIS]; -long axis_interval[NUM_AXIS]; // for speed delay + + bool home_all_axis = true; +//unsigned ?? ToDo: Check int feedrate = 1500, next_feedrate, saved_feedrate; -float time_for_move; + 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. -long timediff = 0; + +//unsigned long steps_taken[NUM_AXIS]; +//long axis_interval[NUM_AXIS]; // for speed delay +//float time_for_move; +//bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. +//long timediff = 0; + //experimental feedrate calc -float d = 0; -float axis_diff[NUM_AXIS] = {0, 0, 0, 0}; +//float d = 0; +//float axis_diff[NUM_AXIS] = {0, 0, 0, 0}; + + +#ifdef USE_ARC_FUNCTION +//For arc centerpont, send bei Command G2/G3 +float offset[3] = {0.0, 0.0, 0.0}; +#endif + #ifdef STEP_DELAY_RATIO long long_step_delay_ratio = STEP_DELAY_RATIO * 100; #endif +///oscillation reduction +#ifdef RAPID_OSCILLATION_REDUCTION + float cumm_wait_time_in_dir[NUM_AXIS]={0.0,0.0,0.0,0.0}; + bool prev_move_direction[NUM_AXIS]={1,1,1,1}; + float osc_wait_remainder = 0.0; +#endif -// comm variables +// comm variables and Commandbuffer +// BUFSIZE is reduced from 8 to 6 to free more RAM for the PLANNER #define MAX_CMD_SIZE 96 -#define BUFSIZE 8 +#define BUFSIZE 6 //8 char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; bool fromsd[BUFSIZE]; -int bufindr = 0; -int bufindw = 0; -int buflen = 0; -int i = 0; + +//Need 1kb Ram --> only work with Atmega1284 +#ifdef SD_FAST_XFER_AKTIV + char fastxferbuffer[SD_FAST_XFER_CHUNK_SIZE + 1]; + int lastxferchar; + long xferbytes; +#endif + +unsigned char bufindr = 0; +unsigned char bufindw = 0; +unsigned char buflen = 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. For a thermistor or AD595 thermocouple, raw values refer to the -// reading from the analog pin. For a MAX6675 thermocouple, the raw value is the temperature in 0.25 -// degree increments (i.e. 100=25 deg). - -int target_raw = 0; -int target_temp = 0; -int current_raw = 0; -int target_bed_raw = 0; -int current_bed_raw = 0; -int tt = 0, bt = 0; -#ifdef PIDTEMP - int temp_iState = 0; - int prev_temp = 0; - int pTerm; - int iTerm; - int dTerm; - //int output; - int error; - int heater_duty = 0; - const int temp_iState_min = 256L * -PID_INTEGRAL_DRIVE_MAX / PID_IGAIN; - const int temp_iState_max = 256L * PID_INTEGRAL_DRIVE_MAX / PID_IGAIN; -#endif -#ifndef HEATER_CURRENT - #define HEATER_CURRENT 255 -#endif -#ifdef SMOOTHING - uint32_t nma = 0; -#endif -#ifdef WATCHPERIOD - int watch_raw = -1000; - unsigned long watchmillis = 0; -#endif -#ifdef MINTEMP - int minttemp = temp2analogh(MINTEMP); -#endif -#ifdef MAXTEMP -int maxttemp = temp2analogh(MAXTEMP); -#endif - +//Send Temperature in °C to Host +int hotendtC = 0, bedtempC = 0; + //Inactivity shutdown variables unsigned long previous_millis_cmd = 0; unsigned long max_inactive_time = 0; unsigned long stepper_inactive_time = 0; +//Temp Montor for repetier +unsigned char manage_monitor = 255; + + +//------------------------------------------------ +//Init the SD card +//------------------------------------------------ #ifdef SDSUPPORT Sd2Card card; SdVolume volume; @@ -161,23 +320,27 @@ unsigned long stepper_inactive_time = 0; bool sdmode = false; bool sdactive = false; bool savetosd = false; - int16_t n; + int16_t read_char_int; - void initsd(){ + 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"); + showString(PSTR("SD init fail\r\n")); } else if (!volume.init(&card)) - Serial.println("volume.init failed"); + showString(PSTR("volume.init failed\r\n")); else if (!root.openRoot(&volume)) - Serial.println("openRoot failed"); + showString(PSTR("openRoot failed\r\n")); else{ sdactive = true; + print_disk_info(); + #ifdef SDINITFILE file.close(); if(file.open(&root, "init.g", O_READ)){ @@ -187,38 +350,237 @@ unsigned long stepper_inactive_time = 0; } #endif } + + #endif + } + + #ifdef SD_FAST_XFER_AKTIV + + #ifdef PIDTEMP + extern int g_heater_pwm_val; #endif + + void fast_xfer() + { + char *pstr; + boolean done = false; + + //force heater pins low + if(HEATER_0_PIN > -1) WRITE(HEATER_0_PIN,LOW); + if(HEATER_1_PIN > -1) WRITE(HEATER_1_PIN,LOW); + + g_heater_pwm_val = 0; + + lastxferchar = 1; + xferbytes = 0; + + pstr = strstr(strchr_pointer+4, " "); + + if(pstr == NULL) + { + showString(PSTR("invalid command\r\n")); + return; + } + + *pstr = '\0'; + + //check mode (currently only RAW is supported + if(strcmp(strchr_pointer+4, "RAW") != 0) + { + showString(PSTR("Invalid transfer codec\r\n")); + return; + }else{ + showString(PSTR("Selected codec: ")); + Serial.println(strchr_pointer+4); + } + + if (!file.open(&root, pstr+1, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) + { + showString(PSTR("open failed, File: ")); + Serial.print(pstr+1); + showString(PSTR(".")); + }else{ + showString(PSTR("Writing to file: ")); + Serial.println(pstr+1); + } + + showString(PSTR("ok\r\n")); + + //RAW transfer codec + //Host sends \0 then up to SD_FAST_XFER_CHUNK_SIZE then \0 + //when host is done, it sends \0\0. + //if a non \0 character is recieved at the beginning, host has failed somehow, kill the transfer. + + //read SD_FAST_XFER_CHUNK_SIZE bytes (or until \0 is recieved) + while(!done) + { + while(!Serial.available()) + { + } + if(Serial.read() != 0) + { + //host has failed, this isn't a RAW chunk, it's an actual command + file.sync(); + file.close(); + return; + } + + for(int i=0;i<SD_FAST_XFER_CHUNK_SIZE+1;i++) + { + while(!Serial.available()) + { + } + lastxferchar = Serial.read(); + //buffer the data... + fastxferbuffer[i] = lastxferchar; + + xferbytes++; + + if(lastxferchar == 0) + break; + } + + if(fastxferbuffer[0] != 0) + { + fastxferbuffer[SD_FAST_XFER_CHUNK_SIZE] = 0; + file.write(fastxferbuffer); + showString(PSTR("ok\r\n")); + }else{ + showString(PSTR("Wrote ")); + Serial.print(xferbytes); + showString(PSTR(" bytes.\r\n")); + done = true; + } + } + + file.sync(); + file.close(); } + #endif + + + void print_disk_info(void) + { + + // print the type of card + showString(PSTR("\nCard type: ")); + switch(card.type()) + { + case SD_CARD_TYPE_SD1: + showString(PSTR("SD1\r\n")); + break; + case SD_CARD_TYPE_SD2: + showString(PSTR("SD2\r\n")); + break; + case SD_CARD_TYPE_SDHC: + showString(PSTR("SDHC\r\n")); + break; + default: + showString(PSTR("Unknown\r\n")); + } - inline void write_command(char *buf){ + //uint64_t freeSpace = volume.clusterCount()*volume.blocksPerCluster()*512; + //uint64_t occupiedSpace = (card.cardSize()*512) - freeSpace; + // print the type and size of the first FAT-type volume + uint32_t volumesize; + showString(PSTR("\nVolume type is FAT")); + Serial.println(volume.fatType(), DEC); + + volumesize = volume.blocksPerCluster(); // clusters are collections of blocks + volumesize *= volume.clusterCount(); // we'll have a lot of clusters + volumesize *= 512; // SD card blocks are always 512 bytes + volumesize /= 1024; //kbytes + volumesize /= 1024; //Mbytes + showString(PSTR("Volume size (Mbytes): ")); + Serial.println(volumesize); + + // list all files in the card with date and size + //root.ls(LS_R | LS_DATE | LS_SIZE); + } + + + + + + FORCE_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){ + + 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"); + + if (file.writeError) + { + showString(PSTR("error writing to file\r\n")); } } + #endif +int FreeRam1(void) +{ + extern int __bss_end; + extern int* __brkval; + int free_memory; + + if (reinterpret_cast<int>(__brkval) == 0) + { + // if no heap use from end of bss section + free_memory = reinterpret_cast<int>(&free_memory) - reinterpret_cast<int>(&__bss_end); + } + else + { + // use from top of stack to heap + free_memory = reinterpret_cast<int>(&free_memory) - reinterpret_cast<int>(__brkval); + } + + return free_memory; +} + +//------------------------------------------------ +//Print a String from Flash to Serial (save RAM) +//------------------------------------------------ +void showString (PGM_P s) +{ + char c; + + while ((c = pgm_read_byte(s++)) != 0) + Serial.print(c); +} + + +//------------------------------------------------ +// Init +//------------------------------------------------ void setup() { + Serial.begin(BAUDRATE); - Serial.println("start"); - for(int i = 0; i < BUFSIZE; i++){ + showString(PSTR("Sprinter\r\n")); + showString(PSTR(_VERSION_TEXT)); + showString(PSTR("\r\n")); + showString(PSTR("start\r\n")); + + for(int i = 0; i < BUFSIZE; i++) + { fromsd[i] = false; } + //Initialize Dir Pins @@ -253,7 +615,7 @@ void setup() SET_OUTPUT(E_ENABLE_PIN); if(!E_ENABLE_ON) WRITE(E_ENABLE_PIN,HIGH); #endif - + #ifdef CONTROLLERFAN_PIN SET_OUTPUT(CONTROLLERFAN_PIN); //Set pin used for driver cooling fan #endif @@ -329,7 +691,7 @@ void setup() #if (LED_PIN > -1) SET_OUTPUT(LED_PIN); WRITE(LED_PIN,LOW); - #endif + #endif //Initialize Step Pins #if (X_STEP_PIN > -1) @@ -344,9 +706,17 @@ void setup() #if (E_STEP_PIN > -1) SET_OUTPUT(E_STEP_PIN); #endif - #ifdef RAMP_ACCELERATION - setup_acceleration(); - #endif + + for(int8_t i=0; i < NUM_AXIS; i++) + { + axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; + } + +// for(int i=0; i < NUM_AXIS; i++){ +// axis_max_interval[i] = 100000000.0 / (max_start_speed_units_per_second[i] * axis_steps_per_unit[i]); +// axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; +// axis_travel_steps_per_sqr_second[i] = max_travel_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; +// } #ifdef HEATER_USES_MAX6675 SET_OUTPUT(SCK_PIN); @@ -369,48 +739,107 @@ void setup() SET_OUTPUT(SDPOWER); WRITE(SDPOWER,HIGH); #endif + + showString(PSTR("SD Start\r\n")); initsd(); #endif + #ifdef PID_SOFT_PWM + showString(PSTR("Soft PWM Init\r\n")); + init_Timer2_softpwm(); + #endif + + showString(PSTR("Planner Init\r\n")); + plan_init(); // Initialize planner; + + showString(PSTR("Stepper Timer init\r\n")); + st_init(); // Initialize stepper + + #ifdef USE_EEPROM_SETTINGS + //first Value --> Init with default + //second value --> Print settings to UART + EEPROM_RetrieveSettings(false,false); + #endif + + //Free Ram + showString(PSTR("Free Ram: ")); + Serial.println(FreeRam1()); + + //Planner Buffer Size + showString(PSTR("Plan Buffer Size:")); + Serial.print((int)sizeof(block_t)*BLOCK_BUFFER_SIZE); + showString(PSTR(" / ")); + Serial.println(BLOCK_BUFFER_SIZE); } + +//------------------------------------------------ +//MAIN LOOP +//------------------------------------------------ void loop() { - if(buflen<3) - get_command(); + if(buflen < (BUFSIZE-1)) + get_command(); - if(buflen){ + if(buflen) + { #ifdef SDSUPPORT - if(savetosd){ - if(strstr(cmdbuffer[bufindr],"M29") == NULL){ + if(savetosd) + { + if(strstr(cmdbuffer[bufindr],"M29") == NULL) + { write_command(cmdbuffer[bufindr]); - Serial.println("ok"); - }else{ + showString(PSTR("ok\r\n")); + } + else + { file.sync(); file.close(); savetosd = false; - Serial.println("Done saving file."); + showString(PSTR("Done saving file.\r\n")); } - }else{ + } + else + { process_commands(); } #else process_commands(); #endif + buflen = (buflen-1); - bufindr = (bufindr + 1)%BUFSIZE; - } - //check heater every n milliseconds - manage_heater(); - manage_inactivity(1); + //bufindr = (bufindr + 1)%BUFSIZE; + //Removed modulo (%) operator, which uses an expensive divide and multiplication + bufindr++; + if(bufindr == BUFSIZE) bufindr = 0; } + + //check heater every n milliseconds + manage_heater(); + manage_inactivity(1); +} + +//------------------------------------------------ +//Check Uart buffer while arc function ist calc a circle +//------------------------------------------------ +void check_buffer_while_arc() +{ + if(buflen < (BUFSIZE-1)) + { + get_command(); + } +} -inline void get_command() +//------------------------------------------------ +//READ COMMAND FROM UART +//------------------------------------------------ +void get_command() { - while( Serial.available() > 0 && buflen < BUFSIZE) { + 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) ) { @@ -419,77 +848,91 @@ inline void get_command() return; } cmdbuffer[bufindw][serial_count] = 0; //terminate string - 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; - } + + 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) ) + { + showString(PSTR("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; - } + 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) + { + showString(PSTR("Error: checksum mismatch, Last Line:")); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + //if no errors, continue parsing + } + else + { + showString(PSTR("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: + gcode_LastN = gcode_N; + //if no errors, continue parsing + } + else // if we don't receive 'N' but still see '*' + { + if((strstr(cmdbuffer[bufindw], "*") != NULL)) + { + showString(PSTR("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 USE_ARC_FUNCTION + case 2: //G2 + case 3: //G3 arc func + #endif #ifdef SDSUPPORT if(savetosd) break; #endif - Serial.println("ok"); - break; - default: - break; - } - - } - bufindw = (bufindw + 1)%BUFSIZE; + showString(PSTR("ok\r\n")); + //Serial.println("ok"); + break; + + default: + break; + } + } + //Removed modulo (%) operator, which uses an expensive divide and multiplication + //bufindw = (bufindw + 1)%BUFSIZE; + bufindw++; + if(bufindw == BUFSIZE) bufindw = 0; buflen += 1; - + comment_mode = false; //for new command serial_count = 0; //clear buffer } @@ -500,51 +943,66 @@ inline void get_command() } } #ifdef SDSUPPORT -if(!sdmode || serial_count!=0){ + 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) + } + while( filesize > sdpos && buflen < BUFSIZE) + { + serial_char = file.read(); + read_char_int = (int)serial_char; + + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || read_char_int == -1) { sdpos = file.curPosition(); - if(sdpos >= filesize){ + if(sdpos >= filesize) + { sdmode = false; - Serial.println("Done printing file"); + showString(PSTR("Done printing file\r\n")); } - 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 + + if(!serial_count) { //if empty line + comment_mode = false; // for new command + return; + } + + cmdbuffer[bufindw][serial_count] = 0; //terminate string + + fromsd[bufindw] = true; + buflen += 1; + //Removed modulo (%) operator, which uses an expensive divide and multiplication + //bufindw = (bufindw + 1)%BUFSIZE; + bufindw++; + if(bufindw == BUFSIZE) bufindw = 0; + + 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 } -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 +FORCE_INLINE float code_value() { return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); } +FORCE_INLINE long code_value_long() { return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); } +FORCE_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) +FORCE_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() +//------------------------------------------------ +// CHECK COMMAND AND CONVERT VALUES +//------------------------------------------------ +FORCE_INLINE void process_commands() { unsigned long codenum; //throw away variable char *starpos = NULL; @@ -564,6 +1022,20 @@ inline void process_commands() //ClearToSend(); return; //break; + #ifdef USE_ARC_FUNCTION + case 2: // G2 - CW ARC + get_arc_coordinates(); + prepare_arc_move(true); + previous_millis_cmd = millis(); + //break; + return; + case 3: // G3 - CCW ARC + get_arc_coordinates(); + prepare_arc_move(false); + previous_millis_cmd = millis(); + //break; + return; + #endif case 4: // G4 dwell codenum = 0; if(code_seen('P')) codenum = code_value(); // milliseconds to wait @@ -575,79 +1047,126 @@ inline void process_commands() break; case 28: //G28 Home all Axis one at a time saved_feedrate = feedrate; - for(int i=0; i < NUM_AXIS; i++) { + saved_feedmultiply = feedmultiply; + previous_millis_cmd = millis(); + + feedmultiply = 100; + + enable_endstops(true); + + 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[0]))) { - if ((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)){ - current_position[0] = -1.5 * X_MAX_LENGTH * X_HOME_DIR; - destination[0] = 0; - feedrate = homing_feedrate[0]; + 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] = -1.5 * X_MAX_LENGTH * X_HOME_DIR; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = 0; + feedrate = homing_feedrate[X_AXIS]; prepare_move(); - - current_position[0] = 5 * X_HOME_DIR; - destination[0] = 0; + + st_synchronize(); + current_position[X_AXIS] = 5 * X_HOME_DIR; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = 0; prepare_move(); - - current_position[0] = -10 * X_HOME_DIR; - destination[0] = 0; + + st_synchronize(); + current_position[X_AXIS] = -10 * X_HOME_DIR; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[X_AXIS] = 0; + feedrate = homing_feedrate[X_AXIS]/2 ; prepare_move(); - - current_position[0] = (X_HOME_DIR == -1) ? 0 : X_MAX_LENGTH; - destination[0] = current_position[0]; + 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[1]))) { - if ((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)){ - current_position[1] = -1.5 * Y_MAX_LENGTH * Y_HOME_DIR; - destination[1] = 0; + //showString(PSTR("HOME X AXIS\r\n")); - feedrate = homing_feedrate[1]; + 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] = -1.5 * Y_MAX_LENGTH * Y_HOME_DIR; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = 0; + feedrate = homing_feedrate[Y_AXIS]; prepare_move(); - - current_position[1] = 5 * Y_HOME_DIR; - destination[1] = 0; + st_synchronize(); + + current_position[Y_AXIS] = 5 * Y_HOME_DIR; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = 0; prepare_move(); - - current_position[1] = -10 * Y_HOME_DIR; - destination[1] = 0; + st_synchronize(); + + current_position[Y_AXIS] = -10 * Y_HOME_DIR; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Y_AXIS] = 0; + feedrate = homing_feedrate[Y_AXIS]/2; prepare_move(); - - current_position[1] = (Y_HOME_DIR == -1) ? 0 : Y_MAX_LENGTH; - destination[1] = current_position[1]; + 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[2]))) { - if ((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)){ - current_position[2] = -1.5 * Z_MAX_LENGTH * Z_HOME_DIR; - destination[2] = 0; - feedrate = homing_feedrate[2]; + //showString(PSTR("HOME Y AXIS\r\n")); + + 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] = -1.5 * Z_MAX_LENGTH * Z_HOME_DIR; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = 0; + feedrate = homing_feedrate[Z_AXIS]; prepare_move(); - - current_position[2] = 2 * Z_HOME_DIR; - destination[2] = 0; + st_synchronize(); + + current_position[Z_AXIS] = 2 * Z_HOME_DIR; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = 0; prepare_move(); - - current_position[2] = -5 * Z_HOME_DIR; - destination[2] = 0; + st_synchronize(); + + current_position[Z_AXIS] = -3 * Z_HOME_DIR; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = 0; + feedrate = homing_feedrate[Z_AXIS]/2; prepare_move(); - - current_position[2] = (Z_HOME_DIR == -1) ? 0 : Z_MAX_LENGTH; - destination[2] = current_position[2]; - feedrate = 0; - - } - } + 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; + } + } + + //showString(PSTR("HOME Z AXIS\r\n")); + #ifdef ENDSTOPS_ONLY_FOR_HOMING + enable_endstops(false); + #endif + feedrate = saved_feedrate; + feedmultiply = saved_feedmultiply; + previous_millis_cmd = millis(); break; case 90: // G90 @@ -657,11 +1176,21 @@ inline void process_commands() relative_mode = true; break; case 92: // G92 - for(int i=0; i < NUM_AXIS; i++) { + 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; - + default: + #ifdef SEND_WRONG_CMD_INFO + showString(PSTR("Unknown G-COM:")); + Serial.println(cmdbuffer[bufindr]); + #endif + break; } } @@ -673,9 +1202,9 @@ inline void process_commands() #ifdef SDSUPPORT case 20: // M20 - list SD card - Serial.println("Begin file list"); + showString(PSTR("Begin file list\r\n")); root.ls(); - Serial.println("End file list"); + showString(PSTR("End file list\r\n")); break; case 21: // M21 - init SD card sdmode = false; @@ -686,72 +1215,88 @@ inline void process_commands() sdactive = false; break; case 23: //M23 - Select file - if(sdactive){ + 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:"); + + if (file.open(&root, strchr_pointer + 4, O_READ)) + { + showString(PSTR("File opened:")); Serial.print(strchr_pointer + 4); - Serial.print(" Size:"); + showString(PSTR(" Size:")); Serial.println(file.fileSize()); sdpos = 0; filesize = file.fileSize(); - Serial.println("File selected"); + showString(PSTR("File selected\r\n")); } - else{ - Serial.println("file.open failed"); + else + { + showString(PSTR("file.open failed\r\n")); } } break; case 24: //M24 - Start SD print - if(sdactive){ + if(sdactive) + { sdmode = true; } break; case 25: //M25 - Pause SD print - if(sdmode){ + if(sdmode) + { sdmode = false; } break; case 26: //M26 - Set SD index - if(sdactive && code_seen('S')){ + 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 "); + if(sdactive) + { + showString(PSTR("SD printing byte ")); Serial.print(sdpos); - Serial.print("/"); + showString(PSTR("/")); Serial.println(filesize); - }else{ - Serial.println("Not SD printing"); + } + else + { + showString(PSTR("Not SD printing\r\n")); } break; - case 28: //M28 - Start SD write - if(sdactive){ + case 28: //M28 - Start SD write + if(sdactive) + { char* npos = 0; file.close(); sdmode = false; starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos != NULL){ + 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)) + + if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) + { + showString(PSTR("open failed, File: ")); + Serial.print(strchr_pointer + 4); + showString(PSTR(".")); + } + else { - 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); + savetosd = true; + showString(PSTR("Writing to file: ")); + Serial.println(strchr_pointer + 4); } } break; @@ -759,6 +1304,38 @@ inline void process_commands() //processed in write to file routine above //savetosd = false; break; + #ifndef SD_FAST_XFER_AKTIV + case 30: // M30 filename - Delete file + if(sdactive) + { + sdmode = false; + file.close(); + + starpos = (strchr(strchr_pointer + 4,'*')); + + if(starpos!=NULL) + *(starpos-1)='\0'; + + if(file.remove(&root, strchr_pointer + 4)) + { + showString(PSTR("File deleted\r\n")); + } + else + { + showString(PSTR("Deletion failed\r\n")); + } + } + break; + #else + case 30: //M30 - fast SD transfer + fast_xfer(); + break; + case 31: //M31 - high speed xfer capabilities + showString(PSTR("RAW:")); + Serial.println(SD_FAST_XFER_CHUNK_SIZE); + break; + #endif + #endif case 42: //M42 -Change pin status via gcode if (code_seen('S')) @@ -780,7 +1357,7 @@ inline void process_commands() { pinMode(pin_number, OUTPUT); digitalWrite(pin_number, pin_status); - analogWrite(pin_number, pin_status); + //analogWrite(pin_number, pin_status); } } } @@ -788,10 +1365,13 @@ inline void process_commands() case 104: // M104 if (code_seen('S')) target_raw = temp2analogh(target_temp = code_value()); #ifdef WATCHPERIOD - if(target_raw > current_raw){ + if(target_raw > current_raw) + { watchmillis = max(1,millis()); watch_raw = current_raw; - }else{ + } + else + { watchmillis = 0; } #endif @@ -803,23 +1383,33 @@ inline void process_commands() break; case 105: // M105 #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675)|| defined HEATER_USES_AD595 - tt = analog2temp(current_raw); + hotendtC = analog2temp(current_raw); #endif #if TEMP_1_PIN > -1 || defined BED_USES_AD595 - bt = analog2tempBed(current_bed_raw); + bedtempC = 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); + showString(PSTR("ok T:")); + Serial.print(hotendtC); #ifdef PIDTEMP - Serial.print(" @:"); + showString(PSTR(" @:")); Serial.print(heater_duty); - Serial.print(","); + /* + showString(PSTR(",P:")); + Serial.print(pTerm); + showString(PSTR(",I:")); Serial.print(iTerm); + showString(PSTR(",D:")); + Serial.print(dTerm); + */ + #ifdef AUTOTEMP + showString(PSTR(",AU:")); + Serial.print(autotemp_setpoint); + #endif #endif #if TEMP_1_PIN > -1 || defined BED_USES_AD595 - Serial.print(" B:"); - Serial.println(bt); + showString(PSTR(" B:")); + Serial.println(bedtempC); #else Serial.println(); #endif @@ -831,10 +1421,13 @@ inline void process_commands() case 109: { // M109 - Wait for extruder heater to reach target. if (code_seen('S')) target_raw = temp2analogh(target_temp = code_value()); #ifdef WATCHPERIOD - if(target_raw>current_raw){ + if(target_raw>current_raw) + { watchmillis = max(1,millis()); watch_raw = current_raw; - }else{ + } + else + { watchmillis = 0; } #endif @@ -855,7 +1448,7 @@ inline void process_commands() #endif if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up/cooling down { - Serial.print("T:"); + showString(PSTR("T:")); Serial.println( analog2temp(current_raw) ); codenum = millis(); } @@ -874,35 +1467,38 @@ inline void process_commands() break; case 190: // M190 - Wait bed for heater to reach target. #if TEMP_1_PIN > -1 - if (code_seen('S')) target_bed_raw = temp2analogh(code_value()); + if (code_seen('S')) target_bed_raw = temp2analogBed(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); - Serial.print("T:"); - Serial.print( tt ); - Serial.print(" B:"); - Serial.println( analog2temp(current_bed_raw) ); + hotendtC=analog2temp(current_raw); + showString(PSTR("T:")); + Serial.print( hotendtC ); + showString(PSTR(" B:")); + Serial.println( analog2tempBed(current_bed_raw) ); codenum = millis(); } - manage_heater(); + manage_heater(); } #endif break; #if FAN_PIN > -1 case 106: //M106 Fan On - if (code_seen('S')){ + if (code_seen('S')) + { WRITE(FAN_PIN, HIGH); - analogWrite(FAN_PIN, constrain(code_value(),0,255) ); + //analogWrite(FAN_PIN, constrain(code_value(),0,255) ); } - else { + else + { WRITE(FAN_PIN, HIGH); - analogWrite(FAN_PIN, 255 ); + //analogWrite(FAN_PIN, 255 ); } break; case 107: //M107 Fan Off - analogWrite(FAN_PIN, 0); + //analogWrite(FAN_PIN, 0); WRITE(FAN_PIN, LOW); break; #endif @@ -921,82 +1517,195 @@ inline void process_commands() axis_relative_modes[3] = true; break; case 84: - if(code_seen('S')){ stepper_inactive_time = code_value() * 1000; } - else{ disable_x(); disable_y(); disable_z(); disable_e(); } + st_synchronize(); // wait for all movements to finish + if(code_seen('S')) + { + stepper_inactive_time = code_value() * 1000; + } + else + { + 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++) { + for(int i=0; i < NUM_AXIS; i++) + { if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); } - #ifdef RAMP_ACCELERATION - setup_acceleration(); - #endif - + // Update start speed intervals and axis order. TODO: refactor axis_max_interval[] calculation into a function, as it + // should also be used in setup() as well +// long temp_max_intervals[NUM_AXIS]; +// for(int i=0; i < NUM_AXIS; i++) +// { +// axis_max_interval[i] = 100000000.0 / (max_start_speed_units_per_second[i] * axis_steps_per_unit[i]);//TODO: do this for +// all steps_per_unit related variables +// } break; case 115: // M115 - Serial.print("FIRMWARE_NAME:Sprinter FIRMWARE_URL:http%%3A/github.com/kliment/Sprinter/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1 UUID:"); - Serial.println(uuid); + showString(PSTR("FIRMWARE_NAME: Sprinter Experimental PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1\r\n")); + //Serial.println(uuid); + showString(PSTR(_DEF_CHAR_UUID)); + showString(PSTR("\r\n")); break; case 114: // M114 - Serial.print("X:"); + showString(PSTR("X:")); Serial.print(current_position[0]); - Serial.print("Y:"); + showString(PSTR("Y:")); Serial.print(current_position[1]); - Serial.print("Z:"); + showString(PSTR("Z:")); Serial.print(current_position[2]); - Serial.print("E:"); + showString(PSTR("E:")); Serial.println(current_position[3]); break; case 119: // M119 + #if (X_MIN_PIN > -1) - Serial.print("x_min:"); - Serial.print((READ(X_MIN_PIN)^X_ENDSTOP_INVERT)?"H ":"L "); + showString(PSTR("x_min:")); + Serial.print((READ(X_MIN_PIN)^X_ENDSTOP_INVERT)?"H ":"L "); #endif #if (X_MAX_PIN > -1) - Serial.print("x_max:"); - Serial.print((READ(X_MAX_PIN)^X_ENDSTOP_INVERT)?"H ":"L "); + showString(PSTR("x_max:")); + Serial.print((READ(X_MAX_PIN)^X_ENDSTOP_INVERT)?"H ":"L "); #endif #if (Y_MIN_PIN > -1) - Serial.print("y_min:"); - Serial.print((READ(Y_MIN_PIN)^Y_ENDSTOP_INVERT)?"H ":"L "); + showString(PSTR("y_min:")); + Serial.print((READ(Y_MIN_PIN)^Y_ENDSTOP_INVERT)?"H ":"L "); #endif #if (Y_MAX_PIN > -1) - Serial.print("y_max:"); - Serial.print((READ(Y_MAX_PIN)^Y_ENDSTOP_INVERT)?"H ":"L "); + showString(PSTR("y_max:")); + Serial.print((READ(Y_MAX_PIN)^Y_ENDSTOP_INVERT)?"H ":"L "); #endif #if (Z_MIN_PIN > -1) - Serial.print("z_min:"); - Serial.print((READ(Z_MIN_PIN)^Z_ENDSTOP_INVERT)?"H ":"L "); + showString(PSTR("z_min:")); + Serial.print((READ(Z_MIN_PIN)^Z_ENDSTOP_INVERT)?"H ":"L "); #endif #if (Z_MAX_PIN > -1) - Serial.print("z_max:"); - Serial.print((READ(Z_MAX_PIN)^Z_ENDSTOP_INVERT)?"H ":"L "); + showString(PSTR("z_max:")); + Serial.print((READ(Z_MAX_PIN)^Z_ENDSTOP_INVERT)?"H ":"L "); #endif - Serial.println(""); + + showString(PSTR("\r\n")); break; - #ifdef RAMP_ACCELERATION - //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]; + + for(int8_t i=0; i < NUM_AXIS; i++) + { + if(code_seen(axis_codes[i])) + { + max_acceleration_units_per_sq_second[i] = code_value(); + 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++) { + 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; + #else + case 202: // M202 max feedrate mm/sec + for(int8_t i=0; i < NUM_AXIS; i++) + { + if(code_seen(axis_codes[i])) max_feedrate[i] = code_value(); + } + break; #endif + case 203: // M203 Temperature monitor + if(code_seen('S')) manage_monitor = code_value(); + if(manage_monitor==100) manage_monitor=1; // Set 100 to heated bed + break; + case 204: // M204 acclereration S normal moves T filmanent only moves + if(code_seen('S')) move_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(); + if(code_seen('T')) mintravelfeedrate = code_value(); + //if(code_seen('B')) minsegmenttime = code_value() ; + if(code_seen('X')) max_xy_jerk = code_value() ; + if(code_seen('Z')) max_z_jerk = code_value() ; + break; + case 220: // M220 S<factor in percent>- set speed factor override percentage + { + if(code_seen('S')) + { + feedmultiply = code_value() ; + if(feedmultiply < 20) feedmultiply = 20; + if(feedmultiply > 200) feedmultiply = 200; + feedmultiplychanged=true; + } + } + break; +#ifdef USE_EEPROM_SETTINGS + case 500: // Store settings in EEPROM + { + EEPROM_StoreSettings(); + } + break; + case 501: // Read settings from EEPROM + { + EEPROM_RetrieveSettings(false,true); + } + break; + case 502: // Revert to default settings + { + EEPROM_RetrieveSettings(true,true); + } + break; + case 503: // print settings currently in memory + { + EEPROM_printSettings(); + } + break; +#endif +#ifdef DEBUG_HEATER_TEMP + case 601: // M601 show Extruder Temp jitter + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675)|| defined HEATER_USES_AD595 + if(current_raw_maxval > 0) + tt_maxval = analog2temp(current_raw_maxval); + if(current_raw_minval < 10000) + tt_minval = analog2temp(current_raw_minval); + #endif + + showString(PSTR("Tmin:")); + Serial.print(tt_minval); + showString(PSTR(" / Tmax:")); + Serial.print(tt_maxval); + showString(PSTR(" ")); + break; + case 602: // M602 reset Extruder Temp jitter + current_raw_minval = 32000; + current_raw_maxval = -32000; + + showString(PSTR("T Minmax Reset ")); + break; +#endif + case 603: // M603 Free RAM + showString(PSTR("Free Ram: ")); + Serial.println(FreeRam1()); + break; + default: + #ifdef SEND_WRONG_CMD_INFO + showString(PSTR("Unknown M-COM:")); + Serial.println(cmdbuffer[bufindr]); + #endif + break; + } } else{ - Serial.println("Unknown command:"); + showString(PSTR("Unknown command:\r\n")); Serial.println(cmdbuffer[bufindr]); } @@ -1004,11 +1713,13 @@ inline void process_commands() } + + void FlushSerialRequestResend() { //char cmdbuffer[bufindr][100]="Resend:"; Serial.flush(); - Serial.print("Resend:"); + showString(PSTR("Resend:")); Serial.println(gcode_LastN + 1); ClearToSend(); } @@ -1020,724 +1731,1368 @@ void ClearToSend() if(fromsd[bufindr]) return; #endif - Serial.println("ok"); + showString(PSTR("ok\r\n")); + //Serial.println("ok"); } -inline void get_coordinates() +FORCE_INLINE void get_coordinates() { - for(int i=0; i < NUM_AXIS; i++) { + 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')) { + + if(code_seen('F')) + { next_feedrate = code_value(); if(next_feedrate > 0.0) feedrate = next_feedrate; } } +#ifdef USE_ARC_FUNCTION +FORCE_INLINE void get_arc_coordinates() +{ + get_coordinates(); + if(code_seen('I')) offset[0] = code_value(); + if(code_seen('J')) offset[1] = code_value(); +} +#endif + + void prepare_move() { - //Find direction - for(int i=0; i < NUM_AXIS; i++) { - if(destination[i] >= current_position[i]) move_direction[i] = 1; - else move_direction[i] = 0; - } - - - if (min_software_endstops) { - if (destination[0] < 0) destination[0] = 0.0; - if (destination[1] < 0) destination[1] = 0.0; - if (destination[2] < 0) destination[2] = 0.0; - } - - if (max_software_endstops) { - if (destination[0] > X_MAX_LENGTH) destination[0] = X_MAX_LENGTH; - if (destination[1] > Y_MAX_LENGTH) destination[1] = Y_MAX_LENGTH; - if (destination[2] > Z_MAX_LENGTH) destination[2] = Z_MAX_LENGTH; - } - - for(int i=0; i < NUM_AXIS; i++) { - axis_diff[i] = destination[i] - current_position[i]; - move_steps_to_take[i] = abs(axis_diff[i]) * axis_steps_per_unit[i]; - } - if(feedrate < 10) - feedrate = 10; - - //Feedrate calc based on XYZ travel distance - float xy_d; - //Check for cases where only one axis is moving - handle those without float sqrt - if(abs(axis_diff[0]) > 0 && abs(axis_diff[1]) == 0 && abs(axis_diff[2])==0) - d=abs(axis_diff[0]); - else if(abs(axis_diff[0]) == 0 && abs(axis_diff[1]) > 0 && abs(axis_diff[2])==0) - d=abs(axis_diff[1]); - else if(abs(axis_diff[0]) == 0 && abs(axis_diff[1]) == 0 && abs(axis_diff[2])>0) - d=abs(axis_diff[2]); - //two or three XYZ axes moving - else if(abs(axis_diff[0]) > 0 || abs(axis_diff[1]) > 0) { //X or Y or both - xy_d = sqrt(axis_diff[0] * axis_diff[0] + axis_diff[1] * axis_diff[1]); - //check if Z involved - if so interpolate that too - d = (abs(axis_diff[2])>0)?sqrt(xy_d * xy_d + axis_diff[2] * axis_diff[2]):xy_d; - } - else if(abs(axis_diff[3]) > 0) - d = abs(axis_diff[3]); - else{ //zero length move - #ifdef DEBUG_PREPARE_MOVE - - log_message("_PREPARE_MOVE - No steps to take!"); - - #endif - return; - } - time_for_move = (d / (feedrate / 60000000.0) ); - //Check max feedrate for each axis is not violated, update time_for_move if necessary - for(int i = 0; i < NUM_AXIS; i++) { - if(move_steps_to_take[i] && abs(axis_diff[i]) / (time_for_move / 60000000.0) > max_feedrate[i]) { - time_for_move = time_for_move / max_feedrate[i] * (abs(axis_diff[i]) / (time_for_move / 60000000.0)); - } + long help_feedrate = 0; + + if (min_software_endstops) + { + if (destination[X_AXIS] < 0) destination[X_AXIS] = 0.0; + if (destination[Y_AXIS] < 0) destination[Y_AXIS] = 0.0; + if (destination[Z_AXIS] < 0) destination[Z_AXIS] = 0.0; } - //Calculate the full speed stepper interval for each axis - for(int i=0; i < NUM_AXIS; i++) { - if(move_steps_to_take[i]) axis_interval[i] = time_for_move / move_steps_to_take[i] * 100; + + if (max_software_endstops) + { + if (destination[X_AXIS] > X_MAX_LENGTH) destination[X_AXIS] = X_MAX_LENGTH; + if (destination[Y_AXIS] > Y_MAX_LENGTH) destination[Y_AXIS] = Y_MAX_LENGTH; + if (destination[Z_AXIS] > Z_MAX_LENGTH) destination[Z_AXIS] = Z_MAX_LENGTH; } - - #ifdef DEBUG_PREPARE_MOVE - log_float("_PREPARE_MOVE - Move distance on the XY plane", xy_d); - log_float("_PREPARE_MOVE - Move distance on the XYZ space", d); - log_int("_PREPARE_MOVE - Commanded feedrate", feedrate); - log_float("_PREPARE_MOVE - Constant full speed move time", time_for_move); - log_float_array("_PREPARE_MOVE - Destination", destination, NUM_AXIS); - log_float_array("_PREPARE_MOVE - Current position", current_position, NUM_AXIS); - log_ulong_array("_PREPARE_MOVE - Steps to take", move_steps_to_take, NUM_AXIS); - log_long_array("_PREPARE_MOVE - Axes full speed intervals", axis_interval, NUM_AXIS); - #endif - unsigned long move_steps[NUM_AXIS]; + help_feedrate = ((long)feedrate*(long)feedmultiply); + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], help_feedrate/6000.0); + for(int i=0; i < NUM_AXIS; i++) - move_steps[i] = move_steps_to_take[i]; - linear_move(move_steps); // make the move + { + current_position[i] = destination[i]; + } } -inline void linear_move(unsigned long axis_steps_remaining[]) // make linear move with preset speeds and destinations, see G0 and G1 + +#ifdef USE_ARC_FUNCTION +void prepare_arc_move(char isclockwise) { - //Determine direction of movement - if (destination[0] > current_position[0]) WRITE(X_DIR_PIN,!INVERT_X_DIR); - else WRITE(X_DIR_PIN,INVERT_X_DIR); - if (destination[1] > current_position[1]) WRITE(Y_DIR_PIN,!INVERT_Y_DIR); - else WRITE(Y_DIR_PIN,INVERT_Y_DIR); - if (destination[2] > current_position[2]) WRITE(Z_DIR_PIN,!INVERT_Z_DIR); - else WRITE(Z_DIR_PIN,INVERT_Z_DIR); - if (destination[3] > current_position[3]) WRITE(E_DIR_PIN,!INVERT_E_DIR); - else WRITE(E_DIR_PIN,INVERT_E_DIR); - movereset: - #if (X_MIN_PIN > -1) - if(!move_direction[0]) if(READ(X_MIN_PIN) != X_ENDSTOP_INVERT) axis_steps_remaining[0]=0; - #endif - #if (Y_MIN_PIN > -1) - if(!move_direction[1]) if(READ(Y_MIN_PIN) != Y_ENDSTOP_INVERT) axis_steps_remaining[1]=0; - #endif - #if (Z_MIN_PIN > -1) - if(!move_direction[2]) if(READ(Z_MIN_PIN) != Z_ENDSTOP_INVERT) axis_steps_remaining[2]=0; - #endif - #if (X_MAX_PIN > -1) - if(move_direction[0]) if(READ(X_MAX_PIN) != X_ENDSTOP_INVERT) axis_steps_remaining[0]=0; - #endif - #if (Y_MAX_PIN > -1) - if(move_direction[1]) if(READ(Y_MAX_PIN) != Y_ENDSTOP_INVERT) axis_steps_remaining[1]=0; - #endif - # if(Z_MAX_PIN > -1) - if(move_direction[2]) if(READ(Z_MAX_PIN) != Z_ENDSTOP_INVERT) axis_steps_remaining[2]=0; - #endif + + float r = hypot(offset[X_AXIS], offset[Y_AXIS]); // Compute arc radius for mc_arc + long help_feedrate = 0; + + help_feedrate = ((long)feedrate*(long)feedmultiply); + // Trace the arc + mc_arc(current_position, destination, offset, X_AXIS, Y_AXIS, Z_AXIS, help_feedrate/6000.0, r, isclockwise); - //Only enable axis that are moving. If the axis doesn't need to move then it can stay disabled depending on configuration. - // TODO: maybe it's better to refactor into a generic enable(int axis) function, that will probably take more ram, - // but will reduce code size - if(axis_steps_remaining[0]) enable_x(); - if(axis_steps_remaining[1]) enable_y(); - if(axis_steps_remaining[2]) enable_z(); - if(axis_steps_remaining[3]) enable_e(); - - //Define variables that are needed for the Bresenham algorithm. Please note that Z is not currently included in the Bresenham algorithm. - unsigned long delta[] = {axis_steps_remaining[0], axis_steps_remaining[1], axis_steps_remaining[2], axis_steps_remaining[3]}; //TODO: implement a "for" to support N axes - long axis_error[NUM_AXIS]; - int primary_axis; - if(delta[1] > delta[0] && delta[1] > delta[2] && delta[1] > delta[3]) primary_axis = 1; - else if (delta[0] >= delta[1] && delta[0] > delta[2] && delta[0] > delta[3]) primary_axis = 0; - else if (delta[2] >= delta[0] && delta[2] >= delta[1] && delta[2] > delta[3]) primary_axis = 2; - else primary_axis = 3; - unsigned long steps_remaining = delta[primary_axis]; - unsigned long steps_to_take = steps_remaining; - for(int i=0; i < NUM_AXIS; i++){ - if(i != primary_axis) axis_error[i] = delta[primary_axis] / 2; - steps_taken[i]=0; - } - interval = axis_interval[primary_axis]; - bool is_print_move = delta[3] > 0; - #ifdef DEBUG_BRESENHAM - log_int("_BRESENHAM - Primary axis", primary_axis); - log_int("_BRESENHAM - Primary axis full speed interval", interval); - log_ulong_array("_BRESENHAM - Deltas", delta, NUM_AXIS); - log_long_array("_BRESENHAM - Errors", axis_error, NUM_AXIS); - #endif + // As far as the parser is concerned, the position is now == target. In reality the + // motion control system might still be processing the action and the real tool position + // in any intermediate location. + for(int8_t i=0; i < NUM_AXIS; i++) + { + current_position[i] = destination[i]; + } +} +#endif - //If acceleration is enabled, do some Bresenham calculations depending on which axis will lead it. - #ifdef RAMP_ACCELERATION - long max_speed_steps_per_second; - long min_speed_steps_per_second; - max_interval = axis_max_interval[primary_axis]; - #ifdef DEBUG_RAMP_ACCELERATION - log_ulong_array("_RAMP_ACCELERATION - Teoric step intervals at move start", axis_max_interval, NUM_AXIS); - #endif - unsigned long new_axis_max_intervals[NUM_AXIS]; - max_speed_steps_per_second = 100000000 / interval; - min_speed_steps_per_second = 100000000 / max_interval; //TODO: can this be deleted? - //Calculate start speeds based on moving axes max start speed constraints. - int slowest_start_axis = primary_axis; - unsigned long slowest_start_axis_max_interval = max_interval; - for(int i = 0; i < NUM_AXIS; i++) - if (axis_steps_remaining[i] >0 && - i != primary_axis && - axis_max_interval[i] * axis_steps_remaining[i]/ axis_steps_remaining[slowest_start_axis] > slowest_start_axis_max_interval) { - slowest_start_axis = i; - slowest_start_axis_max_interval = axis_max_interval[i]; - } - for(int i = 0; i < NUM_AXIS; i++) - if(axis_steps_remaining[i] >0) { - // multiplying slowest_start_axis_max_interval by axis_steps_remaining[slowest_start_axis] - // could lead to overflows when we have long distance moves (say, 390625*390625 > sizeof(unsigned long)) - float steps_remaining_ratio = (float) axis_steps_remaining[slowest_start_axis] / axis_steps_remaining[i]; - new_axis_max_intervals[i] = slowest_start_axis_max_interval * steps_remaining_ratio; - - if(i == primary_axis) { - max_interval = new_axis_max_intervals[i]; - min_speed_steps_per_second = 100000000 / max_interval; - } - } - //Calculate slowest axis plateau time - float slowest_axis_plateau_time = 0; - for(int i=0; i < NUM_AXIS ; i++) { - if(axis_steps_remaining[i] > 0) { - if(is_print_move && axis_steps_remaining[i] > 0) slowest_axis_plateau_time = max(slowest_axis_plateau_time, - (100000000.0 / axis_interval[i] - 100000000.0 / new_axis_max_intervals[i]) / (float) axis_steps_per_sqr_second[i]); - else if(axis_steps_remaining[i] > 0) slowest_axis_plateau_time = max(slowest_axis_plateau_time, - (100000000.0 / axis_interval[i] - 100000000.0 / new_axis_max_intervals[i]) / (float) axis_travel_steps_per_sqr_second[i]); - } - } - //Now we can calculate the new primary axis acceleration, so that the slowest axis max acceleration is not violated - steps_per_sqr_second = (100000000.0 / axis_interval[primary_axis] - 100000000.0 / new_axis_max_intervals[primary_axis]) / slowest_axis_plateau_time; - plateau_steps = (long) ((steps_per_sqr_second / 2.0 * slowest_axis_plateau_time + min_speed_steps_per_second) * slowest_axis_plateau_time); - #ifdef DEBUG_RAMP_ACCELERATION - log_int("_RAMP_ACCELERATION - Start speed limiting axis", slowest_start_axis); - log_ulong("_RAMP_ACCELERATION - Limiting axis start interval", slowest_start_axis_max_interval); - log_ulong_array("_RAMP_ACCELERATION - Actual step intervals at move start", new_axis_max_intervals, NUM_AXIS); - #endif +FORCE_INLINE void kill() +{ + #if TEMP_0_PIN > -1 + target_raw=0; + WRITE(HEATER_0_PIN,LOW); #endif - unsigned long steps_done = 0; - #ifdef RAMP_ACCELERATION - plateau_steps *= 1.01; // This is to compensate we use discrete intervals - acceleration_enabled = true; - unsigned long full_interval = interval; - if(interval > max_interval) acceleration_enabled = false; - boolean decelerating = false; + #if TEMP_1_PIN > -1 + target_bed_raw=0; + if(HEATER_1_PIN > -1) WRITE(HEATER_1_PIN,LOW); #endif + + disable_x(); + disable_y(); + disable_z(); + disable_e(); + + if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); - unsigned long start_move_micros = micros(); - for(int i = 0; i < NUM_AXIS; i++) { - axis_previous_micros[i] = start_move_micros * 100; +} + +FORCE_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(); +} - #ifdef DISABLE_CHECK_DURING_TRAVEL - //If the move time is more than allowed in DISABLE_CHECK_DURING_TRAVEL, let's - // consider this a print move and perform heat management during it - if(time_for_move / 1000 > DISABLE_CHECK_DURING_TRAVEL) is_print_move = true; - //else, if the move is a retract, consider it as a travel move for the sake of this feature - else if(delta[3]>0 && delta[0] + delta[1] + delta[2] == 0) is_print_move = false; - #ifdef DEBUG_DISABLE_CHECK_DURING_TRAVEL - log_bool("_DISABLE_CHECK_DURING_TRAVEL - is_print_move", is_print_move); - #endif - #endif - #ifdef DEBUG_MOVE_TIME - unsigned long startmove = micros(); - #endif + + +// Planner with Interrupt for Stepper + +/* + 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 + +//=========================================================================== +//=============================private variables ============================ +//=========================================================================== + +// Returns the index of the next block in the ring buffer +// NOTE: Removed modulo (%) operator, which uses an expensive divide and multiplication. +static int8_t next_block_index(int8_t block_index) { + block_index++; + if (block_index == BLOCK_BUFFER_SIZE) { block_index = 0; } + return(block_index); +} + + +// Returns the index of the previous block in the ring buffer +static int8_t prev_block_index(int8_t block_index) { + if (block_index == 0) { block_index = BLOCK_BUFFER_SIZE; } + block_index--; + return(block_index); +} + +// The current position of the tool in absolute steps +static long position[4]; +static float previous_speed[4]; // Speed of previous path line segment +static float previous_nominal_speed; // Nominal speed of previous path line segment + + +// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the +// given acceleration: +FORCE_INLINE float estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration) +{ + if (acceleration!=0) { + return((target_rate*target_rate-initial_rate*initial_rate)/ + (2.0*acceleration)); + } + else { + return 0.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 +// 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) + +FORCE_INLINE float intersection_distance(float initial_rate, float final_rate, float acceleration, float distance) +{ + if (acceleration!=0) { + return((2.0*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ + (4.0*acceleration) ); + } + else { + return 0.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. + +void calculate_trapezoid_for_block(block_t *block, float entry_factor, float exit_factor) { + unsigned long initial_rate = ceil(block->nominal_rate*entry_factor); // (step/min) + unsigned long final_rate = ceil(block->nominal_rate*exit_factor); // (step/min) + + // Limit minimal step rate (Otherwise the timer will overflow.) + if(initial_rate <120) {initial_rate=120; } + if(final_rate < 120) {final_rate=120; } - //move until no more steps remain - while(axis_steps_remaining[0] + axis_steps_remaining[1] + axis_steps_remaining[2] + axis_steps_remaining[3] > 0) { - #if defined RAMP_ACCELERATION && defined DISABLE_CHECK_DURING_ACC - if(!accelerating && !decelerating) { - //If more that HEATER_CHECK_INTERVAL ms have passed since previous heating check, adjust temp - #ifdef DISABLE_CHECK_DURING_TRAVEL - if(is_print_move) - #endif - manage_heater(); - } - #else - #ifdef DISABLE_CHECK_DURING_MOVE - {} //Do nothing - #else - //If more that HEATER_CHECK_INTERVAL ms have passed since previous heating check, adjust temp - #ifdef DISABLE_CHECK_DURING_TRAVEL - if(is_print_move) - #endif - manage_heater(); - #endif - #endif - #ifdef RAMP_ACCELERATION - //If acceleration is enabled on this move and we are in the acceleration segment, calculate the current interval - if (acceleration_enabled && steps_done == 0) { - interval = max_interval; - } else if (acceleration_enabled && steps_done <= plateau_steps) { - long current_speed = (long) ((((long) steps_per_sqr_second) / 100) - * ((micros() - start_move_micros) / 100)/100 + (long) min_speed_steps_per_second); - interval = 100000000 / current_speed; - if (interval < full_interval) { - accelerating = false; - interval = full_interval; - } - if (steps_done >= steps_to_take / 2) { - plateau_steps = steps_done; - max_speed_steps_per_second = 100000000 / interval; - accelerating = false; + long acceleration = block->acceleration_st; + int32_t accelerate_steps = + ceil(estimate_acceleration_distance(block->initial_rate, block->nominal_rate, acceleration)); + int32_t decelerate_steps = + floor(estimate_acceleration_distance(block->nominal_rate, block->final_rate, -acceleration)); + + // Calculate the size of Plateau of Nominal Rate. + int32_t 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 = ceil( + intersection_distance(block->initial_rate, block->final_rate, acceleration, block->step_event_count)); + accelerate_steps = max(accelerate_steps,0); // Check limits due to numerical round-off + accelerate_steps = min(accelerate_steps,block->step_event_count); + plateau_steps = 0; + } + + #ifdef ADVANCE + volatile long initial_advance = block->advance*entry_factor*entry_factor; + volatile long final_advance = block->advance*exit_factor*exit_factor; + #endif // ADVANCE + + // block->accelerate_until = accelerate_steps; + // block->decelerate_after = accelerate_steps+plateau_steps; + 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 = accelerate_steps+plateau_steps; + 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. +FORCE_INLINE float max_allowable_speed(float acceleration, float target_velocity, float distance) { + return sqrt(target_velocity*target_velocity-2*acceleration*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)); +//} + + + +// 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; } + + if (next) { + // If entry speed is already at the maximum entry speed, no need to recheck. Block is cruising. + // If not, block in state of acceleration or deceleration. Reset entry speed to maximum and + // check for maximum allowable speed reductions to ensure maximum possible planned speed. + if (current->entry_speed != current->max_entry_speed) { + + // If nominal length true, max junction speed is guaranteed to be reached. Only compute + // for max allowable speed if block is decelerating and nominal length is false. + if ((!current->nominal_length_flag) && (current->max_entry_speed > next->entry_speed)) { + current->entry_speed = min( current->max_entry_speed, + max_allowable_speed(-current->acceleration,next->entry_speed,current->millimeters)); + } else { + current->entry_speed = current->max_entry_speed; } - } else if (acceleration_enabled && steps_remaining <= plateau_steps) { //(interval > minInterval * 100) { - if (!accelerating) { - start_move_micros = micros(); - accelerating = true; - decelerating = true; - } - long current_speed = (long) ((long) max_speed_steps_per_second - ((((long) steps_per_sqr_second) / 100) - * ((micros() - start_move_micros) / 100)/100)); - interval = 100000000 / current_speed; - if (interval > max_interval) - interval = max_interval; - } else { - //Else, we are just use the full speed interval as current interval - interval = full_interval; - accelerating = false; + current->recalculate_flag = true; + } - #endif + } // Skip last block. Already initialized and set for recalculation. +} - //If there are x or y steps remaining, perform Bresenham algorithm - if(axis_steps_remaining[primary_axis]) { - #if (X_MIN_PIN > -1) - if(!move_direction[0]) if(READ(X_MIN_PIN) != X_ENDSTOP_INVERT) if(primary_axis==0) break; else if(axis_steps_remaining[0]) axis_steps_remaining[0]=0; - #endif - #if (Y_MIN_PIN > -1) - if(!move_direction[1]) if(READ(Y_MIN_PIN) != Y_ENDSTOP_INVERT) if(primary_axis==1) break; else if(axis_steps_remaining[1]) axis_steps_remaining[1]=0; - #endif - #if (X_MAX_PIN > -1) - if(move_direction[0]) if(READ(X_MAX_PIN) != X_ENDSTOP_INVERT) if(primary_axis==0) break; else if(axis_steps_remaining[0]) axis_steps_remaining[0]=0; - #endif - #if (Y_MAX_PIN > -1) - if(move_direction[1]) if(READ(Y_MAX_PIN) != Y_ENDSTOP_INVERT) if(primary_axis==1) break; else if(axis_steps_remaining[1]) axis_steps_remaining[1]=0; - #endif - #if (Z_MIN_PIN > -1) - if(!move_direction[2]) if(READ(Z_MIN_PIN) != Z_ENDSTOP_INVERT) if(primary_axis==2) break; else if(axis_steps_remaining[2]) axis_steps_remaining[2]=0; - #endif - #if (Z_MAX_PIN > -1) - if(move_direction[2]) if(READ(Z_MAX_PIN) != Z_ENDSTOP_INVERT) if(primary_axis==2) break; else if(axis_steps_remaining[2]) axis_steps_remaining[2]=0; - #endif - timediff = micros() * 100 - axis_previous_micros[primary_axis]; - if(timediff<0){//check for overflow - axis_previous_micros[primary_axis]=micros()*100; - timediff=interval/2; //approximation - } - while(((unsigned long)timediff) >= interval && axis_steps_remaining[primary_axis] > 0) { - steps_done++; - steps_remaining--; - axis_steps_remaining[primary_axis]--; timediff -= interval; - do_step(primary_axis); - axis_previous_micros[primary_axis] += interval; - for(int i=0; i < NUM_AXIS; i++) if(i != primary_axis && axis_steps_remaining[i] > 0) { - axis_error[i] = axis_error[i] - delta[i]; - if(axis_error[i] < 0) { - do_step(i); axis_steps_remaining[i]--; - axis_error[i] = axis_error[i] + delta[primary_axis]; - } - } - #ifdef STEP_DELAY_RATIO - if(timediff >= interval) delayMicroseconds(long_step_delay_ratio * interval / 10000); - #endif - #ifdef STEP_DELAY_MICROS - if(timediff >= interval) delayMicroseconds(STEP_DELAY_MICROS); - #endif - } +// 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() { + uint8_t block_index = block_buffer_head; + if(((block_buffer_head-block_buffer_tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1)) > 3) { + block_index = (block_buffer_head - 3) & (BLOCK_BUFFER_SIZE - 1); + block_t *block[3] = { NULL, NULL, NULL }; + while(block_index != block_buffer_tail) { + block_index = prev_block_index(block_index); + block[2]= block[1]; + block[1]= block[0]; + block[0] = &block_buffer[block_index]; + planner_reverse_pass_kernel(block[0], block[1], block[2]); } } - #ifdef DEBUG_MOVE_TIME - log_ulong("_MOVE_TIME - This move took", micros()-startmove); - #endif +} + + +// 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(!previous) { return; } - if(DISABLE_X) disable_x(); - if(DISABLE_Y) disable_y(); - if(DISABLE_Z) disable_z(); - if(DISABLE_E) disable_e(); + // 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 the entry speed accordingly. Entry + // speeds have already been reset, maximized, and reverse planned by reverse planner. + // If nominal length is true, max junction speed is guaranteed to be reached. No need to recheck. + if (!previous->nominal_length_flag) { + if (previous->entry_speed < current->entry_speed) { + double entry_speed = min( current->entry_speed, + max_allowable_speed(-previous->acceleration,previous->entry_speed,previous->millimeters) ); + + // Check for junction speed change + if (current->entry_speed != entry_speed) { + current->entry_speed = entry_speed; + current->recalculate_flag = true; + } + } + } +} + +// 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() { + uint8_t 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 = next_block_index(block_index); + } + 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() { + int8_t block_index = block_buffer_tail; + block_t *current; + block_t *next = NULL; - // Update current position partly based on direction, we probably can combine this with the direction code above... - for(int i=0; i < NUM_AXIS; i++) { - if (destination[i] > current_position[i]) current_position[i] = current_position[i] + steps_taken[i] / axis_steps_per_unit[i]; - else current_position[i] = current_position[i] - steps_taken[i] / axis_steps_per_unit[i]; + while(block_index != block_buffer_head) { + current = next; + next = &block_buffer[block_index]; + if (current) { + // Recalculate if current block entry or exit junction speed has changed. + if (current->recalculate_flag || next->recalculate_flag) { + // NOTE: Entry and exit factors always > 0 by all previous logic operations. + calculate_trapezoid_for_block(current, current->entry_speed/current->nominal_speed, + next->entry_speed/current->nominal_speed); + current->recalculate_flag = false; // Reset current only to ensure next trapezoid is computed + } + } + block_index = next_block_index( block_index ); + } + // Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated. + if(next != NULL) { + calculate_trapezoid_for_block(next, next->entry_speed/next->nominal_speed, + MINIMUM_PLANNER_SPEED/next->nominal_speed); + next->recalculate_flag = false; } } -void do_step(int axis) { - switch(axis){ - case 0: - WRITE(X_STEP_PIN, HIGH); - break; - case 1: - WRITE(Y_STEP_PIN, HIGH); - break; - case 2: - WRITE(Z_STEP_PIN, HIGH); - break; - case 3: - WRITE(E_STEP_PIN, HIGH); - break; - } - steps_taken[axis]+=1; - WRITE(X_STEP_PIN, LOW); - WRITE(Y_STEP_PIN, LOW); - WRITE(Z_STEP_PIN, LOW); - WRITE(E_STEP_PIN, LOW); +// 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(); } -#define HEAT_INTERVAL 250 -#ifdef HEATER_USES_MAX6675 -unsigned long max6675_previous_millis = 0; -int max6675_temp = 2000; +void plan_init() { + block_buffer_head = 0; + block_buffer_tail = 0; + memset(position, 0, sizeof(position)); // clear position + previous_speed[0] = 0.0; + previous_speed[1] = 0.0; + previous_speed[2] = 0.0; + previous_speed[3] = 0.0; + previous_nominal_speed = 0.0; +} + + + +FORCE_INLINE void plan_discard_current_block() { + if (block_buffer_head != block_buffer_tail) { + block_buffer_tail = (block_buffer_tail + 1) & BLOCK_BUFFER_MASK; + } +} + +FORCE_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); +} + +// Gets the current block. Returns NULL if buffer empty +FORCE_INLINE bool blocks_queued() +{ + if (block_buffer_head == block_buffer_tail) { + return false; + } + else + return true; +} + +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) { + uint8_t 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 - 1); + } + } + 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(); +} -int read_max6675() + +float junction_deviation = 0.1; +// 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) { - if (millis() - max6675_previous_millis < HEAT_INTERVAL) - return max6675_temp; + // Calculate the buffer head after we push this byte + int next_buffer_head = next_block_index(block_buffer_head); + + // 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); + } + + // The target position of the tool in absolute steps + // Calculate target position in absolute steps + //this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow + 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]; + + // 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 <=dropsegments) { return; }; + + // Compute direction bits for this block + block->direction_bits = 0; + if (target[X_AXIS] < position[X_AXIS]) { block->direction_bits |= (1<<X_AXIS); } + if (target[Y_AXIS] < position[Y_AXIS]) { block->direction_bits |= (1<<Y_AXIS); } + if (target[Z_AXIS] < position[Z_AXIS]) { block->direction_bits |= (1<<Z_AXIS); } + if (target[E_AXIS] < position[E_AXIS]) { block->direction_bits |= (1<<E_AXIS); } - max6675_previous_millis = millis(); - max6675_temp = 0; - - #ifdef PRR - PRR &= ~(1<<PRSPI); - #elif defined PRR0 - PRR0 &= ~(1<<PRSPI); - #endif + #ifdef DELAY_ENABLE + if(block->steps_x != 0) + { + enable_x(); + delayMicroseconds(DELAY_ENABLE); + } + if(block->steps_y != 0) + { + enable_y(); + delayMicroseconds(DELAY_ENABLE); + } + if(if(block->steps_z != 0)) + { + enable_z(); + delayMicroseconds(DELAY_ENABLE); + } + if(if(block->steps_e != 0)) + { + enable_e(); + delayMicroseconds(DELAY_ENABLE); + } + #else + //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(); + #endif + + if (block->steps_e == 0) { + if(feed_rate<mintravelfeedrate) feed_rate=mintravelfeedrate; + } + else { + if(feed_rate<minimumfeedrate) feed_rate=minimumfeedrate; + } + + // slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill + int moves_queued=(block_buffer_head-block_buffer_tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1); +#ifdef SLOWDOWN + if(moves_queued < (BLOCK_BUFFER_SIZE * 0.5) && moves_queued > 1) feed_rate = feed_rate*moves_queued / (BLOCK_BUFFER_SIZE * 0.5); +#endif + + float delta_mm[4]; + delta_mm[X_AXIS] = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS]; + delta_mm[Y_AXIS] = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS]; + delta_mm[Z_AXIS] = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; + delta_mm[E_AXIS] = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS]; - SPCR = (1<<MSTR) | (1<<SPE) | (1<<SPR0); + if ( block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0 ) { + block->millimeters = fabs(delta_mm[E_AXIS]); + } else { + block->millimeters = sqrt(square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_AXIS])); + } - // enable TT_MAX6675 - WRITE(MAX6675_SS, 0); + float inverse_millimeters = 1.0/block->millimeters; // Inverse millimeters to remove multiple divides - // ensure 100ns delay - a bit extra is fine - delay(1); + // Calculate speed in mm/second for each axis. No divide by zero due to previous checks. + float inverse_second = feed_rate * inverse_millimeters; - // read MSB - SPDR = 0; - for (;(SPSR & (1<<SPIF)) == 0;); - max6675_temp = SPDR; - max6675_temp <<= 8; + block->nominal_speed = block->millimeters * inverse_second; // (mm/sec) Always > 0 + block->nominal_rate = ceil(block->step_event_count * inverse_second); // (step/sec) Always > 0 + - // read LSB - SPDR = 0; - for (;(SPSR & (1<<SPIF)) == 0;); - max6675_temp |= SPDR; + + - // disable TT_MAX6675 - WRITE(MAX6675_SS, 1); +/* + // segment time im micro seconds + long segment_time = lround(1000000.0/inverse_second); + if ((blockcount>0) && (blockcount < (BLOCK_BUFFER_SIZE - 4))) { + if (segment_time<minsegmenttime) { // buffer is draining, add extra time. The amount of time added increases if the buffer is still emptied more. + segment_time=segment_time+lround(2*(minsegmenttime-segment_time)/blockcount); + } + } + else { + if (segment_time<minsegmenttime) segment_time=minsegmenttime; + } + // END OF SLOW DOWN SECTION +*/ - if (max6675_temp & 4) - { - // thermocouple open - max6675_temp = 2000; + + // Calculate speed in mm/sec for each axis + float current_speed[4]; + for(int i=0; i < 4; i++) { + current_speed[i] = delta_mm[i] * inverse_second; } - else - { - max6675_temp = max6675_temp >> 3; + + // Limit speed per axis + float speed_factor = 1.0; //factor <=1 do decrease speed + for(int i=0; i < 4; i++) { + if(fabs(current_speed[i]) > max_feedrate[i]) + speed_factor = min(speed_factor, max_feedrate[i] / fabs(current_speed[i])); } - return max6675_temp; -} -#endif + // Correct the speed + if( speed_factor < 1.0) { +// Serial.print("speed factor : "); Serial.println(speed_factor); + for(int i=0; i < 4; i++) { + if(fabs(current_speed[i]) > max_feedrate[i]) + speed_factor = min(speed_factor, max_feedrate[i] / fabs(current_speed[i])); + /* + if(speed_factor < 0.1) { + Serial.print("speed factor : "); Serial.println(speed_factor); + Serial.print("current_speed"); Serial.print(i); Serial.print(" : "); Serial.println(current_speed[i]); + } + */ + } + for(unsigned char i=0; i < 4; i++) { + current_speed[i] *= speed_factor; + } + block->nominal_speed *= speed_factor; + block->nominal_rate *= speed_factor; + } -#ifdef CONTROLLERFAN_PIN -unsigned long lastMotor = 0; //Save the time for when a motor was turned on last -unsigned long lastMotorCheck = 0; + // Compute and limit the acceleration rate for the trapezoid generator. + float steps_per_mm = block->step_event_count/block->millimeters; + if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { + block->acceleration_st = ceil(retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 + } + else { + block->acceleration_st = ceil(move_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 + // Limit acceleration per axis + if(((float)block->acceleration_st * (float)block->steps_x / (float)block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[X_AXIS]; + if(((float)block->acceleration_st * (float)block->steps_y / (float)block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS]; + if(((float)block->acceleration_st * (float)block->steps_e / (float)block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) + block->acceleration_st = axis_steps_per_sqr_second[E_AXIS]; + if(((float)block->acceleration_st * (float)block->steps_z / (float)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 / steps_per_mm; + block->acceleration_rate = (long)((float)block->acceleration_st * 8.388608); + +#if 0 // Use old jerk for now + // Compute path unit vector + double unit_vec[3]; -void controllerFan() -{ - if ((millis() - lastMotorCheck) >= 2500) //Not a time critical function, so we only check every 2500ms - { - lastMotorCheck = millis(); - - if(!READ(X_ENABLE_PIN) || !READ(Y_ENABLE_PIN) || !READ(Z_ENABLE_PIN) || !READ(E_ENABLE_PIN)) //If any of the drivers are enabled... - { - lastMotor = millis(); //... set time to NOW so the fan will turn on + unit_vec[X_AXIS] = delta_mm[X_AXIS]*inverse_millimeters; + unit_vec[Y_AXIS] = delta_mm[Y_AXIS]*inverse_millimeters; + unit_vec[Z_AXIS] = delta_mm[Z_AXIS]*inverse_millimeters; + + // Compute maximum allowable entry speed at junction by centripetal acceleration approximation. + // Let a circle be tangent to both previous and current path line segments, where the junction + // deviation is defined as the distance from the junction to the closest edge of the circle, + // colinear with the circle center. The circular segment joining the two paths represents the + // path of centripetal acceleration. Solve for max velocity based on max acceleration about the + // radius of the circle, defined indirectly by junction deviation. This may be also viewed as + // path width or max_jerk in the previous grbl version. This approach does not actually deviate + // from path, but used as a robust way to compute cornering speeds, as it takes into account the + // nonlinearities of both the junction angle and junction velocity. + double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed + + // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles. + if ((block_buffer_head != block_buffer_tail) && (previous_nominal_speed > 0.0)) { + // Compute cosine of angle between previous and current path. (prev_unit_vec is negative) + // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity. + double cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS] + - previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS] + - previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ; + + // Skip and use default max junction speed for 0 degree acute junction. + if (cos_theta < 0.95) { + vmax_junction = min(previous_nominal_speed,block->nominal_speed); + // Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds. + if (cos_theta > -0.95) { + // Compute maximum junction velocity based on maximum acceleration and junction deviation + double sin_theta_d2 = sqrt(0.5*(1.0-cos_theta)); // Trig half angle identity. Always positive. + vmax_junction = min(vmax_junction, + sqrt(block->acceleration * junction_deviation * sin_theta_d2/(1.0-sin_theta_d2)) ); + } + } + } +#endif + // Start with a safe speed + float vmax_junction = max_xy_jerk/2; + if(fabs(current_speed[Z_AXIS]) > max_z_jerk/2) + vmax_junction = max_z_jerk/2; + vmax_junction = min(vmax_junction, block->nominal_speed); + + if ((moves_queued > 1) && (previous_nominal_speed > 0.0)) { + float jerk = sqrt(pow((current_speed[X_AXIS]-previous_speed[X_AXIS]), 2)+pow((current_speed[Y_AXIS]-previous_speed[Y_AXIS]), 2)); + if((previous_speed[X_AXIS] != 0.0) || (previous_speed[Y_AXIS] != 0.0)) { + vmax_junction = block->nominal_speed; } + if (jerk > max_xy_jerk) { + vmax_junction *= (max_xy_jerk/jerk); + } + if(fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS]) > max_z_jerk) { + vmax_junction *= (max_z_jerk/fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS])); + } + } + block->max_entry_speed = vmax_junction; - if ((millis() - lastMotor) >= (CONTROLLERFAN_SEC*1000UL) || lastMotor == 0) //If the last time any driver was enabled, is longer since than CONTROLLERSEC... - { - WRITE(CONTROLLERFAN_PIN, LOW); //... turn the fan off + // Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED. + double v_allowable = max_allowable_speed(-block->acceleration,MINIMUM_PLANNER_SPEED,block->millimeters); + block->entry_speed = min(vmax_junction, v_allowable); + + // Initialize planner efficiency flags + // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds. + // If a block can de/ac-celerate from nominal speed to zero within the length of the block, then + // the current block and next block junction speeds are guaranteed to always be at their maximum + // junction speeds in deceleration and acceleration, respectively. This is due to how the current + // block nominal speed limits both the current and next maximum junction speeds. Hence, in both + // the reverse and forward planners, the corresponding block junction speed will always be at the + // the maximum junction speed and may always be ignored for any speed reduction checks. + if (block->nominal_speed <= v_allowable) { block->nominal_length_flag = true; } + else { block->nominal_length_flag = false; } + block->recalculate_flag = true; // Always calculate trapezoid for new block + + // Update previous path unit_vector and nominal speed + memcpy(previous_speed, current_speed, sizeof(previous_speed)); // previous_speed[] = current_speed[] + previous_nominal_speed = block->nominal_speed; + + #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 + else { + long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st); + float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * + (current_speed[E_AXIS] * current_speed[E_AXIS] * EXTRUTION_AREA * EXTRUTION_AREA)*256; + block->advance = advance; + if(acc_dist == 0) { + block->advance_rate = 0; + } + else { + block->advance_rate = advance / (float)acc_dist; + } + } + + #endif // ADVANCE + + + + + calculate_trapezoid_for_block(block, block->entry_speed/block->nominal_speed, + MINIMUM_PLANNER_SPEED/block->nominal_speed); + + // Move buffer head + block_buffer_head = next_buffer_head; + + // Update position + memcpy(position, target, sizeof(target)); // position[] = target[] + + planner_recalculate(); + #ifdef AUTOTEMP + getHighESpeed(); + #endif + 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]); + + previous_nominal_speed = 0.0; // Resets planner junction speeds. Assumes start from rest. + previous_speed[0] = 0.0; + previous_speed[1] = 0.0; + previous_speed[2] = 0.0; + previous_speed[3] = 0.0; +} + +#ifdef AUTOTEMP +void getHighESpeed() +{ + static float oldt=0; + if(!autotemp_enabled) + return; + if((target_temp+2) < autotemp_min) //probably temperature set to zero. + return; //do nothing + + float high=0; + uint8_t block_index = block_buffer_tail; + + while(block_index != block_buffer_head) + { + float se=block_buffer[block_index].steps_e/float(block_buffer[block_index].step_event_count)*block_buffer[block_index].nominal_rate; + //se; units steps/sec; + if(se>high) { - WRITE(CONTROLLERFAN_PIN, HIGH); //... turn the fan on + high=se; } + block_index = (block_index+1) & (BLOCK_BUFFER_SIZE - 1); + } + + float t=autotemp_min+high*autotemp_factor; + + if(t<autotemp_min) + t=autotemp_min; + + if(t>autotemp_max) + t=autotemp_max; + + if(oldt>t) + { + t=AUTOTEMP_OLDWEIGHT*oldt+(1-AUTOTEMP_OLDWEIGHT)*t; } + oldt=t; + autotemp_setpoint = (int)t; + } #endif -void manage_heater() + + + +// 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<<OCIE1A) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 &= ~(1<<OCIE1A) + +#ifdef ENDSTOPS_ONLY_FOR_HOMING + #define CHECK_ENDSTOPS if(check_endstops) +#else + #define CHECK_ENDSTOPS +#endif + +static block_t *current_block; // A pointer to the block currently being traced + +// Variables used by The Stepper Driver Interrupt +static unsigned char out_bits; // The next stepping-bits to be output +static long counter_x, // Counter variables for the bresenham line tracer + counter_y, + counter_z, + counter_e; +static unsigned long step_events_completed; // The number of step events executed in the current block +#ifdef ADVANCE + static long advance_rate, advance, final_advance = 0; + static short old_advance = 0; +#endif +static short e_steps; +static unsigned char busy = false; // TRUE when SIG_OUTPUT_COMPARE1A is being serviced. Used to avoid retriggering that handler. +static long acceleration_time, deceleration_time; +static unsigned short acc_step_rate; // needed for deccelaration start point +static char step_loops; +static unsigned short OCR1A_nominal; + +static volatile bool endstop_x_hit=false; +static volatile bool endstop_y_hit=false; +static volatile bool endstop_z_hit=false; + +static bool old_x_min_endstop=false; +static bool old_x_max_endstop=false; +static bool old_y_min_endstop=false; +static bool old_y_max_endstop=false; +static bool old_z_min_endstop=false; +static bool old_z_max_endstop=false; + +static bool check_endstops = true; + + + +// __________________________ +// /| |\ _________________ ^ +// / | | \ /| |\ | +// / | | \ / | | \ s +// / | | | | | \ p +// / | | | | | \ e +// +-----+------------------------+---+--+---------------+----+ e +// | BLOCK 1 | BLOCK 2 | d +// +// time -----> +// +// 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() { - if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) - return; - previous_millis_heater = millis(); - #ifdef HEATER_USES_THERMISTOR - current_raw = analogRead(TEMP_0_PIN); - #ifdef DEBUG_HEAT_MGMT - log_int("_HEAT_MGMT - analogRead(TEMP_0_PIN)", current_raw); - log_int("_HEAT_MGMT - NUMTEMPS", NUMTEMPS); - #endif - // 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 - if (!nma) nma = SMOOTHFACTOR * current_raw; - 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_temp = target_raw = 0; - WRITE(HEATER_0_PIN,LOW); - analogWrite(HEATER_0_PIN, 0); - #if LED_PIN>-1 - WRITE(LED_PIN,LOW); - #endif - }else{ - watchmillis = 0; - } - } - #endif - #ifdef MINTEMP - if(current_raw <= minttemp) - target_temp = target_raw = 0; + // TCNT1 = 0; + if(busy == false) + ENABLE_STEPPER_DRIVER_INTERRUPT(); +} + +void enable_endstops(bool check) +{ + check_endstops = check; +} + +FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) +{ + unsigned short timer; + if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY; + + if(step_rate > 20000) { // If steprate > 20kHz >> step 4 times + step_rate = (step_rate >> 2)&0x3fff; + step_loops = 4; + } + else if(step_rate > 10000) { // If steprate > 10kHz >> step 2 times + step_rate = (step_rate >> 1)&0x7fff; + step_loops = 2; + } + else { + step_loops = 1; + } + + if(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000); + step_rate -= (F_CPU/500000); // Correct for minimal speed + + if(step_rate >= (8*256)) // higher step rate + { // 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; }//(20kHz this should never happen) + return timer; +} + +// Initializes the trapezoid generator from the current block. Called whenever a new +// block begins. +FORCE_INLINE void trapezoid_generator_reset() +{ + #ifdef ADVANCE + advance = current_block->initial_advance; + final_advance = current_block->final_advance; + // Do E steps + advance steps + e_steps += ((advance >>8) - old_advance); + old_advance = advance >>8; #endif - #ifdef MAXTEMP - if(current_raw >= maxttemp) { - target_temp = target_raw = 0; - #if (ALARM_PIN > -1) - WRITE(ALARM_PIN,HIGH); + deceleration_time = 0; + + + // step_rate to timer interval + acc_step_rate = current_block->initial_rate; + acceleration_time = calc_timer(acc_step_rate); + OCR1A = acceleration_time; + OCR1A_nominal = calc_timer(current_block->nominal_rate); + +} + +// "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 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; +// #ifdef ADVANCE +// e_steps = 0; +// #endif + } + else { + OCR1A=2000; // 1kHz. + } + } + + 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; + + // Set direction en check limit switches + if ((out_bits & (1<<X_AXIS)) != 0) { // -direction + WRITE(X_DIR_PIN, INVERT_X_DIR); + CHECK_ENDSTOPS + { + #if X_MIN_PIN > -1 + bool x_min_endstop=(READ(X_MIN_PIN) != X_ENDSTOP_INVERT); + if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) { + endstop_x_hit=true; + step_events_completed = current_block->step_event_count; + } + old_x_min_endstop = x_min_endstop; #endif + } } - #endif - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) - #ifdef PIDTEMP - int current_temp = analog2temp(current_raw); - error = target_temp - current_temp; - int delta_temp = current_temp - prev_temp; - prev_temp = current_temp; - pTerm = ((long)PID_PGAIN * error) / 256; - const int H0 = min(HEATER_DUTY_FOR_SETPOINT(target_temp),HEATER_CURRENT); - heater_duty = H0 + pTerm; - if(error < 20){ - temp_iState += error; - temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = ((long)PID_IGAIN * temp_iState) / 256; - heater_duty += iTerm; + else { // +direction + WRITE(X_DIR_PIN,!INVERT_X_DIR); + CHECK_ENDSTOPS + { + #if X_MAX_PIN > -1 + bool x_max_endstop=(READ(X_MAX_PIN) != X_ENDSTOP_INVERT); + if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){ + endstop_x_hit=true; + step_events_completed = current_block->step_event_count; + } + old_x_max_endstop = x_max_endstop; + #endif } - int prev_error = abs(target_temp - prev_temp); - int log3 = 1; // discrete logarithm base 3, plus 1 - if(prev_error > 81){ prev_error /= 81; log3 += 4; } - if(prev_error > 9){ prev_error /= 9; log3 += 2; } - if(prev_error > 3){ prev_error /= 3; log3 ++; } - dTerm = ((long)PID_DGAIN * delta_temp) / (256*log3); - heater_duty += dTerm; - heater_duty = constrain(heater_duty, 0, HEATER_CURRENT); - analogWrite(HEATER_0_PIN, heater_duty); - #if LED_PIN>-1 - analogWrite(LED_PIN, constrain(LED_PWM_FOR_BRIGHTNESS(heater_duty),0,255)); - #endif - #else - if(current_raw >= target_raw) + } + + if ((out_bits & (1<<Y_AXIS)) != 0) { // -direction + WRITE(Y_DIR_PIN,INVERT_Y_DIR); + CHECK_ENDSTOPS { - WRITE(HEATER_0_PIN,LOW); - analogWrite(HEATER_0_PIN, 0); - #if LED_PIN>-1 - WRITE(LED_PIN,LOW); + #if Y_MIN_PIN > -1 + bool y_min_endstop=(READ(Y_MIN_PIN) != Y_ENDSTOP_INVERT); + if(y_min_endstop && old_y_min_endstop && (current_block->steps_y > 0)) { + endstop_y_hit=true; + step_events_completed = current_block->step_event_count; + } + old_y_min_endstop = y_min_endstop; #endif } - else + } + else { // +direction + WRITE(Y_DIR_PIN,!INVERT_Y_DIR); + CHECK_ENDSTOPS { - WRITE(HEATER_0_PIN,HIGH); - analogWrite(HEATER_0_PIN, HEATER_CURRENT); - #if LED_PIN > -1 - WRITE(LED_PIN,HIGH); + #if Y_MAX_PIN > -1 + bool y_max_endstop=(READ(Y_MAX_PIN) != Y_ENDSTOP_INVERT); + if(y_max_endstop && old_y_max_endstop && (current_block->steps_y > 0)){ + endstop_y_hit=true; + step_events_completed = current_block->step_event_count; + } + old_y_max_endstop = y_max_endstop; #endif } - #endif - #endif - - if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) - return; - previous_millis_bed_heater = millis(); - #ifndef TEMP_1_PIN - return; - #endif - #if TEMP_1_PIN == -1 - return; - #else - - #ifdef BED_USES_THERMISTOR - - current_bed_raw = analogRead(TEMP_1_PIN); - #ifdef DEBUG_HEAT_MGMT - log_int("_HEAT_MGMT - analogRead(TEMP_1_PIN)", current_bed_raw); - log_int("_HEAT_MGMT - BNUMTEMPS", BNUMTEMPS); - #endif - - // 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 - - - #ifdef MINTEMP - if(current_bed_raw >= target_bed_raw || current_bed_raw < minttemp) - #else - if(current_bed_raw >= target_bed_raw) - #endif - { - WRITE(HEATER_1_PIN,LOW); + if ((out_bits & (1<<Z_AXIS)) != 0) { // -direction + WRITE(Z_DIR_PIN,INVERT_Z_DIR); + CHECK_ENDSTOPS + { + #if Z_MIN_PIN > -1 + bool z_min_endstop=(READ(Z_MIN_PIN) != Z_ENDSTOP_INVERT); + if(z_min_endstop && old_z_min_endstop && (current_block->steps_z > 0)) { + endstop_z_hit=true; + step_events_completed = current_block->step_event_count; + } + old_z_min_endstop = z_min_endstop; + #endif + } } - else - { - WRITE(HEATER_1_PIN,HIGH); + else { // +direction + WRITE(Z_DIR_PIN,!INVERT_Z_DIR); + CHECK_ENDSTOPS + { + #if Z_MAX_PIN > -1 + bool z_max_endstop=(READ(Z_MAX_PIN) != Z_ENDSTOP_INVERT); + if(z_max_endstop && old_z_max_endstop && (current_block->steps_z > 0)) { + endstop_z_hit=true; + step_events_completed = current_block->step_event_count; + } + old_z_max_endstop = z_max_endstop; + #endif + } } - #endif + + #ifndef ADVANCE + if ((out_bits & (1<<E_AXIS)) != 0) { // -direction + WRITE(E_DIR_PIN,INVERT_E_DIR); + } + else { // +direction + WRITE(E_DIR_PIN,!INVERT_E_DIR); + } + #endif //!ADVANCE -#ifdef CONTROLLERFAN_PIN - controllerFan(); //Check if fan should be turned on to cool stepper drivers down -#endif -} -#if defined (HEATER_USES_THERMISTOR) || defined (BED_USES_THERMISTOR) -int temp2analog_thermistor(int celsius, const short table[][2], int numtemps) { - int raw = 0; - byte i; - for (i=1; i<numtemps; i++) - { - if (table[i][1] < celsius) - { - raw = table[i-1][0] + - (celsius - table[i-1][1]) * - (table[i][0] - table[i-1][0]) / - (table[i][1] - table[i-1][1]); + for(int8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves) - break; + #ifdef ADVANCE + counter_e += current_block->steps_e; + if (counter_e > 0) { + counter_e -= current_block->step_event_count; + if ((out_bits & (1<<E_AXIS)) != 0) { // - direction + e_steps--; + } + else { + e_steps++; + } + } + #endif //ADVANCE + + counter_x += current_block->steps_x; + if (counter_x > 0) { + WRITE(X_STEP_PIN, HIGH); + counter_x -= current_block->step_event_count; + WRITE(X_STEP_PIN, LOW); } - } - // Overflow: Set to last value in the table - if (i == numtemps) raw = table[i-1][0]; + 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); + } - return 1023 - raw; -} -#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); + } -#if defined (HEATER_USES_AD595) || defined (BED_USES_AD595) -int temp2analog_ad595(int celsius) { - return celsius * 1024 / (500); -} -#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 + step_events_completed += 1; + if(step_events_completed >= current_block->step_event_count) break; + } + // Calculare new timer value + unsigned short timer; + unsigned short step_rate; + if (step_events_completed <= (unsigned long int)current_block->accelerate_until) { + + MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate); + acc_step_rate += current_block->initial_rate; + + // upper limit + if(acc_step_rate > current_block->nominal_rate) + acc_step_rate = current_block->nominal_rate; + + // step_rate to timer interval + timer = calc_timer(acc_step_rate); + OCR1A = timer; + acceleration_time += timer; + #ifdef ADVANCE + for(int8_t i=0; i < step_loops; i++) { + advance += advance_rate; + } + //if(advance > current_block->advance) advance = current_block->advance; + // Do E steps + advance steps + e_steps += ((advance >>8) - old_advance); + old_advance = advance >>8; + + #endif + } + else if (step_events_completed > (unsigned long int)current_block->decelerate_after) { + MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate); + + if(step_rate > acc_step_rate) { // Check step_rate stays positive + step_rate = current_block->final_rate; + } + else { + step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. + } + + // lower limit + if(step_rate < current_block->final_rate) + step_rate = current_block->final_rate; + + // step_rate to timer interval + timer = calc_timer(step_rate); + OCR1A = timer; + deceleration_time += timer; + #ifdef ADVANCE + for(int8_t i=0; i < step_loops; i++) { + advance -= advance_rate; + } + if(advance < final_advance) advance = final_advance; + // Do E steps + advance steps + e_steps += ((advance >>8) - old_advance); + old_advance = advance >>8; + #endif //ADVANCE + } + else { + OCR1A = OCR1A_nominal; + } -#if defined (HEATER_USES_MAX6675) || defined (BED_USES_MAX6675) -int temp2analog_max6675(int celsius) { - return celsius * 4; + // If current block is finished, reset pointer + if (step_events_completed >= current_block->step_event_count) { + current_block = NULL; + plan_discard_current_block(); + } + } } -#endif -#if defined (HEATER_USES_THERMISTOR) || defined (BED_USES_THERMISTOR) -int analog2temp_thermistor(int raw,const short table[][2], int numtemps) { - int celsius = 0; - byte i; - - raw = 1023 - raw; +#ifdef ADVANCE - for (i=1; i<numtemps; i++) - { - if (table[i][0] > raw) +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) +{ + old_OCR0A += 52; // ~10kHz interrupt (250000 / 26 = 9615kHz) + OCR0A = old_OCR0A; + // Set E direction (Depends on E direction + advance) + for(unsigned char i=0; i<4;i++) + { + if (e_steps != 0) { - celsius = table[i-1][1] + - (raw - table[i-1][0]) * - (table[i][1] - table[i-1][1]) / - (table[i][0] - table[i-1][0]); - - break; + WRITE(E0_STEP_PIN, LOW); + if (e_steps < 0) { + WRITE(E0_DIR_PIN, INVERT_E0_DIR); + e_steps++; + WRITE(E0_STEP_PIN, HIGH); + } + else if (e_steps > 0) { + WRITE(E0_DIR_PIN, !INVERT_E0_DIR); + e_steps--; + WRITE(E0_STEP_PIN, HIGH); + } } } + } +#endif // ADVANCE - // Overflow: Set to last value in the table - if (i == numtemps) celsius = table[i-1][1]; - - return celsius; -} -#endif - -#if defined (HEATER_USES_AD595) || defined (BED_USES_AD595) -int analog2temp_ad595(int raw) { - return raw * 500 / 1024; -} -#endif - -#if defined (HEATER_USES_MAX6675) || defined (BED_USES_MAX6675) -int analog2temp_max6675(int raw) { - return raw / 4; -} -#endif - -inline void kill() +void st_init() { - #if TEMP_0_PIN > -1 - target_raw=0; - WRITE(HEATER_0_PIN,LOW); - #endif - #if TEMP_1_PIN > -1 - target_bed_raw=0; - if(HEATER_1_PIN > -1) WRITE(HEATER_1_PIN,LOW); + // waveform generation = 0100 = CTC + TCCR1B &= ~(1<<WGM13); + TCCR1B |= (1<<WGM12); + TCCR1A &= ~(1<<WGM11); + TCCR1A &= ~(1<<WGM10); + + // output mode = 00 (disconnected) + TCCR1A &= ~(3<<COM1A0); + TCCR1A &= ~(3<<COM1B0); + + // Set the timer pre-scaler + // Generally we use a divider of 8, resulting in a 2MHz timer + // frequency on a 16MHz MCU. If you are going to change this, be + // sure to regenerate speed_lookuptable.h with + // create_speed_lookuptable.py + TCCR1B = (TCCR1B & ~(0x07<<CS10)) | (2<<CS10); // 2MHz timer + + OCR1A = 0x4000; + TCNT1 = 0; + ENABLE_STEPPER_DRIVER_INTERRUPT(); + +#ifdef ADVANCE + #if defined(TCCR0A) && defined(WGM01) + TCCR0A &= ~(1<<WGM01); + TCCR0A &= ~(1<<WGM00); + #endif + e_steps = 0; + TIMSK0 |= (1<<OCIE0A); +#endif //ADVANCE + + #ifdef ENDSTOPS_ONLY_FOR_HOMING + enable_endstops(false); + #else + enable_endstops(true); #endif - disable_x(); - disable_y(); - disable_z(); - disable_e(); - - if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); + sei(); } -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(); } +// Block until all buffered steps are executed +void st_synchronize() +{ + while(blocks_queued()) { + manage_heater(); + manage_inactivity(1); + } } -#ifdef RAMP_ACCELERATION -void setup_acceleration() { - for (int i=0; i < NUM_AXIS; i++) { - axis_max_interval[i] = 100000000.0 / (max_start_speed_units_per_second[i] * axis_steps_per_unit[i]); - axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; - axis_travel_steps_per_sqr_second[i] = max_travel_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i]; - } -} -#endif #ifdef DEBUG void log_message(char* message) { diff --git a/Sprinter/arc_func.cpp b/Sprinter/arc_func.cpp new file mode 100644 index 0000000..255129f --- /dev/null +++ b/Sprinter/arc_func.cpp @@ -0,0 +1,147 @@ +/* + arc_func.c - high level interface for issuing motion commands + Part of Grbl + + Copyright (c) 2009-2011 Simen Svale Skogsrud + Copyright (c) 2011 Sungeun K. Jeon + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grbl. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <avr/pgmspace.h> +#include <math.h> + +#include "Configuration.h" +#include "Sprinter.h" + +#ifdef USE_ARC_FUNCTION +// The arc is approximated by generating a huge number of tiny, linear segments. The length of each +// segment is configured in settings.mm_per_arc_segment. +void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8_t axis_1, + uint8_t axis_linear, float feed_rate, float radius, uint8_t isclockwise) +{ + // int acceleration_manager_was_enabled = plan_is_acceleration_manager_enabled(); + // plan_set_acceleration_manager_enabled(false); // disable acceleration management for the duration of the arc + float center_axis0 = position[axis_0] + offset[axis_0]; + float center_axis1 = position[axis_1] + offset[axis_1]; + float linear_travel = target[axis_linear] - position[axis_linear]; + float extruder_travel = target[E_AXIS] - position[E_AXIS]; + float r_axis0 = -offset[axis_0]; // Radius vector from center to current location + float r_axis1 = -offset[axis_1]; + float rt_axis0 = target[axis_0] - center_axis0; + float rt_axis1 = target[axis_1] - center_axis1; + + // CCW angle between position and target from circle center. Only one atan2() trig computation required. + float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1); + if (angular_travel < 0) { angular_travel += 2*M_PI; } + if (isclockwise) { angular_travel -= 2*M_PI; } + + float millimeters_of_travel = hypot(angular_travel*radius, fabs(linear_travel)); + if (millimeters_of_travel < 0.001) { return; } + uint16_t segments = floor(millimeters_of_travel/MM_PER_ARC_SEGMENT); + /* + // Multiply inverse feed_rate to compensate for the fact that this movement is approximated + // by a number of discrete segments. The inverse feed_rate should be correct for the sum of + // all segments. + if (invert_feed_rate) { feed_rate *= segments; } + */ + float theta_per_segment = angular_travel/segments; + float linear_per_segment = linear_travel/segments; + float extruder_per_segment = extruder_travel/segments; + + /* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector, + and phi is the angle of rotation. Based on the solution approach by Jens Geisler. + r_T = [cos(phi) -sin(phi); + sin(phi) cos(phi] * r ; + + For arc generation, the center of the circle is the axis of rotation and the radius vector is + defined from the circle center to the initial position. Each line segment is formed by successive + vector rotations. This requires only two cos() and sin() computations to form the rotation + matrix for the duration of the entire arc. Error may accumulate from numerical round-off, since + all double numbers are single precision on the Arduino. (True double precision will not have + round off issues for CNC applications.) Single precision error can accumulate to be greater than + tool precision in some cases. Therefore, arc path correction is implemented. + + Small angle approximation may be used to reduce computation overhead further. This approximation + holds for everything, but very small circles and large mm_per_arc_segment values. In other words, + theta_per_segment would need to be greater than 0.1 rad and N_ARC_CORRECTION would need to be large + to cause an appreciable drift error. N_ARC_CORRECTION~=25 is more than small enough to correct for + numerical drift error. N_ARC_CORRECTION may be on the order a hundred(s) before error becomes an + issue for CNC machines with the single precision Arduino calculations. + + This approximation also allows mc_arc to immediately insert a line segment into the planner + without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied + a correction, the planner should have caught up to the lag caused by the initial mc_arc overhead. + This is important when there are successive arc motions. + */ + // Vector rotation matrix values + float cos_T = 1-0.5*theta_per_segment*theta_per_segment; // Small angle approximation + float sin_T = theta_per_segment; + + float arc_target[4]; + float sin_Ti; + float cos_Ti; + float r_axisi; + uint16_t i; + int8_t count = 0; + + // Initialize the linear axis + arc_target[axis_linear] = position[axis_linear]; + + // Initialize the extruder axis + arc_target[E_AXIS] = position[E_AXIS]; + + for (i = 1; i<segments; i++) + { // Increment (segments-1) + + if((count == 10) || (count == 15)) + { + //Read the next two Commands while arc is calculating + check_buffer_while_arc(); + } + + if (count < N_ARC_CORRECTION) //25 pieces + { + // Apply vector rotation matrix + r_axisi = r_axis0*sin_T + r_axis1*cos_T; + r_axis0 = r_axis0*cos_T - r_axis1*sin_T; + r_axis1 = r_axisi; + count++; + } + else + { + // Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments. + // Compute exact location by applying transformation matrix from initial radius vector(=-offset). + cos_Ti = cos(i*theta_per_segment); + sin_Ti = sin(i*theta_per_segment); + r_axis0 = -offset[axis_0]*cos_Ti + offset[axis_1]*sin_Ti; + r_axis1 = -offset[axis_0]*sin_Ti - offset[axis_1]*cos_Ti; + count = 0; + } + + // Update arc_target location + arc_target[axis_0] = center_axis0 + r_axis0; + arc_target[axis_1] = center_axis1 + r_axis1; + arc_target[axis_linear] += linear_per_segment; + arc_target[E_AXIS] += extruder_per_segment; + + plan_buffer_line(arc_target[X_AXIS], arc_target[Y_AXIS], arc_target[Z_AXIS], arc_target[E_AXIS], feed_rate); + + } + // Ensure last segment arrives at target location. + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], feed_rate); + + // plan_set_acceleration_manager_enabled(acceleration_manager_was_enabled); +} +#endif diff --git a/Sprinter/arc_func.h b/Sprinter/arc_func.h new file mode 100644 index 0000000..03ecd9d --- /dev/null +++ b/Sprinter/arc_func.h @@ -0,0 +1,32 @@ +/* + arc_func.h - high level interface for issuing motion commands + Part of Grbl + + Copyright (c) 2009-2011 Simen Svale Skogsrud + Copyright (c) 2011 Sungeun K. Jeon + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grbl. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef arc_func_h +#define arc_func_h + +// Execute an arc in offset mode format. position == current xyz, target == target xyz, +// offset == offset from current xyz, axis_XXX defines circle plane in tool space, axis_linear is +// the direction of helical travel, radius == circle radius, isclockwise boolean. Used +// for vector transformation direction. +void mc_arc(float *position, float *target, float *offset, unsigned char axis_0, unsigned char axis_1, + unsigned char axis_linear, float feed_rate, float radius, unsigned char isclockwise); + +#endif diff --git a/Sprinter/heater.cpp b/Sprinter/heater.cpp new file mode 100644 index 0000000..9d494b2 --- /dev/null +++ b/Sprinter/heater.cpp @@ -0,0 +1,591 @@ +/* + Reprap heater funtions based on Sprinter + + + 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 <http://www.gnu.org/licenses/>. */ + +/* + This softwarepart for Heatercontrol is based on Sprinter + big thanks to kliment (https://github.com/kliment/Sprinter) +*/ + + +#include <avr/pgmspace.h> + +#include "heater.h" +#include "fastio.h" +#include "pins.h" +#include "Sprinter.h" + +#ifdef CONTROLLERFAN_PIN + void controllerFan(void); +#endif + +// Manage heater variables. For a thermistor or AD595 thermocouple, raw values refer to the +// reading from the analog pin. For a MAX6675 thermocouple, the raw value is the temperature in 0.25 +// degree increments (i.e. 100=25 deg). + +int target_raw = 0; +int target_temp = 0; +int current_raw = 0; +int current_raw_maxval = -32000; +int current_raw_minval = 32000; +int tt_maxval; +int tt_minval; +int target_bed_raw = 0; +int current_bed_raw = 0; +unsigned long previous_millis_heater, previous_millis_bed_heater, previous_millis_monitor; + +#ifdef PIDTEMP + volatile unsigned char g_heater_pwm_val = 0; + + unsigned char PWM_off_time = 0; + unsigned char PWM_out_on = 0; + + int temp_iState = 0; + int temp_dState = 0; + int prev_temp = 0; + int pTerm; + int iTerm; + int dTerm; + //int output; + int error; + int heater_duty = 0; + const int temp_iState_min = 256L * -PID_INTEGRAL_DRIVE_MAX / PID_IGAIN; + const int temp_iState_max = 256L * PID_INTEGRAL_DRIVE_MAX / PID_IGAIN; +#endif + + +#ifdef AUTOTEMP + float autotemp_max=AUTO_TEMP_MAX; + float autotemp_min=AUTO_TEMP_MIN; + float autotemp_factor=AUTO_TEMP_FACTOR; + int autotemp_setpoint=0; + bool autotemp_enabled=true; +#endif + +#ifndef HEATER_CURRENT + #define HEATER_CURRENT 255 +#endif + +#ifdef SMOOTHING + uint32_t nma = 0; +#endif + +#ifdef WATCHPERIOD + int watch_raw = -1000; + unsigned long watchmillis = 0; +#endif + +#ifdef MINTEMP + int minttemp = temp2analogh(MINTEMP); +#endif + +#ifdef MAXTEMP + int maxttemp = temp2analogh(MAXTEMP); +#endif + + + +#define HEAT_INTERVAL 250 +#ifdef HEATER_USES_MAX6675 +unsigned long max6675_previous_millis = 0; +int max6675_temp = 2000; + +int read_max6675() +{ + if (millis() - max6675_previous_millis < HEAT_INTERVAL) + return max6675_temp; + + max6675_previous_millis = millis(); + + max6675_temp = 0; + + #ifdef PRR + PRR &= ~(1<<PRSPI); + #elif defined PRR0 + PRR0 &= ~(1<<PRSPI); + #endif + + SPCR = (1<<MSTR) | (1<<SPE) | (1<<SPR0); + + // enable TT_MAX6675 + WRITE(MAX6675_SS, 0); + + // ensure 100ns delay - a bit extra is fine + delay(1); + + // read MSB + SPDR = 0; + for (;(SPSR & (1<<SPIF)) == 0;); + max6675_temp = SPDR; + max6675_temp <<= 8; + + // read LSB + SPDR = 0; + for (;(SPSR & (1<<SPIF)) == 0;); + max6675_temp |= SPDR; + + // disable TT_MAX6675 + WRITE(MAX6675_SS, 1); + + if (max6675_temp & 4) + { + // thermocouple open + max6675_temp = 2000; + } + else + { + max6675_temp = max6675_temp >> 3; + } + + return max6675_temp; +} +#endif + + +#ifdef PID_SOFT_PWM + + void init_Timer2_softpwm(void) + { + // This is a simple SOFT PWM with 500 Hz for Extruder Heating + + + TIFR2 = (1 << TOV2); // clear interrupt flag + TCCR2B = (1 << CS22) | (1 << CS20); // start timer (ck/128 prescalar) + TCCR2A = (1 << WGM21); // CTC mode + OCR2A = 128; // We want to have at least 30Hz or else it gets choppy + TIMSK2 = (1 << OCIE2A); // enable timer2 output compare match interrupt + + } + + + ISR(TIMER2_COMPA_vect) + { + + + if(g_heater_pwm_val < 2) + { + #if LED_PIN > -1 + WRITE(LED_PIN,LOW); + #endif + WRITE(HEATER_0_PIN,LOW); + PWM_out_on = 0; + OCR2A = 128; + } + else if(g_heater_pwm_val > 253) + { + #if LED_PIN > -1 + WRITE(LED_PIN,HIGH); + #endif + WRITE(HEATER_0_PIN,HIGH); + PWM_out_on = 1; + OCR2A = 128; + } + else + { + + if(PWM_out_on == 1) + { + + #if LED_PIN > -1 + WRITE(LED_PIN,LOW); + #endif + WRITE(HEATER_0_PIN,LOW); + PWM_out_on = 0; + OCR2A = PWM_off_time; + } + else + { + + #if LED_PIN > -1 + WRITE(LED_PIN,HIGH); + #endif + WRITE(HEATER_0_PIN,HIGH); + PWM_out_on = 1; + + if(g_heater_pwm_val > 253) + { + OCR2A = 253; + PWM_off_time = 2; + } + else if(g_heater_pwm_val < 2) + { + OCR2A = 2; + PWM_off_time = 253; + } + else + { + OCR2A = g_heater_pwm_val; + PWM_off_time = 255 - g_heater_pwm_val; + } + + } + } + + + } + #endif + + + + void manage_heater() + { + + //Temperatur Monitor for repetier + if((millis() - previous_millis_monitor) > 250 ) + { + previous_millis_monitor = millis(); + if(manage_monitor <= 1) + { + showString(PSTR("MTEMP:")); + Serial.print(millis()); + if(manage_monitor<1) + { + showString(PSTR(" ")); + Serial.print(analog2temp(current_raw)); + showString(PSTR(" ")); + Serial.print(target_temp); + showString(PSTR(" ")); + #ifdef PIDTEMP + Serial.println(heater_duty); + #else + #if (HEATER_0_PIN > -1) + if(READ(HEATER_0_PIN)) + Serial.println(255); + else + Serial.println(0); + #else + Serial.println(0); + #endif + #endif + } + #if THERMISTORBED!=0 + else + { + showString(PSTR(" ")); + Serial.print(analog2tempBed(current_bed_raw)); + showString(PSTR(" ")); + Serial.print(analog2tempBed(target_bed_raw)); + showString(PSTR(" ")); + #if (HEATER_1_PIN > -1) + if(READ(HEATER_1_PIN)) + Serial.println(255); + else + Serial.println(0); + #else + Serial.println(0); + #endif + } + #endif + + } + + } + // ENDE Temperatur Monitor for repetier + + if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) + return; + + previous_millis_heater = millis(); + + #ifdef HEATER_USES_THERMISTOR + current_raw = analogRead(TEMP_0_PIN); + #ifdef DEBUG_HEAT_MGMT + log_int("_HEAT_MGMT - analogRead(TEMP_0_PIN)", current_raw); + log_int("_HEAT_MGMT - NUMTEMPS", NUMTEMPS); + #endif + // 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 + + //MIN / MAX save to display the jitter of Heaterbarrel + if(current_raw > current_raw_maxval) + current_raw_maxval = current_raw; + + if(current_raw < current_raw_minval) + current_raw_minval = current_raw; + + #ifdef SMOOTHING + if (!nma) nma = SMOOTHFACTOR * current_raw; + 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_temp = target_raw = 0; + WRITE(HEATER_0_PIN,LOW); + + #ifdef PID_SOFT_PWM + g_heater_pwm_val = 0; + #else + analogWrite(HEATER_0_PIN, 0); + #if LED_PIN>-1 + WRITE(LED_PIN,LOW); + #endif + #endif + } + else + { + watchmillis = 0; + } + } + #endif + + //If tmp is lower then MINTEMP stop the Heater + //or it os better to deaktivate the uutput PIN or PWM ? + #ifdef MINTEMP + if(current_raw <= minttemp) + target_temp = target_raw = 0; + #endif + + #ifdef MAXTEMP + if(current_raw >= maxttemp) + { + target_temp = target_raw = 0; + + #if (ALARM_PIN > -1) + WRITE(ALARM_PIN,HIGH); + #endif + } + #endif + + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595) + #ifdef PIDTEMP + + int current_temp = analog2temp(current_raw); + error = target_temp - current_temp; + int delta_temp = current_temp - prev_temp; + + prev_temp = current_temp; + pTerm = ((long)PID_PGAIN * error) / 256; + const int H0 = min(HEATER_DUTY_FOR_SETPOINT(target_temp),HEATER_CURRENT); + heater_duty = H0 + pTerm; + + if(error < 30) + { + temp_iState += error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = ((long)PID_IGAIN * temp_iState) / 256; + heater_duty += iTerm; + } + + int prev_error = abs(target_temp - prev_temp); + int log3 = 1; // discrete logarithm base 3, plus 1 + + if(prev_error > 81){ prev_error /= 81; log3 += 4; } + if(prev_error > 9){ prev_error /= 9; log3 += 2; } + if(prev_error > 3){ prev_error /= 3; log3 ++; } + + dTerm = ((long)PID_DGAIN * delta_temp) / (256*log3); + heater_duty += dTerm; + heater_duty = constrain(heater_duty, 0, HEATER_CURRENT); + + #ifdef PID_SOFT_PWM + g_heater_pwm_val = (unsigned char)heater_duty; + #else + analogWrite(HEATER_0_PIN, heater_duty); + + #if LED_PIN>-1 + analogWrite(LED_PIN, constrain(LED_PWM_FOR_BRIGHTNESS(heater_duty),0,255)); + #endif + #endif + + #else + + if(current_raw >= target_raw) + { + WRITE(HEATER_0_PIN,LOW); + #if LED_PIN>-1 + WRITE(LED_PIN,LOW); + #endif + } + else + { + WRITE(HEATER_0_PIN,HIGH); + #if LED_PIN > -1 + WRITE(LED_PIN,HIGH); + #endif + } + #endif + #endif + + if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) + return; + + previous_millis_bed_heater = millis(); + + #ifndef TEMP_1_PIN + return; + #endif + + #if TEMP_1_PIN == -1 + return; + #else + + #ifdef BED_USES_THERMISTOR + + current_bed_raw = analogRead(TEMP_1_PIN); + + #ifdef DEBUG_HEAT_MGMT + log_int("_HEAT_MGMT - analogRead(TEMP_1_PIN)", current_bed_raw); + log_int("_HEAT_MGMT - BNUMTEMPS", BNUMTEMPS); + #endif + + // 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 + + + #ifdef MINTEMP + if(current_bed_raw >= target_bed_raw || current_bed_raw < minttemp) + #else + if(current_bed_raw >= target_bed_raw) + #endif + { + WRITE(HEATER_1_PIN,LOW); + } + else + { + WRITE(HEATER_1_PIN,HIGH); + } + #endif + +#ifdef CONTROLLERFAN_PIN + controllerFan(); //Check if fan should be turned on to cool stepper drivers down +#endif + +} + +#if defined (HEATER_USES_THERMISTOR) || defined (BED_USES_THERMISTOR) +int temp2analog_thermistor(int celsius, const short table[][2], int numtemps) +{ + int raw = 0; + byte i; + + for (i=1; i<numtemps; i++) + { + if (table[i][1] < celsius) + { + raw = table[i-1][0] + + (celsius - table[i-1][1]) * + (table[i][0] - table[i-1][0]) / + (table[i][1] - table[i-1][1]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == numtemps) raw = table[i-1][0]; + + return 1023 - raw; +} +#endif + +#if defined (HEATER_USES_AD595) || defined (BED_USES_AD595) +int temp2analog_ad595(int celsius) +{ + return celsius * 1024 / (500); +} +#endif + +#if defined (HEATER_USES_MAX6675) || defined (BED_USES_MAX6675) +int temp2analog_max6675(int celsius) +{ + return celsius * 4; +} +#endif + +#if defined (HEATER_USES_THERMISTOR) || defined (BED_USES_THERMISTOR) +int analog2temp_thermistor(int raw,const short table[][2], int numtemps) { + int celsius = 0; + byte i; + + raw = 1023 - raw; + + for (i=1; i<numtemps; i++) + { + if (table[i][0] > raw) + { + celsius = table[i-1][1] + + (raw - table[i-1][0]) * + (table[i][1] - table[i-1][1]) / + (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; +} +#endif + +#if defined (HEATER_USES_AD595) || defined (BED_USES_AD595) +int analog2temp_ad595(int raw) +{ + return raw * 500 / 1024; +} +#endif + +#if defined (HEATER_USES_MAX6675) || defined (BED_USES_MAX6675) +int analog2temp_max6675(int raw) +{ + return raw / 4; +} +#endif + +#ifdef CONTROLLERFAN_PIN +unsigned long lastMotor = 0; //Save the time for when a motor was turned on last +unsigned long lastMotorCheck = 0; + +void controllerFan() +{ + if ((millis() - lastMotorCheck) >= 2500) //Not a time critical function, so we only check every 2500ms + { + lastMotorCheck = millis(); + + if(!READ(X_ENABLE_PIN) || !READ(Y_ENABLE_PIN) || !READ(Z_ENABLE_PIN) || !READ(E_ENABLE_PIN)) //If any of the drivers are enabled... + { + lastMotor = millis(); //... set time to NOW so the fan will turn on + } + + if ((millis() - lastMotor) >= (CONTROLLERFAN_SEC*1000UL) || lastMotor == 0) //If the last time any driver was enabled, is longer since than CONTROLLERSEC... + { + WRITE(CONTROLLERFAN_PIN, LOW); //... turn the fan off + } + else + { + WRITE(CONTROLLERFAN_PIN, HIGH); //... turn the fan on + } + } +} +#endif + diff --git a/Sprinter/heater.h b/Sprinter/heater.h new file mode 100644 index 0000000..a1d2917 --- /dev/null +++ b/Sprinter/heater.h @@ -0,0 +1,119 @@ +/* + Reprap heater funtions based on Sprinter + + 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 <http://www.gnu.org/licenses/>. */ + +/* + This softwarepart for Heatercontrol is based on Sprinter + big thanks to kliment (https://github.com/kliment/Sprinter) + +*/ + + +#include "Configuration.h" +#include "thermistortables.h" + +#if defined HEATER_USES_THERMISTOR +#define temp2analogh( c ) temp2analog_thermistor(c,temptable,NUMTEMPS) +#define analog2temp( c ) analog2temp_thermistor(c,temptable,NUMTEMPS) +#elif defined HEATER_USES_AD595 +#define temp2analogh( c ) temp2analog_ad595(c) +#define analog2temp( c ) analog2temp_ad595(c) +#elif defined HEATER_USES_MAX6675 +#define temp2analogh( c ) temp2analog_max6675(c) +#define analog2temp( c ) analog2temp_max6675(c) +#endif + +#if defined BED_USES_THERMISTOR +#define temp2analogBed( c ) temp2analog_thermistor((c),bedtemptable,BNUMTEMPS) +#define analog2tempBed( c ) analog2temp_thermistor((c),bedtemptable,BNUMTEMPS) +#elif defined BED_USES_AD595 +#define temp2analogBed( c ) temp2analog_ad595(c) +#define analog2tempBed( c ) analog2temp_ad595(c) +#elif defined BED_USES_MAX6675 +#define temp2analogBed( c ) temp2analog_max6675(c) +#define analog2tempBed( c ) analog2temp_max6675(c) +#endif + +#if defined (HEATER_USES_THERMISTOR) || defined (BED_USES_THERMISTOR) +int temp2analog_thermistor(int celsius, const short table[][2], int numtemps); +int analog2temp_thermistor(int raw,const short table[][2], int numtemps); +#endif + +#if defined (HEATER_USES_AD595) || defined (BED_USES_AD595) +int temp2analog_ad595(int celsius); +int analog2temp_ad595(int raw); +#endif + +#if defined (HEATER_USES_MAX6675) || defined (BED_USES_MAX6675) +int temp2analog_max6675(int celsius); +int analog2temp_max6675(int raw); +#endif + + +extern int target_raw; +extern int target_temp; +extern int current_raw; +extern int current_raw_maxval; +extern int current_raw_minval; +extern int tt_maxval; +extern int tt_minval; +extern int target_bed_raw; +extern int current_bed_raw; +extern unsigned long previous_millis_heater, previous_millis_bed_heater; +extern unsigned char manage_monitor; + +#ifdef PIDTEMP + extern volatile unsigned char g_heater_pwm_val; + + extern unsigned char PWM_off_time; + extern unsigned char PWM_out_on; + + extern int temp_iState; + extern int temp_dState; + extern int prev_temp; + extern int pTerm; + extern int iTerm; + extern int dTerm; + extern int error; + extern int heater_duty; +#endif + + +#ifdef AUTOTEMP + extern float autotemp_max; + extern float autotemp_min; + extern float autotemp_factor; + extern int autotemp_setpoint; + extern bool autotemp_enabled; +#endif + + +#ifdef SMOOTHING + extern uint32_t nma; +#endif + +#ifdef WATCHPERIOD + extern int watch_raw; + extern unsigned long watchmillis; +#endif + + + + +#ifdef PID_SOFT_PWM + void init_Timer2_softpwm(void); +#endif + +void manage_heater(); diff --git a/Sprinter/pins.h b/Sprinter/pins.h index d036610..63ea464 100644 --- a/Sprinter/pins.h +++ b/Sprinter/pins.h @@ -669,7 +669,6 @@ #define Y_ENABLE_PIN 14 #define Z_ENABLE_PIN 26 #define E_ENABLE_PIN 14 - #else #define HEATER_1_PIN 14 // (bed) @@ -688,6 +687,65 @@ #endif /**************************************************************************************** +* Gen7 pin assignment +* +**************************************************************************************** +* for Gen7 to work properly, you should reset your fuses to lfuse= 0xF7 ; hfuse = 0xD4 ; efuse = FD; +* else you will always get a "brown out reset" loop resetting the firmware +* you need a programmer to set the fuses +**/ +#if MOTHERBOARD == 71 //GEN7 with 20 Mhz +#define MOTHERBOARD 7 +#define QUARZ_20MHZ +#endif + +#if MOTHERBOARD == 7 +#define KNOWN_BOARD 1 + +#if !defined(__AVR_ATmega644P__) && !defined(__AVR_ATmega1284P__) && !defined(__AVR_ATmega644__) + #error Oops! Make sure you have 'Sanguino' selected from the 'Tools -> Boards' menu. +#endif + +//x axis pins + #define X_STEP_PIN 19 + #define X_DIR_PIN 18 + #define X_ENABLE_PIN 24 + #define X_MIN_PIN 7 + #define X_MAX_PIN -1 //X - Maxpin is 6 + + //y axis pins + #define Y_STEP_PIN 23 + #define Y_DIR_PIN 22 + #define Y_ENABLE_PIN 24 + #define Y_MIN_PIN 5 + #define Y_MAX_PIN -1 //Y - Maxpin is 2 + + //z axis pins + #define Z_STEP_PIN 26 + #define Z_DIR_PIN 25 + #define Z_ENABLE_PIN 24 + #define Z_MIN_PIN 1 + #define Z_MAX_PIN -1 //Z - Maxpin is 0 + + //extruder pins + #define E_STEP_PIN 28 + #define E_DIR_PIN 27 + #define E_ENABLE_PIN 24 + #define TEMP_0_PIN 1 // Extruder + #define HEATER_0_PIN 4 // Extruder + #define HEATER_1_PIN 3 // Bed + + + #define SDPOWER -1 + #define SDSS -1 + #define LED_PIN -1 + #define TEMP_1_PIN 2 //Bed + #define FAN_PIN -1 + #define PS_ON_PIN 15 + +#endif + +/**************************************************************************************** * Teensylu 0.7 pin assingments (ATMEGA90USB) * Requires the Teensyduino software with Teensy2.0++ selected in arduino IDE! ****************************************************************************************/ diff --git a/Sprinter/speed_lookuptable.h b/Sprinter/speed_lookuptable.h new file mode 100644 index 0000000..1b957b4 --- /dev/null +++ b/Sprinter/speed_lookuptable.h @@ -0,0 +1,151 @@ +#ifndef SPEED_LOOKUPTABLE_H +#define SPEED_LOOKUPTABLE_H + +#include <avr/pgmspace.h> + + + #if F_CPU == 16000000 + const 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}, + { 323, 13}, { 310, 11}, { 299, 11}, { 288, 11}, { 277, 9}, { 268, 9}, { 259, 8}, { 251, 8}, + { 243, 8}, { 235, 7}, { 228, 6}, { 222, 6}, { 216, 6}, { 210, 6}, { 204, 5}, { 199, 5}, + { 194, 5}, { 189, 4}, { 185, 4}, { 181, 4}, { 177, 4}, { 173, 4}, { 169, 4}, { 165, 3}, + { 162, 3}, { 159, 4}, { 155, 3}, { 152, 3}, { 149, 2}, { 147, 3}, { 144, 3}, { 141, 2}, + { 139, 3}, { 136, 2}, { 134, 2}, { 132, 3}, { 129, 2}, { 127, 2}, { 125, 2}, { 123, 2}, + { 121, 2}, { 119, 1}, { 118, 2}, { 116, 2}, { 114, 1}, { 113, 2}, { 111, 2}, { 109, 1}, + { 108, 2}, { 106, 1}, { 105, 2}, { 103, 1}, { 102, 1}, { 101, 1}, { 100, 2}, { 98, 1}, + { 97, 1}, { 96, 1}, { 95, 2}, { 93, 1}, { 92, 1}, { 91, 1}, { 90, 1}, { 89, 1}, + { 88, 1}, { 87, 1}, { 86, 1}, { 85, 1}, { 84, 1}, { 83, 0}, { 83, 1}, { 82, 1}, + { 81, 1}, { 80, 1}, { 79, 1}, { 78, 0}, { 78, 1}, { 77, 1}, { 76, 1}, { 75, 0}, + { 75, 1}, { 74, 1}, { 73, 1}, { 72, 0}, { 72, 1}, { 71, 1}, { 70, 0}, { 70, 1}, + { 69, 0}, { 69, 1}, { 68, 1}, { 67, 0}, { 67, 1}, { 66, 0}, { 66, 1}, { 65, 0}, + { 65, 1}, { 64, 1}, { 63, 0}, { 63, 1}, { 62, 0}, { 62, 1}, { 61, 0}, { 61, 1}, + { 60, 0}, { 60, 0}, { 60, 1}, { 59, 0}, { 59, 1}, { 58, 0}, { 58, 1}, { 57, 0}, + { 57, 1}, { 56, 0}, { 56, 0}, { 56, 1}, { 55, 0}, { 55, 1}, { 54, 0}, { 54, 0}, + { 54, 1}, { 53, 0}, { 53, 0}, { 53, 1}, { 52, 0}, { 52, 0}, { 52, 1}, { 51, 0}, + { 51, 0}, { 51, 1}, { 50, 0}, { 50, 0}, { 50, 1}, { 49, 0}, { 49, 0}, { 49, 1}, + { 48, 0}, { 48, 0}, { 48, 1}, { 47, 0}, { 47, 0}, { 47, 0}, { 47, 1}, { 46, 0}, + { 46, 0}, { 46, 1}, { 45, 0}, { 45, 0}, { 45, 0}, { 45, 1}, { 44, 0}, { 44, 0}, + { 44, 0}, { 44, 1}, { 43, 0}, { 43, 0}, { 43, 0}, { 43, 1}, { 42, 0}, { 42, 0}, + { 42, 0}, { 42, 1}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 1}, { 40, 0}, + { 40, 0}, { 40, 0}, { 40, 0}, { 40, 1}, { 39, 0}, { 39, 0}, { 39, 0}, { 39, 0}, + { 39, 1}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 1}, { 37, 0}, { 37, 0}, + { 37, 0}, { 37, 0}, { 37, 0}, { 37, 1}, { 36, 0}, { 36, 0}, { 36, 0}, { 36, 0}, + { 36, 1}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 1}, + { 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} + }; + + const 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}, + { 8928, 308}, { 8620, 287}, { 8333, 269}, { 8064, 252}, { 7812, 237}, { 7575, 223}, { 7352, 210}, { 7142, 198}, + { 6944, 188}, { 6756, 178}, { 6578, 168}, { 6410, 160}, { 6250, 153}, { 6097, 145}, { 5952, 139}, { 5813, 132}, + { 5681, 126}, { 5555, 121}, { 5434, 115}, { 5319, 111}, { 5208, 106}, { 5102, 102}, { 5000, 99}, { 4901, 94}, + { 4807, 91}, { 4716, 87}, { 4629, 84}, { 4545, 81}, { 4464, 79}, { 4385, 75}, { 4310, 73}, { 4237, 71}, + { 4166, 68}, { 4098, 66}, { 4032, 64}, { 3968, 62}, { 3906, 60}, { 3846, 59}, { 3787, 56}, { 3731, 55}, + { 3676, 53}, { 3623, 52}, { 3571, 50}, { 3521, 49}, { 3472, 48}, { 3424, 46}, { 3378, 45}, { 3333, 44}, + { 3289, 43}, { 3246, 41}, { 3205, 41}, { 3164, 39}, { 3125, 39}, { 3086, 38}, { 3048, 36}, { 3012, 36}, + { 2976, 35}, { 2941, 35}, { 2906, 33}, { 2873, 33}, { 2840, 32}, { 2808, 31}, { 2777, 30}, { 2747, 30}, + { 2717, 29}, { 2688, 29}, { 2659, 28}, { 2631, 27}, { 2604, 27}, { 2577, 26}, { 2551, 26}, { 2525, 25}, + { 2500, 25}, { 2475, 25}, { 2450, 23}, { 2427, 24}, { 2403, 23}, { 2380, 22}, { 2358, 22}, { 2336, 22}, + { 2314, 21}, { 2293, 21}, { 2272, 20}, { 2252, 20}, { 2232, 20}, { 2212, 20}, { 2192, 19}, { 2173, 18}, + { 2155, 19}, { 2136, 18}, { 2118, 18}, { 2100, 17}, { 2083, 17}, { 2066, 17}, { 2049, 17}, { 2032, 16}, + { 2016, 16}, { 2000, 16}, { 1984, 16}, { 1968, 15}, { 1953, 16}, { 1937, 14}, { 1923, 15}, { 1908, 15}, + { 1893, 14}, { 1879, 14}, { 1865, 14}, { 1851, 13}, { 1838, 14}, { 1824, 13}, { 1811, 13}, { 1798, 13}, + { 1785, 12}, { 1773, 13}, { 1760, 12}, { 1748, 12}, { 1736, 12}, { 1724, 12}, { 1712, 12}, { 1700, 11}, + { 1689, 12}, { 1677, 11}, { 1666, 11}, { 1655, 11}, { 1644, 11}, { 1633, 10}, { 1623, 11}, { 1612, 10}, + { 1602, 10}, { 1592, 10}, { 1582, 10}, { 1572, 10}, { 1562, 10}, { 1552, 9}, { 1543, 10}, { 1533, 9}, + { 1524, 9}, { 1515, 9}, { 1506, 9}, { 1497, 9}, { 1488, 9}, { 1479, 9}, { 1470, 9}, { 1461, 8}, + { 1453, 8}, { 1445, 9}, { 1436, 8}, { 1428, 8}, { 1420, 8}, { 1412, 8}, { 1404, 8}, { 1396, 8}, + { 1388, 7}, { 1381, 8}, { 1373, 7}, { 1366, 8}, { 1358, 7}, { 1351, 7}, { 1344, 8}, { 1336, 7}, + { 1329, 7}, { 1322, 7}, { 1315, 7}, { 1308, 6}, { 1302, 7}, { 1295, 7}, { 1288, 6}, { 1282, 7}, + { 1275, 6}, { 1269, 7}, { 1262, 6}, { 1256, 6}, { 1250, 7}, { 1243, 6}, { 1237, 6}, { 1231, 6}, + { 1225, 6}, { 1219, 6}, { 1213, 6}, { 1207, 6}, { 1201, 5}, { 1196, 6}, { 1190, 6}, { 1184, 5}, + { 1179, 6}, { 1173, 5}, { 1168, 6}, { 1162, 5}, { 1157, 5}, { 1152, 6}, { 1146, 5}, { 1141, 5}, + { 1136, 5}, { 1131, 5}, { 1126, 5}, { 1121, 5}, { 1116, 5}, { 1111, 5}, { 1106, 5}, { 1101, 5}, + { 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} + }; + + #else + + const uint16_t speed_lookuptable_fast[256][2] PROGMEM = { + {62500, 54055}, {8445, 3917}, {4528, 1434}, {3094, 745}, {2349, 456}, {1893, 307}, {1586, 222}, {1364, 167}, + {1197, 131}, {1066, 105}, {961, 86}, {875, 72}, {803, 61}, {742, 53}, {689, 45}, {644, 40}, + {604, 35}, {569, 32}, {537, 28}, {509, 25}, {484, 23}, {461, 21}, {440, 19}, {421, 17}, + {404, 16}, {388, 15}, {373, 14}, {359, 13}, {346, 12}, {334, 11}, {323, 10}, {313, 10}, + {303, 9}, {294, 9}, {285, 8}, {277, 7}, {270, 8}, {262, 7}, {255, 6}, {249, 6}, + {243, 6}, {237, 6}, {231, 5}, {226, 5}, {221, 5}, {216, 5}, {211, 4}, {207, 5}, + {202, 4}, {198, 4}, {194, 4}, {190, 3}, {187, 4}, {183, 3}, {180, 3}, {177, 4}, + {173, 3}, {170, 3}, {167, 2}, {165, 3}, {162, 3}, {159, 2}, {157, 3}, {154, 2}, + {152, 3}, {149, 2}, {147, 2}, {145, 2}, {143, 2}, {141, 2}, {139, 2}, {137, 2}, + {135, 2}, {133, 2}, {131, 2}, {129, 1}, {128, 2}, {126, 2}, {124, 1}, {123, 2}, + {121, 1}, {120, 2}, {118, 1}, {117, 1}, {116, 2}, {114, 1}, {113, 1}, {112, 2}, + {110, 1}, {109, 1}, {108, 1}, {107, 2}, {105, 1}, {104, 1}, {103, 1}, {102, 1}, + {101, 1}, {100, 1}, {99, 1}, {98, 1}, {97, 1}, {96, 1}, {95, 1}, {94, 1}, + {93, 1}, {92, 1}, {91, 0}, {91, 1}, {90, 1}, {89, 1}, {88, 1}, {87, 0}, + {87, 1}, {86, 1}, {85, 1}, {84, 0}, {84, 1}, {83, 1}, {82, 1}, {81, 0}, + {81, 1}, {80, 1}, {79, 0}, {79, 1}, {78, 0}, {78, 1}, {77, 1}, {76, 0}, + {76, 1}, {75, 0}, {75, 1}, {74, 1}, {73, 0}, {73, 1}, {72, 0}, {72, 1}, + {71, 0}, {71, 1}, {70, 0}, {70, 1}, {69, 0}, {69, 1}, {68, 0}, {68, 1}, + {67, 0}, {67, 1}, {66, 0}, {66, 1}, {65, 0}, {65, 0}, {65, 1}, {64, 0}, + {64, 1}, {63, 0}, {63, 1}, {62, 0}, {62, 0}, {62, 1}, {61, 0}, {61, 1}, + {60, 0}, {60, 0}, {60, 1}, {59, 0}, {59, 0}, {59, 1}, {58, 0}, {58, 0}, + {58, 1}, {57, 0}, {57, 0}, {57, 1}, {56, 0}, {56, 0}, {56, 1}, {55, 0}, + {55, 0}, {55, 1}, {54, 0}, {54, 0}, {54, 1}, {53, 0}, {53, 0}, {53, 0}, + {53, 1}, {52, 0}, {52, 0}, {52, 1}, {51, 0}, {51, 0}, {51, 0}, {51, 1}, + {50, 0}, {50, 0}, {50, 0}, {50, 1}, {49, 0}, {49, 0}, {49, 0}, {49, 1}, + {48, 0}, {48, 0}, {48, 0}, {48, 1}, {47, 0}, {47, 0}, {47, 0}, {47, 1}, + {46, 0}, {46, 0}, {46, 0}, {46, 0}, {46, 1}, {45, 0}, {45, 0}, {45, 0}, + {45, 1}, {44, 0}, {44, 0}, {44, 0}, {44, 0}, {44, 1}, {43, 0}, {43, 0}, + {43, 0}, {43, 0}, {43, 1}, {42, 0}, {42, 0}, {42, 0}, {42, 0}, {42, 0}, + {42, 1}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 1}, {40, 0}, + {40, 0}, {40, 0}, {40, 0}, {40, 1}, {39, 0}, {39, 0}, {39, 0}, {39, 0}, + {39, 0}, {39, 0}, {39, 1}, {38, 0}, {38, 0}, {38, 0}, {38, 0}, {38, 0}, +}; + + const uint16_t speed_lookuptable_slow[256][2] PROGMEM = { + {62500, 10417}, {52083, 7441}, {44642, 5580}, {39062, 4340}, {34722, 3472}, {31250, 2841}, {28409, 2368}, {26041, 2003}, + {24038, 1717}, {22321, 1488}, {20833, 1302}, {19531, 1149}, {18382, 1021}, {17361, 914}, {16447, 822}, {15625, 745}, + {14880, 676}, {14204, 618}, {13586, 566}, {13020, 520}, {12500, 481}, {12019, 445}, {11574, 414}, {11160, 385}, + {10775, 359}, {10416, 336}, {10080, 315}, {9765, 296}, {9469, 278}, {9191, 263}, {8928, 248}, {8680, 235}, + {8445, 222}, {8223, 211}, {8012, 200}, {7812, 191}, {7621, 181}, {7440, 173}, {7267, 165}, {7102, 158}, + {6944, 151}, {6793, 145}, {6648, 138}, {6510, 133}, {6377, 127}, {6250, 123}, {6127, 118}, {6009, 113}, + {5896, 109}, {5787, 106}, {5681, 101}, {5580, 98}, {5482, 95}, {5387, 91}, {5296, 88}, {5208, 86}, + {5122, 82}, {5040, 80}, {4960, 78}, {4882, 75}, {4807, 73}, {4734, 70}, {4664, 69}, {4595, 67}, + {4528, 64}, {4464, 63}, {4401, 61}, {4340, 60}, {4280, 58}, {4222, 56}, {4166, 55}, {4111, 53}, + {4058, 52}, {4006, 51}, {3955, 49}, {3906, 48}, {3858, 48}, {3810, 45}, {3765, 45}, {3720, 44}, + {3676, 43}, {3633, 42}, {3591, 40}, {3551, 40}, {3511, 39}, {3472, 38}, {3434, 38}, {3396, 36}, + {3360, 36}, {3324, 35}, {3289, 34}, {3255, 34}, {3221, 33}, {3188, 32}, {3156, 31}, {3125, 31}, + {3094, 31}, {3063, 30}, {3033, 29}, {3004, 28}, {2976, 28}, {2948, 28}, {2920, 27}, {2893, 27}, + {2866, 26}, {2840, 25}, {2815, 25}, {2790, 25}, {2765, 24}, {2741, 24}, {2717, 24}, {2693, 23}, + {2670, 22}, {2648, 22}, {2626, 22}, {2604, 22}, {2582, 21}, {2561, 21}, {2540, 20}, {2520, 20}, + {2500, 20}, {2480, 20}, {2460, 19}, {2441, 19}, {2422, 19}, {2403, 18}, {2385, 18}, {2367, 18}, + {2349, 17}, {2332, 18}, {2314, 17}, {2297, 16}, {2281, 17}, {2264, 16}, {2248, 16}, {2232, 16}, + {2216, 16}, {2200, 15}, {2185, 15}, {2170, 15}, {2155, 15}, {2140, 15}, {2125, 14}, {2111, 14}, + {2097, 14}, {2083, 14}, {2069, 14}, {2055, 13}, {2042, 13}, {2029, 13}, {2016, 13}, {2003, 13}, + {1990, 13}, {1977, 12}, {1965, 12}, {1953, 13}, {1940, 11}, {1929, 12}, {1917, 12}, {1905, 12}, + {1893, 11}, {1882, 11}, {1871, 11}, {1860, 11}, {1849, 11}, {1838, 11}, {1827, 11}, {1816, 10}, + {1806, 11}, {1795, 10}, {1785, 10}, {1775, 10}, {1765, 10}, {1755, 10}, {1745, 9}, {1736, 10}, + {1726, 9}, {1717, 10}, {1707, 9}, {1698, 9}, {1689, 9}, {1680, 9}, {1671, 9}, {1662, 9}, + {1653, 9}, {1644, 8}, {1636, 9}, {1627, 8}, {1619, 9}, {1610, 8}, {1602, 8}, {1594, 8}, + {1586, 8}, {1578, 8}, {1570, 8}, {1562, 8}, {1554, 7}, {1547, 8}, {1539, 8}, {1531, 7}, + {1524, 8}, {1516, 7}, {1509, 7}, {1502, 7}, {1495, 7}, {1488, 7}, {1481, 7}, {1474, 7}, + {1467, 7}, {1460, 7}, {1453, 7}, {1446, 6}, {1440, 7}, {1433, 7}, {1426, 6}, {1420, 6}, + {1414, 7}, {1407, 6}, {1401, 6}, {1395, 7}, {1388, 6}, {1382, 6}, {1376, 6}, {1370, 6}, + {1364, 6}, {1358, 6}, {1352, 6}, {1346, 5}, {1341, 6}, {1335, 6}, {1329, 5}, {1324, 6}, + {1318, 5}, {1313, 6}, {1307, 5}, {1302, 6}, {1296, 5}, {1291, 5}, {1286, 6}, {1280, 5}, + {1275, 5}, {1270, 5}, {1265, 5}, {1260, 5}, {1255, 5}, {1250, 5}, {1245, 5}, {1240, 5}, + {1235, 5}, {1230, 5}, {1225, 5}, {1220, 5}, {1215, 4}, {1211, 5}, {1206, 5}, {1201, 5}, + }; + #endif + +#endif diff --git a/Sprinter/store_eeprom.cpp b/Sprinter/store_eeprom.cpp new file mode 100644 index 0000000..c2cd353 --- /dev/null +++ b/Sprinter/store_eeprom.cpp @@ -0,0 +1,213 @@ +/* + EEPROM routines to save Sprinter Settings + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include <avr/eeprom.h> +#include <avr/pgmspace.h> +#include <inttypes.h> + +#include "Sprinter.h" +#include "store_eeprom.h" +#include "Configuration.h" + + + +#ifdef USE_EEPROM_SETTINGS + +//====================================================================================== +//========================= Read / Write EEPROM ======================================= +template <class T> int EEPROM_writeAnything(int &ee, const T& value) +{ + const byte* p = (const byte*)(const void*)&value; + int i; + for (i = 0; i < (int)sizeof(value); i++) + eeprom_write_byte((unsigned char *)ee++, *p++); + return i; +} + +template <class T> int EEPROM_readAnything(int &ee, T& value) +{ + byte* p = (byte*)(void*)&value; + int i; + for (i = 0; i < (int)sizeof(value); i++) + *p++ = eeprom_read_byte((unsigned char *)ee++); + return i; +} +//====================================================================================== + + +void EEPROM_StoreSettings() +{ + + unsigned long ul_help = 20000; + unsigned int ui_help = 0; + 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,move_acceleration); + EEPROM_writeAnything(i,retract_acceleration); + EEPROM_writeAnything(i,minimumfeedrate); + EEPROM_writeAnything(i,mintravelfeedrate); + EEPROM_writeAnything(i,ul_help); //Min Segment Time, not used yet + EEPROM_writeAnything(i,max_xy_jerk); + EEPROM_writeAnything(i,max_z_jerk); + + //PID Settings, not used yet --> placeholder + ui_help = 2560; + EEPROM_writeAnything(i,ui_help); //Kp + ui_help = 64; + EEPROM_writeAnything(i,ui_help); //Ki + ui_help = 4096; + EEPROM_writeAnything(i,ui_help); //Kd + + char ver2[4]=EEPROM_VERSION; + i=EEPROM_OFFSET; + EEPROM_writeAnything(i,ver2); // validate data + showString(PSTR("Settings Stored\r\n")); + +} + + +void EEPROM_printSettings() +{ + // if def=true, the default values will be used + #ifdef PRINT_EEPROM_SETTING + showString(PSTR("Steps per unit:\r\n")); + showString(PSTR(" M92 X")); + Serial.print(axis_steps_per_unit[0]); + showString(PSTR(" Y")); + Serial.print(axis_steps_per_unit[1]); + showString(PSTR(" Z")); + Serial.print(axis_steps_per_unit[2]); + showString(PSTR(" E")); + Serial.println(axis_steps_per_unit[3]); + + showString(PSTR("Maximum feedrates (mm/s):\r\n")); + showString(PSTR(" M203 X")); + Serial.print(max_feedrate[0]); + showString(PSTR(" Y")); + Serial.print(max_feedrate[1]); + showString(PSTR(" Z")); + Serial.print(max_feedrate[2]); + showString(PSTR(" E")); + Serial.println(max_feedrate[3]); + + showString(PSTR("Maximum Acceleration (mm/s2):\r\n")); + showString(PSTR(" M201 X")); + Serial.print(max_acceleration_units_per_sq_second[0] ); + showString(PSTR(" Y")); + Serial.print(max_acceleration_units_per_sq_second[1] ); + showString(PSTR(" Z")); + Serial.print(max_acceleration_units_per_sq_second[2] ); + showString(PSTR(" E")); + Serial.println(max_acceleration_units_per_sq_second[3]); + + showString(PSTR("Acceleration: S=acceleration, T=retract acceleration\r\n")); + showString(PSTR(" M204 S")); + Serial.print(move_acceleration ); + showString(PSTR(" T")); + Serial.println(retract_acceleration); + + showString(PSTR("Advanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), X=maximum xY jerk (mm/s), Z=maximum Z jerk (mm/s)\r\n")); + + showString(PSTR(" M205 S")); + Serial.print(minimumfeedrate ); + showString(PSTR(" T" )); + Serial.print(mintravelfeedrate ); +// showString(PSTR(" B")); +// Serial.print(minsegmenttime ); + showString(PSTR(" X")); + Serial.print(max_xy_jerk ); + showString(PSTR(" Z")); + Serial.println(max_z_jerk); + + #ifdef PIDTEMP + /* + showString(PSTR("PID settings:"); + showString(PSTR(" M301 P")); + Serial.print(Kp); + showString(PSTR(" I")); + Serial.print(Ki); + SshowString(PSTR(" D")); + Serial.print(Kd); + */ + #endif + #endif + +} + + +void EEPROM_RetrieveSettings(bool def, bool printout) +{ // if def=true, the default values will be used + + int i=EEPROM_OFFSET; + char stored_ver[4]; + char ver[4]=EEPROM_VERSION; + unsigned long ul_help = 0; + + EEPROM_readAnything(i,stored_ver); //read stored version + 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,move_acceleration); + EEPROM_readAnything(i,retract_acceleration); + EEPROM_readAnything(i,minimumfeedrate); + EEPROM_readAnything(i,mintravelfeedrate); + EEPROM_readAnything(i,ul_help); //min Segmenttime --> not used yet + EEPROM_readAnything(i,max_xy_jerk); + EEPROM_readAnything(i,max_z_jerk); + + unsigned int Kp,Ki,Kd; + EEPROM_readAnything(i,Kp); + EEPROM_readAnything(i,Ki); + EEPROM_readAnything(i,Kd); + + showString(PSTR("Stored settings retreived\r\n")); + } + else + { + + float tmp1[]=_AXIS_STEP_PER_UNIT; + float tmp2[]=_MAX_FEEDRATE; + long tmp3[]=_MAX_ACCELERATION_UNITS_PER_SQ_SECOND; + for (short 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]; + } + move_acceleration=_ACCELERATION; + retract_acceleration=_RETRACT_ACCELERATION; + minimumfeedrate=DEFAULT_MINIMUMFEEDRATE; + mintravelfeedrate=DEFAULT_MINTRAVELFEEDRATE; + max_xy_jerk=_MAX_XY_JERK; + max_z_jerk=_MAX_Z_JERK; + + showString(PSTR("Using Default settings\r\n")); + } + + if(printout) + { + EEPROM_printSettings(); + } +} + +#endif diff --git a/Sprinter/store_eeprom.h b/Sprinter/store_eeprom.h new file mode 100644 index 0000000..cff25d3 --- /dev/null +++ b/Sprinter/store_eeprom.h @@ -0,0 +1,49 @@ +/* + EEPROM routines to save Sprinter Settings + + 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 <http://www.gnu.org/licenses/>. +*/ + + +#ifndef __EEPROMH +#define __EEPROMH + +#define EEPROM_OFFSET 100 + + +// 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. +#define EEPROM_VERSION "S01" + + +extern float axis_steps_per_unit[4]; +extern float max_feedrate[4]; +extern long max_acceleration_units_per_sq_second[4]; +extern float move_acceleration; +extern float retract_acceleration; +extern float mintravelfeedrate; +extern float minimumfeedrate; +extern float max_xy_jerk; +extern float max_z_jerk; + + +extern void EEPROM_RetrieveSettings(bool def, bool printout ); +extern void EEPROM_printSettings(); +extern void EEPROM_StoreSettings(); + + +#endif diff --git a/Sprinter/thermistortables.h b/Sprinter/thermistortables.h index ef1e78b..eccfe88 100644 --- a/Sprinter/thermistortables.h +++ b/Sprinter/thermistortables.h @@ -176,7 +176,7 @@ const short temptable_3[NUMTEMPS_3][2] = { #if (THERMISTORHEATER == 4) || (THERMISTORBED == 4) //10k thermistor #define NUMTEMPS_4 20 -short temptable_4[NUMTEMPS_4][2] = { +const short temptable_4[NUMTEMPS_4][2] = { {1, 430}, {54, 137}, {107, 107}, |