Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 7c066a8cc9d0
Choose a base ref
...
head repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 5ed0af7833e4
Choose a head ref
  • 4 commits
  • 11 files changed
  • 1 contributor

Commits on Feb 15, 2020

  1. Copy the full SHA
    f8459ec View commit details
  2. ClockRecoveryDecoder: reduce drift when running open loop on signals …

    …without a lot of transitions
    azonenberg committed Feb 15, 2020
    Copy the full SHA
    f95ab90 View commit details
  3. Copy the full SHA
    2f86ea3 View commit details
  4. Copy the full SHA
    5ed0af7 View commit details
2 changes: 1 addition & 1 deletion scopehal/LeCroyOscilloscope.cpp
Original file line number Diff line number Diff line change
@@ -1286,7 +1286,7 @@ size_t LeCroyOscilloscope::GetTriggerChannelIndex()
//Update cache
if(isdigit(source[1]))
m_triggerChannel = source[1] - '1';
else if(!strcmp(source, "EX"))
else if(strstr(source, "EX") == source) //EX or EX10 for /1 or /10
m_triggerChannel = m_extTrigChannel->GetIndex();
else
{
1 change: 1 addition & 0 deletions scopeprotocols/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ set(SCOPEPROTOCOLS_SOURCES
ACCoupleDecoder.cpp
ClockJitterDecoder.cpp
ClockRecoveryDecoder.cpp
ClockRecoveryDebugDecoder.cpp
DCOffsetDecoder.cpp
DifferenceDecoder.cpp
DVIDecoder.cpp
115 changes: 115 additions & 0 deletions scopeprotocols/ClockRecoveryDebugDecoder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@

/***********************************************************************************************************************
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2020 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
* following conditions are met: *
* *
* * Redistributions of source code must retain the above copyright notice, this list of conditions, and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials provided with the distribution. *
* *
* * Neither the name of the author nor the names of any contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
* *
***********************************************************************************************************************/

#include "../scopehal/scopehal.h"
#include "scopeprotocols.h"
#include "../scopehal/AnalogRenderer.h"

using namespace std;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

ClockRecoveryDebugDecoder::ClockRecoveryDebugDecoder(string color)
: ProtocolDecoder(OscilloscopeChannel::CHANNEL_TYPE_ANALOG, color, CAT_CLOCK)
{
//Set up channels
m_signalNames.push_back("PLL");
m_channels.push_back(NULL);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Factory methods

ChannelRenderer* ClockRecoveryDebugDecoder::CreateRenderer()
{
return new AnalogRenderer(this);
}

bool ClockRecoveryDebugDecoder::ValidateChannel(size_t i, OscilloscopeChannel* channel)
{
if( (i == 0) && (dynamic_cast<ClockRecoveryDecoder*>(channel) != NULL) )
return true;
return false;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Accessors

void ClockRecoveryDebugDecoder::SetDefaultName()
{
char hwname[256];
snprintf(hwname, sizeof(hwname), "ClockRecPhase(%s)", m_channels[0]->m_displayname.c_str());
m_hwname = hwname;
m_displayname = m_hwname;
}

string ClockRecoveryDebugDecoder::GetProtocolName()
{
return "Clock Recovery Phase";
}

bool ClockRecoveryDebugDecoder::IsOverlay()
{
return false;
}

bool ClockRecoveryDebugDecoder::NeedsConfig()
{
return false;
}

double ClockRecoveryDebugDecoder::GetVoltageRange()
{
auto chin = dynamic_cast<ClockRecoveryDecoder*>(m_channels[0]);
if(chin == NULL)
return 100;
return chin->m_nominalPeriod;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Actual decoder logic

void ClockRecoveryDebugDecoder::Refresh()
{
auto chin = dynamic_cast<ClockRecoveryDecoder*>(m_channels[0]);

//Get the input data
if(chin == NULL)
{
SetData(NULL);
return;
}

SetData(chin->m_phaseErrorCapture);
chin->m_phaseErrorCapture = NULL;
return;

}
63 changes: 63 additions & 0 deletions scopeprotocols/ClockRecoveryDebugDecoder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/***********************************************************************************************************************
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2019 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
* following conditions are met: *
* *
* * Redistributions of source code must retain the above copyright notice, this list of conditions, and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials provided with the distribution. *
* *
* * Neither the name of the author nor the names of any contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
* *
***********************************************************************************************************************/

/**
@file
@author Andrew D. Zonenberg
@brief Declaration of ClockRecoveryDebugDecoder
*/
#ifndef ClockRecoveryDebugDecoder_h
#define ClockRecoveryDebugDecoder_h

#include "../scopehal/ProtocolDecoder.h"

class ClockRecoveryDebugDecoder : public ProtocolDecoder
{
public:
ClockRecoveryDebugDecoder(std::string color);

virtual void Refresh();
virtual ChannelRenderer* CreateRenderer();

virtual bool NeedsConfig();
virtual bool IsOverlay();

static std::string GetProtocolName();
virtual void SetDefaultName();

virtual double GetVoltageRange();

virtual bool ValidateChannel(size_t i, OscilloscopeChannel* channel);

PROTOCOL_DECODER_INITPROC(ClockRecoveryDebugDecoder)

protected:
};

#endif
39 changes: 34 additions & 5 deletions scopeprotocols/ClockRecoveryDecoder.cpp
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@
***********************************************************************************************************************/

#include "../scopehal/scopehal.h"
#include "ClockRecoveryDecoder.h"
#include "scopeprotocols.h"
#include "../scopehal/DigitalRenderer.h"

using namespace std;
@@ -54,6 +54,9 @@ ClockRecoveryDecoder::ClockRecoveryDecoder(string color)
m_threshname = "Threshold";
m_parameters[m_threshname] = ProtocolDecoderParameter(ProtocolDecoderParameter::TYPE_FLOAT);
m_parameters[m_threshname].SetFloatVal(0);

m_phaseErrorCapture = NULL;
m_nominalPeriod = 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -139,6 +142,7 @@ void ClockRecoveryDecoder::Refresh()
//Look up the nominal baud rate and convert to time
int64_t baud = m_parameters[m_baudname].GetIntVal();
int64_t ps = static_cast<int64_t>(1.0e12f / baud);
m_nominalPeriod = ps;

//Create the output waveform and copy our timescales
DigitalCapture* cap = new DigitalCapture;
@@ -147,6 +151,15 @@ void ClockRecoveryDecoder::Refresh()
cap->m_triggerPhase = 0;
cap->m_timescale = 1; //recovered clock time scale is single picoseconds

//Create debug capture
if(m_phaseErrorCapture != NULL)
m_phaseErrorCapture = NULL;
m_phaseErrorCapture = new TimeCapture;
m_phaseErrorCapture->m_startTimestamp = din->m_startTimestamp;
m_phaseErrorCapture->m_startPicoseconds = din->m_startPicoseconds;
m_phaseErrorCapture->m_triggerPhase = 0;
m_phaseErrorCapture->m_timescale = 1;

double start = GetTime();

//Timestamps of the edges
@@ -175,6 +188,7 @@ void ClockRecoveryDecoder::Refresh()
cap->m_samples.reserve(edges.size());
size_t igate = 0;
bool gating = false;
int cycles_open_loop = 0;
for(; (edgepos < tend) && (nedge < edges.size()-1); edgepos += period)
{
float center = period/2;
@@ -213,12 +227,24 @@ void ClockRecoveryDecoder::Refresh()
//If not, just run the NCO open loop.
//Allow multiple edges in the UI if the frequency is way off.
int64_t tnext = edges[nedge];
cycles_open_loop ++;
while(tnext + center < edgepos)
{
//Find phase error
int64_t delta = (edgepos - tnext) - period;
total_error += fabs(delta);

//Extend the previous debug sample to now
if(!m_phaseErrorCapture->m_samples.empty())
{
auto& last = m_phaseErrorCapture->m_samples[m_phaseErrorCapture->size() - 1];
last.m_duration = tnext - last.m_offset;
}

//Record the current phase error
m_phaseErrorCapture->m_samples.push_back(AnalogSample(
tnext, period, delta));

//If the clock is currently gated, re-sync to the edge
if(was_gating && !gating)
{
@@ -227,17 +253,20 @@ void ClockRecoveryDecoder::Refresh()
}

//Check sign of phase and do bang-bang feedback (constant shift regardless of error magnitude)
//If we skipped some edges, apply a larger correction
else if(delta > 0)
{
period -= 0.00005 * period;
edgepos -= 0.005 * period;
period -= 0.000025 * period * cycles_open_loop;
edgepos -= 0.0025 * period * cycles_open_loop;
}
else
{
period += 0.00005 * period;
edgepos += 0.005 * period;
period += 0.000025 * period * cycles_open_loop;
edgepos += 0.0025 * period * cycles_open_loop;
}

cycles_open_loop = 0;

//LogDebug("%ld,%ld,%.2f\n", nedge, delta, period);
tnext = edges[++nedge];
}
6 changes: 5 additions & 1 deletion scopeprotocols/ClockRecoveryDecoder.h
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2019 Andrew D. Zonenberg *
* Copyright (c) 2012-2020 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
@@ -57,6 +57,10 @@ class ClockRecoveryDecoder : public ProtocolDecoder

PROTOCOL_DECODER_INITPROC(ClockRecoveryDecoder)

//Debug
TimeCapture* m_phaseErrorCapture;
int64_t m_nominalPeriod;

protected:
std::string m_baudname;
std::string m_threshname;
42 changes: 23 additions & 19 deletions scopeprotocols/TMDSDecoder.cpp
Original file line number Diff line number Diff line change
@@ -53,6 +53,10 @@ TMDSDecoder::TMDSDecoder(string color)

m_signalNames.push_back("clk");
m_channels.push_back(NULL);

m_lanename = "Lane number";
m_parameters[m_lanename] = ProtocolDecoderParameter(ProtocolDecoderParameter::TYPE_INT);
m_parameters[m_lanename].SetIntVal(0);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -168,11 +172,14 @@ void TMDSDecoder::Refresh()
}
}

int lane = m_parameters[m_lanename].GetIntVal();

//HDMI Video guard band (HDMI 1.4 spec 5.2.2.1)
static const bool video_guard[2][10] =
static const bool video_guard[3][10] =
{
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 1 },
{ 1, 1, 0, 0, 1, 1, 0, 0, 1, 0 } //also used for data guard band, 5.2.3.3
{ 1, 1, 0, 0, 1, 1, 0, 0, 1, 0 }, //also used for data guard band, 5.2.3.3
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 1 },
};

//TODO: TERC4 (5.4.3)
@@ -216,24 +223,21 @@ void TMDSDecoder::Refresh()
//Check for HDMI video/control leading guard band
if( (last_symbol_type == TYPE_PREAMBLE) || (last_symbol_type == TYPE_GUARD) )
{
for(size_t j=0; j<2; j++)
match = true;
for(size_t k=0; k<10; k++)
{
match = true;
for(size_t k=0; k<10; k++)
{
if(sampdata[i+k].m_sample != video_guard[j][k])
match = false;
}
if(sampdata[i+k].m_sample != video_guard[lane][k])
match = false;
}

if(match)
{
cap->m_samples.push_back(TMDSSample(
sampdata[i].m_offset,
sampdata[i+10].m_offset - sampdata[i].m_offset,
TMDSSymbol(TMDSSymbol::TMDS_TYPE_GUARD, j)));
last_symbol_type = TYPE_GUARD;
break;
}
if(match)
{
cap->m_samples.push_back(TMDSSample(
sampdata[i].m_offset,
sampdata[i+10].m_offset - sampdata[i].m_offset,
TMDSSymbol(TMDSSymbol::TMDS_TYPE_GUARD, 0)));
last_symbol_type = TYPE_GUARD;
break;
}
}

@@ -259,7 +263,7 @@ void TMDSDecoder::Refresh()
if(d8)
d ^= (d << 1);
else
d = ~(d << 1);
d ^= (d << 1) ^ 0xfe;

cap->m_samples.push_back(TMDSSample(
sampdata[i].m_offset,
Loading