diff options
author | Martin Braun <martin.braun@ettus.com> | 2019-11-14 13:35:20 -0800 |
---|---|---|
committer | Brent Stapleton <brent.stapleton@ettus.com> | 2020-01-23 11:37:51 -0800 |
commit | 354886ed4cee82317f6ad45bc57a14af67cce85f (patch) | |
tree | 0bb7b1d99055676c28fd20f04f90dfbcd424ffae | |
parent | 90a72e8cd4cd1d4971c0e09d9813c9fc43371062 (diff) | |
download | uhd-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-x | mpm/python/e320_bist | 4 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/e31x.py | 98 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/e31x_periphs.py | 16 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/e320.py | 101 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/e320_periphs.py | 8 |
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): """ |