kopia lustrzana https://github.com/ArjanteMarvelde/uSDR-pico
V3.07
Q&D fix for I2C issue: i2c_write_blocking() returning prematurely, causing misses in register writes. Effect was erratic behaviour of the Si5351 clocks. General fix will follow.pull/13/head
rodzic
2ad6d2b9ba
commit
2e6bf94cb4
208
hmi.c
208
hmi.c
|
@ -147,20 +147,51 @@ bool ptt_active; // Resulting state
|
||||||
#define MAX(x, y) ((x)>(y)?(x):(y)) // Get max value
|
#define MAX(x, y) ((x)>(y)?(x):(y)) // Get max value
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HMI State Machine,
|
* GPIO IRQ callback routine
|
||||||
* Handle event according to current state
|
* Sets the detected event and invokes the HMI state machine
|
||||||
* Code needs to be optimized
|
|
||||||
*/
|
*/
|
||||||
void hmi_handler(uint8_t event)
|
void hmi_callback(uint gpio, uint32_t events)
|
||||||
{
|
{
|
||||||
/* Special case for TUNE state */
|
uint8_t evt=HMI_E_NOEVENT;
|
||||||
|
|
||||||
|
// Decide what the event was
|
||||||
|
switch (gpio)
|
||||||
|
{
|
||||||
|
case GP_ENC_A: // Encoder
|
||||||
|
if (events&GPIO_IRQ_EDGE_FALL)
|
||||||
|
evt = gpio_get(GP_ENC_B)?HMI_E_INCREMENT:HMI_E_DECREMENT;
|
||||||
|
break;
|
||||||
|
case GP_AUX_0: // Enter
|
||||||
|
if (events&GPIO_IRQ_EDGE_FALL)
|
||||||
|
evt = HMI_E_ENTER;
|
||||||
|
break;
|
||||||
|
case GP_AUX_1: // Escape
|
||||||
|
if (events&GPIO_IRQ_EDGE_FALL)
|
||||||
|
evt = HMI_E_ESCAPE;
|
||||||
|
break;
|
||||||
|
case GP_AUX_2: // Previous
|
||||||
|
if (events&GPIO_IRQ_EDGE_FALL)
|
||||||
|
evt = HMI_E_LEFT;
|
||||||
|
break;
|
||||||
|
case GP_AUX_3: // Next
|
||||||
|
if (events&GPIO_IRQ_EDGE_FALL)
|
||||||
|
evt = HMI_E_RIGHT;
|
||||||
|
break;
|
||||||
|
default: // Stray...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** HMI State Machine **/
|
||||||
|
|
||||||
|
// Special case for TUNE state
|
||||||
if (hmi_state == HMI_S_TUNE)
|
if (hmi_state == HMI_S_TUNE)
|
||||||
{
|
{
|
||||||
switch (event)
|
switch (evt)
|
||||||
{
|
{
|
||||||
case HMI_E_ENTER: // Commit current value
|
case HMI_E_ENTER: // Commit current value
|
||||||
si_setfreq(0, HMI_MULFREQ*(hmi_freq-FC_OFFSET)); // Commit frequency
|
// To be defined action
|
||||||
break;
|
break;
|
||||||
case HMI_E_ESCAPE: // Enter submenus
|
case HMI_E_ESCAPE: // Enter submenus
|
||||||
hmi_sub[hmi_state] = hmi_option; // Store selection (i.e. digit)
|
hmi_sub[hmi_state] = hmi_option; // Store selection (i.e. digit)
|
||||||
|
@ -185,8 +216,8 @@ void hmi_handler(uint8_t event)
|
||||||
return; // Early bail-out
|
return; // Early bail-out
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Actions for other states */
|
// Actions for other states
|
||||||
switch (event)
|
switch (evt)
|
||||||
{
|
{
|
||||||
case HMI_E_ENTER:
|
case HMI_E_ENTER:
|
||||||
hmi_sub[hmi_state] = hmi_option; // Store value for selected option
|
hmi_sub[hmi_state] = hmi_option; // Store value for selected option
|
||||||
|
@ -213,102 +244,10 @@ void hmi_handler(uint8_t event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* GPIO IRQ callback routine
|
|
||||||
* Sets the detected event and invokes the HMI state machine
|
|
||||||
*/
|
|
||||||
void hmi_callback(uint gpio, uint32_t events)
|
|
||||||
{
|
|
||||||
uint8_t evt=HMI_E_NOEVENT;
|
|
||||||
|
|
||||||
switch (gpio)
|
|
||||||
{
|
|
||||||
case GP_ENC_A: // Encoder
|
|
||||||
if (events&GPIO_IRQ_EDGE_FALL)
|
|
||||||
evt = gpio_get(GP_ENC_B)?HMI_E_INCREMENT:HMI_E_DECREMENT;
|
|
||||||
break;
|
|
||||||
case GP_AUX_0: // Enter
|
|
||||||
if (events&GPIO_IRQ_EDGE_FALL)
|
|
||||||
evt = HMI_E_ENTER;
|
|
||||||
break;
|
|
||||||
case GP_AUX_1: // Escape
|
|
||||||
if (events&GPIO_IRQ_EDGE_FALL)
|
|
||||||
evt = HMI_E_ESCAPE;
|
|
||||||
break;
|
|
||||||
case GP_AUX_2: // Previous
|
|
||||||
if (events&GPIO_IRQ_EDGE_FALL)
|
|
||||||
evt = HMI_E_LEFT;
|
|
||||||
break;
|
|
||||||
case GP_AUX_3: // Next
|
|
||||||
if (events&GPIO_IRQ_EDGE_FALL)
|
|
||||||
evt = HMI_E_RIGHT;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hmi_handler(evt); // Invoke state machine
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the User interface
|
* Redraw the 16x2 LCD display, representing current state
|
||||||
*/
|
* This function is invoked regularly from the main loop.
|
||||||
void hmi_init(void)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Notes on using GPIO interrupts:
|
|
||||||
* The callback handles interrupts for all GPIOs with IRQ enabled.
|
|
||||||
* Level interrupts don't seem to work properly.
|
|
||||||
* For debouncing, the GPIO pins should be pulled-up and connected to gnd with 100nF.
|
|
||||||
* PTT has separate debouncing logic
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Init input GPIOs
|
|
||||||
gpio_init_mask(GP_MASK_IN);
|
|
||||||
|
|
||||||
// Enable pull-ups
|
|
||||||
gpio_pull_up(GP_ENC_A);
|
|
||||||
gpio_pull_up(GP_ENC_B);
|
|
||||||
gpio_pull_up(GP_AUX_0);
|
|
||||||
gpio_pull_up(GP_AUX_1);
|
|
||||||
gpio_pull_up(GP_AUX_2);
|
|
||||||
gpio_pull_up(GP_AUX_3);
|
|
||||||
gpio_pull_up(GP_PTT);
|
|
||||||
gpio_set_oeover(GP_PTT, GPIO_OVERRIDE_HIGH); // Enable output on PTT GPIO; bidirectional
|
|
||||||
|
|
||||||
// Enable interrupt on level low
|
|
||||||
gpio_set_irq_enabled(GP_ENC_A, GPIO_IRQ_EDGE_ALL, true);
|
|
||||||
gpio_set_irq_enabled(GP_AUX_0, GPIO_IRQ_EDGE_ALL, true);
|
|
||||||
gpio_set_irq_enabled(GP_AUX_1, GPIO_IRQ_EDGE_ALL, true);
|
|
||||||
gpio_set_irq_enabled(GP_AUX_2, GPIO_IRQ_EDGE_ALL, true);
|
|
||||||
gpio_set_irq_enabled(GP_AUX_3, GPIO_IRQ_EDGE_ALL, true);
|
|
||||||
gpio_set_irq_enabled(GP_PTT, GPIO_IRQ_EDGE_ALL, false);
|
|
||||||
|
|
||||||
// Set callback, one for all GPIO, not sure about correctness!
|
|
||||||
gpio_set_irq_enabled_with_callback(GP_ENC_A, GPIO_IRQ_EDGE_ALL, true, hmi_callback);
|
|
||||||
|
|
||||||
// Initialize LCD and set VFO
|
|
||||||
hmi_state = HMI_S_TUNE;
|
|
||||||
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)
|
|
||||||
|
|
||||||
ptt_state = PTT_DEBOUNCE;
|
|
||||||
ptt_active = false;
|
|
||||||
|
|
||||||
dsp_setmode(hmi_sub[HMI_S_MODE]);
|
|
||||||
dsp_setvox(hmi_sub[HMI_S_VOX]);
|
|
||||||
dsp_setagc(hmi_sub[HMI_S_AGC]);
|
|
||||||
relay_setattn(hmi_pre[hmi_sub[HMI_S_PRE]]);
|
|
||||||
relay_setband(hmi_bpf[hmi_sub[HMI_S_BPF]]);
|
|
||||||
hmi_update = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Redraw the display, representing current state
|
|
||||||
* This function is called regularly from the main loop.
|
|
||||||
*/
|
*/
|
||||||
void hmi_evaluate(void)
|
void hmi_evaluate(void)
|
||||||
{
|
{
|
||||||
|
@ -377,9 +316,9 @@ void hmi_evaluate(void)
|
||||||
|
|
||||||
|
|
||||||
/* Set parameters corresponding to latest entered option value */
|
/* Set parameters corresponding to latest entered option value */
|
||||||
|
|
||||||
// Frequency might have been changed in hmi_handler, so set anyway
|
// See if VFO needs update
|
||||||
si_setfreq(0, HMI_MULFREQ*(hmi_freq-FC_OFFSET));
|
si_evaluate(0, hmi_freq);
|
||||||
|
|
||||||
// Check bandfilter setting (thanks Alex)
|
// Check bandfilter setting (thanks Alex)
|
||||||
if (hmi_freq < 2500000UL) band = REL_LPF2;
|
if (hmi_freq < 2500000UL) band = REL_LPF2;
|
||||||
|
@ -407,3 +346,60 @@ void hmi_evaluate(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the User interface
|
||||||
|
*/
|
||||||
|
void hmi_init(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Notes on using GPIO interrupts:
|
||||||
|
* The callback handles interrupts for all GPIOs with IRQ enabled.
|
||||||
|
* Level interrupts don't seem to work properly.
|
||||||
|
* For debouncing, the GPIO pins should be pulled-up and connected to gnd with 100nF.
|
||||||
|
* PTT has separate debouncing logic
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Init input GPIOs
|
||||||
|
gpio_init_mask(GP_MASK_IN);
|
||||||
|
|
||||||
|
// Enable pull-ups
|
||||||
|
gpio_pull_up(GP_ENC_A);
|
||||||
|
gpio_pull_up(GP_ENC_B);
|
||||||
|
gpio_pull_up(GP_AUX_0);
|
||||||
|
gpio_pull_up(GP_AUX_1);
|
||||||
|
gpio_pull_up(GP_AUX_2);
|
||||||
|
gpio_pull_up(GP_AUX_3);
|
||||||
|
gpio_pull_up(GP_PTT);
|
||||||
|
gpio_set_oeover(GP_PTT, GPIO_OVERRIDE_HIGH); // Enable output on PTT GPIO; bidirectional
|
||||||
|
|
||||||
|
// Enable interrupt on level low
|
||||||
|
gpio_set_irq_enabled(GP_ENC_A, GPIO_IRQ_EDGE_ALL, true);
|
||||||
|
gpio_set_irq_enabled(GP_AUX_0, GPIO_IRQ_EDGE_ALL, true);
|
||||||
|
gpio_set_irq_enabled(GP_AUX_1, GPIO_IRQ_EDGE_ALL, true);
|
||||||
|
gpio_set_irq_enabled(GP_AUX_2, GPIO_IRQ_EDGE_ALL, true);
|
||||||
|
gpio_set_irq_enabled(GP_AUX_3, GPIO_IRQ_EDGE_ALL, true);
|
||||||
|
gpio_set_irq_enabled(GP_PTT, GPIO_IRQ_EDGE_ALL, false);
|
||||||
|
|
||||||
|
// Set callback, one for all GPIO, not sure about correctness!
|
||||||
|
gpio_set_irq_enabled_with_callback(GP_ENC_A, GPIO_IRQ_EDGE_ALL, true, hmi_callback);
|
||||||
|
|
||||||
|
// Initialize LCD and set VFO
|
||||||
|
hmi_state = HMI_S_TUNE;
|
||||||
|
hmi_option = 4; // Active kHz digit
|
||||||
|
hmi_freq = 7074000UL; // Initial frequency
|
||||||
|
|
||||||
|
si_setphase(0, 1); // Set phase to 90deg (depends on mixer type)
|
||||||
|
si_evaluate(0, HMI_MULFREQ*(hmi_freq-FC_OFFSET)); // Set freq to 7074 kHz (depends on mixer type)
|
||||||
|
|
||||||
|
ptt_state = PTT_DEBOUNCE;
|
||||||
|
ptt_active = false;
|
||||||
|
|
||||||
|
dsp_setmode(hmi_sub[HMI_S_MODE]);
|
||||||
|
dsp_setvox(hmi_sub[HMI_S_VOX]);
|
||||||
|
dsp_setagc(hmi_sub[HMI_S_AGC]);
|
||||||
|
relay_setattn(hmi_pre[hmi_sub[HMI_S_PRE]]);
|
||||||
|
relay_setband(hmi_bpf[hmi_sub[HMI_S_BPF]]);
|
||||||
|
hmi_update = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
13
monitor.c
13
monitor.c
|
@ -87,7 +87,7 @@ void mon_si(void)
|
||||||
/*
|
/*
|
||||||
* Dumps the VFO registers
|
* Dumps the VFO registers
|
||||||
*/
|
*/
|
||||||
extern vfo_t vfo[2];
|
vfo_t m_vfo;
|
||||||
void mon_vfo(void)
|
void mon_vfo(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -96,11 +96,12 @@ void mon_vfo(void)
|
||||||
i = atoi(argv[1]);
|
i = atoi(argv[1]);
|
||||||
if ((i<0)||(i>1)) return;
|
if ((i<0)||(i>1)) return;
|
||||||
|
|
||||||
printf("Frequency: %lu\n", vfo[i].freq);
|
si_getvfo(i, &m_vfo); // Get local copy
|
||||||
printf("Phase : %u\n", (int)(vfo[i].phase));
|
printf("Frequency: %lu\n", m_vfo.freq);
|
||||||
printf("Ri : %lu\n", (int)(vfo[i].ri));
|
printf("Phase : %u\n", (int)(m_vfo.phase));
|
||||||
printf("MSi : %lu\n", (int)(vfo[i].msi));
|
printf("Ri : %lu\n", (int)(m_vfo.ri));
|
||||||
printf("MSN : %g\n\n", vfo[i].msn);
|
printf("MSi : %lu\n", (int)(m_vfo.msi));
|
||||||
|
printf("MSN : %g\n\n", m_vfo.msn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
159
si5351.c
159
si5351.c
|
@ -189,30 +189,35 @@ Control Si5351 (see AN619):
|
||||||
#define SI_VFO1CTL 0b00101101 // nonINT, PLLB, nonINV, SRC=MS, 4mA
|
#define SI_VFO1CTL 0b00101101 // nonINT, PLLB, nonINV, SRC=MS, 4mA
|
||||||
|
|
||||||
// PLL_RESET register 177 values
|
// PLL_RESET register 177 values
|
||||||
#define SI_PLLB_RST 0b10000000 // Reset PLL B
|
#define SI_PLLB_RST 0b10001100 // Reset PLL B
|
||||||
#define SI_PLLA_RST 0b00100000 // Reset PLL A
|
#define SI_PLLA_RST 0b00101100 // Reset PLL A
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define SI_XTAL_FREQ 25001414UL // Replace with measured crystal frequency of XTAL for CL = 10pF (default)
|
#define SI_XTAL_FREQ 25001414UL // Replace with measured crystal frequency of XTAL for CL = 10pF (default)
|
||||||
#define SI_MSN_LO ((0.4e9)/SI_XTAL_FREQ) // Should be 600M, but 400MHz works too
|
#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_MSN_HI ((0.9e9)/SI_XTAL_FREQ)
|
||||||
|
#define SI_VCO_LO 400000000UL // Should be 600MHz, but 400MHz works too
|
||||||
|
#define SI_VCO_HI 900000000UL
|
||||||
#define SI_PLL_C 1000000UL // Parameter c for PLL-A and -B setting
|
#define SI_PLL_C 1000000UL // Parameter c for PLL-A and -B setting
|
||||||
|
|
||||||
|
|
||||||
vfo_t vfo[2]; // 0: clk0 / clk1 1: clk2
|
vfo_t vfo[2]; // 0: clk0 / clk1 1: clk2
|
||||||
|
|
||||||
|
int si_getvfo(int i, vfo_t *v)
|
||||||
void si_setfreq(int i, uint32_t f)
|
|
||||||
{
|
{
|
||||||
if ((i<0)||(i>1)) return; // Check VFO range
|
if ((i<0)||(i>1)) return 0; // 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
|
v->freq = vfo[i].freq;
|
||||||
vfo[i].flag |= 0x01;
|
v->phase = vfo[i].phase;
|
||||||
|
v->ri = vfo[i].ri;
|
||||||
|
v->msi = vfo[i].msi;
|
||||||
|
v->msn = vfo[i].msn;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void si_setphase(int i, uint8_t p)
|
void si_setphase(int i, uint8_t p)
|
||||||
{
|
{
|
||||||
if (i!=0) return; // Check VFO range
|
if (i!=0) return; // Check VFO range
|
||||||
|
@ -220,7 +225,6 @@ void si_setphase(int i, uint8_t p)
|
||||||
if (vfo[i].phase == p) return; // Anything to set at all?
|
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].phase = p; // Entry checks pass, so do the actual setting
|
||||||
vfo[i].flag |= 0x02;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void si_enable(int i, bool en)
|
void si_enable(int i, bool en)
|
||||||
|
@ -309,7 +313,7 @@ void si_setmsn(int i)
|
||||||
P3 = c
|
P3 = c
|
||||||
|
|
||||||
*/
|
*/
|
||||||
void si_setmsi(uint8_t i)
|
void si_setmsi(int i)
|
||||||
{
|
{
|
||||||
uint8_t data[16]; // I2C trx buffer
|
uint8_t data[16]; // I2C trx buffer
|
||||||
uint32_t P1;
|
uint32_t P1;
|
||||||
|
@ -317,7 +321,8 @@ void si_setmsi(uint8_t i)
|
||||||
|
|
||||||
if ((i<0)||(i>1)) return; // Check VFO range
|
if ((i<0)||(i>1)) return; // Check VFO range
|
||||||
|
|
||||||
P1 = (uint32_t)(128*(uint32_t)floor(vfo[i].msi) - 512);
|
P1 = vfo[i].msi; // Upgrade msi to uint32_t
|
||||||
|
P1 = 128*P1-512;
|
||||||
R = vfo[i].ri;
|
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)
|
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)
|
||||||
|
|
||||||
|
@ -353,6 +358,7 @@ void si_setmsi(uint8_t i)
|
||||||
data[1] = 0; // offset == 0 for 0deg
|
data[1] = 0; // offset == 0 for 0deg
|
||||||
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
||||||
}
|
}
|
||||||
|
sleep_us(500);
|
||||||
if ((vfo[0].phase==PH180)||(vfo[0].phase==PH270)) // Phase is 180 or 270 deg?
|
if ((vfo[0].phase==PH180)||(vfo[0].phase==PH270)) // Phase is 180 or 270 deg?
|
||||||
{
|
{
|
||||||
data[0] = SI_CLK0_CTL; // set the invert flag
|
data[0] = SI_CLK0_CTL; // set the invert flag
|
||||||
|
@ -367,112 +373,77 @@ void si_setmsi(uint8_t i)
|
||||||
data[2] = SI_VFO0CTL; // CLK1: nonINV
|
data[2] = SI_VFO0CTL; // CLK1: nonINV
|
||||||
i2c_write_blocking(i2c0, I2C_VFO, data, 3, false);
|
i2c_write_blocking(i2c0, I2C_VFO, data, 3, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset PLL A (use with care, this causes a click)
|
||||||
|
sleep_us(500);
|
||||||
|
data[0] = SI_PLL_RESET;
|
||||||
|
data[1] = SI_PLLA_RST|SI_PLLB_RST;
|
||||||
|
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
data[0] = SI_CLK2_CTL; // set the invert flag
|
data[0] = SI_CLK2_CTL; // set the invert flag
|
||||||
data[1] = SI_VFO1CTL; // CLK2: nonINV
|
data[1] = SI_VFO1CTL; // CLK2: nonINV
|
||||||
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
||||||
}
|
|
||||||
|
// Reset PLL B (use with care, this causes a click)
|
||||||
// Reset associated PLL
|
sleep_us(500);
|
||||||
data[0] = SI_PLL_RESET;
|
data[0] = SI_PLL_RESET;
|
||||||
data[1] = (i==1)?SI_PLLB_RST:SI_PLLA_RST;
|
data[1] = SI_PLLA_RST|SI_PLLB_RST;
|
||||||
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
i2c_write_blocking(i2c0, I2C_VFO, data, 2, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function needs to be invoked at regular intervals, e.g. 10x per sec. See hmi.c
|
* 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
|
* For VFO i, calculate required MSN setting, MSN = MSi*Ri*Fout/Fxtal based on required frequency
|
||||||
|
*
|
||||||
* If still in range,
|
* If still in range,
|
||||||
* then just set MSN registers
|
* then just set MSN registers
|
||||||
* else,
|
* else,
|
||||||
* recalculate MSi and Ri as well
|
* recalculate MSi and Ri as well
|
||||||
* set MSN, MSi and Ri registers (implicitly resets PLL)
|
* set MSN, MSi and Ri registers (implicitly resets PLL)
|
||||||
*/
|
*/
|
||||||
void si_evaluate(void)
|
void si_evaluate(int i, uint32_t freq)
|
||||||
{
|
{
|
||||||
double msn;
|
double msn;
|
||||||
|
uint32_t fvco;
|
||||||
|
|
||||||
if (vfo[0].flag)
|
if ((i<0)||(i>1)) return; // Check VFO range
|
||||||
|
if (vfo[i].freq == freq) return; // Nothing to do
|
||||||
|
|
||||||
|
|
||||||
|
fvco = freq*vfo[i].msi; // Required Fvco
|
||||||
|
if ((fvco>=SI_VCO_LO)&&(fvco<SI_VCO_HI)) // Check MSN range
|
||||||
{
|
{
|
||||||
msn = (double)(vfo[0].msi); // Re-calculate MSN
|
vfo[i].msn = (double)fvco / SI_XTAL_FREQ; // Calculate required MSN
|
||||||
msn = msn * (double)(vfo[0].ri);
|
si_setmsn(i); // Set registers
|
||||||
msn = msn * (double)(vfo[0].freq) / SI_XTAL_FREQ;
|
|
||||||
|
|
||||||
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 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 = 128;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
vfo[0].phase = PH090;
|
|
||||||
|
|
||||||
si_setmsn(0);
|
|
||||||
si_setmsi(0);
|
|
||||||
}
|
|
||||||
vfo[0].flag = 0;
|
|
||||||
}
|
}
|
||||||
if (vfo[1].flag)
|
else
|
||||||
{
|
{
|
||||||
msn = (double)(vfo[1].msi); // Re-calculate MSN
|
// Pre-scale Ri, stretch down Ri=1 range to 3MHz
|
||||||
msn = msn * (double)(vfo[1].ri);
|
// Otherwise use just 32 and 128
|
||||||
msn = msn * (double)(vfo[1].freq) / SI_XTAL_FREQ;
|
vfo[i].ri = (freq<1000000UL)?128:((freq<3000000UL)?32 : 1);
|
||||||
|
|
||||||
if ((msn>=SI_MSN_LO)&&(msn<SI_MSN_HI)) // Check MSN range
|
// Set MSi
|
||||||
{
|
if (freq < 6000000UL) // Handle Low end of Ri=1 range
|
||||||
vfo[1].msn = msn;
|
vfo[i].msi = (uint8_t)126; // Maximum MSi on Fvco=(4x126)MHz
|
||||||
si_setmsn(1);
|
else // Or calculate MSi on Fvco=750MHz
|
||||||
}
|
vfo[i].msi = (uint8_t)((700000000UL / (freq * vfo[i].ri)) & 0x000000fe);
|
||||||
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 = (double)(vfo[i].msi); // Re-calculate MSN
|
||||||
msn = msn * (double)(vfo[1].ri);
|
msn = msn * (double)(vfo[i].ri);
|
||||||
msn = msn * (double)(vfo[1].freq) / SI_XTAL_FREQ;
|
msn = msn * (double)(vfo[i].freq) / SI_XTAL_FREQ;
|
||||||
vfo[1].msn = msn;
|
vfo[i].msn = msn;
|
||||||
|
|
||||||
si_setmsn(1);
|
vfo[i].phase = (i==1)?PH000:PH090; // Hard coded phase
|
||||||
si_setmsi(1);
|
|
||||||
}
|
si_setmsn(i);
|
||||||
vfo[1].flag = 0;
|
si_setmsi(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfo[i].freq = freq; // Adopt new freq
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -497,14 +468,12 @@ void si_init(void)
|
||||||
|
|
||||||
// Initialize VFO values
|
// Initialize VFO values
|
||||||
vfo[0].freq = 7074000;
|
vfo[0].freq = 7074000;
|
||||||
vfo[0].flag = 0;
|
|
||||||
vfo[0].phase = PH090;
|
vfo[0].phase = PH090;
|
||||||
vfo[0].ri = 1;
|
vfo[0].ri = 1;
|
||||||
vfo[0].msi = 106;
|
vfo[0].msi = 106;
|
||||||
vfo[0].msn = ((double)vfo[0].freq*vfo[0].msi)/(double)SI_XTAL_FREQ;
|
vfo[0].msn = ((double)vfo[0].freq*vfo[0].msi)/(double)SI_XTAL_FREQ;
|
||||||
|
|
||||||
vfo[1].freq = 10000000;
|
vfo[1].freq = 10000000;
|
||||||
vfo[1].flag = 0;
|
|
||||||
vfo[1].phase = PH000;
|
vfo[1].phase = PH000;
|
||||||
vfo[1].ri = 1;
|
vfo[1].ri = 1;
|
||||||
vfo[1].msi = 76;
|
vfo[1].msi = 76;
|
||||||
|
|
9
si5351.h
9
si5351.h
|
@ -30,7 +30,6 @@
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint32_t freq; // type can hold up to 4GHz
|
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 phase; // in quarter waves (0, 1, 2, 3)
|
||||||
uint8_t ri; // Ri (1 .. 128), but should be 1 for VFO 0
|
uint8_t ri; // Ri (1 .. 128), but should be 1 for VFO 0
|
||||||
uint8_t msi; // MSi parameter a (4, 6, 8 .. 126)
|
uint8_t msi; // MSi parameter a (4, 6, 8 .. 126)
|
||||||
|
@ -38,12 +37,12 @@ typedef struct
|
||||||
} vfo_t;
|
} vfo_t;
|
||||||
|
|
||||||
|
|
||||||
int si_getreg(uint8_t *data, uint8_t reg, uint8_t len);
|
int si_getreg(uint8_t *buffer, uint8_t reg, uint8_t len);
|
||||||
void si_init(void);
|
int si_getvfo(int i, vfo_t *v);
|
||||||
void si_evaluate(void);
|
|
||||||
void si_setfreq(int i, uint32_t f);
|
|
||||||
void si_setphase(int i, uint8_t p);
|
void si_setphase(int i, uint8_t p);
|
||||||
void si_enable(int i, bool en);
|
void si_enable(int i, bool en);
|
||||||
|
void si_init(void);
|
||||||
|
void si_evaluate(int i, uint32_t freq);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _SI5351_H */
|
#endif /* _SI5351_H */
|
4
uSDR.c
4
uSDR.c
|
@ -86,6 +86,7 @@ int main()
|
||||||
* i2c0 is used for the si5351 interface
|
* i2c0 is used for the si5351 interface
|
||||||
* i2c1 is used for the LCD and all other interfaces
|
* i2c1 is used for the LCD and all other interfaces
|
||||||
* if the display cannot keep up, try lowering the i2c1 frequency
|
* if the display cannot keep up, try lowering the i2c1 frequency
|
||||||
|
* Do not invoke i2c using functions from interrupt handlers!
|
||||||
*/
|
*/
|
||||||
i2c_init(i2c0, 400000); // i2c0 initialisation at 400Khz
|
i2c_init(i2c0, 400000); // i2c0 initialisation at 400Khz
|
||||||
gpio_set_function(I2C0_SDA, GPIO_FUNC_I2C);
|
gpio_set_function(I2C0_SDA, GPIO_FUNC_I2C);
|
||||||
|
@ -112,9 +113,8 @@ int main()
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
sem_acquire_blocking(&loop_sem); // Wait until timer callback releases sem
|
sem_acquire_blocking(&loop_sem); // Wait until timer callback releases sem
|
||||||
|
hmi_evaluate(); // Refresh HMI (and VFO, BPF, etc)
|
||||||
mon_evaluate(); // Check monitor input
|
mon_evaluate(); // Check monitor input
|
||||||
si_evaluate(); // Refresh VFO settings
|
|
||||||
hmi_evaluate(); // Refresh HMI
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Ładowanie…
Reference in New Issue