h1r9: fix inverted spectrum on TX

Unify and clean up the firmware spectrum inversion handling for all
hardware platforms.
This commit is contained in:
Michael Ossmann
2022-12-06 23:41:34 -05:00
committed by Mike Walters
parent 50a2e9dd56
commit bdb6000bb4
4 changed files with 42 additions and 54 deletions

View File

@ -134,7 +134,7 @@ static struct gpio_t gpio_cpld_pp_tdo = GPIO(1, 8);
/* other CPLD interface GPIO pins */ /* other CPLD interface GPIO pins */
static struct gpio_t gpio_hw_sync_enable = GPIO(5, 12); static struct gpio_t gpio_hw_sync_enable = GPIO(5, 12);
static struct gpio_t gpio_rx_q_invert = GPIO(0, 13); static struct gpio_t gpio_q_invert = GPIO(0, 13);
/* HackRF One r9 */ /* HackRF One r9 */
#ifdef HACKRF_ONE #ifdef HACKRF_ONE
@ -254,7 +254,7 @@ w25q80bv_driver_t spi_flash = {
}; };
sgpio_config_t sgpio_config = { 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, .gpio_hw_sync_enable = &gpio_hw_sync_enable,
.slice_mode_multislice = true, .slice_mode_multislice = true,
}; };

View File

@ -30,9 +30,7 @@
#include "sgpio.h" #include "sgpio.h"
#ifdef RAD1O
static void update_q_invert(sgpio_config_t* const config); static void update_q_invert(sgpio_config_t* const config);
#endif
void sgpio_configure_pin_functions(sgpio_config_t* const config) void sgpio_configure_pin_functions(sgpio_config_t* const config)
{ {
@ -62,10 +60,10 @@ void sgpio_configure_pin_functions(sgpio_config_t* const config)
SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[12] */ SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[12] */
} }
sgpio_cpld_stream_rx_set_q_invert(config, 0); sgpio_cpld_set_mixer_invert(config, 0);
hw_sync_enable(0); hw_sync_enable(0);
gpio_output(config->gpio_rx_q_invert); gpio_output(config->gpio_q_invert);
gpio_output(config->gpio_hw_sync_enable); gpio_output(config->gpio_hw_sync_enable);
} }
@ -122,11 +120,9 @@ void sgpio_configure(sgpio_config_t* const config, const sgpio_direction_t direc
; ;
// clang-format on // clang-format on
#ifdef RAD1O
/* The data direction might have changed. Check if we need to /* The data direction might have changed. Check if we need to
* adjust the q inversion. */ * adjust the q inversion. */
update_q_invert(config); update_q_invert(config);
#endif
// Enable SGPIO pin outputs. // Enable SGPIO pin outputs.
const uint_fast16_t sgpio_gpio_data_direction = const uint_fast16_t sgpio_gpio_data_direction =
@ -294,60 +290,52 @@ bool sgpio_cpld_stream_is_enabled(sgpio_config_t* const config)
return (SGPIO_GPIO_OUTREG & (1L << 10)) == 0; /* SGPIO10 */ return (SGPIO_GPIO_OUTREG & (1L << 10)) == 0; /* SGPIO10 */
} }
#ifdef RAD1O /*
/* The rad1o hardware has a bug which makes it * The spectrum can be inverted by the analog section of the hardware in two
* necessary to also switch between the two options based * different ways:
* on TX or RX mode.
* *
* We use the state of the pin to determine which way we * - The front-end mixer can introduce an inversion depending on the frequency
* have to go. * tuning configuration.
* *
* As TX/RX can change without sgpio_cpld_stream_rx_set_q_invert * - Routing of the analog baseband signals can introduce an inversion
* being called, we store a local copy of its parameter. */ * depending on the design of the hardware platform and whether we are in RX
static bool sgpio_invert = false; * 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 /* Called when TX/RX changes or sgpio_cpld_set_mixer_invert() gets called. */
* gets called. */
static void update_q_invert(sgpio_config_t* const config) static void update_q_invert(sgpio_config_t* const config)
{ {
/* 1=Output SGPIO11 High(TX mode), 0=Output SGPIO11 Low(RX mode) */ /* 1=Output SGPIO11 High(TX mode), 0=Output SGPIO11 Low(RX mode) */
bool tx_mode = (SGPIO_GPIO_OUTREG & (1 << 11)) > 0; bool tx_mode = (SGPIO_GPIO_OUTREG & (1 << 11)) > 0;
/* 0.13: P1_18 */ /*
if (!sgpio_invert & !tx_mode) { * This switch will need to change if we modify the CPLD to handle
gpio_write(config->gpio_rx_q_invert, 1); * inversion the same way for RX and TX.
} else if (!sgpio_invert & tx_mode) { */
gpio_write(config->gpio_rx_q_invert, 0); bool baseband_invert = false;
} else if (sgpio_invert & !tx_mode) { switch (detected_platform()) {
gpio_write(config->gpio_rx_q_invert, 0); case BOARD_ID_RAD1O:
} else if (sgpio_invert & tx_mode) { case BOARD_ID_HACKRF1_R9:
gpio_write(config->gpio_rx_q_invert, 1); 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( void sgpio_cpld_set_mixer_invert(sgpio_config_t* const config, const uint_fast8_t invert)
sgpio_config_t* const config,
const uint_fast8_t invert)
{ {
if (invert) { if (invert) {
sgpio_invert = true; mixer_invert = true;
} else { } else {
sgpio_invert = false; mixer_invert = false;
} }
update_q_invert(config); update_q_invert(config);
} }
#else
void sgpio_cpld_stream_rx_set_q_invert(sgpio_config_t* const config, uint_fast8_t invert)
{
/*
* The RX IQ channels on HackRF One r9 are not inverted as they are
* on OG or Jawbreaker, so the opposite setting is required.
*/
if (detected_platform() == BOARD_ID_HACKRF1_R9) {
invert = (invert > 0) ? 0 : 1;
}
gpio_write(config->gpio_rx_q_invert, invert);
}
#endif

View File

@ -36,7 +36,7 @@ typedef enum {
} sgpio_direction_t; } sgpio_direction_t;
typedef struct sgpio_config_t { typedef struct sgpio_config_t {
gpio_t gpio_rx_q_invert; gpio_t gpio_q_invert;
gpio_t gpio_hw_sync_enable; gpio_t gpio_hw_sync_enable;
bool slice_mode_multislice; bool slice_mode_multislice;
} sgpio_config_t; } sgpio_config_t;
@ -49,6 +49,6 @@ void sgpio_cpld_stream_enable(sgpio_config_t* const config);
void sgpio_cpld_stream_disable(sgpio_config_t* const config); void sgpio_cpld_stream_disable(sgpio_config_t* const config);
bool sgpio_cpld_stream_is_enabled(sgpio_config_t* const config); bool sgpio_cpld_stream_is_enabled(sgpio_config_t* const config);
void sgpio_cpld_stream_rx_set_q_invert(sgpio_config_t* const config, uint_fast8_t invert); void sgpio_cpld_set_mixer_invert(sgpio_config_t* const config, uint_fast8_t invert);
#endif //__SGPIO_H__ #endif //__SGPIO_H__

View File

@ -84,13 +84,13 @@ bool set_freq(const uint64_t freq)
/* Set Freq and read real freq */ /* Set Freq and read real freq */
real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz); real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz);
max283x_set_frequency(&max283x, real_mixer_freq_hz - freq); max283x_set_frequency(&max283x, real_mixer_freq_hz - freq);
sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 1); sgpio_cpld_set_mixer_invert(&sgpio_config, 1);
} else if ((freq_mhz >= MIN_BYPASS_FREQ_MHZ) && (freq_mhz < MAX_BYPASS_FREQ_MHZ)) { } else if ((freq_mhz >= MIN_BYPASS_FREQ_MHZ) && (freq_mhz < MAX_BYPASS_FREQ_MHZ)) {
rf_path_set_filter(&rf_path, RF_PATH_FILTER_BYPASS); rf_path_set_filter(&rf_path, RF_PATH_FILTER_BYPASS);
MAX2837_freq_hz = (freq_mhz * FREQ_ONE_MHZ) + freq_hz; MAX2837_freq_hz = (freq_mhz * FREQ_ONE_MHZ) + freq_hz;
/* mixer_freq_mhz <= not used in Bypass mode */ /* mixer_freq_mhz <= not used in Bypass mode */
max283x_set_frequency(&max283x, MAX2837_freq_hz); max283x_set_frequency(&max283x, MAX2837_freq_hz);
sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0); sgpio_cpld_set_mixer_invert(&sgpio_config, 0);
} else if ((freq_mhz >= MIN_HP_FREQ_MHZ) && (freq_mhz <= MAX_HP_FREQ_MHZ)) { } else if ((freq_mhz >= MIN_HP_FREQ_MHZ) && (freq_mhz <= MAX_HP_FREQ_MHZ)) {
if (freq_mhz < MID1_HP_FREQ_MHZ) { if (freq_mhz < MID1_HP_FREQ_MHZ) {
/* IF is graduated from 2170 MHz to 2740 MHz */ /* IF is graduated from 2170 MHz to 2740 MHz */
@ -111,7 +111,7 @@ bool set_freq(const uint64_t freq)
/* Set Freq and read real freq */ /* Set Freq and read real freq */
real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz); real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz);
max283x_set_frequency(&max283x, freq - real_mixer_freq_hz); max283x_set_frequency(&max283x, freq - real_mixer_freq_hz);
sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0); sgpio_cpld_set_mixer_invert(&sgpio_config, 0);
} else { } else {
/* Error freq_mhz too high */ /* Error freq_mhz too high */
success = false; success = false;
@ -149,9 +149,9 @@ bool set_freq_explicit(
rf_path_set_filter(&rf_path, path); rf_path_set_filter(&rf_path, path);
max283x_set_frequency(&max283x, if_freq_hz); max283x_set_frequency(&max283x, if_freq_hz);
if (lo_freq_hz > 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 { } 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) { if (path != RF_PATH_FILTER_BYPASS) {
(void) mixer_set_frequency(&mixer, lo_freq_hz / FREQ_ONE_MHZ); (void) mixer_set_frequency(&mixer, lo_freq_hz / FREQ_ONE_MHZ);