Skip to content

Commit

Permalink
Fix watchdog feeding (address #4)
Browse files Browse the repository at this point in the history
  • Loading branch information
prototypicalpro committed Apr 8, 2020
1 parent 48e600f commit 128ef72
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 4 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ FeatherFault currently handles three failure modes: hanging, [memory overflow](h

Hanging detection is implemented using the SAMD watchdog timer early warning interrupt. As a result, FeatherFault will not detect hanging unless `FeatherFault::StartWDT` is called somewhere in the beginning of the sketch. Note that similar to normal watchdog operation, FeatherFaults detection must be periodically resetting using `MARK` macro; this means that the `MARK` macro must be placed such that it is called at least periodically under the timeout specified. In long operations that cannot be `MARK`ed (sleep being an example), use `FeatherFault::StopWDT` to disable the watchdog during that time.

Behind the scenes watchdog feeding is implemented in terms of a global atomic boolean which determines if the device should fault during the watchdog interrupt, as opposed to the standard register write found in SleepyDog and other libraries. This decision was made because feeding the WDT on the SAMD21 is [extremely slow (1-5ms)](https://www.avrfreaks.net/forum/c21-watchdog-syncing-too-slow), which is unacceptable for the `MARK` macro (see https://github.com/OPEnSLab-OSU/FeatherFault/issues/4). Note that due to this implementation, the watchdog interrupt happens regularly and may take an extended period of time (1-5ms), causing possible timing issues with other code.

#### Memory Overflow Detection

Memory overflow detection is implemented by checking the top of the heap against the top of the stack. If the stack is overwriting the heap, memory is assumed to be corrupted and the board is immediately reset. This check is performed inside the `MARK` macro.
Expand Down
17 changes: 14 additions & 3 deletions src/FeatherFault.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ typedef union {

static const uint32_t pageSizes[] = { 8, 16, 32, 64, 128, 256, 512, 1024 };

/** Global atmoic bool to check if the watchdog has been fed, we use a boolean instead of WDT_Reset because watchdog synchronization is slow */
static volatile std::atomic_bool should_feed_watchdog(false);
/** Global atomic bool to specify that last_line or last_file are being written to, determines if a fault happened while they were being written */
static volatile std::atomic_bool is_being_written(false);
/** Global variable to store the last line MARKed, written by FeatherFault::_Mark and read by FeatherFault::HandleFault */
Expand Down Expand Up @@ -146,8 +148,14 @@ static void WDTReset() {
/** WDT Handler, calls HandleFault(FeatherFault::FAULT_HUNG) */
[[ noreturn ]] __attribute__ ((interrupt ("IRQ"))) void WDT_Handler() {
WDT->INTFLAG.bit.EW = 1; // Clear interrupt flag
// Handle fault!
HandleFault(FeatherFault::FAULT_HUNG);
// Check if the watchdog has been "fed", if so, reset the watchdog and continue
if (should_feed_watchdog.load()){
should_feed_watchdog.store(false);
WDTReset();
}
// else there's been a timeout, so fault!
else
HandleFault(FeatherFault::FAULT_HUNG);
}

/** HardFault Handler, calls HandleFault(FeatherFault::FAULT_HARDFAULT) */
Expand Down Expand Up @@ -194,6 +202,7 @@ void FeatherFault::StartWDT(const FeatherFault::WDTTimeout timeout) {
// Start watchdog now!
WDT->CTRL.bit.ENABLE = 1;
while(WDT->STATUS.bit.SYNCBUSY);
should_feed_watchdog.load(false);
}


Expand All @@ -211,7 +220,9 @@ void FeatherFault::SetCallback(volatile void(*callback)()) {

/* See FeatherFault.h */
void FeatherFault::_Mark(const int line, const char* file) {
WDTReset();
// feed the watchdog
should_feed_watchdog.store(true);
// write the last marked data
is_being_written.store(true);
last_line = line;
last_file = file;
Expand Down
2 changes: 1 addition & 1 deletion src/FeatherFault.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,4 @@ namespace FeatherFault {
* This macro is a proxy for FeatherFault::_Mark, allowing it to
* grab the line # and filename.
*/
#define MARK { FeatherFault::_Mark(__LINE__, __SHORT_FILE__); }
#define MARK { constexpr const char* const filename = __SHORT_FILE__; FeatherFault::_Mark(__LINE__, filename); }

0 comments on commit 128ef72

Please sign in to comment.