uhd/host/examples/spi.cpp
Martin Braun 0fdc47dfaf examples: Remove unused constants
Unused variables, constants, and functions cause compiler warnings on
recent compilers. We therefore remove those, or comment them out. The
heuristic for when to comment out and when to delete is as such: If
there is a list of constants or variables, where the unused constant
makes sense within a list, it is commented out. Otherwise, it is
deleted.
2024-10-29 17:59:42 +01:00

137 lines
5.4 KiB
C++

//
// 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 size_t SPI_DEFAULT_CLK_PIN = 0;
static const size_t SPI_DEFAULT_SDI_PIN = 1;
static const size_t SPI_DEFAULT_SDO_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 sdi;
size_t sdo;
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")
("sdo", po::value<size_t>(&sdo)->default_value(SPI_DEFAULT_SDO_PIN), "number of pin for serial data out")
("sdi", po::value<size_t>(&sdi)->default_value(SPI_DEFAULT_SDI_PIN), "number of pin for serial data in")
("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 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>();
// 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 peripheral configuration per peripheral
uhd::features::spi_periph_config_t periph_cfg;
periph_cfg.periph_clk = clk;
periph_cfg.periph_sdi = sdi;
periph_cfg.periph_sdo = sdo;
periph_cfg.periph_cs = cs;
// The vector holds the peripheral configs with index=peripheral number
std::vector<uhd::features::spi_periph_config_t> periph_cfgs;
periph_cfgs.push_back(periph_cfg);
// Set the data direction register
uint32_t outputs = 0x0;
outputs |= 1 << periph_cfg.periph_clk;
outputs |= 1 << periph_cfg.periph_sdo;
outputs |= 1 << periph_cfg.periph_cs;
usrp->set_gpio_attr("GPIOA", "DDR", outputs & 0xFFFFFF);
auto spi_ref = spi_getter_iface.get_spi_ref(periph_cfgs);
std::cout << "Using pins: " << std::endl
<< " Clock = " << (int)(periph_cfg.periph_clk) << std::endl
<< " SDO = " << (int)(periph_cfg.periph_sdo) << std::endl
<< " SDI = " << (int)(periph_cfg.periph_sdi) << std::endl
<< " CS = " << (int)(periph_cfg.periph_cs) << 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 SDI and SDO 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;
}