From 1f73f2fd2519b2c513f1206955f65f1fdadd937d Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Thu, 8 Sep 2022 03:33:47 -0400 Subject: [PATCH] h1r9: add Si5351A support --- firmware/common/hackrf_core.c | 115 +++++++++++++++++++++++++--------- firmware/common/si5351c.c | 57 ++++++++++++----- 2 files changed, 127 insertions(+), 45 deletions(-) diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 122dcae0..0d313df0 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -36,6 +36,7 @@ #include "i2c_lpc.h" #include "cpld_jtag.h" #include "platform_detect.h" +#include "clkin.h" #include #include #include @@ -414,14 +415,26 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom) MSx_P2 = (128 * b) % c; MSx_P3 = c; - /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ - si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + /* + * On HackRF One r9 all sample clocks are externally derived + * from MS1/CLK1 operating at twice the sample rate. + */ + si5351c_configure_multisynth(&clock_gen, 1, MSx_P1, MSx_P2, MSx_P3, 0); + } else { + /* + * On other platforms the clock generator produces three + * different sample clocks, all derived from multisynth 0. + */ + /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ + si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1); - /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ - si5351c_configure_multisynth(&clock_gen, 1, 0, 0, 0, 0); //p1 doesn't matter + /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ + si5351c_configure_multisynth(&clock_gen, 1, 0, 0, 0, 0); //p1 doesn't matter - /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ - si5351c_configure_multisynth(&clock_gen, 2, 0, 0, 0, 0); //p1 doesn't matter + /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ + si5351c_configure_multisynth(&clock_gen, 2, 0, 0, 0, 0); //p1 doesn't matter + } if (streaming) { sgpio_cpld_stream_enable(&sgpio_config); @@ -482,14 +495,38 @@ bool sample_rate_set(const uint32_t sample_rate_hz) return false; } - /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ - si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + /* + * On HackRF One r9 all sample clocks are externally derived + * from MS1/CLK1 operating at twice the sample rate. + */ + si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 0); + } else { + /* + * On other platforms the clock generator produces three + * different sample clocks, all derived from multisynth 0. + */ + /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ + si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1); - /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ - si5351c_configure_multisynth(&clock_gen, 1, p1, 0, 1, 0); //p1 doesn't matter + /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ + si5351c_configure_multisynth( + &clock_gen, + 1, + p1, + 0, + 1, + 0); //p1 doesn't matter - /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ - si5351c_configure_multisynth(&clock_gen, 2, p1, 0, 1, 0); //p1 doesn't matter + /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ + si5351c_configure_multisynth( + &clock_gen, + 2, + p1, + 0, + 1, + 0); //p1 doesn't matter + } return true; } @@ -596,7 +633,12 @@ void cpu_clock_init(void) si5351c_configure_pll_multisynth(&clock_gen); /* - * Clocks: + * Clocks on HackRF One r9: + * CLK0 -> MAX5864/CPLD/SGPIO (sample clocks) + * CLK1 -> RFFC5072/MAX2837 + * CLK2 -> External Clock Output/LPC43xx (power down at boot) + * + * Clocks on other platforms: * CLK0 -> MAX5864/CPLD * CLK1 -> CPLD * CLK2 -> SGPIO @@ -607,22 +649,33 @@ void cpu_clock_init(void) * CLK7 -> LPC43xx (uses a 12MHz crystal by default) */ - /* MS4/CLK4 is the source for the RFFC5071 mixer (MAX2837 on rad1o). */ - si5351c_configure_multisynth( - &clock_gen, - 4, - 20 * 128 - 512, - 0, - 1, - 0); /* 800/20 = 40MHz */ - /* MS5/CLK5 is the source for the MAX2837 clock input (MAX2871 on rad1o). */ - si5351c_configure_multisynth( - &clock_gen, - 5, - 20 * 128 - 512, - 0, - 1, - 0); /* 800/20 = 40MHz */ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + /* MS0/CLK0 is the reference for both RFFC5071 and MAX2837. */ + si5351c_configure_multisynth( + &clock_gen, + 0, + 20 * 128 - 512, + 0, + 1, + 0); /* 800/20 = 40MHz */ + } else { + /* MS4/CLK4 is the source for the RFFC5071 mixer (MAX2837 on rad1o). */ + si5351c_configure_multisynth( + &clock_gen, + 4, + 20 * 128 - 512, + 0, + 1, + 0); /* 800/20 = 40MHz */ + /* MS5/CLK5 is the source for the MAX2837 clock input (MAX2871 on rad1o). */ + si5351c_configure_multisynth( + &clock_gen, + 5, + 20 * 128 - 512, + 0, + 1, + 0); /* 800/20 = 40MHz */ + } /* MS6/CLK6 is unused. */ /* MS7/CLK7 is unused. */ @@ -766,6 +819,10 @@ void cpu_clock_init(void) // CCU2_CLK_APLL_CFG = 0; // CCU2_CLK_SDIO_CFG = 0; #endif + + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + clkin_detect_init(); + } } clock_source_t activate_best_clock_source(void) diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index d7d97fdb..09f1ba6a 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -191,7 +191,7 @@ void si5351c_configure_clock_control( const enum pll_sources source) { uint8_t pll; - uint8_t clk3_ctrl; + uint8_t clkout_ctrl; #ifdef RAD1O (void) source; @@ -201,31 +201,29 @@ void si5351c_configure_clock_control( #if (defined JAWBREAKER || defined HACKRF_ONE) if (source == PLL_SOURCE_CLKIN) { - if (detected_platform() < BOARD_ID_HACKRF1_R9) { + /* PLLB on CLKIN */ + pll = SI5351C_CLK_PLL_SRC_B; + if (detected_platform() == BOARD_ID_HACKRF1_R9) { /* * HackRF One r9 always uses PLL A on the XTAL input * but externally switches that input to CLKIN. */ - pll = SI5351C_CLK_PLL_SRC_A; gpio_set(&gpio_h1r9_clkin_en); - } else { - /* PLLB on CLKIN */ - pll = SI5351C_CLK_PLL_SRC_B; } } else { /* PLLA on XTAL */ pll = SI5351C_CLK_PLL_SRC_A; - if (detected_platform() < BOARD_ID_HACKRF1_R9) { + if (detected_platform() == BOARD_ID_HACKRF1_R9) { gpio_clear(&gpio_h1r9_clkin_en); } } #endif if (clkout_enabled) { - clk3_ctrl = SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | + clkout_ctrl = SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA); } else { - clk3_ctrl = SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE; + clkout_ctrl = SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE; } /* Clock to CPU is deactivated as it is not used and creates noise */ @@ -241,7 +239,7 @@ void si5351c_configure_clock_control( SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_0_4) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA), - clk3_ctrl, + clkout_ctrl, SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_6MA) | SI5351C_CLK_INV, @@ -249,18 +247,28 @@ void si5351c_configure_clock_control( 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*/ - , + SI5351C_CLK_INT_MODE, /* not connected, but: PLL A int mode */ SI5351C_CLK_POWERDOWN | - SI5351C_CLK_INT_MODE /*not connected, but: plla int mode*/ + SI5351C_CLK_INT_MODE /* not connected, but: PLL B int mode */ }; + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + data[1] = SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC_A | + SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA); + data[2] = SI5351C_CLK_FRAC_MODE | SI5351C_CLK_PLL_SRC_A | + SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA); + data[3] = clkout_ctrl; + data[4] = SI5351C_CLK_POWERDOWN; + data[5] = SI5351C_CLK_POWERDOWN; + data[6] = SI5351C_CLK_POWERDOWN; + } si5351c_write(drv, data, sizeof(data)); } #define SI5351C_CLK_ENABLE(x) (0 << x) #define SI5351C_CLK_DISABLE(x) (1 << x) #define SI5351C_REG_OUTPUT_EN (3) -#define SI5351C_REG_CLK3_CTRL (19) void si5351c_enable_clock_outputs(si5351c_driver_t* const drv) { @@ -270,8 +278,19 @@ void si5351c_enable_clock_outputs(si5351c_driver_t* const drv) uint8_t value = SI5351C_CLK_ENABLE(0) | SI5351C_CLK_ENABLE(1) | SI5351C_CLK_ENABLE(2) | SI5351C_CLK_ENABLE(4) | SI5351C_CLK_ENABLE(5) | SI5351C_CLK_DISABLE(6) | SI5351C_CLK_DISABLE(7); + uint8_t clkout = 3; - value |= (clkout_enabled) ? SI5351C_CLK_ENABLE(3) : SI5351C_CLK_DISABLE(3); + /* HackRF One r9 has only three clock generator outputs. */ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + clkout = 2; + value = SI5351C_CLK_ENABLE(0) | SI5351C_CLK_ENABLE(1) | + SI5351C_CLK_DISABLE(3) | SI5351C_CLK_DISABLE(4) | + SI5351C_CLK_DISABLE(5) | SI5351C_CLK_DISABLE(6) | + SI5351C_CLK_DISABLE(7); + } + + value |= (clkout_enabled) ? SI5351C_CLK_ENABLE(clkout) : + SI5351C_CLK_DISABLE(clkout); uint8_t data[] = {SI5351C_REG_OUTPUT_EN, value}; si5351c_write(drv, data, sizeof(data)); @@ -325,8 +344,14 @@ void si5351c_clkout_enable(si5351c_driver_t* const drv, uint8_t enable) { clkout_enabled = (enable > 0); + //FIXME this should be somewhere else + uint8_t clkout = 3; + /* HackRF One r9 has only three clock generator outputs. */ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + clkout = 2; + } /* Configure clock to 10MHz */ - si5351c_configure_multisynth(drv, 3, 80 * 128 - 512, 0, 1, 0); + si5351c_configure_multisynth(drv, clkout, 80 * 128 - 512, 0, 1, 0); si5351c_configure_clock_control(drv, active_clock_source); si5351c_enable_clock_outputs(drv);