getting a dac0808 to work properly for dds synth

hi there,

i am trying to build my own wavetable dds synth based on
http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/
using a duemilanove.

for better sound i would like to use dacs. (like defex did for his amazing wavetable synth)
i have setup a dac0808 like it's described in its datasheet on page 4 (typical application).
http://www.ti.com/lit/ds/symlink/dac0808.pdf

for power i use two 9v batteries connected in a way so i can get positive and negative supply voltage + ground.
(like the first circuit here: Virtual Ground Circuits)

the arduinos 5v is used as reference voltage for the dac.

as an amp i use an lm386 circuit which works fine with other signals.

i can get an output out of the dacs, similar to the one of the pwm, however the sound quality is not good.
there's a lot of hiss on the output

heres an audio demo of how it sounds: http://db.tt/vFkGAn5Y (swiping from 0 to 8000hz and back, recorded directly without the amp)

ugghh, pretty bad :frowning:

i should note that i only use 6 bits, as i can't find a way to output a 8 bits via port registers on the duemilanove!
however, sound tends to get noisier the more bits i add.

am i doing anything wrong or missing something with the dac output via portd/b?

should i set up the dac differenty than i did??

any help would be very appreciated!

cheers,
jns

heres the code (also attached):

/*
 *
 * DDS Sine Generator mit ATMEGS 168
 * Timer2 generates the  31250 KHz Clock Interrupt
 *
 * KHM 2009 /  Martin Nawrath
 * Kunsthochschule fuer Medien Koeln
 * Academy of Media Arts Cologne

 */

#include "avr/pgmspace.h"

// table of 256 sine values / one sine period / stored in flash memory
PROGMEM  prog_uchar sine256[]  = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
  242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
  221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
  76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
  33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124
};


#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

int ledPin = 13;                 // LED pin 7
int testPin = 7;
int t2Pin = 6;
byte bb;
byte mask = 1;

double dfreq, oldDfreq;
// const double refclk=31372.549;  // =16MHz / 510
const double refclk=31376.6;      // measured

// variables used inside interrupt service declared as voilatile
volatile byte icnt;              // var inside interrupt
volatile byte icnt1;             // var inside interrupt
volatile byte c4ms;              // counter incremented all 4ms
volatile unsigned long phaccu;   // pahse accumulator
volatile unsigned long tword_m;  // dds tuning word m

int offset = 0;

void setup()
{
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
  Serial.begin(115200);        // connect to the serial port
  Serial.println("DDS Test");
  

//  pinMode(6, OUTPUT);      // sets the digital pin as output
//  pinMode(7, OUTPUT);      // sets the digital pin as output
  DDRD = DDRD | B11111110;  // set pins 1 - 7 as outputs, leave 0 for serial in communication with the board!
//  pinMode(11, OUTPUT);     // pin11= PWM  output / frequency output

  Setup_timer2();

  // disable interrupts to avoid timing distortion
  cbi (TIMSK0,TOIE0);              // disable Timer0 !!! delay() is now not available
  sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt

  dfreq=100.0;                    // initial output frequency = 1000.o Hz
  tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word 

}
void loop()
{
  while(1) {
//     if (c4ms > 250) {                 // timer / wait fou a full second
      c4ms=0;
      if (analogRead(0) || oldDfreq) {
        dfreq=map(analogRead(0), 0, 1023, 0, 8000);          // read Poti on analog pin 0 to adjust output frequency from 0..8000 Hz
//        dfreq=analogRead(0);
        oldDfreq = dfreq;
        
      }


      
      PORTD = byte(pgm_read_byte_near(sine256 + icnt));
//      integerToDigitalOut(pgm_read_byte_near(sine256 + icnt));
      
      cbi (TIMSK2,TOIE2);              // disble Timer2 Interrupt
      tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word
      sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt 

//    }

//   sbi(PORTD,6); // Test / set PORTD,7 high to observe timing with a scope
//   cbi(PORTD,6); // Test /reset PORTD,7 high to observe timing with a scope
   

   
  }
 }
//******************************************************************
// timer2 setup
// set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer2() {

// Timer2 Clock Prescaler to : 1
  sbi (TCCR2B, CS20);
  cbi (TCCR2B, CS21);
  cbi (TCCR2B, CS22);

  // Timer2 PWM Mode set to Phase Correct PWM
  cbi (TCCR2A, COM2A0);  // clear Compare Match
  sbi (TCCR2A, COM2A1);

  sbi (TCCR2A, WGM20);  // Mode 1  / Phase Correct PWM
  cbi (TCCR2A, WGM21);
  cbi (TCCR2B, WGM22);
}

//******************************************************************
// Timer2 Interrupt Service at 31372,550 KHz = 32uSec
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)
// runtime : 8 microseconds ( inclusive push and pop)
ISR(TIMER2_OVF_vect) {

//  sbi(PORTD,7);          // Test / set PORTD,7 high to observe timing with a oscope

  phaccu=phaccu+tword_m; // soft DDS, phase accu with 32 bits
  icnt=phaccu >> 24;     // use upper 8 bits for phase accu as frequency information
                         // read value fron ROM sine table and send to PWM DAC
//  OCR2A=pgm_read_byte_near(sine256 + offset+ icnt);    


  if(icnt1++ == 125) {  // increment variable c4ms all 4 milliseconds
    c4ms++;
    icnt1=0;
   }   

// cbi(PORTD,7);            // reset PORTD,7
}

void integerToDigitalOut(int val) {
  
  int pin = 9;
  byte data = byte(val);
  
  for (mask =  00000001; mask > 0; mask <<= 1) {
    if (data & mask){ //if bitwise AND resolves to true
      digitalWrite(pin,HIGH); // send 1
    }
    else{ //if bitwise and resolves to false
      digitalWrite(pin,LOW); // send 0
    }
    pin--;
//    delayMicroseconds(bitDelay); //delay
  }
}

DDS_Sinewave_Generator_OUT.ino (5.26 KB)

It sounds like you have noise on the audio circuits.
It begins with heavy mains pickup before any sound is produced.

What we would need to see is a schematic of how you have wired it up as opposed, "a bit like this".
You need to isolate the grounds an d only have them join at one point, you need to AC couple the output of the DAC to the audio amplifier. Also what is you audio reference ground attached to?

thanks for the reply!

here is the diagram of how i hooked it up:

hope that helps!

you're right, i'm confused with the grounds, as i'm using both, from the arduino as well as from the dual power supply.
i think my grounds never join.
how do i ac couple the output to the audio amplifier? just put a capacitor there?
i guess my audio reference ground is connected to the arduinos ground.

merry christmas, btw :wink:

cheers,
jns

i think my grounds never join.

The need to join.

how do i ac couple the output to the audio amplifier? just put a capacitor there?

Basically yes, but this device has a current output not a voltage one and it is less than 2mA. You need to put it into an op amp like the circuit on page 4 of the data sheet.

Why are you using resistor values that are not on that data sheet. You use 2K2 where the data sheet says 5K (this should be 4K7) also you seem to use a 2.47M resistor when the data sheet says again 5K.

What are you doing with the unused inputs, you can't just leave them to float as they will generate a lot of noise.

The final thing is you appear to have the input the wrong way round. Pin 5 on the chip is the most significant bit but you show it going to "Digital 1" which would imply it is the least significant bit.

Okay, the grounds join.
I noticed no difference, wether I use the ground from the Arduino or not.

I output the signal from the DAC directly to my computer. I think for now my computers audio in handles the ac coupling, as the signal looks fine.

I guess I got confused with the resistor values displayed on the datasheet.
After experimenting with R14 I decided to use a 22k. 4k7 gave me a way too loud (and distorted) signal.
R15 is 4k7 now.

I switched to a Arduino MEGA, so I can use all Pins over PORTA and leave no inputs on the chip open.

YES, I really had the inputs the wrong way around!!

So, after all these changes, the result is much better.
Still, I don't get a clean sine, there's some tonal noise on the signal.
Check it out: http://db.tt/jcJdMDq0
(ATTENTION: starts very soft, gets loud!)
When looking at the audio signal in a sample editor, etc.. I noticed that at higher frequencies the sine wave doesn't look very much like a sine wave anymore.

Thanks for all the help!

I noticed that at higher frequencies the sine wave doesn't look very much like a sine wave anymore.

It won't, this is because you are only getting a few samples per cycle and it doesn't look much like a sin wave on an oscilloscope. However providing you get at least two samples per cycle you should be able to recover the signal.

It won't, this is because you are only getting a few samples per cycle and it doesn't look much like a sin wave on an oscilloscope. However providing you get at least two samples per cycle you should be able to recover the signal.

But the highest frequency of the audio sample was 1000 Hz. Shouldn't the 31372.55 Hz clock interrupt be fast enough?
Or did I understand the code wrong?

From the site I found the code on:

Arduino Sine wave Generator using the direct digital synthesis Method

Here we describe how to generate sine waves with an Arduino board in a very accurate way. Almost no additional hardware is required. The frequency range reaches form zero to 16 KHz with a resolution of a millionth part of one Hertz! Distortions can be kept less than one percent on frequencies up to 3 KHz.

http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/

I just realized, that I had the output to the DAC not in the ISR but in the main loop.
Put it in the ISR and the resolution is much better now!