The first step in a reset handler should be to save the processor state. This involves saving important register values like the program counter, stack pointer, and any other registers that contain information needed to restore the state of the program prior to the reset. Preserving this state is crucial so that after the reset handling is complete, the program can resume where it left off rather than starting completely from scratch.
Why Saving State is Important
When a microcontroller or embedded system undergoes a reset, it means that the processor is restarting and all registers are set back to their default values. This erases any program state that existed prior to the reset. Without preserving some of that old state, there would be no way for the program to know where it was or what it was doing before the reset occurred. The program counter (PC) register for example, holds the memory address of the next instruction that needs to be executed. If this value gets erased, the program will start executing from the beginning as if it just freshly powered on. Any variables stored in registers would also get erased if their values are not preserved.
By saving important state like the PC, stack pointer, and any general purpose registers that hold data, the reset handler can restore this state after doing the necessary reset handling. This way, the program can pick up right where it left off rather than starting from the beginning. The user experience is much better when resets do not disrupt program operation beyond what is absolutely necessary for the reset handling.
How to Save State During Reset
Most processor architectures provide special register banks or memory regions that are not erased on reset. The reset handler can leverage these to preserve state. For example, many ARM Cortex-M processors provide a Backup Register set that maintains its contents even after reset. The reset handler can copy important main register values like the PC and stack pointer into the backup set early on. After the rest of reset handling completes, it can copy the values back to restore the main processor state.
Another common technique is to designate a specific SRAM region that is not reset on power up. The reset handler can copy necessary state variables into this SRAM area before they are erased from their main registers. External low power SRAM or battery backed RAM can also be used to store state across reset. The reset handler just needs to copy important data there early on before register values are lost.
Some processors also provide debugging features like shadow register sets that can retain state across reset or debugging. These shadow registers or special CPU modes can be leverage by the reset handler as well if available.
What State Needs Preserving
The most important state to preserve is:
- Program counter value – To resume program execution from same point
- Stack pointer – To maintain proper stack operation
- Working registers – Any live data needed for program
- Status/control registers – For mode/state control info
Beyond the program counter and stack pointer, the reset handler needs to identify any other registers that contain data that is still needed by the program after reset. This may include things like:
- Live data variables
- Peripheral configuration settings
- System clocks/dividers
- DIO/GPIO states
- Communication peripheral states
- Memory allocation info
The analysis requires understanding which register contents can be discarded on reset versus which ones need maintained. This depends on the program logic and structure of the specific system being designed.
Challenges of State Preservation
Some key challenges around properly preserving state include:
- Identifying live state – The reset handler needs to be coded to save only data that is still relevant to the program after reset. Saving non-live data wastes effort.
- Allocating storage – Enough registers/RAM needs allocated to preserve all required state. This depends on the system size.
- Access timing – State saving needs done early enough before reset erases registers.
- Multitasking – More complex to preserve task states in RTOS or multi-threaded applications.
- Resource conflicts – Access conflicts if reset handler uses same resources as application code.
Careful design is required to overcome these challenges and ensure seamless state preservation across reset. The data that needs preserved must be well understood. Proper storage must be allocated. The preserved state data should also be validated after reset prior to restoring state, in case any corruption occurred.
Saving State in Cortex-M Reset Handler
Here is an example reset handler for an ARM Cortex-M processor that demonstrates how to properly save state: /* Reset handler */ void Reset_Handler(void) { /* Define storage for register values */ uint32_t saved_msp, saved_psp, saved_primask; /* Stop watchdog timer */ WDT->CR = WDT_CR_DISABLE_Msk; /* Copy MSP and PSP into backup registers */ saved_msp = __get_MSP(); saved_psp = __get_PSP(); SCB->SHPR[3] = saved_msp; SCB->SHPR[4] = saved_psr; /* Store PRIMASK register */ saved_primask = __get_PRIMASK(); SCB->SHPR[5] = saved_primask; /* Perform rest of reset handling */ \\ . . . /* Restore preserved register state */ __set_MSP(SCB->SHPR[3]); __set_PSP(SCB->SHPR[4]); __set_PRIMASK(SCB->SHPR[5]); }
This demonstrates storage of the core stack pointers (MSP, PSP), as well as status register PRIMASK. The watchdog timer is disabled since it can trigger before state is preserved. The stack pointers and status register are copied into the backup registers provided in the Cortex-M architecture for this purpose. After reset handling, the main registers are restored from the backup set.
This is just a simple example. A real-world reset handler would likely need to save more application specific state like peripheral configs, GPIO states, live variable values, etc. The same principles apply of identifying important state early and storing it somewhere safe until it can be restored.
Reset Handler Register Usage
Care must be taken in the reset handler to not overwrite any registers that still contain needed state before it can be preserved. Using the core register bank early in the reset handler can avoid issues. For example:
- R0 – R3: Available for temporary usage
- R4 – R11: May contain application state to preserve
- R12: Contains stack pointer, need preserved
- R13: Contains stack pointer, need preserved
- R14: Contains return address, could hold PC state
- R15: Contains program counter state
General purpose registers R4-R11 may hold important data so should generally be preserved vs. reused if possible. R12-R15 contain crucial stack and PC info. Only R0-R3 are safe for temporary work storage without affecting application state.
The reset handler must be carefully coded to avoid corrupting important state before it can be purposefully saved. Using the proper registers is an important aspect of this.
Validating Saved State
As an added robustness measure, it can be useful for the reset handler to validate any saved state before restoring it. For example, checksums or other integrity checks could detect if any saved register values were altered or corrupted during the reset sequence. If invalid state is detected, the reset handler may be able to reconstruct defaults or at least avoid restoring faulty state to the active registers.
For embedded systems requiring high reliability, validating preserved state improves the robustness against faults and reduces the chance of getting stuck in a crash loop after reset.
Conclusion
The first step in an effective reset handler is saving crucial processor state like the program counter, stack pointer, and any other live application data early in the reset sequence before it can be lost. This preserves the context so the program can seamlessly resume after reset handling. Careful design is needed to identify state, allocate storage, and avoid resource conflicts. Validating the saved state adds further robustness against faults. Following these best practices for state preservation enables reset events to be handled gracefully without losing program continuity.