Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 9

AD9850 Waveform Generator

1
An interrupt-driven rotary encoder, connected to the ATmega328 interrupt pins ( D2 and D3), adjus
steps. Pushing the rotary encoder's button (connected to D4) resets the frequency to 1 kHz.

The steps are set with a second rotary encoder (not interrupt-driven) connected to ATmega328 pin
them to 1 Hz, 10 Hz, 50 Hz, 100 Hz, 500 Hz, 1 kHz, 2.5 kHz, 5 kHz, 10 kHz, 100 kHz and 500 kH
the step to 1 Hz.

The 1.8" TFT display connects to the ATmega328 pins A1, A0, D13, D12, D11 and D10. D10 to D13
Adafruit library. Pin D9 connects to the display's LED pin via a 100 ohm resistor. D9 is a PWM pin s
desired. I've set it in software to '255' -ie maximum brightness.

There are some very similar 1.8" TFT displays available - the one I used has an ST7735 controller
(and different Adafruit library) and - not provided for in the PCB layout - require 1k series resisto

I've used a 5 volts 1.5A regulator in the power supply section. With a 12v DC input, the regulator
I included a jumpered link in the PCB design so an on/off switch could easily be added.

2
The two rotary encoders are soldered to the small front-panel-mounted PCB with the track side up
of thin insulation under them.

PCB Layout
Download Circuit Wizard PCB Layout.

Download PCB layout in PDF Format.

Construction

3
4
Main Components
1.8" TFT Display Module (ST7735 Controller)

AD9850 DDS Module

50x130x100mm enclosure

The ATmega328 'sketch'


AD9850 Datasheet

5
AD9850 DDS Module

Arduino Libraries:

Adafruit_GFX Library
Adafruit_ST7735 Library
Rotary Encoder Library
/* Based on AD9851 code from Andrew Smallbone - modified for AD9850
http://www.rocketnumbernine.com/2011/10/25/programming-the-ad9851-dds-synthesizer
*/

#include <Adafruit_GFX.h> // Core graphics library https://github.com/adafruit/Ada


#include <Adafruit_ST7735.h> // Hardware-specific library https://github.com/adafruit
#include <SPI.h>

#include <Rotary.h> // Rotary encoder: https://github.com/brianlow/Rotary

int TFT_LED = 9;
#define TFT_SCLK 13 // 1.8" TFT Display.
#define TFT_MOSI 11 //
#define TFT_CS 10
#define TFT_RST A1
#define TFT_DC A0

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

#define AD9850_CLOCK 125000000 // Module crystal frequency. Tweak here for accur

#define W_CLK 8 // AD9850 Module pins.


#define FQ_UD 7
#define DATA 6
#define RESET 5

#define stepPin1 A3 // Set 'Step' rotary encoder pins


#define stepPin2 A2
int forceHzStep = A4; // 'Step' rotary encoder's push button - Set 1 Hz
int forcekHz = 4; // Interrupt-driven encoder's push button - force

Rotary i = Rotary(stepPin1, stepPin2); // Rotart encoder for setting increment.


Rotary r = Rotary(2, 3); // Rotary encoder for frequency connects to inter

long unsigned int freq = 1000; // Set initial frequency.


long unsigned int freqOld = freq;

long int timer;

char* stepText[11] = {" 1 Hz", " 10 Hz", " 50 Hz", "100 Hz", "500 Hz", " 1 kHz", "2.5
" 5 kHz", " 10 kHz", "100 kHz", "500 kHz"};

int stepPointer = 0;
unsigned long incr = 0;
String units = stepText[stepPointer];

#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }

// transfers a byte, a bit at a time, LSB first to the 9850 via serial DATA line
void tfr_byte(byte data) {
for (int i = 0; i < 8; i++, data >>= 1) {
digitalWrite(DATA, data & 0x01);

6
pulseHigh(W_CLK); //after each bit sent, CLK is pulsed high
}
}

void sendFrequency(double frequency) {


int32_t freq1 = frequency * 4294967295/AD9850_CLOCK; // note 125 MHz clock on 9850
for (int b = 0; b < 4; b++, freq1 >>= 8) {
tfr_byte(freq1 & 0xFF);
}
tfr_byte(0x000); // Final control byte, all 0 for 9850 chip
pulseHigh(FQ_UD); // Done! Should see output
}

void setup() {

pinMode(2, INPUT_PULLUP); // Pins for interrupt-driven rotary encoder and p


pinMode(3, INPUT_PULLUP);
pinMode(forceHzStep, INPUT_PULLUP);
pinMode(forcekHz, INPUT_PULLUP);

pinMode(FQ_UD, OUTPUT); // Configure pins for output to AD9850 module.


pinMode(W_CLK, OUTPUT);
pinMode(DATA, OUTPUT);
pinMode(RESET, OUTPUT);

pinMode(TFT_RST, OUTPUT); // Configure pins for output to TFT display.


pinMode(TFT_DC, OUTPUT);
pinMode(TFT_LED, OUTPUT);

analogWrite(TFT_LED, 255); // Adjust backlight brightness.

// Configure interrupt and enable for rotary encoder.


PCICR |= (1 << PCIE2);
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
sei();

tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab

tft.setRotation(3);
tft.setTextWrap(false); // Allow text to run off right edge
tft.fillScreen(ST7735_BLACK);

tft.setCursor(15, tft.height() -20);


tft.setTextSize(1);
tft.drawFastHLine(0, tft.height() - 23, tft.width()-10, ST7735_BLUE);
tft.setTextColor(ST7735_BLUE);
tft.println("AD9850 1 Hz to 5 MHz ");
tft.print(" sinewave generator");

// Initialise the AD9850 module.


pulseHigh(RESET);
pulseHigh(W_CLK);
pulseHigh(FQ_UD); // this pulse enables serial mode - Datasheet page 12 figure 10

updateDisplay(); // Update the TFT display.


}

void getStep() {
switch(stepPointer) {
case 0: incr = 1; break;
case 1: incr = 10; break;
case 2: incr = 50; break;
case 3: incr = 100; break;

7
case 4: incr = 500; break;
case 5: incr = 1000; break;
case 6: incr = 2500; break;
case 7: incr = 5000; break;
case 8: incr = 10000; break;
case 9: incr = 100000; break;
case 10: incr = 500000; break;
}
}

void updateDisplay() {
getStep(); //
units = stepText[stepPointer];

tft.fillRect(0, 15, 160, 20, ST7735_BLACK);

tft.setTextColor(ST7735_YELLOW);
tft.setCursor(10, 20);
tft.setTextSize(1);
tft.print("Step: ");
tft.setTextSize(2);
tft.setCursor(60, 15);
tft.print(units);

tft.fillRect(0, 40, 160, 60, ST7735_BLACK);


tft.setTextColor(ST7735_GREEN);
tft.setTextSize(2);
if (freq < 1000) {
tft.setCursor(78, 50);
if (freq < 1000) tft.print(" ");
if (freq < 100) tft.print(" ");
tft.print(freq);
tft.setCursor(58, 75);
tft.print(" Hz");
} else
if (freq < 1000000) {
tft.setCursor(40, 50);
if (freq < 10000) tft.print(" ");
tft.print((float)freq/1000, 3);
tft.setCursor(58, 75);
tft.print(" kHz");
} else {
format(freq);
tft.setCursor(58, 75);
tft.print(" MHz");
}
}

void format(long value) {


int M = (value/1000000);
int T100 = ((value/100000)%10);
int T10 = ((value/10000)%10);
int T1 = ((value/1000)%10);
int U100 = ((value/100)%10);
int U10 = ((value/10)%10);
int U1 = ((value/1)%10);
tft.setCursor(25, 50);
tft.print(M);tft.print(".");tft.print(T100);tft.print(T10);tft.print(T1);
tft.print(",");tft.print(U100);tft.print(U10);tft.print(U1);
}

void loop() {
// Check 'Step' rotary encoder.
unsigned char result = i.process();

8
if (result) {
if (result == DIR_CW) {if (stepPointer < 10) stepPointer++;}
if (result == DIR_CCW) {if (stepPointer > 0) stepPointer--;}
updateDisplay();
}

if (digitalRead(forceHzStep) == LOW) {
stepPointer = 0;
updateDisplay();
delay(50);
}

if (digitalRead(forcekHz) == LOW) {
freq = 1000;
sendFrequency(freq);
updateDisplay();
delay(350);
}
if (freqOld != freq) {
sendFrequency(freq);
updateDisplay();
freqOld = freq;
}
}

ISR(PCINT2_vect) {
unsigned char result = r.process();
if (result) {
if (result == DIR_CW) {
if ((freq + incr) <= 10000000) freq += incr;
} else {
if ((freq - incr) >= 10) freq -= incr;
}
if (freq <= 10) freq = 10;
if (freq >=10000000) freq = 10000000;
}
}

You might also like