diff --git a/.travis.yml b/.travis.yml index 8476bf27..9a4ea0f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,7 @@ script: - cd ../.. - mkdir firmware/build-hackrf-one - mkdir firmware/build-jawbreaker + - mkdir firmware/build-rad1o - cd firmware/libopencm3 - make - cd ../build-hackrf-one @@ -45,6 +46,9 @@ script: - cd ../build-jawbreaker - cmake -DBOARD=JAWBREAKER .. - make + - cd ../build-rad1o + - cmake -DBOARD=RAD1O .. + - make addons: apt: diff --git a/firmware/README b/firmware/README index e6087c2c..58ea89d1 100644 --- a/firmware/README +++ b/firmware/README @@ -32,6 +32,7 @@ $ make $ hackrf_spiflash -w hackrf_usb.bin If you have a Jawbreaker, add -DBOARD=JAWBREAKER to the cmake command. +If you have a rad1o, use -DBOARD=RAD1O instead. It is possible to use a USB Device Firmware Upgrade (DFU) method to load diff --git a/firmware/common/hackrf-ui.h b/firmware/common/hackrf-ui.h new file mode 100644 index 00000000..95b82489 --- /dev/null +++ b/firmware/common/hackrf-ui.h @@ -0,0 +1,17 @@ +#ifndef HACKRF_UI_H +#define HACKRF_UI_H + +#include +#include + +void hackrf_ui_init(void) __attribute__((weak)); +void hackrf_ui_setFrequency(uint64_t _freq) __attribute__((weak)); +void hackrf_ui_setSampleRate(uint32_t _sample_rate) __attribute__((weak)); +void hackrf_ui_setDirection(const rf_path_direction_t _direction) __attribute__((weak)); +void hackrf_ui_setFilterBW(uint32_t bw) __attribute__((weak)); +void hackrf_ui_setLNAPower(bool _lna_on) __attribute__((weak)); +void hackrf_ui_setBBLNAGain(const uint32_t gain_db) __attribute__((weak)); +void hackrf_ui_setBBVGAGain(const uint32_t gain_db) __attribute__((weak)); +void hackrf_ui_setBBTXVGAGain(const uint32_t gain_db) __attribute__((weak)); + +#endif diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 545b57e5..185dc5b7 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -22,14 +22,13 @@ */ #include "hackrf_core.h" +#include "hackrf-ui.h" #include "si5351c.h" #include "spi_ssp.h" #include "max2837.h" #include "max2837_target.h" #include "max5864.h" #include "max5864_target.h" -#include "rffc5071.h" -#include "rffc5071_spi.h" #include "w25q80bv.h" #include "w25q80bv_target.h" #include "i2c_bus.h" @@ -47,10 +46,13 @@ #define WAIT_CPU_CLOCK_INIT_DELAY (10000) /* GPIO Output PinMux */ -static struct gpio_t gpio_led[3] = { +static struct gpio_t gpio_led[] = { GPIO(2, 1), GPIO(2, 2), - GPIO(2, 8) + GPIO(2, 8), +#ifdef RAD1O + GPIO(5, 26), +#endif }; static struct gpio_t gpio_1v8_enable = GPIO(3, 6); @@ -74,19 +76,7 @@ static struct gpio_t gpio_max2837_b7 = GPIO(2, 15); /* MAX5864 SPI chip select (AD_CS) GPIO PinMux */ static struct gpio_t gpio_max5864_select = GPIO(2, 7); -/* RFFC5071 GPIO serial interface PinMux */ -#ifdef JELLYBEAN -static struct gpio_t gpio_rffc5072_select = GPIO(3, 8); -static struct gpio_t gpio_rffc5072_clock = GPIO(3, 9); -static struct gpio_t gpio_rffc5072_data = GPIO(3, 10); -static struct gpio_t gpio_rffc5072_reset = GPIO(3, 11); -#endif -#if (defined JAWBREAKER || defined HACKRF_ONE) -static struct gpio_t gpio_rffc5072_select = GPIO(2, 13); -static struct gpio_t gpio_rffc5072_clock = GPIO(5, 6); -static struct gpio_t gpio_rffc5072_data = GPIO(3, 3); -static struct gpio_t gpio_rffc5072_reset = GPIO(2, 14); - +#if (defined JAWBREAKER || defined HACKRF_ONE || defined RAD1O) /* static struct gpio_t gpio_sync_in_a = GPIO(3, 8); static struct gpio_t gpio_sync_in_b = GPIO(3, 9); @@ -108,6 +98,9 @@ static struct gpio_t gpio_sync_out_b = GPIO(3, 9); #ifdef HACKRF_ONE static struct gpio_t gpio_vaa_disable = GPIO(2, 9); #endif +#ifdef RAD1O +static struct gpio_t gpio_vaa_enable = GPIO(2, 9); +#endif static struct gpio_t gpio_w25q80bv_hold = GPIO(1, 14); static struct gpio_t gpio_w25q80bv_wp = GPIO(1, 15); @@ -129,6 +122,20 @@ static struct gpio_t gpio_amp_bypass = GPIO(0, 14); static struct gpio_t gpio_rx_amp = GPIO(1, 11); static struct gpio_t gpio_no_rx_amp_pwr = GPIO(1, 12); #endif +#ifdef RAD1O +static struct gpio_t gpio_tx_rx_n = GPIO(0, 11); +static struct gpio_t gpio_tx_rx = GPIO(0, 14); +static struct gpio_t gpio_by_mix = GPIO(1, 12); +static struct gpio_t gpio_by_mix_n = GPIO(2, 10); +static struct gpio_t gpio_by_amp = GPIO(1, 0); +static struct gpio_t gpio_by_amp_n = GPIO(5, 5); +static struct gpio_t gpio_mixer_en = GPIO(5, 16); +static struct gpio_t gpio_low_high_filt = GPIO(2, 11); +static struct gpio_t gpio_low_high_filt_n = GPIO(2, 12); +static struct gpio_t gpio_tx_amp = GPIO(2, 15); +static struct gpio_t gpio_rx_lna = GPIO(5, 15); +#endif + #if 0 /* GPIO Input */ static struct gpio_t gpio_boot[] = { @@ -141,7 +148,7 @@ static struct gpio_t gpio_boot[] = { /* CPLD JTAG interface GPIO pins */ static struct gpio_t gpio_cpld_tdo = GPIO(5, 18); static struct gpio_t gpio_cpld_tck = GPIO(3, 0); -#ifdef HACKRF_ONE +#if defined HACKRF_ONE || defined RAD1O static struct gpio_t gpio_cpld_tms = GPIO(3, 4); static struct gpio_t gpio_cpld_tdi = GPIO(3, 1); #else @@ -244,25 +251,6 @@ max5864_driver_t max5864 = { .target_init = max5864_target_init, }; -const rffc5071_spi_config_t rffc5071_spi_config = { - .gpio_select = &gpio_rffc5072_select, - .gpio_clock = &gpio_rffc5072_clock, - .gpio_data = &gpio_rffc5072_data, -}; - -spi_bus_t spi_bus_rffc5071 = { - .config = &rffc5071_spi_config, - .start = rffc5071_spi_start, - .stop = rffc5071_spi_stop, - .transfer = rffc5071_spi_transfer, - .transfer_gather = rffc5071_spi_transfer_gather, -}; - -rffc5071_driver_t rffc5072 = { - .bus = &spi_bus_rffc5071, - .gpio_reset = &gpio_rffc5072_reset, -}; - const ssp_config_t ssp_config_w25q80bv = { .data_bits = SSP_DATA_8BITS, .serial_clock_rate = 2, @@ -313,6 +301,19 @@ rf_path_t rf_path = { .gpio_rx_amp = &gpio_rx_amp, .gpio_no_rx_amp_pwr = &gpio_no_rx_amp_pwr, #endif +#ifdef RAD1O + .gpio_tx_rx_n = &gpio_tx_rx_n, + .gpio_tx_rx = &gpio_tx_rx, + .gpio_by_mix = &gpio_by_mix, + .gpio_by_mix_n = &gpio_by_mix_n, + .gpio_by_amp = &gpio_by_amp, + .gpio_by_amp_n = &gpio_by_amp_n, + .gpio_mixer_en = &gpio_mixer_en, + .gpio_low_high_filt = &gpio_low_high_filt, + .gpio_low_high_filt_n = &gpio_low_high_filt_n, + .gpio_tx_amp = &gpio_tx_amp, + .gpio_rx_lna = &gpio_rx_lna, +#endif }; jtag_gpio_t jtag_gpio_cpld = { @@ -377,6 +378,8 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom) uint32_t a, b, c; uint32_t rem; + hackrf_ui_setSampleRate(rate_num/2); + /* Find best config */ a = (VCO_FREQ * rate_denom) / rate_num; @@ -460,7 +463,9 @@ bool sample_rate_set(const uint32_t sample_rate_hz) { default: return false; } - + + hackrf_ui_setSampleRate(sample_rate_hz); + /* NOTE: Because MS1, 2, 3 outputs are slaved to PLLA, the p1, p2, p3 * values are irrelevant. */ @@ -476,7 +481,7 @@ bool sample_rate_set(const uint32_t sample_rate_hz) { return true; #endif -#if (defined JAWBREAKER || defined HACKRF_ONE) +#if (defined JAWBREAKER || defined HACKRF_ONE || defined RAD1O) uint32_t p1 = 4608; uint32_t p2 = 0; uint32_t p3 = 0; @@ -541,7 +546,11 @@ bool sample_rate_set(const uint32_t sample_rate_hz) { } bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz) { - return max2837_set_lpf_bandwidth(&max2837, bandwidth_hz); + uint32_t bandwidth_hz_real = max2837_set_lpf_bandwidth(&max2837, bandwidth_hz); + + if(bandwidth_hz_real) hackrf_ui_setFilterBW(bandwidth_hz_real); + + return bandwidth_hz_real != 0; } /* clock startup for Jellybean with Lemondrop attached @@ -616,6 +625,33 @@ void cpu_clock_init(void) si5351c_write(&clock_gen, ms7data, sizeof(ms7data)); #endif +#ifdef RAD1O + /* rad1o clocks: + * CLK0 -> MAX5864/CPLD + * CLK1 -> CPLD + * CLK2 -> SGPIO + * CLK3 -> External Clock Output + * CLK4 -> MAX2837 + * CLK5 -> MAX2871 + * CLK6 -> none + * CLK7 -> LPC4330 (but LPC4330 starts up on its own crystal) */ + + /* MS3/CLK3 is the source for the external clock output. */ + si5351c_configure_multisynth(&clock_gen, 3, 80*128-512, 0, 1, 0); /* 800/80 = 10MHz */ + + /* MS4/CLK4 is the source for the MAX2837 clock input. */ + si5351c_configure_multisynth(&clock_gen, 4, 20*128-512, 0, 1, 0); /* 800/20 = 40MHz */ + + /* MS5/CLK5 is the source for the RFFC5071 mixer. */ + si5351c_configure_multisynth(&clock_gen, 5, 20*128-512, 0, 1, 0); /* 800/20 = 40MHz */ + + /* MS6/CLK6 is unused. */ + + /* MS7/CLK7 is the source for the LPC43xx microcontroller. */ + uint8_t ms7data[] = { 90, 255, 20, 0 }; + si5351c_write(&clock_gen, ms7data, sizeof(ms7data)); +#endif + /* Set to 10 MHz, the common rate between Jellybean and Jawbreaker. */ sample_rate_set(10000000); @@ -893,7 +929,10 @@ void pin_setup(void) { scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_NOPULL); scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_NOPULL); scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_NOPULL); - +#ifdef RAD1O + scu_pinmux(SCU_PINMUX_LED4, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4); +#endif + scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_NOPULL); /* Configure USB indicators */ @@ -908,6 +947,9 @@ void pin_setup(void) { gpio_output(&gpio_led[0]); gpio_output(&gpio_led[1]); gpio_output(&gpio_led[2]); +#ifdef RAD1O + gpio_output(&gpio_led[3]); +#endif gpio_output(&gpio_1v8_enable); @@ -928,11 +970,29 @@ void pin_setup(void) { gpio_output(&gpio_sync_out_b); #endif +#ifdef RAD1O + /* Configure RF power supply (VAA) switch control signal as output */ + gpio_output(&gpio_vaa_enable); + + /* Safe state: start with VAA turned off: */ + disable_rf_power(); + + scu_pinmux(SCU_PINMUX_GPIO3_10, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_GPIO3_11, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); + + gpio_input(&gpio_sync_in_a); + gpio_input(&gpio_sync_in_b); + + gpio_output(&gpio_sync_out_a); + gpio_output(&gpio_sync_out_b); +#endif + /* 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_rffc5071, &rffc5071_spi_config); + + mixer_bus_setup(&mixer); rf_path_pin_setup(&rf_path); @@ -960,6 +1020,16 @@ void disable_rf_power(void) { } #endif +#ifdef RAD1O +void enable_rf_power(void) { + gpio_set(&gpio_vaa_enable); +} + +void disable_rf_power(void) { + gpio_clear(&gpio_vaa_enable); +} +#endif + void led_on(const led_t led) { gpio_set(&gpio_led[led]); } @@ -1001,4 +1071,3 @@ void hw_sync_copy_state() { bool hw_sync_ready() { return (gpio_read(&gpio_sync_in_a) && gpio_read(&gpio_sync_in_b)); } - diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 8b4e8316..82cfc52c 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -37,7 +37,7 @@ extern "C" #include "max2837.h" #include "max5864.h" -#include "rffc5071.h" +#include "mixer.h" #include "w25q80bv.h" #include "sgpio.h" #include "rf_path.h" @@ -47,6 +47,7 @@ extern "C" #define BOARD_ID_JELLYBEAN 0 #define BOARD_ID_JAWBREAKER 1 #define BOARD_ID_HACKRF_ONE 2 +#define BOARD_ID_RAD1O 3 #ifdef JELLYBEAN #define BOARD_ID BOARD_ID_JELLYBEAN @@ -60,6 +61,10 @@ extern "C" #define BOARD_ID BOARD_ID_HACKRF_ONE #endif +#ifdef RAD1O +#define BOARD_ID BOARD_ID_RAD1O +#endif + /* * SCU PinMux */ @@ -68,6 +73,9 @@ extern "C" #define SCU_PINMUX_LED1 (P4_1) /* GPIO2[1] on P4_1 */ #define SCU_PINMUX_LED2 (P4_2) /* GPIO2[2] on P4_2 */ #define SCU_PINMUX_LED3 (P6_12) /* GPIO2[8] on P6_12 */ +#ifdef RAD1O +#define SCU_PINMUX_LED4 (PB_6) /* GPIO5[26] on PB_6 */ +#endif #define SCU_PINMUX_EN1V8 (P6_10) /* GPIO3[6] on P6_10 */ @@ -92,7 +100,7 @@ extern "C" /* CPLD JTAG interface */ #define SCU_PINMUX_CPLD_TDO (P9_5) /* GPIO5[18] */ #define SCU_PINMUX_CPLD_TCK (P6_1) /* GPIO3[ 0] */ -#ifdef HACKRF_ONE +#if (defined HACKRF_ONE || defined RAD1O) #define SCU_PINMUX_CPLD_TMS (P6_5) /* GPIO3[ 4] */ #define SCU_PINMUX_CPLD_TDI (P6_2) /* GPIO3[ 1] */ #else @@ -112,7 +120,7 @@ extern "C" #ifdef JELLYBEAN #define SCU_PINMUX_SGPIO8 (P1_12) #endif -#if (defined JAWBREAKER || defined HACKRF_ONE) +#if (defined JAWBREAKER || defined HACKRF_ONE || defined RAD1O) #define SCU_PINMUX_SGPIO8 (P9_6) #endif #define SCU_PINMUX_SGPIO9 (P4_3) @@ -134,6 +142,12 @@ extern "C" #define SCU_XCVR_B6 (P5_5) /* GPIO2[14] on P5_5 */ #define SCU_XCVR_B7 (P5_6) /* GPIO2[15] on P5_6 */ #endif +#ifdef RAD1O +#define SCU_XCVR_RXHP (P8_1) /* GPIO[] on P8_1 */ +#define SCU_XCVR_B6 (P8_2) /* GPIO[] on P8_2 */ +#define SCU_XCVR_B7 (P9_3) /* GPIO[] on P8_3 */ +#endif + #define SCU_XCVR_ENABLE (P4_6) /* GPIO2[6] on P4_6 */ #define SCU_XCVR_RXENABLE (P4_5) /* GPIO2[5] on P4_5 */ #define SCU_XCVR_TXENABLE (P4_4) /* GPIO2[4] on P4_4 */ @@ -155,6 +169,15 @@ extern "C" #define SCU_MIXER_SDATA (P6_4) /* GPIO3[3] on P6_4 */ #define SCU_MIXER_RESETX (P5_5) /* GPIO2[14] on P5_5 */ #endif +#ifdef RAD1O +#define SCU_VCO_CE (P5_4) /* GPIO2[13] on P5_4 */ +#define SCU_VCO_SCLK (P2_6) /* GPIO5[6] on P2_6 */ +#define SCU_VCO_SDATA (P6_4) /* GPIO3[3] on P6_4 */ +#define SCU_VCO_LE (P5_5) /* GPIO2[14] on P5_5 */ +#define SCU_VCO_MUX (PB_5) /* GPIO5[25] on PB_5 */ +#define SCU_MIXER_EN (P6_8) /* GPIO5[16] on P6_8 */ +#define SCU_SYNT_RFOUT_EN (P6_9) /* GPIO3[5] on P6_9 */ +#endif /* RF LDO control */ #ifdef JAWBREAKER @@ -165,6 +188,10 @@ extern "C" #ifdef HACKRF_ONE #define SCU_NO_VAA_ENABLE (P5_0) /* GPIO2[9] on P5_0 */ #endif +#ifdef RAD1O +#define SCU_VAA_ENABLE (P5_0) /* GPIO2[9] on P5_0 */ +#endif + /* SPI flash */ #define SCU_SSP0_MISO (P3_6) @@ -190,6 +217,18 @@ extern "C" #define SCU_RX_AMP (P2_11) /* GPIO1[11] on P2_11 */ #define SCU_NO_RX_AMP_PWR (P2_12) /* GPIO1[12] on P2_12 */ #endif +#ifdef RAD1O +#define SCU_BY_AMP (P1_7) /* GPIO1[0] on P1_7 */ +#define SCU_BY_AMP_N (P2_5) /* GPIO5[5] on P2_5 */ +#define SCU_TX_RX (P2_10) /* GPIO0[14] on P2_10 */ +#define SCU_TX_RX_N (P2_11) /* GPIO1[11] on P2_11 */ +#define SCU_BY_MIX (P2_12) /* GPIO1[12] on P2_12 */ +#define SCU_BY_MIX_N (P5_1) /* GPIO2[10] on P5_1 */ +#define SCU_LOW_HIGH_FILT (P5_2) /* GPIO2[11] on P5_2 */ +#define SCU_LOW_HIGH_FILT_N (P5_3) /* GPIO2[12] on P5_3 */ +#define SCU_TX_AMP (P5_6) /* GPIO2[15] on P5_6 */ +#define SCU_RX_LNA (P6_7) /* GPIO5[15] on P6_7 */ +#endif /* TODO add other Pins */ #define SCU_PINMUX_GPIO3_8 (P7_0) /* GPIO3[8] */ @@ -240,7 +279,7 @@ extern const ssp_config_t ssp_config_max5864; extern max2837_driver_t max2837; extern max5864_driver_t max5864; -extern rffc5071_driver_t rffc5072; +extern mixer_driver_t mixer; extern w25q80bv_driver_t spi_flash; extern sgpio_config_t sgpio_config; extern rf_path_t rf_path; @@ -262,7 +301,7 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom); bool sample_rate_set(const uint32_t sampling_rate_hz); bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz); -#ifdef HACKRF_ONE +#if (defined HACKRF_ONE || defined RAD1O) void enable_rf_power(void); void disable_rf_power(void); #endif @@ -271,6 +310,7 @@ typedef enum { LED1 = 0, LED2 = 1, LED3 = 2, + LED4 = 3, } led_t; void led_on(const led_t led); diff --git a/firmware/common/max2837.c b/firmware/common/max2837.c index d99b740f..2e853598 100644 --- a/firmware/common/max2837.c +++ b/firmware/common/max2837.c @@ -279,7 +279,7 @@ static const max2837_ft_t max2837_ft[] = { { 0, 0 }, }; -bool max2837_set_lpf_bandwidth(max2837_driver_t* const drv, const uint32_t bandwidth_hz) { +uint32_t max2837_set_lpf_bandwidth(max2837_driver_t* const drv, const uint32_t bandwidth_hz) { const max2837_ft_t* p = max2837_ft; while( p->bandwidth_hz != 0 ) { if( p->bandwidth_hz >= bandwidth_hz ) { @@ -291,10 +291,9 @@ bool max2837_set_lpf_bandwidth(max2837_driver_t* const drv, const uint32_t bandw if( p->bandwidth_hz != 0 ) { set_MAX2837_FT(drv, p->ft); max2837_regs_commit(drv); - return true; - } else { - return false; } + + return p->bandwidth_hz; } bool max2837_set_lna_gain(max2837_driver_t* const drv, const uint32_t gain_db) { diff --git a/firmware/common/max2837.h b/firmware/common/max2837.h index a9962fad..dcf6829c 100644 --- a/firmware/common/max2837.h +++ b/firmware/common/max2837.h @@ -91,7 +91,7 @@ extern void max2837_stop(max2837_driver_t* const drv); /* Set frequency in Hz. Frequency setting is a multi-step function * where order of register writes matters. */ extern void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq); -bool max2837_set_lpf_bandwidth(max2837_driver_t* const drv, const uint32_t bandwidth_hz); +uint32_t max2837_set_lpf_bandwidth(max2837_driver_t* const drv, const uint32_t bandwidth_hz); bool max2837_set_lna_gain(max2837_driver_t* const drv, const uint32_t gain_db); bool max2837_set_vga_gain(max2837_driver_t* const drv, const uint32_t gain_db); bool max2837_set_txvga_gain(max2837_driver_t* const drv, const uint32_t gain_db); diff --git a/firmware/common/max2871.c b/firmware/common/max2871.c new file mode 100644 index 00000000..ea073307 --- /dev/null +++ b/firmware/common/max2871.c @@ -0,0 +1,236 @@ +#include "max2871.h" +#include "max2871_regs.h" + +#if (defined DEBUG) +#include +#define LOG printf +#else +#define LOG(x,...) +#include +#include +#include "hackrf_core.h" +#endif + +#include +#include + +static void max2871_spi_write(max2871_driver_t* const drv, uint8_t r, uint32_t v); +static void max2871_write_registers(max2871_driver_t* const drv); +static void delay_ms(int ms); + +void max2871_setup(max2871_driver_t* const drv) +{ + /* Configure GPIO pins. */ + scu_pinmux(SCU_VCO_CE, SCU_GPIO_FAST); + scu_pinmux(SCU_VCO_SCLK, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + /* Only used for the debug pin config: scu_pinmux(SCU_VCO_SCLK, SCU_GPIO_FAST); */ + scu_pinmux(SCU_VCO_SDATA, SCU_GPIO_FAST); + scu_pinmux(SCU_VCO_LE, SCU_GPIO_FAST); + scu_pinmux(SCU_VCO_MUX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + scu_pinmux(SCU_SYNT_RFOUT_EN, SCU_GPIO_FAST); + + /* Set GPIO pins as outputs. */ + gpio_output(drv->gpio_vco_ce); + gpio_output(drv->gpio_vco_sclk); + gpio_output(drv->gpio_vco_sdata); + gpio_output(drv->gpio_vco_le); + gpio_output(drv->gpio_synt_rfout_en); + + /* MUX is an input */ + gpio_input(drv->gpio_vco_mux); + + /* set to known state */ + gpio_set(drv->gpio_vco_ce); /* active high */ + gpio_clear(drv->gpio_vco_sclk); + gpio_clear(drv->gpio_vco_sdata); + gpio_set(drv->gpio_vco_le); /* active low */ + gpio_set(drv->gpio_synt_rfout_en); /* active high */ + + max2871_regs_init(); + int i; + for(i = 5; i >= 0; i--) { + max2871_spi_write(drv, i, max2871_get_register(i)); + delay_ms(20); + } + + max2871_set_INT(1); + max2871_set_N(4500); + max2871_set_FRAC(0); + max2871_set_CPL(0); + max2871_set_CPT(0); + max2871_set_P(1); + max2871_set_M(0); + max2871_set_LDS(0); + max2871_set_SDN(0); + max2871_set_MUX(0x0C); /* Register 6 readback */ + max2871_set_DBR(0); + max2871_set_RDIV2(0); + max2871_set_R(1); /* 40 MHz f_PFD */ + max2871_set_REG4DB(1); + max2871_set_CP(15); /* ?: CP charge pump current 0-15 */ + max2871_set_LDF(1); /* INT-N */ + max2871_set_LDP(0); /* ?: Lock-Detect Precision */ + max2871_set_PDP(1); + max2871_set_SHDN(0); + max2871_set_TRI(0); + max2871_set_RST(0); + max2871_set_VCO(0); + max2871_set_VAS_SHDN(0); + max2871_set_VAS_TEMP(1); + max2871_set_CSM(0); + max2871_set_MUTEDEL(1); + max2871_set_CDM(0); + max2871_set_CDIV(0); + max2871_set_SDLDO(0); + max2871_set_SDDIV(0); + max2871_set_SDREF(0); + max2871_set_BS(20*40); /* For 40 MHz f_PFD */ + max2871_set_FB(1); /* Do not put DIVA into the feedback loop */ + max2871_set_DIVA(0); + max2871_set_SDVCO(0); + max2871_set_MTLD(1); + max2871_set_BDIV(0); + max2871_set_RFB_EN(0); + max2871_set_BPWR(0); + max2871_set_RFA_EN(0); + max2871_set_APWR(3); + max2871_set_SDPLL(0); + max2871_set_F01(1); + max2871_set_LD(1); + max2871_set_ADCS(0); + max2871_set_ADCM(0); + + max2871_write_registers(drv); + + max2871_set_frequency(drv, 3500); +} + +static void delay_ms(int ms) +{ + uint32_t i; + while(ms--) { + for (i = 0; i < 20000; i++) { + __asm__("nop"); + } + } +} + + +static void serial_delay(void) +{ + uint32_t i; + + for (i = 0; i < 2; i++) + __asm__("nop"); +} + + +/* SPI register write + * + * Send 32 bits: + * First 29 bits are data + * Last 3 bits are register number */ +static void max2871_spi_write(max2871_driver_t* const drv, uint8_t r, uint32_t v) { +#if DEBUG + LOG("0x%04x -> reg%d\n", v, r); +#else + + uint32_t bits = 32; + uint32_t msb = 1 << (bits -1); + uint32_t data = v | r; + + /* make sure everything is starting in the correct state */ + gpio_set(drv->gpio_vco_le); + gpio_clear(drv->gpio_vco_sclk); + gpio_clear(drv->gpio_vco_sdata); + + /* start transaction by bringing LE low */ + gpio_clear(drv->gpio_vco_le); + + while (bits--) { + if (data & msb) + gpio_set(drv->gpio_vco_sdata); + else + gpio_clear(drv->gpio_vco_sdata); + data <<= 1; + + serial_delay(); + gpio_set(drv->gpio_vco_sclk); + + serial_delay(); + gpio_clear(drv->gpio_vco_sclk); + } + + gpio_set(drv->gpio_vco_le); +#endif +} + +static uint32_t max2871_spi_read(max2871_driver_t* const drv) +{ + uint32_t bits = 32; + uint32_t data = 0; + + max2871_spi_write(drv, 0x06, 0x0); + + serial_delay(); + gpio_set(drv->gpio_vco_sclk); + serial_delay(); + gpio_clear(drv->gpio_vco_sclk); + serial_delay(); + + while (bits--) { + gpio_set(drv->gpio_vco_sclk); + serial_delay(); + + gpio_clear(drv->gpio_vco_sclk); + serial_delay(); + + data <<= 1; + data |= gpio_read(drv->gpio_vco_mux) ? 1 : 0; + } + return data; +} + +static void max2871_write_registers(max2871_driver_t* const drv) +{ + int i; + for(i = 5; i >= 0; i--) { + max2871_spi_write(drv, i, max2871_get_register(i)); + } +} + +/* Set frequency (MHz). */ +uint64_t max2871_set_frequency(max2871_driver_t* const drv, uint16_t mhz) +{ + int n = mhz / 40; + int diva = 0; + + while(n * 40 < 3000) { + n *= 2; + diva += 1; + } + + max2871_set_RFA_EN(0); + max2871_write_registers(drv); + + max2871_set_N(n); + max2871_set_DIVA(diva); + max2871_write_registers(drv); + + while(max2871_spi_read(drv) & MAX2871_VASA); + + max2871_set_RFA_EN(1); + max2871_write_registers(drv); + + return (mhz/40)*40 * 1000000; +} + +void max2871_enable(max2871_driver_t* const drv) +{ + gpio_set(drv->gpio_vco_ce); +} +void max2871_disable(max2871_driver_t* const drv) +{ + gpio_clear(drv->gpio_vco_ce); +} + diff --git a/firmware/common/max2871.h b/firmware/common/max2871.h new file mode 100644 index 00000000..f84f5309 --- /dev/null +++ b/firmware/common/max2871.h @@ -0,0 +1,21 @@ +#ifndef MAX2871_H +#define MAX2871_H + +#include "gpio.h" + +#include + +typedef struct { + gpio_t gpio_vco_ce; + gpio_t gpio_vco_sclk; + gpio_t gpio_vco_sdata; + gpio_t gpio_vco_le; + gpio_t gpio_synt_rfout_en; + gpio_t gpio_vco_mux; +} max2871_driver_t; + +extern void max2871_setup(max2871_driver_t* const drv); +extern uint64_t max2871_set_frequency(max2871_driver_t* const drv, uint16_t mhz); +extern void max2871_enable(max2871_driver_t* const drv); +extern void max2871_disable(max2871_driver_t* const drv); +#endif diff --git a/firmware/common/max2871_regs.c b/firmware/common/max2871_regs.c new file mode 100644 index 00000000..aec781d1 --- /dev/null +++ b/firmware/common/max2871_regs.c @@ -0,0 +1,299 @@ +#include "max2871_regs.h" +#include + +static uint32_t registers[6]; + +void max2871_regs_init(void) +{ + registers[0] = 0x007D0000; + registers[1] = 0x2000FFF9; + registers[2] = 0x00004042; + registers[3] = 0x0000000B; + registers[4] = 0x6180B23C; + registers[5] = 0x00400005; +} + +uint32_t max2871_get_register(int reg) +{ + return registers[reg]; +} + +void max2871_set_INT(uint32_t v) +{ + registers[0] &= ~(0x1 << 31); + registers[0] |= v << 31; +} + +void max2871_set_N(uint32_t v) +{ + registers[0] &= ~(0xFFFF << 15); + registers[0] |= v << 15; +} + +void max2871_set_FRAC(uint32_t v) +{ + registers[0] &= ~(0xFFF << 3); + registers[0] |= v << 3; +} + +void max2871_set_CPL(uint32_t v) +{ + registers[1] &= ~(0x3 << 29); + registers[1] |= v << 29; +} + +void max2871_set_CPT(uint32_t v) +{ + registers[1] &= ~(0x3 << 27); + registers[1] |= v << 27; +} + +void max2871_set_P(uint32_t v) +{ + registers[1] &= ~(0xFFF << 15); + registers[1] |= v << 15; +} + +void max2871_set_M(uint32_t v) +{ + registers[1] &= ~(0xFFF << 3); + registers[1] |= v << 3; +} + +void max2871_set_LDS(uint32_t v) +{ + registers[2] &= ~(0x1 << 31); + registers[2] |= v << 31; +} + +void max2871_set_SDN(uint32_t v) +{ + registers[2] &= ~(0x3 << 29); + registers[2] |= v << 29; +} + +void max2871_set_MUX(uint32_t v) +{ + registers[2] &= ~(0x7 << 26); + registers[5] &= ~(0x1 << 18); + registers[2] |= (v & 0x7) << 26; + registers[5] |= ((v & 0x8) >> 3) << 18; +} + +void max2871_set_DBR(uint32_t v) +{ + registers[2] &= ~(0x1 << 25); + registers[2] |= v << 25; +} + +void max2871_set_RDIV2(uint32_t v) +{ + registers[2] &= ~(0x1 << 24); + registers[2] |= v << 24; +} + +void max2871_set_R(uint32_t v) +{ + registers[2] &= ~(0x3FF << 14); + registers[2] |= v << 14; +} + +void max2871_set_REG4DB(uint32_t v) +{ + registers[2] &= ~(0x1 << 13); + registers[2] |= v << 13; +} + +void max2871_set_CP(uint32_t v) +{ + registers[2] &= ~(0xF << 9); + registers[2] |= v << 9; +} + +void max2871_set_LDF(uint32_t v) +{ + registers[2] &= ~(0x1 << 8); + registers[2] |= v << 8; +} + +void max2871_set_LDP(uint32_t v) +{ + registers[2] &= ~(0x1 << 7); + registers[2] |= v << 7; +} + +void max2871_set_PDP(uint32_t v) +{ + registers[2] &= ~(0x1 << 6); + registers[2] |= v << 6; +} + +void max2871_set_SHDN(uint32_t v) +{ + registers[2] &= ~(0x1 << 5); + registers[2] |= v << 5; +} + +void max2871_set_TRI(uint32_t v) +{ + registers[2] &= ~(0x1 << 4); + registers[2] |= v << 4; +} + +void max2871_set_RST(uint32_t v) +{ + registers[2] &= ~(0x1 << 3); + registers[2] |= v << 3; +} + +void max2871_set_VCO(uint32_t v) +{ + registers[3] &= ~(0x3F << 26); + registers[3] |= v << 26; +} + +void max2871_set_VAS_SHDN(uint32_t v) +{ + registers[3] &= ~(0x1 << 25); + registers[3] |= v << 25; +} + +void max2871_set_VAS_TEMP(uint32_t v) +{ + registers[3] &= ~(0x1 << 24); + registers[3] |= v << 24; +} + +void max2871_set_CSM(uint32_t v) +{ + registers[3] &= ~(0x1 << 18); + registers[3] |= v << 18; +} + +void max2871_set_MUTEDEL(uint32_t v) +{ + registers[3] &= ~(0x1 << 17); + registers[3] |= v << 17; +} + +void max2871_set_CDM(uint32_t v) +{ + registers[3] &= ~(0x3 << 15); + registers[3] |= v << 15; +} + +void max2871_set_CDIV(uint32_t v) +{ + registers[3] &= ~(0xFFF << 3); + registers[3] |= v << 3; +} + +void max2871_set_SDLDO(uint32_t v) +{ + registers[4] &= ~(0x1 << 28); + registers[4] |= v << 28; +} + +void max2871_set_SDDIV(uint32_t v) +{ + registers[4] &= ~(0x1 << 27); + registers[4] |= v << 27; +} + +void max2871_set_SDREF(uint32_t v) +{ + registers[4] &= ~(0x1 << 26); + registers[4] |= v << 26; +} + +void max2871_set_BS(uint32_t v) +{ + registers[4] &= ~(0x3 << 24); + registers[4] &= ~(0xFF << 12); + registers[4] |= ((v & 0x300) >> 8) << 24; + registers[4] |= (v & 0xFF) << 12; +} + +void max2871_set_FB(uint32_t v) +{ + registers[4] &= ~(0x1 << 23); + registers[4] |= v << 23; +} + +void max2871_set_DIVA(uint32_t v) +{ + registers[4] &= ~(0x7 << 20); + registers[4] |= v << 20; +} + +void max2871_set_SDVCO(uint32_t v) +{ + registers[4] &= ~(0x1 << 11); + registers[4] |= v << 11; +} + +void max2871_set_MTLD(uint32_t v) +{ + registers[4] &= ~(0x1 << 10); + registers[4] |= v << 10; +} + +void max2871_set_BDIV(uint32_t v) +{ + registers[4] &= ~(0x1 << 9); + registers[4] |= v << 9; +} + +void max2871_set_RFB_EN(uint32_t v) +{ + registers[4] &= ~(0x1 << 8); + registers[4] |= v << 8; +} + +void max2871_set_BPWR(uint32_t v) +{ + registers[4] &= ~(0x3 << 6); + registers[4] |= v << 6; +} + +void max2871_set_RFA_EN(uint32_t v) +{ + registers[4] &= ~(0x1 << 5); + registers[4] |= v << 5; +} + +void max2871_set_APWR(uint32_t v) +{ + registers[4] &= ~(0x3 << 3); + registers[4] |= v << 3; +} + +void max2871_set_SDPLL(uint32_t v) +{ + registers[5] &= ~(0x1 << 25); + registers[5] |= v << 25; +} + +void max2871_set_F01(uint32_t v) +{ + registers[5] &= ~(0x1 << 24); + registers[5] |= v << 24; +} + +void max2871_set_LD(uint32_t v) +{ + registers[5] &= ~(0x3 << 22); + registers[5] |= v << 22; +} + +void max2871_set_ADCS(uint32_t v) +{ + registers[5] &= ~(0x1 << 6); + registers[5] |= v << 6; +} + +void max2871_set_ADCM(uint32_t v) +{ + registers[5] &= ~(0x7 << 3); + registers[5] |= v << 3; +} diff --git a/firmware/common/max2871_regs.h b/firmware/common/max2871_regs.h new file mode 100644 index 00000000..5acd11c4 --- /dev/null +++ b/firmware/common/max2871_regs.h @@ -0,0 +1,56 @@ +#ifndef MAX2871_REGS_H +#define MAX2871_REGS_H +#include + +#define MAX2871_VASA (1 << 9) + +void max2871_regs_init(void); +uint32_t max2871_get_register(int reg); + +void max2871_set_INT(uint32_t v); +void max2871_set_N(uint32_t v); +void max2871_set_FRAC(uint32_t v); +void max2871_set_CPL(uint32_t v); +void max2871_set_CPT(uint32_t v); +void max2871_set_P(uint32_t v); +void max2871_set_M(uint32_t v); +void max2871_set_LDS(uint32_t v); +void max2871_set_SDN(uint32_t v); +void max2871_set_MUX(uint32_t v); +void max2871_set_DBR(uint32_t v); +void max2871_set_RDIV2(uint32_t v); +void max2871_set_R(uint32_t v); +void max2871_set_REG4DB(uint32_t v); +void max2871_set_CP(uint32_t v); +void max2871_set_LDF(uint32_t v); +void max2871_set_LDP(uint32_t v); +void max2871_set_PDP(uint32_t v); +void max2871_set_SHDN(uint32_t v); +void max2871_set_TRI(uint32_t v); +void max2871_set_RST(uint32_t v); +void max2871_set_VCO(uint32_t v); +void max2871_set_VAS_SHDN(uint32_t v); +void max2871_set_VAS_TEMP(uint32_t v); +void max2871_set_CSM(uint32_t v); +void max2871_set_MUTEDEL(uint32_t v); +void max2871_set_CDM(uint32_t v); +void max2871_set_CDIV(uint32_t v); +void max2871_set_SDLDO(uint32_t v); +void max2871_set_SDDIV(uint32_t v); +void max2871_set_SDREF(uint32_t v); +void max2871_set_BS(uint32_t v); +void max2871_set_FB(uint32_t v); +void max2871_set_DIVA(uint32_t v); +void max2871_set_SDVCO(uint32_t v); +void max2871_set_MTLD(uint32_t v); +void max2871_set_BDIV(uint32_t v); +void max2871_set_RFB_EN(uint32_t v); +void max2871_set_BPWR(uint32_t v); +void max2871_set_RFA_EN(uint32_t v); +void max2871_set_APWR(uint32_t v); +void max2871_set_SDPLL(uint32_t v); +void max2871_set_F01(uint32_t v); +void max2871_set_LD(uint32_t v); +void max2871_set_ADCS(uint32_t v); +void max2871_set_ADCM(uint32_t v); +#endif diff --git a/firmware/common/mixer.c b/firmware/common/mixer.c new file mode 100644 index 00000000..93467327 --- /dev/null +++ b/firmware/common/mixer.c @@ -0,0 +1,144 @@ +#include "mixer.h" +#include "rffc5071.h" +#include "rffc5071_spi.h" +#include "max2871.h" +#include "gpio_lpc.h" + +/* RFFC5071 GPIO serial interface PinMux */ +#if (defined JAWBREAKER || defined HACKRF_ONE) +static struct gpio_t gpio_rffc5072_select = GPIO(2, 13); +static struct gpio_t gpio_rffc5072_clock = GPIO(5, 6); +static struct gpio_t gpio_rffc5072_data = GPIO(3, 3); +static struct gpio_t gpio_rffc5072_reset = GPIO(2, 14); +#endif +#ifdef RAD1O +static struct gpio_t gpio_vco_ce = GPIO(2, 13); +static struct gpio_t gpio_vco_sclk = GPIO(5, 6); +static struct gpio_t gpio_vco_sdata = GPIO(3, 3); +static struct gpio_t gpio_vco_le = GPIO(2, 14); +static struct gpio_t gpio_vco_mux = GPIO(5, 25); +static struct gpio_t gpio_synt_rfout_en = GPIO(3, 5); +#endif + +#if (defined JAWBREAKER || defined HACKRF_ONE) +const rffc5071_spi_config_t rffc5071_spi_config = { + .gpio_select = &gpio_rffc5072_select, + .gpio_clock = &gpio_rffc5072_clock, + .gpio_data = &gpio_rffc5072_data, +}; + +spi_bus_t spi_bus_rffc5071 = { + .config = &rffc5071_spi_config, + .start = rffc5071_spi_start, + .stop = rffc5071_spi_stop, + .transfer = rffc5071_spi_transfer, + .transfer_gather = rffc5071_spi_transfer_gather, +}; + +mixer_driver_t mixer = { + .bus = &spi_bus_rffc5071, + .gpio_reset = &gpio_rffc5072_reset, +}; +#endif +#ifdef RAD1O +mixer_driver_t mixer = { + .gpio_vco_ce = &gpio_vco_ce, + .gpio_vco_sclk = &gpio_vco_sclk, + .gpio_vco_sdata = &gpio_vco_sdata, + .gpio_vco_le = &gpio_vco_le, + .gpio_synt_rfout_en = &gpio_synt_rfout_en, + .gpio_vco_mux = &gpio_vco_mux, +}; +#endif + +void mixer_bus_setup(mixer_driver_t* const mixer) +{ +#if (defined JAWBREAKER || defined HACKRF_ONE) + (void) mixer; + spi_bus_start(&spi_bus_rffc5071, &rffc5071_spi_config); +#endif +#ifdef RAD1O + (void) mixer; +#endif +} + +void mixer_setup(mixer_driver_t* const mixer) +{ +#if (defined JAWBREAKER || defined HACKRF_ONE) + rffc5071_setup(mixer); +#endif +#ifdef RAD1O + max2871_setup(mixer); +#endif +} + +uint64_t mixer_set_frequency(mixer_driver_t* const mixer, uint16_t mhz) +{ +#if (defined JAWBREAKER || defined HACKRF_ONE) + return rffc5071_set_frequency(mixer, mhz); +#endif +#ifdef RAD1O + return max2871_set_frequency(mixer, mhz); +#endif +} + +void mixer_tx(mixer_driver_t* const mixer) +{ +#if (defined JAWBREAKER || defined HACKRF_ONE) + rffc5071_tx(mixer); +#endif +#ifdef RAD1O + (void) mixer; +#endif +} + +void mixer_rx(mixer_driver_t* const mixer) +{ +#if (defined JAWBREAKER || defined HACKRF_ONE) + rffc5071_rx(mixer); +#endif +#ifdef RAD1O + (void) mixer; +#endif +} + +void mixer_rxtx(mixer_driver_t* const mixer) +{ +#if (defined JAWBREAKER || defined HACKRF_ONE) + rffc5071_rxtx(mixer); +#endif +#ifdef RAD1O + (void) mixer; +#endif +} + +void mixer_enable(mixer_driver_t* const mixer) +{ +#if (defined JAWBREAKER || defined HACKRF_ONE) + rffc5071_enable(mixer); +#endif +#ifdef RAD1O + (void) mixer; +#endif +} + +void mixer_disable(mixer_driver_t* const mixer) +{ +#if (defined JAWBREAKER || defined HACKRF_ONE) + rffc5071_disable(mixer); +#endif +#ifdef RAD1O + (void) mixer; +#endif +} + +void mixer_set_gpo(mixer_driver_t* const mixer, uint8_t gpo) +{ +#if (defined JAWBREAKER || defined HACKRF_ONE) + rffc5071_set_gpo(mixer, gpo); +#endif +#ifdef RAD1O + (void) mixer; + (void) gpo; +#endif +} diff --git a/firmware/common/mixer.h b/firmware/common/mixer.h new file mode 100644 index 00000000..cf46e7c5 --- /dev/null +++ b/firmware/common/mixer.h @@ -0,0 +1,52 @@ +/* + * Copyright 2012 Michael Ossmann + * 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 __MIXER_H +#define __MIXER_H + +#if (defined JAWBREAKER || defined HACKRF_ONE) +#include "rffc5071.h" +typedef rffc5071_driver_t mixer_driver_t; +#endif + +#ifdef RAD1O +#include "max2871.h" +typedef max2871_driver_t mixer_driver_t; +#endif + +#include +extern void mixer_bus_setup(mixer_driver_t* const mixer); +extern void mixer_setup(mixer_driver_t* const mixer); + +/* Set frequency (MHz). */ +extern uint64_t mixer_set_frequency(mixer_driver_t* const mixer, uint16_t mhz); + +/* Set up rx only, tx only, or full duplex. Chip should be disabled + * before _tx, _rx, or _rxtx are called. */ +extern void mixer_tx(mixer_driver_t* const mixer); +extern void mixer_rx(mixer_driver_t* const mixer); +extern void mixer_rxtx(mixer_driver_t* const mixer); +extern void mixer_enable(mixer_driver_t* const mixer); +extern void mixer_disable(mixer_driver_t* const mixer); +extern void mixer_set_gpo(mixer_driver_t* const drv, uint8_t gpo); + +#endif // __MIXER_H diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index 78860936..05a627bd 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -26,12 +26,14 @@ #include -#include +#include "hackrf-ui.h" + +#include #include #include #include -#if (defined JAWBREAKER || defined HACKRF_ONE) +#if (defined JAWBREAKER || defined HACKRF_ONE || defined RAD1O) /* * RF switches on Jawbreaker are controlled by General Purpose Outputs (GPO) on * the RFFC5072. @@ -40,6 +42,9 @@ * SWITCHCTRL_NO_TX_AMP_PWR and SWITCHCTRL_NO_RX_AMP_PWR are not normally used * on HackRF One as the amplifier power is instead controlled only by * SWITCHCTRL_AMP_BYPASS. + * + * The rad1o also uses GPIO pins to control the different switches. The amplifiers + * are also connected to the LPC. */ #define SWITCHCTRL_NO_TX_AMP_PWR (1 << 0) /* GPO1 turn off TX amp power */ #define SWITCHCTRL_AMP_BYPASS (1 << 1) /* GPO2 bypass amp section */ @@ -148,9 +153,73 @@ 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) { - rffc5071_set_gpo(&rffc5072, 0x00); /* turn on antenna power by clearing GPO1 */ + mixer_set_gpo(&mixer, 0x00); /* turn on antenna power by clearing GPO1 */ } else { - rffc5071_set_gpo(&rffc5072, 0x01); /* turn off antenna power by setting GPO1 */ + mixer_set_gpo(&mixer, 0x01); /* turn off antenna power by setting GPO1 */ + } +} +#endif + +#ifdef RAD1O +static void switchctrl_set_rad1o(rf_path_t* const rf_path, uint8_t ctrl) { + if (ctrl & SWITCHCTRL_TX) { + gpio_set(rf_path->gpio_tx_rx_n); + gpio_clear(rf_path->gpio_tx_rx); + } else { + gpio_clear(rf_path->gpio_tx_rx_n); + gpio_set(rf_path->gpio_tx_rx); + } + + if (ctrl & SWITCHCTRL_MIX_BYPASS) { + gpio_clear(rf_path->gpio_by_mix); + gpio_set(rf_path->gpio_by_mix_n); + gpio_clear(rf_path->gpio_mixer_en); + } else { + gpio_set(rf_path->gpio_by_mix); + gpio_clear(rf_path->gpio_by_mix_n); + gpio_set(rf_path->gpio_mixer_en); + } + + if (ctrl & SWITCHCTRL_HP) { + gpio_set(rf_path->gpio_low_high_filt); + gpio_clear(rf_path->gpio_low_high_filt_n); + } else { + gpio_clear(rf_path->gpio_low_high_filt); + gpio_set(rf_path->gpio_low_high_filt_n); + } + + if (ctrl & SWITCHCTRL_AMP_BYPASS) { + gpio_clear(rf_path->gpio_by_amp); + gpio_set(rf_path->gpio_by_amp_n); + + gpio_clear(rf_path->gpio_tx_amp); + gpio_clear(rf_path->gpio_rx_lna); + + } else if (ctrl & SWITCHCTRL_TX) { + gpio_set(rf_path->gpio_by_amp); + gpio_clear(rf_path->gpio_by_amp_n); + + gpio_set(rf_path->gpio_tx_amp); + gpio_clear(rf_path->gpio_rx_lna); + + } else { + gpio_set(rf_path->gpio_by_amp); + gpio_clear(rf_path->gpio_by_amp_n); + + gpio_clear(rf_path->gpio_tx_amp); + gpio_set(rf_path->gpio_rx_lna); + } + + /* + * These normally shouldn't be set post-Jawbreaker, but they can be + * used to explicitly turn off power to the amplifiers while AMP_BYPASS + * is unset: + */ + if (ctrl & SWITCHCTRL_NO_TX_AMP_PWR) { + gpio_clear(rf_path->gpio_tx_amp); + } + if (ctrl & SWITCHCTRL_NO_RX_AMP_PWR) { + gpio_clear(rf_path->gpio_rx_lna); } } #endif @@ -158,9 +227,11 @@ static void switchctrl_set_hackrf_one(rf_path_t* const rf_path, uint8_t ctrl) { static void switchctrl_set(rf_path_t* const rf_path, const uint8_t gpo) { #ifdef JAWBREAKER (void) rf_path; /* silence unused param warning */ - rffc5071_set_gpo(&rffc5072, gpo); + mixer_set_gpo(&mixer, gpo); #elif HACKRF_ONE switchctrl_set_hackrf_one(rf_path, gpo); +#elif RAD1O + switchctrl_set_rad1o(rf_path, gpo); #else (void)gpo; #endif @@ -201,6 +272,41 @@ void rf_path_pin_setup(rf_path_t* const rf_path) { gpio_output(rf_path->gpio_mix_bypass); gpio_output(rf_path->gpio_rx); + /* + * Safe (initial) switch settings turn off both amplifiers and antenna port + * power and enable both amp bypass and mixer bypass. + */ + switchctrl_set(rf_path, SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_MIX_BYPASS); +#elif RAD1O + /* Configure RF switch control signals */ + scu_pinmux(SCU_BY_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_BY_AMP_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + scu_pinmux(SCU_TX_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_TX_RX_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_BY_MIX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_BY_MIX_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_LOW_HIGH_FILT, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_LOW_HIGH_FILT_N,SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_TX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_RX_LNA, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + scu_pinmux(SCU_MIXER_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); + + /* Configure RF power supply (VAA) switch */ + scu_pinmux(SCU_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + + /* Configure RF switch control signals as outputs */ + gpio_output(rf_path->gpio_tx_rx_n); + gpio_output(rf_path->gpio_tx_rx); + gpio_output(rf_path->gpio_by_mix); + gpio_output(rf_path->gpio_by_mix_n); + gpio_output(rf_path->gpio_by_amp); + gpio_output(rf_path->gpio_by_amp_n); + gpio_output(rf_path->gpio_mixer_en); + gpio_output(rf_path->gpio_low_high_filt); + gpio_output(rf_path->gpio_low_high_filt_n); + gpio_output(rf_path->gpio_tx_amp); + gpio_output(rf_path->gpio_rx_lna); + /* * Safe (initial) switch settings turn off both amplifiers and antenna port * power and enable both amp bypass and mixer bypass. @@ -220,7 +326,7 @@ void rf_path_init(rf_path_t* const rf_path) { max2837_setup(&max2837); max2837_start(&max2837); - rffc5071_setup(&rffc5072); + mixer_setup(&mixer); switchctrl_set(rf_path, switchctrl); } @@ -234,11 +340,11 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d /* TX amplifier is in path, be sure to enable TX amplifier. */ rf_path->switchctrl &= ~SWITCHCTRL_NO_TX_AMP_PWR; } - rffc5071_tx(&rffc5072); + mixer_tx(&mixer); if( rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS ) { - rffc5071_disable(&rffc5072); + mixer_disable(&mixer); } else { - rffc5071_enable(&rffc5072); + mixer_enable(&mixer); } ssp1_set_mode_max5864(); max5864_tx(&max5864); @@ -253,11 +359,11 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d /* RX amplifier is in path, be sure to enable RX amplifier. */ rf_path->switchctrl &= ~SWITCHCTRL_NO_RX_AMP_PWR; } - rffc5071_rx(&rffc5072); + mixer_rx(&mixer); if( rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS ) { - rffc5071_disable(&rffc5072); + mixer_disable(&mixer); } else { - rffc5071_enable(&rffc5072); + mixer_enable(&mixer); } ssp1_set_mode_max5864(); max5864_rx(&max5864); @@ -274,7 +380,7 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d rf_path_set_lna(rf_path, 0); /* Set RF path to receive direction when "off" */ rf_path->switchctrl &= ~SWITCHCTRL_TX; - rffc5071_disable(&rffc5072); + mixer_disable(&mixer); ssp1_set_mode_max5864(); max5864_standby(&max5864); ssp1_set_mode_max2837(); @@ -284,6 +390,8 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d } switchctrl_set(rf_path, rf_path->switchctrl); + + hackrf_ui_setDirection(direction); } void rf_path_set_filter(rf_path_t* const rf_path, const rf_path_filter_t filter) { @@ -291,18 +399,18 @@ void rf_path_set_filter(rf_path_t* const rf_path, const rf_path_filter_t filter) default: case RF_PATH_FILTER_BYPASS: rf_path->switchctrl |= SWITCHCTRL_MIX_BYPASS; - rffc5071_disable(&rffc5072); + mixer_disable(&mixer); break; case RF_PATH_FILTER_LOW_PASS: rf_path->switchctrl &= ~(SWITCHCTRL_HP | SWITCHCTRL_MIX_BYPASS); - rffc5071_enable(&rffc5072); + mixer_enable(&mixer); break; case RF_PATH_FILTER_HIGH_PASS: rf_path->switchctrl &= ~SWITCHCTRL_MIX_BYPASS; rf_path->switchctrl |= SWITCHCTRL_HP; - rffc5071_enable(&rffc5072); + mixer_enable(&mixer); break; } @@ -326,6 +434,8 @@ void rf_path_set_lna(rf_path_t* const rf_path, const uint_fast8_t enable) { } switchctrl_set(rf_path, rf_path->switchctrl); + + hackrf_ui_setLNAPower(enable); } /* antenna port power control */ diff --git a/firmware/common/rf_path.h b/firmware/common/rf_path.h index 205d3fdd..e12a8c10 100644 --- a/firmware/common/rf_path.h +++ b/firmware/common/rf_path.h @@ -56,6 +56,19 @@ typedef struct rf_path_t { gpio_t gpio_rx_amp; gpio_t gpio_no_rx_amp_pwr; #endif +#ifdef RAD1O + gpio_t gpio_tx_rx_n; + gpio_t gpio_tx_rx; + gpio_t gpio_by_mix; + gpio_t gpio_by_mix_n; + gpio_t gpio_by_amp; + gpio_t gpio_by_amp_n; + gpio_t gpio_mixer_en; + gpio_t gpio_low_high_filt; + gpio_t gpio_low_high_filt_n; + gpio_t gpio_tx_amp; + gpio_t gpio_rx_lna; +#endif } rf_path_t; void rf_path_pin_setup(rf_path_t* const rf_path); diff --git a/firmware/common/sgpio.c b/firmware/common/sgpio.c index 075b6eaf..6180ad53 100644 --- a/firmware/common/sgpio.c +++ b/firmware/common/sgpio.c @@ -27,6 +27,10 @@ #include +#ifdef RAD1O +static void update_q_invert(sgpio_config_t* const config); +#endif + void sgpio_configure_pin_functions(sgpio_config_t* const config) { scu_pinmux(SCU_PINMUX_SGPIO0, SCU_GPIO_FAST | SCU_CONF_FUNCTION3); scu_pinmux(SCU_PINMUX_SGPIO1, SCU_GPIO_FAST | SCU_CONF_FUNCTION3); @@ -88,6 +92,12 @@ void sgpio_configure( | (1L << 10) // disable codec data stream during configuration (Output SGPIO10 High) ; +#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 = (direction == SGPIO_DIRECTION_TX) @@ -264,6 +274,48 @@ bool sgpio_cpld_stream_rx_set_decimation(sgpio_config_t* const config, const uin return (skip_n < 8); } +#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. + * + * We use the state of the pin to determine which way we + * have to go. + * + * 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; + +/* Called when TX/RX changes od sgpio_cpld_stream_rx_set_q_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); + } +} + +void sgpio_cpld_stream_rx_set_q_invert(sgpio_config_t* const config, const uint_fast8_t invert) { + if( invert ) { + sgpio_invert = true; + } else { + sgpio_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/si5351c.c b/firmware/common/si5351c.c index 36730930..89932191 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -243,10 +243,42 @@ void si5351c_configure_clock_control(si5351c_driver_t* const drv, const enum pll } #endif -/* Enable CLK outputs 0, 1, 2, 3, 4, 5, 7 only. */ +#ifdef RAD1O +void si5351c_configure_clock_control(si5351c_driver_t* const drv, const enum pll_sources source) +{ + (void) source; + uint8_t pll; + + /* PLLA on XTAL */ + pll = SI5351C_CLK_PLL_SRC_A; + + /* Clock to CPU is deactivated as it is not used and creates noise */ + /* External clock output is deactivated as it is not used and creates noise */ + uint8_t data[] = {16 + ,SI5351C_CLK_FRAC_MODE | SI5351C_CLK_PLL_SRC(pll) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA) + ,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) + ,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) + ,SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE /*not connected, but: plla int mode*/ + ,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_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | 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_POWERDOWN | SI5351C_CLK_INT_MODE /*not connected, but: plla int mode*/ + }; + si5351c_write(drv, data, sizeof(data)); +} +#endif + void si5351c_enable_clock_outputs(si5351c_driver_t* const drv) { +#ifdef RAD1O + /* Enable CLK outputs 0, 1, 2, 4, 5 only. */ + /* 7: Clock to CPU is deactivated as it is not used and creates noise */ + /* 3: External clock output is deactivated as it is not used and creates noise */ + uint8_t data[] = { 3, ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 4) | (1 << 5))}; +#else + /* Enable CLK outputs 0, 1, 2, 3, 4, 5, 7 only. */ uint8_t data[] = { 3, 0x40 }; +#endif si5351c_write(drv, data, sizeof(data)); } diff --git a/firmware/common/tuning.c b/firmware/common/tuning.c index 166f910c..b33b90d3 100644 --- a/firmware/common/tuning.c +++ b/firmware/common/tuning.c @@ -22,8 +22,10 @@ #include "tuning.h" +#include "hackrf-ui.h" + #include -#include +#include #include #include @@ -54,9 +56,9 @@ uint64_t freq_cache = 100000000; bool set_freq(const uint64_t freq) { bool success; - uint32_t RFFC5071_freq_mhz; + uint32_t mixer_freq_mhz; uint32_t MAX2837_freq_hz; - uint64_t real_RFFC5071_freq_hz; + uint64_t real_mixer_freq_hz; const uint32_t freq_mhz = freq / 1000000; const uint32_t freq_hz = freq % 1000000; @@ -68,18 +70,22 @@ bool set_freq(const uint64_t freq) if(freq_mhz < MAX_LP_FREQ_MHZ) { rf_path_set_filter(&rf_path, RF_PATH_FILTER_LOW_PASS); +#ifdef RAD1O + max2837_freq_nominal_hz = 2300000000; +#else /* IF is graduated from 2650 MHz to 2343 MHz */ max2837_freq_nominal_hz = 2650000000 - (freq / 7); - RFFC5071_freq_mhz = (max2837_freq_nominal_hz / FREQ_ONE_MHZ) + freq_mhz; +#endif + mixer_freq_mhz = (max2837_freq_nominal_hz / FREQ_ONE_MHZ) + freq_mhz; /* Set Freq and read real freq */ - real_RFFC5071_freq_hz = rffc5071_set_frequency(&rffc5072, RFFC5071_freq_mhz); - max2837_set_frequency(&max2837, real_RFFC5071_freq_hz - 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); }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; - /* RFFC5071_freq_mhz <= not used in Bypass mode */ + /* 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); }else if( (freq_mhz >= MIN_HP_FREQ_MHZ) && (freq_mhz <= MAX_HP_FREQ_MHZ) ) @@ -95,10 +101,10 @@ bool set_freq(const uint64_t freq) max2837_freq_nominal_hz = 2500000000 + ((freq - 5100000000) / 9); } rf_path_set_filter(&rf_path, RF_PATH_FILTER_HIGH_PASS); - RFFC5071_freq_mhz = freq_mhz - (max2837_freq_nominal_hz / FREQ_ONE_MHZ); + mixer_freq_mhz = freq_mhz - (max2837_freq_nominal_hz / FREQ_ONE_MHZ); /* Set Freq and read real freq */ - real_RFFC5071_freq_hz = rffc5071_set_frequency(&rffc5072, RFFC5071_freq_mhz); - max2837_set_frequency(&max2837, freq - real_RFFC5071_freq_hz); + 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); }else { @@ -108,6 +114,7 @@ bool set_freq(const uint64_t freq) max2837_set_mode(&max2837, prior_max2837_mode); if( success ) { freq_cache = freq; + hackrf_ui_setFrequency(freq); } return success; } @@ -137,7 +144,7 @@ bool set_freq_explicit(const uint64_t if_freq_hz, const uint64_t lo_freq_hz, sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0); } if (path != RF_PATH_FILTER_BYPASS) { - (void)rffc5071_set_frequency(&rffc5072, lo_freq_hz / FREQ_ONE_MHZ); + (void)mixer_set_frequency(&mixer, lo_freq_hz / FREQ_ONE_MHZ); } return true; } diff --git a/firmware/common/usb.c b/firmware/common/usb.c index f77bc28b..f8e4bd8c 100644 --- a/firmware/common/usb.c +++ b/firmware/common/usb.c @@ -72,7 +72,7 @@ void usb_peripheral_reset() { while( (RESET_ACTIVE_STATUS0 & RESET_CTRL0_USB0_RST) == 0 ); } -static void usb_phy_enable() { +void usb_phy_enable() { CREG_CREG0 &= ~CREG_CREG0_USB0PHY; } diff --git a/firmware/common/usb.h b/firmware/common/usb.h index a6fa6a92..aa21beb2 100644 --- a/firmware/common/usb.h +++ b/firmware/common/usb.h @@ -29,6 +29,7 @@ #include "usb_type.h" void usb_peripheral_reset(); +void usb_phy_enable(); void usb_device_init( const uint_fast8_t device_ordinal, diff --git a/firmware/common/w25q80bv.c b/firmware/common/w25q80bv.c index 999c3d52..73dd0224 100644 --- a/firmware/common/w25q80bv.c +++ b/firmware/common/w25q80bv.c @@ -61,11 +61,10 @@ void w25q80bv_setup(w25q80bv_driver_t* const drv) drv->target_init(drv); - device_id = 0; - while(device_id != W25Q80BV_DEVICE_ID_RES) - { + do { device_id = w25q80bv_get_device_id(drv); - } + } while(device_id != W25Q80BV_DEVICE_ID_RES && + device_id != W25Q16DV_DEVICE_ID_RES); } uint8_t w25q80bv_get_status(w25q80bv_driver_t* const drv) @@ -117,11 +116,10 @@ void w25q80bv_chip_erase(w25q80bv_driver_t* const drv) { uint8_t device_id; - device_id = 0; - while(device_id != W25Q80BV_DEVICE_ID_RES) - { + do { device_id = w25q80bv_get_device_id(drv); - } + } while(device_id != W25Q80BV_DEVICE_ID_RES && + device_id != W25Q16DV_DEVICE_ID_RES); w25q80bv_write_enable(drv); w25q80bv_wait_while_busy(drv); @@ -165,11 +163,10 @@ void w25q80bv_program(w25q80bv_driver_t* const drv, uint32_t addr, uint32_t len, uint16_t first_block_len; uint8_t device_id; - device_id = 0; - while(device_id != W25Q80BV_DEVICE_ID_RES) - { + do { device_id = w25q80bv_get_device_id(drv); - } + } while(device_id != W25Q80BV_DEVICE_ID_RES && + device_id != W25Q16DV_DEVICE_ID_RES); /* do nothing if we would overflow the flash */ if ((len > drv->num_bytes) || (addr > drv->num_bytes) diff --git a/firmware/common/w25q80bv.h b/firmware/common/w25q80bv.h index 9d244c4d..494332a1 100644 --- a/firmware/common/w25q80bv.h +++ b/firmware/common/w25q80bv.h @@ -27,6 +27,8 @@ #include #include +#define W25Q80BV_DEVICE_ID_RES 0x13 /* Expected device_id for W25Q80BV */ +#define W25Q16DV_DEVICE_ID_RES 0x14 /* Expected device_id for W25Q16DV */ #include "spi_bus.h" #include "gpio.h" diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index a5a9f06a..177da4d3 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -104,10 +104,9 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/max2837_target.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864_target.c - ${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071.c + ${PATH_HACKRF_FIRMWARE_COMMON}/mixer.c ${PATH_HACKRF_FIRMWARE_COMMON}/i2c_bus.c ${PATH_HACKRF_FIRMWARE_COMMON}/i2c_lpc.c - ${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071_spi.c ${PATH_HACKRF_FIRMWARE_COMMON}/w25q80bv.c ${PATH_HACKRF_FIRMWARE_COMMON}/w25q80bv_target.c ${PATH_HACKRF_FIRMWARE_COMMON}/spi_bus.c @@ -115,6 +114,20 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/gpio_lpc.c ) + if(BOARD STREQUAL "RAD1O") + SET(SRC_M4 + ${SRC_M4} + ${PATH_HACKRF_FIRMWARE_COMMON}/max2871.c + ${PATH_HACKRF_FIRMWARE_COMMON}/max2871_regs.c + ) + else() + SET(SRC_M4 + ${SRC_M4} + ${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071.c + ${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071_spi.c + ) + endif() + configure_file( ${PATH_HACKRF_FIRMWARE_COMMON}/m0_bin.s.cmake m0_bin.s diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 2e7cf8f9..51d8a088 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -46,6 +46,8 @@ #include "usb_api_transceiver.h" #include "usb_bulk_buffer.h" +#include "hackrf-ui.h" + static const usb_request_handler_fn vendor_request_handler[] = { NULL, usb_vendor_request_set_transceiver_mode, @@ -55,8 +57,13 @@ static const usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_read_si5351c, usb_vendor_request_set_sample_rate_frac, usb_vendor_request_set_baseband_filter_bandwidth, +#ifdef RAD1O + NULL, // write_rffc5071 not used + NULL, // read_rffc5071 not used +#else usb_vendor_request_write_rffc5071, usb_vendor_request_read_rffc5071, +#endif usb_vendor_request_erase_spiflash, usb_vendor_request_write_spiflash, usb_vendor_request_read_spiflash, @@ -154,8 +161,11 @@ void usb_set_descriptor_by_serial_number(void) int main(void) { pin_setup(); enable_1v8_power(); -#ifdef HACKRF_ONE +#if (defined HACKRF_ONE || defined RAD1O) enable_rf_power(); + + /* Let the voltage stabilize */ + delay(1000000); #endif cpu_clock_init(); @@ -176,6 +186,8 @@ int main(void) { nvic_set_priority(NVIC_USB0_IRQ, 255); + hackrf_ui_init(); + usb_run(&usb_device); rf_path_init(&rf_path); diff --git a/firmware/hackrf_usb/usb_api_register.c b/firmware/hackrf_usb/usb_api_register.c index 373354d9..0fd8bfc2 100644 --- a/firmware/hackrf_usb/usb_api_register.c +++ b/firmware/hackrf_usb/usb_api_register.c @@ -107,6 +107,7 @@ usb_request_status_t usb_vendor_request_read_si5351c( } } +#ifndef RAD1O usb_request_status_t usb_vendor_request_write_rffc5071( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage @@ -115,7 +116,7 @@ usb_request_status_t usb_vendor_request_write_rffc5071( { if( endpoint->setup.index < RFFC5071_NUM_REGS ) { - rffc5071_reg_write(&rffc5072, endpoint->setup.index, endpoint->setup.value); + rffc5071_reg_write(&mixer, endpoint->setup.index, endpoint->setup.value); usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; } @@ -134,7 +135,7 @@ usb_request_status_t usb_vendor_request_read_rffc5071( { if( endpoint->setup.index < RFFC5071_NUM_REGS ) { - value = rffc5071_reg_read(&rffc5072, endpoint->setup.index); + value = rffc5071_reg_read(&mixer, endpoint->setup.index); endpoint->buffer[0] = value & 0xff; endpoint->buffer[1] = value >> 8; usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2, @@ -147,3 +148,4 @@ usb_request_status_t usb_vendor_request_read_rffc5071( return USB_REQUEST_STATUS_OK; } } +#endif diff --git a/firmware/hackrf_usb/usb_api_transceiver.c b/firmware/hackrf_usb/usb_api_transceiver.c index 19178473..4532d28a 100644 --- a/firmware/hackrf_usb/usb_api_transceiver.c +++ b/firmware/hackrf_usb/usb_api_transceiver.c @@ -22,6 +22,7 @@ #include "usb_api_transceiver.h" +#include "hackrf-ui.h" #include #include #include "sgpio_isr.h" @@ -152,6 +153,7 @@ usb_request_status_t usb_vendor_request_set_lna_gain( if( stage == USB_TRANSFER_STAGE_SETUP ) { const uint8_t value = max2837_set_lna_gain(&max2837, endpoint->setup.index); endpoint->buffer[0] = value; + if(value) hackrf_ui_setBBLNAGain(endpoint->setup.index); usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, NULL, NULL); usb_transfer_schedule_ack(endpoint->out); @@ -166,6 +168,7 @@ usb_request_status_t usb_vendor_request_set_vga_gain( if( stage == USB_TRANSFER_STAGE_SETUP ) { const uint8_t value = max2837_set_vga_gain(&max2837, endpoint->setup.index); endpoint->buffer[0] = value; + if(value) hackrf_ui_setBBVGAGain(endpoint->setup.index); usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, NULL, NULL); usb_transfer_schedule_ack(endpoint->out); @@ -180,6 +183,7 @@ usb_request_status_t usb_vendor_request_set_txvga_gain( if( stage == USB_TRANSFER_STAGE_SETUP ) { const uint8_t value = max2837_set_txvga_gain(&max2837, endpoint->setup.index); endpoint->buffer[0] = value; + if(value) hackrf_ui_setBBTXVGAGain(endpoint->setup.index); usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, NULL, NULL); usb_transfer_schedule_ack(endpoint->out); diff --git a/firmware/hackrf_usb/usb_descriptor.c b/firmware/hackrf_usb/usb_descriptor.c index 6f6560b1..f11ce887 100644 --- a/firmware/hackrf_usb/usb_descriptor.c +++ b/firmware/hackrf_usb/usb_descriptor.c @@ -30,6 +30,8 @@ #define USB_PRODUCT_ID (0x6089) #elif JAWBREAKER #define USB_PRODUCT_ID (0x604B) +#elif RAD1O +#define USB_PRODUCT_ID (0xCC15) #else #define USB_PRODUCT_ID (0xFFFF) #endif diff --git a/firmware/mixertx/mixertx.c b/firmware/mixertx/mixertx.c index a6c2024a..fc537c66 100644 --- a/firmware/mixertx/mixertx.c +++ b/firmware/mixertx/mixertx.c @@ -36,7 +36,7 @@ int main(void) ssp1_set_mode_max2837(); max2837_setup(&max2837); - rffc5071_setup(&rffc5072); + mixer_setup(&mixer); led_on(LED2); max2837_set_frequency(&max2837, freq);