aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrung N Tran <trung.tran@ettus.com>2018-02-01 14:28:41 -0800
committerMartin Braun <martin.braun@ettus.com>2018-02-21 16:58:51 -0800
commit6d0404c678d44eb41b39f792dff5915fd218f722 (patch)
tree6cc6839bc0c60882a0b42ecc1e9b48ca1c53091b
parentd5109ae99e5da24707a8d7a6d57b96f6deabbede (diff)
downloaduhd-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.hpp2
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp132
-rw-r--r--mpm/python/usrp_mpm/periph_manager/n310.py79
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
###########################################################################