diff --git a/.travis.yml b/.travis.yml index cb96d2aa8..cc420ee79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,16 +3,17 @@ before_install: - sudo apt-get install -y ninja-build script: - bash -x test.sh - - bash -x build.sh + - cp Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h Firmware/Configuration_prusa.h + - bash -x build.sh || { echo "1_75mm_MK3-EINSy10a-E3Dv6full variant failed" && false; } - rm Firmware/Configuration_prusa.h - cp Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h Firmware/Configuration_prusa.h - - bash -x build.sh + - bash -x build.sh || { echo "1_75mm_MK25-RAMBo13a-E3Dv6full variant failed" && false; } - rm Firmware/Configuration_prusa.h - cp Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h Firmware/Configuration_prusa.h - - bash -x build.sh + - bash -x build.sh || { echo "1_75mm_MK25-RAMBo10a-E3Dv6full variant failed" && false; } - rm Firmware/Configuration_prusa.h - cp Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h Firmware/Configuration_prusa.h - - bash -x build.sh + - bash -x build.sh || { echo "1_75mm_MK2-RAMBo13a-E3Dv6full variant failed" && false; } - rm Firmware/Configuration_prusa.h - cp Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h Firmware/Configuration_prusa.h - - bash -x build.sh \ No newline at end of file + - bash -x build.sh || { echo "1_75mm_MK2-RAMBo10a-E3Dv6full variant failed" && false; } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b0798404..c0c2aacd0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,9 @@ set(TEST_SOURCES Tests/tests.cpp Tests/Example_test.cpp Tests/Timer_test.cpp + Tests/AutoDeplete_test.cpp Firmware/Timer.cpp + Firmware/AutoDeplete.cpp ) add_executable(tests ${TEST_SOURCES}) target_include_directories(tests PRIVATE Tests) diff --git a/Firmware/AutoDeplete.cpp b/Firmware/AutoDeplete.cpp new file mode 100644 index 000000000..9c4340f09 --- /dev/null +++ b/Firmware/AutoDeplete.cpp @@ -0,0 +1,79 @@ +//! @file +//! @author: Marek Bel +//! @date Jan 3, 2019 + +#include "AutoDeplete.h" +#include "assert.h" + +//! @brief bit field marking depleted filaments +//! +//! binary 1 marks filament as depleted +//! Zero initialized value means, that no filament is depleted. +static uint8_t depleted; +static const uint8_t filamentCount = 5; + +//! @return binary 1 for all filaments +//! @par fCount number of filaments +static constexpr uint8_t allDepleted(uint8_t fCount) +{ + return fCount == 1 ? 1 : ((1 << (fCount - 1)) | allDepleted(fCount - 1)); +} + +//! @brief Is filament available for printing? +//! @par filament Filament number to be checked +//! @retval true Filament is available for printing. +//! @retval false Filament is not available for printing. +static bool loaded(uint8_t filament) +{ + if (depleted & (1 << filament)) return false; + return true; +} + +//! @brief Mark filament as not available for printing. +//! @par filament filament to be marked +void ad_markDepleted(uint8_t filament) +{ + assert(filament < filamentCount); + if (filament < filamentCount) + { + depleted |= 1 << filament; + } +} + +//! @brief Mark filament as available for printing. +//! @par filament filament to be marked +void ad_markLoaded(uint8_t filament) +{ + assert(filament < filamentCount); + if (filament < filamentCount) + { + depleted &= ~(1 << filament); + } +} + +//! @brief Get alternative filament, which is not depleted +//! @par filament filament +//! @return Filament, if it is depleted, returns next available, +//! if all filaments are depleted, returns filament function parameter. +uint8_t ad_getAlternative(uint8_t filament) +{ + assert(filament < filamentCount); + for (uint8_t i = 0; i + +void ad_markDepleted(uint8_t filament); +void ad_markLoaded(uint8_t filament); +uint8_t ad_getAlternative(uint8_t filament); +bool ad_allDepleted(); + +#endif /* AUTODEPLETE_H */ diff --git a/Firmware/Configuration.h b/Firmware/Configuration.h index 399b703d8..37b7f6be9 100644 --- a/Firmware/Configuration.h +++ b/Firmware/Configuration.h @@ -126,13 +126,11 @@ // Comment the following line to disable PID and enable bang-bang. #define PIDTEMP #define BANG_MAX 255 // limits current to nozzle while in bang-bang mode; 255=full current -#define PID_MAX BANG_MAX // limits current to nozzle while PID is active (see PID_FUNCTIONAL_RANGE below); 255=full current +#define PID_MAX BANG_MAX // limits current to nozzle while PID is active; 255=full current #ifdef PIDTEMP //#define PID_DEBUG // Sends debug data to the serial port. //#define PID_OPENLOOP 1 // Puts PID in open loop. M104/M140 sets the output power from 0 to PID_MAX //#define SLOW_PWM_HEATERS // PWM with very low frequency (roughly 0.125Hz=8s) and minimum state time of approximately 1s useful for heaters driven by a relay - #define PID_FUNCTIONAL_RANGE 10 // If the temperature difference between the target temperature and the actual temperature - // is more then PID_FUNCTIONAL_RANGE then the PID will be shut off and the heater will be set to min/max. #define PID_INTEGRAL_DRIVE_MAX PID_MAX //limit for the integral term #define K1 0.95 //smoothing factor within the PID #define PID_dT ((OVERSAMPLENR * 10.0)/(F_CPU / 64.0 / 256.0)) //sampling period of the temperature routine diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index ee1ee55ae..9334d686e 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -78,6 +78,7 @@ #include #include "Dcodes.h" +#include "AutoDeplete.h" #ifdef SWSPI @@ -6947,6 +6948,10 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) } else { tmp_extruder = code_value(); + if (mmu_enabled && lcd_autoDepleteEnabled()) + { + tmp_extruder = ad_getAlternative(tmp_extruder); + } } st_synchronize(); snmm_filaments_used |= (1 << tmp_extruder); //for stop print @@ -7641,6 +7646,7 @@ void Stop() disable_heater(); if(Stopped == false) { Stopped = true; + lcd_print_stop(); Stopped_gcode_LastN = gcode_LastN; // Save last g_code for restart SERIAL_ERROR_START; SERIAL_ERRORLNRPGM(MSG_ERR_STOPPED); diff --git a/Firmware/mmu.cpp b/Firmware/mmu.cpp index 2b5bd3ca5..c901fa21d 100644 --- a/Firmware/mmu.cpp +++ b/Firmware/mmu.cpp @@ -1,4 +1,4 @@ -//mmu.cpp +//! @file #include "mmu.h" #include "planner.h" @@ -14,6 +14,7 @@ #include "printers.h" #include #include "io_atmega2560.h" +#include "AutoDeplete.h" #ifdef TMC2130 #include "tmc2130.h" @@ -245,7 +246,7 @@ void mmu_loop(void) mmu_printf_P(PSTR("T%d\n"), filament); mmu_state = 3; // wait for response mmu_fil_loaded = true; - if(ir_sensor_detected) mmu_idl_sens = 1; //if idler sensor detected, use it for T-code + mmu_idl_sens = 1; } else if ((mmu_cmd >= MMU_CMD_L0) && (mmu_cmd <= MMU_CMD_L4)) { @@ -263,7 +264,7 @@ void mmu_loop(void) #endif //MMU_DEBUG mmu_puts_P(PSTR("C0\n")); //send 'continue loading' mmu_state = 3; - if(ir_sensor_detected) mmu_idl_sens = 1; //if idler sensor detected use it for C0 code + mmu_idl_sens = 1; } else if (mmu_cmd == MMU_CMD_U0) { @@ -326,8 +327,15 @@ void mmu_loop(void) if (!mmu_finda && CHECK_FSENSOR && fsensor_enabled) { fsensor_stop_and_save_print(); enquecommand_front_P(PSTR("FSENSOR_RECOVER")); //then recover - if (lcd_autoDepleteEnabled()) enquecommand_front_P(PSTR("M600 AUTO")); //save print and run M600 command - else enquecommand_front_P(PSTR("M600")); //save print and run M600 command + ad_markDepleted(mmu_extruder); + if (lcd_autoDepleteEnabled() && !ad_allDepleted()) + { + enquecommand_front_P(PSTR("M600 AUTO")); //save print and run M600 command + } + else + { + enquecommand_front_P(PSTR("M600")); //save print and run M600 command + } } mmu_state = 1; if (mmu_cmd == 0) @@ -339,19 +347,20 @@ void mmu_loop(void) } return; case 3: //response to mmu commands - if (mmu_idl_sens && ir_sensor_detected) { - if (PIN_GET(IR_SENSOR_PIN) == 0 && mmu_loading_flag) - { + if (mmu_idl_sens) + { + if (PIN_GET(MMU_IDLER_SENSOR_PIN) == 0 && mmu_loading_flag) + { #ifdef MMU_DEBUG - printf_P(PSTR("MMU <= 'A'\n")); + printf_P(PSTR("MMU <= 'A'\n")); #endif //MMU_DEBUG - mmu_puts_P(PSTR("A\n")); //send 'abort' request - mmu_idl_sens = 0; - //printf_P(PSTR("MMU IDLER_SENSOR = 0 - ABORT\n")); - } - //else - //printf_P(PSTR("MMU IDLER_SENSOR = 1 - WAIT\n")); - } + mmu_puts_P(PSTR("A\n")); //send 'abort' request + mmu_idl_sens = 0; + //printf_P(PSTR("MMU IDLER_SENSOR = 0 - ABORT\n")); + } + //else + //printf_P(PSTR("MMU IDLER_SENSOR = 1 - WAIT\n")); + } if (mmu_rx_ok() > 0) { #ifdef MMU_DEBUG @@ -420,69 +429,96 @@ int8_t mmu_set_filament_type(uint8_t extruder, uint8_t filament) return timeout?1:0; } +//! @brief Enqueue MMUv2 command +//! +//! Call manage_response() after enqueuing to process command. +//! If T command is enqueued, it disables current for extruder motor if TMC2130 driver present. +//! If T or L command is enqueued, it marks filament loaded in AutoDeplete module. void mmu_command(uint8_t cmd) { -#ifdef TMC2130 if ((cmd >= MMU_CMD_T0) && (cmd <= MMU_CMD_T4)) { //disable extruder motor +#ifdef TMC2130 tmc2130_set_pwr(E_AXIS, 0); - //printf_P(PSTR("E-axis disabled\n")); - } #endif //TMC2130 + //printf_P(PSTR("E-axis disabled\n")); + ad_markLoaded(cmd - MMU_CMD_T0); + } + if ((cmd >= MMU_CMD_L0) && (cmd <= MMU_CMD_L4)) + { + ad_markLoaded(cmd - MMU_CMD_L0); + } mmu_cmd = cmd; mmu_ready = false; } -void mmu_load_step() { +//! @brief Rotate extruder idler to catch filament +//! @par synchronize +//! * true blocking call +//! * false non-blocking call +void mmu_load_step(bool synchronize) +{ current_position[E_AXIS] = current_position[E_AXIS] + MMU_LOAD_FEEDRATE * 0.1; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], MMU_LOAD_FEEDRATE, active_extruder); - st_synchronize(); + if (synchronize) st_synchronize(); +} + +//! @brief Is nozzle hot enough to move extruder wheels and do we have idler sensor? +//! +//! Do load steps only if temperature is higher then min. temp for safe extrusion and +//! idler sensor present. +//! Otherwise "cold extrusion prevented" would be send to serial line periodically +//! and watchdog reset will be triggered by lack of keep_alive processing. +//! +//! @retval true temperature is high enough to move extruder +//! @retval false temperature is not high enough to move extruder, turned +//! off E-stepper to prevent over-heating and allow filament pull-out if necessary +bool can_extrude() +{ + if ((degHotend(active_extruder) < EXTRUDE_MINTEMP) || !mmu_idler_sensor_detected) + { + disable_e0(); + delay_keep_alive(100); + return false; + } + return true; } bool mmu_get_response(uint8_t move) { - mmu_loading_flag = false; - if (!ir_sensor_detected) move = MMU_NO_MOVE; + mmu_loading_flag = false; printf_P(PSTR("mmu_get_response - begin move:%d\n"), move); KEEPALIVE_STATE(IN_PROCESS); while (mmu_cmd != 0) { -// mmu_loop(); delay_keep_alive(100); } while (!mmu_ready) { -// mmu_loop(); - if ((mmu_state != 3) && (mmu_last_cmd == 0)) break; - //Do load steps only if temperature is higher then min. temp for safe extrusion. - //Otherwise "cold extrusion prevented" would be send to serial line periodically - if (degHotend(active_extruder) < EXTRUDE_MINTEMP) { - disable_e0(); //turn off E-stepper to prevent overheating and alow filament pull-out if necessary - delay_keep_alive(100); - continue; - } - switch (move) { - case MMU_LOAD_MOVE: - mmu_loading_flag = true; - mmu_load_step(); + case MMU_LOAD_MOVE: + mmu_loading_flag = true; + if (can_extrude()) mmu_load_step(); //don't rely on "ok" signal from mmu unit; if filament detected by idler sensor during loading stop loading movements to prevent infinite loading if (PIN_GET(IR_SENSOR_PIN) == 0) move = MMU_NO_MOVE; break; case MMU_UNLOAD_MOVE: - if (PIN_GET(IR_SENSOR_PIN) == 0) //filament is still detected by idler sensor, printer helps with unlading - { - printf_P(PSTR("Unload 1\n")); - current_position[E_AXIS] = current_position[E_AXIS] - MMU_LOAD_FEEDRATE * MMU_LOAD_TIME_MS*0.001; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], MMU_LOAD_FEEDRATE, active_extruder); - st_synchronize(); + if (PIN_GET(MMU_IDLER_SENSOR_PIN) == 0) //filament is still detected by idler sensor, printer helps with unlading + { + if (can_extrude()) + { + printf_P(PSTR("Unload 1\n")); + current_position[E_AXIS] = current_position[E_AXIS] - MMU_LOAD_FEEDRATE * MMU_LOAD_TIME_MS*0.001; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], MMU_LOAD_FEEDRATE, active_extruder); + st_synchronize(); + } } else //filament was unloaded from idler, no additional movements needed { @@ -492,12 +528,15 @@ bool mmu_get_response(uint8_t move) } break; case MMU_TCODE_MOVE: //first do unload and then continue with infinite loading movements - if (PIN_GET(IR_SENSOR_PIN) == 0) //filament detected by idler sensor, we must unload first - { - printf_P(PSTR("Unload 2\n")); - current_position[E_AXIS] = current_position[E_AXIS] - MMU_LOAD_FEEDRATE * MMU_LOAD_TIME_MS*0.001; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], MMU_LOAD_FEEDRATE, active_extruder); - st_synchronize(); + if (PIN_GET(MMU_IDLER_SENSOR_PIN) == 0) //filament detected by idler sensor, we must unload first + { + if (can_extrude()) + { + printf_P(PSTR("Unload 2\n")); + current_position[E_AXIS] = current_position[E_AXIS] - MMU_LOAD_FEEDRATE * MMU_LOAD_TIME_MS*0.001; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], MMU_LOAD_FEEDRATE, active_extruder); + st_synchronize(); + } } else //delay to allow mmu unit to pull out filament from bondtech gears and then start with infinite loading { @@ -505,6 +544,7 @@ bool mmu_get_response(uint8_t move) disable_e0(); //turn off E-stepper to prevent overheating and alow filament pull-out if necessary delay_keep_alive(MMU_LOAD_TIME_MS); move = MMU_LOAD_MOVE; + printf_P(PSTR("mmu_get_response - begin move:%d\n"), move); } break; case MMU_NO_MOVE: @@ -518,27 +558,20 @@ bool mmu_get_response(uint8_t move) mmu_ready = false; // printf_P(PSTR("mmu_get_response - end %d\n"), ret?1:0); return ret; - -/* //waits for "ok" from mmu - //function returns true if "ok" was received - //if timeout is set to true function return false if there is no "ok" received before timeout - bool response = true; - LongTimer mmu_get_reponse_timeout; - KEEPALIVE_STATE(IN_PROCESS); - mmu_get_reponse_timeout.start(); - while (mmu_rx_ok() <= 0) - { - delay_keep_alive(100); - if (timeout && mmu_get_reponse_timeout.expired(5 * 60 * 1000ul)) - { //5 minutes timeout - response = false; - break; - } - } - printf_P(PSTR("mmu_get_response - end %d\n"), response?1:0); - return response;*/ } +//! @brief Wait for active extruder to reach temperature set +//! +//! This function is blocking and showing lcd_wait_for_heater() screen +//! which is constantly updated with nozzle temperature. +void mmu_wait_for_heater_blocking() +{ + while ((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5) + { + delay_keep_alive(1000); + lcd_wait_for_heater(); + } +} void manage_response(bool move_axes, bool turn_off_nozzle, uint8_t move) { @@ -633,11 +666,7 @@ void manage_response(bool move_axes, bool turn_off_nozzle, uint8_t move) lcd_display_message_fullscreen_P(_i("MMU OK. Resuming temperature...")); delay_keep_alive(3000); } - while ((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5) - { - delay_keep_alive(1000); - lcd_wait_for_heater(); - } + mmu_wait_for_heater_blocking(); } if (move_axes) { lcd_clear(); @@ -751,7 +780,7 @@ void mmu_M600_load_filament(bool automatic) #endif //MMU_M600_SWITCH_EXTRUDER } else { - tmp_extruder = (tmp_extruder+1)%5; + tmp_extruder = ad_getAlternative(tmp_extruder); } lcd_update_enable(false); lcd_clear(); @@ -940,7 +969,7 @@ static const E_step ramming_sequence[] PROGMEM = }; //! @brief Unload sequence to optimize shape of the tip of the unloaded filament -static void filament_ramming() +void mmu_filament_ramming() { for(uint8_t i = 0; i < (sizeof(ramming_sequence)/sizeof(E_step));++i) { @@ -972,7 +1001,7 @@ void extr_unload() if (mmu_extruder == MMU_FILAMENT_UNKNOWN) lcd_print(" "); else lcd_print(mmu_extruder + 1); - filament_ramming(); + mmu_filament_ramming(); mmu_command(MMU_CMD_U0); // get response @@ -1366,6 +1395,7 @@ void mmu_continue_loading() setAllTargetHotends(0); lcd_setstatuspgm(_i("MMU load failed "));////MSG_RECOVERING_PRINT c=20 r=1 mmu_fil_loaded = false; //so we can retry same T-code again + isPrintPaused = true; } } else { //mmu_ir_sensor_detected == false diff --git a/Firmware/mmu.h b/Firmware/mmu.h index 6e7704d64..473ee99d7 100644 --- a/Firmware/mmu.h +++ b/Firmware/mmu.h @@ -1,4 +1,7 @@ -//mmu.h +//! @file + +#ifndef MMU_H +#define MMU_H #include @@ -71,7 +74,7 @@ extern void mmu_command(uint8_t cmd); extern bool mmu_get_response(uint8_t move = 0); -extern void manage_response(bool move_axes, bool turn_off_nozzle, uint8_t move = 0); +extern void manage_response(bool move_axes, bool turn_off_nozzle, uint8_t move = MMU_NO_MOVE); extern void mmu_load_to_nozzle(); @@ -119,3 +122,8 @@ extern void mmu_eject_fil_2(); extern void mmu_eject_fil_3(); extern void mmu_eject_fil_4(); extern void mmu_continue_loading(); +extern void mmu_filament_ramming(); +extern void mmu_wait_for_heater_blocking(); +extern void mmu_load_step(bool synchronize = true); + +#endif //MMU_H diff --git a/Firmware/temperature.cpp b/Firmware/temperature.cpp index 98e8aee37..41b8a0779 100644 --- a/Firmware/temperature.cpp +++ b/Firmware/temperature.cpp @@ -41,6 +41,15 @@ #include "adc.h" #include "ConfigurationStore.h" +#include "Timer.h" +#include "Configuration_prusa.h" + + +extern "C" { +extern void timer02_init(void); +extern void timer02_set_pwm0(uint8_t pwm0); +} + //=========================================================================== //=============================public variables============================ @@ -103,15 +112,15 @@ static volatile bool temp_meas_ready = false; #ifdef PIDTEMP //static cannot be external: - static float temp_iState[EXTRUDERS] = { 0 }; - static float temp_dState[EXTRUDERS] = { 0 }; + static float iState_sum[EXTRUDERS] = { 0 }; + static float dState_last[EXTRUDERS] = { 0 }; static float pTerm[EXTRUDERS]; static float iTerm[EXTRUDERS]; static float dTerm[EXTRUDERS]; //int output; static float pid_error[EXTRUDERS]; - static float temp_iState_min[EXTRUDERS]; - static float temp_iState_max[EXTRUDERS]; + static float iState_sum_min[EXTRUDERS]; + static float iState_sum_max[EXTRUDERS]; // static float pid_input[EXTRUDERS]; // static float pid_output[EXTRUDERS]; static bool pid_reset[EXTRUDERS]; @@ -152,6 +161,8 @@ static volatile bool temp_meas_ready = false; # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1 } #endif +static ShortTimer oTimer4minTempHeater,oTimer4minTempBed; + // Init min and max temp with extreme values to prevent false errors during startup static int minttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_RAW_LO_TEMP , HEATER_1_RAW_LO_TEMP , HEATER_2_RAW_LO_TEMP ); static int maxttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_RAW_HI_TEMP , HEATER_1_RAW_HI_TEMP , HEATER_2_RAW_HI_TEMP ); @@ -252,6 +263,7 @@ static void temp_runaway_stop(bool isPreheat, bool isBed); if (extruder<0) { soft_pwm_bed = (MAX_BED_POWER)/2; + timer02_set_pwm0(soft_pwm_bed << 1); bias = d = (MAX_BED_POWER)/2; } else @@ -288,7 +300,10 @@ static void temp_runaway_stop(bool isPreheat, bool isBed); if(millis() - t2 > 5000) { heating=false; if (extruder<0) + { soft_pwm_bed = (bias - d) >> 1; + timer02_set_pwm0(soft_pwm_bed << 1); + } else soft_pwm[extruder] = (bias - d) >> 1; t1=millis(); @@ -342,7 +357,10 @@ static void temp_runaway_stop(bool isPreheat, bool isBed); } } if (extruder<0) + { soft_pwm_bed = (bias + d) >> 1; + timer02_set_pwm0(soft_pwm_bed << 1); + } else soft_pwm[extruder] = (bias + d) >> 1; pid_cycle++; @@ -413,7 +431,7 @@ void updatePID() { #ifdef PIDTEMP for(int e = 0; e < EXTRUDERS; e++) { - temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / cs.Ki; + iState_sum_max[e] = PID_INTEGRAL_DRIVE_MAX / cs.Ki; } #endif #ifdef PIDTEMPBED @@ -582,6 +600,12 @@ void checkExtruderAutoFans() #endif // any extruder auto fan pins set +// ready for eventually parameters adjusting +void resetPID(uint8_t) // only for compiler-warning elimination (if function do nothing) +//void resetPID(uint8_t extruder) +{ +} + void manage_heater() { #ifdef WATCHDOG @@ -593,9 +617,13 @@ void manage_heater() if(temp_meas_ready != true) //better readability return; +// more precisely - this condition partially stabilizes time interval for regulation values evaluation (@ ~ 230ms) updateTemperaturesFromRawValues(); + check_max_temp(); + check_min_temp(); + #ifdef TEMP_RUNAWAY_BED_HYSTERESIS temp_runaway_check(0, target_temperature_bed, current_temperature_bed, (int)soft_pwm_bed, true); #endif @@ -611,38 +639,42 @@ void manage_heater() pid_input = current_temperature[e]; #ifndef PID_OPENLOOP - pid_error[e] = target_temperature[e] - pid_input; - if(pid_error[e] > PID_FUNCTIONAL_RANGE) { - pid_output = BANG_MAX; - pid_reset[e] = true; - } - else if(pid_error[e] < -PID_FUNCTIONAL_RANGE || target_temperature[e] == 0) { + if(target_temperature[e] == 0) { pid_output = 0; pid_reset[e] = true; - } - else { - if(pid_reset[e] == true) { - temp_iState[e] = 0.0; + } else { + pid_error[e] = target_temperature[e] - pid_input; + if(pid_reset[e]) { + iState_sum[e] = 0.0; + dTerm[e] = 0.0; // 'dState_last[e]' initial setting is not necessary (see end of if-statement) pid_reset[e] = false; } +#ifndef PonM pTerm[e] = cs.Kp * pid_error[e]; - temp_iState[e] += pid_error[e]; - temp_iState[e] = constrain(temp_iState[e], temp_iState_min[e], temp_iState_max[e]); - iTerm[e] = cs.Ki * temp_iState[e]; - - //K1 defined in Configuration.h in the PID settings + iState_sum[e] += pid_error[e]; + iState_sum[e] = constrain(iState_sum[e], iState_sum_min[e], iState_sum_max[e]); + iTerm[e] = cs.Ki * iState_sum[e]; + // K1 defined in Configuration.h in the PID settings #define K2 (1.0-K1) - dTerm[e] = (cs.Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]); - pid_output = pTerm[e] + iTerm[e] - dTerm[e]; + dTerm[e] = (cs.Kd * (pid_input - dState_last[e]))*K2 + (K1 * dTerm[e]); // e.g. digital filtration of derivative term changes + pid_output = pTerm[e] + iTerm[e] - dTerm[e]; // subtraction due to "Derivative on Measurement" method (i.e. derivative of input instead derivative of error is used) if (pid_output > PID_MAX) { - if (pid_error[e] > 0 ) temp_iState[e] -= pid_error[e]; // conditional un-integration + if (pid_error[e] > 0 ) iState_sum[e] -= pid_error[e]; // conditional un-integration pid_output=PID_MAX; - } else if (pid_output < 0){ - if (pid_error[e] < 0 ) temp_iState[e] -= pid_error[e]; // conditional un-integration + } else if (pid_output < 0) { + if (pid_error[e] < 0 ) iState_sum[e] -= pid_error[e]; // conditional un-integration pid_output=0; } +#else // PonM ("Proportional on Measurement" method) + iState_sum[e] += cs.Ki * pid_error[e]; + iState_sum[e] -= cs.Kp * (pid_input - dState_last[e]); + iState_sum[e] = constrain(iState_sum[e], 0, PID_INTEGRAL_DRIVE_MAX); + dTerm[e] = cs.Kd * (pid_input - dState_last[e]); + pid_output = iState_sum[e] - dTerm[e]; // subtraction due to "Derivative on Measurement" method (i.e. derivative of input instead derivative of error is used) + pid_output = constrain(pid_output, 0, PID_MAX); +#endif // PonM } - temp_dState[e] = pid_input; + dState_last[e] = pid_input; #else pid_output = constrain(target_temperature[e], 0, PID_MAX); #endif //PID_OPENLOOP @@ -659,7 +691,7 @@ void manage_heater() SERIAL_ECHO(" iTerm "); SERIAL_ECHO(iTerm[e]); SERIAL_ECHO(" dTerm "); - SERIAL_ECHOLN(dTerm[e]); + SERIAL_ECHOLN(-dTerm[e]); #endif //PID_DEBUG #else /* PID off */ pid_output = 0; @@ -669,16 +701,12 @@ void manage_heater() #endif // Check if temperature is within the correct range -#ifdef AMBIENT_THERMISTOR - if(((current_temperature_ambient < MINTEMP_MINAMBIENT) || (current_temperature[e] > minttemp[e])) && (current_temperature[e] < maxttemp[e])) -#else //AMBIENT_THERMISTOR - if((current_temperature[e] > minttemp[e]) && (current_temperature[e] < maxttemp[e])) -#endif //AMBIENT_THERMISTOR + if((current_temperature[e] < maxttemp[e]) && (target_temperature[e] != 0)) { soft_pwm[e] = (int)pid_output >> 1; } else - { + { soft_pwm[e] = 0; } @@ -763,55 +791,61 @@ void manage_heater() pid_output = constrain(target_temperature_bed, 0, MAX_BED_POWER); #endif //PID_OPENLOOP -#ifdef AMBIENT_THERMISTOR - if(((current_temperature_bed > BED_MINTEMP) || (current_temperature_ambient < MINTEMP_MINAMBIENT)) && (current_temperature_bed < BED_MAXTEMP)) -#else //AMBIENT_THERMISTOR - if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) -#endif //AMBIENT_THERMISTOR + if(current_temperature_bed < BED_MAXTEMP) { soft_pwm_bed = (int)pid_output >> 1; + timer02_set_pwm0(soft_pwm_bed << 1); } else { soft_pwm_bed = 0; + timer02_set_pwm0(soft_pwm_bed << 1); } #elif !defined(BED_LIMIT_SWITCHING) // Check if temperature is within the correct range - if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) + if(current_temperature_bed < BED_MAXTEMP) { if(current_temperature_bed >= target_temperature_bed) { soft_pwm_bed = 0; + timer02_set_pwm0(soft_pwm_bed << 1); } else { soft_pwm_bed = MAX_BED_POWER>>1; + timer02_set_pwm0(soft_pwm_bed << 1); } } else { soft_pwm_bed = 0; + timer02_set_pwm0(soft_pwm_bed << 1); WRITE(HEATER_BED_PIN,LOW); } #else //#ifdef BED_LIMIT_SWITCHING // Check if temperature is within the correct band - if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) + if(current_temperature_bed < BED_MAXTEMP) { if(current_temperature_bed > target_temperature_bed + BED_HYSTERESIS) { soft_pwm_bed = 0; + timer02_set_pwm0(soft_pwm_bed << 1); } else if(current_temperature_bed <= target_temperature_bed - BED_HYSTERESIS) { soft_pwm_bed = MAX_BED_POWER>>1; + timer02_set_pwm0(soft_pwm_bed << 1); } } else { soft_pwm_bed = 0; + timer02_set_pwm0(soft_pwm_bed << 1); WRITE(HEATER_BED_PIN,LOW); } #endif + if(target_temperature_bed==0) + soft_pwm_bed = 0; #endif #ifdef HOST_KEEPALIVE_FEATURE @@ -983,7 +1017,6 @@ static void updateTemperaturesFromRawValues() CRITICAL_SECTION_END; } - void tp_init() { #if MB(RUMBA) && ((TEMP_SENSOR_0==-1)||(TEMP_SENSOR_1==-1)||(TEMP_SENSOR_2==-1)||(TEMP_SENSOR_BED==-1)) @@ -997,8 +1030,8 @@ void tp_init() // populate with the first value maxttemp[e] = maxttemp[0]; #ifdef PIDTEMP - temp_iState_min[e] = 0.0; - temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / cs.Ki; + iState_sum_min[e] = 0.0; + iState_sum_max[e] = PID_INTEGRAL_DRIVE_MAX / cs.Ki; #endif //PIDTEMP #ifdef PIDTEMPBED temp_iState_min_bed = 0.0; @@ -1050,10 +1083,12 @@ void tp_init() adc_init(); + timer02_init(); + // Use timer0 for temperature measurement // Interleave temperature interrupt with millies interrupt - OCR0B = 128; - TIMSK0 |= (1< -1 target_temperature_bed=0; soft_pwm_bed=0; + timer02_set_pwm0(soft_pwm_bed << 1); #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 WRITE(HEATER_BED_PIN,LOW); #endif @@ -1525,8 +1561,8 @@ void adc_ready(void) //callback from adc when sampling finished } // extern "C" -// Timer 0 is shared with millies -ISR(TIMER0_COMPB_vect) +// Timer2 (originaly timer0) is shared with millies +ISR(TIMER2_COMPB_vect) { static bool _lock = false; if (_lock) return; @@ -1534,11 +1570,6 @@ ISR(TIMER0_COMPB_vect) asm("sei"); if (!temp_meas_ready) adc_cycle(); - else - { - check_max_temp(); - check_min_temp(); - } lcd_buttons_update(); static unsigned char pwm_count = (1 << SOFT_PWM_SCALE); @@ -1598,7 +1629,7 @@ ISR(TIMER0_COMPB_vect) #endif #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 soft_pwm_b = soft_pwm_bed; - if(soft_pwm_b > 0) WRITE(HEATER_BED_PIN,1); else WRITE(HEATER_BED_PIN,0); + //if(soft_pwm_b > 0) WRITE(HEATER_BED_PIN,1); else WRITE(HEATER_BED_PIN,0); #endif } #ifdef FAN_SOFT_PWM @@ -1735,7 +1766,7 @@ ISR(TIMER0_COMPB_vect) state_timer_heater_b = MIN_STATE_TIME; } state_heater_b = 1; - WRITE(HEATER_BED_PIN, 1); + //WRITE(HEATER_BED_PIN, 1); } } else { // turn OFF heather only if the minimum time is up @@ -1934,26 +1965,49 @@ void check_min_temp_bed() void check_min_temp() { +static bool bCheckingOnHeater=false; // state variable, which allows to short no-checking delay (is set, when temperature is (first time) over heaterMintemp) +static bool bCheckingOnBed=false; // state variable, which allows to short no-checking delay (is set, when temperature is (first time) over bedMintemp) #ifdef AMBIENT_THERMISTOR - static uint8_t heat_cycles = 0; - if (current_temperature_raw_ambient > OVERSAMPLENR*MINTEMP_MINAMBIENT_RAW) - { - if (READ(HEATER_0_PIN) == HIGH) - { -// if ((heat_cycles % 10) == 0) -// printf_P(PSTR("X%d\n"), heat_cycles); - if (heat_cycles > 50) //reaction time 5-10s - check_min_temp_heater0(); - else - heat_cycles++; - } - else - heat_cycles = 0; - return; - } +if(current_temperature_raw_ambient>(OVERSAMPLENR*MINTEMP_MINAMBIENT_RAW)) // thermistor is NTC type, so operator is ">" ;-) + { // ambient temperature is low +#endif //AMBIENT_THERMISTOR +// *** 'common' part of code for MK2.5 & MK3 +// * nozzle checking +if(target_temperature[active_extruder]>minttemp[active_extruder]) + { // ~ nozzle heating is on + bCheckingOnHeater=bCheckingOnHeater||(current_temperature[active_extruder]>=minttemp[active_extruder]); // for eventually delay cutting + if(oTimer4minTempHeater.expired(HEATER_MINTEMP_DELAY)||(!oTimer4minTempHeater.running())||bCheckingOnHeater) + { + bCheckingOnHeater=true; // not necessary + check_min_temp_heater0(); // delay is elapsed or temperature is/was over minTemp => periodical checking is active + } + } +else { // ~ nozzle heating is off + oTimer4minTempHeater.start(); + bCheckingOnHeater=false; + } +// * bed checking +if(target_temperature_bed>BED_MINTEMP) + { // ~ bed heating is on + bCheckingOnBed=bCheckingOnBed||(current_temperature_bed>=BED_MINTEMP); // for eventually delay cutting + if(oTimer4minTempBed.expired(BED_MINTEMP_DELAY)||(!oTimer4minTempBed.running())||bCheckingOnBed) + { + bCheckingOnBed=true; // not necessary + check_min_temp_bed(); // delay is elapsed or temperature is/was over minTemp => periodical checking is active + } + } +else { // ~ bed heating is off + oTimer4minTempBed.start(); + bCheckingOnBed=false; + } +// *** end of 'common' part +#ifdef AMBIENT_THERMISTOR + } +else { // ambient temperature is standard + check_min_temp_heater0(); + check_min_temp_bed(); + } #endif //AMBIENT_THERMISTOR - check_min_temp_heater0(); - check_min_temp_bed(); } #if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1)) diff --git a/Firmware/temperature.h b/Firmware/temperature.h index 9a3cee834..e94629d18 100644 --- a/Firmware/temperature.h +++ b/Firmware/temperature.h @@ -27,8 +27,8 @@ #include "stepper.h" #endif -#define ENABLE_TEMPERATURE_INTERRUPT() TIMSK0 |= (1< +#include +#include + + +uint8_t timer02_pwm0 = 0; + +void timer02_set_pwm0(uint8_t pwm0) +{ + if (timer02_pwm0 == pwm0) return; + if (pwm0) + { + TCCR0A |= (2 << COM0B0); + OCR0B = pwm0 - 1; + } + else + { + TCCR0A &= ~(2 << COM0B0); + OCR0B = 0; + } +} + +void timer02_init(void) +{ + //save sreg + uint8_t _sreg = SREG; + //disable interrupts for sure + cli(); + //mask timer0 interrupts - disable all + TIMSK0 &= ~(1<> 3) +#define FRACT_MAX (1000 >> 3) + +extern volatile unsigned long timer0_overflow_count; +extern volatile unsigned long timer0_millis; +unsigned char timer0_fract = 0; + +ISR(TIMER2_OVF_vect) +{ + // copy these to local variables so they can be stored in registers + // (volatile variables must be read from memory on every access) + unsigned long m = timer0_millis; + unsigned char f = timer0_fract; + + m += MILLIS_INC; + f += FRACT_INC; + if (f >= FRACT_MAX) + { + f -= FRACT_MAX; + m += 1; + } + + timer0_fract = f; + timer0_millis = m; + timer0_overflow_count++; +} + diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 26b6ee760..80d03e68f 100644 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -163,6 +163,7 @@ static void lcd_selftest_screen_step(int _row, int _col, int _state, const char static bool lcd_selftest_manual_fan_check(int _fan, bool check_opposite); static bool lcd_selftest_fan_dialog(int _fan); static bool lcd_selftest_fsensor(); +static bool selftest_irsensor(); static void lcd_selftest_error(int _error_no, const char *_error_1, const char *_error_2); static void lcd_colorprint_change(); #ifdef SNMM @@ -237,6 +238,8 @@ bool wait_for_unclick; // float raw_Ki, raw_Kd; #endif +bool bMain; // flag (i.e. 'fake parameter') for 'lcd_sdcard_menu()' function + const char STR_SEPARATOR[] PROGMEM = "------------"; @@ -5886,7 +5889,10 @@ static void lcd_main_menu() if (!is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL)) { //if (farm_mode) MENU_ITEM_SUBMENU_P(MSG_FARM_CARD_MENU, lcd_farm_sdcard_menu); - /*else*/ MENU_ITEM_SUBMENU_P(_T(MSG_CARD_MENU), lcd_sdcard_menu); + /*else*/ { + bMain=true; // flag ('fake parameter') for 'lcd_sdcard_menu()' function + MENU_ITEM_SUBMENU_P(_T(MSG_CARD_MENU), lcd_sdcard_menu); + } } #if SDCARDDETECT < 1 MENU_ITEM_GCODE_P(_i("Change SD card"), PSTR("M21")); // SD-card changed by user////MSG_CNG_SDCARD c=0 r=0 @@ -5895,6 +5901,7 @@ static void lcd_main_menu() } else { + bMain=true; // flag (i.e. 'fake parameter') for 'lcd_sdcard_menu()' function MENU_ITEM_SUBMENU_P(_i("No SD card"), lcd_sdcard_menu);////MSG_NO_CARD c=0 r=0 #if SDCARDDETECT < 1 MENU_ITEM_GCODE_P(_i("Init. SD card"), PSTR("M21")); // Manually initialize the SD-card via user interface////MSG_INIT_SDCARD c=0 r=0 @@ -6227,7 +6234,10 @@ void lcd_sdcard_menu() MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MAIN)); + if(bMain) // i.e. default menu-item + MENU_ITEM_BACK_P(_T(MSG_MAIN)); + else // i.e. menu-item after card insertion + MENU_ITEM_FUNCTION_P(_T(MSG_WATCH),lcd_return_to_status); card.getWorkDirName(); if (card.filename[0] == '/') { @@ -6323,28 +6333,24 @@ bool lcd_selftest() _result = true; #endif } - - if (_result) - { - _progress = lcd_selftest_screen(3, _progress, 3, true, 1000); - _result = lcd_selfcheck_check_heater(false); - } - if (_result) { //current_position[Z_AXIS] += 15; //move Z axis higher to avoid false triggering of Z end stop in case that we are very low - just above heatbed - _progress = lcd_selftest_screen(4, _progress, 3, true, 2000); + _progress = lcd_selftest_screen(3, _progress, 3, true, 2000); #ifdef TMC2130 - _result = lcd_selfcheck_axis_sg(X_AXIS); + _result = lcd_selfcheck_axis_sg(X_AXIS); #else - _result = lcd_selfcheck_axis(X_AXIS, X_MAX_POS); + _result = lcd_selfcheck_axis(X_AXIS, X_MAX_POS); #endif //TMC2130 } + + + if (_result) { - _progress = lcd_selftest_screen(4, _progress, 3, true, 0); + _progress = lcd_selftest_screen(3, _progress, 3, true, 0); #ifndef TMC2130 _result = lcd_selfcheck_pulleys(X_AXIS); @@ -6354,7 +6360,7 @@ bool lcd_selftest() if (_result) { - _progress = lcd_selftest_screen(5, _progress, 3, true, 1500); + _progress = lcd_selftest_screen(4, _progress, 3, true, 1500); #ifdef TMC2130 _result = lcd_selfcheck_axis_sg(Y_AXIS); #else @@ -6364,7 +6370,7 @@ bool lcd_selftest() if (_result) { - _progress = lcd_selftest_screen(5, _progress, 3, true, 0); + _progress = lcd_selftest_screen(4, _progress, 3, true, 0); #ifndef TMC2130 _result = lcd_selfcheck_pulleys(Y_AXIS); #endif // TMC2130 @@ -6385,7 +6391,7 @@ bool lcd_selftest() current_position[Z_AXIS] = current_position[Z_AXIS] + 10; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); st_synchronize(); - _progress = lcd_selftest_screen(6, _progress, 3, true, 1500); + _progress = lcd_selftest_screen(5, _progress, 3, true, 1500); _result = lcd_selfcheck_axis(2, Z_MAX_POS); if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) != 1) { enquecommand_P(PSTR("G28 W")); @@ -6412,25 +6418,46 @@ bool lcd_selftest() if (_result) { - _progress = lcd_selftest_screen(7, _progress, 3, true, 2000); //check bed + _progress = lcd_selftest_screen(6, _progress, 3, true, 2000); //check bed _result = lcd_selfcheck_check_heater(true); } + + if (_result) + { + _progress = lcd_selftest_screen(7, _progress, 3, true, 1000); //check nozzle + _result = lcd_selfcheck_check_heater(false); + } if (_result) { - _progress = lcd_selftest_screen(8, _progress, 3, true, 2000); //bed ok -#ifdef PAT9125 - if (mmu_enabled == false) { - _progress = lcd_selftest_screen(9, _progress, 3, true, 2000); //check filaments sensor - _result = lcd_selftest_fsensor(); - } + _progress = lcd_selftest_screen(8, _progress, 3, true, 2000); //nozzle ok } +#ifdef FILAMENT_SENSOR + if (_result) + { + + if (mmu_enabled) + { + _progress = lcd_selftest_screen(9, _progress, 3, true, 2000); //check filaments sensor + _result = selftest_irsensor(); + if (_result) + { + _progress = lcd_selftest_screen(10, _progress, 3, true, 2000); //fil sensor OK + } + } else + { +#ifdef PAT9125 + _progress = lcd_selftest_screen(9, _progress, 3, true, 2000); //check filaments sensor + _result = lcd_selftest_fsensor(); + if (_result) + { + _progress = lcd_selftest_screen(10, _progress, 3, true, 2000); //fil sensor OK + } +#endif //PAT9125 + } + } +#endif //FILAMENT_SENSOR if (_result) { - if (mmu_enabled == false) - { - _progress = lcd_selftest_screen(10, _progress, 3, true, 2000); //fil sensor OK - } -#endif // PAT9125 _progress = lcd_selftest_screen(11, _progress, 3, true, 5000); //all correct } else @@ -6642,7 +6669,7 @@ static bool lcd_selfcheck_axis(int _axis, int _travel) } else { - _progress = lcd_selftest_screen(4 + _axis, _progress, 3, false, 0); + _progress = lcd_selftest_screen(3 + _axis, _progress, 3, false, 0); _lcd_refresh = 0; } @@ -6809,7 +6836,7 @@ static bool lcd_selfcheck_check_heater(bool _isbed) manage_heater(); manage_inactivity(true); - _progress = (_isbed) ? lcd_selftest_screen(7, _progress, 2, false, 400) : lcd_selftest_screen(3, _progress, 2, false, 400); + _progress = (_isbed) ? lcd_selftest_screen(6, _progress, 2, false, 400) : lcd_selftest_screen(7, _progress, 2, false, 400); /*if (_isbed) { MYSERIAL.print("Bed temp:"); MYSERIAL.println(degBed()); @@ -6835,9 +6862,10 @@ static bool lcd_selfcheck_check_heater(bool _isbed) MYSERIAL.print("Opposite result:"); MYSERIAL.println(_opposite_result); */ - if (_opposite_result < ((_isbed) ? 10 : 3)) + + if (_opposite_result < ((_isbed) ? 30 : 9)) { - if (_checked_result >= ((_isbed) ? 3 : 10)) + if (_checked_result >= ((_isbed) ? 9 : 30)) { _stepresult = true; } @@ -6985,6 +7013,70 @@ static bool lcd_selftest_fsensor(void) } return (!fsensor_not_responding); } + +//! @brief Self-test of infrared barrier filament sensor mounted on MK3S with MMUv2 printer +//! +//! Test whether sensor is not triggering filament presence when extruder idler is moving without filament. +//! +//! Steps: +//! * Backup current active extruder temperature +//! * Pre-heat to PLA extrude temperature. +//! * Unload filament possibly present. +//! * Move extruder idler same way as during filament load +//! and sample MMU_IDLER_SENSOR_PIN. +//! * Check that pin doesn't go low. +//! +//! @retval true passed +//! @retval false failed +static bool selftest_irsensor() +{ + class TempBackup + { + public: + TempBackup(): + m_temp(degTargetHotend(active_extruder)), + m_extruder(active_extruder){} + ~TempBackup(){setTargetHotend(m_temp,m_extruder);} + private: + float m_temp; + uint8_t m_extruder; + }; + uint8_t progress; + { + TempBackup tempBackup; + setTargetHotend(ABS_PREHEAT_HOTEND_TEMP,active_extruder); + mmu_wait_for_heater_blocking(); + progress = lcd_selftest_screen(9, 0, 1, true, 0); + mmu_filament_ramming(); + } + progress = lcd_selftest_screen(9, progress, 1, true, 0); + mmu_command(MMU_CMD_U0); + manage_response(false, false); + + for(uint_least8_t i = 0; i < 200; ++i) + { + if (0 == (i % 32)) progress = lcd_selftest_screen(9, progress, 1, true, 0); + + mmu_load_step(false); + while (blocks_queued()) + { + if (PIN_GET(MMU_IDLER_SENSOR_PIN) == 0) return false; +#ifdef TMC2130 + manage_heater(); + // Vojtech: Don't disable motors inside the planner! + if (!tmc2130_update_sg()) + { + manage_inactivity(true); + } +#else //TMC2130 + manage_heater(); + // Vojtech: Don't disable motors inside the planner! + manage_inactivity(true); +#endif //TMC2130 + } + } + return true; +} #endif //FILAMENT_SENSOR static bool lcd_selftest_manual_fan_check(int _fan, bool check_opposite) @@ -7147,7 +7239,7 @@ static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bo lcd_update_enable(false); int _step_block = 0; - const char *_indicator = (_progress > _progress_scale) ? "-" : "|"; + const char *_indicator = (_progress >= _progress_scale) ? "-" : "|"; if (_clear) lcd_clear(); @@ -7158,12 +7250,12 @@ static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bo if (_step == 0) lcd_puts_P(_T(MSG_SELFTEST_FAN)); if (_step == 1) lcd_puts_P(_T(MSG_SELFTEST_FAN)); if (_step == 2) lcd_puts_P(_i("Checking endstops"));////MSG_SELFTEST_CHECK_ENDSTOPS c=20 r=0 - if (_step == 3) lcd_puts_P(_i("Checking hotend "));////MSG_SELFTEST_CHECK_HOTEND c=20 r=0 - if (_step == 4) lcd_puts_P(_i("Checking X axis "));////MSG_SELFTEST_CHECK_X c=20 r=0 - if (_step == 5) lcd_puts_P(_i("Checking Y axis "));////MSG_SELFTEST_CHECK_Y c=20 r=0 - if (_step == 6) lcd_puts_P(_i("Checking Z axis "));////MSG_SELFTEST_CHECK_Z c=20 r=0 - if (_step == 7) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED)); - if (_step == 8) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED)); + if (_step == 3) lcd_puts_P(_i("Checking X axis "));////MSG_SELFTEST_CHECK_X c=20 r=0 + if (_step == 4) lcd_puts_P(_i("Checking Y axis "));////MSG_SELFTEST_CHECK_Y c=20 r=0 + if (_step == 5) lcd_puts_P(_i("Checking Z axis "));////MSG_SELFTEST_CHECK_Z c=20 r=0 + if (_step == 6) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED)); + if (_step == 7 + || _step == 8) lcd_puts_P(_i("Checking hotend "));////MSG_SELFTEST_CHECK_HOTEND c=20 r=0 if (_step == 9) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR)); if (_step == 10) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR)); if (_step == 11) lcd_puts_P(_i("All correct "));////MSG_SELFTEST_CHECK_ALLCORRECT c=20 r=0 @@ -7191,26 +7283,27 @@ static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bo else if (_step < 9) { //SERIAL_ECHOLNPGM("Other tests"); - _step_block = 3; - lcd_selftest_screen_step(3, 9, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Hotend", _indicator); - _step_block = 4; + _step_block = 3; lcd_selftest_screen_step(2, 2, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "X", _indicator); - _step_block = 5; + _step_block = 4; lcd_selftest_screen_step(2, 8, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Y", _indicator); - _step_block = 6; + _step_block = 5; lcd_selftest_screen_step(2, 14, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Z", _indicator); - _step_block = 7; + _step_block = 6; lcd_selftest_screen_step(3, 0, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Bed", _indicator); + + _step_block = 7; + lcd_selftest_screen_step(3, 9, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Hotend", _indicator); } if (_delay > 0) delay_keep_alive(_delay); _progress++; - return (_progress > _progress_scale * 2) ? 0 : _progress; + return (_progress >= _progress_scale * 2) ? 0 : _progress; } static void lcd_selftest_screen_step(int _row, int _col, int _state, const char *_name, const char *_indicator) @@ -7517,7 +7610,9 @@ void menu_lcd_lcdupdate_func(void) if (lcd_oldcardstatus) { card.initsd(); - LCD_MESSAGERPGM(_i("Card inserted"));////MSG_SD_INSERTED c=0 r=0 + LCD_MESSAGERPGM(_T(WELCOME_MSG)); + bMain=false; // flag (i.e. 'fake parameter') for 'lcd_sdcard_menu()' function + menu_submenu(lcd_sdcard_menu); //get_description(); } else diff --git a/Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h index 7bceb096f..852275392 100644 --- a/Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h @@ -1,6 +1,7 @@ #ifndef CONFIGURATION_PRUSA_H #define CONFIGURATION_PRUSA_H +#include /*------------------------------------ GENERAL SETTINGS *------------------------------------*/ @@ -102,10 +103,18 @@ EXTRUDER SETTINGS *------------------------------------*/ // Mintemps -#define HEATER_0_MINTEMP 15 +#define HEATER_0_MINTEMP 30 #define HEATER_1_MINTEMP 5 #define HEATER_2_MINTEMP 5 -#define BED_MINTEMP 15 +#define HEATER_MINTEMP_DELAY 15000 // [ms] ! if changed, check maximal allowed value @ ShortTimer +#if HEATER_MINTEMP_DELAY>USHRT_MAX +#error "Check maximal allowed value @ ShortTimer (see HEATER_MINTEMP_DELAY definition)" +#endif +#define BED_MINTEMP 30 +#define BED_MINTEMP_DELAY 50000 // [ms] ! if changed, check maximal allowed value @ ShortTimer +#if BED_MINTEMP_DELAY>USHRT_MAX +#error "Check maximal allowed value @ ShortTimer (see BED_MINTEMP_DELAY definition)" +#endif // Maxtemps #if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP) diff --git a/Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h b/Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h index 14fbd865b..d001f37f8 100644 --- a/Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h @@ -1,6 +1,7 @@ #ifndef CONFIGURATION_PRUSA_H #define CONFIGURATION_PRUSA_H +#include /*------------------------------------ GENERAL SETTINGS *------------------------------------*/ @@ -102,10 +103,18 @@ EXTRUDER SETTINGS *------------------------------------*/ // Mintemps -#define HEATER_0_MINTEMP 15 +#define HEATER_0_MINTEMP 30 #define HEATER_1_MINTEMP 5 #define HEATER_2_MINTEMP 5 -#define BED_MINTEMP 15 +#define HEATER_MINTEMP_DELAY 15000 // [ms] ! if changed, check maximal allowed value @ ShortTimer +#if HEATER_MINTEMP_DELAY>USHRT_MAX +#error "Check maximal allowed value @ ShortTimer (see HEATER_MINTEMP_DELAY definition)" +#endif +#define BED_MINTEMP 30 +#define BED_MINTEMP_DELAY 50000 // [ms] ! if changed, check maximal allowed value @ ShortTimer +#if BED_MINTEMP_DELAY>USHRT_MAX +#error "Check maximal allowed value @ ShortTimer (see BED_MINTEMP_DELAY definition)" +#endif // Maxtemps #if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP) diff --git a/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h index a0323213c..e12e6609b 100644 --- a/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h @@ -1,6 +1,7 @@ #ifndef CONFIGURATION_PRUSA_H #define CONFIGURATION_PRUSA_H +#include /*------------------------------------ GENERAL SETTINGS *------------------------------------*/ @@ -155,10 +156,18 @@ *------------------------------------*/ // Mintemps -#define HEATER_0_MINTEMP 15 +#define HEATER_0_MINTEMP 30 #define HEATER_1_MINTEMP 5 #define HEATER_2_MINTEMP 5 -#define BED_MINTEMP 15 +#define HEATER_MINTEMP_DELAY 15000 // [ms] ! if changed, check maximal allowed value @ ShortTimer +#if HEATER_MINTEMP_DELAY>USHRT_MAX +#error "Check maximal allowed value @ ShortTimer (see HEATER_MINTEMP_DELAY definition)" +#endif +#define BED_MINTEMP 30 +#define BED_MINTEMP_DELAY 50000 // [ms] ! if changed, check maximal allowed value @ ShortTimer +#if BED_MINTEMP_DELAY>USHRT_MAX +#error "Check maximal allowed value @ ShortTimer (see BED_MINTEMP_DELAY definition)" +#endif // Maxtemps #if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP) diff --git a/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h index ba3de9104..bfcbf7419 100644 --- a/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h @@ -1,6 +1,7 @@ #ifndef CONFIGURATION_PRUSA_H #define CONFIGURATION_PRUSA_H +#include /*------------------------------------ GENERAL SETTINGS *------------------------------------*/ @@ -156,10 +157,18 @@ *------------------------------------*/ // Mintemps -#define HEATER_0_MINTEMP 15 +#define HEATER_0_MINTEMP 30 #define HEATER_1_MINTEMP 5 #define HEATER_2_MINTEMP 5 -#define BED_MINTEMP 15 +#define HEATER_MINTEMP_DELAY 15000 // [ms] ! if changed, check maximal allowed value @ ShortTimer +#if HEATER_MINTEMP_DELAY>USHRT_MAX +#error "Check maximal allowed value @ ShortTimer (see HEATER_MINTEMP_DELAY definition)" +#endif +#define BED_MINTEMP 30 +#define BED_MINTEMP_DELAY 50000 // [ms] ! if changed, check maximal allowed value @ ShortTimer +#if BED_MINTEMP_DELAY>USHRT_MAX +#error "Check maximal allowed value @ ShortTimer (see BED_MINTEMP_DELAY definition)" +#endif // Maxtemps #if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP) diff --git a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h index e1ff0036c..7ced6b864 100644 --- a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h @@ -1,6 +1,7 @@ #ifndef CONFIGURATION_PRUSA_H #define CONFIGURATION_PRUSA_H +#include /*------------------------------------ GENERAL SETTINGS *------------------------------------*/ @@ -276,7 +277,15 @@ #define HEATER_0_MINTEMP 15 #define HEATER_1_MINTEMP 5 #define HEATER_2_MINTEMP 5 +#define HEATER_MINTEMP_DELAY 15000 // [ms] ! if changed, check maximal allowed value @ ShortTimer +#if HEATER_MINTEMP_DELAY>USHRT_MAX +#error "Check maximal allowed value @ ShortTimer (see HEATER_MINTEMP_DELAY definition)" +#endif #define BED_MINTEMP 15 +#define BED_MINTEMP_DELAY 50000 // [ms] ! if changed, check maximal allowed value @ ShortTimer +#if BED_MINTEMP_DELAY>USHRT_MAX +#error "Check maximal allowed value @ ShortTimer (see BED_MINTEMP_DELAY definition)" +#endif // Maxtemps #if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP) diff --git a/README.md b/README.md index 593f9134e..b7fc1155e 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ The script downloads Arduino with our modifications and Rambo board support inst a. install `"Arduino Software IDE"` for your preferred operating system `https://www.arduino.cc -> Software->Downloads` -it is recommended to use older version `"1.6.9"`, as it is used on out build server to produce official builds. +it is recommended to use version `"1.8.5"`, as it is used on out build server to produce official builds. _note: in the case of persistent compilation problems, check the version of the currently used C/C++ compiler (GCC) - should be `4.8.1`; version can be verified by entering the command `avr-gcc --version` if you are not sure where the file is placed (depends on how `"Arduino Software IDE"` was installed), you can use the search feature within the file system_ diff --git a/Tests/AutoDeplete_test.cpp b/Tests/AutoDeplete_test.cpp new file mode 100644 index 000000000..fb2964bc0 --- /dev/null +++ b/Tests/AutoDeplete_test.cpp @@ -0,0 +1,146 @@ +/** + * @file + * @author Marek Bel + */ + +#include "catch.hpp" + +#include "../Firmware/AutoDeplete.h" + +TEST_CASE( "AutoDeplete test.", "[AutoDeplete]" ) +{ + CHECK(ad_allDepleted() == false); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 1); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + + ad_markDepleted(1); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 2); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markDepleted(3); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 2); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 4); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markDepleted(4); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 2); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 0); + CHECK(ad_getAlternative(4) == 0); + CHECK(ad_allDepleted() == false); + + ad_markDepleted(4); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 2); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 0); + CHECK(ad_getAlternative(4) == 0); + CHECK(ad_allDepleted() == false); + + ad_markDepleted(0); + + CHECK(ad_getAlternative(0) == 2); + CHECK(ad_getAlternative(1) == 2); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 2); + CHECK(ad_getAlternative(4) == 2); + CHECK(ad_allDepleted() == false); + + ad_markDepleted(2); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 1); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == true); + + ad_markDepleted(2); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 1); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == true); + + ad_markLoaded(4); + + CHECK(ad_getAlternative(0) == 4); + CHECK(ad_getAlternative(1) == 4); + CHECK(ad_getAlternative(2) == 4); + CHECK(ad_getAlternative(3) == 4); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markLoaded(0); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 4); + CHECK(ad_getAlternative(2) == 4); + CHECK(ad_getAlternative(3) == 4); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markLoaded(3); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 3); + CHECK(ad_getAlternative(2) == 3); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markLoaded(3); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 3); + CHECK(ad_getAlternative(2) == 3); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markLoaded(2); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 2); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markLoaded(1); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 1); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markLoaded(1); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 1); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + +} diff --git a/build.sh b/build.sh index 45bb9a931..051f1352c 100755 --- a/build.sh +++ b/build.sh @@ -12,7 +12,7 @@ if [ ! -f "PF-build-env-Linux64-$BUILD_ENV.zip" ]; then fi if [ ! -d "../../PF-build-env-$BUILD_ENV" ]; then - unzip PF-build-env-Linux64-$BUILD_ENV.zip -d ../../PF-build-env-$BUILD_ENV || exit 4 + unzip -q PF-build-env-Linux64-$BUILD_ENV.zip -d ../../PF-build-env-$BUILD_ENV || exit 4 fi cd ../../PF-build-env-$BUILD_ENV || exit 5