📄 si57x_freqprogfirmware_withf300.#1
字号:
//''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
// 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 + -