Reference control added
This commit is contained in:
parent
6960498fcb
commit
e266d37b96
Binary file not shown.
@ -82,14 +82,11 @@ Device::~Device()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::Configure(Protocol::SweepSettings settings)
|
bool Device::SendPacket(Protocol::PacketInfo packet)
|
||||||
{
|
{
|
||||||
if(m_connected) {
|
if(m_connected) {
|
||||||
unsigned char buffer[128];
|
unsigned char buffer[1024];
|
||||||
Protocol::PacketInfo p;
|
unsigned int length = Protocol::EncodePacket(packet, buffer, sizeof(buffer));
|
||||||
p.type = Protocol::PacketType::SweepSettings;
|
|
||||||
p.settings = settings;
|
|
||||||
unsigned int length = Protocol::EncodePacket(p, buffer, sizeof(buffer));
|
|
||||||
if(!length) {
|
if(!length) {
|
||||||
qCritical() << "Failed to encode packet";
|
qCritical() << "Failed to encode packet";
|
||||||
return false;
|
return false;
|
||||||
@ -107,78 +104,35 @@ bool Device::Configure(Protocol::SweepSettings settings)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Device::Configure(Protocol::SweepSettings settings)
|
||||||
|
{
|
||||||
|
Protocol::PacketInfo p;
|
||||||
|
p.type = Protocol::PacketType::SweepSettings;
|
||||||
|
p.settings = settings;
|
||||||
|
return SendPacket(p);
|
||||||
|
}
|
||||||
|
|
||||||
bool Device::SetManual(Protocol::ManualControl manual)
|
bool Device::SetManual(Protocol::ManualControl manual)
|
||||||
{
|
{
|
||||||
if(m_connected) {
|
Protocol::PacketInfo p;
|
||||||
unsigned char buffer[128];
|
p.type = Protocol::PacketType::ManualControl;
|
||||||
Protocol::PacketInfo p;
|
p.manual = manual;
|
||||||
p.type = Protocol::PacketType::ManualControl;
|
return SendPacket(p);
|
||||||
p.manual = manual;
|
|
||||||
unsigned int length = Protocol::EncodePacket(p, buffer, sizeof(buffer));
|
|
||||||
if(!length) {
|
|
||||||
qCritical() << "Failed to encode packet";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int actual_length;
|
|
||||||
auto ret = libusb_bulk_transfer(m_handle, EP_Data_Out_Addr, buffer, length, &actual_length, 0);
|
|
||||||
if(ret < 0) {
|
|
||||||
qCritical() << "Error sending data: "
|
|
||||||
<< libusb_strerror((libusb_error) ret);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::SendFirmwareChunk(Protocol::FirmwarePacket &fw)
|
bool Device::SendFirmwareChunk(Protocol::FirmwarePacket &fw)
|
||||||
{
|
{
|
||||||
if(m_connected) {
|
Protocol::PacketInfo p;
|
||||||
unsigned char buffer[Protocol::FirmwareChunkSize + 4 + 8];
|
p.type = Protocol::PacketType::FirmwarePacket;
|
||||||
Protocol::PacketInfo p;
|
p.firmware = fw;
|
||||||
p.type = Protocol::PacketType::FirmwarePacket;
|
return SendPacket(p);
|
||||||
p.firmware = fw;
|
|
||||||
unsigned int length = Protocol::EncodePacket(p, buffer, sizeof(buffer));
|
|
||||||
if(!length) {
|
|
||||||
qCritical() << "Failed to encode packet";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int actual_length;
|
|
||||||
auto ret = libusb_bulk_transfer(m_handle, EP_Data_Out_Addr, buffer, length, &actual_length, 0);
|
|
||||||
if(ret < 0) {
|
|
||||||
qCritical() << "Error sending data: "
|
|
||||||
<< libusb_strerror((libusb_error) ret);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::SendCommandWithoutPayload(Protocol::PacketType type)
|
bool Device::SendCommandWithoutPayload(Protocol::PacketType type)
|
||||||
{
|
{
|
||||||
if(m_connected) {
|
Protocol::PacketInfo p;
|
||||||
unsigned char buffer[32];
|
p.type = type;
|
||||||
Protocol::PacketInfo p;
|
return SendPacket(p);
|
||||||
p.type = type;
|
|
||||||
unsigned int length = Protocol::EncodePacket(p, buffer, sizeof(buffer));
|
|
||||||
if(!length) {
|
|
||||||
qCritical() << "Failed to encode packet";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int actual_length;
|
|
||||||
auto ret = libusb_bulk_transfer(m_handle, EP_Data_Out_Addr, buffer, length, &actual_length, 0);
|
|
||||||
if(ret < 0) {
|
|
||||||
qCritical() << "Error sending data: "
|
|
||||||
<< libusb_strerror((libusb_error) ret);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<QString> Device::GetDevices()
|
std::set<QString> Device::GetDevices()
|
||||||
|
@ -46,6 +46,7 @@ public:
|
|||||||
// connect to a VNA device. If serial is specified only connecting to this device, otherwise to the first one found
|
// connect to a VNA device. If serial is specified only connecting to this device, otherwise to the first one found
|
||||||
Device(QString serial = QString());
|
Device(QString serial = QString());
|
||||||
~Device();
|
~Device();
|
||||||
|
bool SendPacket(Protocol::PacketInfo packet);
|
||||||
bool Configure(Protocol::SweepSettings settings);
|
bool Configure(Protocol::SweepSettings settings);
|
||||||
bool SetManual(Protocol::ManualControl manual);
|
bool SetManual(Protocol::ManualControl manual);
|
||||||
bool SendFirmwareChunk(Protocol::FirmwarePacket &fw);
|
bool SendFirmwareChunk(Protocol::FirmwarePacket &fw);
|
||||||
|
@ -403,7 +403,6 @@ void VNA::ConnectToDevice(QString serial)
|
|||||||
lConnectionStatus.setText("Connected to " + device->serial());
|
lConnectionStatus.setText("Connected to " + device->serial());
|
||||||
qInfo() << "Connected to " << device->serial();
|
qInfo() << "Connected to " << device->serial();
|
||||||
lDeviceInfo.setText(device->getLastDeviceInfoString());
|
lDeviceInfo.setText(device->getLastDeviceInfoString());
|
||||||
device->Configure(settings);
|
|
||||||
connect(device, &Device::DatapointReceived, this, &VNA::NewDatapoint);
|
connect(device, &Device::DatapointReceived, this, &VNA::NewDatapoint);
|
||||||
connect(device, &Device::LogLineReceived, &deviceLog, &DeviceLog::addLine);
|
connect(device, &Device::LogLineReceived, &deviceLog, &DeviceLog::addLine);
|
||||||
connect(device, &Device::ConnectionLost, this, &VNA::DeviceConnectionLost);
|
connect(device, &Device::ConnectionLost, this, &VNA::DeviceConnectionLost);
|
||||||
@ -414,21 +413,26 @@ void VNA::ConnectToDevice(QString serial)
|
|||||||
ui->actionManual_Control->setEnabled(true);
|
ui->actionManual_Control->setEnabled(true);
|
||||||
ui->menuDefault_Calibration->setEnabled(true);
|
ui->menuDefault_Calibration->setEnabled(true);
|
||||||
ui->actionFirmware_Update->setEnabled(true);
|
ui->actionFirmware_Update->setEnabled(true);
|
||||||
// Check if default calibration exists and attempt to load it
|
{
|
||||||
QSettings settings;
|
// Check if default calibration exists and attempt to load it
|
||||||
auto key = "DefaultCalibration"+device->serial();
|
QSettings settings;
|
||||||
if (settings.contains(key)) {
|
auto key = "DefaultCalibration"+device->serial();
|
||||||
auto filename = settings.value(key).toString();
|
if (settings.contains(key)) {
|
||||||
qDebug() << "Attempting to load default calibration file \"" << filename << "\"";
|
auto filename = settings.value(key).toString();
|
||||||
if(QFile::exists(filename)) {
|
qDebug() << "Attempting to load default calibration file \"" << filename << "\"";
|
||||||
cal.openFromFile(filename);
|
if(QFile::exists(filename)) {
|
||||||
ApplyCalibration(cal.getType());
|
cal.openFromFile(filename);
|
||||||
|
ApplyCalibration(cal.getType());
|
||||||
|
}
|
||||||
|
ui->actionRemoveDefaultCal->setEnabled(true);
|
||||||
|
} else {
|
||||||
|
qDebug() << "No default calibration file set for this device";
|
||||||
|
ui->actionRemoveDefaultCal->setEnabled(false);
|
||||||
}
|
}
|
||||||
ui->actionRemoveDefaultCal->setEnabled(true);
|
|
||||||
} else {
|
|
||||||
qDebug() << "No default calibration file set for this device";
|
|
||||||
ui->actionRemoveDefaultCal->setEnabled(false);
|
|
||||||
}
|
}
|
||||||
|
// Configure initial state of device
|
||||||
|
device->Configure(settings);
|
||||||
|
UpdateReference();
|
||||||
} catch (const runtime_error e) {
|
} catch (const runtime_error e) {
|
||||||
DisconnectDevice();
|
DisconnectDevice();
|
||||||
UpdateDeviceList();
|
UpdateDeviceList();
|
||||||
@ -553,26 +557,28 @@ void VNA::CreateToolbars()
|
|||||||
// Reference toolbar
|
// Reference toolbar
|
||||||
auto tb_reference = new QToolBar("Reference", this);
|
auto tb_reference = new QToolBar("Reference", this);
|
||||||
tb_reference->addWidget(new QLabel("Ref:"));
|
tb_reference->addWidget(new QLabel("Ref:"));
|
||||||
toolbars.referenceType = new QComboBox();
|
toolbars.reference.type = new QComboBox();
|
||||||
toolbars.referenceType->addItem("Int");
|
toolbars.reference.type->addItem("Int");
|
||||||
toolbars.referenceType->addItem("Ext");
|
toolbars.reference.type->addItem("Ext");
|
||||||
auto refInAuto = new QCheckBox("Auto");
|
toolbars.reference.automatic = new QCheckBox("Auto");
|
||||||
refInAuto->setChecked(true);
|
connect(toolbars.reference.automatic, &QCheckBox::clicked, [this](bool checked) {
|
||||||
toolbars.referenceType->setEnabled(false);
|
toolbars.reference.type->setEnabled(!checked);
|
||||||
connect(refInAuto, &QCheckBox::clicked, [this](bool checked) {
|
UpdateReference();
|
||||||
// TODO change device settings
|
|
||||||
toolbars.referenceType->setEnabled(!checked);
|
|
||||||
});
|
});
|
||||||
tb_reference->addWidget(toolbars.referenceType);
|
// toolbars.reference.automatic->setChecked(true);
|
||||||
tb_reference->addWidget(refInAuto);
|
tb_reference->addWidget(toolbars.reference.type);
|
||||||
|
tb_reference->addWidget(toolbars.reference.automatic);
|
||||||
tb_reference->addSeparator();
|
tb_reference->addSeparator();
|
||||||
tb_reference->addWidget(new QLabel("Ref out:"));
|
tb_reference->addWidget(new QLabel("Ref out:"));
|
||||||
auto refOutEnabled = new QCheckBox();
|
toolbars.reference.outputEnabled = new QCheckBox();
|
||||||
auto refOutFreq = new QComboBox();
|
toolbars.reference.outFreq = new QComboBox();
|
||||||
refOutFreq->addItem("10 MHz");
|
toolbars.reference.outFreq->addItem("10 MHz");
|
||||||
refOutFreq->addItem("100 MHz");
|
toolbars.reference.outFreq->addItem("100 MHz");
|
||||||
tb_reference->addWidget(refOutEnabled);
|
tb_reference->addWidget(toolbars.reference.outputEnabled);
|
||||||
tb_reference->addWidget(refOutFreq);
|
tb_reference->addWidget(toolbars.reference.outFreq);
|
||||||
|
connect(toolbars.reference.type, qOverload<int>(&QComboBox::currentIndexChanged), this, &VNA::UpdateReference);
|
||||||
|
connect(toolbars.reference.outFreq, qOverload<int>(&QComboBox::currentIndexChanged), this, &VNA::UpdateReference);
|
||||||
|
connect(toolbars.reference.outputEnabled, &QCheckBox::clicked, this, &VNA::UpdateReference);
|
||||||
|
|
||||||
addToolBar(tb_reference);
|
addToolBar(tb_reference);
|
||||||
|
|
||||||
@ -860,6 +866,35 @@ void VNA::StartCalibrationMeasurement(Calibration::Measurement m)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VNA::UpdateReference()
|
||||||
|
{
|
||||||
|
if(!device) {
|
||||||
|
// can't update without a device connected
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Protocol::ReferenceSettings s = {};
|
||||||
|
if(toolbars.reference.automatic->isChecked()) {
|
||||||
|
s.AutomaticSwitch = 1;
|
||||||
|
}
|
||||||
|
if(toolbars.reference.type->currentText()=="Ext") {
|
||||||
|
s.UseExternalRef = 1;
|
||||||
|
}
|
||||||
|
if(toolbars.reference.outputEnabled->isChecked()) {
|
||||||
|
switch(toolbars.reference.outFreq->currentIndex()) {
|
||||||
|
case 0:
|
||||||
|
s.ExtRefOuputFreq = 10000000;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
s.ExtRefOuputFreq = 100000000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Protocol::PacketInfo p;
|
||||||
|
p.type = Protocol::PacketType::Reference;
|
||||||
|
p.reference = s;
|
||||||
|
device->SendPacket(p);
|
||||||
|
}
|
||||||
|
|
||||||
void VNA::ConstrainAndUpdateFrequencies()
|
void VNA::ConstrainAndUpdateFrequencies()
|
||||||
{
|
{
|
||||||
if(settings.f_stop > maxFreq) {
|
if(settings.f_stop > maxFreq) {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "Device/devicelog.h"
|
#include "Device/devicelog.h"
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include <QButtonGroup>
|
#include <QButtonGroup>
|
||||||
|
#include <QCheckBox>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
@ -63,6 +64,7 @@ private slots:
|
|||||||
void DisableCalibration(bool force = false);
|
void DisableCalibration(bool force = false);
|
||||||
void ApplyCalibration(Calibration::Type type);
|
void ApplyCalibration(Calibration::Type type);
|
||||||
void StartCalibrationMeasurement(Calibration::Measurement m);
|
void StartCalibrationMeasurement(Calibration::Measurement m);
|
||||||
|
void UpdateReference();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void CalibrationMeasurementComplete(Calibration::Measurement m);
|
void CalibrationMeasurementComplete(Calibration::Measurement m);
|
||||||
@ -110,7 +112,12 @@ private:
|
|||||||
QStackedWidget *central;
|
QStackedWidget *central;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
QComboBox *referenceType;
|
struct {
|
||||||
|
QComboBox *type;
|
||||||
|
QCheckBox *automatic;
|
||||||
|
QCheckBox *outputEnabled;
|
||||||
|
QComboBox *outFreq;
|
||||||
|
} reference;
|
||||||
} toolbars;
|
} toolbars;
|
||||||
|
|
||||||
Preferences pref;
|
Preferences pref;
|
||||||
|
@ -100,6 +100,7 @@ void App_Start() {
|
|||||||
|
|
||||||
uint32_t lastNewPoint = HAL_GetTick();
|
uint32_t lastNewPoint = HAL_GetTick();
|
||||||
bool sweepActive = false;
|
bool sweepActive = false;
|
||||||
|
Protocol::ReferenceSettings reference;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
uint32_t notification;
|
uint32_t notification;
|
||||||
@ -113,39 +114,16 @@ void App_Start() {
|
|||||||
lastNewPoint = HAL_GetTick();
|
lastNewPoint = HAL_GetTick();
|
||||||
if(result.pointNum == settings.points - 1) {
|
if(result.pointNum == settings.points - 1) {
|
||||||
// end of sweep
|
// end of sweep
|
||||||
// read PLL temperatures
|
VNA::Ref::applySettings(reference);
|
||||||
uint8_t tempSource, tempLO;
|
|
||||||
VNA::GetTemps(&tempSource, &tempLO);
|
|
||||||
LOG_INFO("PLL temperatures: %u/%u", tempSource, tempLO);
|
|
||||||
// Read ADC min/max
|
|
||||||
auto limits = FPGA::GetADCLimits();
|
|
||||||
#define ADC_LIMIT 30000
|
|
||||||
// Compile info packet
|
// Compile info packet
|
||||||
packet.type = Protocol::PacketType::DeviceInfo;
|
packet.type = Protocol::PacketType::DeviceInfo;
|
||||||
packet.info.FPGA_configured = 1;
|
packet.info.FPGA_configured = 1;
|
||||||
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) {
|
|
||||||
packet.info.ADC_overload = true;
|
|
||||||
} else {
|
|
||||||
packet.info.ADC_overload = false;
|
|
||||||
}
|
|
||||||
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;
|
||||||
auto status = FPGA::GetStatus();
|
VNA::fillDeviceInfo(&packet.info);
|
||||||
packet.info.LO1_locked = (status & (int) FPGA::Interrupt::LO1Unlock) ? 0 : 1;
|
|
||||||
packet.info.source_locked = (status & (int) FPGA::Interrupt::SourceUnlock) ? 0 : 1;
|
|
||||||
packet.info.extRefAvailable = 0;
|
|
||||||
packet.info.extRefInUse = 0;
|
|
||||||
packet.info.temperatures.LO1 = tempLO;
|
|
||||||
packet.info.temperatures.source = tempSource;
|
|
||||||
packet.info.temperatures.MCU = 0;
|
|
||||||
Communication::Send(packet);
|
Communication::Send(packet);
|
||||||
FPGA::ResetADCLimits();
|
FPGA::ResetADCLimits();
|
||||||
LOG_INFO("ADC limits: P1: %d/%d P2: %d/%d R: %d/%d",
|
|
||||||
limits.P1min, limits.P1max, limits.P2min, limits.P2max,
|
|
||||||
limits.Rmin, limits.Rmax);
|
|
||||||
// Start next sweep
|
// Start next sweep
|
||||||
FPGA::StartSweep();
|
FPGA::StartSweep();
|
||||||
}
|
}
|
||||||
@ -194,6 +172,13 @@ void App_Start() {
|
|||||||
manual = packet.manual;
|
manual = packet.manual;
|
||||||
VNA::ConfigureManual(manual, VNAStatusCallback);
|
VNA::ConfigureManual(manual, VNAStatusCallback);
|
||||||
break;
|
break;
|
||||||
|
case Protocol::PacketType::Reference:
|
||||||
|
reference = packet.reference;
|
||||||
|
if(!sweepActive) {
|
||||||
|
// can update right now
|
||||||
|
VNA::Ref::applySettings(reference);
|
||||||
|
}
|
||||||
|
break;
|
||||||
#ifdef HAS_FLASH
|
#ifdef HAS_FLASH
|
||||||
case Protocol::PacketType::ClearFlash:
|
case Protocol::PacketType::ClearFlash:
|
||||||
FPGA::AbortSweep();
|
FPGA::AbortSweep();
|
||||||
@ -238,7 +223,10 @@ void App_Start() {
|
|||||||
if(sweepActive && HAL_GetTick() - lastNewPoint > 1000) {
|
if(sweepActive && HAL_GetTick() - lastNewPoint > 1000) {
|
||||||
LOG_WARN("Timed out waiting for point, last received point was %d", result.pointNum);
|
LOG_WARN("Timed out waiting for point, last received point was %d", result.pointNum);
|
||||||
LOG_WARN("FPGA status: 0x%04x", FPGA::GetStatus());
|
LOG_WARN("FPGA status: 0x%04x", FPGA::GetStatus());
|
||||||
|
FPGA::AbortSweep();
|
||||||
// restart the current sweep
|
// restart the current sweep
|
||||||
|
VNA::Init();
|
||||||
|
VNA::Ref::applySettings(reference);
|
||||||
VNA::ConfigureSweep(settings, VNACallback);
|
VNA::ConfigureSweep(settings, VNACallback);
|
||||||
sweepActive = true;
|
sweepActive = true;
|
||||||
lastNewPoint = HAL_GetTick();
|
lastNewPoint = HAL_GetTick();
|
||||||
|
@ -187,6 +187,23 @@ static int16_t EncodeSweepSettings(Protocol::SweepSettings d, uint8_t *buf,
|
|||||||
return e.getSize();
|
return e.getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Protocol::ReferenceSettings DecodeReferenceSettings(uint8_t *buf) {
|
||||||
|
Protocol::ReferenceSettings d;
|
||||||
|
Decoder e(buf);
|
||||||
|
e.get<uint32_t>(d.ExtRefOuputFreq);
|
||||||
|
d.AutomaticSwitch = e.getBits(1);
|
||||||
|
d.UseExternalRef = e.getBits(1);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
static int16_t EncodeReferenceSettings(Protocol::ReferenceSettings d, uint8_t *buf,
|
||||||
|
uint16_t bufSize) {
|
||||||
|
Encoder e(buf, bufSize);
|
||||||
|
e.add<uint32_t>(d.ExtRefOuputFreq);
|
||||||
|
e.addBits(d.AutomaticSwitch, 1);
|
||||||
|
e.addBits(d.UseExternalRef, 1);
|
||||||
|
return e.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
@ -388,6 +405,9 @@ uint16_t Protocol::DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info) {
|
|||||||
case PacketType::SweepSettings:
|
case PacketType::SweepSettings:
|
||||||
info->settings = DecodeSweepSettings(&data[4]);
|
info->settings = DecodeSweepSettings(&data[4]);
|
||||||
break;
|
break;
|
||||||
|
case PacketType::Reference:
|
||||||
|
info->reference = DecodeReferenceSettings(&data[4]);
|
||||||
|
break;
|
||||||
case PacketType::DeviceInfo:
|
case PacketType::DeviceInfo:
|
||||||
info->info = DecodeDeviceInfo(&data[4]);
|
info->info = DecodeDeviceInfo(&data[4]);
|
||||||
break;
|
break;
|
||||||
@ -403,6 +423,7 @@ uint16_t Protocol::DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info) {
|
|||||||
case PacketType::Ack:
|
case PacketType::Ack:
|
||||||
case PacketType::PerformFirmwareUpdate:
|
case PacketType::PerformFirmwareUpdate:
|
||||||
case PacketType::ClearFlash:
|
case PacketType::ClearFlash:
|
||||||
|
case PacketType::Nack:
|
||||||
// no payload, nothing to do
|
// no payload, nothing to do
|
||||||
break;
|
break;
|
||||||
case PacketType::None:
|
case PacketType::None:
|
||||||
@ -421,6 +442,9 @@ uint16_t Protocol::EncodePacket(PacketInfo packet, uint8_t *dest, uint16_t dests
|
|||||||
case PacketType::SweepSettings:
|
case PacketType::SweepSettings:
|
||||||
payload_size = EncodeSweepSettings(packet.settings, &dest[4], destsize - 8);
|
payload_size = EncodeSweepSettings(packet.settings, &dest[4], destsize - 8);
|
||||||
break;
|
break;
|
||||||
|
case PacketType::Reference:
|
||||||
|
payload_size = EncodeReferenceSettings(packet.reference, &dest[4], destsize - 8);
|
||||||
|
break;
|
||||||
case PacketType::DeviceInfo:
|
case PacketType::DeviceInfo:
|
||||||
payload_size = EncodeDeviceInfo(packet.info, &dest[4], destsize - 8);
|
payload_size = EncodeDeviceInfo(packet.info, &dest[4], destsize - 8);
|
||||||
break;
|
break;
|
||||||
@ -436,6 +460,7 @@ uint16_t Protocol::EncodePacket(PacketInfo packet, uint8_t *dest, uint16_t dests
|
|||||||
case PacketType::Ack:
|
case PacketType::Ack:
|
||||||
case PacketType::PerformFirmwareUpdate:
|
case PacketType::PerformFirmwareUpdate:
|
||||||
case PacketType::ClearFlash:
|
case PacketType::ClearFlash:
|
||||||
|
case PacketType::Nack:
|
||||||
// no payload, nothing to do
|
// no payload, nothing to do
|
||||||
break;
|
break;
|
||||||
case PacketType::None:
|
case PacketType::None:
|
||||||
|
@ -23,6 +23,12 @@ using SweepSettings = struct _sweepSettings {
|
|||||||
int16_t cdbm_excitation; // in 1/100 dbm
|
int16_t cdbm_excitation; // in 1/100 dbm
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using ReferenceSettings = struct _referenceSettings {
|
||||||
|
uint32_t ExtRefOuputFreq;
|
||||||
|
uint8_t AutomaticSwitch:1;
|
||||||
|
uint8_t UseExternalRef:1;
|
||||||
|
};
|
||||||
|
|
||||||
using DeviceInfo = struct _deviceInfo {
|
using DeviceInfo = struct _deviceInfo {
|
||||||
uint16_t FW_major;
|
uint16_t FW_major;
|
||||||
uint16_t FW_minor;
|
uint16_t FW_minor;
|
||||||
@ -102,6 +108,7 @@ enum class PacketType : uint8_t {
|
|||||||
ClearFlash = 8,
|
ClearFlash = 8,
|
||||||
PerformFirmwareUpdate = 9,
|
PerformFirmwareUpdate = 9,
|
||||||
Nack = 10,
|
Nack = 10,
|
||||||
|
Reference = 11,
|
||||||
};
|
};
|
||||||
|
|
||||||
using PacketInfo = struct _packetinfo {
|
using PacketInfo = struct _packetinfo {
|
||||||
@ -109,6 +116,7 @@ using PacketInfo = struct _packetinfo {
|
|||||||
union {
|
union {
|
||||||
Datapoint datapoint;
|
Datapoint datapoint;
|
||||||
SweepSettings settings;
|
SweepSettings settings;
|
||||||
|
ReferenceSettings reference;
|
||||||
DeviceInfo info;
|
DeviceInfo info;
|
||||||
ManualControl manual;
|
ManualControl manual;
|
||||||
ManualStatus status;
|
ManualStatus status;
|
||||||
|
@ -63,6 +63,8 @@ bool FPGA::Configure(Flash *f, uint32_t start_address, uint32_t bitstream_size)
|
|||||||
|
|
||||||
bool FPGA::Init(HaltedCallback cb) {
|
bool FPGA::Init(HaltedCallback cb) {
|
||||||
halted_cb = cb;
|
halted_cb = cb;
|
||||||
|
SysCtrlReg = 0;
|
||||||
|
ISRMaskReg = 0;
|
||||||
// Reset FPGA
|
// Reset FPGA
|
||||||
High(FPGA_RESET);
|
High(FPGA_RESET);
|
||||||
SetMode(Mode::FPGA);
|
SetMode(Mode::FPGA);
|
||||||
|
@ -2,12 +2,32 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#define LOG_LEVEL LOG_LEVEL_INFO
|
#define LOG_LEVEL LOG_LEVEL_DEBUG
|
||||||
#define LOG_MODULE "SI5351"
|
#define LOG_MODULE "SI5351"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
bool Si5351C::Init(uint32_t clkin_freq) {
|
bool Si5351C::Init(uint32_t clkin_freq) {
|
||||||
bool success = true;
|
bool success = true;
|
||||||
|
FreqCLKINDiv = 0;
|
||||||
|
|
||||||
|
// Disable OEB pin functionality
|
||||||
|
success &= WriteRegister(Reg::OEBPinMask, 0xFF);
|
||||||
|
// Disable all outputs
|
||||||
|
success &= WriteRegister(Reg::OutputEnableControl, 0xFF);
|
||||||
|
|
||||||
|
// Enable fanouts
|
||||||
|
success &= WriteRegister(Reg::FanoutEnable, 0xD0);
|
||||||
|
|
||||||
|
if(success) {
|
||||||
|
LOG_INFO("Initialized");
|
||||||
|
} else {
|
||||||
|
LOG_ERR("Initialization failed");
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Si5351C::ConfigureCLKIn(uint32_t clkin_freq) {
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
uint8_t clkinDiv = 0;
|
uint8_t clkinDiv = 0;
|
||||||
while (clkin_freq / (1 << clkinDiv) > 40000000) {
|
while (clkin_freq / (1 << clkinDiv) > 40000000) {
|
||||||
@ -26,19 +46,6 @@ bool Si5351C::Init(uint32_t clkin_freq) {
|
|||||||
value |= clkinDiv << 6;
|
value |= clkinDiv << 6;
|
||||||
success &= WriteRegister(Reg::PLLInputSource, value);
|
success &= WriteRegister(Reg::PLLInputSource, value);
|
||||||
|
|
||||||
// Disable OEB pin functionality
|
|
||||||
success &= WriteRegister(Reg::OEBPinMask, 0xFF);
|
|
||||||
// Disable all outputs
|
|
||||||
success &= WriteRegister(Reg::OutputEnableControl, 0xFF);
|
|
||||||
|
|
||||||
// Enable fanouts
|
|
||||||
success &= WriteRegister(Reg::FanoutEnable, 0xD0);
|
|
||||||
|
|
||||||
if(success) {
|
|
||||||
LOG_INFO("Initialized");
|
|
||||||
} else {
|
|
||||||
LOG_ERR("Initialization failed");
|
|
||||||
}
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,6 +285,17 @@ bool Si5351C::WriteRegisterRange(Reg start, const uint8_t *data, uint8_t len) {
|
|||||||
I2C_MEMADD_SIZE_8BIT, (uint8_t*) data, len, 100) == HAL_OK;
|
I2C_MEMADD_SIZE_8BIT, (uint8_t*) data, len, 100) == HAL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Si5351C::ExtCLKAvailable() {
|
||||||
|
uint8_t value;
|
||||||
|
ReadRegister(Reg::DeviceStatus, &value);
|
||||||
|
LOG_DEBUG("Device status: 0x%02x", value);
|
||||||
|
if (value & 0x10) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Si5351C::ReadRegisterRange(Reg start, uint8_t *data, uint8_t len) {
|
bool Si5351C::ReadRegisterRange(Reg start, uint8_t *data, uint8_t len) {
|
||||||
return HAL_I2C_Mem_Read(i2c, address, (int) start,
|
return HAL_I2C_Mem_Read(i2c, address, (int) start,
|
||||||
I2C_MEMADD_SIZE_8BIT, data, len, 100) == HAL_OK;
|
I2C_MEMADD_SIZE_8BIT, data, len, 100) == HAL_OK;
|
||||||
@ -338,3 +356,5 @@ bool Si5351C::ReadRawCLKConfig(uint8_t clknum, uint8_t *config) {
|
|||||||
auto reg = (Reg) ((int) Reg::MS0_CONFIG + 8 * clknum);
|
auto reg = (Reg) ((int) Reg::MS0_CONFIG + 8 * clknum);
|
||||||
return ReadRegisterRange(reg, config, 8);
|
return ReadRegisterRange(reg, config, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ public:
|
|||||||
FreqCLKINDiv(0) {
|
FreqCLKINDiv(0) {
|
||||||
};
|
};
|
||||||
bool Init(uint32_t clkin_freq = 0);
|
bool Init(uint32_t clkin_freq = 0);
|
||||||
|
bool ConfigureCLKIn(uint32_t clkin_freq);
|
||||||
bool SetPLL(PLL pll, uint32_t frequency, PLLSource src);
|
bool SetPLL(PLL pll, uint32_t frequency, PLLSource src);
|
||||||
bool SetCLK(uint8_t clknum, uint32_t frequency, PLL source, DriveStrength strength = DriveStrength::mA2, uint32_t PLLFreqOverride = 0);
|
bool SetCLK(uint8_t clknum, uint32_t frequency, PLL source, DriveStrength strength = DriveStrength::mA2, uint32_t PLLFreqOverride = 0);
|
||||||
bool SetCLKtoXTAL(uint8_t clknum);
|
bool SetCLKtoXTAL(uint8_t clknum);
|
||||||
@ -38,6 +39,7 @@ public:
|
|||||||
bool Disable(uint8_t clknum);
|
bool Disable(uint8_t clknum);
|
||||||
bool Locked(PLL pll);
|
bool Locked(PLL pll);
|
||||||
bool ResetPLL(PLL pll);
|
bool ResetPLL(PLL pll);
|
||||||
|
bool ExtCLKAvailable();
|
||||||
|
|
||||||
// Direct register access of clk configuration registers
|
// Direct register access of clk configuration registers
|
||||||
// config has to point to a buffer containing at least 8 bytes
|
// config has to point to a buffer containing at least 8 bytes
|
||||||
|
@ -36,6 +36,9 @@ static uint16_t IFTableIndexCnt = 0;
|
|||||||
|
|
||||||
static constexpr uint32_t BandSwitchFrequency = 25000000;
|
static constexpr uint32_t BandSwitchFrequency = 25000000;
|
||||||
|
|
||||||
|
static uint32_t extOutFreq = 0;
|
||||||
|
static bool extRefInUse = false;
|
||||||
|
|
||||||
using namespace VNAHAL;
|
using namespace VNAHAL;
|
||||||
|
|
||||||
static void HaltedCallback() {
|
static void HaltedCallback() {
|
||||||
@ -129,6 +132,10 @@ bool VNA::Init() {
|
|||||||
Si5351.SetPLL(Si5351C::PLL::B, 800000000, Si5351C::PLLSource::XTAL);
|
Si5351.SetPLL(Si5351C::PLL::B, 800000000, Si5351C::PLLSource::XTAL);
|
||||||
while(!Si5351.Locked(Si5351C::PLL::B));
|
while(!Si5351.Locked(Si5351C::PLL::B));
|
||||||
|
|
||||||
|
extRefInUse = 0;
|
||||||
|
extOutFreq = 0;
|
||||||
|
Si5351.Disable(SiChannel::ReferenceOut);
|
||||||
|
|
||||||
// Both MAX2871 get a 100MHz reference
|
// Both MAX2871 get a 100MHz reference
|
||||||
Si5351.SetCLK(SiChannel::Source, 100000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2);
|
Si5351.SetCLK(SiChannel::Source, 100000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2);
|
||||||
Si5351.Enable(SiChannel::Source);
|
Si5351.Enable(SiChannel::Source);
|
||||||
@ -137,10 +144,6 @@ bool VNA::Init() {
|
|||||||
// 16MHz FPGA clock
|
// 16MHz FPGA clock
|
||||||
Si5351.SetCLK(SiChannel::FPGA, 16000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2);
|
Si5351.SetCLK(SiChannel::FPGA, 16000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2);
|
||||||
Si5351.Enable(SiChannel::FPGA);
|
Si5351.Enable(SiChannel::FPGA);
|
||||||
// TODO reference settings controllable through USB
|
|
||||||
// // 10 MHz external reference clock
|
|
||||||
// Si5351.SetCLK(6, 10000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA8);
|
|
||||||
// Si5351.Enable(6);
|
|
||||||
|
|
||||||
// Generate second LO with Si5351
|
// Generate second LO with Si5351
|
||||||
Si5351.SetCLK(SiChannel::Port1LO2, IF1 - IF2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
|
Si5351.SetCLK(SiChannel::Port1LO2, IF1 - IF2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
|
||||||
@ -410,3 +413,80 @@ bool VNA::GetTemps(uint8_t *source, uint8_t *lo) {
|
|||||||
FPGA::SetMode(FPGA::Mode::FPGA);
|
FPGA::SetMode(FPGA::Mode::FPGA);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VNA::fillDeviceInfo(Protocol::DeviceInfo *info) {
|
||||||
|
// read PLL temperatures
|
||||||
|
uint8_t tempSource, tempLO;
|
||||||
|
VNA::GetTemps(&tempSource, &tempLO);
|
||||||
|
LOG_INFO("PLL temperatures: %u/%u", tempSource, tempLO);
|
||||||
|
// Read ADC min/max
|
||||||
|
auto limits = FPGA::GetADCLimits();
|
||||||
|
LOG_INFO("ADC limits: P1: %d/%d P2: %d/%d R: %d/%d",
|
||||||
|
limits.P1min, limits.P1max, limits.P2min, limits.P2max,
|
||||||
|
limits.Rmin, limits.Rmax);
|
||||||
|
#define ADC_LIMIT 30000
|
||||||
|
// Set VNA related member of info struct
|
||||||
|
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->temperatures.LO1 = tempLO;
|
||||||
|
info->temperatures.source = tempSource;
|
||||||
|
info->temperatures.MCU = 0;
|
||||||
|
FPGA::ResetADCLimits();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VNA::Ref::available() {
|
||||||
|
return Si5351.ExtCLKAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VNA::Ref::applySettings(Protocol::ReferenceSettings s) {
|
||||||
|
if(extOutFreq != s.ExtRefOuputFreq) {
|
||||||
|
extOutFreq = s.ExtRefOuputFreq;
|
||||||
|
if(extOutFreq == 0) {
|
||||||
|
Si5351.Disable(SiChannel::ReferenceOut);
|
||||||
|
LOG_INFO("External reference output disabled");
|
||||||
|
} else {
|
||||||
|
Si5351.SetCLK(SiChannel::ReferenceOut, extOutFreq, Si5351C::PLL::A);
|
||||||
|
Si5351.Enable(SiChannel::ReferenceOut);
|
||||||
|
LOG_INFO("External reference output set to %luHz", extOutFreq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool useExternal = s.UseExternalRef || (s.AutomaticSwitch && Ref::available());
|
||||||
|
if(useExternal != extRefInUse) {
|
||||||
|
// switch between internal and external reference
|
||||||
|
extRefInUse = useExternal;
|
||||||
|
if(extRefInUse) {
|
||||||
|
if(!Ref::available()) {
|
||||||
|
LOG_WARN("Forced switch to external reference but no signal detected");
|
||||||
|
}
|
||||||
|
Si5351.ConfigureCLKIn(10000000);
|
||||||
|
Si5351.SetPLL(Si5351C::PLL::A, 800000000, Si5351C::PLLSource::CLKIN);
|
||||||
|
Si5351.SetPLL(Si5351C::PLL::B, 800000000, Si5351C::PLLSource::CLKIN);
|
||||||
|
LOG_INFO("Switched to external reference");
|
||||||
|
FPGA::Enable(FPGA::Periphery::ExtRefLED);
|
||||||
|
} else {
|
||||||
|
Si5351.SetPLL(Si5351C::PLL::A, 800000000, Si5351C::PLLSource::XTAL);
|
||||||
|
Si5351.SetPLL(Si5351C::PLL::B, 800000000, Si5351C::PLLSource::XTAL);
|
||||||
|
LOG_INFO("Switched to internal reference");
|
||||||
|
FPGA::Disable(FPGA::Periphery::ExtRefLED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
constexpr uint32_t lock_timeout = 10;
|
||||||
|
uint32_t start = HAL_GetTick();
|
||||||
|
while(!Si5351.Locked(Si5351C::PLL::A) || !Si5351.Locked(Si5351C::PLL::A)) {
|
||||||
|
if(HAL_GetTick() - start > lock_timeout) {
|
||||||
|
LOG_ERR("Clock distributor PLLs failed to lock");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -12,7 +12,14 @@ using StatusCallback = void(*)(FPGA::SamplingResult);
|
|||||||
bool Init();
|
bool Init();
|
||||||
bool ConfigureSweep(Protocol::SweepSettings s, SweepCallback cb);
|
bool ConfigureSweep(Protocol::SweepSettings s, SweepCallback cb);
|
||||||
bool ConfigureManual(Protocol::ManualControl m, StatusCallback cb);
|
bool ConfigureManual(Protocol::ManualControl m, StatusCallback cb);
|
||||||
|
|
||||||
|
// Only call the following function when the sweep is inactive
|
||||||
bool GetTemps(uint8_t *source, uint8_t *lo);
|
bool GetTemps(uint8_t *source, uint8_t *lo);
|
||||||
|
void fillDeviceInfo(Protocol::DeviceInfo *info);
|
||||||
|
namespace Ref {
|
||||||
|
bool available();
|
||||||
|
bool applySettings(Protocol::ReferenceSettings s);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user