diff options
| author | Michael West <michael.west@ettus.com> | 2014-02-18 16:18:04 -0800 | 
|---|---|---|
| committer | Michael West <michael.west@ettus.com> | 2014-02-18 16:18:04 -0800 | 
| commit | 4d9c03d44b02d0ee91355280dbc58d1f19deddea (patch) | |
| tree | 8e40fa4fb361933252cffae4af98a5e9df9218c1 /host/lib | |
| parent | 7fef199d194c9a63b3312845979fa353f90f4d23 (diff) | |
| download | uhd-4d9c03d44b02d0ee91355280dbc58d1f19deddea.tar.gz uhd-4d9c03d44b02d0ee91355280dbc58d1f19deddea.tar.bz2 uhd-4d9c03d44b02d0ee91355280dbc58d1f19deddea.zip | |
- Fix for BUG #264: ./test_pps_input --source external passes even with no 1 PPS on external input on X3xx
- Fixed behavior of PPS and clock references to be consistent and intuitive.
-- Added detection of clock reference and PPS.
-- Changed order of precedence to external, gpsdo, internal for default of clock and PPS.
-- Throws runtime error if the user requests a reference clock or PPS that is not present.
- Bumped FPGA compatibility to 4.
Diffstat (limited to 'host/lib')
| -rw-r--r-- | host/lib/usrp/x300/x300_fw_common.h | 2 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 101 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_impl.hpp | 1 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_regs.hpp | 14 | 
4 files changed, 81 insertions, 37 deletions
| diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h index c470e9bff..632391644 100644 --- a/host/lib/usrp/x300/x300_fw_common.h +++ b/host/lib/usrp/x300/x300_fw_common.h @@ -31,7 +31,7 @@ extern "C" {  #define X300_FW_COMPAT_MAJOR 3  #define X300_FW_COMPAT_MINOR 0 -#define X300_FPGA_COMPAT_MAJOR 3 +#define X300_FPGA_COMPAT_MAJOR 4  //shared memory sections - in between the stack and the program space  #define X300_FW_SHMEM_BASE 0x6000 diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index b20897fc6..5e0635767 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -581,12 +581,11 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)      // Init shadow and clock source; the device comes up with it's internal      // clock source before locking to something else (if requested). -    mb.clock_control_regs__clock_source = 0; -    mb.clock_control_regs__pps_select = 0; +    mb.clock_control_regs__clock_source = ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL; +    mb.clock_control_regs__pps_select = ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL;      mb.clock_control_regs__pps_out_enb = 0;      mb.clock_control_regs__tcxo_enb = 1;      mb.clock_control_regs__gpsdo_pwr = 1; -    this->update_clock_source(mb, "internal");      this->update_clock_control(mb);      size_t hw_rev = 0; @@ -767,32 +766,29 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)      _tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(rx_fe_spec);      _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(tx_fe_spec); -    //GPS installed: use external ref, time, and init time spec -    if (mb.gps and mb.gps->gps_detected()) -    { -        UHD_MSG(status) << "Setting references to the internal GPSDO" << std::endl; -        _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; -        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 / "time_source" / "value").set("external"); +    UHD_MSG(status) << "Initializing clock and PPS references..." << std::endl; +    try { +        //First, try external source          _tree->access<std::string>(mb_path / "clock_source" / "value").set("external"); -        boost::this_thread::sleep(boost::posix_time::milliseconds(100)); -        if (this->get_ref_locked(mb.zpu_ctrl).to_bool()) -        { -            UHD_MSG(status) << "Setting references to external sources" << std::endl; -        } -        else +        _tree->access<std::string>(mb_path / "time_source" / "value").set("external"); +        UHD_MSG(status) << "References initialized to external sources" << std::endl; +    } catch (uhd::exception::runtime_error &e) { +        //No external source detected - set to the GPSDO if installed +        if (mb.gps and mb.gps->gps_detected())          { -            UHD_MSG(status) << "Setting references to internal sources" << std::endl; -            _tree->access<std::string>(mb_path / "time_source" / "value").set("internal"); +            _tree->access<std::string>(mb_path / "clock_source" / "value").set("gpsdo"); +            _tree->access<std::string>(mb_path / "time_source" / "value").set("gpsdo"); +            UHD_MSG(status) << "References initialized to GPSDO sources" << std::endl; +            UHD_MSG(status) << "Initializing time to the GPSDO time" << std::endl; +            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"); +            _tree->access<std::string>(mb_path / "time_source" / "value").set("internal"); +            UHD_MSG(status) << "References initialized to internal sources" << std::endl;          }      } +  }  x300_impl::~x300_impl(void) @@ -1297,9 +1293,9 @@ void x300_impl::update_clock_control(mboard_members_t &mb)  {      const size_t reg = mb.clock_control_regs__clock_source          | (mb.clock_control_regs__pps_select << 2) -        | (mb.clock_control_regs__pps_out_enb << 3) -        | (mb.clock_control_regs__tcxo_enb << 4) -        | (mb.clock_control_regs__gpsdo_pwr << 5) +        | (mb.clock_control_regs__pps_out_enb << 4) +        | (mb.clock_control_regs__tcxo_enb << 5) +        | (mb.clock_control_regs__gpsdo_pwr << 6)      ;      mb.zpu_ctrl->poke32(SR_ADDR(SET0_BASE, ZPU_SR_CLOCK_CTRL), reg);  } @@ -1307,42 +1303,75 @@ void x300_impl::update_clock_control(mboard_members_t &mb)  void x300_impl::update_clock_source(mboard_members_t &mb, const std::string &source)  {      mb.clock_control_regs__clock_source = 0; +    mb.clock_control_regs__tcxo_enb = 0;      if (source == "internal") { -        mb.clock_control_regs__clock_source = 0x2; - -        mb.clock_control_regs__tcxo_enb = (source == "internal")? 1 : 0; +        mb.clock_control_regs__clock_source = ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL; +        mb.clock_control_regs__tcxo_enb = 1;      } else if (source == "external") { -        mb.clock_control_regs__clock_source = 0x0; +        mb.clock_control_regs__clock_source = ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL;      } else if (source == "gpsdo") { -        mb.clock_control_regs__clock_source = 0x3; +        mb.clock_control_regs__clock_source = ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO;      } else {          throw uhd::key_error("update_clock_source: unknown source: " + source);      }      this->update_clock_control(mb); + +    //check for lock - poll every 10 ms for up to 1 second +    for (int i = 0; i < 10; i++) +    { +        boost::this_thread::sleep(boost::posix_time::milliseconds(100)); +        if (get_ref_locked(mb.zpu_ctrl).to_bool()) +            return; +    } + +    //failed to lock on reference +    throw uhd::runtime_error((boost::format("The %d reference clock failed to lock.  Please check the clock and try again.") % source).str());  }  void x300_impl::update_time_source(mboard_members_t &mb, const std::string &source)  {      if (source == "internal") { -        // no action needed +        mb.clock_control_regs__pps_select = ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL;      } else if (source == "external") { -        mb.clock_control_regs__pps_select = (source == "external")? 1 : 0; +        mb.clock_control_regs__pps_select = ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL;      } else if (source == "gpsdo") { -        // no action needed +        mb.clock_control_regs__pps_select = ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO;      } else {          throw uhd::key_error("update_time_source: unknown source: " + source);      }      this->update_clock_control(mb); + +    //check for valid pps +    if (!is_pps_present(mb.zpu_ctrl)) +    { +        throw uhd::runtime_error((boost::format("The %d PPS was not detected.  Please check the PPS source and try again.") % source).str()); +    }  }  sensor_value_t x300_impl::get_ref_locked(wb_iface::sptr ctrl)  { -    const bool lock = (ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS)) & (1 << 2)) != 0; +    uint32_t clk_status = ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS)); +    const bool lock = ((clk_status & ZPU_RB_CLK_STATUS_LMK_LOCK) != 0);      return sensor_value_t("Ref", lock, "locked", "unlocked");  } +bool x300_impl::is_pps_present(wb_iface::sptr ctrl) +{ +    // The ZPU_RB_CLK_STATUS_PPS_DETECT bit toggles with each rising edge of the PPS. +    // We monitor it for up to 1.5 seconds looking for it to toggle. +    uint32_t pps_detect = ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS)) & ZPU_RB_CLK_STATUS_PPS_DETECT; +    for (int i = 0; i < 15; i++) +    { +        boost::this_thread::sleep(boost::posix_time::milliseconds(100)); +        uint32_t clk_status = ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS)); +        if (pps_detect != (clk_status & ZPU_RB_CLK_STATUS_PPS_DETECT)) +            return true; +    } +    return false; +} +  void x300_impl::set_db_eeprom(i2c_iface::sptr i2c, const size_t addr, const uhd::usrp::dboard_eeprom_t &db_eeprom)  {      db_eeprom.store(*i2c, addr); diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index 1fb3676a0..b64f9ad01 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -302,6 +302,7 @@ private:      void update_time_source(mboard_members_t&, const std::string &);      uhd::sensor_value_t get_ref_locked(uhd::wb_iface::sptr); +    bool is_pps_present(uhd::wb_iface::sptr);      void set_db_eeprom(uhd::i2c_iface::sptr i2c, const size_t, const uhd::usrp::dboard_eeprom_t &);      void set_mb_eeprom(uhd::i2c_iface::sptr i2c, const uhd::usrp::mboard_eeprom_t &); diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp index e4ae76a38..fb1786deb 100644 --- a/host/lib/usrp/x300/x300_regs.hpp +++ b/host/lib/usrp/x300/x300_regs.hpp @@ -68,12 +68,26 @@ localparam ZPU_SR_SPI        = 32;  localparam ZPU_SR_ETHINT0    = 40;  localparam ZPU_SR_ETHINT1    = 56; +//clock controls +#define ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL  0x00 +#define ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL  0x02 +#define ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO     0x03 +#define ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL  0x00 +#define ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL  0x02 +#define ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO     0x03 +  localparam ZPU_RB_SPI = 2;  localparam ZPU_RB_CLK_STATUS = 3;  localparam ZPU_RB_COMPAT_NUM = 6;  localparam ZPU_RB_ETH_TYPE0  = 4;  localparam ZPU_RB_ETH_TYPE1  = 5; +//clock status +#define ZPU_RB_CLK_STATUS_LMK_STATUS    (0x3 << 0) +#define ZPU_RB_CLK_STATUS_LMK_LOCK      (0x1 << 2) +#define ZPU_RB_CLK_STATUS_LMK_HOLDOVER  (0x1 << 3) +#define ZPU_RB_CLK_STATUS_PPS_DETECT    (0x1 << 4) +  //spi slaves on radio  #define DB_DAC_SEN (1 << 7)  #define DB_ADC_SEN (1 << 6) | 
