This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

User defined functions in uVision3

Has anyone ever seen an authoritative document on using
debug functions in uVision3?  It could be a powerful tool if
I knew how to use it, but what little information I have
come across is scattered across 2 hardcopy manuals, a bit
more in the help file system, and smatterings in the Keil
Knowledgebase.

Here are clues, not documented anywhere, that I have
discovered by trial and error:
  - If the last line of a .ini file containing function
    definitions does not end in a CR/LF, you get a "syntax
    error".
  - The "Breakpoint Set (BS), and "Go" (GO) commands may be
    executed from the command line, but not inside a
    function.
  - If you access program variables from the function, you
    must halt execution at a point in the program where
    they are all in scope before you load the function with
    an "include" command.  Otherwise you get another "syntax
    error."
  - When you define and/or when you invoke a function, you
    must terminate its name with a pair of parentheses.
    When you "kill" the function, you must omit the
    parentheses. Otherwise, you get another one of those
    ubiquitous "syntax errors".
  - It could be that everything is a syntax error in this
    domain.  The messages are that useful.              :-}

Perhaps if we all pool our insights, we will have a running
start on a manual.
============================================================
Gary Lynch           |   To send mail, no$pam in domain name
lynchg@no$pam.com    |   must be changed to stacoenergy.

  • I must admit that sometimes I have spent more time debugging my signal functions than my controller code.

  • Thanks for telling us the manual and tools weaknesses.

    We have tried to improve it by new examples. Did you saw already:
    http://www.keil.com/support/man/docs/uv3/uv3_simulation.htm

    Reinhard

  • We may have a semantic gap here.  The material you reference
    seems to be about signal functions, which as best I
    understand, are only available in the simulator.  They are
    used to generate input numbers that look like peripheral
    ports to the application.
    
    I am using what the manual calls the "target hardware
    debugger" running on my own board (flash programmed via JTAG
    interface). My signals come directly from the hardware
    itself. I have never used the simulator at all.
    
    Is a user function something I can use with the hardware
    debugger capability, or am I trying to force my cat to haul
    a piano upstairs?
    
    It isn't obvious from the manual.
    ============================================================
    Gary Lynch           |   To send mail, no$pam in domain name
    lynchg@no$pam.com    |   must be changed to stacoenergy.

  • Way back on Dec 5, 2005; I posted to this forum under the
    aforementioned subject line:
    >
    > Has anyone ever seen an authoritative document on using
    > debug functions in uVision3? It could be a powerful tool if
    > I knew how to use it, but what little information I have
    > come across is scattered across 2 hardcopy manuals, a bit
    > more in the help file system, and smatterings in the Keil
    > Knowledgebase.
    >

    I issued a challenge to all users to share what they had
    figured out around this topic, hoping our combined knowledge
    could be compiled into our own, home-grown user's manual.
    From the deafening silence, I concluded there wasn't much
    knowledge to go around.

    On Friday, August 04, 2006 9:46 AM; I received a message
    from fellow forum denizen, Petter Gran-Jansen:
    >
    > Hello Gary.
    >
    > My name is Petter Gran-Jansen and working with uVision3,
    > ARM, Agsi, signals and functions.
    >
    > I have read your Forum mail "User defined functions
    > uVision3" dated 12/6/05.
    >
    > I agree. ...
    >

    This was followed, approximately 2-1/2 hours later, by a
    message from Reinhard Keil:
    >
    > Hello Petter,
    >
    > well it is sometimes good to tell others your frustration. I
    > also agree that documentation can be improved a lot and we
    > are actually hiring in the moment people for doing this.
    >

    I would like to extend a warm "Danke schön" to Herr
    Keil for taking notice, and look forward to seeing what he
    comes up with.

    For Petter and fellow suffers of this documentation dearth,
    I have not been sitting on my hands in the 9 months since my
    original rant, and have had some success solving problems
    with user-defined functions, which I share with you all.

    You are going to have to read it piecemeal as the server prohibits me
    from saying all I want to in one breath. If you are reading this
    with Internet Explorer and the preformatted sections have white
    bands running across the width, try re-sizing the window.

    This info came from:

    • Getting Started with uVision2, pp. 89-144;
    • Getting Started, Creating Applications with uVision3, pp. [actually this book contains nothing useful on functions, but they sent it to me for some reason];
    • The Keil tech support guys <tip of the engineering hat> in Texas,
    • The Help system built into uVision3, particularly those points in the table of contents heading structure I have marked with a "#":
              Getting Started User's Guide
                +--Introduction
                +--Creating Applications
                +--Testing Programs
                |  +--Tips and Tricks
            #   |  |  +--Command Input from File
            #   |  |  +--Write Debug Output to a File
                +--Sample Programs
                +--Using On-Chip Peripherals
                +--RTX51 Tiny Real-Time Operating Systems
      
              uVision (R) IDE User's Guide
                +--uVision3 Overview
                +--User Interface
                +--Creating Applications
                +--Utilities
                +--Debugging
                |  +--Debug Windows and Dialogs
            #   |  |  +--Output Window-Command
                |  +--Tips and Tricks
                |  |  +--Command Input from File
                |  |  +--Write Debug Output to a File
                +--Debug Commands
            #   |  +--INCLUDE
            #   |  +--KILL
            #   |  +--LOG
                +--Debug Functions
            #   |  +--Creating Functions
            #   |  +--Invoking Functions
            #   |  +--Predefined Functions
            #   |  +--User Functions
            #   |  +--Differences Between uVision3 and C
                +--Simulation
                +--Flash Programming
                +--Dialogs
                +--Example Programs
                +--Command Line
                +--Appendix
      
    • The on-line Knowledgebase,
    • Assorted threads in this forum, and (last, but not least)
    • The School of Hard Knocks.

      User-defined functions are a powerful debugging tool, but they are also wretchedly difficult to master. The following guidelines aim to make this process easier.

      [continued in part 2]

    1. Although it is technically possible to create a user- defined function from the 'Output Window-Command' page of uVision 3, it is almost never worth the hassle. You are better off saving your definition to a command file and read the command file in with the INCLUDE command in the 'Output Window-Command' page.
    2. Syntax of user-defined function definition is very close to C, except:
      • The definition is preceded by the key word "FUNC",
      • Function parameter names may not overlap any variable name in the application, including automatics. This condition is case-insensitive.
      • There are no function prototypes, and forward references are not allowed. Therefore if a user-defined function calls another function defined in same command file:
                  func1()
                  +--func2()
                  |  +--func3()
                  func4()
        

        they must be declared in inverse call order.

                    FUNC void func4(void) {
                      ....
                    }
                    FUNC void func3(void) {
                      ....
                    }
                    FUNC void func2(void) {
                      ....
                      func3();
                    }
                    FUNC void func1(void) {
                      ....
                      func2();
                      func4();
                    }
        
      • Types are spelled slightly differently:
                  - BIT     - INT     - UINT
                  - CHAR    - LONG    - ULONG
                  - FLOAT   - UCHAR   - VOID
        

        Case is not supposed to matter, but I have only tried the upper-case versions.

    3. The most effective user functions output data to a file on your workstation using the "log" command. To reduce wear & tear on my (biological) memory, I use the same name for the script file, the function it defines, and the log file the function creates--just change the extension. The default extension for a command file is .ini. The following simple example uses these principles to grab a "snapshot" of the I/O port SFRs of the Silicon Labs C8051F04x MCUs:
            /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
            /*                                                         */
            /* dumpIoPorts.ini                                         */
            /* Version of 08/06/06                                     */
            /*                                                         */
            /* Debug script to dump content of all I/O port config     */
            /* SFRs                                                    */
            /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
      
            FUNC void dumpIoPorts(void) {
              INT ri, ci;
      
              exec("log > dumpIoPorts.log");
      
            /* + + + + + + + + + + + + + + + + */
            /*                                 */
            /*  Output template of SFR dump:   */
            /*                    Input Output */
            /*        Port  Data  Mode  Mode   */
            /*        ----  ----  ----  ----   */
            /*         P0    00    ..    00    */
            /*         P1    00    00    00    */
            /*         P2    00    00    00    */
            /*         P3    00    00    00    */
            /*         P4    00    ..    00    */
            /*         P5    00    ..    00    */
            /*         P6    00    ..    00    */
            /*         P7    00    ..    00    */
            /* + + + + + + + + + + + + + + + + */
      
              printf("            Input Output\n");
              printf("Port  Data  Mode  Mode\n");
              printf("----  ----  ----  ----\n");
      
              printf(" P0    %02X    ..    %02X\n",   P0, P0MDOUT);
              printf(" P1    %02X    %02X    %02X\n", P1, P1MDIN, P1MDOUT);
              printf(" P2    %02X    %02X    %02X\n", P2, P2MDIN, P2MDOUT);
              printf(" P3    %02X    %02X    %02X\n", P3, P3MDIN, P3MDOUT);
              printf(" P4    %02X    ..    %02X\n",   P4, P4MDOUT);
              printf(" P5    %02X    ..    %02X\n",   P5, P5MDOUT);
              printf(" P6    %02X    ..    %02X\n",   P6, P6MDOUT);
              printf(" P7    %02X    ..    %02X\n",   P7, P7MDOUT);
      
              exec("log off");
            }
      

      [continued in part 3]

    1. User-defined functions are subject to several more "eccentricities":
      • The last line of a command file must end with a CR/LF, else you will get a "syntax error."
      • Never declare an automatic variable within a user- defined function and forget to use it. You will get a "syntax error."
      • User-defined functions may not use arrays, structures, pointers, or global variables from the target application.
      • All automatics of the target application referenced by your function must be in-scope both at the time the command file is read, and when the function is invoked. I generally pick a single break point from which I can do both. Know what you get if you forget this? Hint: "syntax error"

      You can work around the 3rd item by creating a function inside your target application, declare a bunch of automatics, and copy all globals of interest to one of the automatics before you hit the breakpoint from which you define your function:

            int glob1, glob2;
      
            void main(void) {
      
              int lclMn1, lclMn2;
      
              uV3Break(lclMn1, lclMn2);
            }
      
            void uV3Break(int parm1, int parm2);
              int glbuV1, glbuV2;
              int dummy;
      
              glbuV1 = glob1;
              glbuV2 = glob2
      
              dummy = 0;
              return;
            }
      

      At this point: parm1, parm2, glbuV1, glbuV2 are all in scope and can be used by a user-defined function.

      Here the statement "dummy = 1" gives me a place to set a breakpoint, from which to launch my command file.

    2. You can create the moral equivalent of a global from a command file with the #define command, but you must encapsulate a #define command inside an exec() command:
      exec("#define NO_OF_SAMPLES 12");
      
    3. You read the command file in from the 'Output Window- Command' page, using the INCLUDE command:
      include dumpIoPorts.ini
      
    4. If your command file is long and errors occur early in the read, the diagnostics may scroll up beyond the top of the window so quickly you do not notice. A quick way to verify that a function definition took is the
      DIR UFUNC
      

      command. If your function does not appear in the list, it failed.

    5. You invoke the function directly from the 'Output Window-Command' page:
      dumpIoPorts();
      

      You may invoke it from inside a command file, too, but I haven't found that particularly useful.

    6. If your function definition succeeded, but has logic errors, you must first delete it:
      KILL FUNC dumpIoPorts
      

      before you can read the next version back in.

      Note that in the definition and invocation of my function, I have adhered to strict C syntax for the function name, including parentheses that surround a parameter list (even if you use no parameters), and the terminating semi-colon. Note also that I DO NOT use the latter 2 elements with the KILL command. Try that and you run afoul of the infamous ....

      <drum roll>

      Aw, never mind. You know the routine by now.

    7. If the foregoing seems a little tedious, there is a vastly superior alternative. It is mentioned in my Getting Started manual, pp. 127-128, but is very easy to miss. It is called the "Debug-Function Editor", and is accessed from the "Debug/Function Editor (open .Ini file) ..." drop-down menu (in debug mode only). With this single dialog box you can:
      • Create,
      • Edit,
      • Save,
      • Read into your application ("Compile")
      • Change and overwrite old version in one operation;

      and I recommend it over the manual methods.

    8. It would be extremely useful to be able to start and stop execution of the target under script control, but I have never been able to master this art. I have developed a powerful work-around, and will publish it under its own thread, should anyone have a need.

    ============================================================
    Gary Lynch           |   To send mail, no$pam in domain name
    lynchg@no$pam.com    |   must be changed to stacoenergy.