diff options
| author | Martin Braun <martin.braun@ettus.com> | 2014-09-25 17:29:43 -0700 | 
|---|---|---|
| committer | Martin Braun <martin.braun@ettus.com> | 2014-09-25 17:29:43 -0700 | 
| commit | 994e993893d921c074ce4097632f8fa5bdecff66 (patch) | |
| tree | c1e0fe3601e0ce8d7fa3690f578d0f341e610fed | |
| parent | a1767ede3c147c1748c6a33a52469d0cba644bf5 (diff) | |
| parent | 9dc96fd9bf8d430a9f41f3476bc62cc3ba43e1d7 (diff) | |
| download | uhd-994e993893d921c074ce4097632f8fa5bdecff66.tar.gz uhd-994e993893d921c074ce4097632f8fa5bdecff66.tar.bz2 uhd-994e993893d921c074ce4097632f8fa5bdecff66.zip | |
Merge branch 'maint'
| -rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 15 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_adc_ctrl.cpp | 14 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_adc_ctrl.hpp | 1 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_clock_ctrl.cpp | 5 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_dac_ctrl.cpp | 123 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_dac_ctrl.hpp | 12 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 60 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_impl.hpp | 2 | 
8 files changed, 177 insertions, 55 deletions
| diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index 78b979e04..3ff502858 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -151,6 +151,21 @@ static device_addrs_t b200_find(const device_addr_t &hint)              new_addr["type"] = "b200";              new_addr["name"] = mb_eeprom["name"];              new_addr["serial"] = handle->get_serial(); +            if (not mb_eeprom["product"].empty()) +            { +                switch (boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"])) +                { +                case 0x0001: +                case 0x7737: +                    new_addr["product"] = "B200"; +                    break; +                case 0x7738: +                case 0x0002: +                    new_addr["product"] = "B210"; +                    break; +                default: UHD_MSG(error) << "B200 unknown product code: " << mb_eeprom["product"] << std::endl; +                } +            }              //this is a found b200 when the hint serial and name match or blank              if (                  (not hint.has_key("name")   or hint["name"]   == new_addr["name"]) and diff --git a/host/lib/usrp/x300/x300_adc_ctrl.cpp b/host/lib/usrp/x300/x300_adc_ctrl.cpp index 53d1662ae..b0e4e4b95 100644 --- a/host/lib/usrp/x300/x300_adc_ctrl.cpp +++ b/host/lib/usrp/x300/x300_adc_ctrl.cpp @@ -38,6 +38,11 @@ public:      x300_adc_ctrl_impl(uhd::spi_iface::sptr iface, const size_t slaveno):          _iface(iface), _slaveno(slaveno)      { +        init(); +    } + +    void init() +    {          //power-up adc         _ads62p48_regs.reset = 1;          this->send_ads62p48_reg(0x00); //issue a reset to the ADC @@ -50,8 +55,8 @@ public:          _ads62p48_regs.lvds_cmos = ads62p48_regs_t::LVDS_CMOS_DDR_LVDS;          _ads62p48_regs.channel_control = ads62p48_regs_t::CHANNEL_CONTROL_INDEPENDENT;          _ads62p48_regs.data_format = ads62p48_regs_t::DATA_FORMAT_2S_COMPLIMENT; -	_ads62p48_regs.clk_out_pos_edge = ads62p48_regs_t::CLK_OUT_POS_EDGE_MINUS7_26; -	_ads62p48_regs.clk_out_neg_edge = ads62p48_regs_t::CLK_OUT_NEG_EDGE_MINUS7_26; +        _ads62p48_regs.clk_out_pos_edge = ads62p48_regs_t::CLK_OUT_POS_EDGE_MINUS7_26; +        _ads62p48_regs.clk_out_neg_edge = ads62p48_regs_t::CLK_OUT_NEG_EDGE_MINUS7_26;          this->send_ads62p48_reg(0); @@ -76,6 +81,11 @@ public:      } +    void reset() +    { +        init(); +    } +      double set_gain(const double &gain)      {          const meta_range_t gain_range = meta_range_t(0, 6.0, 0.5); diff --git a/host/lib/usrp/x300/x300_adc_ctrl.hpp b/host/lib/usrp/x300/x300_adc_ctrl.hpp index c8ce19c94..90fb88cec 100644 --- a/host/lib/usrp/x300/x300_adc_ctrl.hpp +++ b/host/lib/usrp/x300/x300_adc_ctrl.hpp @@ -41,6 +41,7 @@ public:      virtual void set_test_word(const std::string &patterna, const std::string &patternb, const boost::uint32_t = 0) = 0; +    virtual void reset(void) = 0;  };  #endif /* INCLUDED_X300_ADC_CTRL_HPP */ diff --git a/host/lib/usrp/x300/x300_clock_ctrl.cpp b/host/lib/usrp/x300/x300_clock_ctrl.cpp index ffb97e147..21411e651 100644 --- a/host/lib/usrp/x300/x300_clock_ctrl.cpp +++ b/host/lib/usrp/x300/x300_clock_ctrl.cpp @@ -299,8 +299,6 @@ void set_master_clock_rate(double clock_rate) {      // Register 3      _lmk04816_regs.CLKout6_7_DIV = vco_div;      _lmk04816_regs.CLKout6_7_OSCin_Sel = lmk04816_regs_t::CLKOUT6_7_OSCIN_SEL_VCO; -    _lmk04816_regs.CLKout6_ADLY_SEL = lmk04816_regs_t::CLKOUT6_ADLY_SEL_D_EV_X; -    _lmk04816_regs.CLKout7_ADLY_SEL = lmk04816_regs_t::CLKOUT7_ADLY_SEL_D_EV_X;      // Register 4      _lmk04816_regs.CLKout8_9_DIV = vco_div;      // Register 5 @@ -322,9 +320,6 @@ void set_master_clock_rate(double clock_rate) {      _lmk04816_regs.CLKout6_TYPE = lmk04816_regs_t::CLKOUT6_TYPE_LVPECL_700MVPP; //DB0_DAC      _lmk04816_regs.CLKout7_TYPE = lmk04816_regs_t::CLKOUT7_TYPE_LVPECL_700MVPP; //DB1_DAC      _lmk04816_regs.CLKout8_TYPE = lmk04816_regs_t::CLKOUT8_TYPE_LVPECL_700MVPP; //DB0_ADC -    // Analog delay of 900ps to synchronize the DAC reference clocks with the source synchronous DAC clocks. -    // This delay may need to vary due to temperature.  Tested and verified at room temperature only. -    _lmk04816_regs.CLKout6_7_ADLY = 0x10;      // Register 8      _lmk04816_regs.CLKout9_TYPE = lmk04816_regs_t::CLKOUT9_TYPE_LVPECL_700MVPP; //DB1_ADC diff --git a/host/lib/usrp/x300/x300_dac_ctrl.cpp b/host/lib/usrp/x300/x300_dac_ctrl.cpp index a9d9a7730..62fe55c35 100644 --- a/host/lib/usrp/x300/x300_dac_ctrl.cpp +++ b/host/lib/usrp/x300/x300_dac_ctrl.cpp @@ -43,7 +43,13 @@ class x300_dac_ctrl_impl : public x300_dac_ctrl  {  public:      x300_dac_ctrl_impl(uhd::spi_iface::sptr iface, const size_t slaveno, const double refclk): -        _iface(iface), _slaveno(slaveno) +        _iface(iface), _slaveno(slaveno), _refclk(refclk) +    { +        init(); +        check_pll(); +    } + +    void init()      {          write_ad9146_reg(0x00, 0x20); // Take DAC into reset.          write_ad9146_reg(0x00, 0x80); // Enable SPI reads and come out of reset @@ -51,43 +57,31 @@ public:          // Calculate N0 to be VCO friendly.          // Aim for VCO between 1 and 2GHz, assert otherwise. -	//  const int N1 = 4; -	const int N1 = 4; +        //  const int N1 = 4; +        const int N1 = 4;          int N0_val, N0;          for (N0_val = 0; N0_val < 3; N0_val++)          {              N0 = (1 << N0_val); //1, 2, 4 -            if ((refclk * N0 * N1) >= 1e9) break; +            if ((_refclk * N0 * N1) >= 1e9) break;          } -        UHD_ASSERT_THROW((refclk * N0 * N1) >= 1e9); -        UHD_ASSERT_THROW((refclk * N0 * N1) <= 2e9); +        UHD_ASSERT_THROW((_refclk * N0 * N1) >= 1e9); +        UHD_ASSERT_THROW((_refclk * N0 * N1) <= 2e9);          /* Start PLL */          //write_ad9146_reg(0x0C, 0xD1); // Narrow PLL loop filter, Midrange charge pump.          write_ad9146_reg(0x0D, 0xD1 | (N0_val << 2)); // N1=4, N2=16, N0 as calculated -	//write_ad9146_reg(0x0D, 0x90 | (N0_val << 2)); // N1=2, N2=8, N0 as calculated +        //write_ad9146_reg(0x0D, 0x90 | (N0_val << 2)); // N1=2, N2=8, N0 as calculated          write_ad9146_reg(0x0A, 0xCF); // Auto init VCO band training as per datasheet          write_ad9146_reg(0x0A, 0xA0); // See above. -        // Verify PLL is Locked. 1 sec timeout.  -        // NOTE: Data sheet inconsistant about which pins give PLL lock status. FIXME! -        const time_spec_t exit_time = time_spec_t::get_system_time() + time_spec_t(1.0); -        while (true) -        { -            const size_t reg_e = read_ad9146_reg(0x0E); /* Expect bit 7 = 1 */ -            if ((exit_time < time_spec_t::get_system_time()) && ((reg_e & (1 << 7)) == 0)) -	      throw uhd::runtime_error("x300_dac_ctrl: timeout waiting for DAC PLL to lock"); -	    else if  ((reg_e & ((1 << 7) | (1 << 6))) != 0) break; -            boost::this_thread::sleep(boost::posix_time::milliseconds(10)); -        } -          /* Skew DCI signal to find stable data eye */          //write_ad9146_reg(0x16, 0x04); //Disable delay in DCI          //write_ad9146_reg(0x16, 0x00); //165ps delay in DCI          //write_ad9146_reg(0x16, 0x01); //375ps delay in DCI          write_ad9146_reg(0x16, 0x02); //615ps delay in DCI          //write_ad9146_reg(0x16, 0x03); //720ps delay in DCI -  +          write_ad9146_reg(0x03, 0x00); // 2's comp, I first, byte wide interface          //fpga wants I,Q in the sample word: @@ -97,7 +91,14 @@ public:          write_ad9146_reg(0x03, (1 << 6)); //2s comp, i first, byte mode          write_ad9146_reg(0x10, 0x48); // Disable SYNC mode. -        write_ad9146_reg(0x17, 0x04); // FIFO write pointer offset + +        // FIFO write pointer offset +        // It was found that the read was happening before the write +        // so the FIFO was maintainining a depth of 3 during operation. +        // Setting it to 5 to ensure it maintains the ideal depth of 4. +        // TODO:  Investigate RefClk -> DCI clock timing. +        write_ad9146_reg(0x17, 0x05); +          write_ad9146_reg(0x18, 0x02); // Request soft FIFO align          write_ad9146_reg(0x18, 0x00); // (See above)          write_ad9146_reg(0x1B, 0xE4); // Bypass: Modulator, InvSinc, IQ Bal @@ -106,6 +107,8 @@ public:          write_ad9146_reg(0x1C, 0x00); // Configure HB1          write_ad9146_reg(0x1D, 0x00); // Configure HB2 +        // Clear event flags +        write_ad9146_reg(0x06, 0xFF);      } @@ -118,27 +121,71 @@ public:          )      } -  void arm_dac_sync(void) -  { -    // -    // Attempt to synchronize AD9146's -    // -    write_ad9146_reg(0x10, 0xCF); // Enable SYNC mode. Sync Averaging set to 128. - -    const time_spec_t exit_time = time_spec_t::get_system_time() + time_spec_t(1.0); -    while (true) -      { -	const size_t reg_12 = read_ad9146_reg(0x12); /* Expect bit 7 = 0, bit 6 = 1 */ -	if ((exit_time < time_spec_t::get_system_time()) && (((reg_12 & (1 << 6)) == 0) || ((reg_12 & (1 << 7)) != 0))) -	  throw uhd::runtime_error("x300_dac_ctrl: timeout waiting for backend synchronization"); -	else if (((reg_12 & (1 << 6)) != 0) && ((reg_12 & (1 << 7)) == 0))  break; -	boost::this_thread::sleep(boost::posix_time::milliseconds(10)); -      } -  } +    void arm_dac_sync(void) +    { +        // +        // Attempt to synchronize AD9146's +        // +        write_ad9146_reg(0x10, 0x48);   // Disable SYNC mode. +        write_ad9146_reg(0x06, 0x30);   // Clear Sync event flags +        write_ad9146_reg(0x10, 0xCF);   // Enable SYNC mode. Sync Averaging set to 128. +    } + +    void reset() +    { +        init(); +    } + +    void check_pll() +    { +        // Verify PLL is Locked. 1 sec timeout. +        // NOTE: Data sheet inconsistant about which pins give PLL lock status. FIXME! +        const time_spec_t exit_time = time_spec_t::get_system_time() + time_spec_t(1.0); +        while (true) +        { +            const size_t reg_e = read_ad9146_reg(0x0E); // PLL Status (Expect bit 7 = 1) +            const size_t reg_6 = read_ad9146_reg(0x06); // Event Flags (Expect bit 7 = 0 and bit 6 = 1) +            if ((((reg_e >> 7) & 0x1) == 0x1) && (((reg_6 >> 6) & 0x3) == 0x1)) +                break; +            if (exit_time < time_spec_t::get_system_time()) +                throw uhd::runtime_error("x300_dac_ctrl: timeout waiting for DAC PLL to lock"); +            if (reg_6 & (1 << 7))               // Sync lost? +                write_ad9146_reg(0x06, 0xC0);   // Clear PLL event flags +            boost::this_thread::sleep(boost::posix_time::milliseconds(10)); +        } +    } + +    void check_dac_sync() +    { +        const time_spec_t exit_time = time_spec_t::get_system_time() + time_spec_t(1.0); +        while (true) +        { +            boost::this_thread::sleep(boost::posix_time::milliseconds(1));  // wait for sync to complete +            const size_t reg_12 = read_ad9146_reg(0x12);    // Sync Status (Expect bit 7 = 0, bit 6 = 1) +            const size_t reg_6 = read_ad9146_reg(0x06);     // Event Flags (Expect bit 5 = 0 and bit 4 = 1) +            if ((((reg_12 >> 6) & 0x3) == 0x1) && (((reg_6 >> 4) & 0x3) == 0x1)) +                break; +            if (exit_time < time_spec_t::get_system_time()) +                throw uhd::runtime_error("x300_dac_ctrl: timeout waiting for backend synchronization"); +            if (reg_12 & (1 << 7))  // Sync acquired and lost? +                arm_dac_sync();     // Re-arm and try again +            else if (reg_6 & (1 << 5)) +                write_ad9146_reg(0x06, 0x30);   // Clear Sync event flags +        } +    } + +    void check_frontend_sync() +    { +        // Register 0x19 has a thermometer indicator of the FIFO depth +        const size_t reg_19 = read_ad9146_reg(0x19); +        if ((reg_19 & 0xFF) != 0xF) +            UHD_MSG(warning) << "x300_dac_ctrl: unexpected FIFO depth [0x" << std::hex << (reg_19 & 0xFF) << std::dec << "]" << std::endl; +    }  private:      uhd::spi_iface::sptr _iface;      const size_t _slaveno; +    const double _refclk;  };  /*********************************************************************** diff --git a/host/lib/usrp/x300/x300_dac_ctrl.hpp b/host/lib/usrp/x300/x300_dac_ctrl.hpp index 78046cee5..5fd7e13d8 100644 --- a/host/lib/usrp/x300/x300_dac_ctrl.hpp +++ b/host/lib/usrp/x300/x300_dac_ctrl.hpp @@ -39,6 +39,18 @@ public:      // ! Arm the sync feature in DAC      virtual void arm_dac_sync(void) = 0; + +    // ! Check for successful backend sync +    virtual void check_dac_sync(void) = 0; + +    // ! Reset the DAC +    virtual void reset(void) = 0; + +    // ! Check for PLL lock +    virtual void check_pll(void) = 0; + +    // ! Check for successful frontend sync +    virtual void check_frontend_sync(void) = 0;  };  #endif /* INCLUDED_X300_DAC_CTRL_HPP */ diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index a670f28c4..1494a100e 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -737,6 +737,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)      // setup time sources and properties      ////////////////////////////////////////////////////////////////////      _tree->create<std::string>(mb_path / "time_source" / "value") +        .set("internal")          .subscribe(boost::bind(&x300_impl::update_time_source, this, boost::ref(mb), _1));      static const std::vector<std::string> time_sources = boost::assign::list_of("internal")("external")("gpsdo");      _tree->create<std::vector<std::string> >(mb_path / "time_source" / "options").set(time_sources); @@ -750,7 +751,10 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)      // setup clock sources and properties      ////////////////////////////////////////////////////////////////////      _tree->create<std::string>(mb_path / "clock_source" / "value") -        .subscribe(boost::bind(&x300_impl::update_clock_source, this, boost::ref(mb), _1)); +        .set("internal") +        .subscribe(boost::bind(&x300_impl::update_clock_source, this, boost::ref(mb), _1)) +        .subscribe(boost::bind(&x300_impl::reset_clocks, this, boost::ref(mb))) +        .subscribe(boost::bind(&x300_impl::reset_radios, this, boost::ref(mb)));      static const std::vector<std::string> clock_source_options = boost::assign::list_of("internal")("external")("gpsdo");      _tree->create<std::vector<std::string> >(mb_path / "clock_source" / "options").set(clock_source_options); @@ -827,15 +831,6 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)          const time_t tp = time_t(mb.gps->get_sensor("gps_time").to_int()+1);          _tree->access<time_spec_t>(mb_path / "time" / "pps").set(time_spec_t(tp));      } else { -        _tree->access<std::string>(mb_path / "clock_source" / "value").set("internal"); -        try { -            wait_for_ref_locked(mb.zpu_ctrl, 1.0); -        } catch (uhd::exception::runtime_error &e) { -            // Ignore for now - It can sometimes take longer than 1 second to lock and that is OK. -            //UHD_MSG(warning) << "Clock reference failed to lock to internal source during device initialization.  " << -            //    "Check for the lock before operation or ignore this warning if using another clock source." << std::endl; -        } -        _tree->access<std::string>(mb_path / "time_source" / "value").set("internal");          UHD_MSG(status) << "References initialized to internal sources" << std::endl;      }  } @@ -1401,6 +1396,51 @@ void x300_impl::update_clock_source(mboard_members_t &mb, const std::string &sou       */  } +void x300_impl::reset_clocks(mboard_members_t &mb) +{ +    mb.clock->reset_clocks(); + +    if (mb.hw_rev > 4) +    { +        try { +            wait_for_ref_locked(mb.zpu_ctrl, 30.0); +        } catch (uhd::runtime_error &e) { +            //failed to lock on reference +            throw uhd::runtime_error((boost::format("PLL failed to lock to reference clock.")).str()); +        } +    } +} + +void x300_impl::reset_radios(mboard_members_t &mb) +{ +    // reset ADCs and DACs +    BOOST_FOREACH (radio_perifs_t& perif, mb.radio_perifs) +    { +        perif.adc->reset(); +        perif.dac->reset(); +    } + +    // check PLL locks +    BOOST_FOREACH (radio_perifs_t& perif, mb.radio_perifs) +    { +        perif.dac->check_pll(); +    } + +    // Sync DACs +    BOOST_FOREACH (radio_perifs_t& perif, mb.radio_perifs) +    { +        perif.dac->arm_dac_sync(); +    } +    BOOST_FOREACH (radio_perifs_t& perif, mb.radio_perifs) +    { +        perif.dac->check_dac_sync(); +        // Arm FRAMEP/N sync pulse +        // TODO:  Investigate timing of the sync frame pulse. +        perif.ctrl->poke32(TOREG(SR_DACSYNC), 0x1); +        perif.dac->check_frontend_sync(); +    } +} +  void x300_impl::update_time_source(mboard_members_t &mb, const std::string &source)  {      if (source == "internal") { diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index 1130c24d6..ff0af9069 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -344,6 +344,8 @@ private:      void set_time_source_out(mboard_members_t&, const bool);      void update_clock_source(mboard_members_t&, const std::string &);      void update_time_source(mboard_members_t&, const std::string &); +    void reset_clocks(mboard_members_t&); +    void reset_radios(mboard_members_t&);      uhd::sensor_value_t get_ref_locked(uhd::wb_iface::sptr);      void wait_for_ref_locked(uhd::wb_iface::sptr, double timeout = 0.0); | 
