View previous topic :: View next topic |
Author |
Message |
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
Any ideas on technique? |
Posted: Sun Jan 15, 2012 2:47 pm |
|
|
The issue is about a way to easily remove debug statements from the code when versioning
...I have been wrapping each debug trace in #IFDEF DEBUG_ENABLED
#ENDIF
I can also use a text editor and remove all debugging statements but it has the small disadvantage of keeping to source code versions one with debug statements the other without
Is there a better way to make the debug trace statement mute in a release version and still keep it embedded in the code?
Example code
Code: |
#define DEBUG_ENABLED
#IFDEF DEBUG_ENABLED
#use rs232(debugger,STREAM=MONITOR) //// debug to MONITOR via pin b3
#define debug(x) fprintf(MONITOR,"%s = %d\r\n",#x,x);
#ENDIF
main()
{
int8 myvariable=8;
#IFDEF DEBUG_ENABLED
debug(myvariable); /// prints to the console "myvariable=8"
#ENDIF
while(1);
} |
Specific compiler versions or PIC devices are omitted since this is a generic question about technique. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Sun Jan 15, 2012 3:15 pm |
|
|
Leave them in!.....
Use this approach instead:
Code: |
#define DEBUG_ENABLED
#IFDEF DEBUG_ENABLED
#define debug(x) fprintf(MONITOR,"%s = %d\r\n",#x,x);
#ELSE
#define debug(x) ;
#ENDIF
void main(void) {
int8 myvariable=8;
debug(myvariable); /// prints to the console "myvariable=8"
while(1);
}
|
when 'DEBUG_ENABLED' is not defined, all the debug statements just get replaced with a single ; which does nothing.
Best Wishes |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Sun Jan 15, 2012 3:27 pm |
|
|
Thanks
It makes so much sense I missed it. |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Sun Jan 15, 2012 4:58 pm |
|
|
It gets a bit more tricky.
What if fprintf(MONITOR, has several variables which vary between fprintf statements
Ex
Code: |
fprintf(MONITOR," 0x%x\n\r",var);
fprintf(MONITOR," 0x%x 0x%x\n\r",var1,var2);
fprintf(MONITOR," 0x%x 0x%x 0x%x\n\r",var1,var2,var3);
int8 var[5]={1,2,3,4,5};
i=2;
fprintf(MONITOR," 0x%x 0x%x 0x%x\n\r",var[i]);
|
Is there a technique to mute them as easily as
did in Ttelmah's reply? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Jan 16, 2012 5:38 am |
|
|
On a PC I would use a generic debug function like: Code: | void debug_print(const char *format, ...)
{
#ifdef DEBUG
va_list args;
va_start(args, format);
fprintf(MONITOR, format, args);
va_end(args);
#endif
} |
Usage: Code: | #define DEBUG TRUE
debug_print("My hyperfantastic debug facility, version %d\n", 1.23); |
A good optimizing compiler will remove the empty function in the release version. I don't have the CCS compiler here so can not test how good CCS does the job. Maybe some #inline addition is necessary.
Here are more similar answers, but I don't know how well CCS supports them: http://stackoverflow.com/questions/1941307/c-debug-print-macros |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Mon Jan 16, 2012 10:59 am |
|
|
Code: |
#include <stdarg.h>
void debug_print(const char *format, ...)
{
#ifdef DEBUG_TRACE
va_list args;// create special argument pointer
va_start(args, format); // initialize argptr starting after format
fprintf(MONITOR, format, args);
va_end(args);
#endif
} |
This was a really good idea but the CCS 4.124 compiler
errors out on *format ...expecting an identifier
Now having trace printf in the code must be useful to others hopefully someone has a cool way of muting them short of wrapping each one in #IFDEF DEBUG_TRACE statements
Now,often times the code reads nicer if the printf is spread over several lines
Code: |
fprintf(MONITOR," some text %d %d %d",
My_verbose_variable1,
My_verbose_variable2,
My_verbose_variable3); |
Any ideas on muting this multiple line construct? |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Mon Jan 16, 2012 3:36 pm |
|
|
In over 30 projects, some of of considerable complexity - involving as many as 3 pics interacting - I have NEVER used "debug", as other hardware/software analysis has always done the trick.
Perhaps someone could tell me the attraction /benefit pf debug insertion?? |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Mon Jan 16, 2012 4:12 pm |
|
|
I often have a "sync" pin that I will pulse to trigger a scope or logic analyzer at certain times. I may give it a single, double, tripple, or even quadruple pulse to mark up to 4 different points in the code. Printing out ASCII messages usually takes too much time.
Many years ago I bought a bondout ICE from Microchip. It cost a lot of money but found I rarely used it. It doesn't support any of the newer chips now.
I don't use MPLAB anymore either. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Mon Jan 16, 2012 5:05 pm |
|
|
Sherpadoug 's methods of debug find a lot of resonance with me...
my favorite tools for debug are external instruments ( of which I have great choices, in depth - in any area I need ).
When I think about it - my debug tools are
* pin toggles -
* rs-232 messages
* canned routines that I use to do postmortem AND activity updates.
The overhead and code alteration ( time domain especially ) introduced by MPLAB - and especially dreadful pic circuit SIMULATION ala Proteus make no sense to me at all.
I just assume if my overall design, code included, is not working - and the LST file looks right -- then there is a circuit or conceptual problem - && it MUST be my problem - and I just dig in and experiment with the code till I suss it out.
That approach and the odd tip on this forum - has never failed yet
You could say I never go the debug habit |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Mon Jan 16, 2012 5:13 pm |
|
|
This project involves radio communications between several transceivers in a mesh network.
Each transceiver has a FSM . Some states are forced by asynchronous interrupts. When the mesh network has issues it often is a function of one or more transceivers being in the wrong state with respect to its FSM or in the right state just at the wrong time. I find it useful to debug this via a logging aka tracing of the FSM states. The CCS debugger programmer has the capability thru a single pin and without any additional hardware being required on the target boards to display data on a monitor. That's why the compiler has the debugger parameters in the #use RS232 statement. Further the printf to the monitor can be used via the CCS ICD and also at run time via CCS load. If the code holds up in real testing the debugging code is removed. Anyway the reason I do this isn't that relevant since my request was for ideas on technique.
Last edited by Douglas Kennedy on Mon Jan 16, 2012 7:21 pm; edited 2 times in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jan 16, 2012 5:19 pm |
|
|
Quote: |
Perhaps someone could tell me the attraction /benefit pf debug insertion??
|
His "debug" statements are printfs. He's not doing anything materially
different than you are, he's just leaving the printf code in there, and
deactivating it for production with a #define statement. This is done for
convenience, so he doesn't have to examine the program at the end of
the development cycle, and comment out each individual diagnostic printf
line. That's what this thread is all about - the fine points of how to do this. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Tue Jan 17, 2012 3:01 am |
|
|
My own technique is to start by putting all the actual debug defines, into a file 'debug.h'.
The has at it's start the test for the debugging indicator (whatever you want to use - I tend to do this the opposite way round, and have the debugging code load by default, and have an indicator 'PRODUCTION', which is set to turn off the debugging). The first 90% will be the definitions for the various routines, while the second part has the 'null' definitions that do nothing when debugging is disabled.
Then I'll have perhaps a define for 'debug_pulse', which toggles a pin, or generates a short pulse, together with a few defines for whatever type of variable displays/output I want. Typically 'debug_int' which displays one int variable, and sometimes some others that display other variable types, or multiple variables. I'll also sometimes use a 'debug_eeprom' definition, that writes a value to a location in the EEPROM. All 'debug' definitions begin with the word debug, so can easily be found if required.
Now, the generic function suggested by Ckielstra won't work on CCS, because printf, is parsed at compile time, and is not a included in the code as a 'universal' function. The compiler works out what subsections are needed and only includes these in the final code, so can't handle variables being handed to this function.
Realistically the multi-version debug that Douglas wants can be handled by the wrapper approach just as easily as the single line, by having two or three debug variants, something like 'debug_one_var', and debug_three_vars' for example. Avoid having too many versions though....
Best Wishes |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Tue Jan 17, 2012 9:34 am |
|
|
Ttelmah thanks for the excellent idea on technique. I've been using the text editor replacing debug with //debug and reversing it //debug to debug. I'm switching to PRODUCTION rather than DEBUG in the directive.....PRODUCTION is a much more positive.
Now is there was a way for #DEFINE to do pure text editor replacement
as follows?
Code: |
IFDEF PRODUCTION
#DEFINE debug //fprintf
#ELSE
#DEFINE debug fprintf
#ENDIF
//// in the code
debug(MONITOR," var1=%d var2=%d",var1,var2); |
|
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Tue Jan 17, 2012 11:15 am |
|
|
now that i see what is being discussed, this approach has always been simple enough for me to deal with and the structure i have fallen into is this:
Code: |
// in header area set=1 for test set=0 for release compilation
#define debug 1
// wherever i inserted some trashy debug code
#if (debug)
// any and all locally created debug code NOT desired on release
#endif
// lastly in the early stages of main() after RS232 init
#if (debug)
printf("** WARNING DEBUG ** \r\n");
#end
|
let no mistake of mine go unpunished --
as always - i am happy to learn the deficiencies of the method .
Last edited by asmboy on Tue Jan 17, 2012 11:31 am; edited 1 time in total |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Tue Jan 17, 2012 11:30 am |
|
|
If you want to keep doing it your old way you can replace
#if (1==debug)
with
#if (debug)
That saves the PIC doing a subtraction in the if() statement, and makes more liguistic sense. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
|