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

View File

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

View File

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

View File

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