From c081c2ea5794f0d3ee93e04f09df6669c850f3ac Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 9 Oct 2019 19:05:31 +0200 Subject: [PATCH] Add work on FIR configuration --- CMakeLists.txt | 1 + .../signal_source/libs/ad9361_manager.cc | 537 +----------------- .../signal_source/libs/ad9361_manager.h | 49 -- 3 files changed, 6 insertions(+), 581 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a93d2cf3..d142a7b92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2293,6 +2293,7 @@ set_package_properties(LIBAD9361 PROPERTIES ) if(NOT LIBAD9361_FOUND) set(GRIIO_FOUND FALSE) + set(ENABLE_AD9361 OFF) endif() if(ENABLE_PLUTOSDR OR ENABLE_FMCOMMS2) if(NOT GRIIO_FOUND) diff --git a/src/algorithms/signal_source/libs/ad9361_manager.cc b/src/algorithms/signal_source/libs/ad9361_manager.cc index a57aadf27..c06943571 100644 --- a/src/algorithms/signal_source/libs/ad9361_manager.cc +++ b/src/algorithms/signal_source/libs/ad9361_manager.cc @@ -38,31 +38,6 @@ #include #include -#define MIN_ADC_CLK 25000000UL // 25 MHz -#define MAX_ADC_CLK 640000000UL // 640 MHz -#define MIN_DATA_RATE MIN_ADC_CLK / 48 -#define MAX_DATA_RATE 61440000UL // Output of FIR (RX) -#define MAX_DAC_CLK (MAX_ADC_CLK / 2) -#define MIN_DAC_CLK 25000000UL // 25 MHz -#define MAX_RX_HB1 122880000UL -#define MAX_RX_HB2 245760000UL -#define MAX_RX_HB3 320000000UL -#define MAX_TX_HB1 122880000UL -#define MAX_TX_HB2 245760000UL -#define MAX_TX_HB3 320000000UL -#define MAX_FIR MAX_DATA_RATE * 2 -#define MAX_BBPLL_DIV 64 -#define MIN_BBPLL_FREQ 714928500UL // 715 MHz - 100ppm -#define MAX_BBPLL_FREQ 1430143000UL // 1430 MHz + 100ppm -#define check(val, min, max) ((val) <= (max) ? (val) >= (min) : false) - -const uint64_t TX_MAX_PATH_RATES[] = {MAX_DAC_CLK, MAX_TX_HB3, MAX_TX_HB2, MAX_TX_HB1, MAX_FIR}; -const uint64_t TX_MIN_PATH_RATES[] = {MIN_DAC_CLK, 0, 0, 0, 0}; -const uint64_t RX_MAX_PATH_RATES[] = {MAX_ADC_CLK, MAX_RX_HB3, MAX_RX_HB2, MAX_RX_HB1, MAX_FIR}; -const uint64_t RX_MIN_PATH_RATES[] = {MIN_ADC_CLK, 0, 0, 0, 0}; - -uint64_t max_rate_found; - /* check return value of attr_write function */ void errchk(int v, const char *what) { @@ -95,508 +70,6 @@ struct iio_device *get_ad9361_phy(struct iio_context *ctx) } -void set_max_taps(struct filter_design_parameters *fdpTX, - struct filter_design_parameters *fdpRX) -{ - // RX side - int N, M, K; - if (fdpRX->HB3 == 3) - N = 16 * floor(fdpRX->converter_rate / (fdpRX->Rdata)); - else - N = 16 * floor(fdpRX->converter_rate / (2 * fdpRX->Rdata)); - if (N > 128) - N = 128; - // TX side - if (fdpTX->FIR == 1) - M = 64; - else - M = 128; - K = 16 * floor(fdpTX->converter_rate * fdpTX->DAC_div / (2 * fdpTX->Rdata)); - if (K < M) - M = K; - - // Pick the smallest - if (M > N) - { - fdpTX->maxTaps = N; - fdpRX->maxTaps = N; - } - else - { - fdpTX->maxTaps = M; - fdpRX->maxTaps = M; - } -} - - -double calculate_rfbw(double pll_rate, double caldiv, bool TX, - double *rcaldiv) -{ - double rfbw, min_rfbw, max_rfbw, scale; - if (TX) - { - scale = 1.6; - min_rfbw = 1250000; - max_rfbw = 40000000; - } - else - { - scale = 1.4; - min_rfbw = 400000; - max_rfbw = 56000000; - } - rfbw = - (double)round((pll_rate / caldiv) * (2 / (scale * (2 * M_PI) / log(2)))); - - // If the RF bandwidth is outside the range of acceptable values we modify - // the divider value until it falls into an acceptable range. - while ((rfbw < min_rfbw) || (rfbw > max_rfbw)) - { - if (rfbw < min_rfbw) - caldiv = caldiv - 1; - else - caldiv = caldiv + 1; - - if ((caldiv < 1) || (caldiv > 511)) - { - fprintf(stderr, "Calibration divider out of bounds (1 - 511): %f\n", caldiv); - return -EINVAL; - } - rfbw = calculate_rfbw(pll_rate, caldiv, TX, rcaldiv); - } - *rcaldiv = caldiv; - return rfbw; -} - -void set_rates(uint64_t *rx_path_clks, - uint64_t *tx_path_clks, int DAC_div, uint64_t *rates, - int dec_table_index) -{ - int k; - - // Check if ADC will run faster in config - if (rates[1] > max_rate_found) - max_rate_found = rates[1]; - else - return; - - for (k = 0; k < 6; k++) - { - rx_path_clks[k] = rates[k]; - tx_path_clks[k] = rates[k]; - - if (k > 0) - { // Adjust HB's for DAC divider setting - if ((dec_table_index < 2) && (k < 4)) - tx_path_clks[k] = rates[k] / DAC_div; - else if ((dec_table_index < 4) && (k < 3)) - tx_path_clks[k] = rates[k] / DAC_div; - } - } -} - - -int check_dac_adc_config(uint64_t pll_bb, int PLL_mult, - int dec_table_index) -{ - // Need to determine if DAC divider is required and if ADC and DAC rates - // can be satisfied - uint64_t with_dd, without_dd; - bool a, b, c; - - with_dd = pll_bb / PLL_mult / 2; - without_dd = pll_bb / PLL_mult / 1; - - a = check(with_dd, MIN_DAC_CLK, MAX_DAC_CLK); - b = check(without_dd, MIN_ADC_CLK, MAX_ADC_CLK); - c = check(without_dd, MIN_DAC_CLK, MAX_DAC_CLK); - - if (c && b) - return 1; // Run without dac div - else if (a && b && (dec_table_index < 5)) - return 2; // Run with dac div - else - return -1; -} - - -bool check_rates(int FIR __attribute__((unused)), const int *HB_configs, uint64_t samp_rate, - uint64_t *rates) -{ - int j; - bool c = true; - - rates[5] = samp_rate; - for (j = 4; j > 0; j--) - { - rates[j] = rates[j + 1] * HB_configs[j - 1]; - if (j > 1) - { - c &= check(rates[j], TX_MIN_PATH_RATES[j - 1], TX_MAX_PATH_RATES[j - 1]); - c &= check(rates[j], RX_MIN_PATH_RATES[j - 1], RX_MAX_PATH_RATES[j - 1]); - } - } - return c; -} - - -int determine_pll_div(uint64_t *rates) -{ - // Determine necessary PLL multiplier - uint64_t tmp; - int PLL_mult = MAX_BBPLL_DIV; - while (PLL_mult > 1) - { - tmp = (uint64_t)rates[1] * PLL_mult; - if (check(tmp, MIN_BBPLL_FREQ, MAX_BBPLL_FREQ)) - { - rates[0] = (uint64_t)rates[1] * PLL_mult; - return PLL_mult; - } - PLL_mult >>= 1; - } - return -1; -} - - -int determine_path_rates_with_fir(uint64_t sample_rate, - uint64_t rate_gov, - uint64_t *rx_path_clks, - uint64_t *tx_path_clks, - int FIR) -{ - uint64_t rates[6]; - int PLL_mult, k; - - max_rate_found = 0UL; - - const int HB_configs[][4] = { - {3, 2, 2, FIR}, //12 - {2, 2, 2, FIR}, //8 - {3, 2, 1, FIR}, //6 - {2, 2, 1, FIR}, //4 - {2, 1, 1, FIR}, //2 - {3, 1, 1, FIR}, //3 - {1, 1, 1, FIR}, //1 - }; - - // RX Path: - // BBPLL -> /PLL_div -> /HB3 -> /HB2 -> /HB1 -> /FIR - // TX Path: - // BBPLL -> /(PLL_div*DAC_div) -> /HB3 -> /HB2 -> /HB1 -> /FIR - - // Cycle through possible decimations from highest to lowest - for (k = 0; k < 7; k++) - { - // HB3 cannot be 3 if rate_gov enabled - if ((rate_gov > 0) && HB_configs[k][0] == 3) - continue; - // Check if HB and FIR rates are valid - if (check_rates(FIR, HB_configs[k], sample_rate, rates)) - { - // Calculate PLL divider for configuration - PLL_mult = determine_pll_div(rates); - if (PLL_mult > 0) - { - // Determine DAC divider setting and check ADC/DAC settings - int dac_div = check_dac_adc_config(rates[0], PLL_mult, k); - // printf("dac_div: %d\n",dac_div); - if (dac_div > 0) - set_rates(rx_path_clks, tx_path_clks, dac_div, rates, k); - } - } - } - - if (max_rate_found == 0UL) - return -EINVAL; - else - return 0; -} - - -int ad9361_calculate_rf_clock_chain(uint64_t sample_rate, - uint64_t rate_gov, - uint64_t *rx_path_clks, - uint64_t *tx_path_clks) -{ - int ret, k; - int FIR[] = {4, 2, 1}; - - // Check desired rate within bounds - if (!check(sample_rate, MIN_DATA_RATE, MAX_DATA_RATE)) - return -EINVAL; - - // Rate selection will try to: - // 1. Utilize the maximum decimation in the FIR - // 2. Run the ADC/DAC as fast as possible - // 3. Use the most decimation possible starting with HB3(closest to ADC)->HB1 - - // Cycle through available FIR settings - for (k = 0; k < 3; k++) - { - ret = determine_path_rates_with_fir(sample_rate, rate_gov, rx_path_clks, - tx_path_clks, FIR[k]); - if (ret == 0) - break; - } - return ret; -} - - -int apply_custom_filter(struct iio_device *dev, unsigned dec_tx, - unsigned dec_rx, short *tapsTx, - short *tapsRx, unsigned taps, - uint64_t rate, - int gain_tx, int gain_rx, - uint64_t wnom_tx, uint64_t wnom_rx) -{ - struct iio_channel *chanTX, *chanRX; - long long current_rate; - int ret, i, enable, len = 0; - char *buf; - - chanTX = iio_device_find_channel(dev, "voltage0", true); - if (chanTX == NULL) - return -ENODEV; - - ret = iio_channel_attr_read_longlong(chanTX, "sampling_frequency", ¤t_rate); - if (ret < 0) - return ret; - - ret = ad9361_get_trx_fir_enable(dev, &enable); - if (ret < 0) - return ret; - - if (enable) - { - if (current_rate <= (25000000 / 12)) - iio_channel_attr_write_longlong(chanTX, "sampling_frequency", 3000000); - - ret = ad9361_set_trx_fir_enable(dev, false); - if (ret < 0) - return ret; - } - - buf = (char *)malloc(FIR_BUF_SIZE); - if (!buf) - return -ENOMEM; - - - len += snprintf(buf + len, FIR_BUF_SIZE - len, "RX 3 GAIN %d DEC %d\n", gain_rx, - dec_rx); - len += snprintf(buf + len, FIR_BUF_SIZE - len, "TX 3 GAIN %d INT %d\n", gain_tx, - dec_tx); - - for (i = 0; i < (int)taps; i++) - len += snprintf(buf + len, FIR_BUF_SIZE - len, "%d,%d\n", tapsRx[i], tapsTx[i]); - - len += snprintf(buf + len, FIR_BUF_SIZE - len, "\n"); - - ret = iio_device_attr_write_raw(dev, "filter_fir_config", buf, len); - free(buf); - - if (ret < 0) - return ret; - - if (rate <= (25000000 / 12)) - { - int dacrate, txrate, max; - char readbuf[100]; - ret = iio_device_attr_read(dev, "tx_path_rates", readbuf, sizeof(readbuf)); - if (ret < 0) - return ret; - ret = sscanf(readbuf, "BBPLL:%*d DAC:%d T2:%*d T1:%*d TF:%*d TXSAMP:%d", - &dacrate, &txrate); - if (ret != 2) - return -EFAULT; - if (txrate == 0) - return -EINVAL; - max = (dacrate / txrate) * 16; - if (max < taps) - iio_channel_attr_write_longlong(chanTX, "sampling_frequency", 3000000); - - - ret = ad9361_set_trx_fir_enable(dev, true); - if (ret < 0) - return ret; - ret = iio_channel_attr_write_longlong(chanTX, "sampling_frequency", rate); - if (ret < 0) - return ret; - } - else - { - ret = iio_channel_attr_write_longlong(chanTX, "sampling_frequency", rate); - if (ret < 0) - return ret; - ret = ad9361_set_trx_fir_enable(dev, true); - if (ret < 0) - return ret; - } - - chanRX = iio_device_find_channel(dev, "voltage0", false); - if (chanRX == NULL) - return -ENODEV; - ret = iio_channel_attr_write_longlong(chanTX, "rf_bandwidth", wnom_tx); - if (ret < 0) - return ret; - ret = iio_channel_attr_write_longlong(chanRX, "rf_bandwidth", wnom_rx); - if (ret < 0) - return ret; - - return 0; -} - - -int ad9361_set_bb_rate_custom_filter_auto(struct iio_device *dev, - uint64_t rate) -{ - struct filter_design_parameters fdpTX; - struct filter_design_parameters fdpRX; - short taps_tx[128]; - short taps_rx[128]; - int ret, num_taps_tx, num_taps_rx, gain_tx, gain_rx; - unsigned dec_tx, dec_rx, num_taps; - - ret = ad9361_calculate_rf_clock_chain_fdp(&fdpTX, &fdpRX, rate); - if (ret < 0) - return ret; - - ret = ad9361_generate_fir_taps(&fdpRX, taps_rx, &num_taps_rx, &gain_rx); - if (ret < 0) - return ret; - - ret = ad9361_generate_fir_taps(&fdpTX, taps_tx, &num_taps_tx, &gain_tx); - if (ret < 0) - return ret; - - dec_tx = (unsigned)fdpTX.FIR; - dec_rx = (unsigned)fdpRX.FIR; - num_taps = (unsigned)fdpTX.maxTaps; - ret = apply_custom_filter(dev, dec_tx, dec_rx, taps_tx, taps_rx, num_taps, - rate, gain_tx, gain_rx, fdpTX.wnom, fdpRX.wnom); - if (ret < 0) - return ret; - - return 0; -} - -int build_configuration(struct filter_design_parameters *fdpTX, - struct filter_design_parameters *fdpRX, - uint64_t sample_rate, - uint64_t Fpass, - uint64_t Fstop, - uint64_t wnomTX, - uint64_t wnomRX) -{ - double div, max; - uint64_t rx_path_clk[6]; - uint64_t tx_path_clk[6]; - uint64_t *path_clk; - struct filter_design_parameters *fdp; - int ret, k; - uint64_t rate_gov = 0; - - ret = ad9361_calculate_rf_clock_chain((uint64_t)sample_rate, - rate_gov, rx_path_clk, tx_path_clk); - if (ret < 0) - return -EINVAL; - - for (k = 0; k < 2; k++) - { - if (k > 0) - { - path_clk = tx_path_clk; - fdp = fdpTX; - fdp->RxTx = "Tx"; - fdp->DAC_div = (double)rx_path_clk[1] / tx_path_clk[1]; - } - else - { - path_clk = rx_path_clk; - fdp = fdpRX; - fdp->RxTx = "Rx"; - fdp->DAC_div = 1.0; - } - // Map rates and dividers - fdp->PLL_rate = (double)path_clk[0]; - fdp->converter_rate = (double)path_clk[1]; - fdp->PLL_mult = (double)path_clk[0] / path_clk[1]; - fdp->HB3 = (double)path_clk[1] / path_clk[2]; - fdp->HB2 = (double)path_clk[2] / path_clk[3]; - fdp->HB1 = (double)path_clk[3] / path_clk[4]; - fdp->FIR = (double)path_clk[4] / path_clk[5]; - - // Set default parameters - fdp->Rdata = (double)path_clk[5]; - fdp->Type = "Lowpass"; - fdp->int_FIR = 1; - fdp->Apass = 0.5; - fdp->Astop = 80; - fdp->phEQ = -1; - fdp->FIRdBmin = 0; - // Define filter design specifications - fdp->Fpass = (double)Fpass; - fdp->Fstop = (double)Fstop; - fdp->Fcenter = 0.0; - if (k > 0) - fdp->wnom = (double)wnomTX; - else - fdp->wnom = (double)wnomRX; - // Determine default analog bandwidth - div = ceil((fdp->PLL_rate / fdp->wnom) * (log(2) / (2 * M_PI))); - max = (div > 1) ? div : 1.0; - fdp->caldiv = (max > 511) ? 511.0 : max; - fdp->RFbw = calculate_rfbw(fdp->PLL_rate, fdp->caldiv, k > 0, &(fdp->caldiv)); - - if (fdp->RFbw < 0) - return -EINVAL; - } - set_max_taps(fdpTX, fdpRX); - - return 0; -} - - -int ad9361_set_bb_rate_custom_filter_manual(struct iio_device *dev, - uint64_t rate, uint64_t Fpass, - uint64_t Fstop, uint64_t wnom_tx, uint64_t wnom_rx) -{ - struct filter_design_parameters fdpTX; - struct filter_design_parameters fdpRX; - short taps_tx[128]; - short taps_rx[128]; - int ret, num_taps_tx, num_taps_rx, gain_tx, gain_rx; - unsigned dec_tx, dec_rx, num_taps; - - if (Fpass >= Fstop) - return -EINVAL; - - ret = build_configuration(&fdpTX, &fdpRX, rate, Fpass, Fstop, wnom_tx, - wnom_rx); - if (ret < 0) - return ret; - - ret = ad9361_generate_fir_taps(&fdpRX, taps_rx, &num_taps_rx, &gain_rx); - if (ret < 0) - return ret; - - ret = ad9361_generate_fir_taps(&fdpTX, taps_tx, &num_taps_tx, &gain_tx); - if (ret < 0) - return ret; - - dec_tx = (unsigned)fdpTX.FIR; - dec_rx = (unsigned)fdpRX.FIR; - num_taps = (unsigned)fdpTX.maxTaps; - - ret = apply_custom_filter(dev, dec_tx, dec_rx, taps_tx, taps_rx, num_taps, - rate, gain_tx, gain_rx, wnom_tx, wnom_rx); - if (ret < 0) - return ret; - - return 0; -} - - /* finds AD9361 streaming IIO devices */ bool get_ad9361_stream_dev(struct iio_context *ctx, enum iodev d, struct iio_device **dev) { @@ -893,14 +366,14 @@ bool config_ad9361_rx_remote(const std::string &remote_host, std::cout << "* Initializing AD9361 IIO streaming channels\n"; if (!get_ad9361_stream_ch(ctx, RX, rx, 0, &rx_chan1)) { - std::cout << "RX chan i not found\n"; - throw std::runtime_error("RX chan i not found"); + std::cout << "RX channel 1 not found\n"; + throw std::runtime_error("RX channel 1 not found"); } if (!get_ad9361_stream_ch(ctx, RX, rx, 1, &rx_chan2)) { - std::cout << "RX chan q not found\n"; - throw std::runtime_error("RX chan q not found"); + std::cout << "RX channel 2 not found\n"; + throw std::runtime_error("RX channel 2 not found"); } if (filter_source_ == "Off") @@ -1448,7 +921,7 @@ bool load_fir_filter( return false; } - /* Here, we verify that the filter file contains data for both RX+TX. */ + // Here, we verify that the filter file contains data for both RX+TX. { char buf[256]; do diff --git a/src/algorithms/signal_source/libs/ad9361_manager.h b/src/algorithms/signal_source/libs/ad9361_manager.h index e94bfd55b..7216ae4f8 100644 --- a/src/algorithms/signal_source/libs/ad9361_manager.h +++ b/src/algorithms/signal_source/libs/ad9361_manager.h @@ -55,7 +55,6 @@ struct stream_cfg const char *rfport; // Port name }; - /* check return value of attr_write function */ void errchk(int v, const char *what); @@ -131,52 +130,4 @@ bool ad9361_disable_lo_local(); bool load_fir_filter(std::string &filter, struct iio_device *phy); -int ad9361_set_bb_rate_custom_filter_manual(struct iio_device *dev, - uint64_t rate, uint64_t Fpass, - uint64_t Fstop, uint64_t wnom_tx, uint64_t wnom_rx); - -int ad9361_set_bb_rate_custom_filter_auto(struct iio_device *dev, - uint64_t rate); - -int apply_custom_filter(struct iio_device *dev, unsigned dec_tx, - unsigned dec_rx, short *tapsTx, - short *tapsRx, unsigned taps, - uint64_t rate, - int gain_tx, int gain_rx, - uint64_t wnom_tx, uint64_t wnom_rx); - -int ad9361_calculate_rf_clock_chain(uint64_t sample_rate, - uint64_t rate_gov, - uint64_t *rx_path_clks, - uint64_t *tx_path_clks); - -int determine_path_rates_with_fir(uint64_t sample_rate, - uint64_t rate_gov, - uint64_t *rx_path_clks, - uint64_t *tx_path_clks, - uint64_t tmp, - int FIR); - -bool check_rates(int FIR, const int *HB_configs, uint64_t samp_rate, - uint64_t *rates); - -int determine_pll_div(uint64_t *rates); - -int check_dac_adc_config(uint64_t pll_bb, int PLL_mult, - int dec_table_index); - -double calculate_rfbw(double pll_rate, double caldiv, bool TX, - double *rcaldiv); - -int build_configuration(struct filter_design_parameters *fdpTX, - struct filter_design_parameters *fdpRX, - uint64_t sample_rate, - uint64_t Fpass, - uint64_t Fstop, - uint64_t wnomTX, - uint64_t wnomRX); - -void set_max_taps(struct filter_design_parameters *fdpTX, - struct filter_design_parameters *fdpRX); - #endif // GNSS_SDR_AD9361_MANAGER_H_