aboutsummaryrefslogtreecommitdiffstats
path: root/host/tests/lmx2572_test.cpp
diff options
context:
space:
mode:
authorLars Amsel <lars.amsel@ni.com>2021-06-04 08:27:50 +0200
committerAaron Rossetto <aaron.rossetto@ni.com>2021-06-10 12:01:53 -0500
commit2a575bf9b5a4942f60e979161764b9e942699e1e (patch)
tree2f0535625c30025559ebd7494a4b9e7122550a73 /host/tests/lmx2572_test.cpp
parente17916220cc955fa219ae37f607626ba88c4afe3 (diff)
downloaduhd-2a575bf9b5a4942f60e979161764b9e942699e1e.tar.gz
uhd-2a575bf9b5a4942f60e979161764b9e942699e1e.tar.bz2
uhd-2a575bf9b5a4942f60e979161764b9e942699e1e.zip
uhd: Add support for the USRP X410
Co-authored-by: Lars Amsel <lars.amsel@ni.com> Co-authored-by: Michael Auchter <michael.auchter@ni.com> Co-authored-by: Martin Braun <martin.braun@ettus.com> Co-authored-by: Paul Butler <paul.butler@ni.com> Co-authored-by: Cristina Fuentes <cristina.fuentes-curiel@ni.com> Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com> Co-authored-by: Virendra Kakade <virendra.kakade@ni.com> Co-authored-by: Lane Kolbly <lane.kolbly@ni.com> Co-authored-by: Max Köhler <max.koehler@ni.com> Co-authored-by: Andrew Lynch <andrew.lynch@ni.com> Co-authored-by: Grant Meyerhoff <grant.meyerhoff@ni.com> Co-authored-by: Ciro Nishiguchi <ciro.nishiguchi@ni.com> Co-authored-by: Thomas Vogel <thomas.vogel@ni.com>
Diffstat (limited to 'host/tests/lmx2572_test.cpp')
-rw-r--r--host/tests/lmx2572_test.cpp150
1 files changed, 150 insertions, 0 deletions
diff --git a/host/tests/lmx2572_test.cpp b/host/tests/lmx2572_test.cpp
new file mode 100644
index 000000000..21ed1e7f5
--- /dev/null
+++ b/host/tests/lmx2572_test.cpp
@@ -0,0 +1,150 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include "lmx2572_regs.hpp"
+#include <uhdlib/usrp/common/lmx2572.hpp>
+#include <boost/test/unit_test.hpp>
+#include <map>
+
+
+class lmx2572_mem
+{
+public:
+ lmx2572_mem()
+ {
+ // Copy silicone defaults into mem
+ for (uint8_t addr = 0; addr < regs.get_num_regs(); addr++) {
+ mem[addr] = regs.get_reg(addr);
+ }
+ }
+
+ void poke16(const uint8_t addr, const uint16_t data)
+ {
+ if (regs.get_ro_regs().count(addr)) {
+ throw uhd::runtime_error("Writing to RO reg!");
+ }
+ mem[addr] = data;
+ }
+
+ uint16_t peek16(const uint8_t addr)
+ {
+ return mem.at(addr);
+ }
+
+ lmx2572_regs_t regs;
+ std::map<uint8_t, uint16_t> mem;
+};
+
+
+BOOST_AUTO_TEST_CASE(lmx_init_test)
+{
+ auto mem = lmx2572_mem{};
+ auto lo = lmx2572_iface::make(
+ [&](const uint8_t addr, const uint16_t data) { mem.poke16(addr, data); },
+ [&](const uint8_t addr) -> uint16_t { return mem.peek16(addr); },
+ [](const uhd::time_spec_t&) {});
+ lo->reset();
+}
+
+void UHD_CHECK_REGMAP(
+ std::map<uint8_t, uint16_t> expected, std::map<uint8_t, uint16_t> actual)
+{
+ for (const auto& expected_r : expected) {
+ // Little hack so if this fails, we see all the info:
+ const std::string exp_str = "R" + std::to_string(expected_r.first)
+ + "==" + std::to_string(expected_r.second);
+ const std::string act_str = "R" + std::to_string(expected_r.first)
+ + "==" + std::to_string(actual.at(expected_r.first));
+ BOOST_CHECK_EQUAL(exp_str, act_str);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(lmx_sync_tune_test)
+{
+ auto mem = lmx2572_mem{};
+ auto lo = lmx2572_iface::make(
+ [&](const uint8_t addr, const uint16_t data) { mem.poke16(addr, data); },
+ [&](const uint8_t addr) -> uint16_t { return mem.peek16(addr); },
+ [](const uhd::time_spec_t&) {});
+ lo->reset();
+ // Mimick ZBX settings:
+ constexpr bool zbx_spur_dodging = false;
+ lo->set_sync_mode(true);
+ lo->set_output_enable(lmx2572_iface::output_t::RF_OUTPUT_A, true);
+ lo->set_output_enable(lmx2572_iface::output_t::RF_OUTPUT_B, false);
+ // Test Category 1A + SYNC:
+ lo->set_frequency(
+ 50 * 64e6, 64e6, zbx_spur_dodging);
+ lo->commit();
+ // These values are generated with TICS PRO. We don't check all the values,
+ // mainly the ones related to sync operation.
+ UHD_CHECK_REGMAP(
+ std::map<uint8_t, uint16_t>{
+ {36, 0x0032}, // Lower bits of N-divider, integer part
+ {42, 0x0000}, // PLL_NUM upper
+ {43, 0x0000}, // PLL_NUM lower
+ },
+ mem.mem);
+ // Test max frequency just to test boundary conditions:
+ lo->set_frequency(
+ 100 * 64e6, 64e6, zbx_spur_dodging);
+ lo->commit();
+
+ // Test Category 1B + SYNC:
+ // Will set CHDIV to 2.
+ lo->set_frequency(
+ 40 * 64e6, 64e6, zbx_spur_dodging);
+ lo->commit();
+ UHD_CHECK_REGMAP(
+ std::map<uint8_t, uint16_t>{
+ {36, 0x0028},
+ {42, 0x0000},
+ {43, 0x0000},
+ },
+ mem.mem);
+
+ // Test Category 2 + SYNC:
+ // Will set CHDIV to 8.
+ lo->set_frequency(
+ 10 * 64e6, 64e6, zbx_spur_dodging);
+ lo->commit();
+ UHD_CHECK_REGMAP(
+ std::map<uint8_t, uint16_t>{
+ {36, 0x0050},
+ {42, 0x0000},
+ {43, 0x0000},
+ },
+ mem.mem);
+ // VCO_PHASE_SYNC_EN must be off in this case, b/c we're using the SYNC pin
+ BOOST_CHECK_EQUAL(mem.mem[0] & (1 << 14), 0);
+
+ // Test Category 3 + SYNC:
+ // Will set CHDIV to 1.
+ lo->set_frequency(
+ 50.5 * 64e6, 64e6, zbx_spur_dodging);
+ lo->commit();
+ UHD_CHECK_REGMAP(
+ std::map<uint8_t, uint16_t>{
+ {36, 0x0032},
+ },
+ mem.mem);
+ // VCO_PHASE_SYNC_EN must be on in this case
+ BOOST_CHECK(mem.mem[0] & (1 << 14));
+
+ // Will set CHDIV to 2.
+ lo->set_frequency(
+ 50.5 * 64e6 / 2, 64e6, zbx_spur_dodging);
+ lo->commit();
+ UHD_CHECK_REGMAP(
+ std::map<uint8_t, uint16_t>{
+ {11, 0xB028}, // PLL_R == 2. Note this is a ZBX-specific design choice.
+ {36, 0x0032}, // With PLL_R == 2, you would expect this to be 100, but it's
+ // only half that!
+ },
+ mem.mem);
+ // VCO_PHASE_SYNC_EN must be on in this case
+ BOOST_CHECK(mem.mem[0] & (1 << 14));
+}