Digistump Forums
The DigiX => DigiX Support => Topic started by: tastewar 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:
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?
-
So when the watchdog timer resets the board, it reboots and is waiting for you to connect and press a key, correct?
-
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?
-
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.
#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);
}
-
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.
-
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.
-
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?
-
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.
-
Very cool, Jeff! Thanks for the info.
Thanks to your pointer, I have written up a test sketch which seems to bear this out:
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?
-
in sam/system/CMSIS/Device/ATMEL/sam3xa/include/instance_rstc.h:
#define REG_RSTC_SR (*(RoReg*)0x400E1A04U) /**< \brief (RSTC) Status Register */
in sam/system/CMSIS/Device/ATMEL/sam3xa/include/component_rstc.h:
#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 */
-
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. :-(
-
Thanks for both bits of info, gogol. I've re-coded as:
unsigned char x = ( REG_RSTC_SR & RSTC_SR_RSTTYP_Msk ) >> RSTC_SR_RSTTYP_Pos;
-
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.
-
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!
-
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
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.
-
OK, I guess I misread just a general post though.