Saturday, 28 February 2015

Debugging DSP Algorithms And Real-time Applications

I am often asked how I debug real-time and DSP functions. Here is a summary of what works for me.

While there are solutions for displaying signal data graphically, which we will discuss later, I often find that I need to log precise values so that I can check for single bit errors etc. To this end, printf is a pretty good solution but I find that a better one is to use fprintf to log the data to files, this way the tests can be automated and it is easy to use file comparison tools, like KDiff3, or python to check for differences between successive runs.

At a top level I’ll always use a
#define DEBUG_ON 1 // Set to 1 to enable debugging
and then use conditional compilation.

Next, I will use fprintf to send the results to a log file, called debug.log.
So the first thing we need to do is clear any existing open debug.log file, as follows :

int clearDebugfprintf (void)

{
    FILE *fp_LogFile;
    fp_LogFile = fopen( "debug.log", "w");
    if (fp_LogFile == NULL)
    {
        return (1);                  // Return error
    }
    fclose (fp_LogFile);

    return (0);                      // Return no error
}

For the actual logging I will typically use the following two functions or variations of them :

This function works in the same way as printf :

int debugfprintf (const char *ArgumentType, ...)

{
    va_list p_ArgumentList;

   FILE *fp_LogFile;
    fp_LogFile = fopen ("debug.log", "a");
    if (fp_LogFile == NULL)
    {
        return (1);
    }

    va_start (p_ArgumentList, ArgumentType);
    vfprintf (fp_LogFile, ArgumentType, p_ArgumentList);
    va_end (p_ArgumentList);
    fclose (fp_LogFile);

    return (0);
}


This function works in the same way as vprintf :

int debugvfprintf (const char *format,
    va_list ap)

{
    FILE *fp_LogFile;
    fp_LogFile = fopen( "debug.log", "a");
    if (fp_LogFile == NULL)
    {
        return (1);
    }

    vfprintf (fp_LogFile, format, ap);

    fclose (fp_LogFile);

    return (0);
}

One of the most common problems with these functions is how to include them in real-time applications without breaking the response time requirements. JTAG is horrendously slow for this requirement but on my favourite XMOS microcontrollers the debug data can be sent back to the development workstation using a parallel data path, called xSCOPE, in real-time - https://www.xmos.com/products/tools/xscope. xSCOPE uses the xCONNECT data path to route the data with very little overhead on the application being debugged.

To display data graphically I will typically use Gnuplot, as I documented in this blog post http://realgonegeek.blogspot.co.uk/2014/01/interfacing-cc-to-gnuplot.html, or the XMOS xSCOPE graphical display in xTIMEcomposer.

No comments:

Post a Comment