Browse Source

Fix MINTEMP errors and fsensor runout

DRracer 5 years ago
parent
commit
9cb0bc7bcf

+ 7 - 0
Firmware/Marlin.h

@@ -390,6 +390,13 @@ extern LongTimer safetyTimer;
 
 #define PRINT_PERCENT_DONE_INIT   0xff
 #define PRINTER_ACTIVE (IS_SD_PRINTING || is_usb_printing || isPrintPaused || (custom_message_type == CUSTOM_MSG_TYPE_TEMCAL) || saved_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL) || card.paused || mmu_print_saved)
+//! Beware - mcode_in_progress is set as soon as the command gets really processed,
+//! which is not the same as posting the M600 command into the command queue
+//! There can be a considerable lag between posting M600 and its real processing which might result
+//! in posting multiple M600's into the command queue
+//! Instead, the fsensor uses another state variable :( , which is set to true, when the M600 command is enqued
+//! and is reset to false when the fsensor returns into its filament runout finished handler
+//! I'd normally change this macro, but who knows what would happen in the MMU :)
 #define CHECK_FSENSOR ((IS_SD_PRINTING || is_usb_printing) && (mcode_in_progress != 600) && !saved_printing && e_active())
 
 extern void calculate_extruder_multipliers();

+ 4 - 0
Firmware/Marlin_main.cpp

@@ -3552,6 +3552,10 @@ void process_commands()
                enquecommand_P(PSTR("M24")); 
 		}	
 #ifdef FILAMENT_SENSOR
+		else if (code_seen("fsensor_recover_IR")) //! PRUSA fsensor_recover_IR
+		{
+			fsensor_restore_print_and_continue_IR();
+		}
 		else if (code_seen("fsensor_recover")) //! PRUSA fsensor_recover
 		{
                fsensor_restore_print_and_continue();

+ 22 - 10
Firmware/fsensor.cpp

@@ -57,6 +57,11 @@ bool fsensor_not_responding = false;
 bool fsensor_printing_saved = false;
 //! enable/disable quality meassurement
 bool fsensor_oq_meassure_enabled = false;
+//! as explained in the CHECK_FSENSOR macro: this flag is set to true when fsensor posts
+//! the M600 into the command queue, which elliminates the hazard of having posted multiple M600's
+//! before the first one gets read and started processing.
+//! Btw., the IR fsensor could do up to 6 posts before the command queue managed to start processing the first M600 ;)
+static bool fsensor_m600_enqueued = false;
 
 //! number of errors, updated in ISR
 uint8_t fsensor_err_cnt = 0;
@@ -118,11 +123,17 @@ void fsensor_stop_and_save_print(void)
     stop_and_save_print_to_ram(0, 0); //XYZE - no change
 }
 
-void fsensor_restore_print_and_continue(void)
+void fsensor_restore_print_and_continue_IR(void)
 {
-    printf_P(PSTR("fsensor_restore_print_and_continue\n"));
 	fsensor_watch_runout = true;
 	fsensor_err_cnt = 0;
+	fsensor_m600_enqueued = false;
+}
+
+void fsensor_restore_print_and_continue(void)
+{
+    printf_P(PSTR("fsensor_restore_print_and_continue\n"));
+    fsensor_restore_print_and_continue_IR();
     restore_print_from_ram_and_continue(0); //XYZ = orig, E - no change
 }
 
@@ -575,14 +586,15 @@ void fsensor_update(void)
 			fsensor_oq_meassure_enabled = oq_meassure_enabled_tmp;
 		}
 #else //PAT9125
-		if ((digitalRead(IR_SENSOR_PIN) == 1) && CHECK_FSENSOR && fsensor_enabled && ir_sensor_detected)
-		{
-			fsensor_stop_and_save_print();
-			printf_P(PSTR("fsensor_update - M600\n"));
-			eeprom_update_byte((uint8_t*)EEPROM_FERROR_COUNT, eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) + 1);
-			eeprom_update_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) + 1);
-			enquecommand_front_P(PSTR("PRUSA fsensor_recover"));
-			enquecommand_front_P((PSTR("M600")));
+		if ((digitalRead(IR_SENSOR_PIN) == 1) && CHECK_FSENSOR && fsensor_enabled && ir_sensor_detected && ( ! fsensor_m600_enqueued) )
+		{	// just plan a simple M600 without any additional position save/restore,
+			// which caused weird heating issues standing directly over the print
+			printf_P(PSTR("fsensor_update - M600\n"));
+			eeprom_update_byte((uint8_t*)EEPROM_FERROR_COUNT, eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) + 1);
+			eeprom_update_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) + 1);
+			enquecommand_front_P(PSTR("PRUSA fsensor_recover_IR"));
+			fsensor_m600_enqueued = true;
+			enquecommand_front_P((PSTR("M600")));
 		}
 #endif //PAT9125
 }

+ 3 - 0
Firmware/fsensor.h

@@ -18,6 +18,9 @@ extern bool fsensor_oq_meassure_enabled;
 //! @name save restore printing
 //! @{
 extern void fsensor_stop_and_save_print(void);
+//! special handling for the IR sensor (no restore position and heating, since this is already correctly handled in the M600 itself)
+extern void fsensor_restore_print_and_continue_IR(void);
+//! legacy restore print - restore position and heatup to original temperature - for the MMU and the optical fsensor
 extern void fsensor_restore_print_and_continue(void);
 //! @}
 

+ 1 - 1
Firmware/menu.cpp

@@ -26,7 +26,7 @@ uint8_t menu_data[MENU_DATA_SIZE];
 #endif
 
 uint8_t menu_depth = 0;
-
+uint8_t menu_block_entering_on_serious_errors = SERIOUS_ERR_NONE;
 uint8_t menu_line = 0;
 uint8_t menu_item = 0;
 uint8_t menu_row = 0;

+ 21 - 0
Firmware/menu.h

@@ -28,6 +28,27 @@ extern uint8_t menu_data[MENU_DATA_SIZE];
 
 extern uint8_t menu_depth;
 
+//! definition of serious errors possibly blocking the main menu
+//! Use them as bit mask, so that the code may set various errors at the same time
+enum ESeriousErrors {
+	SERIOUS_ERR_NONE            = 0,
+	SERIOUS_ERR_MINTEMP_HEATER  = 0x01,
+	SERIOUS_ERR_MINTEMP_BED     = 0x02
+}; // and possibly others in the future.
+
+//! this is a flag for disabling entering the main menu. If this is set
+//! to anything != 0, the only the main status screen will be shown on the
+//! LCD and the user will be prevented from entering the menu.
+//! Now used only to block doing anything with the printer when there is
+//! the infamous MINTEMP error (SERIOUS_ERR_MINTEMP).
+extern uint8_t menu_block_entering_on_serious_errors;
+
+//! a pair of macros for manipulating the serious errors
+//! a c++ class would have been better
+#define menu_set_serious_error(x) menu_block_entering_on_serious_errors |= x;
+#define menu_unset_serious_error(x) menu_block_entering_on_serious_errors &= ~x;
+#define menu_is_serious_error(x) (menu_block_entering_on_serious_errors & x) != 0
+
 extern uint8_t menu_line;
 extern uint8_t menu_item;
 extern uint8_t menu_row;

+ 87 - 2
Firmware/temperature.cpp

@@ -1469,6 +1469,15 @@ void disable_heater()
     #endif
   #endif 
 }
+//! codes of alert messages for the LCD - it is shorter to compare an uin8_t
+//! than raw const char * of the messages themselves.
+//! Could be used for MAXTEMP situations too - after reaching MAXTEMP and turning off the heater automagically
+//! the heater/bed may cool down and a similar alert message like "MAXTERM fixed..." may be displayed.
+enum { LCDALERT_NONE = 0, LCDALERT_HEATERMINTEMP, LCDALERT_BEDMINTEMP, LCDALERT_MINTEMPFIXED, LCDALERT_PLEASERESTART };
+
+//! remember the last alert message sent to the LCD
+//! to prevent flicker and improve speed
+uint8_t last_alert_sent_to_lcd = LCDALERT_NONE;
 
 void max_temp_error(uint8_t e) {
   disable_heater();
@@ -1502,13 +1511,23 @@ void min_temp_error(uint8_t e) {
 #endif
 //if (current_temperature_ambient < MINTEMP_MINAMBIENT) return;
   disable_heater();
+	static const char err[] PROGMEM = "Err: MINTEMP";
   if(IsStopped() == false) {
     SERIAL_ERROR_START;
     SERIAL_ERRORLN((int)e);
     SERIAL_ERRORLNPGM(": Extruder switched off. MINTEMP triggered !");
-    LCD_ALERTMESSAGEPGM("Err: MINTEMP");
+    lcd_setalertstatuspgm(err);
+    last_alert_sent_to_lcd = LCDALERT_HEATERMINTEMP;
+  } else if( last_alert_sent_to_lcd != LCDALERT_HEATERMINTEMP ){ // only update, if the lcd message is to be changed (i.e. not the same as last time)
+	// we are already stopped due to some error, only update the status message without flickering
+	lcd_updatestatuspgm(err);
+	last_alert_sent_to_lcd = LCDALERT_HEATERMINTEMP;
   }
   #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
+//	if( last_alert_sent_to_lcd != LCDALERT_HEATERMINTEMP ){
+//		last_alert_sent_to_lcd = LCDALERT_HEATERMINTEMP;
+//		lcd_print_stop();
+//	}
   Stop();
   #endif
   if (farm_mode) { prusa_statistics(92); }
@@ -1538,10 +1557,16 @@ void bed_min_temp_error(void) {
 #if HEATER_BED_PIN > -1
     WRITE(HEATER_BED_PIN, 0);
 #endif
+	static const char err[] PROGMEM = "Err: MINTEMP BED";
     if(IsStopped() == false) {
         SERIAL_ERROR_START;
         SERIAL_ERRORLNPGM("Temperature heated bed switched off. MINTEMP triggered !");
-        LCD_ALERTMESSAGEPGM("Err: MINTEMP BED");
+		lcd_setalertstatuspgm(err);
+		last_alert_sent_to_lcd = LCDALERT_BEDMINTEMP;
+	} else if( last_alert_sent_to_lcd != LCDALERT_BEDMINTEMP ){ // only update, if the lcd message is to be changed (i.e. not the same as last time)
+		// we are already stopped due to some error, only update the status message without flickering
+		lcd_updatestatuspgm(err);
+		last_alert_sent_to_lcd = LCDALERT_BEDMINTEMP;
     }
 #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
     Stop();
@@ -2015,6 +2040,52 @@ void check_max_temp()
 #endif
 
 }
+//! number of repeating the same state with consecutive step() calls
+//! used to slow down text switching
+struct alert_automaton_mintemp {
+	enum { ALERT_AUTOMATON_SPEED_DIV = 5 };
+	uint8_t state, repeat = ALERT_AUTOMATON_SPEED_DIV;
+
+	void substep(uint8_t next_state){
+		if( repeat == 0 ){
+			state = next_state; // advance to the next state
+			repeat = ALERT_AUTOMATON_SPEED_DIV; // and prepare repeating for it too
+		} else {
+			--repeat;
+		}
+	}
+
+	void step(float current_temp, float mintemp){
+		static const char m2[] PROGMEM = "MINTEMP fixed";
+		static const char m1[] PROGMEM = "Please restart";
+		switch(state){
+		case 0: // initial state - check hysteresis
+			if( current_temp > mintemp ){
+				state = 1;
+			}
+			// otherwise keep the Err MINTEMP alert message on the display,
+			// i.e. do not transfer to state 1
+			break;
+		case 1: // the temperature has risen above the hysteresis check
+			lcd_setalertstatuspgm(m2);
+			substep(3);
+			last_alert_sent_to_lcd = LCDALERT_MINTEMPFIXED;
+			break;
+		case 2: // displaying "Please restart"
+			lcd_updatestatuspgm(m1);
+			substep(3);
+			last_alert_sent_to_lcd = LCDALERT_PLEASERESTART;
+			break;
+		case 3: // displaying "MINTEMP fixed"
+			lcd_updatestatuspgm(m2);
+			substep(2);
+			last_alert_sent_to_lcd = LCDALERT_MINTEMPFIXED;
+			break;
+		}
+	}
+};
+
+static alert_automaton_mintemp aam[2];
 
 void check_min_temp_heater0()
 {
@@ -2024,7 +2095,16 @@ void check_min_temp_heater0()
 #else
 	if (current_temperature_raw[0] <= minttemp_raw[0]) {
 #endif
+		menu_set_serious_error(SERIOUS_ERR_MINTEMP_HEATER);
 		min_temp_error(0);
+	} else if( menu_is_serious_error(SERIOUS_ERR_MINTEMP_HEATER) ) {
+		// no recovery, just force the user to restart the printer
+		// which is a safer variant than just continuing printing
+		// The automaton also checks for hysteresis - the temperature must have reached a few degrees above the MINTEMP, before
+		// we shall signalize, that MINTEMP has been fixed
+		// Code notice: normally the aam instance would have been placed here as static alert_automaton_mintemp aam, but
+		// due to stupid compiler that takes 16 more bytes.
+		aam[0].step(current_temperature[0], minttemp[0] + TEMP_HYSTERESIS);
 	}
 }
 
@@ -2035,7 +2115,12 @@ void check_min_temp_bed()
 #else
 	if (current_temperature_bed_raw <= bed_minttemp_raw) {
 #endif
+		menu_set_serious_error(SERIOUS_ERR_MINTEMP_BED);
 		bed_min_temp_error();
+	} else if( menu_is_serious_error(SERIOUS_ERR_MINTEMP_BED) ){
+		// no recovery, just force the user to restart the printer
+		// which is a safer variant than just continuing printing
+		aam[1].step(current_temperature_bed, BED_MINTEMP + TEMP_HYSTERESIS);
 	}
 }
 

+ 14 - 4
Firmware/ultralcd.cpp

@@ -252,6 +252,7 @@ static void lcd_send_status();
 static void lcd_connect_printer();
 #endif //FARM_CONNECT_MESSAGE
 
+//! Beware: has side effects - forces lcd_draw_update to 2, which means clear the display
 void lcd_finishstatus();
 
 static void lcd_sdcard_menu();
@@ -1018,7 +1019,10 @@ static void lcd_status_screen()
 		}
 	}
 
-	if (current_click && (lcd_commands_type != LCD_COMMAND_STOP_PRINT)) //click is aborted unless stop print finishes
+	if (current_click
+		&& (lcd_commands_type != LCD_COMMAND_STOP_PRINT) //click is aborted unless stop print finishes
+		&& ( menu_block_entering_on_serious_errors == SERIOUS_ERR_NONE ) // or a serious error blocks entering the menu
+	)
 	{
 		menu_depth = 0; //redundant, as already done in lcd_return_to_status(), just to be sure
 		menu_submenu(lcd_main_menu);
@@ -8276,13 +8280,19 @@ void lcd_setstatus(const char* message)
   strncpy(lcd_status_message, message, LCD_WIDTH);
   lcd_finishstatus();
 }
+void lcd_updatestatuspgm(const char *message){
+	strncpy_P(lcd_status_message, message, LCD_WIDTH);
+	lcd_status_message[LCD_WIDTH] = 0;
+	lcd_finishstatus();
+	// hack lcd_draw_update to 1, i.e. without clear
+	lcd_draw_update = 1;
+}
+
 void lcd_setstatuspgm(const char* message)
 {
   if (lcd_status_message_level > 0)
     return;
-  strncpy_P(lcd_status_message, message, LCD_WIDTH);
-  lcd_status_message[LCD_WIDTH] = 0;
-  lcd_finishstatus();
+  lcd_updatestatuspgm(message);
 }
 void lcd_setalertstatuspgm(const char* message)
 {

+ 9 - 0
Firmware/ultralcd.h

@@ -18,7 +18,16 @@ extern void menu_lcd_lcdupdate_func(void);
 void ultralcd_init();
 void lcd_setstatus(const char* message);
 void lcd_setstatuspgm(const char* message);
+//! return to the main status screen and display the alert message
+//! Beware - it has sideeffects:
+//! - always returns the display to the main status screen
+//! - always makes lcd_reset (which is slow and causes flicker)
+//! - does not update the message if there is already one (i.e. lcd_status_message_level > 0)
 void lcd_setalertstatuspgm(const char* message);
+//! only update the alert message on the main status screen
+//! has no sideeffects, may be called multiple times
+void lcd_updatestatuspgm(const char *message);
+
 void lcd_reset_alert_level();
 uint8_t get_message_level();
 void lcd_adjust_z();