diff options
author | Martin Anderseck <martin.anderseck@ni.com> | 2022-01-05 18:41:40 +0100 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2022-01-14 14:35:36 -0600 |
commit | 09689f9805fcf00d8da9b907f617ba50a4abd699 (patch) | |
tree | 34e4bbe7eb2aa30ef411534f73b7ffc9c8747b92 /host/examples/spi.cpp | |
parent | f2904bfbd4b16c994550da583dba88cc551d8e6a (diff) | |
download | uhd-09689f9805fcf00d8da9b907f617ba50a4abd699.tar.gz uhd-09689f9805fcf00d8da9b907f617ba50a4abd699.tar.bz2 uhd-09689f9805fcf00d8da9b907f617ba50a4abd699.zip |
SPI: Add SPI example
Add example to demonstrate and test SPI functionality.
Diffstat (limited to 'host/examples/spi.cpp')
-rw-r--r-- | host/examples/spi.cpp | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/host/examples/spi.cpp b/host/examples/spi.cpp new file mode 100644 index 000000000..e5372cac3 --- /dev/null +++ b/host/examples/spi.cpp @@ -0,0 +1,135 @@ +// +// Copyright 2022 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +// Example for SPI testing. +// +// This example shows how to work with SPI which is based on the GPIO +// interface of the X410. + +#include <uhd/features/spi_getter_iface.hpp> +#include <uhd/usrp/multi_usrp.hpp> +#include <uhd/utils/safe_main.hpp> +#include <stdlib.h> +#include <boost/program_options.hpp> +#include <iostream> + +static const std::string SPI_DEFAULT_GPIO = "GPIOA"; +static const size_t SPI_DEFAULT_CLK_PIN = 0; +static const size_t SPI_DEFAULT_MISO_PIN = 1; +static const size_t SPI_DEFAULT_MOSI_PIN = 2; +static const size_t SPI_DEFAULT_CS_PIN = 3; +static const size_t SPI_DEFAULT_PAYLOAD_LENGTH = 32; +static const std::string SPI_DEFAULT_PAYLOAD = "0xfefe"; +static const size_t SPI_DEFAULT_CLK_DIVIDER = 4; + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char* argv[]) +{ + // variables to be set by po + std::string args; + size_t clk; + size_t miso; + size_t mosi; + size_t cs; + size_t payload_length; + size_t clk_divider; + std::string payload_str; + uint32_t payload; + + // setup the program options + po::options_description desc("Allowed options"); + // clang-format off + desc.add_options() + ("help", "help message") + ("args", po::value<std::string>(&args)->default_value(""), "multi uhd device address args") + ("list-banks", "print list of banks before running tests") + ("clk", po::value<size_t>(&clk)->default_value(SPI_DEFAULT_CLK_PIN), "number of pin for SPI clock") + ("mosi", po::value<size_t>(&mosi)->default_value(SPI_DEFAULT_MOSI_PIN), "number of pin for MOSI") + ("miso", po::value<size_t>(&miso)->default_value(SPI_DEFAULT_MISO_PIN), "number of pin for MISO") + ("cs", po::value<size_t>(&cs)->default_value(SPI_DEFAULT_CS_PIN), "number of pin for chip select") + ("payload", po::value<std::string>(&payload_str)->default_value(SPI_DEFAULT_PAYLOAD), "payload as integer value") + ("length", po::value<size_t>(&payload_length)->default_value(SPI_DEFAULT_PAYLOAD_LENGTH), "payload length in bits") + ("clk-div", po::value<size_t>(&clk_divider)->default_value(SPI_DEFAULT_CLK_DIVIDER), "clock divider for SPI") + ; + // clang-format on + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + // print the help message + if (vm.count("help")) { + std::cout << argv[0] << " " << desc << std::endl; + return ~0; + } + + // create a usrp device + std::cout << 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")) { + std::cout << "Available GPIO banks: " << std::endl; + auto banks = usrp->get_gpio_banks(0); + for (auto& bank : banks) { + std::cout << "* " << bank << std::endl; + } + } + + // Get the SPI getter interface from where we'll get + auto& spi_getter_iface = + usrp->get_radio_control().get_feature<uhd::features::spi_getter_iface>(); + + // Set all available pins to SPI for GPIO0 and GPIO1 + std::vector<std::string> sources(12, "DB0_SPI"); + usrp->set_gpio_src("GPIO0", sources); + usrp->set_gpio_src("GPIO1", sources); + + // Create slave configuration per slave + uhd::features::spi_slave_config_t slave_cfg; + slave_cfg.slave_clk = clk; + slave_cfg.slave_miso = miso; + slave_cfg.slave_mosi = mosi; + slave_cfg.slave_ss = cs; + + // The vector holds the slave configs with index=slave number + std::vector<uhd::features::spi_slave_config_t> slave_cfgs; + slave_cfgs.push_back(slave_cfg); + + // Set the data direction register + uint32_t outputs = 0x0; + outputs |= 1 << slave_cfg.slave_clk; + outputs |= 1 << slave_cfg.slave_mosi; + outputs |= 1 << slave_cfg.slave_ss; + usrp->set_gpio_attr("GPIOA", "DDR", outputs & 0xFFFFFF); + auto spi_ref = spi_getter_iface.get_spi_ref(slave_cfgs); + + std::cout << "Using pins: " << std::endl + << " Clock = " << (int)(slave_cfg.slave_clk) << std::endl + << " MOSI = " << (int)(slave_cfg.slave_mosi) << std::endl + << " MISO = " << (int)(slave_cfg.slave_miso) << std::endl + << " CS = " << (int)(slave_cfg.slave_ss) << std::endl + << std::endl; + + payload = strtoul(payload_str.c_str(), NULL, 0); + std::cout << "Writing payload: 0x" << std::hex << payload << " with length " + << std::dec << payload_length << " bits" << std::endl; + // The spi_config_t holds items like the clock divider and the MISO + // and MOSI edges + uhd::spi_config_t config; + config.divider = clk_divider; + config.use_custom_divider = true; + config.mosi_edge = config.EDGE_RISE; + config.miso_edge = config.EDGE_FALL; + + // Do the SPI transaction. There are write() and read() methods available, too. + std::cout << "Performing SPI transaction..." << std::endl; + uint32_t read_data = spi_ref->transact_spi(0, config, payload, payload_length, true); + std::cout << "Data read: 0x" << std::hex << read_data << std::endl; + + return EXIT_SUCCESS; +} |