From 3b4977bd2e25feb56a18d76d9fea2047fb519be1 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Sun, 27 Jan 2019 10:24:21 +0000 Subject: [PATCH] Add software watchdog timer. --- README.md | 7 ++++ soft_wdt/soft_wdt.py | 38 +++++++++++++++++++++ soft_wdt/swdt_tests.py | 75 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 soft_wdt/soft_wdt.py create mode 100644 soft_wdt/swdt_tests.py diff --git a/README.md b/README.md index 0215564..b321669 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,13 @@ program to access shared data in a manner which ensures data integrity. Access the simpler of the Pyboard's watchdog timers. +# software watchdog (soft_wdt) + +A software watchdog timer with a fixed or variable timeout. Supports temporary +suspension and permanent cancellation. The latter can be useful when debugging +code to prevent a machine reboot when the application fails, terminates or is +interrupted with ctrl-c. See code and comments in swdt_tests.py. + # reverse Fast reverse a bytearray in Arm Thumb assembler. diff --git a/soft_wdt/soft_wdt.py b/soft_wdt/soft_wdt.py new file mode 100644 index 0000000..0934e47 --- /dev/null +++ b/soft_wdt/soft_wdt.py @@ -0,0 +1,38 @@ +# soft_wdt.py A software watchdog timer +# Supports fixed or variable time period. +# Supports temporary suspension and permanent cancellation. + +# Copyright (c) Peter Hinch 2019 +# Released under the MIT licence. + +from machine import Timer, reset +from micropython import const +WDT_SUSPEND = const(-1) +WDT_CANCEL = const(-2) +WDT_CB = const(-3) + +def wdt(secs=0): + timer = Timer(-1) + timer.init(period=1000, mode=Timer.PERIODIC, callback=lambda t:wdt_feed()) + cnt = secs + run = False # Disable until 1st feed + def inner(feed=WDT_CB): + nonlocal cnt, run, timer + if feed > 0: # Call with variable timeout + cnt = feed + run = True + elif feed == 0: # Fixed timeout + cnt = secs + run = True + elif feed < 0: # WDT control/callback + if feed == WDT_SUSPEND: + run = False # Temporary suspension + elif feed == WDT_CANCEL: + timer.deinit() # Permanent cancellation + elif feed == WDT_CB and run: # Timer callback and is running. + cnt -= 1 + if cnt <= 0: + reset() + return inner + +wdt_feed = wdt(2) # Modify this for preferred default period (secs) diff --git a/soft_wdt/swdt_tests.py b/soft_wdt/swdt_tests.py new file mode 100644 index 0000000..6d18ef6 --- /dev/null +++ b/soft_wdt/swdt_tests.py @@ -0,0 +1,75 @@ +# swdt_tests Test/demo scripts for soft_wdt + +# Copyright (c) Peter Hinch 2019 +# Released under the MIT licence. +import utime +from soft_wdt import wdt_feed, WDT_CANCEL, WDT_SUSPEND + +# Exception trapping and cancellation are invaluable when debugging code: put +# cancellation in the finally block of a try statement so that the hardware +# doesn't reset when code terminates either naturally or in response to an +# error or ctrl-c interrupt. + +# Normal operation. Illustrates exception trapping. You can interrupt this with +# ctrl-c +def normal(): + try: + for x in range(10, 0, -1): + print('nunning', x) + utime.sleep(0.5) + wdt_feed(5) # Hold off for 5s + + print('Should reset in 5s') + utime.sleep(10) + except KeyboardInterrupt: + pass + finally: + wdt_feed(WDT_CANCEL) # Should never execute + +# Suspend and resume + +def suspend(): + for x in range(10, 0, -1): + print('nunning', x) + utime.sleep(0.5) + wdt_feed(5) # Hold off for 5s + + wdt_feed(WDT_SUSPEND) + for x in range(5, 0, -1): + print('suspended', x) + utime.sleep(0.5) + + for x in range(5, 0, -1): + print('nunning', x) + utime.sleep(0.5) + wdt_feed(5) # Hold off for 5s + + print('Should reset in 5s') + utime.sleep(10) + wdt_feed(WDT_CANCEL) # Should never execute + +# Default period + +def default(): + for x in range(10, 0, -1): + print('nunning', x) + utime.sleep(0.5) + wdt_feed(5) # Hold off for 5s + + wdt_feed(0) # Use default period + print('Should reset in 2s') + utime.sleep(10) + wdt_feed(WDT_CANCEL) # Should never execute + +# Cancellation +def cancel(): + for x in range(10, 0, -1): + print('nunning', x) + utime.sleep(0.5) + wdt_feed(5) # Hold off for 5s + + wdt_feed(WDT_CANCEL) + + print('Pause 10s: should not reset in 5s') + utime.sleep(10) + print('WDT is permanently cancelled.')