Arduino DDS Sinewave Generator

On an Arduino Mega the pin mappings are somewhat different. The compare output for Timer 2A is on pin 10 instead of 11.

Pin mappings:
https://spreadsheets.google.com/pub?key=rtHw_R6eVL140KS9_G8GPkA&gid=0

Yes, thanks guys, I can confirm that it works a charm using pin10 instead of 11 :slight_smile: Good reference, that spreadsheet!

Good work.
Can i generate a 40kHz senoidal signal?.

Can i generate a 40kHz senoidal signal?.

Do you mean "sinusoidal"?
With that software, no - you'd need to boost the clock to at least 80kHz, and I'm not sure the ISR would run at that frequency.

Do you really need a 40kHz sine wave?

AWOL:

Can i generate a 40kHz senoidal signal?.

Do you mean "sinusoidal"?
With that software, no - you'd need to boost the clock to at least 80kHz, and I'm not sure the ISR would run at that frequency.

Do you really need a 40kHz sine wave?

I managed to do it. My current 8bit look up table dds has a 4us interrupt, I have been able to reach 80khz sampling rate but this reaches the limit of the Arduino.
44k is Ok, but without much CPU overhead for somerhing else. Im working on midi synth with 22k rate atm.

EDIT : With this code, I have been able to operate my DIY 8 BIT SPI DAC at a frequency of 330kHz. The output of the DAC was a saw signal (image of the counter...) at 1.35kHz / 256 samples per cycle.
So a 44kHz DDS using a Look up Table is highly feasible indeed.

//Pin connected to ST_CP of 74HC595
int latchPin = 10;
//Pin connected to SH_CP of 74HC595
int clockPin = 13;
////Pin connected to DS of 74HC595
int dataPin = 11;
////
unsigned char test_char=0;

//--- Used to setup SPI based on current pin setup
// this is called in the setup routine;
void setupSPI(){
byte clr;
SPCR |= ( (1<<SPE) | (1<<MSTR) ); // enable SPI as master
SPCR &= ~( (1<<SPR1) | (1<<SPR0) ); // clear prescaler bits
clr=SPSR; // clear SPI status reg
clr=SPDR; // clear SPI data reg
SPSR |= (1<<SPI2X); // set prescaler bits
delay(10);
}

//--- The really fast SPI version of shiftOut
byte spi_transfer(byte data)
{
SPDR = data; // Start the transmission
loop_until_bit_is_set(SPSR, SPIF);
return SPDR; // return the received byte, we don't need that
}

void setup() {
// put your setup code here, to run once:
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
digitalWrite(latchPin, HIGH);
digitalWrite(clockPin, LOW);
digitalWrite(dataPin, LOW);
byte clr;
SPCR |= ( (1<<SPE) | (1<<MSTR) ); // enable SPI as master
SPCR &= ~( (1<<SPR1) | (1<<SPR0) ); // clear prescaler bits
clr=SPSR; // clear SPI status reg
clr=SPDR; // clear SPI data reg
SPSR |= (1<<SPI2X); // set prescaler bits
delay(10);
Serial.begin(9600);
Serial.println("Init Ok");
}

void loop() {
// put your main code here, to run repeatedly:
//shiftOut(dataPin, clockPin, MSBFIRST, test_char);
spi_transfer(test_char);
PORTB &= ~(4); //digitalWrite(latchPin, LOW);
//Serial.println(test_char,DEC);
PORTB |= 4; //digitalWrite(latchPin, HIGH);
//delay(1000);
test_char += 1;
//delay(1000);
}

@D4p0up

why not call setupSPI(); in setup() ??

The same code....

and try Serial.begin(115200) then you have more time for other things....

D4p0up:
With this code, I have been able to operate my DIY 8 BIT SPI DAC at a frequency of 330kHz.

Very nice - I was wondering, from the page you referenced, 1% resistors are needed for 6 bit, and more precise for higher bits - has anyone had success using potentiometers to get more accurate resistances?

Just thinking about it, you reach a point where even the soldering flux has an impact on the total resistor of the resulting design...

integrated chip designers do nanometric adjusments of the R2R ladders to reach the expected accuracy. So with pots... you might end up spending your life seeking for a percentage of digit on your multimeter... in vain.

COntinuing the discussion and answering the question...

About the SPI, I feel like digging into the Datasheet of the AVR and configuring every single bit on my own instead of using the Arduino dedicated functions. Of course they are much more user friendly, but I want to learn more about the HW and be closer as possible to it, so i might do the same, I prefer ton configure it on my own.

About the ADC, I have today very good audio results with my 8 bits DAC presented in the links above. Resistors are basic 5% tolerance, so there is non linearities spread among the way, it can be heared, but for a "lowfi but still accurate" project, it's worth it.

I will eventually use MCP4921's for my final Synth Shield, but only for "cleaning" purpose, I feel perfectly at ease with the current resistor based 8 bit DAC. I have not tried higher resolutions though, because of this table you mention.

I don't understand why you don't just lose the shift register and have the R-2R ladder on 8 Arduino pins (say port D then writing is a single instruction). You'll get to MHz with the sinewave table perhaps?

Good question, simple answer: The lower the pin count, the better it is.

In the audio synth application I'm currently working on, I need the pins 0 & 1 for Midi In/Out purpose, and also need four analog inputs for control Knobs and so on. Add to this three Leds for Synth operation purpose (gate + lfo rate + general purpose), four buttons for operation like preset managment and edition, and make the breakout:

2 + 4 + 3 + 4 = 13 pins, with 9 being discretes.

With this basic setup, I have no room for Port dedicated 8 Bit DAC on a Uno board.

Then, in the future I plan to use a MCP4921 as a DAC. This will lead to better results, so using a homemade SPI DAC in this case is the best way to anticipate design evolutions.

However, as I mentionned on my blog, I started using a rough 6bits DAC on PortC with great success... except for dynamic range of course :slight_smile:

Is it possible to have a three phase sine wave with this generator ?
I would like to generate a 10 kHz to idealy 18 kHz three phase wave.
Does miro-Hertz precision will pertain with this change ?

ten Khz is anyway a problem, the atmega is to slw for that. using a dedicated DDS chip would be a solution
maybe some manufactor has a 3 phase version.

martin

You definitely could with the R2R SPI DAC trick presented above:

Just chain 3 x 74HC595 with their associated DAC, and use the same method as described above, except that the 3 respective phase accumulators should be initialised with 0, (1/3)x2^16, (2/3)x2^16.

This will make 3 outputs !

Thanks for those two replies, the original post about frequency production limit came from an email that I addressed to marnaw about 10 Khz to 18 Khz 3-phase sine wave.
I found this and marnaw is in the pdf file.(I)

I did not be able to contact the author and he claimed of 13 Khz, I think it's about switching pwm, don't you ?
So, first, my question still pertain : does I really need a dedicated dds to perform my signals ?

Second, does marnaw work deal with this, sometimes also called magic sine waves ?(II)
Best regards.
Sril

Edit (09/23/11) :
(I) is a non finish student work about control motor, does not need to be read, sorry.
(II) deal with a method to suppress harmony under a certain level from base frequency and is not the same as described heare, sorry.
I insist to present my apologizes for stupid lost time to read me.

Go-on my work with a 3-phased generating circuit.

Hi

Came across this utility/routine for the Arduino, looks great. I am still digesting the program as I have very basic knowledge of C language and specifically some of the commands used in this routine.

My question is this;
I would like to modify this to be able to generate 2 sine wave outputs, same frequency, but one of the sine wave needs to be shifted 90 degrees from the other. Can it be modified for this? Some help in finding where explanations of all these particular commands could be found would be useful. I imagine that the commands to drive the second sine wave would need to be contained in the interrupt service routine.

I think I should be able to use the same sine value table but shifted by 64 values for an out of phase wave of 90 degrees.
Thanks for any help.

Can't you just maintain two table pointers 90 degrees out of phase, and do the summing in the ISR?
(watch out for unsigned arithmetic summing the samples)
It would limit the highest frequency you could generate.
Or, if the two signals are always the same amount out of phase, simply generate a single lookup at compile-time.

AWOL nailed it.

As mentioned above, just initialise the two phase accumulators with 0 and 16384 (pi/2).

The rest of the DDS is the same...

Thanks for the suggestions.
I got it working just as hoped. I simply initialized the second PWM output then created a second sine table lookup pointer that is shifted by -64 bytes, which generates the same wave but phase shifted by 90 degrees. Awesome. My project can now move ahead.

A question for those who used this code ( And apologies if some of the question might sound silly, but my issue will be more to do with the hardware).
Would i be feasible to transform this code to also modulate the signal, using an input ( from a pot, lets say) to influence the speed of modulation ( a LFO, lets say) ?!?
I notice there is a pot...Is that pot influencing the frequency ?!?
Always found this code interesting, but only more recently im getting to grips with the hardware features and limitations.
My aims are low frequencies, audio based anyway. By the way, what would be the limitations of this, as is ?!( I noticed the ook-up table issues for higher frequencies etc)
*PS-GOT IT

The frequency range reaches form zero to 16 KHz with a resolution of a millionth part of one Hertz!

Thanks in advance and many thanks to the original programmer above all !!

Yes, it would be easy to use a potentiometer. Since the program requires that you specify a frequency value, you can read the pot and use that value to specify the frequency to generate. The original program used a pot for this very purpose. I took this out of the code as I needed specific digital frequency values entered by the user.