![]() |
libbladeRF
2.5.0
Nuand bladeRF library
|
This page describes how to use the bladeRF Synchronous Interface to transmit and receive samples.
The example listed here configures and uses both the RX and TX channels. To use just one or the other, simply remove the code for the unneeded channel.
First, one must allocate any "working buffers" in which samples will be stored. These are the rx_samples
and tx_samples
buffers shown in the below snippet. The samples_len
variable defines the length of these buffers, in units of samples. Remember, when using the SC16 Q11 format, one sample consists of two int16_t
values: I and Q, and when using 2x2 MIMO, samples from two channels are interleaved.
libbladeRF's synchronous interface maintains its own set of internal buffers, which it uses to keep an underlying asynchronous data stream running. This alleviates the need for the user to handle asynchronous callbacks and managing buffer transfers. Instead, the synchronous interface simply copies data to/from the aforementioned "user" buffers, for arbitrary request lengths.
It is important to note, however, that users of the synchronous interface should still be conscious of the workings of the underlying Asynchronous Interface.
Before making calls to bladerf_sync_rx() and bladerf_sync_tx(), one must configure the underlying stream using the bladerf_sync_config() function, as shown in the following snippet.
The second argument to bladerf_sync_config() specifies the channel direction and layout. In the case of SISO (1x1), we use BLADERF_RX_X1 and BLADERF_TX_X1 layouts for RX and TX, respectively.
If one forgets to configure the synchronous interface before attempting to call bladerf_sync_rx() or bladerf_sync_tx(), a BLADERF_ERR_INVAL status will be returned.
The buffer_size
parameter configures the size of the buffers, in units of samples, that are sent to/from the hardware via the USB interface. These must be a multiple of 1024. Smaller values will help minimize latency, but will require that the user can process samples quickly. If one does not have low-latency constraints, buffer sizes of 8192 or 16384 are generally good starting points.
The num_buffers
parameter defines how many internal samples buffers should be allocated and used by the interface. A large number of buffers ensures that the buffers can continue to be filled/consumed while the user operates on samples, with a potential trade-off of increased latency. If this number is too small one may risk overrunning RX buffers, or underrunning TX buffers.
The num_transfers
parameter defines how many of these buffers may be in-flight at any given point in time. As a rule of thumb, a value that is less than or equal to half the number of buffers is a good starting value. Note that the maximum value may be limited by the underlying (USB) layer. It is generally not necessary (or sometimes even possible) to exceed a value of 32 transfers.
The timeout_ms
parameter defines a maximum amount of time that is allowed between completion of the synchronous interface's underlying stream buffers. Take care to ensure that this value is sufficiently large, considering the sample rate being used and the desired size of stream buffers.
After configuring the synchronous interface, one must also enable the RF front end of the associated stream direction(s), via bladerf_enable_module():
The bladerf_sync_rx() and bladerf_sync_tx() functions are used to receive and transmit an arbitrary number of samples.
Remember that when transmitting, the samples will only be sent to the hardware once an underlying stream buffer has been filled (whose size was defined by the buffer_size
parameter provided to bladerf_sync_config()). Therefore, when transmitting a small number of samples, one may need to zero-pad or configure the interface to use small buffers.
Below is an example loop that receives samples, processes them, and occasionally transmits a response.
Since metadata is not being used, a NULL
pointer is provided to the bladerf_metadata parameter of the bladerf_sync_rx and bladerf_sync_tx calls.
The timeout (in ms) parameter defines how long bladerf_sync_rx() and bladerf_sync_tx() may block. This value should be greater than the timeout provided to bladerf_sync_config() to ensure these functions do not time out before the underlying data stream times out (or completes).
At the end of this loop, a usleep()
call is made to ensure buffers of transmitted samples finally reach the RF front end. Note that the lower bound this delay is determined by the number of buffers that may have been filled by bladerf_sync_tx() and the sample rate.
When finished using a stream, bladerf_enable_module() may be used to turn off the associated RF front end. This will also de-initialize and deallocate the underlying data associated with the stream.