Ad9851 dds
Hi all
I am trying to get to grips with sending data to an AD9851 DDS chip. However, being completely new to things here (and to the Propellor) it is proving problematic.
http://www.analog.com/en/rfif-components/direct-digital-synthesis-dds/ad9851/products/product.html
The chip needs a 40 bit binary word which can either be transmitted serially or as 5 x 8 bit bytes (much faster). Only the 32 LSBs of the 40 bit word are reqired to define the frequency. These 32 bits are calculated by the formula 32bits = (F_out x 2^32) / F_clock. F_out is the desired frequency.
For an example, using a clock of 125MHz, the words for 10MHz are:
W0 00
W1 14
W2 7A
W3 E1
W4 48
lhttp://designtools.analog.com/dt/dds/ad9851.html
The first problem is calculating the word as the Spin compiler does not like the decimal representation of 2^32 (4294967296). I can fix that by approximating the number to 4294967295, or perhaps pre-dividing by F_clock which is another constant. I then end up with a decimal number representing the 32 bit word.
It could be that it is already the binary number I need but I'm guessing that it's not as it is probably stored in a clever way to account for decimal places and pos/neg (?). If so I need to clean it up so that I can send it out (another puzzle at this stage).
I have looked about on t'internet for code for this application; there is plenty of PIC stuff and some C, but neither helps me at all. Has anyone got anything they would care to share or can anyone give me one or two clues as to some of the Spin elements that I need to get familiar with!
I'm on a steep learning curve here and I'm close to the bottom at the moment, hanging on by my finger nails...
Any clues would be much appreciated.
Thanks
Richard
I am trying to get to grips with sending data to an AD9851 DDS chip. However, being completely new to things here (and to the Propellor) it is proving problematic.
http://www.analog.com/en/rfif-components/direct-digital-synthesis-dds/ad9851/products/product.html
The chip needs a 40 bit binary word which can either be transmitted serially or as 5 x 8 bit bytes (much faster). Only the 32 LSBs of the 40 bit word are reqired to define the frequency. These 32 bits are calculated by the formula 32bits = (F_out x 2^32) / F_clock. F_out is the desired frequency.
For an example, using a clock of 125MHz, the words for 10MHz are:
W0 00
W1 14
W2 7A
W3 E1
W4 48
lhttp://designtools.analog.com/dt/dds/ad9851.html
The first problem is calculating the word as the Spin compiler does not like the decimal representation of 2^32 (4294967296). I can fix that by approximating the number to 4294967295, or perhaps pre-dividing by F_clock which is another constant. I then end up with a decimal number representing the 32 bit word.
It could be that it is already the binary number I need but I'm guessing that it's not as it is probably stored in a clever way to account for decimal places and pos/neg (?). If so I need to clean it up so that I can send it out (another puzzle at this stage).
I have looked about on t'internet for code for this application; there is plenty of PIC stuff and some C, but neither helps me at all. Has anyone got anything they would care to share or can anyone give me one or two clues as to some of the Spin elements that I need to get familiar with!
I'm on a steep learning curve here and I'm close to the bottom at the moment, hanging on by my finger nails...
Any clues would be much appreciated.
Thanks
Richard

Comments
Word_to_send := ((F_out << 16) / F_clk) << 16
You may not want 16 in both places. The two numbers should add up to 32, though. The first one should be small enough that F_out won't overflow a 32-bit number, but otherwise as large as possible.
Looking at the operators it looks like a bitwise reverse, used with a bitwise encode, a test and a shift left might be a way of shifting out a number correctly. There has to be an easier way though. It looks way too clumsy.
PUB Divide(Fout, Fclock) : f Fout <<= 1 repeat 32 'perform long division of (Fout / Fclock) * 2^32 f <<= 1 if Fout => Fclock Fout -= Fclock f++ Fout <<= 1Or if you prefer PASM:Divide ' Calculate ((Fout / Fclock) * 2^32) mov Counter,#32 mov Quotient,#0 mov Dividend,Fout mov Divisor,Fclock shl Dividend,#1 :Loop shl Quotient,#1 ' Double the quotient cmpsub dividend,divisor wc ' Attempt to subtract clk_freq from output freq if_c add quotient,#1 ' Add one to the quotient if subtraction occurred shl dividend,#1 ' Double the output freq djnz Counter,#:Loop ' And repeat until dividend shifted 32 times (multiplied by 2^32) wrlong Quotient,parI really need to re-learn my binary maths!
Cheers.
I think that I can use & to do my testing:
If (DDS_word & $0001) > 0 'then LSB is 1
maybe?
Var Long Fout, Fclock, f PUB CalcF_and_Load Fout := 70.454 'Test data Fclock := 125 'Test data f := 0 'Hard clear f 'Calculate the frequency word required Fout <<= 1 repeat 32 'perform long division of (Fout / Fclock) * 2^32 f <<= 1 if Fout => Fclock Fout -= Fclock f++ Fout <<= 1 'Set pins to outputs dira[16]~~ 'Used for Serial Load dira[18]~~ 'Used for W_CLK dira[22]~~ 'Used to update freq after load (FQ_UD) 'Shift out the data LSB first (32 bits) f <-= 1 ' pre-align lsb repeat 32 outa[16] := (f ->= 1) & 1 ' output data bit Waitcnt (clkfreq/2 + cnt) ' let it settle !outa[18] ' clock the bit Waitcnt (clkfreq/2 + cnt) !outa[18] 'add 8 more clock cycles to fill last 8 bits with 0s repeat 8 Waitcnt (clkfreq/2 + cnt) !outa[18] Waitcnt (clkfreq/2 + cnt) !outa[18] 'Send FQ_UD to transfer data into DDS registers Waitcnt (clkfreq/2 + cnt) !outa[22] Waitcnt (clkfreq/2 + cnt) !outa[22]It is set to run slow for testing. I dont have an AD9851 here as yet to test it.
I will report back once I am able to test it "live".
Regards
Richard
Regards
Richard
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 'assign pins W_CLK = 3 FQ_UD = 2 SER_DATA = 1 RST = 0 P23 = 23 'Mirrors W_CLK P22 = 22 'Mirrors SER_DATA P21 = 21 'Mirrors FQ_UQ P20 = 20 'Mirrors RST Obj Debug : "Debug_LCD03" Var Long Fout, f, Fclock Byte W0 Pub Main Debug.Start (21, 9600, 4) Debug.Backlight(true) Debug.CLS Debug.Str(string("LCD Debug")) Debug.NL Reset_AD9851 Debug.CLS Debug.Str(string("Reset okay")) Debug.NL Calc_F Load_F Repeat Pri Reset_AD9851 | i 'Set ports to outputs dira[0..3] ~~ 'Data to AD9851 dira[20..23]~~ 'Quickstart LED repeater 'Reset device 'Toggle RST !Outa[RST] Dly !Outa[RST] Dly 'Switch device to serial mode 'Toggle W_CLK !Outa[W_CLK] Dly !Outa[W_ClK] Dly 'Toggle FQ_UD !Outa[FQ_UD] Dly !Outa[FQ_UD] Dly 'Clear register Outa[SER_DATA]~ 'fill register with zeros 'Send 40 clock cycles Repeat 80 !Outa[W_CLK] Dly !Outa[FQ_UD] Dly !Outa[FQ_UD] Dly Pri Calc_F Fout:= 2_140_000 'Hz 'System clock Fclock := 180_000_000 'Hz 'Calculate the frequency word required Fout <<= 1 repeat 32 'perform long division of (Fout / Fclock) * 2^32 f <<= 1 if Fout => Fclock Fout -= Fclock f++ Fout <<= 1 Pri Load_F 'Shift out the data LSB first (32 bits) f <-= 1 ' pre-align lsb repeat 32 outa[SER_DATA] := (f ->= 1) & 1 Dly !outa[W_CLK] ' output data bit ' Dly !outa[W_CLK] Dly 'Phase registers and clock multiplier 'Sets clock multiplier to x 6 W0 := 00_0001 'Shift out word W0 W0 <-= 1 repeat 8 outa[SER_DATA] := (W0 ->= 1) & 1 Dly !outa[W_CLK] Dly !outa[W_CLK] Dly 'Send FQ_UD to transfer data into DDS registers !outa[FQ_UD] Dly !outa[FQ_UD] Dly PRI Dly 'Mirrors data lines to LEDs and adds delays 'to help visual debug If Outa[W_CLK] == 1 Outa[P23] := 1 ELSE Outa[P23] := 0 If Outa[SER_DATA] == 1 Outa[P22] := 1 ELSE Outa[P22] := 0 If Outa[FQ_UD] == 1 Outa[P21] := 1 ELSE Outa[P21] := 0 If Outa[RST] == 1 Outa[P20] := 1 ELSE Outa[P20] := 0 Waitcnt (clkfreq/100 + cnt)PS I have no idea how Chris' divide and multiply code actually works. I would love some pointers to that!
Regards
Richard
The second question is does a call to an object always return from that object irrespective of what the object does?
I would welcome advice on any other errors you see!
Cheers
Richard
AD9851_Demo - Archive [Date 2012.05.23 Time 20.38].zip