diff --git a/Software/PC_Application/Application b/Software/PC_Application/Application index 7d5b462..351d308 100755 Binary files a/Software/PC_Application/Application and b/Software/PC_Application/Application differ diff --git a/Software/PC_Application/Device/device.cpp b/Software/PC_Application/Device/device.cpp index 322a1a1..04b3057 100644 --- a/Software/PC_Application/Device/device.cpp +++ b/Software/PC_Application/Device/device.cpp @@ -82,14 +82,11 @@ Device::~Device() } } -bool Device::Configure(Protocol::SweepSettings settings) +bool Device::SendPacket(Protocol::PacketInfo packet) { if(m_connected) { - unsigned char buffer[128]; - Protocol::PacketInfo p; - p.type = Protocol::PacketType::SweepSettings; - p.settings = settings; - unsigned int length = Protocol::EncodePacket(p, buffer, sizeof(buffer)); + unsigned char buffer[1024]; + unsigned int length = Protocol::EncodePacket(packet, buffer, sizeof(buffer)); if(!length) { qCritical() << "Failed to encode packet"; 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) { - if(m_connected) { - unsigned char buffer[128]; - Protocol::PacketInfo p; - p.type = Protocol::PacketType::ManualControl; - 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; - } + Protocol::PacketInfo p; + p.type = Protocol::PacketType::ManualControl; + p.manual = manual; + return SendPacket(p); } bool Device::SendFirmwareChunk(Protocol::FirmwarePacket &fw) { - if(m_connected) { - unsigned char buffer[Protocol::FirmwareChunkSize + 4 + 8]; - Protocol::PacketInfo p; - p.type = Protocol::PacketType::FirmwarePacket; - 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; - } + Protocol::PacketInfo p; + p.type = Protocol::PacketType::FirmwarePacket; + p.firmware = fw; + return SendPacket(p); } bool Device::SendCommandWithoutPayload(Protocol::PacketType type) { - if(m_connected) { - unsigned char buffer[32]; - Protocol::PacketInfo 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; - } + Protocol::PacketInfo p; + p.type = type; + return SendPacket(p); } std::set Device::GetDevices() diff --git a/Software/PC_Application/Device/device.h b/Software/PC_Application/Device/device.h index 89fa5ae..55fa5c6 100644 --- a/Software/PC_Application/Device/device.h +++ b/Software/PC_Application/Device/device.h @@ -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 Device(QString serial = QString()); ~Device(); + bool SendPacket(Protocol::PacketInfo packet); bool Configure(Protocol::SweepSettings settings); bool SetManual(Protocol::ManualControl manual); bool SendFirmwareChunk(Protocol::FirmwarePacket &fw); diff --git a/Software/PC_Application/vna.cpp b/Software/PC_Application/vna.cpp index ea5a534..f7aa1f9 100644 --- a/Software/PC_Application/vna.cpp +++ b/Software/PC_Application/vna.cpp @@ -403,7 +403,6 @@ void VNA::ConnectToDevice(QString serial) lConnectionStatus.setText("Connected to " + device->serial()); qInfo() << "Connected to " << device->serial(); lDeviceInfo.setText(device->getLastDeviceInfoString()); - device->Configure(settings); connect(device, &Device::DatapointReceived, this, &VNA::NewDatapoint); connect(device, &Device::LogLineReceived, &deviceLog, &DeviceLog::addLine); connect(device, &Device::ConnectionLost, this, &VNA::DeviceConnectionLost); @@ -414,21 +413,26 @@ void VNA::ConnectToDevice(QString serial) ui->actionManual_Control->setEnabled(true); ui->menuDefault_Calibration->setEnabled(true); ui->actionFirmware_Update->setEnabled(true); - // Check if default calibration exists and attempt to load it - QSettings settings; - auto key = "DefaultCalibration"+device->serial(); - if (settings.contains(key)) { - auto filename = settings.value(key).toString(); - qDebug() << "Attempting to load default calibration file \"" << filename << "\""; - if(QFile::exists(filename)) { - cal.openFromFile(filename); - ApplyCalibration(cal.getType()); + { + // Check if default calibration exists and attempt to load it + QSettings settings; + auto key = "DefaultCalibration"+device->serial(); + if (settings.contains(key)) { + auto filename = settings.value(key).toString(); + qDebug() << "Attempting to load default calibration file \"" << filename << "\""; + if(QFile::exists(filename)) { + 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) { DisconnectDevice(); UpdateDeviceList(); @@ -553,26 +557,28 @@ void VNA::CreateToolbars() // Reference toolbar auto tb_reference = new QToolBar("Reference", this); tb_reference->addWidget(new QLabel("Ref:")); - toolbars.referenceType = new QComboBox(); - toolbars.referenceType->addItem("Int"); - toolbars.referenceType->addItem("Ext"); - auto refInAuto = new QCheckBox("Auto"); - refInAuto->setChecked(true); - toolbars.referenceType->setEnabled(false); - connect(refInAuto, &QCheckBox::clicked, [this](bool checked) { - // TODO change device settings - toolbars.referenceType->setEnabled(!checked); + toolbars.reference.type = new QComboBox(); + toolbars.reference.type->addItem("Int"); + toolbars.reference.type->addItem("Ext"); + toolbars.reference.automatic = new QCheckBox("Auto"); + connect(toolbars.reference.automatic, &QCheckBox::clicked, [this](bool checked) { + toolbars.reference.type->setEnabled(!checked); + UpdateReference(); }); - tb_reference->addWidget(toolbars.referenceType); - tb_reference->addWidget(refInAuto); + // toolbars.reference.automatic->setChecked(true); + tb_reference->addWidget(toolbars.reference.type); + tb_reference->addWidget(toolbars.reference.automatic); tb_reference->addSeparator(); tb_reference->addWidget(new QLabel("Ref out:")); - auto refOutEnabled = new QCheckBox(); - auto refOutFreq = new QComboBox(); - refOutFreq->addItem("10 MHz"); - refOutFreq->addItem("100 MHz"); - tb_reference->addWidget(refOutEnabled); - tb_reference->addWidget(refOutFreq); + toolbars.reference.outputEnabled = new QCheckBox(); + toolbars.reference.outFreq = new QComboBox(); + toolbars.reference.outFreq->addItem("10 MHz"); + toolbars.reference.outFreq->addItem("100 MHz"); + tb_reference->addWidget(toolbars.reference.outputEnabled); + tb_reference->addWidget(toolbars.reference.outFreq); + connect(toolbars.reference.type, qOverload(&QComboBox::currentIndexChanged), this, &VNA::UpdateReference); + connect(toolbars.reference.outFreq, qOverload(&QComboBox::currentIndexChanged), this, &VNA::UpdateReference); + connect(toolbars.reference.outputEnabled, &QCheckBox::clicked, this, &VNA::UpdateReference); 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() { if(settings.f_stop > maxFreq) { diff --git a/Software/PC_Application/vna.h b/Software/PC_Application/vna.h index 02d1925..0ce0380 100644 --- a/Software/PC_Application/vna.h +++ b/Software/PC_Application/vna.h @@ -17,6 +17,7 @@ #include "Device/devicelog.h" #include "preferences.h" #include +#include namespace Ui { class MainWindow; @@ -63,6 +64,7 @@ private slots: void DisableCalibration(bool force = false); void ApplyCalibration(Calibration::Type type); void StartCalibrationMeasurement(Calibration::Measurement m); + void UpdateReference(); signals: void CalibrationMeasurementComplete(Calibration::Measurement m); @@ -110,7 +112,12 @@ private: QStackedWidget *central; struct { - QComboBox *referenceType; + struct { + QComboBox *type; + QCheckBox *automatic; + QCheckBox *outputEnabled; + QComboBox *outFreq; + } reference; } toolbars; Preferences pref; diff --git a/Software/VNA_embedded/Application/App.cpp b/Software/VNA_embedded/Application/App.cpp index 6e09120..8aa10cd 100644 --- a/Software/VNA_embedded/Application/App.cpp +++ b/Software/VNA_embedded/Application/App.cpp @@ -100,6 +100,7 @@ void App_Start() { uint32_t lastNewPoint = HAL_GetTick(); bool sweepActive = false; + Protocol::ReferenceSettings reference; while (1) { uint32_t notification; @@ -113,39 +114,16 @@ void App_Start() { lastNewPoint = HAL_GetTick(); if(result.pointNum == settings.points - 1) { // end of sweep - // 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(); - #define ADC_LIMIT 30000 + VNA::Ref::applySettings(reference); // Compile info packet packet.type = Protocol::PacketType::DeviceInfo; 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_minor = FW_MINOR; packet.info.HW_Revision = HW_REVISION; - auto status = FPGA::GetStatus(); - 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; + VNA::fillDeviceInfo(&packet.info); Communication::Send(packet); 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 FPGA::StartSweep(); } @@ -194,6 +172,13 @@ void App_Start() { manual = packet.manual; VNA::ConfigureManual(manual, VNAStatusCallback); break; + case Protocol::PacketType::Reference: + reference = packet.reference; + if(!sweepActive) { + // can update right now + VNA::Ref::applySettings(reference); + } + break; #ifdef HAS_FLASH case Protocol::PacketType::ClearFlash: FPGA::AbortSweep(); @@ -238,7 +223,10 @@ void App_Start() { if(sweepActive && HAL_GetTick() - lastNewPoint > 1000) { LOG_WARN("Timed out waiting for point, last received point was %d", result.pointNum); LOG_WARN("FPGA status: 0x%04x", FPGA::GetStatus()); + FPGA::AbortSweep(); // restart the current sweep + VNA::Init(); + VNA::Ref::applySettings(reference); VNA::ConfigureSweep(settings, VNACallback); sweepActive = true; lastNewPoint = HAL_GetTick(); diff --git a/Software/VNA_embedded/Application/Communication/Protocol.cpp b/Software/VNA_embedded/Application/Communication/Protocol.cpp index cfd0a6f..2059f8b 100644 --- a/Software/VNA_embedded/Application/Communication/Protocol.cpp +++ b/Software/VNA_embedded/Application/Communication/Protocol.cpp @@ -187,6 +187,23 @@ static int16_t EncodeSweepSettings(Protocol::SweepSettings d, uint8_t *buf, return e.getSize(); } +static Protocol::ReferenceSettings DecodeReferenceSettings(uint8_t *buf) { + Protocol::ReferenceSettings d; + Decoder e(buf); + e.get(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(d.ExtRefOuputFreq); + e.addBits(d.AutomaticSwitch, 1); + e.addBits(d.UseExternalRef, 1); + return e.getSize(); +} + static Protocol::DeviceInfo DecodeDeviceInfo(uint8_t *buf) { Protocol::DeviceInfo d; Decoder e(buf); @@ -388,6 +405,9 @@ uint16_t Protocol::DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info) { case PacketType::SweepSettings: info->settings = DecodeSweepSettings(&data[4]); break; + case PacketType::Reference: + info->reference = DecodeReferenceSettings(&data[4]); + break; case PacketType::DeviceInfo: info->info = DecodeDeviceInfo(&data[4]); break; @@ -403,6 +423,7 @@ uint16_t Protocol::DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info) { case PacketType::Ack: case PacketType::PerformFirmwareUpdate: case PacketType::ClearFlash: + case PacketType::Nack: // no payload, nothing to do break; case PacketType::None: @@ -421,6 +442,9 @@ uint16_t Protocol::EncodePacket(PacketInfo packet, uint8_t *dest, uint16_t dests case PacketType::SweepSettings: payload_size = EncodeSweepSettings(packet.settings, &dest[4], destsize - 8); break; + case PacketType::Reference: + payload_size = EncodeReferenceSettings(packet.reference, &dest[4], destsize - 8); + break; case PacketType::DeviceInfo: payload_size = EncodeDeviceInfo(packet.info, &dest[4], destsize - 8); break; @@ -436,6 +460,7 @@ uint16_t Protocol::EncodePacket(PacketInfo packet, uint8_t *dest, uint16_t dests case PacketType::Ack: case PacketType::PerformFirmwareUpdate: case PacketType::ClearFlash: + case PacketType::Nack: // no payload, nothing to do break; case PacketType::None: diff --git a/Software/VNA_embedded/Application/Communication/Protocol.hpp b/Software/VNA_embedded/Application/Communication/Protocol.hpp index 6d62027..0425c0a 100644 --- a/Software/VNA_embedded/Application/Communication/Protocol.hpp +++ b/Software/VNA_embedded/Application/Communication/Protocol.hpp @@ -23,6 +23,12 @@ using SweepSettings = struct _sweepSettings { 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 { uint16_t FW_major; uint16_t FW_minor; @@ -102,6 +108,7 @@ enum class PacketType : uint8_t { ClearFlash = 8, PerformFirmwareUpdate = 9, Nack = 10, + Reference = 11, }; using PacketInfo = struct _packetinfo { @@ -109,6 +116,7 @@ using PacketInfo = struct _packetinfo { union { Datapoint datapoint; SweepSettings settings; + ReferenceSettings reference; DeviceInfo info; ManualControl manual; ManualStatus status; diff --git a/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.cpp b/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.cpp index 4ee7ef8..bbf50b3 100644 --- a/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.cpp +++ b/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.cpp @@ -63,6 +63,8 @@ bool FPGA::Configure(Flash *f, uint32_t start_address, uint32_t bitstream_size) bool FPGA::Init(HaltedCallback cb) { halted_cb = cb; + SysCtrlReg = 0; + ISRMaskReg = 0; // Reset FPGA High(FPGA_RESET); SetMode(Mode::FPGA); diff --git a/Software/VNA_embedded/Application/Drivers/Si5351C.cpp b/Software/VNA_embedded/Application/Drivers/Si5351C.cpp index f9eb911..6e32345 100644 --- a/Software/VNA_embedded/Application/Drivers/Si5351C.cpp +++ b/Software/VNA_embedded/Application/Drivers/Si5351C.cpp @@ -2,12 +2,32 @@ #include -#define LOG_LEVEL LOG_LEVEL_INFO +#define LOG_LEVEL LOG_LEVEL_DEBUG #define LOG_MODULE "SI5351" #include "Log.h" bool Si5351C::Init(uint32_t clkin_freq) { 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; while (clkin_freq / (1 << clkinDiv) > 40000000) { @@ -26,19 +46,6 @@ bool Si5351C::Init(uint32_t clkin_freq) { value |= clkinDiv << 6; 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; } @@ -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; } +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) { return HAL_I2C_Mem_Read(i2c, address, (int) start, 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); return ReadRegisterRange(reg, config, 8); } + + diff --git a/Software/VNA_embedded/Application/Drivers/Si5351C.hpp b/Software/VNA_embedded/Application/Drivers/Si5351C.hpp index e55b74b..16b8011 100644 --- a/Software/VNA_embedded/Application/Drivers/Si5351C.hpp +++ b/Software/VNA_embedded/Application/Drivers/Si5351C.hpp @@ -30,6 +30,7 @@ public: FreqCLKINDiv(0) { }; bool Init(uint32_t clkin_freq = 0); + bool ConfigureCLKIn(uint32_t clkin_freq); 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 SetCLKtoXTAL(uint8_t clknum); @@ -38,6 +39,7 @@ public: bool Disable(uint8_t clknum); bool Locked(PLL pll); bool ResetPLL(PLL pll); + bool ExtCLKAvailable(); // Direct register access of clk configuration registers // config has to point to a buffer containing at least 8 bytes diff --git a/Software/VNA_embedded/Application/VNA.cpp b/Software/VNA_embedded/Application/VNA.cpp index 2ebda5f..5f9bde0 100644 --- a/Software/VNA_embedded/Application/VNA.cpp +++ b/Software/VNA_embedded/Application/VNA.cpp @@ -36,6 +36,9 @@ static uint16_t IFTableIndexCnt = 0; static constexpr uint32_t BandSwitchFrequency = 25000000; +static uint32_t extOutFreq = 0; +static bool extRefInUse = false; + using namespace VNAHAL; static void HaltedCallback() { @@ -129,6 +132,10 @@ bool VNA::Init() { Si5351.SetPLL(Si5351C::PLL::B, 800000000, Si5351C::PLLSource::XTAL); while(!Si5351.Locked(Si5351C::PLL::B)); + extRefInUse = 0; + extOutFreq = 0; + Si5351.Disable(SiChannel::ReferenceOut); + // Both MAX2871 get a 100MHz reference Si5351.SetCLK(SiChannel::Source, 100000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2); Si5351.Enable(SiChannel::Source); @@ -137,10 +144,6 @@ bool VNA::Init() { // 16MHz FPGA clock Si5351.SetCLK(SiChannel::FPGA, 16000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2); 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 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); 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; +} diff --git a/Software/VNA_embedded/Application/VNA.hpp b/Software/VNA_embedded/Application/VNA.hpp index 74d379f..0a90d83 100644 --- a/Software/VNA_embedded/Application/VNA.hpp +++ b/Software/VNA_embedded/Application/VNA.hpp @@ -12,7 +12,14 @@ using StatusCallback = void(*)(FPGA::SamplingResult); bool Init(); bool ConfigureSweep(Protocol::SweepSettings s, SweepCallback 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); +void fillDeviceInfo(Protocol::DeviceInfo *info); +namespace Ref { + bool available(); + bool applySettings(Protocol::ReferenceSettings s); +} }