From fffb15cc816ae347b9aa6acd536140bc2e32c121 Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Fri, 13 Jan 2023 15:18:00 +0100 Subject: [PATCH] Fix MK2.5 softReset() Disable the watchdog early in the program More documentation for pins file retrigger build fix watchdog not getting disabled on user app boot Fix interrupts not enabled during setup() --- Firmware/Marlin_main.cpp | 47 +++++++++++++++++++++++++++++------- Firmware/optiboot_xflash.cpp | 6 ++--- Firmware/pins_Einsy_1_0.h | 1 + Firmware/pins_Rambo_1_0.h | 2 ++ Firmware/pins_Rambo_1_3.h | 2 ++ 5 files changed, 45 insertions(+), 13 deletions(-) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index eafe7b77c..58c50f6c7 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -84,6 +84,7 @@ #include "Prusa_farm.h" #include +#include #include #include "Dcodes.h" @@ -700,10 +701,40 @@ void failstats_reset_print() #endif } -void softReset() -{ +void watchdogEarlyDisable(void) { + // Regardless if the watchdog support is enabled or not, disable the watchdog very early + // after the program starts since there's no danger in doing this. + // The reason for this is because old bootloaders might not handle the watchdog timer at all, + // leaving it enabled when jumping to the program. This could cause another watchdog reset + // during setup() if not handled properly. So to avoid any issue of this kind, stop the + // watchdog timer manually. + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + wdt_reset(); + MCUSR &= ~_BV(WDRF); + wdt_disable(); + } +} + +void softReset(void) { cli(); - wdt_enable(WDTO_15MS); +#ifdef WATCHDOG + // If the watchdog support is enabled, use that for resetting. The timeout value is customized + // for each board since the miniRambo ships with a bootloader which doesn't properly handle the + // WDT. In order to avoid bootlooping, the watchdog is set to a value large enough for the + // usual timeout of the bootloader to pass. + wdt_enable(WATCHDOG_SOFT_RESET_VALUE); +#else + #warning WATCHDOG not defined. See the following comment for more details about the implications + // In case the watchdog is not enabled, the reset is acomplished by jumping to the bootloader + // vector manually. This however is somewhat dangerous since the peripherals don't get reset + // by this operation. Considering this is not going to be used in any production firmware, + // it can be left as is and just be cautious with it. The only way to accomplish a peripheral + // reset is by an external reset, by a watchdog reset or by a power cycle. All of these options + // can't be accomplished just from software. One way to minimize the dangers of this is by + // setting all dangerous pins to INPUT before jumping to the bootloader, but that still doesn't + // reset other peripherals such as UART, timers, INT, PCINT, etc... + asm volatile("jmp 0x3E000"); +#endif while(1); } @@ -1061,6 +1092,8 @@ static void xflash_err_msg() // are initialized by the main() routine provided by the Arduino framework. void setup() { + watchdogEarlyDisable(); + timer2_init(); // enables functional millis mmu_init(); @@ -4282,18 +4315,14 @@ void process_commands() mmu_reset(); } else if (code_seen_P(PSTR("RESET"))) { // PRUSA RESET -#ifdef WATCHDOG #if defined(XFLASH) && defined(BOOTAPP) boot_app_magic = BOOT_APP_MAGIC; boot_app_flags = BOOT_APP_FLG_RUN; #endif //defined(XFLASH) && defined(BOOTAPP) softReset(); -#elif defined(BOOTAPP) //this is a safety precaution. This is because the new bootloader turns off the heaters, but the old one doesn't. The watchdog should be used most of the time. - asm volatile("jmp 0x3E000"); -#endif - } + } #ifdef PRUSA_SN_SUPPORT - else if (code_seen_P(PSTR("SN"))) { // PRUSA SN + else if (code_seen_P(PSTR("SN"))) { // PRUSA SN char SN[20]; eeprom_read_block(SN, (uint8_t*)EEPROM_PRUSA_SN, 20); if (SN[19]) diff --git a/Firmware/optiboot_xflash.cpp b/Firmware/optiboot_xflash.cpp index 02d198918..791435b83 100644 --- a/Firmware/optiboot_xflash.cpp +++ b/Firmware/optiboot_xflash.cpp @@ -55,9 +55,7 @@ static void putch(char ch) { static void verifySpace() { if (getch() != CRC_EOP) { putch(STK_FAILED); - wdt_enable(WDTO_15MS); // shorten WD timeout - while (1) // and busy-loop so that WD causes - ; // a reset and app start. + softReset(); } putch(STK_INSYNC); } @@ -300,7 +298,7 @@ uint8_t optiboot_xflash_enter() } else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */ // Adaboot no-wait mod - wdt_enable(WDTO_15MS); + wdt_enable(WATCHDOG_SOFT_RESET_VALUE); verifySpace(); } else { diff --git a/Firmware/pins_Einsy_1_0.h b/Firmware/pins_Einsy_1_0.h index d8c316b44..12409de4e 100755 --- a/Firmware/pins_Einsy_1_0.h +++ b/Firmware/pins_Einsy_1_0.h @@ -19,6 +19,7 @@ #define XFLASH // external 256kB flash #define BOOTAPP // bootloader support +#define WATCHDOG_SOFT_RESET_VALUE WDTO_15MS #define XFLASH_PIN_CS 32 diff --git a/Firmware/pins_Rambo_1_0.h b/Firmware/pins_Rambo_1_0.h index b727e52f6..17629af6b 100644 --- a/Firmware/pins_Rambo_1_0.h +++ b/Firmware/pins_Rambo_1_0.h @@ -14,6 +14,8 @@ #define SWI2C_SDA 20 //SDA on P3 #define SWI2C_SCL 84 //PH2 on P3, sensor cable must be rewired +// This should be long enough to safely exit the bootloader when it uses the default timeout (~1-2s) +#define WATCHDOG_SOFT_RESET_VALUE WDTO_2S #define X_STEP_PIN 37 diff --git a/Firmware/pins_Rambo_1_3.h b/Firmware/pins_Rambo_1_3.h index e6bdfd93e..3d8099e5c 100644 --- a/Firmware/pins_Rambo_1_3.h +++ b/Firmware/pins_Rambo_1_3.h @@ -17,6 +17,8 @@ #define D_REQUIRE 23 //Z_MAX (white) #endif //MICROMETER_LOGGING +// This should be long enough to safely exit the bootloader when it uses the default timeout (~1-2s) +#define WATCHDOG_SOFT_RESET_VALUE WDTO_2S #define X_STEP_PIN 37