The Cleanest Reset for an ARM Processor

10,309

Solution 1

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);
}

Solution 2

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...)

Solution 3

I agree with @Dan that if your system has a watchdog timer available, that should provide the cleanest whole-board reset. BUT... If your processor is an ARMv7-M architecture (e.g. Cortex-M3, etc), you may be able to do the following even if you do NOT have a watchdog timer available, depending on your particular implementation:

#define SYSRESETREQ    (1<<2)
#define VECTKEY        (0x05fa0000UL)
#define VECTKEY_MASK   (0x0000ffffUL)
#define AIRCR          (*(uint32_t*)0xe000ed0cUL) // fixed arch-defined address
#define REQUEST_EXTERNAL_RESET (AIRCR=(AIRCR&VECTKEY_MASK)|VECTKEY|SYSRESETREQ)

printf("\nRequesting an external reset...\n");
fflush(stdout);
REQUEST_EXTERNAL_RESET;
printf("\nIt doesn't seem to have worked.\n");
fflush(stdout);

See the ARMv7-M Architecture Reference Manual, search for AIRCR and SYSRESETREQ.

This may be effectively the same solution as what "Judge Maygarden" posted, but the identifiers used in his post appear to be Atmel-specific, while the AIRCR register & SYSRESETREQ bits are defined by the underlying ARMv7-M architecture, not by Atmel.

Share:
10,309
waffleman
Author by

waffleman

Updated on June 04, 2022

Comments

  • waffleman
    waffleman almost 2 years

    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?

  • waffleman
    waffleman almost 14 years
    In the example code above, a reset of the peripherals (internal and external) is done.
  • Igor Skochinsky
    Igor Skochinsky over 13 years
    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.