unsigned char I2C_adr;
unsigned char byte_adr=7;
unsigned char SI570_data[6];

#define _2(x) (1UL << x)
#define f_min (4850*_2(19))	//min VCO frequency 4850 MHz*2^19
#define f_max (5670*_2(19))	//max VCO frequency 5670 MHz*2
#define f_av  (5260*_2(19))	//average VCO frequency
#define f freq.qw			//desired frequency
#define RFREQ rfreq._.w1_4	//upper 30 bits
#define _RFREQ rfreq._.w0	//lower 8 bits
#define fcryst fcr.qw

union 
{
unsigned long qw;
unsigned char bytes[4];
}freq,fcr;						//frequency [MHz]*2^21, crystal frequency [MHz]*2^24
							


struct char_long
{
unsigned char w0;
unsigned long w1_4;
};

union 
{
struct char_long _;
unsigned char w[5];
}rfreq; 							//make 38 RFREQ bits accessible in different ways

unsigned char	N;					//slow divider 
unsigned char	HS_DIV;				//fast divider 
unsigned long   debug;

unsigned char SI570CalcRegs(void){	//calculates SI570 registers from frequency*2^21, 34000clocks = 2ms required
unsigned long x;
unsigned long vco;					//VCO frequency [MHz]*2^19
unsigned long N0;
unsigned char valid=0;
uint16_t _N;
unsigned char _HS_DIV;
unsigned char i,d;
	vco=f_max;
	N0=f_av/(f/8); 					//(f/2/4): last binary digit is 0.5 digit for rounding, note different scalings of f and f_av
	_HS_DIV=11;
	while (_HS_DIV>3)
		{
		_N=(uint16_t)N0/_HS_DIV;	//last digit of N is 0.5 digit for rounding
		_N=(_N+1)>>1;				//rounded to the nearest integer 
		if (_N>2) _N&=0xFE;			//N=1 or even
		if (_N>128) _N=128;			//N<=2^7
		if (_N!=1)					//calculate VCO frequency for these divider values, avoid overflows
			{						//better numerical accuracy, when cases are handled separately	
			x=f/2;					//f needs to be divided by 4 due to different scaling
			x=x*_HS_DIV;	
			x=x*(_N/2);				//_N even here
			}
		else
			{
			x=f/4;					
			x=x*_HS_DIV;
			}
		if ((x>=f_min)&(x<=vco))	//find best divider values with vco smallest but still alowed
		    {
			valid=1;
			vco=x;
			N=_N;
			HS_DIV=_HS_DIV;
			}

		_HS_DIV--;
		if ((_HS_DIV==10)|(_HS_DIV==8)) _HS_DIV--;	//skip unavailable divider ratios
		}
	if (valid>0)
		{
		////////////////debug	
		debug=vco/_2(19);
		////////////////debug ende
		N=N-1;						//convert divider ratio to SI570 register value
		HS_DIV=HS_DIV-4;			//convert divider ratio to SI570 register value
		RFREQ=0;					//higher 30 bit
		_RFREQ=0;					//lower 8 bit
		for (i=1;i<=34;i++)			//34 bit division RFREQ=vco/fcryst. Note that RFREQ only has 34 bits !=0
			{
			d=vco/fcryst;
			if (i<=26) RFREQ=(RFREQ<<1)+d;
			else _RFREQ=(_RFREQ<<1)+d;
			vco=(vco-d*fcryst)<<1;
			}
		for (i=5;i>=1;i--)
			{
			SI570_data[i]=rfreq.w[5-i];
			}
		SI570_data[1]=(SI570_data[1] & 0x3f)|(N<<6);
		SI570_data[0]=(N>>2) | (HS_DIV<<5);
		}							//division done
	return(valid);					//return 1 if valid register content found, else 0
}


void SI570_freezeNCO(void)
{
I2CSendStart();					
I2CSendByte(I2C_adr<<1);	    // send device address 
I2CSendByte(137);			    // send Byte address 137
I2CSendByte(0x10);	    		// send freeze cmd 0x10
I2CSendStop();
}

void SI570_unfreezeNCO(void)
{
I2CSendStart();					
I2CSendByte(I2C_adr<<1);	    // send device address 
I2CSendByte(137);			    // send Byte address 137
I2CSendByte(0x00);	    		// send unfreeze cmd 0x00
I2CSendStop();
}

void SI570_Load(void)
{
uchar i;
    SI570_freezeNCO();
	I2CSendStart();	
	I2CSendByte((I2C_adr<<1) & 0xFE);	// send device address 
	I2CSendByte(byte_adr);				// send Byte address 
	for (i=0;i<=5;i++)	I2CSendByte(SI570_data[i]);	 // send data 
	I2CSendStop();
	SI570_unfreezeNCO();
	I2CSendStart();	
	I2CSendByte((I2C_adr<<1) & 0xFE);	// send device address 
	I2CSendByte(135);					// send Byte address 
	I2CSendByte(0x40);					// send new frequency available 
	I2CSendStop();
}
