Maker Pro
Maker Pro

Arduino Sound generator wanted

GrahamB

Feb 28, 2018
7
Joined
Feb 28, 2018
Messages
7
A Sound or tone generator for some Arduino projects I am working on.

Controlled by the Arduino, possibly using a DAC no more than 2, even a digital pot or two but these are more expensive, but control voltages are 0-5V

Requirements:

  • 0-5V control voltage via a DAC, or PWM output.
  • Outputs a tone in the range of human hearing, 20 – 20KHz, or at least the Piano range, ~25-4.5KHz
  • Digital volume control.
  • Must have an off or 0Hz to allow spaces between the notes or another method of achieving this such as volume.
  • Can require a separate power supply of anything up to 18V (2x9V batteries)
  • Can ideally produce separate waveforms, Sine, Square, Sawtooth (both rising and falling if possible) and Triangle.
  • Waveform selection must be controllable by software. Analogue master volume, tone controls etc. are allowed.
  • Cheap, preferably less than £15 Max for all the components.
  • No SM components, all should be breadboardable (is that a word?)
Likely to be driving a very cheap speaker so sound quality is nice but not all that important.

Background

Using the Arduino I can drive a square wave quite easily, but it takes processor cycles and sounds tinny, I can’t generate a meaningful waveform at anything approaching 100Hz, never mind 20 KHz or even 4.5KHz.

I have a basic electronics understanding, I fully understand (I think) wires, I even nearly understand those new fangled things like capacitors and transistors (Well, the npn ones). Diodes unfortunately are still just a one way street to me. But I am booked in for an induction course at my local college.
 

GrahamB

Feb 28, 2018
7
Joined
Feb 28, 2018
Messages
7

BobK

Jan 5, 2010
7,682
Joined
Jan 5, 2010
Messages
7,682
The trick to getting non-square waveforms out of a microcontroller is called PWM. To get audio signals up to 20 Khz, you would need to use at least 50KHz as the PWM frequency, 100KHz would be better. The PWM period is changed over a cycle of the designed waveform to match the voltage at that point in the cycle. You do this by using a table of values, and set the duty cycle of the PWM for each PWM cycle.

The output of this is a bunch of pulses of varying widths. If you wanted to get a high quality signal out of it, you pass it through an RC circuit to smooth it to what would look like the desired waveform, but has jaggies at the PWM frequency. A multipole filter can pretty much remove the jaggies.

But, if all you want to do is run a speaker, you don't even need to remove the jaggies. You can use the PWM signal out as is to drive and H-bridge with the speaker connected directly and a small capacitor across the speaker terminals. You would used signed values in the waveform table and reverse the H-bridge for negative values. With a 5V microcontroller you can get about 2.5W into an 8Ω speaker out of this simple method, without needing a power amplifier. This is basically a class D amplifier.

To illustrate, let's use a triangle wave.

PWM frequency is 50,000 Hz

Output frequency is 500 Hz. So there will be 100 PWM period for each cycle.

You would start with 0% duty cycle, over the next 50 PWM cycles you would up the duty cycle by 2%, ending with 100%. Then over the next 50 cycles reduce the duty cycle by 2% ending up back at zero, where you start over again.

You can make an arbitrary waveform by putting the values of a single cycle in a table. The table can be a fixed size, something like 256 entries. You keep an index to the table as a fractional number. With each cycle you add a specific amount to the fractional value, and use the integer part of it as the index to pull the duty cycle out of the table, allowing it to wrap around when you reach the table size.

So, with 50,000Hz PWM frequency and a 256 entry table, if you used an increment of 1 you would go through the table every 256 cycles and the output frequency would be 50,000 / 256 = 195 Hz. The relationship is

Fout = Fpwm / tablesize * increment

or

increment = Fout * tablesize / Fpwm

So, to get a frequency of 1000 Hz, you would use

increment = 1000 * 256 / 50,000 = 5.12

Hope this helps,

Bob
 

virtual1

Mar 29, 2012
13
Joined
Mar 29, 2012
Messages
13
not sure if this is too specific or high end for your use, but I find these very useful, and they're not too expensive. considering the high frequencies they're capable of, precision at LF should be outstanding
https://www.ebay.com/itm/311331205021
 

GrahamB

Feb 28, 2018
7
Joined
Feb 28, 2018
Messages
7
The trick to getting non-square waveforms out of a microcontroller is called PWM. To get audio signals up to 20 Khz, you would need to use at least 50KHz as the PWM frequency, 100KHz would be better. The PWM period is changed over a cycle of the designed waveform to match the voltage at that point in the cycle. You do this by using a table of values, and set the duty cycle of the PWM for each PWM cycle.

The output of this is a bunch of pulses of varying widths. If you wanted to get a high quality signal out of it, you pass it through an RC circuit to smooth it to what would look like the desired waveform, but has jaggies at the PWM frequency. A multipole filter can pretty much remove the jaggies.

But, if all you want to do is run a speaker, you don't even need to remove the jaggies. You can use the PWM signal out as is to drive and H-bridge with the speaker connected directly and a small capacitor across the speaker terminals. You would used signed values in the waveform table and reverse the H-bridge for negative values. With a 5V microcontroller you can get about 2.5W into an 8Ω speaker out of this simple method, without needing a power amplifier. This is basically a class D amplifier.

To illustrate, let's use a triangle wave.

PWM frequency is 50,000 Hz

Output frequency is 500 Hz. So there will be 100 PWM period for each cycle.

You would start with 0% duty cycle, over the next 50 PWM cycles you would up the duty cycle by 2%, ending with 100%. Then over the next 50 cycles reduce the duty cycle by 2% ending up back at zero, where you start over again.

You can make an arbitrary waveform by putting the values of a single cycle in a table. The table can be a fixed size, something like 256 entries. You keep an index to the table as a fractional number. With each cycle you add a specific amount to the fractional value, and use the integer part of it as the index to pull the duty cycle out of the table, allowing it to wrap around when you reach the table size.

So, with 50,000Hz PWM frequency and a 256 entry table, if you used an increment of 1 you would go through the table every 256 cycles and the output frequency would be 50,000 / 256 = 195 Hz. The relationship is

Fout = Fpwm / tablesize * increment

or

increment = Fout * tablesize / Fpwm

So, to get a frequency of 1000 Hz, you would use

increment = 1000 * 256 / 50,000 = 5.12

Hope this helps,

Bob
 

GrahamB

Feb 28, 2018
7
Joined
Feb 28, 2018
Messages
7
Thanks, I am aware of this approach. But to generate a frequency of say 4,500Hz using a 256 lookup table requires an update every 0.87 microseconds.
I think This is beyond the capabilities of an Arduino, never mind it doing anything else. Even dropping the resolution of the look up table to 64 entries only gives 3.4 microseconds between updates,
This is what I currently use but can only get about 150Hz using a resolution of 16 in the lookup table. And that is without doing much else and it sounds rubbish.
 

BobK

Jan 5, 2010
7,682
Joined
Jan 5, 2010
Messages
7,682
Thanks, I am aware of this approach. But to generate a frequency of say 4,500Hz using a 256 lookup table requires an update every 0.87 microseconds.
I think This is beyond the capabilities of an Arduino, never mind it doing anything else. Even dropping the resolution of the look up table to 64 entries only gives 3.4 microseconds between updates,
This is what I currently use but can only get about 150Hz using a resolution of 16 in the lookup table. And that is without doing much else and it sounds rubbish.
No, it doesn't. The update is done only at each PWM cycle. If the PWM frequency is 50 KHz, then it is 20us per cycle, which is well within the ability of an 8MHz processor (160 instruction times). There is even sufficient time left over to do other tasks in the meanwhile.

If you look at the formula I gave you:

increment = 4500 * 256 / 50,000 = 23.04

So you don't actually access all of the 256 entries in the table for this frequency. When you get to 20 KHz the waveform is very distorted, but it doesn't matter, since the harmonics that should not be there are ones that you cannot hear.

Believe me, it works. Have you ever heard of DDS? That is exactly what we are doing. Pretty much the standard technology for signal generators today up to hundreds of Megahertz.

Bob
 
Last edited:
Top