aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/examples/spi.cpp10
-rw-r--r--host/lib/include/uhdlib/usrp/cores/spi_core_4000.hpp2
-rw-r--r--host/lib/usrp/cores/spi_core_4000.cpp18
-rw-r--r--host/lib/usrp/x400/x400_radio_control.cpp41
-rw-r--r--host/lib/usrp/x400/x400_radio_control.hpp3
-rw-r--r--mpm/python/usrp_mpm/periph_manager/x4xx_dio_control.py19
6 files changed, 64 insertions, 29 deletions
diff --git a/host/examples/spi.cpp b/host/examples/spi.cpp
index e5372cac3..e986eb7d3 100644
--- a/host/examples/spi.cpp
+++ b/host/examples/spi.cpp
@@ -68,8 +68,7 @@ int UHD_SAFE_MAIN(int argc, char* argv[])
// create a usrp device
std::cout << std::endl;
- std::cout << "Creating the usrp device with: " << args << "..."
- << std::endl;
+ std::cout << "Creating the usrp device with: " << args << "..." << std::endl;
auto usrp = uhd::usrp::multi_usrp::make(args);
if (vm.count("list-banks")) {
@@ -80,7 +79,12 @@ int UHD_SAFE_MAIN(int argc, char* argv[])
}
}
- // Get the SPI getter interface from where we'll get
+ // Get the SPI getter interface from where we'll get the SPI interface itself
+ if (!usrp->get_radio_control().has_feature<uhd::features::spi_getter_iface>()) {
+ std::cout << "Error: Could not find SPI_Getter_Iface. Please check if your FPGA "
+ "image is up to date.\n";
+ return EXIT_FAILURE;
+ }
auto& spi_getter_iface =
usrp->get_radio_control().get_feature<uhd::features::spi_getter_iface>();
diff --git a/host/lib/include/uhdlib/usrp/cores/spi_core_4000.hpp b/host/lib/include/uhdlib/usrp/cores/spi_core_4000.hpp
index 4577b14cf..faeb9b03d 100644
--- a/host/lib/include/uhdlib/usrp/cores/spi_core_4000.hpp
+++ b/host/lib/include/uhdlib/usrp/cores/spi_core_4000.hpp
@@ -35,6 +35,7 @@ public:
const size_t spi_transaction_cfg,
const size_t spi_transaction_go,
const size_t spi_status,
+ const size_t spi_controller_info,
const mapper_sptr port_mapper);
//! Configures the SPI transaction. The vector index refers to the slave number.
@@ -43,4 +44,3 @@ public:
};
}} // namespace uhd::cores
-
diff --git a/host/lib/usrp/cores/spi_core_4000.cpp b/host/lib/usrp/cores/spi_core_4000.cpp
index 1d72dd88d..55486d6c8 100644
--- a/host/lib/usrp/cores/spi_core_4000.cpp
+++ b/host/lib/usrp/cores/spi_core_4000.cpp
@@ -25,6 +25,7 @@ public:
const size_t spi_transaction_cfg,
const size_t spi_transaction_go,
const size_t spi_status,
+ const size_t spi_controller_info,
const mapper_sptr port_mapper)
: _poke32(std::move(poke32_fn))
, _peek32(std::move(peek32_fn))
@@ -32,6 +33,7 @@ public:
, _spi_transaction_cfg(spi_transaction_cfg)
, _spi_transaction_go(spi_transaction_go)
, _spi_status(spi_status)
+ , _spi_ctrl_info(spi_controller_info)
, _port_mapper(port_mapper)
{
}
@@ -39,12 +41,17 @@ public:
void set_spi_slave_config(
const std::vector<uhd::features::spi_slave_config_t>& ssc) override
{
- if (ssc.size() > 4) {
- throw uhd::value_error(
- "Passed more than 4 SPI slaves. Maximum number of SPI slaves is 4.");
+ const size_t num_slaves_allowed = _peek32(_spi_ctrl_info) & 0xF;
+ if (ssc.size() > num_slaves_allowed) {
+ throw uhd::value_error("Number of configurations passed ("
+ + std::to_string(ssc.size())
+ + ") exceeds the maximum number allowed by "
+ "the bitfile per radio block. Maximum number: "
+ + std::to_string(num_slaves_allowed));
}
_spi_slave_config = ssc;
+ _slave_ctrl_cache.assign(_spi_slave_config.size(), 0);
}
uint32_t transact_spi(const int which_slave,
@@ -135,8 +142,9 @@ private:
const size_t _spi_transaction_cfg;
const size_t _spi_transaction_go;
const size_t _spi_status;
+ const size_t _spi_ctrl_info;
const mapper_sptr _port_mapper;
- std::vector<uint32_t> _slave_ctrl_cache{0, 0, 0, 0};
+ std::vector<uint32_t> _slave_ctrl_cache;
uint32_t _transaction_cfg_cache = 0;
std::mutex _mutex;
std::vector<uhd::features::spi_slave_config_t> _spi_slave_config;
@@ -161,6 +169,7 @@ spi_core_4000::sptr spi_core_4000::make(spi_core_4000::poke32_fn_t&& poke32_fn,
const size_t spi_transaction_cfg,
const size_t spi_transaction_go,
const size_t spi_status,
+ const size_t spi_controller_info,
const mapper_sptr port_mapper)
{
return std::make_shared<spi_core_4000_impl>(std::move(poke32_fn),
@@ -169,6 +178,7 @@ spi_core_4000::sptr spi_core_4000::make(spi_core_4000::poke32_fn_t&& poke32_fn,
spi_transaction_cfg,
spi_transaction_go,
spi_status,
+ spi_controller_info,
port_mapper);
}
diff --git a/host/lib/usrp/x400/x400_radio_control.cpp b/host/lib/usrp/x400/x400_radio_control.cpp
index ef2d6bd21..59207d486 100644
--- a/host/lib/usrp/x400/x400_radio_control.cpp
+++ b/host/lib/usrp/x400/x400_radio_control.cpp
@@ -191,20 +191,32 @@ x400_radio_control_impl::x400_radio_control_impl(make_args_ptr make_args)
auto gpio_port_mapper = std::shared_ptr<uhd::mapper::gpio_port_mapper>(
new uhd::rfnoc::x400::x400_gpio_port_mapping);
- auto spicore = uhd::cores::spi_core_4000::make(
- [this](const uint32_t addr, const uint32_t data) {
- regs().poke32(addr, data, get_command_time(0));
- },
- [this](
- const uint32_t addr) { return regs().peek32(addr, get_command_time(0)); },
- x400_regs::SPI_SLAVE_CFG,
- x400_regs::SPI_TRANSACTION_CFG_REG,
- x400_regs::SPI_TRANSACTION_GO_REG,
- x400_regs::SPI_STATUS_REG,
- gpio_port_mapper);
-
- _spi_getter_iface = std::make_shared<x400_spi_getter>(spicore);
- register_feature(_spi_getter_iface);
+
+ // Check if SPI is available as GPIO source, otherwise don't register
+ // SPI_GETTER_IFace
+ auto gpio_srcs = _mb_control->get_gpio_srcs("GPIO0");
+ if (std::count(gpio_srcs.begin(), gpio_srcs.end(), "DB0_SPI") > 0) {
+ auto spicore = uhd::cores::spi_core_4000::make(
+ [this](const uint32_t addr, const uint32_t data) {
+ regs().poke32(addr, data, get_command_time(0));
+ },
+ [this](const uint32_t addr) {
+ return regs().peek32(addr, get_command_time(0));
+ },
+ x400_regs::SPI_SLAVE_CFG,
+ x400_regs::SPI_TRANSACTION_CFG_REG,
+ x400_regs::SPI_TRANSACTION_GO_REG,
+ x400_regs::SPI_STATUS_REG,
+ x400_regs::SPI_CONTROLLER_INFO_REG,
+ gpio_port_mapper);
+
+ _spi_getter_iface = std::make_shared<x400_spi_getter>(spicore);
+ register_feature(_spi_getter_iface);
+ } else {
+ UHD_LOG_INFO("x400_radio_control",
+ "SPI functionality not available in this FPGA image. Please update to at "
+ "least version 7.7 to use SPI.");
+ }
}
}
@@ -816,5 +828,4 @@ std::string x400_radio_control_impl::get_dboard_fe_from_chan(
UHD_RFNOC_BLOCK_REGISTER_FOR_DEVICE_DIRECT(
x400_radio_control, RADIO_BLOCK, X400, "Radio", true, "radio_clk", "ctrl_clk")
-
}} // namespace uhd::rfnoc
diff --git a/host/lib/usrp/x400/x400_radio_control.hpp b/host/lib/usrp/x400/x400_radio_control.hpp
index cd45291bc..7fcf9a12a 100644
--- a/host/lib/usrp/x400/x400_radio_control.hpp
+++ b/host/lib/usrp/x400/x400_radio_control.hpp
@@ -54,6 +54,9 @@ constexpr uint32_t SPI_TRANSACTION_GO_REG = SPI_SLAVE_CFG + 0x0014;
//! Base address for SPI_STATUS Register
constexpr uint32_t SPI_STATUS_REG = SPI_SLAVE_CFG + 0x0018;
+//! Base address for SPI_CONTROLLER_INFO Register
+constexpr uint32_t SPI_CONTROLLER_INFO_REG = SPI_SLAVE_CFG + 0x001C;
+
} // namespace x400_regs
class x400_radio_control_impl : public radio_control_impl
diff --git a/mpm/python/usrp_mpm/periph_manager/x4xx_dio_control.py b/mpm/python/usrp_mpm/periph_manager/x4xx_dio_control.py
index 3c001be5c..93ef0ba94 100644
--- a/mpm/python/usrp_mpm/periph_manager/x4xx_dio_control.py
+++ b/mpm/python/usrp_mpm/periph_manager/x4xx_dio_control.py
@@ -147,6 +147,7 @@ class DioControl:
FPGA_DIO_SW_DIO_CONTROL_REGISTER = FPGA_DIO_REGISTER_BASE + 0x20
FULL_DIO_FPGA_COMPAT = (7, 5)
+ FULL_SPI_FPGA_COMPAT = (7, 7)
# DIO registers addresses in CPLD
CPLD_DIO_DIRECTION_REGISTER = 0x30
@@ -157,9 +158,10 @@ class DioControl:
X4XX_GPIO_SRC_MPM = "MPM"
X4XX_GPIO_SRC_USER_APP = "USER_APP"
X4XX_GPIO_SRC_RADIO = [
- ["DB0_RF0", "DB0_RF1", "DB0_SPI"],
- ["DB1_RF0", "DB1_RF1", "DB1_SPI"]
+ ["DB0_RF0", "DB0_RF1"],
+ ["DB1_RF0", "DB1_RF1"]
]
+ X4XX_GPIO_SPI_SRC_RADIO = [["DB0_SPI"], ["DB1_SPI"]]
X4XX_GPIO_WIDTH = 12
# pylint: enable=bad-whitespace
@@ -227,6 +229,8 @@ class DioControl:
self.mboard_cpld = mboard_cpld
if self.mboard_regs.get_compat_number() < self.FULL_DIO_FPGA_COMPAT:
self.log.warning("DIO board does not support the full feature set.")
+ if self.mboard_regs.get_compat_number() < self.FULL_SPI_FPGA_COMPAT:
+ self.log.warning("DIO board does not support SPI.")
# initialize port mapping for HDMI and DIO
self.port_mappings = {}
self.mapping = None
@@ -263,6 +267,9 @@ class DioControl:
]
for dboard in dboards:
gpio_srcs.extend(self.X4XX_GPIO_SRC_RADIO[dboard.slot_idx])
+ # Only add SPI if FPGA version is high enough
+ if self.mboard_regs.get_compat_number() >= self.FULL_SPI_FPGA_COMPAT:
+ gpio_srcs.extend(self.X4XX_GPIO_SPI_SRC_RADIO[dboard.slot_idx])
self._gpio_srcs = {
gpio_bank : gpio_srcs for gpio_bank in self.X4XX_GPIO_BANKS
@@ -895,10 +902,10 @@ class DioControl:
:return: board status
"""
result = "\n" \
- + self._format_row(["%s mapping" % self.mapping.name, self.DIO_PORTS[0], self.DIO_PORTS[1]]) \
- + self._format_row(["", "", ""], "-", "+") \
- + self._format_row(["voltage"] + self._get_voltage()) \
- + self._format_row(["", "", ""], "-", "+")
+ + self._format_row(["%s mapping" % self.mapping.name, self.DIO_PORTS[0], self.DIO_PORTS[1]]) \
+ + self._format_row(["", "", ""], "-", "+") \
+ + self._format_row(["voltage"] + self._get_voltage()) \
+ + self._format_row(["", "", ""], "-", "+")
register = self.mboard_regs.peek32(self.FPGA_DIO_MASTER_REGISTER)
result += self._format_row(["master"] + self._format_registers(register))