kopia lustrzana https://github.com/ArjanteMarvelde/uSDR-pico
V3.03
Added automatic bandfilter switching Optimized si5351 driver a bitpull/13/head
rodzic
de115a043c
commit
53e7c155f5
9
dsp.h
9
dsp.h
|
@ -7,10 +7,15 @@
|
|||
* Author: Arjan te Marvelde
|
||||
*
|
||||
* See dsp.c for more information
|
||||
*
|
||||
* HERE THE SELECTION BETWEEN TIME OR FREQUENCY DOMAIN PROCESSING IS MADE
|
||||
* DO THIS BY SETTING THE #define DSP_FFT TO 0 OR TO 1 RESPECTIVELY
|
||||
*
|
||||
*/
|
||||
|
||||
// 1 for FFT, 0 for time domain processing
|
||||
#define DSP_FFT 0
|
||||
#define DSP_FFT 1
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
|
43
hmi.c
43
hmi.c
|
@ -115,11 +115,12 @@ char hmi_o_vox [HMI_NVOX][8] = {"NoVOX","VOX-L","VOX-M","VOX-H"}; // Indexed b
|
|||
char hmi_o_bpf [HMI_NBPF][8] = {"<2.5","2-6","5-12","10-24","20-40"}; // Indexed by
|
||||
|
||||
// Map option to setting
|
||||
int hmi_mode[4] = {MODE_USB, MODE_LSB, MODE_AM, MODE_CW};
|
||||
int hmi_agc[3] = {AGC_NONE, AGC_SLOW, AGC_FAST};
|
||||
int hmi_pre[5] = {REL_ATT_30, REL_ATT_20, REL_ATT_10, REL_ATT_00, REL_PRE_10};
|
||||
int hmi_vox[4] = {VOX_OFF, VOX_LOW, VOX_MEDIUM, VOX_HIGH};
|
||||
int hmi_bpf[5] = {REL_LPF2, REL_BPF6, REL_BPF12, REL_BPF24, REL_BPF40};
|
||||
int hmi_mode[HMI_NMODE] = {MODE_USB, MODE_LSB, MODE_AM, MODE_CW};
|
||||
int hmi_agc[HMI_NAGC] = {AGC_NONE, AGC_SLOW, AGC_FAST};
|
||||
int hmi_pre[HMI_NPRE] = {REL_ATT_30, REL_ATT_20, REL_ATT_10, REL_ATT_00, REL_PRE_10};
|
||||
int hmi_vox[HMI_NVOX] = {VOX_OFF, VOX_LOW, VOX_MEDIUM, VOX_HIGH};
|
||||
int hmi_bpf[HMI_NBPF] = {REL_LPF2, REL_BPF6, REL_BPF12, REL_BPF24, REL_BPF40};
|
||||
|
||||
|
||||
int hmi_state, hmi_option; // Current state and menu option selection
|
||||
int hmi_sub[HMI_NSTATES] = {4,0,0,3,0,2}; // Stored option selection per state
|
||||
|
@ -159,7 +160,7 @@ void hmi_handler(uint8_t event)
|
|||
switch (event)
|
||||
{
|
||||
case HMI_E_ENTER: // Commit current value
|
||||
SI_SETFREQ(0, HMI_MULFREQ*(hmi_freq-FC_OFFSET)); // Commit frequency
|
||||
si_setfreq(0, HMI_MULFREQ*(hmi_freq-FC_OFFSET)); // Commit frequency
|
||||
break;
|
||||
case HMI_E_ESCAPE: // Enter submenus
|
||||
hmi_sub[hmi_state] = hmi_option; // Store selection (i.e. digit)
|
||||
|
@ -291,8 +292,8 @@ void hmi_init(void)
|
|||
hmi_option = 4; // Active kHz digit
|
||||
hmi_freq = 7074000UL; // Initial frequency
|
||||
|
||||
SI_SETFREQ(0, HMI_MULFREQ*(hmi_freq-FC_OFFSET)); // Set freq to 7074 kHz (depends on mixer type)
|
||||
SI_SETPHASE(0, 1); // Set phase to 90deg (depends on mixer type)
|
||||
si_setfreq(0, HMI_MULFREQ*(hmi_freq-FC_OFFSET)); // Set freq to 7074 kHz (depends on mixer type)
|
||||
si_setphase(0, 1); // Set phase to 90deg (depends on mixer type)
|
||||
|
||||
ptt_state = PTT_DEBOUNCE;
|
||||
ptt_active = false;
|
||||
|
@ -311,6 +312,7 @@ void hmi_init(void)
|
|||
*/
|
||||
void hmi_evaluate(void)
|
||||
{
|
||||
int band;
|
||||
char s[32];
|
||||
|
||||
// Print top line of display
|
||||
|
@ -373,11 +375,28 @@ void hmi_evaluate(void)
|
|||
if (ptt_state == 0) // Set PTT when debounced level low
|
||||
ptt_active = true;
|
||||
|
||||
|
||||
|
||||
/* Set parameters corresponding to latest entered option value */
|
||||
SI_SETFREQ(0, HMI_MULFREQ*(hmi_freq-FC_OFFSET)); // Always set frequency
|
||||
if (hmi_update) // Others only when indicated
|
||||
{
|
||||
|
||||
// Frequency might have been changed in hmi_handler, so set anyway
|
||||
si_setfreq(0, HMI_MULFREQ*(hmi_freq-FC_OFFSET));
|
||||
|
||||
// Check bandfilter setting (thanks Alex)
|
||||
if (hmi_freq < 2500000UL) band = REL_LPF2;
|
||||
else if (hmi_freq < 6000000UL) band = REL_BPF6;
|
||||
else if (hmi_freq < 12000000UL) band = REL_BPF12;
|
||||
else if (hmi_freq < 24000000UL) band = REL_BPF24;
|
||||
else band = REL_BPF40;
|
||||
if (band != hmi_bpf[hmi_sub[HMI_S_BPF]]) // Force update when changed
|
||||
{
|
||||
hmi_bpf[hmi_sub[HMI_S_BPF]] = band;
|
||||
hmi_update = true;
|
||||
}
|
||||
|
||||
// Update peripherals according to menu setting
|
||||
// For frequency si5351 is set directly, HMI top line follows
|
||||
if (hmi_update)
|
||||
{
|
||||
dsp_setmode(hmi_sub[HMI_S_MODE]);
|
||||
dsp_setvox(hmi_sub[HMI_S_VOX]);
|
||||
dsp_setagc(hmi_sub[HMI_S_AGC]);
|
||||
|
|
19
relay.c
19
relay.c
|
@ -6,15 +6,18 @@
|
|||
*
|
||||
* Two PCF8574 expanders are on the I2C bus, one on the RX and one on the BPF board.
|
||||
* The RX (0x42) bit assignments:
|
||||
* 0: Enable -20dB attenuator
|
||||
* 1: Enable -10dB attenuator
|
||||
* 2: Enable +10dB pre-amplifier
|
||||
* 0x03: Enable -20dB and -10dB attenuators
|
||||
* 0x01: Enable -20dB attenuator
|
||||
* 0x02: Enable -10dB attenuator
|
||||
* 0x04: Enable +10dB pre-amplifier
|
||||
* 0x00: No attenuator or pre-amp
|
||||
*
|
||||
* The BPF (0x40) bit assignments:
|
||||
* 0: Enable LPF 2.5 MHz
|
||||
* 1: Enable BPF 2.0 - 6.0 MHz
|
||||
* 2: Enable BPF 5.0 -12.0 MHz
|
||||
* 3: Enable BPF 10.0 -24.0 MHz
|
||||
* 4: Enable BPF 20.0 -40.0 MHz
|
||||
* 0x01: Enable LPF 2.5 MHz
|
||||
* 0x02: Enable BPF 2.0 - 6.0 MHz
|
||||
* 0x04: Enable BPF 5.0 -12.0 MHz
|
||||
* 0x08: Enable BPF 10.0 -24.0 MHz
|
||||
* 0x10: Enable BPF 20.0 -40.0 MHz
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
|
160
si5351.c
160
si5351.c
|
@ -9,13 +9,13 @@
|
|||
|
||||
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 channel i can be derived from either.
|
||||
Fvco is between 600MHz and 900MHz, but the spec in reality is more relaxed.
|
||||
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.
|
||||
Only certain values of MSi and Ri are allowed when quadrature output is needed.
|
||||
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.
|
||||
|
||||
+-------+ +-------+ +------+
|
||||
- Fxtal --> | * MSN | -- Fvco --> | / MSi | --> | / Ri | -- Fout -->
|
||||
|
@ -27,28 +27,24 @@ Details:
|
|||
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)
|
||||
|
||||
---Derivation of register values, for MSN and MSi---
|
||||
---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)
|
||||
|
||||
This VFO implementation assumes PLLA is used for clk0 and clk1, PLLB is used for clk2
|
||||
This VFO implementation assumes PLLA is used for VFO0 (clk0 and clk1), and PLLB is used for VFO1 (clk2)
|
||||
|
||||
Algorithm to get from frequency to synthesizer settings:
|
||||
(this assumes that the current settings are consistent, i.e. must be initialized at startup)
|
||||
| calculate new MSN from the desired Fout, based on current Ri and MSi
|
||||
The algorithm to get from required Fout to synthesizer settings:
|
||||
| calculate new <MSN> from the desired <Fout>, based on the current <Ri> and <MSi>
|
||||
| if MSN is still inside [600/Fxtal, 900/Fxtal]
|
||||
| then
|
||||
| just write the MSN parameter registers
|
||||
| just update the MSN related registers
|
||||
| else
|
||||
| re-calculate MSi, Ri and MSN from desired Fout
|
||||
| write the MSi and Ri parameter registers, including phase offset (MSi equals phase offset for 90 deg, use INV to shift 180deg more)
|
||||
| write the MSN parameter registers
|
||||
| re-calculate <MSi>, <Ri> and <MSN> from desired <Fout>
|
||||
| write the <MSi> and <Ri> parameter registers, including phase offset (MSi equals phase offset for 90 deg, use INV to shift 180deg more)
|
||||
| write the <MSN> parameter registers
|
||||
| reset PLL
|
||||
|
||||
Ri=128 for Fout <1 MHz
|
||||
Ri= 32 for Fout 1-6 MHz
|
||||
Ri= 1 for Fout >6 MHz
|
||||
(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
|
||||
|
@ -70,7 +66,10 @@ 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),
|
||||
- Set INV bit (reg 17) to add 180 deg.
|
||||
NOTE: Phase offsets only work when Ri = 1, this means minimum Fout is 4.762MHz at Fvco = 600MHz. Additional flip/flop dividers are needed to get 80m band frequencies, or Fvco must be tuned below spec.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Control Si5351 (see AN619):
|
||||
|
@ -159,10 +158,12 @@ Control Si5351 (see AN619):
|
|||
#define SI_PLL_RESET 177
|
||||
#define SI_XTAL_LOAD 183
|
||||
|
||||
// CLK_OE register 3 values
|
||||
// CLK_OE register 3 masks
|
||||
#define SI_CLK0_ENABLE 0b00000001 // Enable clock 0 output
|
||||
#define SI_CLK1_ENABLE 0b00000010 // Enable clock 1 output
|
||||
#define SI_CLK2_ENABLE 0b00000100 // Enable clock 2 output
|
||||
#define SI_VFO0_DISABLE 0b00000011 // Set bits to disable
|
||||
#define SI_VFO1_DISABLE 0b00000100 // Set bits to disable
|
||||
|
||||
// CLKi_CTL register 16, 17, 18 values
|
||||
// Normally 0x4f for clk 0 and 1, 0x6f for clk 2
|
||||
|
@ -184,8 +185,59 @@ Control Si5351 (see AN619):
|
|||
#define SI_PLL_C 1000000UL // Parameter c for PLL-A and -B setting
|
||||
|
||||
|
||||
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 msi; // MSi parameter a (4, 6, 8 .. 126)
|
||||
double msn; // MSN (24.0 .. 35.9999)
|
||||
} vfo_t;
|
||||
vfo_t vfo[2]; // 0: clk0 / clk1 1: clk2
|
||||
|
||||
vfo_t vfo[2]; // 0: clk0 & clk1 1: clk2
|
||||
|
||||
void si_setfreq(int i, uint32_t f)
|
||||
{
|
||||
if ((i<0)||(i>1)) return; // Check VFO range
|
||||
if (f>150000000) return; // Check frequency range
|
||||
if (vfo[i].freq == f) return; // Anything to set at all?
|
||||
|
||||
vfo[i].freq = f; // Entry checks pass, so do the actual setting
|
||||
vfo[i].flag = 1;
|
||||
}
|
||||
|
||||
void si_setphase(int i, uint8_t p)
|
||||
{
|
||||
if (i!=0) return; // Check VFO range
|
||||
if (p>3) return; // Check phase range
|
||||
if (vfo[i].phase == p) return; // Anything to set at all?
|
||||
|
||||
vfo[i].phase = p; // Entry checks pass, so do the actual setting
|
||||
vfo[i].flag = 1;
|
||||
}
|
||||
|
||||
void si_enable(int i, bool en)
|
||||
{
|
||||
uint8_t data[2];
|
||||
|
||||
if ((i<0)||(i>1)) return; // Check VFO range
|
||||
|
||||
data[0] = SI_CLK_OE; // Read OE register
|
||||
i2c_write_blocking(i2c0, I2C_VFO, &data[0], 1, true);
|
||||
i2c_read_blocking(i2c0, I2C_VFO, &data[1], 1, false);
|
||||
|
||||
data[0] = SI_CLK_OE;
|
||||
if (i==0)
|
||||
{
|
||||
data[1] = en ? data[1]&~SI_VFO0_DISABLE : data[1]|SI_VFO0_DISABLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
data[1] = en ? data[1]&~SI_VFO1_DISABLE : data[1]|SI_VFO1_DISABLE;
|
||||
}
|
||||
i2c_write_blocking(i2c0, I2C_VFO, &data[0], 2, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* read contents of SI5351 registers, from reg to reg+len-1, output in data array
|
||||
|
@ -207,23 +259,26 @@ int si_getreg(uint8_t *data, uint8_t reg, uint8_t len)
|
|||
* Optimize for speed, this may be called with short intervals
|
||||
* See also SiLabs AN619 section 3.2
|
||||
*/
|
||||
void si_setmsn(uint8_t i)
|
||||
void si_setmsn(int i)
|
||||
{
|
||||
uint8_t data[16]; // I2C trx buffer
|
||||
uint32_t P1, P2; // MSN parameters
|
||||
uint32_t A;
|
||||
uint32_t B;
|
||||
|
||||
i=(i>0?1:0);
|
||||
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 - (float)A) * SI_PLL_C); // B is C * fraction part of MSN (C is a constant)
|
||||
P2 = (uint32_t)(floor((float)(128 * B) / (float)SI_PLL_C));
|
||||
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));
|
||||
P1 = (uint32_t)(128 * A + P2 - 512);
|
||||
P2 = (uint32_t)(128 * B - SI_PLL_C * P2);
|
||||
|
||||
// transfer registers
|
||||
data[0] = (i==0?SI_SYNTH_PLLA:SI_SYNTH_PLLB);
|
||||
// transfer PLL A or PLL B registers
|
||||
if (i==0)
|
||||
data[0] = SI_SYNTH_PLLA;
|
||||
else
|
||||
data[0] = SI_SYNTH_PLLB;
|
||||
data[1] = (SI_PLL_C & 0x0000FF00) >> 8;
|
||||
data[2] = (SI_PLL_C & 0x000000FF);
|
||||
data[3] = (P1 & 0x00030000) >> 16;
|
||||
|
@ -252,7 +307,10 @@ void si_setmsi(uint8_t i)
|
|||
R = vfo[i].ri;
|
||||
R = (R&0xf0) ? ((R&0xc0)?((R&0x80)?7:6):(R&0x20)?5:4) : ((R&0x0c)?((R&0x08)?3:2):(R&0x02)?1:0); // quick log2(r)
|
||||
|
||||
data[0] = (i==0?SI_SYNTH_MS0:SI_SYNTH_MS2);
|
||||
if (i==0)
|
||||
data[0] = SI_SYNTH_MS0;
|
||||
else
|
||||
data[0] = SI_SYNTH_MS2;
|
||||
data[1] = 0x00;
|
||||
data[2] = 0x01;
|
||||
data[3] = ((P1 & 0x00030000) >> 16) | (R << 4 );
|
||||
|
@ -272,18 +330,18 @@ void si_setmsi(uint8_t i)
|
|||
if (vfo[0].phase&1) // Phase is either 90 or 270 deg?
|
||||
{
|
||||
data[0] = SI_CLK1_PHOFF;
|
||||
data[1] = vfo[0].msi;
|
||||
data[1] = vfo[0].msi; // offset == MSi for 90deg
|
||||
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
||||
}
|
||||
else // Phase is 0 or 180 deg
|
||||
{
|
||||
data[0] = SI_CLK1_PHOFF;
|
||||
data[1] = 0;
|
||||
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?
|
||||
{
|
||||
data[0] = SI_CLK1_CTL;
|
||||
data[0] = SI_CLK1_CTL; // Then set the invert flag
|
||||
data[1] = 0x5d; // CLK1: INT, PLLA, INV, MS, 8mA
|
||||
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
||||
}
|
||||
|
@ -304,13 +362,13 @@ void si_setmsi(uint8_t i)
|
|||
*/
|
||||
void si_evaluate(void)
|
||||
{
|
||||
float msn;
|
||||
double msn;
|
||||
|
||||
if (vfo[0].flag)
|
||||
{
|
||||
msn = (float)(vfo[0].msi); // Re-calculate MSN
|
||||
msn = msn * (float)(vfo[0].ri);
|
||||
msn = msn * (float)(vfo[0].freq) / SI_XTAL_FREQ;
|
||||
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))
|
||||
{
|
||||
vfo[0].msn = msn;
|
||||
|
@ -318,15 +376,25 @@ void si_evaluate(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
vfo[0].ri = (vfo[0].freq<1000000)?128:((vfo[0].freq<3000000)?32:1); // Pre-scale Ri, stretch down Ri=1 range
|
||||
if ((vfo[0].freq >= 3000000)&&(vfo[0].freq < 6000000)) // Low end of Ri=1 range
|
||||
vfo[0].msi = (uint8_t)126; // Maximum MSi on Fvco=(4x126)MHz
|
||||
// Pre-scale Ri, stretch down Ri=1 range
|
||||
if (vfo[0].freq<1000000)
|
||||
vfo[0].ri = 128;
|
||||
else if (vfo[0].freq<3000000)
|
||||
vfo[0].ri = 32;
|
||||
else
|
||||
vfo[0].msi = (uint8_t)(750000000UL / (vfo[0].freq * vfo[0].ri)) & 0xfe; // Calculate MSi on Fvco=750MHz
|
||||
msn = (float)(vfo[0].msi); // Re-calculate MSN
|
||||
msn = msn * (float)(vfo[0].ri);
|
||||
msn = msn * (float)(vfo[0].freq) / SI_XTAL_FREQ;
|
||||
vfo[0].ri = 1;
|
||||
|
||||
// Set MSi
|
||||
if ((vfo[0].freq >= 3000000)&&(vfo[0].freq < 6000000)) // Handle Low end of Ri=1 range
|
||||
vfo[0].msi = (uint8_t)126; // Maximum MSi on Fvco=(4x126)MHz
|
||||
else // Or calculate MSi on Fvco=750MHz
|
||||
vfo[0].msi = (uint8_t)(750000000UL / (vfo[0].freq * vfo[0].ri)) & 0x000000fe;
|
||||
|
||||
msn = (double)(vfo[0].msi); // Re-calculate MSN
|
||||
msn = msn * (double)(vfo[0].ri);
|
||||
msn = msn * (double)(vfo[0].freq) / SI_XTAL_FREQ;
|
||||
vfo[0].msn = msn;
|
||||
|
||||
si_setmsn(0);
|
||||
si_setmsi(0);
|
||||
}
|
||||
|
@ -424,9 +492,9 @@ void si_init(void)
|
|||
data[1] = 0xa0;
|
||||
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
||||
|
||||
// Enable all outputs
|
||||
// Enable only VFO0 outputs
|
||||
data[0] = SI_CLK_OE;
|
||||
data[1] = 0x00;
|
||||
data[1] = ~SI_VFO0_DISABLE;
|
||||
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
||||
}
|
||||
|
||||
|
|
31
si5351.h
31
si5351.h
|
@ -6,31 +6,28 @@
|
|||
* Created: March 2021
|
||||
* Author: Arjan
|
||||
*
|
||||
* Driver for Si5351A chip.
|
||||
* 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
|
||||
*
|
||||
* See si5351.c for more information
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
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 msi; // MSi parameter a (4, 6, 8 .. 126)
|
||||
float msn; // MSN (24.0 .. 35.9999)
|
||||
} vfo_t;
|
||||
extern vfo_t vfo[2]; // Table contains all control data for three clk outputs, but 0 and 1 are coupled in vfo[0]
|
||||
#define PH000 0
|
||||
#define PH090 1
|
||||
#define PH180 2
|
||||
#define PH270 3
|
||||
|
||||
int si_getreg(uint8_t *data, uint8_t reg, uint8_t len);
|
||||
void si_init(void);
|
||||
void si_evaluate(void);
|
||||
void si_setfreq(int i, uint32_t f);
|
||||
void si_setphase(int i, uint8_t p);
|
||||
void si_enable(int i, bool en);
|
||||
|
||||
#define SI_GETFREQ(i) ((((i)>=0)&&((i)<2))?vfo[(i)].freq:0)
|
||||
#define SI_INCFREQ(i, d) if ((((i)>=0)&&((i)<2))&&((vfo[(i)].freq)<(150000000-(d)))) { vfo[(i)].freq += (d); vfo[(i)].flag = 1;}
|
||||
#define SI_DECFREQ(i, d) if ((((i)>=0)&&((i)<2))&&((vfo[(i)].freq)>(d))) { (vfo[(i)].freq) -= (d); vfo[(i)].flag = 1;}
|
||||
#define SI_SETFREQ(i, f) if ((((i)>=0)&&((i)<2))&&((f)<150000000)) { vfo[(i)].freq = (f); vfo[(i)].flag = 1;}
|
||||
#define SI_SETPHASE(i, p) if (((i)>=0)&&((i)<2)) {vfo[(i)].phase = ((uint8_t)p)&3; vfo[(i)].flag = 1;}
|
||||
|
||||
#endif /* _SI5351_H */
|
Ładowanie…
Reference in New Issue