Calculate tuning value for the AD9850 DDS.


Closed Thread
Results 1 to 17 of 17
  1. #1
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516

    Default Calculate tuning value for the AD9850 DDS.

    Hi,
    I've written an article in the Wiki which shows two possible ways to calculate the 32bit tuning value for the AD9850 DDS chip from Analog Devices.

    This thread is intended for discussions and questions regarding the article.

    /Henrik.

  2. #2
    Join Date
    Dec 2011
    Location
    IO93ok
    Posts
    190


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    Very interesting Henrik.

    I have only skimped through the wiki just now and will read properly offline.

    I'm currently using one of the cheap ebay modules on a board i designed and a 16f628 to produce a tunable signal generator dds, this is other peoples code in asm though. One other code is a sweep generator/signal generator with decade digit selection by rotary encoder.

    I had been trying to do the maths (Nowhere near my capability) to use a rotary encoder in pbp. I did achieve an incrementing counter in pbp with it but got no further to convert to the tuning word.
    I was also able to get it to any frequency by inserting the byte sequence for the tuning word into the code. I had all the amateur bands set up as subs and using a pushbutton could step through them.

    I wanted to do the dds in pbp so I could add further features such as keypad freq entry, vfo a and vfo b, along with band switching outputs for a ham radio transceiver I'm building.

    Below is some sample code. I did move on much further but then got into a jam with ideas.

    Regards,
    Rob


    Code:
    '****************************************************************
    '*  Name    : DDS Frequency Generator                           *
    '*  Author  :                                    *                               *
    '*  Date    : 10/29/2012                                        *
    '*  Version : 1.0                                               *
    '*  Notes   : Uses ebay DDS board and rotary encoder            *
    '*          :                                                   *
    '****************************************************************
    
    '
    ;  16f628a
    ;  __config _CP_OFF&_LVP_OFF&_BODEN_OFF&_PWRTE_OFF&_WDT_OFF&_INTRC_OSC_NOCLKOUT
    ; 
    '       
    '
            '
            '       LCD Display
            '       -----------
            '      
            '
    Define LCD_DREG PORTB          ' Port for LCD Data
    Define LCD_DBIT 0              ' Use lower 4 bits of Port
    Define LCD_RSREG PORTB         ' Port for RegisterSelect (RS) bit
    Define LCD_RSBIT 6             ' Port Pin for RS bit
    Define LCD_RWBIT 5             ' Port Pin for RS bit
    Define LCD_EREG PORTB          ' Port for Enable (E) bit
    Define LCD_EBIT 4              ' Port Pin for E bit
    Define LCB_BITS 4              ' Using 4-bit bus
    Define LCD_LINES 2             ' Using 2 line Display
    Define LCD_COMMANDUS 1200      ' Command Delay (uS)
    DEFINE LCD_DATAUS 50           ' Data Delay (uS)
            '
            '      Control Buttons/Lines
            '      ---------------------
    PB_1 var PortA.4              ' Take this pin low momentarily to change step
    PB_2 var PortA.3              ' Take this pin low momentarily to change band
    PB_3 var PortA.2              ' Take this pin low momentarily to RESET
    EncoderRight var PortA.1       ' rotary encoder pin
    EncoderLeft var PortA.0      ' rotary encoder pin
    
    
    ddsload var PortB.7           ' dds control word pin
    ddsdata var PortB.3           ' dds data input
    ddsclock var PortB.2          ' dds clock input
    
    
    
    fStep var byte
    fcount var byte
    Counter var word
    
    
        CMCON=7      'sets 16f628 comparator pins to digital
        TRISA=%00011111       'Button & encoder inputs
    
    Counter = 0
    fcount = 0
    fstep = 1     ;start at 1 digit count
    
        LOW DDSLOAD
    
    'CONFIGURE DISPLAY
        pause 1000
        LCDOUT $FE,1    ' Clear screen
        pause 10
        lcdout $fe,$c0,dec5 counter        ; reset to zero on start
    
    
    ddstart:
        shiftout ddsdata,ddsclock,0,[ $07,$2B,$02,$0C ]   ;start value
        toggle ddsload
        pause 100
    
    ;Rotary Encoder Code################################################
    
    mainloop1:
    
        if EncoderRight=0 then                 'here is switch 2 of the rotary encoder
            counter=counter+1
            gosub up
            gosub dds
            gosub lcd
        endif
    
    'IF PB_1=0 THEN inc_step
    
        if EncoderLeft=0 then                 'here is switch 1 of the rotary encoder
            counter = counter-1
            gosub down
            gosub dds
            gosub lcd
        endif
    
        goto mainloop1
        
    lcd:
        lcdout $fe,$c0,dec5 counter
        while (EncoderLeft=0 or EncoderRight=0):pause 10:wend
        return
    
    
    inc_step:
        fcount=fcount+1
        if fcount=2 then fstep=100
        if fcount=1 then fstep=10
        fcount=1
        return
    
    dds:
        shiftout ddsdata,ddsclock,0,[counter]
        toggle ddsload
        return
    
    up:
    
        counter[0]=counter[0]+1
        if counter[0]>99 then
            counter[0]=0
            counter[1]=counter[1]+1
            if counter[1]>99 then
                counter[1]=0
                counter[2]=counter[2]+1
                if counter[2]>99 then
                    counter[2]=0
                    counter[3]=counter[3]+1
                    if counter[3]>99 then
                        counter[3]=0     ;reset to zero
                    endif
                endif
            endif
        endif
    return
    
    down:
    
        counter[0]=counter[0]-1
        if counter[0]<1 then
            counter[0]=0
            counter[1]=counter[1]-1
            if counter[1]<1 then
                counter[1]=99
                counter[2]=counter[2]-1
                if counter[2]<1 then
                    counter[2]=99
                    counter[3]=counter[3]-1
                    if counter[3]<1 then
                        counter[3]=99
                    endif
                endif
            endif
        endif
    return
    
    end
    Last edited by tasmod; - 6th January 2013 at 17:26.

  3. #3
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    Hi Rob,
    Yes, I remember the problem with your up/down counter not working properly....
    You're still having that Counter variable declared as a WORD but treating it as a 4 byte array in your UP/DOWN subrouitines. That's a crash waiting to happen since the up/down routines writing to the array will write to memory "outside" of the declared variable corrupting what ever is there. I thought we covered that...

    When setting the frequency you need to shift 40 bits (32bits tuning value + 8bits control) into the AD9850 and then pulse the Update Frequency pin. Looking at your code I see two main issues (appart from the Counter variable discussed above):
    A) In your DDS subroutine that shifts out the tuning value you're only shifting out 8 bits. Even if Counter is declared as a WORD (which it shouldn't be anyway) it will only shift 8 bits when written like that.
    B) You're not pulsing the Update Frequency pin, you're toggling it. The AD9850 updates the frequency on the rising edge of that signal so by toggling it like you're doing every second update would fail.

    /Henrik.

  4. #4
    Join Date
    Dec 2011
    Location
    IO93ok
    Posts
    190


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    Hmm yes. I posted the first version i worked as i was on the wrong pc.
    I did move on quite a bit.
    The toggle was changed later.
    The 40 bit control word has the 32 bit then next 8 bit as zero. So this can be set as a constant to be addaed at end of the word.

    Sorry if this is messy its from my mobile.

  5. #5
    Join Date
    Jun 2008
    Location
    Varese , Italy
    Posts
    326


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    Hi to all in this forum.
    I am using the magic number to control my AD9850 DDS and it worked very well for years.
    Now I am going to use the AD9912 DDS and I will like to calculate or to have the magic number to control it : the ref clock is 100 MHz internally multiplied by 10 so the real ref should be 1 GHz. I am using PBP 2.50 and longs.
    I understand that the 9912 has a 48 bit tuning word (FTW): what will be the limitations in this case ?
    Thanks in advance for any assistance .
    regards,
    Ambrogio
    iw2fvo

  6. #6
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    Hi,
    The AD9912 datasheet says: FTW = 2^48 * (fdds / 1GHz) where fdds is the desired frequency and 1GHz is the reference clock.
    As per the Wiki example for the AD9850, but with these numbers instead, you calculate 2^48/1GHz=281475 which is what I believe is the "magic number" you're referring to.

    So, FTW = fdds * 281475 which we can verify against the example in the datasheet:
    19,440,000 * 281475 = 5471874000000 which in reality would result in a frequency 1.6085Hz higher than ideal due to 2^48/1GHz not being exactly 281475. Does it matter? That's up to you.

    Now, LONGS are "only" 32 bits so what's the highest frequency possible? Well, 2^32/281475=15258.788Hz.

    Since the ** operator, when used with LONGs, results in an 48bit wide intermediate result I would guess we could use some trickery and retrieve all 48 bits directly but I don't have time to play around with that right now.

    /Henrik.

  7. #7
    Join Date
    Jun 2008
    Location
    Varese , Italy
    Posts
    326


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    Thanks Henrik for the kind reply on the matter.
    On the AD9850 the FTW is computed by the following : FTW = Frequency ** 2251800.
    I call magic number the " 2251800" constant.
    What will be the constant for the ad9912 DDS?
    How could I determine the frequency limitation due to the longs .. etc ?
    Thanks again for the assistance.
    Regards,
    Ambrgio
    iw2fvo

  8. #8
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    Did you READ my previous reply?

  9. #9
    Join Date
    Jun 2008
    Location
    Varese , Italy
    Posts
    326


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    sorry Henrik:
    I do not want you to hurry at all.
    Just in case you will have time ... it will be very interesting result for all members of the radio hams club here.
    thanks for all again
    regards,
    iw2fvo

  10. #10
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    I enjoyed your article, Henrik, but I'm shocked at the processing overhead. I wrote and tested a simple calc_ftw() function in XC8, really not much more than a basic 32x32 multiplication routine, and I was wondering if something similar would be worth implementing in PBP?

    Cheerful regards, Mike

    Code:
       unsigned char ftw[8];            // ftw calculation array
    
    
    /************************************************************************
     *  Calculate AD9850 'FTW' (Frequency Tuning Word)                      *
     *                                                                      *
     *  The 32-bit 'f' input is frequency*100 (0.01-Hz resolution) which    *
     *  allows scaling the DDS constant up to 32-bits.  Multiply the two    *
     *  32-bit terms and divide the 64-bit result by 2^32 (use the upper    *
     *  four bytes) for the 32-bit 'FTW'.                                   *
     *                                                                      *
     *  FTW * 2^32 = freq*100 * 2^32/RefClk*2^32/100                        *
     *  FTW * 2^32 = freq*100 * 1475739526                                  *
     *                                                                      *
     *  Fitting the frequency*100 value into a 32-bit variable makes our    *
     *  upper frequency limit ~42,949,672.95-Hz.                            *
     *                                                                      *
     *  --- target --  ---- ftw ----  --- actual --                         *
     *  42,949,672.00  1,475,739,493  42,949,672.00   764 cycles            *
     *  37,000,000.00  1,271,310,320  37,000,000.01   764  "                *
     *  25,000,000.00    858,993,459  24,999,999.99   764  "                *
     *  10,000,000.00    343,597,384  10,000,000.01   764  "                *
     *   1,000,000.00     34,359,738     999,999.99   764  "                *
     *     125,000.00      4,294,967     124,999.99   764  "                *
     *      10,000.00        343,597       9,999.99   764  "                *
     *                                                                      *
     *  XC8 example                        (50 words, <1000 cycles)         *
     ************************************************************************/
    
       void calcFTW(unsigned long f)    // calculate AD9850 32-bit "FTW"
       { long c = 1475739526;           // the "constant" term
         asm("movlb   _ftw/128      "); // bank 0                           |00
         asm("clrf    _ftw+0        "); // clear FTW array                  |00
         asm("clrf    _ftw+1        "); //  "                               |00
         asm("clrf    _ftw+2        "); //  "                               |00
         asm("clrf    _ftw+3        "); //  "                               |00
         asm("clrf    _ftw+4        "); //  "                               |00
         asm("clrf    _ftw+5        "); //  "                               |00
         asm("clrf    _ftw+6        "); //  "                               |00
         asm("clrf    _ftw+7        "); //  "                               |00
         asm("bsf     _ftw+3,7      "); // loop count (32 iterations)       |00
     /*                                                                     *
      *  multiply 32-bit freq*100 value by our 32-bit "constant" and use    *
      *  the upper 32-bits of the 64-bit result ftw[4..7] as the "FTW".     *
      *                                                                     */
         asm("mult32x32:            "); //
      // asm("rrf     calcFTW@c+0,W "); // preserve 'constant" variable     |00
         asm("rrf     calcFTW@c+3,F "); // constant uh                      |00
         asm("rrf     calcFTW@c+2,F "); // constant ul                      |00
         asm("rrf     calcFTW@c+1,F "); // constant hi                      |00
         asm("rrf     calcFTW@c+0,F "); // constant lo                      |00
         asm("skipc                 "); //                                  |00
         asm("bra     nextbit       "); //                                  |00
         asm("movf    calcFTW@f+0,W "); // frequency lo                     |00
         asm("addwf   _ftw+4,F      "); //                                  |00
         asm("movf    calcFTW@f+1,W "); // frequency hi                     |00
         asm("addwfc  _ftw+5,F      "); //                                  |00
         asm("movf    calcFTW@f+2,W "); // frequency ul                     |00
         asm("addwfc  _ftw+6,F      "); //                                  |00
         asm("movf    calcFTW@f+3,W "); // frequency uh                     |00
         asm("addwfc  _ftw+7,F      "); //                                  |00
         asm("nextbit:              "); //                                  |00
         asm("rrf     _ftw+7,F      "); //                                  |00
         asm("rrf     _ftw+6,F      "); //                                  |00
         asm("rrf     _ftw+5,F      "); //                                  |00
         asm("rrf     _ftw+4,F      "); //                                  |00
         asm("rrf     _ftw+3,F      "); //                                  |00
         asm("rrf     _ftw+2,F      "); //                                  |00
         asm("rrf     _ftw+1,F      "); //                                  |00
         asm("rrf     _ftw+0,F      "); //                                  |00
         asm("skipc                 "); // done? yes, skip, else            |00
         asm("bra     mult32x32     "); //                                  |00
         asm("movlw   0x80          "); // rounding...                      |00
         asm("addwf   _ftw+3,W      "); //  "                               |00
         asm("movlw   0             "); //  "                               |00
         asm("addwfc  _ftw+4,F      "); //  "                               |00
         asm("addwfc  _ftw+5,F      "); //  "                               |00
         asm("addwfc  _ftw+6,F      "); //  "                               |00
         asm("addwfc  _ftw+7,F      "); //  "                               |00
       }

  11. #11
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    Here's a slightly optimized version of the AD9850 calcFTW() function (XC8) from the previous post. This version is smaller and nearly 100 cycles faster weighing in at 42 words and 665 cycles.

    I hope someone can take advantage of it and turn it into a PBP function.


    Code:
       unsigned long ftw;      // 32-bit Frequency Tuning Word
    
    /************************************************************************
     *  Calculate AD9850 'FTW' (Frequency Tuning Word)      Mike McLaren    *
     *                                                                      *
     *  The 32-bit 'f' input is frequency*100 (0.01-Hz resolution) which    *
     *  allows scaling the DDS constant up to 32-bits.  Multiply the two    *
     *  32-bit terms and divide the 64-bit product by 2^32.  The 32-bit     *
     *  result is the frequency tuning word in the 'ftw' variable.          *
     *                                                                      *
     *  FTW * 2^32 = freq*100 * 2^32/RefClk*2^32/100                        *
     *  FTW * 2^32 = freq*100 * 1475739526                                  *
     *                                                                      *
     *  Fitting the frequency*100 value into a 32-bit variable makes our    *
     *  upper frequency limit ~42,949,672.95-Hz.                            *
     *                                                                      *
     *  --- target --  ---- ftw ----  --- actual --                         *
     *  42,949,672.00  1,475,739,493  42,949,672.00                         *
     *  37,000,000.00  1,271,310,320  37,000,000.01                         *
     *  25,000,000.00    858,993,459  24,999,999.99                         *
     *  10,000,000.00    343,597,384  10,000,000.01                         *
     *   1,000,000.00     34,359,738     999,999.99                         *
     *     125,000.00      4,294,967     124,999.99                         *
     *      10,000.00        343,597       9,999.99                         *
     *                                                                      *
     *  XC8 example                        (42 words, 665 cycles)           *
     ************************************************************************/
    
       void calcFTW(unsigned long f)    // calculate AD9850 32-bit "FTW"
       { long c = 1475739526;           // the "constant" term
         unsigned char n = 32;          //
     /*                                                                     *
      *  multiply 32-bit freq*100 value by our 32-bit "constant" and use    *
      *  the upper 32-bits ('ftw') of the 64-bit result                     *
      *                                                                     */
         asm("mult32x32:            "); //
         asm("clrc                  "); //                                  |00
         asm("btfss   calcFTW@c+0,0 "); //                                  |00
         asm("bra     nextbit       "); //                                  |00
         asm("movf    calcFTW@f+0,W "); // frequency lo                     |00
         asm("addwf   _ftw+0,F      "); //                                  |00
         asm("movf    calcFTW@f+1,W "); // frequency hi                     |00
         asm("addwfc  _ftw+1,F      "); //                                  |00
         asm("movf    calcFTW@f+2,W "); // frequency ul                     |00
         asm("addwfc  _ftw+2,F      "); //                                  |00
         asm("movf    calcFTW@f+3,W "); // frequency uh                     |00
         asm("addwfc  _ftw+3,F      "); //                                  |00
         asm("nextbit:              "); //                                  |00
         asm("rrf     _ftw+3,F      "); //                                  |00
         asm("rrf     _ftw+2,F      "); //                                  |00
         asm("rrf     _ftw+1,F      "); //                                  |00
         asm("rrf     _ftw+0,F      "); //                                  |00
         asm("rrf     calcFTW@c+3,F "); //                                  |00
         asm("rrf     calcFTW@c+2,F "); //                                  |00
         asm("rrf     calcFTW@c+1,F "); //                                  |00
         asm("rrf     calcFTW@c+0,F "); //                                  |00
         asm("decfsz  calcFTW@n,F   "); // done? yes, skip, else            |00
         asm("bra     mult32x32     "); //                                  |00
         asm("movlw   0x80          "); // rounding...                      |00
         asm("addwf   calcFTW@c+3,W "); //  "                               |00
         asm("movlw   0             "); //  "                               |00
         asm("addwfc  _ftw+0,F      "); //  "                               |00
         asm("addwfc  _ftw+1,F      "); //  "                               |00
         asm("addwfc  _ftw+2,F      "); //  "                               |00
         asm("addwfc  _ftw+3,F      "); //  "                               |00
       }
    Last edited by Mike, K8LH; - 17th July 2018 at 08:48.

  12. #12
    Join Date
    May 2013
    Location
    australia
    Posts
    2,379


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    mike you may find this interesting
    www.picbasic.co.uk/forum/showthread.php?t=12433
    Warning I'm not a teacher

  13. #13
    Join Date
    Sep 2009
    Posts
    737


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    Mike,
    It can be almost copy/paste in PBP. I can try to sort details to work in PBP. But I don't understand what is calcFTW@c,@f,@n... Is it just variables declared in function?
    Can you explain?
    Last edited by pedja089; - 19th July 2018 at 10:14.

  14. #14
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    Yes, in XC8 that's how you would address the "local" variables (c, f, and n) using assembly language.

  15. #15
    Join Date
    Sep 2009
    Posts
    737


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    Here it is. It wasn't tested...
    Code:
    ftw var long ; unsigned long ftw;      // 32-bit Frequency Tuning Word
    f var long
    
    ;/************************************************************************
    ; *  Calculate AD9850 'FTW' (Frequency Tuning Word)      Mike McLaren    *
    ; *                                                                      *
    ; *  The 32-bit 'f' input is frequency*100 (0.01-Hz resolution) which    *
    ; *  allows scaling the DDS constant up to 32-bits.  Multiply the two    *
    ; *  32-bit terms and divide the 64-bit product by 2^32.  The 32-bit     *
    ; *  result is the frequency tuning word in the 'ftw' variable.          *
    ; *                                                                      *
    ; *  FTW * 2^32 = freq*100 * 2^32/RefClk*2^32/100                        *
    ; *  FTW * 2^32 = freq*100 * 1475739526                                  *
    ; *                                                                      *
    ; *  Fitting the frequency*100 value into a 32-bit variable makes our    *
    ; *  upper frequency limit ~42,949,672.95-Hz.                            *
    ; *                                                                      *
    ; *  --- target --  ---- ftw ----  --- actual --                         *
    ; *  42,949,672.00  1,475,739,493  42,949,672.00                         *
    ; *  37,000,000.00  1,271,310,320  37,000,000.01                         *
    ; *  25,000,000.00    858,993,459  24,999,999.99                         *
    ; *  10,000,000.00    343,597,384  10,000,000.01                         *
    ; *   1,000,000.00     34,359,738     999,999.99                         *
    ; *     125,000.00      4,294,967     124,999.99                         *
    ; *      10,000.00        343,597       9,999.99                         *
    ; *                                                                      *
    ; *  XC8 example                        (42 words, 665 cycles)           *
    ; ************************************************************************/
    
    calcFTW: ;   void calcFTW(unsigned long f)    // calculate AD9850 32-bit "FTW"
    ;   { long c = 1475739526;           // the "constant" term
    ;     unsigned char n = 32;          //
    	c VAR LONG : C=1475739526    
    	n VAR BYTE : n=32
    ; /*                                                                     *
    ;  *  multiply 32-bit freq*100 value by our 32-bit "constant" and use    *
    ;  *  the upper 32-bits ('ftw') of the 64-bit result                     *
    ;  *                                                                     */
    ASM
    mult32x32:            ; //
     BCF STATUS,C ; clrc                  ; //                                  |00
     btfss   _c+0,0 ; //                                  |00
     bra     nextbit       ; //                                  |00
     movf    _f+0,W ; // frequency lo                     |00
     addwf   _ftw+0,F      ; //                                  |00
     movf    _f+1,W ; // frequency hi                     |00
     addwfc  _ftw+1,F      ; //                                  |00
     movf    _f+2,W ; // frequency ul                     |00
     addwfc  _ftw+2,F      ; //                                  |00
     movf    _f+3,W ; // frequency uh                     |00
     addwfc  _ftw+3,F      ; //                                  |00
    nextbit:              ; //                                  |00
     RRCF      _ftw+3,F      ; //                                  |00
     RRCF      _ftw+2,F      ; //                                  |00
     RRCF      _ftw+1,F      ; //                                  |00
     RRCF      _ftw+0,F      ; //                                  |00
     RRCF      _c+3,F ; //                                  |00
     RRCF      _c+2,F ; //                                  |00
     RRCF      _c+1,F ; //                                  |00
     RRCF      _c+0,F ; //                                  |00
     decfsz  _n,F   ; // done? yes, skip, else            |00
     bra     mult32x32     ; //                                  |00
     movlw   0x80          ; // rounding...                      |00
     addwf   _c+3,W ; //  "                               |00
     movlw   0             ; //  "                               |00
     addwfc  _ftw+0,F      ; //  "                               |00
     addwfc  _ftw+1,F      ; //  "                               |00
     addwfc  _ftw+2,F      ; //  "                               |00
     addwfc  _ftw+3,F      ; //  "                               |00
     ENDASM;   }
    Return
    clrc and rrf are pseudo instruction from XC8. So I replaced it with real instruction.

    Usage:

    F=123 : Call calcFTW
    result is in ftw

  16. #16
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    Very interesting. Thank you. I'm not a PBP user so I had no idea inserting an assembly code function into a PBP program was that easy.

    I suspect you're coding for an 18F which has RRCF and RRNCF instructions where my example was for an "enhanced mid-range" 16F1823 device which has slightly different RRF, ASRF, and LSRF instructions. Hopefully, those 16F instructions are supported in PBP. Also, when using assembly language, careful attention to banking is required. I found XC8 assigned the 'ftw' variable in Bank 0 RAM and the other variables were assigned in the "common" 0x70..0x7F area.

    One might conclude that implementing an assembly language method in a program could save hundreds of words of program memory and thousands of instruction cycles processing time but it also requires careful attention to detail and environment.

    Hopefully, someone may be able to take advantage of a similar method in their PBP AD9850/AD9851 or Si5351 Digital VFO project.

    Cheerful regards, Mike, K8LH
    Last edited by Mike, K8LH; - 20th July 2018 at 17:53.

  17. #17
    Join Date
    Sep 2009
    Posts
    737


    Did you find this post helpful? Yes | No

    Default Re: Calculate tuning value for the AD9850 DDS.

    I use 18F for 99% of my project. So by default i go to 18F ASM. Also pbp for 16F doesn't support long variables(because of large overhead, but in my opinion it should).

    You are right, but I put all variables used in ASM into BANKA. So you dont need banking, at all. I forgot to do that here.
    Here is corrected version.
    Code:
    ftw var long ; unsigned long ftw;      // 32-bit Frequency Tuning Word
    f var long BANKA
    
    ;/************************************************************************
    ; *  Calculate AD9850 'FTW' (Frequency Tuning Word)      Mike McLaren    *
    ; *                                                                      *
    ; *  The 32-bit 'f' input is frequency*100 (0.01-Hz resolution) which    *
    ; *  allows scaling the DDS constant up to 32-bits.  Multiply the two    *
    ; *  32-bit terms and divide the 64-bit product by 2^32.  The 32-bit     *
    ; *  result is the frequency tuning word in the 'ftw' variable.          *
    ; *                                                                      *
    ; *  FTW * 2^32 = freq*100 * 2^32/RefClk*2^32/100                        *
    ; *  FTW * 2^32 = freq*100 * 1475739526                                  *
    ; *                                                                      *
    ; *  Fitting the frequency*100 value into a 32-bit variable makes our    *
    ; *  upper frequency limit ~42,949,672.95-Hz.                            *
    ; *                                                                      *
    ; *  --- target --  ---- ftw ----  --- actual --                         *
    ; *  42,949,672.00  1,475,739,493  42,949,672.00                         *
    ; *  37,000,000.00  1,271,310,320  37,000,000.01                         *
    ; *  25,000,000.00    858,993,459  24,999,999.99                         *
    ; *  10,000,000.00    343,597,384  10,000,000.01                         *
    ; *   1,000,000.00     34,359,738     999,999.99                         *
    ; *     125,000.00      4,294,967     124,999.99                         *
    ; *      10,000.00        343,597       9,999.99                         *
    ; *                                                                      *
    ; *  XC8 example                        (42 words, 665 cycles)           *
    ; ************************************************************************/
    
    calcFTW: ;   void calcFTW(unsigned long f)    // calculate AD9850 32-bit "FTW"
    ;   { long c = 1475739526;           // the "constant" term
    ;     unsigned char n = 32;          //
    	c VAR LONG BANKA : C=1475739526    
    	n VAR BYTE BANKA : n=32
    ; /*                                                                     *
    ;  *  multiply 32-bit freq*100 value by our 32-bit "constant" and use    *
    ;  *  the upper 32-bits ('ftw') of the 64-bit result                     *
    ;  *                                                                     */
    ASM
    mult32x32:            ; //
     BCF STATUS,C ; clrc                  ; //                                  |00
     btfss   _c+0,0 ; //                                  |00
     bra     nextbit       ; //                                  |00
     movf    _f+0,W ; // frequency lo                     |00
     addwf   _ftw+0,F      ; //                                  |00
     movf    _f+1,W ; // frequency hi                     |00
     addwfc  _ftw+1,F      ; //                                  |00
     movf    _f+2,W ; // frequency ul                     |00
     addwfc  _ftw+2,F      ; //                                  |00
     movf    _f+3,W ; // frequency uh                     |00
     addwfc  _ftw+3,F      ; //                                  |00
    nextbit:              ; //                                  |00
     RRCF      _ftw+3,F      ; //                                  |00
     RRCF      _ftw+2,F      ; //                                  |00
     RRCF      _ftw+1,F      ; //                                  |00
     RRCF      _ftw+0,F      ; //                                  |00
     RRCF      _c+3,F ; //                                  |00
     RRCF      _c+2,F ; //                                  |00
     RRCF      _c+1,F ; //                                  |00
     RRCF      _c+0,F ; //                                  |00
     decfsz  _n,F   ; // done? yes, skip, else            |00
     bra     mult32x32     ; //                                  |00
     movlw   0x80          ; // rounding...                      |00
     addwf   _c+3,W ; //  "                               |00
     movlw   0             ; //  "                               |00
     addwfc  _ftw+0,F      ; //  "                               |00
     addwfc  _ftw+1,F      ; //  "                               |00
     addwfc  _ftw+2,F      ; //  "                               |00
     addwfc  _ftw+3,F      ; //  "                               |00
     ENDASM;   }
    Return

Similar Threads

  1. OSCTUNE Tuning range
    By MikeBZH in forum Schematics
    Replies: 3
    Last Post: - 8th June 2009, 06:54
  2. Need help in controlling DDS AD9850/51
    By vu2iia in forum mel PIC BASIC Pro
    Replies: 4
    Last Post: - 7th March 2007, 13:40
  3. RF video reciever - digital tuning
    By RYTECH in forum Schematics
    Replies: 13
    Last Post: - 15th September 2006, 01:05
  4. calculate with date
    By Pedro Pinto in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 14th October 2005, 17:49
  5. iButton CRC-8 Calculate
    By Pesa in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 4th May 2005, 10:05

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts