Using similar code, but with the addition of the DmaFIFO to the chain, I have created the attached source code. Additionally, I have attached a "log" file which shows the command line parameters as well as the response for an individual run. I have a few remarks:
- In general, the code works in that I can repetitively stream the desired waveform file and it looks as expected on a signal analyzer. However, it is not well optimized such that when I increase the streaming rate to 100 MS/s, I get errors (and sometimes see a couple of issues at 50 MS/s. - In the log file, you will find some "L" and many "U". This was actually a "good" run. In additional runs, there were many more "U" that continued throughout the run - If instead of this rfnoc tx example, I use a multi_usrp object to handle the details of connecting the blocks and streaming the data, I have no problems (no "L" or "U"), even at 100 MS/s - So, it seems clear to me that I have not connected / configured the blocks optimally Here are my questions: - What am I doing wrong that is causing the sub-optimal streaming? - Why do I get the following warnings? Could this explain the sub-optimal streaming? What is the correct way to configure SPP for each block or connection? - [WARNING] [RFNOC] Assuming max packet size for 0/DmaFIFO_0 - [WARNING] [RFNOC] Assuming max packet size for 0/DUC_0 - Why do I get the following error message upon program termination? - AssertionError: [0/DmaFIFO_0] Attempting to disconnect input port 0, which is not registered as connected! Thanks for any help. Rob On Thu, Sep 20, 2018 at 7:22 PM Ryan Marlow via USRP-users < usrp-users@lists.ettus.com> wrote: > Hey Leo, > Glad to hear you were able to work things out. One quick note about the > code I attached previously. Located a minor typo/bug that you'll want to > fix if you want to actually transmit useful data. > >> 219 radio_ctrl->set_rx_frequency(freq, radio_chan); >> > should be: > >> 219 radio_ctrl->set_tx_frequency(freq, radio_chan); >> > Notice the change from rx->tx. > Best, > Ryan Marlow > > > On Thu, Sep 20, 2018 at 10:35 AM, Leandro Echevarría < > leoechevar...@gmail.com> wrote: > >> Hey Ryan, >> >> Thanks a lot! I actually ended up doing pretty much the exact same things >> you described, and came up with a piece of code very similar to yours. >> Yours is neater though, so I will keep it ;-). >> >> Regards, >> >> Leo >> >> On Wed, Sep 19, 2018 at 7:52 PM Ryan Marlow <r...@lmarlow.com> wrote: >> >>> Hey Leo, >>> I haven't seen anyone respond yet and I recently needed to develop a TX >>> RFNoC example of my own. I worked off the rfnoc_rx_to_file.cpp example. Far >>> from perfect, but it gets the job done (transmits data). The main changes >>> are: >>> - copied send_from_file function from tx_samples_from_file.cpp example >>> to handle the streaming of data from the input file >>> - reversed the order that blocks are connected in the graph->connect() >>> function. Now connects optional arg block -> radio. Was radio -> optional >>> arg block. >>> - uses tx_stream instead of rx_stream. >>> Just add this cpp file to the CMake file in the host/examples dir to >>> build it then try it out. >>> I ran it with: >>> build/examples$ ./rfnoc_tx_from_file --block-id DUC_0 --block-args >>> output_rate=200e6,input_rate=5e6 --duration 5 --file usrp_samples.dat >>> >>> Hope that helps, >>> Ryan >>> -- >>> Ryan L. Marlow >>> R L Marlow Consulting LLC >>> rlmarlow.com >>> >> > > > -- > Ryan L. Marlow > R L Marlow Consulting LLC > rlmarlow.com > _______________________________________________ > USRP-users mailing list > USRP-users@lists.ettus.com > http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com >
$ ./rfnoc_tx_samples_from_file --file=$HOME/Documents/waveforms/mtone_100_0p8_0_le.bin --freq=2400e6 --rate=100e6 --gain=0 Creating the USRP device with: . . . [INFO] [UHD] linux; GNU C++ version 5.4.0 20160609; Boost_105800; UHD_3.13.0.3-0-g85347b89 [INFO] [X300] X300 initialization sequence... [INFO] [X300] Maximum frame size: 8000 bytes. [INFO] [X300] Radio 1x clock: 200 MHz [INFO] [0/DmaFIFO_0] Initializing block control (NOC ID: 0xF1F0D00000000000) [INFO] [0/DmaFIFO_0] BIST passed (Throughput: 1309 MB/s) [INFO] [0/DmaFIFO_0] BIST passed (Throughput: 1298 MB/s) [INFO] [0/Radio_0] Initializing block control (NOC ID: 0x12AD100000000001) [INFO] [0/Radio_1] Initializing block control (NOC ID: 0x12AD100000000001) [INFO] [0/DDC_0] Initializing block control (NOC ID: 0xDDC0000000000000) [INFO] [0/DDC_1] Initializing block control (NOC ID: 0xDDC0000000000000) [INFO] [0/DUC_0] Initializing block control (NOC ID: 0xD0C0000000000000) [INFO] [0/DUC_1] Initializing block control (NOC ID: 0xD0C0000000000000) Using radio 0, channel 0 Using duc 0, channel 0 Using FIFO 0, channel 0 Setting TX Freq: 2400.000000 MHz... Actual TX Freq: 2400.000000 MHz... Setting TX Rate: 100.000000 Msps... DUC input rate: 100 MS/s; DUC output rate: 200 MS/s Setting TX Gain: 0.000000 dB... Actual TX Gain: 0.000000 dB... Using streamer args: block_id=0/DmaFIFO_0,block_port=0 Connecting... 0/DmaFIFO_0 ==> 0/DUC_0 [WARNING] [RFNOC] Assuming max packet size for 0/DmaFIFO_0 0/DUC_0 ==> 0/Radio_0 [WARNING] [RFNOC] Assuming max packet size for 0/DUC_0 Start streaming... Replaying data (Press Ctrl+C to stop)... LLLUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU^C Streaming stopped terminate called after throwing an instance of 'uhd::assertion_error' what(): AssertionError: [0/DmaFIFO_0] Attempting to disconnect input port 0, which is not registered as connected! Aborted (core dumped) $
// // Copyright 2018 Ettus Research, A National Instruments Company // // SPDX-License-Identifier: GPL-3.0-or-later // // // Description: // // This example demonstrates using the rfnoc blocks to play data from a file. #include <uhd/utils/safe_main.hpp> #include <uhd/device3.hpp> #include <uhd/rfnoc/radio_ctrl.hpp> #include <uhd/rfnoc/duc_block_ctrl.hpp> #include <uhd/rfnoc/block_ctrl.hpp> #include <uhd/utils/thread.hpp> #include <boost/program_options.hpp> #include <boost/format.hpp> #include <fstream> #include <csignal> #include <thread> namespace po = boost::program_options; using std::cout; using std::endl; /////////////////////////////////////////////////////////////////////////////// static volatile bool stop_signal_called = false; // Ctrl+C handler void sig_int_handler(int) { stop_signal_called = true; } int UHD_SAFE_MAIN(int argc, char *argv[]) { uhd::set_thread_priority_safe(); // We use sc16 in this example, but the replay block only uses 64-bit words // and is not aware of the CPU or wire format. std::string wire_format("sc16"); std::string cpu_format("sc16"); /////////////////////////////////////////////////////////////////////////// // Handle command line options std::string args, radio_args, file, ant, ref; double rate, freq, gain, bw; size_t radio_id, radio_chan, duc_id, duc_chan, fifo_id, fifo_chan, nsamps; po::options_description desc("Allowed Options"); desc.add_options() ("help", "help message") ("args", po::value<std::string>(&args)->default_value(""), "multi uhd device address args") ("radio-id", po::value<size_t>(&radio_id)->default_value(0), "radio block to use (e.g., 0 or 1).") ("radio-chan", po::value<size_t>(&radio_chan)->default_value(0), "radio channel to use") ("radio-args", po::value<std::string>(&radio_args), "radio arguments") ("duc-id", po::value<size_t>(&duc_id)->default_value(0), "duc block to use (e.g., 0 or 1)") ("duc-chan", po::value<size_t>(&duc_chan)->default_value(0), "duc channel to use") ("fifo-id", po::value<size_t>(&fifo_id)->default_value(0), "fifo block to use (e.g., 0 or 1).") ("fifo-chan", po::value<size_t>(&fifo_chan)->default_value(0), "fifo channel to use") ("nsamps", po::value<uint64_t>(&nsamps)->default_value(0), "number of samples to play (0 for infinite)") ("file", po::value<std::string>(&file)->default_value("usrp_samples.dat"), "name of the file to read binary samples from") ("freq", po::value<double>(&freq), "RF center frequency in Hz") ("rate", po::value<double>(&rate), "sample rate of host->usrp streaming") ("gain", po::value<double>(&gain), "gain for the RF chain") ("ant", po::value<std::string>(&ant), "antenna selection") ("bw", po::value<double>(&bw), "analog front-end filter bandwidth in Hz") ("ref", po::value<std::string>(&ref)->default_value("internal"), "reference source (internal, external, mimo)") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); // Print help message if (vm.count("help")) { cout << boost::format("UHD/RFNoC Replay samples from file %s") % desc << endl; cout << "This application uses the Replay block to playback data from a file to a radio" << endl << endl; return EXIT_FAILURE; } /////////////////////////////////////////////////////////////////////////// // Create USRP device and block controls cout << "Creating the USRP device with: " << args << ". . .\n" << endl; uhd::device3::sptr usrp = uhd::device3::make(args); // Create handle for radio object uhd::rfnoc::block_id_t radio_ctrl_id(0, "Radio", radio_id); uhd::rfnoc::radio_ctrl::sptr radio_ctrl; radio_ctrl = usrp->get_block_ctrl<uhd::rfnoc::radio_ctrl>(radio_ctrl_id); std::cout << "Using radio " << radio_id << ", channel " << radio_chan << std::endl; // Create handle for digital upconverter object uhd::rfnoc::block_id_t duc_ctrl_id(0, "DUC", duc_id); uhd::rfnoc::duc_block_ctrl::sptr duc_ctrl; duc_ctrl = usrp->get_block_ctrl<uhd::rfnoc::duc_block_ctrl>(duc_ctrl_id); std::cout << "Using duc " << duc_id << ", channel " << duc_chan << std::endl; // Create handle for DmaFIFO uhd::rfnoc::block_id_t fifo_ctrl_id(0, "DmaFIFO", fifo_id); uhd::rfnoc::block_ctrl_base::sptr fifo_ctrl; fifo_ctrl = usrp->get_block_ctrl<uhd::rfnoc::block_ctrl_base>(fifo_ctrl_id); std::cout << "Using FIFO " << fifo_id << ", channel " << fifo_chan << std::endl; /////////////////////////////////////////////////////////////////////////// // Configure radio and DUC // Lock clocks radio_ctrl->set_clock_source(ref); // Apply any radio arguments provided radio_ctrl->set_args(radio_args); // Set the center frequency if (not vm.count("freq")) { std::cerr << "Please specify the center frequency with --freq" << std::endl; return EXIT_FAILURE; } std::cout << boost::format("Setting TX Freq: %f MHz...") % (freq/1e6) << std::endl; radio_ctrl->set_tx_frequency(freq, radio_chan); std::cout << boost::format("Actual TX Freq: %f MHz...") % (radio_ctrl->get_tx_frequency(radio_chan)/1e6) << std::endl << std::endl; // Set the sample rate if (vm.count("rate")) { std::cout << boost::format("Setting TX Rate: %f Msps...") % (rate/1e6) << std::endl; //radio_ctrl->set_rate(rate); duc_ctrl->set_arg("input_rate",rate,duc_chan); duc_ctrl->set_arg("output_rate",radio_ctrl->get_rate(),duc_chan); std::cout << "DUC input rate: " << duc_ctrl->get_arg<double>("input_rate",duc_chan)/1e6 << " MS/s; DUC output rate: " << duc_ctrl->get_arg<double>("output_rate",duc_chan)/1e6 << " MS/s" << std::endl << std::endl; } // Set the RF gain if (vm.count("gain")) { std::cout << boost::format("Setting TX Gain: %f dB...") % gain << std::endl; radio_ctrl->set_tx_gain(gain, radio_chan); std::cout << boost::format("Actual TX Gain: %f dB...") % radio_ctrl->get_tx_gain(radio_chan) << std::endl << std::endl; } // Set the analog front-end filter bandwidth if (vm.count("bw")) { std::cout << boost::format("Setting TX Bandwidth: %f MHz...") % (bw / 1e6) << std::endl; radio_ctrl->set_tx_bandwidth(bw, radio_chan); std::cout << boost::format("Actual TX Bandwidth: %f MHz...") % (radio_ctrl->get_tx_bandwidth(radio_chan) / 1e6) << std::endl << std::endl; } // Set the antenna if (vm.count("ant")) { radio_ctrl->set_tx_antenna(ant, radio_chan); } // Allow for some setup time std::this_thread::sleep_for(std::chrono::milliseconds(1000)); /////////////////////////////////////////////////////////////////////////// // Setup streamer to DUC block uhd::device_addr_t streamer_args; uhd::stream_args_t stream_args(cpu_format, wire_format); uhd::tx_streamer::sptr tx_stream; streamer_args["block_id"] = fifo_ctrl->get_block_id().to_string(); streamer_args["block_port"] = str(boost::format("%d") % fifo_chan); stream_args.args = streamer_args; tx_stream = usrp->get_tx_stream(stream_args); //const size_t tx_spb = tx_stream->get_max_num_samps(); cout << "Using streamer args: " << stream_args.args.to_string() << endl; /////////////////////////////////////////////////////////////////////////// // Connect DmaFIFO->DUC->Radio uhd::rfnoc::graph::sptr tx_graph = usrp->create_graph("rfnoc_tx"); usrp->clear(); //int radio_spp = tx_spb; std::cout << "Connecting..." << std::endl; std::cout << " " << fifo_ctrl->get_block_id() << " ==> " << duc_ctrl->get_block_id() << std::endl; tx_graph->connect(fifo_ctrl->get_block_id(), fifo_chan, duc_ctrl->get_block_id(), duc_chan); std::cout << " " << duc_ctrl->get_block_id() << " ==> " << radio_ctrl->get_block_id() << std::endl << std::endl; tx_graph->connect(duc_ctrl->get_block_id(), duc_chan, radio_ctrl->get_block_id(), radio_chan); /////////////////////////////////////////////////////////////////////////// // Read the data to replay // Open the file std::ifstream infile(file.c_str(), std::ifstream::binary); if (!infile.is_open()) { std::cerr << "Could not open specified file" << std::endl; return EXIT_FAILURE; } // Get the file size infile.seekg(0, std::ios::end); size_t file_size = infile.tellg(); int num_samps = file_size / 4; // Create buffer std::vector<char> tx_buffer(num_samps*4); char* tx_buf_ptr = &tx_buffer[0]; // Read file into buffer, rounded down to number of words infile.seekg(0, std::ios::beg); infile.read(tx_buf_ptr, num_samps*4); infile.close(); /////////////////////////////////////////////////////////////////////////// // Stream the data cout << "Start streaming..." << endl; uhd::tx_metadata_t tx_md; tx_md.start_of_burst = true; tx_md.end_of_burst = false; tx_md.has_time_spec = true; tx_md.time_spec = radio_ctrl->get_time_now() + uhd::time_spec_t(1.0); /////////////////////////////////////////////////////////////////////////// // Wait until user says to stop // Setup SIGINT handler (Ctrl+C) stop_signal_called = false; std::signal(SIGINT, &sig_int_handler); cout << "Replaying data (Press Ctrl+C to stop)..." << endl; while (not stop_signal_called) { size_t num_tx_samps = tx_stream->send(tx_buf_ptr, num_samps, tx_md); //std::cout << "samps sent: " << num_tx_samps << std::endl; tx_md.start_of_burst = false; tx_md.has_time_spec = false; if (num_tx_samps != num_samps) { cout << boost::format("ERROR: Unable to send %d samples") % num_samps << endl; return EXIT_FAILURE; } } // Remove SIGINT handler std::signal(SIGINT, SIG_DFL); // send one more buffer with end-of-burst true tx_md.end_of_burst = true; tx_stream->send(tx_buf_ptr, num_samps, tx_md); std::cout << std::endl << "Streaming stopped" << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); return EXIT_SUCCESS; }
_______________________________________________ USRP-users mailing list USRP-users@lists.ettus.com http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com