manufacturer of I/O-rich SBCs, operator interfaces, handheld instruments, and development tools for embedded control low cost single board computers, embedded controllers, and operator interfaces for scientific instruments & industrial control development tools for embedded control order our low cost I/O-rich embedded control products embedded controller manufacturer profile single board computers & embedded controllers development tools & starter kits for your embedded design operator interfaces with touchscreens and graphical user interface plug-in expansion modules for digital & analog I/O C language & Forth language integrated development tools, IDE single board and embedded computer accessories embedded controller enclosures, bezels, environmental gaskets

The C Programmer’s Guide to the QVGA Controller

Table of Contents

PART 1 GETTING STARTED

Introduction. How to Use This Manual

Chapter 1: Getting to Know Your QVGA

PART 2 PROGRAMMING THE QVGA CONTROLLER

Chapter 2: Your First Program

Chapter 3: The IDE: Writing, Compiling, Downloading and Debugging Programs

Chapter 4: Making Effective Use of Memory

The QVGA Controller’s Memory Map

Addressing Memory in C

Software Development Using Flash Memory

Locating Nonvolatile Data in EEPROM

Using C Arrays and Forth (Kernel) Arrays

Chapter 5: Programming the Graphical User Interface

Chapter 6: Real Time Programming

Chapter 7: Failure and Run-Time Error Recovery

PART 3 COMMUNICATIONS, MEASUREMENT, AND CONTROL

Chapter 8: Digital and Timer-Controlled I/O

Chapter 9: Data Acquisition Using the QVGA Controller

Chapter 10: Outputting Voltages with Digital to Analog Conversion

Chapter 11: Serial Communications

Chapter 12: The Battery-Backed Real Time Clock

PART 4: PUTTING IT ALL TOGETHER

Chapter 13: A Turnkeyed Application

PART 5: REFERENCE DATA

Appendix A: QVGA Electrical Specifications

Appendix B: Connector Pinouts

Appendix C: Physical Dimensions

Appendix D: Schematics (pdf)

Chapter 4

<< Previous | Next>>

Making Effective Use of Memory

The QVGA Controller’s Memory Map

The QVGA Controller uses a paged memory system to expand the processor’s 64Kbyte address space to 8 Megabytes of addressable memory. The top half (32 Kbytes) of the address space (at addresses 0x8000 to 0xFFFF) addresses a common memory page that is always visible (i.e., accessible using standard 16-bit addresses) to any code running, no matter where it resides in the memory space.  The bottom half  (32 Kbytes) of the address space (at addresses 0x0000 to 0x7FFF) is duplicated many times and addressed through the processor’s 16-bit address bus augmented by an 8-bit page address.  Together the address and page are held in a 32-bit data type, an xaddress

A subroutine on any page can fetch or store to any address on the same page or in the common memory, or transfer control to another routine there.  It “sees” a 64K address space comprising its own page at addresses from 0x0000 to 0x7FFF and the common memory at addresses 0x8000 to 0xFFFF.  To address memory on another page, or to call a routine on another page, special memory access routines are used to change the page.  The heap memory manager and array routines allow you to think of the paged memory as contiguous memory for data storage.  The operating system automatically handles function calls and returns among the pages.

The operating system is designed so that there is very little speed penalty associated with changing pages.  The QED-Forth operating system automatically and transparently handles page changes

Figure 4‑1 illustrates the memory map of the QED Board.  Briefly, the upper 32K of the 68HC11's address space, the common memory, is always accessible without a page change.  In the lower 32K of the processor’s address space, the operating system creates 256 pages of memory selected by an 8 bit on-chip port, with each page containing 32 Kbytes.  The 32K of common memory at addresses 0x8000 to 0xFFFF (the upper half of the processor’s memory space) is always accessible without a page change.  Up to 256 pages (32K per page) occupy the paged memory at addresses 0x0000 to 0x7FFF.  The first 9 pages of the QVGA Controller’s 19 pages of installed memory are shown in the figure.

Figure 4‑1    The paged memory space of the QVGA Controller. 

Common Memory

The common memory is addressed at locations 0x8000 – 0xFFFF.  Some of it is used by the 68HC11 processor, some by the Forth kernel, and some is available for your programs to use.  The processor’s registers are located at 0x8000 – 0x805F, onboard hardware occupies addresses through 0x80FF, and the operating system reserves memory through location 0x8DFF for user areas, buffers, and stacks.  For example, the default user area that runs the interactive Forth interpreter occupies 0x8400 – 0x84FF.

The 8 Kbytes at locations 0x8E00 – 0xADFF are available RAM for the user.  The Control-C compiler uses this area for static variables, arrays, task areas, etc.  The Forth memory map routine USE.PAGE locates the variable area starting at address 8E00 in common memory.

The processor’s on-chip EEPROM (Electrically Erasable Programmable Read Only Memory) is located at 0xAE00 – 0xAFFF.  Locations 0xAE00 – 0xAEBF are reserved by the operating system for use by the SAVE and RESTORE utilities, and for interrupt vectors.  EEPROM at 0xAEC0 – 0xAFFF is available to your programs.

Table 4‑1      Partition of Flash and RAM among Kernel and Application Functions

Function

Size

Memory Page

Memory Address

Physical Location

Kernel Flash (160K)

 

 

 

 

Kernel

64K

00, 0C

0000 – 7FFF

QED Board S1

Kernel

1K

0E

various

QED Board S1

Kernel

19K

common

B400 – FFFF

QED Board S1

Kernel

12K

0F

0000 – 2FFF

QED Board S1

GUI Toolkit

64K

07, 0D

0000 –7FFF

QED Board S1

Kernel RAM (4K)

 

 

 

 

Kernel

3.5K

common

8000 – 8DFF

QED Board S2

Kernel

0.5K

0E

various

QED Board S2

RTC

48 bytes

 

B3D0– B3FF

68HC11

Kernel EEPROM (192 bytes)

 

 

 

 

Kernel

192 bytes

common

AE00 – AEBF

68HC11

Application Flash (224K to 608K)

 

 

 

 

Application code and graphic images

96K

04 – 06
(01– 03)

0000 – 7FFF

QED Board S1

Application code and graphic images

128K

70 – 73
(60 – 63)

0000 – 7FFF

QVGA Board

Application code and graphic images,
available with extended memory option

384K

74 – 7F
(64 – 6F)

0000 – 7FFF

QVGA Board

Application RAM (253K to 637K)

 

 

 

 

C variables

512 bytes

common

B000 – B1FF

68HC11

C variables, available at runtime but used during download as a Flash write buffer

464 bytes

common

B200 – B3CF

68HC11

C Variables and task area,
optionally battery-backed

8K

common

8E00 – ADFF

QED Board S2

Arrays and heap memory,
optionally battery-backed

20K

0F

3000 – 7FFF

QED Board S2

Arrays and heap memory,
optionally battery-backed

96K

01 – 03
(04 – 06)

0000 – 7FFF

QED Board S2

Arrays and heap memory

128K

60 – 63
(70 – 73)

0000 – 7FFF

QVGA Board

Arrays and heap memory,
available with extended memory option

384K

64 – 6F
(74 – 7F)

0000 – 7FFF

QVGA Board

Application EEPROM

 

 

 

 

EEPROM Variables

320 bytes

common

AEC0 – AFFF

68HC11

Notes:

1. Pages not enclosed in parentheses indicate the standard, or run-time memory map; pages in parentheses indicate the addressing of the memory during program download, i.e., the download memory map.

2. The 128K RAM in socket S2 on the QED-Flash Board can be optionally battery-backed.

3. Pages 00, 07, 0C, 0D, 0E and a portion of 0F are reserved to the operating system (the Kernel).

4. Application code is free to reside on pages 01-06, 60-6F, and 70-7F.

5. Addresses from 8000 through FFFF comprise common memory that is visible to code on all pages.

The 68HC11’s 1 Kbyte of on-chip RAM is located at 0xB000 – 0xB3FF.  Locations 0xB3F0 – 0xB3FF are reserved for the real-time clock buffers.  Locations 0xB3D0-0xB3DF are reserved for support of Forth interrupt service routines called from C-compiled programs. Locations 0xB200 – 0xB3CF are reserved for the flash programming routines. Locations 0xB000 – 0xB1FF are always available to the programmer (this area is named ONCHIP_RAM in the C linker command file; C programmers can locate data in this area using a #pragma directive).

Locations 0xB400 – 0xBFFF and 0xC100 – 0xFFFF contain kernel code.  A notch at 0xC000 – 0xC07F is not decoded by any onboard devices, and provides a convenient place for the user to memory map I/O that must be accessed quickly (that is, without requiring a page change).  Of course, an almost limitless amount of I/O can be mapped onto pages in the QVGA Controller’s 8 Megabyte address space.

Paged Memory

Occupying the paged memory space are 384K Flash and 256K RAM.  Of the QVGA Controller’s 384K of Flash, 224K is available for your application program and data storage.  The remainder is used by the QED Forth Kernel for its multitasking operating system, debugger, interactive Forth compiler, assembler, and hundreds of pre-coded device driver functions.  Of the 256K of RAM, 253K is available for application program use.  Up to 128K of that can be optionally battery backed.  An option is available that expands the installed memory to 768K Flash and 640K SRAM.

Table 4‑1 illustrates the partitioning of the onboard memory between the operating system (Kernel) and your application functions. Most of the Flash memory is available as two blocks of contiguously addressable memory on pages 4-6 and 70-73.  RAM for your application program is also available in the paged memory in two contiguously addressable chunks, filling pages 1-3 and 60-63.  There is also 20K available RAM on page 0F, and approximately 9K in the common memory.  This 9K is particularly important because it is used to hold C variables and task space for each separate task your application program sets up.

Table 4‑2      Partition of the Common Memory

Address

Size (bytes)

Type

Function

C100  –   FFFF

16128

Flash

Kernel – code

C000  –   C0FF

     256

I/O

Memory mapped I/O

B400  –   BFFF

   3072

Flash

Kernel – code

B3F0  –   B3FF

       16

RAM

Kernel – Real Time Clock Buffer

B3E0  –   B3EF

       16

RAM

Kernel

B3D0  –   B3DF

       16

RAM

Kernel – C/Forth ISR vectors

B200  –   B3CF

     464

RAM

Application – C variables at runtime, Flash write buffer during program download

B000  –   B1FF

     512

ONCHIP_RAM

Application – C variables

AEC0 –   AFFF

     320

EEPROM

Application – nonvolatile storage

AE00  –   AEBF

     192

EEPROM

Kernel

8E00   –   ADFF

   8192

RAM

Application – C Variables and multitasking task areas, optionally battery-backed

8500   –   8DFF

   2304

RAM

Kernel – buffers and stacks

8400   –   84FF

     256

RAM

Kernel – Forth user area

8060   –   83FF

     928

RAM

Kernel – buffers and stacks

8000   –   805F

       96

RAM

Kernel – processor Control Registers

Shaded entries indicate memory available for application programs.

The common memory is also partitioned between the operating system and application program.  Table 4‑2  shows the addresses used by the operating system, and in boldfaced type those addresses available to the application program.

Addressing Memory in C

Although 8-bits are sufficient to address the 256 possible pages, the page is padded out to a more standard 16-bit date type so that the full address, lower 16 bits plus 16-bit page, occupies 32 bits.  We’ll refer to this full address as an xaddress (32-bit extended addresses). Three macros are available in the \mosaic\fabius\include\mosaic\types.h file to simplify the manipulation of xaddresses  and their constituent 16-bit addresses and pages.  These C macros are:

 

TO_XADDR

XADDR_TO_ADDR

XADDR_TO_PAGE

Multi-page C programs rely on a “page change” routine in the common kernel memory to call functions on other pages.  Unlike the Forth compiler, the C compiler is not “page smart”, and does not know at compile time whether a page change is needed.  In fact, page changes are rarely needed, because most functions call other functions that are located on the same page or in common memory.  Calls to functions on the same page or to common memory take only 11.5 or 13.75 microseconds, respectively, while function calls to other pages require just under 49 microseconds.  Because page changes are rare, the average execution speed of multi-page C applications is not significantly impacted by the need for page changes.

Addressing Flash

Flash memory is nonvolatile, like PROM.  Thus it retains its contents even when power is removed, and provides an excellent location for storing program code.  Simple write cycles to the device do not modify the memory contents, so the program code is fairly safe even if the processor “gets lost”.  But flash memory is also re-programmable, and the flash programming functions are present right in the QVGA Controller's onboard software library. These functions invoke a special memory access sequence to program the flash memory contents “on the fly”.  This allows you to modify your operating software (for example, to perform system upgrades).  You can also store data in the flash device.  You can program from 1 byte up to 65,535 bytes with a single function call using the pre-coded flash programming routine.  Programming time is approximately 60 milliseconds per kilobyte.

Six special functions facilitate access to Flash memory. Their function names are:

 

DownloadMap()  PageToFlash()  PageToRam()

StandardMap()  ToFlash()      WhichMap() 

 

DOWNLOAD.MAP   PAGE.TO.FLASH PAGE.TO.RAM

STANDARD.MAP   TO.FLASH WHICH.MAP

The FLASH programming functions use a buffer in the 68HC11's on-chip RAM starting at hex addresses B200-B3CF.  The remaining on-chip RAM at B000 to B1FF is available to you.  Also, because FLASH programming is generally not done at run-time, you can still use the Flash buffer for run-time variables.

Software Development Using Flash Memory

Because code cannot be downloaded or compiled directly into flash memory, the flash memory map implements page swapping to provide a mechanism for getting the compiled code into the flash memory.  There are two page-swap modes: one is called the Standard Map and the other is called the Download Map.  As the names suggest, the Standard Map is used during run-time, and the Download Map is used during downloading and compilation of Forth source code C-compiler S-records from the PC to the QED Board. The two maps are very similar; the effect of changing from the Standard to the Download map is to swap the locations of pages between the flash and the RAM.

Table 4‑3      Addressing the Flash and RAM in Standard and Download Memory Maps

 

Flash Pages

RAM Pages

Standard Address Map

04 – 06

70 – 7F

01 – 03

60 – 6F

Download Address Map

01 – 03

60 – 6F

04 – 06

70 – 7F

In normal operation the Flash memory is addressed on pages 04-06 and 70-7F, and the RAM is addressed on pages 01-03 and 60-6F.  During download their addresses are swapped, so that the Flash is addressed at pages 01-03 and 60-6F and the RAM at pages 04-06 and 70-7F.

To see how it works let’s consider a hypothetical download.  Suppose you have compiled code intended to load into the Flash and run from it at addresses on page 4.  Automated commands contained in the download file establish the download map, load the code into RAM, transfer the code to flash, and re-establish the standard map.  In this case, the download file would:

    1. Swap the addresses of the RAM and Flash (by executing the command DOWNLOAD.MAP) so that the RAM is now addressed on page 04;

    2. Download the code to its proper addresses on page 04;

    3. Copy the code (using the command PAGE.TO.FLASH) from page 04 into the Flash addressed on page 01; then,

    4. Swap (by executing the command STANDAD.MAP) the RAM and Flash addresses back so that the Flash is now addressed on page 04, and the RAM on page 01 is available for run-time use by your program. 

The Control-C download file does all this for you so you don’t need to worry about the details.  But if you’re interested, just peruse the download file in the editor where you’ll see the commands it uses to manage memory during the download process.

You can now run the program by typing

MAIN

or any function name that was preceded with the _Q designator.  (By the way, the _Q does not compromise performance in any way; it simply makes it possible for the PC-resident batch routines to send out the execution addresses of the designated functions to the QVGA Controller to simplify debugging). 

You can also execute an autostart command to cause a specified function to be automatically called upon each restart.  To place the autostart vector in EEPROM inside the processor, execute the command:

CFA.FOR  MAIN AUTOSTART

To place the autostart vector in flash in socket S1, execute the command:

CFA.FOR  MAIN PRIORITY.AUTOSTART

For most applications, the PRIORITY.AUTOSTART option is preferable because it locates the autostart vector with the code in the flash memory device.

C EXAMPLE SESSION

Here’s how easy it is to compile a C program into flash:

First compile a source code file.  For example, to run a “Hello World” program, your source code file might be named HIWORLD.C with the following contents:

#include <\mosaic\allqed.h>  // this include statement should

// appear at the top of each source // code file.

_Q void HelloWorld( void ) 

{ printf(“\nHello Everyone!\n”);

}

void main( void )

{ HelloWorld();

}

Use the standard “hammer” icon to compile the file onto a single page (page 4).  Those with C compilers shipped in late 1998 can just send the HIWORLD.TXT file to the QED Board using the Terminal program. 

We recommend using the QEDTERM.EXE terminal program that is available on the Mosaic Industries web site (www.mosaic-industries.com) or on the Demo and Driver Disk that accompanies each new QED-Flash Board; it runs under Windows 95, 98, and NT. Customers running Windows 3.x can use the Microsoft Windows TERMINAL.EXE program.

For those with older versions of the C compiler, type the following commands from the terminal to the QED Board:

DOWNLOAD.MAP   

<use the terminal’s Send Text File feature to send HIWORLD.TXT to the QED Board>

4 PAGE.TO.FLASH

5 PAGE.TO.FLASH

STANDARD.MAP

MAIN// executes the program!

You’ve compiled your program, downloaded it into RAM, transferred it to flash, and executed it.  If you want to set up an autostart routine, follow the standard procedure as explained above, or consult the final chapter of the “Getting Started with the QED Board Using the Control C Programming Language” manual.

How the Kernel (QED-Forth) Changes Pages (from QED Software Manual)

Compilation of Page Changes (from QED Software Manual)

The Memory Map (from QED Software Manual)

Appendix A QED Board Memory Map (from QED Software Manual)

QED Board Memory Map Description (from QED Software Manual)

The QED Board’s Address Space and Onboard Memory (from QED Hardware)

Write-Protection Transforms Memory Pages to Emulated ROM (from QED Hardware)

Splitting the Dictionary to Write-Protect Debugged Code (from QED Software Manual)

Burning An Application PROM to Move Into Production (from QED Hardware)

Using the Heap Memory Manager

The Heap Memory Manager (from QED Software Manual)

Multiple Heaps – One Heap per Task

Multiple Heaps (from QED Software Manual)

Heap Compaction (from QED Software Manual)

Handles to Heap Items (from QED Software Manual)

Heap Size (from QED Software Manual)

Initializing the Heap (from QED Software Manual)

Allocating Heap Items (from QED Software Manual)

De-allocating Heap Items (from QED Software Manual)

Maximizing the Efficiency of Heap Compaction (from QED Software Manual)

Resizing and Copying Heap Items (from QED Software Manual)

Transferring Heap Items (from QED Software Manual)

Heap-Based Data Structures (from QED Software Manual)

Locating Nonvolatile Data in EEPROM

The QVGA Controller’s built-in EEPROM provides an ideal place to store calibration constants or other data that must be changed from time to time, but that must be retained even when power is removed.  The EEPROM (Electrically Erasable Programmable Read-Only Memory) can be modified up to 10,000 times before it loses its ability to retain data.  The ANALOGIO.C file presents an example of how to locate a static “variable” in EEPROM. 

The EEPROM variable should be declared as an un-initialized static variable; these are located by the linker in the “data” section, which normally points to system RAM where normal variables are stored. By following the syntax presented here, you can relocate the data section to point to EEPROM while defining the EEPROM variables, and then restore the data section to its standard RAM location.  To define an EEPROM variable, use the following code:

 

#pragma  option data=.eeprom  // put the following variables in eeprom

static uchar numsamples;

static int  nonvolatile_int;

static float calibration_value;

#pragma  option data=.data  // restore the data area to RAM

The #pragma statements are pre-processor directives that are interpreted by the linker.  In the code fragment above, we located three nonvolatile variables in EEPROM; note that we did NOT include initializers in the declaration statements.  Initializers don’t make any sense for EEPROM variables, because special functions must be called to store values into EEPROM, so initialization can’t be accomplished by placing initialization data in the download file.  These EEPROM variables must be initialized programmatically at run-time.

To store data into the EEPROM variables, use the following functions which are declared in the XMEM.H file in the \MOSAIC\FABIUS\INCLUDE\MOSAIC directory:

 

void StoreEEChar(char value, char* addr)

void StoreEEInt(int value, int* addr)

void StoreEELong(long value, long* addr)

void StoreEEFloat(float value, float* addr)

To learn how to interactively modify the contents of EEPROM variables, read the glossary entries for these functions in the Control-C Glossary.

These EEPROM storage functions are easy to use.  For example, to store the value 123 into the character variable numsamples, you would place the following statement in your program:

 

StoreEEChar( 123, &numsamples);

To avoid wearing out the EEPROM by executing unneeded write cycles, these functions check whether each EEPROM byte already holds its specified contents.  If so, the write is not performed.  Thus there is no penalty for redundant execution of commands that initialize particular locations in EEPROM.

While EEPROM variables must initialized programmatically at run-time the first time they are used, they don’t need to be re-initialized each time the processor starts up because the nonvolatile EEPROM retains the data.  Even so, initializations can be performed every time the processor starts up, with no adverse effects on the life span of the EEPROM.  For example, initialization code in an autostart routine could execute ATTACH functions to ensure that all needed interrupt vectors are properly initialized each time the processor restarts.  If the EEPROM cells have been corrupted for some reason, the ATTACH command installs the correct contents, but if the specified interrupt vector information is already in the EEPROM, the memory cells are not needlessly rewritten.

Interrupts are disabled during writes to EEPROM

All of the EEPROM storage routines globally disable interrupts while each EEPROM byte is being programmed, and it takes 20 milliseconds to program each byte.  Thus you should avoid storing values in EEPROM while time-critical events are being serviced by interrupts.

For experts and the curious: Interrupts are disabled during stores to EEPROM  because QED-Forth vectors all interrupts via the EEPROM, and the 68HC11 hardware does not allow any EEPROM cells to be read while a single EEPROM cell is being written to. Thus if an interrupt occurs while one of the EEPROM storage functions is writing to EEPROM, the interrupt will not be able to read the instruction code in the interrupt vector.  Disabling interrupts prevents this error, but the interrupt service is delayed until the EEPROM write is finished.

Write-Protecting EEPROM

It is possible to write-protect locations within the EEPROM to ensure the integrity of calibration constants or other vital information. This is done using the EEPROM block protect register named BPROT (MC68HC11F1 Technical Data Manual,  p.8-2).  Four blocks of size 32, 64, 128, and 288 bytes may be individually protected by storing an appropriate configuration value to BPROT.  The contents of the BPROT register may be changed using the C function InstallRegisterInitsQED-Forth word INSTALL.REGISTER.INITS; please consult its glossary entry for details.

To make a turnkeyed application maximally “bullet-proof” and fail-safe, consider using the BPROT register to protect the first three blocks in the EEPROM totaling 224 bytes.  This protects the onboard kernel’s configuration region (the first 32 bytes in EEPROM) plus the interrupt vectors (the next 160 bytes in EEPROM) plus an additional 32 bytes available the programmer.  The remaining 288 bytes of EEPROM then remain available for modification by the application program.

Once values have been stored in the EEPROM, they may be read using the conventional memory fetch operations such as C@, @, and 2@.

Using C Arrays and Forth (Kernel) Arrays

Storing Data Acquisition Results in C Arrays and Forth Arrays

Programs written in Control-C use space in common memory to store variables.  You may store simple variables or arrays of variables there using standard C syntax.  However, common memory is a limited to approximately 9K.  It can get used quickly in multitasking systems because each task requires a task area of about 1K.  Consequently, the programmer may require access to additional RAM.  Access is provided through the use of Kernel Arrays, also called Forth Arrays.  Using Forth Arrays you may dynamically dimension arrays of virtually any size in the extended address space – and their memory allocation is automatically handled by the kernel’s heap memory manager.

The code presented in the sample program ANALOGIO.C uses a C array and a FORTH_ARRAY to store the results of multiple A/D conversions.  This section uses that code as an example to discuss some interesting features of both C Arrays and FORTH_ARRAYs.

Declaring a C Array

The use of C arrays is discussed in detail in all standard C texts.  In this program, the one-dimensional 16-element character array named results_8 is declared and allocated in RAM using the statement:

 

uchar results_8[DEFAULT_NUMSAMPLES];

where DEFAULT_NUMSAMPLES is a constant equal to 16.  The arrays are easy to use.  For example, the following C statement assigns the last element in the array to a static variable named my_variable:

 

my_variable = results_8[15];

To see another simple example that demonstrates how C arrays are accessed, look at the InitAnalog() function in the ANALOGIO.C file. The results_8 array is zeroed by executing the following statement:

 

for(i=0; i< DEFAULT_NUMSAMPLES; i++)

results_8[i] = 0;         // zero the array

Note that this array is dimensioned and allocated by the compiler and linker.  In contrast, FORTH_ARRAYS are dimensioned and allocated dynamically by the run-time program itself.

Converting a 16 Bit Address to a 32 Bit xaddress

The AD8ToCArray() function that we just used provides an interesting example of type conversion.  The definition of the function is:

 

_Q void AD8ToCArray( int channel)

{  EXTENDED_ADDR buffer;

buffer.sixteen_bit.addr16 = results_8;

buffer.sixteen_bit.page16 = 0;

AD8Multiple(buffer.addr32,0,DEFAULT_NUMSAMPLES,channel);

}

The purpose of AD8ToCArray() is to properly call AD8Multiple() which is defined in the ANALOG.H file.  AD8Multiple() is optimized to use a FORTH_ARRAY buffer, and so expects a 32 bit buffer xaddress instead of a simple 16 bit buffer address.  To convert the simple 16 bit address returned by results_8 into a 32 bit extended address, we take advantage of the EXTENDED_ADDR union defined in the TYPES.H file in the \MOSAIC\FABIUS\INCLUDE\MOSAIC directory.  The union is defined as:

 

typedef union{    xaddr addr32;

struct{ uint  page16;

char* addr16;

} sixteen_bit;

}  EXTENDED_ADDR;

To convert a 16 bit address into a 32 bit xaddress, we use the EXTENDED_ADDR typedef to declare an instance of the union (named “buffer” in this example), store the 16 bit address into the buffer.sixteen_bit.addr16 element, and store 0 (the default page) into the buffer.sixteen_bit.page16 element.  Then we reference the corresponding 32 bit xaddress via the buffer.addr32 element of the union.  While it is rare that you will have to convert from 16 bit to 32 bit address types, this example provides a template for how to do it.

A Review of FORTH ARRAYs

FORTH_ARRAYs have two key advantages.  First, they are allocated in paged memory, so they allow your program to access the large 8 Megabyte memory space of the QED Board.  In contrast, C arrays must reside in the available common RAM which is limited to approximately 9 kilobytes on the QVGA Controller.  Second, they can be dynamically dimensioned, re-dimensioned and de-allocated (deleted) while your program is running; this boosts efficiency by maximizing the use of the available memory.

To define a new Forth Array, simply use the FORTH_ARRAY typedef followed by a name of your choice.  For example, in the ANALOGIO.C file the following declaration appears:

 

FORTH_ARRAY  results_12;

Before the FORTH_ARRAY can be accessed at runtime, it must be dimensioned.  This is typically accomplished by calling the DIM() macro defined in the ARRAY.H header file.  For example, to dimension the results_12 array to have 10 rows and 1 column of integer data, we would execute:

 

DIM(int, 10, 1, results_12);

In the ANALOGIO.C file, the pre-defined macro named DIM_AD12_BUFFER() invokes the DIM() routine for us (its definition is in the ANALOG.H file in the \MOSAIC\FABIUS\INCLUDE\MOSAIC directory).

After the FORTH_ARRAY is dimensioned, it can be accessed by a family of macros and functions that are defined in the ARRAY.H header file and are described in the Control-C Glossary.  These include functions that fetch from, store to, and calculate the address of individual elements, swap and copy entire arrays, fill an array with a specified character, and delete the array so that it no longer requires memory in the heap. The PrintForthArray() and InitAnalog() functions in ANALOGIO.C provide examples of how to call a few of these functions.

Printing the Contents of a FORTH ARRAY

The PrintForthArray() function presented in ANALOGIO.C is a more general version of the PrintFPArray() function in GETSTART.C as discussed in an earlier chapter. The function is defined as follows:

 

_Q void PrintForthArray(int float_flag, FORTH_ARRAY* array_ptr)

// works for FORTH_ARRAYS dimensioned using the standard DIM() macro.

// float_flag is true if array holds float numbers, false otherwise.

{ int r, c;

putchar(‘\n’);

for (r = 0; r < NUMROWS(array_ptr); r++) // for each row

{   for  (c = 0; c < NUMCOLUMNS(array_ptr); c++) // for each column

if(float_flag)

printf(“%9.4g  “,FARRAYFETCH(float,r,c,array_ptr));

else     

printf(“%9ld  “,ARRAYFETCH(long,r,c,array_ptr));

putchar(‘\n’);       // newline after each row is printed

PauseOnKey();        // implement xon/xoff output flow control

}

}

After calling putchar() to output a newline character, we enter nested for() statements that print the contents of each element.  Because the compiler treats floating point numbers differently than numbers stored in other formats, we use FARRAYFETCH() to access floating point arrays, and ARRAYFETCH() to access char, int or long arrays.  The PauseOnKey() function is called once per row to suspend the QVGA Controller’s printed output if the terminal program has sent the XOFF handshake character; the printout resumes when the terminal sends the XON character.  PauseOnKey() also gives the user the ability to terminate the printout by typing a carriage return character from the terminal.

This function can be tailored to meet the detailed needs of your application.  You can change the printf() formatting, or insert extra carriage returns to confine the printout to one screen width.

Access Routines for Arrays and Matrices

The routines 2ARRAY.STORE and 2ARRAY.FETCH have been added to the kernel to enable you to store to and fetch from 2-dimensional arrays or matrices.  The unique aspect of these routines is that they properly handle data of different sizes (1 byte, 2 bytes, or 4 bytes) depending upon the way that the array or matrix is dimensioned.  For example, if an array named CHAR.ARRAY is dimensioned (using the DIMENSIONED routine) to hold 1 byte per element, then executing

 

0  0  ‘ CHAR.ARRAY 2ARRAY.FETCH

will return the first 8-bit character in the array.  If another array named DATA.ARRAY is dimensioned to hold 16-bit data, then executing

 

0  0  ‘  DATA.ARRAY 2ARRAY.FETCH

will return the first 2-byte element in the array.  These routines help support access to paged memory when programming in Control-C.


Wildcard Carrier Board Drivers

\ ****************************************************************************************

\ FILE NAME:  To_xFlash.4th

\ Kernel extension for supporting memory management and flash programming for the

\ Wildcard Carrier Board and QVGA Controller Board

\ Copyright 2002-2003 Mosaic Industries, Inc.  All rights reserved.

\ ---------------------------------------------------------------------

\ DATE:        2/06/2003

\ VERSION:     1.2

\ SUPPORTED HARDWARE:

\ QED-4 (FLASH) Board

\       QVGA Controller Board

\ WildCard Carrier Board

\ ---------------------------------------------------------------------

\ Please see the Wildcard Carrier Board User Guide for detailed instructions.

\

\ These are the User Functions defined by this driver:

\ To_xFlash      ( xsource_addr\xdestination_addr\numbytes -- success )

\ Query_xMemory  ( page -- device.size&type )

\ Is_xRAM        ( page -- flag )

\ Is_xFlash      ( page -- flag )

\ Page_To_xFlash ( source.page -- )

\ Download_Map_QVGA ( -- )

\ Download_Map_WCB  ( -- )

\ Standard_Map_QVGA ( -- )

\ Standard_Map_WCB  ( -- )

\

\ To_xFlash allows writes to the extra flash chip on the WCB, the QVGA Controller,

\ and/or the kernel flash chip. This function has the same behavior as To_Flash

\ (see its glossary entry in the QED-FLASH update notice), but uses the ID of the

\ flash device to determine how to perform the write.

\

\ Query_xMemory determines the size and type of an extra memory device. The value

\ returned is a signed integer of the size in kilobytes. The sign represents the

\ device type, a positive size for RAM, and negative for flash. A value of zero

\ means either no device resides at the base page, or a flash chip is installed with

\ either an unknown ID, or is write protected.

\ Two notes on Query_xMemory:

\   The base page of the device must equal the bitwise-AND of the page and 0xF0.

\   Zero is returned if the base is zero

\

\ Is_xRAM and Is_xFlash return true is the given page resides on the coorepsonding

\ memory device. Note, these functions are wrappers for Query_xMemory.

\

\ Page_To_xFlash is the To_xFlash replacement for PAGE.TO.FLASH. It is aware of the

\ RAM and flash devices available for the WCB and QVGA Controller, and provides

\ download friendly error reporting.

\ Note, it relies on Is_xRAM and Is_xFlash for parameter checking

\

\ Note, the above functions use the same buffer areas as the kernel routines

\ that they supercede (ie To.Flash and Page.To.Flash).

\ (buffers are located in the top half of onchip RAM from 0xB200-0xB3E0).

\ These routines are not re-entrant with respect to multitasking.

\ This means that a multitasking application cannot support simultaneous

\ flash programming by separate tasks unless a resource variable is defined

\ and GET and RELEASE are used.

\

\ Download_Map_QVGA, Download_Map_WCB, Standard_Map_QVGA, Standard_Map_WCB provide a

\ simple way to set the memory map of a board while clearly stating what is being done.

\

\ Standard Map        Download Map

\ RAM     Flash       RAM     Flash

\ QED 01-03   04-06       04-06   01-03

\ WCB 40-4F   50-5F       50-5F   40-4F

\ QVGA 60-6F   70-7F       70-7F   60-6F

\

\ NOTE: The memory map of the QED Board is maintained across power cycles and resets,

\   but is cleared by a factory cleanup. However, the WCB and QVGA, revert to standard

\   map at powerup, but maintain their state across resets or factory cleanups.

\

\ The above functions should provide simple means to compile code for storage in the

\ flash devices of the QED Board, the Wildcard Carrier Board, or the QVGA Controller.

\

\ Top Level C Functions:

\   int To_xFlash ( xaddr source, xaddr destination, uint numbytes )

\   int Query_xMemory ( int page )

\   bool Is_xRAM ( int page )

\   bool Is_xFlash ( int page )

\   void Page_To_xFlash ( int source_page )

\   void Download_Map_QVGA ( void )

\   void Download_Map_WCB ( void )