AVR DDS signal generator V2.0
-->Finally second and improved AVR DDS signal generator is here. First AVR DDS V1.0 generator was only an attempt of running DDS algorithm without any amplitude control. This time I still wanted to keep things simple like minimum count of widely accessible components circuit, single sided PCB that comes together with good functionality.

AVR DDS specification
AVR DDS signal generator V2.0 is a firmware based DDS signal generator which uses slightly modified Jesper’s DDS algorithm adapted to AVR-GCC C program as in-line ASM. Signal generator has two outputs – one for DDS signal and another for high speed [1..8MHz] square signal – which may be used for reliving microcontrollers with wrong fuse settings or for other purposes as well. High speed (HS) signal is direct output from Atmega16 OC1A(PD5) pin. DDS output is used for all other signals that are generated via R2R resistor network and is adjusted via LM358N offset and amplitude regulating circuits. Offset and amplitude can be regulated by two potentiometers. Offset can be regulated in range +5V..-5V while amplitude in range 0..10V. DDS frequency range is from 0 to 65534Hz that is more than enough for testing audio circuits and other tasks.
Main AVR DDS V2.0 signal generator features:
- Simple circuit with easily accessible and cheap components;
- Single sided PCB;
- In box power supply with external AC plug;
- Dedicated high speed (HS) signal output up to 8MHz;
- DDS signal with variable amplitude and offset;
- DDS signals: sine, square, saw, rev saw, triangle, ECG and noise.
- 2×16 LCD menu;
- Intuitive 5 button keypad.
- Frequency adjusting steps: 1, 10, 100, 1000, 10000Hz;
- Restoring last configuration after power up.
In the block diagram you may see logical structure of signal generatorV2.0

As you can see device requires several voltages: +5V, -12V, +12V, GND. -12V and +12V are used for offset and amplitude control. In this case power supply is constructed by using simple transformer and few voltage regulators.
Power supply block is assembled on a separate prototyping PCB board.
If you do not want to build power supply you may use PC ATX power supply unit where all required voltages are available. You may need to modify molex connector wiring as follows:
LCD menu control
All actions can be viewed in LCD menu. Menu can be controlled with 5 buttons that are next to LCD module

Up and down arrow buttons are used for browsing menu while right and left arrow buttons are used for changing frequency value. When middle button is pressed – signal generating starts. Press middle button again to stop signal generator. Here is a complete menu system of signal generator.
Important to notice, that there is a separate menu for changing frequency step. This is convenient if you need to change generator frequencies in wide range. This allows to set any frequency with relatively few button clicks.
Noise generation don’t have frequency setting. It uses simple rand() function where results are continuously output to DDS output.
High speed signal has four frequencies available: 1, 2, 4 and 8MHz.
Circuit diagram and PCB
Circuit diagram of DDS generator (excluding power supply) is very simple with easy accessible components. It uses following parts:
- AVR Atmega16 microcontroller clocked with 16MHz external crystal;
- Standard HD44780-based 2×16 LCD module;
- R2R DAC made of simple resistors;
- LM358N low power dual op amplifier;
- Two potentiometers;
- 5 buttons;
- several connectors and sockets.
Circuit diagram and PCB:
Single sided PCB:
Assembly
DDS generator is assembled in to plastic box:

Test run:

AVR DDS 2.0 Firmware
As I have mentioned DDS function is a modified Jesper’s DDS algorithm. Main modification is adding additional ASM line which enables to stop DDS generation. In version 1.0 the only option was to reset device, dds function checks if CPHA bit is set in SPCR register which is set during external interrupt service routine (stop button). So now algorithm takes 10 CPU cycles instead 9.
void static inline Signal_OUT(const uint8_t *signal, uint8_t ad2, uint8_t ad1, uint8_t ad0){
asm volatile( “eor r18, r18 ;r18<-0″ “\n\t”
“eor r19, r19 ;r19<-0″ “\n\t”
“1:” “\n\t”
“add r18, %0 ;1 cycle” “\n\t”
“adc r19, %1 ;1 cycle” “\n\t”
“adc %A3, %2 ;1 cycle” “\n\t”
“lpm ;3 cycles” “\n\t”
“out %4, __tmp_reg__ ;1 cycle” “\n\t”
“sbis %5, 2 ;1 cycle if no skip” “\n\t”
“rjmp 1b ;2 cycles. Total 10 cycles” “\n\t”
:
:”r” (ad0),”r” (ad1),”r” (ad2),”e” (signal),”I” (_SFR_IO_ADDR(PORTA)), “I” (_SFR_IO_ADDR(SPCR))
:”r18″, “r19″
);}
DDS Signal tables has to be placed in flash sections where address starts with 0xXX00. So these sections has to be defined in makefile for proper memory placement:
#Define sections where to store signal tables
LDFLAGS += -Wl,-section-start=.MySection1=0×3A00
LDFLAGS += -Wl,-section-start=.MySection2=0×3B00
LDFLAGS += -Wl,-section-start=.MySection3=0×3C00
LDFLAGS += -Wl,-section-start=.MySection4=0×3D00
LDFLAGS += -Wl,-section-start=.MySection5=0×3E00
LDFLAGS += -Wl,-section-start=.MySection6=0×3F00
LCD control library is described here.
I don’t want to go too deep in code discussions. Source code is commented pretty well if there will be any questions and suggestions about source code – feel free to drop a comment.
Testing and discussion
I have tested signal generator with oscilloscope and frequency counter. Signals look like expected in all frequency range [1 to 65535Hz]. Amplitude and offset regulator works OK. If offset is set to 5V, then maximum clear signal amplitude may be 5V as another 5V is already used for offset(same is if offset is -5V).
Here are few test signals on oscilloscope screen:
I am thinking of adding sinus sweep functionality in future firmware updates. Maybe I will if there will be a need :)
Download latests firmware (WinAVR20071221) and source code version here (source code and hex[120kB])
Download EagleCAD schematic and PCB here ( EagleCAD project[45kB])
Proteus simulation files with latest firmware included (avrdds_proteus [31kB])
Blogsphere: TechnoratiFeedsterBloglines
Bookmark: Del.icio.usSpurlFurlSimpyBlinkDigg
RSS feed for comments on this post | TrackBack URI for this post
| New on WinAVR Tutorial | New on WinARM Tutorial |

March 11th, 2008 at 12:00 pm
[...] on the website. Signal generators can be very expensive, this version shouldn’t break the bank. – Link [Read this article] [Comment on this article] Source: MAKE [...]
March 11th, 2008 at 12:02 pm
[...] on the website. Signal generators can be very expensive, this version shouldn’t break the bank. – Link [Read this article] [Comment on this article] [...]
March 11th, 2008 at 8:41 pm
[...] AVR DDS signal generator - [Link] [...]
March 11th, 2008 at 11:06 pm
[...] http://www.scienceprog.com/avr-dds-signal-generator-v20 addthis_url = ‘http%3A%2F%2Fwww.ni-c.de%2F2008%2F03%2F11%2Favr-dds-signal-generator-v20%2F’; [...]
March 12th, 2008 at 11:19 pm
[...] Źródło http://www.scienceprog.com/avr-dds-signal-generator-v20/ [...]
March 13th, 2008 at 2:20 am
Excelent project. I wondered thought if others might be interested in my way of making custom “membrane” switches for projects?
Design the artwork and print it out on a sheet of paper. Cut it out the correct size and put it in the middle of a laminate pouch and run it through the laminator. Mine is not a very good laminator, so I actually run it through again as soon as it comes out.
Cut out the box and cut the laminated sheet to be at least 10mm larger than the hole. Run hot-melt adhesive around the hole inside the BOX. Place box face-down on a hard surface and place your laminated legend(s) in place. Quickly place a piece of polythene over that and a heavy object to flatten it all while the glue sets.
using a sharp knife carefully scrape away any hot-melt adhesive that ouzed out onto the face of your legends while cooling.
Mount the switches onto their own PCB or any inflexible surface and mount them behind the legend, fixing the edge of the board via spacers/washers to the box. the switches should be pressed into the legend just slightly when monuted.
March 28th, 2008 at 3:12 pm
Which fuse-bits is this Atmega16 using??
March 28th, 2008 at 4:28 pm
Fuse settings with PonyProg

March 30th, 2008 at 7:40 am
[...] relationship. Instead, I want to bring to you attention the AVR DDS signal 2.0. Scienceprog.com has an article on it which links to the AVR DDS V1.0 generator as [...]
April 1st, 2008 at 12:43 am
Thankyou for the great tutorial on you signal gen. I was wondering, would you possibly be able to write your DDS algorithm in pseudo code? I am a PIC guy, and all that AVR assembly is driving me nuts :( .
Thankyou greatly
April 1st, 2008 at 11:48 am
krazatchu made PCB modifications in order to get rid of smd. Also he made following modifications:
1) added the power supply to the board to run from battery…
2) removed the ISP to save space
3) changed the pin header for lcd to 1×16
4) fat traces for toner transfer…
5) separate ground returns for analog and digital…
Just follow forum thread
http://forum.scienceprog.com/viewtopic.php?f=9&t=281&p=399#p399
So if you like printer toner transfer pcb technology, you can choose this option.
April 9th, 2008 at 5:26 am
It will be very interesting when we can get our hands onto Xmega chips with the streaming DMA DACs, and what kind of DDS we can cook up then.
April 30th, 2008 at 6:41 pm
I’ve assembled V2.0 DDS generator.
It doesn’t work:
1) LCD display without any character. There are black rectangles in the upper line only.
2) There is not any pulse at PC0…PC7 outputs (found by oscilloscope)
Several times I did READ and WRITE operations. So MEGA16 is in good condition.
It might be FUSE bits are not O.K.
Here are the latest FUSE bits, which I got from the chip:
Fuses
OSCCAL = B1, B1, AC, AF
BODLEVEL = 0
BODEN = 1
SUT = 2
CKSEL = E
BLB1 = 3
BLB0 = 3
OCDEN = 1
JTAGEN = 0
CKOPT = 0
EESAVE = 1
BOOTSZ = 0
BOOTRST = 1
Would you please give me advice how to solve this problem?
April 30th, 2008 at 9:25 pm
It is hard to say now. Above you can see fuse settings done with PonyProg software. According to your settings seems to be that CKSEL is wrong. Should be CKSEL=F.
May 1st, 2008 at 9:04 pm
I tried CKSEL=F also, but with the same result.
I used another ISP programmer. I used it many times for many different projects.
Would you please answer to my E-mail directly
May 23rd, 2008 at 11:12 pm
Can you add in software duty cycle??Wich compiler you use??
May 24th, 2008 at 11:22 pm
Compiler is WinAVR AVR-GCC.
Adding duty cycle would be a little bit complicated. Probably best solution would be to use HS output and change duty cycle by changing timer output compare parameter. Right now I am not planing on adding this functionality. But you are free to modify the code.
July 14th, 2008 at 10:50 am
Hello,
thanks for this interesting project, but i have the same problem as Anatoliy, it wont start, black rectangles on LCD. It is not mt first AVR or/and PIC project, so i am confused, what I do wrong? I use serial COM port programmer and PonyProg software with fuses as in picture in this thread. Any ideas and help please? :)
Thank You in advance!
July 16th, 2008 at 1:38 pm
It started working, i just didnt write right fuse settings with PonyProg (how typical :) ).
July 25th, 2008 at 11:16 am
Hi
what type of complier did you used?
September 6th, 2008 at 3:54 pm
For PonyProg selected fuse:OCDEN, BOOTSE1 and BOOTSE0.Now my DDS work…73!
October 7th, 2008 at 3:54 am
Ok…
I keep getting a non-working atmega16 (LCD top row lit only). I am using STK500 with AVR Studio 4 to program the atmega16. I would guess that it’s not working because of the fuse settings. Can someone who used AVR Studio successfully make a screen shot of the fuse settings please.
Also, with the osc fuse, should it be set to one of the “ext crystal” settings, because the schematic uses a crystal with 18pf caps.
PS… This is probably a stupid question but I should be programing the FLASH right? With AVR Studio you can program the FLASH and/or EEPROM.
May 10th, 2009 at 6:08 pm
i simulate this function generator with proteus 7.2; the result is:
lcd and lm358 and noise signal all are okey but sin and other pulses are not generated…
any idea plz???!!!
May 10th, 2009 at 9:24 pm
I just tried – it simulates ok. I have attached latest Proteus simulation file to the end of article.
May 14th, 2009 at 7:00 am
can the same project be done using atmega16L.WH ALL D CHANGES TO BE MADE with this regard…hlp me
May 18th, 2009 at 12:49 pm
first of all thx scienceprog for reply and upload new files. and could you please say wich version of proteus you use for test the FG_DDS_2? i run it with 7.2 and same result applied.
May 18th, 2009 at 5:19 pm
Now i finish testing the DDS_2 on BreadBoard… the result is:
all pulses are generated. my fuse bits that are zero (Marked) are: BOOTSZ0 & BOOTSZ1 & SUT1 & SUT1 at Hattel Paralel Programer.
The problem is lcd and maximum Frequancy, lcd after start will dissapear and Fmax=20KHz
are fuses and my lcd okey??
any idea plz…???!!!
May 18th, 2009 at 10:02 pm
I used Proteus 7.2.
I cannot predict how it runs on 20MHz as I only tried on 16Mz. If you have possibility – try change it to 16 to see how it works. Anyway all timings are tied to 16MHz crystal, so menu functions will be incorrect.
June 20th, 2009 at 4:58 am
Hi,two questions,here is a main.eep,do I need to program it into atmega16?second,I use ponyprog and stk200 cable and fuse settings from above to burn the atmega16,I also get the result on top row of the lcd with squares only,I tried various combinations of fuse setting still with no luck,and now I got two dead atmega16 after many attempt of fuse settings.can please someone guide me the right way to program the atmega16.
June 23rd, 2009 at 8:04 pm
Hello!
Great project! I have made pcb with little different pin connection. I looked into source and made some little changes:
in main.c
#define R2RPORT PORTD
#define R2RDDR DDRD
//define button port and dedicated pins
#define BPORT PORTC
#define BPIN PINC
#define BDDR DDRC
#define DOWN 0//PORTD
#define LEFT 1//PORTD
#define START 2//PORTD
#define RIGHT 3//PORTD
#define UP 4//PORTD
//Define Highs Speed (HS) signal output
#define HSDDR DDRC
#define HSPORT PORTC
in lcd.h
#define LCD_RS 5
#define LCD_RW 6
#define LCD_E 4
#define LCD_D0 0
#define LCD_D1 1
#define LCD_D2 3
#define LCD_D3 4
#define LCD_D4 0
#define LCD_D5 1
#define LCD_D6 2
#define LCD_D7 3
#define LDP PORTB
#define LCP PORTB
#define LDDR DDRB
#define LCDR DDRB
Whis changes describes my schematics connection. I use avr-gcc (WinAVR 20090313) 4.3.2 to complile the code. Everything is fine. But the i try to test it in Proteus model (i also changed it correcpondly my schematic) nothing works. Can you give some idea? I can send all sources if you need.
July 8th, 2009 at 10:32 pm
In “AVR controlled DDS generator software writing” post you wrote that
loop taking 10 clock cycles was able to reach 6.25kHz.
Here we have 256 samples, 9 clock loop and same 16mHz clock… and
frequency over 65kHz.
Counting other way… On 16MHz clock and 256 samples we can get 62.5kHz
if we put sample out every clock cycle. But the loop is 9 clock cycles.
So the question is: If the loop puts a sample out every 9 clock cycles
the “real” frequency where all samples are going out is ~6.9kHz and
above that this DDS algorithm is skipping samples, yes?
July 8th, 2009 at 11:10 pm
Ups, my bad :) I’ve pasted this comment under new version with 10 clock cycles loop, but I thing everyone gets the idea.
July 23rd, 2009 at 5:10 am
Hi,
dear Scienceprog,
I´ve been trying to set this project, for a while ;(
with some problems in the LCD
did your project for win avr lcd 4 n 8 bits
and doesnt work either,
so i guess is a problem with the LCD
here , in this dds2 I used this fuses in avr studio, from what you show in pony prog:
high 0×19, low 0xcf,
lock bits, 0xff
no response, just a blank line,
in this project and the 8 n 4 bits
could it be the delay? (some one told me need 400us)
where can i set this in your libraries, thanks
;)
July 23rd, 2009 at 7:31 am
to mako…Delays are at least in milliseconds, so there should be no prob with that. if you have a chance – test your hardware with another application, to see if there is no bugs in board.
———–
to johny126…when frequencies goes over 6.9kHz – algorithm starts skipping samples – this way loosing resolution. So you can increase frequency as long as you are satisfied with signal shape.
August 11th, 2009 at 4:48 pm
Hi scienceprog.
i found my mistakes. (fuses)
i used 2*ca3140 for final op-amps insted of one lm358 because of its higher slew rate. and i realize that its better to parallel a 70pF cap on DDS_OUT to reduce the output noise.
sorry for my english. (im Iranian)
regard. post comment if idea.
October 11th, 2009 at 1:22 am
Hi and thank you for your nice project,
I have built my version of DDS replacing Smd parts and made it on pcb. For the programming I used AVR Studio in conjuction with WinAVR but all I get is 16 blank chars on LCD. Used osciloscope/multimeter to test output etc and 2 more mega16 but nothing changed.Fuse setting were calculated to 0×19 0xC9 if I can recall based on your ponyprog screenshot.
Any ideas?
Thanks in advance!
October 12th, 2009 at 8:23 pm
To everflow:
I programming Atmega with AVRStudio but not needed select JTAGEN. The fuse settings: HIGH=0×59 and LOW=0xCF. I use this settings and working the DDS.
October 13th, 2009 at 8:11 am
To san398:
Many thanks for your reply. It did work! If I enable JTAGEN it just fails! Would be nice to figure out what’s wrong there but that would do for now. Thank you again you I was busting my mind many days over now with that fuse thingie.
October 21st, 2009 at 10:17 am
Anyone has used a DAC instead of the R2R network?
I am thinking of using a AD558. Do you think it’ll work? I haven’t got into DACs so far and I don’t rly know if that one will be a direct replacement for the ladder network so any ideas are welcome.
Thanks!
October 21st, 2009 at 7:33 pm
Should work perfectly in my opinion. Just connect CE and CS pins of AD558 to “ground” to enable “transparent” mode.
October 22nd, 2009 at 4:50 am
Nice project! Could it be modified so that the phase of the waveform can be adjusted?
November 16th, 2009 at 3:53 am
Great job! I using WinAVR 20090313, and with the ’s’ opimizations, I needed to change this code to make it work.
struct signal{
volatile uint8_t mode; //signal
volatile uint8_t fr1; //Frequency [0..7]
volatile uint8_t fr2; //Frequency [8..15]
volatile uint8_t fr3; //Frequency [16..31]
volatile uint32_t freq; //frequency value
volatile uint8_t flag; //if “0″generator is OFF, “1″ – ON
volatile uint32_t acc; //accumulator
volatile uint8_t ON;
volatile uint8_t HSfreq; //high speed frequency [1...4Mhz]
volatile uint32_t deltafreq; //frequency step value
}SG;
It works as published when the optimization level is set to 0.
Thanks!
November 19th, 2009 at 1:07 pm
Hello,
I have a problem with this project. It seems it operates at twice the speed. On HS output, measuring with an frequincy meter, for 1Mhz i get 2Mhz, for 2Mhz i get a reading of 4Mhz, etc. Also, the menu seems to work too fast, if i pres a button once (for a short period of time) it will repet the command (it will switch verry fast, something like double pressing).
The uC was programed using the firmware from: http://www.scienceprog.com/wp-content/uploads/2008/03/firmware.zip .
The PCB is the one from this site, the only modifications i’ve done are: removed ISP connector and rearenged the components to fit BNC connector directly to PCB.
Xtal is 16Mhz with 22pico capacitors.
Thanks.
November 20th, 2009 at 11:15 am
That is really strange. Did you try to re-flash chip? What about DDS signals – are they generated correctly?
November 20th, 2009 at 1:06 pm
First time i’ve flashed the chip (not verry shure about the fusebits) and it worked to slow :)
I no not have an osciloscope to view DDS signals…
In the forum topics there are a few variants of fusebits, which one is corect? Is low fuse: 0xCF and high fuse: 0×59 corect?
Thanks!
November 21st, 2009 at 1:17 pm
My fuse settings are
High = 0b00011001 = 0×19
Low = 0b11001111 = 0xCF
November 22nd, 2009 at 9:58 pm
With high fuse set to 0×19 the devices doesn’t work at all, it just shows an black row… I’m lost…
November 23rd, 2009 at 7:22 pm
How about a firmware update? The sweep would be really nice for measuring inductors by means of resonance frequency.
It takes way too many button presses to do that manually with this signal generator.
November 23rd, 2009 at 10:33 pm
Just read the fuses from signal generator:
high fuse = 0xD9
low fuse = 0xFF
Hope this helps.
November 23rd, 2009 at 10:34 pm
Sweep is in the list – just need time to work on it.
November 23rd, 2009 at 11:24 pm
high fuse = 0xD9
low fuse = 0xFF => the device work’s at twice the speed :(
Another strange thing i noticed: when set to OFF i can read 16Mhz (speed of crystal), when set to ON => twice the value it should be….
December 19th, 2009 at 8:11 pm
I have build this fine project, and its works very fine with a LCD HD44780 display, but will not work with a LCD KS0066 display. What to do ??
January 8th, 2010 at 9:11 pm
more about displays:
The KS0066 controller is a klone of HD44780, and should be Equivalent.The 2 displays work fine in all af my 4 other Atmel-projects, so why will the KS0066-display not work in this project??
Can someone explain ??
January 9th, 2010 at 11:04 pm
Hi
I’m thinking to build this project but the problem is I can’t find a HD44780 LCD. Is it ok if I use a different LCD?
January 12th, 2010 at 12:15 am
Hi,i build the project,but It doesn’t work.I see only black rectangles in the first line.What that means?Bad programmed Atmega or wrong LCD.I’m using AC162B LCD(KS0066U) – same pinouts like many other models.
Thanks in advance!
January 12th, 2010 at 2:47 pm
Problem Fixed.Wrong programmed Atmega.Uncheck JTAGEN checkbox in Ponyprog.My settings are :
OCDEN,BOOTSZ,BOOTRST,SUT1,SUT0 checked.All others are NOT checked.No problem with KS0066U Driver!I can try with Bigger LCD module-PC2002L (same pinouts and driver).
Thanks for nice project.
73 from Bulgaria,LZ1JER.
February 7th, 2010 at 9:35 pm
Hi Scienceprog,
I appreciate you making this cool project available to everybody! I hope yopu are still watching this blog. Anyways, I built it and everything seems to be working fine. The LCD reads fine and the buttons work fine, but I am not getting a readable signal out of it. I get a signal of sorts, but it seems like maybe it’s just static.
Any ideas what might be causing this? I am hooking it up to my scope to try to read it.
Thanks,
Jeremy
February 7th, 2010 at 10:37 pm
Never mind, I got it working and it is awesome!!!! I had a short that looked like a trace, but when I compared it to the PCB I realized it wasn’t supposed to be there.
Regards,
Jeredmy
February 8th, 2010 at 11:55 am
Glad you made it. And yeah… most of problems occur in hardware design – especially when when PCB is home manufactured. Solder bridges between traces and traces with micro-cracks (open) can be hardly seen at first glance.