1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
|
/*! \page page_x400_gpio_api X4x0 GPIO API
\tableofcontents
\section x4x0gpio_fpanel The X4x0 Front Panel GPIO
Like other USRP devices (e.g., E310, X310), the X4x0 devices expose auxiliary
GPIO connections through the motherboard. These GPIO pins can be controlled from
either the user application in the FPGA or from the radio blocks.
There are 24 GPIO pins in total, split between two HDMI connectors (labelled
GPIO0 and GPIO1) which each expose 12 pins.
Additionally, the X4x0 GPIO lines include a 3.3V power supply which is disabled
by default, which can provide up to 450mA with overcurrent protection. See
\ref x4x0_gpio_power
\subsection x4x0gpio_fpanel_gpio X4x0 Front Panel GPIO
The GPIO port is not meant to drive big loads.
\subsubsection x4x0gpio_fpanel_conn Connector
\image html HDMI_Connector_Pinout.svg HDMI pinout
\subsubsection x4x0gpio_fpanel_pins Pin Mapping
- Pin 1: Data[0]
- Pin 2: 0V
- Pin 3: Data[1]
- Pin 4: Data[2]
- Pin 5: 0V
- Pin 6: Data[3]
- Pin 7: Data[4]
- Pin 8: 0V
- Pin 9: Data[5]
- Pin 10: Data[6]
- Pin 11: 0V
- Pin 12: Data[7]
- Pin 13: Data[8]
- Pin 14: N/C
- Pin 15: Data[9]
- Pin 16: Data[10]
- Pin 17: 0V
- Pin 18: +3.3V (see \ref x4x0_gpio_power)
- Pin 19: Data[11]
\subsection x4x0_gpio_output Setting GPIO Output
The GPIO lines can be configured according to the
uhd::usrp::multi_usrp::set_gpio_attr() API, like can be seen at \ref
xgpio_fpanel_atr.
The major difference is that in order to use that API, the GPIO source must be
correctly configured. The source can be configured using
uhd::usrp::multi_usrp::set_gpio_src(), which takes two arguments: A "bank" and a
"src". The `bank` argument specifies the GPIO port to configure, and the `src`
argument is a vector of twelve elements, each specifying the source for the
given GPIO pin.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
# Set every pin on GPIO0 to be controlled by DB1_RF0
usrp.set_gpio_src("GPIO0", ["DB1_RF0"]*12)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The bank can be either "GPIO0" or "GPIO1", and the sources can be any
combination of:
- <b>DBx_RFy</b>: Controlled by the slot-x radio block via the set_gpio_attr
API, with ATR states derived from channel y on that slot if CTRL is set to 1. If
CTRL is set to 0, y is ignored and can be either 0 or 1.
- <b>DBx_SPI</b>: Controlled via the digital interface block in the slot-x
radio block.
- <b>PS</b>: Controlled directly via the Linux GPIO API on the embedded
processor.
- <b>USER_APP</b>: Controlled via user logic in the FPGA. Note that this only
works with custom modifications to the FPGA codebase, and not with standard UHD
FPGA images.
Once the source is set, using the GPIO proceeds identically to the usage on
other devices. Note that the values and masks for the
uhd::usrp::multi_usrp::set_gpio_attr() API combines all 24 pins, with bits
[23:12] representing the GPIO1 port and bits [11:0] representing the GPIO0 port.
For example, to configure the 4th bit on GPIO1 (HDMI pin number 7) as a high
output, one would run:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
pin_mask = 1 << (12 + 4) # 12 for GPIO1, 4 for the bit on that port
usrp.set_gpio_attr("GPIOA", "CTRL", 0, pin_mask) # Non-ATR mode
usrp.set_gpio_attr("GPIOA", "DDR", pin_mask, pin_mask) # Output
usrp.set_gpio_attr("GPIOA", "OUT", pin_mask, pin_mask) # Set value high
usrp.set_gpio_attr("GPIOA", "OUT", 0, pin_mask) # Set value low
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\subsection x4x0_gpio_power Configuring External Power Supply
The X410's GPIO ports each have 3.3V power supply pins, which is disabled by
default. The GPIO lines will function correctly without the external power
supply enabled, and the voltage of the power supply is independent of the
selected GPIO line voltage. To enable the power supply, call the
uhd::features::gpio_power_iface::set_external_power() method on the gpio_power
discoverable feature attached to the mb_controller:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
auto usrp = uhd::usrp::multi_usrp::make("type=x4xx");
auto& gpio = usrp->get_mb_controller().get_feature<uhd::features::gpio_power_iface>();
gpio.set_external_power("GPIO1", true); // Enable external power on GPIO1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The status of the external power supply can be queried using
uhd::features::gpio_power_iface::get_external_power_status(), which will return
one of the following values:
- <b>OFF</b>: Power supply is disabled (the default).
- <b>ON</b>: Power supply is operating normally.
- <b>FAULT</b>: Power supply has encountered a fault and disabled itself. This
condition can be cleared by calling
uhd::features::gpio_power_iface::set_external_power().
\subsection x4x0_gpio_voltage Configuring GPIO Voltage
The voltage level of the I/O lines can be selected as any of 1.8V, 2.5V, or 3.3V
voltage levels on a per-bank basis. To do this use the
uhd::features::gpio_power_iface::set_port_voltage() API:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
auto usrp = uhd::usrp::multi_usrp::make("type=x4xx");
auto& gpio = usrp->get_mb_controller().get_feature<uhd::features::gpio_power_iface>();
gpio.set_port_voltage("GPIO0", "2V5"); // Set GPIO0 voltage to 2.5V
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Valid values can be enumerated with the
uhd::features::gpio_power_iface::supported_voltages() call, and are "1V8",
"2V5", and "3V3".
\section x4x0_spi_iface The x4x0 SPI Mode
The GPIO ports of the x4x0 can be used with the Serial Peripheral Interface (SPI) to control
external components. To use SPI mode, set the pins you need on the desired GPIO port to be
controlled by the SPI engine and configure the data direction.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
auto usrp = uhd::usrp::multi_usrp::make(args);
auto& spi_getter_iface =
usrp->get_radio_control().get_feature<uhd::features::spi_getter_iface>();
usrp->set_gpio_src("GPIO0",
{"DB0_SPI",
"DB0_SPI",
"DB0_SPI",
"DB0_SPI",
"DB0_SPI",
"DB0_SPI",
"DB0_SPI",
"DB0_SPI",
"DB0_SPI",
"DB0_SPI",
"DB0_SPI",
"DB0_SPI"});
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The example shows the usage of GPIO port 0 (GPIO0) for SPI and needs to be run for
GPIO1 again to use that port with SPI, too.
\subsection x4x0_spi_cfg Configuration of SPI lines
The x4x0 SPI mode supports up to 4 peripherals. All of these peripherals may have a different SPI pin
configuration. The pins available for the usage with SPI are listed in \ref x4x0gpio_fpanel_pins.
For GPIO0 the available pins are enumerated from 0 through 11, for GPIO1 the available pins are
from 12 through 23.
The vector of peripheral configurations is passed to the spi_iface_getter to get the reference:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
uhd::features::spi_periph_config_t periph_cfg;
periph_cfg.periph_clk = 0;
periph_cfg.periph_sdi = 1;
periph_cfg.periph_sdo = 2;
periph_cfg.periph_cs = 3;
std::vector<uhd::features::spi_periph_config_t> periph_cfgs;
periph_cfgs.push_back(periph_cfg);
auto spi_ref = spi_getter_iface.get_spi_ref(periph_cfgs);
// Set data direction register (set all to outgoing except for SDI)
usrp->set_gpio_attr("GPIOA", "DDR", 0xD, 0xF);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\subsection x4x0_spi_r_w Write and read on SPI
With the SPI reference read and write operations can be performed. For doing this,
some characteristics of the SPI need to be configured:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
uhd::spi_config_t config;
config.divider = 4;
config.miso_edge = config.EDGE_RISE;
...
spi_ref->write_spi(0, config, 0xFEFE, 32);
uint32_t read_data = spi_ref->read_spi(0, config, 0xFEFE, 32);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The terms 'MISO' and 'MOSI' in the spi_config_t struct map to 'SDI' and 'SDO' respectively.
They are legacy terms which will not be used in new code anymore following the resolution
to redefine SPI signal names by the Open Source Hardware Association:
<https://oshwa.org/resources/a-resolution-to-redefine-spi-signal-names/>
The SPI clock frequency, \f$f_{SCLK}\f$, is derived from the radio clock
frequency (\f$f_{RADIO\_CLK}\f$) and the SPI clock divider value
(\f$SPI\_CLK\_DIV\f$). For X410, the SPI clock frequency is given by the
equation shown below, where \f$f_{RADIO\_CLK}\f$ is 122.88 MHz or 125 MHz,
depending on the master clock rate. Note that this is the master clock rate
divided by 1 (for 100 MHz bandwidth), by 2 (for 200 MHz bandwidth), or by 4
(for 400 MHz bandwidth).
\f[X410: f_{SCLK} = \frac{f_{RADIO\_CLK}}{SPI\_CLK\_DIV + 1}\f]
For X440, the SPI clock frequency is given by the equation shown below, where
\f$f_{RADIO\_CLK}\f$ is the master clock rate divided by 8.
\f[X440: f_{SCLK} = \frac{f_{RADIO\_CLK}}{2\cdot\left(SPI\_CLK\_DIV + 1\right)}\f]
*/
// vim:ft=doxygen:
|