diff options
Diffstat (limited to 'host/lib/usrp/e100/e100_impl.cpp')
-rw-r--r-- | host/lib/usrp/e100/e100_impl.cpp | 188 |
1 files changed, 120 insertions, 68 deletions
diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp index d610c0b12..a0fa6c47e 100644 --- a/host/lib/usrp/e100/e100_impl.cpp +++ b/host/lib/usrp/e100/e100_impl.cpp @@ -28,6 +28,7 @@ #include <boost/functional/hash.hpp> #include <boost/assign/list_of.hpp> #include <fstream> +#include <ctime> using namespace uhd; using namespace uhd::usrp; @@ -64,7 +65,7 @@ static device_addrs_t e100_find(const device_addr_t &hint){ new_addr["node"] = fs::system_complete(fs::path(hint["node"])).string(); try{ i2c_iface::sptr i2c_iface = e100_ctrl::make_dev_i2c_iface(E100_I2C_DEV_NODE); - const mboard_eeprom_t mb_eeprom(*i2c_iface, mboard_eeprom_t::MAP_E100); + const mboard_eeprom_t mb_eeprom(*i2c_iface, E100_EEPROM_MAP_KEY); new_addr["name"] = mb_eeprom["name"]; new_addr["serial"] = mb_eeprom["serial"]; } @@ -86,15 +87,6 @@ static device_addrs_t e100_find(const device_addr_t &hint){ /*********************************************************************** * Make **********************************************************************/ -static size_t hash_fpga_file(const std::string &file_path){ - size_t hash = 0; - std::ifstream file(file_path.c_str()); - if (not file.good()) throw uhd::io_error("cannot open fpga file for read: " + file_path); - while (file.good()) boost::hash_combine(hash, file.get()); - file.close(); - return hash; -} - static device::sptr e100_make(const device_addr_t &device_addr){ return device::sptr(new e100_impl(device_addr)); } @@ -114,13 +106,9 @@ static const uhd::dict<std::string, std::string> model_to_fpga_file_name = boost e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ _tree = property_tree::make(); - //setup the main interface into fpga - const std::string node = device_addr["node"]; - _fpga_ctrl = e100_ctrl::make(node); - //read the eeprom so we can determine the hardware _dev_i2c_iface = e100_ctrl::make_dev_i2c_iface(E100_I2C_DEV_NODE); - const mboard_eeprom_t mb_eeprom(*_dev_i2c_iface, mboard_eeprom_t::MAP_E100); + const mboard_eeprom_t mb_eeprom(*_dev_i2c_iface, E100_EEPROM_MAP_KEY); //determine the model string for this device const std::string model = device_addr.get("model", mb_eeprom.get("model", "")); @@ -133,20 +121,19 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //extract the fpga path and compute hash const std::string default_fpga_file_name = model_to_fpga_file_name[model]; - const std::string e100_fpga_image = find_image_path(device_addr.get("fpga", default_fpga_file_name)); - const boost::uint32_t file_hash = boost::uint32_t(hash_fpga_file(e100_fpga_image)); - - //When the hash does not match: - // - close the device node - // - load the fpga bin file - // - re-open the device node - if (_fpga_ctrl->peek32(E100_REG_RB_MISC_TEST32) != file_hash){ - _fpga_ctrl.reset(); - e100_load_fpga(e100_fpga_image); - _fpga_ctrl = e100_ctrl::make(node); + std::string e100_fpga_image; + try{ + e100_fpga_image = find_image_path(device_addr.get("fpga", default_fpga_file_name)); } + catch(...){ + UHD_MSG(error) << boost::format("Could not find FPGA image. %s\n") % print_images_error(); + throw; + } + e100_load_fpga(e100_fpga_image); - //setup clock control here to ensure that the FPGA has a good clock before we continue + //////////////////////////////////////////////////////////////////// + // Setup the FPGA clock over AUX SPI + //////////////////////////////////////////////////////////////////// bool dboard_clocks_diff = true; if (mb_eeprom.get("revision", "0") == "3") dboard_clocks_diff = false; else if (mb_eeprom.get("revision", "0") == "4") dboard_clocks_diff = true; @@ -158,12 +145,32 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ _aux_spi_iface = e100_ctrl::make_aux_spi_iface(); _clock_ctrl = e100_clock_ctrl::make(_aux_spi_iface, master_clock_rate, dboard_clocks_diff); + //////////////////////////////////////////////////////////////////// + // setup the main interface into fpga + // - do this after aux spi, because we share gpio147 + //////////////////////////////////////////////////////////////////// + const std::string node = device_addr["node"]; + _fpga_ctrl = e100_ctrl::make(node); + + //////////////////////////////////////////////////////////////////// + // Initialize FPGA control communication + //////////////////////////////////////////////////////////////////// + fifo_ctrl_excelsior_config fifo_ctrl_config; + fifo_ctrl_config.async_sid_base = E100_TX_ASYNC_SID; + fifo_ctrl_config.num_async_chan = 1; + fifo_ctrl_config.ctrl_sid_base = E100_CTRL_MSG_SID; + fifo_ctrl_config.spi_base = TOREG(SR_SPI); + fifo_ctrl_config.spi_rb = REG_RB_SPI; + _fifo_ctrl = fifo_ctrl_excelsior::make(_fpga_ctrl, fifo_ctrl_config); + //Perform wishbone readback tests, these tests also write the hash bool test_fail = false; - UHD_MSG(status) << "Performing wishbone readback test... " << std::flush; + UHD_MSG(status) << "Performing control readback test... " << std::flush; + size_t hash = time(NULL); for (size_t i = 0; i < 100; i++){ - _fpga_ctrl->poke32(E100_REG_SR_MISC_TEST32, file_hash); - test_fail = _fpga_ctrl->peek32(E100_REG_RB_MISC_TEST32) != file_hash; + boost::hash_combine(hash, i); + _fifo_ctrl->poke32(TOREG(SR_MISC+0), boost::uint32_t(hash)); + test_fail = _fifo_ctrl->peek32(REG_RB_CONFIG0) != boost::uint32_t(hash); if (test_fail) break; //exit loop on any failure } UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl; @@ -180,8 +187,7 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //////////////////////////////////////////////////////////////////// // Create controller objects //////////////////////////////////////////////////////////////////// - _fpga_i2c_ctrl = i2c_core_100::make(_fpga_ctrl, E100_REG_SLAVE(3)); - _fpga_spi_ctrl = spi_core_100::make(_fpga_ctrl, E100_REG_SLAVE(2)); + _fpga_i2c_ctrl = i2c_core_200::make(_fifo_ctrl, TOREG(SR_I2C), REG_RB_I2C); _data_transport = e100_make_mmap_zero_copy(_fpga_ctrl); //////////////////////////////////////////////////////////////////// @@ -189,7 +195,8 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //////////////////////////////////////////////////////////////////// _tree->create<std::string>("/name").set("E-Series Device"); const fs_path mb_path = "/mboards/0"; - _tree->create<std::string>(mb_path / "name").set(str(boost::format("%s (euewanee)") % model)); + _tree->create<std::string>(mb_path / "name").set(model); + _tree->create<std::string>(mb_path / "codename").set("Euwanee"); //////////////////////////////////////////////////////////////////// // setup the mboard eeprom @@ -204,12 +211,17 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //^^^ clock created up top, just reg props here... ^^^ _tree->create<double>(mb_path / "tick_rate") .publish(boost::bind(&e100_clock_ctrl::get_fpga_clock_rate, _clock_ctrl)) + .subscribe(boost::bind(&fifo_ctrl_excelsior::set_tick_rate, _fifo_ctrl, _1)) .subscribe(boost::bind(&e100_impl::update_tick_rate, this, _1)); + //subscribe the command time while we are at it + _tree->create<time_spec_t>(mb_path / "time/cmd") + .subscribe(boost::bind(&fifo_ctrl_excelsior::set_time, _fifo_ctrl, _1)); + //////////////////////////////////////////////////////////////////// // create codec control objects //////////////////////////////////////////////////////////////////// - _codec_ctrl = e100_codec_ctrl::make(_fpga_spi_ctrl); + _codec_ctrl = e100_codec_ctrl::make(_fifo_ctrl/*spi*/); const fs_path rx_codec_path = mb_path / "rx_codecs/A"; const fs_path tx_codec_path = mb_path / "tx_codecs/A"; _tree->create<std::string>(rx_codec_path / "name").set("ad9522"); @@ -231,24 +243,37 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //////////////////////////////////////////////////////////////////// // Create the GPSDO control //////////////////////////////////////////////////////////////////// - try{ - _gps = gps_ctrl::make(e100_ctrl::make_gps_uart_iface(E100_UART_DEV_NODE)); - } - catch(std::exception &e){ - UHD_MSG(error) << "An error occurred making GPSDO control: " << e.what() << std::endl; - } - if (_gps.get() != NULL and _gps->gps_detected()){ - BOOST_FOREACH(const std::string &name, _gps->get_sensors()){ - _tree->create<sensor_value_t>(mb_path / "sensors" / name) - .publish(boost::bind(&gps_ctrl::get_sensor, _gps, name)); + static const fs::path GPSDO_VOLATILE_PATH("/media/ram/e100_internal_gpsdo.cache"); + if (not fs::exists(GPSDO_VOLATILE_PATH)) + { + UHD_MSG(status) << "Detecting internal GPSDO.... " << std::flush; + try{ + _gps = gps_ctrl::make(e100_ctrl::make_gps_uart_iface(E100_UART_DEV_NODE)); + } + catch(std::exception &e){ + UHD_MSG(error) << "An error occurred making GPSDO control: " << e.what() << std::endl; + } + if (_gps and _gps->gps_detected()) + { + UHD_MSG(status) << "found" << std::endl; + BOOST_FOREACH(const std::string &name, _gps->get_sensors()) + { + _tree->create<sensor_value_t>(mb_path / "sensors" / name) + .publish(boost::bind(&gps_ctrl::get_sensor, _gps, name)); + } + } + else + { + UHD_MSG(status) << "not found" << std::endl; + std::ofstream(GPSDO_VOLATILE_PATH.string().c_str(), std::ofstream::binary) << "42" << std::endl; } } //////////////////////////////////////////////////////////////////// // create frontend control objects //////////////////////////////////////////////////////////////////// - _rx_fe = rx_frontend_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_FRONT)); - _tx_fe = tx_frontend_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TX_FRONT)); + _rx_fe = rx_frontend_core_200::make(_fifo_ctrl, TOREG(SR_RX_FE)); + _tx_fe = tx_frontend_core_200::make(_fifo_ctrl, TOREG(SR_TX_FE)); _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec") .subscribe(boost::bind(&e100_impl::update_rx_subdev_spec, this, _1)); @@ -277,13 +302,17 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //////////////////////////////////////////////////////////////////// // create rx dsp control objects //////////////////////////////////////////////////////////////////// - _rx_dsps.push_back(rx_dsp_core_200::make( - _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_DSP0), E100_REG_SR_ADDR(UE_SR_RX_CTRL0), E100_RX_SID_BASE + 0 - )); - _rx_dsps.push_back(rx_dsp_core_200::make( - _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_DSP1), E100_REG_SR_ADDR(UE_SR_RX_CTRL1), E100_RX_SID_BASE + 1 - )); - for (size_t dspno = 0; dspno < _rx_dsps.size(); dspno++){ + const size_t num_rx_dsps = _fifo_ctrl->peek32(REG_RB_NUM_RX_DSP); + for (size_t dspno = 0; dspno < num_rx_dsps; dspno++) + { + const size_t sr_off = dspno*32; + _rx_dsps.push_back(rx_dsp_core_200::make( + _fifo_ctrl, + TOREG(SR_RX_DSP0+sr_off), + TOREG(SR_RX_CTRL0+sr_off), + E100_RX_SID_BASE + dspno + )); + _rx_dsps[dspno]->set_link_rate(E100_RX_LINK_RATE_BPS); _tree->access<double>(mb_path / "tick_rate") .subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _rx_dsps[dspno], _1)); @@ -306,7 +335,7 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ // create tx dsp control objects //////////////////////////////////////////////////////////////////// _tx_dsp = tx_dsp_core_200::make( - _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TX_DSP), E100_REG_SR_ADDR(UE_SR_TX_CTRL), E100_TX_ASYNC_SID + _fifo_ctrl, TOREG(SR_TX_DSP), TOREG(SR_TX_CTRL), E100_TX_ASYNC_SID ); _tx_dsp->set_link_rate(E100_TX_LINK_RATE_BPS); _tree->access<double>(mb_path / "tick_rate") @@ -326,12 +355,12 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ // create time control objects //////////////////////////////////////////////////////////////////// time64_core_200::readback_bases_type time64_rb_bases; - time64_rb_bases.rb_hi_now = E100_REG_RB_TIME_NOW_HI; - time64_rb_bases.rb_lo_now = E100_REG_RB_TIME_NOW_LO; - time64_rb_bases.rb_hi_pps = E100_REG_RB_TIME_PPS_HI; - time64_rb_bases.rb_lo_pps = E100_REG_RB_TIME_PPS_LO; + time64_rb_bases.rb_hi_now = REG_RB_TIME_NOW_HI; + time64_rb_bases.rb_lo_now = REG_RB_TIME_NOW_LO; + time64_rb_bases.rb_hi_pps = REG_RB_TIME_PPS_HI; + time64_rb_bases.rb_lo_pps = REG_RB_TIME_PPS_LO; _time64 = time64_core_200::make( - _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TIME64), time64_rb_bases + _fifo_ctrl, TOREG(SR_TIME64), time64_rb_bases ); _tree->access<double>(mb_path / "tick_rate") .subscribe(boost::bind(&time64_core_200::set_tick_rate, _time64, _1)); @@ -349,13 +378,14 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //setup reference source props _tree->create<std::string>(mb_path / "clock_source/value") .subscribe(boost::bind(&e100_impl::update_clock_source, this, _1)); - static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("auto"); + std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("auto"); + if (_gps and _gps->gps_detected()) clock_sources.push_back("gpsdo"); _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources); //////////////////////////////////////////////////////////////////// // create user-defined control objects //////////////////////////////////////////////////////////////////// - _user = user_settings_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_USER_REGS)); + _user = user_settings_core_200::make(_fifo_ctrl, TOREG(SR_USER_REGS)); _tree->create<user_settings_core_200::user_reg_t>(mb_path / "user/regs") .subscribe(boost::bind(&user_settings_core_200::set_reg, _user, _1)); @@ -369,6 +399,9 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ tx_db_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_TX_DB); gdb_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_TX_DB ^ 5); + //disable rx dc offset if LFRX + if (rx_db_eeprom.id == 0x000f) _tree->access<bool>(rx_fe_path / "dc_offset" / "enable").set(false); + //create the properties and register subscribers _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/rx_eeprom") .set(rx_db_eeprom) @@ -381,7 +414,7 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ .subscribe(boost::bind(&e100_impl::set_db_eeprom, this, "gdb", _1)); //create a new dboard interface and manager - _dboard_iface = make_e100_dboard_iface(_fpga_ctrl, _fpga_i2c_ctrl, _fpga_spi_ctrl, _clock_ctrl, _codec_ctrl); + _dboard_iface = make_e100_dboard_iface(_fifo_ctrl, _fpga_i2c_ctrl, _fifo_ctrl/*spi*/, _clock_ctrl, _codec_ctrl); _tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_dboard_iface); _dboard_manager = dboard_manager::make( rx_db_eeprom.id, tx_db_eeprom.id, gdb_eeprom.id, @@ -401,7 +434,11 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ } //initialize io handling - this->io_init(); + _recv_demuxer = recv_packet_demuxer::make(_data_transport, _rx_dsps.size(), E100_RX_SID_BASE); + + //allocate streamer weak ptrs containers + _rx_streamers.resize(_rx_dsps.size()); + _tx_streamers.resize(1/*known to be 1 dsp*/); //////////////////////////////////////////////////////////////////// // do some post-init tasks @@ -425,10 +462,11 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ _tree->access<std::string>(mb_path / "time_source/value").set("none"); //GPS installed: use external ref, time, and init time spec - if (_gps.get() != NULL and _gps->gps_detected()){ + if (_gps and _gps->gps_detected()){ + _time64->enable_gpsdo(); UHD_MSG(status) << "Setting references to the internal GPSDO" << std::endl; - _tree->access<std::string>(mb_path / "time_source/value").set("external"); - _tree->access<std::string>(mb_path / "clock_source/value").set("external"); + _tree->access<std::string>(mb_path / "time_source/value").set("gpsdo"); + _tree->access<std::string>(mb_path / "clock_source/value").set("gpsdo"); UHD_MSG(status) << "Initializing time to the internal GPSDO" << std::endl; _time64->set_time_next_pps(time_spec_t(time_t(_gps->get_sensor("gps_time").to_int()+1))); } @@ -448,7 +486,7 @@ double e100_impl::update_rx_codec_gain(const double gain){ } void e100_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){ - mb_eeprom.commit(*_dev_i2c_iface, mboard_eeprom_t::MAP_E100); + mb_eeprom.commit(*_dev_i2c_iface, E100_EEPROM_MAP_KEY); } void e100_impl::set_db_eeprom(const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){ @@ -458,9 +496,23 @@ void e100_impl::set_db_eeprom(const std::string &type, const uhd::usrp::dboard_e } void e100_impl::update_clock_source(const std::string &source){ + + if (source == "pps_sync"){ + _clock_ctrl->use_external_ref(); + _fifo_ctrl->poke32(TOREG(SR_MISC+2), 1); + return; + } + if (source == "_pps_sync_"){ + _clock_ctrl->use_external_ref(); + _fifo_ctrl->poke32(TOREG(SR_MISC+2), 3); + return; + } + _fifo_ctrl->poke32(TOREG(SR_MISC+2), 0); + if (source == "auto") _clock_ctrl->use_auto_ref(); else if (source == "internal") _clock_ctrl->use_internal_ref(); else if (source == "external") _clock_ctrl->use_external_ref(); + else if (source == "gpsdo") _clock_ctrl->use_external_ref(); else throw uhd::runtime_error("unhandled clock configuration reference source: " + source); } @@ -470,7 +522,7 @@ sensor_value_t e100_impl::get_ref_locked(void){ } void e100_impl::check_fpga_compat(void){ - const boost::uint32_t fpga_compat_num = _fpga_ctrl->peek32(E100_REG_RB_COMPAT); + const boost::uint32_t fpga_compat_num = _fifo_ctrl->peek32(REG_RB_COMPAT); boost::uint16_t fpga_major = fpga_compat_num >> 16, fpga_minor = fpga_compat_num & 0xffff; if (fpga_major == 0){ //old version scheme fpga_major = fpga_minor; |