WIP: preparation for zero span mode

This commit is contained in:
Jan Käberich 2022-06-20 01:02:09 +02:00
parent e8560e1a67
commit 6393ae7fc3
22 changed files with 299 additions and 69 deletions

View File

@ -341,6 +341,9 @@ These commands change or query VNA settings. Although most of them are available
\subsubsection{VNA:FREQuency:FULL}
\event{Sets the device to the maximum span possible}{VNA:FREQuency:FULL}{None}
\subsubsection{VNA:FREQuency:ZERO}
\event{Sets the device to zero span mode}{VNA:FREQuency:ZERO}{None}
\subsubsection{VNA:POWer:START}
\event{Sets the start power of the power sweep}{VNA:POWer:START}{<start power>, in dBm}
\query{Queries the currently selected start power}{VNA:POWer:START?}{None}{start power in dBm}

View File

@ -174,6 +174,39 @@ std::vector<Marker::Format> Marker::applicableFormats()
break;
}
break;
case Trace::DataType::TimeZeroSpan:
switch(type) {
case Type::Manual:
case Type::Delta:
case Type::Maximum:
case Type::Minimum:
case Type::PeakTable:
if(Trace::isSAParamater(parentTrace->liveParameter())) {
ret.push_back(Format::dBm);
ret.push_back(Format::dBuV);
} else {
ret.push_back(Format::dB);
ret.push_back(Format::dBAngle);
ret.push_back(Format::RealImag);
}
if(parentTrace) {
if(parentTrace->isReflection()) {
ret.push_back(Format::Impedance);
ret.push_back(Format::VSWR);
ret.push_back(Format::SeriesR);
ret.push_back(Format::Capacitance);
ret.push_back(Format::Inductance);
ret.push_back(Format::QualityFactor);
}
if(!isnan(parentTrace->getNoise(parentTrace->minX()))) {
ret.push_back(Format::Noise);
}
}
break;
default:
break;
}
break;
case Trace::DataType::Frequency:
switch(type) {
case Type::Manual:
@ -313,6 +346,7 @@ QString Marker::readableData(Format f)
break;
case Trace::DataType::Frequency:
case Trace::DataType::Power:
case Trace::DataType::TimeZeroSpan:
switch(type) {
case Type::PeakTable:
return "Found " + QString::number(helperMarkers.size()) + " peaks";
@ -461,6 +495,7 @@ QString Marker::readablePosition()
}
switch(getDomain()) {
case Trace::DataType::Time:
case Trace::DataType::TimeZeroSpan:
ret += Unit::ToString(pos, "s", "pnum ", 6);
break;
case Trace::DataType::Frequency:
@ -487,6 +522,17 @@ QString Marker::readableSettings()
return "Unhandled case";
}
break;
case Trace::DataType::TimeZeroSpan:
switch(type) {
case Type::Manual:
case Type::Maximum:
case Type::Minimum:
case Type::Delta:
return Unit::ToString(position, "s", "fpnum ", 4);
default:
return "Unhandled case";
}
break;
case Trace::DataType::Frequency:
switch(type) {
case Type::Manual:
@ -539,6 +585,17 @@ QString Marker::tooltipSettings()
break;
}
break;
case Trace::DataType::TimeZeroSpan:
switch(type) {
case Type::Manual:
case Type::Maximum:
case Type::Minimum:
case Type::Delta:
return "Time";
default:
break;
}
break;
case Trace::DataType::Frequency:
switch(type) {
case Type::Manual:
@ -829,6 +886,12 @@ std::set<Marker::Type> Marker::getSupportedTypes()
}
}
break;
case Trace::DataType::TimeZeroSpan:
supported.insert(Type::Manual);
supported.insert(Type::Maximum);
supported.insert(Type::Minimum);
supported.insert(Type::Delta);
break;
case Trace::DataType::Power:
supported.insert(Type::Manual);
supported.insert(Type::Maximum);
@ -1285,6 +1348,19 @@ SIUnitEdit *Marker::getSettingsEditor()
return nullptr;
}
break;
case Trace::DataType::TimeZeroSpan:
switch(type) {
case Type::Manual:
case Type::Maximum:
case Type::Minimum:
case Type::Delta:
ret = new SIUnitEdit("", "fpnum k", 6);
ret->setValue(position);
break;
default:
return nullptr;
}
break;
case Trace::DataType::Frequency:
switch(type) {
case Type::Manual:
@ -1347,6 +1423,19 @@ void Marker::adjustSettings(double value)
setPosition(value);
}
}
break;
default:
break;
}
break;
case Trace::DataType::TimeZeroSpan:
switch(type) {
case Type::Manual:
case Type::Maximum:
case Type::Minimum:
case Type::Delta:
setPosition(value);
break;
default:
break;
}

View File

@ -61,6 +61,7 @@ public:
Frequency,
Time,
Power,
TimeZeroSpan,
Invalid,
};

View File

@ -63,44 +63,54 @@ void Trace::clear() {
emit outputSamplesChanged(0, 0);
}
void Trace::addData(const Trace::Data& d, DataType domain, double reference_impedance) {
void Trace::addData(const Trace::Data& d, DataType domain, double reference_impedance, int index) {
if(this->domain != domain) {
clear();
this->domain = domain;
emit typeChanged(this);
}
// add or replace data in vector while keeping it sorted with increasing frequency
auto lower = lower_bound(data.begin(), data.end(), d, [](const Data &lhs, const Data &rhs) -> bool {
return lhs.x < rhs.x;
});
// calculate index now because inserting a sample into data might lead to reallocation -> arithmetic on lower not valid anymore
auto index = lower - data.begin();
if(lower == data.end()) {
// highest frequency yet, add to vector
data.push_back(d);
} else if(lower->x == d.x) {
switch(_liveType) {
case LivedataType::Overwrite:
// replace this data element
*lower = d;
break;
case LivedataType::MaxHold:
// replace this data element
if(abs(d.y) > abs(lower->y)) {
*lower = d;
}
break;
case LivedataType::MinHold:
// replace this data element
if(abs(d.y) < abs(lower->y)) {
*lower = d;
}
break;
default: break;
if(index >= 0) {
// index position specified
if(data.size() <= index) {
data.resize(index + 1);
}
data[index] = d;
} else {
// insert at this position
data.insert(lower, d);
// no index given, determine position by X-coordinate
// add or replace data in vector while keeping it sorted with increasing frequency
auto lower = lower_bound(data.begin(), data.end(), d, [](const Data &lhs, const Data &rhs) -> bool {
return lhs.x < rhs.x;
});
// calculate index now because inserting a sample into data might lead to reallocation -> arithmetic on lower not valid anymore
index = lower - data.begin();
if(lower == data.end()) {
// highest frequency yet, add to vector
data.push_back(d);
} else if(lower->x == d.x) {
switch(_liveType) {
case LivedataType::Overwrite:
// replace this data element
*lower = d;
break;
case LivedataType::MaxHold:
// replace this data element
if(abs(d.y) > abs(lower->y)) {
*lower = d;
}
break;
case LivedataType::MinHold:
// replace this data element
if(abs(d.y) < abs(lower->y)) {
*lower = d;
}
break;
default: break;
}
} else {
// insert at this position
data.insert(lower, d);
}
}
if(this->reference_impedance != reference_impedance) {
this->reference_impedance = reference_impedance;

View File

@ -45,7 +45,7 @@ public:
};
void clear();
void addData(const Data& d, DataType domain, double reference_impedance = 50.0);
void addData(const Data& d, DataType domain, double reference_impedance = 50.0, int index = -1);
void addData(const Data& d, const Protocol::SpectrumAnalyzerSettings& s);
void setName(QString name);
void setVelocityFactor(double v);

View File

@ -324,6 +324,7 @@ std::set<YAxis::Type> YAxis::getSupported(XAxis::Type type, TraceModel::DataSour
switch(type) {
case XAxis::Type::Frequency:
case XAxis::Type::Power:
case XAxis::Type::TimeZeroSpan:
ret.insert(YAxis::Type::Magnitude);
ret.insert(YAxis::Type::MagnitudeLinear);
ret.insert(YAxis::Type::Phase);
@ -489,6 +490,7 @@ QString XAxis::TypeToName(Type type)
case Type::Time: return "Time";
case Type::Distance: return "Distance";
case Type::Power: return "Power";
case Type::TimeZeroSpan: return "Time (Zero Span)";
default: return "Unknown";
}
}
@ -511,6 +513,7 @@ QString XAxis::Unit(Type type)
case Type::Time: return "s";
case Type::Distance: return "m";
case Type::Power: return "dBm";
case Type::TimeZeroSpan: return "s";
default: return "";
}
}

View File

@ -36,6 +36,7 @@ public:
Time,
Distance,
Power,
TimeZeroSpan,
Last,
};
XAxis();

View File

@ -212,6 +212,7 @@ void TraceModel::addVNAData(const VNAData& d, TraceMath::DataType datatype)
source = DataSource::VNA;
for(auto t : traces) {
if (t->isLive() && !t->isPaused()) {
int index = -1;
Trace::Data td;
switch(datatype) {
case TraceMath::DataType::Frequency:
@ -220,6 +221,10 @@ void TraceModel::addVNAData(const VNAData& d, TraceMath::DataType datatype)
case TraceMath::DataType::Power:
td.x = (double) d.cdbm / 100.0;
break;
case TraceMath::DataType::TimeZeroSpan:
td.x = d.time;
index = d.pointNum;
break;
default:
// invalid type, can not add
return;
@ -233,7 +238,7 @@ void TraceModel::addVNAData(const VNAData& d, TraceMath::DataType datatype)
// not a VNA trace, skip
continue;
}
t->addData(td, datatype, d.reference_impedance);
t->addData(td, datatype, d.reference_impedance, index);
}
}
}

View File

@ -196,9 +196,6 @@ QPoint TraceSmithChart::dataToPixel(std::complex<double> d)
QPoint TraceSmithChart::dataToPixel(Trace::Data d)
{
if(d.x < sweep_fmin || d.x > sweep_fmax) {
return QPoint();
}
return dataToPixel(d.y);}
std::complex<double> TraceSmithChart::pixelToData(QPoint p)
@ -450,6 +447,7 @@ bool TraceSmithChart::dropSupported(Trace *t)
switch(t->outputType()) {
case Trace::DataType::Frequency:
case Trace::DataType::Power:
case Trace::DataType::TimeZeroSpan:
return true;
default:
return false;

View File

@ -244,6 +244,11 @@ bool TraceXYPlot::configureForTrace(Trace *t)
setYAxis(0, YAxis::Type::Magnitude, false, true, 0, 1, 1.0);
setYAxis(1, YAxis::Type::Phase, false, true, 0, 1, 1.0);
break;
case Trace::DataType::TimeZeroSpan:
setXAxis(XAxis::Type::TimeZeroSpan, XAxisMode::FitTraces, false, 0, 1, 0.1);
setYAxis(0, YAxis::Type::Magnitude, false, true, 0, 1, 1.0);
setYAxis(1, YAxis::Type::Phase, false, true, 0, 1, 1.0);
break;
case Trace::DataType::Invalid:
// unable to add
return false;
@ -875,6 +880,8 @@ bool TraceXYPlot::domainMatch(Trace *t)
return t->outputType() == Trace::DataType::Time;
case XAxis::Type::Power:
return t->outputType() == Trace::DataType::Power;
case XAxis::Type::TimeZeroSpan:
return t->outputType() == Trace::DataType::TimeZeroSpan;
case XAxis::Type::Last:
return false;
}

View File

@ -66,6 +66,7 @@ VNA::VNA(AppWindow *window, QString name)
calEdited = false;
changingSettings = false;
settings.sweepType = SweepType::Frequency;
settings.zerospan = false;
traceModel.setSource(TraceModel::DataSource::VNA);
@ -304,6 +305,11 @@ VNA::VNA(AppWindow *window, QString name)
connect(bFull, &QPushButton::clicked, this, &VNA::SetFullSpan);
frequencySweepActions.push_back(tb_sweep->addWidget(bFull));
auto bZero = new QPushButton(QIcon::fromTheme("zoom-fit-best", QIcon(":/icons/zoom-fit.png")), "");
bZero->setToolTip("Zero span");
connect(bZero, &QPushButton::clicked, this, &VNA::SetZeroSpan);
frequencySweepActions.push_back(tb_sweep->addWidget(bZero));
auto bZoomIn = new QPushButton(QIcon::fromTheme("zoom-in", QIcon(":/icons/zoom-in.png")), "");
bZoomIn->setToolTip("Zoom in");
connect(bZoomIn, &QPushButton::clicked, this, &VNA::SpanZoomIn);
@ -837,7 +843,9 @@ void VNA::NewDatapoint(Protocol::Datapoint d)
auto vd = VNAData(d);
vd = average.process(vd);
if(!settings.zerospan) {
vd = average.process(vd);
}
if(calMeasuring) {
if(average.currentSweep() == averages) {
// this is the last averaging sweep, use values for calibration
@ -862,14 +870,26 @@ void VNA::NewDatapoint(Protocol::Datapoint d)
}
TraceMath::DataType type;
switch(settings.sweepType) {
case SweepType::Last:
case SweepType::Frequency:
type = TraceMath::DataType::Frequency;
break;
case SweepType::Power:
type = TraceMath::DataType::Power;
break;
if(settings.zerospan) {
type = TraceMath::DataType::TimeZeroSpan;
// keep track of first point time
if(vd.pointNum == 0) {
settings.firstPointTime = vd.time;
vd.time = 0;
} else {
vd.time -= settings.firstPointTime;
}
} else {
switch(settings.sweepType) {
case SweepType::Last:
case SweepType::Frequency:
type = TraceMath::DataType::Frequency;
break;
case SweepType::Power:
type = TraceMath::DataType::Power;
break;
}
}
traceModel.addVNAData(vd, type);
@ -949,12 +969,12 @@ void VNA::SettingsChanged(bool resetTraces, std::function<void (Device::Transmis
s.logSweep = settings.Freq.logSweep;
} else if(settings.sweepType == SweepType::Power) {
s.fixedPowerSetting = 0;
s.f_start = start;
s.f_stop = stop;
s.f_start = settings.Power.frequency;
s.f_stop = settings.Power.frequency;
s.points = npoints;
s.if_bandwidth = settings.bandwidth;
s.cdbm_excitation_start = settings.Power.start * 100;
s.cdbm_excitation_stop = settings.Power.stop * 100;
s.cdbm_excitation_start = start * 100;
s.cdbm_excitation_stop = stop * 100;
s.logSweep = false;
}
if(window->getDevice() && Mode::getActiveMode() == this) {
@ -1060,6 +1080,13 @@ void VNA::SetFullSpan()
ConstrainAndUpdateFrequencies();
}
void VNA::SetZeroSpan()
{
auto center = (settings.Freq.start + settings.Freq.stop) / 2;
SetStartFreq(center);
SetStopFreq(center);
}
void VNA::SpanZoomIn()
{
auto center = (settings.Freq.start + settings.Freq.stop) / 2;
@ -1108,14 +1135,14 @@ void VNA::SetStartPower(double level)
{
settings.Power.start = level;
emit startPowerChanged(level);
SettingsChanged();
ConstrainAndUpdateFrequencies();
}
void VNA::SetStopPower(double level)
{
settings.Power.stop = level;
emit stopPowerChanged(level);
SettingsChanged();
ConstrainAndUpdateFrequencies();
}
void VNA::SetPowerSweepFrequency(double freq)
@ -1327,6 +1354,11 @@ void VNA::SetupSCPI()
SetFullSpan();
return "";
}, nullptr));
scpi_freq->add(new SCPICommand("ZERO", [=](QStringList params) -> QString {
Q_UNUSED(params)
SetZeroSpan();
return "";
}, nullptr));
auto scpi_power = new SCPINode("POWer");
SCPINode::add(scpi_power);
scpi_power->add(new SCPICommand("START", [=](QStringList params) -> QString {
@ -1527,6 +1559,8 @@ void VNA::ConstrainAndUpdateFrequencies()
if(settings.Freq.start < Device::Info(window->getDevice()).limits_minFreq) {
settings.Freq.start = Device::Info(window->getDevice()).limits_minFreq;
}
settings.zerospan = (settings.sweepType == SweepType::Frequency && settings.Freq.start == settings.Freq.stop)
|| (settings.sweepType == SweepType::Power && settings.Power.start == settings.Power.stop);
emit startFreqChanged(settings.Freq.start);
emit stopFreqChanged(settings.Freq.stop);
emit spanChanged(settings.Freq.stop - settings.Freq.start);

View File

@ -69,6 +69,8 @@ public:
// if the number of points is higher than supported by the hardware, the sweep has to be segmented into multiple parts
int segments;
int activeSegment;
bool zerospan;
double firstPointTime; // timestamp of the first point in the sweep, only use when zerospan is used
};
public slots:
@ -84,6 +86,7 @@ private slots:
void SetCenterFreq(double freq);
void SetSpan(double span);
void SetFullSpan();
void SetZeroSpan();
void SpanZoomIn();
void SpanZoomOut();

View File

@ -14,11 +14,13 @@ public:
std::complex<double>(d.real_S21, d.imag_S21),
std::complex<double>(d.real_S22, d.imag_S22));
frequency = d.frequency;
time = (double) d.us / 1000000.0;
cdbm = d.cdbm;
pointNum = d.pointNum;
reference_impedance = 50.0;
}
double frequency;
double time;
int cdbm;
Sparam S;
unsigned int pointNum;

View File

@ -48,6 +48,7 @@ static void USBPacketReceived(const Protocol::PacketInfo &p) {
inline void App_Init() {
STM::Init();
Delay::Init();
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
handle = xTaskGetCurrentTaskHandle();
usb_init(communication_usb_input);

View File

@ -13,9 +13,18 @@ using Datapoint = struct _datapoint {
float real_S21, imag_S21;
float real_S12, imag_S12;
float real_S22, imag_S22;
uint64_t frequency;
int16_t cdbm;
uint16_t pointNum;
union {
struct {
// for non-zero span
uint64_t frequency;
int16_t cdbm;
};
struct {
// for zero span
uint64_t us; // time in us since first datapoint
};
};
uint16_t pointNum;
};
using SweepSettings = struct _sweepSettings {

View File

@ -2,15 +2,51 @@
#include "stm.hpp"
static volatile uint64_t t_us = 0;
void Delay::Init() {
TIM1->CNT = 0;
// enable update interrupt
TIM1->DIER |= TIM_DIER_UIE;
HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
TIM1->CR1 |= TIM_CR1_CEN;
}
uint64_t Delay::get_us() {
HAL_NVIC_DisableIRQ(TIM1_UP_TIM16_IRQn);
uint32_t buf = TIM1->CNT;
uint16_t timer_value = buf & 0xFFFF;
uint64_t ret;
if(buf & 0x80000000) {
// UIF bit set, timer overflow not handled yet
ret = t_us + UINT16_MAX + timer_value;
} else {
ret = t_us + timer_value;
}
HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
return ret;
}
void Delay::ms(uint32_t t) {
while(t--) {
us(1000);
}
}
void Delay::us(uint32_t t) {
TIM1->CNT = 0;
TIM1->CR1 |= TIM_CR1_CEN;
while (TIM1->CNT < t)
;
TIM1->CR1 &= ~TIM_CR1_CEN;
uint64_t start = get_us();
while(start + t > get_us());
}
extern "C" {
void TIM1_UP_TIM16_IRQHandler() {
// clear bit
TIM1->SR &= ~TIM_SR_UIF;
// update count
t_us += UINT16_MAX;
}
}

View File

@ -4,6 +4,10 @@
namespace Delay {
void Init();
uint64_t get_us();
void ms(uint32_t t);
void us(uint32_t t);

View File

@ -6,6 +6,7 @@
#include "Exti.hpp"
#include "VNA.hpp"
#include "Manual.hpp"
#include "delay.hpp"
#include "SpectrumAnalyzer.hpp"
#include <cstring>
@ -19,7 +20,7 @@ HW::Mode activeMode;
static bool unlevel = false;
static Protocol::ReferenceSettings ref;
static uint32_t lastISR;
static uint64_t lastISR;
static uint32_t IF1 = HW::DefaultIF1;
static uint32_t IF2 = HW::DefaultIF2;
@ -60,8 +61,8 @@ static void ReadComplete(const FPGA::SamplingResult &result) {
}
static void FPGA_Interrupt(void*) {
lastISR = Delay::get_us();
FPGA::InitiateSampleRead(ReadComplete);
lastISR = HAL_GetTick();
}
void HW::Work() {
@ -209,7 +210,7 @@ void HW::SetMode(Mode mode) {
if(mode != Mode::Idle) {
// do a full initialization when switching directly between modes
HW::Init();
lastISR = HAL_GetTick();
lastISR = Delay::get_us();
}
SetIdle();
activeMode = mode;
@ -287,8 +288,8 @@ HW::AmplitudeSettings HW::GetAmplitudeSettings(int16_t cdbm, uint64_t freq, bool
}
bool HW::TimedOut() {
constexpr uint32_t timeout = 1000;
if(activeMode != Mode::Idle && HAL_GetTick() - lastISR > timeout) {
constexpr uint64_t timeout = 1000000;
if(activeMode != Mode::Idle && Delay::get_us() - lastISR > timeout) {
return true;
} else {
return false;
@ -415,6 +416,10 @@ uint8_t HW::getADCPrescaler() {
return ADCprescaler;
}
uint64_t HW::getLastISRTimestamp() {
return lastISR;
}
uint16_t HW::getDFTPhaseInc() {
return DFTphaseInc;
}

View File

@ -97,6 +97,7 @@ void SetMode(Mode mode);
void SetIdle();
void Work();
bool TimedOut();
uint64_t getLastISRTimestamp();
void SetOutputUnlevel(bool unlev);

View File

@ -30,6 +30,10 @@ static Si5351C::DriveStrength fixedPowerLowband;
static bool adcShifted;
static uint32_t actualBandwidth;
static uint64_t firstPointTime;
static bool firstPoint;
static bool zerospan;
static constexpr uint8_t sourceHarmonic = 5;
static constexpr uint8_t LOHarmonic = 3;
@ -140,6 +144,8 @@ bool VNA::Setup(Protocol::SweepSettings s) {
IFTableIndexCnt = 0;
zerospan = (s.f_start == s.f_stop) && (s.cdbm_excitation_start == s.cdbm_excitation_stop);
bool last_lowband = false;
// invalidate first entry of IFTable, preventing switing of 2.LO in halted callback
@ -302,6 +308,7 @@ bool VNA::Setup(Protocol::SweepSettings s) {
FPGA::EnableInterrupt(FPGA::Interrupt::NewData);
FPGA::EnableInterrupt(FPGA::Interrupt::SweepHalted);
// Start the sweep
firstPoint = true;
FPGA::StartSweep();
return true;
}
@ -329,8 +336,20 @@ bool VNA::MeasurementDone(const FPGA::SamplingResult &result) {
auto port1 = port1_raw / ref;
auto port2 = port2_raw / ref;
data.pointNum = pointCnt;
data.frequency = getPointFrequency(pointCnt);
data.cdbm = settings.cdbm_excitation_start + (settings.cdbm_excitation_stop - settings.cdbm_excitation_start) * pointCnt / (settings.points - 1);
if(zerospan) {
uint64_t timestamp = HW::getLastISRTimestamp();
if(firstPoint) {
data.us = 0;
firstPointTime = timestamp;
firstPoint = false;
} else {
data.us = timestamp - firstPointTime;
}
} else {
// non-zero span, set frequency/power
data.frequency = getPointFrequency(pointCnt);
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();

View File

@ -322,7 +322,7 @@ ProjectManager.StackSize=0x400
ProjectManager.TargetToolchain=STM32CubeIDE
ProjectManager.ToolChainLocation=
ProjectManager.UnderRoot=true
ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-MX_DMA_Init-DMA-false-HAL-true,3-SystemClock_Config-RCC-false-HAL-false,4-MX_I2C2_Init-I2C2-false-HAL-true,5-MX_SPI1_Init-SPI1-false-HAL-true,6-MX_SPI2_Init-SPI2-false-HAL-true,7-MX_UCPD1_Init-UCPD1-false-LL-true,8-MX_USART3_UART_Init-USART3-false-HAL-true,9-MX_USB_PCD_Init-USB-false-HAL-true,10-MX_USBPD_Init-USBPD-false-HAL-false,11-MX_TIM1_Init-TIM1-false-HAL-true,12-MX_TIM2_Init-TIM2-false-HAL-true,13-MX_ADC1_Init-ADC1-false-HAL-true
ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-MX_DMA_Init-DMA-false-HAL-true,3-SystemClock_Config-RCC-false-HAL-false,4-MX_I2C2_Init-I2C2-false-HAL-true,5-MX_SPI1_Init-SPI1-false-HAL-true,6-MX_SPI2_Init-SPI2-false-HAL-true,7-MX_UCPD1_Init-UCPD1-false-LL-true,8-MX_USART3_UART_Init-USART3-false-HAL-true,9-MX_USB_PCD_Init-USB-false-HAL-true,10-MX_TIM1_Init-TIM1-false-HAL-true,11-MX_TIM2_Init-TIM2-false-HAL-true,12-MX_ADC1_Init-ADC1-false-HAL-true
RCC.ADC12Freq_Value=160000000
RCC.AHBFreq_Value=160000000
RCC.APB1Freq_Value=160000000
@ -387,8 +387,7 @@ SPI2.Direction=SPI_DIRECTION_2LINES
SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler,DataSize
SPI2.Mode=SPI_MODE_MASTER
SPI2.VirtualType=VM_MASTER
TIM1.IPParameters=Prescaler,PeriodNoDither
TIM1.PeriodNoDither=65535
TIM1.IPParameters=Prescaler
TIM1.Prescaler=159
TIM2.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
TIM2.IPParameters=Channel-PWM Generation1 CH1,Prescaler,PeriodNoDither,OCMode_PWM-PWM Generation1 CH1