Many times in applications using the Watchdog timer, there may be a requirement to detect if a reset occurred due to Watchdog or POR / XRES and the application may either start fresh in case of POR / XRES or recover and start executing from the state when the watchdog reset occurred.
DETECT THE SOURCE OF RESET
The first requirement is to find out the source of reset. This can be done by checking the WDRS bit in the CPU_SCR0 register. This bit is set in case of a watchdog reset event. The below code in the beginning of main.c can be used.
if(CPU_SCR0 & CPU_SCR0_WDRS_MASK)
// Reset is due to Watchdog
PRESERVE GLOBAL VARIABLES
In order to recover from a watchdog reset and resume the application, it is necessary that the Global variables be preserved when the watchdog reset occurs. This can be done by setting the IRAMDIS bit in the CPU_SCR1 register. When this bit is set, all the cells marked “??” in the table 3-4 of Technical reference manual (SRAM Map Post SWBootReset (00h)) are preserved during a Watchdog reset.
Add the below code in the beginning of main.c to preserve the content of these RAM locations.
CPU_SRC1 |= CPU_SCR1_IRAMDIS;
There are a few more points to consider in the usage of the IRAMDIS bit.
· When using C as the programming language, the boot.asm sets all the global variables to 0x00. This has to be disabled. The boot.asm has a constant “C_LANGUAGE_SUPPORT”, in the beginning. Set this constant to 0 to disable the global initialization. Change the value of the constant in boot.tpl in the project folder, save boot.tpl and Generate Application. As “boot.asm” is generated from boot.tpl, the change will now reflect in boot.asm.
· Only RAM locations from 0x03 are preserved when IRAMDIS is set. Locations 0x00, 0x01 and 0x02 will still get reset. So, no global variable should be placed in these locations. This is highly unlikely to happen though. By default all the global variables are placed in the area “bss”, which follows the areas “virtual_registers” (used by the compiler to store virtual registers) and “InterruptRAM” (used for user module variables). These areas will mostly occupy the locations 0x00 to 0x02 and more. In the remote possibility that both these areas are empty and “bss” starts from 0x00, you will have to create a custom area and place it at a location above 0x02, and place all the locals in this area. More details about placing globals in the desired RAM location can be found in this KB article. The location of the RAM areas can be checked in the project map file (with .mp extension) in the “output” folder in the project.
· Only RAM Page-0 gets cleared by resets and need be preserved by IRAMDIS bit. In devices with more than 256 bytes of RAM, Page-1 and above are not changed by a watchdog reset. So, locating all the global variables in RAM Page-1 or above will not require setting the IRAMDIS bit.
ADDING SOME MORE RELIABILITY
What if the event that caused the watchdog reset (RF interference or a power supply spike), also corrupted some of the global variables? We need to be able to detect this and start the program normally. Create a checksum of all the global variables that are critical to the program and store it in another variable. Every time one of the global variables is updated, update the checksum as well. On watchdog reset, calculate the checksum of all the global variables and compare it with the checksum variable. If the calculated value matches the stored value, then the global variables are intact and the process may proceed to recover from the last state. If the checksum values do not match, then the process can start from beginning.
The code in the beginning of main.c will look something like this:
CPU_SRC1 |= CPU_SCR1_IRAMDIS; // Set the IRAMDIS bit
if(CPU_SCR0 & CPU_SCR0_WDRS_MASK) // Check the source of reset
Reset is due to Watchdog.
Calculate the checksum of the global variables.
If Checksum matches:
Resume from the last state
Start application from beginning
Reset is due to POR / XRES. Start the application from beginning
CLEARING THE WATCHDOG TIMER
Some basic guidelines about when to clear the watchdog timer:
1. Watchdog timer should be cleared in the main code.
2. Watchdog timer must never be cleared in an ISR.
3. It should be cleared as less as possible.
4. Timeout duration must be set by considering the worst case execution time of the loop.