Submitted by mdiaconescu on
Choosing a MCU with a small amount of RAM (e.g., the ATmega328p
MCU has only 2KB RAM), and programming it by using dynamic memory allocation
(e.g., by using malloc
) may cause memory fragmentation
having as side effect strange MCU behavior. In such cases, observing the
"real free" amount of RAM and rebooting the device whenever a dangerously
low level is detected may be the only (or the simplest) solution for having
the project running for a long amount of time.
We present three currently available and simple methods which allows to programmatically reset an Arduino.
Watchdog reset - the recommended method
Whenever possible, this is the method one should use. Not only that was
designed and implemented by the chip manufacturer, but also produces a clean
reset, with the same results as when you freshly power the Arduino (or the
custom Arduino-brained project board). Think on a watchdog as on a
kind of guardian for the micro-controller, able to power it off then back
on. Once a watchdog was started, the program must emit signals (also named
reset signals) within specified time slots, and in the absence of the
correct signal, it simply produces a reset. The specific time periods are
called prescallers and are normally defined as constants. For Atmel MCUs
found in the Arduino boards, the following prescaller constants were
defined: WDTO_15MS
, WDTO_30MS
,
WDTO_60MS
, WDTO_120MS
, WDTO_250MS
,
WDTO_500MS
, WDTO_1S
, WDTO_2S
,
WDTO_4S
, and WDTO_8S
. Their names are suggestive,
indicating possible time slots between 15 milliseconds and 8 seconds.
The following code shows how to use the watchdog to reset the Arduino on-demand:
#include <avr/wdt.h> void softwareReset( uint8_t prescaller) { // start watchdog with the provided prescaller wdt_enable( prescaller); // wait for the prescaller time to expire // without sending the reset signal by using // the wdt_reset() method while(1) {} } void setup() { // add setup code here...} void loop() { // ... various code... // restart in 60 milliseconds softwareReset( WDTO_60MS); }
We have discussed about how use a watchdog for auto-reset purposes, but it has many other use cases, such as waking-up the MCU from power-down states or debugging.
Program restart - the unclean method
This method does not really perform a MCU reboot, but rather a program
restart. The obvious negative effect is that the MCU hardware states remains
mostly unchanged. This includes the pin modes, their
current HIGH
or LOW
states and so on.
The following code shows how to implement the softwareReset
method by using assembly language and executing a jump to the address where
the program starts:
void softwareReset( unsigned long delayMillis) { uint32_t resetTime = millis() + delayMillis; while ( resetTime > millis()) { /* wait and do nothing until the required delay expires... */ } // jump to the start of the program asm volatile ( "jmp 0"); }
Enforce hardware reset - the hacker's method
This method requires to connect one of the digital pins (e.g., digital pin
7) to the reset pin of the Arduino via a 1kOhm or 2.2kOhm resistor.
Then set the digital pin as OUTPUT
and keep it
HIGH
as long as no reboot/reset is required. Once a reboot is
needed, just set the digital pin to LOW
. This method works
because by putting the reset pin to a LOW
state, the
micro-controller receives a "hardware reset signal". The following Arduino
sketch code shows how to implement and use this method:
void softwareReset( uint8_t prescaller) { uint32_t resetTime = millis() + delayMillis; while ( resetTime > millis()) { /* wait and do nothing until the required delay expires... */ } // set digital pin 7 to LOW - reset the MCU digitalWrite( 7, LOW); } void setup() { // set digital pin 7 mode to OUTPUT // it is connected to reset pin via 1kOHM resistor pinMode( 7, OUTPUT); digitalWrite( 7, HIGH); } void loop() { // ... various code... // restart in 60 milliseconds softwareReset( 60); }
Unfortunately, this method can't be used on all Arduino boards and also not
with every Atmel MCU. The main problem is that the digital pins goes in a
LOW
state when set to OUTPUT
thus resulting in a
reset loop which may require to remove the connection with the reset pin
before being able to reprogram the MCU. We confirm that Arduino
UNO and Arduino MEGA2560 boards can be safely used with
this method.
While Arduino was mostly in our discussion (so, Atmel MCUs), there are many other MCUs designed and produced by various manufacturers where the above presented methods work in the same way. However, different code may be required and in case of using "the hacker method", one may need also to study the chip datasheet for being able to correctly use the reset and I/O pins and even may have to use a different resistor value.