Protocol adjustment + exposing settings for DFT

This commit is contained in:
Jan Käberich 2020-11-07 13:22:10 +01:00
parent ce475fa042
commit a2389fca13
19 changed files with 314 additions and 205 deletions

View File

@ -111,22 +111,40 @@ uint8_t *USBInBuffer::getBuffer() const
return buffer; return buffer;
} }
static Protocol::DeviceLimits limits = { static constexpr Protocol::DeviceInfo defaultInfo = {
.minFreq = 0, .ProtocolVersion = Protocol::Version,
.maxFreq = 6000000000, .FW_major = 0,
.minIFBW = 10, .FW_minor = 0,
.maxIFBW = 50000, .FW_patch = 0,
.maxPoints = 4501, .HW_Revision = '0',
.cdbm_min = -4000, .extRefAvailable = 0,
.cdbm_max = 0, .extRefInUse = 0,
.minRBW = 10, .FPGA_configured = 0,
.maxRBW = 100000, .source_locked = 0,
.LO1_locked = 0,
.ADC_overload = 0,
.temp_source = 0,
.temp_LO1 = 0,
.temp_MCU = 0,
.limits_minFreq = 0,
.limits_maxFreq = 6000000000,
.limits_minIFBW = 10,
.limits_maxIFBW = 50000,
.limits_maxPoints = 4501,
.limits_cdbm_min = -4000,
.limits_cdbm_max = 0,
.limits_minRBW = 15,
.limits_maxRBW = 100000,
}; };
Protocol::DeviceInfo Device::lastInfo = defaultInfo;
Device::Device(QString serial) Device::Device(QString serial)
{ {
qDebug() << "Starting device connection..."; qDebug() << "Starting device connection...";
lastInfo = defaultInfo;
m_handle = nullptr; m_handle = nullptr;
lastInfoValid = false; lastInfoValid = false;
libusb_init(&m_context); libusb_init(&m_context);
@ -182,8 +200,8 @@ Device::Device(QString serial)
connect(this, &Device::receivedAnswer, this, &Device::transmissionFinished, Qt::QueuedConnection); connect(this, &Device::receivedAnswer, this, &Device::transmissionFinished, Qt::QueuedConnection);
transmissionTimer.setSingleShot(true); transmissionTimer.setSingleShot(true);
transmissionActive = false; transmissionActive = false;
// got a new connection, request limits // got a new connection, request info
SendCommandWithoutPayload(Protocol::PacketType::RequestDeviceLimits); SendCommandWithoutPayload(Protocol::PacketType::RequestDeviceInfo);
} }
Device::~Device() Device::~Device()
@ -282,11 +300,6 @@ std::set<QString> Device::GetDevices()
return serials; return serials;
} }
Protocol::DeviceLimits Device::Limits()
{
return limits;
}
void Device::USBHandleThread() void Device::USBHandleThread()
{ {
qInfo() << "Receive thread started" << flush; qInfo() << "Receive thread started" << flush;
@ -366,7 +379,7 @@ void Device::SearchDevices(std::function<bool (libusb_device_handle *, QString)>
libusb_free_device_list(devList, 1); libusb_free_device_list(devList, 1);
} }
Protocol::DeviceInfo Device::getLastInfo() const const Protocol::DeviceInfo &Device::Info()
{ {
return lastInfo; return lastInfo;
} }
@ -379,8 +392,8 @@ QString Device::getLastDeviceInfoString()
} else { } else {
ret.append("HW Rev."); ret.append("HW Rev.");
ret.append(lastInfo.HW_Revision); ret.append(lastInfo.HW_Revision);
ret.append(" FW "+QString::number(lastInfo.FW_major)+"."+QString::number(lastInfo.FW_minor).rightJustified(2, '0')); ret.append(" FW "+QString::number(lastInfo.FW_major)+"."+QString::number(lastInfo.FW_minor)+"."+QString::number(lastInfo.FW_patch));
ret.append(" Temps: "+QString::number(lastInfo.temperatures.source)+"°C/"+QString::number(lastInfo.temperatures.LO1)+"°C/"+QString::number(lastInfo.temperatures.MCU)+"°C"); ret.append(" Temps: "+QString::number(lastInfo.temp_source)+"°C/"+QString::number(lastInfo.temp_LO1)+"°C/"+QString::number(lastInfo.temp_MCU)+"°C");
ret.append(" Reference:"); ret.append(" Reference:");
if(lastInfo.extRefInUse) { if(lastInfo.extRefInUse) {
ret.append("External"); ret.append("External");
@ -412,7 +425,13 @@ void Device::ReceivedData()
emit SpectrumResultReceived(packet.spectrumResult); emit SpectrumResultReceived(packet.spectrumResult);
break; break;
case Protocol::PacketType::DeviceInfo: case Protocol::PacketType::DeviceInfo:
lastInfo = packet.info; if(packet.info.ProtocolVersion != Protocol::Version) {
if(!lastInfoValid) {
emit NeedsFirmwareUpdate(packet.info.ProtocolVersion, Protocol::Version);
}
} else {
lastInfo = packet.info;
}
lastInfoValid = true; lastInfoValid = true;
emit DeviceInfoUpdated(); emit DeviceInfoUpdated();
break; break;
@ -424,10 +443,7 @@ void Device::ReceivedData()
emit NackReceived(); emit NackReceived();
emit receivedAnswer(TransmissionResult::Nack); emit receivedAnswer(TransmissionResult::Nack);
break; break;
case Protocol::PacketType::DeviceLimits: default:
limits = packet.limits;
break;
default:
break; break;
} }
} while (handled_len > 0); } while (handled_len > 0);

View File

@ -65,12 +65,11 @@ public:
bool SendFirmwareChunk(Protocol::FirmwarePacket &fw); bool SendFirmwareChunk(Protocol::FirmwarePacket &fw);
bool SendCommandWithoutPayload(Protocol::PacketType type); bool SendCommandWithoutPayload(Protocol::PacketType type);
QString serial() const; QString serial() const;
Protocol::DeviceInfo getLastInfo() const; static const Protocol::DeviceInfo& Info();
QString getLastDeviceInfoString(); QString getLastDeviceInfoString();
// Returns serial numbers of all connected devices // Returns serial numbers of all connected devices
static std::set<QString> GetDevices(); static std::set<QString> GetDevices();
static Protocol::DeviceLimits Limits();
signals: signals:
void DatapointReceived(Protocol::Datapoint); void DatapointReceived(Protocol::Datapoint);
void ManualStatusReceived(Protocol::ManualStatus); void ManualStatusReceived(Protocol::ManualStatus);
@ -80,6 +79,7 @@ signals:
void AckReceived(); void AckReceived();
void NackReceived(); void NackReceived();
void LogLineReceived(QString line); void LogLineReceived(QString line);
void NeedsFirmwareUpdate(int usedProtocol, int requiredProtocol);
private slots: private slots:
void ReceivedData(); void ReceivedData();
void ReceivedLog(); void ReceivedLog();
@ -119,7 +119,7 @@ private:
QString m_serial; QString m_serial;
bool m_connected; bool m_connected;
std::thread *m_receiveThread; std::thread *m_receiveThread;
Protocol::DeviceInfo lastInfo; static Protocol::DeviceInfo lastInfo;
bool lastInfoValid; bool lastInfoValid;
}; };

View File

@ -10,10 +10,10 @@ SignalgeneratorWidget::SignalgeneratorWidget(QWidget *parent) :
ui->frequency->setPrefixes(" kMG"); ui->frequency->setPrefixes(" kMG");
connect(ui->frequency, &SIUnitEdit::valueChanged, [=](double newval) { connect(ui->frequency, &SIUnitEdit::valueChanged, [=](double newval) {
if(newval < Device::Limits().minFreq) { if(newval < Device::Info().limits_minFreq) {
newval = Device::Limits().minFreq; newval = Device::Info().limits_minFreq;
} else if (newval > Device::Limits().maxFreq) { } else if (newval > Device::Info().limits_maxFreq) {
newval = Device::Limits().maxFreq; newval = Device::Info().limits_maxFreq;
} }
ui->frequency->setValueQuiet(newval); ui->frequency->setValueQuiet(newval);
emit SettingsChanged(); emit SettingsChanged();

View File

@ -251,6 +251,13 @@ void SpectrumAnalyzer::SettingsChanged()
settings.pointNum = settings.f_stop - settings.f_start + 1; settings.pointNum = settings.f_stop - settings.f_start + 1;
} }
auto pref = Preferences::getInstance();
if(pref.Acquisition.useDFTinSAmode && settings.RBW <= pref.Acquisition.RBWLimitForDFT) {
settings.UseDFT = 1;
} else {
settings.UseDFT = 0;
}
if(window->getDevice()) { if(window->getDevice()) {
window->getDevice()->Configure(settings); window->getDevice()->Configure(settings);
} }
@ -311,8 +318,8 @@ void SpectrumAnalyzer::SetSpan(double span)
void SpectrumAnalyzer::SetFullSpan() void SpectrumAnalyzer::SetFullSpan()
{ {
settings.f_start = Device::Limits().minFreq; settings.f_start = Device::Info().limits_minFreq;
settings.f_stop = Device::Limits().maxFreq; settings.f_stop = Device::Info().limits_maxFreq;
ConstrainAndUpdateFrequencies(); ConstrainAndUpdateFrequencies();
} }
@ -340,10 +347,10 @@ void SpectrumAnalyzer::SpanZoomOut()
void SpectrumAnalyzer::SetRBW(double bandwidth) void SpectrumAnalyzer::SetRBW(double bandwidth)
{ {
if(bandwidth > Device::Limits().maxRBW) { if(bandwidth > Device::Info().limits_maxRBW) {
bandwidth = Device::Limits().maxRBW; bandwidth = Device::Info().limits_maxRBW;
} else if(bandwidth < Device::Limits().minRBW) { } else if(bandwidth < Device::Info().limits_minRBW) {
bandwidth = Device::Limits().minRBW; bandwidth = Device::Info().limits_minRBW;
} }
settings.RBW = bandwidth; settings.RBW = bandwidth;
emit RBWChanged(settings.RBW); emit RBWChanged(settings.RBW);
@ -365,14 +372,14 @@ void SpectrumAnalyzer::UpdateAverageCount()
void SpectrumAnalyzer::ConstrainAndUpdateFrequencies() void SpectrumAnalyzer::ConstrainAndUpdateFrequencies()
{ {
if(settings.f_stop > Device::Limits().maxFreq) { if(settings.f_stop > Device::Info().limits_maxFreq) {
settings.f_stop = Device::Limits().maxFreq; settings.f_stop = Device::Info().limits_maxFreq;
} }
if(settings.f_start > settings.f_stop) { if(settings.f_start > settings.f_stop) {
settings.f_start = settings.f_stop; settings.f_start = settings.f_stop;
} }
if(settings.f_start < Device::Limits().minFreq) { if(settings.f_start < Device::Info().limits_minFreq) {
settings.f_start = Device::Limits().minFreq; settings.f_start = Device::Info().limits_minFreq;
} }
emit startFreqChanged(settings.f_start); emit startFreqChanged(settings.f_start);
emit stopFreqChanged(settings.f_stop); emit stopFreqChanged(settings.f_stop);

View File

@ -217,7 +217,11 @@ VNA::VNA(AppWindow *window)
points->setSingleStep(100); points->setSingleStep(100);
points->setToolTip("Points/sweep"); points->setToolTip("Points/sweep");
connect(points, qOverload<int>(&QSpinBox::valueChanged), this, &VNA::SetPoints); connect(points, qOverload<int>(&QSpinBox::valueChanged), this, &VNA::SetPoints);
connect(this, &VNA::pointsChanged, points, &QSpinBox::setValue); connect(this, &VNA::pointsChanged, [=](int p) {
points->blockSignals(true);
points->setValue(p);
points->blockSignals(false);
});
tb_acq->addWidget(new QLabel("Points:")); tb_acq->addWidget(new QLabel("Points:"));
tb_acq->addWidget(points); tb_acq->addWidget(points);
@ -499,8 +503,8 @@ void VNA::SetSpan(double span)
void VNA::SetFullSpan() void VNA::SetFullSpan()
{ {
settings.f_start = Device::Limits().minFreq; settings.f_start = Device::Info().limits_minFreq;
settings.f_stop = Device::Limits().maxFreq; settings.f_stop = Device::Info().limits_maxFreq;
ConstrainAndUpdateFrequencies(); ConstrainAndUpdateFrequencies();
} }
@ -528,10 +532,10 @@ void VNA::SpanZoomOut()
void VNA::SetSourceLevel(double level) void VNA::SetSourceLevel(double level)
{ {
if(level > Device::Limits().cdbm_max / 100.0) { if(level > Device::Info().limits_cdbm_max / 100.0) {
level = Device::Limits().cdbm_max / 100.0; level = Device::Info().limits_cdbm_max / 100.0;
} else if(level < Device::Limits().cdbm_min / 100.0) { } else if(level < Device::Info().limits_cdbm_min / 100.0) {
level = Device::Limits().cdbm_min / 100.0; level = Device::Info().limits_cdbm_min / 100.0;
} }
emit sourceLevelChanged(level); emit sourceLevelChanged(level);
settings.cdbm_excitation = level * 100; settings.cdbm_excitation = level * 100;
@ -540,10 +544,10 @@ void VNA::SetSourceLevel(double level)
void VNA::SetPoints(unsigned int points) void VNA::SetPoints(unsigned int points)
{ {
if (points < 2) { if(points > Device::Info().limits_maxPoints) {
points = Device::Info().limits_maxPoints;
} else if (points < 2) {
points = 2; points = 2;
} else if(points > Device::Limits().maxPoints) {
points = Device::Limits().maxPoints;
} }
emit pointsChanged(points); emit pointsChanged(points);
settings.points = points; settings.points = points;
@ -552,10 +556,10 @@ void VNA::SetPoints(unsigned int points)
void VNA::SetIFBandwidth(double bandwidth) void VNA::SetIFBandwidth(double bandwidth)
{ {
if(bandwidth > Device::Limits().maxIFBW) { if(bandwidth > Device::Info().limits_maxIFBW) {
bandwidth = Device::Limits().maxIFBW; bandwidth = Device::Info().limits_maxIFBW;
} else if(bandwidth < Device::Limits().minIFBW) { } else if(bandwidth < Device::Info().limits_minIFBW) {
bandwidth = Device::Limits().minIFBW; bandwidth = Device::Info().limits_minIFBW;
} }
settings.if_bandwidth = bandwidth; settings.if_bandwidth = bandwidth;
emit IFBandwidthChanged(bandwidth); emit IFBandwidthChanged(bandwidth);
@ -651,14 +655,14 @@ void VNA::StartCalibrationMeasurement(Calibration::Measurement m)
void VNA::ConstrainAndUpdateFrequencies() void VNA::ConstrainAndUpdateFrequencies()
{ {
if(settings.f_stop > Device::Limits().maxFreq) { if(settings.f_stop > Device::Info().limits_maxFreq) {
settings.f_stop = Device::Limits().maxFreq; settings.f_stop = Device::Info().limits_maxFreq;
} }
if(settings.f_start > settings.f_stop) { if(settings.f_start > settings.f_stop) {
settings.f_start = settings.f_stop; settings.f_start = settings.f_stop;
} }
if(settings.f_start < Device::Limits().minFreq) { if(settings.f_start < Device::Info().limits_minFreq) {
settings.f_start = Device::Limits().minFreq; settings.f_start = Device::Info().limits_minFreq;
} }
emit startFreqChanged(settings.f_start); emit startFreqChanged(settings.f_start);
emit stopFreqChanged(settings.f_stop); emit stopFreqChanged(settings.f_stop);

View File

@ -95,14 +95,7 @@ AppWindow::AppWindow(QWidget *parent)
connect(ui->actionDisconnect, &QAction::triggered, this, &AppWindow::DisconnectDevice); connect(ui->actionDisconnect, &QAction::triggered, this, &AppWindow::DisconnectDevice);
connect(ui->actionQuit, &QAction::triggered, this, &AppWindow::close); connect(ui->actionQuit, &QAction::triggered, this, &AppWindow::close);
connect(ui->actionManual_Control, &QAction::triggered, this, &AppWindow::StartManualControl); connect(ui->actionManual_Control, &QAction::triggered, this, &AppWindow::StartManualControl);
connect(ui->actionFirmware_Update, &QAction::triggered, [=](){ connect(ui->actionFirmware_Update, &QAction::triggered, this, &AppWindow::StartFirmwareUpdateDialog);
if(device) {
auto fw_update = new FirmwareUpdateDialog(device);
connect(fw_update, &FirmwareUpdateDialog::DeviceRebooting, this, &AppWindow::DisconnectDevice);
connect(fw_update, &FirmwareUpdateDialog::DeviceRebooted, this, &AppWindow::ConnectToDevice);
fw_update->exec();
}
});
connect(ui->actionPreferences, &QAction::triggered, [=](){ connect(ui->actionPreferences, &QAction::triggered, [=](){
Preferences::getInstance().edit(); Preferences::getInstance().edit();
// settings might have changed, update necessary stuff // settings might have changed, update necessary stuff
@ -172,6 +165,7 @@ void AppWindow::ConnectToDevice(QString serial)
connect(device, &Device::DeviceInfoUpdated, [this]() { connect(device, &Device::DeviceInfoUpdated, [this]() {
lDeviceInfo.setText(device->getLastDeviceInfoString()); lDeviceInfo.setText(device->getLastDeviceInfoString());
}); });
connect(device, &Device::NeedsFirmwareUpdate, this, &AppWindow::DeviceNeedsUpdate);
ui->actionDisconnect->setEnabled(true); ui->actionDisconnect->setEnabled(true);
ui->actionManual_Control->setEnabled(true); ui->actionManual_Control->setEnabled(true);
ui->actionFirmware_Update->setEnabled(true); ui->actionFirmware_Update->setEnabled(true);
@ -316,6 +310,28 @@ void AppWindow::UpdateReference()
device->SendPacket(p); device->SendPacket(p);
} }
void AppWindow::StartFirmwareUpdateDialog()
{
if(device) {
auto fw_update = new FirmwareUpdateDialog(device);
connect(fw_update, &FirmwareUpdateDialog::DeviceRebooting, this, &AppWindow::DisconnectDevice);
connect(fw_update, &FirmwareUpdateDialog::DeviceRebooted, this, &AppWindow::ConnectToDevice);
fw_update->exec();
}
}
void AppWindow::DeviceNeedsUpdate(int reported, int expected)
{
auto ret = QMessageBox::warning(this, "Warning",
"The device reports are different protocol"
"version (" + QString::number(reported) + ") than expected (" + QString::number(expected) + ").\n"
"A firmware update is strongly suggested. Do you want to update now?",
QMessageBox::Yes | QMessageBox::No);
if (ret == QMessageBox::Yes) {
StartFirmwareUpdateDialog();
}
}
Device *AppWindow::getDevice() const Device *AppWindow::getDevice() const
{ {
return device; return device;

View File

@ -42,7 +42,8 @@ private slots:
int UpdateDeviceList(); int UpdateDeviceList();
void StartManualControl(); void StartManualControl();
void UpdateReference(); void UpdateReference();
void StartFirmwareUpdateDialog();
void DeviceNeedsUpdate(int reported, int expected);
private: private:
void DeviceConnectionLost(); void DeviceConnectionLost();
void CreateToolbars(); void CreateToolbars();

View File

@ -67,6 +67,13 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) :
ui->StartupSARBW->setUnit("Hz"); ui->StartupSARBW->setUnit("Hz");
ui->StartupSARBW->setPrefixes(" k"); ui->StartupSARBW->setPrefixes(" k");
// Acquisition page
ui->AcquisitionDFTlimitRBW->setUnit("Hz");
ui->AcquisitionDFTlimitRBW->setPrefixes(" k");
connect(ui->AcquisitionUseDFT, &QCheckBox::toggled, [=](bool enabled) {
ui->AcquisitionDFTlimitRBW->setEnabled(enabled);
});
// Page selection // Page selection
connect(ui->treeWidget, &QTreeWidget::currentItemChanged, [=](QTreeWidgetItem *current, QTreeWidgetItem *) { connect(ui->treeWidget, &QTreeWidget::currentItemChanged, [=](QTreeWidgetItem *current, QTreeWidgetItem *) {
auto name = current->text(0); auto name = current->text(0);
@ -107,6 +114,8 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) :
p->Startup.SA.signalID = ui->StartupSASignalID->isChecked(); p->Startup.SA.signalID = ui->StartupSASignalID->isChecked();
p->Acquisition.alwaysExciteBothPorts = ui->AcquisitionAlwaysExciteBoth->isChecked(); p->Acquisition.alwaysExciteBothPorts = ui->AcquisitionAlwaysExciteBoth->isChecked();
p->Acquisition.suppressPeaks = ui->AcquisitionSuppressPeaks->isChecked(); p->Acquisition.suppressPeaks = ui->AcquisitionSuppressPeaks->isChecked();
p->Acquisition.useDFTinSAmode = ui->AcquisitionUseDFT->isChecked();
p->Acquisition.RBWLimitForDFT = ui->AcquisitionDFTlimitRBW->value();
p->General.graphColors.background = ui->GeneralGraphBackground->getColor(); p->General.graphColors.background = ui->GeneralGraphBackground->getColor();
p->General.graphColors.axis = ui->GeneralGraphAxis->getColor(); p->General.graphColors.axis = ui->GeneralGraphAxis->getColor();
p->General.graphColors.divisions = ui->GeneralGraphDivisions->getColor(); p->General.graphColors.divisions = ui->GeneralGraphDivisions->getColor();
@ -147,6 +156,8 @@ void PreferencesDialog::setInitialGUIState()
ui->AcquisitionAlwaysExciteBoth->setChecked(p->Acquisition.alwaysExciteBothPorts); ui->AcquisitionAlwaysExciteBoth->setChecked(p->Acquisition.alwaysExciteBothPorts);
ui->AcquisitionSuppressPeaks->setChecked(p->Acquisition.suppressPeaks); ui->AcquisitionSuppressPeaks->setChecked(p->Acquisition.suppressPeaks);
ui->AcquisitionUseDFT->setChecked(p->Acquisition.useDFTinSAmode);
ui->AcquisitionDFTlimitRBW->setValue(p->Acquisition.RBWLimitForDFT);
ui->GeneralGraphBackground->setColor(p->General.graphColors.background); ui->GeneralGraphBackground->setColor(p->General.graphColors.background);
ui->GeneralGraphAxis->setColor(p->General.graphColors.axis); ui->GeneralGraphAxis->setColor(p->General.graphColors.axis);

View File

@ -44,6 +44,8 @@ public:
struct { struct {
bool alwaysExciteBothPorts; bool alwaysExciteBothPorts;
bool suppressPeaks; bool suppressPeaks;
bool useDFTinSAmode;
double RBWLimitForDFT;
} Acquisition; } Acquisition;
struct { struct {
struct { struct {
@ -60,7 +62,7 @@ private:
QString name; QString name;
QVariant def; QVariant def;
}; };
const std::array<SettingDescription, 22> descr = {{ const std::array<SettingDescription, 24> descr = {{
{&Startup.ConnectToFirstDevice, "Startup.ConnectToFirstDevice", true}, {&Startup.ConnectToFirstDevice, "Startup.ConnectToFirstDevice", true},
{&Startup.RememberSweepSettings, "Startup.RememberSweepSettings", false}, {&Startup.RememberSweepSettings, "Startup.RememberSweepSettings", false},
{&Startup.DefaultSweep.start, "Startup.DefaultSweep.start", 1000000.0}, {&Startup.DefaultSweep.start, "Startup.DefaultSweep.start", 1000000.0},
@ -80,6 +82,8 @@ private:
{&Startup.SA.signalID, "Startup.SA.signalID", true}, {&Startup.SA.signalID, "Startup.SA.signalID", true},
{&Acquisition.alwaysExciteBothPorts, "Acquisition.alwaysExciteBothPorts", true}, {&Acquisition.alwaysExciteBothPorts, "Acquisition.alwaysExciteBothPorts", true},
{&Acquisition.suppressPeaks, "Acquisition.suppressPeaks", true}, {&Acquisition.suppressPeaks, "Acquisition.suppressPeaks", true},
{&Acquisition.useDFTinSAmode, "Acquisition.useDFTinSAmode", true},
{&Acquisition.RBWLimitForDFT, "Acquisition.RBWLimitForDFT", 3000.0},
{&General.graphColors.background, "General.graphColors.background", QColor(Qt::black)}, {&General.graphColors.background, "General.graphColors.background", QColor(Qt::black)},
{&General.graphColors.axis, "General.graphColors.axis", QColor(Qt::white)}, {&General.graphColors.axis, "General.graphColors.axis", QColor(Qt::white)},
{&General.graphColors.divisions, "General.graphColors.divisions", QColor(Qt::gray)}, {&General.graphColors.divisions, "General.graphColors.divisions", QColor(Qt::gray)},

View File

@ -73,7 +73,7 @@
</size> </size>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="Startup"> <widget class="QWidget" name="Startup">
<layout class="QHBoxLayout" name="horizontalLayout_4"> <layout class="QHBoxLayout" name="horizontalLayout_4">
@ -454,23 +454,58 @@
<widget class="QWidget" name="Acquisition"> <widget class="QWidget" name="Acquisition">
<layout class="QVBoxLayout" name="verticalLayout_5"> <layout class="QVBoxLayout" name="verticalLayout_5">
<item> <item>
<widget class="QCheckBox" name="AcquisitionAlwaysExciteBoth"> <widget class="QGroupBox" name="groupBox_6">
<property name="toolTip"> <property name="title">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If only S11/S21 or S22/S12 are enabled, faster sweeps are possible by only exciting one port. Checking this option forces the device to always excite both ports even when the measurements from one port will not be used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>Vector Network Analyzer</string>
</property>
<property name="text">
<string>Always perform full 2-port measurement</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QCheckBox" name="AcquisitionAlwaysExciteBoth">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If only S11/S21 or S22/S12 are enabled, faster sweeps are possible by only exciting one port. Checking this option forces the device to always excite both ports even when the measurements from one port will not be used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Always perform full 2-port measurement</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="AcquisitionSuppressPeaks">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Due to limited fractional divider settings, the source and 1.LO PLLs are not able to reach every frequency exactly. At some specific frequencies this causes the final IF to shift. At these frequencies there will be a positive or negative peak in the trace measurement that is not actually there.&lt;br/&gt;&lt;br/&gt;Checking this option shifts the 2.LO for points where this could be an issue. This will remove the peaks but slows down the sweep slightly.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Suppress invalid peaks</string>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="AcquisitionSuppressPeaks"> <widget class="QGroupBox" name="groupBox_7">
<property name="toolTip"> <property name="title">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Due to limited fractional divider settings, the source and 1.LO PLLs are not able to reach every frequency exactly. At some specific frequencies this causes the final IF to shift. At these frequencies there will be a positive or negative peak in the trace measurement that is not actually there.&lt;br/&gt;&lt;br/&gt;Checking this option shifts the 2.LO for points where this could be an issue. This will remove the peaks but slows down the sweep slightly.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>Spectrum Analyzer</string>
</property>
<property name="text">
<string>Suppress invalid peaks</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<layout class="QFormLayout" name="formLayout_5">
<item row="0" column="0">
<widget class="QCheckBox" name="AcquisitionUseDFT">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Normally, the spectrum analyzer mode tunes the LO for each point and measures the final IF only at one frequency. When this option is enabled, a DFT of the final IF is calculated instead which covers multiple frequencies with one measurement.&lt;/p&gt;&lt;p&gt;This can speed up the measurement at low RBWs significantly.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Use DFT when RBW is below</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SIUnitEdit" name="AcquisitionDFTlimitRBW"/>
</item>
</layout>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>

View File

@ -189,6 +189,8 @@
<listOptionValue builtIn="false" value="FW_MAJOR=0"/> <listOptionValue builtIn="false" value="FW_MAJOR=0"/>
<listOptionValue builtIn="false" value="FW_PATCH=0"/>
<listOptionValue builtIn="false" value="FW_MINOR=1"/> <listOptionValue builtIn="false" value="FW_MINOR=1"/>
<listOptionValue builtIn="false" value="USE_FULL_LL_DRIVER"/> <listOptionValue builtIn="false" value="USE_FULL_LL_DRIVER"/>

View File

@ -155,10 +155,10 @@ void App_Start() {
SA::Setup(recv_packet.spectrumSettings); SA::Setup(recv_packet.spectrumSettings);
Communication::SendWithoutPayload(Protocol::PacketType::Ack); Communication::SendWithoutPayload(Protocol::PacketType::Ack);
break; break;
case Protocol::PacketType::RequestDeviceLimits: case Protocol::PacketType::RequestDeviceInfo:
Protocol::PacketInfo p; Protocol::PacketInfo p;
p.type = Protocol::PacketType::DeviceLimits; p.type = Protocol::PacketType::DeviceInfo;
p.limits = HW::Limits; HW::fillDeviceInfo(&p.info);
Communication::Send(p); Communication::Send(p);
break; break;
#ifdef HAS_FLASH #ifdef HAS_FLASH

View File

@ -238,35 +238,58 @@ static int16_t EncodeGeneratorSettings(Protocol::GeneratorSettings d, uint8_t *b
static Protocol::DeviceInfo DecodeDeviceInfo(uint8_t *buf) { static Protocol::DeviceInfo DecodeDeviceInfo(uint8_t *buf) {
Protocol::DeviceInfo d; Protocol::DeviceInfo d;
Decoder e(buf); Decoder e(buf);
e.get<uint16_t>(d.FW_major); e.get(d.ProtocolVersion);
e.get<uint16_t>(d.FW_minor); e.get(d.FW_major);
e.get<char>(d.HW_Revision); e.get(d.FW_minor);
e.get(d.FW_patch);
e.get(d.HW_Revision);
d.extRefAvailable = e.getBits(1); d.extRefAvailable = e.getBits(1);
d.extRefInUse = e.getBits(1); d.extRefInUse = e.getBits(1);
d.FPGA_configured = e.getBits(1); d.FPGA_configured = e.getBits(1);
d.source_locked = e.getBits(1); d.source_locked = e.getBits(1);
d.LO1_locked = e.getBits(1); d.LO1_locked = e.getBits(1);
d.ADC_overload = e.getBits(1); d.ADC_overload = e.getBits(1);
e.get<uint8_t>(d.temperatures.source); e.get(d.temp_source);
e.get<uint8_t>(d.temperatures.LO1); e.get(d.temp_LO1);
e.get<uint8_t>(d.temperatures.MCU); e.get(d.temp_MCU);
e.get(d.limits_minFreq);
e.get(d.limits_maxFreq);
e.get(d.limits_minIFBW);
e.get(d.limits_maxIFBW);
e.get(d.limits_maxPoints);
e.get(d.limits_cdbm_min);
e.get(d.limits_cdbm_max);
e.get(d.limits_minRBW);
e.get(d.limits_maxRBW);
return d; return d;
} }
static int16_t EncodeDeviceInfo(Protocol::DeviceInfo d, uint8_t *buf, static int16_t EncodeDeviceInfo(Protocol::DeviceInfo d, uint8_t *buf,
uint16_t bufSize) { uint16_t bufSize) {
d.ProtocolVersion = Protocol::Version;
Encoder e(buf, bufSize); Encoder e(buf, bufSize);
e.add<uint16_t>(d.FW_major); e.add(d.ProtocolVersion);
e.add<uint16_t>(d.FW_minor); e.add(d.FW_major);
e.add<char>(d.HW_Revision); e.add(d.FW_minor);
e.add(d.FW_patch);
e.add(d.HW_Revision);
e.addBits(d.extRefAvailable, 1); e.addBits(d.extRefAvailable, 1);
e.addBits(d.extRefInUse, 1); e.addBits(d.extRefInUse, 1);
e.addBits(d.FPGA_configured, 1); e.addBits(d.FPGA_configured, 1);
e.addBits(d.source_locked, 1); e.addBits(d.source_locked, 1);
e.addBits(d.LO1_locked, 1); e.addBits(d.LO1_locked, 1);
e.addBits(d.ADC_overload, 1); e.addBits(d.ADC_overload, 1);
e.add<uint8_t>(d.temperatures.source); e.add(d.temp_source);
e.add<uint8_t>(d.temperatures.LO1); e.add(d.temp_LO1);
e.add<uint8_t>(d.temperatures.MCU); e.add(d.temp_MCU);
e.add(d.limits_minFreq);
e.add(d.limits_maxFreq);
e.add(d.limits_minIFBW);
e.add(d.limits_maxIFBW);
e.add(d.limits_maxPoints);
e.add(d.limits_cdbm_min);
e.add(d.limits_cdbm_max);
e.add(d.limits_minRBW);
e.add(d.limits_maxRBW);
return e.getSize(); return e.getSize();
} }
@ -378,6 +401,7 @@ static Protocol::SpectrumAnalyzerSettings DecodeSpectrumAnalyzerSettings(uint8_t
d.WindowType = e.getBits(2); d.WindowType = e.getBits(2);
d.SignalID = e.getBits(1); d.SignalID = e.getBits(1);
d.Detector = e.getBits(3); d.Detector = e.getBits(3);
d.UseDFT = e.getBits(1);
return d; return d;
} }
static int16_t EncodeSpectrumAnalyzerSettings(Protocol::SpectrumAnalyzerSettings d, uint8_t *buf, static int16_t EncodeSpectrumAnalyzerSettings(Protocol::SpectrumAnalyzerSettings d, uint8_t *buf,
@ -390,6 +414,7 @@ static int16_t EncodeSpectrumAnalyzerSettings(Protocol::SpectrumAnalyzerSettings
e.addBits(d.WindowType, 2); e.addBits(d.WindowType, 2);
e.addBits(d.SignalID, 1); e.addBits(d.SignalID, 1);
e.addBits(d.Detector, 3); e.addBits(d.Detector, 3);
e.addBits(d.UseDFT, 1);
return e.getSize(); return e.getSize();
} }
@ -412,35 +437,6 @@ static int16_t EncodeSpectrumAnalyzerResult(Protocol::SpectrumAnalyzerResult d,
return e.getSize(); return e.getSize();
} }
static Protocol::DeviceLimits DecodeDeviceLimits(uint8_t *buf) {
Protocol::DeviceLimits d;
Decoder e(buf);
e.get(d.minFreq);
e.get(d.maxFreq);
e.get(d.minIFBW);
e.get(d.maxIFBW);
e.get(d.maxPoints);
e.get(d.cdbm_min);
e.get(d.cdbm_max);
e.get(d.minRBW);
e.get(d.maxRBW);
return d;
}
static int16_t EncodeDeviceLimits(Protocol::DeviceLimits d, uint8_t *buf,
uint16_t bufSize) {
Encoder e(buf, bufSize);
e.add(d.minFreq);
e.add(d.maxFreq);
e.add(d.minIFBW);
e.add(d.maxIFBW);
e.add(d.maxPoints);
e.add(d.cdbm_min);
e.add(d.cdbm_max);
e.add(d.minRBW);
e.add(d.maxRBW);
return e.getSize();
}
static Protocol::FirmwarePacket DecodeFirmwarePacket(uint8_t *buf) { static Protocol::FirmwarePacket DecodeFirmwarePacket(uint8_t *buf) {
Protocol::FirmwarePacket d; Protocol::FirmwarePacket d;
// simple packet format, memcpy is faster than using the decoder // simple packet format, memcpy is faster than using the decoder
@ -545,14 +541,11 @@ uint16_t Protocol::DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info) {
case PacketType::SpectrumAnalyzerResult: case PacketType::SpectrumAnalyzerResult:
info->spectrumResult = DecodeSpectrumAnalyzerResult(&data[4]); info->spectrumResult = DecodeSpectrumAnalyzerResult(&data[4]);
break; break;
case PacketType::DeviceLimits:
info->limits = DecodeDeviceLimits(&data[4]);
break;
case PacketType::Ack: case PacketType::Ack:
case PacketType::PerformFirmwareUpdate: case PacketType::PerformFirmwareUpdate:
case PacketType::ClearFlash: case PacketType::ClearFlash:
case PacketType::Nack: case PacketType::Nack:
case PacketType::RequestDeviceLimits: case PacketType::RequestDeviceInfo:
// no payload, nothing to do // no payload, nothing to do
break; break;
case PacketType::None: case PacketType::None:
@ -595,14 +588,11 @@ uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_
case PacketType::SpectrumAnalyzerResult: case PacketType::SpectrumAnalyzerResult:
payload_size = EncodeSpectrumAnalyzerResult(packet.spectrumResult, &dest[4], destsize - 8); payload_size = EncodeSpectrumAnalyzerResult(packet.spectrumResult, &dest[4], destsize - 8);
break; break;
case PacketType::DeviceLimits:
payload_size = EncodeDeviceLimits(packet.limits, &dest[4], destsize - 8);
break;
case PacketType::Ack: case PacketType::Ack:
case PacketType::PerformFirmwareUpdate: case PacketType::PerformFirmwareUpdate:
case PacketType::ClearFlash: case PacketType::ClearFlash:
case PacketType::Nack: case PacketType::Nack:
case PacketType::RequestDeviceLimits: case PacketType::RequestDeviceInfo:
// no payload, nothing to do // no payload, nothing to do
break; break;
case PacketType::None: case PacketType::None:

View File

@ -4,6 +4,8 @@
namespace Protocol { namespace Protocol {
static constexpr uint16_t Version = 1;
// When changing/adding/removing variables from these structs also adjust the decode/encode functions in Protocol.cpp // When changing/adding/removing variables from these structs also adjust the decode/encode functions in Protocol.cpp
using Datapoint = struct _datapoint { using Datapoint = struct _datapoint {
@ -39,8 +41,10 @@ using GeneratorSettings = struct _generatorSettings {
}; };
using DeviceInfo = struct _deviceInfo { using DeviceInfo = struct _deviceInfo {
uint16_t FW_major; uint16_t ProtocolVersion;
uint16_t FW_minor; uint8_t FW_major;
uint8_t FW_minor;
uint8_t FW_patch;
char HW_Revision; char HW_Revision;
uint8_t extRefAvailable:1; uint8_t extRefAvailable:1;
uint8_t extRefInUse:1; uint8_t extRefInUse:1;
@ -48,11 +52,18 @@ using DeviceInfo = struct _deviceInfo {
uint8_t source_locked:1; uint8_t source_locked:1;
uint8_t LO1_locked:1; uint8_t LO1_locked:1;
uint8_t ADC_overload:1; uint8_t ADC_overload:1;
struct { uint8_t temp_source;
uint8_t source; uint8_t temp_LO1;
uint8_t LO1; uint8_t temp_MCU;
uint8_t MCU; uint64_t limits_minFreq;
} temperatures; uint64_t limits_maxFreq;
uint32_t limits_minIFBW;
uint32_t limits_maxIFBW;
uint16_t limits_maxPoints;
int16_t limits_cdbm_min;
int16_t limits_cdbm_max;
uint32_t limits_minRBW;
uint32_t limits_maxRBW;
}; };
using ManualStatus = struct _manualstatus { using ManualStatus = struct _manualstatus {
@ -107,6 +118,7 @@ using SpectrumAnalyzerSettings = struct _spectrumAnalyzerSettings {
uint8_t WindowType :2; uint8_t WindowType :2;
uint8_t SignalID :1; uint8_t SignalID :1;
uint8_t Detector :3; uint8_t Detector :3;
uint8_t UseDFT :1;
}; };
using SpectrumAnalyzerResult = struct _spectrumAnalyzerResult { using SpectrumAnalyzerResult = struct _spectrumAnalyzerResult {
@ -116,18 +128,6 @@ using SpectrumAnalyzerResult = struct _spectrumAnalyzerResult {
uint16_t pointNum; uint16_t pointNum;
}; };
using DeviceLimits = struct _deviceLimits {
uint64_t minFreq;
uint64_t maxFreq;
uint32_t minIFBW;
uint32_t maxIFBW;
uint16_t maxPoints;
int16_t cdbm_min;
int16_t cdbm_max;
uint32_t minRBW;
uint32_t maxRBW;
};
static constexpr uint16_t FirmwareChunkSize = 256; static constexpr uint16_t FirmwareChunkSize = 256;
using FirmwarePacket = struct _firmwarePacket { using FirmwarePacket = struct _firmwarePacket {
uint32_t address; uint32_t address;
@ -150,8 +150,7 @@ enum class PacketType : uint8_t {
Generator = 12, Generator = 12,
SpectrumAnalyzerSettings = 13, SpectrumAnalyzerSettings = 13,
SpectrumAnalyzerResult = 14, SpectrumAnalyzerResult = 14,
RequestDeviceLimits = 15, RequestDeviceInfo = 15,
DeviceLimits = 16,
}; };
using PacketInfo = struct _packetinfo { using PacketInfo = struct _packetinfo {
@ -167,7 +166,6 @@ using PacketInfo = struct _packetinfo {
ManualStatus status; ManualStatus status;
SpectrumAnalyzerSettings spectrumSettings; SpectrumAnalyzerSettings spectrumSettings;
SpectrumAnalyzerResult spectrumResult; SpectrumAnalyzerResult spectrumResult;
DeviceLimits limits;
}; };
}; };

View File

@ -7,6 +7,7 @@
#include "VNA.hpp" #include "VNA.hpp"
#include "Manual.hpp" #include "Manual.hpp"
#include "SpectrumAnalyzer.hpp" #include "SpectrumAnalyzer.hpp"
#include <cstring>
#define LOG_LEVEL LOG_LEVEL_INFO #define LOG_LEVEL LOG_LEVEL_INFO
#define LOG_MODULE "HW" #define LOG_MODULE "HW"
@ -222,33 +223,39 @@ void HW::SetIdle() {
FPGA::Enable(FPGA::Periphery::PortSwitch, false); FPGA::Enable(FPGA::Periphery::PortSwitch, false);
} }
void HW::fillDeviceInfo(Protocol::DeviceInfo *info) { void HW::fillDeviceInfo(Protocol::DeviceInfo *info, bool updateEvenWhenBusy) {
// read PLL temperatures // copy constant default values
uint8_t tempSource, tempLO; memcpy(info, &HW::Info, sizeof(HW::Info));
GetTemps(&tempSource, &tempLO); if(activeMode == Mode::Idle || updateEvenWhenBusy) {
LOG_INFO("PLL temperatures: %u/%u", tempSource, tempLO); // updating values from FPGA allowed
// Read ADC min/max
auto limits = FPGA::GetADCLimits(); // read PLL temperatures
LOG_INFO("ADC limits: P1: %d/%d P2: %d/%d R: %d/%d", uint8_t tempSource, tempLO;
limits.P1min, limits.P1max, limits.P2min, limits.P2max, GetTemps(&tempSource, &tempLO);
limits.Rmin, limits.Rmax); LOG_INFO("PLL temperatures: %u/%u", tempSource, tempLO);
#define ADC_LIMIT 30000 // Read ADC min/max
if(limits.P1min < -ADC_LIMIT || limits.P1max > ADC_LIMIT auto limits = FPGA::GetADCLimits();
|| limits.P2min < -ADC_LIMIT || limits.P2max > ADC_LIMIT LOG_INFO("ADC limits: P1: %d/%d P2: %d/%d R: %d/%d",
|| limits.Rmin < -ADC_LIMIT || limits.Rmax > ADC_LIMIT) { limits.P1min, limits.P1max, limits.P2min, limits.P2max,
info->ADC_overload = true; limits.Rmin, limits.Rmax);
} else { #define ADC_LIMIT 30000
info->ADC_overload = false; if(limits.P1min < -ADC_LIMIT || limits.P1max > ADC_LIMIT
|| limits.P2min < -ADC_LIMIT || limits.P2max > ADC_LIMIT
|| limits.Rmin < -ADC_LIMIT || limits.Rmax > ADC_LIMIT) {
info->ADC_overload = true;
} else {
info->ADC_overload = false;
}
auto status = FPGA::GetStatus();
info->LO1_locked = (status & (int) FPGA::Interrupt::LO1Unlock) ? 0 : 1;
info->source_locked = (status & (int) FPGA::Interrupt::SourceUnlock) ? 0 : 1;
info->extRefAvailable = Ref::available();
info->extRefInUse = extRefInUse;
info->temp_LO1 = tempLO;
info->temp_source = tempSource;
FPGA::ResetADCLimits();
} }
auto status = FPGA::GetStatus(); info->temp_MCU = STM::getTemperature();
info->LO1_locked = (status & (int) FPGA::Interrupt::LO1Unlock) ? 0 : 1;
info->source_locked = (status & (int) FPGA::Interrupt::SourceUnlock) ? 0 : 1;
info->extRefAvailable = Ref::available();
info->extRefInUse = extRefInUse;
info->temperatures.LO1 = tempLO;
info->temperatures.source = tempSource;
info->temperatures.MCU = STM::getTemperature();
FPGA::ResetADCLimits();
} }
bool HW::Ref::available() { bool HW::Ref::available() {

View File

@ -38,16 +38,30 @@ static_assert(ADCprescaler * ADCSamplerate == FPGA::Clockrate, "ADCSamplerate ca
static constexpr uint16_t DFTphaseInc = 4096 * IF2 / ADCSamplerate; static constexpr uint16_t DFTphaseInc = 4096 * IF2 / ADCSamplerate;
static_assert(DFTphaseInc * ADCSamplerate == 4096 * IF2, "DFT can not be computed for 2.IF"); static_assert(DFTphaseInc * ADCSamplerate == 4096 * IF2, "DFT can not be computed for 2.IF");
static constexpr Protocol::DeviceLimits Limits = { static constexpr Protocol::DeviceInfo Info = {
.minFreq = 0, .ProtocolVersion = Protocol::Version,
.maxFreq = 6000000000, .FW_major = FW_MAJOR,
.minIFBW = ADCSamplerate / MaxSamples, .FW_minor = FW_MINOR,
.maxIFBW = ADCSamplerate / MinSamples, .FW_patch = FW_PATCH,
.maxPoints = FPGA::MaxPoints, .HW_Revision = HW_REVISION,
.cdbm_min = -4000, .extRefAvailable = 0,
.cdbm_max = 0, .extRefInUse = 0,
.minRBW = (uint32_t) (ADCSamplerate * 2.23f / MaxSamples), .FPGA_configured = 0,
.maxRBW = (uint32_t) (ADCSamplerate * 2.23f / MinSamples), .source_locked = 0,
.LO1_locked = 0,
.ADC_overload = 0,
.temp_source = 0,
.temp_LO1 = 0,
.temp_MCU = 0,
.limits_minFreq = 0,
.limits_maxFreq = 6000000000,
.limits_minIFBW = ADCSamplerate / MaxSamples,
.limits_maxIFBW = ADCSamplerate / MinSamples,
.limits_maxPoints = FPGA::MaxPoints,
.limits_cdbm_min = -4000,
.limits_cdbm_max = 0,
.limits_minRBW = (uint32_t) (ADCSamplerate * 2.23f / MaxSamples),
.limits_maxRBW = (uint32_t) (ADCSamplerate * 2.23f / MinSamples),
}; };
enum class Mode { enum class Mode {
@ -63,7 +77,7 @@ void SetIdle();
void Work(); void Work();
bool GetTemps(uint8_t *source, uint8_t *lo); bool GetTemps(uint8_t *source, uint8_t *lo);
void fillDeviceInfo(Protocol::DeviceInfo *info); void fillDeviceInfo(Protocol::DeviceInfo *info, bool updateEvenWhenBusy = false);
namespace Ref { namespace Ref {
bool available(); bool available();
// reference won't change until update is called // reference won't change until update is called

View File

@ -23,7 +23,6 @@ static Protocol::PacketInfo p;
static bool active = false; static bool active = false;
static uint32_t lastLO2; static uint32_t lastLO2;
static uint32_t actualRBW; static uint32_t actualRBW;
static bool usingDFT;
static uint16_t DFTpoints; static uint16_t DFTpoints;
static bool negativeDFT; // if true, a positive frequency shift at input results in a negative shift at the 2.IF. Handle DFT accordingly static bool negativeDFT; // if true, a positive frequency shift at input results in a negative shift at the 2.IF. Handle DFT accordingly
@ -106,7 +105,7 @@ static void StartNextSample() {
Si5351.SetCLK(SiChannel::Port2LO2, LO2freq, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); Si5351.SetCLK(SiChannel::Port2LO2, LO2freq, Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
lastLO2 = LO2freq; lastLO2 = LO2freq;
} }
if (usingDFT) { if (s.UseDFT) {
uint32_t spacing = (s.f_stop - s.f_start) / (points - 1); uint32_t spacing = (s.f_stop - s.f_start) / (points - 1);
uint32_t start = HW::IF2; uint32_t start = HW::IF2;
if(negativeDFT) { if(negativeDFT) {
@ -166,11 +165,16 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
FPGA::Enable(FPGA::Periphery::Port1Mixer); FPGA::Enable(FPGA::Periphery::Port1Mixer);
FPGA::Enable(FPGA::Periphery::Port2Mixer); FPGA::Enable(FPGA::Periphery::Port2Mixer);
// automatically select DFT mode for lower RBWs if (s.UseDFT) {
usingDFT = actualRBW <= 1000; uint32_t spacing = (s.f_stop - s.f_start) / (points - 1);
// The DFT can only look at a small bandwidth otherwise the passband of the final ADC filter is visible in the data
if (usingDFT) { // Limit to about 30kHz
DFTpoints = FPGA::DFTbins; // use full DFT in FPGA uint32_t maxDFTpoints = 30000 / spacing;
// Limit to actual supported number of bins
if(maxDFTpoints > FPGA::DFTbins) {
maxDFTpoints = FPGA::DFTbins;
}
DFTpoints = maxDFTpoints;
FPGA::DisableInterrupt(FPGA::Interrupt::NewData); FPGA::DisableInterrupt(FPGA::Interrupt::NewData);
} else { } else {
DFTpoints = 1; // can only measure one point at a time DFTpoints = 1; // can only measure one point at a time
@ -191,7 +195,7 @@ bool SA::MeasurementDone(const FPGA::SamplingResult &result) {
for(uint16_t i=0;i<DFTpoints;i++) { for(uint16_t i=0;i<DFTpoints;i++) {
float port1, port2; float port1, port2;
if (usingDFT) { if (s.UseDFT) {
// use DFT result // use DFT result
auto dft = FPGA::ReadDFTResult(); auto dft = FPGA::ReadDFTResult();
port1 = dft.P1; port1 = dft.P1;
@ -217,7 +221,7 @@ bool SA::MeasurementDone(const FPGA::SamplingResult &result) {
} }
} }
if (usingDFT) { if (s.UseDFT) {
FPGA::StopDFT(); FPGA::StopDFT();
// will be started again in StartNextSample // will be started again in StartNextSample
} }

View File

@ -264,9 +264,8 @@ void VNA::Work() {
packet.info.FW_major = FW_MAJOR; packet.info.FW_major = FW_MAJOR;
packet.info.FW_minor = FW_MINOR; packet.info.FW_minor = FW_MINOR;
packet.info.HW_Revision = HW_REVISION; packet.info.HW_Revision = HW_REVISION;
HW::fillDeviceInfo(&packet.info); HW::fillDeviceInfo(&packet.info, true);
Communication::Send(packet); Communication::Send(packet);
FPGA::ResetADCLimits();
// Start next sweep // Start next sweep
FPGA::StartSweep(); FPGA::StartSweep();
} }

View File

@ -101,6 +101,7 @@ MCU = $(CPU) -mthumb $(FLOAT-ABI) $(FPU)
C_DEFS = \ C_DEFS = \
-DFW_MAJOR=0 \ -DFW_MAJOR=0 \
-DFW_MINOR=1 \ -DFW_MINOR=1 \
-DFW_PATCH=0 \
-DUSE_FULL_LL_DRIVER \ -DUSE_FULL_LL_DRIVER \
-DHW_REVISION="'B'" \ -DHW_REVISION="'B'" \
-D__weak="__attribute__((weak))" \ -D__weak="__attribute__((weak))" \