Author Topic: Help with WatchDog?  (Read 14772 times)

tastewar

  • Jr. Member
  • **
  • Posts: 50
Help with WatchDog?
« on: March 12, 2014, 02:16:24 pm »
So I've posted about a couple of issues with the wifi seeming to get locked up. Seemed like the WDT was a reasonable solution. My code can't get to my WiFiReset function if it's hung up in some wifi call. So I am using the WDT Enabled version of the board from the Arduino Board menu. I had something of an issue when doing the initial development work, in that if I had rebooted the board, but it was waiting for me to enter something in the serial console, it would reboot, and that was annoying.

I thought I had solved that issue by including code like this:

Code: [Select]
void setup ( )
{
  WDT_Disable(WDT);
  unsigned long wdp_ms = 2048;
  unsigned long    wst;
  pinMode ( WiFiResetPin, OUTPUT );
  pinMode ( LEDPin, OUTPUT );
  digitalWrite ( WiFiResetPin, HIGH );
  digitalWrite ( LEDPin, LOW );
  ResetWiFi ( );
  Serial.begin ( 9600 );
  while( !Serial.available ( ) )
  {
     Serial.println ( "Enter any key to begin" );
     delay ( 1000 );
  }
  WDT_Enable( WDT, 0x2000 | wdp_ms | ( wdp_ms << 16 ));
  wst = millis ( );
  do
  {
    if ( millis ( ) - wst > 5000 )
    {
      DebugOutLn ( "Error connecting to WiFi network" );
      ResetWiFi ( );
      ImStillAlive ( );
      wst = millis ( );
    }
    delay ( 10 );
  } while ( wifi.ready ( ) != 1 );

BTW, my ImStillAlive function does two things: it toggles the built-in LED on pin 13, and it calls WDT_Restart ( WDT ); and that's the only call to WDT_Restart in the code.

So I'm surprised that my project still seems to lock up (it's powered by a 9V, 1A supply, BTW), I can see that the LED has stopped flashing completely. But the board doesn't ever seem to reboot!

Can you see anything wrong with my approach?

JeffRand

  • Newbie
  • *
  • Posts: 44
Re: Help with WatchDog?
« Reply #1 on: March 12, 2014, 08:13:05 pm »
So when the watchdog timer resets the board, it reboots and is waiting for you to connect and press a key, correct?

tastewar

  • Jr. Member
  • **
  • Posts: 50
Re: Help with WatchDog?
« Reply #2 on: March 12, 2014, 08:39:22 pm »
No; it never reboots. I currently have *all* the interaction with the Serial port commented out, so it can start up disconnected from the computer. But it never reboots. I will see my LED solidly on or off for longer than my patience. My understanding is that using 2048 should represent 8 seconds.

So, my fix for the "reboot loop" was to attempt to disable the WDT until *after* the serial interaction with the computer. But now it seems like my "enable" isn't taking.

Should it be possible to enable/disable the WDT while the system is running, as I'm attempting?

JeffRand

  • Newbie
  • *
  • Posts: 44
Re: Help with WatchDog?
« Reply #3 on: March 13, 2014, 12:42:15 am »
I did a little research on the watchdog timer and found that in section 17.4 of the MCU datasheet (http://www.atmel.com/Images/doc11057.pdf) the watchdog mode register can only be written once. Only a processor reset will reset it. So, if you disable it, it can't be re-enabled.

I found that this code works for me. I blink the LED once a second while it is waiting for a key press. After I press a key, if my router is off, I get the error message every 5 seconds. Once my router is on, I get the WiFi connected message. If it hangs in the loop testing wifi.ready, I get a reboot after 8 seconds and it goes back to blinking once a second waiting for a key press.

Code: [Select]
#include "advancedFunctions.h"
#include <DigiFi.h>

DigiFi wifi;

const byte LEDPin = 13;

void setup ( )
{
  unsigned long wdp_ms = 2048;
  unsigned long    wst;
  int toggle = 0;
  WDT_Enable( WDT, 0x2000 | wdp_ms | ( wdp_ms << 16 ));
  digitalWrite ( LEDPin, LOW );
  Serial.begin ( 9600 );
  wifi.begin(9600);
  while( !Serial.available ( ) )
  {
     Serial.println ( "Enter any key to begin" );
     digitalWrite ( LEDPin, LOW );
     delay(500);
     digitalWrite ( LEDPin, HIGH );
     delay(500);
     WDT_Restart(WDT);
  }
  wst = millis ( );
  do
  {
    if ( millis ( ) - wst > 5000 )
    {
      Serial.println ( "Error connecting to WiFi network" );
      WDT_Restart(WDT);
      toggle = 1 - toggle;
      digitalWrite ( LEDPin, toggle );
      wst = millis ( );
    }
    delay(10);
  } while ( wifi.ready ( ) != 1 );
  Serial.println ( "WiFi Connected" );
}

void loop() {
  WDT_Restart(WDT);
  delay(1000);
}

tastewar

  • Jr. Member
  • **
  • Posts: 50
Re: Help with WatchDog?
« Reply #4 on: March 13, 2014, 05:29:14 am »
Thank you, Jeff! That's just the bit of info I needed. I was trying to have one nice bit of code that would deal with both "development mode" (attached to computer) and "production mode." I'll have to find a slightly different way.

digistump

  • Administrator
  • Hero Member
  • *****
  • Posts: 1465
Re: Help with WatchDog?
« Reply #5 on: March 14, 2014, 11:59:14 pm »
Thanks for figuring that out Jeff - I haven't ever tried to change it mid program so never ran into it - but I linked to your post from the wiki for future users.

tastewar

  • Jr. Member
  • **
  • Posts: 50
Re: Help with WatchDog?
« Reply #6 on: March 15, 2014, 06:03:36 pm »
Is there a way to tell (in setup) if we're here as a result of a watchdog timer expiration vs. reset button/power up?

JeffRand

  • Newbie
  • *
  • Posts: 44
Re: Help with WatchDog?
« Reply #7 on: March 15, 2014, 06:23:59 pm »
Yes, I believe you can. Look at section 14.5.2 on page 237 of the datasheet for the MCU. It describes the reset controller status register (RSTC_SR). It has three bits that define the reset type. From those you can tell what type of reset was done.

tastewar

  • Jr. Member
  • **
  • Posts: 50
Re: Help with WatchDog?
« Reply #8 on: March 16, 2014, 07:47:46 pm »
Very cool, Jeff! Thanks for the info.

Thanks to your pointer, I have written up a test sketch which seems to bear this out:

Code: [Select]
void setup ( )
{
  unsigned long wdp_ms = 2048; // 8 seconds
  WDT_Enable( WDT, 0x2000 | wdp_ms | ( wdp_ms << 16 ));
  Serial.begin ( 9600 );
  while ( !Serial.available ( ) )
  {
    Serial.println ( "Enter any key to begin" );
    delay ( 1000 );
  }
  Serial.println ( "Starting setup" );
  unsigned long *pSR;
  pSR=(unsigned long *)0x400E1A04;
  unsigned long x = *pSR;
  x >>= 8;
  x &= 7;
  Serial.print ( "reset type is " );
  switch ( x )
  {
    case 0:
      Serial.println ( "General Reset" );
      break;
    case 1:
      Serial.println ( "Backup Reset" );
      break;
    case 2:
      Serial.println ( "Watchdog Reset" );
      break;
    case 3:
      Serial.println ( "Software Reset" );
      break;
    case 4:
      Serial.println ( "User Reset" );
      break;
    default:
      Serial.println ( "Unknown" );
  }
}

void loop ( )
{
  delay ( 1000 );
}

I know that often times, there are register names for these things, but I tried using the name from the datasheet (RSTC_SR), but it made the compiler sad. So, two questions from this:

1. Anyone know if there is a symbolic constant that can be used instead of my ugly literal constants?
2. I was able to get all the expected values to show up (General, Watchdog, Software) but not User. I was expecting the on-board reset button to generate a User Reset, which is documented as "NRST pin detected low" -- is this not what the reset button does?

gogol

  • Sr. Member
  • ****
  • Posts: 398
Re: Help with WatchDog?
« Reply #9 on: March 17, 2014, 02:37:58 am »
in sam/system/CMSIS/Device/ATMEL/sam3xa/include/instance_rstc.h:
Code: [Select]
#define REG_RSTC_SR (*(RoReg*)0x400E1A04U) /**< \brief (RSTC) Status Register */
in sam/system/CMSIS/Device/ATMEL/sam3xa/include/component_rstc.h:
Code: [Select]
#define RSTC_SR_URSTS (0x1u << 0) /**< \brief (RSTC_SR) User Reset Status */
#define RSTC_SR_RSTTYP_Pos 8
#define RSTC_SR_RSTTYP_Msk (0x7u << RSTC_SR_RSTTYP_Pos) /**< \brief (RSTC_SR) Reset Type */


gogol

  • Sr. Member
  • ****
  • Posts: 398
Re: Help with WatchDog?
« Reply #10 on: March 17, 2014, 02:43:05 am »
Quote from: tastewar
I was expecting the on-board reset button to generate a User Reset, which is documented as "NRST pin detected low" -- is this not what the reset button does?

http://digistump.com/board/index.php/topic,1216.msg5376.html#msg5376

Unfortunately that is an design-mismatch of the Arduino DUE inherited by the DigiX, that NRST is NOT AVAILABLE.  :-(

tastewar

  • Jr. Member
  • **
  • Posts: 50
Re: Help with WatchDog?
« Reply #11 on: March 17, 2014, 05:42:14 am »
Thanks for both bits of info, gogol. I've re-coded as:

Code: [Select]
unsigned char x = ( REG_RSTC_SR & RSTC_SR_RSTTYP_Msk ) >> RSTC_SR_RSTTYP_Pos;

dfarrell

  • Newbie
  • *
  • Posts: 30
Re: Help with WatchDog?
« Reply #12 on: March 24, 2014, 06:36:25 pm »
I mentioned somewhere else here, it is far better to use a logic pin (PC11) to reset the WiFi, the MASTER-RESET reset line is a very slow edge which many parts do not like.  A logic pin is very fast, there is no RC on it.  Also, driving NRSTB from the CPU side may damage the CPU as it is driving a capacitor w/o series resistance.  The part may have some protection for this, I did not check.

tastewar

  • Jr. Member
  • **
  • Posts: 50
Re: Help with WatchDog?
« Reply #13 on: March 24, 2014, 06:59:18 pm »
Hi dfarrell-

I'm not sure if your post is just for general information or directed at me in particular, but I was not attempting to use NRSTB, I was just adding code to my program to be able to detect why we're executing the setup function, and I was testing the various cases I could, and was surprised I couldn't detect a reset. That's why the discussion over various resets came up.

I am, in my code, using the pin 106 wifi reset, having bridged the appropriate solder jumper.

Cheers!

gogol

  • Sr. Member
  • ****
  • Posts: 398
Re: Help with WatchDog?
« Reply #14 on: March 25, 2014, 02:17:20 am »
I mentioned somewhere else here, it is far better to use a logic pin (PC11) to reset the WiFi, the MASTER-RESET reset line is a very slow edge which many parts do not like.  A logic pin is very fast, there is no RC on it.  Also, driving NRSTB from the CPU side may damage the CPU as it is driving a capacitor w/o series resistance.  The part may have some protection for this, I did not check.

I think, that this is well understood by all participiants in that thread.   

If you however wish to initiate a system reset, look to:  ./hardware/arduino/sam/cores/arduino/Reset.cpp

Code: [Select]
void banzai() {
// Disable all interrupts
__disable_irq();
// Set bootflag to run SAM-BA bootloader at restart
const int EEFC_FCMD_CGPB = 0x0C;
const int EEFC_KEY = 0x5A;
while ((EFC0->EEFC_FSR & EEFC_FSR_FRDY) == 0);
        EFC0->EEFC_FCR =
            EEFC_FCR_FCMD(EEFC_FCMD_CGPB) |
                    EEFC_FCR_FARG(1) |
            EEFC_FCR_FKEY(EEFC_KEY);
while ((EFC0->EEFC_FSR & EEFC_FSR_FRDY) == 0);

// After the next reset, SAM-BA is booted instead of flash.

// BANZAIIIIIII!!!
const int RSTC_KEY = 0xA5;
RSTC->RSTC_CR =
RSTC_CR_KEY(RSTC_KEY) |
RSTC_CR_PROCRST |
RSTC_CR_PERRST;
while (true);
}

If you omit clearing the GPNVM-bit, you perform a core reset, without booting into SAM-BA.  So it is no need driving NRSTB for reset.