aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2019-11-14 13:35:20 -0800
committerBrent Stapleton <brent.stapleton@ettus.com>2020-01-23 11:37:51 -0800
commit354886ed4cee82317f6ad45bc57a14af67cce85f (patch)
tree0bb7b1d99055676c28fd20f04f90dfbcd424ffae
parent90a72e8cd4cd1d4971c0e09d9813c9fc43371062 (diff)
downloaduhd-354886ed4cee82317f6ad45bc57a14af67cce85f.tar.gz
uhd-354886ed4cee82317f6ad45bc57a14af67cce85f.tar.bz2
uhd-354886ed4cee82317f6ad45bc57a14af67cce85f.zip
mpm: e320/e310: Expose APIs to drive GPIO source via UHD
This enables the *gpio_src* APIs for the E320 and the E31x.
-rwxr-xr-xmpm/python/e320_bist4
-rw-r--r--mpm/python/usrp_mpm/periph_manager/e31x.py98
-rw-r--r--mpm/python/usrp_mpm/periph_manager/e31x_periphs.py16
-rw-r--r--mpm/python/usrp_mpm/periph_manager/e320.py101
-rw-r--r--mpm/python/usrp_mpm/periph_manager/e320_periphs.py8
5 files changed, 147 insertions, 80 deletions
diff --git a/mpm/python/e320_bist b/mpm/python/e320_bist
index ad5b2163a..c9662fe14 100755
--- a/mpm/python/e320_bist
+++ b/mpm/python/e320_bist
@@ -334,7 +334,7 @@ class E320BIST(bist.UsrpBIST):
- read_patterns: A list of patterns that were read back
"""
assert 'gpio' in self.tests_to_run
- GPIO_WIDTH = 8
+ gpio_width = 8
patterns = range(16)
if self.args.dry_run:
return True, {
@@ -353,7 +353,7 @@ class E320BIST(bist.UsrpBIST):
" Run a GPIO test for a given set of patterns "
gpio_ctrl = e320_periphs.FrontpanelGPIO(ddr)
for pattern in patterns:
- bist.gpio_set_all(gpio_ctrl, pattern, GPIO_WIDTH, ddr)
+ bist.gpio_set_all(gpio_ctrl, pattern, gpio_width, ddr)
time.sleep(0.1)
gpio_rb = gpio_ctrl.get_all()
if pattern != gpio_rb:
diff --git a/mpm/python/usrp_mpm/periph_manager/e31x.py b/mpm/python/usrp_mpm/periph_manager/e31x.py
index 355945de4..d2e22b498 100644
--- a/mpm/python/usrp_mpm/periph_manager/e31x.py
+++ b/mpm/python/usrp_mpm/periph_manager/e31x.py
@@ -33,6 +33,10 @@ E310_DEFAULT_ENABLE_FPGPIO = True
E310_DEFAULT_DONT_RELOAD_FPGA = False # False means idle image gets reloaded
E310_FPGA_COMPAT = (5, 0)
E310_DBOARD_SLOT_IDX = 0
+E310_GPIO_SRC_PS = "PS"
+# We use the index positions of RFA and RFB to map between name and radio index
+E310_GPIO_SRCS = ("RFA", "RFB", E310_GPIO_SRC_PS)
+E310_FPGPIO_WIDTH = 6
###############################################################################
# Transport managers
@@ -565,40 +569,70 @@ class e31x(ZynqComponents, PeriphManagerBase):
self.mboard_regs_control.set_time_source(time_source)
###########################################################################
- # Hardware peripheral controls
+ # GPIO API
###########################################################################
- 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 8 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 8 pins GPIO
- 00: means the pin is driven by radio 0
- 01: means the pin is driven by radio 1
- """
- 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 8 pins GPIO.
- 00: means the pin is driven by radio 0
- 01: means the pin is driven by radio 1
- """
- return self.mboard_regs_control.get_fp_gpio_radio_src()
+ def get_gpio_banks(self):
+ """
+ Returns a list of GPIO banks over which MPM has any control
+ """
+ return E310_GPIO_BANKS
+
+ def get_gpio_srcs(self, bank):
+ """
+ Return a list of valid GPIO sources for a given bank
+ """
+ assert bank in self.get_gpio_banks(), "Invalid GPIO bank: {}".format(bank)
+ return self._fp_gpio_srcs
+
+ def get_gpio_src(self, bank):
+ """
+ Return the currently selected GPIO source for a given bank. The return
+ value is a list of strings. The length of the vector is identical to
+ the number of controllable GPIO pins on this bank.
+ """
+ assert bank in self.get_gpio_banks(), "Invalid GPIO bank: {}".format(bank)
+ gpio_master_reg = self.mboard_regs_control.get_fp_gpio_master()
+ gpio_radio_src_reg = self.mboard_regs_control.get_fp_gpio_radio_src()
+ def get_gpio_src_i(gpio_pin_index):
+ """
+ Return the current radio source given a pin index.
+ """
+ if gpio_master_reg & (1 << gpio_pin_index):
+ return E310_GPIO_SRC_PS
+ radio_src = (gpio_radio_src_reg >> (2 * gpio_pin_index)) & 0b11
+ assert radio_src in (0, 1)
+ return E310_GPIO_SRCS[radio_src]
+ return [get_gpio_src_i(i) for i in range(E310_FPGPIO_WIDTH)]
+
+ def set_gpio_src(self, bank, src):
+ """
+ Set the GPIO source for a given bank.
+ """
+ assert bank in self.get_gpio_banks(), "Invalid GPIO bank: {}".format(bank)
+ assert len(src) == E310_FPGPIO_WIDTH, \
+ "Invalid number of GPIO sources!"
+ gpio_master_reg = 0x00
+ gpio_radio_src_reg = self.mboard_regs_control.get_fp_gpio_radio_src()
+ for src_index, src_name in enumerate(src):
+ if src_name not in self.get_gpio_srcs(bank):
+ raise RuntimeError(
+ "Invalid GPIO source name `{}' at bit position {}!"
+ .format(src_name, src_index))
+ gpio_master_flag = (src_name == E310_GPIO_SRC_PS)
+ gpio_master_reg = gpio_master_reg | (gpio_master_flag << src_index)
+ if gpio_master_flag:
+ continue
+ # If PS is not the master, we also need to update the radio source:
+ radio_index = E310_GPIO_SRCS.index(src_name)
+ gpio_radio_src_reg = gpio_radio_src_reg | (radio_index << (2*src_index))
+ self.log.trace("Updating GPIO source: master==0x{:02X} radio_src={:03X}"
+ .format(gpio_master_reg, gpio_radio_src_reg))
+ self.mboard_regs_control.set_fp_gpio_master(gpio_master_reg)
+ self.mboard_regs_control.set_fp_gpio_radio_src(gpio_radio_src_reg)
+ ###########################################################################
+ # Hardware peripheral controls
+ ###########################################################################
def set_channel_mode(self, channel_mode):
"Set channel mode in FPGA and select which tx channel to use"
self.mboard_regs_control.set_channel_mode(channel_mode)
diff --git a/mpm/python/usrp_mpm/periph_manager/e31x_periphs.py b/mpm/python/usrp_mpm/periph_manager/e31x_periphs.py
index bb84ebb3e..05e72fcb6 100644
--- a/mpm/python/usrp_mpm/periph_manager/e31x_periphs.py
+++ b/mpm/python/usrp_mpm/periph_manager/e31x_periphs.py
@@ -72,24 +72,24 @@ class MboardRegsControl(MboardRegsCommon):
def set_fp_gpio_master(self, value):
"""set driver for front panel GPIO
Arguments:
- value {unsigned} -- value is a single bit bit mask of 8 pins GPIO
+ value {unsigned} -- value is a single bit bit mask of 6 pins GPIO
"""
with self.regs:
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 8 pins GPIO.
+ The return value is a bit mask of 6 pins GPIO.
0: means the pin is driven by PL
1: means the pin is driven by PS
"""
with self.regs:
- return self.peek32(self.MB_GPIO_MASTER) & 0xfff
+ return self.peek32(self.MB_GPIO_MASTER) & 0xff
def set_fp_gpio_radio_src(self, value):
"""set driver for front panel GPIO
Arguments:
- value {unsigned} -- value is 2-bit bit mask of 8 pins GPIO
+ value {unsigned} -- value is 2-bit bit mask of 6 pins GPIO
00: means the pin is driven by radio 0
01: means the pin is driven by radio 1
"""
@@ -98,12 +98,12 @@ class MboardRegsControl(MboardRegsCommon):
def get_fp_gpio_radio_src(self):
"""get which radio is driving front panel gpio
- The return value is 2-bit bit mask of 8 pins GPIO.
+ The return value is 2-bit bit mask of 6 pins GPIO.
00: means the pin is driven by radio 0
01: means the pin is driven by radio 1
"""
with self.regs:
- return self.peek32(self.MB_GPIO_RADIO_SRC) & 0xffffff
+ return self.peek32(self.MB_GPIO_RADIO_SRC) & 0xfff
def set_time_source(self, time_source):
"""
@@ -114,10 +114,10 @@ class MboardRegsControl(MboardRegsCommon):
self.log.trace("Setting time source to internal")
pps_sel_val = self.MB_CLOCK_CTRL_PPS_SEL_INT
elif time_source == 'gpsdo':
- self.log.debug("Setting time source to gpsdo...")
+ self.log.trace("Setting time source to gpsdo...")
pps_sel_val = self.MB_CLOCK_CTRL_PPS_SEL_GPS
elif time_source == 'external':
- self.log.debug("Setting time source to external...")
+ self.log.trace("Setting time source to external...")
pps_sel_val = self.MB_CLOCK_CTRL_PPS_SEL_EXT
else:
assert False, "Cannot set to invalid time source: {}".format(time_source)
diff --git a/mpm/python/usrp_mpm/periph_manager/e320.py b/mpm/python/usrp_mpm/periph_manager/e320.py
index f206ef26a..8e698250e 100644
--- a/mpm/python/usrp_mpm/periph_manager/e320.py
+++ b/mpm/python/usrp_mpm/periph_manager/e320.py
@@ -35,7 +35,11 @@ E320_DEFAULT_ENABLE_FPGPIO = True
E320_FPGA_COMPAT = (5, 0)
E320_MONITOR_THREAD_INTERVAL = 1.0 # seconds
E320_DBOARD_SLOT_IDX = 0
-
+E320_GPIO_BANKS = "FP0"
+E320_GPIO_SRC_PS = "PS"
+# We use the index positions of RFA and RFB to map between name and radio index
+E320_GPIO_SRCS = ("RFA", "RFB", E320_GPIO_SRC_PS)
+E320_FPGPIO_WIDTH = 8
###############################################################################
# Transport managers
@@ -500,41 +504,70 @@ class e320(ZynqComponents, PeriphManagerBase):
self.mboard_regs_control.set_time_source(time_source, self.get_ref_clock_freq())
###########################################################################
- # Hardware peripheral controls
+ # GPIO API
###########################################################################
+ def get_gpio_banks(self):
+ """
+ Returns a list of GPIO banks over which MPM has any control
+ """
+ return E320_GPIO_BANKS
+
+ def get_gpio_srcs(self, bank):
+ """
+ Return a list of valid GPIO sources for a given bank
+ """
+ assert bank in self.get_gpio_banks(), "Invalid GPIO bank: {}".format(bank)
+ return self._fp_gpio_srcs
+
+ def get_gpio_src(self, bank):
+ """
+ Return the currently selected GPIO source for a given bank. The return
+ value is a list of strings. The length of the vector is identical to
+ the number of controllable GPIO pins on this bank.
+ """
+ assert bank in self.get_gpio_banks(), "Invalid GPIO bank: {}".format(bank)
+ gpio_master_reg = self.mboard_regs_control.get_fp_gpio_master()
+ gpio_radio_src_reg = self.mboard_regs_control.get_fp_gpio_radio_src()
+ def get_gpio_src_i(gpio_pin_index):
+ """
+ Return the current radio source given a pin index.
+ """
+ if gpio_master_reg & (1 << gpio_pin_index):
+ return E320_GPIO_SRC_PS
+ radio_src = (gpio_radio_src_reg >> (2 * gpio_pin_index)) & 0b11
+ assert radio_src in (0, 1)
+ return E320_GPIO_SRCS[radio_src]
+ return [get_gpio_src_i(i) for i in range(E320_FPGPIO_WIDTH)]
+
+ def set_gpio_src(self, bank, src):
+ """
+ Set the GPIO source for a given bank.
+ """
+ assert bank in self.get_gpio_banks(), "Invalid GPIO bank: {}".format(bank)
+ assert len(src) == E320_FPGPIO_WIDTH, \
+ "Invalid number of GPIO sources!"
+ gpio_master_reg = 0x00
+ gpio_radio_src_reg = self.mboard_regs_control.get_fp_gpio_radio_src()
+ for src_index, src_name in enumerate(src):
+ if src_name not in self.get_gpio_srcs(bank):
+ raise RuntimeError(
+ "Invalid GPIO source name `{}' at bit position {}!"
+ .format(src_name, src_index))
+ gpio_master_flag = (src_name == E320_GPIO_SRC_PS)
+ gpio_master_reg = gpio_master_reg | (gpio_master_flag << src_index)
+ if gpio_master_flag:
+ continue
+ # If PS is not the master, we also need to update the radio source:
+ radio_index = E320_GPIO_SRCS.index(src_name)
+ gpio_radio_src_reg = gpio_radio_src_reg | (radio_index << (2*src_index))
+ self.log.trace("Updating GPIO source: master==0x{:02X} radio_src={:04X}"
+ .format(gpio_master_reg, gpio_radio_src_reg))
+ self.mboard_regs_control.set_fp_gpio_master(gpio_master_reg)
+ self.mboard_regs_control.set_fp_gpio_radio_src(gpio_radio_src_reg)
- 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 8 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 8 pins GPIO
- 00: means the pin is driven by radio 0
- 01: means the pin is driven by radio 1
- """
- 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 8 pins GPIO.
- 00: means the pin is driven by radio 0
- 01: means the pin is driven by radio 1
- """
- return self.mboard_regs_control.get_fp_gpio_radio_src()
-
+ ###########################################################################
+ # Hardware peripheral controls
+ ###########################################################################
def enable_gps(self, enable):
"""
Turn power to the GPS (CLK_GPS_PWR_EN) off or on.
diff --git a/mpm/python/usrp_mpm/periph_manager/e320_periphs.py b/mpm/python/usrp_mpm/periph_manager/e320_periphs.py
index 8dcd5a9ba..626ee602a 100644
--- a/mpm/python/usrp_mpm/periph_manager/e320_periphs.py
+++ b/mpm/python/usrp_mpm/periph_manager/e320_periphs.py
@@ -153,7 +153,7 @@ class MboardRegsControl(MboardRegsCommon):
value {unsigned} -- value is a single bit bit mask of 8 pins GPIO
"""
with self.regs:
- return self.poke32(self.MB_GPIO_MASTER, value)
+ self.poke32(self.MB_GPIO_MASTER, value)
def get_fp_gpio_master(self):
"""get "who" is driving front panel gpio
@@ -162,7 +162,7 @@ class MboardRegsControl(MboardRegsCommon):
1: means the pin is driven by PS
"""
with self.regs:
- return self.peek32(self.MB_GPIO_MASTER) & 0xfff
+ return self.peek32(self.MB_GPIO_MASTER) & 0xff
def set_fp_gpio_radio_src(self, value):
"""set driver for front panel GPIO
@@ -172,7 +172,7 @@ class MboardRegsControl(MboardRegsCommon):
01: means the pin is driven by radio 1
"""
with self.regs:
- return self.poke32(self.MB_GPIO_RADIO_SRC, value)
+ self.poke32(self.MB_GPIO_RADIO_SRC, value)
def get_fp_gpio_radio_src(self):
"""get which radio is driving front panel gpio
@@ -181,7 +181,7 @@ class MboardRegsControl(MboardRegsCommon):
01: means the pin is driven by radio 1
"""
with self.regs:
- return self.peek32(self.MB_GPIO_RADIO_SRC) & 0xffffff
+ return self.peek32(self.MB_GPIO_RADIO_SRC) & 0xffff
def set_time_source(self, time_source, ref_clk_freq):
"""