Author Topic: ad9850 dds  (Read 19592 times)

0 Members and 1 Guest are viewing this topic.

Offline matiseTopic starter

  • Contributor
  • Posts: 28
ad9850 dds
« on: May 29, 2014, 12:29:09 pm »
hi all.
Im programming a pic for this dds ad9850-module.
Im probably Close to solve it but its still doesnt work.
here is my code.

#include <p18f1220.h>
#pragma config WDT=OFF , OSC=HS, PWRT=ON, LVP=OFF, MCLRE=OFF
#include <delays.h>

// data 10
// clk  12
// ud   11

unsigned int fr1 = 0x0A,fr2 = 0x3D,fr3=0x70,fr4=0xA4;
int count,j;
void main(void)
{
   T0CON = 0b11000111;
   ADCON1 = 0x7F;        //All IO are digital or 0b01111111 in binary
   TRISA = 0b11111111;   //sets PORTA as all inputs
   PORTA = 0b00000000;   //turns off PORTA outputs
   TRISB = 0b00000000;   //sets PORTB as all outputs
   PORTB = 0b00000000;   //turns off PORTB outputs, good start position
   
   while(1)   
{
   
   for(count=0;count<8;count++)
   {
   
   PORTBbits.RB4 = 1;
   PORTBbits.RB4 = fr4 & 0x01;
   fr4 >>= 1;
   PORTBbits.RB6 = 1;
   PORTBbits.RB6 = 0;
      
   }
   for(count=0;count<8;count++)
   {
   
   PORTBbits.RB4 = 1;
   PORTBbits.RB4 = fr3 & 0x01;
   fr3 >>= 1;
   PORTBbits.RB6 = 1;
   PORTBbits.RB6 = 0;

   }
   for(count=0;count<8;count++)
   {
   
   PORTBbits.RB4 = 1;
   PORTBbits.RB4 = fr2 & 0x01;
   fr2 >>= 1;
   PORTBbits.RB6 = 1;
   PORTBbits.RB6 = 0;
   
   }
   for(count=0;count<8;count++)
   {
   
   PORTBbits.RB4 = 1;
   PORTBbits.RB4 = fr1 & 0x01;
       fr1 >>= 1;
   PORTBbits.RB6 = 1;
   PORTBbits.RB6 = 0;
   
   }
   PORTBbits.RB4 = 0;
   for(count=0;count<8;count++)
   {
   PORTBbits.RB6 = 1;
   PORTBbits.RB6 = 0;
      
   }
   PORTBbits.RB5 = 1;
   PORTBbits.RB5 = 0;

   
   }
}

As you can see my pic is an 8-bit so i have split up the data out in four smaller Groups, fr1, fr2, fr3 and fr4...
It works and i see in my oscilloscope both data and Clock-signals...
Anyone have any idea whats wrong here?
Its just no signal out from my dds...

Lets see if i can upload some Pictures.



« Last Edit: May 29, 2014, 02:42:38 pm by matise »
 

Offline matiseTopic starter

  • Contributor
  • Posts: 28
Re: ad9850 dds
« Reply #1 on: May 29, 2014, 12:48:51 pm »
hm, i have photos showing the signals in my oscilloscope.
But i dont know how to upload it here.
i will try again later.
 

Offline retrolefty

  • Super Contributor
  • ***
  • Posts: 1648
  • Country: us
  • measurement changes behavior
Re: ad9850 dds
« Reply #2 on: May 29, 2014, 01:11:51 pm »
Not sure it will help, but here is a basic DDS testing 'sketch' running on a arduino board. It shows needing to send a 'reset' to the device before a desired frequency word.

Code: [Select]
//AD9850 DDS test

#define DDS_CLOCK 125000000

#define  CLOCK  8  //pin connections for DDS
#define  LOAD 9
#define  DATA  10
#define  RESET 11
#define  probePin 12
#define  ledPin 13

void setup()
{
  pinMode (DATA,  OUTPUT);
  pinMode (CLOCK, OUTPUT);
  pinMode (LOAD,  OUTPUT);
  pinMode (RESET, OUTPUT);
  pinMode (probePin, INPUT);
  pinMode (ledPin, OUTPUT);
 
 
  AD9850_init();
  AD9850_reset();
  SetFrequency(28000000);
}
void SetFrequency(unsigned long frequency)
{
  unsigned long tuning_word = (frequency * pow(2, 32)) / DDS_CLOCK;
  digitalWrite (LOAD, LOW);

  shiftOut(DATA, CLOCK, LSBFIRST, tuning_word);
  shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 8);
  shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 16);
  shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 24);
  shiftOut(DATA, CLOCK, LSBFIRST, 0x0);
  digitalWrite (LOAD, HIGH);
}

void AD9850_init()
{

  digitalWrite(RESET, LOW);
  digitalWrite(CLOCK, LOW);
  digitalWrite(LOAD, LOW);
  digitalWrite(DATA, LOW);
}

void AD9850_reset()
{
  //reset sequence is:
  // CLOCK & LOAD = LOW
  //  Pulse RESET high for a few uS (use 5 uS here)
  //  Pulse CLOCK high for a few uS (use 5 uS here)
  //  Set DATA to ZERO and pulse LOAD for a few uS (use 5 uS here)

  // data sheet diagrams show only RESET and CLOCK being used to reset the device, but I see no output unless I also
  // toggle the LOAD line here.

  digitalWrite(CLOCK, LOW);
  digitalWrite(LOAD, LOW);

  digitalWrite(RESET, LOW);
  delay(5);
  digitalWrite(RESET, HIGH);  //pulse RESET
  delay(5);
  digitalWrite(RESET, LOW);
  delay(5);

  digitalWrite(CLOCK, LOW);
  delay(5);
  digitalWrite(CLOCK, HIGH);  //pulse CLOCK
  delay(5);
  digitalWrite(CLOCK, LOW);
  delay(5);
  digitalWrite(DATA, LOW);    //make sure DATA pin is LOW

    digitalWrite(LOAD, LOW);
  delay(5);
  digitalWrite(LOAD, HIGH);  //pulse LOAD
  delay(5);
  digitalWrite(LOAD, LOW);
  // Chip is RESET now
}


void loop()
{
// read the state of the pushbutton value:
  int probeState = digitalRead(probePin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (probeState == HIGH) {     
    // turn LED on:
   SetFrequency(28001000);   
    digitalWrite(ledPin, HIGH); 
  }
  else {
    // turn LED off:
      SetFrequency(28000000);
    digitalWrite(ledPin, LOW);
  }
}

 

Tac Eht Xilef

  • Guest
Re: ad9850 dds
« Reply #3 on: May 29, 2014, 01:58:35 pm »
Not sure it will help, but here is a basic DDS testing 'sketch' running on a arduino board. It shows needing to send a 'reset' to the device before a desired frequency word.

AFAIK the reset is only needed at startup - at least, my programs based on that very test sketch run fine without doing a reset every time the frequency is changed. But it is most definitely needed at startup, otherwise you just get ... well, weak noise; it's not even at the normal output level.

OP: looks like you're missing a connection to the reset pin, and failing to init and reset the AD9850 properly at startup. You may also have issues with timing when toggling the control pins and sending the data - look at the delays in the Arduino code retrolefty posted, and consider that you may also need to add a slight delay before toggling the clock.

And if you want fast frequency changes, use serial parallel mode. For some reason I've never been able to get serial mode work as quickly as other people reckon it works...
« Last Edit: May 30, 2014, 08:31:26 am by Tac Eht Xilef »
 

Offline matiseTopic starter

  • Contributor
  • Posts: 28
Re: ad9850 dds
« Reply #4 on: May 29, 2014, 03:07:41 pm »
hm, i thought that "ud" or freq update is the reset.
My last line in the code is that freq update code.

Is there Another reset you are talking about?

 

Offline retrolefty

  • Super Contributor
  • ***
  • Posts: 1648
  • Country: us
  • measurement changes behavior
Re: ad9850 dds
« Reply #5 on: May 29, 2014, 03:27:41 pm »
hm, i thought that "ud" or freq update is the reset.
My last line in the code is that freq update code.

Is there Another reset you are talking about?

Read the comments in the code I posted. Seems there is something that has to be done before you just set/send a desired output frequency. In arduino coding the setup function is performed just once, and that is where the program does this 'reset' function, and then the main loop() function runs forever.

 I didn't write that code, but have used it for a quick check out for a 9850 module I bought and as I recall it did seem to work fine. I haven't yet decided on a project to use the DDS for but figured it was a very cool item that can work from low audio frequencies up to rf frequencies.

 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: ad9850 dds
« Reply #6 on: May 29, 2014, 03:51:13 pm »
Quote
here is my code.

The structure is very poor and basically unworkable.

I would suggest that you organize it different:

1) figure out a way to control a pin: set / clear / read a pin -> all other pieces that require access to a pin would be done through those macros / functions;
2) using the macros / functions in 1), figure out a way to reset the device and send a byte to the device;
3) using the functions in 2), figure out a way to send control signals / commands to the device;
4) using the functions in 3), figure out a way to control the device through a set of functions, like set frequencies, or control phases, etc.

With this approach, it would be much easier to write, understand and debug your code.
================================
https://dannyelectronics.wordpress.com/
 

Offline Farley

  • Regular Contributor
  • *
  • Posts: 88
  • Country: us
Re: ad9850 dds
« Reply #7 on: May 29, 2014, 06:53:06 pm »
Can you post a schematic showing how you've connected the AD9850? Is it wired to enable serial mode (pin 2 to GND, pins 3&4 to +V)? 

As others have said, there is a reset sequence and timing requirements for the serial clock and frequency update pulses.

Though it may seem painful, sitting down with a cup of tea and reading (or re-reading) through the manufacturer's data sheet might be beneficial. At least pages 9 through 12.
 

Tac Eht Xilef

  • Guest
Re: ad9850 dds
« Reply #8 on: May 30, 2014, 01:47:47 am »
hm, i thought that "ud" or freq update is the reset.
My last line in the code is that freq update code.

Is there Another reset you are talking about?

Yup, there's a reset pin. You need 4 pins to communicate - data, clock, load (FQ_UD), and reset. The reset pin is fairly important; if you don't hardware reset the AD9850 to start with you'll get incoherent junk out of it.

By default, the AD9850 powers up in parallel mode. There's actually 2 ways of getting it into serial mode:
  • The datasheet way - if D2 is tied low and D1 & D0 tied high at powerup/reset, it goes into serial mode (data in on D7). See figures 10 & 11 of the datasheet for details.
  • The other way - if you go follow a particular sequence of toggling clock/load/reset/data (D7) after powerup/reset, it goes into serial mode. IIRC this isn't mentioned in the AD9850 datasheet - someone found it in the docs for a different AD DDS (AD9851?), tried it on the AD9850, found it worked, and now every article on using those cheap DDS modules uses this method.
Either way, you need to hardware reset the thing before it'll work properly. Read the datasheet carefully, check out any of the many examples on the 'net for connection details, work through and understand the arduino sketch retrolefty posted, and post your circuit diagram if you're still having trouble. And yes, dannyf is right - break your code up into functional blocks & use them for init/reset/send/load, rather than straightlining it all in one.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: ad9850 dds
« Reply #9 on: May 30, 2014, 10:22:42 am »
Quote
By default, the AD9850 powers up in parallel mode. There's actually 2 ways of getting it into serial mode:
The datasheet way - if D2 is tied low and D1 & D0 tied high at powerup/reset, it goes into serial mode (data in on D7). See figures 10 & 11 of the datasheet for details.
The other way - if you go follow a particular sequence of toggling clock/load/reset/data (D7) after powerup/reset, it goes into serial mode. IIRC this isn't mentioned in the AD9850 datasheet - someone found it in the docs for a different AD DDS (AD9851?), tried it on the AD9850, found it worked, and now every article on using those cheap DDS modules uses this method.

The 2nd approach (sending xxxxx011) is mentioned in the datasheet and exhibited as Figure 10 (I think).
================================
https://dannyelectronics.wordpress.com/
 

Tac Eht Xilef

  • Guest
Re: ad9850 dds
« Reply #10 on: May 30, 2014, 11:01:23 am »
The 2nd approach (sending xxxxx011) is mentioned in the datasheet and exhibited as Figure 10 (I think).

Ah, so it is...

(Really, AD? Who the f&^% goes looking inside the sequence diagrams for that sort of thing? It's bad enough that the only mention of hardwiring D0-D2 for startup in serial mode is in a note on the same diagram...

You even include a table listing the commands you can't use on pain of chip death - would it have killed you to include a table listing the few commands you can use?!)
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: ad9850 dds
« Reply #11 on: May 30, 2014, 11:21:47 am »
Quote
Who the f&^% goes looking inside the sequence diagrams for that sort of thing?

Any programmer who's working on that chip?
================================
https://dannyelectronics.wordpress.com/
 

Offline matiseTopic starter

  • Contributor
  • Posts: 28
Re: ad9850 dds
« Reply #12 on: May 31, 2014, 06:38:51 am »


I followed this one.
Rst to ground there...

I will build func. block in m code and try to solve this reset-problem.
Im aware of the timing to...
Its probably just some minor adjustments to get it work.
« Last Edit: May 31, 2014, 06:44:08 am by matise »
 

Offline matiseTopic starter

  • Contributor
  • Posts: 28
Re: ad9850 dds
« Reply #13 on: May 31, 2014, 07:59:52 am »



Ok, some photos.
You can see data and Clock signals here...
also i can see that there is a small delay between the 8-bit loops...
I dont know if that matter.
Maybe that will be better when i use functionblock in my program?

Picture also shows the last 8 clockbit in the program that fills up the 40 bits the dds need...

You can see the Connection on my card...
vcc, D0 and D1 to +
Gnd, D2 and rst to -

i have followed the scheme i posted earlier...

I hope ive done Everything how it should be.
 

Offline matiseTopic starter

  • Contributor
  • Posts: 28
Re: ad9850 dds
« Reply #14 on: May 31, 2014, 08:03:36 am »
 

Offline matiseTopic starter

  • Contributor
  • Posts: 28
Re: ad9850 dds
« Reply #15 on: May 31, 2014, 08:04:47 am »
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: ad9850 dds
« Reply #16 on: May 31, 2014, 11:02:31 am »
Nice pictures.
================================
https://dannyelectronics.wordpress.com/
 

Tac Eht Xilef

  • Guest
Re: ad9850 dds
« Reply #17 on: May 31, 2014, 02:25:07 pm »
I followed this one.

So what's with the diodes and resistors that appear to be on the data/clk/FQ pins in your later pic? (We can probably guess, but why should we?). They're not on the circuit diagram you've posted...

Rst to ground there...

Fair enough. Every one of those modules I've played with required reset to be toggled at startup regardless of parallel/serial mode. Maybe that's why they're so cheap?
 

Offline matiseTopic starter

  • Contributor
  • Posts: 28
Re: ad9850 dds
« Reply #18 on: May 31, 2014, 03:40:46 pm »
That diodes was just an experiment i tried, but ts not conneced to the Circuit now.  :)

When i turn on the Power, for a split second its a signal coming out from dds, but its to short to measure what it is.
Maybe it start up but something goes wrong..

I will not give up and buy an arduino yet.  :)
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: ad9850 dds
« Reply #19 on: May 31, 2014, 05:09:51 pm »
Don't focus on getting this piece of code to work.

Instead, focus on 1) learning the right way to code; and 2) learning to code to the datasheet. Once you have mastered the two, it is easy to code any device - AD9850 is actually one of the easiest to code.
================================
https://dannyelectronics.wordpress.com/
 

Offline matiseTopic starter

  • Contributor
  • Posts: 28
Re: ad9850 dds
« Reply #20 on: June 01, 2014, 08:52:59 am »
i will give it a try now to code to the datasheet.  :)

i upload the datasheet here.



page 9 talks about parallell and serial mode.
I use the serial mode.
What the datasheet says here is:

"In serial load mode, subsequent rising edges of W_CLK shift
the 1-bit data on Pin 25 (D7) through the 40 bits of programming
information. After 40 bits are shifted through, an FQ_UD
pulse is required to update the output frequency (or phase)".

What is it i have to understand here?
Im not shure but i Think they meen that data is sent, one bit at a time up to 40 bits...
And the clockpulse "split" up that datapulses so the dds can Count them correct...
Something like that, right?

And then after 40 data/clockpulses an FQ_UD pulse is needed to update and start the over again from data bit 1...

ok

page 10 and 11 in datasheet shows the parallell mode.
The serial mode is on page 12...
So that comes next.

 

Offline matiseTopic starter

  • Contributor
  • Posts: 28
Re: ad9850 dds
« Reply #21 on: June 01, 2014, 09:12:18 am »
Ok, page 12 then in datasheet about serielmode.


Here i see data from W0 to W39...
From lsb w0 to msb at w39...

Ive learned that this mean that we want to "roll up" the frequensy in hexcode from right to left...
Thats what im doing in my code here:

for(count=0;count<8;count++)
   {
   
   PORTBbits.RB4 = 1;
   PORTBbits.RB4 = fr4 & 0x01;
   fr4 >>= 1;
   PORTBbits.RB6 = 1;
   PORTBbits.RB6 = 0;
      
   }

ok, fr4 is 8 bit of frequency hexcode.
here:  fr4=0xA4

I put the last bit in that hexnr and send it to data out (RB4)...
After that i use fr4>>=1; to get ready for next bit...
Right?
After that comes the clockpulse on RB6.

I guess that is what the Picture shows at page 12.
Datapulses and the clockpulses and after that FQ_UD...

I dont understand W32 to W39.
It says "Control", "powerdown" and "phase"...
I just programmed 8 more clockpulses ther to fill up to 40 bits and then FQ_UD pulse on RB5...

That is all i can see and understand from this page...
What more can i understand from that page?
 

Offline matiseTopic starter

  • Contributor
  • Posts: 28
Re: ad9850 dds
« Reply #22 on: June 01, 2014, 09:20:14 am »
And then its something more on page 13...


I dont understand this Picture really.
w32=0, w33=0, w34=1, and then w=x...

Maybe someone here undestand this?

Well, thats all i can get out from this datasheet...
From here i understand, there is all the info i should need to program this dds.

But i fail big time.  :)
 

Offline Rerouter

  • Super Contributor
  • ***
  • Posts: 4694
  • Country: au
  • Question Everything... Except This Statement
Re: ad9850 dds
« Reply #23 on: June 01, 2014, 10:12:24 am »
32 and 33 are reserved codes for factory testing, and the chips will not work as intended with some of the combinations (i had an overflow on the frequency variable) until you power cycle

34 controls whether the chip is running or in sleep mode, essentially turns the output on or off,

the finally phase, which is handy if you wish to use phase modulation on your signal, as if the phase control word does not change the phase of the updated frequency is continuous (e.g. it doesn't restart the cycle but continues at whatever point on the cycle it was at) but if you do change it the signals phase will suddenly jump forward or back however much you set,

the phase is shown as X's in that image as it doesn't matter what it is in reference to what they are describing
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: ad9850 dds
« Reply #24 on: June 01, 2014, 11:17:33 am »
Quote
What more can i understand from that page?

Learning to read a datasheet is THE basic skill an embedded programmer has to have.

In this case, you need to send 40 bits of data to the chip, lsb first. The particular 40-bit data stream has 32 bits of frequency first (bit 0-31), followed by 8 bits of a control word (bit32-39).

The approach I laid out for you earlier could be implemented like this, following your own coding:

Code: [Select]
//send 8 bits to ad9850, lsb first
void ad9850_sendbyte(unsigned char fr4) {
  unsigned char count; //bit count

  for(count=0;count<8;count++)
  {
   
   AD9850_WCLK = 0; //clear wclk pin
   //PORTBbits.RB4 = 1;
   AD9850_DATA/*PORTBbits.RB4*/ = fr4 & 0x01;  //send bit
   fr4 >>= 1;
   AD9850_WCLK = 1; //PORTBbits.RB6 = 1; //strobe out data on the rising edge
     
   }
   AD9850_WCLK = 0;  //PORTBbits.RB6 = 0;  //wclk idles low
}

To send the 40-bit data stream, you could do something like this

Code: [Select]
//send 40 bits to ad9850 (32-bit freq + 8-bit control word), lsb first
void ad9850_sendwords(unsigned long freq, unsigned char ctrl) {
  AD9850_FQUD = 0; //fqud idles low
  //send freq (32-bit)
  ad9850_sendbyte(freq); freq = freq >> 8; //send lsb
  ad9850_sendbyte(freq); freq = freq >> 8;
  ad9850_sendbyte(freq); freq = freq >> 8;
  ad9850_sendbyte(freq); /*freq = freq >> 8;*/ //send msb
  ad9850_sendbyte(ctrl); //send control world

  //strobe fq_ud
  AD9850_FQUD = 1;
  AD9850_FQUD = 0;

}

So send a frequency word 0x12345678 to the chip + power it on would be something like this:

Code: [Select]
#define AD9850_POWERON 0x00 //turn on ad9850
  ad9850_sendwords(0x12345689ul, AD9850_POWERON);

shutting it down would be
Code: [Select]
#define AD9850_SHUTDOWN 0x04 //turn off ad9850
  ad9850_sendwords(freq, AD9850_SHUTDOWN);

Connectionwise, you need 3 lines: FQUD, WCLK and DATA. RESET is tied to ground, D0..2 connected as required by the datasheet.

Once you have it debugged, split it in a .c and .h file so you can use it in other projects.

You are done then. There really isn't much beyond that.
================================
https://dannyelectronics.wordpress.com/
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf