diff options
author | michael-west <michael.west@ettus.com> | 2015-10-12 14:06:32 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2015-10-12 16:32:55 -0700 |
commit | 539223d93986e77968018cb808e0ea04f1c516f4 (patch) | |
tree | 33ef3298c9a042a0257371ce985dea45078d8c9d /host/lib/usrp | |
parent | 36feb03dcb3b370d6e42f247691da22960d0eace (diff) | |
download | uhd-539223d93986e77968018cb808e0ea04f1c516f4.tar.gz uhd-539223d93986e77968018cb808e0ea04f1c516f4.tar.bz2 uhd-539223d93986e77968018cb808e0ea04f1c516f4.zip |
B200: Fix for CODEC loopback test failure
- Add delay after putting CODEC in loopback mode
Diffstat (limited to 'host/lib/usrp')
-rw-r--r-- | host/lib/usrp/common/ad936x_manager.cpp | 38 |
1 files changed, 34 insertions, 4 deletions
diff --git a/host/lib/usrp/common/ad936x_manager.cpp b/host/lib/usrp/common/ad936x_manager.cpp index 8c8897803..e56fd3a82 100644 --- a/host/lib/usrp/common/ad936x_manager.cpp +++ b/host/lib/usrp/common/ad936x_manager.cpp @@ -80,34 +80,64 @@ class ad936x_manager_impl : public ad936x_manager } } + + // + // loopback_self_test checks the integrity of the FPGA->AD936x->FPGA sample interface. + // The AD936x is put in loopback mode that sends the TX data unchanged to the RX side. + // A test value is written to the codec_idle register in the TX side of the radio. + // The readback register is then used to capture the values on the TX and RX sides + // simultaneously for comparison. It is a reasonably effective test for AC timing + // since I/Q Ch0/Ch1 alternate over the same wires. Note, however, that it uses + // whatever timing is configured at the time the test is called rather than select + // worst case conditions to stress the interface. + // void loopback_self_test( wb_iface::sptr iface, wb_iface::wb_addr_type codec_idle_addr, wb_iface::wb_addr_type codec_readback_addr ) { + // Put AD936x in loopback mode _codec_ctrl->data_port_loopback(true); UHD_MSG(status) << "Performing CODEC loopback test... " << std::flush; UHD_ASSERT_THROW(bool(iface)); size_t hash = size_t(time(NULL)); + + // Allow some time for AD936x to enter loopback mode. + // There is no clear statement in the documentation of how long it takes, + // but UG-570 does say to "allow six ADC_CLK/64 clock cycles of flush time" + // when leaving the TX or RX states. That works out to ~75us at the + // minimum clock rate of 5 MHz, which lines up with test results. + // Sleeping 1ms is far more than enough. + boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + for (size_t i = 0; i < 100; i++) { + // Create test word boost::hash_combine(hash, i); const boost::uint32_t word32 = boost::uint32_t(hash) & 0xfff0fff0; + + // Write test word to codec_idle idle register (on TX side) iface->poke32(codec_idle_addr, word32); - // We do 2 peeks so we have enough idleness for loopback to propagate - iface->peek64(codec_readback_addr); + + // Read back values - TX is lower 32-bits and RX is upper 32-bits const boost::uint64_t rb_word64 = iface->peek64(codec_readback_addr); const boost::uint32_t rb_tx = boost::uint32_t(rb_word64 >> 32); const boost::uint32_t rb_rx = boost::uint32_t(rb_word64 & 0xffffffff); + + // Compare TX and RX values to test word bool test_fail = word32 != rb_tx or word32 != rb_rx; - if (test_fail) { + if(test_fail) + { UHD_MSG(status) << "fail" << std::endl; throw uhd::runtime_error("CODEC loopback test failed."); } } UHD_MSG(status) << "pass" << std::endl; - /* Zero out the idle data. */ + + // Zero out the idle data. iface->poke32(codec_idle_addr, 0); + + // Take AD936x out of loopback mode _codec_ctrl->data_port_loopback(false); } |