diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 8bf46d536453..20c110ff7b2e 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -3279,7 +3279,7 @@ // This is for Prusa MK3-style extruders. Customize for your hardware. #define MMU2_FILAMENTCHANGE_EJECT_FEED 80.0 #define MMU2_LOAD_TO_NOZZLE_SEQUENCE \ - { 7.2, 562 }, \ + { 7.2, 1145 }, \ { 14.4, 871 }, \ { 36.0, 1393 }, \ { 14.4, 871 }, \ @@ -3299,7 +3299,25 @@ { -50.0, 2000 } #endif - // Using a sensor like the MMU2S + /** + * MMU Extruder Sensor + * Add support for Prusa IR Sensor (or other) to detect that filament reach the extruder to make loading filament more reliable + * If your extruder is equipped with a filament sensor located less than 38mm from the gears you can use this feature + * During loading to the extruder, the sensor will stop the loading command when he's triggered and make a last move to load filament to the gears + * If no filament is detected, MMU2 will make more loading attemps, if finally no filament is detected, the printer will enter in runout state + */ + + //#define MMU_EXTRUDER_SENSOR + #if ENABLED(MMU_EXTRUDER_SENSOR) + #define MMU_LOADING_ATTEMPTS_NR 5 //max. number of attempts to load filament if first load fail + #endif + + /** + * Using a sensor like the MMU2S + * This mode only work if you have a MK3S extruder with sensor sensing the extruder idler mmu2s + * See https://help.prusa3d.com/en/guide/3b-mk3s-mk2-5s-extruder-upgrade_41560, step 11 + */ + //#define PRUSA_MMU2_S_MODE #if ENABLED(PRUSA_MMU2_S_MODE) #define MMU2_C0_RETRY 5 // Number of retries (total time = timeout*retries) diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index 826dc51d79af..aa6c7162cf4d 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -56,55 +56,56 @@ #define BOARD_3DRAG 1100 // 3Drag Controller #define BOARD_K8200 1101 // Velleman K8200 Controller (derived from 3Drag Controller) #define BOARD_K8400 1102 // Velleman K8400 Controller (derived from 3Drag Controller) -#define BOARD_BAM_DICE 1103 // 2PrintBeta BAM&DICE with STK drivers -#define BOARD_BAM_DICE_DUE 1104 // 2PrintBeta BAM&DICE Due with STK drivers -#define BOARD_MKS_BASE 1105 // MKS BASE v1.0 -#define BOARD_MKS_BASE_14 1106 // MKS BASE v1.4 with Allegro A4982 stepper drivers -#define BOARD_MKS_BASE_15 1107 // MKS BASE v1.5 with Allegro A4982 stepper drivers -#define BOARD_MKS_BASE_16 1108 // MKS BASE v1.6 with Allegro A4982 stepper drivers -#define BOARD_MKS_BASE_HEROIC 1109 // MKS BASE 1.0 with Heroic HR4982 stepper drivers -#define BOARD_MKS_GEN_13 1110 // MKS GEN v1.3 or 1.4 -#define BOARD_MKS_GEN_L 1111 // MKS GEN L -#define BOARD_KFB_2 1112 // BigTreeTech or BIQU KFB2.0 -#define BOARD_ZRIB_V20 1113 // zrib V2.0 control board (Chinese knock off RAMPS replica) -#define BOARD_FELIX2 1114 // Felix 2.0+ Electronics Board (RAMPS like) -#define BOARD_RIGIDBOARD 1115 // Invent-A-Part RigidBoard -#define BOARD_RIGIDBOARD_V2 1116 // Invent-A-Part RigidBoard V2 -#define BOARD_SAINSMART_2IN1 1117 // Sainsmart 2-in-1 board -#define BOARD_ULTIMAKER 1118 // Ultimaker -#define BOARD_ULTIMAKER_OLD 1119 // Ultimaker (Older electronics. Pre 1.5.4. This is rare) -#define BOARD_AZTEEG_X3 1120 // Azteeg X3 -#define BOARD_AZTEEG_X3_PRO 1121 // Azteeg X3 Pro -#define BOARD_ULTIMAIN_2 1122 // Ultimainboard 2.x (Uses TEMP_SENSOR 20) -#define BOARD_RUMBA 1123 // Rumba -#define BOARD_RUMBA_RAISE3D 1124 // Raise3D N series Rumba derivative -#define BOARD_RL200 1125 // Rapide Lite 200 (v1, low-cost RUMBA clone with drv) -#define BOARD_FORMBOT_TREX2PLUS 1126 // Formbot T-Rex 2 Plus -#define BOARD_FORMBOT_TREX3 1127 // Formbot T-Rex 3 -#define BOARD_FORMBOT_RAPTOR 1128 // Formbot Raptor -#define BOARD_FORMBOT_RAPTOR2 1129 // Formbot Raptor 2 -#define BOARD_BQ_ZUM_MEGA_3D 1130 // bq ZUM Mega 3D -#define BOARD_MAKEBOARD_MINI 1131 // MakeBoard Mini v2.1.2 is a control board sold by MicroMake -#define BOARD_TRIGORILLA_13 1132 // TriGorilla Anycubic version 1.3-based on RAMPS EFB -#define BOARD_TRIGORILLA_14 1133 // ... Ver 1.4 -#define BOARD_TRIGORILLA_14_11 1134 // ... Rev 1.1 (new servo pin order) -#define BOARD_RAMPS_ENDER_4 1135 // Creality: Ender-4, CR-8 -#define BOARD_RAMPS_CREALITY 1136 // Creality: CR10S, CR20, CR-X -#define BOARD_RAMPS_DAGOMA 1137 // Dagoma F5 -#define BOARD_FYSETC_F6_13 1138 // FYSETC F6 1.3 -#define BOARD_FYSETC_F6_14 1139 // FYSETC F6 1.4 -#define BOARD_DUPLICATOR_I3_PLUS 1140 // Wanhao Duplicator i3 Plus -#define BOARD_VORON 1141 // VORON Design -#define BOARD_TRONXY_V3_1_0 1142 // Tronxy TRONXY-V3-1.0 -#define BOARD_Z_BOLT_X_SERIES 1143 // Z-Bolt X Series -#define BOARD_TT_OSCAR 1144 // TT OSCAR -#define BOARD_OVERLORD 1145 // Overlord/Overlord Pro -#define BOARD_HJC2560C_REV1 1146 // ADIMLab Gantry v1 -#define BOARD_HJC2560C_REV2 1147 // ADIMLab Gantry v2 -#define BOARD_TANGO 1148 // BIQU Tango V1 -#define BOARD_MKS_GEN_L_V2 1149 // MKS GEN L V2 -#define BOARD_COPYMASTER_3D 1150 // Copymaster 3D -#define BOARD_ORTUR_4 1151 // Ortur 4 +#define BOARD_K8600 1103 // Velleman K8600 Controller (Vertex Nano) +#define BOARD_BAM_DICE 1104 // 2PrintBeta BAM&DICE with STK drivers +#define BOARD_BAM_DICE_DUE 1105 // 2PrintBeta BAM&DICE Due with STK drivers +#define BOARD_MKS_BASE 1106 // MKS BASE v1.0 +#define BOARD_MKS_BASE_14 1107 // MKS BASE v1.4 with Allegro A4982 stepper drivers +#define BOARD_MKS_BASE_15 1108 // MKS BASE v1.5 with Allegro A4982 stepper drivers +#define BOARD_MKS_BASE_16 1109 // MKS BASE v1.6 with Allegro A4982 stepper drivers +#define BOARD_MKS_BASE_HEROIC 1110 // MKS BASE 1.0 with Heroic HR4982 stepper drivers +#define BOARD_MKS_GEN_13 1111 // MKS GEN v1.3 or 1.4 +#define BOARD_MKS_GEN_L 1112 // MKS GEN L +#define BOARD_KFB_2 1113 // BigTreeTech or BIQU KFB2.0 +#define BOARD_ZRIB_V20 1114 // zrib V2.0 control board (Chinese knock off RAMPS replica) +#define BOARD_FELIX2 1115 // Felix 2.0+ Electronics Board (RAMPS like) +#define BOARD_RIGIDBOARD 1116 // Invent-A-Part RigidBoard +#define BOARD_RIGIDBOARD_V2 1117 // Invent-A-Part RigidBoard V2 +#define BOARD_SAINSMART_2IN1 1118 // Sainsmart 2-in-1 board +#define BOARD_ULTIMAKER 1119 // Ultimaker +#define BOARD_ULTIMAKER_OLD 1120 // Ultimaker (Older electronics. Pre 1.5.4. This is rare) +#define BOARD_AZTEEG_X3 1121 // Azteeg X3 +#define BOARD_AZTEEG_X3_PRO 1122 // Azteeg X3 Pro +#define BOARD_ULTIMAIN_2 1123 // Ultimainboard 2.x (Uses TEMP_SENSOR 20) +#define BOARD_RUMBA 1124 // Rumba +#define BOARD_RUMBA_RAISE3D 1125 // Raise3D N series Rumba derivative +#define BOARD_RL200 1126 // Rapide Lite 200 (v1, low-cost RUMBA clone with drv) +#define BOARD_FORMBOT_TREX2PLUS 1127 // Formbot T-Rex 2 Plus +#define BOARD_FORMBOT_TREX3 1128 // Formbot T-Rex 3 +#define BOARD_FORMBOT_RAPTOR 1129 // Formbot Raptor +#define BOARD_FORMBOT_RAPTOR2 1130 // Formbot Raptor 2 +#define BOARD_BQ_ZUM_MEGA_3D 1131 // bq ZUM Mega 3D +#define BOARD_MAKEBOARD_MINI 1132 // MakeBoard Mini v2.1.2 is a control board sold by MicroMake +#define BOARD_TRIGORILLA_13 1133 // TriGorilla Anycubic version 1.3-based on RAMPS EFB +#define BOARD_TRIGORILLA_14 1134 // ... Ver 1.4 +#define BOARD_TRIGORILLA_14_11 1135 // ... Rev 1.1 (new servo pin order) +#define BOARD_RAMPS_ENDER_4 1136 // Creality: Ender-4, CR-8 +#define BOARD_RAMPS_CREALITY 1137 // Creality: CR10S, CR20, CR-X +#define BOARD_RAMPS_DAGOMA 1138 // Dagoma F5 +#define BOARD_FYSETC_F6_13 1139 // FYSETC F6 1.3 +#define BOARD_FYSETC_F6_14 1140 // FYSETC F6 1.4 +#define BOARD_DUPLICATOR_I3_PLUS 1141 // Wanhao Duplicator i3 Plus +#define BOARD_VORON 1142 // VORON Design +#define BOARD_TRONXY_V3_1_0 1143 // Tronxy TRONXY-V3-1.0 +#define BOARD_Z_BOLT_X_SERIES 1144 // Z-Bolt X Series +#define BOARD_TT_OSCAR 1145 // TT OSCAR +#define BOARD_OVERLORD 1146 // Overlord/Overlord Pro +#define BOARD_HJC2560C_REV1 1147 // ADIMLab Gantry v1 +#define BOARD_HJC2560C_REV2 1148 // ADIMLab Gantry v2 +#define BOARD_TANGO 1149 // BIQU Tango V1 +#define BOARD_MKS_GEN_L_V2 1150 // MKS GEN L V2 +#define BOARD_COPYMASTER_3D 1151 // Copymaster 3D +#define BOARD_ORTUR_4 1152 // Ortur 4 // // RAMBo and derivatives diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index bc81f78cd311..4bd853d219c9 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -162,7 +162,7 @@ #define STR_ERR_MATERIAL_INDEX "M145 S out of range (0-1)" #define STR_ERR_M421_PARAMETERS "M421 incorrect parameter usage" #define STR_ERR_BAD_PLANE_MODE "G5 requires XY plane mode" -#define STR_ERR_MESH_XY "Mesh point cannot be resolved" +#define STR_ERR_MESH_XY "Mesh point out of range" #define STR_ERR_ARC_ARGS "G2/G3 bad parameters" #define STR_ERR_PROTECTED_PIN "Protected Pin" #define STR_ERR_M420_FAILED "Failed to enable Bed Leveling" diff --git a/Marlin/src/feature/mmu2/mmu2.cpp b/Marlin/src/feature/mmu2/mmu2.cpp index 6c61b714f751..2ddfd72647f6 100644 --- a/Marlin/src/feature/mmu2/mmu2.cpp +++ b/Marlin/src/feature/mmu2/mmu2.cpp @@ -51,8 +51,13 @@ MMU2 mmu2; #define MMU_TODELAY 100 #define MMU_TIMEOUT 10 -#define MMU_CMD_TIMEOUT 60000ul // 5min timeout for mmu commands (except P0) -#define MMU_P0_TIMEOUT 3000ul // Timeout for P0 command: 3seconds +#define MMU_CMD_TIMEOUT 45000UL // 45s timeout for mmu commands (except P0) +#define MMU_P0_TIMEOUT 3000UL // Timeout for P0 command: 3seconds + +#if ENABLED(MMU_EXTRUDER_SENSOR) + uint8_t mmu_idl_sens = 0; + static bool mmu_loading_flag = false; +#endif #define MMU_CMD_NONE 0 #define MMU_CMD_T0 0x10 @@ -79,11 +84,7 @@ MMU2 mmu2; #define MMU_CMD_F3 0x73 #define MMU_CMD_F4 0x74 -#if ENABLED(MMU2_MODE_12V) - #define MMU_REQUIRED_FW_BUILDNR 132 -#else - #define MMU_REQUIRED_FW_BUILDNR 126 -#endif +#define MMU_REQUIRED_FW_BUILDNR TERN(MMU2_MODE_12V, 132, 126) #define MMU2_NO_TOOL 99 #define MMU_BAUD 115200 @@ -99,7 +100,7 @@ int8_t MMU2::state = 0; volatile int8_t MMU2::finda = 1; volatile bool MMU2::finda_runout_valid; int16_t MMU2::version = -1, MMU2::buildnr = -1; -millis_t MMU2::last_request, MMU2::next_P0_request; +millis_t MMU2::prev_request, MMU2::prev_P0_request; char MMU2::rx_buffer[MMU_RX_SIZE], MMU2::tx_buffer[MMU_TX_SIZE]; #if BOTH(HAS_LCD_MENU, MMU2_MENUS) @@ -159,6 +160,10 @@ uint8_t MMU2::get_current_tool() { return extruder == MMU2_NO_TOOL ? -1 : extruder; } +#if EITHER(PRUSA_MMU2_S_MODE, MMU_EXTRUDER_SENSOR) + #define FILAMENT_PRESENT() (READ(FIL_RUNOUT_PIN) != FIL_RUNOUT_INVERTING) +#endif + void MMU2::mmu_loop() { switch (state) { @@ -248,6 +253,7 @@ void MMU2::mmu_loop() { int filament = cmd - MMU_CMD_T0; DEBUG_ECHOLNPAIR("MMU <= T", filament); tx_printf_P(PSTR("T%d\n"), filament); + TERN_(MMU_EXTRUDER_SENSOR, mmu_idl_sens = 1); // enable idler sensor, if any state = 3; // wait for response } else if (WITHIN(cmd, MMU_CMD_L0, MMU_CMD_L4)) { @@ -296,7 +302,7 @@ void MMU2::mmu_loop() { last_cmd = cmd; cmd = MMU_CMD_NONE; } - else if (ELAPSED(millis(), next_P0_request)) { + else if (ELAPSED(millis(), prev_P0_request + 300)) { // read FINDA tx_str_P(PSTR("P0\n")); state = 2; // wait for response @@ -312,26 +318,35 @@ void MMU2::mmu_loop() { // This is super annoying. Only activate if necessary // if (finda_runout_valid) DEBUG_ECHOLNPAIR_F("MMU <= 'P0'\nMMU => ", finda, 6); - state = 1; - - if (cmd == 0) ready = true; - if (!finda && finda_runout_valid) filament_runout(); + if (cmd == 0) ready = true; + state = 1; } - else if (ELAPSED(millis(), last_request + MMU_P0_TIMEOUT)) // Resend request after timeout (3s) + else if (ELAPSED(millis(), prev_request + MMU_P0_TIMEOUT)) // Resend request after timeout (3s) state = 1; TERN_(PRUSA_MMU2_S_MODE, check_filament()); break; case 3: // response to mmu commands + #if ENABLED(MMU_EXTRUDER_SENSOR) + if (mmu_idl_sens) { + if (FILAMENT_PRESENT() && mmu_loading_flag) { + DEBUG_ECHOLNPGM("MMU <= 'A'\n"); + tx_str_P(PSTR("A\n")); // send 'abort' request + mmu_idl_sens = 0; + DEBUG_ECHOLNPGM("MMU IDLER_SENSOR = 0 - ABORT\n"); + } + } + #endif + if (rx_ok()) { DEBUG_ECHOLNPGM("MMU => 'ok'"); ready = true; state = 1; last_cmd = MMU_CMD_NONE; } - else if (ELAPSED(millis(), last_request + MMU_CMD_TIMEOUT)) { + else if (ELAPSED(millis(), prev_request + MMU_CMD_TIMEOUT)) { // resend request after timeout if (last_cmd) { DEBUG_ECHOLNPGM("MMU retry"); @@ -351,7 +366,7 @@ void MMU2::mmu_loop() { bool MMU2::rx_start() { // check for start message if (rx_str_P(PSTR("start\n"))) { - next_P0_request = millis() + 300; + prev_P0_request = millis(); return true; } return false; @@ -397,7 +412,7 @@ void MMU2::tx_str_P(const char* str) { uint8_t len = strlen_P(str); LOOP_L_N(i, len) mmuSerial.write(pgm_read_byte(str++)); rx_buffer[0] = '\0'; - last_request = millis(); + prev_request = millis(); } /** @@ -408,7 +423,7 @@ void MMU2::tx_printf_P(const char* format, int argument = -1) { uint8_t len = sprintf_P(tx_buffer, format, argument); LOOP_L_N(i, len) mmuSerial.write(tx_buffer[i]); rx_buffer[0] = '\0'; - last_request = millis(); + prev_request = millis(); } /** @@ -419,7 +434,7 @@ void MMU2::tx_printf_P(const char* format, int argument1, int argument2) { uint8_t len = sprintf_P(tx_buffer, format, argument1, argument2); LOOP_L_N(i, len) mmuSerial.write(tx_buffer[i]); rx_buffer[0] = '\0'; - last_request = millis(); + prev_request = millis(); } /** @@ -435,7 +450,7 @@ void MMU2::clear_rx_buffer() { */ bool MMU2::rx_ok() { if (rx_str_P(PSTR("ok\n"))) { - next_P0_request = millis() + 300; + prev_P0_request = millis(); return true; } return false; @@ -476,32 +491,206 @@ static bool mmu2_not_responding() { return success; } -#endif + /** + * Handle tool change + */ + void MMU2::tool_change(const uint8_t index) { + + if (!enabled) return; + + set_runout_valid(false); + + if (index != extruder) { + + DISABLE_AXIS_E0(); + ui.status_printf_P(0, GET_TEXT(MSG_MMU2_LOADING_FILAMENT), int(index + 1)); + + command(MMU_CMD_T0 + index); + manage_response(true, true); + + if (load_to_gears()) { + extruder = index; // filament change is finished + active_extruder = 0; + ENABLE_AXIS_E0(); + SERIAL_ECHO_START(); + SERIAL_ECHOLNPAIR(STR_ACTIVE_EXTRUDER, int(extruder)); + } + ui.reset_status(); + } + + set_runout_valid(true); + } + + /** + * Handle special T?/Tx/Tc commands + * + * T? Gcode to extrude shouldn't have to follow, load to extruder wheels is done automatically + * Tx Same as T?, except nozzle doesn't have to be preheated. Tc must be placed after extruder nozzle is preheated to finish filament load. + * Tc Load to nozzle after filament was prepared by Tx and extruder nozzle is already heated. + */ + void MMU2::tool_change(const char* special) { + + if (!enabled) return; + + #if ENABLED(MMU2_MENUS) + + set_runout_valid(false); + + switch (*special) { + case '?': { + uint8_t index = mmu2_choose_filament(); + while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); + load_filament_to_nozzle(index); + } break; + + case 'x': { + planner.synchronize(); + uint8_t index = mmu2_choose_filament(); + DISABLE_AXIS_E0(); + command(MMU_CMD_T0 + index); + manage_response(true, true); + + if (load_to_gears()) { + mmu_loop(); + ENABLE_AXIS_E0(); + extruder = index; + active_extruder = 0; + } + } break; + + case 'c': { + while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); + execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence)); + } break; + } + + set_runout_valid(true); + + #endif // MMU2_MENUS + } + +#elif ENABLED(MMU_EXTRUDER_SENSOR) + + /** + * Handle tool change + */ + void MMU2::tool_change(const uint8_t index) { + if (!enabled) return; + + set_runout_valid(false); + + if (index != extruder) { + DISABLE_AXIS_E0(); + if (FILAMENT_PRESENT()) { + DEBUG_ECHOLNPGM("Unloading\n"); + mmu_loading_flag = false; + command(MMU_CMD_U0); + manage_response(true, true); + } + ui.status_printf_P(0, GET_TEXT(MSG_MMU2_LOADING_FILAMENT), int(index + 1)); + mmu_loading_flag = true; + command(MMU_CMD_T0 + index); + manage_response(true, true); + mmu_continue_loading(); + command(MMU_CMD_C0); + extruder = index; + active_extruder = 0; + + ENABLE_AXIS_E0(); + SERIAL_ECHO_START(); + SERIAL_ECHOLNPAIR(STR_ACTIVE_EXTRUDER, int(extruder)); + + ui.reset_status(); + } + + set_runout_valid(true); + } + + /** + * Handle special T?/Tx/Tc commands + * + * T? Gcode to extrude shouldn't have to follow, load to extruder wheels is done automatically + * Tx Same as T?, except nozzle doesn't have to be preheated. Tc must be placed after extruder nozzle is preheated to finish filament load. + * Tc Load to nozzle after filament was prepared by Tx and extruder nozzle is already heated. + */ + void MMU2::tool_change(const char* special) { + if (!enabled) return; + + #if ENABLED(MMU2_MENUS) + + set_runout_valid(false); + + switch (*special) { + case '?': { + DEBUG_ECHOLNPGM("case ?\n"); + uint8_t index = mmu2_choose_filament(); + while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); + load_filament_to_nozzle(index); + } break; + + case 'x': { + DEBUG_ECHOLNPGM("case x\n"); + planner.synchronize(); + uint8_t index = mmu2_choose_filament(); + DISABLE_AXIS_E0(); + command(MMU_CMD_T0 + index); + manage_response(true, true); + mmu_continue_loading(); + command(MMU_CMD_C0); + mmu_loop(); + + ENABLE_AXIS_E0(); + extruder = index; + active_extruder = 0; + } break; + + case 'c': { + DEBUG_ECHOLNPGM("case c\n"); + while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); + execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence)); + } break; + } + + set_runout_valid(true); + + #endif // MMU2_MENUS + } + + void MMU2::mmu_continue_loading() { + for (uint8_t i = 0; i < MMU_LOADING_ATTEMPTS_NR; i++) { + DEBUG_ECHOLNPAIR("Additional load attempt #", i); + if (FILAMENT_PRESENT()) break; + command(MMU_CMD_C0); + manage_response(true, true); + } + if (!FILAMENT_PRESENT()) { + DEBUG_ECHOLNPGM("Filament never reached sensor, runout"); + filament_runout(); + } + mmu_idl_sens = 0; + } + +#elif DISABLED(MMU_EXTRUDER_SENSOR) && DISABLED(PRUSA_MMU2_S_MODE) /** * Handle tool change */ -void MMU2::tool_change(uint8_t index) { - +void MMU2::tool_change(const uint8_t index) { if (!enabled) return; set_runout_valid(false); if (index != extruder) { - DISABLE_AXIS_E0(); ui.status_printf_P(0, GET_TEXT(MSG_MMU2_LOADING_FILAMENT), int(index + 1)); - command(MMU_CMD_T0 + index); manage_response(true, true); - - if (load_to_gears()) { - extruder = index; // filament change is finished - active_extruder = 0; - ENABLE_AXIS_E0(); - SERIAL_ECHO_START(); - SERIAL_ECHOLNPAIR(STR_ACTIVE_EXTRUDER, int(extruder)); - } + command(MMU_CMD_C0); + extruder = index; //filament change is finished + active_extruder = 0; + ENABLE_AXIS_E0(); + SERIAL_ECHO_START(); + SERIAL_ECHOLNPAIR(STR_ACTIVE_EXTRUDER, int(extruder)); ui.reset_status(); } @@ -518,7 +707,6 @@ void MMU2::tool_change(uint8_t index) { * */ void MMU2::tool_change(const char* special) { - if (!enabled) return; #if ENABLED(MMU2_MENUS) @@ -527,27 +715,29 @@ void MMU2::tool_change(const char* special) { switch (*special) { case '?': { + DEBUG_ECHOLNPGM("case ?\n"); uint8_t index = mmu2_choose_filament(); while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); load_filament_to_nozzle(index); } break; case 'x': { + DEBUG_ECHOLNPGM("case x\n"); planner.synchronize(); uint8_t index = mmu2_choose_filament(); DISABLE_AXIS_E0(); command(MMU_CMD_T0 + index); manage_response(true, true); + command(MMU_CMD_C0); + mmu_loop(); - if (load_to_gears()) { - mmu_loop(); - ENABLE_AXIS_E0(); - extruder = index; - active_extruder = 0; - } + ENABLE_AXIS_E0(); + extruder = index; + active_extruder = 0; } break; case 'c': { + DEBUG_ECHOLNPGM("case c\n"); while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence)); } break; @@ -556,7 +746,9 @@ void MMU2::tool_change(const char* special) { set_runout_valid(true); #endif -} + } + +#endif // MMU_EXTRUDER_SENSOR /** * Set next command @@ -593,7 +785,7 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { bool response = false; mmu_print_saved = false; xyz_pos_t resume_position; - int16_t resume_hotend_temp; + int16_t resume_hotend_temp = thermalManager.degTargetHotend(active_extruder); KEEPALIVE_STATE(PAUSED_FOR_USER); @@ -652,7 +844,7 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { } } -void MMU2::set_filament_type(uint8_t index, uint8_t filamentType) { +void MMU2::set_filament_type(const uint8_t index, const uint8_t filamentType) { if (!enabled) return; cmd_arg = filamentType; @@ -667,20 +859,21 @@ void MMU2::filament_runout() { } #if ENABLED(PRUSA_MMU2_S_MODE) + void MMU2::check_filament() { - const bool runout = READ(FIL_RUNOUT_PIN) ^ (FIL_RUNOUT_INVERTING); - if (runout && !mmu2s_triggered) { + const bool present = FILAMENT_PRESENT(); + if (present && !mmu2s_triggered) { DEBUG_ECHOLNPGM("MMU <= 'A'"); tx_str_P(PSTR("A\n")); } - mmu2s_triggered = runout; + mmu2s_triggered = present; } bool MMU2::can_load() { execute_extruder_sequence((const E_Step *)can_load_sequence, COUNT(can_load_sequence)); int filament_detected_count = 0; - const int steps = MMU2_CAN_LOAD_RETRACT / MMU2_CAN_LOAD_INCREMENT; + const int steps = (MMU2_CAN_LOAD_RETRACT) / (MMU2_CAN_LOAD_INCREMENT); DEBUG_ECHOLNPGM("MMU can_load:"); LOOP_L_N(i, steps) { execute_extruder_sequence((const E_Step *)can_load_increment_sequence, COUNT(can_load_increment_sequence)); @@ -689,7 +882,7 @@ void MMU2::filament_runout() { if (mmu2s_triggered) ++filament_detected_count; } - if (filament_detected_count <= steps - (MMU2_CAN_LOAD_DEVIATION / MMU2_CAN_LOAD_INCREMENT)) { + if (filament_detected_count <= steps - (MMU2_CAN_LOAD_DEVIATION) / (MMU2_CAN_LOAD_INCREMENT)) { DEBUG_ECHOLNPGM(" failed."); return false; } @@ -702,7 +895,7 @@ void MMU2::filament_runout() { #if BOTH(HAS_LCD_MENU, MMU2_MENUS) // Load filament into MMU2 - void MMU2::load_filament(uint8_t index) { + void MMU2::load_filament(const uint8_t index) { if (!enabled) return; command(MMU_CMD_L0 + index); manage_response(false, false); @@ -714,7 +907,7 @@ void MMU2::filament_runout() { * Switch material and load to nozzle * */ - bool MMU2::load_filament_to_nozzle(uint8_t index) { + bool MMU2::load_filament_to_nozzle(const uint8_t index) { if (!enabled) return false; @@ -739,7 +932,6 @@ void MMU2::filament_runout() { } /** - * * Load filament to nozzle of multimaterial printer * * This function is used only only after T? (user select filament) and M600 (change filament). @@ -751,7 +943,7 @@ void MMU2::filament_runout() { execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence)); } - bool MMU2::eject_filament(uint8_t index, bool recover) { + bool MMU2::eject_filament(const uint8_t index, const bool recover) { if (!enabled) return false; @@ -798,9 +990,7 @@ void MMU2::filament_runout() { } /** - * - * unload from hotend and retract to MMU - * + * Unload from hotend and retract to MMU */ bool MMU2::unload() { diff --git a/Marlin/src/feature/mmu2/mmu2.h b/Marlin/src/feature/mmu2/mmu2.h index 8dd07f88475d..c956139f54db 100644 --- a/Marlin/src/feature/mmu2/mmu2.h +++ b/Marlin/src/feature/mmu2/mmu2.h @@ -44,24 +44,24 @@ class MMU2 { static void init(); static void reset(); static void mmu_loop(); - static void tool_change(uint8_t index); + static void tool_change(const uint8_t index); static void tool_change(const char* special); static uint8_t get_current_tool(); - static void set_filament_type(uint8_t index, uint8_t type); + static void set_filament_type(const uint8_t index, const uint8_t type); #if BOTH(HAS_LCD_MENU, MMU2_MENUS) static bool unload(); static void load_filament(uint8_t); static void load_all(); - static bool load_filament_to_nozzle(uint8_t index); - static bool eject_filament(uint8_t index, bool recover); + static bool load_filament_to_nozzle(const uint8_t index); + static bool eject_filament(const uint8_t index, const bool recover); #endif private: static bool rx_str_P(const char* str); static void tx_str_P(const char* str); - static void tx_printf_P(const char* format, int argument); - static void tx_printf_P(const char* format, int argument1, int argument2); + static void tx_printf_P(const char* format, const int argument); + static void tx_printf_P(const char* format, const int argument1, const int argument2); static void clear_rx_buffer(); static bool rx_ok(); @@ -89,6 +89,10 @@ class MMU2 { FORCE_INLINE static bool load_to_gears() { return true; } #endif + #if ENABLED(MMU_EXTRUDER_SENSOR) + static void mmu_continue_loading(); + #endif + static bool enabled, ready, mmu_print_saved; static uint8_t cmd, cmd_arg, last_cmd, extruder; @@ -96,7 +100,7 @@ class MMU2 { static volatile int8_t finda; static volatile bool finda_runout_valid; static int16_t version, buildnr; - static millis_t last_request, next_P0_request; + static millis_t prev_request, prev_P0_request; static char rx_buffer[MMU_RX_SIZE], tx_buffer[MMU_TX_SIZE]; static inline void set_runout_valid(const bool valid) { diff --git a/Marlin/src/feature/spindle_laser_types.h b/Marlin/src/feature/spindle_laser_types.h index 9e3f2bae48a8..7fa93420d157 100644 --- a/Marlin/src/feature/spindle_laser_types.h +++ b/Marlin/src/feature/spindle_laser_types.h @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm diff --git a/Marlin/src/gcode/bedlevel/M420.cpp b/Marlin/src/gcode/bedlevel/M420.cpp index 3effc3173bb9..50b2f6f15896 100644 --- a/Marlin/src/gcode/bedlevel/M420.cpp +++ b/Marlin/src/gcode/bedlevel/M420.cpp @@ -84,12 +84,12 @@ void GcodeSuite::M420() { } #endif + xyz_pos_t oldpos = current_position; + // If disabling leveling do it right away // (Don't disable for just M420 or M420 V) if (seen_S && !to_enable) set_bed_leveling_enabled(false); - xyz_pos_t oldpos = current_position; - #if ENABLED(AUTO_BED_LEVELING_UBL) // L to load a mesh from the EEPROM diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index ead70bc2574c..9c5907a5ccc2 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -78,11 +78,7 @@ #endif #endif -#if ENABLED(G29_RETRY_AND_RECOVER) - #define G29_RETURN(b) return b; -#else - #define G29_RETURN(b) return; -#endif +#define G29_RETURN(b) return TERN_(G29_RETRY_AND_RECOVER, b) /** * G29: Detailed Z probe, probes the bed at 3 or more points. @@ -164,11 +160,7 @@ */ G29_TYPE GcodeSuite::G29() { - #if EITHER(DEBUG_LEVELING_FEATURE, PROBE_MANUALLY) - const bool seenQ = parser.seen('Q'); - #else - constexpr bool seenQ = false; - #endif + const bool seenQ = EITHER(DEBUG_LEVELING_FEATURE, PROBE_MANUALLY) && parser.seen('Q'); // G29 Q is also available if debugging #if ENABLED(DEBUG_LEVELING_FEATURE) @@ -179,25 +171,12 @@ G29_TYPE GcodeSuite::G29() { log_machine_info(); } marlin_debug_flags = old_debug_flags; - #if DISABLED(PROBE_MANUALLY) - if (seenQ) G29_RETURN(false); - #endif + if (DISABLED(PROBE_MANUALLY) && seenQ) G29_RETURN(false); #endif - #if ENABLED(PROBE_MANUALLY) - const bool seenA = parser.seen('A'); - #else - constexpr bool seenA = false; - #endif - - const bool no_action = seenA || seenQ, - faux = - #if ENABLED(DEBUG_LEVELING_FEATURE) && DISABLED(PROBE_MANUALLY) - parser.boolval('C') - #else - no_action - #endif - ; + const bool seenA = TERN0(PROBE_MANUALLY, parser.seen('A')), + no_action = seenA || seenQ, + faux = ENABLED(DEBUG_LEVELING_FEATURE) && DISABLED(PROBE_MANUALLY) ? parser.boolval('C') : no_action; // Don't allow auto-leveling without homing first if (axis_unhomed_error()) G29_RETURN(false); @@ -208,11 +187,7 @@ G29_TYPE GcodeSuite::G29() { } // Define local vars 'static' for manual probing, 'auto' otherwise - #if ENABLED(PROBE_MANUALLY) - #define ABL_VAR static - #else - #define ABL_VAR - #endif + #define ABL_VAR TERN_(PROBE_MANUALLY, static) ABL_VAR int verbose_level; ABL_VAR xy_pos_t probePos; @@ -346,11 +321,7 @@ G29_TYPE GcodeSuite::G29() { G29_RETURN(false); } - dryrun = parser.boolval('D') - #if ENABLED(PROBE_MANUALLY) - || no_action - #endif - ; + dryrun = parser.boolval('D') || TERN0(PROBE_MANUALLY, no_action); #if ENABLED(AUTO_BED_LEVELING_LINEAR) @@ -430,26 +401,27 @@ G29_TYPE GcodeSuite::G29() { planner.synchronize(); + if (!faux) remember_feedrate_scaling_off(); + // Disable auto bed leveling during G29. // Be formal so G29 can be done successively without G28. if (!no_action) set_bed_leveling_enabled(false); + // Deploy certain probes before starting probing #if HAS_BED_PROBE - // Deploy the probe. Probe will raise if needed. - if (probe.deploy()) { + if (ENABLED(BLTOUCH)) + do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE); + else if (probe.deploy()) { set_bed_leveling_enabled(abl_should_enable); G29_RETURN(false); } #endif - if (!faux) remember_feedrate_scaling_off(); - #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - #if ENABLED(PROBE_MANUALLY) - if (!no_action) - #endif - if (gridSpacing != bilinear_grid_spacing || probe_position_lf != bilinear_start) { + if (TERN1(PROBE_MANUALLY, !no_action) + && (gridSpacing != bilinear_grid_spacing || probe_position_lf != bilinear_start) + ) { // Reset grid to 0.0 or "not probed". (Also disables ABL) reset_bed_level(); @@ -560,8 +532,7 @@ G29_TYPE GcodeSuite::G29() { PR_INNER_VAR = abl_probe_index - (PR_OUTER_VAR * PR_INNER_END); // Probe in reverse order for every other row/column - bool zig = (PR_OUTER_VAR & 1); // != ((PR_OUTER_END) & 1); - + const bool zig = (PR_OUTER_VAR & 1); // != ((PR_OUTER_END) & 1); if (zig) PR_INNER_VAR = (PR_INNER_END - 1) - PR_INNER_VAR; probePos = probe_position_lf + gridSpacing * meshCount.asFloat(); @@ -576,19 +547,14 @@ G29_TYPE GcodeSuite::G29() { // Is there a next point to move to? if (abl_probe_index < abl_points) { _manual_goto_xy(probePos); // Can be used here too! - #if HAS_SOFTWARE_ENDSTOPS - // Disable software endstops to allow manual adjustment - // If G29 is not completed, they will not be re-enabled - soft_endstops_enabled = false; - #endif + // Disable software endstops to allow manual adjustment + // If G29 is not completed, they will not be re-enabled + TERN_(HAS_SOFTWARE_ENDSTOPS, soft_endstops_enabled = false); G29_RETURN(false); } else { - // Leveling done! Fall through to G29 finishing code below - SERIAL_ECHOLNPGM("Grid probing done."); - // Re-enable software endstops, if needed TERN_(HAS_SOFTWARE_ENDSTOPS, soft_endstops_enabled = saved_soft_endstops_state); } @@ -599,11 +565,9 @@ G29_TYPE GcodeSuite::G29() { if (abl_probe_index < abl_points) { probePos = points[abl_probe_index]; _manual_goto_xy(probePos); - #if HAS_SOFTWARE_ENDSTOPS - // Disable software endstops to allow manual adjustment - // If G29 is not completed, they will not be re-enabled - soft_endstops_enabled = false; - #endif + // Disable software endstops to allow manual adjustment + // If G29 is not completed, they will not be re-enabled + TERN_(HAS_SOFTWARE_ENDSTOPS, soft_endstops_enabled = false); G29_RETURN(false); } else { @@ -670,10 +634,8 @@ G29_TYPE GcodeSuite::G29() { TERN_(AUTO_BED_LEVELING_LINEAR, indexIntoAB[meshCount.x][meshCount.y] = ++abl_probe_index); // 0... - #if IS_KINEMATIC - // Avoid probing outside the round or hexagonal area - if (!probe.can_reach(probePos)) continue; - #endif + // Avoid probing outside the round or hexagonal area + if (TERN0(IS_KINEMATIC, !probe.can_reach(probePos))) continue; if (verbose_level) SERIAL_ECHOLNPAIR("Probing mesh point ", int(pt_index), "/", int(GRID_MAX_POINTS), "."); TERN_(HAS_DISPLAY, ui.status_printf_P(0, PSTR(S_FMT " %i/%i"), GET_TEXT(MSG_PROBING_MESH), int(pt_index), int(GRID_MAX_POINTS))); @@ -898,11 +860,7 @@ G29_TYPE GcodeSuite::G29() { // Unapply the offset because it is going to be immediately applied // and cause compensation movement in Z - #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) - const float fade_scaling_factor = planner.fade_scaling_factor_for_z(current_position.z); - #else - constexpr float fade_scaling_factor = 1.0f; - #endif + const float fade_scaling_factor = TERN(ENABLE_LEVELING_FADE_HEIGHT, planner.fade_scaling_factor_for_z(current_position.z), 1); current_position.z -= fade_scaling_factor * bilinear_z_offset(current_position); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(" corrected Z:", current_position.z); diff --git a/Marlin/src/gcode/bedlevel/abl/M421.cpp b/Marlin/src/gcode/bedlevel/abl/M421.cpp index 74514bf4170c..2e46fafcd009 100644 --- a/Marlin/src/gcode/bedlevel/abl/M421.cpp +++ b/Marlin/src/gcode/bedlevel/abl/M421.cpp @@ -36,28 +36,39 @@ #endif /** - * M421: Set a single Mesh Bed Leveling Z coordinate + * M421: Set one or more Mesh Bed Leveling Z coordinates * * Usage: * M421 I J Z * M421 I J Q + * + * - If I is omitted, set the entire row + * - If J is omitted, set the entire column + * - If both I and J are omitted, set all */ void GcodeSuite::M421() { int8_t ix = parser.intval('I', -1), iy = parser.intval('J', -1); - const bool hasI = ix >= 0, - hasJ = iy >= 0, - hasZ = parser.seen('Z'), - hasQ = !hasZ && parser.seen('Q'); + const bool hasZ = parser.seenval('Z'), + hasQ = !hasZ && parser.seenval('Q'); - if (!hasI || !hasJ || !(hasZ || hasQ)) - SERIAL_ERROR_MSG(STR_ERR_M421_PARAMETERS); - else if (!WITHIN(ix, 0, GRID_MAX_POINTS_X - 1) || !WITHIN(iy, 0, GRID_MAX_POINTS_Y - 1)) - SERIAL_ERROR_MSG(STR_ERR_MESH_XY); - else { - z_values[ix][iy] = parser.value_linear_units() + (hasQ ? z_values[ix][iy] : 0); - TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); - TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(ix, iy, z_values[ix][iy])); + if (hasZ || hasQ) { + if (WITHIN(ix, -1, GRID_MAX_POINTS_X - 1) && WITHIN(iy, -1, GRID_MAX_POINTS_Y - 1)) { + const float zval = parser.value_linear_units(); + uint8_t sx = ix >= 0 ? ix : 0, ex = ix >= 0 ? ix : GRID_MAX_POINTS_X - 1, + sy = iy >= 0 ? iy : 0, ey = iy >= 0 ? iy : GRID_MAX_POINTS_Y - 1; + LOOP_S_LE_N(x, sx, ex) { + LOOP_S_LE_N(y, sy, ey) { + z_values[x][y] = zval + (hasQ ? z_values[x][y] : 0); + TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y])); + } + } + TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); + } + else + SERIAL_ERROR_MSG(STR_ERR_MESH_XY); } + else + SERIAL_ERROR_MSG(STR_ERR_M421_PARAMETERS); } #endif // AUTO_BED_LEVELING_BILINEAR diff --git a/Marlin/src/gcode/host/M114.cpp b/Marlin/src/gcode/host/M114.cpp index 8a31f248bf06..389188ada8eb 100644 --- a/Marlin/src/gcode/host/M114.cpp +++ b/Marlin/src/gcode/host/M114.cpp @@ -179,7 +179,7 @@ report_xyze(from_steppers); const xyze_float_t diff = from_steppers - leveled; - SERIAL_ECHOPGM("Diff: "); + SERIAL_ECHOPGM("Diff: "); report_xyze(diff); } diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h index 7d5cb060b99d..70601c3158ae 100644 --- a/Marlin/src/inc/Conditionals_post.h +++ b/Marlin/src/inc/Conditionals_post.h @@ -1587,6 +1587,15 @@ #if _HAS_STOP(Z,MAX) #define HAS_Z_MAX 1 #endif +#if _HAS_STOP(X,STOP) + #define HAS_X_STOP 1 +#endif +#if _HAS_STOP(Y,STOP) + #define HAS_Y_STOP 1 +#endif +#if _HAS_STOP(Z,STOP) + #define HAS_Z_STOP 1 +#endif #if PIN_EXISTS(X2_MIN) #define HAS_X2_MIN 1 #endif diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index c8f8907e88b2..da29c0ecf0ee 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -2742,12 +2742,14 @@ static_assert( _ARR_TEST(3,0) && _ARR_TEST(3,1) && _ARR_TEST(3,2) * Prusa MMU2 requirements */ #if ENABLED(PRUSA_MMU2) - #if DISABLED(NOZZLE_PARK_FEATURE) - #error "PRUSA_MMU2 requires NOZZLE_PARK_FEATURE." - #elif EXTRUDERS != 5 + #if EXTRUDERS != 5 #error "PRUSA_MMU2 requires EXTRUDERS = 5." - #elif ENABLED(PRUSA_MMU2_S_MODE) && DISABLED(FILAMENT_RUNOUT_SENSOR) - #error "PRUSA_MMU2_S_MODE requires FILAMENT_RUNOUT_SENSOR. Enable it to continue." + #elif DISABLED(NOZZLE_PARK_FEATURE) + #error "PRUSA_MMU2 requires NOZZLE_PARK_FEATURE. Enable it to continue." + #elif EITHER(PRUSA_MMU2_S_MODE, MMU_EXTRUDER_SENSOR) && DISABLED(FILAMENT_RUNOUT_SENSOR) + #error "PRUSA_MMU2_S_MODE or MMU_EXTRUDER_SENSOR requires FILAMENT_RUNOUT_SENSOR. Enable it to continue." + #elif BOTH(PRUSA_MMU2_S_MODE, MMU_EXTRUDER_SENSOR) + #error "Enable only one of PRUSA_MMU2_S_MODE or MMU_EXTRUDER_SENSOR." #elif DISABLED(ADVANCED_PAUSE_FEATURE) static_assert(nullptr == strstr(MMU2_FILAMENT_RUNOUT_SCRIPT, "M600"), "ADVANCED_PAUSE_FEATURE is required to use M600 with PRUSA_MMU2."); #endif diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 147bbf864a17..abe4df3286aa 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2020-05-14" + #define STRING_DISTRIBUTION_DATE "2020-05-18" #endif /** diff --git a/Marlin/src/lcd/language/language_fr.h b/Marlin/src/lcd/language/language_fr.h index 3daac87a2835..ee866629b3e8 100644 --- a/Marlin/src/lcd/language/language_fr.h +++ b/Marlin/src/lcd/language/language_fr.h @@ -476,15 +476,16 @@ namespace Language_fr { PROGMEM Language_Str MSG_LCD_PROBING_FAILED = _UxGT("Echec sonde"); PROGMEM Language_Str MSG_M600_TOO_COLD = _UxGT("M600: Trop froid"); + PROGMEM Language_Str MSG_KILL_MMU2_FIRMWARE = _UxGT("MAJ firmware MMU!!"); PROGMEM Language_Str MSG_MMU2_CHOOSE_FILAMENT_HEADER = _UxGT("CHOISIR FILAMENT"); PROGMEM Language_Str MSG_MMU2_MENU = _UxGT("MMU"); PROGMEM Language_Str MSG_MMU2_NOT_RESPONDING = _UxGT("MMU ne répond plus"); - PROGMEM Language_Str MSG_MMU2_RESUME = _UxGT("Continuer impr."); - PROGMEM Language_Str MSG_MMU2_RESUMING = _UxGT("Reprise..."); - PROGMEM Language_Str MSG_MMU2_LOAD_FILAMENT = _UxGT("Charger filament"); - PROGMEM Language_Str MSG_MMU2_LOAD_ALL = _UxGT("Charger tous"); + PROGMEM Language_Str MSG_MMU2_RESUME = _UxGT("Continuer Imp. MMU"); + PROGMEM Language_Str MSG_MMU2_RESUMING = _UxGT("Reprise MMU..."); + PROGMEM Language_Str MSG_MMU2_LOAD_FILAMENT = _UxGT("Charge dans MMU"); + PROGMEM Language_Str MSG_MMU2_LOAD_ALL = _UxGT("Charger tous dans MMU"); PROGMEM Language_Str MSG_MMU2_LOAD_TO_NOZZLE = _UxGT("Charger dans buse"); - PROGMEM Language_Str MSG_MMU2_EJECT_FILAMENT = _UxGT("Ejecter filament"); + PROGMEM Language_Str MSG_MMU2_EJECT_FILAMENT = _UxGT("Ejecter fil. du MMU"); PROGMEM Language_Str MSG_MMU2_EJECT_FILAMENT_N = _UxGT("Ejecter fil. ~"); PROGMEM Language_Str MSG_MMU2_UNLOAD_FILAMENT = _UxGT("Retrait filament"); PROGMEM Language_Str MSG_MMU2_LOADING_FILAMENT = _UxGT("Chargem. fil. %i..."); diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp index 092043b59c5e..47d63df64b70 100644 --- a/Marlin/src/module/endstops.cpp +++ b/Marlin/src/module/endstops.cpp @@ -674,6 +674,15 @@ void Endstops::update() { } \ }while(0) + // Core Sensorless Homing needs to test an Extra Pin + #define CORE_DIAG(QQ,A,MM) (CORE_IS_##QQ && A##_SENSORLESS && !A##_SPI_SENSORLESS && HAS_##A##_##MM) + #define PROCESS_CORE_ENDSTOP(A1,M1,A2,M2) do { \ + if (TEST_ENDSTOP(_ENDSTOP(A1,M1))) { \ + _ENDSTOP_HIT(A2,M2); \ + planner.endstop_triggered(_AXIS(A2)); \ + } \ + }while(0) + // Call the endstop triggered routine for dual endstops #define PROCESS_DUAL_ENDSTOP(A, MINMAX) do { \ const byte dual_hit = TEST_ENDSTOP(_ENDSTOP(A, MINMAX)) | (TEST_ENDSTOP(_ENDSTOP(A##2, MINMAX)) << 1); \ @@ -742,16 +751,35 @@ void Endstops::update() { } #endif - // Now, we must signal, after validation, if an endstop limit is pressed or not + // Signal, after validation, if an endstop limit is pressed or not + if (stepper.axis_is_moving(X_AXIS)) { if (stepper.motor_direction(X_AXIS_HEAD)) { // -direction #if HAS_X_MIN || (X_SPI_SENSORLESS && X_HOME_DIR < 0) PROCESS_ENDSTOP_X(MIN); + #if CORE_DIAG(XY, Y, MIN) + PROCESS_CORE_ENDSTOP(Y,MIN,X,MIN); + #elif CORE_DIAG(XY, Y, MAX) + PROCESS_CORE_ENDSTOP(Y,MAX,X,MIN); + #elif CORE_DIAG(XZ, Z, MIN) + PROCESS_CORE_ENDSTOP(Z,MIN,X,MIN); + #elif CORE_DIAG(XZ, Z, MAX) + PROCESS_CORE_ENDSTOP(Z,MAX,X,MIN); + #endif #endif } else { // +direction #if HAS_X_MAX || (X_SPI_SENSORLESS && X_HOME_DIR > 0) PROCESS_ENDSTOP_X(MAX); + #if CORE_DIAG(XY, Y, MIN) + PROCESS_CORE_ENDSTOP(Y,MIN,X,MAX); + #elif CORE_DIAG(XY, Y, MAX) + PROCESS_CORE_ENDSTOP(Y,MAX,X,MAX); + #elif CORE_DIAG(XZ, Z, MIN) + PROCESS_CORE_ENDSTOP(Z,MIN,X,MAX); + #elif CORE_DIAG(XZ, Z, MAX) + PROCESS_CORE_ENDSTOP(Z,MAX,X,MAX); + #endif #endif } } @@ -760,11 +788,29 @@ void Endstops::update() { if (stepper.motor_direction(Y_AXIS_HEAD)) { // -direction #if HAS_Y_MIN || (Y_SPI_SENSORLESS && Y_HOME_DIR < 0) PROCESS_ENDSTOP_Y(MIN); + #if CORE_DIAG(XY, X, MIN) + PROCESS_CORE_ENDSTOP(X,MIN,Y,MIN); + #elif CORE_DIAG(XY, X, MAX) + PROCESS_CORE_ENDSTOP(X,MAX,Y,MIN); + #elif CORE_DIAG(YZ, Z, MIN) + PROCESS_CORE_ENDSTOP(Z,MIN,Y,MIN); + #elif CORE_DIAG(YZ, Z, MAX) + PROCESS_CORE_ENDSTOP(Z,MAX,Y,MIN); + #endif #endif } else { // +direction #if HAS_Y_MAX || (Y_SPI_SENSORLESS && Y_HOME_DIR > 0) PROCESS_ENDSTOP_Y(MAX); + #if CORE_DIAG(XY, X, MIN) + PROCESS_CORE_ENDSTOP(X,MIN,Y,MAX); + #elif CORE_DIAG(XY, X, MAX) + PROCESS_CORE_ENDSTOP(X,MAX,Y,MAX); + #elif CORE_DIAG(YZ, Z, MIN) + PROCESS_CORE_ENDSTOP(Z,MIN,Y,MAX); + #elif CORE_DIAG(YZ, Z, MAX) + PROCESS_CORE_ENDSTOP(Z,MAX,Y,MAX); + #endif #endif } } @@ -776,6 +822,15 @@ void Endstops::update() { if ( TERN1(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN, z_probe_enabled) && TERN1(HAS_CUSTOM_PROBE_PIN, !z_probe_enabled) ) PROCESS_ENDSTOP_Z(MIN); + #if CORE_DIAG(XZ, X, MIN) + PROCESS_CORE_ENDSTOP(X,MIN,Z,MIN); + #elif CORE_DIAG(XZ, X, MAX) + PROCESS_CORE_ENDSTOP(X,MAX,Z,MIN); + #elif CORE_DIAG(YZ, Y, MIN) + PROCESS_CORE_ENDSTOP(Y,MIN,Z,MIN); + #elif CORE_DIAG(YZ, Y, MAX) + PROCESS_CORE_ENDSTOP(Y,MAX,Z,MIN); + #endif #endif // When closing the gap check the enabled probe @@ -790,6 +845,15 @@ void Endstops::update() { #elif !HAS_CUSTOM_PROBE_PIN || Z_MAX_PIN != Z_MIN_PROBE_PIN // No probe or probe is Z_MIN || Probe is not Z_MAX PROCESS_ENDSTOP(Z, MAX); #endif + #if CORE_DIAG(XZ, X, MIN) + PROCESS_CORE_ENDSTOP(X,MIN,Z,MAX); + #elif CORE_DIAG(XZ, X, MAX) + PROCESS_CORE_ENDSTOP(X,MAX,Z,MAX); + #elif CORE_DIAG(YZ, Y, MIN) + PROCESS_CORE_ENDSTOP(Y,MIN,Z,MAX); + #elif CORE_DIAG(YZ, Y, MAX) + PROCESS_CORE_ENDSTOP(Y,MAX,Z,MAX); + #endif #endif } } @@ -804,19 +868,37 @@ void Endstops::update() { bool Endstops::tmc_spi_homing_check() { bool hit = false; #if X_SPI_SENSORLESS - if (tmc_spi_homing.x && stepperX.test_stall_status()) { + if (tmc_spi_homing.x && (stepperX.test_stall_status() + #if CORE_IS_XY && Y_SPI_SENSORLESS + || stepperY.test_stall_status() + #elif CORE_IS_XZ && Z_SPI_SENSORLESS + || stepperZ.test_stall_status() + #endif + )) { SBI(live_state, X_STOP); hit = true; } #endif #if Y_SPI_SENSORLESS - if (tmc_spi_homing.y && stepperY.test_stall_status()) { + if (tmc_spi_homing.y && (stepperY.test_stall_status() + #if CORE_IS_XY && X_SPI_SENSORLESS + || stepperX.test_stall_status() + #elif CORE_IS_YZ && Z_SPI_SENSORLESS + || stepperZ.test_stall_status() + #endif + )) { SBI(live_state, Y_STOP); hit = true; } #endif #if Z_SPI_SENSORLESS - if (tmc_spi_homing.z && stepperZ.test_stall_status()) { + if (tmc_spi_homing.z && (stepperZ.test_stall_status() + #if CORE_IS_XZ && X_SPI_SENSORLESS + || stepperX.test_stall_status() + #elif CORE_IS_YZ && Y_SPI_SENSORLESS + || stepperY.test_stall_status() + #endif + )) { SBI(live_state, Z_STOP); hit = true; } diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 021405b4a997..673eee3a924a 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -348,6 +348,11 @@ void line_to_current_position(const feedRate_t &fr_mm_s/*=feedrate_mm_s*/) { #endif // IS_KINEMATIC +/** + * Do a fast or normal move to 'destination' with an optional FR. + * - Move at normal speed regardless of feedrate percentage. + * - Extrude the specified length regardless of flow percentage. + */ void _internal_move_to_destination(const feedRate_t &fr_mm_s/*=0.0f*/ #if IS_KINEMATIC , const bool is_fast/*=false*/ @@ -360,8 +365,8 @@ void _internal_move_to_destination(const feedRate_t &fr_mm_s/*=0.0f*/ feedrate_percentage = 100; #if EXTRUDERS - const float old_fac = planner.e_factor[active_extruder]; - planner.e_factor[active_extruder] = 1.0f; + const float old_fac = planner.e_factor[active_extruder]; + planner.e_factor[active_extruder] = 1.0f; #endif #if IS_KINEMATIC diff --git a/Marlin/src/pins/mega/pins_PICA.h b/Marlin/src/pins/mega/pins_PICA.h index f00d817d6e89..506ce242c5e5 100644 --- a/Marlin/src/pins/mega/pins_PICA.h +++ b/Marlin/src/pins/mega/pins_PICA.h @@ -29,8 +29,8 @@ * Applies to PICA, PICA_REVB */ -#ifndef BOARD_NAME - #define BOARD_NAME "PICA" +#ifndef BOARD_INFO_NAME + #define BOARD_INFO_NAME "PICA" #endif /* diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index 3ce761c6cfff..3dc7a675930f 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -98,6 +98,8 @@ #include "ramps/pins_K8200.h" // ATmega1280, ATmega2560 env:mega1280 env:mega2560 (3DRAG) #elif MB(K8400) #include "ramps/pins_K8400.h" // ATmega1280, ATmega2560 env:mega1280 env:mega2560 (3DRAG) +#elif MB(K8600) + #include "ramps/pins_K8600.h" // ATmega1280, ATmega2560 env:mega1280 env:mega2560 #elif MB(K8800) #include "ramps/pins_K8800.h" // ATmega1280, ATmega2560 env:mega1280 env:mega2560 (3DRAG) #elif MB(BAM_DICE) diff --git a/Marlin/src/pins/ramps/pins_FYSETC_F6_14.h b/Marlin/src/pins/ramps/pins_FYSETC_F6_14.h index f0eb0bf4c643..0597e23a1600 100644 --- a/Marlin/src/pins/ramps/pins_FYSETC_F6_14.h +++ b/Marlin/src/pins/ramps/pins_FYSETC_F6_14.h @@ -25,7 +25,7 @@ // FYSETC F6 v1.4 pin assignments // -#define BOARD_NAME "FYSETC F6 1.4" +#define BOARD_INFO_NAME "FYSETC F6 1.4" #define Z_MAX_PIN 2 diff --git a/Marlin/src/pins/ramps/pins_K8600.h b/Marlin/src/pins/ramps/pins_K8600.h new file mode 100644 index 000000000000..17c230fe32a3 --- /dev/null +++ b/Marlin/src/pins/ramps/pins_K8600.h @@ -0,0 +1,127 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * VERTEX NANO Arduino Mega with RAMPS EFB v1.4 pin assignments. + */ + +#if HOTENDS > 1 + #error "Only 1 hotend is supported for Vertex Nano." +#endif + +#define BOARD_INFO_NAME "K8600" +#define DEFAULT_MACHINE_NAME "Vertex Nano" + +// +// Limit Switches +// +#define X_MIN_PIN 3 +#define Y_MAX_PIN 14 +#define Z_MAX_PIN 18 +#define Z_MIN_PIN -1 + +// +// Heaters / Fans +// +#define FAN_PIN 8 + +// +// Misc. Functions +// +#define CASE_LIGHT_PIN 7 + +// +// Other RAMPS pins +// +#define IS_RAMPS_EFB // Override autodetection. Bed will be undefined. +#include "pins_RAMPS.h" + +// +// Steppers +// +#undef X_STEP_PIN +#undef X_DIR_PIN +#undef X_ENABLE_PIN +#define X_STEP_PIN 54 +#define X_DIR_PIN 55 +#define X_ENABLE_PIN 38 + +#undef Y_STEP_PIN +#undef Y_DIR_PIN +#undef Y_ENABLE_PIN +#define Y_STEP_PIN 60 +#define Y_DIR_PIN 61 +#define Y_ENABLE_PIN 56 + +#undef Z_ENABLE_PIN +#define Z_ENABLE_PIN 63 + +#undef E0_STEP_PIN +#undef E0_DIR_PIN +#undef E0_ENABLE_PIN +#define E0_STEP_PIN 26 +#define E0_DIR_PIN 28 +#define E0_ENABLE_PIN 24 + +// +// Heaters / Fans +// +#undef HEATER_BED_PIN + +// +// Misc. Functions +// +#undef SDSS +#define SDSS 25 // 53 + +// +// LCD / Controller +// +#if BOTH(ULTRA_LCD, NEWPANEL) + #undef BEEPER_PIN + + #undef LCD_PINS_RS + #undef LCD_PINS_ENABLE + #undef LCD_PINS_D4 + #undef LCD_PINS_D5 + #undef LCD_PINS_D6 + #undef LCD_PINS_D7 + #define LCD_PINS_RS 27 + #define LCD_PINS_ENABLE 29 + #define LCD_PINS_D4 37 + #define LCD_PINS_D5 35 + #define LCD_PINS_D6 33 + #define LCD_PINS_D7 31 + + // Buttons + #undef BTN_EN1 + #undef BTN_EN2 + #undef BTN_ENC + #define BTN_EN1 17 + #define BTN_EN2 16 + #define BTN_ENC 23 + +#else + + #define BEEPER_PIN 33 + +#endif diff --git a/Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h b/Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h index 8d7687f52042..5dbffd2897e5 100644 --- a/Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h +++ b/Marlin/src/pins/stm32f1/pins_GTM32_REV_B.h @@ -30,7 +30,7 @@ #error "Oops! Select an STM32F1 board in 'Tools > Board.'" #endif -#define BOARD_NAME "GTM32 Pro VB" +#define BOARD_INFO_NAME "GTM32 Pro VB" #define DEFAULT_MACHINE_NAME "M201" //#define DISABLE_DEBUG diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3.h index 34c265c47b16..5e8f89d56d8e 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3.h @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3D.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3D.h index 9091c99dfc82..e6cf4e528c0d 100644 --- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3D.h +++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_E3D.h @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm diff --git a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN2.h b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN2.h index 36298d05f5e6..0aa6f709f67c 100644 --- a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN2.h +++ b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN2.h @@ -28,7 +28,7 @@ #endif #ifndef BOARD_INFO_NAME - #define BOARD_NAME "MKS_ROBIN2" + #define BOARD_INFO_NAME "MKS_ROBIN2" #endif #ifndef DEFAULT_MACHINE_NAME diff --git a/Marlin/src/pins/stm32f4/pins_VAKE403D.h b/Marlin/src/pins/stm32f4/pins_VAKE403D.h index 4d27910c1664..08f8adebc4f1 100644 --- a/Marlin/src/pins/stm32f4/pins_VAKE403D.h +++ b/Marlin/src/pins/stm32f4/pins_VAKE403D.h @@ -28,7 +28,7 @@ #endif #define DEFAULT_MACHINE_NAME "STM32F446VET6" -#define BOARD_NAME "STM32F4 VAkE" +#define BOARD_INFO_NAME "STM32F4 VAkE" //#define I2C_EEPROM diff --git a/buildroot/share/PlatformIO/variants/BIGTREE_BTT002/variant.h b/buildroot/share/PlatformIO/variants/BIGTREE_BTT002/variant.h index ca56b5f456ee..ecc319f47ce0 100644 --- a/buildroot/share/PlatformIO/variants/BIGTREE_BTT002/variant.h +++ b/buildroot/share/PlatformIO/variants/BIGTREE_BTT002/variant.h @@ -245,11 +245,9 @@ extern "C" { // Timer Definitions //Do not use timer used by PWM pins when possible. See PinMap_PWM in PeripheralPins.c -#define TIMER_TONE TIM6 -#define TIMER_SERIAL TIM7 - -// Do not use basic timer: OC is required -#define TIMER_SERVO TIM2 //TODO: advanced-control timers don't work +#define TIMER_TONE TIM7 +#define TIMER_SERVO TIM5 +#define TIMER_SERIAL TIM2 // UART Definitions // Define here Serial instance number to map on Serial generic name diff --git a/buildroot/share/tests/teensy35-tests b/buildroot/share/tests/teensy35-tests index f2a098e7cd1c..c729f212a427 100755 --- a/buildroot/share/tests/teensy35-tests +++ b/buildroot/share/tests/teensy35-tests @@ -83,13 +83,21 @@ exec_test $1 $2 "Mixing Extruder" # opt_set NUM_SERVOS 1 # opt_enable SWITCHING_EXTRUDER ULTIMAKERCONTROLLER # exec_test $1 $2 "SWITCHING_EXTRUDER" + # # Enable COREXY # restore_configs opt_set MOTHERBOARD BOARD_TEENSY35_36 opt_enable COREXY -exec_test $1 $2 "COREXY" +opt_set X_DRIVER_TYPE TMC5160 +opt_set Y_DRIVER_TYPE TMC5160 +opt_set X_MIN_ENDSTOP_INVERTING true +opt_set Y_MIN_ENDSTOP_INVERTING true +opt_add X_CS_PIN 46 +opt_add Y_CS_PIN 47 +opt_enable USE_ZMIN_PLUG MONITOR_DRIVER_STATUS SENSORLESS_HOMING +exec_test $1 $2 "Teensy 3.5/3.6 COREXY" # # Enable COREXZ @@ -97,7 +105,7 @@ exec_test $1 $2 "COREXY" restore_configs opt_set MOTHERBOARD BOARD_TEENSY35_36 opt_enable COREXZ -exec_test $1 $2 "COREXZ" +exec_test $1 $2 "Teensy 3.5/3.6 COREXZ" # # Enable Dual Z with Dual Z endstops