...
 
Commits (121)
Release 20.01.0 (pending)
==========================
LimeSuite library changes:
- Including LimeRFE support
- Update CGEN calculation to allow lower CGEN values
- Configure RF switches (when possible) to avoid transmission during calibration
- Automatically reconfigure GFIR LPF after sample rate change
- Remove LMS_EnableCalibCache function from LimeSuite.h
- Improve PLL locking in calibration procedures
- Fix Tx transfer size being set to Rx transfer size
- Fix RF path being auto-set after it was selected explicitly for LimeSDR-Mini
- Add option to perform Rx phase alignment instead of of always running it
- Improve SXT/SXR tune by automatically retrying with higher bias current setting
- Update FIFO buffers to use memory more efficiently
SoapyLMS:
- Add oversampling setting
- Set bandwidth to sample rate if bandwidth is not explicitly set
- Fix possible segfault when 2 Rx cahnnels are used
- Pause streaming when changing sample rate
- Return time error when negative timestmp is used
- Automatically use wide enough bandwidth setting for RF frequencies bellow 30 MHz
- Remove master clock setting
- Add setting descriptions
- Implement read for setting advertised by getSettingInfo()
LimeSuiteGUI:
- Add panel for LMS API function testing
- Add option to play WFM file from software
- fix channel measurement in FFTviewer for Ch.B in MIMO mode
Octave plugin:
- Add LimeGetStreamStatus function
- Add LimeTransceiveSamples function
- Update antenna selection after loading ini file
Other changes:
- Fix LimeQuickTest not outputing to windows command line
Release 19.04.0 (2019-05-09)
==========================
......
......@@ -73,6 +73,9 @@ LimeSDRTest* LimeSDRTest::Connect()
{
std::string str = "->Device: ";
str += handles[0].serialize();
str += ", HW=" + std::string(info->hardwareVersion);
str += ", GW=" + std::string(info->gatewareVersion);
UpdateStatus(LMS_TEST_INFO, str.c_str());
if (str.find("USB 3") == std::string::npos)
{
......@@ -80,6 +83,9 @@ LimeSDRTest* LimeSDRTest::Connect()
UpdateStatus(LMS_TEST_INFO, str.c_str());
}
UpdateStatus(LMS_TEST_LOGFILE, handles[0].serial.c_str());
str = "Chip temperature: " + std::to_string(int(dev->GetChipTemperature())) + " C";
UpdateStatus(LMS_TEST_INFO, str.c_str());
}
if (strstr(info->deviceName, lime::GetDeviceName(lime::LMS_DEV_LIMESDR)))
......
......@@ -14,13 +14,13 @@
#include <iostream>
#include <getopt.h>
#ifdef QUICKTEST_GUI
#ifdef NDEBUG
#ifdef _MSC_VER
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#endif
#endif
#ifdef QUICKTEST_GUI
static Fl_Button** buttons;
static Fl_Window* popup = nullptr;
static Fl_Multiline_Output* out;
......@@ -320,7 +320,7 @@ int main(int argc, char** argv)
#else
int gui = 1;
#endif
static struct option long_options[] = {
struct option long_options[] = {
{"gui", no_argument, &gui, 1},
{"no-gui", no_argument, &gui, 0},
{0, 0, 0, 0}
......
# Lime Suite
The Lime Suite application software provides drivers
and SDR application support for the LMS7002M RFIC,
and hardware like the LimeSDR, NovenaRF7, and others.
Read more about Lime Suite on the official project page:
* https://myriadrf.org/projects/lime-suite/
Lime Suite is a collection of software supporting several hardware platforms
based on the LMS7002M transceiver RFIC, such as LimeSDR family. It contains the
following components:
* **LimeSuite library** that provides C-style API;
* **LimeSuiteGUI** application for accessing low-level chip and board settings, displaying FFT, updating firmware and more;
* **SoapyLMS** plugin for LimeSDR support in SoapySDR;
* **LimeUtil** command line tool for listing LimeSDR devices and updating firmware;
* **LimeQuickTest** application to run some basic tests;
* **LimeSuite API examples** (basicRX, basicTX, singleRX, dualRXTX, gpio_example);
* **Octave plugin** (provides some basic functionality only);
## Build Status
......@@ -18,6 +22,10 @@ Find build and install instructions for Lime Suite on the wiki:
* http://wiki.myriadrf.org/Lime_Suite
Information about LimeSDR boards:
* https://wiki.myriadrf.org/LimeSDR
## Help and support
The discourse forum is a good way to find help and discuss topics:
......
This diff is collapsed.
......@@ -12,8 +12,6 @@
#include <set>
#include "Streamer.h"
static const double DEFAULT_CLOCK_RATE = 80e6;
namespace lime
{
class LIME_API LMS7_Device;
......@@ -133,7 +131,7 @@ public:
std::complex<double> getDCOffset(const int direction, const size_t channel) const;
bool hasIQBalance(const int direction, const size_t channel) const;
void setIQBalance(const int direction, const size_t channel, const std::complex<double> &balance);
std::complex<double> getIQBalance(const int direction, const size_t channel) const;
......@@ -145,7 +143,7 @@ public:
std::vector<std::string> listGains(const int direction, const size_t channel) const;
void setGain(const int direction, const size_t channel, const double value) override;
double getGain(const int direction, const size_t channel) const;
void setGain(const int direction, const size_t channel, const std::string &name, const double value);
......@@ -167,7 +165,7 @@ public:
void setFrequency(const int direction, const size_t channel, const std::string &name, const double frequency, const SoapySDR::Kwargs &args = SoapySDR::Kwargs());
double getFrequency(const int direction, const size_t channel, const std::string &name) const;
double getFrequency(const int direction, const size_t channel) const override;
std::vector<std::string> listFrequencies(const int direction, const size_t channel) const;
......@@ -195,8 +193,6 @@ public:
* Bandwidth API
******************************************************************/
std::map<int, std::map<size_t, double>> _actualBw;
void setBandwidth(const int direction, const size_t channel, const double bw);
double getBandwidth(const int direction, const size_t channel) const;
......@@ -207,12 +203,8 @@ public:
* Clocking API
******************************************************************/
void setMasterClockRate(const double rate);
double getMasterClockRate(void) const;
SoapySDR::RangeList getMasterClockRates(void) const;
/*******************************************************************
* Time API
******************************************************************/
......@@ -264,9 +256,9 @@ public:
SoapySDR::ArgInfoList getSettingInfo(const int direction, const size_t channel) const;
void writeSetting(const int direction, const size_t channel, const std::string &key, const std::string &value);
std::string readSetting(const std::string &key) const;
std::string readSetting(const int direction, const size_t channel, const std::string &key) const;
/*******************************************************************
......@@ -284,11 +276,27 @@ public:
unsigned readGPIODir(const std::string &bank) const;
private:
struct Channel{
Channel():freq(-1),bw(-1),rf_bw(-1),cal_bw(-1),gfir_bw(-1),tst_dc(0){};
double freq;
double bw;
double rf_bw;
double cal_bw;
double gfir_bw;
int tst_dc;
};
int setBBLPF(bool direction, size_t channel, double bw);
const SoapySDR::Kwargs _deviceArgs; //!< stash of constructor arguments
const std::string _moduleName;
lime::LMS7_Device * lms7Device;
double sampleRate;
double sampleRate[2]; //sampleRate[direction]
int oversampling;
std::set<std::pair<int, size_t>> _channelsToCal;
mutable std::recursive_mutex _accessMutex;
std::vector<Channel> mChannels[2]; //mChannels[direction]
std::set<SoapySDR::Stream *> activeStreams;
unsigned channelCount;
};
......@@ -84,7 +84,7 @@ SoapySDR::ArgInfoList SoapyLMS7::getStreamArgsInfo(const int direction, const si
argInfos.push_back(info);
}
//link format
//skip calibrations
{
SoapySDR::ArgInfo info;
info.value = "false";
......@@ -95,6 +95,17 @@ SoapySDR::ArgInfoList SoapyLMS7::getStreamArgsInfo(const int direction, const si
argInfos.push_back(info);
}
//align phase of Rx channels
{
SoapySDR::ArgInfo info;
info.value = "false";
info.key = "alignPhase";
info.name = "align phase";
info.description = "Attempt to align phase of Rx channels.";
info.type = SoapySDR::ArgInfo::BOOL;
argInfos.push_back(info);
}
return argInfos;
}
......@@ -116,6 +127,7 @@ SoapySDR::Stream *SoapyLMS7::setupStream(
stream->skipCal = args.count("skipCal") != 0 and args.at("skipCal") == "true";
StreamConfig config;
config.align = args.count("alignPhase") != 0 and args.at("alignPhase") == "true";
config.isTx = (direction == SOAPY_SDR_TX);
config.performanceLatency = 0.5;
config.bufferLength = 0; //auto
......@@ -198,17 +210,22 @@ int SoapyLMS7::activateStream(
std::unique_lock<std::recursive_mutex> lock(_accessMutex);
auto icstream = (IConnectionStream *)stream;
const auto &streamID = icstream->streamID;
if (sampleRate == 0.0)
if (sampleRate[SOAPY_SDR_TX] == 0.0 && sampleRate[SOAPY_SDR_RX] == 0.0)
throw std::runtime_error("SoapyLMS7::activateStream() - the sample rate has not been configured!");
if (sampleRate[SOAPY_SDR_RX] <= 0.0)
sampleRate[SOAPY_SDR_RX] = lms7Device->GetRate(LMS_CH_RX, 0);
//perform self calibration with current bandwidth settings
//this is for the set-it-and-forget-it style of use case
//where boards are configured, the stream is setup,
//and the configuration is maintained throughout the run
while (not _channelsToCal.empty() and not icstream->skipCal)
{
auto dir = _channelsToCal.begin()->first;
bool dir = _channelsToCal.begin()->first;
auto ch = _channelsToCal.begin()->second;
lms7Device->Calibrate(dir== SOAPY_SDR_TX,ch,_actualBw.at(dir).at(ch),0);
auto bw = mChannels[dir].at(ch).rf_bw > 0 ? mChannels[dir].at(ch).rf_bw : sampleRate[dir];
bw = bw>2.5e6 ? bw : 2.5e6;
lms7Device->Calibrate(dir== SOAPY_SDR_TX, ch, bw, 0);
mChannels[dir].at(ch).cal_bw = bw;
_channelsToCal.erase(_channelsToCal.begin());
}
//stream requests used with rx
......@@ -222,6 +239,7 @@ int SoapyLMS7::activateStream(
int status = i->Start();
if(status != 0) return SOAPY_SDR_STREAM_ERROR;
}
activeStreams.insert(stream);
return 0;
}
......@@ -240,7 +258,7 @@ int SoapyLMS7::deactivateStream(
int status = i->Stop();
if(status != 0) return SOAPY_SDR_STREAM_ERROR;
}
activeStreams.erase(stream);
return 0;
}
......@@ -356,7 +374,7 @@ int SoapyLMS7::readStream(
}
StreamChannel::Metadata metadata;
const uint64_t cmdTicks = ((icstream->flags & SOAPY_SDR_HAS_TIME) != 0)?SoapySDR::timeNsToTicks(icstream->timeNs, sampleRate):0;
const uint64_t cmdTicks = ((icstream->flags & SOAPY_SDR_HAS_TIME) != 0)?SoapySDR::timeNsToTicks(icstream->timeNs, sampleRate[SOAPY_SDR_RX]):0;
int status = _readStreamAligned(icstream, (char * const *)buffs, numElems, cmdTicks, metadata, timeoutUs/1000);
if (status < 0) return status;
......@@ -403,7 +421,7 @@ int SoapyLMS7::readStream(
flags = 0;
if ((metadata.flags & RingFIFO::END_BURST) != 0) flags |= SOAPY_SDR_END_BURST;
if ((metadata.flags & RingFIFO::SYNC_TIMESTAMP) != 0) flags |= SOAPY_SDR_HAS_TIME;
timeNs = SoapySDR::ticksToTimeNs(metadata.timestamp, sampleRate);
timeNs = SoapySDR::ticksToTimeNs(metadata.timestamp, sampleRate[SOAPY_SDR_RX]);
//return num read or error code
return (status >= 0) ? status : SOAPY_SDR_STREAM_ERROR;
......@@ -417,12 +435,14 @@ int SoapyLMS7::writeStream(
const long long timeNs,
const long timeoutUs)
{
if ((flags & SOAPY_SDR_HAS_TIME) && (timeNs <= 0))
return SOAPY_SDR_TIME_ERROR;
auto icstream = (IConnectionStream *)stream;
const auto &streamID = icstream->streamID;
//input metadata
StreamChannel::Metadata metadata;
metadata.timestamp = SoapySDR::timeNsToTicks(timeNs, sampleRate);
metadata.timestamp = SoapySDR::timeNsToTicks(timeNs, sampleRate[SOAPY_SDR_RX]);
metadata.flags = (flags & SOAPY_SDR_HAS_TIME) ? lime::RingFIFO::SYNC_TIMESTAMP : 0;
metadata.flags |= (flags & SOAPY_SDR_END_BURST) ? lime::RingFIFO::END_BURST : 0;
......@@ -478,13 +498,13 @@ int SoapyLMS7::readStreamStatus(
if (seconds.count()> (double)timeoutUs/1e6)
return SOAPY_SDR_TIMEOUT;
//sleep to avoid high CPU load
if (timeoutUs >= 2000)
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (timeoutUs >= 1000000)
std::this_thread::sleep_for(std::chrono::milliseconds(500));
else
std::this_thread::sleep_for(std::chrono::microseconds(1+timeoutUs/2));
std::this_thread::sleep_for(std::chrono::microseconds(timeoutUs));
}
timeNs = SoapySDR::ticksToTimeNs(metadata.timestamp, sampleRate);
timeNs = SoapySDR::ticksToTimeNs(metadata.timestamp, sampleRate[SOAPY_SDR_RX]);
//output metadata
flags |= SOAPY_SDR_HAS_TIME;
return ret;
......
This diff is collapsed.
limesuite (20.01.0-1) unstable; urgency=low
* Release 20.01.0 (2020-01-28)
-- Lime Microsystems <[email protected]> Thu, 28 Feb 2020 15:00:00 +0300
limesuite (19.04.0-1) unstable; urgency=low
* Release 19.04.0 (2019-05-09)
......
......@@ -16,7 +16,7 @@ Homepage: https://myriadrf.org/projects/lime-suite/
Vcs-Git: https://github.com/myriadrf/LimeSuite.git
Vcs-Browser: https://github.com/myriadrf/LimeSuite.git
Package: liblimesuite19.04-1
Package: liblimesuite20.01-1
Section: libs
Architecture: any
Multi-Arch: same
......@@ -30,7 +30,7 @@ Package: liblimesuite-dev
Section: libdevel
Architecture: any
Depends:
liblimesuite19.04-1 (= ${binary:Version}),
liblimesuite20.01-1 (= ${binary:Version}),
${misc:Depends}
Description: Lime Suite - development files
Lime Suite application software.
......@@ -39,7 +39,7 @@ Package: limesuite
Section: comm
Architecture: any
Depends:
liblimesuite19.04-1 (= ${binary:Version}),
liblimesuite20.01-1 (= ${binary:Version}),
${shlibs:Depends},
${misc:Depends},
xdg-utils
......@@ -59,7 +59,7 @@ Section: comm
Architecture: any
Multi-Arch: same
Depends:
liblimesuite19.04-1 (= ${binary:Version}),
liblimesuite20.01-1 (= ${binary:Version}),
${shlibs:Depends},
${misc:Depends}
Description: Lime Suite - SoapySDR bindings
......@@ -73,7 +73,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, udev
Description: Lime Suite - USB rules for udev
Lime Suite application software.
Package: limesuite-images19.04
Package: limesuite-images20.01
Section: libs
Architecture: any
Multi-Arch: same
......@@ -87,7 +87,7 @@ Package: limesuite-images
Section: libs
Architecture: any
Multi-Arch: same
Depends: ${shlibs:Depends}, ${misc:Depends}, limesuite-images19.04
Depends: ${shlibs:Depends}, ${misc:Depends}, limesuite-images20.01
Description: Lime Suite - Install firmware and gateware images
Lime Suite application software.
.
......
......@@ -523,14 +523,14 @@ MAX_INITIALIZER_LINES = 10
# at the bottom of the documentation of classes and structs. If set to YES the
# list will mention the files that were used to generate the documentation.
SHOW_USED_FILES = YES
SHOW_USED_FILES = NO
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
# This will remove the Files entry from the Quick Index and from the
# Folder Tree View (if specified). The default is YES.
SHOW_FILES = YES
SHOW_FILES = NO
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
# Namespaces page.
......
......@@ -13,10 +13,19 @@ LMS API is a set of C functions that are exported by LimeSuite library. Its main
/*! \page page_changelog Changelog
### v20.01.0
\li Remove LMS_EnableCalibCache() function
\li Fixed \ref lms_stream_t::throughputVsLatency setting not working for Tx streams
\li Added automatic reconfiguration of GFIR when sample rate is changed after calling LMS_SetGFIRLPF()
\li Added \ref LMS_ALIGN_CH_PHASE option to run Rx phase alignment for MIMO configuration
\li Fixed RF path being auto-set after it was explicitly selected for LimeSDR-Mini
\li Added log level definition \ref LMS_LOG_CRITICAL
### v19.04.0
\li Added support for LimeNet-Micro
\ii Added saving and loading of analog IQ/DC calibration state to LMS_SaveConfig() and LMS_SaveConfig()
\li Added saving and loading of analog IQ/DC calibration state to LMS_SaveConfig() and LMS_SaveConfig()
\li Fixed Rx stream failing to start on LimeSDR-USB when Tx is disabled and sample rate is <2.5 MSps
\li Fixed Tx ch.B calibration when Rx ch.B is disabled
......
......@@ -785,6 +785,7 @@ uint8_t CalibrateTxSetup(bool extLoopback)
//SXR
Modify_SPI_Reg_bits(MAC, 1); //switch to ch. A
SetDefaultsSX();
Modify_SPI_Reg_bits(ICT_VCO, 255);
{
const float_type SXRfreq = GetFrequencySX(LMS7002M_Tx) - bandwidthRF/ calibUserBwDivider - calibrationSXOffset_Hz;
//SX VCO is powered up in SetFrequencySX/Tune
......@@ -946,8 +947,8 @@ uint8_t CalibrateRxSetup(bool extLoopback)
//rfe
{
ROM const uint16_t RxSetupAddr[] = {0x0084, 0x0085,0x00AE,0x010C,0x010D,0x0113,0x0115,0x0119};
ROM const uint16_t RxSetupData[] = {0x0400, 0x0001,0xF000,0x0000,0x0040,0x000C,0x0000,0x0000};
ROM const uint16_t RxSetupMask[] = {0xF8FF, 0x0007,0xF000,0x001A,0x0040,0x003C,0xC000,0x8000};
ROM const uint16_t RxSetupData[] = {0x0400, 0x0001,0xF000,0x0000,0x0046,0x000C,0x0000,0x0000};
ROM const uint16_t RxSetupMask[] = {0xF8FF, 0x0007,0xF000,0x001A,0x0046,0x003C,0xC000,0x8000};
ROM const uint16_t RxSetupWrOnlyAddr[] = {0x0100,0x0101,0x0102,0x0103,0x0104,0x0105,0x0106,0x0107,0x0108,0x0109,0x010A,0x0200,0x0201,0x0202,0x0208,0x0240,0x0400,0x0401,0x0402,0x0403,0x0407,0x040A,0x040C,0x0440,0x05C0,0x05CB,0x0203,0x0204,0x0205,0x0206,0x0207,0x0241,0x0404,0x0405,0x0406,0x0408,0x0409,0x0441,0x05C1,0x05C2,0x05C3,0x05C4,0x05C5,0x05C6,0x05C7,0x05C8,0x05C9,0x05CA,0x05CC, 0x0081};
ROM const uint16_t RxSetupWrOnlyData[] = {0x3408,0x6001,0x3180,0x0A12,0x0088,0x0007,0x318C,0x318C,0x0426,0x61C1,0x104C,0x008D,0x07FF,0x07FF,0x2070,0x0020,0x0081,0x07FF,0x07FF,0x4000,0x0700,0x1000,0x2098,0x0020,0x00FF,0x2020};
ROM const RegisterBatch batch = {
......@@ -1081,6 +1082,7 @@ uint8_t CalibrateRxSetup(bool extLoopback)
//in TDD do nothing
Modify_SPI_Reg_bits(MAC, 1);
SetDefaultsSX();
Modify_SPI_Reg_bits(ICT_VCO, 255);
status = SetFrequencySX(LMS7002M_Rx, GetFrequencySX(LMS7002M_Tx) - bandwidthRF/ calibUserBwDivider - 9e6);
}
else
......@@ -1096,6 +1098,7 @@ uint8_t CalibrateRxSetup(bool extLoopback)
//SXT
Modify_SPI_Reg_bits(MAC, 2);
SetDefaultsSX();
Modify_SPI_Reg_bits(ICT_VCO, 255);
status = SetFrequencySX(LMS7002M_Tx, SXRfreqHz + bandwidthRF/ calibUserBwDivider + 9e6);
}
SPI_write(0x0020, x0020val);
......
......@@ -225,6 +225,7 @@ uint8_t SetFrequencySX(const bool tx, const float_type freq_Hz)
{
const uint16_t macBck = SPI_read(0x0020);
bool canDeliverFrequency;
uint8_t valICT = 255;
Modify_SPI_Reg_bits(MAC, tx?2:1);
//find required VCO frequency
{
......@@ -254,6 +255,7 @@ uint8_t SetFrequencySX(const bool tx, const float_type freq_Hz)
}
canDeliverFrequency = false;
for(;;)
{
uint8_t sel_vco, bestVCO, bestCSW;
uint8_t bestScore = 255;// best is closest to 0
......@@ -275,6 +277,11 @@ uint8_t SetFrequencySX(const bool tx, const float_type freq_Hz)
}
Modify_SPI_Reg_bits(SEL_VCO, bestVCO);
Modify_SPI_Reg_bits(CSW_VCO, bestCSW);
if(canDeliverFrequency || valICT == 45)
break;
Modify_SPI_Reg_bits(ICT_VCO, valICT -= 70);
}
SPI_write(0x0020, macBck);
if (canDeliverFrequency == false)
......@@ -334,7 +341,7 @@ uint8_t TuneVCO(bool SX) // 0-cgen, 1-SXR, 2-SXT
Modify_SPI_Reg_bits(0x0086, MSB_LSB(2, 1), 0); //activate VCO and comparator
}
#ifndef __cplusplus
gComparatorDelayCounter = 0xFFFF - (uint16_t)((0.0003/12)*RefClk); // ~300us
gComparatorDelayCounter = 0xFFFF - (uint16_t)((0.0009/12)*RefClk); // ~900us
#endif
//check if lock is within VCO range
Modify_SPI_Reg_bits(addrCSW_VCO, msblsb, 0);
......
#include <octave/oct.h>
#include <octave/Cell.h>
#include <octave/ov-struct.h>
#include <vector>
#include <string>
......@@ -164,6 +164,19 @@ DEFUN_DLD (LimeLoadConfig, args, nargout,
{
return octave_value(-1);
}
int chCnt = LMS_GetNumChannels(lmsDev, LMS_CH_RX);
chCnt = chCnt > maxChCnt ? maxChCnt : chCnt;
for(int ch=0; ch< chCnt; ++ch) //set antenna to update RF switches
{
int ant = LMS_GetAntenna(lmsDev, LMS_CH_RX, ch);
if(ant < 0 || LMS_SetAntenna(lmsDev, LMS_CH_RX, ch, ant) < 0)
octave_stdout << "Error setting Rx antenna for ch: " << ch << endl;
ant = LMS_GetAntenna(lmsDev, LMS_CH_TX, ch);
if(ant < 0 || LMS_SetAntenna(lmsDev, LMS_CH_TX, ch, ant) < 0)
octave_stdout << "Error setting Tx antenna for ch: " << ch << endl;
}
octave_stdout << "Config loaded successfully: " << endl;
return octave_value(0);
......@@ -268,7 +281,6 @@ DEFUN_DLD (LimeStopStreaming, args, nargout,
octave_stdout << "LimeSuite not initialized" << endl;
return octave_value(-1);
}
int nargin = args.length();
octave_stdout << "StopStreaming" << endl;
StopStream();
return octave_value_list();
......@@ -281,10 +293,10 @@ CH parameter is optional, valid values are 0 and 1")
if (!rxbuffers)
{
octave_stdout << "Rx streaming not initialized" << endl;
return octave_value(-1);
return octave_value_list();;
}
int nargin = args.length ();
int nargin = args.length();
if (nargin != 2 && nargin != 1)
{
print_usage ();
......@@ -295,11 +307,11 @@ CH parameter is optional, valid values are 0 and 1")
unsigned chIndex;
if (nargin == 2)
{
chIndex = args(1).int_value ();
chIndex = args(1).int_value();
if (chIndex >= maxChCnt)
{
octave_stdout << "Invalid channel number" << endl;
return octave_value(-1);
return octave_value_list();;
}
}
else
......@@ -348,12 +360,12 @@ CH parameter is optional, valid values are 0 and 1")
return octave_value(-1);
}
int nargin = args.length ();
int nargin = args.length();
int check=0;
if (nargin != 2 && nargin != 1)
{
print_usage ();
return octave_value_list ();
return octave_value(-1);
}
int chIndex = 0;
......@@ -397,6 +409,100 @@ CH parameter is optional, valid values are 0 and 1")
return octave_value (samplesWrite);
}
DEFUN_DLD (LimeTransceiveSamples, args, ,
"RXSIGNAL = LimeTransceiveSamples( TXSIGNAL, RXOFFSET, CH) - transmit TXSIGNAL and receive RXSIGNAL (same length as TXSIGNAL).\n\
RXOFFSET [optional] - number of samples to skip at the beginning of receive (default 0)\n\
CH [optional] - channel to use for transmit and receive, valid values are 0 and 1 (default 0)")
{
if (!rxbuffers)
{
octave_stdout << "Rx streaming not initialized" << endl;
return octave_value_list();
}
if (!txbuffers)
{
octave_stdout << "Tx streaming not initialized" << endl;
return octave_value_list();
}
int nargin = args.length ();
if (nargin == 0 || nargin > 3)
{
print_usage ();
return octave_value_list();
}
unsigned chIndex = 0;
if (nargin == 3)
{
chIndex = args(2).int_value ();
if ((chIndex >= maxChCnt) || (streamRx[chIndex].handle == 0) || (streamTx[chIndex].handle == 0))
{
octave_stdout << "Invalid channel" << endl;
return octave_value_list();
}
}
//transmit part
const int timeout_ms = 1000;
lms_stream_meta_t meta = {0, false, false};
ComplexRowVector iqdataTx=args(0).complex_row_vector_value();
dim_vector iqdataSize=iqdataTx.dims();
const int samplesCount = iqdataSize(0) > iqdataSize(1) ? iqdataSize(0) : iqdataSize(1);
for(int i=0; i < samplesCount; ++i)
{
octave_value iqdatum = scaleFactor*iqdataTx(i);
Complex iqdatum2 = iqdatum.complex_value();
short i_sample = iqdatum2.real(); //
short q_sample = iqdatum2.imag(); //
txbuffers[i].i = i_sample;
txbuffers[i].q = q_sample;
}
const int samplesWrite = LMS_SendStream(&streamTx[chIndex], (const void*)txbuffers, samplesCount, &meta, timeout_ms);
if (samplesWrite != samplesCount)
octave_stdout << "Error transmitting samples: send " << samplesWrite +"/" +samplesCount << endl;
//Receive part
int offset = nargin > 1 ? args(1).int_value() : 0;
if (offset < 0)
{
octave_stdout << "Invalid RXOFFSET value" << endl;
offset = 0;
}
Complex val=Complex(0.0,0.0);
ComplexRowVector iqdataRx( samplesCount, val ); // index 0 to N-1
int samplesCollected = 0;
int retries = 5;
while(samplesCollected < samplesCount && retries--)
{
int samplesToRead = 0;
if(samplesCount-samplesCollected > streamRx[chIndex].fifoSize/2)
samplesToRead = streamRx[chIndex].fifoSize/2;
else
samplesToRead = samplesCount-samplesCollected;
int samplesRead = LMS_RecvStream(&streamRx[chIndex], (void*)rxbuffers, samplesToRead, &meta, timeout_ms);
if (samplesRead < 0)
{
octave_stdout << "Error reading samples" << endl;
return octave_value(-1);
}
if (offset >= samplesRead)
{
offset -= samplesRead;
continue;
}
for(int i=offset; i<samplesRead; ++i)
iqdataRx(samplesCollected++)=Complex(rxbuffers[i].i/scaleFactor,rxbuffers[i].q/scaleFactor);
offset = 0;
}
return octave_value(iqdataRx);
}
DEFUN_DLD (LimeLoopWFMStart, args, ,
"LimeLoopWFMStart(SIGNAL) - upload SIGNAL to device RAM for repeated transmitting")
{
......@@ -459,6 +565,41 @@ DEFUN_DLD (LimeLoopWFMStop, args, ,
return octave_value ();
}
DEFUN_DLD (LimeGetStreamStatus, args, nargout,
"LimeGetStreamStatus() - Get Stream Status")
{
if(lmsDev == NULL)
{
octave_stdout << "LimeSuite not initialized" << endl;
return octave_value(-1);
}
octave_scalar_map st;
lms_stream_status_t status;
for (int i = 0; i < maxChCnt; i++)
{
if ((streamRx[i].handle) && (LMS_GetStreamStatus(&streamRx[i], &status) == 0))
{
st.assign("fifo_size", status.fifoSize);
st.assign("rx_data_rate", status.linkRate);
std::string ch = std::string("rx") + char('0'+i);
st.assign(ch+"_fifo_filled", status.fifoFilledCount);
st.assign(ch+"_fifo_overruns", status.overrun);
st.assign(ch+"_lost_packets", status.droppedPackets);
}
if ((streamTx[i].handle)&& (LMS_GetStreamStatus(&streamTx[i], &status) == 0))
{
st.assign("fifo_size", status.fifoSize);
st.assign("tx_data_rate", status.linkRate);
std::string ch = std::string("tx") + char('0'+i);
st.assign(ch+"_fifo_filled", status.fifoFilledCount);
st.assign(ch+"_fifo_underrun", status.underrun);
}
}
return octave_value (st);
}
void FreeResources()
{
if(lmsDev)
......
......@@ -6,7 +6,8 @@ autoload('LimeStartStreaming', 'LimeSuite.oct')
autoload('LimeStopStreaming', 'LimeSuite.oct')
autoload('LimeReceiveSamples', 'LimeSuite.oct')
autoload('LimeTransmitSamples', 'LimeSuite.oct')
autoload('LimeGetFIFOStatus', 'LimeSuite.oct')
autoload('LimeGetStreamStatus', 'LimeSuite.oct')
autoload('LimeLoopWFMStart', 'LimeSuite.oct')
autoload('LimeLoopWFMStop', 'LimeSuite.oct')
autoload('LimeGetDeviceList', 'LimeSuite.oct')
\ No newline at end of file
autoload('LimeGetDeviceList', 'LimeSuite.oct')
autoload('LimeTransceiveSamples', 'LimeSuite.oct')
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
......@@ -13,10 +13,11 @@ fifoSize = 1024*1024 %set library FIFO size to 1 MSample
LimeStartStreaming(fifoSize,["rx0"; "rx1"]); % start RX from channels 0 and 1
%receive samples, overwrite the same array
for i=1:16
for i=1:40
samplesCh0 = LimeReceiveSamples(readCnt,0); % read samples from RX channel 0
samplesCh1 = LimeReceiveSamples(readCnt,1); % read samples from RX channel 1
end
LimeGetStreamStatus() %must run at least 1s to get data rate (B/s)
%stop streaming
LimeStopStreaming(); % stop streaming
LimeDestroy(); % close device
......
clear all;
LoadLimeSuite
% generate test signal
phase = pi/600; % phase step
periods = 30; % periods to generate
txSignal = 0.7*complex(sin(phase:phase:periods*2*pi), cos(phase:phase:periods*2*pi));
LimeInitialize(); % open device
LimeLoadConfig('loop.ini'); % load configuration from file
%LimeLoadConfig('loop_mini.ini'); % load configuration from file
% use LimeSuiteGUI to create configuration file
%Real-time sample streaming
fifoSize = 1024*1024 % set library FIFO size to 1 MSample
LimeStartStreaming(fifoSize,["rx0"; "tx0"]); % start TX and RX channel 0
% send and receive samples to/from channel 0
% discard first 30K samples in Rx
rxSignal1 = LimeTransceiveSamples(txSignal, 30000);
for i=1:16
rxSignal2 = LimeTransceiveSamples(txSignal); % send and receive samples to/from channel 0
end
figure 1
plot(real(rxSignal1)); %plot first rx
figure 2
plot(real(rxSignal2)); %plot last rx
LimeGetStreamStatus() %must run at least 1s to get data rate (B/s)
sleep(1);
LimeStopStreaming(); % stop streaming
LimeDestroy(); % close device
......@@ -17,6 +17,7 @@ LimeStartStreaming(fifoSize,"tx0"); % start TX to channel 0
for i=1:100
LimeTransmitSamples(src,0); % send samples to TX channel 0
end
LimeGetStreamStatus() %must run at least 1s to get data rate (B/s)
sleep(1);
LimeStopStreaming(); % stop streaming
......
......@@ -39,7 +39,7 @@ int LMS7_LimeNET_micro::Init()
{0x010B, 0x0001}, {0x010C, 0x8865}, {0x010E, 0x0000}, {0x010F, 0x3142},
{0x0110, 0x2B14}, {0x0111, 0x0000}, {0x0112, 0x942E}, {0x0113, 0x03C2},
{0x0114, 0x00D0}, {0x0117, 0x1230}, {0x0119, 0x18D2}, {0x011C, 0x8941},
{0x011D, 0x0000}, {0x011E, 0x0740}, {0x0120, 0xE680}, {0x0121, 0x3650},
{0x011D, 0x0000}, {0x011E, 0x0740}, {0x0120, 0xE6C0}, {0x0121, 0x3650},
{0x0123, 0x000F}, {0x0200, 0x00E1}, {0x0208, 0x017B}, {0x020B, 0x4000},
{0x020C, 0x8000}, {0x0400, 0x8081}, {0x0404, 0x0006}, {0x040B, 0x1020},
{0x040C, 0x00FB}
......@@ -56,7 +56,7 @@ int LMS7_LimeNET_micro::Init()
lms->Modify_SPI_Reg_bits(LMS7param(MAC), 2);
lms->SPI_write(0x0123, 0x000F); //SXT
lms->SPI_write(0x0120, 0xE680); //SXT
lms->SPI_write(0x0120, 0xE6C0); //SXT
lms->SPI_write(0x011C, 0x8941); //SXT
lms->EnableChannel(false, false);
lms->EnableChannel(true, false);
......
......@@ -6,6 +6,7 @@
*/
#include "LimeSDR.h"
#include "device_constants.h"
#include "FPGA_common.h"
namespace lime
{
......@@ -70,6 +71,16 @@ int LMS7_LimeSDR::EnableChannel(bool dir_tx, unsigned chan, bool enabled)
return ret;
}
int LMS7_LimeSDR::Calibrate(bool dir_tx, unsigned chan, double bw, unsigned flags)
{
//switch RF path (may improve things in some configurations)
uint16_t value = fpga->ReadRegister(0x17);
fpga->WriteRegister(0x17, (value & (~0x77)) | 0x11);
int ret = LMS7_Device::Calibrate(dir_tx, chan, bw, flags);
fpga->WriteRegister(0x17, value);
return ret;
}
}
......
......@@ -20,6 +20,7 @@ public:
std::vector<std::string> GetProgramModes() const override;
int Program(const std::string& mode, const char* data, size_t len, lime::IConnection::ProgrammingCallback callback) const override;
int EnableChannel(bool dir_tx, unsigned chan, bool enabled) override;
int Calibrate(bool dir_tx, unsigned chan, double bw, unsigned flags) override;
};
}
......
......@@ -10,7 +10,7 @@
namespace lime
{
LMS7_LimeSDR_PCIE::LMS7_LimeSDR_PCIE(lime::IConnection* conn, LMS7_Device *obj) : LMS7_Generic(conn, obj)
LMS7_LimeSDR_PCIE::LMS7_LimeSDR_PCIE(lime::IConnection* conn, LMS7_Device *obj) : LMS7_LimeSDR(conn, obj)
{
}
......@@ -20,44 +20,11 @@ std::vector<std::string> LMS7_LimeSDR_PCIE::GetProgramModes() const
program_mode::mcuRAM, program_mode::mcuEEPROM, program_mode::mcuReset};
}
int LMS7_LimeSDR_PCIE::SetRate(double f_Hz, int oversample)
int LMS7_LimeSDR_PCIE::Program(const std::string& mode, const char* data, size_t len, lime::IConnection::ProgrammingCallback callback) const
{
bool bypass = (oversample == 1) || (oversample == 0 && f_Hz > 62e6);
for (unsigned i = 0; i < GetNumChannels(false);i++)
{
if (rx_channels[i].cF_offset_nco != 0.0 || tx_channels[i].cF_offset_nco != 0.0)
{
bypass = false;
break;
}
}
lime::LMS7002M* lms = lms_list[0];
if (!bypass)
return LMS7_Device::SetRate(f_Hz, oversample);
if ((lms->SetFrequencyCGEN(f_Hz*4) != 0)
|| (lms->Modify_SPI_Reg_bits(LMS7param(EN_ADCCLKH_CLKGN), 0) != 0)
|| (lms->Modify_SPI_Reg_bits(LMS7param(CLKH_OV_CLKL_CGEN), 2) != 0)
|| (lms->Modify_SPI_Reg_bits(LMS7param(MAC), 2) != 0)
|| (lms->Modify_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP), 7) != 0)
|| (lms->Modify_SPI_Reg_bits(LMS7param(HBI_OVR_TXTSP), 7) != 0)
|| (lms->Modify_SPI_Reg_bits(LMS7param(MAC), 1) != 0)
|| (lms->SetInterfaceFrequency(lms->GetFrequencyCGEN(), 7, 7) != 0))
return -1;
return SetFPGAInterfaceFreq(7, 7);
return LMS7_Device::Program(mode, data, len, callback);
}
int LMS7_LimeSDR_PCIE::EnableChannel(bool dir_tx, unsigned chan, bool enabled)
{
int ret = LMS7_Device::EnableChannel(dir_tx, chan, enabled);
if (dir_tx) //always enable DAC, otherwise sample rates <2.5MHz do not work
lms_list[0]->Modify_SPI_Reg_bits(LMS7_PD_TX_AFE1, 0);
return ret;
}
}
......
......@@ -7,18 +7,17 @@
#ifndef LIMESDR_PCIE_H
#define LIMESDR_PCIE_H
#include "LmsGeneric.h"
#include "LimeSDR.h"
namespace lime
{
class LMS7_LimeSDR_PCIE : public LMS7_Generic
class LMS7_LimeSDR_PCIE : public LMS7_LimeSDR
{
public:
LMS7_LimeSDR_PCIE(lime::IConnection* conn, LMS7_Device *obj = nullptr);
std::vector<std::string> GetProgramModes() const override;
int SetRate(double f_Hz, int oversample) override;
int EnableChannel(bool dir_tx, unsigned chan, bool enabled) override;
int Program(const std::string& mode, const char* data, size_t len, lime::IConnection::ProgrammingCallback callback) const override;
private:
};
......
......@@ -48,7 +48,7 @@ int LMS7_LimeSDR_mini::Init()
{0x010A, 0x1F4C}, {0x010B, 0x0001}, {0x010C, 0x8865}, {0x010E, 0x0000},
{0x010F, 0x3142}, {0x0110, 0x2B14}, {0x0111, 0x0000}, {0x0112, 0x942E},
{0x0113, 0x03C2}, {0x0114, 0x00D0}, {0x0117, 0x1230}, {0x0119, 0x18D2},
{0x011C, 0x8941}, {0x011D, 0x0000}, {0x011E, 0x0740}, {0x0120, 0xE680},
{0x011C, 0x8941}, {0x011D, 0x0000}, {0x011E, 0x0740}, {0x0120, 0xE6C0},
{0x0121, 0x3650}, {0x0123, 0x000F}, {0x0200, 0x00E1}, {0x0208, 0x017B},
{0x020B, 0x4000}, {0x020C, 0x8000}, {0x0400, 0x8081}, {0x0404, 0x0006},
{0x040B, 0x1020}, {0x040C, 0x00FB}
......@@ -83,7 +83,7 @@ int LMS7_LimeSDR_mini::Init()
lms->Modify_SPI_Reg_bits(LMS7param(MAC), 2);
lms->SPI_write(0x0123, 0x000F); //SXT
lms->SPI_write(0x0120, 0xE680); //SXT
lms->SPI_write(0x0120, 0xE6C0); //SXT
lms->SPI_write(0x011C, 0x8941); //SXT
lms->EnableChannel(false, false);
lms->EnableChannel(true, false);
......@@ -141,8 +141,9 @@ int LMS7_LimeSDR_mini::SetFrequency(bool isTx, unsigned chan, double f_Hz)
channel.cF_offset_nco = 0;
if (setTDD(f_Hz) != 0)
return -1;
return AutoRFPath(isTx, f_Hz);
if ((isTx && auto_tx_path) || (!isTx && auto_rx_path))
return AutoRFPath(isTx, f_Hz);
return 0;
}
std::vector<std::string> LMS7_LimeSDR_mini::GetPathNames(bool dir_tx, unsigned chan) const
......@@ -157,7 +158,10 @@ int LMS7_LimeSDR_mini::Calibrate(bool dir_tx, unsigned chan, double bw, unsigned
{
//switch RF path to improve calibration results
uint16_t value = fpga->ReadRegister(0x17);
fpga->WriteRegister(0x17, value^(3<<8));
uint16_t wr_val = value & (~0x3300);
wr_val |= lms_list[0]->GetBandTRF() == LMS_PATH_TX2 ? 0x1000 : 0x2000;
wr_val |= lms_list[0]->GetPathRFE() == LMS7002M::PathRFE::PATH_RFE_LNAW ? 0x100 : 0x200;
fpga->WriteRegister(0x17, wr_val);
int ret = LMS7_Device::Calibrate(dir_tx, chan, bw, flags);
fpga->WriteRegister(0x17, value);
return ret;
......@@ -244,6 +248,7 @@ int LMS7_LimeSDR_mini::SetRate(double f_Hz, int oversample)
double fpgaRxPLL = lms->GetReferenceClk_TSP(lime::LMS7002M::Rx);
if (fpga->SetInterfaceFreq(fpgaTxPLL, fpgaRxPLL, 0) != 0)
return -1;
lms->ResetLogicregisters();
return 0;
}
......
......@@ -9,6 +9,7 @@
#include "Logger.h"
#include "LMS64CProtocol.h"
#include "Streamer.h"
#include "../limeRFE/RFE_Device.h"
using namespace std;
......@@ -281,11 +282,6 @@ API_EXPORT int CALL_CONV LMS_GPIODirWrite(lms_device_t *dev, const uint8_t* buff
return conn ? conn->GPIODirWrite(buffer,len) : -1;
}
API_EXPORT int CALL_CONV LMS_EnableCalibCache(lms_device_t *dev, bool enable)
{
return LMS_EnableCache(dev, enable);
}
API_EXPORT int CALL_CONV LMS_EnableCache(lms_device_t *dev, bool enable)
{
lime::LMS7_Device* lms = CheckDevice(dev);
......@@ -316,7 +312,14 @@ API_EXPORT int CALL_CONV LMS_GetNumChannels(lms_device_t * device, bool dir_tx)
API_EXPORT int CALL_CONV LMS_SetLOFrequency(lms_device_t *device, bool dir_tx, size_t chan, float_type frequency)
{
lime::LMS7_Device* lms = CheckDevice(device, chan);
return lms ? lms->SetFrequency(dir_tx, chan,frequency) : -1;
int ret = lms ? lms->SetFrequency(dir_tx, chan,frequency) : -1;
#ifdef LIMERFE
auto rfe = lms->GetLimeRFE();
if (rfe && ret == 0)
rfe->SetFrequency(dir_tx, chan, frequency);
#endif
return ret;
}
API_EXPORT int CALL_CONV LMS_GetLOFrequency(lms_device_t *device, bool dir_tx, size_t chan, float_type *frequency)
......@@ -479,13 +482,18 @@ API_EXPORT int CALL_CONV LMS_Calibrate(lms_device_t *device, bool dir_tx, size_t
if (!lms)
return -1;
if (lms->ReadLMSReg(0x2F) == 0x3840)
{
lime::error("Calibration not supported");
return -1;
}
#ifdef LIMERFE
auto rfe = lms->GetLimeRFE();
if (rfe)
rfe->OnCalibrate(chan, false);
#endif
int ret = lms->Calibrate(dir_tx, chan, bw, flags);
return lms->Calibrate(dir_tx, chan, bw, flags);
#ifdef LIMERFE
if (rfe)
rfe->OnCalibrate(chan, true);
#endif
return ret;
}
API_EXPORT int CALL_CONV LMS_LoadConfig(lms_device_t *device, const char *filename)
......@@ -722,6 +730,7 @@ API_EXPORT int CALL_CONV LMS_SetupStream(lms_device_t *device, lms_stream_t *str
config.bufferLength = stream->fifoSize;
config.channelID = stream->channel;
config.performanceLatency = stream->throughputVsLatency;
config.align = stream->channel & LMS_ALIGN_CH_PHASE;
switch(stream->dataFmt)
{
case lms_stream_t::LMS_FMT_F32:
......@@ -960,4 +969,4 @@ extern "C" API_EXPORT int CALL_CONV LMS_TransferLMS64C(lms_device_t *dev, int cm
}
return LMS_SUCCESS;
}
}
\ No newline at end of file
......@@ -70,7 +70,7 @@ LMS7_Device* LMS7_Device::CreateDevice(const lime::ConnectionHandle& handle, LMS
return device;
}
LMS7_Device::LMS7_Device(LMS7_Device *obj) : connection(nullptr), lms_chip_id(0),fpga(nullptr)
LMS7_Device::LMS7_Device(LMS7_Device *obj) : connection(nullptr), lms_chip_id(0),fpga(nullptr), limeRFE(nullptr)
{
if (obj != nullptr)
{
......@@ -126,6 +126,11 @@ int LMS7_Device::ConfigureGFIR(bool tx, unsigned ch, bool enabled, double bandwi
int L;
int div = 1;
if (tx)
tx_channels[ch].gfir_bw = enabled ? bandwidth : -1;
else
rx_channels[ch].gfir_bw = enabled ? bandwidth : -1;
bandwidth /= 1e6;
lime::LMS7002M* lms = SelectChannel(ch);
......@@ -159,7 +164,6 @@ int LMS7_Device::ConfigureGFIR(bool tx, unsigned ch, bool enabled, double bandwi
L = div > 8 ? 8 : div;
div -= 1;
w *=0.95;
w2 = w*1.1;
if (w2 > 0.495)
{
......@@ -341,6 +345,12 @@ int LMS7_Device::SetRate(double f_Hz, int oversample)
if (tx_channels[i].cF_offset_nco != 0)
SetNCOFreq(true, i, 0, -tx_channels[i].cF_offset_nco);
auto gfir_bw = tx_channels[i].gfir_bw;
if (gfir_bw > 0)
ConfigureGFIR(true, i, true, gfir_bw);
gfir_bw = rx_channels[i].gfir_bw;
if (gfir_bw > 0)
ConfigureGFIR(false, i, true, gfir_bw);
}
return 0;
......@@ -600,9 +610,13 @@ int LMS7_Device::SetRate(bool tx, double f_Hz, unsigned oversample)
if (tx_channels[i].cF_offset_nco != 0)
SetNCOFreq(true, i, 0, -tx_channels[i].cF_offset_nco);
auto gfir_bw = tx ? tx_channels[i].gfir_bw : rx_channels[i].gfir_bw;
if (gfir_bw > 0)
ConfigureGFIR(tx, i, true, gfir_bw);
}
return 0;
return 0;
}
int LMS7_Device::SetRate(unsigned ch, double rxRate, double txRate, unsigned oversample)
......@@ -636,9 +650,13 @@ int LMS7_Device::SetFPGAInterfaceFreq(int interp, int dec, double txPhase, doubl
}
if (std::fabs(rxPhase) > 360 || std::fabs(txPhase) > 360)
return fpga->SetInterfaceFreq(fpgaTxPLL, fpgaRxPLL, lms_chip_id);
else
return fpga->SetInterfaceFreq(fpgaTxPLL,fpgaRxPLL, txPhase, rxPhase, lms_chip_id);
{
if (fpga->SetInterfaceFreq(fpgaTxPLL, fpgaRxPLL, lms_chip_id) != 0)
return -1;
}
else if (fpga->SetInterfaceFreq(fpgaTxPLL,fpgaRxPLL, txPhase, rxPhase, lms_chip_id) != 0)
return -1;
return lms->ResetLogicregisters();
}
double LMS7_Device::GetRate(bool tx, unsigned chan, double *rf_rate_Hz) const
......@@ -779,6 +797,11 @@ int LMS7_Device::SetGFIRCoef(bool tx, unsigned chan, lms_gfir_t filt, const doub
int div = 1;
int ret = 0;
if (tx)
tx_channels[chan].gfir_bw = -1.0;
else
rx_channels[chan].gfir_bw = -1.0;
if (count > 120)
{
lime::ReportError(ERANGE, "Max number of coefficients for GFIR3 is 120 and for GFIR1(2) - 40");
......@@ -791,23 +814,18 @@ int LMS7_Device::SetGFIRCoef(bool tx, unsigned chan, lms_gfir_t filt, const doub
}
lime::LMS7002M* lms = SelectChannel(chan);
double interface_Hz;
int ratio;
if (tx)
{
ratio = lms->Get_SPI_Reg_bits(LMS7param(HBI_OVR_TXTSP));
interface_Hz = lms->GetReferenceClk_TSP(lime::LMS7002M::Tx);
}
else
{
ratio = lms->Get_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP));
interface_Hz = lms->GetReferenceClk_TSP(lime::LMS7002M::Rx);
}
if (ratio == 7)
interface_Hz /= 2;
else
if (ratio != 7)
div = (2<<(ratio));
if ((div > 8) || (count == 120) || (count == 40 && filt != LMS_GFIR3))
......@@ -1340,7 +1358,7 @@ int LMS7_Device::Init()
{0x010E, 0x0000}, {0x010F, 0x3142}, {0x0110, 0x2B14}, {0x0111, 0x0000},
{0x0112, 0x000C}, {0x0113, 0x03C2}, {0x0114, 0x01F0}, {0x0115, 0x000D},
{0x0118, 0x418C}, {0x0119, 0x5292}, {0x011A, 0x3001}, {0x011C, 0x8941},
{0x011D, 0x0000}, {0x011E, 0x0984}, {0x0120, 0xE680}, {0x0121, 0x3638},
{0x011D, 0x0000}, {0x011E, 0x0984}, {0x0120, 0xE6C0}, {0x0121, 0x3638},
{0x0122, 0x0514}, {0x0123, 0x200F}, {0x0200, 0x00E1}, {0x0208, 0x017B},
{0x020B, 0x4000}, {0x020C, 0x8000}, {0x0400, 0x8081}, {0x0404, 0x0006},
{0x040B, 0x1020}, {0x040C, 0x00FB}
......@@ -1499,10 +1517,20 @@ int LMS7_Device::SetClockFreq(unsigned clk_id, double freq, int channel)
case LMS_CLOCK_SXR:
if (freq <= 0)
return lms->TuneVCO(lime::LMS7002M::VCO_SXR);
if (channel != -1)
{
rx_channels[channel].cF_offset_nco = 0.0;
rx_channels[channel].freq = freq;
}
return lms->SetFrequencySX(false, freq);
case LMS_CLOCK_SXT:
if (freq <= 0)
return lms->TuneVCO(lime::LMS7002M::VCO_SXT);
if (channel != -1)
{
tx_channels[channel].cF_offset_nco = 0.0;
tx_channels[channel].freq = freq;
}
return lms->SetFrequencySX(true, freq);
case LMS_CLOCK_CGEN:
{
......@@ -1576,35 +1604,29 @@ lms_dev_info_t* LMS7_Device::GetInfo()
return &devInfo;
}
int LMS7_Device::Synchronize(bool toChip) const
int LMS7_Device::Synchronize(bool toChip)
{
int ret=0;
for (unsigned i = 0; i < lms_list.size(); i++)
{
lime::LMS7002M* lms = lms_list[i];
int ret=0;
if (toChip)
{
if (lms->UploadAll()==0)
{
int tmp = lms_chip_id;
lms_chip_id = i;
lms->Modify_SPI_Reg_bits(LMS7param(MAC),1,true);
int interp = lms->Get_SPI_Reg_bits(LMS7param(HBI_OVR_TXTSP));
int decim = lms->Get_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP));
double fpgaTxPLL = lms->GetReferenceClk_TSP(lime::LMS7002M::Tx);
if (interp != 7)
fpgaTxPLL /= pow(2.0, interp);
double fpgaRxPLL = lms->GetReferenceClk_TSP(lime::LMS7002M::Rx);
if (decim != 7)
fpgaRxPLL /= pow(2.0, decim);
lms->SetInterfaceFrequency(lms->GetFrequencyCGEN(), interp, decim);
ret = fpga ? fpga->SetInterfaceFreq(fpgaTxPLL,fpgaRxPLL, i) : 0;
ret = SetFPGAInterfaceFreq(-1, -1, -1000, -1000);
lms_chip_id = tmp;
}
}
else
ret = lms->DownloadAll();
if (ret != 0)
return ret;
break;
}
return 0;
return ret;
}
int LMS7_Device::SetLogCallback(void(*func)(const char* cstr, const unsigned int type))
......@@ -1633,17 +1655,20 @@ int LMS7_Device::LoadConfig(const char *filename, int ind)
lime::LMS7002M* lms = lms_list.at(ind == -1 ? lms_chip_id : ind);
if (lms->LoadConfig(filename)==0)
{
lms->Modify_SPI_Reg_bits(LMS7param(MAC),1,true);
int interp = lms->Get_SPI_Reg_bits(LMS7param(HBI_OVR_TXTSP));
int decim = lms->Get_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP));
double fpgaTxPLL = lms->GetReferenceClk_TSP(lime::LMS7002M::Tx);
if (interp != 7)
fpgaTxPLL /= pow(2.0, interp);
double fpgaRxPLL = lms->GetReferenceClk_TSP(lime::LMS7002M::Rx);
if (decim != 7)
fpgaRxPLL /= pow(2.0, decim);
lms->SetInterfaceFrequency(lms->GetFrequencyCGEN(), interp, decim);
return fpga ?fpga->SetInterfaceFreq(fpgaTxPLL,fpgaRxPLL, lms_chip_id) : 0;
//tune PLLs as saved VCO settings may not work
lms->Modify_SPI_Reg_bits(LMS7param(MAC), 1);
if (!lms->Get_SPI_Reg_bits(LMS7param(PD_VCO)))
lms->SetFrequencySX(false, lms->GetFrequencySX(false));
lms->Modify_SPI_Reg_bits(LMS7param(MAC), 2);
if (!lms->Get_SPI_Reg_bits(LMS7param(PD_VCO)))
lms->SetFrequencySX(true, lms->GetFrequencySX(true));
if (!lms->Get_SPI_Reg_bits(LMS7param(PD_VCO_CGEN)))
{
lms->TuneVCO(lime::LMS7002M::VCO_CGEN);
lms->Modify_SPI_Reg_bits(LMS7param(MAC),1,true);
return SetFPGAInterfaceFreq(-1, -1, -1000, -1000);
}
return 0;
}
return -1;
}