kopia lustrzana https://github.com/ArjanteMarvelde/uSDR-pico
				
				
				
			
							rodzic
							
								
									53e7c155f5
								
							
						
					
					
						commit
						caaf154a13
					
				
							
								
								
									
										7
									
								
								dsp.c
								
								
								
								
							
							
						
						
									
										7
									
								
								dsp.c
								
								
								
								
							| 
						 | 
				
			
			@ -338,13 +338,14 @@ bool __not_in_flash_func(dsp_callback)(repeating_timer_t *t)
 | 
			
		|||
	// Crude AGC mechanism **TO BE IMPROVED**
 | 
			
		||||
	if (!tx_enabled)	
 | 
			
		||||
	{
 | 
			
		||||
		// Approximate amplitude, with alpha max + beta min function
 | 
			
		||||
		uint32_t i=adc_level[1],q=adc_level[0];
 | 
			
		||||
		if (i>q)
 | 
			
		||||
			temp = (MAX(i,((29*i/32) + (61*q/128))))>>LSH;
 | 
			
		||||
		else
 | 
			
		||||
			temp = (MAX(q,((29*q/32) + (61*i/128))))>>LSH;
 | 
			
		||||
		s_rssi = MAX(1,temp);
 | 
			
		||||
		rx_agc = AGC_TOP/s_rssi;											// calculate required AGC factor
 | 
			
		||||
		rx_agc = AGC_TOP/s_rssi;											// calculate scaling factor
 | 
			
		||||
		if (rx_agc==0) rx_agc=1;
 | 
			
		||||
	}
 | 
			
		||||
		
 | 
			
		||||
| 
						 | 
				
			
			@ -363,7 +364,7 @@ bool __not_in_flash_func(dsp_callback)(repeating_timer_t *t)
 | 
			
		|||
		pwm_set_gpio_level(22, A_buf[dsp_active][dsp_tick] + DAC_BIAS);		// Output A to DAC
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// When sample buffer is full, move pointer and signal DSP loop
 | 
			
		||||
	// When sample buffer is full, move pointer to next and signal the DSP loop
 | 
			
		||||
	if (++dsp_tick >= BUFSIZE)												// Increment tick and check range
 | 
			
		||||
	{
 | 
			
		||||
		dsp_tick = 0;														// Reset counter
 | 
			
		||||
| 
						 | 
				
			
			@ -505,7 +506,7 @@ void __not_in_flash_func(dsp_loop)()
 | 
			
		|||
			rx();															// Do RX signal processing
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
/////// This is a trap, ptt remains active after once asserted
 | 
			
		||||
/////// This is a trap, ptt remains active after once asserted: to be checked!
 | 
			
		||||
		tx_enabled = vox_active || ptt_active;								// Check RX or TX	
 | 
			
		||||
		
 | 
			
		||||
#if DSP_FFT == 1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										287
									
								
								si5351.c
								
								
								
								
							
							
						
						
									
										287
									
								
								si5351.c
								
								
								
								
							| 
						 | 
				
			
			@ -9,30 +9,35 @@
 | 
			
		|||
 
 | 
			
		||||
Si5351 principle of operation:
 | 
			
		||||
==============================
 | 
			
		||||
Crystal frequency <Fxtal> (usually 25MHz) is multiplied in a PLL by <MSN> to obtain <Fvco>.
 | 
			
		||||
PLL A and B have independent MSN values, the <Fout> on channel <i> can be derived from either.
 | 
			
		||||
<Fvco> must be between 600MHz and 900MHz, but the spec is more relaxed in reality.
 | 
			
		||||
<Fvco> is divided by <MSi> and <Ri> to obtain the output frequency <Fout>.
 | 
			
		||||
<MSi> and <Ri> are selected to be in the ballpark of desired frequency range.
 | 
			
		||||
<MSN> is then used for tuning <Fout>.
 | 
			
		||||
Only certain values of <MSi> and <Ri> are allowed when quadrature output is required.
 | 
			
		||||
Crystal frequency Fxtal (usually 25MHz) is multiplied in a PLL by MSN to obtain Fvco.
 | 
			
		||||
PLLs A and B have independent MSN values, leading to two Fvco frequencies.
 | 
			
		||||
The output Fout on each channel (i) can be derived from either Fvco.
 | 
			
		||||
Fvco must be between 600MHz and 900MHz, but the spec is more relaxed in reality.
 | 
			
		||||
In the second stage, an Fvco is divided by MSi and Ri to obtain the output frequency Fout.
 | 
			
		||||
Only certain values of MSi and Ri are allowed when quadrature output is required.
 | 
			
		||||
 | 
			
		||||
             +-------+             +-------+     +------+
 | 
			
		||||
 - Fxtal --> | * MSN | -- Fvco --> | / MSi | --> | / Ri | -- Fout -->
 | 
			
		||||
             +-------+             +-------+     +------+
 | 
			
		||||
Tuning stragtegy:
 | 
			
		||||
MSi and Ri are selected to be in the ballpark of desired frequency range.
 | 
			
		||||
MSN is then used for tuning Fout.
 | 
			
		||||
 | 
			
		||||
Details:
 | 
			
		||||
========
 | 
			
		||||
 ---Derivation of Fout---
 | 
			
		||||
 | 
			
		||||
             +-------+             +-------+     +------+
 | 
			
		||||
   Fxtal --> | * MSN | -- Fvco --> | / MSi | --> | / Ri | -- Fout -->
 | 
			
		||||
             +-------+             +-------+     +------+
 | 
			
		||||
 | 
			
		||||
 MSN determines:          Fvco = Fxtal * (MSN)      , where MSN = a + b/c
 | 
			
		||||
 MSi and Ri determine:    Fout = Fvco / (Ri*MSi)    , where MSi = a + b/c	(different a, b and c)
 | 
			
		||||
 MSi and Ri determine:    Fout = Fvco / (Ri*MSi)    , where MSi = a + b/c	(note: different a, b and c)
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 ---Derivation of the register values, that determine MSN and MSi---
 | 
			
		||||
 P1 = 128*a + Floor(128*b/c) - 512
 | 
			
		||||
 P2 = 128*b - c*Floor(128*b/c)			(P2 = 0 for MSi integer mode, or calculated for MSN tuning)
 | 
			
		||||
 P3 = c									(P3 = 1 for MSi integer mode, or P3 = 1000000 for MSN tuning)
 | 
			
		||||
 P1 = 128*a + Floor(128*b/c) - 512		(P1 = calculated for MSN tuning,  P1 = 750MHz/Fout for MSi integer mode)
 | 
			
		||||
 P2 = 128*b - c*Floor(128*b/c)			(P2 = calculated for MSN tuning,  P2 = 0 for MSi integer mode)
 | 
			
		||||
 P3 = c									(P3 = c = 1000000 for MSN tuning, P3 = 1 for MSi integer mode)
 | 
			
		||||
 
 | 
			
		||||
 This VFO implementation assumes PLLA is used for VFO0 (clk0 and clk1), and PLLB is used for VFO1 (clk2)
 | 
			
		||||
 
 | 
			
		||||
 This VFO implementation assumes PLLA is used for VFO 0 (clk0 and clk1), and PLLB is used for VFO 1 (clk2)
 | 
			
		||||
 
 | 
			
		||||
 The algorithm to get from required Fout to synthesizer settings:
 | 
			
		||||
 | calculate new <MSN> from the desired <Fout>, based on the current <Ri> and <MSi>
 | 
			
		||||
| 
						 | 
				
			
			@ -46,28 +51,35 @@ Details:
 | 
			
		|||
 |   reset PLL
 | 
			
		||||
 (this all assumes that the current settings are consistent, i.e. must be initialized at startup)
 | 
			
		||||
 | 
			
		||||
Some boundary values:
 | 
			
		||||
Ri		MSi		Lo MHz	    Hi MHz
 | 
			
		||||
1		  4		150.000000	225.000000
 | 
			
		||||
1		126		  4.761905	  7.142857
 | 
			
		||||
32		  4		  4.687500	  7.031250
 | 
			
		||||
32		126		  0.148810	  0.223214
 | 
			
		||||
128		  4		  1.171875	  1.757813
 | 
			
		||||
128		126		  0.037202	  0.055804
 | 
			
		||||
Calculate MSi:
 | 
			
		||||
	MSi = 750MHz/(Fout*Ri)	// Target for mid-band, i.e. Fvco=750MHz
 | 
			
		||||
	MSi &= 0xfe				// Make it even, minimum is 4 in case of integer mode
 | 
			
		||||
 | 
			
		||||
MSi: target for mid-band, i.e. Fvco=750MHz
 | 
			
		||||
     MSi = 750MHz/(Fout*Ri)
 | 
			
		||||
	 MSi &= 0xfe	// Make it even
 | 
			
		||||
Calculate MSN:
 | 
			
		||||
	MSN = MSi*Ri*Fout/Fxtal (spec mandates between 24 and 36, but could be stretched)
 | 
			
		||||
	
 | 
			
		||||
MSN = MSi*Ri*Fout/Fxtal (should be between 24 and 36)
 | 
			
		||||
	
 | 
			
		||||
Only use MSi even-integers, i.e. d=[4, 6, 8..126], e=0 and f=100000, and set INT bits in reg 22, 23. 
 | 
			
		||||
Some boundary values, assuming 600M < Fvco < 900M.
 | 
			
		||||
With low end 400M, Low MHz is multiplied with 2/3.
 | 
			
		||||
------------+--------------+-----------------------+
 | 
			
		||||
Ri		MSi	:	a	b	c  |    Low MHz	  High MHz
 | 
			
		||||
1		  4	:	4	0	1  | 150.000000	225.000000	
 | 
			
		||||
1		126	: 126	0	1  |   4.761905	  7.142857
 | 
			
		||||
32		  4	:	4	0	1  |   4.687500	  7.031250
 | 
			
		||||
32		126	:  126	0	1  |   0.148810	  0.223214
 | 
			
		||||
128		  4	:	4	0	1  |   1.171875	  1.757813
 | 
			
		||||
128		126	:  126	0	1  |   0.037202	  0.055804
 | 
			
		||||
 | 
			
		||||
NOTE: Phase offsets
 | 
			
		||||
The PHOFF is given as a multiple of 1/(4*Fvco), so when MSi == PHOFF the shift will be 90deg.
 | 
			
		||||
It also implies that MSi must be an integer, and Ri == 1.
 | 
			
		||||
 | 
			
		||||
Only use MSi even-integers, i.e. a=[4, 6, 8..126], b=0 and c=100000, and set INT bits in reg 22, 23. 
 | 
			
		||||
Quadrature Phase offsets (i.e. delay): 
 | 
			
		||||
- Offset for MS0 (reg 165) must be 0 (cosine), 
 | 
			
		||||
- Offset for MS1 (reg 166) must be equal to divider MS1 for 90 deg (sine),
 | 
			
		||||
- Phase offset for MS0 (reg 165) must be 0 (cos: delay = 0), 
 | 
			
		||||
- Phase offset for MS1 (reg 166) must be equal to divider MS1 for 90 deg (sin: delay = MSi / 4*Fvco),
 | 
			
		||||
- Set INV bit (reg 17) to add 180 deg.
 | 
			
		||||
 | 
			
		||||
NOTE: Phase offsets only work when Ri = 1, 
 | 
			
		||||
This implies that minimum Fout is 4.762MHz at Fvco = 600MHz. 
 | 
			
		||||
Additional flip/flop dividers are needed to get down to 80m band frequencies, or Fvco must be tuned below spec.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -180,7 +192,7 @@ Control Si5351 (see AN619):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
#define SI_XTAL_FREQ	25001414UL											// Replace with measured crystal frequency of XTAL for CL = 10pF (default)
 | 
			
		||||
#define SI_MSN_LO		((0.6e9)/SI_XTAL_FREQ)
 | 
			
		||||
#define SI_MSN_LO		((0.4e9)/SI_XTAL_FREQ)								// Should be 600M, but 400MHz works too
 | 
			
		||||
#define SI_MSN_HI		((0.9e9)/SI_XTAL_FREQ)
 | 
			
		||||
#define SI_PLL_C		1000000UL											// Parameter c for PLL-A and -B setting
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -190,7 +202,7 @@ typedef struct
 | 
			
		|||
	uint32_t freq;		// type can hold up to 4GHz
 | 
			
		||||
	uint8_t  flag;		// flag != 0 when update needed
 | 
			
		||||
	uint8_t  phase;		// in quarter waves (0, 1, 2, 3)
 | 
			
		||||
	uint8_t  ri;		// Ri (1 .. 128)
 | 
			
		||||
	uint8_t  ri;		// Ri (1 .. 128), but should be 1 for VFO 0
 | 
			
		||||
	uint8_t  msi;		// MSi parameter a (4, 6, 8 .. 126)
 | 
			
		||||
	double   msn;		// MSN (24.0 .. 35.9999)
 | 
			
		||||
} vfo_t;
 | 
			
		||||
| 
						 | 
				
			
			@ -230,11 +242,11 @@ void si_enable(int i, bool en)
 | 
			
		|||
	data[0] = SI_CLK_OE;
 | 
			
		||||
	if (i==0)
 | 
			
		||||
	{
 | 
			
		||||
		data[1] = en ? data[1]&~SI_VFO0_DISABLE : data[1]|SI_VFO0_DISABLE;
 | 
			
		||||
		data[1] = en ? data[1]&~SI_VFO0_DISABLE : data[1]|SI_VFO0_DISABLE;	// clk0 and clk1
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		data[1] = en ? data[1]&~SI_VFO1_DISABLE : data[1]|SI_VFO1_DISABLE;
 | 
			
		||||
		data[1] = en ? data[1]&~SI_VFO1_DISABLE : data[1]|SI_VFO1_DISABLE;	// clk2
 | 
			
		||||
	}
 | 
			
		||||
	i2c_write_blocking(i2c0, I2C_VFO, &data[0], 2, false);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -258,19 +270,26 @@ int si_getreg(uint8_t *data, uint8_t reg, uint8_t len)
 | 
			
		|||
 * Set up MSN PLL divider for vfo[i], assuming MSN has been set in vfo[i]
 | 
			
		||||
 * Optimize for speed, this may be called with short intervals
 | 
			
		||||
 * See also SiLabs AN619 section 3.2
 | 
			
		||||
 * VFO 0 refers to PLL a, VFO 1 refers to PLL B
 | 
			
		||||
 | 
			
		||||
 MSN = a + b/c
 | 
			
		||||
 c = 1000000							(Fxtal/c step size)
 | 
			
		||||
 P1 = 128*a + Floor(128*b/c) - 512
 | 
			
		||||
 P2 = 128*b - c*Floor(128*b/c)
 | 
			
		||||
 P3 = c
 | 
			
		||||
 | 
			
		||||
 */
 | 
			
		||||
void si_setmsn(int i)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t  data[16];														// I2C trx buffer
 | 
			
		||||
	uint32_t P1, P2;														// MSN parameters
 | 
			
		||||
	uint32_t A;
 | 
			
		||||
	uint32_t B;
 | 
			
		||||
	uint32_t P1, P2;														// MSN parameters, P3 is SI_PLL_C
 | 
			
		||||
	uint32_t A, B;
 | 
			
		||||
 | 
			
		||||
	if ((i<0)||(i>1)) return;												// Check VFO range
 | 
			
		||||
	
 | 
			
		||||
	A  = (uint32_t)(floor(vfo[i].msn));										// A is integer part of MSN
 | 
			
		||||
	B  = (uint32_t)((vfo[i].msn - (double)A) * SI_PLL_C);					// B is C * fraction part of MSN (C is a constant)
 | 
			
		||||
	P2 = (uint32_t)(floor((double)(128 * B) / (double)SI_PLL_C));
 | 
			
		||||
	P2 = (uint32_t)(floor((double)(128 * B) / (double)SI_PLL_C));			// use P2 for intermediate result..
 | 
			
		||||
	P1 = (uint32_t)(128 * A + P2 - 512);
 | 
			
		||||
	P2 = (uint32_t)(128 * B - SI_PLL_C * P2);
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -293,7 +312,13 @@ void si_setmsn(int i)
 | 
			
		|||
/*
 | 
			
		||||
 * Set up registers with MS and R divider for vfo[i], assuming values have been set in vfo[i]
 | 
			
		||||
 * In this implementation we only use integer mode, i.e. b=0 and P3=1
 | 
			
		||||
 * See also SiLabs AN619 section 4.1
 | 
			
		||||
 | 
			
		||||
 MSi = a + b/c
 | 
			
		||||
 c = 1, b=0
 | 
			
		||||
 P1 = 128*a - 512
 | 
			
		||||
 P2 = 0
 | 
			
		||||
 P3 = c
 | 
			
		||||
 | 
			
		||||
 */
 | 
			
		||||
void si_setmsi(uint8_t i)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -301,7 +326,7 @@ void si_setmsi(uint8_t i)
 | 
			
		|||
	uint32_t P1;
 | 
			
		||||
	uint8_t  R;
 | 
			
		||||
 | 
			
		||||
	i=(i>0?1:0);
 | 
			
		||||
	if ((i<0)||(i>1)) return;												// Check VFO range
 | 
			
		||||
	
 | 
			
		||||
	P1 = (uint32_t)(128*(uint32_t)floor(vfo[i].msi) - 512);
 | 
			
		||||
	R  = vfo[i].ri;
 | 
			
		||||
| 
						 | 
				
			
			@ -321,13 +346,13 @@ void si_setmsi(uint8_t i)
 | 
			
		|||
	data[8] = 0x00;
 | 
			
		||||
	i2c_write_blocking(i2c0, I2C_VFO, data, 9, false);
 | 
			
		||||
 | 
			
		||||
	// If vfo[0] also set clk 1	
 | 
			
		||||
	// If vfo[0] also set clk 1	and phase offset, (integer mode and high drive current for low phase noise).
 | 
			
		||||
	if (i==0)
 | 
			
		||||
	{
 | 
			
		||||
		data[0] = SI_SYNTH_MS1;												// Same data in synthesizer
 | 
			
		||||
		i2c_write_blocking(i2c0, I2C_VFO, data, 9, false);
 | 
			
		||||
		
 | 
			
		||||
		if (vfo[0].phase&1)													// Phase is either 90 or 270 deg?
 | 
			
		||||
		if (vfo[0].phase&(PH000|PH270))										// Phase is either 90 or 270 deg?
 | 
			
		||||
		{
 | 
			
		||||
			data[0] = SI_CLK1_PHOFF;
 | 
			
		||||
			data[1] = vfo[0].msi;											// offset == MSi for 90deg
 | 
			
		||||
| 
						 | 
				
			
			@ -339,12 +364,24 @@ void si_setmsi(uint8_t i)
 | 
			
		|||
			data[1] = 0;													// offset == 0 for 0deg
 | 
			
		||||
			i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
 | 
			
		||||
		}
 | 
			
		||||
		if (vfo[0].phase&2)													// Phase is 180 or 270 deg?
 | 
			
		||||
		if (vfo[0].phase&(PH180|PH270))										// Phase is 180 or 270 deg?
 | 
			
		||||
		{
 | 
			
		||||
			data[0] = SI_CLK1_CTL;											// Then set the invert flag
 | 
			
		||||
			data[1] = 0x5d;													// CLK1: INT, PLLA, INV, MS, 8mA
 | 
			
		||||
			data[0] = SI_CLK1_CTL;											// set the invert flag
 | 
			
		||||
			data[1] = 0x1f;													// CLK1: nonINT, PLLA, INV, MS, 8mA
 | 
			
		||||
			i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			data[0] = SI_CLK1_CTL;											// clear the invert flag
 | 
			
		||||
			data[1] = 0x0f;													// CLK1: nonINT, PLLA, nonINV, MS, 8mA
 | 
			
		||||
			i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		data[0] = SI_CLK2_CTL;												// set the invert flag
 | 
			
		||||
		data[1] = 0x2f;														// CLK2: nonINT, PLLB, nonINV, MS, 8mA
 | 
			
		||||
		i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
 | 
			
		||||
	}
 | 
			
		||||
		
 | 
			
		||||
	// Reset associated PLL
 | 
			
		||||
| 
						 | 
				
			
			@ -355,10 +392,13 @@ void si_setmsi(uint8_t i)
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This function needs to be invoked at regular intervals, e.g. 10x per sec. See hmi.c
 | 
			
		||||
 * For each vfo, calculate required MSN setting, MSN = MSi*Ri*Fout/Fxtal
 | 
			
		||||
 * If in range, just set MSN registers
 | 
			
		||||
 * If not in range, recalculate MSi and Ri and also MSN
 | 
			
		||||
 * Set MSN, MSi and Ri registers (implicitly resets PLL)
 | 
			
		||||
 * If still in range, 
 | 
			
		||||
 *	then just set MSN registers
 | 
			
		||||
 * else, 
 | 
			
		||||
 *	recalculate MSi and Ri as well
 | 
			
		||||
 *	set MSN, MSi and Ri registers (implicitly resets PLL)
 | 
			
		||||
 */
 | 
			
		||||
void si_evaluate(void)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -369,20 +409,22 @@ void si_evaluate(void)
 | 
			
		|||
		msn = (double)(vfo[0].msi); 										// Re-calculate MSN
 | 
			
		||||
		msn = msn * (double)(vfo[0].ri);
 | 
			
		||||
		msn = msn * (double)(vfo[0].freq) / SI_XTAL_FREQ;
 | 
			
		||||
		if ((msn>=SI_MSN_LO)&&(msn<SI_MSN_HI))
 | 
			
		||||
		
 | 
			
		||||
		if ((msn>=SI_MSN_LO)&&(msn<SI_MSN_HI))								// Check MSN range
 | 
			
		||||
		{
 | 
			
		||||
			vfo[0].msn = msn;
 | 
			
		||||
			si_setmsn(0);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// Pre-scale Ri, stretch down Ri=1 range
 | 
			
		||||
			if (vfo[0].freq<1000000)
 | 
			
		||||
				vfo[0].ri  = 128;
 | 
			
		||||
			else if (vfo[0].freq<3000000)
 | 
			
		||||
			// Pre-scale Ri, stretch down Ri=1 range to 3MHz
 | 
			
		||||
			// Otherwise use just 32 and 128
 | 
			
		||||
			if (vfo[0].freq>3000000)
 | 
			
		||||
				vfo[0].ri  = 1;
 | 
			
		||||
			else if (vfo[0].freq>1000000)
 | 
			
		||||
				vfo[0].ri  = 32;
 | 
			
		||||
			else
 | 
			
		||||
				vfo[0].ri  = 1;
 | 
			
		||||
				vfo[0].ri  = 128;
 | 
			
		||||
			
 | 
			
		||||
			// Set MSi
 | 
			
		||||
			if ((vfo[0].freq >= 3000000)&&(vfo[0].freq < 6000000))			// Handle Low end of Ri=1 range
 | 
			
		||||
| 
						 | 
				
			
			@ -402,6 +444,40 @@ void si_evaluate(void)
 | 
			
		|||
	}
 | 
			
		||||
	if (vfo[1].flag)
 | 
			
		||||
	{
 | 
			
		||||
		msn = (double)(vfo[1].msi); 										// Re-calculate MSN
 | 
			
		||||
		msn = msn * (double)(vfo[1].ri);
 | 
			
		||||
		msn = msn * (double)(vfo[1].freq) / SI_XTAL_FREQ;
 | 
			
		||||
		
 | 
			
		||||
		if ((msn>=SI_MSN_LO)&&(msn<SI_MSN_HI))								// Check MSN range
 | 
			
		||||
		{
 | 
			
		||||
			vfo[1].msn = msn;
 | 
			
		||||
			si_setmsn(1);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// Pre-scale Ri, stretch down Ri=1 range to 3MHz
 | 
			
		||||
			// Otherwise use just 32 and 128
 | 
			
		||||
			if (vfo[1].freq>3000000)
 | 
			
		||||
				vfo[1].ri  = 1;
 | 
			
		||||
			else if (vfo[1].freq>1000000)
 | 
			
		||||
				vfo[1].ri  = 32;
 | 
			
		||||
			else
 | 
			
		||||
				vfo[1].ri  = 128;
 | 
			
		||||
			
 | 
			
		||||
			// Set MSi
 | 
			
		||||
			if ((vfo[1].freq >= 3000000)&&(vfo[1].freq < 6000000))			// Handle Low end of Ri=1 range
 | 
			
		||||
				vfo[1].msi = (uint8_t)126;									// Maximum MSi on Fvco=(4x126)MHz
 | 
			
		||||
			else															// Or calculate MSi on Fvco=750MHz
 | 
			
		||||
				vfo[1].msi = (uint8_t)(750000000UL / (vfo[1].freq * vfo[1].ri)) & 0x000000fe;
 | 
			
		||||
 | 
			
		||||
			msn = (double)(vfo[1].msi); 									// Re-calculate MSN
 | 
			
		||||
			msn = msn * (double)(vfo[1].ri);
 | 
			
		||||
			msn = msn * (double)(vfo[1].freq) / SI_XTAL_FREQ;
 | 
			
		||||
			vfo[1].msn = msn;
 | 
			
		||||
			
 | 
			
		||||
			si_setmsn(1);
 | 
			
		||||
			si_setmsi(1);
 | 
			
		||||
		}
 | 
			
		||||
		vfo[1].flag = 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -409,92 +485,39 @@ void si_evaluate(void)
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * Initialize the Si5351 VFO registers
 | 
			
		||||
 * Hard initialize Synth registers to: 7.074MHz, CLK1 90 deg ahead, PLLA for CLK 0&1, PLLB for CLK2
 | 
			
		||||
 | Ri=1,
 | 
			
		||||
 | MSi=68,    P1=8192, P2=0,      P3=1
 | 
			
		||||
 | MSN=27.2   P1=2969, P2=600000, P3=1000000
 | 
			
		||||
 */
 | 
			
		||||
void si_init(void)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t data[16];														// I2C trx buffer
 | 
			
		||||
 | 
			
		||||
	vfo[0].freq  = 10000000;	// Check this, should be 7074000?
 | 
			
		||||
	vfo[0].flag  = 0;
 | 
			
		||||
	vfo[0].phase = 1;
 | 
			
		||||
	vfo[0].ri    = 1;
 | 
			
		||||
	vfo[0].msi   = 68;
 | 
			
		||||
	vfo[0].msn   = 27.2;
 | 
			
		||||
	vfo[1].freq  = 10000000;	// Check this, should be 7074000?
 | 
			
		||||
	vfo[1].flag  = 0;
 | 
			
		||||
	vfo[1].phase = 0;
 | 
			
		||||
	vfo[1].ri    = 1;
 | 
			
		||||
	vfo[1].msi   = 68;
 | 
			
		||||
	vfo[1].msn   = 27.2;
 | 
			
		||||
 | 
			
		||||
	// PLLA: MSN P1=0x00000b99, P2=0x000927c0, P3=0x000f4240
 | 
			
		||||
	data[0] = SI_SYNTH_PLLA;
 | 
			
		||||
	data[1] = 0x42;															// MSNA_P3[15:8]
 | 
			
		||||
	data[2] = 0x40;															// MSNA_P3[7:0]
 | 
			
		||||
	data[3] = 0x00;															// 0b000000 , MSNA_P1[17:16]
 | 
			
		||||
	data[4] = 0x0b;															// MSNA_P1[15:8]
 | 
			
		||||
	data[5] = 0x99;															// MSNA_P1[7:0]
 | 
			
		||||
	data[6] = 0xf9;															// MSNA_P3[19:16] , MSNA_P2[19:16]
 | 
			
		||||
	data[7] = 0x27;															// MSNA_P2[15:8]
 | 
			
		||||
	data[8] = 0xc0;															// MSNA_P2[7:0]
 | 
			
		||||
	i2c_write_blocking(i2c0, I2C_VFO, data, 9, false);
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	// PLLB: MSN P1=0x00000b99, P2=0x000927c0, P3=0x000f4240
 | 
			
		||||
	data[0] = SI_SYNTH_PLLB;												// Same content
 | 
			
		||||
	i2c_write_blocking(i2c0, I2C_VFO, data, 9, false);
 | 
			
		||||
 | 
			
		||||
	// MS0 P1=0x00002000, P2=0x00000000, P3=0x00000001, R=1
 | 
			
		||||
	data[0] = SI_SYNTH_MS0;
 | 
			
		||||
	data[1] = 0x00;															// MS0_P3[15:8]
 | 
			
		||||
	data[2] = 0x01;															// MS0_P3[7:0]
 | 
			
		||||
	data[3] = 0x00;															// 0b0, R0_DIV[2:0] , MS0_DIVBY4[1:0] , MS0_P1[17:16] 
 | 
			
		||||
	data[4] = 0x20;															// MS0_P1[15:8]
 | 
			
		||||
	data[5] = 0x00;															// MS0_P1[7:0]
 | 
			
		||||
	data[6] = 0x00;															// MS0_P3[19:16] , MS0_P2[19:16]
 | 
			
		||||
	data[7] = 0x00;															// MS0_P2[15:8]
 | 
			
		||||
	data[8] = 0x00;															// MS0_P2[7:0]
 | 
			
		||||
	i2c_write_blocking(i2c0, I2C_VFO, data, 9, false);
 | 
			
		||||
 | 
			
		||||
	// MS1 P1=0x00002000, P2=0x00000000, P3=0x00000001, R=1
 | 
			
		||||
	data[0] = SI_SYNTH_MS1;													// Same content
 | 
			
		||||
	i2c_write_blocking(i2c0, I2C_VFO, data, 9, false);
 | 
			
		||||
 | 
			
		||||
	// MS2 P1=0x00002000, P2=0x00000000, P3=0x00000001, R=1
 | 
			
		||||
	data[0] = SI_SYNTH_MS2;													// Same content
 | 
			
		||||
	i2c_write_blocking(i2c0, I2C_VFO, data, 9, false);
 | 
			
		||||
 | 
			
		||||
	// Phase offsets for 3 clocks
 | 
			
		||||
	data[0] = SI_CLK0_PHOFF;
 | 
			
		||||
	data[1] = 0x00;															// CLK0: phase 0 deg
 | 
			
		||||
	data[2] = 0x44;															// CLK1: phase 90 deg (=MSi)
 | 
			
		||||
	data[3] = 0x00;															// CLK2: phase 0 deg
 | 
			
		||||
	i2c_write_blocking(i2c0, I2C_VFO, data, 4, false);
 | 
			
		||||
 | 
			
		||||
	// Output port settings for 3 clocks
 | 
			
		||||
	data[0] = SI_CLK0_CTL;
 | 
			
		||||
	data[1] = 0x4d;															// CLK0: INT, PLLA, nonINV, MS, 4mA
 | 
			
		||||
	data[2] = 0x4d;															// CLK1: INT, PLLA, nonINV, MS, 4mA
 | 
			
		||||
	data[3] = 0x6f;															// CLK2: INT, PLLB, nonINV, MS, 8mA
 | 
			
		||||
	i2c_write_blocking(i2c0, I2C_VFO, data, 4, false);
 | 
			
		||||
 | 
			
		||||
	// Disable spread spectrum (startup state is undefined)	
 | 
			
		||||
	data[0] = SI_SS_EN;
 | 
			
		||||
	data[1] = 0x00;
 | 
			
		||||
	i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
 | 
			
		||||
	
 | 
			
		||||
	// Reset both PLL
 | 
			
		||||
	data[0] = SI_PLL_RESET;
 | 
			
		||||
	data[1] = 0xa0;
 | 
			
		||||
	i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
 | 
			
		||||
	// Initialize VFO values
 | 
			
		||||
	vfo[0].freq  = 7074000;
 | 
			
		||||
	vfo[0].flag  = 0;
 | 
			
		||||
	vfo[0].phase = PH090;
 | 
			
		||||
	vfo[0].ri    = 1;
 | 
			
		||||
	vfo[0].msi   = 106;
 | 
			
		||||
	vfo[0].msn   = ((double)vfo[0].freq*vfo[0].msi)/(double)SI_XTAL_FREQ;
 | 
			
		||||
	
 | 
			
		||||
	// Enable only VFO0 outputs	
 | 
			
		||||
	data[0] = SI_CLK_OE;
 | 
			
		||||
	data[1] = ~SI_VFO0_DISABLE;
 | 
			
		||||
	i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
 | 
			
		||||
	vfo[1].freq  = 10000000;
 | 
			
		||||
	vfo[1].flag  = 0;
 | 
			
		||||
	vfo[1].phase = PH000;
 | 
			
		||||
	vfo[1].ri    = 1;
 | 
			
		||||
	vfo[1].msi   = 76;
 | 
			
		||||
	vfo[1].msn   = ((double)vfo[1].freq*vfo[1].msi)/(double)SI_XTAL_FREQ;
 | 
			
		||||
	
 | 
			
		||||
	// Commit settings
 | 
			
		||||
	si_setmsn(0);
 | 
			
		||||
	si_setmsi(0);	
 | 
			
		||||
	si_setmsn(1);
 | 
			
		||||
	si_setmsi(1);	
 | 
			
		||||
 | 
			
		||||
	// Enable only VFO 0 outputs	
 | 
			
		||||
	si_enable(0, true);
 | 
			
		||||
	si_enable(1, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										9
									
								
								si5351.h
								
								
								
								
							
							
						
						
									
										9
									
								
								si5351.h
								
								
								
								
							| 
						 | 
				
			
			@ -10,13 +10,18 @@
 | 
			
		|||
 * VFO 0 is a quadrature clock on outputs 0 and 1, 
 | 
			
		||||
 * VFO 1 is a regular clock on output 2.
 | 
			
		||||
 *
 | 
			
		||||
 * The quadrature clock allows to set shared frequency and phase offsets of 0, 90, 180 and 270 deg
 | 
			
		||||
 * The regular clock just allows to set frequency, phase is ignored
 | 
			
		||||
 * VFO 0 allows to set frequency and phase offsets of 0-90-180-270 deg (delay clk1 wrt clk0)
 | 
			
		||||
 * VFO 1 just allows to set frequency, phase is ignored
 | 
			
		||||
 * 
 | 
			
		||||
 * Use the 'set' functions to change VFO settings.
 | 
			
		||||
 * Make regular calls to the 'evaluate' function to commit the changes (if any).
 | 
			
		||||
 * To get smooth tuning, a suggested interval is 0.1sec, e.g. from a timer loop
 | 
			
		||||
 *
 | 
			
		||||
 * See si5351.c for more information 
 | 
			
		||||
 *
 | 
			
		||||
 */ 
 | 
			
		||||
 | 
			
		||||
// Phase definitions for si_setphase()
 | 
			
		||||
#define PH000	0
 | 
			
		||||
#define PH090	1
 | 
			
		||||
#define PH180	2
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue