I just completed a DDS project, on an Atmel AVR employing ASM, and have come to the conclusion that an 8 bit look-up table and 8 bit DAC create too much quantization distortion at low frequencies; for lack of better wording, I'm getting a sine wave with a ladder effect on my oscilloscope.
Obviously, If I smooth out the waveform with a big LPF, I have problems with amplitude in higher frequencies.
In theory, upgrading from an 8 bit to 12 bit DAC and employing interpolation with the 4 least significant bits should allow me to raise the cutoff point of my filter a significant enough amount to alleviate problems with waveform amplitude at higher frequencies. My problem is that I don't have a clue how to do this or if there is an easier way to remove the zipper effect.. perhaps 12 bit look-up tables?
So far, I've created an infinite loop and every time the loop completes a cycle, a value is sent to the DAC based on the position of the pointer related to the look-up table. Here's where I get confused. I've read tons of info on this and still haven't found a working example. If I have an infinite loop, how am I supposed to stuff the interpolation values between the table look-up values? About the best thing that I can think of is (a + b) /2; I can probably implement this and get an extra bit or the equivalent of a 512 point look-up table, but I'd like to think that there is an easier way or something that could potentially deliver better results. I don't know C or how to employ it, but I will give it a try if it is prudent.
Currently, my clock is at 1MHZ and I could probably go to 16MHZ if necessary.
Here is a sample of my code:
; Set sinewave output as default
ldi ZH, High(sine*2); setup Z pointer hi
ldi ZL, Low(sine*2) ; setup Z pointer lo
; Clear accumulator
clr r29 ; clear accumulator
; Setup adder registers
ldi r24,0x50 ; Fine adder value change register
ldi r25,0x08 ; Middle adder value change register
ldi r26,0x00 ; Coarse adder value change register
LOOP1:
add r28,r24 ; 1 Adder values carry over to higher registers. Higher registers raise freq. in larger steps
adc r29,r25 ; 1
adc r30,r26 ; 1 r30 is database address pointer for Z register
lpm r0, Z ; 3 (Load Program Memory) Reads byte from database into the destination register based on Z pointer
out PORTD,r0
rjmp LOOP1 ; 2 => 9 cycles