Designing the tiny noisemaker

Noisemakers based on an ATmega328 or ATtiny45/85, and a small piezo speaker. From left to right, top to bottom: Version 1. First experiment with ATmega328, running with 16MHz crystal. Eventually used the 8MHz internal clock, to use less power. Crystal no longer needed. Version 2: Second experiment with ATmega328, without crystal. Down to 7 microamps of current draw when sleeping. Also omitted capacitor for power smoothing. Seems to work fine. Version 3: Switched to an ATtiny45 for it's smaller size. Also removed programming header. Need to remove chip to program now. Version 4: Final version. Using an ATtiny85 glued directly to a CR2032 battery holder. Added programming header back on, but only 4 pins. Need to use gator clips to attach power and ground for programming.
Progression of prototypes

In my previous post, I wrote about how I got the current draw on my noisemaker down to a small enough amount that it should be able to run for months. (More to come about battery life when my experiment is finished.) I didn’t originally start with an ATtiny45/85 though, so I thought I would write a bit about what I started with, and how the design changed as I went.

I started out, as I usually do, with an Arduino Uno. What I wanted to do originally was use PWM to play sounds on a piezo speaker. Timer1 is the library I found that let me do that. With that, I was able to get some pretty annoying beeping sounds out of that little piezo speaker.

Since I wanted to plant 8-10 of these in the office, $35 each for an Uno was way too much. I wanted to be able to make them for less than $10 each. To do this, I would need to get this working with a bare AVR chip and no external oscillator. This would also make them smaller and easier to hide.

My first step toward that goal was to reproduce the same circuit on a breadboard using an ATmega328. Without the USB-serial converter from the Uno, I would need to program it through the ICSP pins using my Arduino-ISP programmer.

Arduino ISP connected to breadboard with ATmega328
Arduino ISP connected to breadboard with ATmega328 (piezo not pictured)

Once this was working (which was pretty quick since this wasn’t the first time I had done this sort of thing) I decided to dead-bug a prototype. I was apprehensive about soldering directly to the chip though, because I’d never done it before, and I didn’t have any spare chips around. I did, however, have a whole bunch of 28-pin DIP sockets around, so I popped the chip into one of those, and soldered everything to that. Thus was born my first prototype:

Original prototype
Original prototype

Unfortunately, this prototype still required some kind of power source. I had neglected to consider that when I constructed it. I decided, possibly hastily, to come back to that later. In hindsight, the power supply is something I should consider early on in the design, considering how much it affected the final design. I decided instead to concentrate on the fact that it was also still using a fairly expensive (only $2, but it adds up when you’re making 10) crystal oscillator, and a large and expensive ATmega328. I knew from a previous project that by setting fuses, I could get the AVR to run without the need of the oscillator, so I set the appropriate fuses, and got it beeping away annoyingly without needing the oscillator. To prove it was working, I constructed a 2nd prototype, without the oscillator, or the two 20pf capacitors needed for the oscillator. I also decided to forgo the 10uf capacitor between GND and Vcc, trusting that whatever battery I used would be able to supply sufficiently ripply-free power to make it unnecessary.

Second prototype
Second prototype

The 3rd prototype was when I decided to try shrinking it in size and cost by using an ATtiny45. This presented a bit of a challenge since they don’t have a 16-bit timer, for the PWM sounds, like the ATmega328. Instead of trying to get things working with an 8-bit timer (which I’m not sure has the resolution for playing back notes and such) I ended up rewriting it all to just bit-bang the sounds out. This worked great, but I still had the problem of the power source to work out.

Third prototype
Third prototype

Somewhere along the way, I don’t actually remember when, I did all the work to get the power consumption down to tiny amounts. I also discovered that once I turned off the brownout protection as part of that, I was able to run the whole thing from a CR2032 coin-cell battery. I included the coin-cell holder in the photo above for scale. It’s much bigger than both the ATtiny and the piezo buzzer combined, so that gave me an idea: Why not glue the IC and piezo to the back of the battery holder, and wire it all up like that. A bit of playing around with different arrangements led me to this:

Final prototype of noisemaker
Final prototype of noisemaker

The CR2032 is only 3V, but at the clock speed I was running the AVR, and with brownout protection set low (or off, in my case), it runs fine at 3V. The only downside is that the piezo isn’t as loud as it was at 4.5 or 5 volts.

I’m actually quite proud of how this turned out, other than the diode. The IC, piezo, and 4-pin header are all glued to the back of the battery holder. Pins 5,6,7 (MOSI, MISO, SCK) are bent over flat so they touch the pins on the 4-pin header. The Vcc pin is bent, carefully, around sideways so it touches the positive terminal of the battery holder. The negative pin of the piezo buzzer is touching the negative terminal of the battery holder.

One of the leads on the resistor from Vcc to pin 1 (reset) is bent around down the center of the IC and over to the 4th pin on the 4-pin header, to make those 4 pins easily accessible for programming. Another resistor (for purposes I’ll explain shortly) is run from pin 7 to the IC’s ground pin, and that resistor lead also carries on to connect to the negative terminal of the battery.

Finally, a diode connects the positive terminal of the piezo buzzer to pin 2 on the IC. The first two prototypes connected the piezo directly to the IC. When I was working on the 3rd prototype, the first one to use an ATtiny, I got it working on a breadboard first. While I was working on the code for bit-banging the sounds, I noticed that some frequencies would cause the AVR to reset. I kind of suspect that a capacitor across the +/- terminals might fix that, but for some reason I didn’t try that at the time. I didn’t realize then that a piezo speaker isn’t (I think?) an inductive load, like a regular speaker would be, so I thought that maybe I needed a diode to prevent reverse current spikes. I’m not entirely sure why it fixed the problem, but it certainly seems to have fixed it.

Low power ATmega/tiny with watchdog timer

At work recently, the pranks have been escalating. I’ve decided that for my next salvo, I’m going to build the most annoying beeping device I can. I’m using an ATtiny45/85 chip, programmed using the Arduino development environment.

 

The clone army grows
The clone army grows

The device is intended to be planted somewhere near the target’s desk, and will just beep (or make some other annoying sound), every 5-8 minutes. In that respect, it’s very similar to the Annoy-a-tron that ThinkGeek sells. (Which was one of my previous salvos.)

Three primary factors influenced the design of this, in this order:

  1. Low power consumption
  2. Inexpensive
  3. Small size

It’s likely to take the subject days, if not weeks, to find it at that rate, so the battery needs to last for at least a few weeks. This means either having a huge battery pack, which would go against point #3, or making the AVR chip use very little power. Thankfully, there are some excellent resources out there about lowering power use on an AVR chip.

As I intend to make around 10 of these devices, keeping the cost down was important. In the end, this led to it drawing about 7 times as power as is possible to get it down to, but with a lower part count, which translates to lower cost. In particular, Sparkfun has an excellent tutorial on getting an AVR down to only 1 microamp of current draw, however this uses a 32KHz watch crystal, which I intended to do without.

Making this as small as possible was quite a challenge, but in the end, the largest parts were the battery and battery holder. This requirement led me away from the 28-pin DIP ATmega328 I prototyped with to an 8-pin DIP ATtiny45/85 that I used in the end. Even the piezo speaker I used is bigger than the AVR.

However, the most challenging part of this project for me was getting the power consumption down to a rate that would allow the CR2032 battery, chosen for it’s size, to power this for long enough. Most of what I learned about power saving I learned from the aforementioned Sparkfun tutorial, and the nightingale example from this page. I found there were 4 key things to getting an AVR to run at low power:

  1. Putting the chip to sleep when it’s idle. (delay() doesn’t do this.)
  2. Setting the clock speed low.
  3. Disabling any peripherals you’re not using
  4. Disabling brown-out protection.

1. Putting the chip to sleep when it’s idle.

Putting the chip to sleep is pretty easy:

set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();

But then you need some way to wake it up. The Sparkfun tutorial uses a 32.686kHz external clock crystal to run Timer2 and wake it up every 8 seconds. Since I’m trying to keep the cost down, I’m forgoing the use of an external clock crystal, so I need a different way to wake the chip back up. Instead, I’m using the internal watchdog timer to wake it up, which I learned about from the nightingale example. I copied the setup_watchdog function from that example and I call it in my setup(), with setup_watchdog(9) so that it wakes up every 8 seconds. When it wakes up, it then calls a function, which is defined like:

ISR(WDT_vect) {
  watchdog_counter++;
}

watchdog_counter is a global variable in my program, used in loop() to keep track of how many times the watchdog has been called.

The loop looks something like:

void loop() {
  sleep_mode();
  // ZZzz....
  if (watchdog_counter >= 60) {
    watchdog_counter = 0;
    annoy();
  }
}

When sleep_mode() is called, the chip goes to sleep, and drops down to much lower current draw. Approximately 8 seconds later, the watchdog wakes it up, and calls the function defined with ISR(WDT_vect). Once that function returns, the loop() function continues again by returning from the call to sleep_mode(). At this point then, the code runs as you would expect it to. It continues on the next line, which checks the counter. If it’s high enough, it calls annoy() and makes annoying noises. When it reaches the bottom of the loop, and continues again at the top, it calls sleep_mode() and goes back to sleep. So to summarize: every 8 seconds it gets woken up, loop() comes out of it’s coma, checks if it’s time to make noise, and then goes back to sleep.

That alone has a dramatic effect on the power usage, but to really get it low, there’s three more things to do.

2. Setting the clock speed low.

The ATmega328 on the Arduino Uno runs at 16MHz. This is great when you care more about getting things done quickly than about power use. For my application, it’s much faster than I need, so I’m happy to sacrifice some speed if it’ll use less power. As a result, my chip is only running at 8MHz. It’s also using the internal oscillator for this, instead of an external clock crystal, to save parts, and lower the cost.

To change the clock speed, and to make it use the internal oscillator, you need an AVR programmer of some sort. There are many AVR programmers out there, but since I had a few spare Arduino boards kicking around, I’m using the Arduino-ISP sketch to turn one of them into a programmer. My ATMega328 is on a breadboard, with the minimum supporting hardware for it to run.

Changing things like the clock speed is done by setting “fuses”. If you haven’t set fuses before, keep this in mind: Setting fuses wrong can do (almost) irreversible things like disabling programming. With that warning in mind, Adafruit has some good info about using avrdude to set fuses.

As far as I’ve been able to determine, this only affects the power usage of the chip when it’s awake.  While it’s sleeping, the clock speed doesn’t appear to have any effect on the current draw.

I’m using E2 for lfuse on an ATyiny85, to set a 8MHz clock.  Lowering it to 1MHz didn’t make much of a difference in power use.

3. Disabling any peripherals you’re not using

With the chip asleep, and the clock at 8MHz, it was still drawing 330 microamps.

The Sparkfun tutorial had some examples of how to disable various parts of the chip.  This can all be done in the code. The code from the example is intended for an ATmega328, so not all of it applies to the ATtiny85.  This is the only part that had any effect on the current draw while asleep for me:

ADCSRA &= ~(1<<ADEN); //Disable ADC
ACSR = (1<<ACD); //Disable the analog comparator
DIDR0 = 0x3F; //Disable digital input buffers on all ADC0-ADC5 pins.

4. Disabling brown-out protection.

At this point, the current draw when asleep was 30 microamps.  Still higher than I wanted.

The trick, which again I learned from the SparkFun tutorial, was to disable brown-out protection.  It’s pretty easy to do, once you already know how to set fuses. I’m just setting efuse to 07 (or FF, which is the same thing) to disable brownout protection.

With all that done, it’s drawing 0.007ma when it’s sleeping, and about 7ma when it’s actually beeping.  7 microamps is exactly what the ATtiny85 datasheet (figure22-12) claims it should draw at 5 volts in power-down mode, with the watchdog timer running, at 25°C.

I suppose one thing that’s worth mentioning is that my circuit is ridiculously simple, so there’s nothing else that could end up drawing extra power. I have a 10k resistor from the reset pin to the Vcc pin, and a piezo speaker connected to a digital output pin, and ground. I have a stack of coin cell batteries connected to Vcc and ground, without any capacitors or anything. It’s been working just fine that way.

More info about power usage to come in a future blog post.