From 815dfcb14b95d6a95a348cc2b87d53605049584d Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sat, 20 Jan 2018 15:39:21 +0100 Subject: [PATCH] Implemented a stepper timer reset after a long blocking cli() or DISABLE_STEPPER_DRIVER_INTERRUPT(). If this is not done, the stepper interrupt would likely overflow, leading to a maximum 32ms delay before the stepper interrupt wakes up. In addition, the stepper timer overflow error would be reported by the debug builds. --- Firmware/Marlin_main.cpp | 9 ++++++++- Firmware/planner.cpp | 12 ++++++++---- Firmware/stepper.cpp | 16 +--------------- Firmware/stepper.h | 18 ++++++++++++++---- Firmware/ultralcd.cpp | 5 +++++ 5 files changed, 36 insertions(+), 24 deletions(-) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 91cabb90..16581b81 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -628,6 +628,8 @@ void crashdet_stop_and_save_print2() cmdqueue_reset(); //empty cmdqueue card.sdprinting = false; card.closefile(); + // Reset and re-enable the stepper timer just before the global interrupts are enabled. + st_reset_timer(); sei(); } @@ -1993,11 +1995,14 @@ void force_high_power_mode(bool start_high_power_section) { if (silent == 1) { //we are in silent mode, set to normal mode to enable crash detection - + // Wait for the planner queue to drain and for the stepper timer routine to reach an idle state. st_synchronize(); cli(); tmc2130_mode = (start_high_power_section == true) ? TMC2130_MODE_NORMAL : TMC2130_MODE_SILENT; tmc2130_init(); + // We may have missed a stepper timer interrupt due to the time spent in the tmc2130_init() routine. + // Be safe than sorry, reset the stepper timer before re-enabling interrupts. + st_reset_timer(); sei(); digipot_init(); } @@ -7918,6 +7923,8 @@ void stop_and_save_print_to_ram(float z_move, float e_move) card.sdprinting = false; // card.closefile(); saved_printing = true; + // We may have missed a stepper timer interrupt. Be safe than sorry, reset the stepper timer before re-enabling interrupts. + st_reset_timer(); sei(); if ((z_move != 0) || (e_move != 0)) { // extruder or z move #if 1 diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 0aa60866..d7f30d23 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -565,8 +565,7 @@ extern volatile uint32_t step_events_completed; // The number of step events exe void planner_abort_hard() { // Abort the stepper routine and flush the planner queue. - // DISABLE_STEPPER_DRIVER_INTERRUPT - TIMSK1 &= ~(1<decelerate_after after which it decelerates until the trapezoid generator is reset. // The slope of acceleration is calculated with the leib ramp alghorithm. -void st_wake_up() { - // TCNT1 = 0; - ENABLE_STEPPER_DRIVER_INTERRUPT(); -} - -void step_wait(){ - for(int8_t i=0; i < 6; i++){ - } -} - - FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) { unsigned short timer; if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY; @@ -1241,6 +1226,7 @@ void quickStop() DISABLE_STEPPER_DRIVER_INTERRUPT(); while (blocks_queued()) plan_discard_current_block(); current_block = NULL; + st_reset_timer(); ENABLE_STEPPER_DRIVER_INTERRUPT(); } diff --git a/Firmware/stepper.h b/Firmware/stepper.h index 9915de90..2fdec2d6 100644 --- a/Firmware/stepper.h +++ b/Firmware/stepper.h @@ -23,6 +23,9 @@ #include "planner.h" +#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1< 2 #define WRITE_E_STEP(v) { if(current_block->active_extruder == 2) { WRITE(E2_STEP_PIN, v); } else { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}} #define NORM_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, !INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}} @@ -71,11 +74,18 @@ void st_get_position_xy(long &x, long &y); float st_get_position_mm(uint8_t axis); -// The stepper subsystem goes to sleep when it runs out of things to execute. Call this -// to notify the subsystem that it is time to go to work. -void st_wake_up(); +// Call this function just before re-enabling the stepper driver interrupt and the global interrupts +// to avoid a stepper timer overflow. +FORCE_INLINE void st_reset_timer() +{ + // Clear a possible pending interrupt on OCR1A overflow. + TIFR1 |= 1 << OCF1A; + // Reset the counter. + TCNT1 = 0; + // Wake up after 1ms from now. + OCR1A = 2000; +} - void checkHitEndstops(); //call from somewhere to create an serial error message with the locations the endstops where hit, in case they were triggered bool endstops_hit_on_purpose(); //avoid creation of the message, i.e. after homing and before a routine call of checkHitEndstops(); bool endstop_z_hit_on_purpose(); diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 5f5091b0..e5c81ff6 100644 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -3359,6 +3359,8 @@ static void lcd_silent_mode_set() { SilentModeMenu = !SilentModeMenu; eeprom_update_byte((unsigned char *)EEPROM_SILENT, SilentModeMenu); #ifdef TMC2130 + // Wait until the planner queue is drained and the stepper routine achieves + // an idle state. st_synchronize(); if (tmc2130_wait_standstill_xy(1000)) {} // MYSERIAL.print("standstill OK"); @@ -3367,6 +3369,9 @@ static void lcd_silent_mode_set() { cli(); tmc2130_mode = SilentModeMenu?TMC2130_MODE_SILENT:TMC2130_MODE_NORMAL; tmc2130_init(); + // We may have missed a stepper timer interrupt due to the time spent in tmc2130_init. + // Be safe than sorry, reset the stepper timer before re-enabling interrupts. + st_reset_timer(); sei(); #endif //TMC2130 digipot_init();