0

I wrote a generic avr program wrapper which already use the watchdog timer to restart - and after the watchdog reset - recover the the bad situation.

After this recover process i have to restart the avr. Everything i've found in topic "software reset arduino" is about to set the shortest watchdog (15ms) timeout, then spins the CPU (for(;;);) until it cause watchdog reset.

But this results to enter the recovery process which is already done in this point.

It is any elegant way to achieve this?

Some non or less elegant way:

  • I can bind a digital pin to the reset and pull up with a resistor.

  • I can write to a fixed address in the flash or eeprom (but this maybe happens frequently) before soft restart, to prevent entering to recovery mode.


Is there any register that "survives" soft resets?

Edit:

I add mock example code to hint what i trying to do.

In the actual code, in the recovering the microcontroller connect to the serial bus, waits for commands then resets itselft in oder to return to application mode.

/*************************** Application wrapper ******************************/

//define call_application and call_recover as weak empty functions
//so they can be rewritten.

bool isWatchdogReset()
{
    return MCUSR == 8;
}

void softwareReset()
{
    //  wdt_enable(WDTO_15MS);for(;;);// (this way enters recovery mode)
    //or
    //  asm ("jmp 0x0");// (this way function registers not being resetted)
}

bool isSoftwareReset()
{
    //???
}

int main()
{
    bool needRecover = isWatchdogReset() && !isSoftwareReset();
    MCUSR = 0;
    init_board();
    wdt_enable(WDTO_1S);
    while(1)
    {
        if(!needRecover)
        {
            call_application();
        }
        else
        {
            call_recover();
        }
        wdt_reset();
    }   
}


/********************************* Application ********************************/

void call_application()
{
    if(randomTrue())
    {
        //stuck more that 1 secounds, that results WDT reset
    }
    else
    {
        //proper operation
    }
}

/********************************** Recover ***********************************/

void call_recover()
{
    //initialize UART, attach interrupts, Write flash and EEPROM, modify
    //function registers.

    //recovering completed, returning to the original application as like
    //nothing's happened.
    softwareReset();
}

Edit: I try explain short to spot the point:

1) I already use the watchdog timer to detect when the application code is flawed.

2) soft reset is an inproper solution, because it doesn't reset the registers. So onyl the program will be resetted, the state of the microcontroller doesn't.

3) To commit a proper reset, the solution is to timeout the watchdog timer. But see point 1), it is already used, so how can you make the difference of a requested reset and a flawed code recovery reset?

  • and why is the second wdt reset a problem? or why you can"t continue without reset? – Juraj Feb 1 at 9:20
  • 1
    I've read you question three times, but I still don't get what it is you are describing. What is this "recovery process" you are talking about? Are "recovering" stuff in a WDT interrupt routine. – Gerben Feb 1 at 14:02
3

The reset is basically jumping to the reset vector address 0x0000 (if you don't have the bootloader, or you don't want to start it).

There is also the MCUSR register, indicating which reset source caused the reset. It won't be set if you do simple jump to the reset adress.

The memory is also preserved, but C/C++ init code takes place and initialize your global variables. This can be ommited by placing variable/variables into the .noinit section. But it's not defined, what is there after the reset. With combination with MCUSR register you can init the variables for regular reset sources and keep it unchanged if you jump to the reset vector address.

Also the regular reset sources jumps to the bootloader, so it can use the same memory locations as your .noinit variables and trash them.

  • I check MCUSR register right after start to identify the source of reset/power up. Now I've tried this way of reset (void sw_reset(){asm("jmp 0x0");}). It's works, but - as i disassembled - it just resets the stack pointer, which results to start the program again from the main(), but port, timers, UART settings are remains – Dankó Dávid Feb 1 at 10:11
  • 1
    @DankóDávid So you don't want to restart it? Maybe it's an XY Problem? – KIIV Feb 1 at 10:22
  • Note also that a hardware reset sets all the I/O registers to their initial value, which a jump to 0x0000 doesn't. Only very few registers, like MCUSR have no defined initial value. – Edgar Bonet Feb 1 at 10:26
  • @EdgarBonet yes, that might be a problem in the middle of TWI communication or so. But initialization code should be written as there is already something configured. Definitely in this case. – KIIV Feb 1 at 10:33
  • I've edited the question and added an example what the exact problem i trying to solve. 1) I already use the watchdog timer to detect malfunction. 2) I'd like to reset the AVR completely (resetting all function register what the recovery function touched and i can't track), but the only way i've found is to use WDT timeout which results not just to restart, but to recognise as a "malfunction restart". More simplified: I need a malfunction reset (WDT) and an intentional software reset, which not share the same mechanism of reset. Or differentiate the two way of resetting the AVR. – Dankó Dávid Feb 1 at 21:47
2

The logic of you applications is wrong. You set the needRecover at the beginning of main, but test it in your infinite while (1) loop. The needRecover value will not change in the loop.

Do your initialization first no matter if normal power-up or watchdog restart and then do stuff in the infinite loop.

You could put the initialization in a function called setup and the infinite loop in a function called loop. And have a main function like this:

int main( void )
{
  setup();

  for (;;)
  {
    loop();
  }

  return 0;
}

wait, a saw this somewhere already :-)

  • The recovery process should restart the microcontroller. But now this uses watchdog timer to do this. Which cause to enter again into the recovery mode and not to the application mode. – Dankó Dávid Jul 5 at 19:13
  • 1
    @DankóDávid, use watchdog interrupt instead of watchdog. make the arrangements in the interrupt and then reset with wdt_enable(WDTO_15MS); my is here: github.com/jandrassy/Regulator/blob/… – Juraj Jul 5 at 20:22
  • you could use this library github.com/nadavmatalon/WatchDog I plan to replace my watchdog handling with it – Juraj Jul 5 at 20:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.