views:

246

answers:

2

Lately, I've been cleaning up some some C code that runs on an ARM7 controller. In some situations (upgrade, fatal error, etc...) the program will perform a reset. Presently it just jumps to 0 and assumes that the start-up code will reinitialize everything correctly. It got me to thinking about what would be the best procedure a la "Leave No Trace" for an ARM reset. Here is my first crack at it:

void Reset(void)
{
   /* Disable interrupts */
   __disable_interrupts();

/* Reset peripherals, externals and processor */
AT91C_BASE_RSTC->RSTC_RCR = AT91C_RSTC_KEY | AT91C_RSTC_PERRST | AT91C_RSTC_EXTRST| AT91C_RSTC_PROCRST;

while(AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_SRCMP);

/* Jump to the reset vector */
(*(void(*)())0)();
}

This code assumes the IAR ARM compiler and the At91Lib. Anything I haven't considered?

A: 

That should do the trick. I use a similar function with an Atmel SAM3U. I never bothered to poll the status register, but that's a good idea and I'm going to go add that right now!

However, you should never get to the reset vector line since the processor will have already reset. IAR has an __noreturn attribute for use in these cases to allow further compiler optimization. I also load my reset function into ram (see __ramfunc) since I use at the end of firmware updates where the microcontroller can't run from flash.

Also, you shouldn't need AT91C_RSTC_EXTRST flag unless you are controlling the reset of external devices with that line.

__noreturn void Reset(void)
{
    __disable_interrupts();

    AT91C_BASE_RSTC->RSTC_RCR = AT91C_RSTC_KEY |
                                AT91C_RSTC_PERRST |
                                AT91C_RSTC_EXTRST |
                                AT91C_RSTC_PROCRST;

    while (AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_SRCMP);
}
Judge Maygarden
+2  A: 

The very best solution to accomplish a "hard reset", as opposed to simply jumping through the reset vector, is to force a watchdog timer reset -- if you have one, that is.

Since your title is "cleanest reset", that's my advice. If you simply do a "jump to reset vector", the system could be in any number of states (peripherals still active, ADC conversions in progress, etc...)

Dan
In the example code above, a reset of the peripherals (internal and external) is done.
waffleman
AFAIK watchdog reset is the most common way. However, instead of setting a short timeout and waiting you can usually just feed a wrong code to watchdog - in most implementations it causes immediate reset. With manual reset you might forget to reset some stuff, with watchdog you don't need to bother.
Igor Skochinsky