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?
[x] Question
[ ] Enhancement
[ ] Bug
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.
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.
Most helpful comment
Yeah,
mbed_mainis already too late. If we want the watchdog running before __libc_init_array(), we should consider adding a conditional call tohal_watchdog_init()here (similar to theus_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.
I think we could either add the watchdog config to drivers/mbed_lib.json or create a
hal/mbed_lib.jsonfile such as:This would produce
MBED_CONF_HAL_WATCHDOG_INIT_AT_BOOT&MBED_CONF_HAL_WATCHDOG_TIMEOUTfor the user to override inmbed_app.json(and for us to use inmbed_init().@0xc0170, @bulislaw, @donatieng, what do you think? We could add such feature if extending the watchdog API in the future.