mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2024-12-14 12:10:34 +00:00
Add work in the AD9361 manager
This commit is contained in:
parent
09078b6486
commit
43a8090dc6
@ -38,6 +38,30 @@
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#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)
|
||||
@ -71,6 +95,508 @@ 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)
|
||||
{
|
||||
@ -195,17 +721,17 @@ bool config_ad9361_rx_local(uint64_t bandwidth_,
|
||||
// RX stream config
|
||||
// Stream configurations
|
||||
struct stream_cfg rxcfg;
|
||||
rxcfg.bw_hz = bandwidth_; // 2 MHz rf bandwidth
|
||||
rxcfg.fs_hz = sample_rate_; // 2.5 MS/s rx sample rate
|
||||
rxcfg.lo_hz = freq_; // 2.5 GHz rf frequency
|
||||
rxcfg.rfport = rf_port_select_.c_str(); // port A (select for rf freq.)
|
||||
rxcfg.bw_hz = bandwidth_;
|
||||
rxcfg.fs_hz = sample_rate_;
|
||||
rxcfg.lo_hz = freq_;
|
||||
rxcfg.rfport = rf_port_select_.c_str();
|
||||
|
||||
std::cout << "AD9361 Acquiring IIO LOCAL context\n";
|
||||
struct iio_context *ctx;
|
||||
// Streaming devices
|
||||
struct iio_device *rx;
|
||||
struct iio_channel *rx0_i;
|
||||
struct iio_channel *rx0_q;
|
||||
struct iio_channel *rx_chan1;
|
||||
struct iio_channel *rx_chan2;
|
||||
|
||||
ctx = iio_create_default_context();
|
||||
if (!ctx)
|
||||
@ -236,21 +762,21 @@ bool config_ad9361_rx_local(uint64_t bandwidth_,
|
||||
}
|
||||
|
||||
std::cout << "* Initializing AD9361 IIO streaming channels\n";
|
||||
if (!get_ad9361_stream_ch(ctx, RX, rx, 0, &rx0_i))
|
||||
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, &rx0_q))
|
||||
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");
|
||||
}
|
||||
|
||||
std::cout << "* Enabling IIO streaming channels\n";
|
||||
iio_channel_enable(rx0_i);
|
||||
iio_channel_enable(rx0_q);
|
||||
iio_channel_enable(rx_chan1);
|
||||
iio_channel_enable(rx_chan2);
|
||||
|
||||
struct iio_device *ad9361_phy;
|
||||
ad9361_phy = iio_context_find_device(ctx, "ad9361-phy");
|
||||
@ -334,8 +860,8 @@ bool config_ad9361_rx_remote(const std::string &remote_host,
|
||||
struct iio_context *ctx;
|
||||
// Streaming devices
|
||||
struct iio_device *rx;
|
||||
struct iio_channel *rx0_i;
|
||||
struct iio_channel *rx0_q;
|
||||
struct iio_channel *rx_chan1;
|
||||
struct iio_channel *rx_chan2;
|
||||
|
||||
ctx = iio_create_network_context(remote_host.c_str());
|
||||
if (!ctx)
|
||||
@ -365,13 +891,13 @@ bool config_ad9361_rx_remote(const std::string &remote_host,
|
||||
int ret;
|
||||
|
||||
std::cout << "* Initializing AD9361 IIO streaming channels\n";
|
||||
if (!get_ad9361_stream_ch(ctx, RX, rx, 0, &rx0_i))
|
||||
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");
|
||||
}
|
||||
|
||||
if (!get_ad9361_stream_ch(ctx, RX, rx, 1, &rx0_q))
|
||||
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");
|
||||
@ -400,20 +926,18 @@ bool config_ad9361_rx_remote(const std::string &remote_host,
|
||||
// set bw
|
||||
//params.push_back("in_voltage_rf_bandwidth=" + boost::to_string(bandwidth));
|
||||
}
|
||||
//wr_ch_str(rx0_i, "rf_port_select", rf_port_select_.c_str());
|
||||
//wr_ch_str(rx_chan1, "rf_port_select", rf_port_select_.c_str());
|
||||
ret = iio_device_attr_write(ad9361_phy, "in_voltage0_rf_port_select", rf_port_select_.c_str());
|
||||
if (ret)
|
||||
{
|
||||
throw std::runtime_error("Unable to set rf_port_select");
|
||||
}
|
||||
wr_ch_lli(rx0_i, "rf_bandwidth", bandwidth_);
|
||||
|
||||
//if (!get_lo_chan(ctx, "RX", &chn))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
//wr_ch_lli(chn, "frequency", freq_);
|
||||
// in_voltage0_rf_port_select
|
||||
wr_ch_lli(rx_chan1, "rf_bandwidth", bandwidth_);
|
||||
if (!get_lo_chan(ctx, RX, &rx_chan1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
wr_ch_lli(rx_chan1, "frequency", freq_);
|
||||
}
|
||||
else if (filter_source_ == "File")
|
||||
{
|
||||
@ -433,13 +957,17 @@ bool config_ad9361_rx_remote(const std::string &remote_host,
|
||||
{
|
||||
throw std::runtime_error("Unable to set rf_port_select");
|
||||
}
|
||||
wr_ch_lli(rx0_i, "rf_bandwidth", bandwidth_);
|
||||
wr_ch_lli(rx0_i, "frequency", freq_);
|
||||
wr_ch_lli(rx_chan1, "rf_bandwidth", bandwidth_);
|
||||
if (!get_lo_chan(ctx, RX, &rx_chan1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
wr_ch_lli(rx_chan1, "frequency", freq_);
|
||||
}
|
||||
else if (filter_source_ == "Design")
|
||||
{
|
||||
ret = ad9361_set_bb_rate_custom_filter_manual(
|
||||
ad9361_phy, sample_rate_, Fpass_, Fstop_, bandwidth_, bandwidth_);
|
||||
ad9361_phy, sample_rate_, static_cast<uint64_t>(Fpass_), static_cast<uint64_t>(Fstop_), bandwidth_, bandwidth_);
|
||||
if (ret)
|
||||
{
|
||||
throw std::runtime_error("Unable to set BB rate");
|
||||
@ -449,8 +977,12 @@ bool config_ad9361_rx_remote(const std::string &remote_host,
|
||||
{
|
||||
throw std::runtime_error("Unable to set rf_port_select");
|
||||
}
|
||||
wr_ch_lli(rx0_i, "rf_bandwidth", bandwidth_);
|
||||
wr_ch_lli(rx0_i, "frequency", freq_);
|
||||
wr_ch_lli(rx_chan1, "rf_bandwidth", bandwidth_);
|
||||
if (!get_lo_chan(ctx, RX, &rx_chan1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
wr_ch_lli(rx_chan1, "frequency", freq_);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -468,8 +1000,8 @@ bool config_ad9361_rx_remote(const std::string &remote_host,
|
||||
}
|
||||
|
||||
std::cout << "* Enabling IIO streaming channels\n";
|
||||
iio_channel_enable(rx0_i);
|
||||
iio_channel_enable(rx0_q);
|
||||
iio_channel_enable(rx_chan1);
|
||||
iio_channel_enable(rx_chan2);
|
||||
|
||||
ret = iio_device_attr_write(ad9361_phy, "trx_rate_governor", "nominal");
|
||||
if (ret < 0)
|
||||
@ -528,7 +1060,6 @@ bool config_ad9361_rx_remote(const std::string &remote_host,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::cout << "End of AD9361 RX configuration.\n";
|
||||
|
||||
iio_context_destroy(ctx);
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#define FIR_BUF_SIZE 8192
|
||||
|
||||
/* RX is input, TX is output */
|
||||
enum iodev
|
||||
@ -48,7 +49,7 @@ enum iodev
|
||||
/* common RX and TX streaming params */
|
||||
struct stream_cfg
|
||||
{
|
||||
int64_t bw_hz; // Analog banwidth in Hz
|
||||
int64_t bw_hz; // Analog bandwidth in Hz
|
||||
int64_t fs_hz; // Baseband sample rate in Hz
|
||||
int64_t lo_hz; // Local oscillator frequency in Hz
|
||||
const char *rfport; // Port name
|
||||
@ -64,9 +65,6 @@ void wr_ch_lli(struct iio_channel *chn, const char *what, int64_t val);
|
||||
/* write attribute: string */
|
||||
void wr_ch_str(struct iio_channel *chn, const char *what, const char *str);
|
||||
|
||||
/* helper function generating channel names */
|
||||
char *get_ch_name(const char *type, int id, char *tmpstr);
|
||||
|
||||
/* returns ad9361 phy device */
|
||||
struct iio_device *get_ad9361_phy(struct iio_context *ctx);
|
||||
|
||||
@ -127,11 +125,58 @@ bool config_ad9361_lo_remote(const std::string &remote_host,
|
||||
double scale_dds_dbfs_,
|
||||
double phase_dds_deg_);
|
||||
|
||||
|
||||
bool ad9361_disable_lo_remote(const std::string &remote_host);
|
||||
|
||||
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_
|
||||
|
Loading…
Reference in New Issue
Block a user