1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-11-10 20:10:05 +00:00

Add the MAX2771_EVKIT FPGA signal source and the ENABLE_FPGA_MAX2771_EVKIT flag to enable it.

This commit is contained in:
Marc Majoral 2024-07-18 16:33:25 +02:00
parent ac7bdc919b
commit d24c35854a
No known key found for this signature in database
GPG Key ID: 4CC7BE8C367C596C
9 changed files with 862 additions and 6 deletions

View File

@ -44,6 +44,8 @@ option(ENABLE_AD936X_SDR "Enable the use of AD936X front-ends using libiio, requ
option(ENABLE_AD9361 "Enable the use of AD9361 direct to FPGA hardware, requires libiio" OFF)
option(ENABLE_FPGA_MAX2771_EVKIT "Enable the use of MAX2771 EVKIT direct to FPGA hardware" OFF)
option(ENABLE_RAW_UDP "Enable the use of high-optimized custom UDP packet sample source, requires libpcap" OFF)
option(ENABLE_FLEXIBAND "Enable the use of the signal source adater for the Teleorbit Flexiband GNU Radio driver" OFF)
@ -3552,6 +3554,7 @@ add_feature_info(ENABLE_LIMESDR ENABLE_LIMESDR "Enables Limesdr_Signal_Source. R
add_feature_info(ENABLE_FMCOMMS2 ENABLE_FMCOMMS2 "Enables Fmcomms2_Signal_Source for FMCOMMS2/3/4 devices. Requires gr-iio and libad9361-dev.")
add_feature_info(ENABLE_PLUTOSDR ENABLE_PLUTOSDR "Enables Plutosdr_Signal_Source for using ADALM-PLUTO boards. Requires gr-iio.")
add_feature_info(ENABLE_AD9361 ENABLE_AD9361 "Enables Ad9361_Fpga_Signal_Source for devices with the AD9361 chipset. Requires libiio and libad9361-dev.")
add_feature_info(ENABLE_FPGA_MAX2771_EVKIT ENABLE_FPGA_MAX2771_EVKIT "Enables MAX2771_evkit_fpga_signal_source for devices with the MAX2771 chipset.")
add_feature_info(ENABLE_AD936X_SDR ENABLE_AD936X_SDR "Enables Ad936x_Iio_Signal_Source to access AD936X front-ends using libiio. Requires libiio and libad9361-dev.")
add_feature_info(ENABLE_RAW_UDP ENABLE_RAW_UDP "Enables Custom_UDP_Signal_Source for custom UDP packet sample source. Requires libpcap.")
add_feature_info(ENABLE_FLEXIBAND ENABLE_FLEXIBAND "Enables Flexiband_Signal_Source for using Teleorbit's Flexiband RF front-end. Requires gr-teleorbit.")

View File

@ -41,6 +41,14 @@ if(ENABLE_AD9361)
list(APPEND OPT_DRIVER_HEADERS ad9361_fpga_signal_source.h)
endif()
if(ENABLE_FPGA_MAX2771_EVKIT)
###############################################
# MAX2771 EVKIT DIRECT TO FPGA Hardware
###############################################
list(APPEND OPT_DRIVER_SOURCES max2771_evkit_fpga_signal_source.cc)
list(APPEND OPT_DRIVER_HEADERS max2771_evkit_fpga_signal_source.h)
endif()
if(ENABLE_FPGA)
###############################################
# FPGA DMA source
@ -159,7 +167,7 @@ target_include_directories(signal_source_adapters
${GNSSSDR_SOURCE_DIR}/src/core/interfaces
)
if(ENABLE_FPGA OR ENABLE_AD9361)
if(ENABLE_FPGA OR ENABLE_AD9361 OR ENABLE_FPGA_MAX2771_EVKIT)
target_link_libraries(signal_source_adapters
PUBLIC
signal_source_libs

View File

@ -0,0 +1,468 @@
/*!
* \file max2771_evkit_fpga_signal_source.cc
* \brief Signal source for the MAX2771EVKIT evaluation board connected directly
* to FPGA accelerators.
* This source implements only the MAX2771 control. It is NOT compatible with
* conventional SDR acquisition and tracking blocks.
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "max2771_evkit_fpga_signal_source.h"
#include "GPS_L1_CA.h"
#include "GPS_L2C.h"
#include "GPS_L5.h"
#include "configuration_interface.h"
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include <algorithm> // for std::max
#include <chrono> // for std::chrono
#include <cmath> // for std::floor
#include <exception> // for std::exception
#include <iostream> // for std::cout
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/check.h>
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
MAX2771EVKITFpgaSignalSource::MAX2771EVKITFpgaSignalSource(const ConfigurationInterface *configuration,
const std::string &role, unsigned int in_stream, unsigned int out_stream,
Concurrent_Queue<pmt::pmt_t> *queue __attribute__((unused)))
: SignalSourceBase(configuration, role, "Ad9361_Fpga_Signal_Source"s),
freq_(configuration->property(role + ".freq", static_cast<uint64_t>(GPS_L1_FREQ_HZ))),
sample_rate_(configuration->property(role + ".sampling_frequency", default_sampling_rate)),
in_stream_(in_stream),
out_stream_(out_stream),
bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)),
filter_order_(configuration->property(role + ".filter_order", default_filter_order)),
gain_in_(configuration->property(role + ".PGA_gain", default_PGA_gain_value)),
item_size_(sizeof(int8_t)),
chipen_(true),
if_filter_gain_(configuration->property(role + ".enable_IF_filter_gain", true)),
LNA_active_(configuration->property(role + ".LNA_active", false)),
enable_agc_(configuration->property(role + ".enable_AGC", true)),
enable_ovf_check_buffer_monitor_active_(true),
dump_(configuration->property(role + ".dump", false)),
#if USE_GLOG_AND_GFLAGS
rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown))
#else
rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown)))
#endif
{
// some basic checks
if (freq_ != GPS_L1_FREQ_HZ and freq_ != GPS_L2_FREQ_HZ and freq_ != GPS_L5_FREQ_HZ)
{
std::cout << "Configuration parameter freq should take values " << GPS_L1_FREQ_HZ << ", " << GPS_L2_FREQ_HZ << ", or " << GPS_L5_FREQ_HZ << "\n";
std::cout << "Error: provided value freq = " << freq_ << " is not among valid values\n";
std::cout << " This parameter has been set to its default value freq = " << GPS_L1_FREQ_HZ << '\n';
LOG(WARNING) << "Invalid configuration value for freq parameter. Set to freq = " << GPS_L1_FREQ_HZ;
freq_ = GPS_L1_FREQ_HZ;
}
if (sample_rate_ != 4092000 and sample_rate_ != 8184000 and sample_rate_ != 16368000 and sample_rate_ != 32736000)
{
std::cout << "Configuration parameter sampling_frequency should take values 4092000, 8184000, 16368000, or 32736000\n";
std::cout << "Error: provided value sampling_frequency = " << sample_rate_ << " is not among valid values\n";
std::cout << " This parameter has been set to its default value sampling_frequency = " << default_sampling_rate << '\n';
LOG(WARNING) << "Invalid configuration value for sampling_frequency parameter. Set to sampling_frequency = " << default_sampling_rate;
sample_rate_ = default_sampling_rate;
}
if (bandwidth_ != 2500000 and bandwidth_ != 4200000 and bandwidth_ != 8700000 and bandwidth_ != 16400000 and bandwidth_ != 23400000 and bandwidth_ != 36000000)
{
std::cout << "Configuration parameter bandwidth can only take the following values: 2500000, 4200000, 8700000, 16400000, 23400000, and 36000000 Hz\n";
std::cout << "Error: provided value bandwidth = " << bandwidth_ << " is not among valid values\n";
std::cout << " This parameter has been set to its default value bandwidth = " << default_bandwidth << '\n';
LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth = " << default_bandwidth;
bandwidth_ = default_bandwidth;
}
if (filter_order_ != 3 and filter_order_ != 5)
{
std::cout << "Configuration parameter filter_order should take values 3 or 5\n";
std::cout << "Error: provided value filter_order = " << filter_order_ << " is not among valid values\n";
std::cout << " This parameter has been set to its default value filter_order = " << default_filter_order << '\n';
LOG(WARNING) << "Invalid configuration value for filter_order parameter. Set to filter_order = " << default_filter_order;
filter_order_ = default_filter_order;
}
if (gain_in_ > max_PGA_gain_value)
{
std::cout << "Configuration parameter PGA_gain should be up to " << max_PGA_gain_value << "\n";
std::cout << "Error: provided value PGA_gain = " << gain_in_ << " is not among valid values\n";
std::cout << " This parameter has been set to its default value PGA_gain = " << default_PGA_gain_value << '\n';
LOG(WARNING) << "Invalid configuration value for PGA_gain parameter. Set to PGA_gain = " << default_PGA_gain_value;
gain_in_ = default_PGA_gain_value;
}
std::vector<uint32_t> register_values = setup_regs();
spidev_fpga = std::make_shared<Fpga_spidev>();
if (spidev_fpga->SPI_open())
{
std::cerr << "Cannot open SPI device\n";
// stop the receiver
queue->push(pmt::make_any(command_event_make(200, 0)));
return;
}
if (configure(register_values))
{
std::cerr << "Error configuring the MAX2771 device " << '\n';
}
if (spidev_fpga->SPI_close())
{
std::cerr << "Error closing SPI device " << '\n';
}
std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename);
buffer_monitor_fpga = std::make_shared<Fpga_buffer_monitor>(NUM_FREQ_BANDS, dump_, dump_filename);
thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); });
if (in_stream_ > 0)
{
LOG(ERROR) << "A signal source does not have an input stream";
}
if (out_stream_ > 1)
{
LOG(ERROR) << "This implementation only supports one output stream";
}
}
std::vector<uint32_t> MAX2771EVKITFpgaSignalSource::setup_regs(void)
{
std::vector<uint32_t> register_values = std::vector<uint32_t>(MAX2771_NUM_REGS);
uint32_t LNA_mode = (LNA_active_) ? 0x0 : 0x2;
uint32_t Filter_Bandwidth;
switch (bandwidth_)
{
case 2500000:
Filter_Bandwidth = 0x0;
break;
case 4200000:
Filter_Bandwidth = 0x2;
break;
case 8700000:
Filter_Bandwidth = 0x1;
break;
case 16400000:
Filter_Bandwidth = 0x7;
break;
case 23400000:
Filter_Bandwidth = 0x3;
break;
case 36000000:
Filter_Bandwidth = 0x4;
break;
default:
Filter_Bandwidth = 0x0; // default bandwidth
}
uint32_t chipen_select = (chipen_) ? 0x1 : 0x0;
uint32_t Filter_order_sel = (filter_order_ == 5) ? 0x0 : 0x1;
uint32_t IF_filter_gain_sel = (if_filter_gain_) ? 0x1 : 0x0;
register_values[0] = // configuration 1 register
(chipen_select << 31) +
(IDLE << 30) +
(0x8 << 26) + // reserved
(0x8 << 22) + // reserved
(0x2 << 20) + // reserved
(0x1 << 18) + // reserved
(MIXPOLE << 17) +
(LNA_mode << 15) +
(MIXERMODE << 13) +
(FCEN << 6) +
(Filter_Bandwidth << 3) +
(Filter_order_sel << 2) +
(FCENX << 1) +
IF_filter_gain_sel;
uint32_t AGC_mode = (enable_agc_) ? 0x0 : 0x2;
register_values[1] = // configuration 2 register
(0x0 << 31) + // reserved
(0x1 << 29) + // reserved
(ANAIMON << 28) +
(IQEN << 27) +
(GAINREF << 15) +
(SPI_SDIO_CONFIG << 13) +
(AGC_mode << 11) +
(FORMAT << 9) +
(BITS << 6) +
(DRVCFG << 4) +
(0x1 << 3) + // reserved
(0x0 << 2) + // reserved
DIEID;
register_values[2] = // configuration 3 register
(0x0 << 28) + //reserved
(gain_in_ << 22) +
(0x1 << 21) + // reserved
(HILOADEN << 20) +
(0x1 << 19) + // reserved
(0x1 << 18) + // reserved
(0x1 << 17) + // reserved
(0x1 << 16) + // reserved
(FHIPEN << 15) +
(0x0 << 14) + // reserved
(PGAIEN << 13) +
(PGAQEN << 12) +
(STRMEN << 11) +
(STRMSTART << 10) +
(STRMSTOP << 9) +
(0x7 << 6) + // reserved
(STRMBITS << 4) +
(STAMPEN << 3) +
(TIMESYNCEN << 2) +
(DATASYNCEN << 1) +
STRMRST;
uint32_t clock_out_div_ratio;
switch (sample_rate_)
{
case 4092000:
clock_out_div_ratio = 0x1; // XTAL frequency /4
break;
case 8184000:
clock_out_div_ratio = 0x2; // XTAL frequency /2
break;
case 16368000:
clock_out_div_ratio = 0x3; // XTAL frequency
break;
case 32736000:
clock_out_div_ratio = 0x0; // XTAL Frequency x2
break;
default:
clock_out_div_ratio = 0x1; // default XTAL frequency
}
register_values[3] = // PLL configuration register
(clock_out_div_ratio << 29) +
(LOBAND << 28) +
(0x1 << 27) + // reserved
(0x0 << 26) + // reserved
(0x0 << 25) + // reserved
(REFOUTEN << 24) +
(0x1 << 23) + // reserved
(0x0 << 21) + // reserved
(IXTAL << 19) +
(0x10 << 14) + // reserved
(0x0 << 13) + // reserved
(0x0 << 10) + //reserved
(ICP << 9) +
(0x0 << 8) + // reserved
(0x0 << 7) + // reserved
(0x0 << 4) + // reserved
(INT_PLL << 3) +
(PWRSAV << 2) +
(0x0 << 1) + // reserved
0x0; // reserved
uint32_t freq_sel;
switch (freq_)
{
case static_cast<uint64_t>(GPS_L1_FREQ_HZ):
freq_sel = 0x604;
break;
case static_cast<uint64_t>(GPS_L2_FREQ_HZ):
freq_sel = 0x4B0;
break;
case static_cast<uint64_t>(GPS_L5_FREQ_HZ):
freq_sel = 0x47E;
break;
default:
freq_sel = 0x604;
}
//uint32_t freq_sel = (freq_ == GPS_L1_FREQ_HZ) ? 0x604 :
register_values[4] = // PLL integer division register
(0x0 << 28) + //reserved
(freq_sel << 13) +
(RDIV << 3) +
0x0; // reserved
register_values[5] = // PLL fractional division register
(0x0 << 28) + // reserved
(FDIV << 8) +
(0x7 << 4) + // reserved
(0x0 << 3) + // reserved
(0x0 << 2) + // reserved
(0x0 << 1) + // reserved
0x0; // reserved
register_values[6] = // DSP interface register
(0x0 << 28) + // reserved
0x8000000; // reserved
register_values[7] = // clock configuration 1 register
(0x0 << 29) + // reserved
(EXTADCCLK << 28) +
(REFCLK_L_CNT << 16) +
(REFCLK_M_CNT << 4) +
(FCLKIN << 3) +
(ADCCLK << 2) +
(0x1 << 1) + //reserved
MODE;
register_values[8] = TEST_MODE_1_REG_VAL; // test mode 1 register
register_values[9] = TEST_MODE_2_REG_VAL; // test mode 2 register
register_values[10] = // clock configuration 2 register
(0x0 << 29) + // reserved
(0x0 << 28) + // reserved
(ADCCLK_L_CNT << 16) +
(ADCCLK_M_CNT << 4) +
(PRE_FRACDIV_SEL << 3) +
(CLKOUT_SEL << 2) +
0x0; // reserved
return register_values;
}
bool MAX2771EVKITFpgaSignalSource::configure(std::vector<uint32_t> register_values)
{
// write the registers
std::cerr << "Configuring MAX2771 registers" << std::endl;
uint32_t status = 0;
for (uint32_t k = 0; k < register_values.size(); k++)
{
status = spidev_fpga->write_reg32(k, register_values[k]);
if (status)
{
std::cerr << "Error writing the MAX2771 registers" << std::endl;
break;
}
}
// Read the registers and verify that the values are correctly written
std::vector<uint32_t> reg_read = std::vector<uint32_t>(register_values.size());
for (uint8_t n = 0; n < register_values.size(); ++n)
{
status = spidev_fpga->read_reg32(n, &reg_read[n]);
if (status)
{
std::cerr << "Error reading the MAX2771 registers" << std::endl;
return status;
}
else
{
if (reg_read[n] != register_values[n])
{
std::cerr << "Error: Failed to verify the MAX2771 registers " << std::endl;
return -1;
}
}
}
return 0;
}
MAX2771EVKITFpgaSignalSource::~MAX2771EVKITFpgaSignalSource()
{
/* cleanup and exit */
if (rf_shutdown_)
{
chipen_ = false;
std::cout << "* MAX2771 Disabling RX streaming channels\n";
std::vector<uint32_t> register_values = setup_regs();
if (spidev_fpga->SPI_open())
{
std::cerr << "Cannot open SPI device\n";
return;
}
if (configure(register_values))
{
std::cerr << "Error disabling the MAX2771 device " << '\n';
}
if (spidev_fpga->SPI_close())
{
std::cerr << "Error closing SPI device " << '\n';
}
}
// disable buffer overflow checking and buffer monitoring
std::unique_lock<std::mutex> lock_buffer_monitor(buffer_monitor_mutex);
enable_ovf_check_buffer_monitor_active_ = false;
lock_buffer_monitor.unlock();
if (thread_buffer_monitor.joinable())
{
thread_buffer_monitor.join();
}
}
void MAX2771EVKITFpgaSignalSource::run_buffer_monitor_process()
{
bool enable_ovf_check_buffer_monitor_active = true;
std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms));
while (enable_ovf_check_buffer_monitor_active)
{
buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status();
std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms));
std::unique_lock<std::mutex> lock(buffer_monitor_mutex);
if (enable_ovf_check_buffer_monitor_active_ == false)
{
enable_ovf_check_buffer_monitor_active = false;
}
lock.unlock();
}
}
void MAX2771EVKITFpgaSignalSource::connect(gr::top_block_sptr top_block)
{
if (top_block)
{ /* top_block is not null */
};
DLOG(INFO) << "AD9361 FPGA source nothing to connect";
}
void MAX2771EVKITFpgaSignalSource::disconnect(gr::top_block_sptr top_block)
{
if (top_block)
{ /* top_block is not null */
};
DLOG(INFO) << "AD9361 FPGA source nothing to disconnect";
}
gr::basic_block_sptr MAX2771EVKITFpgaSignalSource::get_left_block()
{
LOG(WARNING) << "Trying to get signal source left block.";
return {};
}
gr::basic_block_sptr MAX2771EVKITFpgaSignalSource::get_right_block()
{
return {};
}

View File

@ -0,0 +1,163 @@
/*!
* \file max2771_evkit_fpga_signal_source.h
* \brief Signal source for the MAX2771EVKIT evaluation board connected directly
* to FPGA accelerators.
* This source implements only the MAX2771 control. It is NOT compatible with
* conventional SDR acquisition and tracking blocks.
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_MAX2771_EVKIT_FPGA_SIGNAL_SOURCE_H
#define GNSS_SDR_MAX2771_EVKIT_FPGA_SIGNAL_SOURCE_H
#include "command_event.h"
#include "concurrent_queue.h"
#include "fpga_buffer_monitor.h"
#include "fpga_spidev.h"
#include "gnss_block_interface.h"
#include "signal_source_base.h"
#include <pmt/pmt.h> // for pmt::pmt_t
#include <cstdint> // for fixed-width integer types
#include <memory> // for smart pointers
#include <mutex> // for mutex
#include <string> // for strings
#include <thread> // for threads
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_adapters
* \{ */
class ConfigurationInterface;
class MAX2771EVKITFpgaSignalSource : public SignalSourceBase
{
public:
MAX2771EVKITFpgaSignalSource(const ConfigurationInterface *configuration,
const std::string &role, unsigned int in_stream,
unsigned int out_stream, Concurrent_Queue<pmt::pmt_t> *queue);
~MAX2771EVKITFpgaSignalSource();
std::vector<uint32_t> setup_regs(void);
inline size_t item_size() override
{
return item_size_;
}
void connect(gr::top_block_sptr top_block) override;
void disconnect(gr::top_block_sptr top_block) override;
gr::basic_block_sptr get_left_block() override;
gr::basic_block_sptr get_right_block() override;
private:
const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat");
const uint64_t default_bandwidth = 2500000;
const uint32_t default_filter_order = 5;
const uint64_t default_sampling_rate = 4092000;
const uint32_t default_PGA_gain_value = 0x3A; // default PGA gain when AGC is off
// max PGA gain value
const uint32_t max_PGA_gain_value = 0x3F;
// check buffer overflow and perform buffer monitoring every 1s by default
const uint32_t buffer_monitor_period_ms = 1000;
// buffer overflow and buffer monitoring initial delay
const uint32_t buffer_monitoring_initial_delay_ms = 2000;
// MAX2771 number of configuration registers
const uint32_t MAX2771_NUM_REGS = 11;
// MAX2771 configuration register fields
const uint32_t NUM_FREQ_BANDS = 1;
const uint32_t IDLE = 0x0; // Idle mode disabled
const uint32_t MIXPOLE = 0x0; // set the passive filter pole at mixer output at 13 MHz.
const uint32_t MIXERMODE = 0x0; // L1 band enabled
const uint32_t FCEN = 0x58; // Center frequency not used when in low-pass filter mode. Set to default value.
const uint32_t FCENX = 0x0; // POlyphase filter selection set to Lowpass filter
const uint32_t ANAIMON = 0x0; // analog monitor disabled
const uint32_t IQEN = 0x1; // I and Q channels enable
const uint32_t GAINREF = 0xAA; // AGC Gain ref
const uint32_t SPI_SDIO_CONFIG = 0x0; // SPI SDIO config when tri-stated: nothing applied
const uint32_t FORMAT = 0x1; // sign and magnitude
const uint32_t BITS = 0x2; // number of bits in the ADC = 2
const uint32_t DRVCFG = 0x0; // output driver configuration = CMOS Logic
const uint32_t DIEID = 0x0; // identifies version of IC
const uint32_t HILOADEN = 0x0; // disable output driver for high loads
const uint32_t FHIPEN = 0x1; // enable highpass coupling between filter and PGA.
const uint32_t PGAIEN = 0x1; // I-Channel PGA Enable
const uint32_t PGAQEN = 0x1; // Q-Channel PGA Enable
const uint32_t STRMEN = 0x0; // disable DSP interface for serial streaming of data
const uint32_t STRMSTART = 0x0; // the rising edge of this bit enables data streaming to the output, clock, data, sync and frame sync outputs.
const uint32_t STRMSTOP = 0x0; // the rising edge of this bit disables data streaming to the output, clock, data sync and frame sync outputs.
const uint32_t STRMBITS = 0x1; // number of bits to be streamed: I MSB, I LSB
const uint32_t STAMPEN = 0x1; // enable frame number insertion
const uint32_t TIMESYNCEN = 0x1; // enable the output of the time sync pulses at all times when streaming is enabled.
const uint32_t DATASYNCEN = 0x0; // disable the sync pulses at the DATASYNC output
const uint32_t STRMRST = 0x0; // counter reset not active
const uint32_t LOBAND = 0x0; // L1 band
const uint32_t REFOUTEN = 0x1; // Output clock buffer enable
const uint32_t IXTAL = 0x1; // XTAL osscillator/buffer set to normal current
const uint32_t ICP = 0x0; // charge pump current selection set to 0.5 mA
const uint32_t INT_PLL = 0x1; // PLL mode set to integer-N PLL
const uint32_t PWRSAV = 0x0; // PLL power save mode disabled
const uint32_t RDIV = 0x10; // Set the PLL reference division ratio such that the L1 band is tuned to 1575.42 Mhz
const uint32_t FDIV = 0x80000; // PLL fractional division ratio not used. Set to default value
const uint32_t EXTADCCLK = 0x0; // use internally generated clock
const uint32_t REFCLK_L_CNT = 0x100; // set the L counter of the reference clock configuration to its default value
const uint32_t REFCLK_M_CNT = 0x61B; // set the M counter of the reference clock configuration to its default value
const uint32_t FCLKIN = 0x0; // fractional clock divider set to default value
const uint32_t ADCCLK = 0x0; // ADC clock selection set to reference clock divider/multiplier
const uint32_t MODE = 0x0; // DSP interface mode selection
const uint32_t ADCCLK_L_CNT = 0x100; // set the L counter of the ADC clock configuration to its default value
const uint32_t ADCCLK_M_CNT = 0x61B; // set the M counter of the ADC clock configuration to its default value
const uint32_t PRE_FRACDIV_SEL = 0x0; // bypass fractional clock divider
const uint32_t CLKOUT_SEL = 0x1; // CLKOUT selection set to ADC clock
// MAX2771 configuration register registers
const uint32_t TEST_MODE_1_REG_VAL = 0x01E0F401; // reserved
const uint32_t TEST_MODE_2_REG_VAL = 0x00000002;
bool configure(std::vector<uint32_t> register_values);
void run_buffer_monitor_process();
std::thread thread_buffer_monitor;
std::shared_ptr<Fpga_buffer_monitor> buffer_monitor_fpga;
std::shared_ptr<Fpga_spidev> spidev_fpga;
std::mutex buffer_monitor_mutex;
uint64_t freq_; // frequency of local oscillator
uint64_t sample_rate_;
uint32_t in_stream_;
uint32_t out_stream_;
uint32_t bandwidth_; // 2500000, 4200000, 8700000, 16400000, 23400000, 36000000
uint32_t filter_order_; //3, 5
uint32_t gain_in_; // 0 to 0x3F
size_t item_size_; // 1
bool chipen_; // chip enable
bool if_filter_gain_; // true, false
bool LNA_active_; // true, false
bool enable_agc_; // true, false
bool enable_ovf_check_buffer_monitor_active_;
bool dump_;
bool rf_shutdown_;
};
/** \} */
/** \} */
#endif // GNSS_SDR_MAX2771_EVKIT_FPGA_SIGNAL_SOURCE_H

View File

@ -12,17 +12,24 @@ if(ENABLE_FMCOMMS2 OR ENABLE_AD9361)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.h)
endif()
if(ENABLE_FPGA OR ENABLE_AD9361)
if(ENABLE_FPGA_MAX2771_EVKIT)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_spidev.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_spidev.h)
endif()
if(ENABLE_FPGA)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_switch.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_switch.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dynamic_bit_selection.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dynamic_bit_selection.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_buffer_monitor.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_buffer_monitor.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dma-proxy.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dma-proxy.h)
endif()
if(ENABLE_AD9361 OR ENABLE_FPGA_MAX2771_EVKIT)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_buffer_monitor.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_buffer_monitor.h)
endif()
if(ENABLE_PLUTOSDR)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.cc)

View File

@ -0,0 +1,131 @@
/*!
* \file fpga_spidev.cc
* \brief FPGA SPI control.
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "fpga_spidev.h"
#include <cstring> // for memset()
#include <fcntl.h> // for open(), O_RDWR
#include <iostream> // for std::cerr
#include <linux/spi/spidev.h> // spidev driver
#include <sys/ioctl.h> // for ioctl()
#include <unistd.h> // for close()
int Fpga_spidev::SPI_open()
{
if ((d_fd = open(SPI_DEVICE_NAME.c_str(), O_RDWR)) < 0)
{
std::cerr << "Failed to open the " << SPI_DEVICE_NAME << " device file \n";
return -1;
}
int ret;
int32_t mode = 0;
ret = ioctl(d_fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
{
std::cerr << "can't set spi mode\n";
return -1;
}
ret = ioctl(d_fd, SPI_IOC_RD_MODE32, &mode); // le digo al spi "algo"
if (ret == -1)
{
std::cerr << "can't set spi mode\n";
return -1;
}
return 0;
}
int Fpga_spidev::write_reg32(char addr, uint32_t data)
{
uint8_t data_buffer[2];
uint8_t recv_buffer[4];
int res = 0;
struct spi_ioc_transfer xfer[2];
memset(xfer, 0, sizeof(xfer));
xfer[0].bits_per_word = 8;
xfer[0].speed_hz = SPI_SPEED;
xfer[1].bits_per_word = 8;
xfer[1].speed_hz = SPI_SPEED;
memset(&recv_buffer, 0, sizeof(recv_buffer));
memset(&data_buffer, 0, sizeof(data_buffer));
data_buffer[1] = addr << 4 | 0 << 3;
xfer[0].tx_buf = (unsigned long)data_buffer;
xfer[0].len = 2;
// Would use memcpy but 'data' is in little endian
((char*)recv_buffer)[0] = ((char*)&data)[3];
((char*)recv_buffer)[1] = ((char*)&data)[2];
((char*)recv_buffer)[2] = ((char*)&data)[1];
((char*)recv_buffer)[3] = ((char*)&data)[0];
xfer[1].tx_buf = (unsigned long)recv_buffer;
xfer[1].len = 4;
res = ioctl(d_fd, SPI_IOC_MESSAGE(2), xfer);
if (res < 0)
{
std::cout << "Error sending SPI message\n";
return res;
}
return 0;
}
int Fpga_spidev::read_reg32(uint8_t addr, uint32_t* copy_to)
{
uint8_t data_buffer[2];
uint8_t recv_buffer[4];
int res;
struct spi_ioc_transfer xfer[2];
memset(xfer, 0, sizeof(xfer));
xfer[0].bits_per_word = 8;
xfer[0].speed_hz = SPI_SPEED;
xfer[1].bits_per_word = 8;
xfer[1].speed_hz = SPI_SPEED;
memset(&recv_buffer, 0, sizeof(recv_buffer));
memset(&data_buffer, 0, sizeof(data_buffer));
data_buffer[1] = addr << 4 | 1 << 3;
xfer[0].tx_buf = (unsigned long)data_buffer;
xfer[0].len = 2;
xfer[1].rx_buf = (unsigned long)recv_buffer;
xfer[1].len = 4;
res = ioctl(d_fd, SPI_IOC_MESSAGE(2), xfer);
if (res < 0)
{
std::cout << "Error sending SPI message\n";
return res;
}
// the register data is received in the reverse order
uint32_t tmp_result = 0;
for (uint32_t k = 0; k < 4; ++k)
{
tmp_result = tmp_result + ((recv_buffer[3 - k]) << 8 * k);
}
*copy_to = tmp_result;
return 0;
}
int Fpga_spidev::SPI_close() const
{
return close(d_fd);
}

View File

@ -0,0 +1,61 @@
/*!
* \file fpga_spidev.h
* \brief FPGA SPI control.
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_FPGA_SPIDEV_H
#define GNSS_SDR_FPGA_SPIDEV_H
#include <string>
class Fpga_spidev
{
public:
/*!
* \brief Default constructor.
*/
Fpga_spidev() = default;
/*!
* \brief Default destructor.
*/
~Fpga_spidev() = default;
/*!
* \brief write a register through the SPI.
*/
int write_reg32(char addr, uint32_t data);
/*!
* \brief read a register through the SPI.
*/
int read_reg32(uint8_t addr, uint32_t* copy_to);
/*!
* \brief Open the SPI device driver.
*/
int SPI_open(void);
/*!
* \brief Close the SPI device driver
*/
int SPI_close(void) const;
private:
static const uint32_t SPI_SPEED = 250000;
const std::string SPI_DEVICE_NAME = std::string("/dev/spidev2.0"); // Switch UIO device name
int d_fd;
};
#endif // GNSS_SDR_FPGA_SPIDEV_H

View File

@ -98,6 +98,10 @@ if(ENABLE_AD9361)
target_compile_definitions(core_receiver PRIVATE -DAD9361_DRIVER=1)
endif()
if(ENABLE_FPGA_MAX2771_EVKIT)
target_compile_definitions(core_receiver PRIVATE -DFPGA_MAX2771_EVKIT_DRIVER=1)
endif()
if(ENABLE_OSMOSDR)
if(GROSMOSDR_FOUND)
target_compile_definitions(core_receiver PRIVATE -DOSMOSDR_DRIVER=1)

View File

@ -171,6 +171,10 @@
#include "ad9361_fpga_signal_source.h"
#endif
#if FPGA_MAX2771_EVKIT_DRIVER
#include "max2771_evkit_fpga_signal_source.h"
#endif
#if LIMESDR_DRIVER
#include "limesdr_signal_source.h"
#endif
@ -813,8 +817,6 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
#endif
#if ENABLE_FPGA and AD9361_DRIVER
// The AD9361_DRIVER Driver must be instantiated last. In this way, when using the FPGA, and when using the GNSS receiver
// in post-processing mode, the receiver is configured and ready when the DMA starts sending samples to the receiver.
else if (implementation == "Ad9361_Fpga_Signal_Source")
{
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<Ad9361FpgaSignalSource>(configuration, role, in_streams,
@ -823,6 +825,15 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
}
#endif
#if ENABLE_FPGA and FPGA_MAX2771_EVKIT_DRIVER
else if (implementation == "MAX2771_evkit_Fpga_Signal_Source")
{
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<MAX2771EVKITFpgaSignalSource>(configuration, role, in_streams,
out_streams, queue);
block = std::move(block_);
}
#endif
#if ENABLE_FPGA
else if (implementation == "DMA_Fpga_Signal_Source")
{