more flexible USB protocol for VNA settings/measurements

This commit is contained in:
Jan Käberich 2022-08-06 16:22:12 +02:00
parent 74e6a439af
commit 047f6ce981
13 changed files with 203 additions and 82 deletions

View File

@ -463,8 +463,8 @@ void Device::ReceivedData()
handled_len = Protocol::DecodeBuffer(dataBuffer->getBuffer(), dataBuffer->getReceived(), &packet); handled_len = Protocol::DecodeBuffer(dataBuffer->getBuffer(), dataBuffer->getReceived(), &packet);
dataBuffer->removeBytes(handled_len); dataBuffer->removeBytes(handled_len);
switch(packet.type) { switch(packet.type) {
case Protocol::PacketType::Datapoint: case Protocol::PacketType::VNADatapoint:
emit DatapointReceived(packet.datapoint); emit DatapointReceived(packet.VNAdatapoint);
break; break;
case Protocol::PacketType::ManualStatusV1: case Protocol::PacketType::ManualStatusV1:
emit ManualStatusReceived(packet.manualStatusV1); emit ManualStatusReceived(packet.manualStatusV1);

View File

@ -77,7 +77,7 @@ public:
// Returns serial numbers of all connected devices // Returns serial numbers of all connected devices
static std::set<QString> GetDevices(); static std::set<QString> GetDevices();
signals: signals:
void DatapointReceived(Protocol::Datapoint); void DatapointReceived(Protocol::VNADatapoint<32>*);
void ManualStatusReceived(Protocol::ManualStatusV1); void ManualStatusReceived(Protocol::ManualStatusV1);
void SpectrumResultReceived(Protocol::SpectrumAnalyzerResult); void SpectrumResultReceived(Protocol::SpectrumAnalyzerResult);
void AmplitudeCorrectionPointReceived(Protocol::AmplitudeCorrectionPoint); void AmplitudeCorrectionPointReceived(Protocol::AmplitudeCorrectionPoint);

View File

@ -3,6 +3,8 @@
#include "preferences.h" #include "preferences.h"
#include "../VNA_embedded/Application/Communication/Protocol.hpp" #include "../VNA_embedded/Application/Communication/Protocol.hpp"
#include <cmath>
static VirtualDevice *connected = nullptr; static VirtualDevice *connected = nullptr;
using namespace std; using namespace std;
@ -193,20 +195,30 @@ VirtualDevice::VirtualDevice(QString serial)
m.measurements["PORT2"] = res.port2; m.measurements["PORT2"] = res.port2;
emit SAmeasurementReceived(m); emit SAmeasurementReceived(m);
}); });
connect(dev, &Device::DatapointReceived, [&](Protocol::Datapoint res){ connect(dev, &Device::DatapointReceived, [&](Protocol::VNADatapoint<32> *res){
VNAMeasurement m; VNAMeasurement m;
m.pointNum = res.pointNum; m.pointNum = res->pointNum;
m.Z0 = 50.0; m.Z0 = 50.0;
if(zerospan) { if(zerospan) {
m.us = res.us; m.us = res->us;
} else { } else {
m.frequency = res.frequency; m.frequency = res->frequency;
m.dBm = (double) res.cdbm / 100; m.dBm = (double) res->cdBm / 100;
} }
m.measurements["S11"] = complex<double>(res.real_S11, res.imag_S11); for(auto map : portStageMapping) {
m.measurements["S21"] = complex<double>(res.real_S21, res.imag_S21); // map.first is the port (starts at zero)
m.measurements["S12"] = complex<double>(res.real_S12, res.imag_S12); // map.second is the stage at which this port had the stimulus (starts at zero)
m.measurements["S22"] = complex<double>(res.real_S22, res.imag_S22); complex<double> ref = res->getValue(map.second, map.first, true);
for(int i=0;i<2;i++) {
complex<double> input = res->getValue(map.second, i, false);
if(!std::isnan(ref.real()) && !std::isnan(input.real())) {
// got both required measurements
QString name = "S"+QString::number(i+1)+QString::number(map.first+1);
m.measurements[name] = input / ref;
}
}
}
delete res;
emit VNAmeasurementReceived(m); emit VNAmeasurementReceived(m);
}); });
} else { } else {
@ -301,6 +313,13 @@ bool VirtualDevice::setVNA(const VirtualDevice::VNASettings &s, std::function<vo
if(s.excitedPorts.size() == 0) { if(s.excitedPorts.size() == 0) {
return setIdle(cb); return setIdle(cb);
} }
// create port->stage mapping
portStageMapping.clear();
for(int i=0;i<s.excitedPorts.size();i++) {
portStageMapping[s.excitedPorts[i]] = i;
}
zerospan = (s.freqStart == s.freqStop) && (s.dBmStart == s.dBmStop); zerospan = (s.freqStart == s.freqStop) && (s.dBmStart == s.dBmStop);
auto pref = Preferences::getInstance(); auto pref = Preferences::getInstance();
if(!isCompoundDevice()) { if(!isCompoundDevice()) {
@ -311,11 +330,13 @@ bool VirtualDevice::setVNA(const VirtualDevice::VNASettings &s, std::function<vo
sd.if_bandwidth = s.IFBW; sd.if_bandwidth = s.IFBW;
sd.cdbm_excitation_start = s.dBmStart * 100; sd.cdbm_excitation_start = s.dBmStart * 100;
sd.cdbm_excitation_stop = s.dBmStop * 100; sd.cdbm_excitation_stop = s.dBmStop * 100;
sd.excitePort1 = find(s.excitedPorts.begin(), s.excitedPorts.end(), 1) != s.excitedPorts.end() ? 1 : 0; sd.stages = s.excitedPorts.size() - 1;
sd.excitePort2 = find(s.excitedPorts.begin(), s.excitedPorts.end(), 2) != s.excitedPorts.end() ? 1 : 0; sd.port1Stage = find(s.excitedPorts.begin(), s.excitedPorts.end(), 0) - s.excitedPorts.begin();
sd.port2Stage = find(s.excitedPorts.begin(), s.excitedPorts.end(), 1) - s.excitedPorts.begin();
sd.suppressPeaks = pref.Acquisition.suppressPeaks ? 1 : 0; sd.suppressPeaks = pref.Acquisition.suppressPeaks ? 1 : 0;
sd.fixedPowerSetting = pref.Acquisition.adjustPowerLevel || s.dBmStart != s.dBmStop ? 0 : 1; sd.fixedPowerSetting = pref.Acquisition.adjustPowerLevel || s.dBmStart != s.dBmStop ? 0 : 1;
sd.logSweep = s.logSweep ? 1 : 0; sd.logSweep = s.logSweep ? 1 : 0;
sd.syncMode = 0;
return devices[0]->Configure(sd, [=](Device::TransmissionResult r){ return devices[0]->Configure(sd, [=](Device::TransmissionResult r){
if(cb) { if(cb) {
cb(r == Device::TransmissionResult::Ack); cb(r == Device::TransmissionResult::Ack);
@ -372,6 +393,7 @@ bool VirtualDevice::setSA(const VirtualDevice::SASettings &s, std::function<void
sd.trackingGeneratorPort = s.trackingPort; sd.trackingGeneratorPort = s.trackingPort;
sd.trackingGeneratorOffset = s.trackingOffset; sd.trackingGeneratorOffset = s.trackingOffset;
sd.trackingPower = s.trackingPower; sd.trackingPower = s.trackingPower;
sd.syncMode = 0;
return devices[0]->Configure(sd, [=](Device::TransmissionResult r){ return devices[0]->Configure(sd, [=](Device::TransmissionResult r){
if(cb) { if(cb) {
cb(r == Device::TransmissionResult::Ack); cb(r == Device::TransmissionResult::Ack);

View File

@ -67,7 +67,7 @@ public:
double IFBW; double IFBW;
int points; int points;
bool logSweep; bool logSweep;
std::vector<int> excitedPorts; std::vector<int> excitedPorts; // port count starts at one
}; };
class VNAMeasurement { class VNAMeasurement {
public: public:
@ -177,12 +177,15 @@ private:
Status status; Status status;
bool isCompound; bool isCompound;
std::vector<Device*> devices; std::vector<Device*> devices;
std::vector<int> portMapping;
bool zerospan; bool zerospan;
std::map<Device*, Device::TransmissionResult> results; std::map<Device*, Device::TransmissionResult> results;
CompoundDevice *cdev; CompoundDevice *cdev;
std::map<int, std::vector<Protocol::VNADatapoint<32>*>> compoundDataBuffer;
std::map<int, int> portStageMapping; // maps from excitedPort (count starts at zero) to stage (count starts at zero)
}; };
Q_DECLARE_METATYPE(VirtualDevice::Status) Q_DECLARE_METATYPE(VirtualDevice::Status)

View File

@ -157,6 +157,7 @@ std::vector<Trace *> TraceModel::getTraces() const
bool TraceModel::PortExcitationRequired(int port) bool TraceModel::PortExcitationRequired(int port)
{ {
port++;
for(auto t : traces) { for(auto t : traces) {
if(t->getSource() == Trace::Source::Live && !t->isPaused()) { if(t->getSource() == Trace::Source::Live && !t->isPaused()) {
// this trace needs measurements from VNA, check if port has to be excited for its measurement // this trace needs measurements from VNA, check if port has to be excited for its measurement

View File

@ -925,11 +925,11 @@ void VNA::SettingsChanged(bool resetTraces, std::function<void (bool)> cb)
VirtualDevice::VNASettings s = {}; VirtualDevice::VNASettings s = {};
s.IFBW = settings.bandwidth; s.IFBW = settings.bandwidth;
if(Preferences::getInstance().Acquisition.alwaysExciteBothPorts) { if(Preferences::getInstance().Acquisition.alwaysExciteBothPorts) {
for(int i=1;i<=VirtualDevice::getInfo(window->getDevice()).ports;i++) { for(int i=0;i<VirtualDevice::getInfo(window->getDevice()).ports;i++) {
s.excitedPorts.push_back(i); s.excitedPorts.push_back(i);
} }
} else { } else {
for(int i=1;i<=VirtualDevice::getInfo(window->getDevice()).ports;i++) { for(int i=0;i<VirtualDevice::getInfo(window->getDevice()).ports;i++) {
if(traceModel.PortExcitationRequired(i)) if(traceModel.PortExcitationRequired(i))
s.excitedPorts.push_back(i); s.excitedPorts.push_back(i);
} }

View File

@ -62,7 +62,7 @@ uint16_t Protocol::DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info) {
/* The complete frame has been received, check checksum */ /* The complete frame has been received, check checksum */
auto type = (PacketType) data[3]; auto type = (PacketType) data[3];
uint32_t crc = *(uint32_t*) &data[length - 4]; uint32_t crc = *(uint32_t*) &data[length - 4];
if(type != PacketType::Datapoint) { if(type != PacketType::VNADatapoint) {
uint32_t compare = CRC32(0, data, length - 4); uint32_t compare = CRC32(0, data, length - 4);
if(crc != compare) { if(crc != compare) {
// CRC mismatch, remove header // CRC mismatch, remove header
@ -70,6 +70,8 @@ uint16_t Protocol::DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info) {
info->type = PacketType::None; info->type = PacketType::None;
return data - buf; return data - buf;
} }
// Valid packet, copy packet type and payload
memcpy(info, &data[3], length - 7);
} else { } else {
// Datapoint has the CRC set to zero // Datapoint has the CRC set to zero
if(crc != 0x00000000) { if(crc != 0x00000000) {
@ -77,17 +79,19 @@ uint16_t Protocol::DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info) {
info->type = PacketType::None; info->type = PacketType::None;
return data - buf; return data - buf;
} }
// Create the datapoint
info->type = (PacketType) data[3];
info->VNAdatapoint = new VNADatapoint<32>;
info->VNAdatapoint->decode(&data[4], length - 8);
} }
// Valid packet, copy packet type and payload
memcpy(info, &data[3], length - 7);
return data - buf + length; return data - buf + length;
} }
uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_t destsize) { uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_t destsize) {
int16_t payload_size = 0; int16_t payload_size = 0;
switch (packet.type) { switch (packet.type) {
case PacketType::Datapoint: payload_size = sizeof(packet.datapoint); break; // case PacketType::Datapoint: payload_size = sizeof(packet.datapoint); break;
case PacketType::SweepSettings: payload_size = sizeof(packet.settings); break; case PacketType::SweepSettings: payload_size = sizeof(packet.settings); break;
case PacketType::Reference: payload_size = sizeof(packet.reference); break; case PacketType::Reference: payload_size = sizeof(packet.reference); break;
case PacketType::DeviceInfo: payload_size = sizeof(packet.info); break; case PacketType::DeviceInfo: payload_size = sizeof(packet.info); break;
@ -115,6 +119,7 @@ uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_
case PacketType::RequestDeviceStatus: case PacketType::RequestDeviceStatus:
// no payload // no payload
break; break;
case PacketType::VNADatapoint: payload_size = packet.VNAdatapoint->requiredBufferSize(); break;
case PacketType::None: case PacketType::None:
break; break;
} }
@ -126,14 +131,18 @@ uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_
dest[0] = header; dest[0] = header;
uint16_t overall_size = payload_size + 8; uint16_t overall_size = payload_size + 8;
memcpy(&dest[1], &overall_size, 2); memcpy(&dest[1], &overall_size, 2);
memcpy(&dest[3], &packet, payload_size + 1); // one additional byte for the packet type // Further encoding uses a special case for VNADatapoint packettype
// Calculate checksum
uint32_t crc = 0x00000000; uint32_t crc = 0x00000000;
if(packet.type == PacketType::Datapoint) { if(packet.type == PacketType::VNADatapoint) {
// CRC calculation takes about 18us which is the bulk of the time required to encode and transmit a datapoint. // CRC calculation takes about 18us which is the bulk of the time required to encode and transmit a datapoint.
// Skip CRC for data points to optimize throughput // Skip CRC for data points to optimize throughput
dest[3] = (uint8_t) packet.type;
packet.VNAdatapoint->encode(&dest[4], destsize - 8);
crc = 0x00000000; crc = 0x00000000;
} else { } else {
// Copy rest of the packet
memcpy(&dest[3], &packet, payload_size + 1); // one additional byte for the packet type
// Calculate the CRC
crc = CRC32(0, dest, overall_size - 4); crc = CRC32(0, dest, overall_size - 4);
} }
memcpy(&dest[overall_size - 4], &crc, 4); memcpy(&dest[overall_size - 4], &crc, 4);

View File

@ -1,13 +1,110 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <cstring>
#include <limits>
#include <complex>
namespace Protocol { namespace Protocol {
static constexpr uint16_t Version = 11; static constexpr uint16_t Version = 12;
#pragma pack(push, 1) #pragma pack(push, 1)
enum class Source : uint8_t {
Port1 = 0x01,
Port2 = 0x02,
Port3 = 0x04,
Port4 = 0x08,
Reference = 0x10,
};
template<int s> class VNADatapoint {
public:
VNADatapoint() {
clear();
}
void clear() {
num_values = 0;
pointNum = 0;
cdBm = 0;
frequency = 0;
}
bool addValue(float real, float imag, uint8_t stage, int sourceMask) {
if(num_values >= s) {
return false;
}
real_values[num_values] = real;
imag_values[num_values] = imag;
descr_values[num_values] = stage << 5 | sourceMask;
num_values++;
return true;
}
bool encode(uint8_t *dest, uint16_t destSize) {
if(requiredBufferSize() > destSize) {
return false;
}
memcpy(dest, &frequency, 8);
memcpy(dest+8, &cdBm, 2);
memcpy(dest+10, &pointNum, 2);
dest += 12;
memcpy(dest, real_values, num_values * 4);
dest += num_values * 4;
memcpy(dest, imag_values, num_values * 4);
dest += num_values * 4;
memcpy(dest, descr_values, num_values);
return true;
}
void decode(const uint8_t *buffer, uint16_t size) {
num_values = (size - (8+2+2)) / (1+4+4);
memcpy(&frequency, buffer, 8);
memcpy(&cdBm, buffer+8, 2);
memcpy(&pointNum, buffer+10, 2);
buffer += 12;
memcpy(real_values, buffer, num_values * 4);
buffer += num_values * 4;
memcpy(imag_values, buffer, num_values * 4);
buffer += num_values * 4;
memcpy(descr_values, buffer, num_values);
}
std::complex<double> getValue(uint8_t stage, uint8_t port, bool reference) {
uint8_t sourceMask = 0;
sourceMask |= 0x01 << port;
if(reference) {
sourceMask |= (int) Source::Reference;
}
for(int i=0;i<num_values;i++) {
if(descr_values[i] >> 5 != stage) {
continue;
}
if((descr_values[i] & sourceMask) != sourceMask) {
continue;
}
return std::complex<double>(real_values[i], imag_values[i]);
}
return std::numeric_limits<std::complex<double>>::quiet_NaN();
}
uint16_t requiredBufferSize() {
return 8+2+2+ num_values * (4+4+1);
}
union {
uint64_t frequency;
uint64_t us;
};
int16_t cdBm;
uint16_t pointNum;
private:
float real_values[s];
float imag_values[s];
uint8_t descr_values[s];
uint8_t num_values;
};
using Datapoint = struct _datapoint { using Datapoint = struct _datapoint {
float real_S11, imag_S11; float real_S11, imag_S11;
float real_S21, imag_S21; float real_S21, imag_S21;
@ -33,11 +130,20 @@ using SweepSettings = struct _sweepSettings {
uint16_t points; uint16_t points;
uint32_t if_bandwidth; uint32_t if_bandwidth;
int16_t cdbm_excitation_start; // in 1/100 dbm int16_t cdbm_excitation_start; // in 1/100 dbm
uint8_t excitePort1:1; uint16_t unused:2;
uint8_t excitePort2:1; uint16_t suppressPeaks:1;
uint8_t suppressPeaks:1; uint16_t fixedPowerSetting:1; // if set the attenuator and source PLL power will not be changed across the sweep
uint8_t fixedPowerSetting:1; // if set the attenuator and source PLL power will not be changed across the sweep uint16_t logSweep:1;
uint8_t logSweep:1; uint16_t stages:3;
uint16_t port1Stage:3;
uint16_t port2Stage:3;
/*
* 0: no synchronization
* 1: USB synchronization
* 2: External reference synchronization
* 3: Trigger synchronization (not supported yet by hardware)
*/
uint16_t syncMode:2;
int16_t cdbm_excitation_stop; // in 1/100 dbm int16_t cdbm_excitation_stop; // in 1/100 dbm
}; };
@ -145,6 +251,13 @@ using SpectrumAnalyzerSettings = struct _spectrumAnalyzerSettings {
uint8_t trackingGenerator :1; uint8_t trackingGenerator :1;
uint8_t applySourceCorrection :1; uint8_t applySourceCorrection :1;
uint8_t trackingGeneratorPort :1; // 0 for port1, 1 for port2 uint8_t trackingGeneratorPort :1; // 0 for port1, 1 for port2
/*
* 0: no synchronization
* 1: USB synchronization
* 2: External reference synchronization
* 3: Trigger synchronization (not supported yet by hardware)
*/
uint8_t syncMode :2;
int64_t trackingGeneratorOffset; int64_t trackingGeneratorOffset;
int16_t trackingPower; int16_t trackingPower;
}; };
@ -191,7 +304,7 @@ using AcquisitionFrequencySettings = struct _acquisitionfrequencysettigns {
enum class PacketType : uint8_t { enum class PacketType : uint8_t {
None = 0, None = 0,
Datapoint = 1, //Datapoint = 1, // Deprecated, replaced by VNADatapoint
SweepSettings = 2, SweepSettings = 2,
ManualStatusV1 = 3, ManualStatusV1 = 3,
ManualControlV1 = 4, ManualControlV1 = 4,
@ -217,12 +330,13 @@ enum class PacketType : uint8_t {
AcquisitionFrequencySettings = 24, AcquisitionFrequencySettings = 24,
DeviceStatusV1 = 25, DeviceStatusV1 = 25,
RequestDeviceStatus = 26, RequestDeviceStatus = 26,
VNADatapoint = 27,
}; };
using PacketInfo = struct _packetinfo { using PacketInfo = struct _packetinfo {
PacketType type; PacketType type;
union { union {
Datapoint datapoint; // Datapoint datapoint; // Deprecated, use VNADatapoint instead
SweepSettings settings; SweepSettings settings;
ReferenceSettings reference; ReferenceSettings reference;
GeneratorSettings generator; GeneratorSettings generator;
@ -236,6 +350,11 @@ using PacketInfo = struct _packetinfo {
AmplitudeCorrectionPoint amplitudePoint; AmplitudeCorrectionPoint amplitudePoint;
FrequencyCorrection frequencyCorrection; FrequencyCorrection frequencyCorrection;
AcquisitionFrequencySettings acquisitionFrequencySettings; AcquisitionFrequencySettings acquisitionFrequencySettings;
/*
* When encoding: Pointer may go invalid after call to EncodePacket
* When decoding: VNADatapoint is created on heap by DecodeBuffer, freeing is up to the caller
*/
VNADatapoint<32> *VNAdatapoint;
}; };
}; };

View File

@ -130,10 +130,10 @@ void FPGA::SetSamplesPerPoint(uint32_t nsamples) {
WriteRegister(Reg::SamplesPerPoint, nsamples); WriteRegister(Reg::SamplesPerPoint, nsamples);
} }
void FPGA::SetupSweep(uint8_t stages, uint8_t port1_stage, uint8_t port2_stage, bool individual_halt) { void FPGA::SetupSweep(uint8_t stages, uint8_t port1_stage, uint8_t port2_stage, bool synchronize) {
uint16_t value = 0x0000; uint16_t value = 0x0000;
value |= (uint16_t) (stages & 0x07) << 13; value |= (uint16_t) (stages & 0x07) << 13;
if(individual_halt) { if(synchronize) {
value |= 0x1000; value |= 0x1000;
} }
value |= (port1_stage & 0x07) << 3; value |= (port1_stage & 0x07) << 3;

View File

@ -114,7 +114,7 @@ bool Init(HaltedCallback cb = nullptr);
void WriteRegister(FPGA::Reg reg, uint16_t value); void WriteRegister(FPGA::Reg reg, uint16_t value);
void SetNumberOfPoints(uint16_t npoints); void SetNumberOfPoints(uint16_t npoints);
void SetSamplesPerPoint(uint32_t nsamples); void SetSamplesPerPoint(uint32_t nsamples);
void SetupSweep(uint8_t stages, uint8_t port1_stage, uint8_t port2_stage, bool individual_halt = false); void SetupSweep(uint8_t stages, uint8_t port1_stage, uint8_t port2_stage, bool synchronize = false);
void Enable(Periphery p, bool enable = true); void Enable(Periphery p, bool enable = true);
void Disable(Periphery p); void Disable(Periphery p);
bool IsEnabled(Periphery p); bool IsEnabled(Periphery p);

View File

@ -19,7 +19,7 @@ static uint8_t *USBD_Class_GetDeviceQualifierDescriptor (uint16_t *length);
static usbd_recv_callback_t cb; static usbd_recv_callback_t cb;
static uint8_t usb_receive_buffer[1024]; static uint8_t usb_receive_buffer[1024];
static uint8_t usb_transmit_fifo[8192]; static uint8_t usb_transmit_fifo[6144];
static uint16_t usb_transmit_read_index = 0; static uint16_t usb_transmit_read_index = 0;
static uint16_t usb_transmit_fifo_level = 0; static uint16_t usb_transmit_fifo_level = 0;
static bool data_transmission_active = false; static bool data_transmission_active = false;

View File

@ -224,7 +224,7 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
FPGA::SetWindow((FPGA::Window) s.WindowType); FPGA::SetWindow((FPGA::Window) s.WindowType);
FPGA::Enable(FPGA::Periphery::LO1Chip); FPGA::Enable(FPGA::Periphery::LO1Chip);
FPGA::Enable(FPGA::Periphery::LO1RF); FPGA::Enable(FPGA::Periphery::LO1RF);
FPGA::SetupSweep(0, s.trackingGeneratorPort == 1, s.trackingGeneratorPort == 0); FPGA::SetupSweep(0, s.trackingGeneratorPort == 1, s.trackingGeneratorPort == 0, s.syncMode != 0);
FPGA::Enable(FPGA::Periphery::PortSwitch, s.trackingGenerator); FPGA::Enable(FPGA::Periphery::PortSwitch, s.trackingGenerator);
FPGA::Enable(FPGA::Periphery::Amplifier, s.trackingGenerator); FPGA::Enable(FPGA::Periphery::Amplifier, s.trackingGenerator);
FPGA::Enable(FPGA::Periphery::Port1Mixer); FPGA::Enable(FPGA::Periphery::Port1Mixer);

View File

@ -22,9 +22,8 @@
static Protocol::SweepSettings settings; static Protocol::SweepSettings settings;
static uint16_t pointCnt; static uint16_t pointCnt;
static uint8_t stageCnt; static uint8_t stageCnt;
static uint8_t stages;
static double logMultiplier, logFrequency; static double logMultiplier, logFrequency;
static Protocol::Datapoint data; static Protocol::VNADatapoint<32> data;
static bool active = false; static bool active = false;
static Si5351C::DriveStrength fixedPowerLowband; static Si5351C::DriveStrength fixedPowerLowband;
static bool adcShifted; static bool adcShifted;
@ -81,12 +80,6 @@ bool VNA::Setup(Protocol::SweepSettings s) {
VNA::Stop(); VNA::Stop();
vTaskDelay(5); vTaskDelay(5);
HW::SetMode(HW::Mode::VNA); HW::SetMode(HW::Mode::VNA);
if(s.excitePort1 == 0 && s.excitePort2 == 0) {
// both ports disabled, nothing to do
HW::SetIdle();
active = false;
return false;
}
// Abort possible active sweep first // Abort possible active sweep first
FPGA::SetMode(FPGA::Mode::FPGA); FPGA::SetMode(FPGA::Mode::FPGA);
FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, HW::getADCPrescaler()); FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, HW::getADCPrescaler());
@ -285,19 +278,7 @@ bool VNA::Setup(Protocol::SweepSettings s) {
FPGA::Enable(FPGA::Periphery::SourceRF); FPGA::Enable(FPGA::Periphery::SourceRF);
FPGA::Enable(FPGA::Periphery::LO1Chip); FPGA::Enable(FPGA::Periphery::LO1Chip);
FPGA::Enable(FPGA::Periphery::LO1RF); FPGA::Enable(FPGA::Periphery::LO1RF);
if(s.excitePort1 && s.excitePort2) { FPGA::SetupSweep(s.stages, s.port1Stage, s.port2Stage, s.syncMode != 0);
// two stages, port 1 first, followed by port 2
FPGA::SetupSweep(1, 0, 1);
stages = 2;
} else if(s.excitePort1) {
// one stage, port 1 only
FPGA::SetupSweep(0, 0, 1);
stages = 1;
} else {
// one stage, port 2 only
FPGA::SetupSweep(0, 1, 0);
stages = 1;
}
FPGA::Enable(FPGA::Periphery::PortSwitch); FPGA::Enable(FPGA::Periphery::PortSwitch);
pointCnt = 0; pointCnt = 0;
stageCnt = 0; stageCnt = 0;
@ -315,9 +296,10 @@ bool VNA::Setup(Protocol::SweepSettings s) {
static void PassOnData() { static void PassOnData() {
Protocol::PacketInfo info; Protocol::PacketInfo info;
info.type = Protocol::PacketType::Datapoint; info.type = Protocol::PacketType::VNADatapoint;
info.datapoint = data; info.VNAdatapoint = &data;
Communication::Send(info); Communication::Send(info);
data.clear();
} }
bool VNA::MeasurementDone(const FPGA::SamplingResult &result) { bool VNA::MeasurementDone(const FPGA::SamplingResult &result) {
@ -330,11 +312,9 @@ bool VNA::MeasurementDone(const FPGA::SamplingResult &result) {
return false; return false;
} }
// normal sweep mode // normal sweep mode
auto port1_raw = std::complex<float>(result.P1I, result.P1Q); data.addValue(result.P1I, result.P1Q, stageCnt, (int) Protocol::Source::Port1);
auto port2_raw = std::complex<float>(result.P2I, result.P2Q); data.addValue(result.P2I, result.P2Q, stageCnt, (int) Protocol::Source::Port2);
auto ref = std::complex<float>(result.RefI, result.RefQ); data.addValue(result.RefI, result.RefQ, stageCnt, (int) Protocol::Source::Port1 | (int) Protocol::Source::Port2 | (int) Protocol::Source::Reference);
auto port1 = port1_raw / ref;
auto port2 = port2_raw / ref;
data.pointNum = pointCnt; data.pointNum = pointCnt;
if(zerospan) { if(zerospan) {
uint64_t timestamp = HW::getLastISRTimestamp(); uint64_t timestamp = HW::getLastISRTimestamp();
@ -348,24 +328,11 @@ bool VNA::MeasurementDone(const FPGA::SamplingResult &result) {
} else { } else {
// non-zero span, set frequency/power // non-zero span, set frequency/power
data.frequency = getPointFrequency(pointCnt); data.frequency = getPointFrequency(pointCnt);
data.cdbm = settings.cdbm_excitation_start + (settings.cdbm_excitation_stop - settings.cdbm_excitation_start) * pointCnt / (settings.points - 1); data.cdBm = settings.cdbm_excitation_start + (settings.cdbm_excitation_stop - settings.cdbm_excitation_start) * pointCnt / (settings.points - 1);
}
if(stageCnt == 0 && settings.excitePort1) {
// stimulus is present at port 1
data.real_S11 = port1.real();
data.imag_S11 = port1.imag();
data.real_S21 = port2.real();
data.imag_S21 = port2.imag();
} else {
// stimulus is present at port 2
data.real_S12 = port1.real();
data.imag_S12 = port1.imag();
data.real_S22 = port2.real();
data.imag_S22 = port2.imag();
} }
// figure out whether this sweep point is complete // figure out whether this sweep point is complete
stageCnt++; stageCnt++;
if(stageCnt == stages) { if(stageCnt > settings.stages) {
// point is complete // point is complete
stageCnt = 0; stageCnt = 0;
STM::DispatchToInterrupt(PassOnData); STM::DispatchToInterrupt(PassOnData);
@ -507,7 +474,7 @@ void VNA::PrintStatus() {
HAL_Delay(10); HAL_Delay(10);
LOG_INFO("Points: %d/%d", pointCnt, settings.points); LOG_INFO("Points: %d/%d", pointCnt, settings.points);
HAL_Delay(10); HAL_Delay(10);
LOG_INFO("Stages: %d/%d", stageCnt, stages); LOG_INFO("Stages: %d/%d", stageCnt, settings.stages);
HAL_Delay(10); HAL_Delay(10);
LOG_INFO("FPGA status: 0x%04x", FPGA::GetStatus()); LOG_INFO("FPGA status: 0x%04x", FPGA::GetStatus());
} }