Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

New to MATLAB?

Debug code invoked by timer

Asked by per isakson

per isakson (view profile)

on 3 Mar 2013
Accepted Answer by Daniel

Daniel (view profile)

Debugging code, which is invoked by a timer, is more of a challenge than it should be. The other day I expressed my frustration in What frustrates you about MATLAB?. Now, I'll try to be more constructive.

Wanted: Tips, tricks and tools to help me debug more efficiently. (Below, I present some of mine.)

My code: I have a code that is invoked by a timer on a regular basis. The code consist of a dozen classes and a handful of functions. Both objects and some functions have state. Below, I have included some small functions to illustrate my problems.

My development environment: R2012a (64bit) on Windows 7. I use a unit testing framework with a graphical interface and write some code in debug mode. The framework is based on MUNIT, by Brad Phelan.

Some problems:

  • Matlab's error messages are very generic and include neither function name nor line number
  • "Cannot clear classes". The old state must be cleared before each test. I often restart the unit testing tool to be able to clear old state.
  • Break-points are cleared by clear all and I often forget to reset them before executing the code.

Some examples:

The function, invoked_by_timer, as value of TimerFcn illustrates the error message of Matlab.

    >> debug_invoked_by_timer()
    Error while evaluating TimerFcn for timer 'my_timer' 
    Index exceeds matrix dimensions.

The function, invoked_by_timer_catch, as value of TimerFcn illustrates that it is possible to improve the error message. Daniels comment to my frustration triggered me to do this experiment.

    >> debug_invoked_by_timer()
    Error while evaluating TimerFcn for timer 'my_timer' 
    Error: Index exceeds matrix dimensions.
    In invoked_by_timer.index_out_of_bounds (line: 7)
    In invoked_by_timer.invoked_by_timer (line: 2)
    In invoked_by_timer_catch.invoked_by_timer_catch (line: 3)
    In timercb.timercb (line: 31)
    In timercb.timercb (line: 14)
    In wait.wait (line: 51)
    In debug_invoked_by_timer.debug_invoked_by_timer (line: 17)

TraceHistory is a singleton, which keeps its state after debug_invoked_by_timer has finished. It displays which functions have been called.

    >> log = TraceHistory.Instance;
    >> disp(log)
    --- tracer4m ---

( log.clearHistory and log.setup can be done outside the function, debug_invoked_by_timer).


    function    debug_invoked_by_timer()
        log = TraceHistory.Instance;
        log.setup( {'h:\m\PiaX\Experiments\debug\timer\invoked_by_timer.m'} )  
        tmr = timer('Name'      , 'my_timer'        ...
            ,   'TimerFcn'      , @invoked_by_timer_catch ...
    ...     ,   'TimerFcn'      , @invoked_by_timer ...
            ,   'BusyMode'      , 'drop'            ...
            ,   'ExecutionMode' , 'fixedRate'       ...
            ,   'Period'        ,  1                ...
            ,   'StartDelay'    ,  1                ...     
            ,   'TasksToExecute',  1           ...
        start( tmr )
        wait ( tmr )


    function    invoked_by_timer_catch( tmr, evnt )
            invoked_by_timer( tmr, evnt ) 
        catch me
            str = exception2str( me );
            error( str )


    function    invoked_by_timer( tmr, evnt )
        variable_not_used( tmr, evnt ) 
    function    index_out_of_bounds()
        a = 17;    
        b = a(2);
        variable_not_used( a, b ) 


    function    str = exception2str( me )       
        str = sprintf( 'Error: %s\n', me.message );  
        for s = transpose( me.stack )
           str = [ str, hyperlink_row_( s ) ];   %#ok<AGROW>
    function    str = hyperlink_row_( s )
        [ ~, filename ] = fileparts( s.file );
         str = sprintf                                                      ...
            (   [ 'In <a href="matlab:matlab.desktop.editor.openAndGoToLine'...
                , '(''%s'',%i);">%s.%s (line: %i)</a>\n' ]                  ...
            ,   s.file, s.line, filename,, s.line                    );


    function    variable_not_used( varargin )       
    %variable_not_used - helps keep the code analyzer box green  

Persistent break-point: The function, dbs, sets a break-point on the following line. I found it useful.

    function dbs
    % dbs provides a persistent break-point; debug, dbstop
    %   Based on the FEX contribution kdb 
    %   By Romesh Abeysuriya 15-11-12
        stk = dbstack('-completenames');
        dbstop( 'in', stk(2).file, 'at', num2str( stk(2).line+1 ) )


(Why do I use the timer in the first place? A while-loop with a computed pause would most likely have been good enough and easier to work with.)

See also: Can't find where the warning msg is from



Daniel (view profile)

on 10 Mar 2013

Is there an advantage of exception2str over getReport?

per isakson

per isakson (view profile)

on 10 Mar 2013

No. I was too quick making exception2str. However, now I think my output is easier to read ;). I failed to enter ">" or "/" between the file and the function name.

per isakson

per isakson (view profile)


No products are associated with this question.

1 Answer

Answer by Daniel

Daniel (view profile)

on 6 Mar 2013
Accepted answer

My solution, that I alluded to in the original thread, looks almost identical to your invoke_by_timer_cacth, except I use the getReport method of the MException class instead. I also have defined a generic callback wrapper that I use for all callbacks that includes the try-catch.

The clear classes and clear all issues are separate and I have no insights.



Daniel (view profile)

Contact us