toneAC v1.2 - Twice the volume, higher quality, higher frequency, etc.

toneAC Library Project Homepage**
**

Advantages over the standard tone library:

  • Nearly twice the volume (because it uses two out of phase pins in push/pull fashion)
  • Higher quality (less clicking)
  • Capability of producing higher frequencies (even if running at a lower clock speed)
  • Nearly 1.5k smaller compiled code
  • Bug fixes (standard tone library can generate some odd and unpredictable results)
  • Can set not only the frequency but also the sound volume
  • Less stress on the speaker so it will last longer and sound better

Download:
toneAC v1.2

New in v1.2:
Fixed a counter error which went "over the top" and caused periods of silence (thanks Krodal). For advanced users needing tight code, the TONEAC_TINY switch in toneAC.h activates a version of toneAC() that saves 110 bytes. With TONEAC_TINY, the syntax is toneAC(frequency, length) while playing the note at full volume forever in the background. Added support for the ATmega 640, 644, 1281, 1284P and 2561 microcontrollers.

Connection:
Connection is very similar to a piezo or standard speaker. Except, instead of connecting one speaker wire to ground you connect both speaker wires to Arduino pins. The pins you connect to are specific, as toneAC lets the ATmega microcontroller do all the pin timing and switching. This is important due to the high switching speed possible with toneAC and to make sure the pins are alyways perfectly out of phase with each other (push/pull). See the below list for which pins to use for different Arduinos. Just as usual when connecting a speaker, make sure you add an inline 100 ohm resistor between one of the pins and the speaker wire.

  • Pins 9 & 10 - ATmega328, ATmega128, ATmega640, ATmega8, Uno, Leonardo, etc.
  • Pins 11 & 12 - ATmega2560/2561, ATmega1280/1281, Mega
  • Pins 12 & 13 - ATmega1284P, ATmega644
  • Pins 14 & 15 - Teensy 2.0
  • Pins 25 & 26 - Teensy++ 2.0

Example sketch:

#include <toneAC.h>

void setup() {} // Nothing to setup, just start playing!

void loop() {
  for (unsigned long freq = 125; freq <= 15000; freq += 10) {  
    toneAC(freq); // Play the frequency (125 Hz to 15 kHz in 10 Hz steps).
    delay(1);     // Wait 1 ms so you can hear it.
  }
  toneAC(); // Turn off toneAC, can also use noToneAC().

  while(1); // Stop (so it doesn't repeat forever driving you crazy--you're welcome).
}

Version History:
01/16/2013 v1.1 - Option to play notes in background, returning control back to your sketch for processing while note plays (similar to the way the tone library works). Volume is now linear and in the range from 0-10. Now uses prescaler 256 instead of 64 for frequencies below 123 Hz so it can go down to 1 Hz no matter what speed the CPU is clocked at (helpful if using toneAC to control a two-pin dual LED).
01/11/2013 v1.0 - Initial release.

Enjoy!

Tim

Disadvantages of using toneAC compared to the standard tone library:

  • You must use certain pins (9 & 10 on Uno, 11 & 12 on Mega).
  • Uses two pins instead of one.
  • Tone duration doesn't run as an interrupt, just a simple delay(). This actually may be an advantage to some for simplicity sake.

But, if you're flexible with your pin choices, this is a great upgrade. It also uses timer 1 instead of timer 2, which may free up a conflict you have with the tone library. It also exclusively uses port registers for the fastest and smallest code possible.

Tim

Very cool keep up the good work!

I 'd be cautious to drive high capacitance load like piezo w/o current limiting resistors. Though volume 'd be limited back to 1 pin level.
Don't want to discourage an author, just something to think about, may be put some kind of warning in library header, that reliability of IC could be affected. .

This is great thanks alot for sharing.
**Also using your New Ping library, thanks for that too. 8)

Another good library idea teckel! Your Karma points are way lower than your efforts should show!

Piezo elements are like capacitors, that is a problem for higher frequencies. For ultrasonic sound it is even very bad to use a square wave, because of the peak currents. So there should be a resistor of 220 ohm (or 100 ohm ?) to protect the outputs of the Arduino. Please add a warning about that to your library.

Tested with normal 8 ohm speaker with extra 120 ohm resistor:

  • Arduino Uno, pin 9,10 : good.
  • Arduino Mega 2560, pin 11,12 : good
  • Arduino Leonardo, pin 9,10 : good
  • ATmega8 16MHz, pin 9,10 : good

My conclusion:

  • No nasty click at start and stop : Excellent. A very small click can be heard.
  • Extra loud : Good
  • Small, fast code : Excellent
  • Flexibility : Not so good, fixed pins.
  • Volume control : Good, I needed that. Working roughly, not a linear scale.
  • Frequency range : The lowest frequency is not low enough for a slow blinking two-pin dual led.

If I select a ultrasonic frequency, I don't hear it, but a very small click can be heard when the sound is started and stopped.
Perhaps setting the pins floating (set as inputs) if not used could reduce that. But that will make the code larger.
The normal Arduino tone() library doesn't work for all frequencies with the ATmega8. I didn't test that for your toneAC library very well, but it sounds okay.

Its a very good library. Thank you.

PS: Do you know the Mozzi library ? http://sensorium.github.com/Mozzi/

Magician:
I 'd be cautious to drive high capacitance load like piezo w/o current limiting resistors. Though volume 'd be limited back to 1 pin level.
Don't want to discourage an author, just something to think about, may be put some kind of warning in library header, that reliability of IC could be affected. .
I

I followed the lead of the Arduino.cc website and didn't add a resistor to the piezo circuit drawing. For an 8 Ohm speaker, a single 100 ohm resistor should be used, just like you would with one pin attached. You don't add two resistors, just one. Therefore, it's still twice as loud as using the tone library if you use the same resistor.

Also, isn't there normally a high resistance on a piezo and it's not till high frequencies where the resistance drops to even around 50 ohms? I believe a resistor is only needed for very high frequencies. Also, I believe when driving the piezo with an alternating current like toneAC it doesn't create the high capacitance load like you normally see when driving (charging) it in one direction.

Tim

Krodal:
Piezo elements are like capacitors, that is a problem for higher frequencies. For ultrasonic sound it is even very bad to use a square wave, because of the peak currents. So there should be a resistor of 220 ohm (or 100 ohm ?) to protect the outputs of the Arduino. Please add a warning about that to your library.

I believe a piezo only acts like a capacitor when "charged" in one direction (for example, with the tone library). The deflection of the disc is what generates the current. However, with toneAC it can't charge in this way as an alternating current is being sent. Therefore, the piezo is never charged and never acts like a capacitor. From my understanding of how a charge on a piezo works, supplying an alternating current eliminates the need for a resistor. But, maybe I'm mistaken.

Krodal:
Tested with normal 8 ohm speaker with extra 120 ohm resistor:

  • Arduino Uno, pin 9,10 : good.
  • Arduino Mega 2560, pin 11,12 : good
  • Arduino Leonardo, pin 9,10 : good
  • ATmega8 16MHz, pin 9,10 : good

Nice! Mega, Leonardo, and ATmega8 were my primary concerns. I spent a lot of time sniffing around the Arduino code so I had hoped that I got everything correct.

Krodal:
My conclusion:

  • No nasty click at start and stop : Excellent. A very small click can be heard.
  • Extra loud : Good
  • Small, fast code : Excellent
  • Flexibility : Not so good, fixed pins.

The reason it doesn't have any nasty clicking and noise like you get with the tone library is because I'm letting the ATmega do it's own PWM thing instead of faking it like the tone library does. The tone library just sets up a timed event and then the library twiddles the bits. It works, but not perfectly. This is why I have toneAC fixed to the PWM pins. It would be simple to allow any pins to be used, but the the accuracy wouldn't be perfect (which is required to keep things perfectly out of phase). There would also be a little more to do than with the tone library because two pins would need to be toggled instead of one. Also, as you get into ultrasonic frequencies, there's just not enough processing power on the poor little ATmega to do everything.

Krodal:

  • Volume control : Good, I needed that. Working roughly, not a linear scale.

Very true, the volume is not at all linear. It simply uses the duty cycle which is not linear for audio. I didn't want to hold up the library being released to sort this out. But, it's something I'm still looking into. What I'm thinking is measuring SPL of every duty level and then creating a table of 10 duty cycles (1=min, 10=max) that are linear for volume.

Krodal:

  • Frequency range : The lowest frequency is not low enough for a slow blinking two-pin dual led.

I've got it running here with no problem. For v1.0 of toneAC a 16 MHz ATmega will be able to go down to 2 Hz. My development v1.1 now goes down to 1 Hz (changed to prescaler 256). Here's the sketch I used:

#include <toneAC.h>

void setup() {}

void loop() {
  int pot = analogRead(A0);
  int freq = map(pot, 0, 1023, 3, 30);
  toneAC(freq);
  delay(334);
}

Krodal:
If I select a ultrasonic frequency, I don't hear it, but a very small click can be heard when the sound is started and stopped.
Perhaps setting the pins floating (set as inputs) if not used could reduce that. But that will make the code larger.
The normal Arduino tone() library doesn't work for all frequencies with the ATmega8. I didn't test that for your toneAC library very well, but it sounds okay.

When I do this, I don't hear a click. Then again, I used an ultrasonic (40 kHz) piezo and not a speaker. I'm not so worried about small clicks on start/stop (this is kind of expected). The clicking while playing a constant note or notes is what I have a problem with.

Krodal:
PS: Do you know the Mozzi library ? http://sensorium.github.com/Mozzi/

Not till now. But, doing that kind of thing should be easy with toneAC. Just convert a WAV or MP3 file to something like 8-16 kHz mono and save as RAW. Then load it into a sktech and play the sequence. Maybe I'll do a dog bark example or something.

Tim

As far as I know, a piezo element is always like a capacitor.
If you have a capacitance meter, try your ultrasonic piezo. It could easily be 100nF.
If the capacitance meter uses a DC signal to measure, just add a capacitor in series with the piezo. It won't make any difference.

I used a ultrasonic piezo with a square AC wave (just like toneAC) and my high speed H-bridge driver ic got very hot and got blown.
I learned that 120dB ultrasonic piezo drivers don't use a square wave because of the capacitance. They use some kind of (simulated) sine wave.

If the starting frequency could be 1Hz for a Arduino Uno at 16MHz, that would be very nice.

Can you make a very low volume ?
It is as with the PWM for leds. To get a led dimmed so that it is almost not visible, the pwm should be between 1/1000 or 1/10000.

What about H-bridge drivers for more output power. What kind of driver ic would match your library for a few different applications ?

I did some testing on different acoustic transducers. First, for my ultrasonic transducers I could not get them to draw more than 7 mA no matter the frequency (even the harmonic peak). I have one "piezo" that seems to work more like a regular speaker at 16 ohms. That unit can draw up to 33 mA without a resistor. My guess is that it's not a piezo as my true piezo transducers have a resistance in the mega ohms as they should.

Because of this, I've changed my circuit drawing to include a 100 ohm resistor as it doesn't make much of a difference and it seems that maybe some that claim are piezo are not really piezo. With that said, I'm still not certain that driving a true piezo transducer even at ultrasonic levels requires a resistor when using an alternating current. From what I've read, the capacitance charging only occurs under a DC load, and that charged is discharged when the polarity is reversed (such as in an AC system). Still more testing to confirm this.

For the time being, you should connect a piezo or speaker exactly as you have in the past, a decision on AC connection will need more research. Still toneAC is twice as loud, even when you use or don't use a resistor as you would normally.

Progress on v1.1 of toneAC is coming along. Two major changes that are being tested are a linear volume and a tone length value that works in the background like the tone library. We should see v1.1 released sometime this week.

Tim

Added background playback (timer interrupt controlled) and linear volume to my development version of toneAC. I'll be testing it on Tuesday. Expect a new release probably on Tuesday or Wednesday.

Tim

While not written to do this, toneAC works well controlling a two-pin dual LED. With this and a potentiometer, the sketch below will flash the LED alternating between the two LED colors. This is happening in the background with control returning to your sketch to do other things as noted in the sketch. Every half second it will look at the pot and change the LED flashing speed. This sketch is designed to work with toneAC v1.1 that will be released once I get home

// ---------------------------------------------------------------------------
// Connect a two-pin dual LED to the following pins with inline 220 ohm resistor.
//   Pins  9 & 10 - ATmega328, ATmega128, ATmega8, Uno, Leonardo, etc.
//   Pins 11 & 12 - ATmega2560, ATmega1280, Mega
//   Pins 14 & 15 - Teensy 2.0
//   Pins 25 & 26 - Teensy++ 2.0
// Connect the center lead of a potentiometer to analog pin A0 and the other two leads to +5V and ground.
// ---------------------------------------------------------------------------

#include <toneAC.h>

unsigned long timestamp = 0; // Stores when the next time the routine is set to run.

void setup() {}

void loop() {
  if (millis() > timestamp) { // Is it time yet?
    timestamp += 500;         // Set the next time routine will run. 500 ms because the lowest frequency is 2 Hz, which is a half second.
    int pot = analogRead(A0);            // Read the potentiometer connected to analog pin A0.
    int freq = map(pot, 0, 1023, 2, 40); // Convert pot analog values to a range from 2 to 40 Hz.
    toneAC(freq, 10, 0, true);           // Set the frequency and have it run forever in the background (next event should take over in 500 ms).
  }
  /* Do a bunch of other stuff here, it won't affect toneAC doing its thing. */
}

Because toneAC is designed to be used for audio, duty has been purposed for linear volume control instead of fading the LED from one color to the other evenly. Basically, duty is linear for audio but not for lighting an LED. If there's a desire for linear LED duty control, making a few tweaks to the toneAC library or making a different library designed just for controlling a two color LED would be in order. The above sketch is a teaser that may help someone with a project.

Tim

New in v1.1
Option to play notes in background, returning control back to your sketch for processing while note plays (similar to the way the tone library works). Volume is now linear and in the range from 0-10. Now uses prescaler 256 instead of 64 for frequencies below 122 Hz so it can go down to 1 Hz no matter what speed the CPU is clocked at (helpful if using toneAC to control a two-pin dual LED).

Download:
toneAC v1.1

Tim

I'm still testing it, but I think I found an error.

int f;

while(1)
{
  f = random( 50, 120);
  toneAC(f, 5, 0, true);
  delay(100);
  noToneAC();    // reset registers
}

The example is okay with the noToneAC() to reset the registers.
Try to remove the noToneAC(), that results in gaps in the sound.
Perhaps the counter has to roll-over ?

Krodal:
The example is okay with the noToneAC() to reset the registers.
Try to remove the noToneAC(), that results in gaps in the sound.
Perhaps the counter has to roll-over ?

I heard something like this once, but couldn't duplicate it so I figured I just had a loose connection.

You're exactly correct on your diagnosis. The counter is "over the top" so it needs to wrap before resuming the sound. This isn't very long when using prescaler 1. But, at 122 Hz and below, prescaler 256 is used which is 256 times longer than prescaler 1 and the reason for the long silence.

Since even more problems can happen when we play notes on each side of the prescaler cutoff frequency, I tweaked your sketch to create a torture test:

#include <toneAC.h>

void setup() {}

void loop() {
  int f = random(50, 124);
  toneAC(f, 10, 0, true);
}

Since it includes frequencies above 122Hz, it sometimes also uses prescaler 1. Also, there's no delay so it just hammers the hell of of things. This sketch should produce a static-like noise as it plays random notes as fast as it can. Instead, it's a bunch of random clicks with periods of silence as it frequently goes "over the top".

After some testing, I've isolated the problem and have a fix. In the toneAC.cpp file after the line that reads "ICR1 = top;" add the following line:

  if (TCNT1 > top) TCNT1 = top;         // Counter over the top, not good, put within range.

With this, the above sketch now produces what you'd expect, static. During early development, I set TCNT1 = 0 when starting a tone. That works fine for high frequencies, but poorly at lower frequencies and when changing notes (creates clicks). It's even worse when driving a two-pin dual LED at ultra low frequencies (like at 2 Hz). Adding the noToneAC() in your sketch works because when TCCR1A resets the PWM it automatically sets the counter to zero. While this works, it's not ideal for the above reasons of setting the counter to zero can cause other problems.

In any case, the above line fixes things and I've added it to the development version which will be released in version 1.2.

On a side note, the volume setting doesn't really work well for low frequencies. It doesn't do much to change the volume and lowers the quality (makes it buzzy). I'd suggest to always use 10 for the volume, which keeps the quality high. Only use a lower volume if it's a requirement.

Anyway, thanks for the catch! And leading me in the right direction with the fix.

Tim

First of all, I love the library. It will be my first choice in most applications.
I hope to test the Uno/Mega/Leonardo/ATmega8 with version 1.2, after that it should be ready.
That single line of code makes some of my tests sound a lot better.

I have made a checklist for version 1.2, perhaps there are one to two things that make sense.

(1) The code increased a little (just a little) which is always a problem for the ATmega8
library + example version with 1.0, Arduino Uno : 1516
library + example version with 1.1, Arduino Uno : 1670
library + example version with 1.0, ATmega8 : 1336
library + example version with 1.1, ATmega8 : 1472

(2) The ISR uses millis(), so a roll-over of the millis is possible. The length is no longer fail-safe, so using the delay() function with noToneAC() is preferrable for critical situations.

(3) You don't use the 'L' for long values. I don't mind about it in the sketch, but you could use it in your library. I prefer to use 0L, 256L, - 1L and so on, when long integers are involved.

(4) The examples have the extension *.pde. I would prefer *.ino

(5) In the example you use '/* .... */' for comment, but everwhere else '//'.

(6) In the example, you use a potmeter. But for a small test with the library, a very quick result (showcase) would be needed. And a potmeter will make it unnecessary complicated.

(7) You made 10 volume steps, which is great. But for a 'ping' sound, a smooth decrease of the volume is needed. Or am I asking too much for the library ? Are there open source examples of tunes with volume ?

( 8 ) Why is the sound different for this example ?

int i, freq, vol;

for (i = 0; i<5; i++)
{  
  freq = 900;
  for (vol=10; vol>0; vol--)
    toneAC( freq , vol, 60, false);
  freq = 540;
  for (vol=10; vol>0; vol--)
    toneAC( freq, vol, 60, false);
  delay( 3000);
}

for (i = 0; i<5; i++)
{  
  freq = 900;
  for (vol=10; vol>0; vol--)
  {
    toneAC( freq , vol, 0, true);
    delay(60);
  }
  freq = 540;
  for (vol=10; vol>0; vol--)
  {
    toneAC( freq, vol, 0, true);
    delay(60);
  }
  noToneAC();
  delay( 3000);
}

Krodal:
(1) The code increased a little (just a little) which is always a problem for the ATmega8

Great pains have been taken to keep the code as small as possible. I'm a huge believer in running as much as possible in the background so around 150 additional bytes I believe are important. It's still much smaller than the tone library. I show the Arduino Uno code to be 1604 bytes with Arduino v1.0.2 not 1670. And with the ATmega8 I have it as 1398 instead of 1472 (again v1.0.2). As a test I created a toneACmini() function that only has a frequency and duration (automatically runs in the background). With toneACmini() instead of toneAC() it went down to 1488 bytes on the Uno. But, not sure if 116 bytes is worth confusing people.

Krodal:
(2) The ISR uses millis(), so a roll-over of the millis is possible. The length is no longer fail-safe, so using the delay() function with noToneAC() is preferrable for critical situations.

It uses unsigned long int, so it's about a 50 day range. That should be good for almost any situation. The rollover of micros is critical, but ms hardly ever happens in the real world. Although, I am working on a project right now that I'm trying to get it to run virtually forever.

Krodal:
(3) You don't use the 'L' for long values. I don't mind about it in the sketch, but you could use it in your library. I prefer to use 0L, 256L, - 1L and so on, when long integers are involved.

If there's an advantage I'm not aware of let me know. Most of my longs are unsigned longs. Not sure if that makes a difference.

Krodal:
(4) The examples have the extension *.pde. I would prefer *.ino

They need to be .ino for a library so old versions of Arduino can find them. I'm running only v1.0.2 so everything is a .pde. I change them to .ino just for the library. Other library creators told me to use .ino

Krodal:
(5) In the example you use '/* .... */' for comment, but everwhere else '//'.

I hardly ever use '/* .... */'. I use it in that particular case to try and identify that you can do a bunch of stuff there, not just one line.

Krodal:
(6) In the example, you use a potmeter. But for a small test with the library, a very quick result (showcase) would be needed. And a potmeter will make it unnecessary complicated.

The library is designed for sound, not LEDs. The sample is "toneAC_demo" which doesn't use a pot. The one you're talking about is an advanced one that I don't mention anywhere as it's only for more advanced users that may want to use toneAC for other purposes.

Krodal:
(7) You made 10 volume steps, which is great. But for a 'ping' sound, a smooth decrease of the volume is needed. Or am I asking too much for the library ? Are there open source examples of tunes with volume ?

You're asking too much. I got out my SPL meter and it was HARD to get even 10 volume levels. A square wave just doesn't work well for creating a true volume level. I had to cheat to get even 10, there was really only 9 but that would just be confusing.

Krodal:
( 8 ) Why is the sound different for this example ?

They're very close. But, the first loop is inferior because it uses the foreground method and therefore there's a short period of time where there's no sound, producing a non-constant sound and clicking. This way is designed for a laymen who who isn't too comfortable with programming but they can still generate sound using this method and would probably be totally happy with that. The second way is a more proper way that a higher level programmer would use, knowing that the first way would have a very slight but still noticeable gap between notes reducing quality. I would only ever use the second loop, as I did with the original tone() library as well.

The idea that something runs in the background is very foreign to many novice programmers. They love delay statements, or a command that just does something for as long as they specify and then returns to them when it's done. So, toneAC makes it easy for the masses, but still powerful for those who better understand an interrupt/timer driven paradigm.

Tim

My sketch size was different, because I used my own example.

I like the mini function. Perhaps it will not be used often, it's nice to have as an extra.

Using 'L' or 'UL' for long numbers is something I do for myself, so that I know what I'm doing.

I agree with everything else. Perhaps that ping-pong sound (the second smooth one) can be used as an example ? I'm trying to make more sounds that show what the volume can do.

A page in the playground section would be nice. I can make one, with links to your code and this thread.

But, not sure if 116 bytes is worth confusing people.

think not, but by the time their sketches fill up all memory and the last 116 bytes are critical I assume they aren't confused any more by a stripped lib :wink: