From 0e7fe25f42105de0d01fc568cc717f9f04d825b7 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Sat, 29 Apr 2017 18:57:30 -0700 Subject: mpm: eiscat: Added first pass at EISCAT dboard driver --- mpm/include/mpm/dboards/eiscat_manager.hpp | 70 +++++ mpm/lib/dboards/CMakeLists.txt | 1 + mpm/lib/dboards/eiscat_manager.cpp | 36 +++ mpm/python/pyusrp_periphs.cpp | 2 + mpm/python/usrp_mpm/dboard_manager/__init__.py | 4 +- mpm/python/usrp_mpm/dboard_manager/eiscat.py | 354 ++++++++++++++++++++++- mpm/python/usrp_mpm/dboard_manager/lmk_eiscat.py | 228 +++++++++++++++ mpm/python/usrp_mpm/periph_manager/base.py | 2 +- 8 files changed, 690 insertions(+), 7 deletions(-) create mode 100644 mpm/include/mpm/dboards/eiscat_manager.hpp create mode 100644 mpm/lib/dboards/eiscat_manager.cpp create mode 100644 mpm/python/usrp_mpm/dboard_manager/lmk_eiscat.py diff --git a/mpm/include/mpm/dboards/eiscat_manager.hpp b/mpm/include/mpm/dboards/eiscat_manager.hpp new file mode 100644 index 000000000..42f80ff8e --- /dev/null +++ b/mpm/include/mpm/dboards/eiscat_manager.hpp @@ -0,0 +1,70 @@ +// +// Copyright 2017 Ettus Research (National Instruments) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#pragma once + +#include +#include +#include +#include + +namespace mpm { namespace dboards { + class eiscat_manager// : public dboard_periph_manager + { + public: + eiscat_manager( + const std::string &lmk_spidev, + const std::string &adc0_spidev, + const std::string &adc1_spidev + //const std::string &phdac_spidev, + ); + + /*! Return a reference to the SPI mutex + */ + mpm::types::lockable::sptr get_spi_lock() { return _spi_lock; } + + /*! Return a reference to the clock chip controls + */ + mpm::types::regs_iface::sptr get_clock_ctrl(){ return _clock_ctrl; } + + mpm::types::regs_iface::sptr get_adc0_ctrl(){ return _adc0_ctrl; } + mpm::types::regs_iface::sptr get_adc1_ctrl(){ return _adc1_ctrl; } + + private: + std::shared_ptr _spi_mutex; + + mpm::types::lockable::sptr _spi_lock; + mpm::types::regs_iface::sptr _clock_ctrl; + mpm::types::regs_iface::sptr _adc0_ctrl; + mpm::types::regs_iface::sptr _adc1_ctrl; + //mpm::types::regs_iface::sptr _phdac_ctrl; + }; + +}}; /* namespace mpm::dboards */ + +#ifdef LIBMPM_PYTHON +void export_eiscat(){ + LIBMPM_BOOST_PREAMBLE("eiscat") + using namespace mpm::dboards; + bp::class_("eiscat_manager", bp::init()) + .def("get_spi_lock", &mpm::dboards::eiscat_manager::get_spi_lock) + .def("get_clock_ctrl", &mpm::dboards::eiscat_manager::get_clock_ctrl) + .def("get_adc0_ctrl", &mpm::dboards::eiscat_manager::get_adc0_ctrl) + .def("get_adc1_ctrl", &mpm::dboards::eiscat_manager::get_adc1_ctrl) + ; +} +#endif diff --git a/mpm/lib/dboards/CMakeLists.txt b/mpm/lib/dboards/CMakeLists.txt index 349be0b93..4ca21ee37 100644 --- a/mpm/lib/dboards/CMakeLists.txt +++ b/mpm/lib/dboards/CMakeLists.txt @@ -22,5 +22,6 @@ USRP_PERIPHS_ADD_OBJECT(dboards magnesium_manager.cpp + eiscat_manager.cpp ) diff --git a/mpm/lib/dboards/eiscat_manager.cpp b/mpm/lib/dboards/eiscat_manager.cpp new file mode 100644 index 000000000..f3a9794f8 --- /dev/null +++ b/mpm/lib/dboards/eiscat_manager.cpp @@ -0,0 +1,36 @@ +// +// Copyright 2017 Ettus Research (National Instruments) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include +#include + +using namespace mpm::dboards; +using namespace mpm::chips; + +eiscat_manager::eiscat_manager( + const std::string &lmk_spidev, + const std::string &adc0_spidev, + const std::string &adc1_spidev +) : _spi_mutex(std::make_shared()) + , _spi_lock(mpm::types::lockable::make(_spi_mutex)) + , _clock_ctrl(mpm::chips::make_lmk04828_iface(lmk_spidev)) + , _adc0_ctrl(mpm::chips::make_lmk04828_iface(adc0_spidev)) + , _adc1_ctrl(mpm::chips::make_lmk04828_iface(adc1_spidev)) +{ + +} + diff --git a/mpm/python/pyusrp_periphs.cpp b/mpm/python/pyusrp_periphs.cpp index 5aac12088..c48860ebe 100644 --- a/mpm/python/pyusrp_periphs.cpp +++ b/mpm/python/pyusrp_periphs.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include namespace bp = boost::python; @@ -47,4 +48,5 @@ BOOST_PYTHON_MODULE(libpyusrp_periphs) export_mykonos(); export_xbar(); export_magnesium(); + export_eiscat(); } diff --git a/mpm/python/usrp_mpm/dboard_manager/__init__.py b/mpm/python/usrp_mpm/dboard_manager/__init__.py index e1ae5d3e0..93de24695 100644 --- a/mpm/python/usrp_mpm/dboard_manager/__init__.py +++ b/mpm/python/usrp_mpm/dboard_manager/__init__.py @@ -19,11 +19,11 @@ dboards module __init__.py """ from .. import libpyusrp_periphs as lib from .magnesium import Magnesium -from .eiscat import eiscat +from .eiscat import EISCAT from .test import test from .unknown import unknown HW_PIDS = { - eiscat.hw_pid: eiscat, + EISCAT.hw_pid: EISCAT, Magnesium.hw_pid: Magnesium, } diff --git a/mpm/python/usrp_mpm/dboard_manager/eiscat.py b/mpm/python/usrp_mpm/dboard_manager/eiscat.py index 436307c1e..4534e124d 100644 --- a/mpm/python/usrp_mpm/dboard_manager/eiscat.py +++ b/mpm/python/usrp_mpm/dboard_manager/eiscat.py @@ -17,13 +17,359 @@ """ EISCAT rx board implementation module """ + +import time +from six import iteritems +from ..mpmlog import get_logger +from ..uio import UIO from . import lib from .base import DboardManagerBase +from .lmk_eiscat import LMK04828EISCAT + +N_CHANS = 8 # Chans per dboard + +# Power enable pins +POWER_ENB = 0x200C # Address of the power enable register +PWR_CHAN_EN_2V5 = [ (1<. +# +""" +LMK04828 driver for use with Magnesium +""" + +import time +from ..mpmlog import get_logger + +LMK_CHIP_ID = 6 + +class LMK04828EISCAT(object): + """ + LMK04828 controls for EISCAT daughterboard + """ + def __init__(self, regs_iface, spi_lock, slot=None): + slot = slot or "-A" + self.log = get_logger("LMK04828"+slot) + self.regs_iface = regs_iface + self.spi_lock = spi_lock + self.init() + self.config() + + def pokes8(self, addr_vals): + """ + Apply a series of pokes + """ + for addr, val in addr_vals: + self.regs_iface.poke8(addr, val) + + def init(self): + """ + Basic init. Turns it on. Let's us read SPI. + """ + self.log.info("Init LMK") + self.pokes8(( + (0x000, 0x90), # Assert reset + (0x000, 0x10), # De-assert reset + (0x002, 0x00), # De-assert power down + (0x16E, 0x3B), # PLL2 Lock Detect Config as SDO + )) + if not self.verify_chip_id(): + raise Exception("Unable to locate LMK04828") + + + def config(self): + """ + Write lots of config foo. + """ + self.log.trace("Setting clkout config...") + self.pokes8(( + (0x100, 0x6C), # CLKout Config + (0x101, 0x55), # CLKout Config + (0x103, 0x00), # CLKout Config + (0x104, 0x20), # CLKout Config + (0x105, 0x00), # CLKout Config + (0x106, 0xF3), # CLKout Config + (0x107, 0x05), # CLKout Config + (0x108, 0x6C), # CLKout Config + (0x109, 0x55), # CLKout Config + (0x10B, 0x00), # CLKout Config + (0x10C, 0x20), # CLKout Config + (0x10D, 0x00), # CLKout Config + (0x10E, 0xF1), # CLKout Config + (0x10F, 0x05), # CLKout Config + (0x110, 0x6C), # CLKout Config + (0x111, 0x55), # CLKout Config + (0x113, 0x00), # CLKout Config + (0x114, 0x20), # CLKout Config + (0x115, 0x00), # CLKout Config + (0x116, 0xF1), # CLKout Config + (0x117, 0x05), # CLKout Config + (0x118, 0x6C), # CLKout Config + (0x119, 0x55), # CLKout Config + (0x11B, 0x00), # CLKout Config + (0x11C, 0x20), # CLKout Config + (0x11D, 0x00), # CLKout Config + (0x11E, 0xF1), # CLKout Config + (0x11F, 0x05), # CLKout Config + (0x120, 0x78), # CLKout Config + (0x121, 0x55), # CLKout Config + (0x123, 0x00), # CLKout Config + (0x124, 0x20), # CLKout Config + (0x125, 0x00), # CLKout Config + (0x126, 0xF3), # CLKout Config + (0x127, 0x00), # CLKout Config + (0x128, 0x6C), # CLKout Config + (0x129, 0x55), # CLKout Config + (0x12B, 0x00), # CLKout Config + (0x12C, 0x20), # CLKout Config + (0x12D, 0x00), # CLKout Config + (0x12E, 0xF9), # CLKout Config + (0x12F, 0x00), # CLKout Config + (0x130, 0x6C), # CLKout Config + (0x131, 0x55), # CLKout Config + (0x133, 0x00), # CLKout Config + (0x134, 0x20), # CLKout Config + (0x135, 0x00), # CLKout Config + (0x136, 0xF9), # CLKout Config + (0x137, 0x00), # CLKout Config + (0x138, 0x10), # VCO_MUX to VCO 1; OSCout off + (0x139, 0x00), # SYSREF Source = MUX; SYSREF MUX = Normal SYNC + (0x13A, 0x01), # SYSREF Divide [12:8] + (0x13B, 0xE0), # SYSREF Divide [7:0] + (0x13C, 0x00), # SYSREF DDLY [12:8] + (0x13D, 0x08), # SYSREF DDLY [7:0] ... 8 is default, <8 is reserved + (0x13E, 0x00), # SYSREF Pulse Count = 1 pulse/request + (0x13F, 0x0B), # Feedback Mux: Enabled, DCLKout6, drives PLL1N divider + (0x140, 0x00), # POWERDOWN options + (0x141, 0x00), # Dynamic digital delay enable + (0x142, 0x00), # Dynamic digital delay step + (0x143, 0xD1), # SYNC edge sensitive; SYSREF_CLR; SYNC Enabled; SYNC fro + (0x144, 0x00), # Enable SYNC on all outputs including sysref + (0x145, 0x7F), # Always program to d127 + (0x146, 0x08), # CLKin Type & En + (0x147, 0x0E), # CLKin_SEL = CLKin1 manual; CLKin1 to PLL1 + (0x148, 0x01), # CLKin_SEL0 = input with pullup + (0x149, 0x01), # CLKin_SEL1 = input with pulldown + (0x14A, 0x02), # RESET type as input w/pulldown + (0x14B, 0x01), # Holdover & DAC Manual Mode + (0x14C, 0xF6), # DAC Manual Mode + (0x14D, 0x00), # DAC Settings (defaults) + (0x14E, 0x00), # DAC Settings (defaults) + (0x14F, 0x7F), # DAC Settings (defaults) + (0x150, 0x03), # Holdover Settings (defaults) + (0x151, 0x02), # Holdover Settings (defaults) + (0x152, 0x00), # Holdover Settings (defaults) + (0x153, 0x00), # CLKin0_R divider [13:8], default = 0 + (0x154, 0x0A), # CLKin0_R divider [7:0], default = d120 + (0x155, 0x00), # CLKin1_R divider [13:8], default = 0 + (0x156, 0x01), # CLKin1_R divider [7:0], default = d120 + (0x157, 0x00), # CLKin2_R divider [13:8], default = 0 + (0x158, 0x01), # CLKin2_R divider [7:0], default = d120 + (0x159, 0x00), # PLL1 N divider [13:8], default = 0 + (0x15A, 0x68), # PLL1 N divider [7:0], default = d120 + (0x15B, 0xCF), # PLL1 PFD + (0x15C, 0x27), # PLL1 DLD Count [13:8] + (0x15D, 0x10), # PLL1 DLD Count [7:0] + (0x15E, 0x00), # PLL1 R/N delay, defaults = 0 + (0x15F, 0x13), # Status LD1 pin = PLL2 LD, push-pull output + (0x160, 0x00), # PLL2 R divider [11:8]; + (0x161, 0x01), # PLL2 R divider [7:0] + (0x162, 0x24), # PLL2 prescaler; OSCin freq + (0x163, 0x00), # PLL2 Cal = PLL2 normal val + (0x164, 0x00), # PLL2 Cal = PLL2 normal val + (0x165, 0x0C), # PLL2 Cal = PLL2 normal val + (0x171, 0xAA), # Write this val after x165 + (0x172, 0x02), # Write this val after x165 + (0x17C, 0x15), # VCo1 Cal; write before x168 + (0x17D, 0x33), # VCo1 Cal; write before x168 + (0x166, 0x00), # PLL2 N[17:16] + (0x167, 0x00), # PLL2 N[15:8] + (0x168, 0x0C), # PLL2 N[7:0] + (0x169, 0x51), # PLL2 PFD + (0x16A, 0x00), # PLL2 DLD Count [13:8] = default d32 + (0x16B, 0x10), # PLL2 DLD Count [7:0] = default d0 + (0x16C, 0x00), # PLL2 Loop filter r = 200 ohm + (0x16D, 0x00), # PLL2 loop filter c = 10 pF + (0x173, 0x00), # Do not power down PLL2 or prescaler + )) + time.sleep(0.1) + self.pokes8(( + (0x182, 0x1), # Clear Lock Detect Sticky + (0x182, 0x0), # Clear Lock Detect Sticky + (0x183, 0x1), # Clear Lock Detect Sticky + (0x183, 0x0), # Clear Lock Detect Sticky + )) + time.sleep(0.1) + self.log.trace("Checking PLL lock bits...") + def check_pll_lock(pll_id, addr): + pll_lock_status = self.regs_iface.peek8(addr) + if (pll_lock_status & 0x7) != 0x02: + self.log.error("LMK {} did not lock. Status: {:x}".format(pll_id, pll_lock_status)) + raise RuntimeError("LMK {} did not lock.".format(pll_id)) + check_pll_lock("PLL1", 0x182) + check_pll_lock("PLL2", 0x183) + self.log.trace("Setting SYNC and SYSREF config...") + self.pokes8(( + (0x143, 0xF1), # toggle SYNC polarity to trigger SYNC event + (0x143, 0xD1), # toggle SYNC polarity to trigger SYNC event + (0x139, 0x02), # SYSREF Source = MUX; SYSREF MUX = pulser + (0x144, 0xFF), # Disable SYNC on all outputs including sysref + (0x143, 0x52), # Pulser selected; SYNC enabled; 1 shot enabled + )) + self.log.info("LMK init'd and locked!") + + def get_chip_id(self): + """ + Read back the chip ID + """ + chip_id = self.regs_iface.peek8(0x03) + self.log.trace("Read chip ID: {}".format(chip_id)) + return chip_id + + def verify_chip_id(self): + """ + Returns True if the chip ID matches what we expect, False otherwise. + """ + chip_id = self.get_chip_id() + if chip_id != LMK_CHIP_ID: + self.log.error("wrong chip id {0}".format(chip_id)) + return False + return True + + # TODO delete this + # def enable_sysref_pulse(self): + # """ + # Enable SYSREF pulses + # """ + # self.spi_lock.lock() + # self.poke8(0x139, 0x2) + # self.poke8(0x144, 0xFF) + # self.poke8(0x143, 0x52) + # self.spi_lock.unlock() diff --git a/mpm/python/usrp_mpm/periph_manager/base.py b/mpm/python/usrp_mpm/periph_manager/base.py index 4815bd88d..25f635c68 100644 --- a/mpm/python/usrp_mpm/periph_manager/base.py +++ b/mpm/python/usrp_mpm/periph_manager/base.py @@ -75,7 +75,7 @@ class PeriphManagerBase(object): # eeprom_data = EEPROM().read_eeprom(get_eeprom_path(eeprom_addr)) eeprom_data = None # I know spidev masters on the dboard slots - hw_pid = 2 + hw_pid = 3 if hw_pid in dboard_manager.HW_PIDS: spi_devices = sorted(get_spidev_nodes("e0006000.spi")) self.log.debug("Found spidev nodes: {0}".format(spi_devices)) -- cgit v1.2.3