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.
This commit is contained in:
bubnikv 2018-01-20 15:39:21 +01:00
parent 17a8e2db01
commit 815dfcb14b
5 changed files with 36 additions and 24 deletions

View file

@ -628,6 +628,8 @@ void crashdet_stop_and_save_print2()
cmdqueue_reset(); //empty cmdqueue cmdqueue_reset(); //empty cmdqueue
card.sdprinting = false; card.sdprinting = false;
card.closefile(); card.closefile();
// Reset and re-enable the stepper timer just before the global interrupts are enabled.
st_reset_timer();
sei(); sei();
} }
@ -1993,11 +1995,14 @@ void force_high_power_mode(bool start_high_power_section) {
if (silent == 1) { if (silent == 1) {
//we are in silent mode, set to normal mode to enable crash detection //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(); st_synchronize();
cli(); cli();
tmc2130_mode = (start_high_power_section == true) ? TMC2130_MODE_NORMAL : TMC2130_MODE_SILENT; tmc2130_mode = (start_high_power_section == true) ? TMC2130_MODE_NORMAL : TMC2130_MODE_SILENT;
tmc2130_init(); 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(); sei();
digipot_init(); digipot_init();
} }
@ -7918,6 +7923,8 @@ void stop_and_save_print_to_ram(float z_move, float e_move)
card.sdprinting = false; card.sdprinting = false;
// card.closefile(); // card.closefile();
saved_printing = true; 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(); sei();
if ((z_move != 0) || (e_move != 0)) { // extruder or z move if ((z_move != 0) || (e_move != 0)) { // extruder or z move
#if 1 #if 1

View file

@ -565,8 +565,7 @@ extern volatile uint32_t step_events_completed; // The number of step events exe
void planner_abort_hard() void planner_abort_hard()
{ {
// Abort the stepper routine and flush the planner queue. // Abort the stepper routine and flush the planner queue.
// DISABLE_STEPPER_DRIVER_INTERRUPT DISABLE_STEPPER_DRIVER_INTERRUPT();
TIMSK1 &= ~(1<<OCIE1A);
// Now the front-end (the Marlin_main.cpp with its current_position) is out of sync. // Now the front-end (the Marlin_main.cpp with its current_position) is out of sync.
// First update the planner's current position in the physical motor steps. // First update the planner's current position in the physical motor steps.
@ -612,7 +611,7 @@ void planner_abort_hard()
#endif #endif
} }
#endif #endif
// Clear the planner queue. // Clear the planner queue, reset and re-enable the stepper timer.
quickStop(); quickStop();
// Apply inverse world correction matrix. // Apply inverse world correction matrix.
@ -1297,7 +1296,12 @@ Having the real displacement of the head, we can calculate the total movement le
#ifdef PLANNER_DIAGNOSTICS #ifdef PLANNER_DIAGNOSTICS
planner_update_queue_min_counter(); planner_update_queue_min_counter();
#endif /* PLANNER_DIAGNOSTIC */ #endif /* PLANNER_DIAGNOSTIC */
st_wake_up();
// The stepper timer interrupt will run continuously from now on.
// If there are no planner blocks to be executed by the stepper routine,
// the stepper interrupt ticks at 1kHz to wake up and pick a block
// from the planner queue if available.
ENABLE_STEPPER_DRIVER_INTERRUPT();
} }
#ifdef ENABLE_AUTO_BED_LEVELING #ifdef ENABLE_AUTO_BED_LEVELING

View file

@ -222,10 +222,6 @@ void MultiU24X24toH16(uint16_t& intRes, int32_t& longIn1, long& longIn2)
// Some useful constants // Some useful constants
#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1<<OCIE1A)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 &= ~(1<<OCIE1A)
void checkHitEndstops() void checkHitEndstops()
{ {
if( endstop_x_hit || endstop_y_hit || endstop_z_hit) { if( endstop_x_hit || endstop_y_hit || endstop_z_hit) {
@ -308,17 +304,6 @@ bool enable_z_endstop(bool check)
// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. // 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 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) { FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) {
unsigned short timer; unsigned short timer;
if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY; if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY;
@ -1241,6 +1226,7 @@ void quickStop()
DISABLE_STEPPER_DRIVER_INTERRUPT(); DISABLE_STEPPER_DRIVER_INTERRUPT();
while (blocks_queued()) plan_discard_current_block(); while (blocks_queued()) plan_discard_current_block();
current_block = NULL; current_block = NULL;
st_reset_timer();
ENABLE_STEPPER_DRIVER_INTERRUPT(); ENABLE_STEPPER_DRIVER_INTERRUPT();
} }

View file

@ -23,6 +23,9 @@
#include "planner.h" #include "planner.h"
#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1<<OCIE1A)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 &= ~(1<<OCIE1A)
#if EXTRUDERS > 2 #if EXTRUDERS > 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 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); }}} #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); float st_get_position_mm(uint8_t axis);
// The stepper subsystem goes to sleep when it runs out of things to execute. Call this // Call this function just before re-enabling the stepper driver interrupt and the global interrupts
// to notify the subsystem that it is time to go to work. // to avoid a stepper timer overflow.
void st_wake_up(); 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 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 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(); bool endstop_z_hit_on_purpose();

View file

@ -3359,6 +3359,8 @@ static void lcd_silent_mode_set() {
SilentModeMenu = !SilentModeMenu; SilentModeMenu = !SilentModeMenu;
eeprom_update_byte((unsigned char *)EEPROM_SILENT, SilentModeMenu); eeprom_update_byte((unsigned char *)EEPROM_SILENT, SilentModeMenu);
#ifdef TMC2130 #ifdef TMC2130
// Wait until the planner queue is drained and the stepper routine achieves
// an idle state.
st_synchronize(); st_synchronize();
if (tmc2130_wait_standstill_xy(1000)) {} if (tmc2130_wait_standstill_xy(1000)) {}
// MYSERIAL.print("standstill OK"); // MYSERIAL.print("standstill OK");
@ -3367,6 +3369,9 @@ static void lcd_silent_mode_set() {
cli(); cli();
tmc2130_mode = SilentModeMenu?TMC2130_MODE_SILENT:TMC2130_MODE_NORMAL; tmc2130_mode = SilentModeMenu?TMC2130_MODE_SILENT:TMC2130_MODE_NORMAL;
tmc2130_init(); 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(); sei();
#endif //TMC2130 #endif //TMC2130
digipot_init(); digipot_init();