diff --git a/firmware/common/clkin.c b/firmware/common/clkin.c new file mode 100644 index 00000000..5ab8123a --- /dev/null +++ b/firmware/common/clkin.c @@ -0,0 +1,112 @@ +/* + * 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 +#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) +{ + /* 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); + TIMER1_MR3 = MEASUREMENT_CYCLES; + TIMER1_MR0 = MEASUREMENT_CYCLES; + + /* prevent TIMER1_MR3 from interfering with SCT */ + CREG_CREG6 |= CREG_CREG6_CTOUTCTRL; + + /* Timer2 counts CLKIN */ + timer_set_prescaler(TIMER2, 0); + TIMER2_CCR = TIMER_CCR_CAP3RE; + GIMA_CAP2_3_IN = 0x20; // T1_MAT3 + + /* 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) & (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 + | 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(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(TIMER2); + timer_reset(TIMER1); + timer_enable_counter(TIMER2); + timer_enable_counter(TIMER1); +} + +uint32_t clkin_frequency(void) +{ + return TIMER2_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/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 diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index bc0bb4b3..ee418a77 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -26,8 +26,7 @@ #include "sgpio.h" #include "si5351c.h" #include "spi_ssp.h" -#include "max2837.h" -#include "max2837_target.h" +#include "max283x.h" #include "max5864.h" #include "max5864_target.h" #include "w25q80bv.h" @@ -35,6 +34,8 @@ #include "i2c_bus.h" #include "i2c_lpc.h" #include "cpld_jtag.h" +#include "platform_detect.h" +#include "clkin.h" #include #include #include @@ -59,11 +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); -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); +/* 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); @@ -134,8 +132,17 @@ 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); -static struct gpio_t gpio_rx_q_invert = GPIO(0, 13); +/* other CPLD interface GPIO pins */ +static struct gpio_t gpio_hw_sync_enable = GPIO(5, 12); +static struct gpio_t gpio_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_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 i2c_bus_t i2c0 = { @@ -165,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 @@ -176,7 +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, + .gpio_select = &gpio_max283x_select, }; const ssp_config_t ssp_config_max5864 = { @@ -195,21 +202,14 @@ 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, .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, -}; +max283x_driver_t max283x = {}; max5864_driver_t max5864 = { .bus = &spi_bus_ssp1, @@ -240,7 +240,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, }; @@ -406,14 +406,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); @@ -474,21 +486,46 @@ 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, 1, 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; } 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; + bandwidth_hz_real = max283x_set_lpf_bandwidth(&max283x, bandwidth_hz); if (bandwidth_hz_real) { hackrf_ui()->set_filter_bw(bandwidth_hz_real); @@ -578,6 +615,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); @@ -587,7 +625,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/MAX2839 + * CLK2 -> External Clock Output/LPC43xx (power down at boot) + * + * Clocks on other platforms: * CLK0 -> MAX5864/CPLD * CLK1 -> CPLD * CLK2 -> SGPIO @@ -598,22 +641,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 MAX2839. */ + 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. */ @@ -727,7 +781,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; @@ -738,8 +792,8 @@ void cpu_clock_init(void) 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_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; @@ -757,6 +811,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) @@ -796,9 +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); + spi_bus_start(&spi_bus_ssp1, &ssp_config_max283x); } void ssp1_set_mode_max5864(void) @@ -856,15 +914,26 @@ void pin_setup(void) #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) { +#ifdef HACKRF_ONE + gpio_output(&gpio_h1r9_1v8_enable); + scu_pinmux(SCU_H1R9_EN1V8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); +#endif + } else { + 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: */ 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 @@ -886,10 +955,16 @@ 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); + spi_bus_start(&spi_bus_ssp1, &ssp_config_max283x); mixer_bus_setup(&mixer); +#ifdef HACKRF_ONE + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + rf_path.gpio_rx = &gpio_h1r9_rx; + sgpio_config.gpio_hw_sync_enable = &gpio_h1r9_hw_sync_enable; + } +#endif rf_path_pin_setup(&rf_path); /* Configure external clock in */ @@ -900,12 +975,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 @@ -915,15 +1002,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 @@ -970,7 +1065,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 e24007eb..d6211b37 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -34,7 +34,7 @@ extern "C" { #include "si5351c.h" #include "spi_ssp.h" -#include "max2837.h" +#include "max283x.h" #include "max5864.h" #include "mixer.h" #include "w25q80bv.h" @@ -108,9 +108,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 @@ -232,6 +232,16 @@ 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_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, TRANSCEIVER_MODE_RX = 1, @@ -258,10 +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_max283x; extern const ssp_config_t ssp_config_max5864; -extern max2837_driver_t max2837; +extern max283x_driver_t max283x; extern max5864_driver_t max5864; extern mixer_driver_t mixer; extern w25q80bv_driver_t spi_flash; @@ -271,7 +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_max283x(void); void ssp1_set_mode_max5864(void); void pin_setup(void); 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.c b/firmware/common/max2839.c new file mode 100644 index 00000000..868855d4 --- /dev/null +++ b/firmware/common/max2839.c @@ -0,0 +1,417 @@ +/* + * 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. + */ + +/* + * '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 + +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 */ + 0x00c, /* 1: data sheet says 0x00c but read 0x22c */ + 0x080, /* 2 */ + 0x1b9, /* 3: data sheet says 0x1b9 but read 0x1b0 */ + 0x3e6, /* 4 */ + 0x100, /* 5 */ + 0x000, /* 6 */ + 0x208, /* 7 */ + 0x220, /* 8: data sheet says 0x220 but read 0x000 */ + 0x018, /* 9 */ + 0x00c, /* 10 */ + 0x004, /* 11: data sheet says 0x004 but read 0x000 */ + 0x24f, /* 12 */ + 0x150, /* 13 */ + 0x3c5, /* 14 */ + 0x201, /* 15 */ + 0x01c, /* 16 */ + 0x155, /* 17 */ + 0x155, /* 18 */ + 0x153, /* 19 */ + 0x249, /* 20 */ + 0x02d, /* 21: data sheet says 0x02d but read 0x13d */ + 0x1a9, /* 22 */ + 0x24f, /* 23 */ + 0x180, /* 24 */ + 0x000, /* 25: data sheet says 0x000 but read 0x00a */ + 0x3c0, /* 26 */ + 0x200, /* 27: data sheet says 0x200 but read 0x22a */ + 0x0c0, /* 28 */ + 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) +{ + 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. */ + max2839_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); + + /* 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 maximum RX output common-mode voltage */ + set_MAX2839_RX_VCM(drv, MAX2839_RX_VCM_1_35); + + /* 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); +} + +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) +{ + // 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]; +} + +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_chip_enable(drv, 1); + max2839_regs_commit(drv); + max2839_set_mode(drv, MAX2839_MODE_STANDBY); +} + +void max2839_tx(max2839_driver_t* const drv) +{ + // 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_LPFmode(drv, MAX2839_LPFmode_RxLPF); + max2839_regs_commit(drv); + max2839_set_mode(drv, MAX2839_MODE_RX); +} + +void max2839_stop(max2839_driver_t* const drv) +{ + 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) +{ + uint8_t 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; + } else if (freq < 2500000000U) { + band = MAX2839_LOGEN_BSW_2_4; + } else if (freq < 2600000000U) { + band = MAX2839_LOGEN_BSW_2_5; + } else { + band = MAX2839_LOGEN_BSW_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); + + /* 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 { + 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; +} + +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 (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); + 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) { + return false; + } + requested_vga_gain = gain_db; + max2839_configure_rx_gain(drv); + return true; +} + +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); + return true; +} diff --git a/firmware/common/max2839.h b/firmware/common/max2839.h new file mode 100644 index 00000000..fbffa5b1 --- /dev/null +++ b/firmware/common/max2839.h @@ -0,0 +1,97 @@ +/* + * 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 __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_STANDBY, + 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* bus; + gpio_t gpio_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; + 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 new file mode 100644 index 00000000..bee66846 --- /dev/null +++ b/firmware/common/max2839_regs.def @@ -0,0 +1,259 @@ +/* -*- 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< + * 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 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..06ff6465 --- /dev/null +++ b/firmware/common/max283x.h @@ -0,0 +1,101 @@ +/* + * 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); + +/* 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 3ca6fd75..ba8ef69b 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -28,11 +28,12 @@ #include #include "hackrf_ui.h" - -#include -#include -#include -#include +#include "gpio_lpc.h" +#include "platform_detect.h" +#include "mixer.h" +#include "max283x.h" +#include "max5864.h" +#include "sgpio.h" #if (defined JAWBREAKER || defined HACKRF_ONE || defined RAD1O) /* @@ -81,21 +82,35 @@ #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. + */ + +#ifdef HACKRF_ONE +static struct gpio_t gpio_h1r9_no_ant_pwr = GPIO(2, 4); +#endif + #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 +171,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 @@ -254,17 +281,24 @@ 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_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 - - /* Configure RF power supply (VAA) switch */ - scu_pinmux(SCU_NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + scu_pinmux(SCU_H1R9_RX, 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); + gpio_output(rf_path->gpio_tx); + scu_pinmux(SCU_NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + } /* * Safe (initial) switch settings turn off both amplifiers and antenna port @@ -283,7 +317,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 @@ -334,9 +367,13 @@ void rf_path_init(rf_path_t* const rf_path) max5864_setup(&max5864); max5864_shutdown(&max5864); - ssp1_set_mode_max2837(); - max2837_setup(&max2837); - max2837_start(&max2837); + ssp1_set_mode_max283x(); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + max283x_setup(&max283x, MAX2839_VARIANT); + } else { + max283x_setup(&max283x, MAX2837_VARIANT); + } + max283x_start(&max283x); // On HackRF One, the mixer is now set up earlier in boot. #ifndef HACKRF_ONE @@ -364,8 +401,8 @@ 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); + ssp1_set_mode_max283x(); + max283x_tx(&max283x); sgpio_configure(&sgpio_config, SGPIO_DIRECTION_TX); break; @@ -383,8 +420,8 @@ 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); + ssp1_set_mode_max283x(); + max283x_rx(&max283x); sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX); break; @@ -399,8 +436,8 @@ 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); + ssp1_set_mode_max283x(); + max283x_set_mode(&max283x, MAX283x_MODE_STANDBY); sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX); break; } diff --git a/firmware/common/sgpio.c b/firmware/common/sgpio.c index 8fd4a8ab..ccf7e162 100644 --- a/firmware/common/sgpio.c +++ b/firmware/common/sgpio.c @@ -25,13 +25,12 @@ #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); -#endif void sgpio_configure_pin_functions(sgpio_config_t* const config) { @@ -48,14 +47,23 @@ 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] */ - sgpio_cpld_stream_rx_set_q_invert(config, 0); + 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_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); } @@ -112,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 = @@ -284,55 +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, - const uint_fast8_t invert) -{ - gpio_write(config->gpio_rx_q_invert, invert); -} -#endif diff --git a/firmware/common/sgpio.h b/firmware/common/sgpio.h index a1e10b59..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,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_set_mixer_invert(sgpio_config_t* const config, uint_fast8_t invert); #endif //__SGPIO_H__ diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index 394a6dd5..af858875 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 @@ -179,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; @@ -191,17 +203,28 @@ void si5351c_configure_clock_control( 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 { /* 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) { - 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 */ @@ -217,7 +240,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, @@ -225,18 +248,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_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_4MA); + 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) { @@ -246,10 +279,27 @@ 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)); + + 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( @@ -275,24 +325,67 @@ 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); } } 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) { 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); } + +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_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); + 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 } diff --git a/firmware/common/tuning.c b/firmware/common/tuning.c index 79a238c7..120831c4 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,8 @@ 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); + 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 @@ -83,14 +83,14 @@ 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); - sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 1); + max283x_set_frequency(&max283x, real_mixer_freq_hz - freq); + 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 */ - max2837_set_frequency(&max2837, MAX2837_freq_hz); - sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0); + max283x_set_frequency(&max283x, MAX2837_freq_hz); + 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 */ @@ -110,13 +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); - max2837_set_frequency(&max2837, freq - real_mixer_freq_hz); - sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0); + max283x_set_frequency(&max283x, freq - real_mixer_freq_hz); + sgpio_cpld_set_mixer_invert(&sgpio_config, 0); } else { /* Error freq_mhz too high */ success = false; } - max2837_set_mode(&max2837, prior_max2837_mode); + max283x_set_mode(&max283x, prior_max283x_mode); if (success) { freq_cache = freq; hackrf_ui()->set_frequency(freq); @@ -147,11 +147,11 @@ bool set_freq_explicit( } rf_path_set_filter(&rf_path, path); - 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); + 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); 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-common.cmake b/firmware/hackrf-common.cmake index e7231923..8418e47e 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -170,8 +170,11 @@ 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 + ${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 @@ -185,6 +188,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..bcf9ba87 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__; @@ -64,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, @@ -286,6 +288,8 @@ int main(void) } operacake_init(operacake_allow_gpio); + clkin_detect_init(); + while (true) { transceiver_request_t request; 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; 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( diff --git a/firmware/hackrf_usb/usb_api_transceiver.c b/firmware/hackrf_usb/usb_api_transceiver.c index 18a08938..a6cf86cc 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,8 @@ 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; + value = max283x_set_lna_gain(&max283x, endpoint->setup.index); endpoint->buffer[0] = value; if (value) { hackrf_ui()->set_bb_lna_gain(endpoint->setup.index); @@ -186,8 +188,8 @@ 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; + value = max283x_set_vga_gain(&max283x, endpoint->setup.index); endpoint->buffer[0] = value; if (value) { hackrf_ui()->set_bb_vga_gain(endpoint->setup.index); @@ -209,8 +211,8 @@ 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; + 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);