The Cleanest Reset for an ARM Processor - c

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?

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

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.

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

These days, wouldn't using CMSIS __NVIC_SystemReset(void) be cleanest?

Related

How Can I save some data before hardware reset of microcontroller?

I'm working on one of Freesacle micro controller. This microcontroller has several reset sources (e.g. clock monitor reset, watchdog reset and ...).
Suppose that because of watchdog, my micro controller is reset. How can I save some data just before reset happens. I mean for example how can I understand that where had been the program counter just before watchdog reset. With this method I want to know where I have error (in another words long process) that causes watchdog reset.
Most Freescale MCUs work like this:
RAM is preserved after watchdog reset. But probably not after LVD reset and certainly not after power-on reset. This is in most cases completely undocumented.
The MCU will either have a status register where you can check the reset cause (for example HCS08, MPC5x, Kinetis), or it will have special reset vectors for different reset causes (for example HC11, HCS12, Coldfire).
There is no way to save anything upon reset. Reset happens and only afterwards can you find out what caused the reset.
It is however possible to reserve a chunk of RAM as a special segment. Upon power-on reset, you can initialize this segment by setting everything to zero. If you get a watchdog reset, you can assume that this RAM segment is still valid and intact. So you don't initialize it, but leave it as it is. This method enables you to save variable values across reset. Probably - this is not well documented for most MCU families. I have used this trick at least on HCS08, HCS12 and MPC56.
As for the program counter, you are out of luck. It is reset with no means to recover it. Meaning that the only way to find out where a watchdog reset occurred is the tedious old school way of moving a breakpoint bit by bit down your code, run the program and check if it reached the breakpoint.
Though in case of modern MCUs like MPC56 or Cortex M, you simply check the trace buffer and see what code that caused the reset. Not only do you get the PC, you get to see the C source code. But you might need a professional, Eclipse-free tool chain to do this.
Depending on your microcontroller you may get Reset Reason, but getting previous program counter (PC/IP) after reset is not possible.
Most of modern microcontrollers have provision for Watchdog Interrupt Instead of reset.
You can configure watchdog peripheral to enable interrupt , In that ISR you can check stored context on stack. ( You can take help from JTAG debugger to check call stack).
There are multiple debugging methods available if your micro-controller dosent support above method.
e.g
In simple while(1) based architecture you can use a HW timer and restart it after some section of code. In Timer ISR you will know which code section is consuming long enough than the timer.
Two things:
Write a log! And rotate that log to keep the last 30 min. or whatever reasonable amount of time you think you need to reproduce the error. Where the log stops, you can see what happened just before that. Even in production-level devices there is some level of logging.
(Less, practical) You can attach a debugger to nearly every micrcontroller and step through the code. Probably put a break-point that is hit just before you enter the critical section of code. Some IDEs/uCs allow having "data-breakpoints" that get triggered when certain variables contain certain values.
Disclaimer: I am not familiar with the exact microcontroller that you are using.
It is written in your manual.
I don't know that specific processor but in most microprocessors a watchdog reset is a soft reset, meaning that certain registers will keep information about the reset source and sometimes reason.
You need to post more specific information on your Freescale μC for this be answered properly.
Even if you could get the Program Counter before reset, it wouldn't be advisable to blindly set the program counter to another after reset --- as there would likely have been stack and heap information as well as the data itself may also have changed.
It depends on what you want to preserve after reset, certain behaviour or data? Volatile memory may or may not have been cleared after watchdog (see your uC datasheet) and you will be able to detect a reset after checking reset registers (again see your uC datasheet). By detecting a reset and checking volatile memory you may be able to prepare your uC to restart in a way that you'd prefer after the unlikely event of a reset occurring. You could create a global value and set it to a particular value in global scope, then if it resets, check the value against it when a reset event occurs -- if it is the same, you could assume other memory may also be the same. If volatile memory is not an option you'll need to have a look at the datasheet for non-volatile options, however it is also advisable not to continually write to non-volatile memory due to writing limitations.
The only reliable solution is to use a debugger with trace capability if your chip supports embedded instruction trace.
Some devices have an option to redirect the watchdog timeout to an interrupt rather then a reset. This would allow you to write the watchdog timeout handler much like an exception handler and dump or store the stack information including the return address which will indicate the location the interrupt occurred.
However in some cases, neither solution is a reliable method of achieving your aim. In a multi-tasking environment or system with interrupt handlers, the code running when the watchdog timeout occurs may not be the process that is causing the problem.

16PIC877A Reset with C code

I am using PIC16F877a and I need program reset without using button. When I looked at datasheet and referance designs, there is a button on MLCR pin. If button was pushed, MCU was reset. But I need reset that can control with C code, I don't want to use reset button. Is there another way to do it?
PIC 8-bit MCUS have a software reset assembly instruction:
RESET
http://microchip.wikidot.com/8bit:rst
You will have to use inline assembly. I've never used inline assembly for a PIC, but from this page it looks like this is the correct syntax for MPLAB:
void soft_reset(void)
{
_asm
reset
_endasm
}
Do note that, as the linked page states, an external watchdog timer is generally a better way to trigger a full system reset. With a soft reset, external devices are not also reset. With an external WDT, you simply stop petting the watchdog, and then it resets the whole board.
The format for MPLABX XC16 (assuming that this is the compiler you are using) is:
__asm__ volatile ("reset");
Depending on your processor, you can also examine the contents of the RCON register on startup to find out the cause of the reset (MCLR, software, watchdog timer, brownout, etc.)
For XC8, use #asm and #endasm. Using the example from the XC8 manual
#asm
RESET
#endasm
// do it again the other way...
asm("RESET");
A microcontroller needs to be reset to get to a known state before program execution. Reset is typically generated by hardware signal from external sources, for example, you might find a reset button on the development board. Most microcontroller devices have an input pin for reset.

NVIC_SystemReset() stuck in while loop (STM32F302VB)

I'm currently developing on a STM32F302VB and I need to perform a software reset. On all my previous projects (with STM32F427 and STM32F030C8), I've always used the NVIC_SystemReset() function successfully. But for some reason it won't work with this chip.
The implementation is in CMSIS core_cm4.h and is as follows:
__STATIC_INLINE void NVIC_SystemReset(void)
{
__DSB(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */
SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) |
(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
SCB_AIRCR_SYSRESETREQ_Msk); /* Keep priority group unchanged */
__DSB(); /* Ensure completion of memory access */
while(1); /* wait until reset */
}
The function is called and all instructions are executed, but it gets stuck in the while loop, and reset never happens. I then have to reset it via JTAG to get it out of that state.
I checked the programming manual and the implementation seems fine (not surprising since it works perfectly on F4 and F0).
I really don't know what the problem might be, does someone have an idea what's going on?
Edit: The function is still not working but as a workaround, after the function gets stuck, I pull down the nRST pin and then up. It's ugly, but it works for now. I would rather do it all in software though.
Tony K was right in his comment, the nRST pin was indeed being pulled high externally, because of a routing mistake.
And contrary to what I thought, the nRST pin is taken into account even in a software reset: the reference manual says: "[Reset] sources act on the NRST pin and it is always kept low during the delay phase", so I should have known!
Removing the pull-up did the trick, the NVIC_SystemReset() function now works as expected!
Thank you very much!

Atomic Block for reading vs ARM SysTicks

I am currently porting my DCF77 library (you may find the source code at GitHub) from Arduino (AVR based) to Arduino Due (ARM Cortex M3). I am an absolute beginner with the ARM platform.
With the AVR based Arduino I can use avr-libc to get atomic blocks. Basically this blocks all interrupts during the block and will allow interrupts later on again. For the AVR this was fine. Now for the ARM Cortex things start to get complicated.
First of all: for the current uses of the library this approach would work as well. So my first question is: is there someting similar to the "ATOMIC" macros of avr-libc for ARM? Obviously other people have thought of something in this directions. Since I am using gcc I could enhance these macors to work almost exactly like the avr-libv ATOMIC macors. I already found some CMSIS documentation however this seems only to provide an "enable_irq" macro instead of a "restore_irq" macro.
Question 1: is there any library out there (for gcc) that already does this?
Because ARM has different priority interrupts I could establish the atomicity in different ways as well. In my case the "atomic" blocks must only make sure that they are not interrupted by the systick interrupt. So actually I would not need to block everything to make my blocks "atomic enough". Searching further I found an ARM synchronization primitives article in the developer infocenter. Especially there is a hint at lockless programming. According to the article this is an advanced concept and that there are many publications on it. Searching the net I found only general explanations of the concept, e.g. here. I assume that a lockless implementation would be very cool but at this time I feel not confident enough on ARM to implement this from scratch.
Question 2: does anyone have some hints for me on lockless reads of memory blocks on ARM Cortex M3?
As I already said I only need to protect the lower priority thread from sysTicks. So another option would be to disable sysTicks briefly. Since I am implementing a timing sensitive clock algorithm this must not slow down the overall sysTick frequency in the long run. Introducing some small jitter would be OK though. At this time I would find this most attractive.
Question 3: is there any good way to block sysTick interrupts without losing any ticks?
I also found the CMSIS documentation for semaphores. However I am somewhat overwhelmed. Especially I am wondering if I should use CMSIS and how to do this on an Arduino Due.
Question 4: What would be my best option? Or where should I continue reading?
Partial Answer:
with the hint from Notlikethat I implemented
#if defined(ARDUINO_ARCH_AVR)
#include <util/atomic.h>
#define CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
#elif defined(ARDUINO_ARCH_SAM)
// Workaround as suggested by Stackoverflow user "Notlikethat"
// http://stackoverflow.com/questions/27998059/atomic-block-for-reading-vs-arm-systicks
static inline int __int_disable_irq(void) {
int primask;
asm volatile("mrs %0, PRIMASK\n" : "=r"(primask));
asm volatile("cpsid i\n");
return primask & 1;
}
static inline void __int_restore_irq(int *primask) {
if (!(*primask)) {
asm volatile ("" ::: "memory");
asm volatile("cpsie i\n");
}
}
// This critical section macro borrows heavily from
// avr-libc util/atomic.h
// --> http://www.nongnu.org/avr-libc/user-manual/atomic_8h_source.html
#define CRITICAL_SECTION for (int primask_save __attribute__((__cleanup__(__int_restore_irq))) = __int_disable_irq(), __ToDo = 1; __ToDo; __ToDo = 0)
#else
#error Unsupported controller architecture
#endif
This macro does more or less what I need. However I find there is room for improvement as this blocks all interrupts although it would be sufficient to block only systicks. So Question 3 is still open.
Most of what you've referenced is about synchronising memory accesses between multiple CPUs, or pre-emptively scheduled threads on the same CPU, which seems entirely inappropriate given the stated situation. "Atomicity" in that sense refers to guaranteeing that when one observer is updating memory, any observer reading memory sees either the initial state, or the updated state, but never something part-way in between.
"Atomicity" with respect to interrupts follows the same principle - i.e. ensuring that if an interrupt occurs, a sequence of code has either not run at all, or run completely - but is a conceptually different thing1. There are only two things guaranteed to be atomic w.r.t. interrupts: a single instruction2, or a sequence of instructions executed with interrupts disabled.
The "right" way to achieve that is indeed via the CPSID/CPSIE instructions, which are wrapped in the __disable_irq()/__enable_irq() intrinsics. Note that there are two "stages" of interrupt handling in the system: the M3 core itself only has a single IRQ signal - it's the external NVIC's job to do all the routing/multiplexing/prioritisation of the system IRQs into this one line. When the CPU wants to enter a critical section, all it needs to do is mask its own IRQ input with CPSID, do what it needs, then unmask with CPSIE, at which point any pending IRQ from the NVIC will be taken immediately.
For the case of nested/re-entrant critical sections, the intrinsics provide a handy int __disable_irq(void) form which returns the previous state, so you can unmask conditionally on that.
For other compilers which don't offer such intrinsics, it's straightforward enough to roll your own, e.g.:
static inline int disable_irq(void) {
int primask;
asm volatile("mrs %0, PRIMASK\n"
"cpsid i\n" : "=r"(primask));
return primask & 1;
}
static inline void enable_irq(int primask) {
if (primask)
asm volatile("cpsie i\n");
}
[1] One confusing overlap is the latter sense is often used to achieve the former in single-CPU multitasking - if interrupts are off, no other thread can get scheduled until you've finished, thus will never see partially-updated memory.
[2] With the possible exception of load/store-multiple instructions - in the low-latency interrupt configuration, these can be interrupted, and either restarted or continued upon return.

PIC32 WDT reset not working on some PIC32

I have a PIC32 reset function:
void reset_cpu(void)
{
WDTCON=0x8000;
EnableWDT(); // enable the WDT
ClearWDT();
while(1){};
}
It works on a PIC32MX360F512L but not on a PIC32MX695F512L. It just spins forever. Can anyone tell me why, or suggest another way to reset my processor?
If you are using plib.h, you can simply call this function:
void reset_cpu(void)
{
SoftReset();
while(1){};
}
This has the advantage to trigger an instant reset. From reset.h:
How it works: The following steps are performed by this function:
Step 1 - Execute "unlock" sequence to access the RSWRST register.
Step 2 - Write a '1' to RSWRST.SWRST bit to arm the software reset.
Step 3 - A Read of the RSWRST register must follow the write. This action triggers the software reset, which should occur on the next
clock cycle.
Bear in mind plib is obsolete and will soon be removed from MPLAB XC32. Worth considering Harmony for new designs: http://www.microchip.com/mplabharmony
Nothing immediately stands out to me when looking at the datasheets for both of the microcontrollers. However, I do have a couple of suggestions.
First, in your function you are doing the following:
WDTCON=0x8000;
EnableWDT();
If you look at plib.h you will see that it refers to wdt.h. In wdt.h you can see that EnableWDT() is simply a macro that expands to the following:
WDTCONSET = _WDTCON_WDTCLR_MASK
Where the mask is 0x00008000. Basically, you are performing the same operation twice. Just let the macro take care of enabling it.
Also, since you are using the watchdog to reset your device, there is no need to clear the watchdog. ClearWDT() just resets the watchdog and makes your while(1) loop run longer. So, I would write your function like this:
void reset_cpu(void)
{
EnableWDT();
while(1){};
}
Finally, I would recommend taking a look to ensure that you have the correct processor selected in your IDE. I am not certain that this would cause your problem, but if you had the PIC32MX360F512L selected and tried running it on the PIC32MX695F512L, you could end up with the wrong register definitions (assuming that you are using #include "xc.h").
I would also check on how you are setting your device configuration bits. It is possible to set a very long timeout on the watchdog.

Resources