Mbed-os: Watchdog

Created on 14 Aug 2019  路  9Comments  路  Source: ARMmbed/mbed-os

Description

When using the WDT it's important to get it enabled ASAP on boot, the current API doesn't really allow for this.

Currently the only easy way to enable the WDT is with a call to start at the top of the main, however this does not catch issues such as a hang during the constructor of a global class.

Take the example of a global that talks to some external device, what if something unpredictable happens, the WDT is not enabled yet so can't help.

My current workaround is to have another class and place it above all global classes in main.c
with a constructor that calls start but this doesn't seem the best way?

Perhaps something in mbed_app.json could get the WDT enabled during early init of mbed?

Issue request type


[x] Question
[ ] Enhancement
[ ] Bug

Most helpful comment

Yeah, mbed_main is already too late. If we want the watchdog running before __libc_init_array(), we should consider adding a conditional call to hal_watchdog_init() here (similar to the us_ticker_init()):
https://github.com/ARMmbed/mbed-os/blob/101ae73b87e7082502915c5a4c6f3971fac270bb/rtos/source/TARGET_CORTEX/mbed_boot.c#L74-L83

See the boot sequence for reference.

Perhaps something in mbed_app.json could get the WDT enabled during early init of mbed?

I think we could either add the watchdog config to drivers/mbed_lib.json or create a hal/mbed_lib.json file such as:

{
    "name": "hal",
    "config": {
        "watchdog-init-at-boot": {
            "help": "Initialize the watchdog at boot, before any global objects are created.",
            "value": false
        },
        "watchdog-timeout": {
            "help": "(Applies if hal.watchdog-init-at-boot is true.) Watchdog timeout in milliseconds.",
            "value": 100
        }
    }
}

This would produce MBED_CONF_HAL_WATCHDOG_INIT_AT_BOOT & MBED_CONF_HAL_WATCHDOG_TIMEOUT for the user to override in mbed_app.json (and for us to use in mbed_init().

@0xc0170, @bulislaw, @donatieng, what do you think? We could add such feature if extending the watchdog API in the future.

All 9 comments

Example of my workaround

Watchdog &wdt = Watchdog::get_instance();

class wdtstarter{
  public:
  wdtstarter(int time)
  {
        wdt.start(time);
  }
};

wdtstarter wdstart(60000);

When using the WDT it's important to get it enabled ASAP on boot, the current API doesn't really allow for this.

Can you elaborate more ? What should be possible to do (code snippet) and why it does not work?

Starting watchdog instance during the inital hooks in the bootstrap - is this too late and want to have it earlier?

Take this example (I don't have a board handy to check it does what I expect)

#include "mbed.h"

DigitalOut led1(LED1);
ResetReason rr;
#define SLEEP_TIME                  500 // (msec)
#define PRINT_AFTER_N_LOOPS         20
Watchdog &wdt = Watchdog::get_instance();


class badglobal{
    badglobal()
    {
        while(1);// imagine that some external hardware didnt respond and there was no timeout\recovery code host side.
    }
};

badglobal deathclass;


// main() runs in its own thread in the OS
int main()
{
      wdt.start(5000);

  switch(rr.get())
  {
    case RESET_REASON_POWER_ON:
           printf("Power On Reset\r\n");

    break;
    case RESET_REASON_PIN_RESET:
           printf("External Reset\r\n");

    break;
    case RESET_REASON_BROWN_OUT:
           printf("Brownout Reset\r\n");

    break;
    case RESET_REASON_SOFTWARE:
           printf("System Reset\r\n");

    break;
    case RESET_REASON_WATCHDOG:
           printf("Watchdog Reset\r\n");

    break;
    case RESET_REASON_LOCKUP:
           printf("Lockup Reset\r\n");

    break;
    case RESET_REASON_WAKE_LOW_POWER:
           printf("Lockup Reset\r\n");

    break;
    case RESET_REASON_ACCESS_ERROR:

    break;
    case RESET_REASON_BOOT_ERROR:

    break;
    case RESET_REASON_MULTIPLE:

    break;
    case RESET_REASON_PLATFORM:

    break;
    case RESET_REASON_UNKNOWN:

    break;


  }



    int count = 0;
    while (true) {
        // Blink LED and wait 0.5 seconds
        led1 = !led1;
        wait_ms(SLEEP_TIME);
        printf("alive\r\n");
        if ((0 == count) || (PRINT_AFTER_N_LOOPS == count)) {
            // Following the main thread wait, report on the current system status
            count = 0;
        }
        ++count;
    }
}

It should hang inside the class init before the WDT is enabled.

This is the first(obvious) place for the user to enable the WDT but it doesn't catch all issues.

Ideally the WDT should be enabled at the first opportunity, I don't know where in mbed this could be but I guess after HAL init? I'd hope nothing could go wrong before that!

I hope that makes some sense.

The only hook for it would be mbed_main but that might be too late (already initalized global objects) and right before invoking main. You are after even earlier, aren't you? That is what the above codesnippet does but still not ideal as watchdog might get initialized as the last object in the init array.

cc @ARMmbed/mbed-os-hal Please review

My finding were that so long as the workaround posted above was the first global in main.cpp it would be called before other globals (armc5/6) however I have no idea if this is guaranteed or just luck in my case.

I don't really understand compilers well enough to comment on this. However inside main is too late.
The key is to be able to get the WDT enabled before anything could possibly go wrong!

I'd like to see WDT enabled by default in mbed, with the slowest time out as possible as the default.
I appreciate this may cause issues with new users but I personally would never release something without a WDT!

Yeah, mbed_main is already too late. If we want the watchdog running before __libc_init_array(), we should consider adding a conditional call to hal_watchdog_init() here (similar to the us_ticker_init()):
https://github.com/ARMmbed/mbed-os/blob/101ae73b87e7082502915c5a4c6f3971fac270bb/rtos/source/TARGET_CORTEX/mbed_boot.c#L74-L83

See the boot sequence for reference.

Perhaps something in mbed_app.json could get the WDT enabled during early init of mbed?

I think we could either add the watchdog config to drivers/mbed_lib.json or create a hal/mbed_lib.json file such as:

{
    "name": "hal",
    "config": {
        "watchdog-init-at-boot": {
            "help": "Initialize the watchdog at boot, before any global objects are created.",
            "value": false
        },
        "watchdog-timeout": {
            "help": "(Applies if hal.watchdog-init-at-boot is true.) Watchdog timeout in milliseconds.",
            "value": 100
        }
    }
}

This would produce MBED_CONF_HAL_WATCHDOG_INIT_AT_BOOT & MBED_CONF_HAL_WATCHDOG_TIMEOUT for the user to override in mbed_app.json (and for us to use in mbed_init().

@0xc0170, @bulislaw, @donatieng, what do you think? We could add such feature if extending the watchdog API in the future.

That certainly looks like it would do what I need :-)
It also looks reasonably simple to implement.

@chrissnow thanks for reporting, it definitely makes sense to me!
@fkjagodzinski the solution looks promising. Couple of question we need to answer though.

  • How using HAL directly will affect the usage of the C++ class? First we init the HAL and then the user will need to instantiate the class and use it, will it just work? Is double init ok?
  • How are users going to reload WDT? How much time is needed between the mbed_init and main when their code starts executing?

Also could you document the new functionality in Handbook? Watchdog class is probably the best place.

Thank you for raising this issue. Please note we have updated our policies and
now only defects should be raised directly in GitHub. Going forward questions and
enhancements will be considered in our forums, https://forums.mbed.com/ . If this
issue is still relevant please re-raise it there.
This GitHub issue will now be closed.

Was this page helpful?
0 / 5 - 0 ratings