Dick Cappels' project pages http://www.projects.cappels.org
Return to HOME (more projects)
A 1 Khz Digital Sine Wave Signal Source
The fundamental digital sine wave signal generator, with the frequency fixed at 1 kHz.
Uses AVR controllers equipped with an 8 bit I/O port.

• 1 Khz From a Quartz Crystal
• 1 V P-P Sine Wave Calibrated Output
• 1 KHz Square Wave Output
• 900 mv Inverted Sine Wave Output (Uncalibrated)

Sixteen of those resistors above the micro controller form the R-2R DAC.
Download the WINAVR main source for the 2313 version of the firmware: 2313sine.c
Download the complete zipped WINAVR project for the  2313 version of the firmware: 1_kHz_sine_2313.zip

Download the WINAVR main source for the 8515 version of the firmware: 8515sine080210B.c
Download the complete zipped WINAVR project for the  2313 version of the firmwre: 1_KHz_sine_wave_8515.zip

Find updates at www.projects.cappels.org


If found myself in need of a 1 KHz signal source for an experiments. My function/sweep generator was needed as a pulse generator for the same experiment, so I went though my junk box, looking for circuits from long ago that might fill the need, but found nothing useful.

I had a board with an AT90S8515 and an 8 bit resistor ladder network on it, which serves as a DAC (digital to analog converter), so I thought "This will be easy." and sat down to write the code. Since I wrote it in C rather than assembly, writing the code took much longer than I expected, but in the end, I managed to get it to do what I wanted it to do, and I fixed the typographical errors.

The little generator with the AT90S8515 worked well enough for that experiment, that I decided to build up a version that uses the ATTINY2313 or AT90S2313 (I tested the firmware on both chips) so the 1 kHz sine wave generator would be available for some future experiments that I am planning.

At this point, you might wonder at my choice of an AT90S2313 instead of the ATTINY2313. I still have lots of AT90S2313's and intend to use them where I can. There is not much of a market for obsolete controllers.

Code is provided for the ATTINY2313/AT90S2313 and the ATMEGA8515/AT90S8515. The ATTINY2313 hex file was tested on both the ATTINY2313 and the AT90S2312, while the AT90S8515 hex file was only tested on an AT90S8515. The AT90S8515 hex file is fully expected to run on the ATMEGA8515 without any problems, provided that the ATMEGA8515 is operated in the AT90S8515 compatibility mode (see below).

It should be a (nearly) trivial exercise to re-target the code to compile on any AVR controller with an 8 bit I/O port.

The Circuit

The circuit has three outputs. Two sine wave outputs and one scope sync output.

I would like to explain the new technologies developed for this circuit, but there are no new technologies involved. The firmware sends 8 bit values corresponding to 32  different values per cycle of the firmware, and this appears on an output port, to which is connected an 8 bit DAC. The output of the DAC. Since the sine wave frequency is 1 kHz, a new 8 bit value is sent to the output port every 1/32,00 seconds (every 31.25 microseconds).

The DAC is made up of 9 each 20 k Ohm  and 7 each 10 k Ohm resistors, connected as an R-2R ladder network. The output of the DAC shunted by a voltage divider, whose resistance is 2.8 k Ohms, which simultaneously decreases the amplitude of the the sine wave to about 900 millivolts. Without the voltage divider (6.8k and 4.7K, the output would be nearly 5 volts peak-to-peak.)  An integrated circuit DAC would have worked just fine, and I have some laying around, but somehow, it was more satisfying to make my own DAC with resistors.

Take note, that I used 5% resistors in the DAC, and if the resistors had been at the edge of their specification, the monotonicity would have been about 4 /12 bits. Fortunately, the resistors that I have bothered to measure are much closer to their specified values than this. Even more important, is that in this application, particularly when only generating a relatively coarse 32 values sine wave, a little error in monotonicity only results in as slight increase in harmonic content, and the low pass filter takes care of it.

Spurious signals in the output were about 40 db below the 1 kHz carrier in the original circuit, but a I added a capacitor to the 2313 circuit that is also in parallel with the output of the DAC forms an approximately 1.5 kHZ single pole low pass filter, which is enough to bring the spurious signals to about 50 db below the 1 kHz sine wave, while not affecting the amplitude of the 1 kHz signal much at all.

The reason its nice that the low pass filter does not affect the amplitude of the 1 kHz signal is because this reduces the amplitude's dependency on the corner frequency of the filter. The capacitor could drift quite a bit and not affect the amplitude of the 1 kHz signal much because its not affecting the amplitude much in the first place. If I had placed the corner frequency much lower, it would have more of an affect. As it happens, the .047 uf capacitor that I used in the filter is made with polypropylene, which has a temperature coefficient of about 0.02% per degree C around room temperature.

A voltage follower buffers the signal, which is AC coupled to the output through a 100 uf capacitor. A second output from the buffer drives an inverting amplifier that has a gain adjustment. The second amplifier can be adjusted to provide a calibrated 1 volt P-P output.

The most significant bit from the DAC output is a 1 kHz square wave. Its phase slightly leads that of the sine wave outputs because of the low pass filter on the sine wave. The 1 kHz square wave is useful for triggering my oscilloscope.

A simpler version, shown below, before I got carried away adding the output with the calibrated amplitude and the square wave output is shown below.

This is the simpler circuit. No calibrated output and no scope sync output.

Just to give you an idea of what the ATMEGA8515/AT908515 version would look like, here, below, is a picture of the board I used for the first signal generator. Please not that the circuitry located above the controller, except for the crystal, is left over from other projects.

Most of the components above the micro controller are not used in this project,
and a just left over from previous projects.

This board was originally used in a software phase locked loop, running AttoBasic, and it will likely be used for other projects in the future.

This is essentially the same as the ATTINY2313 circuit.

The schematic above does not show the power supply, but I think it should be easy enough to come up with your own, or adapt the power supply from the ATTINY2313/AT90S2313 circuit. If you are going to use the ATMEGA8515, please remember to set the 8515 compatibility mode. See the example for the STK-500 below.

The image above shows the Fuses panel on the STK-500.


My only cautions for construction are to be careful about noise pickup in the R-2R ladder network, and of course, put the 4 Mhz crystal in the load capacitors close to the controller. The accuracy of the crystal determines the accuracy of the 1 kHz sine wave output.


You can look at the firmware as being made of three parts: Initialization, the main loop, and the timer interrupt routine.


During initialization, the I/O ports are initialized. Significantly, one 8 bit port is set up as an output so it can drive the DAC.

Also during initialization, a 32 value into an array is loaded with values corresponding to 32 values in a sine wave. I could have gotten by with just 8 values representing 90 degrees, and played some tricks to make them into 32 steps -fairly common practice, but why bother when there is plenty of RAM in the AVR controller?  The reason I used an array in RAM instead of just using the constants in program memory is because its nice and fast, and if I was lucky, I could get by without having to be very careful about execution speed.

The 8 bit timer are set up during initialization to cause an interrupt every 1/32,000 of a second, and then just before the main loop, interrupts are enabled.

    Main Loop
Here, the 8515 differs from the 2313 version. In the case of the 8515 version of the code, the controller does nothing but idle in a do nothing loop while waiting for an interrupt. In the case of the 2313 code, the micro controller sleeps and waits for an interrupt within a do nothing loop.

The reason for the 2313 code sleeping is that I feel it is a better practice because the time to service the interrupt will be consistent, and thus, there would be much less chance for jitter in the interrupt latency time, and there fore less chance for jitter in the output wavform.

I looked at cycle-to-cycle jitter with a digital oscilloscope, with a resolution of 250 nanoseconds per division, and did not see any jitter with either the 8515 version of the code nor with the 2313 version of the code.

    Timer Interrupt Routine
During the timer interrupt routine, the timer is reloaded for the next timing interval, which is a total of 1/32,000 second. The actual number loaded into the timer is smaller because of all of the overhead involved in waking from sleep, going to the interrupt vector, and saving registers, etc. before even starting to reload the timer register.

The intertupt routine fetches the next value from the array the pointer incremented. If the pointer then points past the 32nd value in the array, it is set back to the first value.

That's all there is to the firmware itself.

The code was compiled with AVR-GCC 3.4.6. The 2313 version of the firmware was compiled with the AT90S2313 as the target and the resulting hex file was tested on both the AT90S2313 and the ATTINY2313.

HOME (More Projects)


Contents ©2008 Richard Cappels All Rights Reserved. Find updates at www.projects.cappels.org

First posted in February, 2008. Revised March, 2008, March 2012.

You can send  email to me at projects(at)cappels.org. Replace "(at)" with "@" before mailing.

Use of information presented on this page is for personal, nonprofit educational and noncommercial use only. This material (including object files) is copyrighted by Richard Cappels and may not be republished or used directly for commercial purposes. For commercial license, click here.

  Liability Disclaimer and intellectual property notice
(Summary: No warranties, use these pages at your own risk. You may use the information provided here for personal and educational purposes but you may not republish or use this information for any commercial purpose without explicit permission.) I neither express nor imply any warranty for the quality, fitness for any particular purpose or  user, or freedom from patents or other restrictions on the rights of use of any software, firmware, hardware, design, service,information, or advice provided, mentioned,or made reference to in these pages. By utilizing or relying on software, firmware, hardware, design, service,information, or advice provided, mentioned, or made reference to in these pages, the user takes responsibility to assume all risk and associated with said activity and hold Richard Cappels harmless in the event of any loss or expense associated with said activity. The contents of this web site, unless otherwise noted, is copyrighted by Richard Cappels. Use of information presented on this site for personal, nonprofit educational and noncommercial use is encouraged, but unless explicitly stated with respect to particular material, the material itself may not be republished or used directly for commercial purposes. For the purposes of this notice, copying binary data resulting from program files, including assembly source code and object (hex) files into semiconductor memories for personal, nonprofit educational or other noncommercial use is not considered republishing. Entities desiring to use any material published in this pages for commercial purposes should contact the respective copyright holder(s).