diff options
author | Trung N Tran <trung.tran@ettus.com> | 2018-02-01 14:28:41 -0800 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2018-02-21 16:58:51 -0800 |
commit | 6d0404c678d44eb41b39f792dff5915fd218f722 (patch) | |
tree | 6cc6839bc0c60882a0b42ecc1e9b48ca1c53091b | |
parent | d5109ae99e5da24707a8d7a6d57b96f6deabbede (diff) | |
download | uhd-6d0404c678d44eb41b39f792dff5915fd218f722.tar.gz uhd-6d0404c678d44eb41b39f792dff5915fd218f722.tar.bz2 uhd-6d0404c678d44eb41b39f792dff5915fd218f722.zip |
n3xx: add front panel gpio control registers
-rw-r--r-- | host/lib/usrp/dboard/magnesium/magnesium_constants.hpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp | 132 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/n310.py | 79 |
3 files changed, 205 insertions, 8 deletions
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp b/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp index 4df645c33..151e68220 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp @@ -12,7 +12,7 @@ #include <cstddef> static constexpr size_t FPGPIO_MASTER_RADIO = 0; - +static constexpr size_t TOTAL_RADIO_PORTS = 4; static constexpr double AD9371_RX_MIN_BANDWIDTH = 20.0e6; // HZ static constexpr double AD9371_RX_MAX_BANDWIDTH = 100.0e6; // HZ diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp index c781fbfe9..5b0eb60d1 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp @@ -13,7 +13,9 @@ #include <uhd/transport/chdr.hpp> #include <vector> #include <string> - +#include <boost/algorithm/string.hpp> +#include <boost/algorithm/string/split.hpp> +#include <boost/algorithm/string/case_conv.hpp> using namespace uhd; using namespace uhd::rfnoc; @@ -37,6 +39,40 @@ namespace { }; } +//! Helper function to extract single value of port number. +// +// Each GPIO pins can be controlled by each radio output ports. +// This function convert the format of attribute "Radio_N_M" +// to a single value port number = N*number_of_port_per_radio + M + +uint32_t extract_port_number(std::string radio_src_string, uhd::property_tree::sptr ptree){ + std::string s_val = "0"; + std::vector<std::string> radio_strings; + boost::algorithm::split( + radio_strings, + radio_src_string, + boost::is_any_of("_/"), + boost::token_compress_on); + boost::to_lower(radio_strings[0]); + if (radio_strings.size()<3) { + throw uhd::runtime_error(str(boost::format("%s is an invalid GPIO source string.") % radio_src_string)); + } + size_t radio_num = std::stoi(radio_strings[1]); + size_t port_num = std::stoi(radio_strings[2]); + if (radio_strings[0] != "radio") { + throw uhd::runtime_error("Front panel GPIO bank can only accept a radio block as its driver."); + } + std::string radio_port_out = "Radio_"+ radio_strings[1] + "/ports/out"; + std::string radio_port_path = radio_port_out + "/"+ radio_strings[2]; + auto found = ptree->exists(fs_path("xbar")/ radio_port_path); + if (not found){ + throw uhd::runtime_error(str(boost::format( + "Could not find radio port %s.\n") % radio_port_path)); + } + size_t port_size = ptree->list(fs_path("xbar")/ radio_port_out).size(); + return radio_num*port_size + port_num; +} + void magnesium_radio_ctrl_impl::_init_defaults() { UHD_LOG_TRACE(unique_id(), "Initializing defaults..."); @@ -190,11 +226,9 @@ void magnesium_radio_ctrl_impl::_init_peripherals() usrp::gpio_atr::gpio_atr_3000::MASK_SET_ALL ); } - if (get_block_id().get_block_count() == FPGPIO_MASTER_RADIO) { - UHD_LOG_TRACE(unique_id(), "Initializing front-panel GPIO control...") - _fp_gpio = usrp::gpio_atr::gpio_atr_3000::make( - _get_ctrl(0), regs::sr_addr(regs::FP_GPIO), regs::RB_FP_GPIO); - } + UHD_LOG_TRACE(unique_id(), "Initializing front-panel GPIO control...") + _fp_gpio = usrp::gpio_atr::gpio_atr_3000::make( + _get_ctrl(0), regs::sr_addr(regs::FP_GPIO), regs::RB_FP_GPIO); } void magnesium_radio_ctrl_impl::_init_frontend_subtree( @@ -739,8 +773,94 @@ void magnesium_radio_ctrl_impl::_init_prop_tree() .set_publisher([this](){ return this->get_rate(); }) ; } + + // *****FP_GPIO************************ + for(const auto& attr: usrp::gpio_atr::gpio_attr_map) { + if (not _tree->exists(fs_path("gpio") / "FP0" / attr.second)){ + switch (attr.first){ + case usrp::gpio_atr::GPIO_SRC: + //FIXME: move this creation of this branch of ptree out side of radio impl; + // since there's no data dependency between radio and SRC setting for FP0 + _tree->create<std::vector<std::string>>(fs_path("gpio") / "FP0" / attr.second) + .set(std::vector<std::string>( + 32, + usrp::gpio_atr::default_attr_value_map.at(attr.first))) + .add_coerced_subscriber([this, attr]( + const std::vector<std::string> str_val){ + uint32_t radio_src_value = 0; + uint32_t master_value = 0; + for(size_t i = 0 ; i<str_val.size(); i++){ + if(str_val[i] == "PS"){ + master_value += 1<<i;; + }else{ + auto port_num = extract_port_number(str_val[i],_tree); + radio_src_value =(1<<(2*i))*port_num + radio_src_value; + } + } + _rpcc->notify_with_token("set_fp_gpio_master", master_value); + _rpcc->notify_with_token("set_fp_gpio_radio_src", radio_src_value); + }); + break; + case usrp::gpio_atr::GPIO_CTRL: + case usrp::gpio_atr::GPIO_DDR: + _tree->create<std::vector<std::string>>(fs_path("gpio") / "FP0" / attr.second) + .set(std::vector<std::string>( + 32, + usrp::gpio_atr::default_attr_value_map.at(attr.first))) + .add_coerced_subscriber([this, attr]( + const std::vector<std::string> str_val){ + uint32_t val = 0; + for(size_t i = 0 ; i < str_val.size() ; i++){ + val += usrp::gpio_atr::gpio_attr_value_pair.at(attr.second).at(str_val[i])<<i; + } + _fp_gpio->set_gpio_attr(attr.first, val); + }); + break; + case usrp::gpio_atr::GPIO_READBACK:{ + _tree->create<uint32_t>(fs_path("gpio") / "FP0" / attr.second) + .set_publisher([this](){ + return _fp_gpio->read_gpio(); + } + ); + } + break; + default: + _tree->create<uint32_t>(fs_path("gpio") / "FP0" / attr.second) + .set(0) + .add_coerced_subscriber([this, attr](const uint32_t val){ + _fp_gpio->set_gpio_attr(attr.first, val); + }); + } + }else{ + switch (attr.first){ + case usrp::gpio_atr::GPIO_SRC: + break; + case usrp::gpio_atr::GPIO_CTRL: + case usrp::gpio_atr::GPIO_DDR: + _tree->access<std::vector<std::string>>(fs_path("gpio") / "FP0" / attr.second) + .set(std::vector<std::string>(32, usrp::gpio_atr::default_attr_value_map.at(attr.first))) + .add_coerced_subscriber([this, attr](const std::vector<std::string> str_val){ + uint32_t val = 0; + for(size_t i = 0 ; i < str_val.size() ; i++){ + val += usrp::gpio_atr::gpio_attr_value_pair.at(attr.second).at(str_val[i])<<i; + } + _fp_gpio->set_gpio_attr(attr.first, val); + }); + break; + case usrp::gpio_atr::GPIO_READBACK: + break; + default: + _tree->access<uint32_t>(fs_path("gpio") / "FP0" / attr.second) + .set(0) + .add_coerced_subscriber([this, attr](const uint32_t val){ + _fp_gpio->set_gpio_attr(attr.first, val); + }); + } + } + } } + void magnesium_radio_ctrl_impl::_init_mpm_sensors( const direction_t dir, const size_t chan_idx diff --git a/mpm/python/usrp_mpm/periph_manager/n310.py b/mpm/python/usrp_mpm/periph_manager/n310.py index e51e4228d..beef6048c 100644 --- a/mpm/python/usrp_mpm/periph_manager/n310.py +++ b/mpm/python/usrp_mpm/periph_manager/n310.py @@ -33,7 +33,7 @@ N3XX_DEFAULT_CLOCK_SOURCE = 'internal' N3XX_DEFAULT_TIME_SOURCE = 'internal' N3XX_DEFAULT_ENABLE_GPS = True N3XX_DEFAULT_ENABLE_FPGPIO = True -N3XX_FPGA_COMPAT = (5, 1) +N3XX_FPGA_COMPAT = (5, 2) N3XX_MONITOR_THREAD_INTERVAL = 1.0 # seconds N3XX_SFP_TYPES = {0:"", 1:"1G", 2:"10G", 3:"A"} @@ -185,6 +185,8 @@ class MboardRegsControl(object): MB_BUS_COUNTER = 0x0024 MB_SFP0_INFO = 0x0028 MB_SFP1_INFO = 0x002C + MB_GPIO_MASTER = 0x0030 + MB_GPIO_RADIO_SRC = 0x0034 # Bitfield locations for the MB_CLOCK_CTRL register. MB_CLOCK_CTRL_PPS_SEL_INT_10 = 0 # pps_sel is one-hot encoded! @@ -217,6 +219,46 @@ class MboardRegsControl(object): major = (compat_number>>16) & 0xff return (major, minor) + def set_fp_gpio_master(self, value): + """set driver for front panel GPIO + Arguments: + value {unsigned} -- value is a single bit bit mask of 12 pins GPIO + """ + with self.regs.open(): + return self.poke32(self.MB_GPIO_MASTER, value) + + def get_fp_gpio_master(self): + """get "who" is driving front panel gpio + The return value is a bit mask of 12 pins GPIO. + 0: means the pin is driven by PL + 1: means the pin is driven by PS + """ + with self.regs.open(): + return self.peek32(self.MB_GPIO_MASTER) & 0xfff + + def set_fp_gpio_radio_src(self, value): + """set driver for front panel GPIO + Arguments: + value {unsigned} -- value is 2-bit bit mask of 12 pins GPIO + 00: means the pin is driven by radio 0 + 01: means the pin is driven by radio 1 + 10: means the pin is driven by radio 2 + 11: means the pin is driven by radio 3 + """ + with self.regs.open(): + return self.poke32(self.MB_GPIO_RADIO_SRC, value) + + def get_fp_gpio_radio_src(self): + """get which radio is driving front panel gpio + The return value is 2-bit bit mask of 12 pins GPIO. + 00: means the pin is driven by radio 0 + 01: means the pin is driven by radio 1 + 10: means the pin is driven by radio 2 + 11: means the pin is driven by radio 3 + """ + with self.regs.open(): + return self.peek32(self.MB_GPIO_RADIO_SRC) & 0xffffff + def get_build_timestamp(self): """ Returns the build date/time for the FPGA image. @@ -840,6 +882,41 @@ class n310(PeriphManagerBase): self.mboard_regs_control.set_time_source( time_source, self.get_ref_clock_freq()) + def set_fp_gpio_master(self, value): + """set driver for front panel GPIO + Arguments: + value {unsigned} -- value is a single bit bit mask of 12 pins GPIO + """ + self.mboard_regs_control.set_fp_gpio_master(value) + + def get_fp_gpio_master(self): + """get "who" is driving front panel gpio + The return value is a bit mask of 12 pins GPIO. + 0: means the pin is driven by PL + 1: means the pin is driven by PS + """ + return self.mboard_regs_control.get_fp_gpio_master() + + def set_fp_gpio_radio_src(self, value): + """set driver for front panel GPIO + Arguments: + value {unsigned} -- value is 2-bit bit mask of 12 pins GPIO + 00: means the pin is driven by radio 0 + 01: means the pin is driven by radio 1 + 10: means the pin is driven by radio 2 + 11: means the pin is driven by radio 3 + """ + self.mboard_regs_control.set_fp_gpio_radio_src(value) + + def get_fp_gpio_radio_src(self): + """get which radio is driving front panel gpio + The return value is 2-bit bit mask of 12 pins GPIO. + 00: means the pin is driven by radio 0 + 01: means the pin is driven by radio 1 + 10: means the pin is driven by radio 2 + 11: means the pin is driven by radio 3 + """ + return self.mboard_regs_control.get_fp_gpio_radio_src() ########################################################################### # Hardware periphal controls ########################################################################### |