kopia lustrzana https://github.com/ArjanteMarvelde/uSDR-pico
Porównaj commity
3 Commity
32a6ca85d3
...
b43b223dba
Autor | SHA1 | Data |
---|---|---|
ArjanteMarvelde | b43b223dba | |
ArjanteMarvelde | 944f960cb2 | |
ArjanteMarvelde | 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
|
||||
|
|
299
si5351.c
299
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.
|
||||
|
||||
Tuning stragtegy:
|
||||
MSi and Ri are selected to be in the ballpark of desired frequency range.
|
||||
MSN is then used for tuning Fout.
|
||||
|
||||
+-------+ +-------+ +------+
|
||||
- Fxtal --> | * MSN | -- Fvco --> | / MSi | --> | / Ri | -- 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)
|
||||
|
||||
|
||||
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
|
||||
|
||||
MSN = MSi*Ri*Fout/Fxtal (should be between 24 and 36)
|
||||
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. d=[4, 6, 8..126], e=0 and f=100000, and set INT bits in reg 22, 23.
|
||||
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.
|
||||
|
||||
|
@ -171,7 +183,8 @@ Control Si5351 (see AN619):
|
|||
#define SI_CLK_PLL 0b00100000 // Select PLL B as MS source (default 0 = PLL A)
|
||||
#define SI_CLK_INV 0b00010000 // Invert output (i.e. phase + 180deg)
|
||||
#define SI_CLK_SRC 0b00001100 // Select output source: 11=MS, 00=XTAL direct
|
||||
#define SI_CLK_DRV 0b00000011 // Select output drive, increasingly: 2-4-6-8 mA (best risetime, use max = 11)
|
||||
#define SI_CLK_DRV 0b00000011 // Select output drive, increasingly: 2-4-6-8 mA
|
||||
// Play with these to get a nice block output
|
||||
|
||||
// PLL_RESET register 177 values
|
||||
#define SI_PLLB_RST 0b10000000 // Reset PLL B
|
||||
|
@ -180,7 +193,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 +203,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 +243,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 +271,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 +313,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 +327,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 +347,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&(PH090|PH270)) // Phase is 90 or 270 deg?
|
||||
{
|
||||
data[0] = SI_CLK1_PHOFF;
|
||||
data[1] = vfo[0].msi; // offset == MSi for 90deg
|
||||
|
@ -339,12 +365,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] = 0x1d; // CLK1: nonINT, PLLA, INV, MS, 4mA
|
||||
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
data[0] = SI_CLK1_CTL; // clear the invert flag
|
||||
data[1] = 0x0d; // CLK1: nonINT, PLLA, nonINV, MS, 4mA
|
||||
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data[0] = SI_CLK2_CTL; // set the invert flag
|
||||
data[1] = 0x2d; // CLK2: nonINT, PLLB, nonINV, MS, 4mA
|
||||
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
||||
}
|
||||
|
||||
// Reset associated PLL
|
||||
|
@ -355,10 +393,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 +410,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 +445,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 +486,46 @@ 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);
|
||||
// First time init of clock control registers
|
||||
data[0] = SI_CLK0_CTL;
|
||||
data[1] = 0x0d; // CLK0: nonINT, PLLA, nonINV, MS, 4mA
|
||||
data[2] = 0x0d; // CLK1: nonINT, PLLA, nonINV, MS, 4mA
|
||||
data[3] = 0x2d; // CLK2: nonINT, PLLB, nonINV, MS, 4mA
|
||||
i2c_write_blocking(i2c0, I2C_VFO, data, 4, 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;
|
||||
|
||||
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 VFO0 outputs
|
||||
data[0] = SI_CLK_OE;
|
||||
data[1] = ~SI_VFO0_DISABLE;
|
||||
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
||||
// 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