Link here

An Introduction to Extended Memory

Making effective use of the memory on the QCard Controller.

The QCard Controller is a Single Board Computer (SBC) with a paged memory architecture that expands the amount of RAM and Flash memory available for your C-language instrument control applications. The QCard’s onboard operating system, called QED-Forth, provides numerous run-time services, including providing a heap memory manager. Using this memory manager we can access the controller’s extended memory.


1 Megabyte addressable memory space

The standard 68HC11 microcontroller on the QCard includes 1 Kbyte of on-chip RAM, 0.5Kbytes of on-chip EEPROM, and can address 64 kilobytes of memory using 16-bit addressing. The QCard Controller expands this limited address space to 1 Megabyte, addressing the lower 32 Kbytes of the processor’s memory map by means of a 5-bit "Page Latch" that selects one of 32 pages. The 32 pages times 32 Kbytes per page yields 1 Megabyte of addressable memory. The upper 32 Kbytes of the 68HC11’s address space is called the "common memory". This address space is always accessible, regardless of the contents of the Page Latch.


Available common RAM

The ANSI C compiler supports the standard 16-bit addressing scheme via its small memory model. It also supports a medium memory model that allows functions to be called on any specified page using a 24-bit address (16-bit standard address plus an 8-bit page). All C variables and C arrays, however, must be accessible using a simple 16-bit address. For practical purposes, this means that variables and C arrays must reside in the QCard Controller’s available 8 kilobytes of available common RAM located at addresses 0x8E00 to 0xADFF. In multitasking applications, this RAM is also used for task areas; each task requires 1 Kbyte of common RAM area.

You are of course free to use ANSI-standard C arrays located in the variable area in common RAM. These arrays allow you to use standard C pointer arithmetic, and their use is explained in all of the C textbooks. However, if you need to store a lot of data, the available 8K of common RAM may not be sufficient. But don’t worry – you can still use all the memory.


Built-in array library routines manage access to paged memory

The FORTH_ARRAY routines that reside in ROM on the QCard Controller provide an efficient means of accessing the large paged address space for storage of data. The pre-defined DIM() macro makes it easy to dimension a 2-dimensional array to hold signed or unsigned characters, integers, longs, or floating point values. Other pre-defined library functions handle storing, fetching, and copying data to and from the arrays. These QED-Forth functions are callable from C, and provide access to a large contiguous memory space that is very useful for real-time data storage and analysis.

Each array is referred to using a named 16-bit pointer to a "parameter field" structure in common RAM. Once the array has been "dimensioned", this structure holds the number of rows and columns, data size, and a pointer to the QED-Forth heap where the array is allocated. The ROM-resident heap manager allocates and deletes the arrays in real time under the control of the C program, thereby maximizing the effective use of available paged RAM.

This section introduces the use of the arrays, and as we’ll see in a later chapter, they are very useful for storing data from the QCard Controller’s A/D convertors. The header file named ARRAY.H in the \MOSAIC\FABIUS\INCLUDE\MOSAIC directory contains all of the function and macro definitions that are used to access Forth arrays, including the DIM(), FARRAYFETCH() and FARRAYSTORE() macros that are mentioned in this section.


Declaring and dimensioning a FORTH array

Let’s look at the example code in the GETSTART.C file. Approximately 1/3 of the way into the file, you’ll find a section called "Array Dimensioning, Storing and Fetching". The first command in this section is:

FORTH_ARRAY circle_parameters;

which declares a new FORTH_ARRAY named circle_parameters and allocates storage for the structure in the variable area in common RAM. FORTH_ARRAY is a struct typedef (see the ARRAY.H file) that specifies how the dimensioning information for the array is to be stored. Whenever we want to call a function to operate on this array, we will pass the pointer &circle_parameters as an argument to the function.

After using #define directives to define some dimensioning constants, we encounter the following function definition:

_Q void DimAndInitFPArray(float value,int rows,int cols,FORTH_ARRAY* array_ptr)
{  int r,c;
   DIM(float, rows, cols, array_ptr);        // dimension; allocate in heap
   for(c = 0; c < cols; c++)                 // for each column
      for(r=0; r< rows; r++)                 // for each row
         FARRAYSTORE(value,r,c,array_ptr);   // store in array

The function dimensions a FORTH_ARRAY and initializes all elements of the array to have a specified floating point value. The inputs are the floating point value, the number of rows and columns, and a pointer to the FORTH_ARRAY structure in common memory. After declaring the automatic variables r and c, the DIM() macro is invoked to emplace the dimensioning information in the FORTH_ARRAY structure, and allocate memory for the array in the heap.

The first parameter expected by DIM() is a type specifier; type definitions and abbreviations are defined in the TYPES.H file in the \MOSAIC\FABIUS\INCLUDE\MOSAIC directory. Valid type arguments for DIM() include the following:

char  unsigned char  uchar
int   unsigned int   uint
long  unsigned long  ulong
float xaddr

The next two input parameters expected by DIM() are the number of rows and columns, and the final input parameter is a pointer to the FORTH_ARRAY structure. The nested for() statements cycle through each row and column element in the array, calling the macro FARRAYSTORE() to store the specified value into the array element. FARRAYSTORE() expects a floating point value, row and column indices, and a pointer to the FORTH_ARRAY as its inputs.

The starting "F" in the name FARRAYSTORE() means "floating point"; a parallel macro named ARRAYSTORE() is used for arrays that contain signed or unsigned char, int, or long data.

The SaveCircleParameters() function in the GETSTART.C file calls the macro FARRAYSTORE() to store the radius and area as floating point values in their respective columns of the circle_parameters array. Then it increments the row_index variable, handling overflow by resetting the row_index to zero to implement a circular storage buffer.

The next function in GETSTART.C is called PrintFPArray() which prints an array of floating point values to the terminal. Its definition is as follows:

_Q void PrintFPArray(FORTH_ARRAY* array_ptr)
{  int r, c;
   for (r = 0; r < NUMROWS(array_ptr); r++)        // for each row
   {   for  (c = 0;c < NUMCOLUMNS(array_ptr);c++)  // for each col
         printf(“%9.4g  “,FARRAYFETCH(float,r,c,array_ptr));
         // min field width=9;precision=4;g=exp or decimal notation
      putchar(‘\n’);    // newline after each row is printed
      PauseOnKey();  // implement xon/xoff output flow control

As usual, the _Q declarator allows this function to be called interactively from the terminal. PrintFPArray() expects a pointer to a FORTH_ARRAY as its input parameter, and uses 2 nested for() statements to print the contents of the array one row at a time.

The printf() statement invokes the Forth library macro FARRAYFETCH() to fetch the contents of the array at the specified row and column. FARRAYFETCH() returns the value stored in the array; it expects a type specifier (used to cast the return value to the required type), row and column indices, and a pointer to the FORTH_ARRAY as its inputs.

The %9.4g argument to printf() specifies that the number should be printed using either decimal or exponential formatting (whichever displays better precision), with 4 digits to the right of the decimal point and a minimum field width of 9 characters. The putchar(‘\n’) statement inserts a newline character after each row is printed.

The PauseOnKey() function is a handy library routine that serves 2 purposes:

  1. It implements XON/XOFF output flow control to avoid "inundating" the terminal with characters faster than the terminal can process them, and
  2. It allows the user to abort the printout by typing a carriage return from the terminal.

For further details, please consult the definition of PauseOnKey() in the Control-C Glossary.

To see how the DimAndInitFPArray() function is called, scroll down to the function named CalcForever() in the GETSTART.C file. The first statement in the function is:


where 0.0 is the floating point value to be stored in each element, the constants CIRCLE_ROWS and CIRCLE_COLUMNS specify the number of rows and columns in the array, and &circle_parameters is a pointer to the FORTH_ARRAY.


Interactively dimension, initialize and print the array

It is easy to interactively call the functions that we’ve examined. The syntax that we’ll type at the terminal looks similar to an ANSI C function prototype, with one of the following type declarators being used before input parameters that are passed by value:

char     int      long     float
char*    int*     long*    float*

When passing the address of a variable or a structure, use only the name of the variable or structure, without any additional declarators or & operators. All of this is explained in detail in a later Chapter[pkc3]; for now, the goal is see how easy it is to use the interactive function calling tools.

For example, to interactively dimension and initialize the circle_parameters array to have 10 rows, 2 columns, with each element initialized to a value of 34.56, type the following line at your terminal:

DimAndInitFPArray( float 34.56,int 10,int 2,circle_parameters)↓

Remember to type at least one space after the ( character, and after the float and int keywords. QED-Forth will respond to your command with a line of text that summarizes the return value of the function, followed by the "ok" prompt. We can ignore the return value summary, because this function does not return a value.

Now to verify that the initialization was performed correctly, we can type at the terminal:

PrintFPArray( circle_parameters)↓

and, as always, we make sure that there is a space after the ( character. Note that we do not use the & (address-of) operator before the circle_parameters argument; it turns out that circle_parameters has already been defined in QED-Forth as the base address of the FORTH_ARRAY structure.

QED-Forth calls the function which prints the contents of the circle_parameters array, and then summarizes the return information (which we can ignore in this case). You can verify that the value of each array element is the same one that you specified when you called the DimAndInitFPArray() function. (Slight differences in the values are due to rounding errors in the floating point conversion and printing routines.) Using this interactive method, you can test each function with a variety of dimensioning and initialization information.

This page is about: Using Expanded Flash, RAM, and EEPROM Memory, Common and Paged Memory on 68HC11 Microcontroller, Compiler Memory Allocation, Memory Access, Heap Memory Manager, Ideal for Instrument Control Applications – The QCard Controller expands the 68HC11 processor's limited memory space to 1 Megabyte. The available RAM, Flash and EEPROM memory can accommodate sophisticated instrument control applications. paged memory, onchip memory, heap