diff options
Diffstat (limited to 'host/tests/lmx2572_test.cpp')
-rw-r--r-- | host/tests/lmx2572_test.cpp | 150 |
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)); +} |