This post was featured on the Hack-a-Day Blog on 9/14/10
You can download a C-code rewrite of this code, here.
Mimi Yin has a neat implementation of this code for an interactive sculpture.

For the ReacXion Audio/Visual Project I’ve been working on, it’s necessary to drive 5 speakers independently – each with a variable volume and set frequency (though the frequency of each speaker is different). I examined several methods for generating the 5 square waves in hardware – using a 555 timer, oscillating RC with schmitt trigger, and a bunch of opamp circuits. Unfortunately, none of these generated tones as nice as the ones I got when simply using the arduino tone library. The built-in tone() function allows you to generate a squarewave with 50% duty cycle of your selected frequency on any pin on the arduino. It relies on one of the arduino’s 3 timers to work in the background. Specifically, it uses timer2, which is also responsible for controlling PWM on pins 3 and 11. So you naturally loose that ability when using the tone() function. But I wanted to make 5 tones simultaneously! How to do it?
While the tone() function can only be run one instance at a time, I discovered (after much research), that I could hijack one of the timers (again, I chose timer2), and use some clever math and software interrupts to generate 5 tones simultaneously! I wanted to generate 5 tones of the following frequencies:
- C = 131 Hz
- D = 147 Hz
- E = 165 Hz
- G = 196 Hz
- A = 220 Hz
Any music lovers out there will surely recognize this as the pentatonic scale (5 notes that nearly always sound good together). Now, think back to physics, and recall that period = 1/frequency. In other words, each frequency pin will have to cycle from 0V to 5V and back again in the time dictated by the period for that note. See the following picture:

The red portion of the square wave represents one cycle. From the formula above, we can determine the following periods required to generate each note:
- C = 1/131 Hz = 7.6ms
- D = 1/147 Hz = 6.8ms
- E = 1/165 Hz = 6.0ms
- G = 1/196 Hz = 5.1ms
- A = 1/220 Hz = 4.5ms
But, remember that we are dealing with a microcontroller, so we need to flip the value twice every period. If you take a look at the green portions on the image above you’ll see what I’m talking about. In one red portion of the wave, the value needs to change twice. So in reality, we actually need to be able to flip bits twice as fast as the times outlined above. Dividing those values by two, we get the following:
- C = 7.6ms/2 = 3.80ms
- D = 6.8ms/2 = 3.40ms
- E = 6.0ms/2 = 3.00ms
- G = 5.1ms/2 = 2.55ms
- A = 4.5ms/2 = 2.25ms
So, if we want to generate all these tones at the same time, we’re going to need to have an interrupt service that can activate at a Greatest Common Factor for all these values. This interrupt request will toggle the appropriate pin every prescribed number of milliseconds, and we’ll get the tones we need! So, the least common multiple for the variables above would be: .05ms, or 50μs. If we use this ideal value, we can construct an interrupt service request that will initiate every 50μs during our program. Using some counters, we can flip the bits after the appropriate intervals! Let’s calculate those counters now:
- C = 3.80ms/50μs = 76 counts
- D = 3.40ms/50μs = 68 counts
- E = 3.00ms/50μs = 60 counts
- G = 2.55ms/50μs = 51 counts
- A = 2.25ms/50μs = 45 counts
In an ideal world, we would simply have a software interrupt trigger every 50μs, increment 5 separate counters each time, and toggle the associated pin when we reached the right value. For example, every time counter1 reached 76, we would reset it to 0, and toggle the value of that pin. If the only thing you were doing with your CPU was making noises, then this would work quite well. But the whole reason for doing this in an interrupt routine is so that we can do other things simultaneously. For this project, I’m simultaneously controlling a large LED matrix. If the matrix isn’t refreshed often enough, the display looks choppy. Unfortunately, cutting away to an interrupt routine every 50μs was too often, and the display started to look funny. So, I had no choice but to trade off some frequency accuracy for a reduction in how often I activated the interrupt. After some trial and error, I deemed the golden value to be 64μs. It’s a little more than the ideal lowest common denominator, but still close enough that the notes sound good. Using this new value, I calculated new counts, and implemented them in my interrupt routine:
- C = 3.80ms/64μs ≈ 60 counts
- D = 3.40ms/64μs ≈ 53 counts
- E = 3.00ms/64μs ≈ 47 counts
- G = 2.55ms/64μs ≈ 40 counts
- A = 2.25ms/64μs ≈ 35 counts
And that’s it! Using these values, I can simultaneously generate all five notes, while maintaining enough time to quickly update my LED Matrix. Below is the final arduino code for making this work. Thanks to Sebastian Wallin for some awesome information on interfacing with arduino timer interrupts.
Licensed via Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115 //** ReacXion Source Code **//
//** www.jeremyblum.com **//
/* Timer reload value, globally available */
unsigned int tcnt2;
/* Toggle HIGH or LOW digital write */
int toggle1 = 0;
int toggle2 = 0;
int toggle3 = 0;
int toggle4 = 0;
int toggle5 = 0;
/* Keep track of when each note needs to be switched */
int count1 = 0;
int count2 = 0;
int count3 = 0;
int count4 = 0;
int count5 = 0;
/* Frequency Output Pins */
#define FREQ1 9
#define FREQ2 10
#define FREQ3 11
#define FREQ4 12
#define FREQ5 13
//Setup Function will run once at initialization
void setup()
{
/* First disable the timer overflow interrupt*/
TIMSK2 &= ~(1<<TOIE2);
/* Configure timer2 in normal mode (no PWM) */
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
/* Select clock source: internal I/O clock */
ASSR &= ~(1<<AS2);
/* Disable Compare Match A interrupt (only overflow) */
TIMSK2 &= ~(1<<OCIE2A);
/* Configure the prescaler to CPU clock divided by 128 */
TCCR2B |= (1<<CS22) | (1<<CS20); // Set bits
TCCR2B &= ~(1<<CS21); // Clear bit
/* We need to calculate a proper value to load the counter.
* The following loads the value 248 into the Timer 2 counter
* The math behind this is:
* (Desired period) = 64us.
* (CPU frequency) / (prescaler value) = 125000 Hz -> 8us.
* (desired period) / 8us = 8.
* MAX(uint8) - 8 = 248;
*/
/* Save value globally for later reload in ISR */
tcnt2 = 248;
/* Finally load end enable the timer */
TCNT2 = tcnt2;
TIMSK2 |= (1<<TOIE2);
//Configure I/O Pin Directions
pinMode(FREQ1, OUTPUT);
pinMode(FREQ2, OUTPUT);
pinMode(FREQ3, OUTPUT);
pinMode(FREQ4, OUTPUT);
pinMode(FREQ5, OUTPUT);
}
/* Install the Interrupt Service Routine (ISR) for Timer2. */
ISR(TIMER2_OVF_vect) {
/* Reload the timer */
TCNT2 = tcnt2;
count1++; count2++; count3++; count4++; count5++;
if (count1 == 60)
{
digitalWrite(FREQ1, toggle1 == 0 ? HIGH : LOW);
toggle1 = ~toggle1;
count1 = 0;
}
if (count2 == 53)
{
digitalWrite(FREQ2, toggle2 == 0 ? HIGH : LOW);
toggle2 = ~toggle2;
count2 = 0;
}
if (count3 == 47)
{
digitalWrite(FREQ3, toggle3 == 0 ? HIGH : LOW);
toggle3 = ~toggle3;
count3 = 0;
}
if (count4 == 40)
{
digitalWrite(FREQ4, toggle4 == 0 ? HIGH : LOW);
toggle4 = ~toggle4;
count4 = 0;
}
if (count5 == 35)
{
digitalWrite(FREQ5, toggle5 == 0 ? HIGH : LOW);
toggle5 = ~toggle5;
count5 = 0;
}
}
void loop()
{
//Do whatever else you want to do with your arduino!
}













Pingback: 5 Tones, 1 Arduino - Hack a Day
September 14, 2010 at 8:50 am
You might want to low-pass filter the square-wave to get something more useful… ;-)
- michael
September 14, 2010 at 8:57 am
On the idea of outputting multiple tones at once, I had been messing with something similar, but using a s2p chip and dac (just a resistor ladder in my case) to get multiple analog waves out at different forms and frequencies. If you’re interested, I’ve got the code in SVN at http://code.google.com/p/obriencj/source/browse/sequencer/lfo_1/lfo_1.pde
September 14, 2010 at 9:09 am
Hi Jermemy,
nice code, but i noticed one thing: in your isr routine u could speed up things a bit by using else if instead of if in the following ifs. also try to avoid digitalWrite it uses a lot of time,
use direkt pin access instead and save lot s of time!
nice hack!
September 14, 2010 at 10:32 am
Jan> in your isr routine u could speed up things a bit by using else if instead of if in the following ifs
I don’t think so – each if block is dealing with a different counter.
September 14, 2010 at 1:39 pm
Steve is right, they do need to be if statements to account for instances when more than one counter has to be reset in the same cycle. You do make a good point about using digitalWrite though…
Pingback: Connecting Bloggers » Blog Archive » 5 Tones, 1 Arduino
September 14, 2010 at 10:53 am
it is just me, or is he counting from 0 and not taking that into account, so he’s actually 1 rep off of his calculated values?
September 14, 2010 at 1:42 pm
No, I think I should be starting at zero. If I want a cycle to be 3 ticks long for example… 0->1->2->3. I’m actually thinking about the space “between” the numbers. So in this case, I’d need to start at 0 and reset at 3 to get a pulse 3 ticks long.
September 14, 2010 at 1:03 pm
Aleks,
No, I don’t think so, because he is incrementing BEFORE the tests.
Also, it might make it faster to use modulo to test the counters, that way you don’t have to set them to 0 each time. Saving an instruction. But the modulo might cost more than the assignment, so…
September 14, 2010 at 1:43 pm
Also, if I never reset the counters, they may overflow eventually.
September 14, 2010 at 10:17 pm
Mod, just for the record, is monstrously slow.
Fun tip: if you want to cycle count, you can use AVR Studio in debug mode and actually step through your code to see how many cycles each operation takes. (Though this means you can only use the bare metal ATMega functions, not the nice Arduino library.) That’s what I did, and I found lots of neat stuff about the speed of various math operations.
(Summary: add/sub fast, 8 bit ops fast; 32 bit ops slower, mul slower; division and float ops very slow at between 700 ~ 1600 cycles.)
September 14, 2010 at 1:10 pm
Also, HIGH and LOW (I believe) just renaming of true and false (or 1 and 0).
So you might be able to change:
digitalWrite(FREQ5, toggle5 == 0 ? HIGH : LOW);
to
digitalWrite(FREQ5, toggle5);
and save yourself the comparison step.
I may be wrong. YMMV.
September 14, 2010 at 1:44 pm
Yeah, I’m pretty sure you’re right. I’ll play with that a bit.
September 14, 2010 at 1:25 pm
You might be able to go back to 50us if you used a faster method of writing the output pins. This blog post http://www.billporter.info/?p=308 made me aware of just how slow the standard digitalWrite is and that http://code.google.com/p/digitalwritefast/downloads/list is much quicker.
September 14, 2010 at 1:47 pm
Hadn’t heard of this faster digitalWrite – looks really cool! I’ll definitely give it a shot. :)
September 14, 2010 at 2:28 pm
Nicely done. A few possibly helpful tips:
1. It’s easier to test for 0 or negative than other values – so counting down helps.
2. You can toggle an AVR pin with a single instruction, by trying to set it in the PIN register (not PORT). Setting it to a value based on a variable requires a lot more, particularly with wrappers like digitalWrite.
3. The timer will run with your intended period in CTC mode (resetting TCNT from the handler will vary with interrupt latency).
The central tests could thus look like:
ISR(TIMER2_OVF_vect) {
static int8_t count1=max1-1;
if (0>–count1) {
count1=max1-1;
PIND|=_BV(1); // Toggle the output pin
}
}
September 15, 2010 at 8:41 pm
Not to sound like a jerk or anything, but you used the term “Least Common Multiple” wrong… I think you might’ve meant Greatest Common Factor. Still, brilliant!
September 16, 2010 at 7:38 pm
You’re completely right! What was I thinking!? I’ll fix it right now. I guess that’s what I get for writing blog posts at 3AM! ;)
September 17, 2010 at 8:32 am
Interrupting every 50 or 64μSec is barely better than polling, no wonder your LED display gets messed up. You may cause less interruption to your LED display if you calculate how many intervals you need to wait until the next pin toggle, and set the timer to that exact amount. Then you only get timer interrupts when you really need them.
Second, for whatever reason, your blog post is treating the code as HTML, and so everything that has a < (such as <<) or an & followed by a ; is getting eaten. So I can't read your code properly.
But otherwise, nice work!
September 17, 2010 at 11:37 am
I’ve found it to be much better than polling. I tested both ways. Using an ISR produced far better results, whereas polling was too often “off-the-mark”. The sweet spot I found works quite and allows me to drive my LED array with no noticeable lag while still playing notes.
However, your idea is a good one, and it would reduce the number of ISRs I’d have to jump into, so I’ll definitely give it at try. Thanks!
I’ve fixed the code issue too.
September 20, 2010 at 2:57 pm
AWesome work here man! i was wondering, say im working with five buttons. how can i use this to make a polyphonic keyboard? i guess what im saying is that would i just have to make the counters go up and the if statements run only if a button is pressed otherwise reset the counter to zero? and what about volume. i looked into your video for ReacXion, and the sound gradually ramped up. how is this done? i am decent at programming and get the jist of it, i just have not worked with any interupts. thanks!!
September 20, 2010 at 6:14 pm
i know im double posting. sorry! i was wondering what IC you used for the digital potentiometer, and how the transistor circuitry works as well. after watching the other videos i realized that was how you controlled audio volume. pretty clever!
September 20, 2010 at 7:46 pm
If I were you, I just wouldn’t handle the buttons through software all. Simply put a pushbutton between the speaker and ground, so it can only produce noise when the button is pressed. I used the AD5206 digital pot: http://search.digikey.com/scripts/DkSearch/dksus.dll?WT.z_header=search_go&lang=en&site=us&keywords=AD5206BN10-ND&x=0&y=0
It’s also available in a 4-channel version.
September 21, 2010 at 12:13 am
The problem is that I have a controller that changes the nits I play based on some sensors. I’m guessing that this code isn’t ideal for that sort of thing then huh?
September 21, 2010 at 11:37 am
You could definitely make it work. Having even more interrupts might slow things down. You may be best polling the buttons in the main loop.
Pingback: Arduino | Embeddedpub - Embedded Projects
Pingback: Zarathustra | Mimi Yin
October 17, 2010 at 7:06 pm
Nice project!
Time slicing worked for me. Just share the loop time between multiple channels and you only need a single output and no math in your mixer. I have 6 channels working on an AVR324 this way…
http://www.lucidscience.com/pro-lazarus-64%20prototype-1.aspx
Videos near the end show the sound system working.
Brad
February 26, 2011 at 9:11 am
hello sir can you please upload video of this design of 5 speakers
February 26, 2011 at 1:29 pm
This project isn’t finished yet, but this video shows the design that I’m working towards: http://www.youtube.com/watch?v=TeZ_gcoRLFM
Pingback: [Sciguy14] Arduino Tutorial 10: Interrupts and Hardware Debouncing | Ayarafun
July 15, 2011 at 10:17 pm
Hia. I am new to interrupts with the Arduino, and I had a question or two. I feel like there are probably obvious solutions, so excuse me if these questions are pretty dumb. >.< I was wondering how exactly I could use the interrupts to generate these notes for a specified period of time, like if I was to play an eighth note, half, whole, etc? I tried just setting a boolean value on and off with some delays in the loop function, the value effecting the interrupt itself, but it stopped working after going down low enough in milliseconds. And I was hoping to be able to do this with timer interrupts instead of using the loop function, so that I could do it with multiple pins playing notes at different speeds while doing something else at the same time.
July 17, 2011 at 1:47 pm
You might be able to do that by using the other internal time to trigger transistors that switches the signals on and off before they reach the speaker.
January 22, 2012 at 11:38 am
I read your article on driving 5 speakers with one arduino. Nice work.
I was wondering if this would be a good starting point for a project I am working on. I need to drive 4 stepper motors independently with ramp-up and ramp-down. The driver board for the steppers is a Toshiba based board in which I only need to send it a pulse to step the motor, so I will need to send 4 independent pulses to drive each motor at different speeds. Your work looks like the way to go, but the ramping has me in a quandary. Any suggestions?
February 13, 2012 at 10:33 am
Yes, it sounds like using timer interrupts might be the way to go, to ensure you send commands at regular intervals.
February 25, 2012 at 1:29 pm
Very nice. Is there any way I can change the code so that the frequencies are variable, i.e by using a potentiometer to adjust them?
I tried changing
if (count1 == 60)
to
if (count1 == knob)
where ‘knob’ is defined by an analogRead value but this had some weird effects.
February 25, 2012 at 4:12 pm
Actually, just realised that that does work (I’d got something in the wrong place before).
However – is it possible to make it so that the period of the “HIGH” output is different from the period of the “LOW” output?