From dd2468d306b358d0645afa92baa162ccfd0220ac Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 15 Feb 2018 11:44:19 +0100 Subject: [PATCH] Avoid the stepper interrupt being missed by extending the tick time beyond the current time. This is a trick borrwed from upstream Marlin. In debug mode, watch for the missed stepper interrupt ticks where the interrupts are missed by more than 20% of the 10kHz stepper interrupt repeat rate, and show the statistics (number of missed ticks and by how many micro seconds was the interrupt missed, and what was the maximum missed interrupt delay) on the display and send it to the serial line. --- Firmware/stepper.cpp | 32 ++++++++++++++++++-------------- Firmware/ultralcd.cpp | 19 +++++++++++++------ 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index c636ae39..3ac2ffc2 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -131,6 +131,7 @@ uint8_t LastStepMask = 0; #ifdef DEBUG_STEPPER_TIMER_MISSED extern bool stepper_timer_overflow_state; +extern uint16_t stepper_timer_overflow_last; #endif /* DEBUG_STEPPER_TIMER_MISSED */ //=========================================================================== @@ -381,22 +382,25 @@ ISR(TIMER1_COMPA_vect) { isr(); // Don't run the ISR faster than possible -// if (OCR1A < TCNT1 + 16) OCR1A = TCNT1 + 16; + // Is there a 8us time left before the next interrupt triggers? + if (OCR1A < TCNT1 + 16) { #ifdef DEBUG_STEPPER_TIMER_MISSED - // Verify whether the next planned timer interrupt has not been missed already. - // This debugging test takes < 1.125us - // This skews the profiling slightly as the fastest stepper timer - // interrupt repeats at a 100us rate (10kHz). - if (OCR1A < TCNT1) { - stepper_timer_overflow_state = true; - WRITE_NC(BEEPER, HIGH); - SERIAL_PROTOCOLPGM("Stepper timer overflow "); - SERIAL_PROTOCOL(OCR1A); - SERIAL_PROTOCOLPGM("<"); - SERIAL_PROTOCOL(TCNT1); - SERIAL_PROTOCOLLN("!"); - } + // Verify whether the next planned timer interrupt has not been missed already. + // This debugging test takes < 1.125us + // This skews the profiling slightly as the fastest stepper timer + // interrupt repeats at a 100us rate (10kHz). + if (OCR1A + 40 < TCNT1) { + // The interrupt was delayed by more than 20us (which is 1/5th of the 10kHz ISR repeat rate). + // Give a warning. + stepper_timer_overflow_state = true; + stepper_timer_overflow_last = TCNT1 - OCR1A; + // Beep, the beeper will be cleared at the stepper_timer_overflow() called from the main thread. + WRITE(BEEPER, HIGH); + } #endif + // Fix the next interrupt to be executed after 8us from now. + OCR1A = TCNT1 + 16; + } } FORCE_INLINE void stepper_next_block() diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 29c0ed40..6a14a916 100644 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -5182,14 +5182,21 @@ void stack_error() { #ifdef DEBUG_STEPPER_TIMER_MISSED bool stepper_timer_overflow_state = false; +uint16_t stepper_timer_overflow_max = 0; +uint16_t stepper_timer_overflow_last = 0; +uint16_t stepper_timer_overflow_cnt = 0; void stepper_timer_overflow() { - SET_OUTPUT(BEEPER); - WRITE(BEEPER, HIGH); - delay(1000); + char msg[28]; + sprintf_P(msg, PSTR("#%d %d max %d"), ++ stepper_timer_overflow_cnt, stepper_timer_overflow_last >> 1, stepper_timer_overflow_max >> 1); + lcd_setstatus(msg); + stepper_timer_overflow_state = false; + if (stepper_timer_overflow_last > stepper_timer_overflow_max) + stepper_timer_overflow_max = stepper_timer_overflow_last; + SERIAL_ECHOPGM("Stepper timer overflow: "); + MYSERIAL.print(msg); + SERIAL_ECHOLNPGM(""); + WRITE(BEEPER, LOW); - lcd_display_message_fullscreen_P(MSG_STEPPER_TIMER_OVERFLOW_ERROR); - //err_triggered = 1; - while (1) delay_keep_alive(1000); } #endif /* DEBUG_STEPPER_TIMER_MISSED */