Transceiver52M: Enable B210 dual channel support

The main difference between existing UmTRX dual channel is the
single LO on B210 transmit and receive front-ends vs. independent
tuning paths. In order to support dual-ARFCN frequencies, baseband
offset conversion must be applied by tuning the FPGA CORDIC for
each channel. For B210, the following tuning order is applied.

1. If the new frequency of channel A is within the baseband range
   of channel B, then retune both channels with the RF centered
   and equal valued positive and negative baseband shifts.

2. If the new frequency of channel A is not with the baseband range
   of channel B, then retune channel A directly (without manual
   applied offset). Channel B will no longer be tuned to the
   previous frequency.

Signed-off-by: Thomas Tsou <tom@tsou.cc>
This commit is contained in:
Thomas Tsou 2014-02-13 15:09:00 -05:00
parent 18d3b833bc
commit 3ebc772dc2
1 changed files with 89 additions and 12 deletions

View File

@ -349,6 +349,9 @@ private:
std::string str_code(uhd::rx_metadata_t metadata);
std::string str_code(uhd::async_metadata_t metadata);
uhd::tune_request_t select_freq(double wFreq, size_t chan, bool tx);
bool set_freq(double freq, size_t chan, bool tx);
Thread async_event_thrd;
bool diversity;
};
@ -618,7 +621,8 @@ int uhd_device::open(const std::string &args, bool extref)
return -1;
// Verify and set channels
if ((dev_type == UMTRX) && (chans == 2)) {
if ((dev_type == B210) && (chans == 2)) {
} else if ((dev_type == UMTRX) && (chans == 2)) {
uhd::usrp::subdev_spec_t subdev_spec("A:0 B:0");
usrp_dev->set_tx_subdev_spec(subdev_spec);
usrp_dev->set_rx_subdev_spec(subdev_spec);
@ -656,7 +660,9 @@ int uhd_device::open(const std::string &args, bool extref)
else
_rx_rate = _tx_rate / sps;
if ((_tx_rate > 0.0) && (set_rates(_tx_rate, _rx_rate) < 0))
if ((_tx_rate < 0.0) || (_rx_rate < 0.0))
return -1;
if (set_rates(_tx_rate, _rx_rate) < 0)
return -1;
// Create receive buffer
@ -968,6 +974,82 @@ bool uhd_device::updateAlignment(TIMESTAMP timestamp)
return true;
}
uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
{
double rf_spread, rf_freq;
std::vector<double> freqs;
uhd::tune_request_t treq(freq);
if (chans == 1)
return treq;
else if ((dev_type == UMTRX) && (chans == 2))
return treq;
else if ((dev_type != B210) || (chans > 2) || (chan > 1)) {
LOG(ALERT) << chans << " channels unsupported";
return treq;
}
if (tx)
freqs = tx_freqs;
else
freqs = rx_freqs;
/* Tune directly if other channel isn't tuned */
if (freqs[!chan] < 10.0)
return treq;
/* Find center frequency between channels */
rf_spread = fabs(freqs[!chan] - freq);
if (rf_spread > B2XX_CLK_RT) {
LOG(ALERT) << rf_spread << "Hz tuning spread not supported\n";
return treq;
}
rf_freq = (freqs[!chan] + freq) / 2.0f;
treq.rf_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
treq.target_freq = freq;
treq.rf_freq = rf_freq;
return treq;
}
bool uhd_device::set_freq(double freq, size_t chan, bool tx)
{
std::vector<double> freqs;
uhd::tune_result_t tres;
uhd::tune_request_t treq = select_freq(freq, chan, tx);
if (tx) {
tres = usrp_dev->set_tx_freq(treq, chan);
tx_freqs[chan] = usrp_dev->get_tx_freq(chan);
} else {
tres = usrp_dev->set_rx_freq(treq, chan);
rx_freqs[chan] = usrp_dev->get_rx_freq(chan);
}
LOG(INFO) << "\n" << tres.to_pp_string() << std::endl;
/* Manual RF policy means we intentionally tuned with a baseband
* offset for dual-channel purposes. Now retune the other channel
* with the opposite corresponding frequency offset
*/
if (treq.rf_freq_policy == uhd::tune_request_t::POLICY_MANUAL) {
if (tx) {
treq = select_freq(tx_freqs[!chan], !chan, true);
tres = usrp_dev->set_tx_freq(treq, !chan);
tx_freqs[!chan] = usrp_dev->get_tx_freq(!chan);
} else {
treq = select_freq(rx_freqs[!chan], !chan, false);
tres = usrp_dev->set_rx_freq(treq, !chan);
rx_freqs[!chan] = usrp_dev->get_rx_freq(!chan);
}
LOG(INFO) << "\n" << tres.to_pp_string() << std::endl;
}
return true;
}
bool uhd_device::setTxFreq(double wFreq, size_t chan)
{
if (chan >= tx_freqs.size()) {
@ -975,11 +1057,7 @@ bool uhd_device::setTxFreq(double wFreq, size_t chan)
return false;
}
uhd::tune_result_t tr = usrp_dev->set_tx_freq(wFreq, chan);
LOG(INFO) << "\n" << tr.to_pp_string();
tx_freqs[chan] = usrp_dev->get_tx_freq(chan);
return true;
return set_freq(wFreq, chan, true);
}
bool uhd_device::setRxFreq(double wFreq, size_t chan)
@ -989,11 +1067,7 @@ bool uhd_device::setRxFreq(double wFreq, size_t chan)
return false;
}
uhd::tune_result_t tr = usrp_dev->set_rx_freq(wFreq, chan);
LOG(INFO) << "\n" << tr.to_pp_string();
rx_freqs[chan] = usrp_dev->get_rx_freq(chan);
return true;
return set_freq(wFreq, chan, false);
}
double uhd_device::getTxFreq(size_t chan)
@ -1055,6 +1129,9 @@ std::string uhd_device::str_code(uhd::rx_metadata_t metadata)
case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
ost << "An internal receive buffer has filled";
break;
case uhd::rx_metadata_t::ERROR_CODE_ALIGNMENT:
ost << "Multi-channel alignment failed";
break;
case uhd::rx_metadata_t::ERROR_CODE_BAD_PACKET:
ost << "The packet could not be parsed";
break;