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

Thanks!

Pardon my ignorance, but... what is the resolution? Specifically at the >100kHz range?

polymorph: Thanks!

Pardon my ignorance, but... what is the resolution? Specifically at the >100kHz range?

The resolution is always 1 bit, it's a square wave. That's all that toneAC or just about any other audio library will do on the Arduino, a square wave.

I assume you're trying to output a sound sample? That would require an analog waveform, which the Arduino is not good at all at doing (nor could it ever hope to output anything of any quality at a 100kHz range).

Tim

My apologies, I was not clear.

I meant the frequency resolution. A quick look at the files I downloaded would indicate that the resolution at lower frequencies the frequency resolution is better than at some point where the prescaler must change, and there are larger steps in the frequency.

Kind of like how millis() is milliseconds and has an actual resolution of 1ms, but micros(), although it is microseconds and can be given any number, has an actual resolution of 4us.

Actually I'm looking to use this for an RFID card reader in the 125kHz to 134kHz range. I thought I might try some frequency hunting to look for the tag's actual resonant frequency.

polymorph: My apologies, I was not clear.

I meant the frequency resolution. A quick look at the files I downloaded would indicate that the resolution at lower frequencies the frequency resolution is better than at some point where the prescaler must change, and there are larger steps in the frequency.

Kind of like how millis() is milliseconds and has an actual resolution of 1ms, but micros(), although it is microseconds and can be given any number, has an actual resolution of 4us.

Actually I'm looking to use this for an RFID card reader in the 125kHz to 134kHz range. I thought I might try some frequency hunting to look for the tag's actual resonant frequency.

That's correct, the steps between frequencies gets larger as the frequency increases. In about the 125 kHz to 134 kHz range, there will be these frequencies: 123,077, 125,000, 126,984, 129,032, 131,148, 133,333 & 135,593 Hz (basically about a 2 kHz step). As these are based on the clock frequency of the microcontroller, they will also be off depending on your oscillator and ambient temperature (which is why I gave one below and one above the range you're looking for).

Basically, toneAC can generate frequencies in that range, but if accuracy is important, the ATmega is not an ideal platform as it won't be very granular in frequency and it will vary from board to board based on the microcontroller timer.

Also, I would suggest using the frequencies listed above as they will calculate exactly to a different frequency. For example, if you told toneAC to generate a 127,000 Hz frequency, it would generate a 129,032 Hz frequency instead. So, you probably won't get the results you're looking for. In other words, you should use the above frequencies with toneAC and not any in-between.

I hope this answers your question better.

Tim

Yes, that answers my questions. Those are exactly the sorts of details I was looking for. Thank you!

toneAC with Dickson charge pump

I wanted to set my 433MHz TX module to 5V or 12V, to be able to use it at maximum and reduced power.
The Dickson charge pump seems a good solution for that, but it needs two pins with alternating signals.
That is why I decided to use the toneAC, and it works very well. Without load the output is 14V.

The capacitor at the end is 47uF and it is too small. The TX module empties it in 10ms.
The extra bypass diode is to have a voltage close to 5V when the charge pump is not used.
The 470 ohm resistors are to reduce the peak currents, they can be 120 ohm as well. I need to reduce the peak current, because I have a sensitive 433MHz receiver on the same board as well.

The name of the circuit can be “voltage multiplier” or “voltage tripler” or “charge pump” or something like that. This specific circuit is a “Dickson charge pump”.

Update: The output is very weak. I changed the resistors from 470 ohm into 220 ohm.
Test with a load of 10k (about 1mA load):
1 kHz : 4.97 V
2 kHz : 7.07 V
5 kHz : 9.42 V
10 kHz : 10.36 V
20 kHz : 10.71 V
50 kHz : 10.83 V
100 kHz : 10.84 V
200 kHz : 10.84 V
500 kHz : 10.81 V
1 MHz : 10.74 V
2 MHz : 10.41 V
A 1000uF capacitor is charged to 13V in 10 seconds. That is enough for the TX module for 300 ms (50% duty cycle) and during that, the voltage is lowered to 10V. That is enough to switch a light on an off, but not for an alarm. I could have used two or three 5V TX modules instead, with different TX power levels.

charge-pump.jpg

charge-pump-schematic.png

Great library! I'm driving a piezo from a 3v cell, so this really helps!

On an Attiny44a, the OC1A/B pins are shared with MOSI/MISO, which works (and piezo chirps when uploading :) ) with the changes I made to the original code.

I need to use the OC0A/B & TCNT0 instead, which is only 8bit, but I need to drive @ ~4000hz, is it possible?

Can I chain or loop the timer or interrupt to get ~4000hz? Is there an example of this somewhere?

thx!

protoc0l: Great library! I'm driving a piezo from a 3v cell, so this really helps!

On an Attiny44a, the OC1A/B pins are shared with MOSI/MISO, which works (and piezo chirps when uploading :) ) with the changes I made to the original code.

I need to use the OC0A/B & TCNT0 instead, which is only 8bit, but I need to drive @ ~4000hz, is it possible?

Can I chain or loop the timer or interrupt to get ~4000hz? Is there an example of this somewhere?

thx!

toneAC uses timer 1 (OC1A/B) because that timer has the ability to do the automatic alternating push/pull. Other timers won't allow this. However, I also have a toneAC2 library which should work quite nicely for your needs. That is, if you're using a ATmega and not an ATtiny. Why use a ATtiny anyway? The price is about the same, the ATmega has lower power modes, and the ATmega is available in a smaller footprint. I really find no reason for the ATtiny.

Anyway, if it must be an ATtiny for whatever reason, just create your own loop at whatever frequency you want that flips two pins from on to off and vise versa. That would be very simple and easily run at 4kHz.

Tim

teckel: ... Why use a ATtiny anyway? The price is about the same, the ATmega has lower power modes, and the ATmega is available in a smaller footprint. I really find no reason for the ATtiny.

Thx for reply, not really married to the attiny, but I do need something that can run @ ~2v, and I can get the t44a for 80 cents (@10). I did see some atmega8's around the same price, but I think the vcc was higher. Will take another look.

2V is low. The ATmega8L starts at 2.7V.

I did see a trick once ( perhaps on Hackaday ) that an ATtiny or ATmega starts at a low voltage and increased its own voltage with a voltage doubler to run normal.

protoc0l: Thx for reply, not really married to the attiny, but I do need something that can run @ ~2v, and I can get the t44a for 80 cents (@10). I did see some atmega8's around the same price, but I think the vcc was higher. Will take another look.

The ATmega328P can run at 1.8volts and when in low power mode use only 1μA (microamp). I have a couple projects that I've been running for 3 years from a single set of batteries, and the batteries still have a lot left in them.

Question about race conditions in toneAC2: I was seeing some odd behavior in the standard tone() function that I suspect is due to a race condition between the interrupt handler and tone() inself. The doc says you can call tone() while a previous tone is playing and it will just update the frequency, but tone() can be interrupted at any point by its own interrupt, hence the potential race. In searching the web to see if others had observed this I came across toneAC and toneAC2, and intend to use your library. I don't think I can use toneAC because I need the servo library which uses timer1 on my Uno, but toneAC2 should be just the ticket. So my question: Is there any potential race condition if toneAC2 is called while a previous tone is playing? What is the intended behavior?

The main reason I want to use toneAC2 is to take advantage of "twice the volume". I'm currently doing that with tone() using the following push-pull inverter, but software is preferable to hardware:

GizmoGarden: Question about race conditions in toneAC2: I was seeing some odd behavior in the standard tone() function that I suspect is due to a race condition between the interrupt handler and tone() inself. The doc says you can call tone() while a previous tone is playing and it will just update the frequency, but tone() can be interrupted at any point by its own interrupt, hence the potential race. In searching the web to see if others had observed this I came across toneAC and toneAC2, and intend to use your library. I don't think I can use toneAC because I need the servo library which uses timer1 on my Uno, but toneAC2 should be just the ticket. So my question: Is there any potential race condition if toneAC2 is called while a previous tone is playing? What is the intended behavior?

The main reason I want to use toneAC2 is to take advantage of "twice the volume". I'm currently doing that with tone() using the following push-pull inverter, but software is preferable to hardware:

You will need to use toneAC2 as toneAC will conflict with the servo library. That's unfortunate as toneAC is faster, more accurate, etc.

Anyway, I don't think toneAC or toneAC2 will create a race condition because I set the new tone end before setting the new timer settings and monitor the state as well. The intended behavior if you call toneAC/toneAC2 while a current tone is playing is that the tone will simply change. toneAC/toneAC2 resets the counter top in an overflow situation which the tone library does not do. Also, if you specify a length, toneAC2 will run in blocking mode so it would be impossible to call toneAC2 again (although, blocking mode probably won't work with your project).

The toneAC2 library is small, fairly straight-forward, and commented in detail. You should be able to review toneAC2.cpp to see if there's any potential issues.

Tim

I think I do see a race condition in toneAC2 (easy to fix), but tell me what you think. The interrupt handler can call noToneAC2 and thereby change TCCR2A, TCCR2B, and _pinMask1. Suppose that a tone is just ending when toneAC2 is called to start a new one. If the tone-ending interrupt occurs between the lines in toneAC2 that set OCR2A and that disable the interrupt (TIMSK2), then some or all of _pinMask1, TCCR2A, and TCCR2B will be placed into an invalid state. If you simply move the interrupt disable somewhere before the "if (_pinMask1 == 0), the race condition is impossible.

Of course this race bug is rather unlikely to occur, but that is what makes race conditions so nasty and difficult to debug.

And of course I could be wrong here--you know both the code and the timers better than I do.

Now that I look at the code again, I think there is no race condition, but the analysis is subtle. Near the beginning of toneAC you set _tAC2_time. If this unsigned long is set correctly, it will prevent the race condition about which I was concerned in my previous post, since the interrupt handler would then not call noToneAC2. But an unsigned long is four bytes, and setting it on an 8-bit processor is not an atomic operation and can therefore be interrupted. If it is interrupted partway through setting all four bytes, the interrupt handler will run with an invalid value in _tAC2_time, and may or may not call noToneAc2. But I think either case is harmless because nothing that the interrupt handler can change has been read yet by the rest of tomeAC2. Still, I'd move the interrupt disable eariler in toneAC2.

GizmoGarden: Now that I look at the code again, I think there is no race condition, but the analysis is subtle. Near the beginning of toneAC you set _tAC2_time. If this unsigned long is set correctly, it will prevent the race condition about which I was concerned in my previous post, since the interrupt handler would then not call noToneAC2. But an unsigned long is four bytes, and setting it on an 8-bit processor is not an atomic operation and can therefore be interrupted. If it is interrupted partway through setting all four bytes, the interrupt handler will run with an invalid value in _tAC2_time, and may or may not call noToneAc2. But I think either case is harmless because nothing that the interrupt handler can change has been read yet by the rest of tomeAC2. Still, I'd move the interrupt disable eariler in toneAC2.

I set _tAC2_time early to avoid a race condition. Also, stopping the timer earlier if tones are playing quickly can cause a "crackle" sound as we're terminating the tone before starting a new tone with too much computation between (that's why the timer stop and start are so close to each other with only a single if/else statement between them.

I don't believe having _tAC2_time as a long int could also create a race condition. I do, however see two other cases where a race condition could happen. One I corrected in my development code already. The other has to do with the millis() rolling over at 0xFFFFFFFF. It's programmed to deal with the rollover. But, there could be a very rare case where _tAC2_time is set to a very high value and the interrupt misses it before millis() rolls over. Say that _tAC2_time is set to 0xFFFFFFFE and the tone frequency is set to 100Hz. ISR(TIMER2_COMPA_vect) would only be called once every 10ms and it would be very possible that millis() could wrap to 0x0 and never be greater than _tAC2_time to cause the tone to stop. This would be highly rare and the solution would add bulk inside the ISR(TIMER2_COMPA_vect) which isn't a good idea either.

In any case. All of what we're talking about is when we're using toneAC2 to control the length of the tone. Another way of doing it is to not specify the duration which makes toneAC2 just play the tone forever. Then, you could use your sketch to decide when to stop the tone. Depending on your sketch, this may be a good way of avoiding any possible problem.

Tim

Hello, I work on a "home made" sound player project, using a regular 8ohms solenoid speaker and want to generate "ping" notes. I found your library and your AC trick was exactly what I wanted to make louder sound.

But I've a problem with volume control : on full volume (50% duty cycle) the sound is ok, but when I decrease it, it becames twanging like a duck and thus "ping" effect sounds really ugly.

Is this a known problem ? I don't understand why of shorter duty cycle distorts sound so much ?

I tried another solution, by connecting speaker to a timer for frequency and other speaker end to another timer (with higher frequency) onto which I change duty cycle to simulate a variable low voltage. Result is fine, but in this way, i can't use your AC trick thus volume is less loud

By the way, I've another question : With a 50% duty cycle sound, the signal is like this : |500x280 (yes, my oscilloscope comes from another century ...) Top line shows one output pin, bottom line shows other pin inverted, thus speaker receives 0 -> +5 at beginning then +5 -> 0. That's ok.

With lower volume, the signal becames like this : |500x280 thus, +5 -> 0 90% of time, then 0 -> +5 during remaining 10%

Shouldn't it be better to have something like this : |500x280 thus 0 -> 0 90% of time, then 5 -> 0 during 5%, and then 0 -> 5 during remaining 5%

I achieved this by setting OCRxA to (top / volume) and OCRxB to (top - (top / volume)), and compare flags to "normal" Thus, A is high during the beginning of timer count, then low, then B is set to high during last steps and returns low at end. The result sounds not exactly the same, but is still twanging, thus it doesn't solve my problem, but I'd like to have your opinion in this signal generation method ?

Thanks in advance for any help ...

piif:
Hello,
I work on a “home made” sound player project, using a regular 8ohms solenoid speaker and want to generate “ping” notes.
I found your library and your AC trick was exactly what I wanted to make louder sound.

But I’ve a problem with volume control : on full volume (50% duty cycle) the sound is ok, but when I decrease it, it becames twanging like a duck and thus “ping” effect sounds really ugly.

Is this a known problem ? I don’t understand why of shorter duty cycle distorts sound so much ?

I tried another solution, by connecting speaker to a timer for frequency and other speaker end to another timer (with higher frequency) onto which I change duty cycle to simulate a variable low voltage.
Result is fine, but in this way, i can’t use your AC trick thus volume is less loud

By the way, I’ve another question :
With a 50% duty cycle sound, the signal is like this :


(yes, my oscilloscope comes from another century …)
Top line shows one output pin, bottom line shows other pin inverted, thus speaker receives 0 → +5 at beginning then +5 → 0. That’s ok.

With lower volume, the signal becames like this :


thus, +5 → 0 90% of time, then 0 → +5 during remaining 10%

Shouldn’t it be better to have something like this :


thus 0 → 0 90% of time, then 5 → 0 during 5%, and then 0 → 5 during remaining 5%

I achieved this by setting OCRxA to (top / volume) and OCRxB to (top - (top / volume)), and compare flags to “normal”
Thus, A is high during the beginning of timer count, then low, then B is set to high during last steps and returns low at end.
The result sounds not exactly the same, but is still twanging, thus it doesn’t solve my problem, but I’d like to have your opinion in this signal generation method ?

Thanks in advance for any help …

The “volume” is a bit of a hack for sure. It changes the duty cycle, but it’s not ideal. Basically, the goal of toneAC was to create a “push/pull” for the speakers using the built-in timers of the ATmega which would make it high accuracy and very fast. The duty cycle allowed me to adjust the volume so I added it to the library.

I don’t have an oscilloscope to test what the output of toneAC is. But for me, it does change the volume and doesn’t sound like a duck. I’m using only piezo transducers, so maybe that’s the difference? I would be concerned about your modification if the pins are ever both high.

Honestly, I wouldn’t use the volume option in toneAC. It “works” but not well. It’s a bonus only. toneAC was really designed to be driven at 100% to produce a higher sound output, high accuracy, and the ability to do high frequencies.

The reason it still doesn’t sound right with your modification is probably because the pins are out of sync. Maybe if I had an oscilloscope I could mess around with this. But I’m kind of out of luck until such time.

Tim

Thanks for your answer. I've to find a piezo speaker to do the test, but i fear sound will not be loud enough. My goal is to make a door bell, thus it have to be eared from everywhere in my house ...

piif: Thanks for your answer. I've to find a piezo speaker to do the test, but i fear sound will not be loud enough. My goal is to make a door bell, thus it have to be eared from everywhere in my house ...

The best solution to this is using a simple amp (a transistor will do). The output of the ATmega just isn't enough to drive a cone speaker at type of a loud volume.

Tim