@ -1,5 +1,6 @@
/*
* Copyright ( c ) 2014 - 2015 , TAKAHASHI Tomohiro ( TTRFTECH ) edy555 @ gmail . com
* Modified by DiSlord dislordlive @ gmail . com
* All rights reserved .
*
* This is free software ; you can redistribute it and / or modify
@ -21,40 +22,64 @@
# include "nanovna.h"
# include "si5351.h"
# define SI5351_I2C_ADDR (0x60<<1)
// Enable cache for SI5351 CLKX_CONTROL register, little speedup exchange
# define USE_CLK_CONTROL_CACHE TRUE
// XTAL frequency on si5351
# define XTALFREQ 26000000U
// MCLK (processor clock if set, audio codec) frequency clock
# define CLK2_FREQUENCY 8000000U
// Fixed PLL mode multiplier (used in band 1)
# define PLL_N 32
// I2C address on bus (only 0x60 for Si5351A in 10-Pin MSOP)
# define SI5351_I2C_ADDR 0x60
static uint8_t current_band = 0 ;
static uint32_t current_freq = 0 ;
static void
si5351_write ( uint8_t reg , uint8_t dat )
si5351_ bulk_write( const uint8_t * buf , int len )
{
int addr = SI5351_I2C_ADDR > > 1 ;
uint8_t buf [ ] = { reg , dat } ;
i2cAcquireBus ( & I2CD1 ) ;
( void ) i2cMasterTransmitTimeout ( & I2CD1 , addr , buf , 2 , NULL , 0 , 1000 ) ;
( void ) i2cMasterTransmitTimeout ( & I2CD1 , SI5351_I2C_ADDR , buf , len , NULL , 0 , 1000 ) ;
i2cReleaseBus ( & I2CD1 ) ;
}
static void
si5351_bulk_write ( const uint8_t * buf , int len )
#if 0
static void si5351_bulk_read ( uint8_t reg , uint8_t * buf , int len )
{
int addr = SI5351_I2C_ADDR > > 1 ;
i2cAcquireBus ( & I2CD1 ) ;
( void ) i2cMasterTransmitTimeout ( & I2CD1 , addr , buf , len , NULL , 0 , 1000 ) ;
msg_t mr = i2cMasterTransmitTimeout ( & I2CD1 , addr , & reg , 1 , buf , len , 1000 ) ;
i2cReleaseBus ( & I2CD1 ) ;
}
# endif
static inline void
si5351_write ( uint8_t reg , uint8_t dat )
{
uint8_t buf [ ] = { reg , dat } ;
si5351_bulk_write ( buf , 2 ) ;
}
// register addr, length, data, ...
const uint8_t si5351_configs [ ] = {
2 , SI5351_REG_3_OUTPUT_ENABLE_CONTROL , 0xff ,
4 , SI5351_REG_16_CLK0_CONTROL , SI5351_CLK_POWERDOWN , SI5351_CLK_POWERDOWN , SI5351_CLK_POWERDOWN ,
2 , SI5351_REG_183_CRYSTAL_LOAD , SI5351_CRYSTAL_LOAD_8PF ,
// All of this init code run late on sweep
#if 0
// setup PLL (26MHz * 32 = 832MHz, 32/2-2=14)
9 , SI5351_REG_26_PLL_A , /*P3*/ 0 , 1 , /*P1*/ 0 , 14 , 0 , /*P3/P2*/ 0 , 0 , 0 ,
9 , SI5351_REG_PLL_A , /*P3*/ 0 , 1 , /*P1*/ 0 , 14 , 0 , /*P3/P2*/ 0 , 0 , 0 ,
9 , SI5351_REG_PLL_B , /*P3*/ 0 , 1 , /*P1*/ 0 , 14 , 0 , /*P3/P2*/ 0 , 0 , 0 ,
// RESET PLL
2 , SI5351_REG_177_PLL_RESET , SI5351_PLL_RESET_A | SI5351_PLL_RESET_B ,
2 , SI5351_REG_177_PLL_RESET , SI5351_PLL_RESET_A | SI5351_PLL_RESET_B | 0x0C , //
// setup multisynth (832MHz / 104 = 8MHz, 104/2-2=50)
9 , SI5351_REG_58_MULTISYNTH2 , /*P3*/ 0 , 1 , /*P1*/ 0 , 50 , 0 , /*P2|P3*/ 0 , 0 , 0 ,
2 , SI5351_REG_18_CLK2_CONTROL , SI5351_CLK_DRIVE_STRENGTH_2MA | SI5351_CLK_INPUT_MULTISYNTH_N | SI5351_CLK_INTEGER_MODE ,
2 , SI5351_REG_3_OUTPUT_ENABLE_CONTROL , 0 ,
# endif
2 , SI5351_REG_3_OUTPUT_ENABLE_CONTROL , ~ ( SI5351_CLK0_EN | SI5351_CLK1_EN | SI5351_CLK2_EN ) ,
0 // sentinel
} ;
@ -71,232 +96,207 @@ si5351_init(void)
static const uint8_t disable_output [ ] = {
SI5351_REG_16_CLK0_CONTROL ,
SI5351_CLK_POWERDOWN ,
SI5351_CLK_POWERDOWN ,
SI5351_CLK_POWERDOWN
SI5351_CLK_POWERDOWN , // CLK 0
SI5351_CLK_POWERDOWN , // CLK 1
SI5351_CLK_POWERDOWN // CLK 2
} ;
void si5351_disable_output ( void )
/* Get the appropriate starting point for the PLL registers */
static const uint8_t msreg_base [ ] = {
SI5351_REG_42_MULTISYNTH0 ,
SI5351_REG_50_MULTISYNTH1 ,
SI5351_REG_58_MULTISYNTH2 ,
} ;
static const uint8_t clkctrl [ ] = {
SI5351_REG_16_CLK0_CONTROL ,
SI5351_REG_17_CLK1_CONTROL ,
SI5351_REG_18_CLK2_CONTROL
} ;
// Reset PLL need then band changes
static void si5351_reset_pll ( uint8_t mask )
{
si5351_write ( SI5351_REG_3_OUTPUT_ENABLE_CONTROL , 0xff ) ;
si5351_bulk_write ( disable_output , sizeof ( disable_output ) ) ;
// Writing a 1<<5 will reset PLLA, 1<<7 reset PLLB, this is a self clearing bits.
// !!! Need delay before reset PLL for apply PLL freq changes before
chThdSleepMicroseconds ( 400 ) ;
si5351_write ( SI5351_REG_177_PLL_RESET , mask | 0x0C ) ;
}
void si5351_enable_output ( void )
void si5351_ dis able_output( void )
{
si5351_write ( SI5351_REG_3_OUTPUT_ENABLE_CONTROL , 0x00 ) ;
si5351_write ( SI5351_REG_3_OUTPUT_ENABLE_CONTROL , 0xFF ) ;
si5351_bulk_write ( disable_output , sizeof ( disable_output ) ) ;
current_band = 0 ;
}
static void si5351_reset_pll ( void )
void si5351_enable_output ( void )
{
//si5351_write(SI5351_REG_177_PLL_RESET, SI5351_PLL_RESET_A | SI5351_PLL_RESET_B);
si5351_write ( SI5351_REG_177_PLL_RESET , 0xAC ) ;
si5351_write ( SI5351_REG_3_OUTPUT_ENABLE_CONTROL , ~ ( SI5351_CLK0_EN | SI5351_CLK1_EN | SI5351_CLK2_EN ) ) ;
//si5351_reset_pll(SI5351_PLL_RESET_A | SI5351_PLL_RESET_B);
current_freq = 0 ;
current_band = 0 ;
}
static void si5351_setupPLL ( uint8_t pll , /* SI5351_PLL_A or SI5351_PLL_B */
uint8_t mult ,
// Set PLL freq = XTALFREQ * (mult + num/denom)
static void si5351_setupPLL ( uint8_t pllSource , /* SI5351_REG_PLL_A or SI5351_REG_PLL_B */
uint32_t mult ,
uint32_t num ,
uint32_t denom )
{
/* Get the appropriate starting point for the PLL registers */
static const uint8_t pllreg_base [ ] = {
SI5351_REG_26_PLL_A ,
SI5351_REG_34_PLL_B
} ;
uint32_t P1 ;
uint32_t P2 ;
uint32_t P3 ;
/* Feedback Multisynth Divider Equation
* where : a = mult , b = num and c = denom
* P1 register is an 18 - bit value using following formula :
* P1 [ 17 : 0 ] = 128 * mult + floor ( 128 * ( num / denom ) ) - 512
* P1 [ 17 : 0 ] = 128 * mult + int ( ( 128 * num ) / denom ) - 512
* P2 register is a 20 - bit value using the following formula :
* P2 [ 19 : 0 ] = 128 * num - denom * floor ( 128 * ( num / denom ) )
* P2 [ 19 : 0 ] = ( 128 * num ) % denom
* P3 register is a 20 - bit value using the following formula :
* P3 [ 19 : 0 ] = denom
*/
/* Set the main PLL config registers */
if ( num = = 0 )
{
/* Integer mode */
P1 = 128 * mult - 512 ;
P2 = 0 ;
P3 = 1 ;
}
else
{
/* Fractional mode */
//P1 = (uint32_t)(128 * mult + floor(128 * ((float)num/(float)denom)) - 512);
P1 = 128 * mult + ( ( 128 * num ) / denom ) - 512 ;
//P2 = (uint32_t)(128 * num - denom * floor(128 * ((float)num/(float)denom)));
P2 = 128 * num - denom * ( ( 128 * num ) / denom ) ;
mult < < = 7 ;
num < < = 7 ;
uint32_t P1 = mult - 512 ; // Integer mode
uint32_t P2 = 0 ;
uint32_t P3 = 1 ;
if ( num ) { // Fractional mode
P1 + = num / denom ;
P2 = num % denom ;
P3 = denom ;
}
/* The datasheet is a nightmare of typos and inconsistencies here! */
// Pll MSN(A|B) registers Datasheet
uint8_t reg [ 9 ] ;
reg [ 0 ] = pllreg_base [ pll ] ;
reg [ 1 ] = ( P3 & 0x0 000 FF00) > > 8 ;
reg [ 2 ] = ( P3 & 0x 0 00000 FF) ;
reg [ 3 ] = ( P1 & 0x 000 30000) > > 16 ;
reg [ 4 ] = ( P1 & 0x0 000 FF00) > > 8 ;
reg [ 5 ] = ( P1 & 0x 0 00000 FF) ;
reg [ 6 ] = ( ( P3 & 0x 000 F0000) > > 12 ) | ( ( P2 & 0x 000 F0000) > > 16 ) ;
reg [ 7 ] = ( P2 & 0x0 000 FF00) > > 8 ;
reg [ 8 ] = ( P2 & 0x 0 00000 FF) ;
reg [ 0 ] = pllSource ; // SI5351_REG_PLL_A or SI5351_REG_PLL_B
reg [ 1 ] = ( P3 & 0x0FF00 ) > > 8 ; // MSN_P3[15: 8]
reg [ 2 ] = ( P3 & 0x 000FF) ; // MSN_P3[ 7: 0]
reg [ 3 ] = ( P1 & 0x 30000) > > 16 ; // MSN_P1[17:16]
reg [ 4 ] = ( P1 & 0x0 FF00) > > 8 ; // MSN_P1[15: 8]
reg [ 5 ] = ( P1 & 0x 000FF) ; // MSN_P1[ 7: 0]
reg [ 6 ] = ( ( P3 & 0x F0000) > > 12 ) | ( ( P2 & 0x F0000) > > 16 ) ; // MSN_P3[19:16] | MSN_P2[19:16]
reg [ 7 ] = ( P2 & 0x0 FF00) > > 8 ; // MSN_P2[15: 8]
reg [ 8 ] = ( P2 & 0x 000FF) ; // MSN_P2[ 7: 0]
si5351_bulk_write ( reg , 9 ) ;
}
// Set Multisynth divider = (div + num/denom) * rdiv
static void
si5351_setupMultisynth ( uint8_t output ,
uint8_t pllSource ,
si5351_setupMultisynth ( uint8_t channel ,
uint32_t div , // 4,6,8, 8+ ~ 900
uint32_t num ,
uint32_t denom ,
uint32_t rdiv , // SI5351_R_DIV_1~128
uint8_t drive_strength )
uint8_t chctrl ) // SI5351_REG_16_CLKX_CONTROL settings
{
/* Get the appropriate starting point for the PLL registers */
static const uint8_t msreg_base [ ] = {
SI5351_REG_42_MULTISYNTH0 ,
SI5351_REG_50_MULTISYNTH1 ,
SI5351_REG_58_MULTISYNTH2 ,
} ;
static const uint8_t clkctrl [ ] = {
SI5351_REG_16_CLK0_CONTROL ,
SI5351_REG_17_CLK1_CONTROL ,
SI5351_REG_18_CLK2_CONTROL
} ;
uint8_t dat ;
uint32_t P1 ;
uint32_t P2 ;
uint32_t P3 ;
uint32_t div4 = 0 ;
/* Output Multisynth Divider Equations
* where : a = div , b = num and c = denom
* P1 register is an 18 - bit value using following formula :
* P1 [ 17 : 0 ] = 128 * a + floor ( 128 * ( b / c ) ) - 512
* P1 [ 17 : 0 ] = 128 * a + int ( ( 128 * b ) / c ) - 512
* P2 register is a 20 - bit value using the following formula :
* P2 [ 19 : 0 ] = 128 * b - c * floor ( 128 * ( b / c ) )
* P2 [ 19 : 0 ] = ( 128 * b ) % c
* P3 register is a 20 - bit value using the following formula :
* P3 [ 19 : 0 ] = c
*/
/* Set the main PLL config registers */
if ( div = = 4 ) {
div4 = SI5351_DIVBY4 ;
P1 = P2 = 0 ;
P3 = 1 ;
} else if ( num = = 0 ) {
/* Integer mode */
P1 = 128 * div - 512 ;
P2 = 0 ;
P3 = 1 ;
} else {
/* Fractional mode */
P1 = 128 * div + ( ( 128 * num ) / denom ) - 512 ;
P2 = 128 * num - denom * ( ( 128 * num ) / denom ) ;
uint32_t P1 = 0 ;
uint32_t P2 = 0 ;
uint32_t P3 = 1 ;
if ( div = = 4 )
rdiv | = SI5351_DIVBY4 ;
else {
num < < = 7 ;
div < < = 7 ;
P1 = div - 512 ; // Integer mode
if ( num ) { // Fractional mode
P1 + = num / denom ;
P2 = num % denom ;
P3 = denom ;
}
}
/* Set the MSx config registers */
uint8_t reg [ 9 ] ;
reg [ 0 ] = msreg_base [ output ] ;
reg [ 1 ] = ( P3 & 0x0 000 FF00) > > 8 ;
reg [ 2 ] = ( P3 & 0x 0 00000 FF) ;
reg [ 3 ] = ( ( P1 & 0x 000 30000) > > 16 ) | div4 | rdiv ;
reg [ 4 ] = ( P1 & 0x0 000 FF00) > > 8 ;
reg [ 5 ] = ( P1 & 0x 0 00000 FF) ;
reg [ 6 ] = ( ( P3 & 0x 000 F0000) > > 12 ) | ( ( P2 & 0x 000 F0000) > > 16 ) ;
reg [ 7 ] = ( P2 & 0x0 000 FF00) > > 8 ;
reg [ 8 ] = ( P2 & 0x 0 00000 FF) ;
reg [ 0 ] = msreg_base [ channel ] ; // SI5351_REG_42_MULTISYNTH0, SI5351_REG_50_MULTISYNTH1, SI5351_REG_58_MULTISYNTH2
reg [ 1 ] = ( P3 & 0x0 FF00) > > 8 ; // MSx_P3[15: 8]
reg [ 2 ] = ( P3 & 0x 000FF) ; // MSx_P3[ 7: 0]
reg [ 3 ] = ( ( P1 & 0x 30000) > > 16 ) | rdiv ; // Rx_DIV[2:0] | MSx_DIVBY4[1:0] | MSx_P1[17:16]
reg [ 4 ] = ( P1 & 0x0 FF00) > > 8 ; // MSx_P1[15: 8]
reg [ 5 ] = ( P1 & 0x 000FF) ; // MSx_P1[ 7: 0]
reg [ 6 ] = ( ( P3 & 0x F0000) > > 12 ) | ( ( P2 & 0x F0000) > > 16 ) ; // MSx_P3[19:16] | MSx_P2[19:16]
reg [ 7 ] = ( P2 & 0x0 FF00) > > 8 ; // MSx_P2[15: 8]
reg [ 8 ] = ( P2 & 0x 000FF) ; // MSx_P2[ 7: 0]
si5351_bulk_write ( reg , 9 ) ;
/* Configure the clk control and enable the output */
dat = drive_strength | SI5351_CLK_INPUT_MULTISYNTH_N ;
if ( pllSource = = SI5351_PLL_B )
dat | = SI5351_CLK_PLL_SELECT_B ;
uint8_t dat = chctrl | SI5351_CLK_INPUT_MULTISYNTH_N ;
if ( num = = 0 )
dat | = SI5351_CLK_INTEGER_MODE ;
si5351_write ( clkctrl [ output ] , dat ) ;
}
# define XTALFREQ 26000000L
# define PLL_N 32
# define PLLFREQ (XTALFREQ * PLL_N)
static void
si5351_set_frequency_fixedpll ( int channel , int pll , uint32_t pllfreq , uint32_t freq ,
int rdiv , uint8_t drive_strength , int mul )
{
int denom = freq ;
int div = ( pllfreq * mul ) / denom ; // range: 8 ~ 1800
int num = ( pllfreq * mul ) - denom * div ;
# if USE_CLK_CONTROL_CACHE == TRUE
// Use cache for this reg, not update if not change
static uint8_t clk_cache [ 3 ] ;
if ( clk_cache [ channel ] ! = dat ) {
si5351_write ( clkctrl [ channel ] , dat ) ;
clk_cache [ channel ] = dat ;
}
# else
si5351_write ( clkctrl [ channel ] , dat ) ;
# endif
}
// Find better approximate values for n/d
# define MAX_DENOMINATOR ((1 << 20) - 1)
static inline void fractionalSolve ( uint32_t * n , uint32_t * d ) {
// cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227
int max_denominator = ( 1 < < 20 ) - 1 ;
if ( denom > max_denominator ) {
int p0 = 0 , q0 = 1 , p1 = 1 , q1 = 0 ;
uint32_t denom = * d ;
if ( denom > MAX_DENOMINATOR ) {
uint32_t num = * n ;
uint32_t p0 = 0 , q0 = 1 , p1 = 1 , q1 = 0 ;
while ( denom ! = 0 ) {
int a = num / denom ;
int q2 = q0 + a * q1 ;
if ( q2 > max_denominator )
uint32_t a = num / denom ;
uint32_t b = num % denom ;
uint32_t q2 = q0 + a * q1 ;
if ( q2 > MAX_DENOMINATOR )
break ;
int p2 = p0 + a * p1 ;
u int32_ t p2 = p0 + a * p1 ;
p0 = p1 ; q0 = q1 ; p1 = p2 ; q1 = q2 ;
int new_denom = num - a * denom ;
num = denom ; denom = new_denom ;
num = denom ; denom = b ;
}
num = p1 ;
denom = q1 ;
* n = p1 ;
* d = q1 ;
}
si5351_setupMultisynth ( channel , pll , div , num , denom , rdiv , drive_strength ) ;
}
// Setup Multisynth divider for get correct output freq if fixed PLL = pllfreq
static void
si5351_set_frequency_fixeddiv ( int channel , int pll , uint32_t freq , int div ,
uint8_t drive_strength , int mul )
si5351_set_frequency_fixedpll ( uint8_t channel , uint64_t pllfreq , uint32_t freq , uint32_t rdiv , uint8_t chctrl )
{
int denom = XTALFREQ * mul ;
int64_t pllfreq = ( int64_t ) freq * div ;
int multi = pllfreq / denom ;
int num = pllfreq - denom * multi ;
// cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227
int max_denominator = ( 1 < < 20 ) - 1 ;
if ( denom > max_denominator ) {
int p0 = 0 , q0 = 1 , p1 = 1 , q1 = 0 ;
while ( denom ! = 0 ) {
int a = num / denom ;
int q2 = q0 + a * q1 ;
if ( q2 > max_denominator )
break ;
int p2 = p0 + a * p1 ;
p0 = p1 ; q0 = q1 ; p1 = p2 ; q1 = q2 ;
int new_denom = num - a * denom ;
num = denom ; denom = new_denom ;
}
num = p1 ;
denom = q1 ;
}
uint32_t denom = freq ;
uint32_t div = pllfreq / denom ; // range: 8 ~ 1800
uint32_t num = pllfreq % denom ;
fractionalSolve ( & num , & denom ) ;
si5351_setupMultisynth ( channel , div , num , denom , rdiv , chctrl ) ;
}
si5351_setupPLL ( pll , multi , num , denom ) ;
si5351_setupMultisynth ( channel , pll , div , 0 , 1 , SI5351_R_DIV_1 , drive_strength ) ;
// Setup PLL freq if Multisynth divider fixed = div (need get output = freq/mul)
static void
si5351_setupPLL_freq ( uint32_t pllSource , uint32_t freq , uint32_t div , uint32_t mul ) {
uint32_t denom = XTALFREQ * mul ;
uint64_t pllfreq = ( uint64_t ) freq * div ;
uint32_t multi = pllfreq / denom ;
uint32_t num = pllfreq % denom ;
fractionalSolve ( & num , & denom ) ;
si5351_setupPLL ( pllSource , multi , num , denom ) ;
}
/*
* 1 ~ 100 MHz fixed PLL 900 MHz , fractional divider
* 100 ~ 150 MHz fractional PLL 600 - 900 MHz , fixed divider 6
* 150 ~ 200 MHz fractional PLL 600 - 900 MHz , fixed divider 4
*/
#if 0
void
si5351_set_frequency ( int channel , int freq , uint8_t drive_strength )
static void
si5351_set_frequency_fixeddiv ( uint8_t channel , uint32_t pll , uint32_t freq , uint32_t div ,
uint8_t chctrl , uint32_t mul )
{
si5351_setupPLL_freq ( pll , freq , div , mul ) ;
si5351_setupMultisynth ( channel , div , 0 , 1 , SI5351_R_DIV_1 , chctrl ) ;
}
void
si5351_set_frequency ( int channel , uint32_t freq , uint8_t drive_strength ) {
if ( freq < = 100000000 ) {
si5351_setupPLL ( SI5351_PLL_B , 32 , 0 , 1 ) ;
si5351_set_frequency_fixedpll ( channel , SI5351_PLL_B , PLLFREQ , freq , SI5351_R_DIV_1 , drive_strength , 1 ) ;
@ -308,27 +308,59 @@ si5351_set_frequency(int channel, int freq, uint8_t drive_strength)
}
# endif
int current_band = - 1 ;
/*
* Frequency generation divide on 3 band
* Band 1
* 1 ~ 100 MHz fixed PLL = XTALFREQ * PLL_N , fractional divider
* Band 2
* 100 ~ 150 MHz fractional PLL = 600 - 900 MHz , fixed divider ' fdiv = 6 '
* Band 3
* 150 ~ 300 MHz fractional PLL = 600 - 1200 MHz , fixed divider ' fdiv = 4 '
*
* For FREQ_HARMONICS = 300 MHz - band range is :
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* | Band 1 | Band 2 | Band 3 | Band 2 | Band 3 |
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* | Direct mode x1 : x1 | x3 : x5 | x5 - x7 | x7 - x9 | x9 - x11 |
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* | 50 kHz - 100 MHz | 100 - 150 MHz | 150 - 300 MHz | 300 - 450 MHz | 450 - 900 MHz | 900 - 1500 MHz | 1500 - 2100 MHz | 2100 - 2700 MHz |
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* | f = 50 kHz - 300 MHz | f = 100 - 150 | f = 150 - 300 | f = 150 - 300 | f = 214 - 300 | f = 233 - 300 |
* | of = 50 kHz - 300 MHz | of = 60 - 90 | of = 90 - 180 | of = 128 - 215 | of = 166 - 234 | of = 190 - 246 |
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
static inline uint8_t si5351_getBand ( uint32_t freq ) {
if ( freq < 100000000U ) return 1 ;
if ( freq < 150000000U ) return 2 ;
return 3 ;
}
# define DELAY_NORMAL 3
# define DELAY_BANDCHANGE 1
# define DELAY_LOWBAND 1
// Minimum value is 2, freq change apply at next dsp measure, and need skip it
# define DELAY_NORMAL 2
// Additional delay for band 1 (remove unstable generation at begin)
# define DELAY_BAND_1 1
// Band changes need additional delay after reset PLL
# define DELAY_BANDCHANGE_1 2
# define DELAY_BANDCHANGE_2 2
/*
* Maximum supported frequency = FREQ_HARMONICS * 9U
* configure output as follows :
* CLK0 : frequency + offset
* CLK1 : frequency
* CLK2 : fixed 8 MHz
*/
# define CLK2_FREQUENCY 8000000L
int
si5351_set_frequency_with_offset ( uint32_t freq , int offset , uint8_t drive_strength )
{
int band ;
si5351_set_frequency_with_offset ( uint32_t freq , int offset , uint8_t drive_strength ) {
uint8_t band ;
int delay = DELAY_NORMAL ;
if ( freq = = current_freq )
return delay ;
uint32_t ofreq = freq + offset ;
uint32_t mul = 1 , omul = 1 ;
uint32_t rdiv = SI5351_R_DIV_1 ;
uint32_t fdiv ;
current_freq = freq ;
if ( freq > = config . harmonic_freq_threshold * 7U ) {
mul = 9 ;
omul = 11 ;
@ -342,83 +374,50 @@ si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_streng
mul = 3 ;
omul = 5 ;
}
if ( ( freq / mul ) < 100000000U ) {
band = 0 ;
} else if ( ( freq / mul ) < 150000000U ) {
band = 1 ;
} else {
band = 2 ;
}
if ( freq < = 500000U ) {
else if ( freq < = 500000U ) {
rdiv = SI5351_R_DIV_64 ;
freq < < = 6 ;
ofreq < < = 6 ;
} else if ( freq < = 4000000U ) {
rdiv = SI5351_R_DIV_8 ;
freq < < = 3 ;
ofreq < < = 3 ;
}
# if 1
if ( current_band ! = band )
si5351_disable_output ( ) ;
# endif
band = si5351_getBand ( freq / mul ) ;
switch ( band ) {
case 0 :
// fractional divider mode. only PLL A is used.
if ( current_band = = 1 | | current_band = = 2 )
si5351_setupPLL ( SI5351_PLL_A , 32 , 0 , 1 ) ;
// Set PLL twice on changing from band 2
if ( current_band = = 2 )
si5351_setupPLL ( SI5351_PLL_A , 32 , 0 , 1 ) ;
if ( rdiv = = SI5351_R_DIV_8 ) {
freq * = 8 ;
ofreq * = 8 ;
} else if ( rdiv = = SI5351_R_DIV_64 ) {
freq * = 64 ;
ofreq * = 64 ;
}
si5351_set_frequency_fixedpll ( 0 , SI5351_PLL_A , PLLFREQ , ofreq ,
rdiv , drive_strength , omul ) ;
si5351_set_frequency_fixedpll ( 1 , SI5351_PLL_A , PLLFREQ , freq ,
rdiv , drive_strength , mul ) ;
//if (current_band != 0)
si5351_set_frequency_fixedpll ( 2 , SI5351_PLL_A , PLLFREQ , CLK2_FREQUENCY ,
SI5351_R_DIV_1 , SI5351_CLK_DRIVE_STRENGTH_2MA , 1 ) ;
break ;
case 1 :
// Set PLL twice on changing from band 2
if ( current_band = = 2 ) {
si5351_set_frequency_fixeddiv ( 0 , SI5351_PLL_A , ofreq , 6 , drive_strength , omul ) ;
si5351_set_frequency_fixeddiv ( 1 , SI5351_PLL_B , freq , 6 , drive_strength , mul ) ;
// Setup CH0 and CH1 constant PLLA freq at band change, and set CH2 freq = CLK2_FREQUENCY
if ( current_band ! = 1 ) {
si5351_setupPLL ( SI5351_REG_PLL_A , PLL_N , 0 , 1 ) ;
si5351_set_frequency_fixedpll ( 2 , XTALFREQ * PLL_N , CLK2_FREQUENCY , SI5351_R_DIV_1 , SI5351_CLK_DRIVE_STRENGTH_2MA | SI5351_CLK_PLL_SELECT_A ) ;
delay + = DELAY_BANDCHANGE_1 ;
}
// div by 6 mode. both PLL A and B are dedicated for CLK0, CLK1
si5351_set_frequency_fixeddiv ( 0 , SI5351_PLL_A , ofreq , 6 , drive_strength , omul ) ;
si5351_set_frequency_fixeddiv ( 1 , SI5351_PLL_B , freq , 6 , drive_strength , mul ) ;
si5351_set_frequency_fixedpll ( 2 , SI5351_PLL_B , freq / mul * 6 , CLK2_FREQUENCY ,
SI5351_R_DIV_1 , SI5351_CLK_DRIVE_STRENGTH_2MA , 1 ) ;
// Calculate and set CH0 and CH1 divider
si5351_set_frequency_fixedpll ( 0 , ( uint64_t ) omul * XTALFREQ * PLL_N , ofreq , rdiv , drive_strength | SI5351_CLK_PLL_SELECT_A ) ;
si5351_set_frequency_fixedpll ( 1 , ( uint64_t ) mul * XTALFREQ * PLL_N , freq , rdiv , drive_strength | SI5351_CLK_PLL_SELECT_A ) ;
delay + = DELAY_BAND_1 ;
break ;
case 2 :
// div by 4 mode. both PLL A and B are dedicated for CLK0, CLK1
si5351_set_frequency_fixeddiv ( 0 , SI5351_PLL_A , ofreq , 4 , drive_strength , omul ) ;
si5351_set_frequency_fixeddiv ( 1 , SI5351_PLL_B , freq , 4 , drive_strength , mul ) ;
si5351_set_frequency_fixedpll ( 2 , SI5351_PLL_B , freq / mul * 4 , CLK2_FREQUENCY ,
SI5351_R_DIV_1 , SI5351_CLK_DRIVE_STRENGTH_2MA , 1 ) ;
case 2 : // fdiv = 6
case 3 : // fdiv = 4;
fdiv = ( band = = 2 ) ? 6 : 4 ;
// Setup CH0 and CH1 constant fdiv divider at change
if ( current_band ! = band ) {
si5351_setupMultisynth ( 0 , fdiv , 0 , 1 , SI5351_R_DIV_1 , drive_strength | SI5351_CLK_PLL_SELECT_A ) ;
si5351_setupMultisynth ( 1 , fdiv , 0 , 1 , SI5351_R_DIV_1 , drive_strength | SI5351_CLK_PLL_SELECT_B ) ;
delay + = DELAY_BANDCHANGE_2 ;
}
// Calculate and set CH0 and CH1 PLL freq
si5351_setupPLL_freq ( SI5351_REG_PLL_A , ofreq , fdiv , omul ) ; // set PLLA freq = (ofreq/omul)*fdiv
si5351_setupPLL_freq ( SI5351_REG_PLL_B , freq , fdiv , mul ) ; // set PLLB freq = ( freq/ mul)*fdiv
// Calculate CH2 freq = CLK2_FREQUENCY, depend from calculated before CH1 PLLB = (freq/mul)*fdiv
si5351_set_frequency_fixedpll ( 2 , ( uint64_t ) freq * fdiv , CLK2_FREQUENCY * mul , SI5351_R_DIV_1 , SI5351_CLK_DRIVE_STRENGTH_2MA | SI5351_CLK_PLL_SELECT_B ) ;
break ;
}
if ( current_band ! = band ) {
si5351_reset_pll ( ) ;
# if 1
si5351_enable_output ( ) ;
# endif
delay + = DELAY_BANDCHANGE ;
}
if ( band = = 0 )
delay + = DELAY_LOWBAND ;
si5351_reset_pll ( SI5351_PLL_RESET_A | SI5351_PLL_RESET_B ) ;
current_band = band ;
}
return delay ;
}