The C Programmer’s Guide to the Mosaic HandheldTable of ContentsPART 1 GETTING STARTED Introduction. How to Use This Manual Chapter 1: Getting to Know Your Handheld Instrument Chapter 2: Powering Your Handheld PART 2 PROGRAMMING THE MOSAIC HANDHELD Chapter 4: The IDE: Writing, Compiling, Downloading and Debugging Programs Accessing the Standard (Kernel) Library Functions Using the Interactive Debugger Overview of the Forth Language and Programming Environment Displaying the Values of Static Variables Use Type Keywords To Interactively Call C Functions Displaying the Values of FORTH_ARRAY Elements Assigning Values to Static Variables and FORTH_ARRAY Elements Under the Hood of the QED-Forth Interactive Debugger The Handheld Kernel vs. Prior Kernels Chapter 5: Making Effective Use of Memory Chapter 6: Real Time Programming Chapter 7: Failure and Run-Time Error Recovery Chapter 8: Programming the Graphical User Interface PART 3 COMMUNICATIONS, MEASUREMENT, AND CONTROL Chapter 9: Digital and Timer-Controlled I/O Chapter 11: Serial Communications Chapter 12: The Battery-Backed Real Time Clock Chapter 13: Customizing the Handheld's I/O PART 4: REFERENCE DATA |
Chapter 4 The IDE: Writing, Compiling, Downloading and Debugging ProgramsIn this Chapter we’ll explore the Handheld’s tools for writing, editing, downloading and debugging your application program. You’ll learn: How to efficiently use the editor and compiler to write and compile both short and long programs; Coding and file-naming conventions; How to access the Handheld’s onboard funcitons; and, How to interactively debug your programs. Writing ProgramsUsing the Editor/CompilerIn the prior Chapter we introduced the Mosaic IDE and the tools you can use to edit, compile, and download your program. Briefly, the text pad toolbar provides the following buttons: The Debug Tool invokes the compiler and assembler only – it does not produce downloadable code. Use it to quickly check the syntax of a program and find compile errors. The Single-Page Compile Tool performs a standard, single-page memory model build of your program for programs that do not exceed 32 Kbytes of memory. If you see the following warning printed in the compiler output, then you must switch to the multi-page memory model build (Multi-Page Make icon): WARNING: Input section “.doubleword” from ‘progname.o11’ is not used ! The Multi-Page Compile Tool invokes the C compiler’s multi-page build mode for long programs. Still, each source code file should be less than 32 Kbytes worth of compiled source code or the above warning will be issued and the program will not run. The Terminal icon launches the communications program, Mosaic Terminal, which is used to download your compiled program to the Handheld. Sylistic ConventionsCode CommentsAt the top of the GETSTART.C source code file are some comments that tell what the program does. Single- or multi-line comments can be enclosed in the standard
/* */ delimiters. The double-slash
// token means that the remainder of the line is a comment. Note that the editor colors all comments differently to make it easy to distinguish comments from source code. C keywords are also colored differently than user-defined routines. You can change the default colors if you like. Style ConventionsThe example programs on your CD-ROM follow several stylistic conventions. Here is a brief summary: Macros and constants are spelled with CAPITAL_LETTERS. Variable names are spelled with small_letters. Function names use both capital and small letters, with capital letters indicating the start of a new subword within the function name. For example:
void SaveCircleParameters(void) To minimize the need to skip from one file to another, we have decided not to group all #define statements in a header file that is separate from the program being compiled. Rather, the #define statements are defined close to where they are used in the program file that is being compiled. File Naming ConventionsFor backward compatibility with DOS and Windows 3.1, all filenames have 8 or fewer characters. C source code files have the .C extension, and header files have the .H extension. When you use the Make Tool utility to compile a source code file with the filename, NAME.C several files with the extensions shown in Table 4‑1 are created: Table 4‑1 Files Created by the C Compiler.
While this list may seem overwhelming, you won’t have to worry about most of these files. You’ll create your NAME.C and .H source code and header files in a directory of your choice, run the automated Make Tool by clicking on the Make icon, and send the resulting NAME.DLF download file to the Handheld using the Terminal program. In fact, unless you tell it otherwise, the editor’s “File” menu will typically show you only files with the .C and .H extensions (“Source Files”); you won’t have to wade through the files with the other extensions. Similarly, the Mosaic Terminal typically lists only files with the .DLF extension, so it will be easy to select the download file to send to the Handheld. Using Function PrototypesThis stylistic convention deserves its own section. We strongly urge that you define or prototype each function before it is called. If the compiler generates a warning that a function has been called without a prototype, we recommend that you check your source code and insert the required function prototype, or move the definition of the function so that it is defined before it is called. A prototype is a declaration that specifies the function name and the types of its return value and input parameters. For example, the following is a valid function prototype:
_Q float CalcArea( unsigned int radius); This declaration specifies that CalcArea() is a function that expects one unsigned integer input and returns a floating point value. As discussed below, the _Q tags the function as one that is interactively callable during debugging. The CalcArea() function can then be defined later in the source code file. If a function is prototyped in one file and defined in another, add the extern specifer before the prototype. You can preface any function prototype with the _Q tag if you want to interactively call the function from the terminal. The Handheld’s onboard operating system maintains a list, called the dictionary, of the names of functions tagged with the _Q so that it can recognize them when you send a command line from your terminal. Prototype and Declare the Parameter Types of Every Function Defining or prototyping a function before it is called allows the compiler to help find parameter passing errors, and it also prevents unnecessary promotion of parameters that can render the code slower and defeat the Handheld’s interactive function-calling capability. To avoid unwanted promotion and runtime errors, each and every parameter in the function prototype or function definition must be preceded with a type specifier. For example, leaving out the unsigned int keywords in the prototype for CalcArea() above would lead to promotion of the input parameter, possibly resulting in a runtime error message from the compiler or linker. Using function prototypes and definitions that explicitly specify the type of each and every input and output parameter results in more readable and reliable code. Accessing the Standard (Kernel) Library FunctionsThe command
#include < \mosaic\allqed.h > near the top of the GETSTART.C file is a preprocessor directive that includes all of the relevant header files for the Handheld, and all of the standard C header files (such as stdio.h, math.h, float.h, string.h, etc.) We strongly recommend that this statement be placed at the top of each C program file that you write. It gives you access to all of the pre-coded library routines that reside on the Handheld. These routines let you control the A/D converters, digital I/O, serial ports, real-time clock, and many other useful functions. The ALLQED.H file also gives you access to the Handheld’s multitasking and paged memory capabilities, as well as the standard ANSI C library functions including printing and string conversion routines such as printf() and sprintf(). Including these files is very efficient; it generates almost no additional runtime code while giving you access to very powerful capabilities. You can call any of these functions from within your C code. There is one limitation however: Do not nest functions of the type _forth. Many functions that are callable from C are actually of the _forth type. This includes functions that are in the kernel on the Handheld, or are part of software distributions such as the Graphical User Interface (GUI) Toolkit. A call to one of these _forth functions may not be made from within the parameter list of a call to another _forth function. There is always a straightforward way of avoiding such nesting of function calls: simply use a variable to hold the required intermediate return value/parameter. For example, if you need to use the _forth function FetchChar() to fetch the first character from the extended address returned by the _forth function DisplayBuffer() in paged memory, you could execute the following statements:
static xaddr buffer_xaddress = DisplayBuffer( ); FetchChar( buffer_xaddress); This code is correct, while nesting the call to DisplayBuffer() inside the parameter list of FetchChar() would be incorrect. Initializing VariablesCaution: A common mistake made when creating application programs for embedded systems is the use of compile-time initialization for RAM-based quantities such as variables and arrays. While this approach of initializing quantities outside of function definitions may work during program development, it fails when the device goes into production because the variables and arrays are not properly initialized when power is cycled. Only run-time initialization, i.e., initializations that are performed within functions (which are in turn called by the autostart program), will occur reliably in an embedded application. Even users with battery-backed RAM in their systems should always perform initializations within functions. This approach will avoid hard-to-diagnose field failures that result from corrupted data in a battery-backed RAM that is never re-initialized to valid values. Feel free to call Mosaic Industries for help with this or other programming issues. Compiling ProgramsCompiling Multiple Source Code FilesWhen writing large programs it is often useful to break up the program into multiple source code files. The Make Tool allows you to accomplish this in one of two ways. 1. First, you can designate one of your source code files as the primary file, and insert into this file statements of the form,
#include “\path\filename” to include the other source code functions, where \path is the standard DOS path specification that allows the file to be located. The primary file must have a .C extension. 2. Second, you can split your source code into several files that start with the same sequence of characters, such as:
CODE.C // this is the primary file that you compile CODE1.C // CODE1.C and CODE2.C are subsidiary files that are automatically CODE2.C // compiled and linked when CODE.C is compiled All of these files must have the .C extension. Then, when you compile CODE.C using the Make Tool (by clicking on the Hammer icon), all of the files with a .C extension whose name starts with CODE (namely, CODE.C, CODE1.C and CODE2.C) will be compiled and linked together. Note that the Make Tool cannot handle filenames that start with a numeral or filenames that contain the dash character; thus a source code file named 1CODE.C or MY-CODE.C cannot be compiled. Finally, note that one and only one of the program files must include a function named main().
Using the Interactive DebuggerIn the prior chapter, you gained experience using the debugging environment that lets you interactively execute any designated function with input arguments of your own choosing. Now we’ll look more closely at the operation of the debugging environment, and explain how to use it to examine and manipulate the values of static variables, Forth Array elements, and memory locations. The interactive debugging environment conveys several advantages. First, you can test each function of a program individually without changing the main() function and recompiling. This saves compilation and download time. Second, the environment makes it easy to test each function with a wide range of input parameters, allowing you to isolate bugs that might otherwise be missed until later in the program development cycle. Such thorough function-by-function testing of a program facilitates more rapid development of reliable programs. We’ll start by learning how to use the interactive environment to examine the values of static variables. The explanation of how this works involves taking a brief high-level look at the interactive QED-Forth language that is built into the Handheld. Understanding how QED-Forth operates will empower you to take full advantage of the debugging capabilities of the Handheld. Overview of the Forth Language and Programming EnvironmentThe QED-Forth interactive environment makes it easy to examine the contents of static variables. A brief overview of how the Forth language works will help clarify the procedure. The Forth Data StackForth is a stack-oriented high level language that combines the interactive benefits of an interpreter with the speed of a compiler. Unlike C, FORTH is implemented as a two-stack language. In addition to the return stack that most languages use to keep track of function calls and returns, FORTH has a data stack that is used to pass parameters. All arithmetic, logical, I/O, and decision operations remove any required arguments from the data stack and leave the results on the data stack. This leads to postfix notation: the operation is stated after the data or operands are placed on the stack. This is the same notation used by Hewlitt Packard’s RPN (reverse polish notation) calculators. Unlike C, Forth uses spaces as delimiters to distinguish different keywords and tokens. For example, a C compiler can easily parse the addition expression:
5+4 as three distinct tokens: 5, +, and 4. But because the above expression was typed without any spaces, Forth would interpret the expression as a single token, assume it’s the name of a function, and would try to find it in its dictionary. In Forth the expression must be entered as:
5 4 + which includes the required spaces and uses postfix notation to add the numbers and leave the result on the data stack. To see how this works, we’ll talk to the interactive QED-Forth interpreter on the Handheld. To start, enter the terminal now: if the terminal program is already active, click on its window or hold down the “Alt” key and press “Tab” until the terminal announcement appears on your screen. If you haven’t started the terminal program yet during this session, double-click on the Mosaic Terminal icon to start it up. Connect and power up your Handheld; pressing the Return key should cause QED-Forth’s ok prompt to appear in the terminal window. To start, we’ll ensure that the current number base is decimal by typing the command, DECIMAL from the terminal. With each character you type QED-Forth echoes the character in you terminal window. The back arrow in the line above indicates that you pressed the Enter key which sends a carriage return character; but you won’t see it as an echoed character on your screen. QED-Forth executes this command when the terminating carriage return is received. Also recall that QED-Forth case-insensitive, so you can freely mix upper and lower case letters. Now we can put some numbers on the QED-Forth data stack by typing : 5 7 followed by a carriage return. QED-Forth responds: ok ( 2 ) \ 5 \ 7 We have underlined QED-Forth’s response for clarity. QED-Forth is showing a picture of its data stack. The ( 2 ) means that there are two items on the stack. Each of the items is listed, and items are separated by a \ character, which can be read as under. So we could describe the stack right now as 5 under 7; the 7 is on top of the stack, and the 5 is under it. If there are more than 5 items on the stack, the stack print displays the number of stack items and the values of the top 5 items. The stack print that shows what’s on the data stack is a feature of the debugging environment. To disable the stack print, you could execute (that is, type at your terminal) the DEBUG OFF command. It is not recommended that you do this, though; it’s very helpful to keep track of the items on the data stack while developing your program. To multiply the numbers that are now on the stack, type the multiply operator which is a * character: * and QED-Forth responds: ok ( 1 ) \ 35 The QED-Forth * operator removes the two operands 5 and 7 from the stack, multiplies them, and puts the result of the multiplication on the stack. To subtract 5 from the number on the stack, type: 5 - which produces the response: ok ( 1 ) \ 30 The QED-Forth - (minus) operator takes the 35 and the 5 from the stack, subtracts, and puts the result on the data stack. To print the result to the terminal, we could simply type the printing word: . (that’s right, the command is simply a dot, the period on your keyboard) which prints the response: 30 ok The printing word . removes the 30 from the stack and prints it. The stack is now empty, so QED-Forth does not print a stack picture after the ok. Notice that throughout this exercise QED-Forth has been interpreting and executing commands immediately. This is because the Forth language is interactive. The results of executing commands can be immediately determined. If they are incorrect, the command can be changed to correct the problem. This leads to a rapid iterative debugging process that speeds program development. This interactive function execution has been harnessed to speed development of C programs for the Handheld. QED-Forth Numeric Printing FunctionsThere are a variety of QED-Forth printing functions, and some related functions that set the current number base and clean up the data stack. Here is a short list of useful functions that can be executed interactively:
Each of the printing routines removes a number from the data stack and prints it to the terminal. Because characters are promoted to unsigned int in Forth, the . (dot) function is also used to print 8-bit character data. The PrintFP function was specifically written to display floating point numeric output from C programs, as internally QED-Forth uses a non-ANSI floating point representation for its own floating point numbers. The default QED-Forth number base after a COLD restart is DECIMAL. The number base can be changed to hexadecimal by executing HEX. All non-floating-point numbers typed at the terminal or printed by QED-Forth are converted using the current number base (corresponding to the most recent execution of DECIMAL or HEX). Floating point numbers are always converted using the decimal number base. Displaying the Values of Static VariablesNow that we understand how the Forth data stack works, the procedure for examining variables will make sense. The examples presented here use code from the GETSTART.C program that we’ve already discussed in detail. If you have already downloaded the program, you are ready to go. If your board is presently running a multitasking application and you want to download a new file, type WARM to stop the program so that a new download file can be accepted. If you have not yet compiled the GETSTART.C program and you want to do the exercises here, first compile it by opening \MOSAIC\DEMOS_AND_DRIVERS\MISC\C EXAMPLES\GETSTART.C in the TextPad editor, click on the Make Tool, and after the compilation, enter the Mosaic Terminal and use the “Send Text File” menu item to send GETSTART.DLF to the Handheld. To run the program, type main at your terminal – this initializes all the pointers and variables. After typing main, let’s type Nap( ) to put the calculation task asleep; remember to type at least one space after the (. This stops the variables from being updated in the background. Let’s start by initializing the contents of the radius variable to 5 by interactively executing (typing) from the terminal: SetRadiusAndArea( int 5) Remember to type at least one space after the ( character and after int. This function is defined in GETSTART.C as:
_Q SetRadiusAndArea( uint r) { radius = r; area = CalcArea( r); } It assigns the specified input parameter to the unsigned integer radius variable, and assigns the corresponding circular area to the floating point area variable. Now we can check the value of radius. The following interactive command places the contents of the integer variable named radius on the Forth data stack: int radius QED-Forth responds with: ok ( 1 ) \ 5 Because radius is defined as an unsigned integer, we use the unsigned integer printing routine named U. (U-dot) to remove the value from the Forth data stack and print it. Type U. to print the radius an unsigned integer. QED-Forth responds with: 5 ok To speed things up, we can type the entire command sequence on one line so that QED-Forth immediately prints the result. Type: int radius U. and QED-Forth responds with: 5 ok To interactively examine the contents of the floating point area variable, type the command sequence: float area PrintFP and QED-Forth responds: 78.54 ok which is indeed the area of a circle whose radius equals 5. Extracting the Value Referenced by a PointerSometimes C programs add an additional layer of indirection, referencing a value by means of a pointer. An example of this technique appears in the GETSTART.C program in the form of the static variables radius_ptr and area_ptr; they are defined as:
static uint* radius_ptr; static float* area_ptr; In the InitVars() function near the end of the program, these pointers are initialized as follows:
radius_ptr = &radius; area_ptr = &area; In other words, radius_ptr holds the address of a variable that represents the radius, and area_ptr holds the address of a variable that represents the area. Given the radius_ptr and area_ptr, we want to be able to extract the value of radius and area. The following keywords can be executed interactively to accomplish this:
char* int* long* float* Note that there cannot be any spaces before the * in each keyword, and there must be at least one space after the * and before any subsequent number or variable name. For example, to print the radius you can type: int* radius_ptr U. The int* keyword fetches the 16-bit address from radius_ptr and from that location fetches the integer contents. U. then prints the answer to the terminal. Similarly, to print the area you can type: float* area_ptr PrintFP The float* keyword fetches the 16-bit address from area_ptr and from the resulting location fetches the floating point contents. PrintFP then prints the result. Signed versus Unsigned NumbersNote that the type specifier used above does not specify signed versus unsigned numbers; rather, the printing function determines whether the number is interpreted as signed or unsigned. For example, type the following two command lines from the terminal and see how QED-Forth responds: 65535 U. 65535 . In the first instance, QED-Forth prints 65535, while in the second instance, QED-Forth prints -1 (we’re assuming that you have not changed the number base to HEX). The same binary pattern (in this case, all 16 bits of the number are set) can represent either 65535 or -1 depending on how the number is interpreted and printed. Thus by choosing the printing function, you can control whether a number is displayed as a signed or unsigned quantity. SummaryIn summary, to display the contents of a simple static variable, type a command of the form:
type variable_name print_function_name where type is one of the following keywords:
char int long float To display the contents of a static variable that is pointed to by a pointer, type a command of the form:
type pointer_name print_function_name where type is one of the following keywords:
char* int* long* float* Use Type Keywords To Interactively Call C FunctionsThe same family of familiar C type-declaration keywords that we used to fetch the contents of variables is also used to facilitate interactive calling of C functions. Recall that these keywords are:
char int long float char* int* long* float* We have seen that these keywords are used in two different contexts while debugging. In the prior chapter we used them to declare the type of an input parameter while interactively calling a function. For example, we can interactively type from the terminal: CalcArea( int 5) where the int keyword is used with the same syntax as an ANSI-C function prototype to declare the input arguments to the called function. Second, we used the type keywords in this chapter to extract the value from a variable, as in the interactive QED-Forth command int radius U. which prints the contents of the radius variable as an unsigned integer. These two contexts for the use of the int keyword are related. For example, to calculate the area corresponding to the current value of the radius variable, we can interactively execute: CalcArea( int radius) and QED-Forth prints the resulting floating point area in its summary of the return value. The int keyword serves two complementary purposes here: it tells QED-Forth that the input parameter is a 16-bit integer, and it extracts the value of the radius variable so the variable is passed by value. When interactively calling a function, all parameters that are passed by value should be preceded by the appropriate type keyword. However, when passing the address of a variable or a structure, simply state the variable or structure name without any type specifiers or & (address-of) operators. For example, the function prototype for the DimAndInitFPArray() function in GETSTART.C is:
Q void DimAndInitFPArray(float val,int rows,int cols,FORTH_ARRAY* array_ptr) and the program includes the array declaration:
FORTH_ARRAY circle_parameters; which declares circle_parameters as a FORTH_ARRAY structure in memory. As we shall see, executing (typing) the name circle_parameters in QED-Forth leaves the address of the array structure on the stack, so there is no need for additional type declarators or & operators. Thus to interactively dimension the array to have 10 rows, 2 columns and a initialization value of 12.34, we type from the terminal: DimAndInitFPArray( float 12.34,int 10,int 2,circle_parameters) To verify that this worked, you can execute: PrintFPArray( circle_parameters) which displays the contents of the newly initialized circle_parameters matrix. Displaying the Values of FORTH_ARRAY ElementsThe same type specifier keywords that let you examine static variables can also be used to examine any specified element in a two-dimensional FORTH_ARRAY. The syntax is parallel to what we have already used; the difference is that we now append the row and column indices in square brackets after the array name to specify which element should be fetched. For example, recall that circle_parameters is a FORTH_ARRAY that is dimensioned to hold 10 rows and 2 columns of floating point data. To print the contents of the first element in the array at [row=0, col=0], we type: float circle_parameters[ 0, 0] PrintFP and QED-Forth prints the result. While this array notation is not exactly like the standard C syntax, it is straightforward. To print the element whose row index is 5 and whose column index is 1, type: float circle_parameters[ 5, 1] PrintFP As you might expect, there must not be a space before the [ character, and there must be at least one space after the [ character. This is because
circle_parameters[ is defined as a space-delimited QED-Forth function in the GETSTART.DLF file, as explained later in this chapter. All of the keywords that we learned about above can be used to fetch the contents of appropriately dimensioned arrays. Arrays that are dimensioned to hold character, integer, long, or float data are accessed using the char, int, long and float keywords, respectively, in front of the array name. If for some reason you use a FORTH_ARRAY to hold 16-bit pointers , the char*, int*, long* and float* keywords can be used in a manner exactly analogous to the description in the earlier section of this chapter. Assigning Values to Static Variables and FORTH_ARRAY ElementsYou can interactively change the contents of any static variable or FORTH_ARRAY element using the following assignment keywords:
=char =int =long =float Each of these keywords expects to be preceded by the address of a variable or FORTH_ARRAY element, and expects to be followed by a valid number, variable name, or FORTH_ARRAY element specifier. As expected, the value of the right hand side is assigned to the variable or array element on the left hand side of the assignment expression. For example, to change the current value of radius to 22, simply type: radius =int 22 This syntax was designed to be similar to a C statement that assigns the value 22 to the radius variable. As you might guess, =int is a single keyword defined in QED-Forth, so there cannot be any spaces between = and int. Similarly, the other tokens in the expression must be separated by spaces; thus there is at least one space after radius and at least one space before 22. To set the current value of the floating point area variable to 1520. type: area =float 1520. To assign the current value of the area variable to element [ 0, 1] in the FORTH_ARRAY circle_parameters, you can execute: circle_parameters[ 0,1] =float area To check that these operations actually worked, we can execute the following commands to examine the contents of the affected variables and array elements: int radius U. float area PrintFP float circle_parameters[ 0,1] PrintFP Under the Hood of the QED-Forth Interactive DebuggerThis section is for the curious among you; you need not read or understand this section to use the QED-Forth interactive debugger. However, it will give you additional insight into the debugging environment. Variable DeclarationsIn the example above, radius is defined in the GETSTART.DLF download file as a QED-Forth constant whose value is the address of the radius variable. To see for yourself, use you editor to open the GETSTART.DLF file. Select “Open” from the editor’s “file” menu, set the “List Files of Type” option to either “Text Files” or “All Files”, and double click on GETSTART.DLF in the \MOSAIC\DEMOS_AND_DRIVERS\MISC\C_EXAMPLES directory. The top portion of the file is the hexadecimal dump of the compiled C code in the Motorola S2 record format. Near the bottom of the file you’ll see some CONSTANT declarations. Among them is the declaration:
008E03 CONSTANT radius which defines radius as a QED-Forth constant that places the hexadecimal value 8E03 on the stack. You can verify this by clicking on the Terminal window and typing: HEX radius U. DECIMAL from the terminal. This command sequence instructs QED-Forth to print the hexadecimal address of the radius variable, and then return to decimal base. Note that if you want to pass the address of the radius variable as a parameter to a function (also known as passing a pointer or passing by reference), you leave out the int keyword before radius in the parameter list. The keyword int is actually a QED-Forth function that examines the next token in the input stream; if it is already a number such as 5 or 3.2, int simply converts it to the nearest integer. If the next token is a variable address (such as radius), int extracts the 16-bit contents stored at the address. To see this behavior for yourself, try the following commands at your terminal: int 5 U. int 5.45 U. int radius U. These three statements all yield identical results if the value of radius is still 5. Function DeclarationsReturning to the GETSTART.DLF file that you opened in the editor, scroll to the area just above the list of CONSTANT definitions and you will see a set of lines starting with the : (colon) character. In Forth, the : character marks the start of a new definition (function or subroutine), and the ; (semicolon) marks the end of the definition. These are the function definitions that tell QED-Forth the names and execution addresses of each function in GETSTART.C that was preceded by the _Q declarator. Among these functions you will find some familiar ones including:
SetRadiusAndArea( CalcArea( DimAndInitFPArray( PrintFPArray( The body of each of these Forth definitions defines the compilation address and invokes the routine CALL.CFN (meaning call-C-function). CALL.CFN accepts an optional list of comma-delimited parameters terminated by a closing ) and then sets up the stack frame and calls the function. So when you type the interactive command CalcArea( int radius) with a terminal enter key, here’s what happens: 1. When QED-Forth accepts the carriage return, it starts interpreting the command line that has been entered. It looks for the first space-delimited token, and it finds the token:
CalcArea( 2. It looks in its dictionary, and sure enough, it finds that this token has been defined; the definition was compiled when the GETSTART.DLF download file was sent to the Handheld. 3. When QED-Forth executes the CalcArea( token, it executes the CALL.CFN routine which starts looking for a terminating ) character, and processes any tokens that are present. 4. The next space-delimited token found is int, which looks for the next token (in this case, radius). Because radius is not a number, int assumes that it is a variable and extracts the 16-bit contents from the address that is left on the Forth data stack by radius. The contents are left on the Forth data stack. 5. The terminating ) is found, so the CALL.CFN routine pushes the items on the Forth data stack onto the C stack in the proper order to make a legal C stack frame, and then executes the CalcArea() function as defined in the C program at the specified execution address. 6. When the CalcArea() function returns, QED-Forth traps its return value from the 68HC11’s registers and prints the value using integer and floating point formats. FORTH_ARRAY DeclarationsNear the bottom of the GETSTART.DLF file you can find the definition of circle_parameters[ that facilitates examining and modifying any element of this array. The QED-Forth definition is:
: circle_parameters[ circle_parameters DO[] ; As described above, the : character marks the start of a new definition, and the ; marks the end of the definition. The body of the definition is simple: the constant circle_parameters leaves the base address of the FORTH_ARRAY structure on the stack, and DO[] does the rest of the work. DO[] is defined in the QED-Forth kernel; it searches for a row index followed by a comma, and a column index followed by a terminating ] character. Then it passes the specified row, column, and array parameter field address to the Forth function named [] (brackets) which places the 32-bit extended address of the array element on the stack. This extended address can be used as the argument to the familiar keywords that we have discussed such as char, int, long, float, =char, =int, =long, =float, etc. Thus all of the following are legal debugging commands: float circle_parameters[ 3,0] PrintFP circle_parameters[ 2,1] =float area circle_parameters[ 5,0] =float 345. Some of you may have noticed that CalculationTask[ is also declared to QED-Forth as a potential FORTH_ARRAY in the GETSTART.DLF download file; yet we know that CalculationTask is a task identifier, not a FORTH_ARRAY. The reason for this is that Make Tool always declares the last variable allocated in the common RAM as a potential FORTH_ARRAY; it does this because there it can’t determine the allocated size of the last variable. The extra definition of CalculationTask[ does no harm (as long as we don’t try to use it improperly). SummaryThe Make Tool calls the QCC.EXE executable program to create the QED-Forth debugging declarations that appear at the bottom of the .DLF download file. This program has to decide whether each compiler symbol in the .OUT file is a callable function, a variable, or a FORTH_ARRAY. The Make Tool identifies callable functions by detecting the _pascal? tag that the compiler places there in response to the _Q specifier, and in response prints the functionname( definition into the .DLF file. The Make Tool identifies variables by detecting whether the corresponding address lies in the common RAM area, and in response prints a QED-Forth CONSTANT declaration into the .DLF file. Finally, it tentatively identifies FORTH_ARRAYs by checking the size of each variable; if there are exactly 18 bytes allocated to one item in the common RAM, it decides that the associated name should also be declared as a FORTH_ARRAY by printing the name[ definition in the .DLF download file. To be safe, the Make Tool always declares the last variable as a FORTH_ARRAY because it cannot be sure of its allocated size. Other Useful QED-Forth FunctionsQED-Forth is a complete language that includes over a thousand pre-defined functions, all of which reside in ROM on the Handheld. Many of these functions are declared in the header files in the \MOSAIC\FABIUS\INCLUDE\MOSAIC directory, and so are callable from C. The names and descriptions of these functions are detailed in the Control C Glossary in the documentation package. But there are also additional routines described there that are useful while debugging; these allow you to: Modify the contents of EEPROM on the 68HC11 processor. Dump the contents of a specified region of memory in hex and ascii format using the DUMP command. Specify a new baud rate for the serial port to speed downloads using the BAUD1.AT.STARTUP command. Configure the Handheld to execute a specified program each time a reset or restart occurs using the AUTOSTART or PRIORITY.AUTOSTART command. Dump out a replica of the board’s program memory space in Intel Hex or Motorola S2 record format to archive your production code. In sum, the versatile QED-Forth language enhances the power of Control C by providing many operating system functions as well as an interactive debugging environment that speeds program development and testing. The Handheld Kernel vs. Prior KernelsThe Handheld, QCard and QScreen products use a QED-Forth operating system kernel denoted as V4.4x, where the ‘x’ may take on any numeric value. There are several minor differences between V4.4x and the V4.0x kernel used on the QED Board, Panel-Touch Controller, and QVGA Controller products. Briefly, five functions have been added to the V4.4x kernel, and 19 device functions have been removed. The removed functions are device drivers associated with hardware that is not implemented on the Handheld/QCard/QScreen products. In addition, the V4.4x kernel boots up at a default serial baud rate of 19,200 baud, compared to 9600 baud on prior kernels. Table 4‑2 lists the new functions, and Table 4‑3 lists the removed functions. Descriptions of the new functions are provided in the glossary below and in the function reference document that accompanies the Handheld, QCard and QScreen products. Table 4‑2 Functions added to V4.4x kernel
C programmers must include the files named v4_4update.c and V4_4update.h to gain access to the five new functions. These files are located in the \Mosaic\Fabius\Include\Mosaic\v4_4Update directory in the software distribution CD. Simply #include both the v4_4update.h and v4_4update.c files in one of your source files, and also #include v4_4update.h in any other source files that use these new kernel routines.
Table 4‑3 Summary of functions deleted from V4.4x.
Summary of Modified Memory Map FunctionsThe Kernel’s internal memory map functions have been modified to be aware of the Handheld, QCard and QScreen’s memory. In the “standard map”, the Handheld has flash at pages 4-7 that swaps with RAM on parallel pages 1-3, plus flash at hex pages 10-17 that swaps with RAM on parallel hex pages 18-1F. In the “download map”, flash and RAM are swapped: flash is present on pages 1-3 and 18-1F, and RAM is present on pages 4-6 and 10-17. The C development environment transparently handles the loading of program code into flash, so C programmers typically do not have to be concerned with these issues.
|
Home|Site Map|Products|Manuals|Resources|Order|About Us
Copyright (c) 2012 Mosaic Industries, Inc.
Your source for single board computers, embedded controllers, and operator interfaces for instruments and automation