⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 si57x_freqprogfirmware_withf300.c

📁 C8051F300 & Si57x ANSI C Reference Design
💻 C
📖 第 1 页 / 共 3 页
字号:
	// of the valid HS_DIV values from the datasheet.

	// initial_n1 conversion
	initial_n1 = (( reg[0] & 0x1F ) << 2 ) + // get reg 7 bits 0 to 4 
		 (( reg[1] & 0xC0 ) >> 6 );  // add with reg 8 bits 7 and 8

	if(initial_n1 == 0) 
	{
		initial_n1 = 1;
	}
	else if(initial_n1 & 1 != 0) 
	{ 
		// add one to an odd number 
		initial_n1 = initial_n1 + 1;
	}

	// (old method) RFREQ conversion (reconstruct the fractional portion (bits 0 to 28) from the registers)
	// this method requires double precision floating point data type to be accurate
/*	frac_bits = (( reg[2] & 0xF ) * POW_2_24 ); 
	frac_bits = frac_bits + (reg[3] * POW_2_16);
	frac_bits = frac_bits + (reg[4] * 256);
	frac_bits = frac_bits + reg[5];

	rfreq = frac_bits; 
    rfreq = rfreq / POW_2_28;
*/
	// (new method) RFREQ conversion using unsigned long when only a single precision floating point data type is available
	initial_rfreq_long = ( reg[1] & 0x3F );
	initial_rfreq_long = (initial_rfreq_long << 8) + ( reg[2] );
	initial_rfreq_long = (initial_rfreq_long << 8) + ( reg[3] );
	initial_rfreq_long = (initial_rfreq_long << 8) + ( reg[4] );
	initial_rfreq_long = (initial_rfreq_long << 6) + ( reg[5] >> 2 ); //ignore lowest two bits to fit into long
	
	// (old method)  RFREQ conversion (reconstruct the integer portion from the registers)
	rfreq = rfreq + 
	        ( (( reg[1] & 0x3F ) << 4 ) + 
			  (( reg[2] & 0xF0 ) >> 4 ) );

	// (old method) crystal frequency (fxtal) calculation -- new method avoids this conversion to save precision
	fxtal = (fout0 * initial_n1 * initial_hsdiv) / rfreq; //MHz
}
	
//
// Program the next frequency in the list
//
void RunFreqProg()
{
	float ratio = 0;


	currentFrequency = fout1[currFreq];

	// find dividers (get the max and min divider range for the HS_DIV and N1 combo)
	divider_max = floorf(FDCO_MAX / fout1[currFreq]); 		//floorf for SDCC
	curr_div = ceilf(FDCO_MIN / fout1[currFreq]); 			//ceilf for SDCC
	validCombo = 0;			

	while (curr_div <= divider_max) 
	{
		//check all the HS_DIV values with the next curr_div
		for(counter=0; counter<6; counter++)
		{
			// get the next possible n1 value
			hsdiv = HS_DIV[counter];
			curr_n1 = (curr_div * 1.0) / (hsdiv * 1.0);

			// determine if curr_n1 is an integer and an even number or one
			// then it will be a valid divider option for the new frequency	
			n1_tmp = floorf(curr_n1);
			n1_tmp = curr_n1 - n1_tmp;
			if(n1_tmp == 0.0)
			{ 
				//then curr_n1 is an integer
				n1 = (unsigned char) curr_n1;	
							
				if( (n1 == 1) || ((n1 & 1) == 0) ) 
				{ 
					// then the calculated N1 is either 1 or an even number
					validCombo = 1;
				}
			}
			if(validCombo == 1) break;
		}
		if(validCombo == 1) break;
		//increment curr_div to find the next divider
		//since the current one was not valid
		curr_div = curr_div + 1;
	}

	// if(validCombo == 0) at this point then there's an error 
	// in the calculatio. Check if the provided fout0 and fout1 
	// are not valid frequencies

	// (old method) new RFREQ calculation -- kept for comparison purposes
	rfreq = (fout1[currFreq] * n1 * hsdiv) / fxtal; 				//using float
		
	// (new method) calculate RFREQ organizing the float variables to save precision; 
	//  RFREQ is kept as an unsigned long
	//  only 32 bits are available in the long format 
	//  RFREQ in the device has 34 bits of precision
	//  only 34 of the 38 bits are needed since RFREQ is between 42.0 and 50.0 for fxtal of 114.285MHz (nominal)
	ratio = fout1[currFreq] / fout0;								// try to keep ration near 1 to maintain precision
	ratio = ratio * ((1.0 * n1)/(1.0 * initial_n1));
	ratio = ratio * ((1.0 * hsdiv)/(1.0 * initial_hsdiv));
	final_rfreq_long = ratio * initial_rfreq_long;			//using alternative method (unsigned long)	

	for(counter = 0; counter < 6; counter++)
	{
		reg[counter] = 0; //clear registers
	}	

	// new HS_DIV conversion
	hsdiv = hsdiv - 4;
	//reset this memory
	reg[0] = 0; 
	//set the top 3 bits of reg 13
	reg[0] = (hsdiv << 5); 


	// convert new N1 to the binary representation
	if(n1 == 1) n1 = 0;
	else if((n1 & 1) == 0) n1 = n1 - 1; //if n1 is even, subtract one	

	// set reg 7 bits 0 to 4
	reg[0] = SetBits(reg[0], 0xE0, n1 >> 2);
	// set reg 8 bits 6 and 7
	reg[1] = (n1 & 3) << 6;	

	// (new method) load new RFREQ into register map
	reg[1] = reg[1] | (((final_rfreq_long >> 10) >> 10) >> 10); //SDCC does not like to shift by more than ~12
	reg[2] = ((final_rfreq_long >> 11) >> 11);
	reg[3] = ((final_rfreq_long >> 7) >> 7);
	reg[4] = final_rfreq_long >> 6;
	reg[5] = final_rfreq_long << 2;

/*
	// (old method)
	// convert new RFREQ to the binary representation
	// separate the integer part
	whole = floorf(rfreq); 

	// get the binary representation of the fractional part
	frac_bits = floorf((rfreq - whole) * POW_2_28);	

	// set reg 12 to 10 making frac_bits smaller by 
	// shifting off the last 8 bits everytime
	for(counter=5; counter >=3; counter--)
	{
		reg[counter] = frac_bits & 0xFF;
		frac_bits = frac_bits >> 8;
	}
	// set the last 4 bits of the fractional portion in reg 9
	reg[2] = SetBits(reg[2], 0xF0, (frac_bits & 0xF));	

	// set the integer portion of RFREQ across reg 8 and 9
	reg[2] = SetBits(reg[2], 0x0F, (whole & 0xF) << 4);
	reg[1] = SetBits(reg[1], 0xC0, (whole >> 4) & 0x3F);
*/

	// Load the new frequency
	// get the current state of register 137
	reg137 = I2C_ByteRead(137);
	// set the Freeze DCO bit in that register
	I2C_ByteWrite(137, reg137 | 0x10); 

	// load the new values into the device at registers 7 to 12; this MCU code only supports single I2C address writes
	for(counter=0; counter<6; counter++)
	{
		I2C_ByteWrite(counter+7, reg[counter]); 
	}

	// get the current state of register 137
	reg137 = I2C_ByteRead(137);
	// clear the FZ_DCO bit in that register
	I2C_ByteWrite(137, reg137 & 0xEF); 
	// set the NewFreq bit, bit will clear itself once the device is ready
	I2C_ByteWrite(135, 0x40);
}

unsigned char SetBits(unsigned char original, unsigned char reset_mask, unsigned char new_val)
{
	return (( original & reset_mask ) | new_val );
}


//-----------------------------------------------------------------------------
// Initialization Routines
//-----------------------------------------------------------------------------


void Peripheral_Config(void){
   unsigned char i;                    // Temporary counter variable

   PCA0MD &= ~0x40;                    // WDTE = 0 (disable watchdog timer)

   // Set internal oscillator to highest
   // setting of 24500000
   OSCICN |= 0x03;

   // If slave is holding SDA low because of an improper SMBus reset or error
   while(!SDA)
   {
      // Provide clock pulses to allow the slave to advance out
      // of its current state. This will allow it to release SDA.
      XBR1 = 0x40;                     // Enable Crossbar
      SCL = 0;                         // Drive the clock low
      for(i = 0; i < 255; i++);        // Hold the clock low
      SCL = 1;                         // Release the clock
      while(!SCL);                     // Wait for open-drain
                                       // clock output to rise
      for(i = 0; i < 10; i++);         // Hold the clock high
      XBR1 = 0x00;                     // Disable Crossbar
   }

   Port_Initializer ();                // Initialize Crossbar and GPIO

   CKCON = 0x10;                       // Timer 1 is sysclk
                                       // Timer 2 is sysclk/12 (see TMR2CN)

   Timer1_Init ();                     // Configure Timer1 for use as SMBus
                                       // clock source

   Timer2_Init ();                     // Configure Timer2 for use with SMBus
                                       // low timeout detect

   SMBus_Init ();                      // Configure and enable SMBus                                

   IP        |= 0x01;
   EIE1      |= 0x01;					//enable SMBus interrupt
   IT01CF    |= 0x07; //0x03;
   IE        |= 0x81;
   TCON      |= 0x01;					// Enable INT0 to be edge sensitive
   EA = 1;								// Global interrupt enable  ****MUST BE LAST****
}



//-----------------------------------------------------------------------------
// SMBus_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// The SMBus peripheral is configured as follows:
// - SMBus enabled
// - Slave mode disabled
// - Timer1 used as clock source. The maximum SCL frequency will be
//   approximately 1/3 the Timer1 overflow rate
// - Setup and hold time extensions enabled
// - Free and SCL low timeout detection enabled
//
void SMBus_Init (void)
{
   SMB0CF = 0x5D;                      // Use Timer1 overflows as SMBus clock
                                       // source;
                                       // Disable slave mode;
                                       // Enable setup & hold time extensions;
                                       // Enable SMBus Free timeout detect;
                                       // Enable SCL low timeout detect;

   SMB0CF |= 0x80;                     // Enable SMBus;
}


//-----------------------------------------------------------------------------
// Timer1_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// Timer1 is configured as the SMBus clock source as follows:
// - Timer1 in 8-bit auto-reload mode
// - SYSCLK / 12 as Timer1 clock source
// - Timer1 overflow rate => 3 * SMB_FREQUENCY
// - The maximum SCL clock rate will be ~1/3 the Timer1 overflow rate
// - Timer1 enabled
//

void Timer1_Init (void){
// Make sure the Timer can produce the appropriate frequency in 8-bit mode
// Supported SMBus Frequencies range from 10kHz to 100kHz.  The CKCON register
// settings may need to change for frequencies outside this range.
   TMOD = 0x20;                               // Timer1 in 8-bit auto-reload mode
   //CKCON |= 0x10;                             // Timer1 clock source = SYSCLK
   TH1 = 0xFF - (SYSCLK/SMB_FREQUENCY/3) + 1; // 100kHz or 400kHz for SCL
   TL1 = TH1;                                 // Init Timer1
   TR1 = 1;                                   // Timer1 enabled
}

//-----------------------------------------------------------------------------
// Timer2_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// Timer2 configured for Si57x reset delay as
// follows:
// - Timer2 in 16-bit auto-reload mode
// - SYSCLK/12 as Timer2 clock source
// - Timer2 reload registers loaded for RESET_DELAY_TIME overflow

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -