-
Notifications
You must be signed in to change notification settings - Fork 459
Getting Started: XB200 Transverter Board
This page provides an overview of the XB-200 and provides some information on its use.
The XB-200 transverter board is a block up-down converter that expands the bladeRF’s lower frequency range, allowing the bladeRF to be used in HF/VHF applications.
The RX and TX paths each have a set of 3 filters, at the 50MHz-54MHz (6 meter) band, 149MHz-159MHz (2 meter) band, and 206-235MHz (includes 1.25m) bands. There are also pairs of SMA connectors that will let users plug their own band filters into the RF path.
The XB-200 mates to the top of the bladeRF as follows. (There is only one possible orientation)
- XB-200 U20 to bladeRF U74
- XB-200 J5 to bladeRF J61
- XB-200 J6 to bladeRF J60
The transverter was meant to extend the range of the bladeRF without impairing the current frequency capabilities. As such, the transverter has a bypass path as well as a mixed path. The bypass path just connects the antenna port to the IF port directly without any modification to the signal.
The mixed path first has a filterbank for selectivity filtering. This filterbank consists of 4 separate paths: 50MHz filter, 144MHz filter, 222MHz filter and a custom filter. The custom filter can be put in line using the filter SMA connections on the transverter.
Each of the filters was designed to try to notch the terrestrial FM band as much as possible. To be able to receive normal FM, the simplest way is to put an SMA jumper in the custom path (i.e., between the RX/TX FILT and FILT-ANT SMA connectors).
The block converter stage uses an ADF4351 to produce a 1248MHz high-side injection tone. The mixing frequency was chosen because of it being about 3x higher than the 300MHz highest frequency we want to use and we can run the ADF4351 in integer-N mode, reducing spurs which may have resulted from a fractional-N mode of operation. The output of the ADF4351 is always divided by 2x, so 38.4MHz*32.5 = 1248MHz.
Since high side injection is used, the LMS6002D on the bladeRF is tuning to 1248MHz - (desired frequency). Moreover, there is a spectral inversion that is occurring due to the choice of high-side injection. The LMS6002D is programmed to swap I and Q on the data bus being presented to the FPGA to correct for the flip.
There are 10 SMA connectors on the XB-200. Below are brief descriptions of each.
RX
- RXIF (J3): RX Intermediate Frequency. Connect this to the bladeRF RX port (J53) via an SMA cable.
- RXANT (J12): RX Input. Connect an antenna here.
- RXFILT (J8): Mixer-side of the RX custom filter path. Connect this directly to RXFILT-ANT to use no filter, or connect this to one end of your custom filter, and the other end of your filter to RXFILT-ANT.
- RXFILT-ANT (J9): Antenna-side of the RX custom filter path.
- ADC (J14): This SMA exposes the direct ADC sampling path (skipping the LMS6002). This can also be accessed without the XB-200 via J61 on the bladeRF.
- TXIF (J1): TX Intermediate Frequency. Connect this to the bladeRF TX port (J54) via an SMA cable.
- TXANT (J2): TX output. Connect an antenna here. When not transmitting, it is recommended to keep a dummy load or attenuator on this port.
- TXFILT (J11): Mixer-side of the TX custom filter path. Connect this directly to TXFILT-ANT to use no filter, or connect this to one end of your custom filter, and the other end of your filter to TXFILT-ANT.
- TXFILT-ANT (J10): Antenna-side of the TX custom filter path.
- DAC (J15): This SMA exposes the DAC direct sampling path (skipping the LMS6002). This can also be accessed without the XB-200 via J60 on the bladeRF.
GPIO pins are exposed on the XB-200 via J1, J13, and J16. libbladeRF API calls to manipulate these pins are a work in progress.
TO DO: provide jumper pinout and FPGA pin associations.
The general procedure for using the XB-200 programmatically, via libbladeRF is as follows:
- With an open device handle, enable support for the XB-200 via:
bladerf_expansion_attach(dev, BLADERF_XB_200) - Select the desired filter bank for the RX and TX paths. For example, to configure the RX module to use the 149-159MHz filter:
bladerf_xb200_set_filterbank(dev, BLADERF_MODULE_RX, BLADERF_XB200_144M)- See the bladerf_xb200_filter enumeration for other options.
- Specify that the XB-200 mixer path should be used:
bladerf_xb200_set_path(dev, BLADERF_MODULE_RX, BLADERF_XB200_MIX)- To tune to the "normal" bladeRF ranges, bypass the XB-200 mixer by using the BLADERF_XB200_BYPASS value with the above function.
TODO Describe the commands involved with the XB-200
A set of preliminary patches have been submitted to the gr-osmosdr maintainers, and are pending further review. These patches are subject to change.
Below are the two patches and a quick overview of how to apply them. Save these to the filenames indicated below.
# Enter the directory containing the gr-osmosdr source $ cd path/to/gr-osmosdr/source # Ensure you have the latest and greatest. This is required. $ git checkout master $ git pull # Create a nuand-xb200-pending branch. In the future, you can return # to master and delete this branch via: # git checkout master && git branch -D nuand-xb200-pending $ git checkout -b nuand-xb200-pending # Apply the patches $ git am 0001-bladeRF-Add-XB-200-support.patch 0002-bladeRF-auto-filterbank-selection.patch # Now rebuild and re-install as you normally would
0001-bladeRF-Add-XB-200-support.patch
From e6458f30625ed17a944b00ffc97076933a7436ed Mon Sep 17 00:00:00 2001 From: Robert Ghilduta <[email protected]> Date: Wed, 11 Jun 2014 01:11:09 -0700 Subject: [PATCH 1/2] bladeRF: Add XB-200 support This commit adds support for the bladeRF XB-200 transverter expansion board. To enable the expansion board and to allow the osmocom source to down to 0Hz, parameter XB-200 has to be set. Additionally the XB-200 comes with 4 filter banks that can be set via configuration option, xb200filt. The following values are valid: "50M" : 50MHz band "144M" : 144MHz band "222M" : 222MHz band [default] : Custom filter --- lib/bladerf/bladerf_common.cc | 26 ++++++++++++++++++++++++-- lib/bladerf/bladerf_common.h | 2 ++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/bladerf/bladerf_common.cc b/lib/bladerf/bladerf_common.cc index 7516020..ac56747 100644 --- a/lib/bladerf/bladerf_common.cc +++ b/lib/bladerf/bladerf_common.cc @@ -48,7 +48,7 @@ using namespace boost::assign; boost::mutex bladerf_common::_devs_mutex; std::list<boost::weak_ptr<struct bladerf> > bladerf_common::_devs; -bladerf_common::bladerf_common() : _conv_buf(NULL), _conv_buf_size(4096) {} +bladerf_common::bladerf_common() : _conv_buf(NULL), _conv_buf_size(4096), xb_200_attached(false) {} bladerf_common::~bladerf_common() { @@ -305,6 +305,28 @@ void bladerf_common::init(dict_t &dict, bladerf_module module) } + if ( dict.count("xb200")) { + if (bladerf_expansion_attach(_dev.get(), BLADERF_XB_200)) { + std::cerr << "Could not attach XB-200"; + } else { + _xb_200_attached = true; + } + } + + bladerf_xb200_filter filter = BLADERF_XB200_CUSTOM; + if ( dict.count("xb200filt")) { + if ( dict["xb200filt"] == "50M") { + filter = BLADERF_XB200_50M; + } else if ( dict["xb200filt"] == "144M") { + filter = BLADERF_XB200_144M; + } else if ( dict["xb200filt"] == "222M") { + filter = BLADERF_XB200_222M; + } + } + + if (bladerf_xb200_set_filterbank(_dev.get(), module, filter)) { + std::cerr << "Could not set XB-200 filter"; + } /* Show some info about the device we've opened */ std::cerr << _pfx << "Using nuand LLC bladeRF #" << device_number; @@ -387,7 +409,7 @@ void bladerf_common::init(dict_t &dict, bladerf_module module) osmosdr::freq_range_t bladerf_common::freq_range() { /* assuming the same for RX & TX */ - return osmosdr::freq_range_t( 300e6, 3.8e9 ); + return osmosdr::freq_range_t( _xb_200_attached ? 0 : 300e6, 3.8e9 ); } osmosdr::meta_range_t bladerf_common::sample_rates() diff --git a/lib/bladerf/bladerf_common.h b/lib/bladerf/bladerf_common.h index b13a6cf..3b1cb0b 100644 --- a/lib/bladerf/bladerf_common.h +++ b/lib/bladerf/bladerf_common.h @@ -82,6 +82,8 @@ protected: std::string _pfx; + bool _xb_200_attached; + /* BladeRF IQ correction parameters */ static const int16_t DCOFF_SCALE = 2048; static const int16_t GAIN_SCALE = 4096; -- 1.9.1
0002-bladeRF-auto-filterbank-selection.patch
From 1e3e5168361d61704726c7de26e1095b7871c6f5 Mon Sep 17 00:00:00 2001 From: Robert Ghilduta <[email protected]> Date: Wed, 11 Jun 2014 15:01:33 -0700 Subject: [PATCH 2/2] bladeRF: auto filterbank selection Setting xb200filt to "auto" causes the bladeRF sink and source blocks to automatically select the appropriate filterbank based on center frequency. --- lib/bladerf/bladerf_common.cc | 12 ++++++++---- lib/bladerf/bladerf_common.h | 1 + lib/bladerf/bladerf_sink_c.cc | 18 ++++++++++++++++++ lib/bladerf/bladerf_source_c.cc | 18 ++++++++++++++++++ 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/lib/bladerf/bladerf_common.cc b/lib/bladerf/bladerf_common.cc index ac56747..6773d4d 100644 --- a/lib/bladerf/bladerf_common.cc +++ b/lib/bladerf/bladerf_common.cc @@ -48,7 +48,7 @@ using namespace boost::assign; boost::mutex bladerf_common::_devs_mutex; std::list<boost::weak_ptr<struct bladerf> > bladerf_common::_devs; -bladerf_common::bladerf_common() : _conv_buf(NULL), _conv_buf_size(4096), xb_200_attached(false) {} +bladerf_common::bladerf_common() : _conv_buf(NULL), _conv_buf_size(4096), _xb_200_attached(false), _xb_200_auto_filter(false) {} bladerf_common::~bladerf_common() { @@ -315,7 +315,9 @@ void bladerf_common::init(dict_t &dict, bladerf_module module) bladerf_xb200_filter filter = BLADERF_XB200_CUSTOM; if ( dict.count("xb200filt")) { - if ( dict["xb200filt"] == "50M") { + if ( dict["xb200filt"] == "auto") { + _xb_200_auto_filter = true; + } else if ( dict["xb200filt"] == "50M") { filter = BLADERF_XB200_50M; } else if ( dict["xb200filt"] == "144M") { filter = BLADERF_XB200_144M; @@ -324,8 +326,10 @@ void bladerf_common::init(dict_t &dict, bladerf_module module) } } - if (bladerf_xb200_set_filterbank(_dev.get(), module, filter)) { - std::cerr << "Could not set XB-200 filter"; + if (_xb_200_attached && !_xb_200_auto_filter) { + if (bladerf_xb200_set_filterbank(_dev.get(), module, filter)) { + std::cerr << "Could not set XB-200 filter"; + } } /* Show some info about the device we've opened */ diff --git a/lib/bladerf/bladerf_common.h b/lib/bladerf/bladerf_common.h index 3b1cb0b..f67c5b5 100644 --- a/lib/bladerf/bladerf_common.h +++ b/lib/bladerf/bladerf_common.h @@ -83,6 +83,7 @@ protected: std::string _pfx; bool _xb_200_attached; + bool _xb_200_auto_filter; /* BladeRF IQ correction parameters */ static const int16_t DCOFF_SCALE = 2048; diff --git a/lib/bladerf/bladerf_sink_c.cc b/lib/bladerf/bladerf_sink_c.cc index c230e41..32fbd5e 100644 --- a/lib/bladerf/bladerf_sink_c.cc +++ b/lib/bladerf/bladerf_sink_c.cc @@ -183,6 +183,24 @@ double bladerf_sink_c::set_center_freq( double freq, size_t chan ) boost::lexical_cast<std::string>(freq) + ":" + std::string(bladerf_strerror(ret))); } + + if (_xb_200_auto_filter) { + bladerf_xb200_filter filter = BLADERF_XB200_CUSTOM; + if ( freq >= 50e6 && freq <= 54e6 ) { + filter = BLADERF_XB200_50M; + } else if ( freq >= 149e6 && freq <= 159e6 ) { + filter = BLADERF_XB200_144M; + } else if ( freq >= 206e6 && freq <= 235e6 ) { + filter = BLADERF_XB200_222M; + } + + if (bladerf_xb200_set_filterbank(_dev.get(), BLADERF_MODULE_TX, filter)) { + throw std::runtime_error( std::string(__FUNCTION__) + " " + + "Failed to auto set XB-200 filter at frequency " + + boost::lexical_cast<std::string>(freq) + + ":" + std::string(bladerf_strerror(ret))); + } + } } return get_center_freq( chan ); diff --git a/lib/bladerf/bladerf_source_c.cc b/lib/bladerf/bladerf_source_c.cc index d7eaeeb..3b1b5c8 100644 --- a/lib/bladerf/bladerf_source_c.cc +++ b/lib/bladerf/bladerf_source_c.cc @@ -232,6 +232,24 @@ double bladerf_source_c::set_center_freq( double freq, size_t chan ) boost::lexical_cast<std::string>(freq) + ": " + std::string(bladerf_strerror(ret)) ); } + + if (_xb_200_auto_filter) { + bladerf_xb200_filter filter = BLADERF_XB200_CUSTOM; + if ( freq >= 50e6 && freq <= 54e6 ) { + filter = BLADERF_XB200_50M; + } else if ( freq >= 149e6 && freq <= 159e6 ) { + filter = BLADERF_XB200_144M; + } else if ( freq >= 206e6 && freq <= 235e6 ) { + filter = BLADERF_XB200_222M; + } + + if (bladerf_xb200_set_filterbank(_dev.get(), BLADERF_MODULE_RX, filter)) { + throw std::runtime_error( std::string(__FUNCTION__) + " " + + "Failed to auto set XB-200 filter at frequency " + + boost::lexical_cast<std::string>(freq) + + ":" + std::string(bladerf_strerror(ret))); + } + } } return get_center_freq( chan ); -- 1.9.1
To enable the XB200 in software that utilizes gr-osmosdr, add 'xb200' to the source/sink arguments string. By default, the custom filter banks will be selected. Therefore, you must have the FILT and FILT-ANT connected through a filter, or directly connected together (no filter).
If you wish to select one of the other filter paths, append one of the following to the source/sink arguments string:
xb200filt=50M
xb200filt=144M
xb200filt=222M
-
xb200filt=auto
- This option will select an appropriate filter path based upon the selected center frequency.