diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h
index 18e7a11b..65d95a9f 100644
--- a/Firmware/Configuration_adv.h
+++ b/Firmware/Configuration_adv.h
@@ -293,6 +293,7 @@
#define LA_K_DEF 0 // Default K factor (Unit: mm compression per 1mm/s extruder speed)
#define LA_K_MAX 10 // Maximum acceptable K factor (exclusive, see notes in planner.cpp:plan_buffer_line)
#define LA_LA10_MIN LA_K_MAX // Lin. Advance 1.0 threshold value (inclusive)
+ //#define LA_FLOWADJ // Adjust LA along with flow/M221 for uniform width
//#define LA_NOCOMPAT // Disable Linear Advance 1.0 compatibility
//#define LA_LIVE_K // Allow adjusting K in the Tune menu
//#define LA_DEBUG // If enabled, this will generate debug information output over USB.
@@ -441,6 +442,10 @@ const unsigned int dropsegments=5; //everything with less than this number of st
#undef BED_MINTEMP
#undef BED_MAXTEMP
#endif
+#if TEMP_SENSOR_AMBIENT == 0
+ #undef AMBIENT_MINTEMP
+ #undef AMBIENT_MAXTEMP
+#endif
#endif //__CONFIGURATION_ADV_H
diff --git a/Firmware/Dcodes.cpp b/Firmware/Dcodes.cpp
index 1f902c5e..c77cd96e 100644
--- a/Firmware/Dcodes.cpp
+++ b/Firmware/Dcodes.cpp
@@ -1,5 +1,5 @@
#include "Dcodes.h"
-//#include "Marlin.h"
+#include "Marlin.h"
#include "Configuration.h"
#include "language.h"
#include "cmdqueue.h"
@@ -226,9 +226,7 @@ void dcode_0()
LOG("D0 - Reset\n");
if (code_seen('B')) //bootloader
{
- cli();
- wdt_enable(WDTO_15MS);
- while(1);
+ softReset();
}
else //reset
{
@@ -252,8 +250,7 @@ void dcode_1()
cli();
for (int i = 0; i < 8192; i++)
eeprom_write_byte((unsigned char*)i, (unsigned char)0xff);
- wdt_enable(WDTO_15MS);
- while(1);
+ softReset();
}
/*!
@@ -420,8 +417,7 @@ void dcode_5()
boot_dst_addr = (uint32_t)address;
boot_src_addr = (uint32_t)(&data);
bootapp_print_vars();
- wdt_enable(WDTO_15MS);
- while(1);
+ softReset();
}
while (count)
{
@@ -467,8 +463,7 @@ void dcode_7()
boot_copy_size = (uint16_t)0xc00;
boot_src_addr = (uint32_t)0x0003e400;
boot_dst_addr = (uint32_t)0x0003f400;
- wdt_enable(WDTO_15MS);
- while(1);
+ softReset();
*/
}
diff --git a/Firmware/Marlin.h b/Firmware/Marlin.h
index 5c03552b..a1736e9c 100755
--- a/Firmware/Marlin.h
+++ b/Firmware/Marlin.h
@@ -299,7 +299,7 @@ extern float feedrate;
extern int feedmultiply;
extern int extrudemultiply; // Sets extrude multiply factor (in percent) for all extruders
extern int extruder_multiply[EXTRUDERS]; // sets extrude multiply factor (in percent) for each extruder individually
-extern float volumetric_multiplier[EXTRUDERS]; // reciprocal of cross-sectional area of filament (in square millimeters), stored this way to reduce computational burden in planner
+extern float extruder_multiplier[EXTRUDERS]; // reciprocal of cross-sectional area of filament (in square millimeters), stored this way to reduce computational burden in planner
extern float current_position[NUM_AXIS] ;
extern float destination[NUM_AXIS] ;
extern float min_pos[3];
@@ -512,4 +512,6 @@ void load_filament_final_feed();
void marlin_wait_for_click();
void raise_z_above(float target, bool plan=true);
+extern "C" void softReset();
+
#endif
diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 53b04eee..7a89f9bc 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -654,6 +654,12 @@ void failstats_reset_print()
#endif
}
+void softReset()
+{
+ cli();
+ wdt_enable(WDTO_15MS);
+ while(1);
+}
#ifdef MESH_BED_LEVELING
@@ -768,6 +774,7 @@ static void factory_reset(char level)
}
}
+ softReset();
break;
@@ -3394,37 +3401,24 @@ void gcode_M701()
*/
static void gcode_PRUSA_SN()
{
- if (farm_mode) {
- selectedSerialPort = 0;
- putchar(';');
- putchar('S');
- int numbersRead = 0;
- ShortTimer timeout;
- timeout.start();
+ uint8_t selectedSerialPort_bak = selectedSerialPort;
+ char SN[20];
+ selectedSerialPort = 0;
+ SERIAL_ECHOLNRPGM(PSTR(";S"));
+ uint8_t numbersRead = 0;
+ ShortTimer timeout;
+ timeout.start();
- while (numbersRead < 19) {
- while (MSerial.available() > 0) {
- uint8_t serial_char = MSerial.read();
- selectedSerialPort = 1;
- putchar(serial_char);
- numbersRead++;
- selectedSerialPort = 0;
- }
- if (timeout.expired(100u)) break;
+ while (numbersRead < (sizeof(SN) - 1)) {
+ if (MSerial.available() > 0) {
+ SN[numbersRead] = MSerial.read();
+ numbersRead++;
}
- selectedSerialPort = 1;
- putchar('\n');
-#if 0
- for (int b = 0; b < 3; b++) {
- _tone(BEEPER, 110);
- _delay(50);
- _noTone(BEEPER);
- _delay(50);
- }
-#endif
- } else {
- puts_P(_N("Not in farm mode."));
+ if (timeout.expired(100u)) break;
}
+ SN[numbersRead] = 0;
+ selectedSerialPort = selectedSerialPort_bak;
+ SERIAL_ECHOLN(SN);
}
//! Detection of faulty RAMBo 1.1b boards equipped with bigger capacitors
//! at the TACH_1 pin, which causes bad detection of print fan speed.
@@ -3921,9 +3915,7 @@ void process_commands()
#if (defined(WATCHDOG) && (MOTHERBOARD == BOARD_EINSY_1_0a))
boot_app_magic = BOOT_APP_MAGIC;
boot_app_flags = BOOT_APP_FLG_RUN;
- wdt_enable(WDTO_15MS);
- cli();
- while(1);
+ softReset();
#else //WATCHDOG
asm volatile("jmp 0x3E000");
#endif //WATCHDOG
@@ -4391,6 +4383,14 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
#endif //FWRETRACT
+ /*!
+ ### G21 - Sets Units to Millimters G21: Set Units to Millimeters
+ Units are in millimeters. Prusa doesn't support inches.
+ */
+ case 21:
+ break; //Doing nothing. This is just to prevent serial UNKOWN warnings.
+
+
/*!
### G28 - Home all Axes one at a time G28: Move to Origin (Home)
Using `G28` without any parameters will perfom homing of all axes AND mesh bed leveling, while `G28 W` will just home all axes (no mesh bed leveling).
@@ -7342,17 +7342,26 @@ Sigma_Exit:
*/
case 220: // M220 S- set speed factor override percentage
{
- if (code_seen('B')) //backup current speed factor
- {
- saved_feedmultiply_mm = feedmultiply;
- }
- if(code_seen('S'))
- {
- feedmultiply = code_value() ;
- }
- if (code_seen('R')) { //restore previous feedmultiply
- feedmultiply = saved_feedmultiply_mm;
- }
+ bool codesWereSeen = false;
+ if (code_seen('B')) //backup current speed factor
+ {
+ saved_feedmultiply_mm = feedmultiply;
+ codesWereSeen = true;
+ }
+ if (code_seen('S'))
+ {
+ feedmultiply = code_value();
+ codesWereSeen = true;
+ }
+ if (code_seen('R')) //restore previous feedmultiply
+ {
+ feedmultiply = saved_feedmultiply_mm;
+ codesWereSeen = true;
+ }
+ if (!codesWereSeen)
+ {
+ printf_P(PSTR("%i%%\n"), feedmultiply);
+ }
}
break;
@@ -7368,23 +7377,26 @@ Sigma_Exit:
*/
case 221: // M221 S- set extrude factor override percentage
{
- if(code_seen('S'))
- {
- int tmp_code = code_value();
- if (code_seen('T'))
+ if (code_seen('S'))
{
- uint8_t extruder;
- if(setTargetedHotend(221, extruder)){
- break;
- }
- extruder_multiply[extruder] = tmp_code;
+ int tmp_code = code_value();
+ if (code_seen('T'))
+ {
+ uint8_t extruder;
+ if (setTargetedHotend(221, extruder))
+ break;
+ extruder_multiply[extruder] = tmp_code;
+ }
+ else
+ {
+ extrudemultiply = tmp_code ;
+ }
}
else
{
- extrudemultiply = tmp_code ;
+ printf_P(PSTR("%i%%\n"), extrudemultiply);
}
- }
- calculate_extruder_multipliers();
+ calculate_extruder_multipliers();
}
break;
@@ -8612,7 +8624,7 @@ Sigma_Exit:
break;
/*!
- ### M999 - Restart after being stopped M999: Restart after being stopped by error
+ ### M999 - Restart after being stopped M999: Restart after being stopped by error
@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:
@@ -11758,7 +11770,6 @@ void disable_force_z()
#endif // TMC2130
}
-
void enable_force_z()
{
if(bEnableForce_z)
diff --git a/Firmware/bootapp.c b/Firmware/bootapp.c
index 4fd67db2..c4585af5 100644
--- a/Firmware/bootapp.c
+++ b/Firmware/bootapp.c
@@ -9,6 +9,8 @@
extern FILE _uartout;
#define uartout (&_uartout)
+extern void softReset();
+
void bootapp_print_vars(void)
{
fprintf_P(uartout, PSTR("boot_src_addr =0x%08lx\n"), boot_src_addr);
@@ -39,8 +41,7 @@ void bootapp_ram2flash(uint16_t rptr, uint16_t fptr, uint16_t size)
boot_src_addr = (uint32_t)rptr;
boot_dst_addr = (uint32_t)fptr;
bootapp_print_vars();
- wdt_enable(WDTO_15MS);
- while(1);
+ softReset();
}
void bootapp_reboot_user0(uint8_t reserved)
@@ -50,6 +51,5 @@ void bootapp_reboot_user0(uint8_t reserved)
boot_app_flags = BOOT_APP_FLG_USER0;
boot_reserved = reserved;
bootapp_print_vars();
- wdt_enable(WDTO_15MS);
- while(1);
+ softReset();
}
diff --git a/Firmware/eeprom.h b/Firmware/eeprom.h
index 89d7e7f9..5cb7ddb8 100644
--- a/Firmware/eeprom.h
+++ b/Firmware/eeprom.h
@@ -359,6 +359,12 @@ static_assert(sizeof(Sheets) == EEPROM_SHEETS_SIZEOF, "Sizeof(Sheets) is not EEP
| ^ | ^ | ^ | 00h 0 | ^ | LCD backlight mode: __Dim__ | ^ | ^
| 0x0D30 3376 | uint16 | EEPROM_BACKLIGHT_TIMEOUT | 01 00 - ff ff | 0a 00h 65535 | LCD backlight timeout: __10__ seconds | LCD menu | D3 Ax0d30 C2
| 0x0D2C 3372 | float | EEPROM_UVLO_LA_K | ??? | ff ff ff ffh | Power panic saved Linear Advanced K value | ??? | D3 Ax0d2c C4
+| 0x0D2B 3371 | uint8 | EEPROM_ALTFAN_OVERRIDE | ffh 255 | ffh 255 | ALTFAN override unknown state | LCD menu | D3 Ax0d2b C1
+| ^ | ^ | ^ | 00h 0 | ^ | ALTFAN override deactivated | ^ | ^
+| ^ | ^ | ^ | 01h 1 | ^ | ALTFAN override activated | ^ | ^
+| 0x0D2A 3370 | uint8 | EEPROM_EXPERIMENTAL_VISIBILITY | ffh 255 | ffh 255 | Experimental menu visibility unknown state | LCD menu | D3 Ax0d2a C1
+| ^ | ^ | ^ | 00h 0 | ^ | Experimental menu visibility hidden | ^ | ^
+| ^ | ^ | ^ | 01h 1 | ^ | Experimental menu visibility visible | ^ | ^
| Address begin | Bit/Type | Name | Valid values | Default/FactoryReset | Description | Gcode/Function| Debug code
@@ -561,8 +567,11 @@ static Sheets * const EEPROM_Sheets_base = (Sheets*)(EEPROM_SHEETS_BASE);
#define EEPROM_UVLO_LA_K (EEPROM_BACKLIGHT_TIMEOUT-4) // float
+#define EEPROM_ALTFAN_OVERRIDE (EEPROM_UVLO_LA_K-1) //uint8
+#define EEPROM_EXPERIMENTAL_VISIBILITY (EEPROM_ALTFAN_OVERRIDE-1) //uint8
+
//This is supposed to point to last item to allow EEPROM overrun check. Please update when adding new items.
-#define EEPROM_LAST_ITEM EEPROM_UVLO_LA_K
+#define EEPROM_LAST_ITEM EEPROM_EXPERIMENTAL_VISIBILITY
// !!!!!
// !!!!! this is end of EEPROM section ... all updates MUST BE inserted before this mark !!!!!
// !!!!!
diff --git a/Firmware/fastio.h b/Firmware/fastio.h
index e4f25ed8..acded8cb 100644
--- a/Firmware/fastio.h
+++ b/Firmware/fastio.h
@@ -58,7 +58,7 @@
#define _GET_OUTPUT(IO) ((DIO ## IO ## _DDR & MASK(DIO ## IO ## _PIN)) != 0)
/// check if pin is an timer
-#define _GET_TIMER(IO) ((DIO ## IO ## _PWM)
+#define _GET_TIMER(IO) (DIO ## IO ## _PWM)
// why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
diff --git a/Firmware/fsensor.cpp b/Firmware/fsensor.cpp
index 2753ede0..7908c5db 100755
--- a/Firmware/fsensor.cpp
+++ b/Firmware/fsensor.cpp
@@ -478,22 +478,8 @@ bool fsensor_oq_result(void)
}
#endif //FSENSOR_QUALITY
-ISR(FSENSOR_INT_PIN_VECT)
+FORCE_INLINE static void fsensor_isr(int st_cnt)
{
- if (mmu_enabled || ir_sensor_detected) return;
- if (!((fsensor_int_pin_old ^ FSENSOR_INT_PIN_PIN_REG) & FSENSOR_INT_PIN_MASK)) return;
- fsensor_int_pin_old = FSENSOR_INT_PIN_PIN_REG;
-
- // prevent isr re-entry
- static bool _lock = false;
- if (_lock) return;
- _lock = true;
-
- // fetch fsensor_st_cnt atomically
- int st_cnt = fsensor_st_cnt;
- fsensor_st_cnt = 0;
- sei();
-
uint8_t old_err_cnt = fsensor_err_cnt;
uint8_t pat9125_res = fsensor_oq_meassure?pat9125_update():pat9125_update_y();
if (!pat9125_res)
@@ -578,8 +564,28 @@ ISR(FSENSOR_INT_PIN_VECT)
#endif //DEBUG_FSENSOR_LOG
pat9125_y = 0;
- _lock = false;
- return;
+}
+
+ISR(FSENSOR_INT_PIN_VECT)
+{
+ if (mmu_enabled || ir_sensor_detected) return;
+ if (!((fsensor_int_pin_old ^ FSENSOR_INT_PIN_PIN_REG) & FSENSOR_INT_PIN_MASK)) return;
+ fsensor_int_pin_old = FSENSOR_INT_PIN_PIN_REG;
+
+ // prevent isr re-entry
+ static bool _lock = false;
+ if (!_lock)
+ {
+ // fetch fsensor_st_cnt atomically
+ int st_cnt = fsensor_st_cnt;
+ fsensor_st_cnt = 0;
+
+ _lock = true;
+ sei();
+ fsensor_isr(st_cnt);
+ cli();
+ _lock = false;
+ }
}
void fsensor_setup_interrupt(void)
diff --git a/Firmware/menu.cpp b/Firmware/menu.cpp
index d31dce7e..3c4e8926 100755
--- a/Firmware/menu.cpp
+++ b/Firmware/menu.cpp
@@ -48,6 +48,7 @@ void menu_goto(menu_func_t menu, const uint32_t encoder, const bool feedback, bo
{
menu_menu = menu;
lcd_encoder = encoder;
+ menu_top = 0; //reset menu view. Needed if menu_back() is called from deep inside a menu, such as Support
asm("sei");
if (reset_menu_state)
{
diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp
index c0f465c2..2615ef66 100644
--- a/Firmware/planner.cpp
+++ b/Firmware/planner.cpp
@@ -226,11 +226,23 @@ void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit
// Size of Plateau of Nominal Rate.
uint32_t plateau_steps = 0;
+#ifdef LIN_ADVANCE
+ uint16_t final_adv_steps = 0;
+ uint16_t max_adv_steps = 0;
+ if (block->use_advance_lead) {
+ final_adv_steps = final_rate * block->adv_comp;
+ }
+#endif
+
// Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will
// have to use intersection_distance() to calculate when to abort acceleration and start braking
// in order to reach the final_rate exactly at the end of this block.
if (accel_decel_steps < block->step_event_count.wide) {
plateau_steps = block->step_event_count.wide - accel_decel_steps;
+#ifdef LIN_ADVANCE
+ if (block->use_advance_lead)
+ max_adv_steps = block->nominal_rate * block->adv_comp;
+#endif
} else {
uint32_t acceleration_x4 = acceleration << 2;
// Avoid negative numbers
@@ -263,14 +275,20 @@ void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit
decelerate_steps = block->step_event_count.wide;
accelerate_steps = block->step_event_count.wide - decelerate_steps;
}
- }
#ifdef LIN_ADVANCE
- uint16_t final_adv_steps = 0;
- if (block->use_advance_lead) {
- final_adv_steps = exit_speed * block->adv_comp;
- }
+ if (block->use_advance_lead) {
+ if(!accelerate_steps || !decelerate_steps) {
+ // accelerate_steps=0: deceleration-only ramp, max_rate is effectively unused
+ // decelerate_steps=0: acceleration-only ramp, max_rate _is_ final_rate
+ max_adv_steps = final_adv_steps;
+ } else {
+ float max_rate = sqrt(acceleration_x2 * accelerate_steps + initial_rate_sqr);
+ max_adv_steps = max_rate * block->adv_comp;
+ }
+ }
#endif
+ }
CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section
// This block locks the interrupts globally for 4.38 us,
@@ -284,6 +302,7 @@ void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit
block->final_rate = final_rate;
#ifdef LIN_ADVANCE
block->final_adv_steps = final_adv_steps;
+ block->max_adv_steps = max_adv_steps;
#endif
}
CRITICAL_SECTION_END;
@@ -1077,12 +1096,20 @@ Having the real displacement of the head, we can calculate the total movement le
&& delta_mm[E_AXIS] >= 0
&& abs(delta_mm[Z_AXIS]) < 0.5;
if (block->use_advance_lead) {
+#ifdef LA_FLOWADJ
+ // M221/FLOW should change uniformly the extrusion thickness
+ float delta_e = (e - position_float[E_AXIS]) / extruder_multiplier[extruder];
+#else
+ // M221/FLOW only adjusts for an incorrect source diameter
+ float delta_e = (e - position_float[E_AXIS]);
+#endif
+ float delta_D = sqrt(sq(x - position_float[X_AXIS])
+ + sq(y - position_float[Y_AXIS])
+ + sq(z - position_float[Z_AXIS]));
+
// all extrusion moves with LA require a compression which is proportional to the
// extrusion_length to distance ratio (e/D)
- e_D_ratio = (e - position_float[E_AXIS]) /
- sqrt(sq(x - position_float[X_AXIS])
- + sq(y - position_float[Y_AXIS])
- + sq(z - position_float[Z_AXIS]));
+ e_D_ratio = delta_e / delta_D;
// Check for unusual high e_D ratio to detect if a retract move was combined with the last
// print move due to min. steps per segment. Never execute this with advance! This assumes
@@ -1132,53 +1159,7 @@ Having the real displacement of the head, we can calculate the total movement le
block->acceleration_st = (block->acceleration_st + (bresenham_oversample >> 1)) / bresenham_oversample;
#endif
- block->acceleration_rate = (long)((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0)));
-
-#ifdef LIN_ADVANCE
- if (block->use_advance_lead) {
- // the nominal speed doesn't change past this point: calculate the compression ratio for the
- // segment and the required advance steps
- block->adv_comp = extruder_advance_K * e_D_ratio * cs.axis_steps_per_unit[E_AXIS];
- block->max_adv_steps = block->nominal_speed * block->adv_comp;
-
- float advance_speed;
- if (e_D_ratio > 0)
- advance_speed = (extruder_advance_K * e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]);
- else
- advance_speed = cs.max_jerk[E_AXIS] * cs.axis_steps_per_unit[E_AXIS];
-
- // to save more space we avoid another copy of calc_timer and go through slow division, but we
- // still need to replicate the *exact* same step grouping policy (see below)
- if (advance_speed > MAX_STEP_FREQUENCY) advance_speed = MAX_STEP_FREQUENCY;
- float advance_rate = (F_CPU / 8.0) / advance_speed;
- if (advance_speed > 20000) {
- block->advance_rate = advance_rate * 4;
- block->advance_step_loops = 4;
- }
- else if (advance_speed > 10000) {
- block->advance_rate = advance_rate * 2;
- block->advance_step_loops = 2;
- }
- else
- {
- // never overflow the internal accumulator with very low rates
- if (advance_rate < UINT16_MAX)
- block->advance_rate = advance_rate;
- else
- block->advance_rate = UINT16_MAX;
- block->advance_step_loops = 1;
- }
-
- #ifdef LA_DEBUG
- if (block->advance_step_loops > 2)
- // @wavexx: we should really check for the difference between step_loops and
- // advance_step_loops instead. A difference of more than 1 will lead
- // to uneven speed and *should* be adjusted here by furthermore
- // reducing the speed.
- SERIAL_ECHOLNPGM("LA: More than 2 steps per eISR loop executed.");
- #endif
- }
-#endif
+ block->acceleration_rate = ((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0)));
// Start with a safe speed.
// Safe speed is the speed, from which the machine may halt to stop immediately.
@@ -1305,6 +1286,53 @@ Having the real displacement of the head, we can calculate the total movement le
// Precalculate the division, so when all the trapezoids in the planner queue get recalculated, the division is not repeated.
block->speed_factor = block->nominal_rate / block->nominal_speed;
+
+#ifdef LIN_ADVANCE
+ if (block->use_advance_lead) {
+ // calculate the compression ratio for the segment (the required advance steps are computed
+ // during trapezoid planning)
+ float adv_comp = extruder_advance_K * e_D_ratio * cs.axis_steps_per_unit[E_AXIS]; // (step/(mm/s))
+ block->adv_comp = adv_comp / block->speed_factor; // step/(step/min)
+
+ float advance_speed;
+ if (e_D_ratio > 0)
+ advance_speed = (extruder_advance_K * e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]);
+ else
+ advance_speed = cs.max_jerk[E_AXIS] * cs.axis_steps_per_unit[E_AXIS];
+
+ // to save more space we avoid another copy of calc_timer and go through slow division, but we
+ // still need to replicate the *exact* same step grouping policy (see below)
+ if (advance_speed > MAX_STEP_FREQUENCY) advance_speed = MAX_STEP_FREQUENCY;
+ float advance_rate = (F_CPU / 8.0) / advance_speed;
+ if (advance_speed > 20000) {
+ block->advance_rate = advance_rate * 4;
+ block->advance_step_loops = 4;
+ }
+ else if (advance_speed > 10000) {
+ block->advance_rate = advance_rate * 2;
+ block->advance_step_loops = 2;
+ }
+ else
+ {
+ // never overflow the internal accumulator with very low rates
+ if (advance_rate < UINT16_MAX)
+ block->advance_rate = advance_rate;
+ else
+ block->advance_rate = UINT16_MAX;
+ block->advance_step_loops = 1;
+ }
+
+ #ifdef LA_DEBUG
+ if (block->advance_step_loops > 2)
+ // @wavexx: we should really check for the difference between step_loops and
+ // advance_step_loops instead. A difference of more than 1 will lead
+ // to uneven speed and *should* be adjusted here by furthermore
+ // reducing the speed.
+ SERIAL_ECHOLNPGM("LA: More than 2 steps per eISR loop executed.");
+ #endif
+ }
+#endif
+
calculate_trapezoid_for_block(block, block->entry_speed, safe_speed);
if (block->step_event_count.wide <= 32767)
diff --git a/Firmware/planner.h b/Firmware/planner.h
index 2096111e..34899cac 100644
--- a/Firmware/planner.h
+++ b/Firmware/planner.h
@@ -73,12 +73,12 @@ typedef struct {
// steps_x.y,z, step_event_count, acceleration_rate, direction_bits and active_extruder are set by plan_buffer_line().
dda_isteps_t steps_x, steps_y, steps_z, steps_e; // Step count along each axis
dda_usteps_t step_event_count; // The number of step events required to complete this block
- long acceleration_rate; // The acceleration rate used for acceleration calculation
+ uint32_t acceleration_rate; // The acceleration rate used for acceleration calculation
unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
unsigned char active_extruder; // Selects the active extruder
// accelerate_until and decelerate_after are set by calculate_trapezoid_for_block() and they need to be synchronized with the stepper interrupt controller.
- long accelerate_until; // The index of the step event on which to stop acceleration
- long decelerate_after; // The index of the step event on which to start decelerating
+ uint32_t accelerate_until; // The index of the step event on which to stop acceleration
+ uint32_t decelerate_after; // The index of the step event on which to start decelerating
// Fields used by the motion planner to manage acceleration
// float speed_x, speed_y, speed_z, speed_e; // Nominal mm/sec for each axis
@@ -100,13 +100,12 @@ typedef struct {
// Settings for the trapezoid generator (runs inside an interrupt handler).
// Changing the following values in the planner needs to be synchronized with the interrupt handler by disabling the interrupts.
- //FIXME nominal_rate, initial_rate and final_rate are limited to uint16_t by MultiU24X24toH16 in the stepper interrupt anyway!
unsigned long nominal_rate; // The nominal step rate for this block in step_events/sec
unsigned long initial_rate; // The jerk-adjusted step rate at start of block
unsigned long final_rate; // The minimal rate at exit
unsigned long acceleration_st; // acceleration steps/sec^2
- //FIXME does it have to be unsigned long? Probably uint8_t would be just fine.
- unsigned long fan_speed;
+ //FIXME does it have to be int? Probably uint8_t would be just fine. Need to change in other places as well
+ int fan_speed;
volatile char busy;
diff --git a/Firmware/speed_lookuptable.h b/Firmware/speed_lookuptable.h
index 2748dd71..21c6c767 100644
--- a/Firmware/speed_lookuptable.h
+++ b/Firmware/speed_lookuptable.h
@@ -80,15 +80,21 @@ asm volatile ( \
#else //_NO_ASM
-// NOTE: currently not implemented
-void MultiU16X8toH16(unsigned short& intRes, unsigned char& charIn1, unsigned short& intIn2);
-void MultiU24X24toH16(uint16_t& intRes, int32_t& longIn1, long& longIn2);
+static inline void MultiU16X8toH16(uint16_t& intRes, uint8_t& charIn1, uint16_t& intIn2)
+{
+ intRes = ((uint32_t)charIn1 * (uint32_t)intIn2) >> 16;
+}
+
+static inline void MultiU24X24toH16(uint16_t& intRes, uint32_t& longIn1, uint32_t& longIn2)
+{
+ intRes = ((uint64_t)longIn1 * (uint64_t)longIn2) >> 24;
+}
#endif //_NO_ASM
FORCE_INLINE unsigned short calc_timer(uint16_t step_rate, uint8_t& step_loops) {
- unsigned short timer;
+ uint16_t timer;
if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY;
if(step_rate > 20000) { // If steprate > 20kHz >> step 4 times
@@ -108,7 +114,7 @@ FORCE_INLINE unsigned short calc_timer(uint16_t step_rate, uint8_t& step_loops)
if(step_rate >= (8*256)){ // higher step rate
unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0];
unsigned char tmp_step_rate = (step_rate & 0x00ff);
- unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2);
+ uint16_t gain = (uint16_t)pgm_read_word_near(table_address+2);
MultiU16X8toH16(timer, tmp_step_rate, gain);
timer = (unsigned short)pgm_read_word_near(table_address) - timer;
}
diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp
index de250ec9..7c44d791 100644
--- a/Firmware/stepper.cpp
+++ b/Firmware/stepper.cpp
@@ -71,8 +71,7 @@ static dda_isteps_t
counter_z,
counter_e;
volatile dda_usteps_t step_events_completed; // The number of step events executed in the current block
-static int32_t acceleration_time, deceleration_time;
-//static unsigned long accelerate_until, decelerate_after, acceleration_rate, initial_rate, final_rate, nominal_rate;
+static uint32_t acceleration_time, deceleration_time;
static uint16_t acc_step_rate; // needed for deccelaration start point
static uint8_t step_loops;
static uint16_t OCR1A_nominal;
@@ -125,7 +124,7 @@ volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1};
static uint16_t main_Rate;
static uint16_t eISR_Rate;
- static uint16_t eISR_Err;
+ static uint32_t eISR_Err;
static uint16_t current_adv_steps;
static uint16_t target_adv_steps;
@@ -234,7 +233,7 @@ void invert_z_endstop(bool endstop_invert)
// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates
// first block->accelerate_until step_events_completed, then keeps going at constant speed until
// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset.
-// The slope of acceleration is calculated with the leib ramp alghorithm.
+// The slope of acceleration is calculated using v = u + at where t is the accumulated timer values of the steps so far.
// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse.
// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately.
@@ -348,10 +347,7 @@ FORCE_INLINE void stepper_next_block()
#ifdef LIN_ADVANCE
if (current_block->use_advance_lead) {
- e_step_loops = current_block->advance_step_loops;
target_adv_steps = current_block->max_adv_steps;
- } else {
- e_step_loops = 1;
}
e_steps = 0;
nextAdvanceISR = ADV_NEVER;
@@ -736,38 +732,30 @@ FORCE_INLINE uint16_t fastdiv(uint16_t q, uint8_t d)
FORCE_INLINE void advance_spread(uint16_t timer)
{
- if(eISR_Err > timer)
+ eISR_Err += timer;
+
+ uint8_t ticks = 0;
+ while(eISR_Err >= current_block->advance_rate)
+ {
+ ++ticks;
+ eISR_Err -= current_block->advance_rate;
+ }
+ if(!ticks)
{
- // advance-step skipped
- eISR_Err -= timer;
eISR_Rate = timer;
nextAdvanceISR = timer;
return;
}
- // at least one step
- uint8_t ticks = 1;
- uint32_t block = current_block->advance_rate;
- uint16_t max_t = timer - eISR_Err;
- while (block < max_t)
- {
- ++ticks;
- block += current_block->advance_rate;
- }
- if (block > timer)
- eISR_Err += block - timer;
- else
- eISR_Err -= timer - block;
-
- if (ticks <= 4)
- eISR_Rate = fastdiv(timer, ticks);
+ if (ticks <= 3)
+ eISR_Rate = fastdiv(timer, ticks + 1);
else
{
// >4 ticks are still possible on slow moves
- eISR_Rate = timer / ticks;
+ eISR_Rate = timer / (ticks + 1);
}
- nextAdvanceISR = eISR_Rate / 2;
+ nextAdvanceISR = eISR_Rate;
}
#endif
@@ -799,7 +787,7 @@ FORCE_INLINE void isr() {
// 25.12us for acceleration / deceleration.
{
//WRITE_NC(LOGIC_ANALYZER_CH1, true);
- if (step_events_completed.wide <= (unsigned long int)current_block->accelerate_until) {
+ if (step_events_completed.wide <= current_block->accelerate_until) {
// v = t * a -> acc_step_rate = acceleration_time * current_block->acceleration_rate
MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate);
acc_step_rate += uint16_t(current_block->initial_rate);
@@ -812,19 +800,29 @@ FORCE_INLINE void isr() {
acceleration_time += timer;
#ifdef LIN_ADVANCE
if (current_block->use_advance_lead) {
- if (step_events_completed.wide <= (unsigned long int)step_loops)
+ if (step_events_completed.wide <= (unsigned long int)step_loops) {
la_state = ADV_INIT | ADV_ACC_VARY;
+ if (e_extruding && current_adv_steps > target_adv_steps)
+ target_adv_steps = current_adv_steps;
+ }
}
#endif
}
- else if (step_events_completed.wide > (unsigned long int)current_block->decelerate_after) {
+ else if (step_events_completed.wide > current_block->decelerate_after) {
uint16_t step_rate;
MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate);
- step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point.
- if ((step_rate & 0x8000) || step_rate < uint16_t(current_block->final_rate)) {
- // Result is negative or too small.
- step_rate = uint16_t(current_block->final_rate);
+
+ if (step_rate > acc_step_rate) { // Check step_rate stays positive
+ step_rate = uint16_t(current_block->final_rate);
}
+ else {
+ step_rate = acc_step_rate - step_rate; // Decelerate from acceleration end point.
+
+ // lower limit
+ if (step_rate < current_block->final_rate)
+ step_rate = uint16_t(current_block->final_rate);
+ }
+
// Step_rate to timer interval.
uint16_t timer = calc_timer(step_rate, step_loops);
_NEXT_ISR(timer);
@@ -832,9 +830,11 @@ FORCE_INLINE void isr() {
#ifdef LIN_ADVANCE
if (current_block->use_advance_lead) {
- if (step_events_completed.wide <= (unsigned long int)current_block->decelerate_after + step_loops) {
+ if (step_events_completed.wide <= current_block->decelerate_after + step_loops) {
target_adv_steps = current_block->final_adv_steps;
la_state = ADV_INIT | ADV_ACC_VARY;
+ if (e_extruding && current_adv_steps < target_adv_steps)
+ target_adv_steps = current_adv_steps;
}
}
#endif
@@ -848,12 +848,12 @@ FORCE_INLINE void isr() {
#ifdef LIN_ADVANCE
if(current_block->use_advance_lead) {
- if (!nextAdvanceISR) {
- // Due to E-jerk, there can be discontinuities in pressure state where an
- // acceleration or deceleration can be skipped or joined with the previous block.
- // If LA was not previously active, re-check the pressure level
- la_state = ADV_INIT;
- }
+ // Due to E-jerk, there can be discontinuities in pressure state where an
+ // acceleration or deceleration can be skipped or joined with the previous block.
+ // If LA was not previously active, re-check the pressure level
+ la_state = ADV_INIT;
+ if (e_extruding)
+ target_adv_steps = current_adv_steps;
}
#endif
}
@@ -865,14 +865,21 @@ FORCE_INLINE void isr() {
#ifdef LIN_ADVANCE
// avoid multiple instances or function calls to advance_spread
if (la_state & ADV_INIT) {
+ LA_phase = -1;
+
if (current_adv_steps == target_adv_steps) {
- // nothing to be done in this phase
+ // nothing to be done in this phase, cancel any pending eisr
la_state = 0;
+ nextAdvanceISR = ADV_NEVER;
}
else {
- eISR_Err = current_block->advance_rate / 4;
+ // reset error and iterations per loop for this phase
+ eISR_Err = current_block->advance_rate;
+ e_step_loops = current_block->advance_step_loops;
+
if ((la_state & ADV_ACC_VARY) && e_extruding && (current_adv_steps > target_adv_steps)) {
// LA could reverse the direction of extrusion in this phase
+ eISR_Err += current_block->advance_rate;
LA_phase = 0;
}
}
@@ -882,11 +889,13 @@ FORCE_INLINE void isr() {
advance_spread(main_Rate);
if (LA_phase >= 0) {
if (step_loops == e_step_loops)
- LA_phase = (eISR_Rate > main_Rate);
+ LA_phase = (current_block->advance_rate < main_Rate);
else {
// avoid overflow through division. warning: we need to _guarantee_ step_loops
// and e_step_loops are <= 4 due to fastdiv's limit
- LA_phase = (fastdiv(eISR_Rate, step_loops) > fastdiv(main_Rate, e_step_loops));
+ auto adv_rate_n = fastdiv(current_block->advance_rate, step_loops);
+ auto main_rate_n = fastdiv(main_Rate, e_step_loops);
+ LA_phase = (adv_rate_n < main_rate_n);
}
}
}
@@ -928,26 +937,34 @@ FORCE_INLINE void isr() {
FORCE_INLINE void advance_isr() {
if (current_adv_steps > target_adv_steps) {
// decompression
+ if (e_step_loops != 1) {
+ uint16_t d_steps = current_adv_steps - target_adv_steps;
+ if (d_steps < e_step_loops)
+ e_step_loops = d_steps;
+ }
e_steps -= e_step_loops;
if (e_steps) WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR);
- if(current_adv_steps > e_step_loops)
- current_adv_steps -= e_step_loops;
- else
- current_adv_steps = 0;
- nextAdvanceISR = eISR_Rate;
+ current_adv_steps -= e_step_loops;
}
else if (current_adv_steps < target_adv_steps) {
// compression
+ if (e_step_loops != 1) {
+ uint16_t d_steps = target_adv_steps - current_adv_steps;
+ if (d_steps < e_step_loops)
+ e_step_loops = d_steps;
+ }
e_steps += e_step_loops;
if (e_steps) WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR);
current_adv_steps += e_step_loops;
- nextAdvanceISR = eISR_Rate;
}
- else {
+
+ if (current_adv_steps == target_adv_steps) {
// advance steps completed
nextAdvanceISR = ADV_NEVER;
- LA_phase = -1;
- e_step_loops = 1;
+ }
+ else {
+ // schedule another tick
+ nextAdvanceISR = eISR_Rate;
}
}
@@ -1017,7 +1034,7 @@ FORCE_INLINE void advance_isr_scheduler() {
// Schedule the next closest tick, ignoring advance if scheduled too
// soon in order to avoid skewing the regular stepper acceleration
- if (nextAdvanceISR != ADV_NEVER && (nextAdvanceISR + TCNT1 + 40) < nextMainISR)
+ if (nextAdvanceISR != ADV_NEVER && (nextAdvanceISR + 40) < nextMainISR)
OCR1A = nextAdvanceISR;
else
OCR1A = nextMainISR;
diff --git a/Firmware/temperature.cpp b/Firmware/temperature.cpp
index 6e9b6985..cb4fc8ae 100755
--- a/Firmware/temperature.cpp
+++ b/Firmware/temperature.cpp
@@ -152,7 +152,11 @@ uint8_t fanSpeedBckp = 255;
bool fan_measuring = false;
uint8_t fanState = 0;
#ifdef EXTRUDER_ALTFAN_DETECT
- bool extruderFanIsAltfan = false; //set to Noctua
+ struct
+ {
+ uint8_t isAltfan : 1;
+ uint8_t altfanOverride : 1;
+ } altfanStatus;
#endif //EXTRUDER_ALTFAN_DETECT
#endif
@@ -180,6 +184,12 @@ static int bed_minttemp_raw = HEATER_BED_RAW_LO_TEMP;
#ifdef BED_MAXTEMP
static int bed_maxttemp_raw = HEATER_BED_RAW_HI_TEMP;
#endif
+#ifdef AMBIENT_MINTEMP
+static int ambient_minttemp_raw = AMBIENT_RAW_LO_TEMP;
+#endif
+#ifdef AMBIENT_MAXTEMP
+static int ambient_maxttemp_raw = AMBIENT_RAW_HI_TEMP;
+#endif
static void *heater_ttbl_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( (void *)HEATER_0_TEMPTABLE, (void *)HEATER_1_TEMPTABLE, (void *)HEATER_2_TEMPTABLE );
static uint8_t heater_ttbllen_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN, HEATER_2_TEMPTABLE_LEN );
@@ -224,6 +234,15 @@ 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);
@@ -237,10 +256,22 @@ bool extruder_altfan_detect()
EIMSK &= ~(1 << INT6);
countFanSpeed();
- extruderFanIsAltfan = fan_speed[0] > 100;
+ altfanStatus.isAltfan = fan_speed[0] > 100;
setExtruderAutoFanState(1);
- return extruderFanIsAltfan;
+ 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
// return "false", if all extruder-heaters are 'off' (ie. "true", if any heater is 'on')
@@ -494,7 +525,7 @@ void setExtruderAutoFanState(uint8_t state)
if (fanState & 0x01)
{
#ifdef EXTRUDER_ALTFAN_DETECT
- if (extruderFanIsAltfan) newFanSpeed = EXTRUDER_ALTFAN_SPEED_SILENT;
+ 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;
@@ -639,6 +670,7 @@ void manage_heater()
return;
// more precisely - this condition partially stabilizes time interval for regulation values evaluation (@ ~ 230ms)
+ // ADC values need to be converted before checking: converted values are later used in MINTEMP
updateTemperaturesFromRawValues();
check_max_temp();
@@ -1165,7 +1197,6 @@ void tp_init()
#endif //MAXTEMP 2
#ifdef BED_MINTEMP
- /* No bed MINTEMP error implemented?!? */
while(analog2tempBed(bed_minttemp_raw) < BED_MINTEMP) {
#if HEATER_BED_RAW_LO_TEMP < HEATER_BED_RAW_HI_TEMP
bed_minttemp_raw += OVERSAMPLENR;
@@ -1173,7 +1204,6 @@ void tp_init()
bed_minttemp_raw -= OVERSAMPLENR;
#endif
}
-
#endif //BED_MINTEMP
#ifdef BED_MAXTEMP
while(analog2tempBed(bed_maxttemp_raw) > BED_MAXTEMP) {
@@ -1184,6 +1214,25 @@ void tp_init()
#endif
}
#endif //BED_MAXTEMP
+
+#ifdef AMBIENT_MINTEMP
+ while(analog2tempAmbient(ambient_minttemp_raw) < AMBIENT_MINTEMP) {
+#if HEATER_AMBIENT_RAW_LO_TEMP < HEATER_AMBIENT_RAW_HI_TEMP
+ ambient_minttemp_raw += OVERSAMPLENR;
+#else
+ ambient_minttemp_raw -= OVERSAMPLENR;
+#endif
+ }
+#endif //AMBIENT_MINTEMP
+#ifdef AMBIENT_MAXTEMP
+ while(analog2tempAmbient(ambient_maxttemp_raw) > AMBIENT_MAXTEMP) {
+#if HEATER_AMBIENT_RAW_LO_TEMP < HEATER_AMBIENT_RAW_HI_TEMP
+ ambient_maxttemp_raw -= OVERSAMPLENR;
+#else
+ ambient_maxttemp_raw += OVERSAMPLENR;
+#endif
+ }
+#endif //AMBIENT_MAXTEMP
}
#if (defined (TEMP_RUNAWAY_BED_HYSTERESIS) && TEMP_RUNAWAY_BED_TIMEOUT > 0) || (defined (TEMP_RUNAWAY_EXTRUDER_HYSTERESIS) && TEMP_RUNAWAY_EXTRUDER_TIMEOUT > 0)
@@ -1356,7 +1405,7 @@ void temp_runaway_stop(bool isPreheat, bool isBed)
SERIAL_ERROR_START;
isBed ? SERIAL_ERRORLNPGM(" THERMAL RUNAWAY ( PREHEAT HEATBED)") : SERIAL_ERRORLNPGM(" THERMAL RUNAWAY ( PREHEAT HOTEND)");
#ifdef EXTRUDER_ALTFAN_DETECT
- extruderFanIsAltfan = false; //full speed
+ altfanStatus.altfanOverride = 1; //full speed
#endif //EXTRUDER_ALTFAN_DETECT
setExtruderAutoFanState(3);
SET_OUTPUT(FAN_PIN);
@@ -1427,26 +1476,53 @@ enum { LCDALERT_NONE = 0, LCDALERT_HEATERMINTEMP, LCDALERT_BEDMINTEMP, LCDALERT_
//! to prevent flicker and improve speed
uint8_t last_alert_sent_to_lcd = LCDALERT_NONE;
+
+//! update the current temperature error message
+//! @param type short error abbreviation (PROGMEM)
+//! @param func optional lcd update function (lcd_setalertstatus when first setting the error)
+void temp_update_messagepgm(const char* PROGMEM type, void (*func)(const char*) = lcd_updatestatus)
+{
+ char msg[LCD_WIDTH];
+ strcpy_P(msg, PSTR("Err: "));
+ strcat_P(msg, type);
+ (*func)(msg);
+}
+
+//! signal a temperature error on both the lcd and serial
+//! @param type short error abbreviation (PROGMEM)
+//! @param e optional extruder index for hotend errors
+void temp_error_messagepgm(const char* PROGMEM type, uint8_t e = EXTRUDERS)
+{
+ temp_update_messagepgm(type, lcd_setalertstatus);
+
+ SERIAL_ERROR_START;
+
+ if(e != EXTRUDERS) {
+ SERIAL_ERROR((int)e);
+ SERIAL_ERRORPGM(": ");
+ }
+
+ SERIAL_ERRORPGM("Heaters switched off. ");
+ SERIAL_ERRORRPGM(type);
+ SERIAL_ERRORLNPGM(" triggered!");
+}
+
+
void max_temp_error(uint8_t e) {
disable_heater();
if(IsStopped() == false) {
- SERIAL_ERROR_START;
- SERIAL_ERRORLN((int)e);
- SERIAL_ERRORLNPGM(": Extruder switched off. MAXTEMP triggered !");
- LCD_ALERTMESSAGEPGM("Err: MAXTEMP");
+ temp_error_messagepgm(PSTR("MAXTEMP"), e);
}
#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
Stop();
-
-
-
#endif
+
SET_OUTPUT(FAN_PIN);
SET_OUTPUT(BEEPER);
WRITE(FAN_PIN, 1);
WRITE(BEEPER, 1);
#ifdef EXTRUDER_ALTFAN_DETECT
- extruderFanIsAltfan = false; //full speed
+ altfanStatus.altfanOverride = 1; //full speed
#endif //EXTRUDER_ALTFAN_DETECT
setExtruderAutoFanState(3);
// fanSpeed will consumed by the check_axes_activity() routine.
@@ -1458,18 +1534,15 @@ void min_temp_error(uint8_t e) {
#ifdef DEBUG_DISABLE_MINTEMP
return;
#endif
-//if (current_temperature_ambient < MINTEMP_MINAMBIENT) return;
disable_heater();
- static const char err[] PROGMEM = "Err: MINTEMP";
+//if (current_temperature_ambient < MINTEMP_MINAMBIENT) return;
+ static const char err[] PROGMEM = "MINTEMP";
if(IsStopped() == false) {
- SERIAL_ERROR_START;
- SERIAL_ERRORLN((int)e);
- SERIAL_ERRORLNPGM(": Extruder switched off. MINTEMP triggered !");
- lcd_setalertstatuspgm(err);
+ temp_error_messagepgm(err, e);
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);
+ temp_update_messagepgm(err);
last_alert_sent_to_lcd = LCDALERT_HEATERMINTEMP;
}
#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
@@ -1484,37 +1557,27 @@ void min_temp_error(uint8_t e) {
}
void bed_max_temp_error(void) {
-#if HEATER_BED_PIN > -1
- //WRITE(HEATER_BED_PIN, 0);
-#endif
+ disable_heater();
if(IsStopped() == false) {
- SERIAL_ERROR_START;
- SERIAL_ERRORLNPGM("Temperature heated bed switched off. MAXTEMP triggered !");
- LCD_ALERTMESSAGEPGM("Err: MAXTEMP BED");
+ temp_error_messagepgm(PSTR("MAXTEMP BED"));
}
#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
Stop();
#endif
-
}
void bed_min_temp_error(void) {
#ifdef DEBUG_DISABLE_MINTEMP
return;
#endif
-//if (current_temperature_ambient < MINTEMP_MINAMBIENT) return;
-#if HEATER_BED_PIN > -1
- //WRITE(HEATER_BED_PIN, 0);
-#endif
- static const char err[] PROGMEM = "Err: MINTEMP BED";
+ disable_heater();
+ static const char err[] PROGMEM = "MINTEMP BED";
if(IsStopped() == false) {
- SERIAL_ERROR_START;
- SERIAL_ERRORLNPGM("Temperature heated bed switched off. MINTEMP triggered !");
- lcd_setalertstatuspgm(err);
+ temp_error_messagepgm(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);
+ temp_update_messagepgm(err);
last_alert_sent_to_lcd = LCDALERT_BEDMINTEMP;
}
#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
@@ -1522,6 +1585,33 @@ void bed_min_temp_error(void) {
#endif
}
+
+#ifdef AMBIENT_THERMISTOR
+void ambient_max_temp_error(void) {
+ disable_heater();
+ if(IsStopped() == false) {
+ temp_error_messagepgm(PSTR("MAXTEMP AMB"));
+ }
+#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
+ Stop();
+#endif
+}
+
+void ambient_min_temp_error(void) {
+#ifdef DEBUG_DISABLE_MINTEMP
+ return;
+#endif
+ disable_heater();
+ if(IsStopped() == false) {
+ temp_error_messagepgm(PSTR("MINTEMP AMB"));
+ }
+#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
+ Stop();
+#endif
+}
+#endif
+
+
#ifdef HEATER_0_USES_MAX6675
#define MAX6675_HEAT_INTERVAL 250
long max6675_previous_millis = MAX6675_HEAT_INTERVAL;
@@ -1606,18 +1696,8 @@ void adc_ready(void) //callback from adc when sampling finished
} // extern "C"
-// Timer2 (originaly timer0) is shared with millies
-#ifdef SYSTEM_TIMER_2
-ISR(TIMER2_COMPB_vect)
-#else //SYSTEM_TIMER_2
-ISR(TIMER0_COMPB_vect)
-#endif //SYSTEM_TIMER_2
+FORCE_INLINE static void temperature_isr()
{
- static bool _lock = false;
- if (_lock) return;
- _lock = true;
- asm("sei");
-
if (!temp_meas_ready) adc_cycle();
lcd_buttons_update();
@@ -1983,8 +2063,24 @@ ISR(TIMER0_COMPB_vect)
#if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1))
check_fans();
#endif //(defined(TACH_0))
+}
- _lock = false;
+// Timer2 (originaly timer0) is shared with millies
+#ifdef SYSTEM_TIMER_2
+ISR(TIMER2_COMPB_vect)
+#else //SYSTEM_TIMER_2
+ISR(TIMER0_COMPB_vect)
+#endif //SYSTEM_TIMER_2
+{
+ static bool _lock = false;
+ if (!_lock)
+ {
+ _lock = true;
+ sei();
+ temperature_isr();
+ cli();
+ _lock = false;
+ }
}
void check_max_temp()
@@ -2004,11 +2100,19 @@ void check_max_temp()
#else
if (current_temperature_bed_raw >= bed_maxttemp_raw) {
#endif
- target_temperature_bed = 0;
bed_max_temp_error();
}
#endif
-
+//ambient
+#if defined(AMBIENT_MAXTEMP) && (TEMP_SENSOR_AMBIENT != 0)
+#if AMBIENT_RAW_LO_TEMP > AMBIENT_RAW_HI_TEMP
+ if (current_temperature_raw_ambient <= ambient_maxttemp_raw) {
+#else
+ if (current_temperature_raw_ambient >= ambient_maxttemp_raw) {
+#endif
+ ambient_max_temp_error();
+ }
+#endif
}
//! number of repeating the same state with consecutive step() calls
//! used to slow down text switching
@@ -2103,12 +2207,32 @@ void check_min_temp_bed()
}
}
+#ifdef AMBIENT_MINTEMP
+void check_min_temp_ambient()
+{
+#if AMBIENT_RAW_LO_TEMP > AMBIENT_RAW_HI_TEMP
+ if (current_temperature_raw_ambient >= ambient_minttemp_raw) {
+#else
+ if (current_temperature_raw_ambient <= ambient_minttemp_raw) {
+#endif
+ ambient_min_temp_error();
+ }
+}
+#endif
+
void check_min_temp()
{
static bool bCheckingOnHeater=false; // state variable, which allows to short no-checking delay (is set, when temperature is (first time) over heaterMintemp)
static bool bCheckingOnBed=false; // state variable, which allows to short no-checking delay (is set, when temperature is (first time) over bedMintemp)
#ifdef AMBIENT_THERMISTOR
-if(current_temperature_raw_ambient>(OVERSAMPLENR*MINTEMP_MINAMBIENT_RAW)) // thermistor is NTC type, so operator is ">" ;-)
+#ifdef AMBIENT_MINTEMP
+check_min_temp_ambient();
+#endif
+#if AMBIENT_RAW_LO_TEMP > AMBIENT_RAW_HI_TEMP
+if(current_temperature_raw_ambient>(OVERSAMPLENR*MINTEMP_MINAMBIENT_RAW)) // thermistor is NTC type
+#else
+if(current_temperature_raw_ambient=<(OVERSAMPLENR*MINTEMP_MINAMBIENT_RAW))
+#endif
{ // ambient temperature is low
#endif //AMBIENT_THERMISTOR
// *** 'common' part of code for MK2.5 & MK3
diff --git a/Firmware/temperature.h b/Firmware/temperature.h
index 32ff6961..da88a53c 100755
--- a/Firmware/temperature.h
+++ b/Firmware/temperature.h
@@ -273,6 +273,8 @@ 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;
diff --git a/Firmware/thermistortables.h b/Firmware/thermistortables.h
index dc934ccf..721c6b35 100644
--- a/Firmware/thermistortables.h
+++ b/Firmware/thermistortables.h
@@ -1213,6 +1213,8 @@ const short temptable_1047[][2] PROGMEM = {
#endif
#if (THERMISTORAMBIENT == 2000) //100k thermistor NTCG104LH104JT1
+# define AMBIENT_RAW_HI_TEMP 0
+# define AMBIENT_RAW_LO_TEMP 16383
const short temptable_2000[][2] PROGMEM = {
// Source: https://product.tdk.com/info/en/catalog/datasheets/503021/tpd_ntc-thermistor_ntcg_en.pdf
// Calculated using 4.7kohm pullup, voltage divider math, and manufacturer provided temp/resistance
diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp
index 87266914..6f82db04 100755
--- a/Firmware/ultralcd.cpp
+++ b/Firmware/ultralcd.cpp
@@ -1001,6 +1001,36 @@ void lcd_status_screen() // NOT static due to using ins
}
}
+#ifdef ULTIPANEL_FEEDMULTIPLY
+ // Dead zone at 100% feedrate
+ if ((feedmultiply < 100 && (feedmultiply + int(lcd_encoder)) > 100) ||
+ (feedmultiply > 100 && (feedmultiply + int(lcd_encoder)) < 100))
+ {
+ lcd_encoder = 0;
+ feedmultiply = 100;
+ }
+ if (feedmultiply == 100 && int(lcd_encoder) > ENCODER_FEEDRATE_DEADZONE)
+ {
+ feedmultiply += int(lcd_encoder) - ENCODER_FEEDRATE_DEADZONE;
+ lcd_encoder = 0;
+ }
+ else if (feedmultiply == 100 && int(lcd_encoder) < -ENCODER_FEEDRATE_DEADZONE)
+ {
+ feedmultiply += int(lcd_encoder) + ENCODER_FEEDRATE_DEADZONE;
+ lcd_encoder = 0;
+ }
+ else if (feedmultiply != 100)
+ {
+ feedmultiply += int(lcd_encoder);
+ lcd_encoder = 0;
+ }
+#endif //ULTIPANEL_FEEDMULTIPLY
+
+ if (feedmultiply < 10)
+ feedmultiply = 10;
+ else if (feedmultiply > 999)
+ feedmultiply = 999;
+
if (lcd_status_update_delay)
lcd_status_update_delay--;
else
@@ -1077,36 +1107,6 @@ void lcd_status_screen() // NOT static due to using ins
menu_submenu(lcd_main_menu);
lcd_refresh(); // to maybe revive the LCD if static electricity killed it.
}
-
-#ifdef ULTIPANEL_FEEDMULTIPLY
- // Dead zone at 100% feedrate
- if ((feedmultiply < 100 && (feedmultiply + int(lcd_encoder)) > 100) ||
- (feedmultiply > 100 && (feedmultiply + int(lcd_encoder)) < 100))
- {
- lcd_encoder = 0;
- feedmultiply = 100;
- }
- if (feedmultiply == 100 && int(lcd_encoder) > ENCODER_FEEDRATE_DEADZONE)
- {
- feedmultiply += int(lcd_encoder) - ENCODER_FEEDRATE_DEADZONE;
- lcd_encoder = 0;
- }
- else if (feedmultiply == 100 && int(lcd_encoder) < -ENCODER_FEEDRATE_DEADZONE)
- {
- feedmultiply += int(lcd_encoder) + ENCODER_FEEDRATE_DEADZONE;
- lcd_encoder = 0;
- }
- else if (feedmultiply != 100)
- {
- feedmultiply += int(lcd_encoder);
- lcd_encoder = 0;
- }
-#endif //ULTIPANEL_FEEDMULTIPLY
-
- if (feedmultiply < 10)
- feedmultiply = 10;
- else if (feedmultiply > 999)
- feedmultiply = 999;
}
void lcd_commands()
@@ -2126,6 +2126,7 @@ static void lcd_support_menu()
sprintf_P(_md->ip_str, PSTR("%d.%d.%d.%d"),
_md->ip[0], _md->ip[1],
_md->ip[2], _md->ip[3]);
+
} else if (_md->is_flash_air &&
_md->ip[0] == 0 && _md->ip[1] == 0 &&
_md->ip[2] == 0 && _md->ip[3] == 0 &&
@@ -2210,6 +2211,7 @@ static void lcd_support_menu()
MENU_ITEM_SUBMENU_P(_i("Voltages"), lcd_menu_voltages);////MSG_MENU_VOLTAGES c=18 r=1
#endif //defined VOLT_BED_PIN || defined VOLT_PWR_PIN
+
#ifdef DEBUG_BUILD
MENU_ITEM_SUBMENU_P(PSTR("Debug"), lcd_menu_debug);////c=18 r=1
#endif /* DEBUG_BUILD */
@@ -5712,6 +5714,25 @@ static void sheets_menu()
void lcd_hw_setup_menu(void) // can not be "static"
{
+ typedef struct
+ {// 2bytes total
+ int8_t status;
+ uint8_t experimental_menu_visibility;
+ } _menu_data_t;
+ static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data");
+ _menu_data_t* _md = (_menu_data_t*)&(menu_data[0]);
+
+ if (_md->status == 0 || lcd_draw_update)
+ {
+ _md->experimental_menu_visibility = eeprom_read_byte((uint8_t *)EEPROM_EXPERIMENTAL_VISIBILITY);
+ if (_md->experimental_menu_visibility == EEPROM_EMPTY_VALUE)
+ {
+ _md->experimental_menu_visibility = 0;
+ eeprom_update_byte((uint8_t *)EEPROM_EXPERIMENTAL_VISIBILITY, _md->experimental_menu_visibility);
+ }
+ }
+
+
MENU_BEGIN();
MENU_ITEM_BACK_P(_T(bSettings?MSG_SETTINGS:MSG_BACK)); // i.e. default menu-item / menu-item after checking mismatch
@@ -5725,6 +5746,12 @@ void lcd_hw_setup_menu(void) // can not be "static"
//! @todo Don't forget to remove this as soon Fsensor Detection works with mmu
if(!mmu_enabled) MENU_ITEM_FUNCTION_P(PSTR("Fsensor Detection"), lcd_detect_IRsensor);
#endif //IR_SENSOR_ANALOG
+
+ if (_md->experimental_menu_visibility)
+ {
+ MENU_ITEM_SUBMENU_P(PSTR("Experimental"), lcd_experimental_menu);////MSG_MENU_EXPERIMENTAL c=18
+ }
+
MENU_END();
}
@@ -8951,13 +8978,14 @@ void lcd_finishstatus() {
lcd_draw_update = 2;
}
+
void lcd_setstatus(const char* message)
{
if (lcd_status_message_level > 0)
return;
- strncpy(lcd_status_message, message, LCD_WIDTH);
- lcd_finishstatus();
+ lcd_updatestatus(message);
}
+
void lcd_updatestatuspgm(const char *message){
strncpy_P(lcd_status_message, message, LCD_WIDTH);
lcd_status_message[LCD_WIDTH] = 0;
@@ -8972,12 +9000,29 @@ void lcd_setstatuspgm(const char* message)
return;
lcd_updatestatuspgm(message);
}
+
+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)
{
lcd_setstatuspgm(message);
lcd_status_message_level = 1;
lcd_return_to_status();
}
+
+void lcd_setalertstatus(const char* message)
+{
+ lcd_setstatus(message);
+ lcd_status_message_level = 1;
+ lcd_return_to_status();
+}
+
void lcd_reset_alert_level()
{
lcd_status_message_level = 0;
@@ -8997,6 +9042,13 @@ void menu_lcd_longpress_func(void)
lcd_quick_feedback();
return;
}
+ if (menu_menu == lcd_hw_setup_menu)
+ {
+ // only toggle the experimental menu visibility flag
+ lcd_quick_feedback();
+ lcd_experimental_toggle();
+ return;
+ }
// explicitely listed menus which are allowed to rise the move-z or live-adj-z functions
// The lists are not the same for both functions, so first decide which function is to be performed
@@ -9160,3 +9212,25 @@ void lcd_crash_detect_disable()
eeprom_update_byte((uint8_t*)EEPROM_CRASH_DET, 0x00);
}
#endif
+
+void lcd_experimental_toggle()
+{
+ uint8_t oldVal = eeprom_read_byte((uint8_t *)EEPROM_EXPERIMENTAL_VISIBILITY);
+ if (oldVal == EEPROM_EMPTY_VALUE)
+ oldVal = 0;
+ else
+ oldVal = !oldVal;
+ eeprom_update_byte((uint8_t *)EEPROM_EXPERIMENTAL_VISIBILITY, oldVal);
+}
+
+void lcd_experimental_menu()
+{
+ MENU_BEGIN();
+ MENU_ITEM_BACK_P(_T(MSG_BACK));
+
+#ifdef EXTRUDER_ALTFAN_DETECT
+ MENU_ITEM_TOGGLE_P(_N("ALTFAN det."), altfanOverride_get()?_T(MSG_OFF):_T(MSG_ON), altfanOverride_toggle);////MSG_MENU_ALTFAN c=18
+#endif //EXTRUDER_ALTFAN_DETECT
+
+ MENU_END();
+}
diff --git a/Firmware/ultralcd.h b/Firmware/ultralcd.h
index 844c7c7d..7c361332 100755
--- a/Firmware/ultralcd.h
+++ b/Firmware/ultralcd.h
@@ -23,9 +23,11 @@ void lcd_setstatuspgm(const char* message);
//! - 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_setalertstatus(const char* message);
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_updatestatus(const char *message);
void lcd_updatestatuspgm(const char *message);
void lcd_reset_alert_level();
@@ -257,4 +259,7 @@ enum class WizState : uint8_t
void lcd_wizard(WizState state);
+extern void lcd_experimental_toggle();
+extern void lcd_experimental_menu();
+
#endif //ULTRALCD_H
diff --git a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h
index b135d8d1..04b4c526 100644
--- a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h
+++ b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h
@@ -296,6 +296,7 @@
#endif
#define DETECT_SUPERPINDA
#define PINDA_MINTEMP BED_MINTEMP
+#define AMBIENT_MINTEMP -30
// Maxtemps
#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)
@@ -306,6 +307,7 @@
#define HEATER_1_MAXTEMP 305
#define HEATER_2_MAXTEMP 305
#define BED_MAXTEMP 125
+#define AMBIENT_MAXTEMP 100
#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)
// Define PID constants for extruder with PT100
diff --git a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h
index e618c54e..c869ec51 100644
--- a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h
+++ b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h
@@ -298,6 +298,7 @@
#endif
#define DETECT_SUPERPINDA
#define PINDA_MINTEMP BED_MINTEMP
+#define AMBIENT_MINTEMP -30
// Maxtemps
#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)
@@ -308,6 +309,7 @@
#define HEATER_1_MAXTEMP 305
#define HEATER_2_MAXTEMP 305
#define BED_MAXTEMP 125
+#define AMBIENT_MAXTEMP 100
#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)
// Define PID constants for extruder with PT100
diff --git a/README.md b/README.md
index fb1c7968..1562552b 100644
--- a/README.md
+++ b/README.md
@@ -26,14 +26,28 @@ The firmware for the Original Prusa i3 printers is proudly based on [Marlin 1.0.
1. Clone this repository and checkout the correct branch for your desired release version.
-2. Set your printer model.
+1. Set your printer model.
- For MK3 --> skip to step 3.
- If you have a different printer model, follow step [2.b](#2b) from Windows build
+1. Install GNU AWK `sudo apt-get install gawk`
+If you use mawk instead of gawk you get strange errors when multi language support is generated like:
+`awk: line 2: function strtonum never defined
+sed: couldn't write 4 items to stdout: Broken pipe
+./lang-build.sh: 121: ./lang-build.sh: arithmetic expression: expecting EOF: "0x"awk: line 2: function strtonum never defined
+sed: couldn't write 4 items to stdout: Broken pipe
+tr: write error: Broken pipe
+./lang-build.sh: 121: ./lang-build.sh: arithmetic expression: expecting EOF: "0x"awk: line 2: function strtonum never defined
+sed: couldn't write 4 items to stdout: Broken pipe
+tr: write error: Broken pipe
+tr: write error
+cut: write error: Broken pipeNG! - some texts not found in lang_en.txt! updating binary:
+ primary language ids...awk: line 2: function strtonum never defined
+sed: couldn't flush stdout: Broken pipe`
-3. Run `./build.sh`
+1. Run `./build.sh`
- Output hex file is at `"PrusaFirmware/lang/firmware.hex"` . In the same folder you can hex files for other languages as well.
-4. Connect your printer and flash with PrusaSlicer ( Configuration --> Flash printer firmware ) or Slic3r PE.
+1. Connect your printer and flash with PrusaSlicer ( Configuration --> Flash printer firmware ) or Slic3r PE.
- If you wish to flash from Arduino, follow step [2.c](#2c) from Windows build first.
@@ -182,7 +196,7 @@ Example:
`ninja`
-## Runing
+## Running
`./tests`
# 4. Documentation