Posted by & filed under bladeRF.

The 2016.01-rc1 release is available on GitHub.

Happy new year, everyone! This release includes a number fixes and some great new features. Notable items in this release are:

  • A redesigned Object-Oriented MATLAB® interface and Simulink® support via a System Object.
  • Support for taming the bladeRF’s on-board VCTCXO via a 1.8V 1 PPS or 10 MHz input
  • Support for setting the SMB clock output to an arbitrary frequency.
  • Revised and MIT-licensed DC offset calibration routines.
  • FX3 firmware updates:
    • Upgraded to Cypress FX3 SDK v1.3.3
    • A simple error logging mechanism for the FX3 firmware.
  • XB-100 support for libbladeRF and the bladeRF-cli
  • TX-side fixes in libbladeRF

For Windows® users, a new installer is available, along with an updated install guide.

Redesigned MATLAB® & Simulink® support

To better serve bladeRF users interested in leveraging MathWorks® products, we’ve re-designed and re-written our support for these tools from the ground up to yield a more intuitive interface and increased performance. We’ve pleased with the results so far, and hope you will be too!

This new implementation has been pulled into the main bladeRF repository and may be found here.

The driving goal behind this implementation was simplicity, in terms of both usability and implementation. We wished to keep the code between the user and libbladeRF as “thin” as possible, to minimize required maintenance efforts. To achieve this, we created a simple Object-Oriented interface atop of libbladeRF using loadlibrary() and calllib() calls to libbladeRF are made by accessing properties of a bladeRF and calling its wrapper methods.

Below are just few snippets to exemplify this new interface. In future blog posts, we’ll cover more advanced usage of both RX and TX timestamp functionality. Note that one can run the command, doc bladeRF, for more information.

MATLAB® Snippets

Query version information:

>> [major, minor, patch] = bladeRF.version;
>> fprintf('bladeRF MATLAB bindings v%d.%d.%d\n', major, minor, patch)
bladeRF MATLAB bindings v0.1.1
>> [major, minor, patch, ver_string] = bladeRF.library_version;
>> fprintf('libbladeRF %s\n', ver_string)
libbladeRF 1.5.0-git-7f6a461

Probe and display available devices:

>> devices = bladeRF.devices();
>> for n = 1:length(devices)
>>     fprintf('Instance: %2d, Bus: %2d, Address: %2d, Backend: %s, Serial: %s\n', ...
>>             devices(n).instance, devices(n).usb_bus, devices(n).usb_addr, ...
>>             strrep(devices(n).backend, 'BLADERF_BACKEND_', ''), ...
>>             devices(n).serial);
>> end; 
Instance:  0, Bus:  2, Address:  2, Backend: LIBUSB, Serial: b57e7faa1df48fe26d1bf1df03346708
Instance:  1, Bus:  1, Address: 11, Backend: LIBUSB, Serial: e3f9dbf3143e436542cb0f3ae947caab

Instantiate a bladeRF object b and connect to the first available device:

>> b = bladeRF 
b = 
  bladeRF with properties:
          rx: [1x1 bladeRF_XCVR]
          tx: [1x1 bladeRF_XCVR]
      vctcxo: [1x1 bladeRF_VCTCXO]
    loopback: 'NONE'
        info: [1x1 struct]
    versions: [1x1 struct]
          xb: 'None'

The same as the above, but open a device whose serial number starts with “4fb”:

>> b = bladeRF('*:serial=e3f');

Configure RX parameters:

>> b.rx.frequency  = 915.25e6;
>> b.rx.samplerate = 5e6;
>> b.rx.bandwidth  = 3e6;
>> b.rx.lna        = 'MAX';
>> b.rx.vga1       = 30;
>> b.rx.vga2       = 5;

Run DC Calibrations

>> % Run all LMS6002D calibration
>> b.calibrate('ALL');
>> % Calibrate at the current frequency. Note that frequency lists can be used.
>> % See 'help bladeRF_IQCorr.auto_dc'
>> b.rx.corrections.auto_dc();
ans =
  -32.0000  576.0000    0.0002    0.0004

Receive and plot the FFT of 50,000 samples:

>> b.rx.start(); samples = b.receive(50e3); b.rx.stop();
>> pwelch(samples, [], [], b.rx.samplerate, 'centered');

Example result: Stereo FM from a wireless headphones

Deallocate bladeRF object b and close the device:

clear b;

Note: The device is only closed once all handle references have been cleared. (MATLAB inherently provides reference counting of handles.)

bladeRF_rx_gui Demo

The bladeRF_rx_gui.m example puts together the above concepts to create an interactive GUI that provides access to various device properties while displaying
live plots. Here are a few screenshots of it in action:

Simulink® System Object

The bladeRF_Simulink.m file implements a System Object that can me used in am model file via the MATLAB System. Instructions near the end of the Windows® Install Guide describe how to place this in a model and to configure it to RX, TX, or both.

We’ll plan to post more about this in future posts.

VCTCXO Taming via 1 PPS or 10 MHz input

In terms of stability, we’ve been quite pleased with the VCTCXO we’ve used on the bladeRF. However, oscillators will eventually age over time and drift from their calibrated frequency. Furthermore, many bladeRF users are interested in celluar applications, which require significant frequency accuracy.

Thanks to the excellent work of Brian Glod, FPGA v0.5.0 now includes the ability to continuously tame the VCTXCO using a 1.8V 1 PPS or 10 MHz input signal supplied via J71 pin 1. The libbladeRF functions, bladerf_set_vctcxo_tamer_mode() and bladerf_get_vctcxo_tamer_mode() may be used to enable and configure this functionality.

The same can be done in the bladeRF-cli:

bladeRF> set vctcxo_tamer 10MHz

  VCTCXO tamer mode: 10 MHz

# Wait some amount of time. More than 10 seconds should provide a
# very rough VCTCXO trim DAC estimate. 10 minutes should yield
# a more accurate estimate.

bladeRF> print trimdac
 Current VCTCXO trim: 0x8759
 Stored VCTCXO trim:  0x8b28

As we can see in the above, the nominal VCTCXO trim DAC value has deviated slightly from the factory calibrated value. Below we show how to update the value in flash for a bladeRF x40 device. (Simply change the “40” to “115” for an x115.)

bladeRF> set vctcxo_tamer off

  VCTCXO tamer mode: Disabled

bladeRF> flash_init_cal 40 0x8759
[INFO @ usb.c:498] Erasing 1 blocks starting at block 3
[INFO @ usb.c:503] Erased block 3
[INFO @ usb.c:511] Done erasing 1 blocks
[INFO @ usb.c:705] Writing 1 pages starting at page 768
[INFO @ usb.c:709] Writing page 768
[INFO @ usb.c:718] Done writing 1 pages
bladeRF> quit

Below is a picture of a setup using a Leo Bodnar Precision Frequency Reference (GPS Clock),
configured for a 10 MHz output with 16 mA drive strength (configuration). Because this device provides a 3.3V signal and the FPGA input requires 1.8V, a 10 dB attenuator is used. Although the resulting voltage is closer to 2.0V, this is still well within the acceptable limits of the associated Cyclone IV IO bank. (We don’t recommend going much higher, however.)

GPSDO test setup

As shown above, J71-1 is connected to the 10 MHz output, through the attenuator. J72-2 is a connection to ground. One oscilloscope probe is monitoring the VCTCXO trim DAC voltage, via TP40. Another is monitoring the input on J72-1.

We can monitor the VCTCXO tamer via the trim DAC voltage, as shown in the following oscilloscope captures. In the first capture, we can clearly see the different stages of the tamer implementations. Prior to enabling the tamer, we see the factory calibrated value, which is quite close to the final result!

Once the tamer has been enabled, it first calculates the frequency errors obtained when using the minimum and maximum VCTCXO trim DAC values. The tamer then makes an initial coarse guess at the required trim DAC value using a linear approximation of the frequency-error response.

VCTCXO coarse tuning

After obtaining an initial guess the tamer begins running a continuous fine tune operation. In this stage, the tamer tracks frequency error over 1-second, 10-second, and 100-second intervals and updates the VCTCXO trim DAC value, based upon the magnitude of the detected error.

In the below capture, we can see the tamer reacting to an environmental stimulus, in which warm air was blown at the VCTCXO. In response to this stimulus, the tamer slightly increases the trim DAC voltage to compensate. It then reduces it once the stimulus has been removed.

VCTCXO fine tuning

Arbitrary SMB Output Frequencies

It is now possible to configure the bladeRF’s SMB clock output to generate arbitrary frequencies, thanks to a patch set kindly provided by Adam Greig. This functionality is exposed via the following libbladeRF functions:

This can be achieved in the bladeRF-cli via an added optional frequency argument to the set mimo command:

set mimo master <frequency>

DC offset calibration routines

The DC offset calibration routines have been revamped to address some of the issues reported on our GitHub tracker and to yield improved performance. In the near future we’ll be adding the ability to perform the TX calibration in an external loopback configuration; this should help yield even better results on the transmit side. On the RX side, we recommend disconnecting and/or terminating the RX input when performing this calibration.

In order to allow users to integrate these routines (and modifications) into their own projects, they have been relicensed under an MIT license. You can now find dc_calibration.h and dc_calibration.c in the bladeRF repository’s host/common directory.

Firmware Updates

The FX3 firmware and its associated build have been updated for version 1.3.3 of the SDK. For those developing firmware modifications, the only required changes are likely a change of FX3_ROOT in the file.

To assist with debugging, a simple logging mechanism has been added to the firmware. This log may be accessed via the libbladeRF bladerf_get_fw_log() function. The bladeRF-cli provides a fw_log command atop of this function.

XB-100 Support in libbladeRF and bladeRF-cli

The XB-100 was originally intended to help folks developing on the FPGA access a few spare I/O pins while debugging. However, there’s been some interest in using this for other purposes, such as controlling a T-R switch (with proper isolation and logic level conversion, of course) from host software.

bladerf_expansion_attach() now supports the XB100, and convenience macros for I/O mappings the XB100 and XB200 have been added. It is possible to access a subset (including a single pin) of the expansion port I/O via these libbladeRF functions and macros.

The bladeRF-cli exposes these functions via the xb_gpio and xb_gpio_dir, and allows either the entire GPIO (direction) register to be accessed, or an individual pin to be accessed. More information about this can be found here on our wiki.

TX Buffering Fixes

This latest release includes an important fix that addresses a defect in which not all available TX-side buffers were being utilized. If you had previously run into any issues pertaining to transmit underruns, please give these latest changes a shot.


Per request, we’ve introduced a LIBBLADERF_API_VERSION macro to libbladeRF.h to better allow developers to test for the availability of some of the aforementioned new API features at compile-time.

Wrapping Up

While keeping busy, we know we let our blog become a bit inactive. One of our New Year’s resolutions is to change this, and we certainly appreciate any help that members of the SDR community would like to offer. If you have a project or product using the bladeRF, please feel free to contact us to tell us all about it. We’d be happy to give it a spin and post about it here.

As always, thank you so much to everyone in the community for contributing fixes, bug reports, feedback, suggestions, and so much more. In particular, we’d like to thank:


Jon (jynik)

Posted by & filed under bladeRF.

Save on shipping – buy a bladeRF at DEFCON 23!

Nuand will be selling the bladeRF (both x40 and x115), cases, the XB-200 transverter, and GPIO expansion boards at our booth.

Whether you’re new to SDR or a bladeRF veteran, please feel free to swing by to chat and grab some free stickers!

When not at the booth, a few of us will be hanging out in the Wireless Village, where the Wireless Capture the Flag (WCTF) is taking place. If you’d like some help getting started with the bladeRF, introduce yourself and we’ll be happy to help!

If you don’t already own a bladeRF, you might want to give the WCTF a shot. Word on the street is that a couple are being given away as prizes… ­čśë
Nuand getting ready for DEFCON!

Posted by & filed under bladeRF.

The 2015.07 release is available on GitHub.

This release includes some bug fixes and cleanup since the 2015.06-rc1 release. If you haven’t checked it out already, see the 2015.06-rc1 release blog post for some detailed information about tuning-time improvements, scheduled and quick retune functionality, and NIOS II software redesign. FPGA v0.3.4 is included in this release, so be sure to great the latest and greatest from the FPGA downloads page.

Per request, one handy little addition was introduced into libbladeRF — the ability to specify the device to open via a subset of its serial number. This makes life a bit easier for folks using multiple devices with the bladeRF-cli or GNU Radio. As of gr-osmosdr changeset 86ad584, one can use either the “instance” number or the first few characters of the serial number to specify the device to open.

For example, to transmit from one bladeRF with a serial number f12ce1037830... to a second bladeRF with serial number ef6f831d4e4e...:

$ osmocom_fft -a "bladerf=f12" -s 20M -f 910M &
$ osmocom_siggen -a "bladerf=ef6" -s 20M -f 910M --2tone -x 1.25M -y 2.5M &

– Jon (jynik)

Posted by & filed under bladeRF.

The 2015.06-rc1 release is available on GitHub.

It has taken a little longer than we hoped for this rc1 release, but there are some pretty fun and interesting updates included:

  • A redesign of the NIOS II [1] code running on the FPGA
  • An overall speed increase in retuning the LMS6002D
  • Scheduled retune operations – tuning at a specified timestamp counter value
  • “Quick retune” functionality – quickly restore previously identified tuning parameters

Be sure to check out the updated API docs for more details on the new frequency tuning options and improvements.

Over the summer, keep an eye on the nuand-papers repository, where we’ll be looking to upload documents associated with items we’re working on adding to the bladeRF examples directory. Currently, a draft of a paper on the design and implementation of an FRS transceiver using GNU Radio and the bladeRF is posted. We know some solid examples (beyond the simple test programs) are long overdue, and would appreciate any feedback, ideas, patches, or submissions to help move those along.

[1] The NIOS II is a soft-core processor running on the bladeRF’s FPGA. It’s used as a simple means to configure/control both peripherals on the bladeRF and modules in the FPGA’s programmable fabric.


NIOS II Code Redesign

A few months ago, Cameron Karlsson announced on our IRC channel (#bladeRF on Freenode) that he had redesigned the bladeRF NIOS II code for improved extensibility and readability.

Previously, the NIOS II code had used a single message format for communicating host to FPGA requests for control operations, such as accessing 8-bit LMS6002D and Si5338 registers. As other functionality was added, fitting 32 and 64-bit accesses into an interface designed for 8-bit register accesses became rather messy. Furthermore, there were a very limited number of ID bits to denote the target device to access. This did not leave much room for users to customize and expand on this code.

Cameron proposed and implemented lots of cleanup, which provided us with a vast amount of excellent feedback. Cameron also introduced the notion of having different “state machine” implementations that could handle different message formats. This would allow contributors to more easily introduce new functionality with its own message format. While the proposed abstractions made the code much easier to grok, we did see some slowdown in the time needed to complete register accesses.

After reviewing and benchmarking his code, we bounced some additional ideas around with Cameron for another iteration over the proposed changes. We then set to work on the design included in this release. You can find an overview of the new NIOS II code in the updated

We further expanded Cameron’s state machine idea into a “packet handler” interface that provides the ability to: handle a request, provide a response, and queue up deferred work. We then migrated all of the existing requests to the packet formats listed in the aforementioned README. Compatibility with the previous message structure has been maintained though a nios_pkt_legacy format, which ensures older libbladeRF versions continue to operate with newer FPGAs.

As we’ll see below, the notion of “deferred work” was driven by the desire to be able to schedule retune operations. In order to support deferred work, the polling UART peripheral used by the NIOS II was replaced with a custom interrupt-driven “command UART.” This implementation takes care of queuing up an entire request (dropping those with invalid “magic” byte values) before alerting the NIOS II code to the presence of a new request. This frees up the code to iterate over the packet handlers and perform any deferred work because it’s no longer polling the UART for every single byte of the request.

The new packet formats are designed to have a fixed length and many of them only use a subset of the 16-bytes (required for the FX3 UART DMA transfer). Therefore, a future optimization we could make is to fire the “request available” interrupt when the necessary subset of bytes for a particular packet are received. This would allow us to begin handling the request and even sending back the response before reception of all 16 bytes completes. (Patches welcome! ­čśÇ)

After making these changes and re-running a simple timing test, we found that our peripheral access times were not only back to the original values, but consistently a few tens of microseconds faster. Not too shabby!


Improving LMS6002D Tuning Times

We’ve had a large number of requests to be able to support faster re-tuning in order to allow people to write code for sweeping more than 28 MHz of spectrum and to implement simple forms of frequency hopping.

As of the previous (2015.02) release, we measured our bladerf_set_frequency() call to require
~11 ms on USB 3.0, and ~22 ms on USB 2.0. If you take a quick look at our overview of frequency tuning on the bladeRF, or a detailed review of sections 3.4 and 4.6 in the LMS6002D Programming and Calibration Guide, you’ll see a number of register settings are changed each time you retune the device. Many of those┬áregisters contain bits that control other features, necessitating read-modify-write (RMW) operations. By running bladeRF-cli -e 'set frequency 2.415G' -v verbose, you can get a sense of just how many register accesses are involved — it’s quite a few!

As indicated by the differences in times measured for USB 3.0 and USB 2.0, incurring USB overhead for every register access is rather significant.
Therefore, we sought to build the LMS6002D returning code into the FPGA’s NIOS II.

First, the code used to retune the LMS6002D was split into two parts:

  • A section that computes the register values required to tune the device to the specific frequency.
  • The application of those register values and execution of the retune algorithm.

The lms.c code was updated such that it could be build for both the libbladeRF and the NIOS II, and moved to the fpga_common directory. When configured for the FPGA-based tuning mode, the computation of register values is still done on the host. However, instead of issuing control transfers for every register access request, a single transfer containing a newly introduced nios_pkt_retune packet is issued. In response to this, the second set of operations listed above are all performed by the NIOS II code running in the FPGA.

Note that it is still possible to perform entirely “host-based” retuning via bladerf_set_tuning_mode() or the BLADERF_DEFAULT_TUNING_MODE environment variable.

Initially we did not achieve the speed up we expected, considering the clock rate used on the LMS6002D SPI interface. Further investigation [2] showed that this was due to the amount of time between chip select assertion and the clocking of data, as well as a delay between successive bytes.

As shown in the following capture, a single LMS access (consisting of an address byte and a data byte) was taking ~9.6 ╬╝s. The time between the address byte and data byte was approximately 5.71 ╬╝s.


LMS register access taking 9.6 ╬╝s


In short, registers accesses using the generic NIOS II SPI controller were spending more time doing “nothing” than actually communicating data. Since we’re only using the SPI controller for LMS6002D accesses, Brian Glod switched this out with an LMS6002D-specific SPI controller. This reduces an LMS6002D register access to under 1 ╬╝s (zoomed in):


LMS6002D register access in under 1 ╬╝s


An astute reader might notice that the actual transaction, as measured by the duration of the clocks, appears longer. For this release, we reduced the LMS SPI clock from 40 MHz to 20 MHz, due to some timing constraints that were just barely failing at 40 MHz. We’ll be looking to address this and increase the clock back up to 40 MHz. Nonetheless, the new SPI controller allows bladerf_set_frequency() to be performed significantly faster:

  • Host-only tuning on USB 3.0 dropped from 12 ms to 5 ms (2.4x speedup)
  • The FPGA tuning mode reduces that 12 ms to…
    • under 700 ╬╝s for the NIOS II/e core (17.1x speedup)
    • under 450 ╬╝s for the NIOS II/f core (26.7x speedup)

Again, not too shabby — and we haven’t even gotten to the “quick retune” functionality yet! Although not listed above, the speedups on USB 2.0 are equally pleasing.

In the near future, we’ll add support to this controller for accessing multiple registers within a SEN window. Since the register values are not applied to the device until the rising edge of SEN, it would be much more desirable for PLL changes, which are spread across multiple contiguous registers, in a single operation. (This will alleviate some spurious emissions that can occur while retuning with the transmitter enabled.)

[2] Note: The easiest way to place oscilloscope or logic analyzer probes on the LMS6002D SPI interface’s SEN and CLK is using the AB16 and AA15 vias exposed on the bottom of the board.


Scheduled Retunes

One feature we’ve been wanting to introduce is the ability to schedule a retune to occur at a specified sample timestamp value. (For those that are not familiar with it, libbladeRF allows you to transmit and receive samples using some metadata.)

This ability to schedule retunes in relation to transmitted/received is intended to make sweeping or hopping very straight-forward, once you have a sense of how long the underlying retuning operation takes to complete. In essence, you can:

  • Schedule transmission or reception of samples at some timestamp value T via bladerf_sync_tx() or bladerf_sync_rx()
  • Schedule a retune to occur some time R after T + num_samples via bladerf_schedule_retune()
  • Schedule the next TX/RX operation to occur after R + retune_duration. The upper bound for retune_duration will depending on the frequencies one is changing from/to, so you should do some experimenting to ensure you have sufficient “wiggle room” for your particular application.

To implement this functionality, the “Time Tamers” (timestamp counter modules) in the FPGA were separated and updated to provide programmable interrupt functionality. A timestamp field in the nios_pkt_retune format allows the host to specify the relative time at which the retune should take place. The NIOS II code uses the Time Tamer’s programmable interrupt to schedule and trigger a retune callback. In the event that the provided timestamp is in the past, the Time Tamers will immediately fire their interrupts.

Multiple retune requests (currently up to 16) may be queued up. This allows the host to schedule multiple retunes in advance rather than needing to quickly submit the retune request directly beforehand. These queued up operations can also be canceled from the host. The underlying retune queues are flushed when bladerf_open and bladerf_close are called in order to prevent the device from unexpectedly returning on successive uses.

Some test code to exercise this functionality may be found in the libbladeRF_scheduled_retune directory.


“Quick Retune” functionality

It is possible to achieve even quicker retuning by simply saving the final results of the LMS6002D tuning algorithm and re-applying them to registers later. However, this speed increase comes with a trade-off in phase noise. The parameters used to tune the LMS6002D are subject to environmental change, so the register settings from prior results will not necessarily remain the “ideal” values for a particular frequency. Nonetheless, one could update these values by performing a full retune, and then fetching the quick retune parameters at regular intervals.

As you may have already noted, the bladerf_scheduled_retune() function takes an optional pointer to a bladerf_quick_tune structure. The below example, included in the API docs, exemplifies its usage:

    int status;
    unsigned int i, j;
    const unsigned int frequencies[NUM_FREQUENCIES] = {
    struct bladerf_quick_tune quick_tunes[NUM_FREQUENCIES];
    /* Get our quick tune parameters for each frequency we'll be using */
    for (i = 0; i < NUM_FREQUENCIES; i++) {
        status = bladerf_set_frequency(dev, module, frequencies[i]);
        if (status != 0) {
            fprintf(stderr, "Failed to set frequency to %u Hz: %s\n",
                    frequencies[i], bladerf_strerror(status));
            return status;
        status = bladerf_get_quick_tune(dev, module, &quick_tunes[i]);
        if (status != 0) {
            fprintf(stderr, "Failed to get quick tune for %u Hz: %s\n",
                    frequencies[i], bladerf_strerror(status));
            return status;
    for (i = j = 0; i < ITERATIONS; i++) {
        /* Tune to the specified frequency immediately via BLADERF_RETUNE_NOW.
         * Alternatively, this re-tune could be scheduled by providing a
         * timestamp counter value */
        status = bladerf_schedule_retune(dev, module, BLADERF_RETUNE_NOW, 0,
        if (status != 0) {
            fprintf(stderr, "Failed to apply quick tune: %s\n",
            return status;
        j = (j + 1) % NUM_FREQUENCIES;
        /* ... Handle signals at current frequency ... */

Using this functionality reduces the original 12 ms host-based retune time (on USB 3.0) down to…

  • Under 250 ╬╝s for the NIOS II/e core (48x speedup)
  • Under 150 ╬╝s for the NIOS II/f core (80x speedup)

Definitely not too shabby, if you can handle the trade-offs! Here’s a quick capture of this quick retune functionality in action with some CPFSK bursts.

Bursts of CPFSK data hopping using the bladerf_quick_tune functionality.

Thank you!

As always, a big thank you goes out to everyone who has provided feedback, bug reports, patches, and kind words. We really appreciate it, and it’s a pleasure to chat and collaborate with you all via IRC, the forums, and email. Your ongoing support is what makes this project so enjoyable to work on!

We look forward to pulling in some very cool contributions in the coming months, as well as developing some interesting examples and content. We hope you’ll join in the fun!

– Jon (jynik)

Posted by & filed under bladeRF.


If you have accidentally erased your VCTCXO calibration after running kalibrate-bladeRF you can now automatically retrieve your unit’s factory calibration value┬áthrough our online tool. The tool and instructions can be found at┬á . To retrieve your calibration value you will need your serial number. The simplest way to retrieve your bladeRF’s serial number is to probe the device from the command line by running bladeRF-cli -p.

$ bladeRF-cli -p
 Backend: libusb
 Serial: f12ce1037830a1b27f3ceeba1f521413
 USB Bus: 4
 USB Address: 8


Once the system retrieves your calibration value, you will have to write it back to your bladeRF using bladeRF-cli. The flash_init_cal command takes two arguments, the variant of your bladeRF (x40 or x115) and the calibration value.

The calibration retrieval tool will automatically prepare the flash_init_cal command for your device. For example, serial number f12ce1037830a1b27f3ceeba1f521413 corresponds to a bladeRF x40 with a factory VCTCXO calibration value of 0x7a69. The tool automatically prepared the commands to calibrate the device:

$ bladeRF-cli -i
 bladeRF> flash_init_cal 40 0x7a69

Please see the the sample serial number calibration retrieval for more information,