Can this be calculated wo. using double ?

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Guyzz

I have bought a 10.00000000000(Lots'o Zeroes) Mhz Rubidium Freq Reference (Ehh... Doesn't one have to have one ??).

The Rubidium Oscillates around 50Mhz , and there is an AD9830A DDS chip that can divide/adjust the output frequency.

The AD9830A is controlled by a ... "MCU who's name must not be mentioned" or we have to call for "Harry" & hope Leon doesn't read this :-).

Basically there is an RS-232 connection to the MCU , and you can put in a frequency divider word that the MCU writes to the DDS.

I'd like to build it into a box w. a keypad & a LCD, and use an AVR to calc the word and send it via rs232 to the "Dark MCU"

But if i can't get enough precision in the calculations , i'll loose a lot of the above "zeroes".

Some guy made this example in C , and he uses a lot of doubles. But i wonder if this can be made in Integer arithmetik on an AVR , or if i'll have to download another compiler and keep my fingers crossed that this fit's in an eval version.

Quote:
I had to replace percent with paragraph § , or Freaks .. Freaked out :-(

So the printf's are formatted funny


/*
Attached is my program for calculating the frequency divisor words for the FEI 
FE-5650A and FE-5680A rubidium oscillators with the AD9830A based DDS board.  
It compensates for the difference between the R=reference freq that the 'S' 
command returns (the minimum C-field value) and the frequency that the 
oscillator was actually shipped tuned to.

The program does not actually read and write the serial port directly (would be 
a nice mod though).  You will need to recompile it with the values returned by 
your oscillator 'S' command.  There are two #defines at the start of the 
program.

Usage is:
freq 10        (for 10Hz)
freq 10 K     (for 10KHz)
freq 10 M    (for 10MHz)
*/

#include "stdio.h"
#include "math.h"
#include "string.h"

//  This program calculates the Analog Devices 9830A DDS frequency divisor
//  values for programming the FEI FE-5650A and FE-5680A rubidium oscillator
//  units.
//
//  This program was written by Mark S Sims  May 2008.  It is relased to the
//  public domain.  Use it in peace.  Plase share with others what you do
//  with it.
//

// These are the reference freq and divisors returned by the FEI "S" command
// They vary from unit to unit.  Change these to whatever your unit returns (or
// modify this program to interrogate the unit with the "S" command.  While you
// are at it,  modify this program to send the divisor word to the oscillator.
//
#define R  50255055.011982
#define F  0x2ABB5050L

#define FF ((double) 8388608.0)      // the freq the module was calibrated for
#define M  ((double) 4294967296.0)   // 2^32

double r=R;    // working reference frequency
double f=FF;   // working DDS divisor word


void lll(double x)
{  // print divisor as a 64 bit hex value
char s[20];
int i;

   for(i=0; i<16; i++) s[i] = 0;
   i = 0;

   x = x * M * M;
   while(x>0.99) {
      s[i++] = fmod(x, 16);
      if(i > 16) break;
      x = x / 16.0;
   }

   for(i=15; i>=0; i--) {
      printf("§X", s[i]);
      if(i == 8) printf(":");
   }
   printf("\n\n");
}

main(int argc, char *argv[])
{
double d;
double x;

   if(argc > 1) {  // get desired freq from command line
      sscanf(argv[1], "§lf", &f);
      if(argc > 2) {  // if more than one command line arg,  freq is in MHz or KHz
         if(toupper(argv[2][0]) == 'K') f *= (double) 1000.0;
         else if(toupper(argv[2][0]) == 'H') f *= (double) 1.0;
         else f *= (double) 1000000.0;
      }
      else if(strchr(argv[1], 'K')) f *= (double) 1000.0;
      else if(strchr(argv[1], 'k')) f *= (double) 1000.0;
      else if(strchr(argv[1], 'M')) f *= (double) 1000000.0;
      else if(strchr(argv[1], 'm')) f *= (double) 1000000.0;
   }

   // print input data values
   printf("\nR=§19.10lf  F=§08lX   (f=§lf)\n\n",  R,F,FF);

   // calculate what freq the R= and F= values returned from the
   // oscillator would produce
   d = ((double) F) / M;
   d *= r;
   printf("R*F/(2^32)=§19.10lf  ref_scale=§.14lf\n", d, FF/d);

   // scale the R= reference freq by that value to get the actual
   // oscillator reference freq
   r = r * FF / d;
   printf("actual ref=§.10lf\n\n", r);

   // show what the 64 bit DDS divisor should be
   printf("freq=§.10lf\n\n", f);
   d = f / r;
   printf("freq/ref=§.19lf\n", d);

   printf("full divisor=");
   lll(d);


   // calculate the closest 32 bit divisor that the AD9830A DDS chip
   // will actually use
   d *= M;
   d = (double) (unsigned long) (d+0.5);


   // now show the actual generated frequency and the two closest ones
   x = r * (long) (d-1);
   x /= M;
   printf("freq(§08lX) = §.10lf  err=§13.10lf (§.3lg)\n", (long)d-1, x,  x-f, (x-f)/f);

   x = r * (long) d;
   x /= M;
   printf("freq(§08lX) = §.10lf  err=§13.10lf (§.3lg)\n", (long)d, x,  x-f, (x-f)/f);

   x = r * (long) (d+1);
   x /= M;
   printf("freq(§08lX) = §.10lf  err=§13.10lf (§.3lg)\n", (long)d+1, x,  x-f, (x-f)/f);

   printf("\n");
   printf("nearest divisor=§08lX\n", (unsigned long) d);

  system("PAUSE");	
  return 0;   
}

/Bingo

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You should look at it the other way round ;)
The DDS only have a 32 Bit counter, so make the calc. so your result have that "kind" of accuracy any thing better would be a overkill.

Jens

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you send integer register values to the Dark MCU or do you send floating-point frequency values?

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For a similar DDS application I have written
a set of "long-integer" routines just to
convert a long decimal number (ascii-string)
into binary and do a long-division with many
fractional digits in the result for setting a DDS.

So it can be done without double.

But this package is not well documented :shock: .

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@Jens
I know it's only 32bit , but i have to watch out for overflow/rounging err's.

@Jim
I send the 32bit Hex divider value in "Ascii Hex"

@Ossi
I'll have a look at uint64_t (Jörg also suggested that)

Thanx guyzz

/Bingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I thought y'all had long-long in your bag of tricks. That is about 20 decimal digits.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.