ad9850 dds - Page 1
Forum section: electronics / general

author: matise
author_rank: Contributor
timestamp: May 29, 2014, 12:29:09 pm
content: 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 11unsigned 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 binaryTRISA = 0b11111111; //sets PORTA as all inputsPORTA = 0b00000000; //turns off PORTA outputsTRISB = 0b00000000; //sets PORTB as all outputsPORTB = 0b00000000; //turns off PORTB outputs, good start positionwhile(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.

author: matise
author_rank: Contributor
timestamp: May 29, 2014, 12:48:51 pm
content: hm, i have photos showing the signals in my oscilloscope.But i dont know how to upload it here.i will try again later.

author: retrolefty
author_rank: Super Contributor
timestamp: May 29, 2014, 01:11:51 pm
content: 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://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 13void 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 RESETdelay(5);digitalWrite(RESET, LOW);delay(5);digitalWrite(CLOCK, LOW);delay(5);digitalWrite(CLOCK, HIGH); //pulse CLOCKdelay(5);digitalWrite(CLOCK, LOW);delay(5);digitalWrite(DATA, LOW); //make sure DATA pin is LOWdigitalWrite(LOAD, LOW);delay(5);digitalWrite(LOAD, HIGH); //pulse LOADdelay(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);}}

author: Unknown
author_rank: Unknown
timestamp: May 29, 2014, 01:58:35 pm
content: Quote from: retrolefty on May 29, 2014, 01:11:51 pmAFAIK 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, useserialparallel mode. For some reason I've never been able to get serial mode work as quickly as other people reckon it works...

author: matise
author_rank: Contributor
timestamp: May 29, 2014, 03:07:41 pm
content: 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?

author: retrolefty
author_rank: Super Contributor
timestamp: May 29, 2014, 03:27:41 pm
content: Quote from: matise on May 29, 2014, 03:07:41 pmRead 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.

author: dannyf
author_rank: Super Contributor
timestamp: May 29, 2014, 03:51:13 pm
content: QuoteThe 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.

author: Farley
author_rank: Regular Contributor
timestamp: May 29, 2014, 06:53:06 pm
content: 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.

author: Unknown
author_rank: Unknown
timestamp: May 30, 2014, 01:47:47 am
content: Quote from: matise on May 29, 2014, 03:07:41 pmYup, 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.

author: dannyf
author_rank: Super Contributor
timestamp: May 30, 2014, 10:22:42 am
content: QuoteThe 2nd approach (sending xxxxx011) is mentioned in the datasheet and exhibited as Figure 10 (I think).

author: Unknown
author_rank: Unknown
timestamp: May 30, 2014, 11:01:23 am
content: Quote from: dannyf on May 30, 2014, 10:22:42 amAh, so it is...(Really, AD? Who the f&^% goes lookinginsidethe 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 youcan'tuse on pain of chip death - would it have killed you to include a table listing the few commands youcanuse?!)

author: dannyf
author_rank: Super Contributor
timestamp: May 30, 2014, 11:21:47 am
content: QuoteAny programmer who's working on that chip?

author: matise
author_rank: Contributor
timestamp: May 31, 2014, 06:38:51 am
content: 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.

author: matise
author_rank: Contributor
timestamp: May 31, 2014, 07:59:52 am
content: 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.

author: dannyf
author_rank: Super Contributor
timestamp: May 31, 2014, 11:02:31 am
content: Nice pictures.

author: Unknown
author_rank: Unknown
timestamp: May 31, 2014, 02:25:07 pm
content: Quote from: matise on May 31, 2014, 06:38:51 amSo 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...Quote from: matise on May 31, 2014, 06:38:51 amFair 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?

author: matise
author_rank: Contributor
timestamp: May 31, 2014, 03:40:46 pm
content: 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.

author: dannyf
author_rank: Super Contributor
timestamp: May 31, 2014, 05:09:51 pm
content: 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.

author: matise
author_rank: Contributor
timestamp: June 01, 2014, 08:52:59 am
content: 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 shiftthe 1-bit data on Pin 25 (D7) through the 40 bits of programminginformation. After 40 bits are shifted through, an FQ_UDpulse 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...okpage 10 and 11 in datasheet shows the parallell mode.The serial mode is on page 12...So that comes next.

author: matise
author_rank: Contributor
timestamp: June 01, 2014, 09:12:18 am
content: 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=0xA4I 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?

author: matise
author_rank: Contributor
timestamp: June 01, 2014, 09:20:14 am
content: 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.

author: Rerouter
author_rank: Super Contributor
timestamp: June 01, 2014, 10:12:24 am
content: 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 cycle34 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

author: dannyf
author_rank: Super Contributor
timestamp: June 01, 2014, 11:17:33 am
content: QuoteLearning 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://send 8 bits to ad9850, lsb firstvoid ad9850_sendbyte(unsigned char fr4) {unsigned char count; //bit countfor(count=0;count<8;count++){AD9850_WCLK = 0; //clear wclk pin//PORTBbits.RB4 = 1;AD9850_DATA/*PORTBbits.RB4*/ = fr4 & 0x01; //send bitfr4 >>= 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 thisCode://send 40 bits to ad9850 (32-bit freq + 8-bit control word), lsb firstvoid 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 lsbad9850_sendbyte(freq); freq = freq >> 8;ad9850_sendbyte(freq); freq = freq >> 8;ad9850_sendbyte(freq); /*freq = freq >> 8;*/ //send msbad9850_sendbyte(ctrl); //send control world//strobe fq_udAD9850_FQUD = 1;AD9850_FQUD = 0;}So send a frequency word 0x12345678 to the chip + power it on would be something like this:Code:#define AD9850_POWERON 0x00 //turn on ad9850ad9850_sendwords(0x12345689ul, AD9850_POWERON);shutting it down would beCode:#define AD9850_SHUTDOWN 0x04 //turn off ad9850ad9850_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.

author: matise
author_rank: Contributor
timestamp: June 02, 2014, 03:41:21 pm
content: thx a lot for response.im Little busy this week but i will take a look at it soon.

author: Mechatrommer
author_rank: Super Contributor
timestamp: June 02, 2014, 06:26:34 pm
content: this is a working code to control ad9850, but its for atTiny13A (see attached) maybe it can be your learning material, look from bottom up (typical C style) esp at setup() and sendFrequency()... quick looking at the schematics you posted i kinda dont like it since there is no amplitude and offset control, why dont you include those in your circuit? so you wont have to redo the next version. here is one not so good example, but at least it has amplitude and voltage control.just to give you some idea. FWIW.

author: Hydrawerk
author_rank: Super Contributor
timestamp: September 20, 2014, 06:38:05 pm
content: Quote from: retrolefty on May 29, 2014, 01:11:51 pmThank you, you helped me a lot with the initial reset, because it is not said in the AD9850 datasheet.

author: Hydrawerk
author_rank: Super Contributor
timestamp: September 20, 2014, 06:44:38 pm
content: I use this code inspired byretrolefty. I use ATmega32. No Arduino.Code:/*//////////connection ATmega32 with AD9850PORTD=0b 1 1 1 1 0 0 0 0;AD9850 D7 D6 D5 D4 D3 D2 D1 D0PORTB=0b 1 1 1 1 0 0 0 0;AD9850Reset W-CLK FQ-UD*///correctly resetting the AD9850PORTB=0b11110000;_delay_us(5);PORTB=0b11110100;_delay_us(5);PORTB=0b11110000;_delay_us(5);PORTB=0b11110010;_delay_us(5);PORTB=0b11110000;_delay_us(5);PORTD=0b00000000; //data_delay_us(5);PORTB=0b11110001;_delay_us(5);PORTB=0b11110000;// Chip is RESET nowPORTB=0b11110100; //only for temporary_delay_us(5); //output offPORTB=0b11110000;_delay_ms(500);PORTD=0b00000000;PORTB=0b11110001;PORTB=0b11110000;_delay_us(6);////PORTD=0x00; //W0_delay_us(3);PORTB=0b11110010;_delay_us(6);PORTB=0b11110000;_delay_us(3);////PORTD=0x50; //W1_delay_us(3);PORTB=0b11110010;_delay_us(6);PORTB=0b11110000;_delay_us(3);////PORTD=0xAD; //W2_delay_us(3);PORTB=0b11110010;_delay_us(6);PORTB=0b11110000;_delay_us(3);////PORTD=0xC4; //W3_delay_us(3);PORTB=0b11110010;_delay_us(6);PORTB=0b11110000;_delay_us(3);////PORTD=0xFD; //W4_delay_us(3);PORTB=0b11110010;_delay_us(6);PORTB=0b11110000;_delay_us(3);////PORTB=0b11110001; //Frequency update_delay_us(3);PORTB=0b11110011;_delay_us(3);PORTB=0b11110011;_delay_us(6);PORTB=0b11110010;_delay_us(6);I use this online tool to generate the W0 to W4 words.http://designtools.analog.com/dt/dds/ad9850.html