Go Down

Topic: DUE Watchdog usage (Read 2670 times) previous topic - next topic

gogol

When trying to use the Watchdog on the DUE, you will come over short to one finding:
Quote from: SAM3X8E Docmentation chapter 17.4

After a Processor Reset, the value of WDV is 0xFFF, corresponding to the maximum value of
the counter with the external reset generation enabled (field WDRSTEN at 1 after a Backup
Reset). This means that a default Watchdog is running at reset, i.e., at power-up. The user must
either disable it (by setting the WDDIS bit in WDT_MR) if he does not expect to use it or must
reprogram it to meet the maximum Watchdog period the application requires.
The Watchdog Mode Register (WDT_MR) can be written only once. Only a processor reset
resets it. Writing the WDT_MR register reloads the timer with the newly programmed mode
parameters.


As variant.cpp contains the line WDT_Disable(WDT); in its init() function, the watchdog is disabled forever.  So you need solutions, to prevent the disabling.   I added now the following lines in variants.cpp before the init() function:
Code: [Select]

void WDT_Init();

#pragma weak WDT_Init
void WDT_Init()
{
  WDT_Disable(WDT);
}


And replaced   WDT_Disable(WDT);  with  WDT_Init();  in the init() function.

That is now first hand a neutral solution, but gives you the ability to define a strong version of  WDT_Init();  in your program.  That can either be an empty-function, which leaves the Watchdog configured as from startup, or any other code, which changes the Watchdog to call the ISR WDT_Handler() or change any other settings.

Do I miss something in my thoughts or should this go into the main code?

gogol

#1
Apr 15, 2014, 09:42 am Last Edit: Apr 15, 2014, 09:44 am by gogol Reason: 1
Just thinking further: To have a much cleaner solution with the right namespaces
Code: [Select]
void WDT_Init();
should go to wdt.h

Code: [Select]
#pragma weak WDT_Init
void WDT_Init()
{
 WDT_Disable(WDT);
}

should go to wdt.c

And finally in variant.cpp:
Code: [Select]
// WDT_Disable(WDT);
WDT_Init(); // add this line instead of WDT_Disable(WDT);


As soon as the function WDT_Init() gets redefined in the application, this strong version will be used and you are free to configure WDT.

Anything I may have forgotten to think about?

gogol

Still talking only to myself :-(
Comparing the Arduino  hardware/arduino/sam/system/libsam/[source|include]/wdt.[c|h]
with the Atmel Framework version of wdt.[c|h]
I see, that Atmel provides already an wdt_init(),
Code: [Select]

uint32_t wdt_get_timeout_value(uint32_t ul_us, uint32_t ul_sclk);
void wdt_init(Wdt *p_wdt, uint32_t ul_mode, uint16_t us_counter,
uint16_t us_delta);
void wdt_disable(Wdt *p_wdt);
void wdt_restart(Wdt *p_wdt);
uint32_t wdt_get_status(Wdt *p_wdt);
uint32_t wdt_get_us_timeout_period(Wdt *p_wdt, uint32_t ul_sclk);


whereas Arduino provides as counterpart WDT_Enable()
Code: [Select]

extern void WDT_Enable( Wdt* pWDT, uint32_t dwMode ) ;
extern void WDT_Disable( Wdt* pWDT ) ;
extern void WDT_Restart( Wdt* pWDT ) ;
extern uint32_t WDT_GetStatus( Wdt* pWDT ) ;
extern uint32_t WDT_GetPeriod( uint32_t dwMs ) ;


So I think, that the new weak function should be named WDT_Initialze(), to avoid confusion.

Are there any readers here, which work on the that layer of libraries? 

bilica

Hi!

I just can't make WDT work on my Arduino Due!

Do you have any simple code for testing/verifying that WDT works ?

Thanks in advance!

bobcousins


So I think, that the new weak function should be named WDT_Initialze(), to avoid confusion.

Are there any readers here, which work on the that layer of libraries? 


I don't, but I think that would be a very useful patch! I'd like to use the watchdog in some code I am doing.

I guess to get it included requires a git pull request and some polite badgering on the Arduino dev list. :)
Please don't PM me asking for help. Ask questions in the forum.

bilica



So I think, that the new weak function should be named WDT_Initialze(), to avoid confusion.

Are there any readers here, which work on the that layer of libraries? 


I don't, but I think that would be a very useful patch! I'd like to use the watchdog in some code I am doing.

I guess to get it included requires a git pull request and some polite badgering on the Arduino dev list. :)


I found the answer here:  http://forum.arduino.cc/index.php?PHPSESSID=fg7nrj1t8i9bhajs3ebg7suij5&topic=152885.msg1149434#msg1149434

You have first to edit the variants.cpp file in the Arduino core and comment the line "WDT_disable(WDT);" inside the init function.

Then, you are able to set the WDT again (which can be set only once) using:

Code: [Select]

#define __WDP_MS 2048 // edit this number accordingly
WDT_Enable ( WDT, 0x2000 | __WDP_MS | ( __WDP_MS << 16 ) );


and the you can call

Code: [Select]

WDT_Restart( WDT );


somewhere in the loop() function to avoid reboot.





gogol

That exactly is the reason, why I am proposing this patch!
If you change variants.cpp by commenting out the WDT_disable(WDT); line, you break the core libraries for many other programs, as the watchdog is always active

If you do that, you have to edit variants.cpp for each program, depending if you need watchdog in your program or not.
The other way would be copying all the files to a second board, how it is done for the DigiX.  But that needs twice the space on disk and constant sync of both directories for new versions of the IDE.  VERY BAD!!

That exactly was the situation, where I came to the solution for my patch!

Read the entry post of that thread!  I replace the line you are disabling with a line calling a new weak function WDT_Initialze().  This function does primarly the same, as the current line and is disabling WDT.

HOWEVER: A weak function can be redefined somewhere through a strong version.  When the linker finds a  function with the same name, this function will be used instead of the weak one.

That means: Once my patch is included in the CORE files nothing changes at all, as reset is still disabled. So we are backwards compatible.

But as soon, as you are creating a STRONG function WDT_Initialze() in your code, which will call WDT_Enable() instead of WDT_Disable()  you  can use WDT, where you need.

This workaround is needed, as the ARDUINO-architecture gives you no way, to influence  main() before setup() is called.

bilica

Thanks gogol!

I will do it as you suggest it. Much better.

Do you know why we can only change WDT status only once per boot ? Is it a design limitation of the SAM3X architecture ?

Thanks again,



That exactly is the reason, why I am proposing this patch!
If you change variants.cpp by commenting out the WDT_disable(WDT); line, you break the core libraries for many other programs, as the watchdog is always active

If you do that, you have to edit variants.cpp for each program, depending if you need watchdog in your program or not.
The other way would be copying all the files to a second board, how it is done for the DigiX.  But that needs twice the space on disk and constant sync of both directories for new versions of the IDE.  VERY BAD!!

That exactly was the situation, where I came to the solution for my patch!

Read the entry post of that thread!  I replace the line you are disabling with a line calling a new weak function WDT_Initialze().  This function does primarly the same, as the current line and is disabling WDT.

HOWEVER: A weak function can be redefined somewhere through a strong version.  When the linker finds a  function with the same name, this function will be used instead of the weak one.

That means: Once my patch is included in the CORE files nothing changes at all, as reset is still disabled. So we are backwards compatible.

But as soon, as you are creating a STRONG function WDT_Initialze() in your code, which will call WDT_Enable() instead of WDT_Disable()  you  can use WDT, where you need.

This workaround is needed, as the ARDUINO-architecture gives you no way, to influence  main() before setup() is called.

gogol

Quote

Is it a design limitation of the SAM3X architecture ?

Yes, chapter 17.4 of the ATSAM3X8E datasheet says:
Code: [Select]

After a Processor Reset, the value of WDV is 0xFFF, corresponding to the maximum value of
the counter with the external reset generation enabled (field WDRSTEN at 1 after a Backup
Reset). This means that a default Watchdog is running at reset, i.e., at power-up. The user must
either disable it (by setting the WDDIS bit in WDT_MR) if he does not expect to use it or must
reprogram it to meet the maximum Watchdog period the application requires.
The Watchdog Mode Register (WDT_MR) can be written only once. Only a processor reset
resets it. Writing the WDT_MR register reloads the timer with the newly programmed mode
parameters.


Its always a good thing reading the datasheets of the controllers (even when you understand only 5%). but you might get an idea, what the controller is able to. 

g4rb4g3

Thanks for this, i've created a diff file to apply these changes easy.
But somehow I get a warning if I compile a sketch without the WDT_Initialze function...
Code: [Select]
variant.cpp.o: In function `init':
C:\Program Files (x86)\Arduino\arduino-1.5.7\hardware\arduino\sam\variants\arduino_due_x/variant.cpp:378: warning: undefined reference to `WDT_Initialze'

Code: [Select]
--- arduino-1.5.8\hardware\arduino\sam\system\libsam\include\wdt.h Thu Jan 8 17:33:06 2015 UTC
+++ arduino-1.5.8\hardware\arduino\sam\system\libsam\include\wdt.h Thu Jan 8 17:33:06 2015 UTC
@@ -66,6 +66,8 @@
 
 extern uint32_t WDT_GetPeriod( uint32_t dwMs ) ;
 
+void WDT_Initialze();
+
 #ifdef __cplusplus
 }
 #endif
--- arduino-1.5.8\hardware\arduino\sam\system\libsam\source\wdt.c Thu Jan 8 17:33:09 2015 UTC
+++ arduino-1.5.8\hardware\arduino\sam\system\libsam\source\wdt.c Thu Jan 8 17:33:09 2015 UTC
@@ -130,3 +130,13 @@
     }
     return ((dwMs << 8) / 1000) ;
 }
+
+/**
+* \brief default arduino behaviour -> disable the watchdog.
+* watchdog can be enabled from a sketch
+*/
+#pragma weak WDT_Initialze
+void WDT_Initialze()
+{
+ WDT_Disable(WDT);
+}
--- arduino-1.5.8\hardware\arduino\sam\variants\arduino_due_x\variant.cpp Thu Jan 8 17:33:14 2015 UTC
+++ arduino-1.5.8\hardware\arduino\sam\variants\arduino_due_x\variant.cpp Thu Jan 8 17:33:14 2015 UTC
@@ -374,7 +374,8 @@
   }
 
   // Disable watchdog
-  WDT_Disable(WDT);
+  // WDT_Disable(WDT);
+  WDT_Initialze(); // instead of the line above to allow enabling the watchdog from a sketch
 
   // Initialize C library
   __libc_init_array();

g4rb4g3

I tried it now and the watchdog works perfectly!

RayLivingston

When trying to use the Watchdog on the DUE, you will come over short to one finding:
As variant.cpp contains the line WDT_Disable(WDT); in its init() function, the watchdog is disabled forever.  So you need solutions, to prevent the disabling.   I added now the following lines in variants.cpp before the init() function:
Code: [Select]

void WDT_Init();

#pragma weak WDT_Init
void WDT_Init()
{
  WDT_Disable(WDT);
}


And replaced   WDT_Disable(WDT);  with  WDT_Init();  in the init() function.

That is now first hand a neutral solution, but gives you the ability to define a strong version of  WDT_Init();  in your program.  That can either be an empty-function, which leaves the Watchdog configured as from startup, or any other code, which changes the Watchdog to call the ISR WDT_Handler() or change any other settings.

Do I miss something in my thoughts or should this go into the main code?

A very nice solution to the problem!

Regards,
Ray L.

JWScotSat

I like the idea of an easy call for the WatchDog. Have you considered creating a function

Watchdog.begin()

This would be in-keeping with the "arduino" way and makes it very clear in the code that you intend to start a watch dog timer.

l-mb

I'd love to have this included so that I can make my ┬ÁC projects more reliable and able to auto-restart. The ability to have a watchdog timer is quite crucial. Good proposal!

bobcousins

A while ago I created a pull request to get this type of functionality included in the core https://github.com/arduino/Arduino/pull/2210. I forget where it got to, I think there was some cosmetic changes required, but otherwise just needs a "push" to get into the core I think.

It's been kinda low on my list of priorities.
Please don't PM me asking for help. Ask questions in the forum.

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy