programming a pic for ad9850 - Page 1
Forum section: electronics / general

author: matise
author_rank: Contributor
timestamp: November 14, 2013, 04:43:48 pm
content: HiMy first post on this nice forum.I got one of this ad9850 dds-card from china.But there is no good programming examples out there that i can use.I want to try to get it running on 3.6 MHz...If i got it right the clk needed = 3.5 ns (min)And FQ = 7.0 ns. (min)hex=075F6FD2 (3.6MHz)And my header for this is:#include <p18f1220.h>#pragma config WDT=OFF , OSC=INTIO2 , PWRT=ON, LVP=OFF, MCLRE=OFF#include <delays.h>void main(void){//SET UP//OSCCON defaults to 31kHz. So no need to alter it.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; //sets off PORTB outputs, good start positionwhile(1){freq = 075F6FD2;}}I will try to programming this but i need some help.Someone that can help me in right direction here?Lets say data(hex) on RB 4clk RB5FQ RB6thnx matise

author: dannyf
author_rank: Super Contributor
timestamp: November 14, 2013, 06:11:27 pm
content: It is exceedingly simple:1) write a routine to set/clear pins;2) write a routine to send a byte by calling the routine in 1);3) write a routine to send the control words by calling the routine in 2;4) write a routine to decompose the desired frequency into control words;5) write a routine to send the right control words associated with the desired frequency by calling routines in 3) and 4).All you need is to implement each of the 5 steps and you are done.

author: Rufus
author_rank: Super Contributor
timestamp: November 14, 2013, 07:46:42 pm
content: Quote from: dannyf on November 14, 2013, 06:11:27 pmIt is moderately simple for someone who knows what they are doing. For someone who postsfreq = 075F6FD2;and asks what should go there instead it may be exceedingly difficult.I suggest the OP searches the web harder, an example herehttp://www.ccsinfo.com/forum/viewtopic.php?p=155780for instance.

author: matise
author_rank: Contributor
timestamp: November 16, 2013, 09:18:47 am
content: Tnx for the link.I can see now that its not easy to programming a pic for that kind of task...Its a more advanced c-programming than i know of when im programming sensors or lcd...I need to find the right book so i understand this better.Anyone any suggestions?Some pic-book or c-programming books that will cover what i need to learn to program this kind of dds?tnx

author: dannyf
author_rank: Super Contributor
timestamp: November 16, 2013, 11:41:10 pm
content: QuoteI did a ad9850 based signal generation from a 16F684. As easy as 123.

author: dannyf
author_rank: Super Contributor
timestamp: November 16, 2013, 11:42:11 pm
content: Quote1. take a decent class in C;2. read manuals for your tools;3. read the device datasheets.4. code, code and then code some more.

author: Rufus
author_rank: Super Contributor
timestamp: November 17, 2013, 12:20:06 am
content: Quote from: matise on November 16, 2013, 09:18:47 amIt is only 34 lines of code - if you are inexperienced figuring out what it does would be as good a place as any to start to become more experienced.

author: dannyf
author_rank: Super Contributor
timestamp: November 17, 2013, 02:13:23 am
content: Agreed with Rufus.Many times, people are held back from doing fancy stuff because they have no clue about the simpler stuff.

author: Mechatrommer
author_rank: Super Contributor
timestamp: November 17, 2013, 09:21:42 am
content: Quote from: matise on November 14, 2013, 04:43:48 pmgolden loop of eternitymay i suggest LED blinker?

author: matise
author_rank: Contributor
timestamp: January 28, 2014, 06:08:42 pm
content: i guess the idea should be something like this?#include <p18f1220.h>#pragma config WDT=OFF , OSC=INTIO2 , PWRT=ON, LVP=OFF, MCLRE=OFF#include <delays.h>#define data 10#define clk 11#define ud 12unsigned long freq;int count;void main(void){//SET UP//OSCCON defaults to 31kHz. So no need to alter it.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; //sets off PORTB outputs, good start positionfreq = 125413045;while(1){for(count=0;count<32;count++){PORTBbits.RB4 = 1; // DataPORTBbits.RB4 = freq;PORTBbits.RB5 = 1; // ClockPORTBbits.RB5 = 0;}PORTBbits.RB4 = 0;for(count=0;count<8;count++) // 8 blank{PORTBbits.RB5 = 1; // ClockPORTBbits.RB5 = 0;}PORTBbits.RB6 = 1; // UdPORTBbits.RB6 = 0;}}

author: dannyf
author_rank: Super Contributor
timestamp: January 28, 2014, 06:41:51 pm
content: -PORTBbits.RB4 = freq;-not even in the same universe.

author: matise
author_rank: Contributor
timestamp: January 28, 2014, 07:39:11 pm
content: lol, no i can understand that but i dont know how to "link" freg to data out...Rest of it should be something near.I know that the dds want 32 bits, and the Clock give one pulse every loop.then 8 blank and the Clock give pulses and finally ud...Someone about that frequency-data output?Or am i totally wrong with this?

author: Rerouter
author_rank: Super Contributor
timestamp: January 28, 2014, 07:57:10 pm
content: while this has a tiny bit of arduino style code in it i think it could help (if your programming in C, you should only have to point to the correct pins)Code:#define pulseHigh(pin) {bitSet(PORTD, pin); bitClear(PORTD, pin);} // for pulsing ad9850 pins// Initialises AD9850 ModulepulseHigh(RESET); // AD9850 SetuppulseHigh(W_CLK);pulseHigh(FQ_UD); // this pulse enables serial mode - Datasheet page 12 figure 10sendFrequency (0);// transfers a byte, a bit at a time, LSB first to the 9850 via serial DATA linevoid tfr_byte(byte data) {for (byte i=0; i<8; i++, data>>=1) {bitWrite(PORTD, 6, data & 0x01); // Write data out of DATA pinpulseHigh(W_CLK); // after each bit sent, CLK is pulsed high}}/*-------------------------------------------------------------------------------------------------------*/// frequency calc from datasheet page 8 = <sys clock> * <frequency tuning word>/2^32// Steps in 0.02910383046hzvoid sendFrequency(double frequency) {int32_t freq = frequency * 4294967295/125000000; // converts Hz into Binaryfor (byte b=0; b<4; b++, freq>>=8) {tfr_byte(freq & 0xFF);}tfr_byte(0x000); // Final control byte, Includes Phase and power downpulseHigh(FQ_UD); // Done! Should see output}

author: mariush
author_rank: Super Contributor
timestamp: January 28, 2014, 08:23:19 pm
content: Read the PIC datasheet.Use the internal clock of the PIC and set it to some sane Mhz value .. for example 1 Mhz or 4 Mhz. With PIC microcontrollers, everything works in sets of 4 cycles. Most instructions need 4 Hz to finish, some instructions need 2 x 4 Hz to finish. So at best, with 1 Mhz clock you have 250k instructions per second or 250 per ms or 2.5 per ns. With 4 Mhz, you have 1 million instructions per second or about 1000 per ms or 1 per nanosecond.By default, I think the PIC will stay at 31 Khz and that's superslow. Just setting those RB3 and RB4 will take maybe a 10th of a second.If i got it right the clk needed = 3.5 ns (min)And FQ = 7.0 ns. (min)hex=075F6FD2 (3.6MHz)hex=075F6FD2 (3.6MHz)is incorrect.To put a binary value in a variable, you say binarynumber =0b10101010;To put a hexadecimal value in a variable, you say hex =0x075F6FD2;Since you're working with a 8 bit microcontroller, it may be easier for you to store that frequency as 4 separate bytes: hex1 = 0x07; hex2 = 0x5F; hex3 = 0x67; hex4 = 0xD2;You can then write these into a .h file attached to your project, and then just use the function names to get a bit from the each byte:#define bit_get(var,bitno) ((var) & (1 << (bitno)))#define bit_set(var,bitno) ((var) |= 1 << (bitno))#define bit_clear(var,bitno) ((var) &= ~(1 << (bitno)))ex PORTBbits.RB4 = bit_get(hex1,0); <--- put on RB4 the first bit of hex1.PORTBbits.RBx where x = 0 to 7 set the pins of the PORT B to 0 or 1 .. they're BITS. You can only put 0 or 1 there. Can't assign a number like the whole frequency. You have to put one bit at a time, set the clock bit on and then off so that the dds takes the bit inside, then continue with the next bit. You basically have to send 32 bits, one at a time.Now here you have to remember those " clk needed = 3.5 ns (min) And FQ = 7.0 ns. (min) " - if your clock is 4 mhz or something like that, when you put 1 on one of those .RBx variables, you have to keep in mind each of those instructions may take less than 1-2 ns, so you may want to add some delays there to give the other chip time to process what you send to it.You can add in the same .h file some helper functions like these:#define delay_1tcy() asm("nop")#define delay_2tcy() asm("goto $+1")so when you say in your code delay_1tcy(); the pic will waste one instruction doing nothing. Again, at 4 Mhz, that's 1 megainstructions per second or 1000 per ms or 1 per ns. So the PIC waits for 1 ns.If you have to make sure you wait at least 3.5ns, then add delay_2tcy(); twice.Same for the 7ns minimum.--If this is too confusing, you should probably start with a simple blink led example code and move from there.I suggest at least browsing through these documents:MPLAB® XC8 Getting Started Guide :http://ww1.microchip.com/downloads/en/DeviceDoc/50002173A.pdfMPLAB® XC8 C Compiler User’s Guide :http://ww1.microchip.com/downloads/en/DeviceDoc/MPLAB_XC8_C_Compiler_User_Guide.pdf

author: dannyf
author_rank: Super Contributor
timestamp: January 28, 2014, 08:51:31 pm
content: QuoteThat's simple: the datasheet has it explained in great details.QuoteA few issues:1) I would have structured it so that you have a routine that sends the ad9850 a byte, another that sends the tuning word, and another that converts the desired frequency into the tuning word, plus one that reset the device / pins. This allows you considerable flexibility.2)Code:pulseHigh(RESET); // AD9850 SetupYou probably don't want to reset the chip each time you try to change the output frequency.3)Code:int32_t freq = frequency * 4294967295/125000000; // converts Hz into BinaryProbably the least elegant part of the code. You don't want to use floating point math; You want the code to be flexible with regards to master frequency used, etc.They are ways to achieve all of that, entirely in integer math.4)Code:tfr_byte(freq & 0xFF);The AND operation is unnecessary.5)Code:tfr_byte(0x000); // Final control byte, Includes Phase and power downWatch the prototype for tfr_byte.Hope it helps.

author: dannyf
author_rank: Super Contributor
timestamp: January 28, 2014, 09:45:41 pm
content: QuoteAre you sure that you are talking about the same thing?

author: mariush
author_rank: Super Contributor
timestamp: January 28, 2014, 10:05:02 pm
content: Yes.The code in his first post has these:#include <p18f1220.h>#pragma config WDT=OFF , OSC=INTIO2 , PWRT=ON, LVP=OFF, MCLRE=OFF#include <delays.h>void main(void){//SET UP//OSCCON defaults to 31kHz. So no need to alter it.So he's using a PIC18F1220 which has an internal oscillator running at up to 8 Mhz but he leaves it at the default of 31 kHz ... this will make communicating with the ad9850 super slow.later edit: oh, I may have expressed myself incorrectly. Yeah, there's no "clock", i meant internal oscillator.

author: dannyf
author_rank: Super Contributor
timestamp: January 28, 2014, 10:44:56 pm
content: To change that, you can simply write to IRCFx bits - it takes no more than a line to do.

author: Mechatrommer
author_rank: Super Contributor
timestamp: January 28, 2014, 11:14:08 pm
content: you are close! change this...Code:for(count=0;count<32;count++) {PORTBbits.RB4 = 1; // DataPORTBbits.RB4 = freq;PORTBbits.RB5 = 1; // ClockPORTBbits.RB5 = 0;};to this...Code:for(count=0;count<32;count++) {PORTBbits.RB4 = (freq & 1); // DataPORTBbits.RB5 = 1; // Clockfreq >>= 1;PORTBbits.RB5 = 0;};you need additional storage to save freq value though since the loop will modify and zero it at "freq >>= 1;" when leaving the loop. keep up the hardwork!

author: matise
author_rank: Contributor
timestamp: January 29, 2014, 08:59:47 am
content: thank you all very, very much for your help!I will carefuly read your advices the coming weeks and try to get it right.I Think your advices is what i needed.I bought the same c-programming books they use in Universitys and ive almost finnished that, and also i bought pic-books and i now know simpler pic-programming.The last weeks i learned about bit-programming and wrote a rotary encoder program for this dds...PORTAbits.RA0 = 1; //till pin1PORTAbits.RA1 = 1; //till pin2pin1 = PORTAbits.RA0;pin2 = PORTAbits.RA1;if(pin1==1)sum1 = 0x08; // bit 3if(pin2==1)sum1 |= (1<<2); // bit 2ny1 = PORTAbits.RA0; // new encoder bitsny2 = PORTAbits.RA1;if(ny1 != pin1 || ny2 != pin2) //if new encoder numbers{if(ny1==1)sum1 |= (1<<1); // bit 1if(ny2==1)sum1 |= (1<<0); // bit 0if(sum1 == 1 || sum1 == 7 || sum1 == 14 || sum1 == 8 ) freq =+1024; //clockwise movementif(sum1 == 11 || sum1 == 13 || sum1 == 4 || sum1 == 2) freq=-1024; //counter-clockwise movementI hope it will work.The problem is that i cant find any books that teach programming for this kind of stuff...So i try to find "fragments"of info on the net...Electronics takes time to learn and its really not easy.But i take it very seriously.thanks again.

author: dannyf
author_rank: Super Contributor
timestamp: January 29, 2014, 11:15:47 am
content: QuoteCoding a mcu is largely the same as coding on PC: except that there are those special "memory regions" (="registers") that control peripheral activities.So you need to a few things:1) Being good at C.2) Being able to understand the datasheet of the mcu;3) Being able to understand the datasheet of the devices your mcu interacts with.After that, it is a breeze.Your trouble here is that you lacked even the most rudimentary understanding of ad9850.

author: matise
author_rank: Contributor
timestamp: February 02, 2014, 03:30:43 pm
content: I understand now how (freq & 1) works.About tuningword and it increase its number into the phase accumulator each time it receives a Clock pulse.That builds up the sinwave...But i cant find any info about this next line:freq >>= 1;What is this all about?What it says is that it divide freq but why?What is the purpose?

author: mariush
author_rank: Super Contributor
timestamp: February 02, 2014, 04:05:36 pm
content: freq >>=1 is the same thing as freq = freq >> 1which means shift the bits in freq to the right by 1 .. ex 10110101 becomes 01011010 or 181 becomes 90 (181/2)