From 8aa79e9fe5bcdd6e492c146ed9ac614e6db18302 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Fri, 26 Aug 2022 05:47:22 -0400 Subject: [PATCH 001/474] h1r9: use timer to detect external clock frequency --- firmware/common/clkin.c | 114 +++++++++++++++++++++++++++++++ firmware/common/clkin.h | 30 ++++++++ firmware/common/hackrf_core.c | 6 +- firmware/hackrf-common.cmake | 2 + firmware/hackrf_usb/hackrf_usb.c | 4 ++ 5 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 firmware/common/clkin.c create mode 100644 firmware/common/clkin.h diff --git a/firmware/common/clkin.c b/firmware/common/clkin.c new file mode 100644 index 00000000..bef8b8a9 --- /dev/null +++ b/firmware/common/clkin.c @@ -0,0 +1,114 @@ +/* + * Copyright 2022 Great Scott Gadgets + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "gpdma.h" +#include +#include +#include +#include + +#define CLOCK_CYCLES_1_MS (204000) +#define MEASUREMENT_WINDOW_MS (50) +#define MEASUREMENT_CYCLES (CLOCK_CYCLES_1_MS * MEASUREMENT_WINDOW_MS) + +/* DMA linked list item */ +typedef struct { + uint32_t src; + uint32_t dest; + uint32_t next_lli; + uint32_t control; +} dma_lli; + +/* timer control register configuration sequence */ +typedef struct { + uint32_t first_tcr; + uint32_t second_tcr; +} tcr_sequence; + +dma_lli timer_dma_lli; +tcr_sequence reset; + +void clkin_detect_init(void) +{ + /* Timer3 triggers periodic measurement */ + timer_set_prescaler(TIMER3, 0); + timer_set_mode(TIMER3, TIMER_CTCR_MODE_TIMER); + TIMER3_MCR = TIMER_MCR_MR0R; + TIMER3_EMR = TIMER_EMR_EM0 | TIMER_EMR_EM3 | + (TIMER_EMR_EMC_SET << TIMER_EMR_EMC0_SHIFT) | + (TIMER_EMR_EMC_TOGGLE << TIMER_EMR_EMC3_SHIFT); + TIMER3_MR3 = MEASUREMENT_CYCLES; + TIMER3_MR0 = MEASUREMENT_CYCLES; + + /* Timer0 counts CLKIN */ + timer_set_prescaler(TIMER0, 0); + TIMER0_CCR = TIMER_CCR_CAP3RE; + GIMA_CAP0_3_IN = 0x20; // T3_MAT3 + + /* measure CLKIN signal on P2_5, pin 91, CTIN_2 */ + TIMER0_CTCR = TIMER_CTCR_MODE_COUNTER_RISING | TIMER_CTCR_CINSEL_CAPN_2; + scu_pinmux(P2_5, SCU_GPIO_PDN | SCU_CONF_FUNCTION1); + GIMA_CAP0_2_IN = 0x00; // CTIN_2 + + // temporarily testing with T0_CAP1, P1_12, pin 56, P28 pin 4 + //TIMER0_CTCR = TIMER_CTCR_MODE_COUNTER_RISING | TIMER_CTCR_CINSEL_CAPN_1; + //scu_pinmux(P1_12, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); + //GIMA_CAP0_1_IN = 0x20; // T0_CAP1 + + reset.first_tcr = TIMER_TCR_CEN | TIMER_TCR_CRST; + reset.second_tcr = TIMER_TCR_CEN; + timer_dma_lli.src = (uint32_t) & (reset); + timer_dma_lli.dest = (uint32_t) & (TIMER0_TCR); + timer_dma_lli.next_lli = (uint32_t) & (timer_dma_lli); + timer_dma_lli.control = GPDMA_CCONTROL_TRANSFERSIZE(2) | + GPDMA_CCONTROL_SBSIZE(0) // 1 + | GPDMA_CCONTROL_DBSIZE(0) // 1 + | GPDMA_CCONTROL_SWIDTH(2) // 32-bit word + | GPDMA_CCONTROL_DWIDTH(2) // 32-bit word + | GPDMA_CCONTROL_S(0) // AHB Master 0 + | GPDMA_CCONTROL_D(1) // AHB Master 1 + | GPDMA_CCONTROL_SI(1) // increment source + | GPDMA_CCONTROL_DI(0) // do not increment destination + | GPDMA_CCONTROL_PROT1(0) // user mode + | GPDMA_CCONTROL_PROT2(0) // not bufferable + | GPDMA_CCONTROL_PROT3(0) // not cacheable + | GPDMA_CCONTROL_I(0); // interrupt disabled + gpdma_controller_enable(); + GPDMA_C0SRCADDR = timer_dma_lli.src; + GPDMA_C0DESTADDR = timer_dma_lli.dest; + GPDMA_C0LLI = timer_dma_lli.next_lli; + GPDMA_C0CONTROL = timer_dma_lli.control; + GPDMA_C0CONFIG = GPDMA_CCONFIG_DESTPERIPHERAL(0x7) // T3_MAT0 + | GPDMA_CCONFIG_FLOWCNTRL(1) // memory-to-peripheral + | GPDMA_CCONFIG_H(0); // do not halt + gpdma_channel_enable(0); + + /* start counting */ + timer_reset(TIMER0); + timer_reset(TIMER3); + timer_enable_counter(TIMER0); + timer_enable_counter(TIMER3); +} + +uint32_t clkin_frequency(void) +{ + return TIMER0_CR3 * (1000 / MEASUREMENT_WINDOW_MS); +}; diff --git a/firmware/common/clkin.h b/firmware/common/clkin.h new file mode 100644 index 00000000..2f2fa274 --- /dev/null +++ b/firmware/common/clkin.h @@ -0,0 +1,30 @@ +/* + * Copyright 2022 Great Scott Gadgets + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __CLKIN_H__ +#define __CLKIN_H__ + +#include + +void clkin_detect_init(void); +uint32_t clkin_frequency(void); + +#endif //__CLKIN_H__ diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index bc0bb4b3..e0f4a880 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -727,7 +727,7 @@ void cpu_clock_init(void) CCU1_CLK_APB3_ADC1_CFG = 0; CCU1_CLK_APB3_CAN0_CFG = 0; CCU1_CLK_APB3_DAC_CFG = 0; - CCU1_CLK_M4_DMA_CFG = 0; + //CCU1_CLK_M4_DMA_CFG = 0; CCU1_CLK_M4_EMC_CFG = 0; CCU1_CLK_M4_EMCDIV_CFG = 0; CCU1_CLK_M4_ETHERNET_CFG = 0; @@ -737,10 +737,10 @@ void cpu_clock_init(void) // CCU1_CLK_M4_SCT_CFG = 0; CCU1_CLK_M4_SDIO_CFG = 0; CCU1_CLK_M4_SPIFI_CFG = 0; - CCU1_CLK_M4_TIMER0_CFG = 0; + //CCU1_CLK_M4_TIMER0_CFG = 0; CCU1_CLK_M4_TIMER1_CFG = 0; CCU1_CLK_M4_TIMER2_CFG = 0; - CCU1_CLK_M4_TIMER3_CFG = 0; + //CCU1_CLK_M4_TIMER3_CFG = 0; CCU1_CLK_M4_UART1_CFG = 0; CCU1_CLK_M4_USART0_CFG = 0; CCU1_CLK_M4_USART2_CFG = 0; diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index e7231923..ddc76a19 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -185,6 +185,8 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/hackrf_ui.c ${PATH_HACKRF_FIRMWARE_COMMON}/platform_detect.c ${PATH_HACKRF_FIRMWARE_COMMON}/firmware_info.c + ${PATH_HACKRF_FIRMWARE_COMMON}/clkin.c + ${PATH_HACKRF_FIRMWARE_COMMON}/gpdma.c ) if(BOARD STREQUAL "RAD1O") diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 56dd3ebc..893ecd53 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -55,6 +56,7 @@ #include "portapack.h" #include "hackrf_ui.h" #include "platform_detect.h" +#include "clkin.h" extern uint32_t __m0_start__; extern uint32_t __m0_end__; @@ -286,6 +288,8 @@ int main(void) } operacake_init(operacake_allow_gpio); + clkin_detect_init(); + while (true) { transceiver_request_t request; From 6d48671084ce2cf7c31ecf1ff96db9d8a914d0cc Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Tue, 6 Sep 2022 07:28:15 -0400 Subject: [PATCH 002/474] h1r9: initial GPIO definitions --- firmware/common/hackrf_core.c | 33 ++++++++++++++++--- firmware/common/hackrf_core.h | 8 +++++ firmware/common/rf_path.c | 56 ++++++++++++++++++++++++------- firmware/common/si5351c.c | 62 +++++++++++++++++++++++++++++++++-- firmware/common/si5351c.h | 1 + 5 files changed, 142 insertions(+), 18 deletions(-) diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index e0f4a880..122dcae0 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -35,6 +35,7 @@ #include "i2c_bus.h" #include "i2c_lpc.h" #include "cpld_jtag.h" +#include "platform_detect.h" #include #include #include @@ -134,8 +135,15 @@ static struct gpio_t gpio_cpld_pp_tms = GPIO(1, 1); static struct gpio_t gpio_cpld_pp_tdo = GPIO(1, 8); #endif -static struct gpio_t gpio_hw_sync_enable = GPIO(5,12); +/* other CPLD interface GPIO pins */ +static struct gpio_t gpio_hw_sync_enable = GPIO(5, 12); static struct gpio_t gpio_rx_q_invert = GPIO(0, 13); + +/* HackRF One r9 */ +#ifdef HACKRF_ONE +static struct gpio_t gpio_h1r9_rx = GPIO(0, 7); +static struct gpio_t gpio_h1r9_no_rx_amp_pwr = GPIO(3, 6); +#endif // clang-format on i2c_bus_t i2c0 = { @@ -578,6 +586,7 @@ void cpu_clock_init(void) i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); + si5351c_init(&clock_gen); si5351c_disable_all_outputs(&clock_gen); si5351c_disable_oeb_pin_control(&clock_gen); si5351c_power_down_all_clocks(&clock_gen); @@ -811,6 +820,13 @@ void pin_setup(void) /* Configure all GPIO as Input (safe state) */ gpio_init(); + detect_hardware_platform(); +#ifdef HACKRF_ONE + if (detected_platform() < BOARD_ID_HACKRF1_OG) { + halt_and_flash(6000000); + } +#endif + /* TDI and TMS pull-ups are required in all JTAG-compliant devices. * * The HackRF CPLD is always present, so let the CPLD pull up its TDI and TMS. @@ -855,9 +871,16 @@ void pin_setup(void) gpio_output(&gpio_led[3]); #endif - disable_1v8_power(); - gpio_output(&gpio_1v8_enable); - scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + //gpio_1v8_enable = GPIO(1, 12); + disable_1v8_power(); + gpio_output(&gpio_1v8_enable); + scu_pinmux(P2_12, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + } else { + disable_1v8_power(); + gpio_output(&gpio_1v8_enable); + scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + } #ifdef HACKRF_ONE /* Safe state: start with VAA turned off: */ @@ -890,6 +913,8 @@ void pin_setup(void) mixer_bus_setup(&mixer); + rf_path.gpio_rx = &gpio_h1r9_rx; + rf_path.gpio_no_rx_amp_pwr = &gpio_h1r9_no_rx_amp_pwr; rf_path_pin_setup(&rf_path); /* Configure external clock in */ diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index e24007eb..54f3e63d 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -232,6 +232,14 @@ extern "C" { #define SCU_PINMUX_GP_CLKIN (P4_7) +/* HackRF One r9 */ +#define SCU_H1R9_CLKIN_EN (P6_7) /* GPIO5[15] on P6_7 */ +#define SCU_H1R9_CLKOUT_EN (P1_2) /* GPIO0[9] on P1_2 (has boot pull-down) */ +#define SCU_H1R9_MCU_CLK_EN (P1_1) /* GPIO0[8] on P1_1 (has boot pull-up) */ +#define SCU_H1R9_RX (P2_7) /* GPIO0[7] on P4_4 (has boot pull-up) */ +#define SCU_H1R9_NO_RX_AMP_PWR (P6_10) /* GPIO3[6] on P6_10 */ +#define SCU_H1R9_NO_ANT_PWR (P4_4) /* GPIO2[4] on P4_4 */ + typedef enum { TRANSCEIVER_MODE_OFF = 0, TRANSCEIVER_MODE_RX = 1, diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index 3ca6fd75..804f0784 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -28,6 +28,8 @@ #include #include "hackrf_ui.h" +#include "gpio_lpc.h" +#include "platform_detect.h" #include #include @@ -81,21 +83,33 @@ #endif /* - * Antenna port power on HackRF One is controlled by GPO1 on the RFFC5072. - * This is the only thing we use RFFC5072 GPO for on HackRF One. The value of - * SWITCHCTRL_NO_ANT_PWR does not correspond to the GPO1 bit in the gpo - * register. + * Antenna port power on HackRF One (prior to r9) is controlled by GPO1 on the + * RFFC5072. This is the only thing we use RFFC5072 GPO for on HackRF One. + * The value of SWITCHCTRL_NO_ANT_PWR does not correspond to the GPO1 bit in + * the gpo register. */ + #define SWITCHCTRL_ANT_PWR (1 << 6) /* turn on antenna port power */ +/* + * Starting with HackRF One r9 this control signal has been moved to the + * microcontroller. + */ + +static struct gpio_t gpio_h1r9_no_ant_pwr = GPIO(2, 4); //FIXME max2837_tx_enable conflict + #ifdef HACKRF_ONE static void switchctrl_set_hackrf_one(rf_path_t* const rf_path, uint8_t ctrl) { if (ctrl & SWITCHCTRL_TX) { - gpio_set(rf_path->gpio_tx); + if (detected_platform() != BOARD_ID_HACKRF1_R9) { + gpio_set(rf_path->gpio_tx); + } gpio_clear(rf_path->gpio_rx); } else { - gpio_clear(rf_path->gpio_tx); + if (detected_platform() != BOARD_ID_HACKRF1_R9) { + gpio_clear(rf_path->gpio_tx); + } gpio_set(rf_path->gpio_rx); } @@ -156,10 +170,22 @@ static void switchctrl_set_hackrf_one(rf_path_t* const rf_path, uint8_t ctrl) gpio_set(rf_path->gpio_no_rx_amp_pwr); } - if (ctrl & SWITCHCTRL_ANT_PWR) { - mixer_set_gpo(&mixer, 0x00); /* turn on antenna power by clearing GPO1 */ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + if (ctrl & SWITCHCTRL_ANT_PWR) { + gpio_clear(&gpio_h1r9_no_ant_pwr); + } else { + gpio_set(&gpio_h1r9_no_ant_pwr); + } } else { - mixer_set_gpo(&mixer, 0x01); /* turn off antenna power by setting GPO1 */ + if (ctrl & SWITCHCTRL_ANT_PWR) { + mixer_set_gpo( + &mixer, + 0x00); /* turn on antenna power by clearing GPO1 */ + } else { + mixer_set_gpo( + &mixer, + 0x01); /* turn off antenna power by setting GPO1 */ + } } } #endif @@ -256,12 +282,20 @@ void rf_path_pin_setup(rf_path_t* const rf_path) scu_pinmux(SCU_TX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); scu_pinmux(SCU_TX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); scu_pinmux(SCU_MIX_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu_pinmux(SCU_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); scu_pinmux(SCU_NO_TX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); scu_pinmux(SCU_AMP_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); scu_pinmux(SCU_RX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(SCU_NO_RX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); // clang-format on + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + scu_pinmux(SCU_H1R9_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_H1R9_NO_RX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_H1R9_NO_ANT_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + gpio_clear(&gpio_h1r9_no_ant_pwr); + gpio_output(&gpio_h1r9_no_ant_pwr); + } else { + scu_pinmux(SCU_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + scu_pinmux(SCU_NO_RX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + } /* Configure RF power supply (VAA) switch */ scu_pinmux(SCU_NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index 394a6dd5..d7d97fdb 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -21,6 +21,18 @@ */ #include "si5351c.h" +#include "clkin.h" +#include "platform_detect.h" +#include "gpio_lpc.h" +#include "hackrf_core.h" +#include + +/* HackRF One r9 clock control */ +// clang-format off +static struct gpio_t gpio_h1r9_clkin_en = GPIO(5, 15); +static struct gpio_t gpio_h1r9_clkout_en = GPIO(0, 9); +static struct gpio_t gpio_h1r9_mcu_clk_en = GPIO(0, 8); +// clang-format on #include @@ -189,11 +201,23 @@ void si5351c_configure_clock_control( #if (defined JAWBREAKER || defined HACKRF_ONE) if (source == PLL_SOURCE_CLKIN) { - /* 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) { + gpio_clear(&gpio_h1r9_clkin_en); + } } #endif if (clkout_enabled) { @@ -250,6 +274,12 @@ void si5351c_enable_clock_outputs(si5351c_driver_t* const drv) value |= (clkout_enabled) ? SI5351C_CLK_ENABLE(3) : SI5351C_CLK_DISABLE(3); uint8_t data[] = {SI5351C_REG_OUTPUT_EN, value}; si5351c_write(drv, data, sizeof(data)); + + if ((clkout_enabled) && (detected_platform() == BOARD_ID_HACKRF1_R9)) { + gpio_set(&gpio_h1r9_clkout_en); + } else { + gpio_clear(&gpio_h1r9_clkout_en); + } } void si5351c_set_int_mode( @@ -283,7 +313,12 @@ void si5351c_set_clock_source(si5351c_driver_t* const drv, const enum pll_source bool si5351c_clkin_signal_valid(si5351c_driver_t* const drv) { - return (si5351c_read_single(drv, 0) & SI5351C_LOS) == 0; + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + uint32_t f = clkin_frequency(); + return (f > 9000000) && (f < 11000000); + } else { + return (si5351c_read_single(drv, 0) & SI5351C_LOS) == 0; + } } void si5351c_clkout_enable(si5351c_driver_t* const drv, uint8_t enable) @@ -296,3 +331,24 @@ void si5351c_clkout_enable(si5351c_driver_t* const drv, uint8_t enable) si5351c_configure_clock_control(drv, active_clock_source); si5351c_enable_clock_outputs(drv); } + +void si5351c_init(si5351c_driver_t* const drv) +{ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + /* CLKIN_EN */ + scu_pinmux(SCU_H1R9_CLKIN_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + gpio_clear(&gpio_h1r9_clkin_en); + gpio_output(&gpio_h1r9_clkin_en); + + /* CLKOUT_EN */ + scu_pinmux(SCU_H1R9_CLKIN_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + gpio_clear(&gpio_h1r9_clkin_en); + gpio_output(&gpio_h1r9_clkin_en); + + /* MCU_CLK_EN */ + scu_pinmux(SCU_H1R9_MCU_CLK_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + gpio_clear(&gpio_h1r9_mcu_clk_en); + gpio_output(&gpio_h1r9_mcu_clk_en); + } + (void) drv; +} diff --git a/firmware/common/si5351c.h b/firmware/common/si5351c.h index bacf7935..493cc73b 100644 --- a/firmware/common/si5351c.h +++ b/firmware/common/si5351c.h @@ -102,6 +102,7 @@ void si5351c_write( const uint8_t* const data, const size_t data_count); void si5351c_clkout_enable(si5351c_driver_t* const drv, uint8_t enable); +void si5351c_init(si5351c_driver_t* const drv); #ifdef __cplusplus } From 1f73f2fd2519b2c513f1206955f65f1fdadd937d Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Thu, 8 Sep 2022 03:33:47 -0400 Subject: [PATCH 003/474] 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); From 4ffe3658be3d5f5955ff8a8e5bf8f6fcc37a6b94 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sat, 10 Sep 2022 16:57:15 -0400 Subject: [PATCH 004/474] h1r9: add max2839_target.c --- firmware/common/max2839_target.c | 98 ++++++++++++++++++++++++++++++++ firmware/common/max2839_target.h | 32 +++++++++++ 2 files changed, 130 insertions(+) create mode 100644 firmware/common/max2839_target.c create mode 100644 firmware/common/max2839_target.h diff --git a/firmware/common/max2839_target.c b/firmware/common/max2839_target.c new file mode 100644 index 00000000..356313e9 --- /dev/null +++ b/firmware/common/max2839_target.c @@ -0,0 +1,98 @@ +/* + * Copyright 2012-2022 Great Scott Gadgets + * Copyright 2014 Jared Boone + * Copyright 2012 Will Code + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "max2839_target.h" + +#include +#include "hackrf_core.h" + +void max2839_target_init(max2839_driver_t* const drv) +{ + /* Configure SSP1 Peripheral (to be moved later in SSP driver) */ + scu_pinmux(SCU_SSP1_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); + scu_pinmux(SCU_SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); + scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); + + scu_pinmux(SCU_XCVR_CS, SCU_GPIO_FAST); + + /* + * Configure XCVR_CTL GPIO pins. + * + * The RXTX pin is also known as RXENABLE because of its use on the + * MAX2837 which had a separate TXENABLE. On MAX2839 a single RXTX pin + * switches between RX (high) and TX (low) modes. + */ + scu_pinmux(SCU_XCVR_ENABLE, SCU_GPIO_FAST); + scu_pinmux(SCU_XCVR_RXENABLE, SCU_GPIO_FAST); + + /* Set GPIO pins as outputs. */ + gpio_output(drv->gpio_enable); + gpio_output(drv->gpio_rxtx); +} + +void max2839_target_set_mode(max2839_driver_t* const drv, const max2839_mode_t new_mode) +{ + /* MAX2839_MODE_SHUTDOWN: + * All circuit blocks are powered down, except the 4-wire serial bus + * and its internal programmable registers. + * + * MAX2839_MODE_STANDBY: + * Used to enable the frequency synthesizer block while the rest of the + * device is powered down. In this mode, PLL, VCO, and LO generator + * are on, so that Tx or Rx modes can be quickly enabled from this mode. + * These and other blocks can be selectively enabled in this mode. + * + * MAX2839_MODE_TX: + * All Tx circuit blocks are powered on. The external PA is powered on + * after a programmable delay using the on-chip PA bias DAC. The slow- + * charging Rx circuits are in a precharged “idle-off” state for fast + * Tx-to-Rx turnaround time. + * + * MAX2839_MODE_RX: + * All Rx circuit blocks are powered on and active. Antenna signal is + * applied; RF is downconverted, filtered, and buffered at Rx BB I and Q + * outputs. The slow- charging Tx circuits are in a precharged “idle-off” + * state for fast Rx-to-Tx turnaround time. + */ + + switch (new_mode) { + default: + case MAX2839_MODE_SHUTDOWN: + gpio_clear(drv->gpio_enable); + gpio_clear(drv->gpio_rxtx); + break; + case MAX2839_MODE_STANDBY: + gpio_clear(drv->gpio_enable); + gpio_set(drv->gpio_rxtx); + break; + case MAX2839_MODE_TX: + gpio_set(drv->gpio_enable); + gpio_clear(drv->gpio_rxtx); + break; + case MAX2839_MODE_RX: + gpio_set(drv->gpio_enable); + gpio_set(drv->gpio_rxtx); + break; + } + drv->mode = new_mode; +} diff --git a/firmware/common/max2839_target.h b/firmware/common/max2839_target.h new file mode 100644 index 00000000..89488243 --- /dev/null +++ b/firmware/common/max2839_target.h @@ -0,0 +1,32 @@ +/* + * Copyright 2012-2022 Great Scott Gadgets + * Copyright 2014 Jared Boone + * Copyright 2012 Will Code + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __MAX2839_TARGET_H +#define __MAX2839_TARGET_H + +#include "max2839.h" + +void max2839_target_init(max2839_driver_t* const drv); +void max2839_target_set_mode(max2839_driver_t* const drv, const max2839_mode_t new_mode); + +#endif // __MAX2839_TARGET_H From b61c30a50d59c92900ad4d42ae9bbf84a62b6ef4 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sat, 17 Sep 2022 11:59:44 -0400 Subject: [PATCH 005/474] h1r9: bring-up wip --- firmware/common/hackrf_core.c | 49 +++++++++++++++++++------------ firmware/common/platform_detect.c | 6 ++-- firmware/common/rf_path.c | 2 ++ 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 0d313df0..6f707c26 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -142,8 +142,9 @@ static struct gpio_t gpio_rx_q_invert = GPIO(0, 13); /* HackRF One r9 */ #ifdef HACKRF_ONE -static struct gpio_t gpio_h1r9_rx = GPIO(0, 7); -static struct gpio_t gpio_h1r9_no_rx_amp_pwr = GPIO(3, 6); +static struct gpio_t gpio_h1r9_rx = GPIO(0, 7); +static struct gpio_t gpio_h1r9_no_rx_amp_pwr = GPIO(3, 6); +static struct gpio_t gpio_h1r9_1v8_enable = GPIO(1, 12); #endif // clang-format on @@ -500,7 +501,7 @@ bool sample_rate_set(const uint32_t sample_rate_hz) * 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); + si5351c_configure_multisynth(&clock_gen, 1, p1, p2, p3, 0); } else { /* * On other platforms the clock generator produces three @@ -877,13 +878,6 @@ void pin_setup(void) /* Configure all GPIO as Input (safe state) */ gpio_init(); - detect_hardware_platform(); -#ifdef HACKRF_ONE - if (detected_platform() < BOARD_ID_HACKRF1_OG) { - halt_and_flash(6000000); - } -#endif - /* TDI and TMS pull-ups are required in all JTAG-compliant devices. * * The HackRF CPLD is always present, so let the CPLD pull up its TDI and TMS. @@ -928,13 +922,13 @@ void pin_setup(void) gpio_output(&gpio_led[3]); #endif + disable_1v8_power(); if (detected_platform() == BOARD_ID_HACKRF1_R9) { - //gpio_1v8_enable = GPIO(1, 12); - disable_1v8_power(); - gpio_output(&gpio_1v8_enable); +#ifdef HACKRF_ONE + gpio_output(&gpio_h1r9_1v8_enable); scu_pinmux(P2_12, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); +#endif } else { - disable_1v8_power(); gpio_output(&gpio_1v8_enable); scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); } @@ -966,12 +960,17 @@ void pin_setup(void) /* enable input on SCL and SDA pins */ SCU_SFSI2C0 = SCU_I2C0_NOMINAL; - spi_bus_start(&spi_bus_ssp1, &ssp_config_max2837); + //FIXME + //spi_bus_start(&spi_bus_ssp1, &ssp_config_max2837); mixer_bus_setup(&mixer); - rf_path.gpio_rx = &gpio_h1r9_rx; - rf_path.gpio_no_rx_amp_pwr = &gpio_h1r9_no_rx_amp_pwr; +#ifdef HACKRF_ONE + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + rf_path.gpio_rx = &gpio_h1r9_rx; + rf_path.gpio_no_rx_amp_pwr = &gpio_h1r9_no_rx_amp_pwr; + } +#endif rf_path_pin_setup(&rf_path); /* Configure external clock in */ @@ -982,12 +981,24 @@ void pin_setup(void) void enable_1v8_power(void) { - gpio_set(&gpio_1v8_enable); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { +#ifdef HACKRF_ONE + gpio_set(&gpio_h1r9_1v8_enable); +#endif + } else { + gpio_set(&gpio_1v8_enable); + } } void disable_1v8_power(void) { - gpio_clear(&gpio_1v8_enable); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { +#ifdef HACKRF_ONE + gpio_clear(&gpio_h1r9_1v8_enable); +#endif + } else { + gpio_clear(&gpio_1v8_enable); + } } #ifdef HACKRF_ONE diff --git a/firmware/common/platform_detect.c b/firmware/common/platform_detect.c index 5430c5d8..ee9b8d54 100644 --- a/firmware/common/platform_detect.c +++ b/firmware/common/platform_detect.c @@ -42,13 +42,13 @@ static struct gpio_t gpio3_6_on_P6_10 = GPIO(3, 6); * Jawbreaker has a pull-down on P6_10 and nothing on P5_0. * rad1o has a pull-down on P6_10 and a pull-down on P5_0. * HackRF One OG has a pull-down on P6_10 and a pull-up on P5_0. - * HackRF One r9 has a pull-up on P6_10 and a pull-down on P5_0. + * HackRF One r9 has a pull-up on P6_10 and a pull-up on P5_0. //FIXME temporary */ #define JAWBREAKER_RESISTORS (P6_10_PDN) #define RAD1O_RESISTORS (P6_10_PDN | P5_0_PDN) #define HACKRF1_OG_RESISTORS (P6_10_PDN | P5_0_PUP) -#define HACKRF1_R9_RESISTORS (P6_10_PUP | P5_0_PDN) +#define HACKRF1_R9_RESISTORS (P6_10_PUP | P5_0_PUP) /* * LEDs are configured so that they flash if the detected hardware platform is @@ -165,7 +165,7 @@ void detect_hardware_platform(void) platform = BOARD_ID_HACKRF1_OG; break; case HACKRF1_R9_RESISTORS: - if (!(supported_platform() & PLATFORM_HACKRF1_R9)) { + if (!(supported_platform() & PLATFORM_HACKRF1_OG)) { //FIXME temporary halt_and_flash(3000000); } platform = BOARD_ID_HACKRF1_R9; diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index 804f0784..592224b1 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -96,7 +96,9 @@ * microcontroller. */ +#ifdef HACKRF_ONE static struct gpio_t gpio_h1r9_no_ant_pwr = GPIO(2, 4); //FIXME max2837_tx_enable conflict +#endif #ifdef HACKRF_ONE static void switchctrl_set_hackrf_one(rf_path_t* const rf_path, uint8_t ctrl) From dcb9cd1beb59c4e4b306b10efc716ded3666d413 Mon Sep 17 00:00:00 2001 From: grvvy Date: Tue, 13 Sep 2022 14:48:20 -0600 Subject: [PATCH 006/474] h1r9: add preliminary MAX2839 register definitions --- firmware/common/max2839_regs.def | 210 +++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 firmware/common/max2839_regs.def diff --git a/firmware/common/max2839_regs.def b/firmware/common/max2839_regs.def new file mode 100644 index 00000000..b1f34bfb --- /dev/null +++ b/firmware/common/max2839_regs.def @@ -0,0 +1,210 @@ +/* -*- mode: c -*- */ + +#ifndef __MAX2839_REGS_DEF +#define __MAX2839_REGS_DEF + +/* Generate static inline accessors that operate on the global + * regs. Done this way to (1) allow defs to be scraped out and used + * elsewhere, e.g. in scripts, (2) to avoid dealing with endian + * (structs). This may be used in firmware, or on host predefined + * register loads. */ + +#define MAX2839_REG_SET_CLEAN(_d, _r) (_d->regs_dirty &= ~(1UL<<_r)) +#define MAX2839_REG_SET_DIRTY(_d, _r) (_d->regs_dirty |= (1UL<<_r)) + +/* On set_, register is always set dirty, even if nothing + * changed. This makes sure that write that have side effects, + * e.g. frequency setting, are not skipped. */ + +/* n=name, r=regnum, o=offset (bits from LSB), l=length (bits) */ +#define __MREG__(n,r,o,l) \ +static inline uint16_t get_##n(max2839_driver_t* const _d) { \ + return (_d->regs[r] >> (o-l+1)) & ((1<regs[r] &= ~(((1<regs[r] |= ((v&((1< Date: Tue, 13 Sep 2022 15:22:47 -0600 Subject: [PATCH 007/474] h1r9: add preliminary MAX2839 driver and accompanying header file; add some convenience macros to regs_def --- firmware/common/max2839.c | 276 +++++++++++++++++++++++++++++++ firmware/common/max2839.h | 97 +++++++++++ firmware/common/max2839_regs.def | 20 +++ 3 files changed, 393 insertions(+) create mode 100644 firmware/common/max2839.c create mode 100644 firmware/common/max2839.h diff --git a/firmware/common/max2839.c b/firmware/common/max2839.c new file mode 100644 index 00000000..b10e9881 --- /dev/null +++ b/firmware/common/max2839.c @@ -0,0 +1,276 @@ +/* + * Copyright 2012 Will Code? (TODO: Proper attribution) + * Copyright 2014 Jared Boone + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* + * 'gcc -DTEST -DDEBUG -O2 -o test max2839.c' prints out what test + * program would do if it had a real spi library + * + * 'gcc -DTEST -DBUS_PIRATE -O2 -o test max2839.c' prints out bus + * pirate commands to do the same thing. + */ + +#include +#include +#include "max2839.h" +#include "max2839_regs.def" // private register def macros + +/* Default register values. */ +static const uint16_t max2839_regs_default[MAX2839_NUM_REGS] = { + 0x000, /* 0 */ + 0x00C, /* 1 */ + 0x080, /* 2 */ + 0x1b9, /* 3 */ + 0x3e6, /* 4 */ + 0x100, /* 5 */ + 0x000, /* 6 */ + 0x208, /* 7 */ + 0x220, /* 8 */ + 0x018, /* 9 */ + 0x00c, /* 10 */ + 0x004, /* 11 */ + 0x24f, /* 12 */ + 0x150, /* 13 */ + 0x3c5, /* 14 */ + 0x201, /* 15 */ + 0x01c, /* 16 */ + 0x155, /* 17 */ + 0x155, /* 18 */ + 0x153, /* 19 */ + 0x249, /* 20 */ + /* + * Charge Pump Common Mode Enable bit (0) of register 21 must be set or TX + * does not work. Page 1 of the SPI doc says not to set it (0x02c), but + * page 21 says it should be set by default (0x02d). + */ + 0x02d, /* 21 */ + 0x1a9, /* 22 */ + 0x24f, /* 23 */ + 0x180, /* 24 */ + 0x000, /* 25 */ + 0x3c0, /* 26 */ + 0x200, /* 27 */ + 0x0c0, /* 28 */ + 0x03f, /* 29 */ + 0x380, /* 30 */ + 0x340}; /* 31 */ + +/* Set up all registers according to defaults specified in docs. */ +static void max2839_init(max2839_driver_t* const drv) +{ + drv->target_init(drv); + max2839_set_mode(drv, MAX2839_MODE_SHUTDOWN); + + memcpy(drv->regs, max2839_regs_default, sizeof(drv->regs)); + drv->regs_dirty = 0xffffffff; + + /* Write default register values to chip. */ + max2837_regs_commit(drv); +} + +/* + * Set up pins for GPIO and SPI control, configure SSP peripheral for SPI, and + * set our own default register configuration. + */ +void max2839_setup(max2839_driver_t* const drv) +{ + max2839_init(drv); + // TODO + max2839_regs_commit(drv); +} + +static uint16_t max2839_read(max2839_driver_t* const drv, uint8_t r) +{ + uint16_t value = (1 << 15) | (r << 10); + spi_bus_transfer(drv->bus, &value, 1); + return value & 0x3ff; +} + +static void max2839_write(max2839_driver_t* const drv, uint8_t r, uint16_t v) +{ + uint16_t value = (r << 10) | (v & 0x3ff); + spi_bus_transfer(drv->bus, &value, 1); +} + +uint16_t max2839_reg_read(max2839_driver_t* const drv, uint8_t r) +{ + if ((drv->regs_dirty >> r) & 0x1) { + drv->regs[r] = max2839_read(drv, r); + }; + return drv->regs[r]; +} + +void max2839_reg_write(max2839_driver_t* const drv, uint8_t r, uint16_t v) +{ + drv->regs[r] = v; + max2839_write(drv, r, v); + MAX2839_REG_SET_CLEAN(drv, r); +} + +static inline void max2839_reg_commit(max2839_driver_t* const drv, uint8_t r) +{ + max2839_reg_write(drv, r, drv->regs[r]); +} + +void max2839_regs_commit(max2839_driver_t* const drv) +{ + int r; + for (r = 0; r < MAX2839_NUM_REGS; r++) { + if ((drv->regs_dirty >> r) & 0x1) { + max2839_reg_commit(drv, r); + } + } +} + +void max2839_set_mode(max2839_driver_t* const drv, const max2839_mode_t new_mode) +{ + drv->set_mode(drv, new_mode); +} + +max2839_mode_t max2839_mode(max2839_driver_t* const drv) +{ + return drv->mode; +} + +void max2839_start(max2839_driver_t* const drv) +{ + set_MAX2839_EN_SPI(drv, 1); + max2839_regs_commit(drv); + max2839_set_mode(drv, MAX2839_MODE_STANDBY); +} + +void max2839_tx(max2839_driver_t* const drv) +{ + // TODO + max2839_regs_commit(drv); + max2839_set_mode(drv, MAX2839_MODE_TX); +} + +void max2839_rx(max2839_driver_t* const drv) +{ + // TODO + max2839_regs_commit(drv); + max2839_set_mode(drv, MAX2839_MODE_RX); +} + +void max2839_stop(max2839_driver_t* const drv) +{ + // TODO + max2839_regs_commit(drv); + max2839_set_mode(drv, MAX2839_MODE_SHUTDOWN); +} + +void max2839_set_frequency(max2839_driver_t* const drv, uint32_t freq) +{ + // TODO +} + +typedef struct { + uint32_t bandwidth_hz; + uint32_t ft; +} max2839_ft_t; + +// clang-format off +static const max2839_ft_t max2839_ft[] = { + { 1750000, MAX2839_FT_1_75M }, + { 2500000, MAX2839_FT_2_5M }, + { 3500000, MAX2839_FT_3_5M }, + { 5000000, MAX2839_FT_5M }, + { 5500000, MAX2839_FT_5_5M }, + { 6000000, MAX2839_FT_6M }, + { 7000000, MAX2839_FT_7M }, + { 8000000, MAX2839_FT_8M }, + { 9000000, MAX2839_FT_9M }, + { 10000000, MAX2839_FT_10M }, + { 12000000, MAX2839_FT_12M }, + { 14000000, MAX2839_FT_14M }, + { 15000000, MAX2839_FT_15M }, + { 20000000, MAX2839_FT_20M }, + { 24000000, MAX2839_FT_24M }, + { 28000000, MAX2839_FT_28M }, + { 0, 0 }, +}; +//clang-format on + +uint32_t max2839_set_lpf_bandwidth(max2839_driver_t* const drv, const uint32_t bandwidth_hz) { + const max2839_ft_t* p = max2839_ft; + while( p->bandwidth_hz != 0 ) { + if( p->bandwidth_hz >= bandwidth_hz ) { + break; + } + p++; + } + + if( p->bandwidth_hz != 0 ) { + set_MAX2839_FT(drv, p->ft); + max2839_regs_commit(drv); + } + + return p->bandwidth_hz; +} + +bool max2839_set_lna_gain(max2839_driver_t* const drv, const uint32_t gain_db) { + uint16_t val; + // TODO: validate steps here + switch(gain_db){ + case 40: + val = MAX2839_LNAgain_MAX; + break; + case 32: + val = MAX2839_LNAgain_M8; + break; + case 24: + val = MAX2839_LNAgain_M16; + break; + case 8: + val = MAX2839_LNAgain_M32; + break; + default: + return false; + } + set_MAX2839_LNAgain(drv, val); + max2839_reg_commit(drv, 1); + return true; +} + +bool max2839_set_vga_gain(max2839_driver_t* const drv, const uint32_t gain_db) { + if( (gain_db & 0x1) || gain_db > 62) {/* 0b11111*2 */ + return false; +} + + set_MAX2839_VGA(drv, 31-(gain_db >> 1) ); + max2839_reg_commit(drv, 5); + return true; +} + +bool max2839_set_txvga_gain(max2839_driver_t* const drv, const uint32_t gain_db) { + uint16_t val=0; + if(gain_db <16){ + val = 31-gain_db; + val |= (1 << 5); // bit6: 16db + } else{ + val = 31-(gain_db-16); + } + + set_MAX2839_TXVGA_GAIN(drv, val); + max2839_reg_commit(drv, 29); + return true; +} diff --git a/firmware/common/max2839.h b/firmware/common/max2839.h new file mode 100644 index 00000000..915c365a --- /dev/null +++ b/firmware/common/max2839.h @@ -0,0 +1,97 @@ +/* + * Copyright 2012 Will Code? (TODO: Proper attribution) + * Copyright 2014 Jared Boone + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __MAX2839_H +#define __MAX2839_H + +#include +#include + +#include "gpio.h" +#include "spi_bus.h" + +/* 32 registers, each containing 10 bits of data. */ +#define MAX2839_NUM_REGS 32 +#define MAX2839_DATA_REGS_MAX_VALUE 1024 + +typedef enum { + MAX2839_MODE_SHUTDOWN, + MAX2839_MODE_CLKOUT, + MAX2839_MODE_STANDBY, + MAX2839_MODE_RX, + MAX2839_MODE_TX, + MAX2839_MODE_RX_CAL, + MAX2839_MODE_TX_CAL, +} max2839_mode_t; + +struct max2839_driver_t; +typedef struct max2839_driver_t max2839_driver_t; + +struct max2839_driver_t { + spi_bus_t* const bus; + gpio_t gpio_enable; + gpio_t gpio_rx_enable; + gpio_t gpio_tx_enable; + void (*target_init)(max2839_driver_t* const drv); + void (*set_mode)(max2839_driver_t* const drv, const max2839_mode_t new_mode); + max2839_mode_t mode; + uint16_t regs[MAX2839_NUM_REGS]; + uint32_t regs_dirty; +}; + +/* Initialize chip. */ +extern void max2839_setup(max2839_driver_t* const drv); + +/* Read a register via SPI. Save a copy to memory and return + * value. Mark clean. */ +extern uint16_t max2839_reg_read(max2839_driver_t* const drv, uint8_t r); + +/* Write value to register via SPI and save a copy to memory. Mark + * clean. */ +extern void max2839_reg_write(max2839_driver_t* const drv, uint8_t r, uint16_t v); + +/* Write all dirty registers via SPI from memory. Mark all clean. Some + * operations require registers to be written in a certain order. Use + * provided routines for those operations. */ +extern void max2839_regs_commit(max2839_driver_t* const drv); + +max2839_mode_t max2839_mode(max2839_driver_t* const drv); +void max2839_set_mode(max2839_driver_t* const drv, const max2839_mode_t new_mode); + +/* Turn on/off all chip functions. Does not control oscillator and CLKOUT */ +extern void max2839_start(max2839_driver_t* const drv); +extern void max2839_stop(max2839_driver_t* const drv); + +/* Set frequency in Hz. Frequency setting is a multi-step function + * where order of register writes matters. */ +extern void max2839_set_frequency(max2839_driver_t* const drv, uint32_t freq); +uint32_t max2839_set_lpf_bandwidth( + max2839_driver_t* const drv, + const uint32_t bandwidth_hz); +bool max2839_set_lna_gain(max2839_driver_t* const drv, const uint32_t gain_db); +bool max2839_set_vga_gain(max2839_driver_t* const drv, const uint32_t gain_db); +bool max2839_set_txvga_gain(max2839_driver_t* const drv, const uint32_t gain_db); + +extern void max2839_tx(max2839_driver_t* const drv); +extern void max2839_rx(max2839_driver_t* const drv); + +#endif // __MAX2839_H diff --git a/firmware/common/max2839_regs.def b/firmware/common/max2839_regs.def index b1f34bfb..9bc72410 100644 --- a/firmware/common/max2839_regs.def +++ b/firmware/common/max2839_regs.def @@ -54,9 +54,29 @@ __MREG__(MAX2839_RESERVED_6,4,1,2) __MREG__(MAX2839_LPF_CUTOFF,4,3,2) __MREG__(MAX2839_RESERVED_7,4,5,2) __MREG__(MAX2839_LPF_RF_BAND,4,9,4) +#define MAX2839_FT_1_75M 0 +#define MAX2839_FT_2_5M 1 +#define MAX2839_FT_3_5M 2 +#define MAX2839_FT_5M 3 +#define MAX2839_FT_5_5M 4 +#define MAX2839_FT_6M 5 +#define MAX2839_FT_7M 6 +#define MAX2839_FT_8M 7 +#define MAX2839_FT_9M 8 +#define MAX2839_FT_10M 9 +#define MAX2839_FT_12M 10 +#define MAX2839_FT_14M 11 +#define MAX2839_FT_15M 12 +#define MAX2839_FT_20M 13 +#define MAX2839_FT_24M 14 +#define MAX2839_FT_28M 15 /* REG 5 */ __MREG__(MAX2839_LNA1gain_SPI,5,1,2) +#define MAX2839_LNAgain_MAX 0b000 // Pad in 8dB steps, bits reversed +#define MAX2839_LNAgain_M8 0b001 +#define MAX2839_LNAgain_M16 0b010 +#define MAX2839_LNAgain_M32 0b011 __MREG__(MAX2839_Rx1_VGAgain,5,7,6) __MREG__(MAX2839_LPFblock_MODE,5,9,2) From 14183a96eac0c34e06f290a8b0f0d62e26534488 Mon Sep 17 00:00:00 2001 From: grvvy Date: Wed, 14 Sep 2022 12:49:45 -0600 Subject: [PATCH 008/474] h1r9: implement additional MAX2839 functions, change some mreg definition names, fix RF gain control math --- firmware/common/max2839.c | 94 +++++++++++++++++++++++--------- firmware/common/max2839_regs.def | 36 +++++++----- 2 files changed, 91 insertions(+), 39 deletions(-) diff --git a/firmware/common/max2839.c b/firmware/common/max2839.c index b10e9881..c21cf93d 100644 --- a/firmware/common/max2839.c +++ b/firmware/common/max2839.c @@ -56,11 +56,6 @@ static const uint16_t max2839_regs_default[MAX2839_NUM_REGS] = { 0x155, /* 18 */ 0x153, /* 19 */ 0x249, /* 20 */ - /* - * Charge Pump Common Mode Enable bit (0) of register 21 must be set or TX - * does not work. Page 1 of the SPI doc says not to set it (0x02c), but - * page 21 says it should be set by default (0x02d). - */ 0x02d, /* 21 */ 0x1a9, /* 22 */ 0x24f, /* 23 */ @@ -83,7 +78,7 @@ static void max2839_init(max2839_driver_t* const drv) drv->regs_dirty = 0xffffffff; /* Write default register values to chip. */ - max2837_regs_commit(drv); + max2839_regs_commit(drv); } /* @@ -152,35 +147,85 @@ max2839_mode_t max2839_mode(max2839_driver_t* const drv) void max2839_start(max2839_driver_t* const drv) { - set_MAX2839_EN_SPI(drv, 1); + set_MAX2839_chip_enable(drv, 1); max2839_regs_commit(drv); max2839_set_mode(drv, MAX2839_MODE_STANDBY); } void max2839_tx(max2839_driver_t* const drv) { - // TODO + set_MAX2839_LPFblock_MODE(drv, MAX2839_ModeCtrl_TxLPF); max2839_regs_commit(drv); max2839_set_mode(drv, MAX2839_MODE_TX); } void max2839_rx(max2839_driver_t* const drv) { - // TODO + set_MAX2839_LPFblock_MODE(drv, MAX2839_ModeCtrl_RxLPF); max2839_regs_commit(drv); max2839_set_mode(drv, MAX2839_MODE_RX); } void max2839_stop(max2839_driver_t* const drv) { - // TODO + set_MAX2839_chip_enable(drv, 0); max2839_regs_commit(drv); max2839_set_mode(drv, MAX2839_MODE_SHUTDOWN); } void max2839_set_frequency(max2839_driver_t* const drv, uint32_t freq) { - // TODO + uint8_t band; + uint8_t lna_band; + uint32_t div_frac; + uint32_t div_int; + uint32_t div_rem; + uint32_t div_cmp; + int i; + + /* Select band. Allow tuning outside specified bands. */ + if (freq < 2400000000U) { + band = MAX2839_LOGEN_BSW_2_3; + lna_band = MAX2839_LNAband_2_4; + } else if (freq < 2500000000U) { + band = MAX2839_LOGEN_BSW_2_4; + lna_band = MAX2839_LNAband_2_4; + } else if (freq < 2600000000U) { + band = MAX2839_LOGEN_BSW_2_5; + lna_band = MAX2839_LNAband_2_6; + } else { + band = MAX2839_LOGEN_BSW_2_6; + lna_band = MAX2839_LNAband_2_6; + } + + /* ASSUME 40MHz PLL. Ratio = F*(4/3)/40,000,000 = F/30,000,000 */ + div_int = freq / 30000000; + div_rem = freq % 30000000; + div_frac = 0; + div_cmp = 30000000; + for (i = 0; i < 20; i++) { + div_frac <<= 1; + div_cmp >>= 1; + if (div_rem > div_cmp) { + div_frac |= 0x1; + div_rem -= div_cmp; + } + } + + /* Band settings */ + set_MAX2839_LOGEN_BSW(drv, band); + set_MAX2839_LNAband(drv, lna_band); + + /* Write order matters here, so commit INT and FRAC_HI before + * committing FRAC_LO, which is the trigger for VCO + * auto-select. TODO - it's cleaner this way, but it would be + * faster to explicitly commit the registers explicitly so the + * dirty bits aren't scanned twice. */ + set_MAX2839_SYN_INT(drv, div_int); + set_MAX2839_SYN_FRAC_HI(drv, (div_frac >> 10) & 0x3ff); + max2839_regs_commit(drv); + set_MAX2839_SYN_FRAC_LO(drv, div_frac & 0x3ff); + max2839_regs_commit(drv); } typedef struct { @@ -229,25 +274,27 @@ uint32_t max2839_set_lpf_bandwidth(max2839_driver_t* const drv, const uint32_t b bool max2839_set_lna_gain(max2839_driver_t* const drv, const uint32_t gain_db) { uint16_t val; - // TODO: validate steps here switch(gain_db){ case 40: - val = MAX2839_LNAgain_MAX; + val = MAX2839_LNA1gain_MAX; break; case 32: - val = MAX2839_LNAgain_M8; + val = MAX2839_LNA1gain_M8; break; case 24: - val = MAX2839_LNAgain_M16; + val = MAX2839_LNA1gain_M16; break; case 8: - val = MAX2839_LNAgain_M32; + val = MAX2839_LNA1gain_M32; + break; + case 0: + val = MAX2839_LNA1gain_M32; break; default: return false; } - set_MAX2839_LNAgain(drv, val); - max2839_reg_commit(drv, 1); + set_MAX2839_LNA1gain(drv, val); + max2839_reg_commit(drv, 5); return true; } @@ -256,21 +303,16 @@ bool max2839_set_vga_gain(max2839_driver_t* const drv, const uint32_t gain_db) { return false; } - set_MAX2839_VGA(drv, 31-(gain_db >> 1) ); + set_MAX2839_Rx1_VGAgain(drv, (63-gain_db)); max2839_reg_commit(drv, 5); return true; } bool max2839_set_txvga_gain(max2839_driver_t* const drv, const uint32_t gain_db) { uint16_t val=0; - if(gain_db <16){ - val = 31-gain_db; - val |= (1 << 5); // bit6: 16db - } else{ - val = 31-(gain_db-16); - } + val = 63-gain_db; - set_MAX2839_TXVGA_GAIN(drv, val); + set_MAX2839_TX_VGA_GAIN(drv, val); max2839_reg_commit(drv, 29); return true; } diff --git a/firmware/common/max2839_regs.def b/firmware/common/max2839_regs.def index 9bc72410..821d1dda 100644 --- a/firmware/common/max2839_regs.def +++ b/firmware/common/max2839_regs.def @@ -31,7 +31,9 @@ static inline void set_##n(max2839_driver_t* const _d, uint16_t v) { \ __MREG__(MAX2839_RESERVED_1, 0,9,10) /* REG 1 */ -__MREG__(MAX2839_LNAtune,1,1,2) +__MREG__(MAX2839_LNAband,1,1,2) +#define MAX2839_LNAband_2_4 0 // 2.3-2.5 GHz +#define MAX2839_LNAband_2_6 1 // 2.5-2.7 GHz __MREG__(MAX2839_RESERVED_2,1,2,1) __MREG__(MAX2839_MIMO_SELECT,1,3,1) __MREG__(MAX2839_iqerr_trim,1,9,6) @@ -53,7 +55,7 @@ __MREG__(MAX2839_RESERVED_5,3,9,10) __MREG__(MAX2839_RESERVED_6,4,1,2) __MREG__(MAX2839_LPF_CUTOFF,4,3,2) __MREG__(MAX2839_RESERVED_7,4,5,2) -__MREG__(MAX2839_LPF_RF_BAND,4,9,4) +__MREG__(MAX2839_FT,4,9,4) #define MAX2839_FT_1_75M 0 #define MAX2839_FT_2_5M 1 #define MAX2839_FT_3_5M 2 @@ -72,13 +74,17 @@ __MREG__(MAX2839_LPF_RF_BAND,4,9,4) #define MAX2839_FT_28M 15 /* REG 5 */ -__MREG__(MAX2839_LNA1gain_SPI,5,1,2) -#define MAX2839_LNAgain_MAX 0b000 // Pad in 8dB steps, bits reversed -#define MAX2839_LNAgain_M8 0b001 -#define MAX2839_LNAgain_M16 0b010 -#define MAX2839_LNAgain_M32 0b011 +__MREG__(MAX2839_LNA1gain,5,1,2) +#define MAX2839_LNA1gain_MAX 0b000 // Pad in 8dB steps, bits reversed +#define MAX2839_LNA1gain_M8 0b001 +#define MAX2839_LNA1gain_M16 0b010 +#define MAX2839_LNA1gain_M32 0b011 __MREG__(MAX2839_Rx1_VGAgain,5,7,6) __MREG__(MAX2839_LPFblock_MODE,5,9,2) +#define MAX2839_ModeCtrl_RxCalibration 0 +#define MAX2839_ModeCtrl_RxLPF 1 +#define MAX2839_ModeCtrl_TxLPF 2 +#define MAX2839_ModeCtrl_LPFTrim 3 /* REG 6 */ __MREG__(MAX2839_LNA2gain_SPI,6,1,2) @@ -146,7 +152,7 @@ __MREG__(MAX2839_RESERVED_15,15,8,2) __MREG__(MAX2839_RXHP_highpass_corner,15,9,1) /* REG 16 */ -__MREG__(MAX2839_chip_disable,16,0,1) +__MREG__(MAX2839_chip_enable,16,0,1) __MREG__(MAX2839_RXTX_calibration_enable,16,1,1) __MREG__(MAX2839_RESERVED_16,16,5,4) __MREG__(MAX2839_PA_bias_DAC_SPI_enable,16,6,1) @@ -154,14 +160,18 @@ __MREG__(MAX2839_PA_bias_DAC_TX_mode_enable,16,7,1) __MREG__(MAX2839_RESERVED_17,16,9,2) /* REG 17 */ -__MREG__(MAX2839_SYNTH_20bit_FDR_UH,17,9,10) +__MREG__(MAX2839_SYN_FRAC_LO,17,9,10) /* REG 18 */ -__MREG__(MAX2839_SYNTH_20bit_FDR_LH,18,9,10) +__MREG__(MAX2839_SYN_FRAC_HI,18,9,10) /* REG 19 */ -__MREG__(MAX2839_SYNTH_8bit_IDR,19,7,8) -__MREG__(MAX2839_LO_Gen_Band_Switch,19,9,2) +__MREG__(MAX2839_SYN_INT,19,7,8) +__MREG__(MAX2839_LOGEN_BSW,19,9,2) +#define MAX2839_LOGEN_BSW_2_3 0 // 2300 - <2400 MHz +#define MAX2839_LOGEN_BSW_2_4 1 // 2400 - <2500 MHz +#define MAX2839_LOGEN_BSW_2_5 2 // 2500 - <2600 MHz +#define MAX2839_LOGEN_BSW_2_6 3 // 2600 - <2700 MHz /* REG 20 */ __MREG__(MAX2839_RESERVED_18,20,0,1) @@ -213,7 +223,7 @@ __MREG__(MAX2839_PADAC_Output_Current_Ctrl,28,5,6) __MREG__(MAX2839_PADAC_TurnOn_Delay_Ctrl,28,9,4) /* REG 29 */ -__MREG__(MAX2839_TX_VGA_SPI_Gain_Ctrl_Addr27,29,5,6) +__MREG__(MAX2839_TX_VGA_GAIN,29,5,6) __MREG__(MAX2839_RESERVED_29,29,9,4) /* REG 30 */ From 3738270e4f2767dfc628f4ca89c25a151af2aae6 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sat, 17 Sep 2022 14:43:48 -0400 Subject: [PATCH 009/474] h1r9: use MAX2839 --- firmware/common/hackrf_core.c | 49 ++++++++++++++++++++--- firmware/common/hackrf_core.h | 4 ++ firmware/common/max2839.h | 3 +- firmware/common/max2839_regs.def | 68 ++++++++++++++++---------------- firmware/common/rf_path.c | 9 ++++- firmware/hackrf-common.cmake | 2 + 6 files changed, 91 insertions(+), 44 deletions(-) diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 6f707c26..a88e1695 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -28,6 +28,8 @@ #include "spi_ssp.h" #include "max2837.h" #include "max2837_target.h" +#include "max2839.h" +#include "max2839_target.h" #include "max5864.h" #include "max5864_target.h" #include "w25q80bv.h" @@ -189,6 +191,20 @@ const ssp_config_t ssp_config_max2837 = { .gpio_select = &gpio_max2837_select, }; +const ssp_config_t ssp_config_max2839 = { + /* FIXME speed up once everything is working reliably */ + /* + // Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz + const uint8_t serial_clock_rate = 32; + const uint8_t clock_prescale_rate = 128; + */ + // Freq About 4.857MHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz + .data_bits = SSP_DATA_16BITS, + .serial_clock_rate = 21, + .clock_prescale_rate = 2, + .gpio_select = &gpio_max2837_select, +}; + const ssp_config_t ssp_config_max5864 = { /* FIXME speed up once everything is working reliably */ /* @@ -205,7 +221,7 @@ const ssp_config_t ssp_config_max5864 = { spi_bus_t spi_bus_ssp1 = { .obj = (void*) SSP1_BASE, - .config = &ssp_config_max2837, + .config = &ssp_config_max5864, .start = spi_ssp_start, .stop = spi_ssp_stop, .transfer = spi_ssp_transfer, @@ -221,6 +237,14 @@ max2837_driver_t max2837 = { .set_mode = max2837_target_set_mode, }; +max2839_driver_t max2839 = { + .bus = &spi_bus_ssp1, + .gpio_enable = &gpio_max2837_enable, + .gpio_rxtx = &gpio_max2837_rx_enable, + .target_init = max2839_target_init, + .set_mode = max2839_target_set_mode, +}; + max5864_driver_t max5864 = { .bus = &spi_bus_ssp1, .target_init = max5864_target_init, @@ -534,7 +558,12 @@ bool sample_rate_set(const uint32_t sample_rate_hz) bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz) { - uint32_t bandwidth_hz_real = max2837_set_lpf_bandwidth(&max2837, bandwidth_hz); + uint32_t bandwidth_hz_real; + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + bandwidth_hz_real = max2839_set_lpf_bandwidth(&max2839, bandwidth_hz); + } else { + bandwidth_hz_real = max2837_set_lpf_bandwidth(&max2837, bandwidth_hz); + } if (bandwidth_hz_real) { hackrf_ui()->set_filter_bw(bandwidth_hz_real); @@ -636,7 +665,7 @@ void cpu_clock_init(void) /* * Clocks on HackRF One r9: * CLK0 -> MAX5864/CPLD/SGPIO (sample clocks) - * CLK1 -> RFFC5072/MAX2837 + * CLK1 -> RFFC5072/MAX2839 * CLK2 -> External Clock Output/LPC43xx (power down at boot) * * Clocks on other platforms: @@ -651,7 +680,7 @@ void cpu_clock_init(void) */ if (detected_platform() == BOARD_ID_HACKRF1_R9) { - /* MS0/CLK0 is the reference for both RFFC5071 and MAX2837. */ + /* MS0/CLK0 is the reference for both RFFC5071 and MAX2839. */ si5351c_configure_multisynth( &clock_gen, 0, @@ -868,6 +897,11 @@ void ssp1_set_mode_max2837(void) spi_bus_start(max2837.bus, &ssp_config_max2837); } +void ssp1_set_mode_max2839(void) +{ + spi_bus_start(max2839.bus, &ssp_config_max2839); +} + void ssp1_set_mode_max5864(void) { spi_bus_start(max5864.bus, &ssp_config_max5864); @@ -960,8 +994,11 @@ void pin_setup(void) /* enable input on SCL and SDA pins */ SCU_SFSI2C0 = SCU_I2C0_NOMINAL; - //FIXME - //spi_bus_start(&spi_bus_ssp1, &ssp_config_max2837); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + spi_bus_start(&spi_bus_ssp1, &ssp_config_max2839); + } else { + spi_bus_start(&spi_bus_ssp1, &ssp_config_max2837); + } mixer_bus_setup(&mixer); diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 54f3e63d..8045b1d2 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -35,6 +35,7 @@ extern "C" { #include "spi_ssp.h" #include "max2837.h" +#include "max2839.h" #include "max5864.h" #include "mixer.h" #include "w25q80bv.h" @@ -267,9 +268,11 @@ void delay_us_at_mhz(uint32_t us, uint32_t mhz); extern si5351c_driver_t clock_gen; extern const ssp_config_t ssp_config_w25q80bv; extern const ssp_config_t ssp_config_max2837; +extern const ssp_config_t ssp_config_max2839; extern const ssp_config_t ssp_config_max5864; extern max2837_driver_t max2837; +extern max2839_driver_t max2839; //FIXME xcvr hal extern max5864_driver_t max5864; extern mixer_driver_t mixer; extern w25q80bv_driver_t spi_flash; @@ -280,6 +283,7 @@ extern i2c_bus_t i2c0; void cpu_clock_init(void); void ssp1_set_mode_max2837(void); +void ssp1_set_mode_max2839(void); void ssp1_set_mode_max5864(void); void pin_setup(void); diff --git a/firmware/common/max2839.h b/firmware/common/max2839.h index 915c365a..dd7e7f3a 100644 --- a/firmware/common/max2839.h +++ b/firmware/common/max2839.h @@ -49,8 +49,7 @@ typedef struct max2839_driver_t max2839_driver_t; struct max2839_driver_t { spi_bus_t* const bus; gpio_t gpio_enable; - gpio_t gpio_rx_enable; - gpio_t gpio_tx_enable; + gpio_t gpio_rxtx; void (*target_init)(max2839_driver_t* const drv); void (*set_mode)(max2839_driver_t* const drv, const max2839_mode_t new_mode); max2839_mode_t mode; diff --git a/firmware/common/max2839_regs.def b/firmware/common/max2839_regs.def index 821d1dda..25ce449e 100644 --- a/firmware/common/max2839_regs.def +++ b/firmware/common/max2839_regs.def @@ -28,13 +28,13 @@ static inline void set_##n(max2839_driver_t* const _d, uint16_t v) { \ } /* REG 0 */ -__MREG__(MAX2839_RESERVED_1, 0,9,10) +__MREG__(MAX2839_RESERVED_0_9,0,9,10) /* REG 1 */ __MREG__(MAX2839_LNAband,1,1,2) #define MAX2839_LNAband_2_4 0 // 2.3-2.5 GHz #define MAX2839_LNAband_2_6 1 // 2.5-2.7 GHz -__MREG__(MAX2839_RESERVED_2,1,2,1) +__MREG__(MAX2839_RESERVED_1_2,1,2,1) __MREG__(MAX2839_MIMO_SELECT,1,3,1) __MREG__(MAX2839_iqerr_trim,1,9,6) // TODO: D9:D4 but shows only 5 bits for values? @@ -44,17 +44,17 @@ __MREG__(MAX2839_iqerr_trim,1,9,6) /* REG 2 */ __MREG__(MAX2839_LNAgain_SPI,2,0,1) -__MREG__(MAX2839_RESERVED_3,2,1,1) +__MREG__(MAX2839_RESERVED_2_1,2,1,1) __MREG__(MAX2839_RX_IQ_SPI,2,2,1) -__MREG__(MAX2839_RESERVED_4,2,9,7) +__MREG__(MAX2839_RESERVED_2_9,2,9,7) /* REG 3 */ -__MREG__(MAX2839_RESERVED_5,3,9,10) +__MREG__(MAX2839_RESERVED_3_9,3,9,10) /* REG 4 */ -__MREG__(MAX2839_RESERVED_6,4,1,2) +__MREG__(MAX2839_RESERVED_4_1,4,1,2) __MREG__(MAX2839_LPF_CUTOFF,4,3,2) -__MREG__(MAX2839_RESERVED_7,4,5,2) +__MREG__(MAX2839_RESERVED_4_5,4,5,2) __MREG__(MAX2839_FT,4,9,4) #define MAX2839_FT_1_75M 0 #define MAX2839_FT_2_5M 1 @@ -92,36 +92,36 @@ __MREG__(MAX2839_Rx2_VGAgain,6,7,6) __MREG__(MAX2839_RX_VGAoutput,6,9,2) /* REG 7 */ -__MREG__(MAX2839_RESERVED_7,7,0,1) +__MREG__(MAX2839_RESERVED_7_0,7,0,1) __MREG__(MAX2839_RSSIselect,7,1,1) __MREG__(MAX2839_RSSImode,7,2,1) -__MREG__(MAX2839_RESERVED_8,7,6,4) +__MREG__(MAX2839_RESERVED_7_6,7,6,4) __MREG__(MAX2839_RXBBI_RXBBQ,7,7,1) -__MREG__(MAX2839_RESERVED_9,7,8,1) +__MREG__(MAX2839_RESERVED_7_8,7,8,1) __MREG__(MAX2839_RSSIinput,7,9,1) /* REG 8 */ -__MREG__(MAX2839_RESERVED_8,8,0,1) +__MREG__(MAX2839_RESERVED_8_0,8,0,1) __MREG__(MAX2839_VGAgain_SPI,8,1,1) __MREG__(MAX2839_LPFmode,8,2,1) -__MREG__(MAX2839_RESERVED_9,8,9,7) +__MREG__(MAX2839_RESERVED_8_9,8,9,7) /* REG 9 */ __MREG__(MAX2839_Temperature_ADC,9,0,1) __MREG__(MAX2839_Temperature_Clk_En,9,1,1) -__MREG__(MAX2839_RESERVED_10,9,2,1) +__MREG__(MAX2839_RESERVED_9_2,9,2,1) __MREG__(MAX2839_DOUT_Drive_Sel,9,3,1) __MREG__(MAX2839_DOUT_3state_Ctrl,9,4,1) __MREG__(MAX2839_DOUT_Pin_Sel,9,7,3) -__MREG__(MAX2839_RESERVED_11,9,9,2) +__MREG__(MAX2839_RESERVED_9_9,9,9,2) /* REG 10 */ __MREG__(MAX2839_TX_AM_gain,10,1,2) __MREG__(MAX2839_TX_AM_bandwidth,10,4,3) -__MREG__(MAX2839_RESERVED_12,10,9,5) +__MREG__(MAX2839_RESERVED_10_9,10,9,5) /* REG 11 */ -__MREG__(MAX2839_RESERVED_13,11,9,10) +__MREG__(MAX2839_RESERVED_11_9,11,9,10) /* REG 12 */ __MREG__(MAX2839_RXVGA_10M_RXEN_duration,12,1,2) @@ -146,18 +146,18 @@ __MREG__(MAX2839_PA_DRV_DAC,14,9,1) /* REG 15 */ __MREG__(MAX2839_RXVGA_HPFSM_Clk_Divider,15,0,1) -__MREG__(MAX2839_RESERVED_14,15,5,5) +__MREG__(MAX2839_RESERVED_15_5,15,5,5) __MREG__(MAX2839_RXHP_sequence_bypass,15,6,1) -__MREG__(MAX2839_RESERVED_15,15,8,2) +__MREG__(MAX2839_RESERVED_15_8,15,8,2) __MREG__(MAX2839_RXHP_highpass_corner,15,9,1) /* REG 16 */ __MREG__(MAX2839_chip_enable,16,0,1) __MREG__(MAX2839_RXTX_calibration_enable,16,1,1) -__MREG__(MAX2839_RESERVED_16,16,5,4) +__MREG__(MAX2839_RESERVED_16_5,16,5,4) __MREG__(MAX2839_PA_bias_DAC_SPI_enable,16,6,1) __MREG__(MAX2839_PA_bias_DAC_TX_mode_enable,16,7,1) -__MREG__(MAX2839_RESERVED_17,16,9,2) +__MREG__(MAX2839_RESERVED_16_9,16,9,2) /* REG 17 */ __MREG__(MAX2839_SYN_FRAC_LO,17,9,10) @@ -174,14 +174,14 @@ __MREG__(MAX2839_LOGEN_BSW,19,9,2) #define MAX2839_LOGEN_BSW_2_6 3 // 2600 - <2700 MHz /* REG 20 */ -__MREG__(MAX2839_RESERVED_18,20,0,1) +__MREG__(MAX2839_RESERVED_20_0,20,0,1) __MREG__(MAX2839_Reference_Divider_Ratio,20,2,2) -__MREG__(MAX2839_RESERVED_19,20,4,2) +__MREG__(MAX2839_RESERVED_20_4,20,4,2) __MREG__(MAX2839_CLKOUT_Buffer_Drive,20,5,1) -__MREG__(MAX2839_RESERVED_20,20,9,4) +__MREG__(MAX2839_RESERVED_20_9,20,9,4) /* REG 21 */ -__MREG__(MAX2839_RESERVED_21,21,9,10) +__MREG__(MAX2839_RESERVED_21_9,21,9,10) /* REG 22 */ __MREG__(MAX2839_VAS_Operating_Mode_Select,22,0,1) @@ -189,26 +189,26 @@ __MREG__(MAX2839_VAS_Relock_Mode_Select,22,1,1) __MREG__(MAX2839_VAS_Clk_Divide_Ratio,22,4,3) __MREG__(MAX2839_VAS_Delay_Counter_Ratio,22,6,2) __MREG__(MAX2839_VAS_Addr17_Trigger_Enable,22,7,1) -__MREG__(MAX2839_RESERVED_22,22,9,2) +__MREG__(MAX2839_RESERVED_22_9,22,9,2) /* REG 23 */ __MREG__(MAX2839_VAS_Subband_SPI_Overwrite,23,4,5) __MREG__(MAX2839_Crystal_Oscillator_Bias_Select,23,6,2) -__MREG__(MAX2839_RESERVED_23,23,9,3) +__MREG__(MAX2839_RESERVED_23_9,23,9,3) /* REG 24 */ __MREG__(MAX2839_Crystal_Oscillator_Freq_Tuning,24,6,7) -__MREG__(MAX2839_RESERVED_24,24,7,1) +__MREG__(MAX2839_RESERVED_24_7,24,7,1) __MREG__(MAX2839_CLKOUT_Divide_Ratio,24,8,1) __MREG__(MAX2839_Crystal_Oscillator_Core_Enable,24,9,1) /* REG 25 */ -__MREG__(MAX2839_RESERVED_25,25,9,10) +__MREG__(MAX2839_RESERVED_25_9,25,9,10) /* REG 26 */ -__MREG__(MAX2839_RESERVED_26,26,2,3) +__MREG__(MAX2839_RESERVED_26_2,26,2,3) __MREG__(MAX2839_LOGEN_RXTX_Gm_Enable,26,3,1) -__MREG__(MAX2839_RESERVED_27,26,5,2) +__MREG__(MAX2839_RESERVED_26_5,26,5,2) __MREG__(MAX2839_VAS_Test_Signal_Select,26,9,4) /* REG 27 */ @@ -216,7 +216,7 @@ __MREG__(MAX2839_TX_LO_IQ_Phase_SPI_Adjust_Addr27,27,5,6) __MREG__(MAX2839_TX_LO_IQ_Phase_SPI_Adjust_Enable,27,6,1) __MREG__(MAX2839_TX_VGA_Gain_SPI_Ctrl_Enable,27,7,1) __MREG__(MAX2839_TX_DC_Offset_SPI_Adjust_Enable,27,8,1) -__MREG__(MAX2839_RESERVED_28,27,9,1) +__MREG__(MAX2839_RESERVED_27_9,27,9,1) /* REG 28 */ __MREG__(MAX2839_PADAC_Output_Current_Ctrl,28,5,6) @@ -224,17 +224,17 @@ __MREG__(MAX2839_PADAC_TurnOn_Delay_Ctrl,28,9,4) /* REG 29 */ __MREG__(MAX2839_TX_VGA_GAIN,29,5,6) -__MREG__(MAX2839_RESERVED_29,29,9,4) +__MREG__(MAX2839_RESERVED_29_9,29,9,4) /* REG 30 */ __MREG__(MAX2839_TX_DC_Offset_Correction_Addr27,30,5,6) -__MREG__(MAX2839_RESERVED_30,30,7,2) +__MREG__(MAX2839_RESERVED_30_7,30,7,2) __MREG__(MAX2839_PA_DAC_IV_Output_Select,30,8,1) __MREG__(MAX2839_PA_DAC_Voltage_Mode_Output_Select,30,9,1) /* REG 31 */ __MREG__(MAX2839_TX_DC_Offset_Correction_QChannel,31,5,6) -__MREG__(MAX2839_RESERVED_31,31,8,3) +__MREG__(MAX2839_RESERVED_31_8,31,8,3) __MREG__(MAX2839_PA_DAC_Clk_Divide_Ratio,31,9,1) #endif // __MAX2839_REGS_DEF diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index 592224b1..ffff68d1 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -371,8 +371,13 @@ void rf_path_init(rf_path_t* const rf_path) max5864_shutdown(&max5864); ssp1_set_mode_max2837(); - max2837_setup(&max2837); - max2837_start(&max2837); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + max2839_setup(&max2839); + max2839_start(&max2839); + } else { + max2837_setup(&max2837); + max2837_start(&max2837); + } // On HackRF One, the mixer is now set up earlier in boot. #ifndef HACKRF_ONE diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index ddc76a19..b39c8641 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -172,6 +172,8 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/si5351c.c ${PATH_HACKRF_FIRMWARE_COMMON}/max2837.c ${PATH_HACKRF_FIRMWARE_COMMON}/max2837_target.c + ${PATH_HACKRF_FIRMWARE_COMMON}/max2839.c + ${PATH_HACKRF_FIRMWARE_COMMON}/max2839_target.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864_target.c ${PATH_HACKRF_FIRMWARE_COMMON}/mixer.c From a72f084ff048f9bc69b19b6375a8a636fff8d4bf Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Mon, 19 Sep 2022 04:58:47 -0400 Subject: [PATCH 010/474] h1r9: fix CLKOUT_EN pin setup --- firmware/common/si5351c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index 09f1ba6a..a3cb8d3e 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -366,9 +366,9 @@ void si5351c_init(si5351c_driver_t* const drv) gpio_output(&gpio_h1r9_clkin_en); /* CLKOUT_EN */ - scu_pinmux(SCU_H1R9_CLKIN_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - gpio_clear(&gpio_h1r9_clkin_en); - gpio_output(&gpio_h1r9_clkin_en); + scu_pinmux(SCU_H1R9_CLKOUT_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + gpio_clear(&gpio_h1r9_clkout_en); + gpio_output(&gpio_h1r9_clkout_en); /* MCU_CLK_EN */ scu_pinmux(SCU_H1R9_MCU_CLK_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); From f4817b60a3ffaf53e6f0573c75db8a7628af534a Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Mon, 19 Sep 2022 07:35:10 -0400 Subject: [PATCH 011/474] h1r9: MAX2839 driver updates --- firmware/common/max2839.c | 78 ++++++++++++++++++++++---------- firmware/common/max2839_regs.def | 33 ++++++++------ 2 files changed, 74 insertions(+), 37 deletions(-) diff --git a/firmware/common/max2839.c b/firmware/common/max2839.c index c21cf93d..10f5461c 100644 --- a/firmware/common/max2839.c +++ b/firmware/common/max2839.c @@ -36,17 +36,17 @@ /* Default register values. */ static const uint16_t max2839_regs_default[MAX2839_NUM_REGS] = { 0x000, /* 0 */ - 0x00C, /* 1 */ + 0x00c, /* 1: data sheet says 0x00c but read 0x22c */ 0x080, /* 2 */ - 0x1b9, /* 3 */ + 0x1b9, /* 3: data sheet says 0x1b9 but read 0x1b0 */ 0x3e6, /* 4 */ 0x100, /* 5 */ 0x000, /* 6 */ 0x208, /* 7 */ - 0x220, /* 8 */ + 0x220, /* 8: data sheet says 0x220 but read 0x000 */ 0x018, /* 9 */ 0x00c, /* 10 */ - 0x004, /* 11 */ + 0x004, /* 11: data sheet says 0x004 but read 0x000 */ 0x24f, /* 12 */ 0x150, /* 13 */ 0x3c5, /* 14 */ @@ -56,17 +56,24 @@ static const uint16_t max2839_regs_default[MAX2839_NUM_REGS] = { 0x155, /* 18 */ 0x153, /* 19 */ 0x249, /* 20 */ - 0x02d, /* 21 */ + 0x02d, /* 21: data sheet says 0x02d but read 0x13d */ 0x1a9, /* 22 */ 0x24f, /* 23 */ 0x180, /* 24 */ - 0x000, /* 25 */ + 0x000, /* 25: data sheet says 0x000 but read 0x00a */ 0x3c0, /* 26 */ - 0x200, /* 27 */ + 0x200, /* 27: data sheet says 0x200 but read 0x22a */ 0x0c0, /* 28 */ - 0x03f, /* 29 */ - 0x380, /* 30 */ - 0x340}; /* 31 */ + 0x03f, /* 29: data sheet says 0x03f but read 0x07f */ + 0x300, /* 30: data sheet says 0x300 but read 0x398 */ + 0x340}; /* 31: data sheet says 0x340 but read 0x359 */ + +/* + * All of the discrepancies listed above are in fields that either don't matter + * or are undocumented except "set to recommended value". We set them to the + * data sheet defaults even though the inital part we tested started up with + * different settings. + */ /* Set up all registers according to defaults specified in docs. */ static void max2839_init(max2839_driver_t* const drv) @@ -88,7 +95,27 @@ static void max2839_init(max2839_driver_t* const drv) void max2839_setup(max2839_driver_t* const drv) { max2839_init(drv); - // TODO + + /* Use SPI control instead of B0-B7 pins for gain settings. */ + set_MAX2839_LNAgain_SPI(drv, 1); + set_MAX2839_VGAgain_SPI(drv, 1); + set_MAX2839_TX_VGA_Gain_SPI(drv, 1); + + /* enable RXINB */ + set_MAX2839_MIMO_SELECT(drv, 1); + + /* set gains for unused RXINA path to minimum */ + set_MAX2839_LNA1gain(drv, MAX2839_LNA1gain_M32); + set_MAX2839_Rx1_VGAgain(drv, 0x3f); + + //set_MAX2839_TX_VGA_GAIN(drv, 0x18); + + /* maximum RX output common-mode voltage */ + set_MAX2839_RX_VCM(drv, MAX2839_RX_VCM_1_35); + + //FIXME do something with HPFSM/HPC? + //FIXME do something with LPF? + max2839_regs_commit(drv); } @@ -107,9 +134,10 @@ static void max2839_write(max2839_driver_t* const drv, uint8_t r, uint16_t v) uint16_t max2839_reg_read(max2839_driver_t* const drv, uint8_t r) { - if ((drv->regs_dirty >> r) & 0x1) { - drv->regs[r] = max2839_read(drv, r); - }; + // always read actual value from SPI for now + //if ((drv->regs_dirty >> r) & 0x1) { + drv->regs[r] = max2839_read(drv, r); + //}; return drv->regs[r]; } @@ -154,14 +182,16 @@ void max2839_start(max2839_driver_t* const drv) void max2839_tx(max2839_driver_t* const drv) { - set_MAX2839_LPFblock_MODE(drv, MAX2839_ModeCtrl_TxLPF); + // FIXME does this do anything without LPFmode_SPI set? + // do we need it to? + set_MAX2839_LPFmode(drv, MAX2839_LPFmode_TxLPF); max2839_regs_commit(drv); max2839_set_mode(drv, MAX2839_MODE_TX); } void max2839_rx(max2839_driver_t* const drv) { - set_MAX2839_LPFblock_MODE(drv, MAX2839_ModeCtrl_RxLPF); + set_MAX2839_LPFmode(drv, MAX2839_LPFmode_RxLPF); max2839_regs_commit(drv); max2839_set_mode(drv, MAX2839_MODE_RX); } @@ -276,24 +306,24 @@ bool max2839_set_lna_gain(max2839_driver_t* const drv, const uint32_t gain_db) { uint16_t val; switch(gain_db){ case 40: - val = MAX2839_LNA1gain_MAX; + val = MAX2839_LNA2gain_MAX; break; case 32: - val = MAX2839_LNA1gain_M8; + val = MAX2839_LNA2gain_M8; break; case 24: - val = MAX2839_LNA1gain_M16; + // FIXME correct missing settings with VGA adjustment? + case 16: + val = MAX2839_LNA2gain_M16; break; case 8: - val = MAX2839_LNA1gain_M32; - break; case 0: - val = MAX2839_LNA1gain_M32; + val = MAX2839_LNA2gain_M32; break; default: return false; } - set_MAX2839_LNA1gain(drv, val); + set_MAX2839_LNA2gain(drv, val); max2839_reg_commit(drv, 5); return true; } @@ -303,7 +333,7 @@ bool max2839_set_vga_gain(max2839_driver_t* const drv, const uint32_t gain_db) { return false; } - set_MAX2839_Rx1_VGAgain(drv, (63-gain_db)); + set_MAX2839_Rx2_VGAgain(drv, (63-gain_db)); max2839_reg_commit(drv, 5); return true; } diff --git a/firmware/common/max2839_regs.def b/firmware/common/max2839_regs.def index 25ce449e..c857cdd7 100644 --- a/firmware/common/max2839_regs.def +++ b/firmware/common/max2839_regs.def @@ -37,10 +37,9 @@ __MREG__(MAX2839_LNAband,1,1,2) __MREG__(MAX2839_RESERVED_1_2,1,2,1) __MREG__(MAX2839_MIMO_SELECT,1,3,1) __MREG__(MAX2839_iqerr_trim,1,9,6) -// TODO: D9:D4 but shows only 5 bits for values? -// 0b00000 = +4.0 degree phase error -// 0b01111 = 0.0 -// 0b11111 = -4.0 +// 0b000000 = +4.0 degree phase error +// 0b011111 = 0.0 +// 0b111111 = -4.0 /* REG 2 */ __MREG__(MAX2839_LNAgain_SPI,2,0,1) @@ -80,16 +79,24 @@ __MREG__(MAX2839_LNA1gain,5,1,2) #define MAX2839_LNA1gain_M16 0b010 #define MAX2839_LNA1gain_M32 0b011 __MREG__(MAX2839_Rx1_VGAgain,5,7,6) -__MREG__(MAX2839_LPFblock_MODE,5,9,2) -#define MAX2839_ModeCtrl_RxCalibration 0 -#define MAX2839_ModeCtrl_RxLPF 1 -#define MAX2839_ModeCtrl_TxLPF 2 -#define MAX2839_ModeCtrl_LPFTrim 3 +__MREG__(MAX2839_LPFmode,5,9,2) +#define MAX2839_LPFmode_RxCalibration 0 +#define MAX2839_LPFmode_RxLPF 1 +#define MAX2839_LPFmode_TxLPF 2 +#define MAX2839_LPFmode_LPFTrim 3 /* REG 6 */ -__MREG__(MAX2839_LNA2gain_SPI,6,1,2) +__MREG__(MAX2839_LNA2gain,6,1,2) +#define MAX2839_LNA2gain_MAX 0b000 // Pad in 8dB steps, bits reversed +#define MAX2839_LNA2gain_M8 0b001 +#define MAX2839_LNA2gain_M16 0b010 +#define MAX2839_LNA2gain_M32 0b011 __MREG__(MAX2839_Rx2_VGAgain,6,7,6) -__MREG__(MAX2839_RX_VGAoutput,6,9,2) +__MREG__(MAX2839_RX_VCM,6,9,2) +#define MAX2839_RX_VCM_1_0 0b00 // 1.0 V +#define MAX2839_RX_VCM_1_1 0b01 // 1.1 V +#define MAX2839_RX_VCM_1_2 0b10 // 1.2 V +#define MAX2839_RX_VCM_1_35 0b11 // 1.35 V /* REG 7 */ __MREG__(MAX2839_RESERVED_7_0,7,0,1) @@ -103,7 +110,7 @@ __MREG__(MAX2839_RSSIinput,7,9,1) /* REG 8 */ __MREG__(MAX2839_RESERVED_8_0,8,0,1) __MREG__(MAX2839_VGAgain_SPI,8,1,1) -__MREG__(MAX2839_LPFmode,8,2,1) +__MREG__(MAX2839_LPFmode_SPI,8,2,1) __MREG__(MAX2839_RESERVED_8_9,8,9,7) /* REG 9 */ @@ -214,7 +221,7 @@ __MREG__(MAX2839_VAS_Test_Signal_Select,26,9,4) /* REG 27 */ __MREG__(MAX2839_TX_LO_IQ_Phase_SPI_Adjust_Addr27,27,5,6) __MREG__(MAX2839_TX_LO_IQ_Phase_SPI_Adjust_Enable,27,6,1) -__MREG__(MAX2839_TX_VGA_Gain_SPI_Ctrl_Enable,27,7,1) +__MREG__(MAX2839_TX_VGA_Gain_SPI,27,7,1) __MREG__(MAX2839_TX_DC_Offset_SPI_Adjust_Enable,27,8,1) __MREG__(MAX2839_RESERVED_27_9,27,9,1) From edd0a8081292c252daa9d05bbdbd4b4efb840cc2 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Mon, 19 Sep 2022 09:58:48 -0400 Subject: [PATCH 012/474] h1r9: stop writing MAX2837 registers to MAX2839 --- firmware/common/rf_path.c | 40 ++++++++++++----- firmware/common/tuning.c | 55 +++++++++++++++++------ firmware/hackrf_usb/usb_api_transceiver.c | 38 +++++++++++----- 3 files changed, 95 insertions(+), 38 deletions(-) diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index ffff68d1..44ab6947 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -30,11 +30,11 @@ #include "hackrf_ui.h" #include "gpio_lpc.h" #include "platform_detect.h" - -#include -#include -#include -#include +#include "mixer.h" +#include "max2837.h" +#include "max2839.h" +#include "max5864.h" +#include "sgpio.h" #if (defined JAWBREAKER || defined HACKRF_ONE || defined RAD1O) /* @@ -370,11 +370,12 @@ void rf_path_init(rf_path_t* const rf_path) max5864_setup(&max5864); max5864_shutdown(&max5864); - ssp1_set_mode_max2837(); if (detected_platform() == BOARD_ID_HACKRF1_R9) { + ssp1_set_mode_max2839(); max2839_setup(&max2839); max2839_start(&max2839); } else { + ssp1_set_mode_max2837(); max2837_setup(&max2837); max2837_start(&max2837); } @@ -405,8 +406,13 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d } ssp1_set_mode_max5864(); max5864_tx(&max5864); - ssp1_set_mode_max2837(); - max2837_tx(&max2837); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + ssp1_set_mode_max2839(); + max2839_tx(&max2839); + } else { + ssp1_set_mode_max2837(); + max2837_tx(&max2837); + } sgpio_configure(&sgpio_config, SGPIO_DIRECTION_TX); break; @@ -424,8 +430,13 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d } ssp1_set_mode_max5864(); max5864_rx(&max5864); - ssp1_set_mode_max2837(); - max2837_rx(&max2837); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + ssp1_set_mode_max2839(); + max2839_rx(&max2839); + } else { + ssp1_set_mode_max2837(); + max2837_rx(&max2837); + } sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX); break; @@ -440,8 +451,13 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d mixer_disable(&mixer); ssp1_set_mode_max5864(); max5864_standby(&max5864); - ssp1_set_mode_max2837(); - max2837_set_mode(&max2837, MAX2837_MODE_STANDBY); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + ssp1_set_mode_max2839(); + max2839_set_mode(&max2839, MAX2839_MODE_STANDBY); + } else { + ssp1_set_mode_max2837(); + max2837_set_mode(&max2837, MAX2837_MODE_STANDBY); + } sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX); break; } diff --git a/firmware/common/tuning.c b/firmware/common/tuning.c index 79a238c7..597fa396 100644 --- a/firmware/common/tuning.c +++ b/firmware/common/tuning.c @@ -22,14 +22,14 @@ */ #include "tuning.h" - #include "hackrf_ui.h" - -#include -#include -#include -#include -#include +#include "hackrf_core.h" +#include "mixer.h" +#include "max2837.h" +#include "max2839.h" +#include "sgpio.h" +#include "operacake.h" +#include "platform_detect.h" #define FREQ_ONE_MHZ (1000ULL * 1000) @@ -70,8 +70,15 @@ bool set_freq(const uint64_t freq) success = true; - const max2837_mode_t prior_max2837_mode = max2837_mode(&max2837); - max2837_set_mode(&max2837, MAX2837_MODE_STANDBY); + max2839_mode_t prior_max2839_mode = MAX2839_MODE_STANDBY; + max2837_mode_t prior_max2837_mode = MAX2837_MODE_STANDBY; + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + prior_max2839_mode = max2839_mode(&max2839); + max2839_set_mode(&max2839, MAX2839_MODE_STANDBY); + } else { + prior_max2837_mode = max2837_mode(&max2837); + max2837_set_mode(&max2837, MAX2837_MODE_STANDBY); + } if (freq_mhz < MAX_LP_FREQ_MHZ) { rf_path_set_filter(&rf_path, RF_PATH_FILTER_LOW_PASS); #ifdef RAD1O @@ -83,13 +90,21 @@ bool set_freq(const uint64_t freq) mixer_freq_mhz = (max2837_freq_nominal_hz / FREQ_ONE_MHZ) + freq_mhz; /* Set Freq and read real freq */ real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz); - max2837_set_frequency(&max2837, real_mixer_freq_hz - freq); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + max2839_set_frequency(&max2839, real_mixer_freq_hz - freq); + } else { + max2837_set_frequency(&max2837, real_mixer_freq_hz - freq); + } sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 1); } else if ((freq_mhz >= MIN_BYPASS_FREQ_MHZ) && (freq_mhz < MAX_BYPASS_FREQ_MHZ)) { rf_path_set_filter(&rf_path, RF_PATH_FILTER_BYPASS); MAX2837_freq_hz = (freq_mhz * FREQ_ONE_MHZ) + freq_hz; /* mixer_freq_mhz <= not used in Bypass mode */ - max2837_set_frequency(&max2837, MAX2837_freq_hz); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + max2839_set_frequency(&max2839, MAX2837_freq_hz); + } else { + max2837_set_frequency(&max2837, MAX2837_freq_hz); + } sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0); } else if ((freq_mhz >= MIN_HP_FREQ_MHZ) && (freq_mhz <= MAX_HP_FREQ_MHZ)) { if (freq_mhz < MID1_HP_FREQ_MHZ) { @@ -110,13 +125,21 @@ bool set_freq(const uint64_t freq) mixer_freq_mhz = freq_mhz - (max2837_freq_nominal_hz / FREQ_ONE_MHZ); /* Set Freq and read real freq */ real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz); - max2837_set_frequency(&max2837, freq - real_mixer_freq_hz); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + max2839_set_frequency(&max2839, freq - real_mixer_freq_hz); + } else { + max2837_set_frequency(&max2837, freq - real_mixer_freq_hz); + } sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0); } else { /* Error freq_mhz too high */ success = false; } - max2837_set_mode(&max2837, prior_max2837_mode); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + max2839_set_mode(&max2839, prior_max2839_mode); + } else { + max2837_set_mode(&max2837, prior_max2837_mode); + } if (success) { freq_cache = freq; hackrf_ui()->set_frequency(freq); @@ -147,7 +170,11 @@ bool set_freq_explicit( } rf_path_set_filter(&rf_path, path); - max2837_set_frequency(&max2837, if_freq_hz); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + max2839_set_frequency(&max2839, if_freq_hz); + } else { + max2837_set_frequency(&max2837, if_freq_hz); + } if (lo_freq_hz > if_freq_hz) { sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 1); } else { diff --git a/firmware/hackrf_usb/usb_api_transceiver.c b/firmware/hackrf_usb/usb_api_transceiver.c index 18a08938..48bbbb94 100644 --- a/firmware/hackrf_usb/usb_api_transceiver.c +++ b/firmware/hackrf_usb/usb_api_transceiver.c @@ -32,12 +32,14 @@ #include "usb_api_cpld.h" // Remove when CPLD update is handled elsewhere -#include -#include -#include -#include -#include -#include +#include "max2837.h" +#include "max2839.h" +#include "rf_path.h" +#include "tuning.h" +#include "streaming.h" +#include "usb.h" +#include "usb_queue.h" +#include "platform_detect.h" #include #include @@ -163,8 +165,12 @@ usb_request_status_t usb_vendor_request_set_lna_gain( const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { - const uint8_t value = - max2837_set_lna_gain(&max2837, endpoint->setup.index); + uint8_t value; + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + value = max2839_set_lna_gain(&max2839, endpoint->setup.index); + } else { + value = max2837_set_lna_gain(&max2837, endpoint->setup.index); + } endpoint->buffer[0] = value; if (value) { hackrf_ui()->set_bb_lna_gain(endpoint->setup.index); @@ -186,8 +192,12 @@ usb_request_status_t usb_vendor_request_set_vga_gain( const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { - const uint8_t value = - max2837_set_vga_gain(&max2837, endpoint->setup.index); + uint8_t value; + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + value = max2839_set_vga_gain(&max2839, endpoint->setup.index); + } else { + value = max2837_set_vga_gain(&max2837, endpoint->setup.index); + } endpoint->buffer[0] = value; if (value) { hackrf_ui()->set_bb_vga_gain(endpoint->setup.index); @@ -209,8 +219,12 @@ usb_request_status_t usb_vendor_request_set_txvga_gain( const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { - const uint8_t value = - max2837_set_txvga_gain(&max2837, endpoint->setup.index); + uint8_t value; + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + value = max2839_set_txvga_gain(&max2839, endpoint->setup.index); + } else { + value = max2837_set_txvga_gain(&max2837, endpoint->setup.index); + } endpoint->buffer[0] = value; if (value) { hackrf_ui()->set_bb_tx_vga_gain(endpoint->setup.index); From 4db7e8d38a6bb02b6c720aa119c5c9c9b70a6f54 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Mon, 19 Sep 2022 11:54:07 -0400 Subject: [PATCH 013/474] h1r9: more bring-up fixes --- firmware/common/max2839.c | 4 ++-- firmware/common/rf_path.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/firmware/common/max2839.c b/firmware/common/max2839.c index 10f5461c..26fef0f7 100644 --- a/firmware/common/max2839.c +++ b/firmware/common/max2839.c @@ -324,7 +324,7 @@ bool max2839_set_lna_gain(max2839_driver_t* const drv, const uint32_t gain_db) { return false; } set_MAX2839_LNA2gain(drv, val); - max2839_reg_commit(drv, 5); + max2839_reg_commit(drv, 6); return true; } @@ -334,7 +334,7 @@ bool max2839_set_vga_gain(max2839_driver_t* const drv, const uint32_t gain_db) { } set_MAX2839_Rx2_VGAgain(drv, (63-gain_db)); - max2839_reg_commit(drv, 5); + max2839_reg_commit(drv, 6); return true; } diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index 44ab6947..fc04569e 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -97,7 +97,7 @@ */ #ifdef HACKRF_ONE -static struct gpio_t gpio_h1r9_no_ant_pwr = GPIO(2, 4); //FIXME max2837_tx_enable conflict +static struct gpio_t gpio_h1r9_no_ant_pwr = GPIO(2, 4); #endif #ifdef HACKRF_ONE @@ -282,7 +282,6 @@ void rf_path_pin_setup(rf_path_t* const rf_path) scu_pinmux(SCU_NO_MIX_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); scu_pinmux(SCU_RX_MIX_BP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); scu_pinmux(SCU_TX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(SCU_TX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); scu_pinmux(SCU_MIX_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); scu_pinmux(SCU_NO_TX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); scu_pinmux(SCU_AMP_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); @@ -295,8 +294,10 @@ void rf_path_pin_setup(rf_path_t* const rf_path) gpio_clear(&gpio_h1r9_no_ant_pwr); gpio_output(&gpio_h1r9_no_ant_pwr); } else { + scu_pinmux(SCU_TX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); scu_pinmux(SCU_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); scu_pinmux(SCU_NO_RX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + gpio_output(rf_path->gpio_tx); } /* Configure RF power supply (VAA) switch */ @@ -319,7 +320,6 @@ void rf_path_pin_setup(rf_path_t* const rf_path) gpio_output(rf_path->gpio_rx_mix_bp); gpio_output(rf_path->gpio_tx_amp); gpio_output(rf_path->gpio_no_tx_amp_pwr); - gpio_output(rf_path->gpio_tx); gpio_output(rf_path->gpio_mix_bypass); gpio_output(rf_path->gpio_rx); #elif RAD1O From 616705b7e5086c8d9920f356433b78d2c39160cc Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Mon, 19 Sep 2022 22:18:45 -0400 Subject: [PATCH 014/474] h1r9: don't write to outputs in TIMER3 ext. match register Writing to the output bits in the TIMER3 external match register resulted in intermittent failures that varied in likelihood from board to board and from commit to commit for no apparent reason. --- firmware/common/clkin.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/firmware/common/clkin.c b/firmware/common/clkin.c index bef8b8a9..080d02d0 100644 --- a/firmware/common/clkin.c +++ b/firmware/common/clkin.c @@ -52,8 +52,7 @@ void clkin_detect_init(void) timer_set_prescaler(TIMER3, 0); timer_set_mode(TIMER3, TIMER_CTCR_MODE_TIMER); TIMER3_MCR = TIMER_MCR_MR0R; - TIMER3_EMR = TIMER_EMR_EM0 | TIMER_EMR_EM3 | - (TIMER_EMR_EMC_SET << TIMER_EMR_EMC0_SHIFT) | + TIMER3_EMR = (TIMER_EMR_EMC_SET << TIMER_EMR_EMC0_SHIFT) | (TIMER_EMR_EMC_TOGGLE << TIMER_EMR_EMC3_SHIFT); TIMER3_MR3 = MEASUREMENT_CYCLES; TIMER3_MR0 = MEASUREMENT_CYCLES; From 3f7329052417fce303a835af5ad6191522f08087 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sun, 25 Sep 2022 13:26:05 -0400 Subject: [PATCH 015/474] h1r9: configure MAX2839 HPF Without this, the RX baseband gain amplifies a DC offset. --- firmware/common/max2839.c | 8 +++----- firmware/common/max2839_regs.def | 34 ++++++++++++++++++-------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/firmware/common/max2839.c b/firmware/common/max2839.c index 26fef0f7..28cf3ff5 100644 --- a/firmware/common/max2839.c +++ b/firmware/common/max2839.c @@ -108,13 +108,11 @@ void max2839_setup(max2839_driver_t* const drv) set_MAX2839_LNA1gain(drv, MAX2839_LNA1gain_M32); set_MAX2839_Rx1_VGAgain(drv, 0x3f); - //set_MAX2839_TX_VGA_GAIN(drv, 0x18); - - /* maximum RX output common-mode voltage */ + /* set maximum RX output common-mode voltage */ set_MAX2839_RX_VCM(drv, MAX2839_RX_VCM_1_35); - //FIXME do something with HPFSM/HPC? - //FIXME do something with LPF? + /* set HPF corner frequency to 1 kHz */ + set_MAX2839_HPC_STOP(drv, MAX2839_STOP_1K); max2839_regs_commit(drv); } diff --git a/firmware/common/max2839_regs.def b/firmware/common/max2839_regs.def index c857cdd7..8cd578cf 100644 --- a/firmware/common/max2839_regs.def +++ b/firmware/common/max2839_regs.def @@ -131,25 +131,29 @@ __MREG__(MAX2839_RESERVED_10_9,10,9,5) __MREG__(MAX2839_RESERVED_11_9,11,9,10) /* REG 12 */ -__MREG__(MAX2839_RXVGA_10M_RXEN_duration,12,1,2) -__MREG__(MAX2839_RXVGA_10M_B6B7_duration,12,3,2) -__MREG__(MAX2839_RXVGA_600k_RXEN_duration,12,6,3) -__MREG__(MAX2839_RXVGA_600k_B6B7_duration,12,9,3) +__MREG__(MAX2839_HPC_10M_RXEN_duration,12,1,2) +__MREG__(MAX2839_HPC_10M_B6B7_duration,12,3,2) +__MREG__(MAX2839_HPC_600k_RXEN_duration,12,6,3) +__MREG__(MAX2839_HPC_600k_B6B7_duration,12,9,3) /* REG 13 */ -__MREG__(MAX2839_RXVGA_100k_RXEN_duration,13,1,2) -__MREG__(MAX2839_RXVGA_100k_B6B7_duration,13,3,2) -__MREG__(MAX2839_RXVGA_30k_RXEN_duration,13,5,2) -__MREG__(MAX2839_RXVGA_30k_B6B7_duration,13,7,2) -__MREG__(MAX2839_RXVGA_1k_RXEN_duration,13,9,2) +__MREG__(MAX2839_HPC_100k_RXEN_duration,13,1,2) +__MREG__(MAX2839_HPC_100k_B6B7_duration,13,3,2) +__MREG__(MAX2839_HPC_30k_RXEN_duration,13,5,2) +__MREG__(MAX2839_HPC_30k_B6B7_duration,13,7,2) +__MREG__(MAX2839_HPC_1k_RXEN_duration,13,9,2) /* REG 14 */ -__MREG__(MAX2839_RXVGA_1k_B6B7_duration,14,1,2) -__MREG__(MAX2839_RXVGA_HPCa_HPCd_delay,14,3,2) -__MREG__(MAX2839_RXVGA_final_highpass_corner,14,5,2) -__MREG__(MAX2839_RXVGA_highpass_MODE2,14,7,2) -__MREG__(MAX2839_RXVGA_HPFSM_B6B7,14,8,1) -__MREG__(MAX2839_PA_DRV_DAC,14,9,1) +__MREG__(MAX2839_HPC_1k_B6B7_duration,14,1,2) +__MREG__(MAX2839_HPC_DELAY,14,3,2) +__MREG__(MAX2839_HPC_STOP,14,5,2) +#define MAX2839_STOP_100 0 +#define MAX2839_STOP_1K 1 +#define MAX2839_STOP_30K 2 +#define MAX2839_STOP_100K 3 +__MREG__(MAX2839_HPC_STOP_MODE2,14,7,2) +__MREG__(MAX2839_HPC_RXGAIN_EN,14,8,1) +__MREG__(MAX2839_PA_DRV_GATE,14,9,1) /* REG 15 */ __MREG__(MAX2839_RXVGA_HPFSM_Clk_Divider,15,0,1) From ea3b804edfa6f3be61ac03a5d13bc7c96ac6e548 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Tue, 27 Sep 2022 14:42:55 -0400 Subject: [PATCH 016/474] h1r9: workaround platform detection problem On the first spin of r9 one of the pins used for platform detection is pulled up to VAA, not VCC, and VAA hasn't been switched on yet at the time of platform detection. This results in r9 being misidentified as OG from time to time. As a temporary workaround until the next board spin, change the platform from OG to r9 if it is detected as OG but has r9 pin straps. --- firmware/common/platform_detect.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/firmware/common/platform_detect.c b/firmware/common/platform_detect.c index ee9b8d54..1cc6f479 100644 --- a/firmware/common/platform_detect.c +++ b/firmware/common/platform_detect.c @@ -198,6 +198,11 @@ void detect_hardware_platform(void) (adc0_3 == PIN_STRAP_LOW) && (adc0_4 == PIN_STRAP_LOW) && (platform == BOARD_ID_HACKRF1_R9)) { revision = BOARD_REV_HACKRF1_R9; + } else if ( //FIXME temporary + (adc0_3 == PIN_STRAP_LOW) && (adc0_4 == PIN_STRAP_LOW) && + (platform == BOARD_ID_HACKRF1_OG)) { + revision = BOARD_REV_HACKRF1_R9; + platform = BOARD_ID_HACKRF1_R9; } else { revision = BOARD_REV_UNRECOGNIZED; } From 7a0aec00efad374586a641d1c391dac9b48717e4 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Tue, 27 Sep 2022 14:45:58 -0400 Subject: [PATCH 017/474] h1r9: fix usb_vendor_request_reset() The bootloader is configured by pin straps on certain pins. We use some of those for other purposes in r9 which causes the bootloader to misbehave if the device is reset from software. By switching these pins from outputs to inputs just before reset this problem is avoided. --- firmware/hackrf_usb/usb_api_board_info.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/firmware/hackrf_usb/usb_api_board_info.c b/firmware/hackrf_usb/usb_api_board_info.c index e6a2b8f2..97f92a99 100644 --- a/firmware/hackrf_usb/usb_api_board_info.c +++ b/firmware/hackrf_usb/usb_api_board_info.c @@ -33,6 +33,13 @@ #include #include +#ifdef HACKRF_ONE + #include "gpio_lpc.h" +static struct gpio_t gpio_h1r9_clkout_en = GPIO(0, 9); +static struct gpio_t gpio_h1r9_mcu_clk_en = GPIO(0, 8); +static struct gpio_t gpio_h1r9_rx = GPIO(0, 7); +#endif + usb_request_status_t usb_vendor_request_read_board_id( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) @@ -123,7 +130,19 @@ usb_request_status_t usb_vendor_request_reset( const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { +#ifdef HACKRF_ONE + /* + * Set boot pins as inputs so that the bootloader reads them + * correctly after the reset. + */ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + gpio_input(&gpio_h1r9_mcu_clk_en); + gpio_input(&gpio_h1r9_clkout_en); + gpio_input(&gpio_h1r9_rx); + } +#endif wwdt_reset(100000); + usb_transfer_schedule_ack(endpoint->in); } return USB_REQUEST_STATUS_OK; From eb8ed45f9a3d99c3091e4a25f8bd40339065f7aa Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Wed, 28 Sep 2022 04:43:39 -0400 Subject: [PATCH 018/474] h1r9: adjust PLLA according to source frequency --- firmware/common/si5351c.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index a3cb8d3e..0dc48331 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -324,9 +324,20 @@ void si5351c_set_int_mode( void si5351c_set_clock_source(si5351c_driver_t* const drv, const enum pll_sources source) { - if (source != active_clock_source) { - si5351c_configure_clock_control(drv, source); - active_clock_source = source; + if (source == active_clock_source) { + return; + } + si5351c_configure_clock_control(drv, source); + active_clock_source = source; + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + /* 25MHz XTAL * (0x0e00+512)/128 = 800mhz -> int mode */ + uint8_t pll_data[] = {26, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00}; + if (source == PLL_SOURCE_CLKIN) { + /* 10MHz CLKIN * (0x2600+512)/128 = 800mhz */ + pll_data[4] = 0x26; + } + si5351c_write(drv, pll_data, sizeof(pll_data)); + si5351c_reset_pll(drv); } } From 5693f7b193c16bdac56d363df17488670b922faa Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sat, 1 Oct 2022 13:20:46 -0400 Subject: [PATCH 019/474] h1r9: MAX2839: support maximum TX gain, not minimum --- firmware/common/max2839.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/firmware/common/max2839.c b/firmware/common/max2839.c index 28cf3ff5..9dbd089b 100644 --- a/firmware/common/max2839.c +++ b/firmware/common/max2839.c @@ -336,9 +336,10 @@ bool max2839_set_vga_gain(max2839_driver_t* const drv, const uint32_t gain_db) { return true; } -bool max2839_set_txvga_gain(max2839_driver_t* const drv, const uint32_t gain_db) { - uint16_t val=0; - val = 63-gain_db; +bool max2839_set_txvga_gain(max2839_driver_t* const drv, const uint32_t gain_db) +{ + uint16_t val = 0; + val = 47 - gain_db; set_MAX2839_TX_VGA_GAIN(drv, val); max2839_reg_commit(drv, 29); From b15509c2d9e6824ffabe2ceade86c9cf48c2493d Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Mon, 3 Oct 2022 06:08:59 -0400 Subject: [PATCH 020/474] h1r9: MAX2839: emulate MAX2837 RX gain configuration --- firmware/common/max2839.c | 120 +++++++++++++++++++++++++++++--------- 1 file changed, 94 insertions(+), 26 deletions(-) diff --git a/firmware/common/max2839.c b/firmware/common/max2839.c index 9dbd089b..23b64629 100644 --- a/firmware/common/max2839.c +++ b/firmware/common/max2839.c @@ -33,6 +33,9 @@ #include "max2839.h" #include "max2839_regs.def" // private register def macros +static uint8_t requested_lna_gain = 0; +static uint8_t requested_vga_gain = 0; + /* Default register values. */ static const uint16_t max2839_regs_default[MAX2839_NUM_REGS] = { 0x000, /* 0 */ @@ -300,39 +303,104 @@ uint32_t max2839_set_lpf_bandwidth(max2839_driver_t* const drv, const uint32_t b return p->bandwidth_hz; } -bool max2839_set_lna_gain(max2839_driver_t* const drv, const uint32_t gain_db) { +void max2839_configure_rx_gain(max2839_driver_t* const drv) +{ + /* + * restrict requested LNA gain to valid MAX2837 settings: + * 0, 8, 16, 24, 32, or 40 + */ + if (requested_lna_gain > 40) { + requested_lna_gain = 40; + } + requested_lna_gain &= 0x38; + + /* + * restrict requested VGA gain to valid MAX2837 settings: + * even number, 0 through 62 + */ + if (requested_vga_gain > 62) { + requested_vga_gain = 62; + } + requested_vga_gain &= 0x3e; + + /* + * MAX2839 has lower full-scale RX output voltage than MAX2837, so we + * adjust the VGA (baseband) gain to compensate. + */ + uint8_t vga_gain = requested_vga_gain + 3; + uint8_t lna_gain = requested_lna_gain; + + /* + * If that adjustment puts VGA gain out of range, use LNA gain to + * compensate. MAX2839 VGA gain can be any number from 0 through 63. + */ + if (vga_gain > 63) { + if (lna_gain <= 32) { + vga_gain -= 8; + lna_gain += 8; + } else { + vga_gain = 63; + } + } + + /* + * MAX2839 lacks max-24 dB and max-40 dB LNA gain settings, so we use + * VGA gain to compensate. + */ + if (lna_gain == 0) { + lna_gain = 8; + vga_gain = (vga_gain >= 8) ? vga_gain - 8 : 0; + } + if (lna_gain == 16) { + if (vga_gain > 32) { + vga_gain -= 8; + lna_gain += 8; + } else { + vga_gain += 8; + lna_gain -= 8; + } + } + uint16_t val; - switch(gain_db){ - case 40: - val = MAX2839_LNA2gain_MAX; - break; - case 32: - val = MAX2839_LNA2gain_M8; - break; - case 24: - // FIXME correct missing settings with VGA adjustment? - case 16: - val = MAX2839_LNA2gain_M16; - break; - case 8: - case 0: - val = MAX2839_LNA2gain_M32; - break; - default: - return false; + switch (lna_gain) { + case 40: + val = MAX2839_LNA2gain_MAX; + break; + case 32: + val = MAX2839_LNA2gain_M8; + break; + case 24: + case 16: + val = MAX2839_LNA2gain_M16; + break; + case 8: + case 0: + default: + val = MAX2839_LNA2gain_M32; + break; } set_MAX2839_LNA2gain(drv, val); - max2839_reg_commit(drv, 6); + set_MAX2839_Rx2_VGAgain(drv, (63 - vga_gain)); + max2839_regs_commit(drv); +} + +bool max2839_set_lna_gain(max2839_driver_t* const drv, const uint32_t gain_db) +{ + if ((gain_db & 0x7) || gain_db > 40) { + return false; + } + requested_lna_gain = gain_db; + max2839_configure_rx_gain(drv); return true; } -bool max2839_set_vga_gain(max2839_driver_t* const drv, const uint32_t gain_db) { - if( (gain_db & 0x1) || gain_db > 62) {/* 0b11111*2 */ +bool max2839_set_vga_gain(max2839_driver_t* const drv, const uint32_t gain_db) +{ + if ((gain_db & 0x1) || gain_db > 62) { return false; -} - - set_MAX2839_Rx2_VGAgain(drv, (63-gain_db)); - max2839_reg_commit(drv, 6); + } + requested_vga_gain = gain_db; + max2839_configure_rx_gain(drv); return true; } From 7b5d8da8210a566417a8c6d58acd66aca6c2682b Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Mon, 3 Oct 2022 06:26:00 -0400 Subject: [PATCH 021/474] h1r9: swap RX Q inversion --- firmware/common/sgpio.c | 16 +++++++++++----- firmware/common/sgpio.h | 4 +--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/firmware/common/sgpio.c b/firmware/common/sgpio.c index 8fd4a8ab..5c5728fe 100644 --- a/firmware/common/sgpio.c +++ b/firmware/common/sgpio.c @@ -25,9 +25,10 @@ #include #include -#include +#include "hackrf_core.h" +#include "platform_detect.h" -#include +#include "sgpio.h" #ifdef RAD1O static void update_q_invert(sgpio_config_t* const config); @@ -329,10 +330,15 @@ void sgpio_cpld_stream_rx_set_q_invert( } #else -void sgpio_cpld_stream_rx_set_q_invert( - sgpio_config_t* const config, - const uint_fast8_t invert) +void sgpio_cpld_stream_rx_set_q_invert(sgpio_config_t* const config, uint_fast8_t invert) { + /* + * The RX IQ channels on HackRF One r9 are not inverted as they are + * on OG or Jawbreaker, so the opposite setting is required. + */ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + invert = (invert > 0) ? 0 : 1; + } gpio_write(config->gpio_rx_q_invert, invert); } #endif diff --git a/firmware/common/sgpio.h b/firmware/common/sgpio.h index a1e10b59..7779972d 100644 --- a/firmware/common/sgpio.h +++ b/firmware/common/sgpio.h @@ -49,8 +49,6 @@ void sgpio_cpld_stream_enable(sgpio_config_t* const config); void sgpio_cpld_stream_disable(sgpio_config_t* const config); bool sgpio_cpld_stream_is_enabled(sgpio_config_t* const config); -void sgpio_cpld_stream_rx_set_q_invert( - sgpio_config_t* const config, - const uint_fast8_t invert); +void sgpio_cpld_stream_rx_set_q_invert(sgpio_config_t* const config, uint_fast8_t invert); #endif //__SGPIO_H__ From dc67fbd2eeac38f1aad09068f82dc09187a8f25e Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Mon, 3 Oct 2022 22:00:16 -0400 Subject: [PATCH 022/474] h1r9: fix Opera Cake time mode compatibility TIMER3 match register 3 was interfering with SCT, fixed by turning off all ORing of timer outputs with SCT outputs. --- firmware/common/clkin.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/common/clkin.c b/firmware/common/clkin.c index 080d02d0..1d8e7511 100644 --- a/firmware/common/clkin.c +++ b/firmware/common/clkin.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #define CLOCK_CYCLES_1_MS (204000) @@ -56,6 +57,7 @@ void clkin_detect_init(void) (TIMER_EMR_EMC_TOGGLE << TIMER_EMR_EMC3_SHIFT); TIMER3_MR3 = MEASUREMENT_CYCLES; TIMER3_MR0 = MEASUREMENT_CYCLES; + CREG_CREG6 |= CREG_CREG6_CTOUTCTRL; /* Timer0 counts CLKIN */ timer_set_prescaler(TIMER0, 0); From 51bae663fc2c7bfde6c246b49ff07c1aaecd71cf Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Wed, 5 Oct 2022 15:02:53 -0400 Subject: [PATCH 023/474] h1r9: update pin assignments for board spin B --- firmware/common/clkin.c | 51 +++++++++++++++---------------- firmware/common/hackrf_core.c | 43 +++++++++++++++++--------- firmware/common/hackrf_core.h | 16 +++++----- firmware/common/platform_detect.c | 9 ++---- firmware/common/rf_path.c | 8 ++--- firmware/common/sgpio.c | 11 ++++++- 6 files changed, 76 insertions(+), 62 deletions(-) diff --git a/firmware/common/clkin.c b/firmware/common/clkin.c index 1d8e7511..5ab8123a 100644 --- a/firmware/common/clkin.c +++ b/firmware/common/clkin.c @@ -49,35 +49,32 @@ tcr_sequence reset; void clkin_detect_init(void) { - /* Timer3 triggers periodic measurement */ - timer_set_prescaler(TIMER3, 0); - timer_set_mode(TIMER3, TIMER_CTCR_MODE_TIMER); - TIMER3_MCR = TIMER_MCR_MR0R; - TIMER3_EMR = (TIMER_EMR_EMC_SET << TIMER_EMR_EMC0_SHIFT) | + /* Timer1 triggers periodic measurement */ + timer_set_prescaler(TIMER1, 0); + timer_set_mode(TIMER1, TIMER_CTCR_MODE_TIMER); + TIMER1_MCR = TIMER_MCR_MR0R; + TIMER1_EMR = (TIMER_EMR_EMC_SET << TIMER_EMR_EMC0_SHIFT) | (TIMER_EMR_EMC_TOGGLE << TIMER_EMR_EMC3_SHIFT); - TIMER3_MR3 = MEASUREMENT_CYCLES; - TIMER3_MR0 = MEASUREMENT_CYCLES; + TIMER1_MR3 = MEASUREMENT_CYCLES; + TIMER1_MR0 = MEASUREMENT_CYCLES; + + /* prevent TIMER1_MR3 from interfering with SCT */ CREG_CREG6 |= CREG_CREG6_CTOUTCTRL; - /* Timer0 counts CLKIN */ - timer_set_prescaler(TIMER0, 0); - TIMER0_CCR = TIMER_CCR_CAP3RE; - GIMA_CAP0_3_IN = 0x20; // T3_MAT3 + /* Timer2 counts CLKIN */ + timer_set_prescaler(TIMER2, 0); + TIMER2_CCR = TIMER_CCR_CAP3RE; + GIMA_CAP2_3_IN = 0x20; // T1_MAT3 - /* measure CLKIN signal on P2_5, pin 91, CTIN_2 */ - TIMER0_CTCR = TIMER_CTCR_MODE_COUNTER_RISING | TIMER_CTCR_CINSEL_CAPN_2; - scu_pinmux(P2_5, SCU_GPIO_PDN | SCU_CONF_FUNCTION1); - GIMA_CAP0_2_IN = 0x00; // CTIN_2 - - // temporarily testing with T0_CAP1, P1_12, pin 56, P28 pin 4 - //TIMER0_CTCR = TIMER_CTCR_MODE_COUNTER_RISING | TIMER_CTCR_CINSEL_CAPN_1; - //scu_pinmux(P1_12, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); - //GIMA_CAP0_1_IN = 0x20; // T0_CAP1 + /* measure CLKIN_DETECT signal on P4_8, pin 15, CTIN_5 */ + TIMER2_CTCR = TIMER_CTCR_MODE_COUNTER_RISING | TIMER_CTCR_CINSEL_CAPN_2; + scu_pinmux(P4_8, SCU_GPIO_PDN | SCU_CONF_FUNCTION1); // CTIN_5 + GIMA_CAP2_2_IN = 0x00; // CTIN_5 reset.first_tcr = TIMER_TCR_CEN | TIMER_TCR_CRST; reset.second_tcr = TIMER_TCR_CEN; timer_dma_lli.src = (uint32_t) & (reset); - timer_dma_lli.dest = (uint32_t) & (TIMER0_TCR); + timer_dma_lli.dest = (uint32_t) & (TIMER2_TCR); timer_dma_lli.next_lli = (uint32_t) & (timer_dma_lli); timer_dma_lli.control = GPDMA_CCONTROL_TRANSFERSIZE(2) | GPDMA_CCONTROL_SBSIZE(0) // 1 @@ -97,19 +94,19 @@ void clkin_detect_init(void) GPDMA_C0DESTADDR = timer_dma_lli.dest; GPDMA_C0LLI = timer_dma_lli.next_lli; GPDMA_C0CONTROL = timer_dma_lli.control; - GPDMA_C0CONFIG = GPDMA_CCONFIG_DESTPERIPHERAL(0x7) // T3_MAT0 + GPDMA_C0CONFIG = GPDMA_CCONFIG_DESTPERIPHERAL(0x3) // T1_MAT0 | GPDMA_CCONFIG_FLOWCNTRL(1) // memory-to-peripheral | GPDMA_CCONFIG_H(0); // do not halt gpdma_channel_enable(0); /* start counting */ - timer_reset(TIMER0); - timer_reset(TIMER3); - timer_enable_counter(TIMER0); - timer_enable_counter(TIMER3); + timer_reset(TIMER2); + timer_reset(TIMER1); + timer_enable_counter(TIMER2); + timer_enable_counter(TIMER1); } uint32_t clkin_frequency(void) { - return TIMER0_CR3 * (1000 / MEASUREMENT_WINDOW_MS); + return TIMER2_CR3 * (1000 / MEASUREMENT_WINDOW_MS); }; diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index a88e1695..b5acb892 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -144,9 +144,10 @@ static struct gpio_t gpio_rx_q_invert = GPIO(0, 13); /* HackRF One r9 */ #ifdef HACKRF_ONE -static struct gpio_t gpio_h1r9_rx = GPIO(0, 7); -static struct gpio_t gpio_h1r9_no_rx_amp_pwr = GPIO(3, 6); -static struct gpio_t gpio_h1r9_1v8_enable = GPIO(1, 12); +static struct gpio_t gpio_h1r9_rx = GPIO(0, 7); +static struct gpio_t gpio_h1r9_1v8_enable = GPIO(2, 9); +static struct gpio_t gpio_h1r9_vaa_disable = GPIO(3, 6); +static struct gpio_t gpio_h1r9_hw_sync_enable = GPIO(5, 5); #endif // clang-format on @@ -829,10 +830,10 @@ void cpu_clock_init(void) // CCU1_CLK_M4_SCT_CFG = 0; CCU1_CLK_M4_SDIO_CFG = 0; CCU1_CLK_M4_SPIFI_CFG = 0; - //CCU1_CLK_M4_TIMER0_CFG = 0; - CCU1_CLK_M4_TIMER1_CFG = 0; - CCU1_CLK_M4_TIMER2_CFG = 0; - //CCU1_CLK_M4_TIMER3_CFG = 0; + CCU1_CLK_M4_TIMER0_CFG = 0; + //CCU1_CLK_M4_TIMER1_CFG = 0; + //CCU1_CLK_M4_TIMER2_CFG = 0; + CCU1_CLK_M4_TIMER3_CFG = 0; CCU1_CLK_M4_UART1_CFG = 0; CCU1_CLK_M4_USART0_CFG = 0; CCU1_CLK_M4_USART2_CFG = 0; @@ -960,7 +961,7 @@ void pin_setup(void) if (detected_platform() == BOARD_ID_HACKRF1_R9) { #ifdef HACKRF_ONE gpio_output(&gpio_h1r9_1v8_enable); - scu_pinmux(P2_12, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_H1R9_EN1V8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); #endif } else { gpio_output(&gpio_1v8_enable); @@ -972,7 +973,11 @@ void pin_setup(void) disable_rf_power(); /* Configure RF power supply (VAA) switch control signal as output */ - gpio_output(&gpio_vaa_disable); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + gpio_output(&gpio_h1r9_vaa_disable); + } else { + gpio_output(&gpio_vaa_disable); + } #endif #ifdef RAD1O @@ -1005,7 +1010,7 @@ void pin_setup(void) #ifdef HACKRF_ONE if (detected_platform() == BOARD_ID_HACKRF1_R9) { rf_path.gpio_rx = &gpio_h1r9_rx; - rf_path.gpio_no_rx_amp_pwr = &gpio_h1r9_no_rx_amp_pwr; + sgpio_config.gpio_hw_sync_enable = &gpio_h1r9_hw_sync_enable; } #endif rf_path_pin_setup(&rf_path); @@ -1045,15 +1050,23 @@ void enable_rf_power(void) /* many short pulses to avoid one big voltage glitch */ for (i = 0; i < 1000; i++) { - gpio_clear(&gpio_vaa_disable); - gpio_set(&gpio_vaa_disable); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + gpio_set(&gpio_h1r9_vaa_disable); + gpio_clear(&gpio_h1r9_vaa_disable); + } else { + gpio_set(&gpio_vaa_disable); + gpio_clear(&gpio_vaa_disable); + } } - gpio_clear(&gpio_vaa_disable); } void disable_rf_power(void) { - gpio_set(&gpio_vaa_disable); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + gpio_set(&gpio_h1r9_vaa_disable); + } else { + gpio_set(&gpio_vaa_disable); + } } #endif @@ -1100,7 +1113,7 @@ void set_leds(const uint8_t state) void hw_sync_enable(const hw_sync_mode_t hw_sync_mode) { - gpio_write(&gpio_hw_sync_enable, hw_sync_mode == 1); + gpio_write(sgpio_config.gpio_hw_sync_enable, hw_sync_mode == 1); } void halt_and_flash(const uint32_t duration) diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 8045b1d2..0bd22da0 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -109,9 +109,9 @@ extern "C" { #define SCU_PINMUX_SGPIO10 (P1_14) #define SCU_PINMUX_SGPIO11 (P1_17) #define SCU_PINMUX_SGPIO12 (P1_18) -#define SCU_PINMUX_SGPIO13 (P4_8) #define SCU_PINMUX_SGPIO14 (P4_9) #define SCU_PINMUX_SGPIO15 (P4_10) +#define SCU_HW_SYNC_EN (P4_8) /* GPIO5[12] on P4_8 */ /* MAX2837 GPIO (XCVR_CTL) PinMux */ #ifdef RAD1O @@ -234,12 +234,14 @@ extern "C" { #define SCU_PINMUX_GP_CLKIN (P4_7) /* HackRF One r9 */ -#define SCU_H1R9_CLKIN_EN (P6_7) /* GPIO5[15] on P6_7 */ -#define SCU_H1R9_CLKOUT_EN (P1_2) /* GPIO0[9] on P1_2 (has boot pull-down) */ -#define SCU_H1R9_MCU_CLK_EN (P1_1) /* GPIO0[8] on P1_1 (has boot pull-up) */ -#define SCU_H1R9_RX (P2_7) /* GPIO0[7] on P4_4 (has boot pull-up) */ -#define SCU_H1R9_NO_RX_AMP_PWR (P6_10) /* GPIO3[6] on P6_10 */ -#define SCU_H1R9_NO_ANT_PWR (P4_4) /* GPIO2[4] on P4_4 */ +#define SCU_H1R9_CLKIN_EN (P6_7) /* GPIO5[15] on P6_7 */ +#define SCU_H1R9_CLKOUT_EN (P1_2) /* GPIO0[9] on P1_2 (has boot pull-down) */ +#define SCU_H1R9_MCU_CLK_EN (P1_1) /* GPIO0[8] on P1_1 (has boot pull-up) */ +#define SCU_H1R9_RX (P2_7) /* GPIO0[7] on P4_4 (has boot pull-up) */ +#define SCU_H1R9_NO_ANT_PWR (P4_4) /* GPIO2[4] on P4_4 */ +#define SCU_H1R9_EN1V8 (P5_0) /* GPIO2[9] on P5_0 */ +#define SCU_H1R9_NO_VAA_EN (P6_10) /* GPIO3[6] on P6_10 */ +#define SCU_H1R9_HW_SYNC_EN (P2_5) /* GPIO5[5] on P2_5 */ typedef enum { TRANSCEIVER_MODE_OFF = 0, diff --git a/firmware/common/platform_detect.c b/firmware/common/platform_detect.c index 1cc6f479..e1608bd8 100644 --- a/firmware/common/platform_detect.c +++ b/firmware/common/platform_detect.c @@ -42,13 +42,13 @@ static struct gpio_t gpio3_6_on_P6_10 = GPIO(3, 6); * Jawbreaker has a pull-down on P6_10 and nothing on P5_0. * rad1o has a pull-down on P6_10 and a pull-down on P5_0. * HackRF One OG has a pull-down on P6_10 and a pull-up on P5_0. - * HackRF One r9 has a pull-up on P6_10 and a pull-up on P5_0. //FIXME temporary + * HackRF One r9 has a pull-up on P6_10 and a pull-down on P5_0. */ #define JAWBREAKER_RESISTORS (P6_10_PDN) #define RAD1O_RESISTORS (P6_10_PDN | P5_0_PDN) #define HACKRF1_OG_RESISTORS (P6_10_PDN | P5_0_PUP) -#define HACKRF1_R9_RESISTORS (P6_10_PUP | P5_0_PUP) +#define HACKRF1_R9_RESISTORS (P6_10_PUP | P5_0_PDN) /* * LEDs are configured so that they flash if the detected hardware platform is @@ -198,11 +198,6 @@ void detect_hardware_platform(void) (adc0_3 == PIN_STRAP_LOW) && (adc0_4 == PIN_STRAP_LOW) && (platform == BOARD_ID_HACKRF1_R9)) { revision = BOARD_REV_HACKRF1_R9; - } else if ( //FIXME temporary - (adc0_3 == PIN_STRAP_LOW) && (adc0_4 == PIN_STRAP_LOW) && - (platform == BOARD_ID_HACKRF1_OG)) { - revision = BOARD_REV_HACKRF1_R9; - platform = BOARD_ID_HACKRF1_R9; } else { revision = BOARD_REV_UNRECOGNIZED; } diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index fc04569e..bdc5341e 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -286,23 +286,21 @@ void rf_path_pin_setup(rf_path_t* const rf_path) scu_pinmux(SCU_NO_TX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); scu_pinmux(SCU_AMP_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); scu_pinmux(SCU_RX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_NO_RX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); // clang-format on if (detected_platform() == BOARD_ID_HACKRF1_R9) { scu_pinmux(SCU_H1R9_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - scu_pinmux(SCU_H1R9_NO_RX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); scu_pinmux(SCU_H1R9_NO_ANT_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); gpio_clear(&gpio_h1r9_no_ant_pwr); gpio_output(&gpio_h1r9_no_ant_pwr); + scu_pinmux(SCU_H1R9_NO_VAA_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); } else { scu_pinmux(SCU_TX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); scu_pinmux(SCU_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); - scu_pinmux(SCU_NO_RX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); gpio_output(rf_path->gpio_tx); + scu_pinmux(SCU_NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); } - /* Configure RF power supply (VAA) switch */ - scu_pinmux(SCU_NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); - /* * Safe (initial) switch settings turn off both amplifiers and antenna port * power and enable both amp bypass and mixer bypass. diff --git a/firmware/common/sgpio.c b/firmware/common/sgpio.c index 5c5728fe..fe0ddce1 100644 --- a/firmware/common/sgpio.c +++ b/firmware/common/sgpio.c @@ -49,10 +49,19 @@ void sgpio_configure_pin_functions(sgpio_config_t* const config) scu_pinmux(SCU_PINMUX_SGPIO10, SCU_GPIO_FAST | SCU_CONF_FUNCTION6); scu_pinmux(SCU_PINMUX_SGPIO11, SCU_GPIO_FAST | SCU_CONF_FUNCTION6); scu_pinmux(SCU_PINMUX_SGPIO12, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); /* GPIO0[13] */ - scu_pinmux(SCU_PINMUX_SGPIO13, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[12] */ scu_pinmux(SCU_PINMUX_SGPIO14, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[13] */ scu_pinmux(SCU_PINMUX_SGPIO15, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[14] */ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + scu_pinmux( + SCU_H1R9_HW_SYNC_EN, + SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[5] */ + } else { + scu_pinmux( + SCU_HW_SYNC_EN, + SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[12] */ + } + sgpio_cpld_stream_rx_set_q_invert(config, 0); hw_sync_enable(0); From 24f2c1d073a5b932ed0b532c0c50a330f0992c07 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sun, 9 Oct 2022 05:58:26 -0400 Subject: [PATCH 024/474] h1r9: MAX2839: always use the low LNA band --- firmware/common/max2839.c | 13 +++++++------ firmware/common/max2839_regs.def | 10 +++++++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/firmware/common/max2839.c b/firmware/common/max2839.c index 23b64629..a8c69f8c 100644 --- a/firmware/common/max2839.c +++ b/firmware/common/max2839.c @@ -117,6 +117,13 @@ void max2839_setup(max2839_driver_t* const drv) /* set HPF corner frequency to 1 kHz */ set_MAX2839_HPC_STOP(drv, MAX2839_STOP_1K); + /* + * There are two LNA band settings, but we only use one of them. + * Switching to the other one doesn't make the overall spectrum any + * flatter but adds a surprise step in the middle. + */ + set_MAX2839_LNAband(drv, MAX2839_LNAband_2_4); + max2839_regs_commit(drv); } @@ -207,7 +214,6 @@ void max2839_stop(max2839_driver_t* const drv) void max2839_set_frequency(max2839_driver_t* const drv, uint32_t freq) { uint8_t band; - uint8_t lna_band; uint32_t div_frac; uint32_t div_int; uint32_t div_rem; @@ -217,16 +223,12 @@ void max2839_set_frequency(max2839_driver_t* const drv, uint32_t freq) /* Select band. Allow tuning outside specified bands. */ if (freq < 2400000000U) { band = MAX2839_LOGEN_BSW_2_3; - lna_band = MAX2839_LNAband_2_4; } else if (freq < 2500000000U) { band = MAX2839_LOGEN_BSW_2_4; - lna_band = MAX2839_LNAband_2_4; } else if (freq < 2600000000U) { band = MAX2839_LOGEN_BSW_2_5; - lna_band = MAX2839_LNAband_2_6; } else { band = MAX2839_LOGEN_BSW_2_6; - lna_band = MAX2839_LNAband_2_6; } /* ASSUME 40MHz PLL. Ratio = F*(4/3)/40,000,000 = F/30,000,000 */ @@ -245,7 +247,6 @@ void max2839_set_frequency(max2839_driver_t* const drv, uint32_t freq) /* Band settings */ set_MAX2839_LOGEN_BSW(drv, band); - set_MAX2839_LNAband(drv, lna_band); /* Write order matters here, so commit INT and FRAC_HI before * committing FRAC_LO, which is the trigger for VCO diff --git a/firmware/common/max2839_regs.def b/firmware/common/max2839_regs.def index 8cd578cf..bee66846 100644 --- a/firmware/common/max2839_regs.def +++ b/firmware/common/max2839_regs.def @@ -119,7 +119,15 @@ __MREG__(MAX2839_Temperature_Clk_En,9,1,1) __MREG__(MAX2839_RESERVED_9_2,9,2,1) __MREG__(MAX2839_DOUT_Drive_Sel,9,3,1) __MREG__(MAX2839_DOUT_3state_Ctrl,9,4,1) -__MREG__(MAX2839_DOUT_Pin_Sel,9,7,3) +__MREG__(MAX2839_DOUT_SEL,9,7,3) +#define MAX2839_DOUT_SEL_SPI 0 // default, SPI comm +#define MAX2839_DOUT_SEL_PLL_LOCK_DETECT 1 +#define MAX2839_DOUT_SEL_VAS_TEST_OUT 2 +#define MAX2839_DOUT_SEL_HPFSM_TEST_OUT 3 +#define MAX2839_DOUT_SEL_LOGEN_TRIM_OUT 4 +#define MAX2839_DOUT_SEL_RX_FUSE_GASKET 5 +#define MAX2839_DOUT_SEL_TX_FUSE_GASKET 6 +#define MAX2839_DOUT_SEL_ZERO 7 __MREG__(MAX2839_RESERVED_9_9,9,9,2) /* REG 10 */ From bfe882a2fae6af06c27c7601f73125971cf6fc73 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Tue, 11 Oct 2022 14:58:13 +0100 Subject: [PATCH 025/474] h1r9: add MAX283x abstraction layer --- firmware/common/hackrf_core.c | 31 +-- firmware/common/hackrf_core.h | 2 + firmware/common/max2837.h | 2 +- firmware/common/max2839.h | 6 +- firmware/common/max283x.c | 280 ++++++++++++++++++++++ firmware/common/max283x.h | 104 ++++++++ firmware/common/rf_path.c | 17 +- firmware/common/tuning.c | 41 +--- firmware/hackrf-common.cmake | 1 + firmware/hackrf_usb/usb_api_transceiver.c | 18 +- 10 files changed, 411 insertions(+), 91 deletions(-) create mode 100644 firmware/common/max283x.c create mode 100644 firmware/common/max283x.h diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index b5acb892..e81b18b4 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -26,10 +26,7 @@ #include "sgpio.h" #include "si5351c.h" #include "spi_ssp.h" -#include "max2837.h" -#include "max2837_target.h" -#include "max2839.h" -#include "max2839_target.h" +#include "max283x.h" #include "max5864.h" #include "max5864_target.h" #include "w25q80bv.h" @@ -65,9 +62,6 @@ static struct gpio_t gpio_1v8_enable = GPIO(3, 6); /* MAX2837 GPIO (XCVR_CTL) PinMux */ static struct gpio_t gpio_max2837_select = GPIO(0, 15); -static struct gpio_t gpio_max2837_enable = GPIO(2, 6); -static struct gpio_t gpio_max2837_rx_enable = GPIO(2, 5); -static struct gpio_t gpio_max2837_tx_enable = GPIO(2, 4); /* MAX5864 SPI chip select (AD_CS) GPIO PinMux */ static struct gpio_t gpio_max5864_select = GPIO(2, 7); @@ -229,22 +223,7 @@ spi_bus_t spi_bus_ssp1 = { .transfer_gather = spi_ssp_transfer_gather, }; -max2837_driver_t max2837 = { - .bus = &spi_bus_ssp1, - .gpio_enable = &gpio_max2837_enable, - .gpio_rx_enable = &gpio_max2837_rx_enable, - .gpio_tx_enable = &gpio_max2837_tx_enable, - .target_init = max2837_target_init, - .set_mode = max2837_target_set_mode, -}; - -max2839_driver_t max2839 = { - .bus = &spi_bus_ssp1, - .gpio_enable = &gpio_max2837_enable, - .gpio_rxtx = &gpio_max2837_rx_enable, - .target_init = max2839_target_init, - .set_mode = max2839_target_set_mode, -}; +max283x_driver_t max283x = {}; max5864_driver_t max5864 = { .bus = &spi_bus_ssp1, @@ -560,11 +539,7 @@ bool sample_rate_set(const uint32_t sample_rate_hz) bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz) { uint32_t bandwidth_hz_real; - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - bandwidth_hz_real = max2839_set_lpf_bandwidth(&max2839, bandwidth_hz); - } else { - bandwidth_hz_real = max2837_set_lpf_bandwidth(&max2837, bandwidth_hz); - } + bandwidth_hz_real = max283x_set_lpf_bandwidth(&max283x, bandwidth_hz); if (bandwidth_hz_real) { hackrf_ui()->set_filter_bw(bandwidth_hz_real); diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 0bd22da0..5aa08b24 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -34,6 +34,7 @@ extern "C" { #include "si5351c.h" #include "spi_ssp.h" +#include "max283x.h" #include "max2837.h" #include "max2839.h" #include "max5864.h" @@ -273,6 +274,7 @@ extern const ssp_config_t ssp_config_max2837; extern const ssp_config_t ssp_config_max2839; extern const ssp_config_t ssp_config_max5864; +extern max283x_driver_t max283x; extern max2837_driver_t max2837; extern max2839_driver_t max2839; //FIXME xcvr hal extern max5864_driver_t max5864; diff --git a/firmware/common/max2837.h b/firmware/common/max2837.h index 25a78a15..5f0b0024 100644 --- a/firmware/common/max2837.h +++ b/firmware/common/max2837.h @@ -45,7 +45,7 @@ struct max2837_driver_t; typedef struct max2837_driver_t max2837_driver_t; struct max2837_driver_t { - spi_bus_t* const bus; + spi_bus_t* bus; gpio_t gpio_enable; gpio_t gpio_rx_enable; gpio_t gpio_tx_enable; diff --git a/firmware/common/max2839.h b/firmware/common/max2839.h index dd7e7f3a..9be7d090 100644 --- a/firmware/common/max2839.h +++ b/firmware/common/max2839.h @@ -35,19 +35,19 @@ typedef enum { MAX2839_MODE_SHUTDOWN, - MAX2839_MODE_CLKOUT, MAX2839_MODE_STANDBY, - MAX2839_MODE_RX, MAX2839_MODE_TX, + MAX2839_MODE_RX, MAX2839_MODE_RX_CAL, MAX2839_MODE_TX_CAL, + MAX2839_MODE_CLKOUT, } max2839_mode_t; struct max2839_driver_t; typedef struct max2839_driver_t max2839_driver_t; struct max2839_driver_t { - spi_bus_t* const bus; + spi_bus_t* bus; gpio_t gpio_enable; gpio_t gpio_rxtx; void (*target_init)(max2839_driver_t* const drv); diff --git a/firmware/common/max283x.c b/firmware/common/max283x.c new file mode 100644 index 00000000..62f9829d --- /dev/null +++ b/firmware/common/max283x.c @@ -0,0 +1,280 @@ +/* + * Copyright 2012-2022 Great Scott Gadgets + * Copyright 2012 Will Code + * Copyright 2014 Jared Boone + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "max283x.h" + +#include "gpio.h" +#include "gpio_lpc.h" +#include "max2837.h" +#include "max2837_target.h" +#include "max2839.h" +#include "max2839_target.h" +#include "spi_bus.h" + +extern spi_bus_t spi_bus_ssp1; +static struct gpio_t gpio_max2837_enable = GPIO(2, 6); +static struct gpio_t gpio_max2837_rx_enable = GPIO(2, 5); +static struct gpio_t gpio_max2837_tx_enable = GPIO(2, 4); + +max2837_driver_t max2837 = { + .bus = &spi_bus_ssp1, + .gpio_enable = &gpio_max2837_enable, + .gpio_rx_enable = &gpio_max2837_rx_enable, + .gpio_tx_enable = &gpio_max2837_tx_enable, + .target_init = max2837_target_init, + .set_mode = max2837_target_set_mode, +}; + +max2839_driver_t max2839 = { + .bus = &spi_bus_ssp1, + .gpio_enable = &gpio_max2837_enable, + .gpio_rxtx = &gpio_max2837_rx_enable, + .target_init = max2839_target_init, + .set_mode = max2839_target_set_mode, +}; + +/* Initialize chip. */ +void max283x_setup(max283x_driver_t* const drv, max283x_variant_t type) +{ + drv->type = type; + switch (type) { + case MAX2837_VARIANT: + memcpy(&drv->drv.max2837, &max2837, sizeof(max2837)); + max2837_setup(&drv->drv.max2837); + break; + + case MAX2839_VARIANT: + memcpy(&drv->drv.max2839, &max2839, sizeof(max2839)); + max2839_setup(&drv->drv.max2839); + break; + } +} + +/* Read a register via SPI. Save a copy to memory and return + * value. Mark clean. */ +uint16_t max283x_reg_read(max283x_driver_t* const drv, uint8_t r) +{ + switch (drv->type) { + case MAX2837_VARIANT: + return max2837_reg_read(&drv->drv.max2837, r); + break; + + case MAX2839_VARIANT: + return max2839_reg_read(&drv->drv.max2839, r); + break; + } + + return 0; +} + +/* Write value to register via SPI and save a copy to memory. Mark + * clean. */ +void max283x_reg_write(max283x_driver_t* const drv, uint8_t r, uint16_t v) +{ + switch (drv->type) { + case MAX2837_VARIANT: + max2837_reg_write(&drv->drv.max2837, r, v); + break; + + case MAX2839_VARIANT: + max2839_reg_write(&drv->drv.max2839, r, v); + break; + } +} + +/* Write all dirty registers via SPI from memory. Mark all clean. Some + * operations require registers to be written in a certain order. Use + * provided routines for those operations. */ +void max283x_regs_commit(max283x_driver_t* const drv) +{ + switch (drv->type) { + case MAX2837_VARIANT: + max2837_regs_commit(&drv->drv.max2837); + break; + + case MAX2839_VARIANT: + max2839_regs_commit(&drv->drv.max2839); + break; + } +} + +void max283x_set_mode(max283x_driver_t* const drv, const max283x_mode_t new_mode) +{ + switch (drv->type) { + case MAX2837_VARIANT: + max2837_set_mode(&drv->drv.max2837, (max2837_mode_t) new_mode); + break; + + case MAX2839_VARIANT: + max2839_set_mode(&drv->drv.max2839, (max2839_mode_t) new_mode); + break; + } +} + +max283x_mode_t max283x_mode(max283x_driver_t* const drv) +{ + switch (drv->type) { + case MAX2837_VARIANT: + return (max283x_mode_t) max2837_mode(&drv->drv.max2837); + break; + + case MAX2839_VARIANT: + return (max283x_mode_t) max2839_mode(&drv->drv.max2839); + break; + } + + return 0; +} + +//max283x_mode_t max283x_mode(max283x_driver_t* const drv); +//void max283x_set_mode(max283x_driver_t* const drv, const max283x_mode_t new_mode); + +/* Turn on/off all chip functions. Does not control oscillator and CLKOUT */ +void max283x_start(max283x_driver_t* const drv) +{ + switch (drv->type) { + case MAX2837_VARIANT: + max2837_start(&drv->drv.max2837); + break; + + case MAX2839_VARIANT: + max2839_start(&drv->drv.max2839); + break; + } +} + +void max283x_stop(max283x_driver_t* const drv) +{ + switch (drv->type) { + case MAX2837_VARIANT: + max2837_stop(&drv->drv.max2837); + break; + + case MAX2839_VARIANT: + max2839_stop(&drv->drv.max2839); + break; + } +} + +/* Set frequency in Hz. Frequency setting is a multi-step function + * where order of register writes matters. */ +void max283x_set_frequency(max283x_driver_t* const drv, uint32_t freq) +{ + switch (drv->type) { + case MAX2837_VARIANT: + max2837_set_frequency(&drv->drv.max2837, freq); + break; + + case MAX2839_VARIANT: + max2839_set_frequency(&drv->drv.max2839, freq); + break; + } +} + +uint32_t max283x_set_lpf_bandwidth( + max283x_driver_t* const drv, + const uint32_t bandwidth_hz) +{ + switch (drv->type) { + case MAX2837_VARIANT: + return max2837_set_lpf_bandwidth(&drv->drv.max2837, bandwidth_hz); + break; + + case MAX2839_VARIANT: + return max2839_set_lpf_bandwidth(&drv->drv.max2839, bandwidth_hz); + break; + } + + return 0; +} + +bool max283x_set_lna_gain(max283x_driver_t* const drv, const uint32_t gain_db) +{ + switch (drv->type) { + case MAX2837_VARIANT: + return max2837_set_lna_gain(&drv->drv.max2837, gain_db); + break; + + case MAX2839_VARIANT: + return max2839_set_lna_gain(&drv->drv.max2839, gain_db); + break; + } + + return false; +} + +bool max283x_set_vga_gain(max283x_driver_t* const drv, const uint32_t gain_db) +{ + switch (drv->type) { + case MAX2837_VARIANT: + return max2837_set_vga_gain(&drv->drv.max2837, gain_db); + break; + + case MAX2839_VARIANT: + return max2839_set_vga_gain(&drv->drv.max2839, gain_db); + break; + } + + return false; +} + +bool max283x_set_txvga_gain(max283x_driver_t* const drv, const uint32_t gain_db) +{ + switch (drv->type) { + case MAX2837_VARIANT: + return max2837_set_txvga_gain(&drv->drv.max2837, gain_db); + break; + + case MAX2839_VARIANT: + return max2839_set_txvga_gain(&drv->drv.max2839, gain_db); + break; + } + + return false; +} + +void max283x_tx(max283x_driver_t* const drv) +{ + switch (drv->type) { + case MAX2837_VARIANT: + max2837_tx(&drv->drv.max2837); + break; + + case MAX2839_VARIANT: + max2839_tx(&drv->drv.max2839); + break; + } +} + +void max283x_rx(max283x_driver_t* const drv) +{ + switch (drv->type) { + case MAX2837_VARIANT: + max2837_rx(&drv->drv.max2837); + break; + + case MAX2839_VARIANT: + max2839_rx(&drv->drv.max2839); + break; + } +} diff --git a/firmware/common/max283x.h b/firmware/common/max283x.h new file mode 100644 index 00000000..eaf15a70 --- /dev/null +++ b/firmware/common/max283x.h @@ -0,0 +1,104 @@ +/* + * Copyright 2012-2022 Great Scott Gadgets + * Copyright 2012 Will Code + * Copyright 2014 Jared Boone + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __MAX283x_H +#define __MAX283x_H + +#include +#include +#include + +#include "gpio.h" +#include "gpio_lpc.h" +#include "max2837.h" +#include "max2837_target.h" +#include "max2839.h" +#include "max2839_target.h" +#include "spi_bus.h" + +typedef enum { + MAX283x_MODE_SHUTDOWN, + MAX283x_MODE_STANDBY, + MAX283x_MODE_TX, + MAX283x_MODE_RX, + MAX283x_MODE_RX_CAL, + MAX283x_MODE_TX_CAL, + MAX283x_MODE_CLKOUT, +} max283x_mode_t; + +typedef enum { + MAX2837_VARIANT, + MAX2839_VARIANT, +} max283x_variant_t; + +typedef struct { + max283x_variant_t type; + + union { + max2837_driver_t max2837; + max2839_driver_t max2839; + } drv; +} max283x_driver_t; + +/* Initialize chip. */ +void max283x_setup(max283x_driver_t* const drv, max283x_variant_t type); + +/* Read a register via SPI. Save a copy to memory and return + * value. Mark clean. */ +uint16_t max283x_reg_read(max283x_driver_t* const drv, uint8_t r); + +/* Write value to register via SPI and save a copy to memory. Mark + * clean. */ +void max283x_reg_write(max283x_driver_t* const drv, uint8_t r, uint16_t v); + +/* Write all dirty registers via SPI from memory. Mark all clean. Some + * operations require registers to be written in a certain order. Use + * provided routines for those operations. */ +void max283x_regs_commit(max283x_driver_t* const drv); + +//max283x_mode_t max283x_mode(max283x_driver_t* const drv); +//void max283x_set_mode(max283x_driver_t* const drv, const max283x_mode_t new_mode); + +max283x_mode_t max283x_mode(max283x_driver_t* const drv); +void max283x_set_mode(max283x_driver_t* const drv, const max283x_mode_t new_mode); + +/* Turn on/off all chip functions. Does not control oscillator and CLKOUT */ +void max283x_start(max283x_driver_t* const drv); +void max283x_stop(max283x_driver_t* const drv); + +/* Set frequency in Hz. Frequency setting is a multi-step function + * where order of register writes matters. */ +void max283x_set_frequency(max283x_driver_t* const drv, uint32_t freq); +uint32_t max283x_set_lpf_bandwidth( + max283x_driver_t* const drv, + const uint32_t bandwidth_hz); + +bool max283x_set_lna_gain(max283x_driver_t* const drv, const uint32_t gain_db); + +bool max283x_set_vga_gain(max283x_driver_t* const drv, const uint32_t gain_db); +bool max283x_set_txvga_gain(max283x_driver_t* const drv, const uint32_t gain_db); + +void max283x_tx(max283x_driver_t* const drv); +void max283x_rx(max283x_driver_t* const drv); + +#endif // __MAX283x_H diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index bdc5341e..229cfac8 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -31,6 +31,7 @@ #include "gpio_lpc.h" #include "platform_detect.h" #include "mixer.h" +#include "max283x.h" #include "max2837.h" #include "max2839.h" #include "max5864.h" @@ -370,13 +371,12 @@ void rf_path_init(rf_path_t* const rf_path) if (detected_platform() == BOARD_ID_HACKRF1_R9) { ssp1_set_mode_max2839(); - max2839_setup(&max2839); - max2839_start(&max2839); + max283x_setup(&max283x, MAX2839_VARIANT); } else { ssp1_set_mode_max2837(); - max2837_setup(&max2837); - max2837_start(&max2837); + max283x_setup(&max283x, MAX2837_VARIANT); } + max283x_start(&max283x); // On HackRF One, the mixer is now set up earlier in boot. #ifndef HACKRF_ONE @@ -406,11 +406,10 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d max5864_tx(&max5864); if (detected_platform() == BOARD_ID_HACKRF1_R9) { ssp1_set_mode_max2839(); - max2839_tx(&max2839); } else { ssp1_set_mode_max2837(); - max2837_tx(&max2837); } + max283x_tx(&max283x); sgpio_configure(&sgpio_config, SGPIO_DIRECTION_TX); break; @@ -430,11 +429,10 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d max5864_rx(&max5864); if (detected_platform() == BOARD_ID_HACKRF1_R9) { ssp1_set_mode_max2839(); - max2839_rx(&max2839); } else { ssp1_set_mode_max2837(); - max2837_rx(&max2837); } + max283x_rx(&max283x); sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX); break; @@ -451,11 +449,10 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d max5864_standby(&max5864); if (detected_platform() == BOARD_ID_HACKRF1_R9) { ssp1_set_mode_max2839(); - max2839_set_mode(&max2839, MAX2839_MODE_STANDBY); } else { ssp1_set_mode_max2837(); - max2837_set_mode(&max2837, MAX2837_MODE_STANDBY); } + max283x_set_mode(&max283x, MAX283x_MODE_STANDBY); sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX); break; } diff --git a/firmware/common/tuning.c b/firmware/common/tuning.c index 597fa396..ae12c238 100644 --- a/firmware/common/tuning.c +++ b/firmware/common/tuning.c @@ -70,15 +70,8 @@ bool set_freq(const uint64_t freq) success = true; - max2839_mode_t prior_max2839_mode = MAX2839_MODE_STANDBY; - max2837_mode_t prior_max2837_mode = MAX2837_MODE_STANDBY; - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - prior_max2839_mode = max2839_mode(&max2839); - max2839_set_mode(&max2839, MAX2839_MODE_STANDBY); - } else { - prior_max2837_mode = max2837_mode(&max2837); - max2837_set_mode(&max2837, MAX2837_MODE_STANDBY); - } + max283x_mode_t prior_max283x_mode = max283x_mode(&max283x); + max283x_set_mode(&max283x, MAX283x_MODE_STANDBY); if (freq_mhz < MAX_LP_FREQ_MHZ) { rf_path_set_filter(&rf_path, RF_PATH_FILTER_LOW_PASS); #ifdef RAD1O @@ -90,21 +83,13 @@ bool set_freq(const uint64_t freq) mixer_freq_mhz = (max2837_freq_nominal_hz / FREQ_ONE_MHZ) + freq_mhz; /* Set Freq and read real freq */ real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz); - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - max2839_set_frequency(&max2839, real_mixer_freq_hz - freq); - } else { - max2837_set_frequency(&max2837, real_mixer_freq_hz - freq); - } + max283x_set_frequency(&max283x, real_mixer_freq_hz - freq); sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 1); } else if ((freq_mhz >= MIN_BYPASS_FREQ_MHZ) && (freq_mhz < MAX_BYPASS_FREQ_MHZ)) { rf_path_set_filter(&rf_path, RF_PATH_FILTER_BYPASS); MAX2837_freq_hz = (freq_mhz * FREQ_ONE_MHZ) + freq_hz; /* mixer_freq_mhz <= not used in Bypass mode */ - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - max2839_set_frequency(&max2839, MAX2837_freq_hz); - } else { - max2837_set_frequency(&max2837, MAX2837_freq_hz); - } + max283x_set_frequency(&max283x, MAX2837_freq_hz); sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0); } else if ((freq_mhz >= MIN_HP_FREQ_MHZ) && (freq_mhz <= MAX_HP_FREQ_MHZ)) { if (freq_mhz < MID1_HP_FREQ_MHZ) { @@ -125,21 +110,13 @@ bool set_freq(const uint64_t freq) mixer_freq_mhz = freq_mhz - (max2837_freq_nominal_hz / FREQ_ONE_MHZ); /* Set Freq and read real freq */ real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz); - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - max2839_set_frequency(&max2839, freq - real_mixer_freq_hz); - } else { - max2837_set_frequency(&max2837, freq - real_mixer_freq_hz); - } + max283x_set_frequency(&max283x, freq - real_mixer_freq_hz); sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0); } else { /* Error freq_mhz too high */ success = false; } - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - max2839_set_mode(&max2839, prior_max2839_mode); - } else { - max2837_set_mode(&max2837, prior_max2837_mode); - } + max283x_set_mode(&max283x, prior_max283x_mode); if (success) { freq_cache = freq; hackrf_ui()->set_frequency(freq); @@ -170,11 +147,7 @@ bool set_freq_explicit( } rf_path_set_filter(&rf_path, path); - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - max2839_set_frequency(&max2839, if_freq_hz); - } else { - max2837_set_frequency(&max2837, if_freq_hz); - } + max283x_set_frequency(&max283x, if_freq_hz); if (lo_freq_hz > if_freq_hz) { sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 1); } else { diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index b39c8641..8418e47e 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -170,6 +170,7 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/sgpio.c ${PATH_HACKRF_FIRMWARE_COMMON}/rf_path.c ${PATH_HACKRF_FIRMWARE_COMMON}/si5351c.c + ${PATH_HACKRF_FIRMWARE_COMMON}/max283x.c ${PATH_HACKRF_FIRMWARE_COMMON}/max2837.c ${PATH_HACKRF_FIRMWARE_COMMON}/max2837_target.c ${PATH_HACKRF_FIRMWARE_COMMON}/max2839.c diff --git a/firmware/hackrf_usb/usb_api_transceiver.c b/firmware/hackrf_usb/usb_api_transceiver.c index 48bbbb94..a6cf86cc 100644 --- a/firmware/hackrf_usb/usb_api_transceiver.c +++ b/firmware/hackrf_usb/usb_api_transceiver.c @@ -166,11 +166,7 @@ usb_request_status_t usb_vendor_request_set_lna_gain( { if (stage == USB_TRANSFER_STAGE_SETUP) { uint8_t value; - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - value = max2839_set_lna_gain(&max2839, endpoint->setup.index); - } else { - value = max2837_set_lna_gain(&max2837, endpoint->setup.index); - } + value = max283x_set_lna_gain(&max283x, endpoint->setup.index); endpoint->buffer[0] = value; if (value) { hackrf_ui()->set_bb_lna_gain(endpoint->setup.index); @@ -193,11 +189,7 @@ usb_request_status_t usb_vendor_request_set_vga_gain( { if (stage == USB_TRANSFER_STAGE_SETUP) { uint8_t value; - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - value = max2839_set_vga_gain(&max2839, endpoint->setup.index); - } else { - value = max2837_set_vga_gain(&max2837, endpoint->setup.index); - } + value = max283x_set_vga_gain(&max283x, endpoint->setup.index); endpoint->buffer[0] = value; if (value) { hackrf_ui()->set_bb_vga_gain(endpoint->setup.index); @@ -220,11 +212,7 @@ usb_request_status_t usb_vendor_request_set_txvga_gain( { if (stage == USB_TRANSFER_STAGE_SETUP) { uint8_t value; - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - value = max2839_set_txvga_gain(&max2839, endpoint->setup.index); - } else { - value = max2837_set_txvga_gain(&max2837, endpoint->setup.index); - } + value = max283x_set_txvga_gain(&max283x, endpoint->setup.index); endpoint->buffer[0] = value; if (value) { hackrf_ui()->set_bb_tx_vga_gain(endpoint->setup.index); From 50a2e9dd56c20f95805ba48f2df5e9ab07b26698 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Mon, 24 Oct 2022 15:09:01 -0400 Subject: [PATCH 026/474] h1r9: update clock drive strength for spin C --- firmware/common/si5351c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index 0dc48331..84cfeea7 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -254,10 +254,10 @@ void si5351c_configure_clock_control( 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); + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_6MA); 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); + SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_4MA); data[3] = clkout_ctrl; data[4] = SI5351C_CLK_POWERDOWN; data[5] = SI5351C_CLK_POWERDOWN; From bdb6000bb45ea81befc563c83f9314c602c716d2 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Tue, 6 Dec 2022 23:41:34 -0500 Subject: [PATCH 027/474] h1r9: fix inverted spectrum on TX Unify and clean up the firmware spectrum inversion handling for all hardware platforms. --- firmware/common/hackrf_core.c | 4 +- firmware/common/sgpio.c | 78 +++++++++++++++-------------------- firmware/common/sgpio.h | 4 +- firmware/common/tuning.c | 10 ++--- 4 files changed, 42 insertions(+), 54 deletions(-) diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index e81b18b4..f40eea29 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -134,7 +134,7 @@ static struct gpio_t gpio_cpld_pp_tdo = GPIO(1, 8); /* other CPLD interface GPIO pins */ static struct gpio_t gpio_hw_sync_enable = GPIO(5, 12); -static struct gpio_t gpio_rx_q_invert = GPIO(0, 13); +static struct gpio_t gpio_q_invert = GPIO(0, 13); /* HackRF One r9 */ #ifdef HACKRF_ONE @@ -254,7 +254,7 @@ w25q80bv_driver_t spi_flash = { }; sgpio_config_t sgpio_config = { - .gpio_rx_q_invert = &gpio_rx_q_invert, + .gpio_q_invert = &gpio_q_invert, .gpio_hw_sync_enable = &gpio_hw_sync_enable, .slice_mode_multislice = true, }; diff --git a/firmware/common/sgpio.c b/firmware/common/sgpio.c index fe0ddce1..ccf7e162 100644 --- a/firmware/common/sgpio.c +++ b/firmware/common/sgpio.c @@ -30,9 +30,7 @@ #include "sgpio.h" -#ifdef RAD1O static void update_q_invert(sgpio_config_t* const config); -#endif void sgpio_configure_pin_functions(sgpio_config_t* const config) { @@ -62,10 +60,10 @@ void sgpio_configure_pin_functions(sgpio_config_t* const config) SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[12] */ } - sgpio_cpld_stream_rx_set_q_invert(config, 0); + sgpio_cpld_set_mixer_invert(config, 0); hw_sync_enable(0); - gpio_output(config->gpio_rx_q_invert); + gpio_output(config->gpio_q_invert); gpio_output(config->gpio_hw_sync_enable); } @@ -122,11 +120,9 @@ void sgpio_configure(sgpio_config_t* const config, const sgpio_direction_t direc ; // clang-format on -#ifdef RAD1O /* The data direction might have changed. Check if we need to * adjust the q inversion. */ update_q_invert(config); -#endif // Enable SGPIO pin outputs. const uint_fast16_t sgpio_gpio_data_direction = @@ -294,60 +290,52 @@ bool sgpio_cpld_stream_is_enabled(sgpio_config_t* const config) return (SGPIO_GPIO_OUTREG & (1L << 10)) == 0; /* SGPIO10 */ } -#ifdef RAD1O -/* The rad1o hardware has a bug which makes it - * necessary to also switch between the two options based - * on TX or RX mode. +/* + * The spectrum can be inverted by the analog section of the hardware in two + * different ways: * - * We use the state of the pin to determine which way we - * have to go. + * - The front-end mixer can introduce an inversion depending on the frequency + * tuning configuration. * - * As TX/RX can change without sgpio_cpld_stream_rx_set_q_invert - * being called, we store a local copy of its parameter. */ -static bool sgpio_invert = false; + * - Routing of the analog baseband signals can introduce an inversion + * depending on the design of the hardware platform and whether we are in RX + * or TX mode. + * + * When one but not both of the above effects inverts the spectrum, we instruct + * the CPLD to correct the inversion by inverting the Q sample value. + */ +static bool mixer_invert = false; -/* Called when TX/RX changes od sgpio_cpld_stream_rx_set_q_invert - * gets called. */ +/* Called when TX/RX changes or sgpio_cpld_set_mixer_invert() gets called. */ static void update_q_invert(sgpio_config_t* const config) { /* 1=Output SGPIO11 High(TX mode), 0=Output SGPIO11 Low(RX mode) */ bool tx_mode = (SGPIO_GPIO_OUTREG & (1 << 11)) > 0; - /* 0.13: P1_18 */ - if (!sgpio_invert & !tx_mode) { - gpio_write(config->gpio_rx_q_invert, 1); - } else if (!sgpio_invert & tx_mode) { - gpio_write(config->gpio_rx_q_invert, 0); - } else if (sgpio_invert & !tx_mode) { - gpio_write(config->gpio_rx_q_invert, 0); - } else if (sgpio_invert & tx_mode) { - gpio_write(config->gpio_rx_q_invert, 1); + /* + * This switch will need to change if we modify the CPLD to handle + * inversion the same way for RX and TX. + */ + bool baseband_invert = false; + switch (detected_platform()) { + case BOARD_ID_RAD1O: + case BOARD_ID_HACKRF1_R9: + baseband_invert = (tx_mode) ? false : true; + break; + default: + baseband_invert = false; } + + gpio_write(config->gpio_q_invert, mixer_invert ^ baseband_invert); } -void sgpio_cpld_stream_rx_set_q_invert( - sgpio_config_t* const config, - const uint_fast8_t invert) +void sgpio_cpld_set_mixer_invert(sgpio_config_t* const config, const uint_fast8_t invert) { if (invert) { - sgpio_invert = true; + mixer_invert = true; } else { - sgpio_invert = false; + mixer_invert = false; } update_q_invert(config); } - -#else -void sgpio_cpld_stream_rx_set_q_invert(sgpio_config_t* const config, uint_fast8_t invert) -{ - /* - * The RX IQ channels on HackRF One r9 are not inverted as they are - * on OG or Jawbreaker, so the opposite setting is required. - */ - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - invert = (invert > 0) ? 0 : 1; - } - gpio_write(config->gpio_rx_q_invert, invert); -} -#endif diff --git a/firmware/common/sgpio.h b/firmware/common/sgpio.h index 7779972d..e41982c5 100644 --- a/firmware/common/sgpio.h +++ b/firmware/common/sgpio.h @@ -36,7 +36,7 @@ typedef enum { } sgpio_direction_t; typedef struct sgpio_config_t { - gpio_t gpio_rx_q_invert; + gpio_t gpio_q_invert; gpio_t gpio_hw_sync_enable; bool slice_mode_multislice; } sgpio_config_t; @@ -49,6 +49,6 @@ void sgpio_cpld_stream_enable(sgpio_config_t* const config); void sgpio_cpld_stream_disable(sgpio_config_t* const config); bool sgpio_cpld_stream_is_enabled(sgpio_config_t* const config); -void sgpio_cpld_stream_rx_set_q_invert(sgpio_config_t* const config, uint_fast8_t invert); +void sgpio_cpld_set_mixer_invert(sgpio_config_t* const config, uint_fast8_t invert); #endif //__SGPIO_H__ diff --git a/firmware/common/tuning.c b/firmware/common/tuning.c index ae12c238..120831c4 100644 --- a/firmware/common/tuning.c +++ b/firmware/common/tuning.c @@ -84,13 +84,13 @@ bool set_freq(const uint64_t freq) /* Set Freq and read real freq */ real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz); max283x_set_frequency(&max283x, real_mixer_freq_hz - freq); - sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 1); + sgpio_cpld_set_mixer_invert(&sgpio_config, 1); } else if ((freq_mhz >= MIN_BYPASS_FREQ_MHZ) && (freq_mhz < MAX_BYPASS_FREQ_MHZ)) { rf_path_set_filter(&rf_path, RF_PATH_FILTER_BYPASS); MAX2837_freq_hz = (freq_mhz * FREQ_ONE_MHZ) + freq_hz; /* mixer_freq_mhz <= not used in Bypass mode */ max283x_set_frequency(&max283x, MAX2837_freq_hz); - sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0); + sgpio_cpld_set_mixer_invert(&sgpio_config, 0); } else if ((freq_mhz >= MIN_HP_FREQ_MHZ) && (freq_mhz <= MAX_HP_FREQ_MHZ)) { if (freq_mhz < MID1_HP_FREQ_MHZ) { /* IF is graduated from 2170 MHz to 2740 MHz */ @@ -111,7 +111,7 @@ bool set_freq(const uint64_t freq) /* Set Freq and read real freq */ real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz); max283x_set_frequency(&max283x, freq - real_mixer_freq_hz); - sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0); + sgpio_cpld_set_mixer_invert(&sgpio_config, 0); } else { /* Error freq_mhz too high */ success = false; @@ -149,9 +149,9 @@ bool set_freq_explicit( rf_path_set_filter(&rf_path, path); max283x_set_frequency(&max283x, if_freq_hz); if (lo_freq_hz > if_freq_hz) { - sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 1); + sgpio_cpld_set_mixer_invert(&sgpio_config, 1); } else { - sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0); + sgpio_cpld_set_mixer_invert(&sgpio_config, 0); } if (path != RF_PATH_FILTER_BYPASS) { (void) mixer_set_frequency(&mixer, lo_freq_hz / FREQ_ONE_MHZ); From ff4e1107f358a67b586280295bbe85bba41b090e Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Mon, 12 Dec 2022 07:39:18 -0500 Subject: [PATCH 028/474] h1r9: fix clkout PLL source bug --- firmware/common/max2839.c | 3 ++- firmware/common/max2839.h | 3 ++- firmware/common/si5351c.c | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/firmware/common/max2839.c b/firmware/common/max2839.c index a8c69f8c..868855d4 100644 --- a/firmware/common/max2839.c +++ b/firmware/common/max2839.c @@ -1,5 +1,6 @@ /* - * Copyright 2012 Will Code? (TODO: Proper attribution) + * Copyright 2012-2022 Great Scott Gadgets + * Copyright 2012 Will Code * Copyright 2014 Jared Boone * * This file is part of HackRF. diff --git a/firmware/common/max2839.h b/firmware/common/max2839.h index 9be7d090..fbffa5b1 100644 --- a/firmware/common/max2839.h +++ b/firmware/common/max2839.h @@ -1,5 +1,6 @@ /* - * Copyright 2012 Will Code? (TODO: Proper attribution) + * Copyright 2012-2022 Great Scott Gadgets + * Copyright 2012 Will Code * Copyright 2014 Jared Boone * * This file is part of HackRF. diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index 84cfeea7..af858875 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -208,6 +208,7 @@ void si5351c_configure_clock_control( * 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 { From 8051675c6063a3ab1c221e7b0d23db743b1e92b3 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Wed, 4 Jan 2023 17:32:42 +0000 Subject: [PATCH 029/474] h1r9: add R9 to supported platforms --- firmware/common/firmware_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/common/firmware_info.c b/firmware/common/firmware_info.c index aece61cd..b64894b1 100644 --- a/firmware/common/firmware_info.c +++ b/firmware/common/firmware_info.c @@ -30,7 +30,7 @@ #ifdef JAWBREAKER #define SUPPORTED_PLATFORM PLATFORM_JAWBREAKER #elif HACKRF_ONE - #define SUPPORTED_PLATFORM PLATFORM_HACKRF1_OG + #define SUPPORTED_PLATFORM (PLATFORM_HACKRF1_OG | PLATFORM_HACKRF1_R9) #elif RAD1O #define SUPPORTED_PLATFORM PLATFORM_RAD1O #else From c19f85ef24039db812aa59e3d35edc94ea72f257 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sun, 8 Jan 2023 08:21:27 -0500 Subject: [PATCH 030/474] h1r9: use single SSP configuration for MAX283x During r9 hardware development it was thought that the MAX2839 would use a different GPIO pin for chip select, but it ended up being the same pin as is used for MAX2837 on other hardware revisions. This takes the MAX283x abstraction a bit further and fixes a bug with hackrf_debug -m. --- firmware/common/hackrf_core.c | 37 +++++--------------------- firmware/common/hackrf_core.h | 10 ++----- firmware/common/max283x.h | 3 --- firmware/common/rf_path.c | 23 +++------------- firmware/common/ui_rad1o.c | 4 +-- firmware/hackrf_usb/hackrf_usb.c | 4 +-- firmware/hackrf_usb/usb_api_register.c | 12 ++++----- firmware/hackrf_usb/usb_api_register.h | 4 +-- 8 files changed, 25 insertions(+), 72 deletions(-) diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index f40eea29..ee418a77 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -60,8 +60,8 @@ static struct gpio_t gpio_led[] = { // clang-format off static struct gpio_t gpio_1v8_enable = GPIO(3, 6); -/* MAX2837 GPIO (XCVR_CTL) PinMux */ -static struct gpio_t gpio_max2837_select = GPIO(0, 15); +/* MAX283x GPIO (XCVR_CTL) PinMux */ +static struct gpio_t gpio_max283x_select = GPIO(0, 15); /* MAX5864 SPI chip select (AD_CS) GPIO PinMux */ static struct gpio_t gpio_max5864_select = GPIO(2, 7); @@ -172,7 +172,7 @@ si5351c_driver_t clock_gen = { .i2c_address = 0x60, }; -const ssp_config_t ssp_config_max2837 = { +const ssp_config_t ssp_config_max283x = { /* FIXME speed up once everything is working reliably */ /* // Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz @@ -183,21 +183,7 @@ const ssp_config_t ssp_config_max2837 = { .data_bits = SSP_DATA_16BITS, .serial_clock_rate = 21, .clock_prescale_rate = 2, - .gpio_select = &gpio_max2837_select, -}; - -const ssp_config_t ssp_config_max2839 = { - /* FIXME speed up once everything is working reliably */ - /* - // Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz - const uint8_t serial_clock_rate = 32; - const uint8_t clock_prescale_rate = 128; - */ - // Freq About 4.857MHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz - .data_bits = SSP_DATA_16BITS, - .serial_clock_rate = 21, - .clock_prescale_rate = 2, - .gpio_select = &gpio_max2837_select, + .gpio_select = &gpio_max283x_select, }; const ssp_config_t ssp_config_max5864 = { @@ -868,14 +854,9 @@ clock_source_t activate_best_clock_source(void) return source; } -void ssp1_set_mode_max2837(void) +void ssp1_set_mode_max283x(void) { - spi_bus_start(max2837.bus, &ssp_config_max2837); -} - -void ssp1_set_mode_max2839(void) -{ - spi_bus_start(max2839.bus, &ssp_config_max2839); + spi_bus_start(&spi_bus_ssp1, &ssp_config_max283x); } void ssp1_set_mode_max5864(void) @@ -974,11 +955,7 @@ void pin_setup(void) /* enable input on SCL and SDA pins */ SCU_SFSI2C0 = SCU_I2C0_NOMINAL; - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - spi_bus_start(&spi_bus_ssp1, &ssp_config_max2839); - } else { - spi_bus_start(&spi_bus_ssp1, &ssp_config_max2837); - } + spi_bus_start(&spi_bus_ssp1, &ssp_config_max283x); mixer_bus_setup(&mixer); diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 5aa08b24..d6211b37 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -35,8 +35,6 @@ extern "C" { #include "spi_ssp.h" #include "max283x.h" -#include "max2837.h" -#include "max2839.h" #include "max5864.h" #include "mixer.h" #include "w25q80bv.h" @@ -270,13 +268,10 @@ void delay_us_at_mhz(uint32_t us, uint32_t mhz); /* TODO: Hide these configurations */ extern si5351c_driver_t clock_gen; extern const ssp_config_t ssp_config_w25q80bv; -extern const ssp_config_t ssp_config_max2837; -extern const ssp_config_t ssp_config_max2839; +extern const ssp_config_t ssp_config_max283x; extern const ssp_config_t ssp_config_max5864; extern max283x_driver_t max283x; -extern max2837_driver_t max2837; -extern max2839_driver_t max2839; //FIXME xcvr hal extern max5864_driver_t max5864; extern mixer_driver_t mixer; extern w25q80bv_driver_t spi_flash; @@ -286,8 +281,7 @@ extern jtag_t jtag_cpld; extern i2c_bus_t i2c0; void cpu_clock_init(void); -void ssp1_set_mode_max2837(void); -void ssp1_set_mode_max2839(void); +void ssp1_set_mode_max283x(void); void ssp1_set_mode_max5864(void); void pin_setup(void); diff --git a/firmware/common/max283x.h b/firmware/common/max283x.h index eaf15a70..06ff6465 100644 --- a/firmware/common/max283x.h +++ b/firmware/common/max283x.h @@ -76,9 +76,6 @@ void max283x_reg_write(max283x_driver_t* const drv, uint8_t r, uint16_t v); * provided routines for those operations. */ void max283x_regs_commit(max283x_driver_t* const drv); -//max283x_mode_t max283x_mode(max283x_driver_t* const drv); -//void max283x_set_mode(max283x_driver_t* const drv, const max283x_mode_t new_mode); - max283x_mode_t max283x_mode(max283x_driver_t* const drv); void max283x_set_mode(max283x_driver_t* const drv, const max283x_mode_t new_mode); diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index 229cfac8..ba8ef69b 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -32,8 +32,6 @@ #include "platform_detect.h" #include "mixer.h" #include "max283x.h" -#include "max2837.h" -#include "max2839.h" #include "max5864.h" #include "sgpio.h" @@ -369,11 +367,10 @@ void rf_path_init(rf_path_t* const rf_path) max5864_setup(&max5864); max5864_shutdown(&max5864); + ssp1_set_mode_max283x(); if (detected_platform() == BOARD_ID_HACKRF1_R9) { - ssp1_set_mode_max2839(); max283x_setup(&max283x, MAX2839_VARIANT); } else { - ssp1_set_mode_max2837(); max283x_setup(&max283x, MAX2837_VARIANT); } max283x_start(&max283x); @@ -404,11 +401,7 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d } ssp1_set_mode_max5864(); max5864_tx(&max5864); - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - ssp1_set_mode_max2839(); - } else { - ssp1_set_mode_max2837(); - } + ssp1_set_mode_max283x(); max283x_tx(&max283x); sgpio_configure(&sgpio_config, SGPIO_DIRECTION_TX); break; @@ -427,11 +420,7 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d } ssp1_set_mode_max5864(); max5864_rx(&max5864); - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - ssp1_set_mode_max2839(); - } else { - ssp1_set_mode_max2837(); - } + ssp1_set_mode_max283x(); max283x_rx(&max283x); sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX); break; @@ -447,11 +436,7 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d mixer_disable(&mixer); ssp1_set_mode_max5864(); max5864_standby(&max5864); - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - ssp1_set_mode_max2839(); - } else { - ssp1_set_mode_max2837(); - } + ssp1_set_mode_max283x(); max283x_set_mode(&max283x, MAX283x_MODE_STANDBY); sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX); break; diff --git a/firmware/common/ui_rad1o.c b/firmware/common/ui_rad1o.c index 3fc10d3d..8312c12b 100644 --- a/firmware/common/ui_rad1o.c +++ b/firmware/common/ui_rad1o.c @@ -202,7 +202,7 @@ static void ui_update(void) rad1o_lcdDisplay(); // Don't ask... - ssp1_set_mode_max2837(); + ssp1_set_mode_max283x(); } static void rad1o_ui_init(void) @@ -217,7 +217,7 @@ static void rad1o_ui_deinit(void) rad1o_lcdDeInit(); enabled = false; // Don't ask... - ssp1_set_mode_max2837(); + ssp1_set_mode_max283x(); } static void rad1o_ui_set_frequency(uint64_t frequency) diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 893ecd53..bcf9ba87 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -66,8 +66,8 @@ extern uint32_t _etext_ram, _text_ram, _etext_rom; static usb_request_handler_fn vendor_request_handler[] = { NULL, usb_vendor_request_set_transceiver_mode, - usb_vendor_request_write_max2837, - usb_vendor_request_read_max2837, + usb_vendor_request_write_max283x, + usb_vendor_request_read_max283x, usb_vendor_request_write_si5351c, usb_vendor_request_read_si5351c, usb_vendor_request_set_sample_rate_frac, diff --git a/firmware/hackrf_usb/usb_api_register.c b/firmware/hackrf_usb/usb_api_register.c index 9741fd65..b3aa241b 100644 --- a/firmware/hackrf_usb/usb_api_register.c +++ b/firmware/hackrf_usb/usb_api_register.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include @@ -33,15 +33,15 @@ #include -usb_request_status_t usb_vendor_request_write_max2837( +usb_request_status_t usb_vendor_request_write_max283x( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { if (endpoint->setup.index < MAX2837_NUM_REGS) { if (endpoint->setup.value < MAX2837_DATA_REGS_MAX_VALUE) { - max2837_reg_write( - &max2837, + max283x_reg_write( + &max283x, endpoint->setup.index, endpoint->setup.value); usb_transfer_schedule_ack(endpoint->in); @@ -54,14 +54,14 @@ usb_request_status_t usb_vendor_request_write_max2837( } } -usb_request_status_t usb_vendor_request_read_max2837( +usb_request_status_t usb_vendor_request_read_max283x( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { if (stage == USB_TRANSFER_STAGE_SETUP) { if (endpoint->setup.index < MAX2837_NUM_REGS) { const uint16_t value = - max2837_reg_read(&max2837, endpoint->setup.index); + max283x_reg_read(&max283x, endpoint->setup.index); endpoint->buffer[0] = value & 0xff; endpoint->buffer[1] = value >> 8; usb_transfer_schedule_block( diff --git a/firmware/hackrf_usb/usb_api_register.h b/firmware/hackrf_usb/usb_api_register.h index f29ad050..7f26283a 100644 --- a/firmware/hackrf_usb/usb_api_register.h +++ b/firmware/hackrf_usb/usb_api_register.h @@ -27,10 +27,10 @@ #include #include -usb_request_status_t usb_vendor_request_write_max2837( +usb_request_status_t usb_vendor_request_write_max283x( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); -usb_request_status_t usb_vendor_request_read_max2837( +usb_request_status_t usb_vendor_request_read_max283x( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); usb_request_status_t usb_vendor_request_write_si5351c( From 3796bc94d88e5d22ffa9d74168fc3c47c7c03fb7 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sun, 8 Jan 2023 08:27:28 -0500 Subject: [PATCH 031/474] h1r9: check firmware running on r9 for r9 support Previously we checked for OG support instead of r9 support because we didn't yet have a way to tag firmware binaries with support for multiple platforms. --- firmware/common/platform_detect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/common/platform_detect.c b/firmware/common/platform_detect.c index e1608bd8..5430c5d8 100644 --- a/firmware/common/platform_detect.c +++ b/firmware/common/platform_detect.c @@ -165,7 +165,7 @@ void detect_hardware_platform(void) platform = BOARD_ID_HACKRF1_OG; break; case HACKRF1_R9_RESISTORS: - if (!(supported_platform() & PLATFORM_HACKRF1_OG)) { //FIXME temporary + if (!(supported_platform() & PLATFORM_HACKRF1_R9)) { halt_and_flash(3000000); } platform = BOARD_ID_HACKRF1_R9; From d9ebb089a59392f3a3cd1959538544c5032e23ea Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Tue, 31 Jan 2023 22:29:31 -0500 Subject: [PATCH 032/474] set version to 2023.01.1 --- firmware/hackrf-common.cmake | 2 +- host/cmake/set_release.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index 8418e47e..e4de6711 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -62,7 +62,7 @@ if (NOT DEFINED VERSION) OUTPUT_STRIP_TRAILING_WHITESPACE ) if (GIT_VERSION_FOUND) - set(VERSION "2022.09.1+") + set(VERSION "2023.01.1") else (GIT_VERSION_FOUND) set(VERSION "git-${GIT_VERSION}") endif (GIT_VERSION_FOUND) diff --git a/host/cmake/set_release.cmake b/host/cmake/set_release.cmake index 6414e485..fc30b592 100644 --- a/host/cmake/set_release.cmake +++ b/host/cmake/set_release.cmake @@ -8,7 +8,7 @@ if(NOT DEFINED RELEASE) OUTPUT_STRIP_TRAILING_WHITESPACE ) if (GIT_EXIT_VALUE) - set(RELEASE "2022.09.1+") + set(RELEASE "2023.01.1") else (GIT_EXIT_VALUE) execute_process( COMMAND git status -s --untracked-files=no From 00253b02e14d4f9db8be5242a4a29784e93fadf5 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Wed, 8 Feb 2023 14:03:06 -0500 Subject: [PATCH 033/474] set version to 2023.01.1+ --- firmware/hackrf-common.cmake | 2 +- host/cmake/set_release.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index e4de6711..83250c89 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -62,7 +62,7 @@ if (NOT DEFINED VERSION) OUTPUT_STRIP_TRAILING_WHITESPACE ) if (GIT_VERSION_FOUND) - set(VERSION "2023.01.1") + set(VERSION "2023.01.1+") else (GIT_VERSION_FOUND) set(VERSION "git-${GIT_VERSION}") endif (GIT_VERSION_FOUND) diff --git a/host/cmake/set_release.cmake b/host/cmake/set_release.cmake index fc30b592..4e2e9579 100644 --- a/host/cmake/set_release.cmake +++ b/host/cmake/set_release.cmake @@ -8,7 +8,7 @@ if(NOT DEFINED RELEASE) OUTPUT_STRIP_TRAILING_WHITESPACE ) if (GIT_EXIT_VALUE) - set(RELEASE "2023.01.1") + set(RELEASE "2023.01.1+") else (GIT_EXIT_VALUE) execute_process( COMMAND git status -s --untracked-files=no From fe86f005f64578f8ccc241bb79985490dbfd1791 Mon Sep 17 00:00:00 2001 From: grvvy Date: Wed, 8 Feb 2023 12:18:27 -0700 Subject: [PATCH 034/474] change the device long option to required in hackrf_debug --- host/hackrf-tools/src/hackrf_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/hackrf-tools/src/hackrf_debug.c b/host/hackrf-tools/src/hackrf_debug.c index 9d3c15cc..397fc50e 100644 --- a/host/hackrf-tools/src/hackrf_debug.c +++ b/host/hackrf-tools/src/hackrf_debug.c @@ -487,7 +487,7 @@ static struct option long_options[] = { {"register", required_argument, 0, 'n'}, {"write", required_argument, 0, 'w'}, {"read", no_argument, 0, 'r'}, - {"device", no_argument, 0, 'd'}, + {"device", required_argument, 0, 'd'}, {"help", no_argument, 0, 'h'}, {"max2837", no_argument, 0, 'm'}, {"si5351c", no_argument, 0, 's'}, From ebe1ca003a4a04ead06407a4bca6a4f7e6b6c1f3 Mon Sep 17 00:00:00 2001 From: Gianpaolo Macario Date: Tue, 28 Mar 2023 04:10:59 +0200 Subject: [PATCH 035/474] Readme.md: Fix typo (#1299) s/documenation/documentation/ --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 9a8bfea6..45c27954 100644 --- a/Readme.md +++ b/Readme.md @@ -15,7 +15,7 @@ Information on HackRF and purchasing HackRF: https://greatscottgadgets.com/hackr # Documentation -Documentation for HackRF can be viewed on [Read the Docs](https://hackrf.readthedocs.io/en/latest/). The raw documenation files for HackRF are in the [docs folder](https://github.com/mossmann/hackrf/tree/master/docs) in this repository and can be built locally by installing [Sphinx Docs](https://www.sphinx-doc.org/en/master/usage/installation.html) and running `make html`. Documentation changes can be submitted through pull request and suggestions can be made as GitHub issues. +Documentation for HackRF can be viewed on [Read the Docs](https://hackrf.readthedocs.io/en/latest/). The raw documentation files for HackRF are in the [docs folder](https://github.com/mossmann/hackrf/tree/master/docs) in this repository and can be built locally by installing [Sphinx Docs](https://www.sphinx-doc.org/en/master/usage/installation.html) and running `make html`. Documentation changes can be submitted through pull request and suggestions can be made as GitHub issues. To create a PDF of the HackRF documentation from the HackRF repository while on Ubuntu: * run `sudo apt install latexmk texlive-latex-extra` From 464a6019b7a2b1fa7b22afb1322c5e7818165e45 Mon Sep 17 00:00:00 2001 From: Straithe Date: Mon, 10 Apr 2023 16:06:37 -0400 Subject: [PATCH 036/474] reorganize and update existing HackRF documentation (#1295) * reorganize and update existing HackRF documentation * include changes suggested by martinling * Update software support page * fix typo * Update acrylic case link * docs: make adjustments based on feedback from epenelope --- docs/source/LPC43XX_SGPIO_Configuration.rst | 5 +- docs/source/enclosure_options.rst | 2 +- docs/source/faq.rst | 19 + docs/source/getting_help.rst | 12 +- .../getting_started_hackrf_gnuradio.rst | 69 --- docs/source/hackrf_minimum_requirements.rst | 9 + docs/source/hackrf_one.rst | 3 +- docs/source/hackrf_sweep.rst | 119 ---- docs/source/hackrf_tools.rst | 139 +++++ docs/source/hackrfs_buttons.rst | 14 +- docs/source/hardware_triggering.rst | 4 +- docs/source/index.rst | 51 +- docs/source/installing_hackrf_software.rst | 12 +- docs/source/jawbreaker.rst | 59 +- docs/source/leds.rst | 8 + docs/source/libhackrf_api.rst | 575 ------------------ docs/source/sampling_rate.rst | 14 + docs/source/setting_gain.rst | 5 + docs/source/software_support.rst | 129 ++-- docs/source/tips_tricks.rst | 40 -- docs/source/troubleshooting.rst | 69 --- docs/source/updating_firmware.rst | 50 +- docs/source/usb_cables.rst | 27 + docs/source/virtual_machines.rst | 5 + 24 files changed, 398 insertions(+), 1041 deletions(-) delete mode 100644 docs/source/getting_started_hackrf_gnuradio.rst create mode 100644 docs/source/hackrf_minimum_requirements.rst delete mode 100644 docs/source/hackrf_sweep.rst create mode 100644 docs/source/hackrf_tools.rst create mode 100644 docs/source/leds.rst delete mode 100644 docs/source/libhackrf_api.rst create mode 100644 docs/source/sampling_rate.rst create mode 100644 docs/source/setting_gain.rst delete mode 100644 docs/source/tips_tricks.rst delete mode 100644 docs/source/troubleshooting.rst create mode 100644 docs/source/usb_cables.rst create mode 100644 docs/source/virtual_machines.rst diff --git a/docs/source/LPC43XX_SGPIO_Configuration.rst b/docs/source/LPC43XX_SGPIO_Configuration.rst index a1102c9f..fe5a472d 100644 --- a/docs/source/LPC43XX_SGPIO_Configuration.rst +++ b/docs/source/LPC43XX_SGPIO_Configuration.rst @@ -13,11 +13,8 @@ In the current HackRF design, there is a CPLD which manages the interface betwee -Frequently Asked Questions -~~~~~~~~~~~~~~~~~~~~~~~~~~ - Why not use GPDMA to transfer samples through SGPIO? -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It would be great if we could, as that would free up lots of processor time. Unfortunately, the GPDMA scheme in the LPC43xx does not seem to support peripheral-to-memory and memory-to-peripheral transfers with the SGPIO peripheral. diff --git a/docs/source/enclosure_options.rst b/docs/source/enclosure_options.rst index 07b6a9fa..51d3c5ff 100644 --- a/docs/source/enclosure_options.rst +++ b/docs/source/enclosure_options.rst @@ -5,4 +5,4 @@ The commercial version of HackRF One from Great Scott Gadgets ships with an inje * Hammond 1455J1201: HackRF One fits this extruded aluminum enclosure and other similar models from Hammond Manufacturing. In order to use the enclosure's end plates, you will have to drill them. An end plate template can be found in the HackRF One KiCad layout. - * Acrylic sandwich: You can also use a laser cut acrylic enclosure with HackRF One. This is a good option for access to the expansion headers. A design can be found in the HackRF One hardware directory. Use any laser cutting service or purchase from a `reseller `__. \ No newline at end of file + * Acrylic sandwich: You can also use a laser cut acrylic enclosure with HackRF One. This is a good option for access to the expansion headers. A design can be found in the HackRF One hardware directory. Use any laser cutting service or purchase from a `reseller `__. \ No newline at end of file diff --git a/docs/source/faq.rst b/docs/source/faq.rst index 010cf89d..f393514e 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -106,9 +106,28 @@ There was a bug in the HackRF firmware (through release 2013.06.1) that made the A high DC offset is also one of a few symptoms that can be caused by a software version mismatch. A common problem is that people run an old version of gr-osmosdr with newer firmware. + ---- + +How do I deal with the big spike in the middle of my spectrum? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Start by reading :ref:`our FAQ Response on the DC Spike `. After that, there are a few options: + + #. Ignore it. For many applications it isn't a problem. You'll learn to ignore it. + + #. Avoid it. The best way to handle DC offset for most applications is to use offset tuning; instead of tuning to your exact frequency of interest, tune to a nearby frequency so that the entire signal you are interested in is shifted away from 0 Hz but still within the received bandwidth. If your algorithm works best with your signal centered at 0 Hz (many do), you can shift the frequency in the digital domain, moving your signal of interest to 0 Hz and your DC offset away from 0 Hz. HackRF's high maximum sampling rate can be a big help as it allows you to use offset tuning even for relatively wideband signals. + + #. Correct it. There are various ways of removing the DC offset in software. However, these techniques may degrade parts of the signal that are close to 0 Hz. It may look better, but that doesn't necessarily mean that it is better from the standpoint of a demodulator algorithm, for example. Still, correcting the DC offset is often a good choice. + + + +--- + + + What gain controls are provided by HackRF? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/source/getting_help.rst b/docs/source/getting_help.rst index fe7be870..83418c4e 100644 --- a/docs/source/getting_help.rst +++ b/docs/source/getting_help.rst @@ -1,9 +1,11 @@ -================================================ +============ Getting Help -================================================ +============ -Before asking for help with HackRF, check to see if your question is listed in the :ref:`FAQ ` or has already been answered in `GitHub issues `__ or the `mailing list archives `__. +Before asking for help with HackRF, check to see if your question is answered in this documentation, listed in the :ref:`FAQ `, or addressed in the `HackRF GitHub repository issues `__. -For assistance with HackRF use or development, please look at the `issues on the GitHub project `__. This is the preferred place to ask questions so that others may locate the answer to your question in the future. +For assistance with HackRF general use or development, please look at the `issues on the GitHub project `__. This is the preferred place to ask questions so that others may locate the answer to your question in the future. -Many users spend time in the `#hackrf channel on Discord `__. +We invite you to join our community discussions on `Discord `__. Note that while technical support requests are welcome here, we do not have support staff on duty at all times. Be sure to also submit an issue on GitHub if you’ve found a bug or if you want to ensure that your request will be tracked and not overlooked. + +If you wish to see past discussions and questions about HackRF, you may also view the `mailing list archives `__. diff --git a/docs/source/getting_started_hackrf_gnuradio.rst b/docs/source/getting_started_hackrf_gnuradio.rst deleted file mode 100644 index 7603409c..00000000 --- a/docs/source/getting_started_hackrf_gnuradio.rst +++ /dev/null @@ -1,69 +0,0 @@ -================================================ -Getting Started with HackRF and GNU Radio -================================================ - -We recommend getting started by watching the `Software Defined Radio with HackRF `__ video series. This series will introduce you to HackRF One, software including GNU Radio, and teach you the fundamentals of Digital Signal Processing (DSP) needed to take full advantage of the power of Software Defined Radio (SDR). Additional helpful information follows. - -.. _try_pentoo: - -Try Your HackRF with Pentoo Linux -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The easiest way to get started with your HackRF and ensure that it works is to use Pentoo, a Linux distribution with full support for HackRF and GNU Radio. Download the latest Pentoo .iso image from one of the mirrors listed at `http://pentoo.ch/downloads/ `__. Then burn the .iso to a DVD or use `UNetbootin `__ to install the .iso on a USB flash drive. Boot your computer using the DVD or USB flash drive to run Pentoo. Do this natively, not in a virtual machine. (Unfortunately high speed USB operation invariably fails when people try to run HackRF from a virtual machine.) - -Once Pentoo is running, you can immediately use it to :ref:`update firmware ` on your HackRF or use other HackRF command line tools. For a walkthrough, watch `SDR with HackRF, Lesson 5: HackRF One `__. - -To verify that your HackRF is detected, type ``hackrf_info`` at the command line. It should produce a few lines of output including "Found HackRF board." The 3V3, 1V8, RF, and USB LEDs should all be illuminated and are various colors. - -You can type ``startx`` at the command line to launch a desktop environment. Accept the "default config" in the first dialog box. The desktop environment is useful for GNU Radio Companion and other graphical applications but is not required for basic operations such as firmware updates. - -Now you can use programs such as gnuradio-companion or gqrx to start experimenting with your HackRF. Try the Examples below. If you are new to GNU Radio, an excellent place to start is with the `SDR with HackRF `__ video series or with the `GNU Radio guided tutorials `__. - -**Alternative: GNU Radio Live SDR Environment** - -The `GNU Radio Live SDR Environment `__ is another nice bootable Linux .iso with support for HackRF and, of course, GNU Radio. - -Software Setup -~~~~~~~~~~~~~~ - -As mentioned above, the best way to get started with HackRF is to use Pentoo Linux. Eventually you may want to install software to use HackRF with your favorite operating system. - -If your package manager includes the most recent release of libhackrf and gr-osmosdr, then use it to install those packages in addition to GNU Radio. Otherwise, the recommended way to install these tools is by using `PyBOMBS `__. - -See the :ref:`Operating System Tips ` page for information on setting up HackRF software on particular Operating Systems and Linux distributions. - -If you have any trouble, make sure that things work when booted to Pentoo. This will allow you to easily determine if your problem is being caused by hardware or software, and it will give you a way to see how the software is supposed to function. - -Examples -~~~~~~~~ - -A great way to get started with HackRF is the `SDR with HackRF `__ video series. Additional examples follow: - -Testing the HackRF - - #. Plug in the HackRF - #. run the hackrf_info command ``$ hackrf_info`` - -If everything is OK, you should see something similar to the following: - -.. code-block:: sh - - hackrf_info version: 2017.02.1 - libhackrf version: 2017.02.1 (0.5) - Found HackRF - Index: 0 - Serial number: 0000000000000000################ - Board ID Number: 2 (HackRF One) - Firmware Version: 2017.02.1 (API:1.02) - Part ID Number: 0x######## 0x######## - -**FM Radio Example** - -This Example was derived from the following works: - - * `RTL-SDR FM radio receiver with GNU Radio Companion `__ - * `How To Build an FM Receiver with the USRP in Less Than 10 Minutes `__ - - #. Download the FM Radio Receiver python file `here `__ - #. Run the file ``$ python ./fm_radio_rx.py`` - #. You can find the GNU Radio Companion source file `here `__ diff --git a/docs/source/hackrf_minimum_requirements.rst b/docs/source/hackrf_minimum_requirements.rst new file mode 100644 index 00000000..4be16afc --- /dev/null +++ b/docs/source/hackrf_minimum_requirements.rst @@ -0,0 +1,9 @@ +============================================ +Minimum Host System Requirements for HackRF +============================================ + +HackRF requires you to supply 500 mA at 5 V DC to your HackRF via the USB port. If your host computer has difficulty meeting this requirement, you may need to use a powered USB hub. + +There is no specific minimum CPU requirement for the host computer when using a HackRF, but SDR is generally a CPU-intensive application. If you have a slower CPU, you may be unable to run certain SDR software or you may only be able to operate at lower sample rates. + +Most users will want to stream data to or from the HackRF at high speeds. This requires that the host computer supports Hi-Speed USB. Some Hi-Speed USB hosts are better than others, and you may have multiple host controllers on your computer. If you have difficulty operating your HackRF at high sample rates (10 Msps to 20 Msps), try using a different USB port on your computer. If possible, arrange things so that the HackRF is the only device on the bus. \ No newline at end of file diff --git a/docs/source/hackrf_one.rst b/docs/source/hackrf_one.rst index 4fdc0e34..7abddf2d 100644 --- a/docs/source/hackrf_one.rst +++ b/docs/source/hackrf_one.rst @@ -25,4 +25,5 @@ Features * pin headers for expansion * portable * open source - + + diff --git a/docs/source/hackrf_sweep.rst b/docs/source/hackrf_sweep.rst deleted file mode 100644 index 6b85fdb8..00000000 --- a/docs/source/hackrf_sweep.rst +++ /dev/null @@ -1,119 +0,0 @@ -================================================ -hackrf_sweep -================================================ - -Usage -~~~~~ - -.. code-block:: sh - - [-h] # this help - [-d serial_number] # Serial number of desired HackRF - [-a amp_enable] # RX RF amplifier 1=Enable, 0=Disable - [-f freq_min:freq_max] # minimum and maximum frequencies in MHz - [-p antenna_enable] # Antenna port power, 1=Enable, 0=Disable - [-l gain_db] # RX LNA (IF) gain, 0-40dB, 8dB steps - [-g gain_db] # RX VGA (baseband) gain, 0-62dB, 2dB steps - [-w bin_width] # FFT bin width (frequency resolution) in Hz, 2445-5000000 - [-1] # one shot mode - [-N num_sweeps] # Number of sweeps to perform - [-B] # binary output - [-I] # binary inverse FFT output - -r filename # output file - - - -Output fields -~~~~~~~~~~~~~ - -``date, time, hz_low, hz_high, hz_bin_width, num_samples, dB, dB, ...`` - -Running ``hackrf_sweep -f 2400:2490`` gives the following example results: - -.. list-table :: - :header-rows: 1 - :widths: 1 1 1 1 1 1 1 1 1 1 1 - - * - Date - - Time - - Hz Low - - Hz High - - Hz bin width - - Num Samples - - dB - - dB - - dB - - dB - - dB - * - 2019-01-03 - - 11:57:34.967805 - - 2400000000 - - 2405000000 - - 1000000.00 - - 20 - - -64.72 - - -63.36 - - -60.91 - - -61.74 - - -58.58 - * - 2019-01-03 - - 11:57:34.967805 - - 2410000000 - - 2415000000 - - 1000000.00 - - 20 - - -69.22 - - -60.67 - - -59.50 - - -61.81 - - -58.16 - * - 2019-01-03 - - 11:57:34.967805 - - 2405000000 - - 2410000000 - - 1000000.00 - - 20 - - -61.19 - - -70.14 - - -60.10 - - -57.91 - - -61.97 - * - 2019-01-03 - - 11:57:34.967805 - - 2415000000 - - 2420000000 - - 1000000.00 - - 20 - - -72.93 - - -79.14 - - -68.79 - - -70.71 - - -82.78 - * - 2019-01-03 - - 11:57:34.967805 - - 2420000000 - - 2425000000 - - 1000000.00 - - 20 - - -67.57 - - -61.61 - - -57.29 - - -61.90 - - -70.19 - * - 2019-01-03 - - 11:57:34.967805 - - 2430000000 - - 2435000000 - - 1000000.00 - - 20 - - -56.04 - - -59.58 - - -66.24 - - -66.02 - - -62.12 - -Each sweep across the entire specified frequency range is given a single time stamp. - -The fifth column tells you the width in Hz (1 MHz in this case) of each frequency bin, which you can set with ``-w``. The sixth column is the number of samples analyzed to produce that row of data. - -Each of the remaining columns shows the power detected in each of several frequency bins. In this case there are five bins, the first from 2400 to 2401 MHz, the second from 2401 to 2402 MHz, and so forth. diff --git a/docs/source/hackrf_tools.rst b/docs/source/hackrf_tools.rst new file mode 100644 index 00000000..54f38392 --- /dev/null +++ b/docs/source/hackrf_tools.rst @@ -0,0 +1,139 @@ +============ +HackRF Tools +============ + +Great Scott Gadgets provides some commandline tools for interacting with HackRF. + * **hackrf_info** Read device information from HackRF such as serial number and firmware version. + + * **hackrf_transfer** Send and receive signals using HackRF. Input/output files are 8-bit signed quadrature samples. + + * **hackrf_sweep**, a command-line spectrum analyzer. + + * **hackrf_clock** Read and write clock input and output configuration. + + * **hackrf_operacake** Configure Opera Cake antenna switch connected to HackRF. + + * **hackrf_spiflash** A tool to write new firmware to HackRF. See: :ref:`Updating Firmware `. + + * **hackrf_debug** Read and write registers and other low-level configuration for debugging. + + + +hackrf_sweep +~~~~~~~~~~~~ + +Usage +^^^^^ + +.. code-block:: sh + + [-h] # this help + [-d serial_number] # Serial number of desired HackRF + [-a amp_enable] # RX RF amplifier 1=Enable, 0=Disable + [-f freq_min:freq_max] # minimum and maximum frequencies in MHz + [-p antenna_enable] # Antenna port power, 1=Enable, 0=Disable + [-l gain_db] # RX LNA (IF) gain, 0-40dB, 8dB steps + [-g gain_db] # RX VGA (baseband) gain, 0-62dB, 2dB steps + [-w bin_width] # FFT bin width (frequency resolution) in Hz, 2445-5000000 + [-1] # one shot mode + [-N num_sweeps] # Number of sweeps to perform + [-B] # binary output + [-I] # binary inverse FFT output + -r filename # output file + + + +Output fields +^^^^^^^^^^^^^ + +``date, time, hz_low, hz_high, hz_bin_width, num_samples, dB, dB, ...`` + +Running ``hackrf_sweep -f 2400:2490`` gives the following example results: + +.. list-table :: + :header-rows: 1 + :widths: 1 1 1 1 1 1 1 1 1 1 1 + + * - Date + - Time + - Hz Low + - Hz High + - Hz bin width + - Num Samples + - dB + - dB + - dB + - dB + - dB + * - 2019-01-03 + - 11:57:34.967805 + - 2400000000 + - 2405000000 + - 1000000.00 + - 20 + - -64.72 + - -63.36 + - -60.91 + - -61.74 + - -58.58 + * - 2019-01-03 + - 11:57:34.967805 + - 2410000000 + - 2415000000 + - 1000000.00 + - 20 + - -69.22 + - -60.67 + - -59.50 + - -61.81 + - -58.16 + * - 2019-01-03 + - 11:57:34.967805 + - 2405000000 + - 2410000000 + - 1000000.00 + - 20 + - -61.19 + - -70.14 + - -60.10 + - -57.91 + - -61.97 + * - 2019-01-03 + - 11:57:34.967805 + - 2415000000 + - 2420000000 + - 1000000.00 + - 20 + - -72.93 + - -79.14 + - -68.79 + - -70.71 + - -82.78 + * - 2019-01-03 + - 11:57:34.967805 + - 2420000000 + - 2425000000 + - 1000000.00 + - 20 + - -67.57 + - -61.61 + - -57.29 + - -61.90 + - -70.19 + * - 2019-01-03 + - 11:57:34.967805 + - 2430000000 + - 2435000000 + - 1000000.00 + - 20 + - -56.04 + - -59.58 + - -66.24 + - -66.02 + - -62.12 + +Each sweep across the entire specified frequency range is given a single time stamp. + +The fifth column tells you the width in Hz (1 MHz in this case) of each frequency bin, which you can set with ``-w``. The sixth column is the number of samples analyzed to produce that row of data. + +Each of the remaining columns shows the power detected in each of several frequency bins. In this case there are five bins, the first from 2400 to 2401 MHz, the second from 2401 to 2402 MHz, and so forth. diff --git a/docs/source/hackrfs_buttons.rst b/docs/source/hackrfs_buttons.rst index 05120372..d2a6a690 100644 --- a/docs/source/hackrfs_buttons.rst +++ b/docs/source/hackrfs_buttons.rst @@ -1,11 +1,11 @@ -==================== -HackRF One's Buttons -==================== +======= +Buttons +======= -The RESET button resets the microcontroller. This is a reboot that should result in a USB re-enumeration. +The **RESET button** resets the microcontroller. This is a reboot that should result in a USB re-enumeration. -The DFU button invokes a USB DFU bootloader located in the microcontroller's ROM. This bootloader makes it possible to unbrick a HackRF One with damaged firmware because the ROM cannot be overwritten. +The **DFU button** invokes a USB DFU bootloader located in the microcontroller's ROM. This bootloader makes it possible to unbrick a HackRF One with damaged firmware because the ROM cannot be overwritten. + +The DFU button only invokes the bootloader during reset. This means that it can be used for other functions by custom firmware. To invoke DFU mode: Press and hold the DFU button. While holding the DFU button, reset the HackRF One either by pressing and releasing the RESET button or by powering on the HackRF One. Release the DFU button. - -The DFU button only invokes the bootloader during reset. This means that it can be used for other functions by custom firmware. \ No newline at end of file diff --git a/docs/source/hardware_triggering.rst b/docs/source/hardware_triggering.rst index 3f8a6dfa..38d4ed17 100644 --- a/docs/source/hardware_triggering.rst +++ b/docs/source/hardware_triggering.rst @@ -27,9 +27,7 @@ To connect two HackRF Ones for triggering you will need: Open Your HackRF One ~~~~~~~~~~~~~~~~~~~~ -The HackRF One case has small plastic clips holding it together. These may be damaged when the case is opened, but typically the case can still be used after such damage. Please follow the instructions in `this video `__ by `Jared Boone `__. - -Open the enclosures of both HackRF Ones to access their pin headers. +If your HackRF Ones are not bare boards, you will need to open up their cases to access the pin headers on the HackRF Ones. Each HackRF One case has small plastic clips holding it together. These clips may be damaged when the case is opened, but typically the case can still be used after such damage. Please follow the instructions in `this video `__ by `Jared Boone `__ to open your HackRF One cases. Identify the Trigger Pins diff --git a/docs/source/index.rst b/docs/source/index.rst index 707647b1..4ab40fa6 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -6,23 +6,33 @@ Welcome to HackRF's documentation! :maxdepth: 2 :caption: User Documentation - hackrf_one - jawbreaker - faq - troubleshooting getting_help - tips_tricks + faq hackrf_projects_mentions .. toctree:: :maxdepth: 2 - :caption: Software + :caption: HackRF One Hardware + + hackrf_one + hackrf_minimum_requirements + list_of_hardware_revisions + hardware_components + leds + hackrfs_buttons + external_clock_interface + expansion_interface + hardware_triggering + enclosure_options + usb_cables + rf_shield_installation + +.. toctree:: + :maxdepth: 2 + :caption: Jawbreaker Hardware + + jawbreaker - installing_hackrf_software - getting_started_hackrf_gnuradio - software_support - libhackrf_api - hackrf_sweep .. toctree:: :maxdepth: 2 @@ -35,16 +45,14 @@ Welcome to HackRF's documentation! .. toctree:: :maxdepth: 2 - :caption: Hardware + :caption: Software - list_of_hardware_revisions - hardware_components - enclosure_options - hackrfs_buttons - external_clock_interface - expansion_interface - hardware_triggering - rf_shield_installation + installing_hackrf_software + hackrf_tools + software_support + sampling_rate + setting_gain + virtual_machines .. toctree:: :maxdepth: 2 @@ -56,4 +64,5 @@ Welcome to HackRF's documentation! opera_cake_board_addressing opera_cake_port_configuration opera_cake_modes_of_operation - \ No newline at end of file + + diff --git a/docs/source/installing_hackrf_software.rst b/docs/source/installing_hackrf_software.rst index db293dcc..dc4cc181 100644 --- a/docs/source/installing_hackrf_software.rst +++ b/docs/source/installing_hackrf_software.rst @@ -1,8 +1,12 @@ .. _operating_system_tips: -================================================ +========================== Installing HackRF Software -================================================ +========================== + +HackRF software includes HackRF Tools and libhackrf. HackRF Tools are the commandline utilities that let you interact with your HackRF. libhackrf is a low level library that enables software on your computer to operate with HackRF. + + Install Using Package Managers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -60,8 +64,12 @@ Windows: Binaries Binaries are provided as part of the PothosSDR project, they can be downloaded `here `__. + + ----------- + + Installing From Source ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/source/jawbreaker.rst b/docs/source/jawbreaker.rst index ef1f4b3f..9852a474 100644 --- a/docs/source/jawbreaker.rst +++ b/docs/source/jawbreaker.rst @@ -1,6 +1,6 @@ -================================================ +========== Jawbreaker -================================================ +========== HackRF Jawbreaker is the beta test hardware platform for the HackRF project. @@ -20,53 +20,48 @@ Features -Set your Jawbreaker Free! -~~~~~~~~~~~~~~~~~~~~~~~~~ +Hardware Documentation +~~~~~~~~~~~~~~~~~~~~~~ -Jawbreaker has an SMA antenna connector but also includes a built-in PCB antenna intended for operation near 900 MHz. It isn't a very good antenna. Seriously. A paperclip stuck into the SMA connector would probably be better. You can free your Jawbreaker to operate with better antennas by cutting the PCB trace to the PCB antenna with a knife. This enables the SMA connector to be used without interference from the PCB antenna. - -A video that demonstrates the antenna modification is on YouTube: `HackRF Antenna Modification `__ - -The trace to be cut is between the two solder pads inside a box labeled R44 in the `assembly diagram `__. There is an arrow pointing to it printed on the board. - -Due to a manufacturing error, there is solder on R44. R44 may appear as a single solder blob. If you have a soldering iron and solder wick/braid, use a soldering iron and fine solder wick to remove as much solder as you can from the two R44 pads. Then, use a pen knife to gently cut away the area between the two R44 pads. Make multiple, gentle cuts, instead of one or two forceful cuts. As you cut, you'll break through the black solder mask, then the copper trace between the pads, and stop when you reach fiberglass. Remove the copper trace completely, so just the two R44 pads remain. Use a multimeter or continuity tester to verify that the two R44 pads are no longer connected. - -If you don't have a soldering iron, you can cut through the copper trace and the solder blob all at once, but it requires a bit more effort. - -The only reason not to do this is if you want to try Jawbreaker but don't have any antenna with an SMA connector (or adapter). - -If you want to restore the PCB antenna for some reason, you can install a 10 nF capacitor or a 0 ohm resistor on the R44 pads or you may be able to simply create a solder bridge. - - - -SMA, not RP-SMA -~~~~~~~~~~~~~~~ - -Some connectors that appear to be SMA are actually RP-SMA. If you connect an RP-SMA antenna to Jawbreaker, it will seem to connect snugly but won't function at all because neither the male nor female side has a center pin. RP-SMA connectors are most common on 2.4 GHz antennas and are popular on Wi-Fi equipment. +Schematic diagram, assembly diagram, and bill of materials can be found at `https://github.com/greatscottgadgets/hackrf/tree/master/hardware `__ Transmit Power ~~~~~~~~~~~~~~ -The maximum TX power varies by operating frequency: +The maximum TX power for Jawbreaker varies by operating frequency: * 30 MHz to 100 MHz: 5 dBm to 15 dBm, increasing as frequency decreases * 100 MHz to 2300 MHz: 0 dBm to 10 dBm, increasing as frequency decreases - * 2300 MHz to 2700 MHz: 10 dBm to 15 dBm + * 2170 MHz to 2740 MHz: 10 dBm to 15 dBm * 2700 MHz to 4000 MHz: -5 dBm to 5 dBm, increasing as frequency decreases * 4000 MHz to 6000 MHz: -15 dBm to 0 dBm, increasing as frequency decreases Overall, the output power is enough to perform over-the-air experiments at close range or to drive an external amplifier. If you connect an external amplifier, you should also use an external bandpass filter for your operating frequency. -Before you transmit, know your laws. Jawbreaker has not been tested for compliance with regulations governing transmission of radio signals. You are responsible for using your Jawbreaker legally. +Before you transmit, know the laws for the region you are transmitting in. Jawbreaker has not been tested for compliance with regulations governing transmission of radio signals. You are responsible for using your Jawbreaker legally. -Hardware Documentation -~~~~~~~~~~~~~~~~~~~~~~ +SMA, not RP-SMA +~~~~~~~~~~~~~~~ -Schematic diagram, assembly diagram,and bill of materials can be found at `https://github.com/mossmann/hackrf/tree/master/doc/hardware `__ +The connectors on Jawbreaker are SMA, not RP-SMA. SMA connectors and RP-SMA connectors look extremely similar, the difference is that SMA connectors have a center pin. RP-SMA connectors are common on 2.4 GHz antennas and are popular on Wi-Fi equipment. If you connect an RP-SMA antenna to Jawbreaker, it will seem to connect snugly but won't function at all because neither the male nor female side has a center pin. + + + +Recommended PCB and Antenna Changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Jawbreaker has an SMA antenna connector and it also includes a built-in PCB antenna intended for operation near 900 MHz. The built-in PCB antenna isn't a very good antenna. A paperclip stuck into the SMA connector of the Jawbreaker is likely to be better. We recommend that you free your Jawbreaker to operate with better antennas by cutting the PCB trace to the PCB antenna with a knife. This enables the SMA connector to be used without interference from the PCB antenna. + + +The trace to be cut is between the two solder pads inside a box labeled R44. There is an arrow printed on the board that points to the R44 box. A video that demonstrates the antenna modification is on YouTube: `HackRF Antenna Modification `__. + +Due to a manufacturing error, there is solder on the pads in box R44 that you should try to remove before you cut the trace. R44 may appear as a single solder blob. If you have a soldering iron and solder wick/braid, use a soldering iron and fine solder wick to remove as much solder as you can from the two R44 pads. Then, use a pen knife to gently cut away the area between the two R44 pads. Make multiple, gentle cuts, instead of one or two forceful cuts. As you cut, you'll break through the black solder mask, then the copper trace between the pads, and stop when you reach fiberglass. Remove the copper trace completely, so just the two R44 pads remain. Use a multimeter or continuity tester to verify that the two R44 pads are no longer connected. If you don't have a soldering iron, you can cut through the copper trace and the solder blob all at once, but it requires a bit more effort. The only reason not to cut the PCB trace is if you want to try Jawbreaker but don't have any antenna with an SMA connector (or adapter). + +If you want to restore the PCB antenna for some reason, you can install a 10 nF capacitor or a 0 ohm resistor on the R44 pads or you may be able to simply create a solder bridge. @@ -536,14 +531,14 @@ Cut P17 short (trace) to enable external clock input. If short is cut, a jumper More ^^^^ -Additional headers are available. See the `board files `__ for additional details. +Additional headers are available. See the `board files `__ for additional details. Differences between Jawbreaker and HackRF One ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Jawbreaker was the beta platform that preceded HackRF One. HackRF One incorporates the following changes and enhancements: +Jawbreaker was the beta platform that preceded HackRF One. HackRF One incorporates the following changes and enhancements (at minimum): * Antenna port: No modification is necessary to use the SMA antenna port on HackRF One. * PCB antenna: Removed. diff --git a/docs/source/leds.rst b/docs/source/leds.rst new file mode 100644 index 00000000..519e0abd --- /dev/null +++ b/docs/source/leds.rst @@ -0,0 +1,8 @@ +==== +LEDs +==== + + +When HackRF One is plugged in to a USB host, four LEDs should turn on: 3V3, 1V8, RF, and USB. The 3V3 LED indicates that the primary internal power supply is working properly. The 1V8 and RF LEDs indicate that firmware is running and has switched on additional internal power supplies. The USB LED indicates that the HackRF One is communicating with the host over USB. + +The RX and TX LEDs indicate that a receive or transmit operation is currently in progress. diff --git a/docs/source/libhackrf_api.rst b/docs/source/libhackrf_api.rst deleted file mode 100644 index 9e25fa12..00000000 --- a/docs/source/libhackrf_api.rst +++ /dev/null @@ -1,575 +0,0 @@ -================================================ -libhackRF API -================================================ - - - -This document describes the functions, data structures and constants that libHackRF provides. It should be used as a reference for using libHackRF and the HackRF hardware. - -If you are writing a generic SDR application, i.e. not tied to the HackRF hardware, we strongly recommend that you use either gr-osmosdr or SoapySDR to provide support for the broadest possible range of software defined radio hardware. - -For example usage of many of these functions, see the `hackrf_transfer `__ tool. - - - -Setup, Initialization and Shutdown -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -HackRF Init -^^^^^^^^^^^ - -Initialize libHackRF, including global libUSB context to support multiple HackRF hardware devices. - -**Syntax:** ``int hackrf_init()`` - -**Returns:** A value from the hackrf_error constants listed below. - - - -HackRF Open -^^^^^^^^^^^ - -**Syntax:** ``int hackrf_open(hackrf_device** device)`` - -**Returns:** A value from the hackrf_error constants listed below. - - - -HackRF Device List -^^^^^^^^^^^^^^^^^^ - -Retrieve a list of HackRF devices attached to the system. This function finds all devices, regardless of permissions or availability of the hardware. - -**Syntax:** ``hackrf_device_list_t* hackrf_device_list()`` - -**Returns:** A pointer to a hackrf_device_list_t struct, a list of HackRF devices attached to the system. The contents of the hackrf_device_list_t struct are decribed in the data structures section below. - - - - -HackRF Device List Open -^^^^^^^^^^^^^^^^^^^^^^^ - -Open and acquire a handle on a device from the hackrf_device_list_t struct. - -**Syntax:** ``int hackrf_device_list_open(hackrf_device_list_t* list, int idx, hackrf_device** device)`` - -**Params:** - -``list`` - A pointer to a hackrf_device_list_t returned by ``hackrf_device_list()`` - -``idx`` - The list index of the HackRF device to open - -``device`` - Output location for hackrf_device pointer. Only valid when return value is HACKRF_SUCCESS. - -**Returns:** A value from the hackrf_error constants listed below. - - - -HackRF Device List Free -^^^^^^^^^^^^^^^^^^^^^^^ - -**Syntax:** ``void hackrf_device_list_free(hackrf_device_list_t* list)`` - -**Params:** - -``list`` - A pointer to a hackrf_device_list_t returned by ``hackrf_device_list()`` - - - - -HackRF Open By Serial -^^^^^^^^^^^^^^^^^^^^^ - -**Syntax:** ``int hackrf_open_by_serial(const char* const desired_serial_number, hackrf_device** device)`` - -**Returns:** - - - -HackRF Close -^^^^^^^^^^^^ - -**Syntax:** ``int hackrf_close(hackrf_device* device)`` - -**Returns:** A value from the hackrf_error constants listed below. - - - -HackRF Exit -^^^^^^^^^^^ - -Cleanly shutdown libHackRF and the underlying USB context. This does not stop in progress transfers or close the HackRF hardware. ``hackrf_close()`` should be called before this to cleanly close the connection to the hardware. - -**Syntax:** ``int hackrf_exit()`` - -**Returns:** A value from the hackrf_error constants listed below. - - - -Using the Radio -~~~~~~~~~~~~~~~ - -HackRF Start Rx -^^^^^^^^^^^^^^^ - -**Syntax:** ``int hackrf_start_rx(hackrf_device*, hackrf_sample_block_cb_fn, void* rx_ctx)`` - -**Params:** - -**Returns:** A value from the hackrf_error constants listed below. - - - - -HackRF Stop Rx -^^^^^^^^^^^^^^ - -**Syntax:** ``int hackrf_stop_rx(hackrf_device*)`` - -**Params:** - -**Returns:** A value from the hackrf_error constants listed below. - - - - -HackRF Start Tx -^^^^^^^^^^^^^^^ - -**Syntax:** ``int hackrf_start_tx(hackrf_device*, hackrf_sample_block_cb_fn, void* tx_ctx)`` - -**Params:** - -**Returns:** A value from the hackrf_error constants listed below. - - - -HackRF Stop Tx -^^^^^^^^^^^^^^ - -**Syntax:** ``int hackrf_stop_tx(hackrf_device*)`` - -**Params:** - -**Returns:** A value from the hackrf_error constants listed below. - - - -HackRF Set Baseband Filter Bandwidth -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -**Syntax:** ``int hackrf_set_baseband_filter_bandwidth(hackrf_device*, const uint32_t bandwidth_hz)`` - -**Params:** - -**Returns:** A value from the hackrf_error constants listed below. - - - -HackRF Compute Baseband Filter BW -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Compute best default value depending on sample rate (auto filter). - -**Syntax:** ``uint32_t hackrf_compute_baseband_filter_bw(const uint32_t bandwidth_hz)`` - -**Params:** - -**Returns:** A valid baseband filter width available from the Maxim MAX2837 frontend used by the radio. - - - - -HackRF Compute Baseband Filter BW Round Down LT -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Compute nearest freq for bw filter (manual filter) - -**Syntax:** ``uint32_t hackrf_compute_baseband_filter_bw_round_down_lt(const uint32_t bandwidth_hz)`` - -**Params:** - -**Returns:** A valid baseband filter width available from the Maxim MAX2837 frontend used by the radio. - - - -Reading and Writing Registers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -These low level functions are intended for debugging purposes only. - - -HackRF MAX2837 Read -^^^^^^^^^^^^^^^^^^^ - -Read register values from the MAX2837 Baseband IC. - -**Syntax:** ``int hackrf_max2837_read(hackrf_device* device, uint8_t register_number, uint16_t* value)`` - -**Params:** - -**Returns:** - - - -HackRF MAX2837 Write -^^^^^^^^^^^^^^^^^^^^ - -Write register values to the MAX2837 Baseband IC. - -**Syntax:** ``int hackrf_max2837_write(hackrf_device* device, uint8_t register_number, uint16_t value)`` - -**Params:** - -**Returns:** - - - -HackRF Si5351C Read -^^^^^^^^^^^^^^^^^^^ - -Read register values from the Si5351C clock generator IC. - -**Syntax:** ``int hackrf_si5351c_read(hackrf_device* device, uint16_t register_number, uint16_t* value)`` - -**Params:** - -**Returns:** - - - -HackRF Si5351C Write -^^^^^^^^^^^^^^^^^^^^ - -Write register values to the Si5351C clock generator IC. - -**Syntax:** ``int hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16_t value)`` - -**Params:** - -**Returns:** - - - -HackRF RFFC5071 Read -^^^^^^^^^^^^^^^^^^^^ - -Read register values from the RFFC5071 mixer IC. - -**Syntax:** ``int hackrf_rffc5071_read(hackrf_device* device, uint8_t register_number, uint16_t* value)`` - -**Params:** - -**Returns:** - - - -HackRF RFFC5071 Write -^^^^^^^^^^^^^^^^^^^^^ - -Write register values to the RFFC5071 mixer IC. - -**Syntax:** ``int hackrf_rffc5071_write(hackrf_device* device, uint8_t register_number, uint16_t value)`` - -**Params:** - -**Returns:** - - - -Updating Firmware -~~~~~~~~~~~~~~~~~ - -HackRF CPLD Write -^^^^^^^^^^^^^^^^^ - -A bitstream is written to the CPLD by the firmware during normal operation (since release 2021.03.1). This function writes a bitstream to the CPLD's flash which is not necessary for normal use. The device will need to be reset by physically pressing the reset button after hackrf_cpld_write. - -**Syntax:** ``int hackrf_cpld_write(hackrf_device* device, unsigned char* const data, const unsigned int total_length)`` - -**Params:** - -**Returns:** - - - - -HackRF SPI Flash Erase -^^^^^^^^^^^^^^^^^^^^^^ - -**Syntax:** ``int hackrf_spiflash_erase(hackrf_device* device)`` - -**Params:** - -**Returns:** - - - -HackRF SPI Flash Write -^^^^^^^^^^^^^^^^^^^^^^ - -**Syntax:** ``int hackrf_spiflash_write(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* const data)`` - -**Params:** - -**Returns:** - - - -HackRF SPI Flash Read -^^^^^^^^^^^^^^^^^^^^^ - -**Syntax:** ``int hackrf_spiflash_read(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* data)`` - -**Params:** - -**Returns:** - - - -Board Identifiers -~~~~~~~~~~~~~~~~~ - -HackRF Board ID Read -^^^^^^^^^^^^^^^^^^^^ - -**Syntax:** ``int hackrf_board_id_read(hackrf_device* device, uint8_t* value)`` - -**Params:** - -**Returns:** - - - -HackRF Version String Read -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -**Syntax:** ``int hackrf_version_string_read(hackrf_device* device, char* version, uint8_t length)`` - -**Params:** - -**Returns:** - - - -HackRF Board Part ID Serial Number Read -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -**Syntax:** ``int hackrf_board_partid_serialno_read(hackrf_device* device, read_partid_serialno_t* read_partid_serialno)`` - -**Params:** - -**Returns:** - - - -Miscellaneous -~~~~~~~~~~~~~ - -HackRF Error Name -^^^^^^^^^^^^^^^^^ - -**Syntax:** ``const char* hackrf_error_name(enum hackrf_error errcode)`` - -**Params:** - -**Returns:** - - - -HackRF Board ID Name -^^^^^^^^^^^^^^^^^^^^ - -**Syntax:** ``const char* hackrf_board_id_name(enum hackrf_board_id board_id)`` - -**Params:** - -**Returns:** - - - -HackRF USB Board ID Name -^^^^^^^^^^^^^^^^^^^^^^^^ - -**Syntax:** ``const char* hackrf_usb_board_id_name(enum hackrf_usb_board_id usb_board_id)`` - -**Params:** - -**Returns:** - - - -HackRF Filter Path Name -^^^^^^^^^^^^^^^^^^^^^^^ - -**Syntax:** ``const char* hackrf_filter_path_name(const enum rf_path_filter path)`` - -**Params:** - -**Returns:** - - - -Data Structures -~~~~~~~~~~~~~~~ - -``typedef struct hackrf_device hackrf_device`` - -.. code-block :: sh - - typedef struct { - hackrf_device* device; - uint8_t* buffer; - int buffer_length; - int valid_length; - void* rx_ctx; - void* tx_ctx; - } hackrf_transfer; - -.. code-block :: sh - - typedef struct { - uint32_t part_id[2]; - uint32_t serial_no[4]; - } read_partid_serialno_t; - -.. code-block :: sh - - typedef struct { - char **serial_numbers; - enum hackrf_usb_board_id *usb_board_ids; - int *usb_device_index; - int devicecount; - - void **usb_devices; - int usb_devicecount; - } hackrf_device_list_t; - -``typedef int (*hackrf_sample_block_cb_fn)(hackrf_transfer* transfer)`` - - - -Enumerations -~~~~~~~~~~~~ - -Supported board versions -^^^^^^^^^^^^^^^^^^^^^^^^ - -These values identify the board type of the connected hardware. This value can be used as an indicator of capabilities, such as frequency range, bandwidth or antenna port power. - -.. list-table :: - :header-rows: 1 - :widths: 1 1 1 1 - - * - Board - - Frequency range - - Sample Rate - - Antenna port power - * - HackRF One - - 1 MHz–6 GHz - - 20 Msps - - Yes - * - Jawbreaker - - 10 MHz–6 GHz - - 20 Msps - - No - * - rad1o - - 50 MHz–4 GHz - - 20 Msps - - No - * - Jellybean - - N/A - - 20 Msps - - No - -Most boards will identify as HackRF One, Jawbreaker, or rad1o. Jellybean was a pre-production revision of HackRF that is no longer supported. No hardware device should intentionally report itself with an unrecognized or undetected board ID. - -.. code-block :: sh - - enum hackrf_board_id { - BOARD_ID_JELLYBEAN = 0, - BOARD_ID_JAWBREAKER = 1, - BOARD_ID_HACKRF1_OG = 2, - BOARD_ID_RAD1O = 3, - BOARD_ID_HACKRF1_R9 = 4, - BOARD_ID_UNRECOGNIZED = 0xFE, - BOARD_ID_UNDETECTED = 0xFF, - }; - - - -USB Product IDs -^^^^^^^^^^^^^^^ - -.. code-block :: sh - - enum hackrf_usb_board_id { - USB_BOARD_ID_JAWBREAKER = 0x604B, - USB_BOARD_ID_HACKRF_ONE = 0x6089, - USB_BOARD_ID_RAD1O = 0xCC15, - USB_BOARD_ID_INVALID = 0xFFFF, - }; - - - -Transceiver Mode -^^^^^^^^^^^^^^^^ - -HackRF can operate in four main transceiver modes: Receive, Transmit, Signal Source, and Sweep. There is also a CPLD update mode which is used to write firmware images to the CPLD flash. - -The transceiver mode can be changed with ``hackrf_set_transceiver_mode`` with the value parameter set to one of the following: - -.. code-block:: sh - - enum transceiver_mode_t { - HACKRF_TRANSCEIVER_MODE_OFF = 0, - HACKRF_TRANSCEIVER_MODE_RECEIVE = 1, - HACKRF_TRANSCEIVER_MODE_TRANSMIT = 2, - HACKRF_TRANSCEIVER_MODE_SS = 3, - TRANSCEIVER_MODE_CPLD_UPDATE = 4, - TRANSCEIVER_MODE_RX_SWEEP = 5, - }; - -Receive mode (TRANSCEIVER_MODE_RX) is used to stream samples from the radio to the host system. Use ``hackrf_set_freq`` to set the center frequency of receiver and ``hackrf_set_sample_rate`` to set the sample rate (effective bandwidth). - -Transmit mode (TRANSCEIVER_MODE_TX) is used to stream samples from the host to the radio. - -See `hackrf_transfer `__ for an example of setting transmit and receive mode and transferring data over USB. - - - -Function return values -^^^^^^^^^^^^^^^^^^^^^^ - -.. code-block::sh - - enum hackrf_error { - HACKRF_SUCCESS = 0, - HACKRF_TRUE = 1, - HACKRF_ERROR_INVALID_PARAM = -2, - HACKRF_ERROR_NOT_FOUND = -5, - HACKRF_ERROR_BUSY = -6, - HACKRF_ERROR_NO_MEM = -11, - HACKRF_ERROR_LIBUSB = -1000, - HACKRF_ERROR_THREAD = -1001, - HACKRF_ERROR_STREAMING_THREAD_ERR = -1002, - HACKRF_ERROR_STREAMING_STOPPED = -1003, - HACKRF_ERROR_STREAMING_EXIT_CALLED = -1004, - HACKRF_ERROR_USB_API_VERSION = -1005, - HACKRF_ERROR_NOT_LAST_DEVICE = -2000, - HACKRF_ERROR_OTHER = -9999, - }; - - - -RF Filter Path -^^^^^^^^^^^^^^ - -.. code-block:: sh - - enum rf_path_filter { - RF_PATH_FILTER_BYPASS = 0, - RF_PATH_FILTER_LOW_PASS = 1, - RF_PATH_FILTER_HIGH_PASS = 2, - }; diff --git a/docs/source/sampling_rate.rst b/docs/source/sampling_rate.rst new file mode 100644 index 00000000..eab21496 --- /dev/null +++ b/docs/source/sampling_rate.rst @@ -0,0 +1,14 @@ +Sampling Rate and Baseband Filters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Using a sampling rate of less than 8MHz is not recommended. Partly, this is because the MAX5864 (ADC/DAC chip) isn't specified to operate at less than 8MHz, and therefore, no promises are made by Maxim about how it performs. But more importantly, the baseband filter in the MAX2837 has a minimum bandwidth of 1.75MHz. It can't provide enough filtering at 2MHz sampling rate to remove substantial signal energy in adjacent spectrum (more than +/-1MHz from the tuned frequency). The MAX2837 datasheet suggests that at +/-1MHz, the filter provides only 4dB attenuation, and at +/-2MHz (where a signal would alias right into the center of your 2MHz spectrum), it attenuates about 33dB. That's significant. Here's a picture: + +.. image:: ../images/max2837-1m75bw-at-2m.png + :align: center + +At 8MHz sampling rate, and using the minimum 1.75MHz bandwidth filter, this is the response: + +.. image:: ../images/max2837-1m75bw-at-8m.png + :align: center + +You can see that the attenuation is more than 60dB at +/-2.8MHz, which is more than sufficient to remove significant adjacent spectrum interference before the ADC digitizes the baseband. If using this configuration to get a 2MHz sampling rate, use a GNU Radio block after the 8MHz source that performs a 4:1 decimation with a decently sharp low pass filter (complex filter with a cut-off of <1MHz). \ No newline at end of file diff --git a/docs/source/setting_gain.rst b/docs/source/setting_gain.rst new file mode 100644 index 00000000..eae8bfd3 --- /dev/null +++ b/docs/source/setting_gain.rst @@ -0,0 +1,5 @@ +============================ +Setting Gain Controls for RX +============================ + +A good default setting to start with is RF=0 (off), IF=16, baseband=16. Increase or decrease the IF and baseband gain controls roughly equally to find the best settings for your situation. Turn on the RF amp if you need help picking up weak signals. If your gain settings are too low, your signal may be buried in the noise. If one or more of your gain settings is too high, you may see distortion (look for unexpected frequencies that pop up when you increase the gain) or the noise floor may be amplified more than your signal is. diff --git a/docs/source/software_support.rst b/docs/source/software_support.rst index c21ba9bc..e8487652 100644 --- a/docs/source/software_support.rst +++ b/docs/source/software_support.rst @@ -1,82 +1,77 @@ -================================================ -HackRF Compatible Software -================================================ +=========================================== +Third-Party Software Compatible With HackRF +=========================================== -Software with HackRF Support -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Software That Has Direct Support For HackRF +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -This is intended to be a list of software known to work with the HackRF. There are three sections, GNU Radio Based software, those that have direct support, and those that can work with data from the HackRF. +* GQRX + + * `http://gqrx.dk/ `__ + +* GNU Radio + + * https://www.gnuradio.org/ + +* GNU Radio Mode-S/ADS-B + + * `https://github.com/bistromath/gr-air-modes `__ + +* QSpectrumAnalyzer + + * `https://github.com/xmikos/qspectrumanalyzer `__ + +* SDR# + + * `https://airspy.com/download/ `__ + * Windows OS only + * Only nightly builds currently support HackRF One + +* SDR Console + + * https://www.sdr-radio.com/Console + +* Spectrum Analyzer GUI for hackrf_sweep for Windows + + * `https://github.com/pavsa/hackrf-spectrum-analyzer `__ + +* Universal Radio Hacker (Windows/Linux) + + * `https://github.com/jopohl/urh `__ + +* Web-based APRS tracker + + * `https://xakcop.com/aprs-sdr `__ -GNU Radio Based -~~~~~~~~~~~~~~~ +Software That Can Use Data From HackRF +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* Baudline -GNU Radio Mode-S/ADS-B - `https://github.com/bistromath/gr-air-modes `__ + * `http://www.baudline.com/ `__ + * Can view/process HackRF data, e.g. hackrf_transfer -GQRX - `http://gqrx.dk/ `__ - - - -Direct Support -~~~~~~~~~~~~~~ - -SDR# (Windows only) - `https://airspy.com/download/ `__ - - * Only nightly builds currently support HackRF One - `http://sdrsharp.com/downloads/sdr-nightly.zip `__ - -SDR_Radio.com V2 - `http://v2.sdr-radio.com/Radios/HackRF.aspx `__ - -Universal Radio Hacker (Windows/Linux) - `https://github.com/jopohl/urh `__ - -QSpectrumAnalyzer - `https://github.com/xmikos/qspectrumanalyzer `__ - -Spectrum Analyzer GUI for hackrf_sweep for Windows - `https://github.com/pavsa/hackrf-spectrum-analyzer `__ - -Web-based APRS tracker `https://xakcop.com/aprs-sdr `__ - - -Can use HackRF data -~~~~~~~~~~~~~~~~~~~ - -Inspectrum `https://github.com/miek/inspectrum `__ +* Inspectrum + * `https://github.com/miek/inspectrum `__ * Capture analysis tool with advanced features -Baudline `http://www.baudline.com/ `__ (Can view/process HackRF data, e.g. hackrf_transfer) +* Matlab + + .. code-block :: sh + + fid = open('samples.bin', 'r'); + len = 1000; % 1000 samples + y = fread(fid, 2*len, 'int8'); + y = y(1:2:end) + 1j*y(2:2:end); + fclose(fid) -HackRF Tools -~~~~~~~~~~~~ +Troubleshooting Recommendations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In addition to third party tools that support HackRF, we provide some commandline tools for interacting with HackRF. For information on how to use each tool look at the help information provided (e.g. ``hackrf_transfer -h``) or the `manual pages `__. +Many of these tools require libhackrf and at times HackRF Tools. It may help you to have updated libhackrf and HackRF Tools when troubleshooting these applications. - * **hackrf_info** Read device information from HackRF such as serial number and firmware version. - - * **hackrf_transfer** Send and receive signals using HackRF. Input/output files are 8-bit signed quadrature samples. - - * **hackrf_sweep**, a command-line spectrum analyzer. - - * **hackrf_clock** Read and write clock input and output configuration. - - * **hackrf_operacake** Configure Opera Cake antenna switch connected to HackRF. - - * **hackrf_spiflash** A tool to write new firmware to HackRF. See: :ref:`Updating Firmware `. - - * **hackrf_debug** Read and write registers and other low-level configuration for debugging. - - -Handling HackRF data -~~~~~~~~~~~~~~~~~~~~ - -Matlab -^^^^^^ - -.. code-block :: sh - - fid = open('samples.bin', 'r'); - len = 1000; % 1000 samples - y = fread(fid, 2*len, 'int8'); - y = y(1:2:end) + 1j*y(2:2:end); - fclose(fid) +It is also strongly suggested, and usually required, that your HackRF Tools and HackRF firmware match. \ No newline at end of file diff --git a/docs/source/tips_tricks.rst b/docs/source/tips_tricks.rst deleted file mode 100644 index ef55b473..00000000 --- a/docs/source/tips_tricks.rst +++ /dev/null @@ -1,40 +0,0 @@ -================================================ -Tips and Tricks -================================================ - -USB Cables (and why to use a noise reducing one) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The USB cable you choose can make a big difference in what you see when using your HackRF and especially when using it around between 120 and 480 MHz where USB is doing all its work. - - #. Use a shielded USB cable. The best way to guarantee RF interference from USB is to use an unshielded cable. You can test that your cable is shielded by using a continuity tester to verify that the shield on one connector has continuity to the shield on the connector at the other end of the cable. - - #. Use a short USB cable. Trying anything larger than a 6ft cable may yield poor results. The longer the cable, the more loss you can expect and when making this post a 15ft cable was tried and the result was the HackRF would only power up half way. - - #. For best results, select a cable with a ferrite core. These cables are usually advertised to be noise reducing and are recognizable from the plastic block towards one end. - -Screenshot before and after changing to a noise reducing cable (`view full size image `__): - -.. image:: ../images/noisereducingcablescreenshot.jpeg - :align: center - -A shielded cable with ferrite core was used in the right-hand image. - -The before and after images were both taken with the preamp on and the LNA and VGA both set to 24db. - - - -Sampling Rate and Baseband Filters -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Using a sampling rate of less than 8MHz is not recommended. Partly, this is because the MAX5864 (ADC/DAC chip) isn't specified to operate at less than 8MHz, and therefore, no promises are made by Maxim about how it performs. But more importantly, the baseband filter in the MAX2837 has a minimum bandwidth of 1.75MHz. It can't provide enough filtering at 2MHz sampling rate to remove substantial signal energy in adjacent spectrum (more than +/-1MHz from the tuned frequency). The MAX2837 datasheet suggests that at +/-1MHz, the filter provides only 4dB attenuation, and at +/-2MHz (where a signal would alias right into the center of your 2MHz spectrum), it attenuates about 33dB. That's significant. Here's a picture: - -.. image:: ../images/max2837-1m75bw-at-2m.png - :align: center - -At 8MHz sampling rate, and using the minimum 1.75MHz bandwidth filter, this is the response: - -.. image:: ../images/max2837-1m75bw-at-8m.png - :align: center - -You can see that the attenuation is more than 60dB at +/-2.8MHz, which is more than sufficient to remove significant adjacent spectrum interference before the ADC digitizes the baseband. If using this configuration to get a 2MHz sampling rate, use a GNU Radio block after the 8MHz source that performs a 4:1 decimation with a decently sharp low pass filter (complex filter with a cut-off of <1MHz). \ No newline at end of file diff --git a/docs/source/troubleshooting.rst b/docs/source/troubleshooting.rst deleted file mode 100644 index 0a88d98d..00000000 --- a/docs/source/troubleshooting.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. _troubleshooting: - -=============== -Troubleshooting -=============== - -Why isn't my HackRF One detectable after I plug it into my computer? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If your HackRF One isn't immediately detectable it is very possible that your Micro USB cable is not meeting HackRF One's requirements. HackRF One requires quite a bit of supply current and solid USB 2.0 high speed communications to operate. It is common for HackRF One to reveal cables with deficiencies such as carrying power but not data, carrying data but not enough power, etc. Please try multiple cables to resolve this issue. More than once people have gotten their HackRF One to work after trying their fifth cable. - - ----- - - -How do I deal with the big spike in the middle of my spectrum? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Start by reading :ref:`our FAQ Response on the DC Spike `. After that, there are a few options: - - #. Ignore it. For many applications it isn't a problem. You'll learn to ignore it. - - #. Avoid it. The best way to handle DC offset for most applications is to use offset tuning; instead of tuning to your exact frequency of interest, tune to a nearby frequency so that the entire signal you are interested in is shifted away from 0 Hz but still within the received bandwidth. If your algorithm works best with your signal centered at 0 Hz (many do), you can shift the frequency in the digital domain, moving your signal of interest to 0 Hz and your DC offset away from 0 Hz. HackRF's high maximum sampling rate can be a big help as it allows you to use offset tuning even for relatively wideband signals. - - #. Correct it. There are various ways of removing the DC offset in software. However, these techniques may degrade parts of the signal that are close to 0 Hz. It may look better, but that doesn't necessarily mean that it is better from the standpoint of a demodulator algorithm, for example. Still, correcting the DC offset is often a good choice. - - ----- - - -How should I set the gain controls for RX? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A good default setting to start with is RF=0 (off), IF=16, baseband=16. Increase or decrease the IF and baseband gain controls roughly equally to find the best settings for your situation. Turn on the RF amp if you need help picking up weak signals. If your gain settings are too low, your signal may be buried in the noise. If one or more of your gain settings is too high, you may see distortion (look for unexpected frequencies that pop up when you increase the gain) or the noise floor may be amplified more than your signal is. - - ----- - - -What are the minimum system requirements for using HackRF? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The most important requirement is that you supply 500 mA at 5 V DC to your HackRF via the USB port. If your host computer has difficulty meeting this requirement, you may need to use a powered USB hub. - -Most users will want to stream data to or from the HackRF at high speeds. This requires that the host computer supports Hi-Speed USB. Some Hi-Speed USB hosts are better than others, and you may have multiple host controllers on your computer. If you have difficulty operating your HackRF at high sample rates (10 Msps to 20 Msps), try using a different USB port on your computer. If possible, arrange things so that the HackRF is the only device on the bus. - -There is no specific minimum CPU requirement for the host computer, but SDR is generally a CPU-intensive application. If you have a slower CPU, you may be unable to run certain SDR software or you may only be able to operate at lower sample rates. - - ----- - - -Why isn't HackRF working with my virtual machine (VM)? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -HackRF requires the ability to stream data at very high rates over USB. Unfortunately VM software typically has problems with continuous high speed USB transfers. - -There are some known bugs with the HackRF firmware's USB implementation. It is possible that fixing these bugs will improve the ability to operate HackRF with a VM, but there is a very good chance that operation at higher sample rates will still be limited. - - ----- - - -What LEDs should be illuminated on the HackRF? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -When HackRF One is plugged in to a USB host, four LEDs should turn on: 3V3, 1V8, RF, and USB. The 3V3 LED indicates that the primary internal power supply is working properly. The 1V8 and RF LEDs indicate that firmware is running and has switched on additional internal power supplies. The USB LED indicates that the HackRF One is communicating with the host over USB. - -The RX and TX LEDs indicate that a receive or transmit operation is currently in progress. diff --git a/docs/source/updating_firmware.rst b/docs/source/updating_firmware.rst index b696d37f..39d2b2d7 100644 --- a/docs/source/updating_firmware.rst +++ b/docs/source/updating_firmware.rst @@ -4,12 +4,10 @@ Updating Firmware ================================================ -HackRF devices ship with firmware on the SPI flash memory. The firmware can be updated with nothing more than a USB cable and host computer. +HackRF devices ship with firmware on the SPI flash memory. The firmware can be updated with a USB cable and host computer. These instructions allow you to upgrade the firmware in order to take advantage of new features or bug fixes. -If you have any difficulty making this process work from your native operating system, you can :ref:`use Pentoo or the GNU Radio Live DVD ` to perform the updates. - Updating the SPI Flash Firmware @@ -29,22 +27,18 @@ When writing a firmware image to SPI flash, be sure to select firmware with a fi After writing the firmware to SPI flash, you may need to reset the HackRF device by pressing the RESET button or by unplugging it and plugging it back in. -If you get an error that mentions HACKRF_ERROR_NOT_FOUND, check out the :ref:`FAQ `. It's often a permissions problem that can be quickly solved. +If you get an error that mentions HACKRF_ERROR_NOT_FOUND, it is often a permissions problem on your OS. -Updating the CPLD -~~~~~~~~~~~~~~~~~ +Only if Necessary: Recovering the SPI Flash Firmware +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Older versions of HackRF firmware (prior to release 2021.03.1) require an additional step to program a bitstream into the CPLD. +If the firmware installed in SPI flash has been damaged or if you are programming a home-made HackRF for the first time, you will not be able to immediately use the hackrf_spiflash program as listed in the above procedure. Follow these steps instead: -To update the CPLD image, first update the SPI flash firmware, libhackrf, and hackrf-tools to the version you are installing. Then: - -.. code-block :: sh - - hackrf_cpldjtag -x firmware/cpld/sgpio_if/default.xsvf - -After a few seconds, three LEDs should start blinking. This indicates that the CPLD has been programmed successfully. Reset the HackRF device by pressing the RESET button or by unplugging it and plugging it back in. + #. Follow the DFU Boot instructions to start the HackRF in DFU boot mode. + #. Type ``dfu-util --device 1fc9:000c --alt 0 --download hackrf_one_usb.dfu`` to load firmware from a release package into RAM. If you have a Jawbreaker, use hackrf_jawbreaker_usb.dfu instead. Alternatively, use ``make -e BOARD=HACKRF_ONE RUN_FROM=RAM program`` to load the firmware into RAM and start it. + #. Follow the SPI flash firmware update procedure above to write the ".bin" firmware image to SPI flash. @@ -63,17 +57,6 @@ You should only use a firmware image with a filename ending in ".dfu" over DFU, -Only if Necessary: Recovering the SPI Flash Firmware -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If the firmware installed in SPI flash has been damaged or if you are programming a home-made HackRF for the first time, you will not be able to immediately use the hackrf_spiflash program as listed in the above procedure. Follow these steps instead: - - #. Follow the DFU Boot instructions to start the HackRF in DFU boot mode. - #. Type ``dfu-util --device 1fc9:000c --alt 0 --download hackrf_one_usb.dfu`` to load firmware from a release package into RAM. If you have a Jawbreaker, use hackrf_jawbreaker_usb.dfu instead. Alternatively, use ``make -e BOARD=HACKRF_ONE RUN_FROM=RAM program`` to load the firmware into RAM and start it. - #. Follow the SPI flash firmware update procedure above to write the ".bin" firmware image to SPI flash. - - - Obtaining DFU-Util ~~~~~~~~~~~~~~~~~~ @@ -97,4 +80,19 @@ If you are using a platform without a dfu-util package, build instruction can be make sudo make install -Now you will have the current version of DFU Util installed on your system. \ No newline at end of file +Now you will have the current version of DFU Util installed on your system. + + + +Updating the CPLD +~~~~~~~~~~~~~~~~~ + +Older versions of HackRF firmware (prior to release 2021.03.1) require an additional step to program a bitstream into the CPLD. + +To update the CPLD image, first update the SPI flash firmware, libhackrf, and hackrf-tools to the version you are installing. Then: + +.. code-block :: sh + + hackrf_cpldjtag -x firmware/cpld/sgpio_if/default.xsvf + +After a few seconds, three LEDs should start blinking. This indicates that the CPLD has been programmed successfully. Reset the HackRF device by pressing the RESET button or by unplugging it and plugging it back in. \ No newline at end of file diff --git a/docs/source/usb_cables.rst b/docs/source/usb_cables.rst new file mode 100644 index 00000000..c947ce88 --- /dev/null +++ b/docs/source/usb_cables.rst @@ -0,0 +1,27 @@ +========== +USB Cables +========== + +The USB cable you choose can make a big difference in what you see when using your HackRF and especially when using it around between 120 and 480 MHz where USB is doing all its work. + + #. Use a shielded USB cable. The best way to guarantee RF interference from USB is to use an unshielded cable. You can test that your cable is shielded by using a continuity tester to verify that the shield on one connector has continuity to the shield on the connector at the other end of the cable. + + #. Use a short USB cable. Trying anything larger than a 6ft cable may yield poor results. The longer the cable, the more loss you can expect and when making this post a 15ft cable was tried and the result was the HackRF would only power up half way. + + #. For best results, select a cable with a ferrite core. These cables are usually advertised to be noise reducing and are recognizable from the plastic block towards one end. + +Screenshot before and after changing to a noise reducing cable (`view full size image `__): + +.. image:: ../images/noisereducingcablescreenshot.jpeg + :align: center + +A shielded cable with ferrite core was used in the right-hand image. + +The before and after images were both taken with the preamp on and the LNA and VGA both set to 24db. + + + +Why isn't my HackRF One detectable after I plug it into my computer? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If your HackRF One isn't immediately detectable it is very possible that your Micro USB cable is not meeting HackRF One's requirements. HackRF One requires quite a bit of supply current and solid USB 2.0 high speed communications to operate. It is common for HackRF One to reveal cables with deficiencies such as carrying power but not data, carrying data but not enough power, etc. Please try multiple cables to resolve this issue. More than once people have gotten their HackRF One to work after trying their fifth cable. \ No newline at end of file diff --git a/docs/source/virtual_machines.rst b/docs/source/virtual_machines.rst new file mode 100644 index 00000000..a93973e2 --- /dev/null +++ b/docs/source/virtual_machines.rst @@ -0,0 +1,5 @@ +================ +Virtual Machines +================ + +HackRF requires the ability to stream data at very high rates over USB. Unfortunately VM software typically has problems with USB passthrough; especially continuous high speed USB transfers. It is recommended to not use a HackRF with a VM. \ No newline at end of file From 189b5bf693620d43d27fe8accdf112c85ce833a0 Mon Sep 17 00:00:00 2001 From: Jacob Graves Date: Wed, 19 Apr 2023 11:32:32 -0600 Subject: [PATCH 037/474] wrap clkin init in r9 board check (#1307) --- firmware/common/hackrf_core.c | 6 +----- firmware/hackrf_usb/hackrf_usb.c | 6 +++++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index ee418a77..cedff0f3 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -534,7 +534,7 @@ bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz) return bandwidth_hz_real != 0; } -/* +/* Configure PLL1 (Main MCU Clock) to max speed (204MHz). Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. This function shall be called after cpu_clock_init(). @@ -811,10 +811,6 @@ 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/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index bcf9ba87..4b785683 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -288,7 +288,11 @@ int main(void) } operacake_init(operacake_allow_gpio); - clkin_detect_init(); + // FIXME: clock detection on r9 only works when calling init twice + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + clkin_detect_init(); + clkin_detect_init(); + } while (true) { transceiver_request_t request; From 17269d3a7c3f51a483ef58b1d072ac6dac34ddfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20Bar=C3=A1th?= Date: Sun, 23 Apr 2023 04:03:49 +0200 Subject: [PATCH 038/474] Document libhackrf functions using Doxygen (#1244) * Document & comment code * document functions & add pages for groups * Run clang-format * Fix most review change requests * Fix typos, add information on using multiple Opera Cake boards * Update documentation * Changes requested by @Straithe - update project brief - set paper type to letter - move doxyfile * Changes requested by @martinling Excluding the USB API versioning * Remove incomplete USB version info The required versions were only noted at a few places. Will add complete info later, but for now, it's removed --- docs/doxygen/Doxyfile | 2658 +++++++++++++++++++++++++++++++++++ host/libhackrf/src/hackrf.h | 1552 +++++++++++++++++++- 2 files changed, 4167 insertions(+), 43 deletions(-) create mode 100644 docs/doxygen/Doxyfile diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile new file mode 100644 index 00000000..c3d6701f --- /dev/null +++ b/docs/doxygen/Doxyfile @@ -0,0 +1,2658 @@ +# Doxyfile 1.9.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "libhackrf" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "HackRF SDR platform library" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = NO + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = YES + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which efficively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = YES + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= NO + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = NO + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = "../../host/libhackrf/src/hackrf.h" + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), +# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, +# *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to +# YES then doxygen will add the directory of each input to the include path. +# The default value is: YES. + +CLANG_ADD_INC_PATHS = YES + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = NO + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: +# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 1 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /