Saturday, March 22, 2008

Atmega8 audio oscillator

adcro.jpgHere's a simple sine wave audio generator. It generates a nice looking, and sounding sine wave by using a resistor A/D converter connected to 8 pins on port D. To the right is the waveform as displayed on a CRO. Running at 8Mhz (internal oscillator) it puts out a 400Hz tone.

adaudioboard.jpgI generate the 256 constants for the samples of the sine wave with a little python program - the output is pasted into the C source code. The board you see here is a nifty little target board from Evil Mad Scientist.

The resistor ladder is an R-2R design using 10k and 20k resistors. Here's the circuit I used.

The python code is shown here.

from math import sin, radians

for i in range(256):
degrees = i * 360 / 255
value = (sin(radians(degrees)) + 1) * (255 / 2)
print "0x%02x," % int(value),
if ((i + 1) % 16) == 0:

And here is the actual code for the chip:

#include // Defines pins, ports, etc to make programs easier to read
#define F_CPU 800000UL // Sets up the default speed for delay.h

#define DELAY_MS 0

const int sinevalues[] = //256 values
0x7f, 0x81, 0x83, 0x87, 0x8a, 0x8e, 0x90, 0x92, 0x97, 0x99, 0x9d, 0x9f, 0xa2, 0xa6, 0xa8, 0xac,
0xae, 0xb2, 0xb4, 0xb6, 0xba, 0xbc, 0xc0, 0xc2, 0xc4, 0xc7, 0xc9, 0xcd, 0xce, 0xd0, 0xd3, 0xd5,
0xd8, 0xda, 0xdd, 0xde, 0xe0, 0xe3, 0xe4, 0xe7, 0xe8, 0xe9, 0xeb, 0xec, 0xef, 0xf0, 0xf1, 0xf3,
0xf3, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd,
0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfb, 0xfa, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5,
0xf4, 0xf3, 0xf2, 0xf0, 0xef, 0xec, 0xeb, 0xea, 0xe8, 0xe7, 0xe4, 0xe3, 0xe1, 0xde, 0xdd, 0xda,
0xd8, 0xd7, 0xd3, 0xd2, 0xce, 0xcd, 0xc9, 0xc7, 0xc6, 0xc2, 0xc0, 0xbc, 0xba, 0xb8, 0xb4, 0xb2,
0xae, 0xac, 0xaa, 0xa6, 0xa4, 0x9f, 0x9d, 0x99, 0x97, 0x95, 0x90, 0x8e, 0x8a, 0x87, 0x85, 0x81,
0x7f, 0x7a, 0x78, 0x76, 0x71, 0x6f, 0x6b, 0x68, 0x64, 0x62, 0x60, 0x5b, 0x59, 0x55, 0x53, 0x51,
0x4d, 0x4b, 0x47, 0x45, 0x43, 0x3f, 0x3d, 0x39, 0x37, 0x34, 0x32, 0x30, 0x2d, 0x2b, 0x28, 0x26,
0x25, 0x22, 0x20, 0x1d, 0x1c, 0x1a, 0x18, 0x16, 0x14, 0x13, 0x11, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a,
0x09, 0x08, 0x06, 0x06, 0x04, 0x04, 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x03, 0x04, 0x04, 0x06, 0x06, 0x07, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0f, 0x11, 0x13, 0x14, 0x15, 0x18, 0x19, 0x1c, 0x1d, 0x20, 0x22, 0x23,
0x26, 0x28, 0x2b, 0x2d, 0x2f, 0x32, 0x34, 0x37, 0x39, 0x3b, 0x3f, 0x41, 0x45, 0x47, 0x4b, 0x4d,
0x4f, 0x53, 0x55, 0x59, 0x5b, 0x5e, 0x62, 0x64, 0x68, 0x6b, 0x6d, 0x71, 0x73, 0x78, 0x7a, 0x7e

int main()
DDRD = 0xff; // port D all output
short int i;
for(i = 0; i < 0xff; i++)
PORTD = sinevalues[i];


Anonymous said...

That's very cool! Normally I'd just use PWM, but doing it D2A with an R2R is more fun. :)

It would be interesting to plug the output into a AF spectrum analyser (baudline for example) and take a look at the spectural purity. Then compare that to the same thing done with PWM.

I suspect PWM (aka 1-bit D2A) will be much better, but you need to carefully filter out the clocking noise (easier in theory because the frequency can be made very high). The R2R approach still has clocking problems, but also has to deal with component spread in the ladder.

A 2 pole Sallen-Key filter could be used to clean up the signal, perhaps leaving quite a low distortion test source? In particular, its programmability would be very useful. Maybe make up a few different tables, like sawtooth for all harmonics (or sweeps - linearised VCO tuning for example), and two-tone for IMD.

I've actually been playing with stuff this weekend where I am reaching the point I need a HD/IMD test system. I am thinking some Wien-bridge oscillators followed by clean-up filters. Although baudline (et al) can do the lot digitally, my soundcards aren't the best, and tieing up the PC isn't always practical.

Peter Marks said...

Thanks Alan,

Yes, the original spark for this project was the idea of making a two tone generator for testing SSB transmitters.

Interestingly I notice that the PSK31 software I use displays IMD on received signals so it's obviously possible to measure this in software...

Anonymous said...

I need to get off my backside with PSK31 set-up. I have the antenna and radio now, all I need is the interface...

I was going to do it over Easter, but it never happened (other projects instead). I also have visions of a fairly deluxe interface, with level control, isolation on all paths, AF keying circuit, etc.

Peter Marks said...

Yes, I'm looking forward to chatting with you on PSK31.

I'll bring along my old interface next weekend although it's rather prone to RF feedback.

Anonymous said...

Cool! Thanks for posting. Subscribed
to your RSS too.