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

📄 si57x_freqprogfirmware_withf300.#1

📁 C8051F300 & Si57x ANSI C Reference Design
💻 #1
📖 第 1 页 / 共 2 页
字号:
//''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
// Copyright 2007 by Silicon Laboratories
// 
// Si57x_FreqProgFirmware_withF300.c
//
// Distributed by: Silicon Laboratories, Inc.
//
// This file contains proprietary information.
// No dissemination allowed without prior written permission
// from Silicon Laboratories, Inc.
//
// Released August 30, 2007
//
//''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
#include <compiler_defs.h>
#include <c8051F300_defs.h>
#include <math.h>                      // Used for the floor() function
//#include <float.h>

//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------

#define USE_I2C                       // enable this if I2C is going to 
                                      // be used to get to the target device

#define DEBUG                         // enable this to run DEBUG code to verify the I2C    

//these must be floating point number especially 2^28 so that
//there is enough memory to use them in the calculation
#define POW_2_16              65536.0
#define POW_2_24           16777216.0
#define POW_2_28          268435456.0


#define SYSCLK            24500000        // System clock frequency in Hz

#define SMB_FREQUENCY     100000          // Target SCL clock rate
                                          // Can be 100kHz or 400kHz

#define RESET_DELAY_TIME  0.015           // time of delay after the Si57x reset in seconds

#define WRITE             0x00            // SMBus WRITE command
#define READ              0x01            // SMBus READ command


#define INTERRUPT_TIMER2    5             // Timer2 Overflow

// Device addresses (7 bits, lsb is a don't care)
#define  DEVICE_ADDR      0x00            // Device address for slave target - only use zero now
                                       
// SMBus Buffer Size
#define  SMB_BUFF_SIZE    0x08            // Defines the maximum number of bytes
                                          // that can be sent or received in a
                                          // single transfer

// Status vector - top 4 bits only
#define  SMB_MTSTA        0xE0            // (MT) start transmitted
#define  SMB_MTDB         0xC0            // (MT) data byte transmitted
#define  SMB_MRDB         0x80            // (MR) data byte received
// End status vector definition

//------------------------------------------------------------------------------------
// conversion and find dividers variables
//------------------------------------------------------------------------------------

// Change the fout0 and fout1 to configure the Si57x
// frequency plan. See datasheet for fout0 and fout1 ranges.
// Both values must be given in MHz.
code const float fout0 = 622.08064;
code const float fout1 = 945.0;

// Si57x's fdco range -- do not edit
code const float FDCO_MAX = 5670; //MHz 
code const float FDCO_MIN = 4850; //MHz

code const unsigned char HS_DIV[6] = {11, 9, 7, 6, 5, 4};

unsigned char reg[6];
unsigned char counter;
unsigned char n1;
unsigned char hsdiv;
unsigned char done = 0;
unsigned char validCombo;
unsigned char reg137;

unsigned int divider_max;
unsigned int curr_div;
unsigned int whole;

unsigned long temp_bits;
unsigned long frac_bits;

float rfreq;
float fxtal;
float curr_n1;
float n1_tmp;

//-----------------------------------------------------------------------------
// Global VARIABLES
//-----------------------------------------------------------------------------
unsigned char* pSMB_DATA_IN;           // Global pointer for SMBus data
                                       // All receive data is written here

unsigned char SMB_SINGLEBYTE_OUT;      // Global holder for single byte writes.

unsigned char* pSMB_DATA_OUT;          // Global pointer for SMBus data.
                                       // All transmit data is read from here

unsigned char SMB_DATA_LEN;            // Global holder for number of bytes
                                       // to send or receive in the current
                                       // SMBus transfer.

unsigned char WORD_ADDR;               // Global holder for the  word
                                       // address that will be accessed in
                                       // the next transfer

unsigned char TARGET;                  // Target SMBus slave address

bit SMB_BUSY = 0;                      // Software flag to indicate when the
                                       // I2C_ByteRead() or
                                       // I2C_ByteWrite()
                                       // functions have claimed the SMBus

bit SMB_RW;                            // Software flag to indicate the
                                       // direction of the current transfer

bit SMB_SENDWORDADDR;                  // When set, this flag causes the ISR
                                       // to send the 8-bit <WORD_ADDR>
                                       // after sending the slave address.


bit SMB_RANDOMREAD;                    // When set, this flag causes the ISR
                                       // to send a START signal after sending
                                       // the word address.                                      
                                       // The ISR handles this
                                       // switchover if the <SMB_RANDOMREAD>
                                       // bit is set.

bit SMB_ACKPOLL;                       // When set, this flag causes the ISR
                                       // to send a repeated START until the
                                       // slave has acknowledged its address

#ifdef DEBUG
sbit LED = P0^2;                       // LED on port P0.2
sbit RESET_TEST_SIGNAL = P0^3;         // toggled when the reset delay is running
#endif

sbit SDA = P0^0;                       // SMBus on P0.0
sbit SCL = P0^1;                       // and P0.1

//-----------------------------------------------------------------------------
// Function PROTOTYPES
//-----------------------------------------------------------------------------

void Peripheral_Config(void);
void SMBus_Init(void);
void Timer1_Init(void);
void Timer2_Init(void);
void Port_Init(void);

void RunFreqProg(void);
unsigned char SetBits(unsigned char original, unsigned char reset_mask, 
                      unsigned char new_val);

void SMBus_ISR(void);
void I2C_ByteWrite(unsigned char addr, unsigned char dat);
unsigned char I2C_ByteRead(unsigned char addr);

//-----------------------------------------------------------------------------
// MAIN Routine
//-----------------------------------------------------------------------------

void main (void){

#ifdef DEBUG  
   unsigned char temp_char;            // Temporary variable
   bit error_flag = 0;                 // Flag for checking device contents
#endif

   Peripheral_Config();

#ifdef DEBUG
   I2C_ByteWrite(38, 0xBB);
   temp_char = I2C_ByteRead(38);
   RESET_TEST_SIGNAL = 0;
#endif

   RunFreqProg();

#ifdef DEBUG
   // Check that the data was read properly
   if (temp_char != 0xBB)
   {
      error_flag = 1;
   }
  
   // Indicate communication is good
   if (error_flag == 0)
   {
      // LED = ON indicates that the test passed
      LED = 1;
   }
#endif


   while(1);

}

void DelayFinished(void) interrupt INTERRUPT_TIMER2 {
	TR2 = 0;  // turn off timer2 
	ET2 = 0;  // turn off timer2 interrupt
	TF2H = 0; // turn off the interrupt flag
	done = 1; // set the flag to true and let the program continue
#ifdef DEBUG
	RESET_TEST_SIGNAL = 0;	
#endif
}

void RunFreqProg(void){
	// reset the Si57x /////////////////////////////////////////
	I2C_ByteWrite(135, 0x80);
	// need to delay for 15ms so that the reset finishes in the device	
#ifdef DEBUG
    RESET_TEST_SIGNAL = 1;
#endif
	TF2H = 0;
	TF2L = 0;
	done = 0;
	TR2 = 1;  // so enable timer 2 for the delay
	//wait until the timer interrupts to continue with the programming
	while(done==0) {}

	// read registers 7 to 12 ////////////////////////////////////
	// reg[0] is equivalent to register 7 in the device
	// reg[5] is register 12 in the device
	for(counter=0; counter<6; counter++){
		reg[counter] = I2C_ByteRead(counter+7); 
	}

#ifndef USE_I2C
	reg[0] = 0x01;
	reg[1] = 0xC2;
	reg[2] = 0xAA;
	reg[3] = 0xAA;
	reg[4] = 0xAA;
	reg[5] = 0xAB;
#endif

	// HS_DIV conversion //////////////////////////////////////////
	hsdiv = ((reg[0] & 0xE0) >> 5) + 4; // get reg 7 bits 5, 6, 7
	// hsdiv's value could be verified here to ensure that it is one
	// of the valid HS_DIV values from the datasheet.


	// N1 conversion ////////////////////////////////////////////
	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(n1 == 0) {
		n1 = 1;
	} else if (n1 & 1 != 0) { 
		// add one to an odd number 
		n1 = n1 + 1;
	} // else just leave it as-is


	// RFREQ conversion /////////////////////////////////////////
	//  reconstruct the fractional portion (bits 0 to 28)
	//  of the rfreq number from the registers 
	frac_bits = (( reg[4] << 8 ) + reg[5] );
	frac_bits = frac_bits + ( reg[3] * POW_2_16); 
	temp_bits = (( reg[2] & 0xF ) * POW_2_24 ); 
	frac_bits = frac_bits + temp_bits;

	rfreq = frac_bits / POW_2_28;

	//  reconstruct the integer or whole number portion of rfreq
	//  from the registers
	rfreq = rfreq + 
	        ( (( reg[1] & 0x3F ) << 4 ) + 
			  (( reg[2] & 0xF0 ) >> 4 ) );


	// Fxtal calculation //////////////////////////////////////////	
	fxtal = (fout0 * n1 * hsdiv) / rfreq; //MHz

	// find dividers /////////////////////////////////////////////
	// get the max and min divider range for the HS_DIV and N1 combo
	divider_max = floorf(FDCO_MAX / fout1); //floor(FDCO_MAX / fout1); floorf for SDCC
	curr_div = ceilf(FDCO_MIN / fout1); //ceil(FDCO_MIN / fout1); 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

	// RFREQ calculation ///////////////////////////////////////////
	rfreq = (fout1 * n1 * hsdiv) / fxtal;

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


	// N1 conversion ////////////////////////////////////////////
	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;


	// RFREQ conversion ////////////////////////////////////////
	// 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
	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, which is self-clearing
	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.

⌨️ 快捷键说明

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