Skip to content

Commit

Permalink
♻️ Move watchdog to MarlinHAL
Browse files Browse the repository at this point in the history
  • Loading branch information
thinkyhead committed May 20, 2022
1 parent 12da2e9 commit 52eefa9
Show file tree
Hide file tree
Showing 62 changed files with 505 additions and 1,101 deletions.
53 changes: 53 additions & 0 deletions Marlin/src/HAL/AVR/HAL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include "../../inc/MarlinConfig.h"
#include "HAL.h"
#include <avr/wdt.h>

#ifdef USBCON
DefaultSerial1 MSerial0(false, Serial);
Expand Down Expand Up @@ -88,6 +89,58 @@ void MarlinHAL::reboot() {
#endif
}

// ------------------------
// Watchdog Timer
// ------------------------

#if ENABLED(USE_WATCHDOG)

#include <avr/wdt.h>
#include "../../MarlinCore.h"

// Initialize watchdog with 8s timeout, if possible. Otherwise, make it 4s.
void MarlinHAL::watchdog_init() {
#if ENABLED(WATCHDOG_DURATION_8S) && defined(WDTO_8S)
#define WDTO_NS WDTO_8S
#else
#define WDTO_NS WDTO_4S
#endif
#if ENABLED(WATCHDOG_RESET_MANUAL)
// Enable the watchdog timer, but only for the interrupt.
// Take care, as this requires the correct order of operation, with interrupts disabled.
// See the datasheet of any AVR chip for details.
wdt_reset();
cli();
_WD_CONTROL_REG = _BV(_WD_CHANGE_BIT) | _BV(WDE);
_WD_CONTROL_REG = _BV(WDIE) | (WDTO_NS & 0x07) | ((WDTO_NS & 0x08) << 2); // WDTO_NS directly does not work. bit 0-2 are consecutive in the register but the highest value bit is at bit 5
// So worked for up to WDTO_2S
sei();
wdt_reset();
#else
wdt_enable(WDTO_NS); // The function handles the upper bit correct.
#endif
//delay(10000); // test it!
}

//===========================================================================
//=================================== ISR ===================================
//===========================================================================

// Watchdog timer interrupt, called if main program blocks >4sec and manual reset is enabled.
#if ENABLED(WATCHDOG_RESET_MANUAL)
ISR(WDT_vect) {
sei(); // With the interrupt driven serial we need to allow interrupts.
SERIAL_ERROR_MSG(STR_WATCHDOG_FIRED);
minkill(); // interrupt-safe final kill and infinite loop
}
#endif

// Reset watchdog. MUST be called at least every 4 seconds after the
// first watchdog_init or AVR will go into emergency procedures.
void MarlinHAL::watchdog_refresh() { wdt_reset(); }

#endif // USE_WATCHDOG

// ------------------------
// Free Memory Accessor
// ------------------------
Expand Down
5 changes: 4 additions & 1 deletion Marlin/src/HAL/AVR/HAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#include "../shared/Marduino.h"
#include "../shared/HAL_SPI.h"
#include "fastio.h"
#include "watchdog.h"
#include "math.h"

#ifdef USBCON
Expand Down Expand Up @@ -189,6 +188,10 @@ class MarlinHAL {
// Earliest possible init, before setup()
MarlinHAL() {}

// Watchdog
static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {});
static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {});

static void init(); // Called early in setup()
static void init_board() {} // Called less early in setup()
static void reboot(); // Restart the firmware from 0x0
Expand Down
70 changes: 0 additions & 70 deletions Marlin/src/HAL/AVR/watchdog.cpp

This file was deleted.

31 changes: 0 additions & 31 deletions Marlin/src/HAL/AVR/watchdog.h

This file was deleted.

95 changes: 94 additions & 1 deletion Marlin/src/HAL/DUE/HAL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#ifdef ARDUINO_ARCH_SAM

#include "../../inc/MarlinConfig.h"
#include "HAL.h"
#include "../../MarlinCore.h"

#include <Wire.h>
#include "usb/usb_task.h"
Expand Down Expand Up @@ -73,6 +73,99 @@ uint8_t MarlinHAL::get_reset_source() {

void MarlinHAL::reboot() { rstc_start_software_reset(RSTC); }

// ------------------------
// Watchdog Timer
// ------------------------

#if ENABLED(USE_WATCHDOG)

// Initialize watchdog - On SAM3X, Watchdog was already configured
// and enabled or disabled at startup, so no need to reconfigure it
// here.
void MarlinHAL::watchdog_init() { WDT_Restart(WDT); } // Reset watchdog to start clean

// Reset watchdog. MUST be called at least every 4 seconds after the
// first watchdog_init or AVR will go into emergency procedures.
void MarlinHAL::watchdog_refresh() { watchdogReset(); }

#endif

// Override Arduino runtime to either config or disable the watchdog
//
// We need to configure the watchdog as soon as possible in the boot
// process, because watchdog initialization at hardware reset on SAM3X8E
// is unreliable, and there is risk of unintended resets if we delay
// that initialization to a later time.
void watchdogSetup() {

#if ENABLED(USE_WATCHDOG)

// 4 seconds timeout
uint32_t timeout = TERN(WATCHDOG_DURATION_8S, 8000, 4000);

// Calculate timeout value in WDT counter ticks: This assumes
// the slow clock is running at 32.768 kHz watchdog
// frequency is therefore 32768 / 128 = 256 Hz
timeout = (timeout << 8) / 1000;
if (timeout == 0)
timeout = 1;
else if (timeout > 0xFFF)
timeout = 0xFFF;

// We want to enable the watchdog with the specified timeout
uint32_t value =
WDT_MR_WDV(timeout) | // With the specified timeout
WDT_MR_WDD(timeout) | // and no invalid write window
#if !(SAMV70 || SAMV71 || SAME70 || SAMS70)
WDT_MR_WDRPROC | // WDT fault resets processor only - We want
// to keep PIO controller state
#endif
WDT_MR_WDDBGHLT | // WDT stops in debug state.
WDT_MR_WDIDLEHLT; // WDT stops in idle state.

#if ENABLED(WATCHDOG_RESET_MANUAL)
// We enable the watchdog timer, but only for the interrupt.

// Configure WDT to only trigger an interrupt
value |= WDT_MR_WDFIEN; // Enable WDT fault interrupt.

// Disable WDT interrupt (just in case, to avoid triggering it!)
NVIC_DisableIRQ(WDT_IRQn);

// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();

// Initialize WDT with the given parameters
WDT_Enable(WDT, value);

// Configure and enable WDT interrupt.
NVIC_ClearPendingIRQ(WDT_IRQn);
NVIC_SetPriority(WDT_IRQn, 0); // Use highest priority, so we detect all kinds of lockups
NVIC_EnableIRQ(WDT_IRQn);

#else

// a WDT fault triggers a reset
value |= WDT_MR_WDRSTEN;

// Initialize WDT with the given parameters
WDT_Enable(WDT, value);

#endif

// Reset the watchdog
WDT_Restart(WDT);

#else

// Make sure to completely disable the Watchdog
WDT_Disable(WDT);

#endif
}

// ------------------------
// Free Memory Accessor
// ------------------------
Expand Down
11 changes: 7 additions & 4 deletions Marlin/src/HAL/DUE/HAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h"
#include "fastio.h"
#include "watchdog.h"

#include <stdint.h>

Expand Down Expand Up @@ -176,9 +175,13 @@ class MarlinHAL {
// Earliest possible init, before setup()
MarlinHAL() {}

static void init(); // Called early in setup()
static void init_board(); // Called less early in setup()
static void reboot(); // Software reset
// Watchdog
static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {});
static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {});

static void init(); // Called early in setup()
static void init_board(); // Called less early in setup()
static void reboot(); // Restart the firmware

// Interrupts
static bool isr_state() { return !__get_PRIMASK(); }
Expand Down
Loading

0 comments on commit 52eefa9

Please sign in to comment.