diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 3de6dc15..3ff0318a 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -136,9 +136,6 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom) /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ si5351c_configure_multisynth(2, 0, 0, 0, 0);//p1 doesn't matter - /* MS0/CLK3 is the source for the external clock output. */ - //si5351c_configure_multisynth(3, p1, 0, 1, 0); // no clk out - return true; } @@ -248,9 +245,6 @@ bool sample_rate_set(const uint32_t sample_rate_hz) { /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ si5351c_configure_multisynth(2, p1, 0, 1, 0);//p1 doesn't matter - /* MS0/CLK3 is the source for the external clock output. */ - //si5351c_configure_multisynth(3, p1, 0, 1, 0); // no clk out - return true; #endif } @@ -274,8 +268,7 @@ void cpu_clock_init(void) si5351c_power_down_all_clocks(); si5351c_set_crystal_configuration(); si5351c_enable_xo_and_ms_fanout(); - si5351c_configure_pll_sources_for_xtal(); - si5351c_configure_pll1_multisynth(); + si5351c_set_clock_source(PLL_SOURCE_XTAL); #ifdef JELLYBEAN /* @@ -313,6 +306,9 @@ void cpu_clock_init(void) * CLK7 -> LPC4330 (but LPC4330 starts up on its own crystal) */ + /* MS3/CLK3 is the source for the external clock output. */ + si5351c_configure_multisynth(3, 80*128-512, 0, 1, 0); /* 800/80 = 10MHz */ + /* MS4/CLK4 is the source for the RFFC5071 mixer. */ si5351c_configure_multisynth(4, 16*128-512, 0, 1, 0); /* 800/16 = 50MHz */ diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index c976cf0e..dd96605c 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -23,6 +23,8 @@ #include "si5351c.h" #include +enum pll_sources active_clock_source; + /* FIXME return i2c0 status from each function */ /* write to single register */ @@ -117,7 +119,7 @@ void si5351c_set_crystal_configuration() */ void si5351c_enable_xo_and_ms_fanout() { - uint8_t data[] = { 187, 0x50 }; + uint8_t data[] = { 187, 0xD0 }; si5351c_write(data, sizeof(data)); } @@ -127,18 +129,29 @@ void si5351c_enable_xo_and_ms_fanout() * PLLB_SRC=0 (XTAL input) * PLLA_SRC=0 (XTAL input) */ -void si5351c_configure_pll_sources_for_xtal() +void si5351c_configure_pll_sources(const enum pll_sources source) { uint8_t data[] = { 15, 0x00 }; + + if (source == PLL_SOURCE_CLKIN) { + data[1] = 0x0C; + } + si5351c_write(data, sizeof(data)); } /* MultiSynth NA (PLL1) */ -void si5351c_configure_pll1_multisynth() +void si5351c_configure_pll1_multisynth(const enum pll_sources source) { - //init plla and pllb to (0x0e00+512)/128*25mhz xtal = 800mhz -> int mode - uint8_t data[] = { 26, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00 }; - si5351c_write(data, sizeof(data)); + //init plla to (0x0e00+512)/128*25mhz xtal = 800mhz -> int mode + uint8_t data[] = { 26, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00 }; + + if (source == PLL_SOURCE_CLKIN) { + /* 10 MHz input on CLKIN instead of 25 MHz XTAL */ + data[4] = 0x26; + } + + si5351c_write(data, sizeof(data)); //~ data[0] =34;// pllb //~ si5351c_write(data, sizeof(data)); } @@ -233,7 +246,7 @@ void si5351c_configure_clock_control() ,SI5351C_CLK_FRAC_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA) ,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_0_4) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA) ,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_0_4) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA) - ,SI5351C_CLK_POWERDOWN /*not connected, clock out*/ + ,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA) ,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_6MA) ,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_4MA) ,SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE /*not connected, but: plla int mode*/ @@ -243,10 +256,10 @@ void si5351c_configure_clock_control() } #endif -/* Enable CLK outputs 0, 1, 2, 4, 5, 7 only. */ +/* Enable CLK outputs 0, 1, 2, 3, 4, 5, 7 only. */ void si5351c_enable_clock_outputs() { - uint8_t data[] = { 3, 0x48 }; + uint8_t data[] = { 3, 0x40 }; si5351c_write(data, sizeof(data)); } @@ -267,3 +280,28 @@ void si5351c_configure_clock_control() } } + +void si5351c_set_clock_source(const enum pll_sources source) +{ + si5351c_configure_pll_sources(source); + si5351c_configure_pll1_multisynth(source); + + active_clock_source = source; +} + +void si5351c_activate_best_clock_source(void) +{ + uint8_t device_status = si5351c_read_single(0); + + if (device_status & SI5351C_LOS) { + /* CLKIN not detected */ + if (active_clock_source == PLL_SOURCE_CLKIN) { + si5351c_set_clock_source(PLL_SOURCE_XTAL); + } + } else { + /* CLKIN detected */ + if (active_clock_source == PLL_SOURCE_XTAL) { + si5351c_set_clock_source(PLL_SOURCE_CLKIN); + } + } +} diff --git a/firmware/common/si5351c.h b/firmware/common/si5351c.h index 92946c70..562c37b7 100644 --- a/firmware/common/si5351c.h +++ b/firmware/common/si5351c.h @@ -55,13 +55,20 @@ extern "C" #define SI5351C_CLK_IDRV_6MA 2 #define SI5351C_CLK_IDRV_8MA 3 +#define SI5351C_LOS (1<<4) + +enum pll_sources { + PLL_SOURCE_XTAL = 0, + PLL_SOURCE_CLKIN = 1, +}; + void si5351c_disable_all_outputs(); void si5351c_disable_oeb_pin_control(); void si5351c_power_down_all_clocks(); void si5351c_set_crystal_configuration(); void si5351c_enable_xo_and_ms_fanout(); -void si5351c_configure_pll_sources_for_xtal(); -void si5351c_configure_pll1_multisynth(); +void si5351c_configure_pll_sources(const enum pll_sources source); +void si5351c_configure_pll1_multisynth(const enum pll_sources source); void si5351c_configure_multisynth(const uint_fast8_t ms_number, const uint32_t p1, const uint32_t p2, const uint32_t p3, const uint_fast8_t r_div); @@ -72,6 +79,8 @@ void si5351c_set_int_mode(const uint_fast8_t ms_number, const uint_fast8_t on); void si5351c_write_single(uint8_t reg, uint8_t val); uint8_t si5351c_read_single(uint8_t reg); void si5351c_write(uint8_t* const data, const uint_fast8_t data_count); +void si5351c_set_clock_source(const enum pll_sources source); +void si5351c_activate_best_clock_source(void); #ifdef __cplusplus } diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index d2605f1a..3daf0b6c 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -43,6 +43,7 @@ #include "rf_path.h" #include "sgpio_isr.h" #include "usb_bulk_buffer.h" +#include "si5351c.h" static volatile transceiver_mode_t _transceiver_mode = TRANSCEIVER_MODE_OFF; @@ -210,12 +211,18 @@ int main(void) { rf_path_init(); + uint16_t periodic_event_counter = 0; + unsigned int phase = 0; while(true) { // Check whether we need to initiate a CPLD update if (start_cpld_update) cpld_update(); + if (++periodic_event_counter == 0) { + si5351c_activate_best_clock_source(); + } + // Set up IN transfer of buffer 0. if ( usb_bulk_buffer_offset >= 16384 && phase == 1