How to distinguish between ‘reset’ and ‘real power loss’??

Hi folks!

In some cases –?and I’m facing such a case now – it is not the same if you press reset on the Arduino or if you plug the power in and make the system start. I need to distinguish these two cases because of some fail-safe features in my project.

Is there some kind of built-it functionality in the Arduino I could use for this? Or is it only possible with some external components?

I just started thinking about it?… maybe some kind of capacitor between VCC and an analog pin or the like?… and then reading out if the cap is empty or quite fully loaded?…

I just wanted to ask if anyone has done something like that before; so maybe I can avoid inventing the wheel again. ;)

Thanks!

I think if you look at the interrupt types, you can differentiate between a Reset interrupt and a power loss/brown out detection interrupt. Table 12-6 in the datasheet: External Pin, Power-on Reset, Brown-out Reset and Watchdog System Reset

Ok, so maybe not! So external circuit is needed then. Maybe a flip flop that is cleared with power loss, your sketch reads it to see if it's low, indicating a power loss, and clocks it to make it high. A subsequent reset leaves it high, so when your sketch reads it on a re-start and sees it high, you can take other actions.

There’s a CPU register that tells you this.

Look at MCUSR in the “System Control and Reset” section of the datasheet.

Well, that makes it easier: 11.9.1 MCUSR – MCU Status Register The MCU Status Register provides information on which reset source caused an MCU reset.

Bit 7:4: Reserved These bits are unused bits in the ATmega48A/PA/88A/PA/168A/PA/328/P, and will always read as zero. • Bit 3 – WDRF: Watchdog System Reset Flag This bit is set if a Watchdog System Reset occurs. The bit is reset by a Power-on Reset, or by writing a logic zero to the flag. • Bit 2 – BORF: Brown-out Reset Flag This bit is set if a Brown-out Reset occurs. The bit is reset by a Power-on Reset, or by writing a logic zero to the flag. • Bit 1 – EXTRF: External Reset Flag This bit is set if an External Reset occurs. The bit is reset by a Power-on Reset, or by writing a logic zero to the flag. • Bit 0 – PORF: Power-on Reset Flag This bit is set if a Power-on Reset occurs. The bit is reset only by writing a logic zero to the flag.

To make use of the Reset Flags to identify a reset condition, the user should read and then Reset the MCUSR as early as possible in the program. If the register is cleared before another reset occurs, the source of the reset can be found by examining the Reset Flags.

Thanks for your quick answers!

Funny: I just finished my capacitor-solution. ^^

Clever: I already use a flip-flop in this project – and never thought of digitalReading the state in, gnaarpf?… ^^ Even dumber: the whole fuss is about the state of this flip-flop in a certain system state. Silly me. ^^ Thanks for pointing me to the most obvious solution.

Awesome: I’ll also look into the datasheet to find out about this register. This would be a brilliant solution too!

I wanted to thank you guys again!

I now managed to make use of these registers. Here is an example code in case someone in the world is looking for the same thing some later time:

void setup() {

  Serial.begin(38400);

  Serial.print("MCUSR: ");
  Serial.println(MCUSR);

  switch (MCUSR) {
    case 2: // b00000010
            // Reset button or otherwise some software reset
            Serial.println("Reset button was pressed.");
            break;
    case 7: // b00000111
            // Boot up after power loss
            Serial.println("Power loss occured!");
            break;
    }

  // Clear all MCUSR registers immediately for 'next use'
  MCUSR = 0;
}

I didn’t know that accessing these registers is so damn easy! I assume that this is because some Arduino lib is doing the work.

As a follow up: can you give me an example of how this would be written in ‘real’ C code? Or can you point me where in which lib is the place MCUSR is handled?

Thanks!

1 Like

Does that code actually work? I thought the bootloader cleared the MCUSR settings. Anyone know if that has changed?

Darkwing: I didn’t know that accessing these registers is so damn easy! I assume that this is because some Arduino lib is doing the work.

Actually it's lower than that, it's the AVR-GCC compiler. It knows the register names and allows them to be used basically as variables.

As a follow up: can you give me an example of how this would be written in ‘real’ C code? Or can you point me where in which lib is the place MCUSR is handled?

That is real C code! (Well, C++ code.)

Woah, compilers baffle me all the time. Thanks, good to know!

In the meantime I ported my little condensed example sketch into ‘the big project’ and I can tell: this works just fine. No weird stuff happening so far. Directly after uploading a sketch, when the system starts for the first time, the register is 2 (= b0010), meaning a (software) reset was done. This behaves like one would expect.

But I can not tell what happens to the register when uploading a new bootloader (if this is what you mean). Haven’t had this pleasure yet. ;)

Darkwing: But I can not tell what happens to the register when uploading a new bootloader (if this is what you mean). Haven’t had this pleasure yet. ;)

I actually just meant the normal bootloader startup sequence before it passes control to the sketch. I thought MCUSR got lost in that process somewhere. Well that is interesting, I'll have to try it out. Thanks!

MCUSR normally has its contents corrupted by the bootloader. If you get the newest version of optiboot from its source repository (https://code.google.com/p/optiboot/ ) you'll find a patch that permits optiboot to pass the original value of MCUSR on to the user application (and an example of what the application should look like to use that info: https://code.google.com/p/optiboot/issues/detail?id=66

westfw: MCUSR normally has its contents corrupted by the bootloader. If you get the newest version of optiboot from its source repository (https://code.google.com/p/optiboot/ ) you'll find a patch that permits optiboot to pass the original value of MCUSR on to the user application (and an example of what the application should look like to use that info: https://code.google.com/p/optiboot/issues/detail?id=66

Thanks. I think I saw that patch when compiling the 1284P bootloader. I was pretty sure it didn't work on my Unos and clones, but none of them have the latest version of Optiboot. I'll try it!

This would be a more sensible (and functional) code:

void setup() {
  Serial.begin(38400);

  Serial.print("MCUSR: ");
  Serial.println(MCUSR);
  
  if (MCUSR & _BV(EXTRF)){
      // Reset button or otherwise some software reset
      Serial.println("Reset button was pressed.");
  }
  if (MCUSR & (_BV(BORF) | _BV(PORF))){
       // Brownout or Power On
       Serial.println("Power loss occured!");
  }
  if (MCUSR & _BV(WDRF)){
       //Watchdog Reset
       Serial.println("Watchdog Reset");
  }
  // Clear all MCUSR registers immediately for 'next use'
  MCUSR = 0;
}

The case statement you had would either work if ONLY and external reset occurred, or if ALL 3 of brownout, power on and reset occurred. The above code filters the events and detects correctly if either an external reset occurred, or if ANY of brownout or power on occurred. Plus if you press the reset button before it gets to the point of clearing MCUSR, it will allow you to see that too.

Granted you still have the problem of optiboot. Almost worth building a standalone ATMega circuit and using ISP to program it (no bootloader). The bootloader would delay the execution of the reset check code anyway.

Darkwing: I didn’t know that accessing these registers is so damn easy! I assume that this is because some Arduino lib is doing the work.

No, it's a hardware feature of the chip.

fungus: No, it's a hardware feature of the chip.

Partly, but it is also thanks to some of the abstraction from avr-libc.

This is accessing a register without that:

byte value;
asm volatile ("in %0, 0x34 \n\t" :"=r" (value) ); 
print("MCUSR = ");
println(value);

or possibly:

volatile byte* ptr;
ptr = (volatile byte*)0x54; //note adding 0x20 as this treats them as mapped into SRAM.
byte value = *ptr;
print("MCUSR = ");
println(value);

vs. this with the abstraction:

byte value = MCUSR;
print("MCUSR = ");
println(value);

westfw:
MCUSR normally has its contents corrupted by the bootloader.
If you get the newest version of optiboot from its source repository (https://code.google.com/p/optiboot/ ) you’ll find a patch that permits optiboot to pass the original value of MCUSR on to the user application (and an example of what the application should look like to use that info: https://code.google.com/p/optiboot/issues/detail?id=66

I finally got around to compiling Optiboot 5.0 for ATmega328P and am not seeing the results I expected WRT the MCUSR value. When pressing the reset button, I expected to see EXTRF set in MCUSR but instead I see WDRF. Any ideas?

PS: Maybe this is working as designed? See comment #2 at https://code.google.com/p/optiboot/issues/detail?id=66

Output

0 MCUSR=0x08 WDRF

Code

//copy the MCUSR value saved in r2 by Optiboot to a global variable.

#include <Streaming.h>    //http://arduiniana.org/libraries/streaming/

uint8_t mcusr __attribute__ ((section (".noinit")));
void getMCUSR(void) __attribute__((naked)) __attribute__((section(".init0")));

void getMCUSR(void)
{
    __asm__ __volatile__ ( "mov %0, r2 \n" : "=r" (mcusr) : );
}

void setup(void)
{
    Serial.begin(115200);
    Serial << endl << millis() << F(" MCUSR=0x0") << _HEX(mcusr);
    if (mcusr & _BV(WDRF))  Serial << F(" WDRF");
    if (mcusr & _BV(BORF))  Serial << F(" BORF");
    if (mcusr & _BV(EXTRF)) Serial << F(" EXTRF");
    if (mcusr & _BV(PORF))  Serial << F(" PORF");
    Serial << endl;
}

void loop(void)
{
}

That sounds like "as designed." Your sketch won't see EXTRF, because that's the one reason that invokes the bootloader code. You should see PORF on power-on, though, and you know that WDRF means EXTRF, unless you've also turned on the WDT...

westfw: That sounds like "as designed." Your sketch won't see EXTRF, because that's the one reason that invokes the bootloader code. You should see PORF on power-on, though, and you know that WDRF means EXTRF, unless you've also turned on the WDT...

Thanks, that's what I figured. I am also using the WDT so I'll just go sans bootloader, no big deal really.

I see both BORF and PORF on power up, but that is consistent with the behavior without a bootloader.

Thanks very much!