Merge pull request #3552 from wavexx/temp_model_check

Thermal Model protection
This commit is contained in:
DRracer 2022-08-24 19:16:48 +02:00 committed by GitHub
commit 0933fdb6fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 2599 additions and 1455 deletions

View file

@ -9,7 +9,6 @@ before_install:
- sudo iptables -A OUTPUT -o lo -j ACCEPT
- sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
script:
- bash -x test.sh
- cp Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h Firmware/Configuration_prusa.h
- bash -x build.sh || { echo "1_75mm_MK3S-EINSy10a-E3Dv6full variant failed" && false; }
- rm Firmware/Configuration_prusa.h

View file

@ -75,6 +75,9 @@ void Config_StoreSettings()
if (EEPROM_writeData(reinterpret_cast<uint8_t*>(EEPROM_M500_base),reinterpret_cast<uint8_t*>(&cs),sizeof(cs),0), "cs, invalid version")
{
#ifdef TEMP_MODEL
temp_model_save_settings();
#endif
strcpy(cs.version,EEPROM_VERSION); //!< validate data if write succeed
EEPROM_writeData(reinterpret_cast<uint8_t*>(EEPROM_M500_base->version), reinterpret_cast<uint8_t*>(cs.version), sizeof(cs.version), "cs.version valid");
}
@ -173,6 +176,9 @@ void Config_PrintSettings(uint8_t level)
printf_P(PSTR(
"%SArc Settings: P:Max length(mm) S:Min length (mm) N:Corrections R:Min segments F:Segments/sec.\n%S M214 P%.2f S%.2f N%d R%d F%d\n"),
echomagic, echomagic, cs.mm_per_arc_segment, cs.min_mm_per_arc_segment, cs.n_arc_correction, cs.min_arc_segments, cs.arc_segments_per_sec);
#ifdef TEMP_MODEL
temp_model_report_settings();
#endif
}
#endif
@ -321,6 +327,10 @@ bool Config_RetrieveSettings()
// Call updatePID (similar to when we have processed M301)
updatePID();
#ifdef TEMP_MODEL
temp_model_load_settings();
#endif
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Stored settings retrieved");
}
@ -353,6 +363,9 @@ void Config_ResetDefault()
#ifdef PIDTEMP
updatePID();
#endif//PIDTEMP
#ifdef TEMP_MODEL
temp_model_reset_settings();
#endif
calculate_extruder_multipliers();

View file

@ -573,6 +573,7 @@ void dcode_9()
for (uint8_t i = 0; i < ADC_CHAN_CNT; i++)
printf_P(PSTR("\tADC%d=%4d\t(%S)\n"), i, dcode_9_ADC_val(i) >> 4, dcode_9_ADC_name(i));
}
#if 0
else
{
uint8_t index = 0xff;
@ -588,6 +589,7 @@ void dcode_9()
}
}
}
#endif
}
/*!

View file

@ -241,9 +241,10 @@ void prepare_move();
void kill(const char *full_screen_message = NULL, unsigned char id = 0);
void finishAndDisableSteppers();
void UnconditionalStop(); // Stop heaters, motion and clear current print status
void Stop(); // Emergency stop used by overtemp functions which allows recovery
bool IsStopped(); // Returns true if the print has been stopped
void UnconditionalStop(); // Stop heaters, motion and clear current print status
void ThermalStop(bool allow_pause = false); // Emergency stop used by overtemp functions which allows
// recovery (with pause=true)
bool IsStopped(); // Returns true if the print has been stopped
//put an ASCII command at the end of the current buffer, read from flash
#define enquecommand_P(cmd) enquecommand(cmd, true)
@ -255,27 +256,6 @@ void prepare_arc_move(bool isclockwise);
void clamp_to_software_endstops(float target[3]);
void refresh_cmd_timeout(void);
// Timer counter, incremented by the 1ms Arduino timer.
// The standard Arduino timer() function returns this value atomically
// by disabling / enabling interrupts. This is costly, if the interrupts are known
// to be disabled.
#ifdef SYSTEM_TIMER_2
extern volatile unsigned long timer2_millis;
#else //SYSTEM_TIMER_2
extern volatile unsigned long timer0_millis;
#endif //SYSTEM_TIMER_2
// An unsynchronized equivalent to a standard Arduino _millis() function.
// To be used inside an interrupt routine.
FORCE_INLINE unsigned long millis_nc() {
#ifdef SYSTEM_TIMER_2
return timer2_millis;
#else //SYSTEM_TIMER_2
return timer0_millis;
#endif //SYSTEM_TIMER_2
}
#ifdef FAST_PWM_FAN
void setPwmFrequency(uint8_t pin, int val);
#endif
@ -315,18 +295,12 @@ void homeaxis(uint8_t axis, uint8_t cnt = 1, uint8_t* pstep = 0);
void homeaxis(uint8_t axis, uint8_t cnt = 1);
#endif //TMC2130
#ifdef FAN_SOFT_PWM
extern unsigned char fanSpeedSoftPwm;
#endif
#ifdef FWRETRACT
extern bool retracted[EXTRUDERS];
extern float retract_length_swap;
extern float retract_recover_length_swap;
#endif
extern uint8_t host_keepalive_interval;
extern unsigned long starttime;
@ -364,6 +338,10 @@ extern uint8_t saved_printing_type;
#define PRINTING_TYPE_USB 1
#define PRINTING_TYPE_NONE 2
extern float saved_extruder_temperature; //!< Active extruder temperature
extern float saved_bed_temperature; //!< Bed temperature
extern int saved_fan_speed; //!< Print fan speed
//save/restore printing in case that mmu is not responding
extern bool mmu_print_saved;
@ -385,6 +363,8 @@ extern LongTimer safetyTimer;
#define PRINT_PERCENT_DONE_INIT 0xff
#define PRINTER_ACTIVE (IS_SD_PRINTING || usb_timer.running() || isPrintPaused || (custom_message_type == CustomMsg::TempCal) || saved_printing || (lcd_commands_type == LcdCommands::Layer1Cal) || mmu_print_saved || homing_flag || mesh_bed_leveling_flag)
extern bool printer_active();
//! 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
@ -467,6 +447,7 @@ extern uint8_t calc_percent_done();
#define KEEPALIVE_STATE(n) do { busy_state = n;} while (0)
extern void host_keepalive();
extern void host_autoreport();
//extern MarlinBusyState busy_state;
extern int8_t busy_state;
@ -504,7 +485,6 @@ void raise_z_above(float target, bool plan=true);
extern "C" void softReset();
void stack_error();
void pullup_error(bool fromTempISR);
extern uint32_t IP_address;

View file

@ -37,11 +37,10 @@
// These are macros to build serial port register names for the selected SERIAL_PORT (C preprocessor
// requires two levels of indirection to expand macro values properly)
#define SERIAL_REGNAME(registerbase,number,suffix) SERIAL_REGNAME_INTERNAL(registerbase,number,suffix)
#if SERIAL_PORT == 0 && (!defined(UBRR0H) || !defined(UDR0)) // use un-numbered registers if necessary
#define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##suffix
#define SERIAL_REGNAME(registerbase,number,suffix) _REGNAME_SHORT(registerbase, suffix)
#else
#define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##number##suffix
#define SERIAL_REGNAME(registerbase,number,suffix) _REGNAME(registerbase, number, suffix)
#endif
// Registers used by MarlinSerial class (these are expanded

View file

@ -72,6 +72,7 @@
#include "planner.h"
#include "stepper.h"
#include "temperature.h"
#include "fancheck.h"
#include "motion_control.h"
#include "cardreader.h"
#include "ConfigurationStore.h"
@ -379,9 +380,10 @@ static float saved_pos[4] = { X_COORD_INVALID, 0, 0, 0 };
static uint16_t saved_feedrate2 = 0; //!< Default feedrate (truncated from float)
static int saved_feedmultiply2 = 0;
static uint8_t saved_active_extruder = 0;
static float saved_extruder_temperature = 0.0; //!< Active extruder temperature
float saved_extruder_temperature = 0.0; //!< Active extruder temperature
float saved_bed_temperature = 0.0; //!< Bed temperature
static bool saved_extruder_relative_mode = false;
static int saved_fanSpeed = 0; //!< Print fan speed
int saved_fan_speed = 0; //!< Print fan speed
//! @}
static int saved_feedmultiply_mm = 100;
@ -571,6 +573,10 @@ void servo_init()
#endif
}
bool printer_active()
{
return PRINTER_ACTIVE;
}
bool fans_check_enabled = true;
@ -1272,9 +1278,15 @@ void setup()
else { //printer version was changed so use default settings
Config_ResetDefault();
}
SdFatUtil::set_stack_guard(); //writes magic number at the end of static variables to protect against overwriting static memory by stack
tp_init(); // Initialize temperature loop
// writes a magic number at the end of static variables to monitor against incorrect overwriting
// of static memory by stack (this needs to be done before soft_pwm_init, since the check is
// performed inside the soft_pwm_isr)
SdFatUtil::set_stack_guard();
// Initialize pwm/temperature loops
soft_pwm_init();
temp_mgr_init();
#ifdef EXTRUDER_ALTFAN_DETECT
SERIAL_ECHORPGM(_n("Extruder fan type: "));
@ -1359,7 +1371,9 @@ void setup()
setup_photpin();
#if 0
servo_init();
#endif
// Reset the machine correction matrix.
// It does not make sense to load the correction matrix until the machine is homed.
@ -1692,10 +1706,6 @@ void stack_error() {
crash_and_burn(dump_crash_reason::stack_error);
}
void pullup_error(bool fromTempISR) {
crash_and_burn(fromTempISR ? dump_crash_reason::bad_pullup_temp_isr : dump_crash_reason::bad_pullup_step_isr);
}
#ifdef PRUSA_M28
void trace();
@ -1774,7 +1784,7 @@ void serial_read_stream() {
* Output autoreport values according to features requested in M155
*/
#if defined(AUTO_REPORT)
static void host_autoreport()
void host_autoreport()
{
if (autoReportFeatures.TimerExpired())
{
@ -1834,7 +1844,17 @@ void host_keepalive() {
// Before loop(), the setup() function is called by the main() routine.
void loop()
{
KEEPALIVE_STATE(NOT_BUSY);
// Reset a previously aborted command, we can now start processing motion again
planner_aborted = false;
if(Stopped) {
// Currently Stopped (possibly due to an error) and not accepting new serial commands.
// Signal to the host that we're currently busy waiting for supervision.
KEEPALIVE_STATE(PAUSED_FOR_USER);
} else {
// Printer is available for processing, reset state
KEEPALIVE_STATE(NOT_BUSY);
}
if (isPrintPaused && saved_printing_type == PRINTING_TYPE_USB) { //keep believing that usb is being printed. Prevents accessing dangerous menus while pausing.
usb_timer.start();
@ -1843,13 +1863,6 @@ void loop()
;
}
#ifdef FANCHECK
if (fan_check_error && isPrintPaused && !IS_SD_PRINTING) {
KEEPALIVE_STATE(PAUSED_FOR_USER);
host_keepalive(); //prevent timeouts since usb processing is disabled until print is resumed. This is for a crude way of pausing a print on all hosts.
}
#endif
#ifdef PRUSA_M28
if (prusa_sd_card_upload)
{
@ -2206,6 +2219,7 @@ void raise_z_above(float target, bool plan)
// Z needs raising
current_position[Z_AXIS] = target;
clamp_to_software_endstops(current_position);
#if defined(Z_MIN_PIN) && (Z_MIN_PIN > -1) && !defined(DEBUG_DISABLE_ZMINLIMIT)
bool z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING);
@ -2982,7 +2996,7 @@ static void gcode_G28(bool home_x_axis, bool home_y_axis, bool home_z_axis)
static void gcode_G80()
{
st_synchronize();
if (waiting_inside_plan_buffer_line_print_aborted)
if (planner_aborted)
return;
mesh_bed_leveling_flag = true;
@ -3076,7 +3090,7 @@ static void gcode_G80()
plan_buffer_line_curposXYZE(XY_AXIS_FEEDRATE);
// Wait until the move is finished.
st_synchronize();
if (waiting_inside_plan_buffer_line_print_aborted)
if (planner_aborted)
{
custom_message_type = custom_message_type_old;
custom_message_state = custom_message_state_old;
@ -3151,7 +3165,7 @@ static void gcode_G80()
//printf_P(PSTR("after clamping: [%f;%f]\n"), current_position[X_AXIS], current_position[Y_AXIS]);
plan_buffer_line_curposXYZE(XY_AXIS_FEEDRATE);
st_synchronize();
if (waiting_inside_plan_buffer_line_print_aborted)
if (planner_aborted)
{
custom_message_type = custom_message_type_old;
custom_message_state = custom_message_state_old;
@ -4138,6 +4152,7 @@ extern uint8_t st_backlash_y;
//!@n M302 - Allow cold extrudes, or set the minimum extrude S<temperature>.
//!@n M303 - PID relay autotune S<temperature> sets the target temperature. (default target temperature = 150C)
//!@n M304 - Set bed PID parameters P I and D
//!@n M310 - Temperature model settings
//!@n M400 - Finish all moves
//!@n M401 - Lower z-probe if present
//!@n M402 - Raise z-probe if present
@ -4179,16 +4194,6 @@ There are reasons why some G Codes aren't in numerical order.
void process_commands()
{
#ifdef FANCHECK
if(fan_check_error == EFCE_DETECTED) {
fan_check_error = EFCE_REPORTED;
if (usb_timer.running())
lcd_pause_usb_print();
else
lcd_pause_print();
}
#endif
if (!buflen) return; //empty command
#ifdef CMDBUFFER_DEBUG
@ -4642,7 +4647,7 @@ eeprom_update_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM,0xFFFF);
*/
case 0: // G0 -> G1
case 1: // G1
if(Stopped == false) {
{
get_coordinates(); // For X Y Z E F
// When recovering from a previous print move, restore the originally
@ -4701,7 +4706,7 @@ eeprom_update_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM,0xFFFF);
*/
case 2:
if(Stopped == false) {
{
get_arc_coordinates();
prepare_arc_move(true);
}
@ -4709,7 +4714,7 @@ eeprom_update_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM,0xFFFF);
// -------------------------------
case 3:
if(Stopped == false) {
{
get_arc_coordinates();
prepare_arc_move(false);
}
@ -7760,6 +7765,67 @@ Sigma_Exit:
PID_autotune(temp, e, c);
}
break;
#ifdef TEMP_MODEL
/*!
### M310 - Temperature model settings <a href="https://reprap.org/wiki/G-code#M310:_Temperature_model_settings">M310: Temperature model settings</a>
#### Usage
M310 ; report values
M310 [ A ] ; autotune
M310 [ S ] ; set 0=disable 1=enable
M310 [ I ] [ R ] ; set resistance at index
M310 [ P | C ] ; set power, capacitance
M310 [ B | E | W ] ; set beeper, warning and error threshold
M310 [ T ] ; set ambient temperature correction
#### Parameters
- `I` - resistance index position (0-15)
- `R` - resistance value at index (K/W; requires `I`)
- `P` - power (W)
- `C` - capacitance (J/K)
- `S` - set 0=disable 1=enable
- `B` - beep and warn when reaching warning threshold 0=disable 1=enable (default: 1)
- `E` - error threshold (K/s; default in variant)
- `W` - warning threshold (K/s; default in variant)
- `T` - ambient temperature correction (K; default in variant)
- `A` - autotune C+R values
*/
case 310:
{
// parse all parameters
float P = NAN, C = NAN, R = NAN, E = NAN, W = NAN, T = NAN;
int8_t I = -1, S = -1, B = -1, A = -1;
if(code_seen('C')) C = code_value();
if(code_seen('P')) P = code_value();
if(code_seen('I')) I = code_value_short();
if(code_seen('R')) R = code_value();
if(code_seen('S')) S = code_value_short();
if(code_seen('B')) B = code_value_short();
if(code_seen('E')) E = code_value();
if(code_seen('W')) W = code_value();
if(code_seen('T')) T = code_value();
if(code_seen('A')) A = code_value_short();
// report values if nothing has been requested
if(isnan(C) && isnan(P) && isnan(R) && isnan(E) && isnan(W) && isnan(T) && I < 0 && S < 0 && B < 0 && A < 0) {
temp_model_report_settings();
break;
}
// update all parameters
if(B >= 0) temp_model_set_warn_beep(B);
if(!isnan(C) || !isnan(P) || !isnan(T) || !isnan(W) || !isnan(E)) temp_model_set_params(C, P, T, W, E);
if(I >= 0 && !isnan(R)) temp_model_set_resistance(I, R);
// enable the model last, if requested
if(S >= 0) temp_model_set_enabled(S);
// run autotune
if(A >= 0) temp_model_autotune(A);
}
break;
#endif
/*!
### M400 - Wait for all moves to finish <a href="https://reprap.org/wiki/G-code#M400:_Wait_for_current_moves_to_finish">M400: Wait for current moves to finish</a>
@ -8717,16 +8783,6 @@ Sigma_Exit:
}
break;
/*!
### M999 - Restart after being stopped <a href="https://reprap.org/wiki/G-code#M999:_Restart_after_being_stopped_by_error">M999: Restart after being stopped by error</a>
@todo Usually doesn't work. Should be fixed or removed. Most of the time, if `Stopped` it set, the print fails and is unrecoverable.
*/
case 999:
Stopped = false;
lcd_reset_alert_level();
gcode_LastN = Stopped_gcode_LastN;
FlushSerialRequestResend();
break;
/*!
#### End of M-Commands
*/
@ -8870,7 +8926,7 @@ Sigma_Exit:
active_extruder = tmp_extruder;
plan_set_position_curposXYZE();
// Move to the old position if 'F' was in the parameters
if (make_move && Stopped == false) {
if (make_move) {
prepare_move();
}
}
@ -9144,6 +9200,23 @@ Sigma_Exit:
};
#endif
#ifdef TEMP_MODEL_DEBUG
/*!
## D70 - Enable low-level temperature model logging for offline simulation
#### Usage
D70 [ I ]
#### Parameters
- `I` - Enable 0-1 (default 0)
*/
case 70: {
if(code_seen('I'))
temp_model_log_enable(code_value_short());
break;
}
#endif
#ifdef HEATBED_ANALYSIS
/*!
@ -9469,7 +9542,7 @@ void mesh_plan_buffer_line(const float &x, const float &y, const float &z, const
current_position[Z_AXIS] + t * dz,
current_position[E_AXIS] + t * de,
feed_rate, extruder, gcode_target);
if (waiting_inside_plan_buffer_line_print_aborted)
if (planner_aborted)
return;
}
}
@ -9871,6 +9944,7 @@ void UnconditionalStop()
// Disable all heaters and unroll the temperature wait loop stack
disable_heater();
cancel_heatup = true;
heating_status = HeatingStatus::NO_HEATING;
// Clear any saved printing state
cancel_saved_printing();
@ -9890,39 +9964,58 @@ void UnconditionalStop()
CRITICAL_SECTION_END;
}
// Stop: Emergency stop used by overtemp functions which allows recovery
// Emergency stop used by overtemp functions which allows recovery
// WARNING: This function is called *continuously* during a thermal failure.
//
// In addition to stopping the print, this prevents subsequent G[0-3] commands to be
// processed via USB (using "Stopped") until the print is resumed via M999 or
// manually started from scratch with the LCD.
//
// Note that the current instruction is completely discarded, so resuming from Stop()
// will introduce either over/under extrusion on the current segment, and will not
// survive a power panic. Switching Stop() to use the pause machinery instead (with
// the addition of disabling the headers) could allow true recovery in the future.
void Stop()
// This either pauses (for thermal model errors) or stops *without recovery* depending on
// "allow_pause". If pause is allowed, this forces a printer-initiated instantanenous pause (just
// like an LCD pause) that bypasses the host pausing functionality. In this state the printer is
// kept in busy state and *must* be recovered from the LCD.
void ThermalStop(bool allow_pause)
{
// Keep disabling heaters
disable_heater();
if(Stopped == false) {
Stopped = true;
if(allow_pause && (IS_SD_PRINTING || usb_timer.running())) {
if (!isPrintPaused) {
// we cannot make a distinction for the host here, the pause must be instantaneous
// so we call the lcd_pause_print to save the print state internally. Thermal errors
// disable heaters and save the original temperatures to saved_*, which will get
// overwritten by stop_and_save_print_to_ram. For this corner-case, re-instate the
// original values after the pause handler is called.
float bed_temp = saved_bed_temperature;
float ext_temp = saved_extruder_temperature;
int fan_speed = saved_fan_speed;
lcd_pause_print();
saved_bed_temperature = bed_temp;
saved_extruder_temperature = ext_temp;
saved_fan_speed = fan_speed;
}
} else {
// We got a hard thermal error and/or there is no print going on. Just stop.
lcd_print_stop();
// Call the regular stop function if that's the first time during a new print
if(Stopped == false) {
Stopped = true;
lcd_print_stop();
Stopped_gcode_LastN = gcode_LastN; // Save last g_code for restart
// Also prevent further menu entry
menu_set_block(MENU_BLOCK_THERMAL_ERROR);
}
// Eventually report the stopped status (though this is usually overridden by a
// higher-priority alert status message)
SERIAL_ERROR_START;
SERIAL_ERRORLNRPGM(MSG_ERR_STOPPED);
LCD_MESSAGERPGM(_T(MSG_STOPPED));
}
// Report the status on the serial, switch to a busy state
SERIAL_ERROR_START;
SERIAL_ERRORLNRPGM(MSG_ERR_STOPPED);
// Return to the status screen to stop any pending menu action which could have been
// started by the user while stuck in the Stopped state. This also ensures the NEW
// error is immediately shown.
if (menu_menu != lcd_status_screen)
lcd_return_to_status();
// Eventually report the stopped status on the lcd (though this is usually overridden by a
// higher-priority alert status message)
LCD_MESSAGERPGM(_T(MSG_STOPPED));
// Make a warning sound! We cannot use Sound_MakeCustom as this would stop further moves.
// Turn on the speaker here (if not already), and turn it off when back in the main loop.
WRITE(BEEPER, HIGH);
}
// Return to the status screen to stop any pending menu action which could have been
// started by the user while stuck in the Stopped state. This also ensures the NEW
// error is immediately shown.
if (menu_menu != lcd_status_screen)
lcd_return_to_status();
}
bool IsStopped() { return Stopped; };
@ -10754,20 +10847,27 @@ void long_pause() //long pause print
start_pause_print = _millis();
// Stop heaters
heating_status = HeatingStatus::NO_HEATING;
setAllTargetHotends(0);
//lift z
current_position[Z_AXIS] += Z_PAUSE_LIFT;
clamp_to_software_endstops(current_position);
plan_buffer_line_curposXYZE(15);
// Lift z
raise_z_above(current_position[Z_AXIS] + Z_PAUSE_LIFT, true);
//Move XY to side
current_position[X_AXIS] = X_PAUSE_POS;
current_position[Y_AXIS] = Y_PAUSE_POS;
plan_buffer_line_curposXYZE(50);
// Move XY to side
if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) {
current_position[X_AXIS] = X_PAUSE_POS;
current_position[Y_AXIS] = Y_PAUSE_POS;
plan_buffer_line_curposXYZE(50);
}
// Turn off the print fan
fanSpeed = 0;
// did we come here from a thermal error?
if(get_temp_error()) {
// time to stop the error beep
WRITE(BEEPER, LOW);
} else {
// Turn off the print fan
fanSpeed = 0;
}
}
void serialecho_temperatures() {
@ -10871,6 +10971,7 @@ void uvlo_()
// Enable stepper driver interrupt to move Z axis. This should be fine as the planner and
// command queues are empty, SD card printing is disabled, usb is inhibited.
planner_aborted = false;
sei();
// Retract
@ -11003,6 +11104,7 @@ void uvlo_tiny()
// Enable stepper driver interrupt to move Z axis. This should be fine as the planner and
// command queues are empty, SD card printing is disabled, usb is inhibited.
planner_aborted = false;
sei();
// The axis was moved: adjust Z as done on a regular UVLO.
@ -11124,7 +11226,7 @@ void recover_print(uint8_t automatic) {
// Set the target bed and nozzle temperatures and wait.
sprintf_P(cmd, PSTR("M104 S%d"), target_temperature[active_extruder]);
enquecommand(cmd);
sprintf_P(cmd, PSTR("M190 S%d"), target_temperature_bed);
sprintf_P(cmd, PSTR("M140 S%d"), target_temperature_bed);
enquecommand(cmd);
sprintf_P(cmd, PSTR("M109 S%d"), target_temperature[active_extruder]);
enquecommand(cmd);
@ -11472,8 +11574,9 @@ void stop_and_save_print_to_ram(float z_move, float e_move)
saved_feedmultiply2 = feedmultiply; //save feedmultiply
saved_active_extruder = active_extruder; //save active_extruder
saved_extruder_temperature = degTargetHotend(active_extruder);
saved_bed_temperature = degBed();
saved_extruder_relative_mode = axis_relative_modes & E_AXIS_MASK;
saved_fanSpeed = fanSpeed;
saved_fan_speed = fanSpeed;
cmdqueue_reset(); //empty cmdqueue
card.sdprinting = false;
// card.closefile();
@ -11482,7 +11585,7 @@ void stop_and_save_print_to_ram(float z_move, float e_move)
st_reset_timer();
sei();
if ((z_move != 0) || (e_move != 0)) { // extruder or z move
#if 1
// Rather than calling plan_buffer_line directly, push the move into the command queue so that
// the caller can continue processing. This is used during powerpanic to save the state as we
// move away from the print.
@ -11514,13 +11617,6 @@ void stop_and_save_print_to_ram(float z_move, float e_move)
// If this call is invoked from the main Arduino loop() function, let the caller know that the command
// in the command queue is not the original command, but a new one, so it should not be removed from the queue.
repeatcommand_front();
#else
plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS] + z_move, saved_pos[E_AXIS] + e_move, homing_feedrate[Z_AXIS], active_extruder);
st_synchronize(); //wait moving
memcpy(current_position, saved_pos, sizeof(saved_pos));
set_destination_to_current();
#endif
waiting_inside_plan_buffer_line_print_aborted = true; //unroll the stack
}
}
@ -11543,10 +11639,13 @@ void restore_print_from_ram_and_continue(float e_move)
if (fan_check_error == EFCE_FIXED) fan_check_error = EFCE_OK; //reenable serial stream processing if printing from usb
#endif
// for (int axis = X_AXIS; axis <= E_AXIS; axis++)
// current_position[axis] = st_get_position_mm(axis);
active_extruder = saved_active_extruder; //restore active_extruder
fanSpeed = saved_fanSpeed;
// restore bed temperature (bed can be disabled during a thermal warning)
if (degBed() != saved_bed_temperature)
setTargetBed(saved_bed_temperature);
// restore active_extruder
active_extruder = saved_active_extruder;
fanSpeed = saved_fan_speed;
if (degTargetHotend(saved_active_extruder) != saved_extruder_temperature)
{
setTargetHotendSafe(saved_extruder_temperature, saved_active_extruder);
@ -11604,7 +11703,7 @@ void restore_print_from_ram_and_continue(float e_move)
lcd_setstatuspgm(MSG_WELCOME);
saved_printing_type = PRINTING_TYPE_NONE;
saved_printing = false;
waiting_inside_plan_buffer_line_print_aborted = true; //unroll the stack
planner_aborted = true; // unroll the stack
}
// Cancel the state related to a currently saved print

View file

@ -77,5 +77,11 @@ T Timer<T>::elapsed() {
return m_isRunning ? (_millis() - m_started) : 0;
}
template<typename T>
bool Timer<T>::expired_cont(T msPeriod)
{
return !m_isRunning || expired(msPeriod);
}
template class Timer<unsigned long>;
template class Timer<unsigned short>;

View file

@ -21,8 +21,9 @@ public:
void start();
void stop(){m_isRunning = false;}
bool running()const {return m_isRunning;}
bool expired(T msPeriod);
T elapsed();
bool expired(T msPeriod); // returns true only once after expiration, then stops running
T elapsed(); // returns the time in milliseconds since the timer was started or 0 otherwise
bool expired_cont(T msPeriod); // return true when continuosly when expired / not running
protected:
T started()const {return m_started;}
private:

View file

@ -1,95 +0,0 @@
//adc.c
#include "adc.h"
#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "pins.h"
uint8_t adc_state;
uint8_t adc_count;
uint16_t adc_values[ADC_CHAN_CNT];
uint16_t adc_sim_mask;
#ifdef ADC_CALLBACK
extern void ADC_CALLBACK(void);
#endif //ADC_CALLBACK
void adc_init(void)
{
puts_P(PSTR("adc_init"));
adc_sim_mask = 0x00;
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
ADMUX |= (1 << REFS0);
ADCSRA |= (1 << ADEN);
// ADCSRA |= (1 << ADIF) | (1 << ADSC);
DIDR0 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) & 0xff);
DIDR2 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) >> 8);
adc_reset();
// adc_sim_mask = 0b0101;
// adc_sim_mask = 0b100101;
// adc_values[0] = 1023 * 16;
// adc_values[2] = 1023 * 16;
// adc_values[5] = 1002 * 16;
}
void adc_reset(void)
{
adc_state = 0;
adc_count = 0;
uint8_t i; for (i = 0; i < ADC_CHAN_CNT; i++)
if ((adc_sim_mask & (1 << i)) == 0)
adc_values[i] = 0;
}
void adc_setmux(uint8_t ch)
{
ch &= 0x0f;
if (ch & 0x08) ADCSRB |= (1 << MUX5);
else ADCSRB &= ~(1 << MUX5);
ADMUX = (ADMUX & ~(0x07)) | (ch & 0x07);
}
uint8_t adc_chan(uint8_t index)
{
uint8_t chan = 0;
uint16_t mask = 1;
while (mask)
{
if ((mask & ADC_CHAN_MSK) && (index-- == 0)) break;
mask <<= 1;
chan++;
}
return chan;
}
void adc_cycle(void)
{
if (adc_state & 0x80)
{
uint8_t index = adc_state & 0x0f;
if ((adc_sim_mask & (1 << index)) == 0)
adc_values[index] += ADC;
if (++index >= ADC_CHAN_CNT)
{
index = 0;
adc_count++;
if (adc_count >= ADC_OVRSAMPL)
{
#ifdef ADC_CALLBACK
ADC_CALLBACK();
#endif //ADC_CALLBACK
adc_reset();
}
}
adc_setmux(adc_chan(index));
adc_state = index;
}
else
{
ADCSRA |= (1 << ADSC); //start conversion
adc_state |= 0x80;
}
}

81
Firmware/adc.cpp Normal file
View file

@ -0,0 +1,81 @@
#include "adc.h"
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <string.h>
#include "pins.h"
static uint8_t adc_count; //used for oversampling
static uint8_t adc_channel_idx; //bitmask index
volatile uint8_t adc_channel; //regular index
volatile uint16_t adc_values[ADC_CHAN_CNT];
static void adc_reset();
static void adc_setmux(uint8_t ch);
void adc_init()
{
puts_P(PSTR("adc_init"));
DIDR0 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) & 0xff); //disable digital inputs PORTF
DIDR2 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) >> 8); //disable digital inputs PORTK
ADMUX |= (1 << REFS0); //use AVCC as reference
//enable ADC, set prescaler/128, enable interrupt
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADIF) | (1 << ADIE);
}
static void adc_reset()
{
static const uint8_t first_channel_idx = 0;
static_assert((1 << first_channel_idx) & ADC_CHAN_MSK);
ADCSRA &= ~(1 << ADSC); //stop conversion just in case
adc_count = 0;
adc_channel = 0;
adc_channel_idx = first_channel_idx;
adc_setmux(adc_channel_idx);
memset((void*)adc_values, 0, sizeof(adc_values));
}
static void adc_setmux(uint8_t ch)
{
ch &= 0x0f;
if (ch & 0x08) ADCSRB |= (1 << MUX5);
else ADCSRB &= ~(1 << MUX5);
ADMUX = (ADMUX & ~(0x07)) | (ch & 0x07);
}
void adc_start_cycle() {
adc_reset();
ADCSRA |= (1 << ADSC); //start conversion
}
#ifdef ADC_CALLBACK
extern void ADC_CALLBACK();
#endif //ADC_CALLBACK
ISR(ADC_vect)
{
adc_values[adc_channel] += ADC;
if (++adc_count == ADC_OVRSAMPL)
{
// go to the next channel
if (++adc_channel == ADC_CHAN_CNT) {
#ifdef ADC_CALLBACK
ADC_CALLBACK();
#endif
return; // do not start the next measurement since there are no channels remaining
}
// find the next channel
while (++adc_channel_idx) {
if (ADC_CHAN_MSK & (1 << adc_channel_idx)) {
adc_setmux(adc_channel_idx);
adc_count = 0;
break;
}
}
}
ADCSRA |= (1 << ADSC); //start conversion
}

View file

@ -1,15 +1,8 @@
//adc.h
#ifndef _ADC_H
#define _ADC_H
#pragma once
#include <inttypes.h>
#include "config.h"
#if defined(__cplusplus)
extern "C" {
#endif //defined(__cplusplus)
/*
http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
*/
@ -22,24 +15,9 @@ http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
# error "ADC_CHAN_MSK oes not match ADC_CHAN_CNT"
#endif
extern uint8_t adc_state;
extern uint8_t adc_count;
extern uint16_t adc_values[ADC_CHAN_CNT];
extern uint16_t adc_sim_mask;
extern volatile uint8_t adc_channel;
extern volatile uint16_t adc_values[ADC_CHAN_CNT];
extern void adc_init(void);
extern void adc_reset(void);
extern void adc_setmux(uint8_t ch);
extern uint8_t adc_chan(uint8_t index);
extern void adc_cycle(void);
#if defined(__cplusplus)
}
#endif //defined(__cplusplus)
#endif //_ADC_H
extern void adc_init();
extern void adc_start_cycle(); //should be called from an atomic context only
static inline bool adc_cycle_done() { return adc_channel >= ADC_CHAN_CNT; }

View file

@ -28,7 +28,6 @@ ShortTimer serialTimeoutTimer;
long gcode_N = 0;
long gcode_LastN = 0;
long Stopped_gcode_LastN = 0;
uint32_t sdpos_atomic = 0;
@ -464,8 +463,6 @@ void get_command()
// Don't parse N again with code_seen('N')
cmdbuffer[bufindw + CMDHDRSIZE] = '$';
//if no errors, continue parsing
gcode_LastN = gcode_N;
}
// if we don't receive 'N' but still see '*'
if ((cmdbuffer[bufindw + CMDHDRSIZE] != 'N') && (cmdbuffer[bufindw + CMDHDRSIZE] != '$') && (strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*') != NULL))
@ -478,35 +475,48 @@ void get_command()
serial_count = 0;
return;
}
// Handle KILL early, even when Stopped
if(strcmp(cmdbuffer+bufindw+CMDHDRSIZE, "M112") == 0)
kill(MSG_M112_KILL, 2);
// Handle the USB timer
if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'G')) != NULL) {
if (!IS_SD_PRINTING) {
usb_timer.start();
}
if (Stopped == true) {
if (code_value_uint8() <= 3) {
SERIAL_ERRORLNRPGM(MSG_ERR_STOPPED);
LCD_MESSAGERPGM(_T(MSG_STOPPED));
}
}
} // end of 'G' command
}
if (Stopped == true) {
// Stopped can be set either during error states (thermal error: cannot continue), or
// when a printer-initiated action is processed. In such case the printer will send to
// the host an action, but cannot know if the action has been processed while new
// commands are being sent. In this situation we just drop the command while issuing
// periodic "busy" messages in the main loop. Since we're not incrementing the received
// line number, a request for resend will happen (if necessary), ensuring we don't skip
// commands whenever Stopped is cleared and processing resumes.
serial_count = 0;
return;
}
// Command is complete: store the current line into buffer, move to the next line.
//If command was e-stop process now
if(strcmp(cmdbuffer+bufindw+CMDHDRSIZE, "M112") == 0)
kill(MSG_M112_KILL, 2);
// Store the current line into buffer, move to the next line.
// Store type of entry
cmdbuffer[bufindw] = gcode_N ? CMDBUFFER_CURRENT_TYPE_USB_WITH_LINENR : CMDBUFFER_CURRENT_TYPE_USB;
#ifdef CMDBUFFER_DEBUG
SERIAL_ECHO_START;
SERIAL_ECHOPGM("Storing a command line to buffer: ");
SERIAL_ECHO(cmdbuffer+bufindw+CMDHDRSIZE);
SERIAL_ECHOLNPGM("");
#endif /* CMDBUFFER_DEBUG */
// Store command itself
bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE);
if (bufindw == sizeof(cmdbuffer))
bufindw = 0;
++ buflen;
// Update the processed gcode line
gcode_LastN = gcode_N;
#ifdef CMDBUFFER_DEBUG
SERIAL_ECHOPGM("Number of commands in the buffer: ");
SERIAL_ECHO(buflen);

View file

@ -54,7 +54,6 @@ extern char *strchr_pointer;
extern long gcode_N;
extern long gcode_LastN;
extern long Stopped_gcode_LastN;
extern bool cmdqueue_pop_front();
extern void cmdqueue_reset();

View file

@ -6,7 +6,8 @@
#include "pins.h"
#if (defined(VOLT_IR_PIN) && defined(IR_SENSOR))
# define IR_SENSOR_ANALOG
// TODO: IR_SENSOR_ANALOG currently disabled as being incompatible with the new thermal regulation
// # define IR_SENSOR_ANALOG
#endif
//ADC configuration
@ -20,7 +21,7 @@
#define ADC_CHAN_CNT 8 //number of used channels)
#endif //!IR_SENSOR_ANALOG
#define ADC_OVRSAMPL 16 //oversampling multiplier
#define ADC_CALLBACK adc_ready //callback function ()
#define ADC_CALLBACK adc_callback //callback function ()
//SWI2C configuration
//#define SWI2C_SDA 20 //SDA on P3

View file

@ -550,8 +550,16 @@ static Sheets * const EEPROM_Sheets_base = (Sheets*)(EEPROM_SHEETS_BASE);
#define EEPROM_ECOOL_ENABLE (EEPROM_JOB_ID-1) // uint8_t
#define EEPROM_FW_CRASH_FLAG (EEPROM_ECOOL_ENABLE-1) // uint8_t
#define EEPROM_TEMP_MODEL_ENABLE (EEPROM_FW_CRASH_FLAG-1) // uint8_t
#define EEPROM_TEMP_MODEL_P (EEPROM_TEMP_MODEL_ENABLE-4) // float
#define EEPROM_TEMP_MODEL_C (EEPROM_TEMP_MODEL_P-4) // float
#define EEPROM_TEMP_MODEL_R (EEPROM_TEMP_MODEL_C-4*16) // float[16]
#define EEPROM_TEMP_MODEL_Ta_corr (EEPROM_TEMP_MODEL_R-4) // float
#define EEPROM_TEMP_MODEL_W (EEPROM_TEMP_MODEL_Ta_corr-4) // float
#define EEPROM_TEMP_MODEL_E (EEPROM_TEMP_MODEL_W-4) // float
//This is supposed to point to last item to allow EEPROM overrun check. Please update when adding new items.
#define EEPROM_LAST_ITEM EEPROM_FW_CRASH_FLAG
#define EEPROM_LAST_ITEM EEPROM_TEMP_MODEL_E
// !!!!!
// !!!!! this is end of EEPROM section ... all updates MUST BE inserted before this mark !!!!!
// !!!!!

300
Firmware/fancheck.cpp Executable file
View file

@ -0,0 +1,300 @@
// fan control and check
#include "fancheck.h"
#include "cardreader.h"
#include "ultralcd.h"
#include "sound.h"
#include "messages.h"
#include "temperature.h"
#include "stepper.h"
#define FAN_CHECK_PERIOD 5000 //5s
#define FAN_CHECK_DURATION 100 //100ms
#ifdef FANCHECK
volatile uint8_t fan_check_error = EFCE_OK;
#endif
#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
#ifdef EXTRUDER_ALTFAN_DETECT
static struct
{
uint8_t isAltfan : 1;
uint8_t altfanOverride : 1;
} altfanStatus;
#endif //EXTRUDER_ALTFAN_DETECT
unsigned long extruder_autofan_last_check = _millis();
bool fan_measuring = false;
static uint8_t fanState = 0;
#endif
#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
#if defined(FAN_PIN) && FAN_PIN > -1
#if EXTRUDER_0_AUTO_FAN_PIN == FAN_PIN
#error "You cannot set EXTRUDER_0_AUTO_FAN_PIN equal to FAN_PIN"
#endif
#endif
void setExtruderAutoFanState(uint8_t state)
{
//If bit 1 is set (0x02), then the extruder fan speed won't be adjusted according to temperature. Useful for forcing
//the fan to either On or Off during certain tests/errors.
fanState = state;
newFanSpeed = 0;
if (fanState & 0x01)
{
#ifdef EXTRUDER_ALTFAN_DETECT
if (altfanStatus.isAltfan && !altfanStatus.altfanOverride) newFanSpeed = EXTRUDER_ALTFAN_SPEED_SILENT;
else newFanSpeed = EXTRUDER_AUTO_FAN_SPEED;
#else //EXTRUDER_ALTFAN_DETECT
newFanSpeed = EXTRUDER_AUTO_FAN_SPEED;
#endif //EXTRUDER_ALTFAN_DETECT
}
timer4_set_fan0(newFanSpeed);
}
#if (defined(FANCHECK) && (((defined(TACH_0) && (TACH_0 >-1)) || (defined(TACH_1) && (TACH_1 > -1)))))
void countFanSpeed()
{
//SERIAL_ECHOPGM("edge counter 1:"); MYSERIAL.println(fan_edge_counter[1]);
fan_speed[0] = (fan_edge_counter[0] * (float(250) / (_millis() - extruder_autofan_last_check)));
fan_speed[1] = (fan_edge_counter[1] * (float(250) / (_millis() - extruder_autofan_last_check)));
/*SERIAL_ECHOPGM("time interval: "); MYSERIAL.println(_millis() - extruder_autofan_last_check);
SERIAL_ECHOPGM("extruder fan speed:"); MYSERIAL.print(fan_speed[0]); SERIAL_ECHOPGM("; edge counter:"); MYSERIAL.println(fan_edge_counter[0]);
SERIAL_ECHOPGM("print fan speed:"); MYSERIAL.print(fan_speed[1]); SERIAL_ECHOPGM("; edge counter:"); MYSERIAL.println(fan_edge_counter[1]);
SERIAL_ECHOLNPGM(" ");*/
fan_edge_counter[0] = 0;
fan_edge_counter[1] = 0;
}
//! Prints serialMsg to serial port, displays lcdMsg onto the LCD and beeps.
//! Extracted from fanSpeedError to save some space.
//! @param serialMsg pointer into PROGMEM, this text will be printed to the serial port
//! @param lcdMsg pointer into PROGMEM, this text will be printed onto the LCD
static void fanSpeedErrorBeep(const char *serialMsg, const char *lcdMsg){
SERIAL_ECHOLNRPGM(serialMsg);
if (get_message_level() == 0) {
Sound_MakeCustom(200,0,true);
LCD_ALERTMESSAGERPGM(lcdMsg);
}
}
void fanSpeedError(unsigned char _fan) {
if (fan_check_error == EFCE_REPORTED) return;
fan_check_error = EFCE_REPORTED;
if (IS_SD_PRINTING || usb_timer.running()) {
// A print is ongoing, pause the print normally
if(!isPrintPaused) {
if (usb_timer.running())
lcd_pause_usb_print();
else
lcd_pause_print();
}
}
else {
// Nothing is going on, but still turn off heaters and report the error
setTargetHotend0(0);
heating_status = HeatingStatus::NO_HEATING;
}
switch (_fan) {
case 0: // extracting the same code from case 0 and case 1 into a function saves 72B
fanSpeedErrorBeep(PSTR("Extruder fan speed is lower than expected"), MSG_FANCHECK_EXTRUDER);
break;
case 1:
fanSpeedErrorBeep(PSTR("Print fan speed is lower than expected"), MSG_FANCHECK_PRINT);
break;
}
}
void checkFanSpeed()
{
uint8_t max_fan_errors[2];
#ifdef FAN_SOFT_PWM
max_fan_errors[1] = 3; // 15 seconds (Print fan)
max_fan_errors[0] = 2; // 10 seconds (Extruder fan)
#else //FAN_SOFT_PWM
max_fan_errors[1] = 15; // 15 seconds (Print fan)
max_fan_errors[0] = 5; // 5 seconds (Extruder fan)
#endif //FAN_SOFT_PWM
if(fans_check_enabled)
fans_check_enabled = (eeprom_read_byte((uint8_t*)EEPROM_FAN_CHECK_ENABLED) > 0);
static uint8_t fan_speed_errors[2] = { 0,0 };
#if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 >-1))
if ((fan_speed[0] < 20) && (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE)){ fan_speed_errors[0]++;}
else fan_speed_errors[0] = 0;
#endif
#if (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
if ((fan_speed[1] < 5) && ((blocks_queued() ? block_buffer[block_buffer_tail].fan_speed : fanSpeed) > MIN_PRINT_FAN_SPEED)) fan_speed_errors[1]++;
else fan_speed_errors[1] = 0;
#endif
// drop the fan_check_error flag when both fans are ok
if( fan_speed_errors[0] == 0 && fan_speed_errors[1] == 0 && fan_check_error == EFCE_REPORTED){
// we may even send some info to the LCD from here
fan_check_error = EFCE_FIXED;
}
if ((fan_check_error == EFCE_FIXED) && !PRINTER_ACTIVE){
fan_check_error = EFCE_OK; //if the issue is fixed while the printer is doing nothing, reenable processing immediately.
lcd_reset_alert_level(); //for another fan speed error
}
if (fans_check_enabled && (fan_check_error == EFCE_OK))
{
for (uint8_t fan = 0; fan < 2; fan++)
{
if (fan_speed_errors[fan] > max_fan_errors[fan])
{
fan_speed_errors[fan] = 0;
fanSpeedError(fan);
}
}
}
}
#endif //(defined(TACH_0) && TACH_0 >-1) || (defined(TACH_1) && TACH_1 > -1)
#ifdef EXTRUDER_ALTFAN_DETECT
ISR(INT6_vect) {
fan_edge_counter[0]++;
}
bool extruder_altfan_detect()
{
setExtruderAutoFanState(3);
SET_INPUT(TACH_0);
uint8_t overrideVal = eeprom_read_byte((uint8_t *)EEPROM_ALTFAN_OVERRIDE);
if (overrideVal == EEPROM_EMPTY_VALUE)
{
overrideVal = (calibration_status() == CALIBRATION_STATUS_CALIBRATED) ? 1 : 0;
eeprom_update_byte((uint8_t *)EEPROM_ALTFAN_OVERRIDE, overrideVal);
}
altfanStatus.altfanOverride = overrideVal;
CRITICAL_SECTION_START;
EICRB &= ~(1 << ISC61);
EICRB |= (1 << ISC60);
EIMSK |= (1 << INT6);
fan_edge_counter[0] = 0;
CRITICAL_SECTION_END;
extruder_autofan_last_check = _millis();
_delay(1000);
EIMSK &= ~(1 << INT6);
countFanSpeed();
altfanStatus.isAltfan = fan_speed[0] > 100;
setExtruderAutoFanState(1);
return altfanStatus.isAltfan;
}
void altfanOverride_toggle()
{
altfanStatus.altfanOverride = !altfanStatus.altfanOverride;
eeprom_update_byte((uint8_t *)EEPROM_ALTFAN_OVERRIDE, altfanStatus.altfanOverride);
}
bool altfanOverride_get()
{
return altfanStatus.altfanOverride;
}
#endif //EXTRUDER_ALTFAN_DETECT
void checkExtruderAutoFans()
{
#if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1
if (!(fanState & 0x02))
{
fanState &= ~1;
fanState |= current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE;
fanState |= get_temp_error();
}
setExtruderAutoFanState(fanState);
#endif
}
#endif // any extruder auto fan pins set
#if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1))
void readFanTach() {
#ifdef FAN_SOFT_PWM
if (READ(TACH_0) != fan_state[0]) {
if(fan_measuring) fan_edge_counter[0] ++;
fan_state[0] = !fan_state[0];
}
#else //FAN_SOFT_PWM
if (READ(TACH_0) != fan_state[0]) {
fan_edge_counter[0] ++;
fan_state[0] = !fan_state[0];
}
#endif
//if (READ(TACH_1) != fan_state[1]) {
// fan_edge_counter[1] ++;
// fan_state[1] = !fan_state[1];
//}
}
#endif //TACH_0
void checkFans()
{
#ifndef DEBUG_DISABLE_FANCHECK
#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
#ifdef FAN_SOFT_PWM
#ifdef FANCHECK
if ((_millis() - extruder_autofan_last_check > FAN_CHECK_PERIOD) && (!fan_measuring)) {
extruder_autofan_last_check = _millis();
fanSpeedBckp = fanSpeedSoftPwm;
if (fanSpeedSoftPwm >= MIN_PRINT_FAN_SPEED) { //if we are in rage where we are doing fan check, set full PWM range for a short time to measure fan RPM by reading tacho signal without modulation by PWM signal
// printf_P(PSTR("fanSpeedSoftPwm 1: %d\n"), fanSpeedSoftPwm);
fanSpeedSoftPwm = 255;
}
fan_measuring = true;
}
if ((_millis() - extruder_autofan_last_check > FAN_CHECK_DURATION) && (fan_measuring)) {
countFanSpeed();
checkFanSpeed();
//printf_P(PSTR("fanSpeedSoftPwm 1: %d\n"), fanSpeedSoftPwm);
fanSpeedSoftPwm = fanSpeedBckp;
//printf_P(PSTR("fan PWM: %d; extr fanSpeed measured: %d; print fan speed measured: %d \n"), fanSpeedBckp, fan_speed[0], fan_speed[1]);
extruder_autofan_last_check = _millis();
fan_measuring = false;
}
#endif //FANCHECK
checkExtruderAutoFans();
#else //FAN_SOFT_PWM
if(_millis() - extruder_autofan_last_check > 1000) // only need to check fan state very infrequently
{
#if (defined(FANCHECK) && ((defined(TACH_0) && (TACH_0 >-1)) || (defined(TACH_1) && (TACH_1 > -1))))
countFanSpeed();
checkFanSpeed();
#endif //(defined(TACH_0) && TACH_0 >-1) || (defined(TACH_1) && TACH_1 > -1)
checkExtruderAutoFans();
extruder_autofan_last_check = _millis();
}
#endif //FAN_SOFT_PWM
#endif
#endif //DEBUG_DISABLE_FANCHECK
}
void hotendFanSetFullSpeed()
{
#ifdef EXTRUDER_ALTFAN_DETECT
altfanStatus.altfanOverride = 1; //full speed
#endif //EXTRUDER_ALTFAN_DETECT
setExtruderAutoFanState(3);
SET_OUTPUT(FAN_PIN);
#ifdef FAN_SOFT_PWM
fanSpeedSoftPwm = 255;
#else //FAN_SOFT_PWM
analogWrite(FAN_PIN, 255);
#endif //FAN_SOFT_PWM
fanSpeed = 255;
}

35
Firmware/fancheck.h Executable file
View file

@ -0,0 +1,35 @@
// fan control and check
#pragma once
#include "Configuration.h"
#include "config.h"
#if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1))
enum {
EFCE_OK = 0, //!< normal operation, both fans are ok
EFCE_FIXED, //!< previous fan error was fixed
EFCE_REPORTED //!< fan error detected and reported to LCD and serial
};
extern volatile uint8_t fan_check_error;
void readFanTach();
#endif //(defined(TACH_0))
#ifdef EXTRUDER_ALTFAN_DETECT
extern bool extruder_altfan_detect();
extern void altfanOverride_toggle();
extern bool altfanOverride_get();
#endif //EXTRUDER_ALTFAN_DETECT
#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
#ifdef FAN_SOFT_PWM
extern bool fan_measuring;
#endif //FAN_SOFT_PWM
extern unsigned long extruder_autofan_last_check;
void setExtruderAutoFanState(uint8_t state);
void checkExtruderAutoFans();
#endif
void checkFans();
void hotendFanSetFullSpeed();

View file

@ -688,62 +688,8 @@ void fsensor_update(void)
{
if (READ(IR_SENSOR_PIN))
{ // IR_SENSOR_PIN ~ H
#ifdef IR_SENSOR_ANALOG
if(!bIRsensorStateFlag)
{
bIRsensorStateFlag=true;
tIRsensorCheckTimer.start();
}
else
{
if(tIRsensorCheckTimer.expired(IR_SENSOR_STEADY))
{
uint8_t nMUX1,nMUX2;
uint16_t nADC;
bIRsensorStateFlag=false;
// sequence for direct data reading from AD converter
DISABLE_TEMPERATURE_INTERRUPT();
nMUX1=ADMUX; // ADMUX saving
nMUX2=ADCSRB;
adc_setmux(VOLT_IR_PIN);
ADCSRA|=(1<<ADSC); // first conversion after ADMUX change discarded (preventively)
while(ADCSRA&(1<<ADSC))
;
ADCSRA|=(1<<ADSC); // second conversion used
while(ADCSRA&(1<<ADSC))
;
nADC=ADC;
ADMUX=nMUX1; // ADMUX restoring
ADCSRB=nMUX2;
ENABLE_TEMPERATURE_INTERRUPT();
// end of sequence for ...
// Detection of correct function of fsensor v04 - it must NOT read >4.6V
// If it does, it means a disconnected cables or faulty board
if( (oFsensorPCB == ClFsensorPCB::_Rev04) && ( (nADC*OVERSAMPLENR) > IRsensor_Hopen_TRESHOLD ) )
{
fsensor_disable();
fsensor_not_responding = true;
printf_P(PSTR("IR sensor not responding (%d)!\n"),1);
if((ClFsensorActionNA)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_ACTION_NA)==ClFsensorActionNA::_Pause)
// if we are printing and FS action is set to "Pause", force pause the print
if(oFsensorActionNA==ClFsensorActionNA::_Pause)
lcd_pause_print();
}
else
{
#endif //IR_SENSOR_ANALOG
fsensor_checkpoint_print();
fsensor_enque_M600();
#ifdef IR_SENSOR_ANALOG
}
}
}
}
else
{ // IR_SENSOR_PIN ~ L
bIRsensorStateFlag=false;
#endif //IR_SENSOR_ANALOG
fsensor_checkpoint_print();
fsensor_enque_M600();
}
}
#endif //PAT9125

View file

@ -11,6 +11,9 @@
#define CRITICAL_SECTION_END SREG = _sreg;
#endif //CRITICAL_SECTION_START
#define _REGNAME(registerbase,number,suffix) registerbase##number##suffix
#define _REGNAME_SHORT(registerbase,suffix) registerbase##suffix
// Macros to make a string from a macro
#define STRINGIFY_(M) #M
#define STRINGIFY(M) STRINGIFY_(M)

View file

@ -24,7 +24,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_block_mask = MENU_BLOCK_NONE;
uint8_t menu_line = 0;
uint8_t menu_item = 0;
uint8_t menu_row = 0;

View file

@ -29,26 +29,26 @@ extern uint8_t menu_data[MENU_DATA_SIZE];
extern uint8_t menu_depth;
//! definition of serious errors possibly blocking the main menu
//! definition of reasons 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
MENU_BLOCK_NONE = 0,
MENU_BLOCK_THERMAL_ERROR = 0x01,
#ifdef TEMP_MODEL
MENU_BLOCK_TEMP_MODEL_AUTOTUNE = 0x02,
#endif
}; // 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;
//! this is a flag for disabling entering the main menu and longpress. 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.
extern uint8_t menu_block_mask;
//! a pair of macros for manipulating the serious errors
//! a pair of macros for manipulating menu entry
//! 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
#define menu_set_block(x) menu_block_mask |= x;
#define menu_unset_block(x) menu_block_mask &= ~x;
#define menu_is_blocked(x) (menu_block_mask & x) != 0
extern uint8_t menu_line;
extern uint8_t menu_item;

View file

@ -159,6 +159,10 @@ const char MSG_IR_04_OR_NEWER[] PROGMEM_I1 = ISTR(" 0.4 or newer");////MSG_IR_04
const char MSG_IR_03_OR_OLDER[] PROGMEM_I1 = ISTR(" 0.3 or older");////MSG_IR_03_OR_OLDER c=18
const char MSG_IR_UNKNOWN[] PROGMEM_I1 = ISTR("unknown state");////MSG_IR_UNKNOWN c=18
#endif
#ifdef TEMP_MODEL
extern const char MSG_THERMAL_ANOMALY[] PROGMEM_I1 = ISTR("THERMAL ANOMALY");////c=20
extern const char MSG_PAUSED_THERMAL_ERROR[] PROGMEM_I1 = ISTR("PAUSED THERMAL ERROR");////c=20
#endif
//not internationalized messages
const char MSG_AUTO_DEPLETE[] PROGMEM_N1 = ISTR("SpoolJoin"); ////MSG_AUTO_DEPLETE c=13
@ -186,11 +190,11 @@ const char MSG_OK[] PROGMEM_N1 = "ok"; ////
const char MSG_SD_OPEN_FILE_FAIL[] PROGMEM_N1 = "open failed, File: "; ////
const char MSG_ENDSTOP_OPEN[] PROGMEM_N1 = "open"; ////
const char MSG_POWERUP[] PROGMEM_N1 = "PowerUp"; ////
const char MSG_ERR_STOPPED[] PROGMEM_N1 = "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)"; ////
const char MSG_ERR_STOPPED[] PROGMEM_N1 = "Printer stopped due to errors. Supervision required."; ////
const char MSG_ENDSTOP_HIT[] PROGMEM_N1 = "TRIGGERED"; ////
const char MSG_OCTOPRINT_PAUSE[] PROGMEM_N1 = "// action:pause"; ////
const char MSG_OCTOPRINT_ASK_PAUSE[] PROGMEM_N1 = "// action:pause"; ////
const char MSG_OCTOPRINT_PAUSED[] PROGMEM_N1 = "// action:paused"; ////
const char MSG_OCTOPRINT_RESUME[] PROGMEM_N1 = "// action:resume"; ////
const char MSG_OCTOPRINT_ASK_RESUME[] PROGMEM_N1 = "// action:resume"; ////
const char MSG_OCTOPRINT_RESUMED[] PROGMEM_N1 = "// action:resumed"; ////
const char MSG_OCTOPRINT_CANCEL[] PROGMEM_N1 = "// action:cancel"; ////
const char MSG_FANCHECK_EXTRUDER[] PROGMEM_N1 = "Err: EXTR. FAN ERROR"; ////c=20

View file

@ -168,6 +168,10 @@ extern const char MSG_IR_04_OR_NEWER[];
extern const char MSG_IR_03_OR_OLDER[];
extern const char MSG_IR_UNKNOWN[];
#endif
#ifdef TEMP_MODEL
extern const char MSG_THERMAL_ANOMALY[];
extern const char MSG_PAUSED_THERMAL_ERROR[];
#endif
//not internationalized messages
extern const char MSG_BROWNOUT_RESET[];
@ -193,9 +197,9 @@ extern const char MSG_ERR_STOPPED[];
extern const char MSG_ENDSTOP_HIT[];
extern const char MSG_EJECT_FILAMENT[];
extern const char MSG_CUT_FILAMENT[];
extern const char MSG_OCTOPRINT_PAUSE[];
extern const char MSG_OCTOPRINT_ASK_PAUSE[];
extern const char MSG_OCTOPRINT_PAUSED[];
extern const char MSG_OCTOPRINT_RESUME[];
extern const char MSG_OCTOPRINT_ASK_RESUME[];
extern const char MSG_OCTOPRINT_RESUMED[];
extern const char MSG_OCTOPRINT_CANCEL[];
extern const char MSG_FANCHECK_EXTRUDER[];

View file

@ -10,6 +10,7 @@
#include "fsensor.h"
#include "cardreader.h"
#include "cmdqueue.h"
#include "stepper.h"
#include "ultralcd.h"
#include "menu.h"
#include "sound.h"

View file

@ -151,7 +151,7 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa
// Insert the segment into the buffer
plan_buffer_line(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS], feed_rate, extruder, position);
// Handle the situation where the planner is aborted hard.
if (waiting_inside_plan_buffer_line_print_aborted)
if (planner_aborted)
return;
}
}

View file

@ -78,6 +78,9 @@
#define VOLT_IR_PIN 8 //A8
#define TEMP_TIM 5
#define E0_TMC2130_CS 66
#define E0_TMC2130_DIAG 65
#define E0_STEP_PIN 34

View file

@ -57,6 +57,8 @@
#define TEMP_PINDA_PIN 1 //A1
#define TEMP_TIM 3
#define E0_STEP_PIN 34
#define E0_DIR_PIN 43

View file

@ -60,6 +60,8 @@
#define TEMP_PINDA_PIN 1 //A1
#define TEMP_TIM 3
#define E0_STEP_PIN 34
#define E0_DIR_PIN 43

View file

@ -55,6 +55,7 @@
#include "planner.h"
#include "stepper.h"
#include "temperature.h"
#include "fancheck.h"
#include "ultralcd.h"
#include "language.h"
#include "ConfigurationStore.h"
@ -68,6 +69,9 @@
#include "tmc2130.h"
#endif //TMC2130
#include <util/atomic.h>
//===========================================================================
//=============================public variables ============================
//===========================================================================
@ -592,17 +596,7 @@ void check_axes_activity()
#endif
}
bool waiting_inside_plan_buffer_line_print_aborted = false;
/*
void planner_abort_soft()
{
// Empty the queue.
while (blocks_queued()) plan_discard_current_block();
// Relay to planner wait routine, that the current line shall be canceled.
waiting_inside_plan_buffer_line_print_aborted = true;
//current_position[i]
}
*/
bool planner_aborted = false;
#ifdef PLANNER_DIAGNOSTICS
static inline void planner_update_queue_min_counter()
@ -615,12 +609,8 @@ static inline void planner_update_queue_min_counter()
extern volatile uint32_t step_events_completed; // The number of step events executed in the current block
void planner_abort_hard()
void planner_reset_position()
{
// Abort the stepper routine and flush the planner queue.
DISABLE_STEPPER_DRIVER_INTERRUPT();
// Now the front-end (the Marlin_main.cpp with its current_position) is out of sync.
// First update the planner's current position in the physical motor steps.
position[X_AXIS] = st_get_position(X_AXIS);
position[Y_AXIS] = st_get_position(Y_AXIS);
@ -632,6 +622,7 @@ void planner_abort_hard()
current_position[Y_AXIS] = st_get_position_mm(Y_AXIS);
current_position[Z_AXIS] = st_get_position_mm(Z_AXIS);
current_position[E_AXIS] = st_get_position_mm(E_AXIS);
// Apply the mesh bed leveling correction to the Z axis.
#ifdef MESH_BED_LEVELING
if (mbl.active) {
@ -664,8 +655,6 @@ void planner_abort_hard()
#endif
}
#endif
// Clear the planner queue, reset and re-enable the stepper timer.
quickStop();
// Apply inverse world correction matrix.
machine2world(current_position[X_AXIS], current_position[Y_AXIS]);
@ -673,15 +662,29 @@ void planner_abort_hard()
#ifdef LIN_ADVANCE
memcpy(position_float, current_position, sizeof(position_float));
#endif
}
void planner_abort_hard()
{
// Abort the stepper routine and flush the planner queue.
DISABLE_STEPPER_DRIVER_INTERRUPT();
// Now the front-end (the Marlin_main.cpp with its current_position) is out of sync.
planner_reset_position();
// Relay to planner wait routine that the current line shall be canceled.
planner_aborted = true;
// Clear the planner queue, reset and re-enable the stepper timer.
quickStop();
// Resets planner junction speeds. Assumes start from rest.
previous_nominal_speed = 0.0;
memset(previous_speed, 0, sizeof(previous_speed));
// Reset position sync requests
plan_reset_next_e_queue = false;
plan_reset_next_e_sched = false;
// Relay to planner wait routine, that the current line shall be canceled.
waiting_inside_plan_buffer_line_print_aborted = true;
}
void plan_buffer_line_curposXYZE(float feed_rate) {
@ -702,12 +705,11 @@ float junction_deviation = 0.1;
// calculation the caller must also provide the physical length of the line in millimeters.
void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate, uint8_t extruder, const float* gcode_target)
{
// Calculate the buffer head after we push this byte
// Calculate the buffer head after we push this byte
uint8_t next_buffer_head = next_block_index(block_buffer_head);
// If the buffer is full: good! That means we are well ahead of the robot.
// If the buffer is full: good! That means we are well ahead of the robot.
// Rest here until there is room in the buffer.
waiting_inside_plan_buffer_line_print_aborted = false;
if (block_buffer_tail == next_buffer_head) {
do {
manage_heater();
@ -715,18 +717,14 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
manage_inactivity(false);
lcd_update(0);
} while (block_buffer_tail == next_buffer_head);
if (waiting_inside_plan_buffer_line_print_aborted) {
// Inside the lcd_update(0) routine the print has been aborted.
// Cancel the print, do not plan the current line this routine is waiting on.
#ifdef PLANNER_DIAGNOSTICS
planner_update_queue_min_counter();
#endif /* PLANNER_DIAGNOSTICS */
return;
}
}
#ifdef PLANNER_DIAGNOSTICS
planner_update_queue_min_counter();
#endif /* PLANNER_DIAGNOSTICS */
if(planner_aborted) {
// avoid planning the block early if aborted
return;
}
// Prepare to set up new block
block_t *block = &block_buffer[block_buffer_head];
@ -1331,8 +1329,12 @@ Having the real displacement of the head, we can calculate the total movement le
if (block->step_event_count.wide <= 32767)
block->flag |= BLOCK_FLAG_DDA_LOWRES;
// Move the buffer head. From now the block may be picked up by the stepper interrupt controller.
block_buffer_head = next_buffer_head;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
// Move the buffer head ensuring the current block hasn't been cancelled from an isr context
// (this is possible both during crash detection *and* uvlo, thus needing a global cli)
if(planner_aborted) return;
block_buffer_head = next_buffer_head;
}
// Update position
memcpy(position, target, sizeof(target)); // position[] = target[]

View file

@ -255,11 +255,14 @@ FORCE_INLINE bool planner_queue_full() {
return block_buffer_tail == next_block_index;
}
// Reset machine position from stepper counters
extern void planner_reset_position();
// Abort the stepper routine, clean up the block queue,
// wait for the steppers to stop,
// update planner's current position and the current_position of the front end.
extern void planner_abort_hard();
extern bool waiting_inside_plan_buffer_line_print_aborted;
extern bool planner_aborted;
#ifdef PREVENT_DANGEROUS_EXTRUDE
extern int extrude_min_temp;

View file

@ -287,15 +287,6 @@ ISR(TIMER1_COMPA_vect) {
if (sp < SP_min) SP_min = sp;
#endif //DEBUG_STACK_MONITOR
#ifdef DEBUG_PULLUP_CRASH
// check for faulty pull-ups enabled on thermistor inputs
if ((PORTF & (uint8_t)(ADC_DIDR_MSK & 0xff)) || (PORTK & (uint8_t)((ADC_DIDR_MSK >> 8) & 0xff)))
pullup_error(false);
#else
PORTF &= ~(uint8_t)(ADC_DIDR_MSK & 0xff);
PORTK &= ~(uint8_t)((ADC_DIDR_MSK >> 8) & 0xff);
#endif // DEBUG_PULLUP_CRASH
#ifdef LIN_ADVANCE
advance_isr_scheduler();
#else

View file

@ -4,6 +4,7 @@
#define FIRMWARE_SYSTEM_TIMER_H_
#include "Arduino.h"
#include "macros.h"
#define SYSTEM_TIMER_2
#ifdef SYSTEM_TIMER_2
@ -26,4 +27,24 @@
#define timer02_set_pwm0(pwm0)
#endif //SYSTEM_TIMER_2
// Timer counter, incremented by the 1ms Arduino timer.
// The standard Arduino timer() function returns this value atomically
// by disabling / enabling interrupts. This is costly, if the interrupts are known
// to be disabled.
#ifdef SYSTEM_TIMER_2
extern volatile unsigned long timer2_millis;
#else //SYSTEM_TIMER_2
extern volatile unsigned long timer0_millis;
#endif //SYSTEM_TIMER_2
// An unsynchronized equivalent to a standard Arduino _millis() function.
// To be used inside an interrupt routine.
FORCE_INLINE unsigned long millis_nc() {
#ifdef SYSTEM_TIMER_2
return timer2_millis;
#else //SYSTEM_TIMER_2
return timer0_millis;
#endif //SYSTEM_TIMER_2
}
#endif /* FIRMWARE_SYSTEM_TIMER_H_ */

115
Firmware/temp_model.h Normal file
View file

@ -0,0 +1,115 @@
// model-based temperature safety checker declarations
#ifndef TEMP_MGR_INTV
#error "this file is not a public interface, it should be used *only* within temperature.cpp!"
#endif
#include "planner.h"
constexpr uint8_t TEMP_MODEL_CAL_S = 60; // Maximum recording lenght during calibration (s)
constexpr uint8_t TEMP_MODEL_CAL_R_STEP = 4; // Fan interpolation steps during calibration
constexpr float TEMP_MODEL_fS = 0.065; // simulation filter (1st-order IIR factor)
constexpr float TEMP_MODEL_fE = 0.05; // error filter (1st-order IIR factor)
// transport delay buffer size (samples)
constexpr uint8_t TEMP_MODEL_LAG_SIZE = (TEMP_MODEL_LAG / TEMP_MGR_INTV + 0.5);
// resistance values for all fan levels
constexpr uint8_t TEMP_MODEL_R_SIZE = (1 << FAN_SOFT_PWM_BITS);
namespace temp_model {
struct model_data
{
// temporary buffers
float dT_lag_buf[TEMP_MODEL_LAG_SIZE]; // transport delay buffer
uint8_t dT_lag_idx = 0; // transport delay buffer index
float dT_err_prev = 0; // previous temperature delta error
float T_prev = 0; // last temperature extruder
// configurable parameters
float P; // heater power (W)
float C; // heatblock capacitance (J/K)
float R[TEMP_MODEL_R_SIZE]; // heatblock resistance for all fan levels (K/W)
float Ta_corr; // ambient temperature correction (K)
// thresholds
float warn; // warning threshold (K/s)
float err; // error threshold (K/s)
// status flags
union
{
bool flags;
struct
{
bool uninitialized: 1; // model is not initialized
bool error: 1; // error threshold set
bool warning: 1; // warning threshold set
} flag_bits;
};
// pre-computed values (initialized via reset)
float C_i; // heatblock capacitance (precomputed dT/C)
float warn_s; // warning threshold (per sample)
float err_s; // error threshold (per sample)
// simulation functions
void reset(uint8_t heater_pwm, uint8_t fan_pwm, float heater_temp, float ambient_temp);
void step(uint8_t heater_pwm, uint8_t fan_pwm, float heater_temp, float ambient_temp);
};
static bool enabled; // model check enabled
static bool warn_beep = true; // beep on warning threshold
static model_data data; // default heater data
static bool calibrated(); // return calibration/model validity status
static void check(); // check and trigger errors or warnings based on current state
// warning state (updated from from isr context)
volatile static struct
{
float dT_err; // temperature delta error (per sample)
bool warning: 1; // warning condition
bool assert: 1; // warning is still asserted
} warning_state;
static void handle_warning(); // handle warnings from user context
#ifdef TEMP_MODEL_DEBUG
static struct
{
volatile struct
{
uint32_t stamp;
int8_t delta_ms;
uint8_t counter;
uint8_t cur_pwm;
float cur_temp;
float cur_amb;
} entry;
uint8_t serial;
bool enabled;
} log_buf;
static void log_usr(); // user log handler
static void log_isr(); // isr log handler
#endif
} // namespace temp_model
namespace temp_model_cal {
// recording scratch buffer
struct rec_entry
{
float temp; // heater temperature
uint8_t pwm; // heater PWM
};
constexpr uint16_t REC_BUFFER_SIZE = TEMP_MODEL_CAL_S / TEMP_MGR_INTV;
static rec_entry* const rec_buffer = (rec_entry*)block_buffer; // oh-hey, free memory!
static_assert(sizeof(rec_entry[REC_BUFFER_SIZE]) <= sizeof(block_buffer),
"recording length too long to fit within available buffer");
} // namespace temp_model_cal

File diff suppressed because it is too large Load diff

View file

@ -22,29 +22,13 @@
#define temperature_h
#include "Marlin.h"
#include "planner.h"
#include "stepper.h"
#include "config.h"
#ifdef SYSTEM_TIMER_2
#define ENABLE_TEMPERATURE_INTERRUPT() TIMSK2 |= (1<<OCIE2B)
#define DISABLE_TEMPERATURE_INTERRUPT() TIMSK2 &= ~(1<<OCIE2B)
#else //SYSTEM_TIMER_2
#define ENABLE_TEMPERATURE_INTERRUPT() TIMSK0 |= (1<<OCIE0B)
#define DISABLE_TEMPERATURE_INTERRUPT() TIMSK0 &= ~(1<<OCIE0B)
#endif //SYSTEM_TIMER_2
// public functions
void tp_init(); //initialize the heating
void soft_pwm_init(); //initialize the soft pwm isr
void temp_mgr_init(); //initialize the temperature handler
void manage_heater(); //it is critical that this is called periodically.
bool get_temp_error(); //return true if any thermal error is set
extern bool checkAllHotends(void);
@ -82,20 +66,18 @@ extern int current_voltage_raw_bed;
extern uint16_t current_voltage_raw_IR;
#endif //IR_SENSOR_ANALOG
#if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1
extern unsigned char soft_pwm_bed;
#endif
extern bool bedPWMDisabled;
#ifdef PIDTEMP
extern int pid_cycle, pid_number_of_cycles;
extern float _Kp,_Ki,_Kd;
extern bool pid_tuning_finished;
float scalePID_i(float i);
float scalePID_d(float d);
float unscalePID_i(float i);
float unscalePID_d(float d);
bool pidTuningRunning(); // returns true if PID tuning is still running
void preparePidTuning(); // non-blocking call to set "pidTuningRunning" to true immediately
#endif
@ -156,8 +138,7 @@ FORCE_INLINE void setTargetHotend(const float &celsius, uint8_t extruder) {
static inline void setTargetHotendSafe(const float &celsius, uint8_t extruder)
{
if (extruder<EXTRUDERS) {
target_temperature[extruder] = celsius;
resetPID(extruder);
setTargetHotend(celsius, extruder);
}
}
@ -218,7 +199,7 @@ FORCE_INLINE bool isCoolingBed() {
#define CHECK_ALL_HEATERS (checkAllHotends()||(target_temperature_bed!=0))
int getHeaterPower(int heater);
void disable_heater(); // Disable all heaters
void disable_heater(); // Disable all heaters *instantaneously*
void updatePID();
@ -235,39 +216,27 @@ FORCE_INLINE void autotempShutdown(){
void PID_autotune(float temp, int extruder, int ncycles);
void setExtruderAutoFanState(uint8_t state);
void checkExtruderAutoFans();
#ifdef TEMP_MODEL
void temp_model_set_enabled(bool enabled);
void temp_model_set_warn_beep(bool enabled);
void temp_model_set_params(float C = NAN, float P = NAN, float Ta_corr = NAN, float warn = NAN, float err = NAN);
void temp_model_set_resistance(uint8_t index, float R);
void temp_model_report_settings();
void temp_model_reset_settings();
void temp_model_load_settings();
void temp_model_save_settings();
#if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1))
void temp_model_autotune(int16_t temp = 0);
enum {
EFCE_OK = 0, //!< normal operation, both fans are ok
EFCE_FIXED, //!< previous fan error was fixed
EFCE_DETECTED, //!< fan error detected, but not reported yet
EFCE_REPORTED //!< fan error detected and reported to LCD and serial
};
extern volatile uint8_t fan_check_error;
#ifdef TEMP_MODEL_DEBUG
void temp_model_log_enable(bool enable);
#endif
#endif
void countFanSpeed();
void checkFanSpeed();
void fanSpeedError(unsigned char _fan);
void check_fans();
#endif //(defined(TACH_0))
void check_min_temp();
void check_max_temp();
#ifdef EXTRUDER_ALTFAN_DETECT
extern bool extruder_altfan_detect();
extern void altfanOverride_toggle();
extern bool altfanOverride_get();
#endif //EXTRUDER_ALTFAN_DETECT
extern unsigned long extruder_autofan_last_check;
#ifdef FAN_SOFT_PWM
extern unsigned char fanSpeedSoftPwm;
#endif
extern uint8_t fanSpeedBckp;
extern bool fan_measuring;
#endif

View file

@ -10,7 +10,7 @@
#include "Marlin.h"
#include "language.h"
#include "cardreader.h"
#include "temperature.h"
#include "fancheck.h"
#include "stepper.h"
#include "ConfigurationStore.h"
#include "printers.h"
@ -94,14 +94,15 @@ static bool lcd_autoDeplete;
static float manual_feedrate[] = MANUAL_FEEDRATE;
/* LCD message status */
static LongTimer lcd_status_message_timeout;
static uint8_t lcd_status_message_level;
static char lcd_status_message[LCD_WIDTH + 1] = WELCOME_MSG;
/* !Configuration settings */
uint8_t lcd_status_message_level;
char lcd_status_message[LCD_WIDTH + 1] = WELCOME_MSG;
static uint8_t lay1cal_filament = 0;
static const char separator[] PROGMEM = "--------------------";
/** forward declarations **/
@ -597,7 +598,12 @@ void lcdui_print_status_line(void)
break;
}
}
else if ((IS_SD_PRINTING) && (custom_message_type == CustomMsg::Status)) { // If printing from SD, show what we are printing
else if ((IS_SD_PRINTING) &&
(custom_message_type == CustomMsg::Status) &&
(lcd_status_message_level <= LCD_STATUS_INFO) &&
lcd_status_message_timeout.expired_cont(LCD_STATUS_INFO_TIMEOUT))
{
// If printing from SD, show what we are printing
const char* longFilenameOLD = (card.longFilename[0] ? card.longFilename : card.filename);
if(strlen(longFilenameOLD) > LCD_WIDTH) {
uint8_t gh = scrollstuff;
@ -860,7 +866,7 @@ void lcd_status_screen() // NOT static due to using ins
}
if (current_click
&& ( menu_block_entering_on_serious_errors == SERIOUS_ERR_NONE ) // or a serious error blocks entering the menu
&& ( menu_block_mask == MENU_BLOCK_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
@ -869,14 +875,34 @@ void lcd_status_screen() // NOT static due to using ins
}
}
void print_stop();
void lcd_commands()
{
if (planner_aborted) {
// we are still within an aborted command. do not process any LCD command until we return
return;
}
if (lcd_commands_type == LcdCommands::StopPrint)
{
if (!blocks_queued() && !homing_flag)
{
custom_message_type = CustomMsg::Status;
lcd_setstatuspgm(_T(MSG_PRINT_ABORTED));
lcd_commands_type = LcdCommands::Idle;
lcd_commands_step = 0;
print_stop();
}
}
if (lcd_commands_type == LcdCommands::LongPause)
{
if (!blocks_queued() && !homing_flag)
{
if (custom_message_type != CustomMsg::M117)
{
custom_message_type = CustomMsg::Status;
lcd_setstatuspgm(_i("Print paused"));////MSG_PRINT_PAUSED c=20
}
lcd_commands_type = LcdCommands::Idle;
@ -1021,14 +1047,14 @@ void lcd_commands()
lcd_commands_step = 3;
}
if (lcd_commands_step == 3 && !blocks_queued()) { //PID calibration
preparePidTuning(); // ensure we don't move to the next step early
sprintf_P(cmd1, PSTR("M303 E0 S%3u"), pid_temp);
// setting the correct target temperature (for visualization) is done in PID_autotune
enquecommand(cmd1);
lcd_setstatuspgm(_i("PID cal."));////MSG_PID_RUNNING c=20
lcd_commands_step = 2;
}
if (lcd_commands_step == 2 && pid_tuning_finished) { //saving to eeprom
pid_tuning_finished = false;
if (lcd_commands_step == 2 && !pidTuningRunning()) { //saving to eeprom
custom_message_state = 0;
lcd_setstatuspgm(_i("PID cal. finished"));////MSG_PID_FINISHED c=20
setAllTargetHotends(0); // reset all hotends temperature including the number displayed on the main screen
@ -1067,18 +1093,19 @@ void lcd_return_to_status()
void lcd_pause_print()
{
stop_and_save_print_to_ram(0.0, -default_retraction);
lcd_return_to_status();
SERIAL_ECHOLNRPGM(MSG_OCTOPRINT_PAUSED);
isPrintPaused = true;
if (LcdCommands::Idle == lcd_commands_type) {
lcd_commands_type = LcdCommands::LongPause;
}
SERIAL_PROTOCOLLNRPGM(MSG_OCTOPRINT_PAUSED);
// return to status is required to continue processing in the main loop!
lcd_commands_type = LcdCommands::LongPause;
lcd_return_to_status();
}
//! @brief Send host action "pause"
void lcd_pause_usb_print()
{
SERIAL_PROTOCOLLNRPGM(MSG_OCTOPRINT_PAUSE);
SERIAL_PROTOCOLLNRPGM(MSG_OCTOPRINT_ASK_PAUSE);
}
static void lcd_move_menu_axis();
@ -5665,22 +5692,37 @@ static bool fan_error_selftest()
return 0;
}
bool resume_print_checks() {
// reset the lcd status so that a newer error will be shown
lcd_return_to_status();
lcd_reset_alert_level();
// ensure thermal issues (temp or fan) are resolved before we allow to resume
if (get_temp_error()
#ifdef FANCHECK
|| fan_error_selftest()
#endif
) {
return false; // abort if error persists
}
return true;
}
//! @brief Resume paused print, send host action "resumed"
//! @todo It is not good to call restore_print_from_ram_and_continue() from function called by lcd_update(),
//! as restore_print_from_ram_and_continue() calls lcd_update() internally.
void lcd_resume_print()
{
lcd_return_to_status();
lcd_reset_alert_level(); //for fan speed error
if (fan_error_selftest()) {
if (usb_timer.running()) SERIAL_PROTOCOLLNRPGM(MSG_OCTOPRINT_PAUSED);
return; //abort if error persists
}
// reset lcd and ensure we can resume first
if (!resume_print_checks()) return;
cmdqueue_serial_disabled = false;
lcd_setstatuspgm(_T(MSG_FINISHING_MOVEMENTS));
st_synchronize();
custom_message_type = CustomMsg::Resuming;
isPrintPaused = false;
Stopped = false; // resume processing USB commands again
restore_print_from_ram_and_continue(default_retraction);
pause_time += (_millis() - start_pause_print); //accumulate time when print is paused for correct statistics calculation
refresh_cmd_timeout();
@ -5691,7 +5733,11 @@ void lcd_resume_print()
//! @brief Resume paused USB/host print, send host action "resume"
void lcd_resume_usb_print()
{
SERIAL_PROTOCOLLNRPGM(MSG_OCTOPRINT_RESUME); //resume octoprint
// reset lcd and ensure we can resume first
if (!resume_print_checks()) return;
// resume the usb host
SERIAL_PROTOCOLLNRPGM(MSG_OCTOPRINT_ASK_RESUME);
}
static void change_sheet()
@ -5872,14 +5918,16 @@ static void lcd_main_menu()
}
if(isPrintPaused)
{
// only allow resuming if hardware errors (temperature or fan) are cleared
if(!get_temp_error()
#ifdef FANCHECK
if((fan_check_error == EFCE_FIXED) || (fan_check_error == EFCE_OK))
&& ((fan_check_error == EFCE_FIXED) || (fan_check_error == EFCE_OK))
#endif //FANCHECK
{
if (usb_timer.running()) {
MENU_ITEM_SUBMENU_P(_T(MSG_RESUME_PRINT), lcd_resume_usb_print);
} else {
) {
if (saved_printing) {
MENU_ITEM_SUBMENU_P(_T(MSG_RESUME_PRINT), lcd_resume_print);
} else {
MENU_ITEM_SUBMENU_P(_T(MSG_RESUME_PRINT), lcd_resume_usb_print);
}
}
}
@ -6286,56 +6334,61 @@ static void lcd_sd_updir()
menu_data_reset(); //Forces reloading of cached variables.
}
void lcd_print_stop()
// continue stopping the print from the main loop after lcd_print_stop() is called
void print_stop()
{
if (!card.sdprinting) {
SERIAL_ECHOLNRPGM(MSG_OCTOPRINT_CANCEL); // for Octoprint
}
UnconditionalStop();
// save printing time
stoptime = _millis();
unsigned long t = (stoptime - starttime - pause_time) / 1000; //time in s
save_statistics(total_filament_used, t);
// TODO: all the following should be moved in the main marlin loop!
#ifdef MESH_BED_LEVELING
mbl.active = false; //also prevents undoing the mbl compensation a second time in the second planner_abort_hard()
#endif
// lift Z
raise_z_above(current_position[Z_AXIS] + 10, true);
lcd_setstatuspgm(_T(MSG_PRINT_ABORTED));
stoptime = _millis();
unsigned long t = (stoptime - starttime - pause_time) / 1000; //time in s
pause_time = 0;
save_statistics(total_filament_used, t);
// reset current command
lcd_commands_step = 0;
lcd_commands_type = LcdCommands::Idle;
lcd_cooldown(); //turns off heaters and fan; goes to status screen.
if (axis_known_position[Z_AXIS]) {
current_position[Z_AXIS] += Z_CANCEL_LIFT;
clamp_to_software_endstops(current_position);
plan_buffer_line_curposXYZE(manual_feedrate[Z_AXIS] / 60);
}
if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) //if axis are homed, move to parked position.
{
// if axis are homed, move to parking position.
if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) {
current_position[X_AXIS] = X_CANCEL_POS;
current_position[Y_AXIS] = Y_CANCEL_POS;
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60);
}
st_synchronize();
// did we come here from a thermal error?
if(get_temp_error()) {
// time to stop the error beep
WRITE(BEEPER, LOW);
} else {
// Turn off the print fan
fanSpeed = 0;
}
if (mmu_enabled) extr_unload(); //M702 C
finishAndDisableSteppers(); //M84
lcd_setstatuspgm(MSG_WELCOME);
custom_message_type = CustomMsg::Status;
planner_abort_hard(); //needs to be done since plan_buffer_line resets waiting_inside_plan_buffer_line_print_aborted to false. Also copies current to destination.
axis_relative_modes = E_AXIS_MASK; //XYZ absolute, E relative
isPrintPaused = false; //clear isPrintPaused flag to allow starting next print after pause->stop scenario.
}
void lcd_print_stop()
{
// UnconditionalStop() will internally cause planner_abort_hard(), meaning we _cannot_ plan
// any more move in this call! Any further move must happen inside print_stop(), which is called
// by the main loop one iteration later.
UnconditionalStop();
if (!card.sdprinting) {
SERIAL_ECHOLNRPGM(MSG_OCTOPRINT_CANCEL); // for Octoprint
}
#ifdef MESH_BED_LEVELING
mbl.active = false;
#endif
// clear any pending paused state immediately
pause_time = 0;
isPrintPaused = false;
// return to status is required to continue processing in the main loop!
lcd_commands_type = LcdCommands::StopPrint;
lcd_return_to_status();
}
void lcd_sdcard_stop()
@ -7952,57 +8005,70 @@ void lcd_finishstatus() {
}
void lcd_setstatus(const char* message)
static bool lcd_message_check(uint8_t priority)
{
if (lcd_status_message_level > 0)
return;
lcd_updatestatus(message);
// regular priority check
if (priority >= lcd_status_message_level)
return true;
// check if we can override an info message yet
if (lcd_status_message_level == LCD_STATUS_INFO) {
return lcd_status_message_timeout.expired_cont(LCD_STATUS_INFO_TIMEOUT);
}
return false;
}
void lcd_updatestatuspgm(const char *message){
strncpy_P(lcd_status_message, message, LCD_WIDTH);
static void lcd_updatestatus(const char *message, bool progmem = false)
{
if (progmem)
strncpy_P(lcd_status_message, message, LCD_WIDTH);
else
strncpy(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_setstatus(const char* message)
{
if (lcd_message_check(LCD_STATUS_NONE))
lcd_updatestatus(message);
}
void lcd_setstatuspgm(const char* message)
{
if (lcd_status_message_level > 0)
return;
lcd_updatestatuspgm(message);
if (lcd_message_check(LCD_STATUS_NONE))
lcd_updatestatus(message, true);
}
void lcd_updatestatus(const char *message){
strncpy(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_setalertstatuspgm(const char* message, uint8_t severity)
void lcd_setalertstatus_(const char* message, uint8_t severity, bool progmem)
{
if (severity > lcd_status_message_level) {
lcd_updatestatuspgm(message);
lcd_status_message_level = severity;
lcd_return_to_status();
}
if (lcd_message_check(severity)) {
lcd_updatestatus(message, progmem);
lcd_status_message_timeout.start();
lcd_status_message_level = severity;
custom_message_type = CustomMsg::Status;
custom_message_state = 0;
lcd_return_to_status();
}
}
void lcd_setalertstatus(const char* message, uint8_t severity)
{
if (severity > lcd_status_message_level) {
lcd_updatestatus(message);
lcd_status_message_level = severity;
lcd_return_to_status();
}
lcd_setalertstatus_(message, severity, false);
}
void lcd_setalertstatuspgm(const char* message, uint8_t severity)
{
lcd_setalertstatus_(message, severity, true);
}
void lcd_reset_alert_level()
{
lcd_status_message_level = 0;
lcd_status_message_level = 0;
}
uint8_t get_message_level()
@ -8013,9 +8079,9 @@ uint8_t get_message_level()
void menu_lcd_longpress_func(void)
{
backlight_wake();
if (homing_flag || mesh_bed_leveling_flag || menu_menu == lcd_babystep_z || menu_menu == lcd_move_z)
if (homing_flag || mesh_bed_leveling_flag || menu_menu == lcd_babystep_z || menu_menu == lcd_move_z || menu_block_mask != MENU_BLOCK_NONE)
{
// disable longpress during re-entry, while homing or calibration
// disable longpress during re-entry, while homing, calibration or if a serious error
lcd_quick_feedback();
return;
}

View file

@ -9,14 +9,19 @@ extern void menu_lcd_lcdupdate_func(void);
// Call with a false parameter to suppress the LCD update from various places like the planner or the temp control.
void ultralcd_init();
void lcd_setstatus(const char* message);
void lcd_setstatuspgm(const char* message);
//! LCD status severities
#define LCD_STATUS_CRITICAL 2 //< Heater failure
#define LCD_STATUS_ALERT 1 //< Other hardware issue
#define LCD_STATUS_CRITICAL 3 //< Heater failure
#define LCD_STATUS_ALERT 2 //< Other hardware issue
#define LCD_STATUS_INFO 1 //< Message times out after a while
#define LCD_STATUS_NONE 0 //< No alert message set
#define LCD_STATUS_INFO_TIMEOUT 20000
// Set the current status message (equivalent to LCD_STATUS_NONE)
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
@ -25,13 +30,10 @@ void lcd_setstatuspgm(const char* message);
void lcd_setalertstatus(const char* message, uint8_t severity = LCD_STATUS_ALERT);
void lcd_setalertstatuspgm(const char* message, uint8_t severity = LCD_STATUS_ALERT);
//! only update the alert message on the main status screen
//! has no sideeffects, may be called multiple times
void lcd_updatestatus(const char *message);
void lcd_updatestatuspgm(const char *message);
void lcd_reset_alert_level();
//! Get/reset the current alert level
uint8_t get_message_level();
void lcd_reset_alert_level();
void lcd_adjust_z();
void lcd_pick_babystep();
void lcd_alright();

View file

@ -413,6 +413,34 @@
#define TEMP_RUNAWAY_EXTRUDER_HYSTERESIS 15
#define TEMP_RUNAWAY_EXTRUDER_TIMEOUT 45
// model-based temperature check
#define TEMP_MODEL 1 // enable model-based temperature checks
#define TEMP_MODEL_DEBUG 1 // extended runtime logging
#define TEMP_MODEL_P 38. // heater power (W)
#define TEMP_MODEL_C 11. // initial guess for heatblock capacitance (J/K)
#define TEMP_MODEL_Cl 5 // C estimation lower limit
#define TEMP_MODEL_Ch 20 // C estimation upper limit
#define TEMP_MODEL_C_thr 0.01 // C estimation iteration threshold
#define TEMP_MODEL_C_itr 30 // C estimation iteration limit
#define TEMP_MODEL_R 25 // initial guess for heatblock resistance (K/W)
#define TEMP_MODEL_Rl 5 // R estimation lower limit
#define TEMP_MODEL_Rh 50 // R estimation upper limit
#define TEMP_MODEL_R_thr 0.01 // R estimation iteration threshold
#define TEMP_MODEL_R_itr 30 // R estimation iteration limit
#define TEMP_MODEL_Ta_corr -7 // Default ambient temperature correction
#define TEMP_MODEL_LAG 2.1 // Temperature transport delay (s)
#define TEMP_MODEL_W 1.2 // Default warning threshold (K/s)
#define TEMP_MODEL_E 1.74 // Default error threshold (K/s)
#define TEMP_MODEL_CAL_Th 230 // Default calibration working temperature (C)
#define TEMP_MODEL_CAL_Tl 50 // Default calibration cooling temperature (C)
/*------------------------------------
MOTOR CURRENT SETTINGS
*------------------------------------*/

View file

@ -417,6 +417,34 @@
#define TEMP_RUNAWAY_EXTRUDER_HYSTERESIS 15
#define TEMP_RUNAWAY_EXTRUDER_TIMEOUT 45
// model-based temperature check
#define TEMP_MODEL 1 // enable model-based temperature checks
#define TEMP_MODEL_DEBUG 1 // extended runtime logging
#define TEMP_MODEL_P 38. // heater power (W)
#define TEMP_MODEL_C 11. // initial guess for heatblock capacitance (J/K)
#define TEMP_MODEL_Cl 5 // C estimation lower limit
#define TEMP_MODEL_Ch 20 // C estimation upper limit
#define TEMP_MODEL_C_thr 0.01 // C estimation iteration threshold
#define TEMP_MODEL_C_itr 30 // C estimation iteration limit
#define TEMP_MODEL_R 25 // initial guess for heatblock resistance (K/W)
#define TEMP_MODEL_Rl 5 // R estimation lower limit
#define TEMP_MODEL_Rh 50 // R estimation upper limit
#define TEMP_MODEL_R_thr 0.01 // R estimation iteration threshold
#define TEMP_MODEL_R_itr 30 // R estimation iteration limit
#define TEMP_MODEL_Ta_corr -7 // Default ambient temperature correction
#define TEMP_MODEL_LAG 2.1 // Temperature transport delay (s)
#define TEMP_MODEL_W 1.2 // Default warning threshold (K/s)
#define TEMP_MODEL_E 1.74 // Default error threshold (K/s)
#define TEMP_MODEL_CAL_Th 230 // Default calibration working temperature (C)
#define TEMP_MODEL_CAL_Tl 50 // Default calibration cooling temperature (C)
/*------------------------------------
MOTOR CURRENT SETTINGS
*------------------------------------*/

View file

@ -138,15 +138,18 @@ pos_mm_t pos_2_mm(float pos){
void xyzcal_meassure_enter(void)
{
DBG(_n("xyzcal_meassure_enter\n"));
// disable heaters and stop motion before we initialize sm4
disable_heater();
DISABLE_TEMPERATURE_INTERRUPT();
#if (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
DISABLE_FANCHECK_INTERRUPT();
#endif //(defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
st_synchronize();
// disable incompatible interrupts
DISABLE_STEPPER_DRIVER_INTERRUPT();
#ifdef WATCHDOG
wdt_disable();
#endif //WATCHDOG
// setup internal callbacks
sm4_stop_cb = 0;
sm4_update_pos_cb = xyzcal_update_pos;
sm4_calc_delay_cb = xyzcal_calc_delay;
@ -155,21 +158,18 @@ void xyzcal_meassure_enter(void)
void xyzcal_meassure_leave(void)
{
DBG(_n("xyzcal_meassure_leave\n"));
planner_abort_hard();
ENABLE_TEMPERATURE_INTERRUPT();
#if (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
ENABLE_FANCHECK_INTERRUPT();
#endif //(defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
ENABLE_STEPPER_DRIVER_INTERRUPT();
// resync planner position from counters (changed by xyzcal_update_pos)
planner_reset_position();
// re-enable interrupts
#ifdef WATCHDOG
wdt_enable(WDTO_4S);
#ifdef EMERGENCY_HANDLERS
WDTCSR |= (1 << WDIE);
#endif //EMERGENCY_HANDLERS
#endif //WATCHDOG
sm4_stop_cb = 0;
sm4_update_pos_cb = 0;
sm4_calc_delay_cb = 0;
ENABLE_STEPPER_DRIVER_INTERRUPT();
}
@ -999,13 +999,9 @@ BedSkewOffsetDetectionResultType xyzcal_scan_and_process(){
return ret;
}
BedSkewOffsetDetectionResultType xyzcal_find_bed_induction_sensor_point_xy(void){
BedSkewOffsetDetectionResultType ret = BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND;
//@size=258
BedSkewOffsetDetectionResultType xyzcal_find_bed_induction_sensor_point_xy(void) {
// DBG(_n("xyzcal_find_bed_induction_sensor_point_xy x=%ld y=%ld z=%ld\n"), count_position[X_AXIS], count_position[Y_AXIS], count_position[Z_AXIS]);
st_synchronize();
BedSkewOffsetDetectionResultType ret = BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND;
xyzcal_meassure_enter();
if (xyzcal_searchZ())
ret = xyzcal_scan_and_process();