diff options
-rw-r--r-- | host/examples/spi.cpp | 10 | ||||
-rw-r--r-- | host/lib/include/uhdlib/usrp/cores/spi_core_4000.hpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/cores/spi_core_4000.cpp | 18 | ||||
-rw-r--r-- | host/lib/usrp/x400/x400_radio_control.cpp | 41 | ||||
-rw-r--r-- | host/lib/usrp/x400/x400_radio_control.hpp | 3 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/x4xx_dio_control.py | 19 |
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)) |