Sometimes it's useful to self-reset a CPU - this allows the application to completely restart, perhaps to avoid software problems, or perhaps to ensure that the application loads data or settings correctly.
At first glance, it seems it may be possible to simply connect up a digital pin to the reset pin. In theory simply setting the digital pin to low would cause the reset. However, Atmel discourage this approach because as the chip starts it's reset, it sets digital pins tri-state, which stops the reset condition possibly leaving the chip in a half-reset state. Indeed, in all the tests we've done, this approach doesn't seem to work.
There are some other ways to do something similar to a reset. One method is to have the processor execute a Jump instruction to location 0. This is effectively what happens when the chip first powers up. Location 0 contains the bootloader code, so the processor executes that, which is much the same as booting the chip from a reset. However, this approach doesn't stop any configured interrupts, nor does it reset the processor state. The bootloader doesn't necessarily resolve this, so you probably won't end up in a properly "reset" state when the bootloader starts running your program.
A second method is to use the Watchdog built into the chip. It's designed to reset the chip if it doesn't get a signal from the running program within a set time. It's possible to setup the watchdog to look for updates (say) every 1ms, but then deliberately don't do that update, which should make the watchdog reset the chip. In our tests, we found the chip ended up perpetually resetting, which makes recovering quite difficult. This method may work, but we didn't manage to do it properly.
In some of our projects, we've elected to use a hardware method. This is a bit more complicated than the "join an output to the reset pin" method, but it works around the reset time problem. The general idea is to use a capacitor to hold the reset line low for long enough that a full reset occurs, but to charge up and let the chip start running again afterwards. The circuit is very simple:

Calculating the R and C values isn't too hard. The Atmel data sheet says that we must hold the pin low for at least 2.5uS (see page 324 in the main data sheet). All we need to do is calculate R x C so that it comes out greater than 2.5uS. There's a slight catch though, and that's that TTL levels for High and Low aren't exactly 5V and 0V. In fact, the logic levels are more like 2V and 0.8V respectively. That means we need to make sure that the R/C charging time must be more then 2.5uS until it reaches about 2V. Capacitors charge exponentially, which complicates the maths even more, but since we're concerned with the bit between 0 and 2V, and not anything above that, our bit of the exponential curve is mostly straight. That actually means our section of the charge will be really short; I'm going to go ahead and estimate it's about a tenth of the full R/C time. In other words, we have to multiply our resistor and capacitor values by ten to get something that will work.

I'm going to start this using a 0.1uF capacitor. I happen to have a few of them kicking about because I use them for lots of different things. That gives me a "raw" resistor value of 25 ohms (2.5uS / 0.1uF = 25 ohms). However, we've said we need ten times that value, so that means we need 250 ohms (giving us a total charge time of 25us). That should be enough to reset the chip reliably, but since 250ohm resistors aren't something I have a lot of, I'm going to bump it up even further. I'm going to use a 1Kohm resistor (as they're pretty common) - that gives me a total charge time of 100uS - that's 0.1mS - faster than the blink of an eye, so barely noticeable, yet it's massively over the minimum the chip spec needs, so it's definitely going to be safe. Also, using a 1K resistor means it's perfectly safe for me to tap the end of it with a grounded wire without causing too much current to flow - this makes a cheap way of manually resetting the chip while you're working on it. It's also possible to put a switch from the reset pin to ground, which does the same sort of thing in a more user-friendly way - again, that 1K resistor means only a little current will flow, even if you hold your finger on the reset button for a long time.
In our tests, running this code in our program:
pinMode(2, OUTPUT);
digitalWrite(2,LOW);
...is enough to reliably reset the chip. We've tried this hundreds of times, and it's worked throughout, so we're pretty sure it's a good solution.
This circuit is an easy addition to make, to any Arduino based circuit, and even if it's never used in software, it won't cause any harm. It can co-exist with a manual push switch, and is careful about power supply current flow. What's more, it's within the specifications for the chip, so it'll reset it reliably with a physcial switch, or with software.
- Log in to post comments