|
|
Updated 3rd May 2003
A general guide for configuring the Micro-C library/startup
code can
be found in the README.TXT file located in the library
subdirectory
(LIBxx\README.TXT).
For details on the initialization of the CPU, configuring memory
(if
required), interrupts etc. please refer to the manufacturers
data books,
and the library startup file as noted in the README.TXT
mentioned above.
Information on setting up and using the INTERRUPT macro is
located in
the comments at the beginning of the <cpu>INT.H header
file.
Finally, while configuring the library, make liberal use of the
CCxx -L
option to generate a complete listing. This will enable you to
see exactly
how the compiler is laying out the code/data in memory.

This most likely indicates that the compiler is unable to
open it's temporary files.
First, check the setting of the MCTMP environment variable. This
variable defines a PREFIX which is applied temporary filenames.
Make sure that when the content of this variable is prepended to
a filename, the result will be a valid filename and location (ie:
the directory exists, is writable etc.)
Example: Temp directory is C:\TEMP, filename is 'myprog.tmp'
set MCDIR=C:\temp\ <= Note trailing '\'=
c:\temp\myprog.tmp
-or-
set MCDIR=C:\temp\$ <= Results in = c:\temp\$myprog.tmp
DO NOT USE: set MCDIR=C:\temp <= No trailing '\'= c:\tempmyprog.tmp
If you wish, you can delete MCTMP (set MCTMP=), and the compiler
will use the standard 'TEMP=' environment variable definition.
In this case, TEMP= refers to a directory (not a prefix), and
should not have the trailing '\'. eg: set TEMP=C:\temp
<= C:\temp\myprog.tmp
If you are having trouble with the setting of these environment
variables, try setting MCTMP to a single '$' (set MCTMP=$), this
will cause all temp files to be written in the current directory
with a '$' prefix. This will work in nearly all cases.
A less likely cause of this problem can be a setting of FILES=
in your CONFIG.SYS file which is too low. Normally, you should
have FILES= set to at least 30, or larger if other programs can
have files open while you are running the tools. Try increasing
the setting of FILES=
[NOTE: If you are having trouble getting DDS tools to see your
environment variables, MAKE SURE that you are NOT putting spaces
in the settings. ie: use 'SET MCDIR=C:\MC', **not** 'SET MCDIR =
C:\MC' These spaces ARE NOT removed by the system, which makes
them highly undesirable, since they waste space in the
environment area. DDS tools DO NOT accept the spaces in
environment variable settings.]

(What's with the numeric error codes anyway... Didn't this
kind of error reporting go out with the Dinosaurs!!! ?)
DDS Tools DO NOT generate numeric "error code"
messages. All of our tools generate full text error messages
which are output via the DOS standard error stream (usually
console output).
The "error code" that you are seeing is the exit
status of the program step that was running at the time the
error was detected. This is a single byte (0-255) that is passed
back by ALL programs when they terminate, and is used to inform
any calling program that the sub-program succeeded or failed at
its task. A value of 0 indicates that the program succeeded, and
all non-zero values indicate that it failed.
CC* and DDSIDE examine the exit status code and terminate the
entire compile process if any step indicates failure with a
non-zero exit code. As a matter of convenience, they also
display the offending non-zero exit code in case the user needs
it for debugging his setup. (If the tools are not installed
properly, a program step can fail to execute, in which case all
you will get is the DOS exit status when the "exec"
function failed).
Commonly seen exit codes are:
2 -
Command not found (Check MCDIR, PATH)
3 -
Invalid directory (Check MCDIR, MCTMP, command line)
4 - Out
of file handles (Increase FILES= in CONFIG.SYS)
5 - Bad
filename (Check MCDIR,
MCTMP)
254 - Program found
errors during processing
255 - Program was
invoked with incorrect arguments
A complete list of DOS exit codes can be found near the end of
the DDSIDE documentation.
Whenever any of the DDS compile steps fail and return a non-zero
exit code, they ALSO print a detailed error message on the
standard error output device. If you are compiling with CC*,
just look at the output from the last compile step that was
running. If you are using DDSIDE, the output from the last
compile step will be saved in the error log, which can be viewed
(See DDSIDE documentation).
All too often, people see the "...... failed (nnn)"
message in the last line of the CC* output, or the "Step
'.....' failed with exit code nnn", in the status line at
the top of the DDSIDE screen, and fail to see any other error
messages. The messages ARE there! (look for them)
Also note that if assembly errors occur, and you were generating
a listing, the error message will be shown in the listing (by
the lines where the errors occurred) instead of being output on
the console.

These messages are produced by the Micro-C linker (SLINK).
A bit of background:
SLIB is a "generic" name that SLINK assumes for the
processor library if it
is not given one. All of my embedded toolsets use their own
unique library
subdirectory, which is passed to SLINK with the L= option.
Therefore the
subdirectory name "slib" should never be referenced
when executing my
standard tools.
EXTINDEX.LIB is the "Generic" name I use for libraries
for processors that
have only 1 memory model. SLINK assumes this name for the .LIB
file if you
do not give it one. For processors with more than one memory
model, there
are multiple .LIB files. The filename EXTINDEX.LIB is not used
in this case,
as the multiple files are given more meaningful names. For
example, in the
case of the 8051, there are five different memory models and
hence five
different library index files (TINY.LIB, SMALL.LIB, COMPACT.LIB,
MEDIUM.LIB
and LARGE.LIB). The library index file is passed to SLINK with
the I= option.
Also note that for most processors supporting multiple memory
models, the
memory model passed to the compiler (MCC*) must match the index
file linked.
Please refer to the Micro-C technical manual, section entitled
"The Source
Linker" for more details on how libraries, linking and
SLINK work.
The user interface tools I supply (CC* and DDSIDE) all specify a
memory
model to the compiler, and the corresponding library and index
file to
SLINK. You can also refer to my LINKHELP example, which will
generate batch
and makefiles showing you how to compile and link in the various
memory
models using the individual compile steps. (MCP, MCC*, MCO*, ASM*
etc.)
If you are getting a message involving "SLIB" this is
usually an indicator
that the SLINK L= option has not been properly specified (L= is
REQUIRED
for ALL DDS toolsets). If the library directory is correct but
the message
indicates EXTINDEX.LIB "..\LIBxx\EXTINDEX.LIB", this
is usually an indicator
that the SLINK I= option has not been supplied for processors
which require
it.
NOTE: If you are receiving these messages when using Bipom's
Micro-IDE as
the command shell for the compiler, you will have to contact
Bipom to find
out how to properly configure their product for the processor
and memory
model that you are using.

At present, SLINK can deal with only one .LIB file at a time,
which means
that it can really only link with one library at a time.
You can however "fake" it, by merging in the .LIB
files from two (or more)
libraries, and pointing their file entries at the original
library paths.
This has the effect if providing SLINK with a single library
(.LIB), but
having the files physically located in separate directories. You
can use
as many .LIB files as you wish, to create all file/library
combinations
that you may need to use.
eg: to make a library in \mc\mylib which allows you to use your
own files
as well as those from the standard library,
do these steps:
1) Make the directory, and copy in your .ASM library files
2) Run "SINDEX i=TEMP" to generate a TEMP.LIB file
containing the
function definitions for your index files.
3) copy the .LIB file from the standard library (this will be
EXTINDEX.LIB
for CPU's with only one memory model, or
<model>.LIB for CPU's with
multiple memory models).
4) Modify the .LIB file above to reference the full pathname to
the standard
library files. You will have to modify the
'<', '^', '>' and '-' entries
(hint: Your editors global change feature can be
handy here - For example
with my DDSIDE or EDT editors, you can change all
occurances
of: -filename.ASM
to:
-c:\mc\lib51\filename.ASM
with the single command: /s'-'-c:\mc\lib51\
5) Append your TEMP.LIB file to the .LIB file above (it's
entries will still
not contain a pathname, and will therefore
reference the files from this
directory), then delete TEMP.LIB
6) When you run SLINK to link the program, specify L=c:\mc\mylib
(or whatever
directory you used).
-- An alternative is to modify the .LIB files in the micro-c
library
directory to include your symbols will full paths
to the files, then
your library will **always** be linked with the
standard library.

Micro-C actually has TWO preprocessors, and if you are not
using the
right one, #include filenames and other preprocessor features
may not
work the way you expect:
1: The "full up" Micro-C-Preprocessor (MCP.EXE)
The Micro-C-Preprocessor (MCP.EXE) gives full
preprocessor capabilities.
MCP is a separate stand-alone program, and you can run it
by itself to
preprocess (only) your source files if you wish.
The CC* commands and DDSIDE will automatically run MCP
for you... To
run MCP when compiling with CC*, just make sure you add
the -P option
to the CC* command line. From within DDSIDE, make sure
that you have the
"Preprocess" step enabled under
"Compile/Steps".
When you are using MCP:
- #include filenames use the standard "" or
<> syntax:
#include <xxx.h>
<= Include from Micro-C home directory
#include "yyy.h"
<= Include from current directory
#include "c:\tmp\zzz.h"
<= Include from 'C:\TMP'
#include myfile.h
<= "Invalid include file name"
#include c:\mc\stdio.h
<= "Invalid include file name"
- #define supports parameters, recognizes comments, and
accepts macro
definitions containing whitespace, including
line-continuation:
#define ABC 123
<= Define 'ABC' as '123'
#define DEF(a) a+1
<= Define 'DEF(x)' as 'x+1' (parameterized)
#define GHI (a) a+1
<= Define 'GHI' as '(a) a+1'
#define JKL /* null */
<= Define 'JKL as ''
#define MNO ...\
<= Continue definition on next line
- #if/#ifdef/#ifndef/#else/#elif/#endif are all
supported, can be nested.
- #undef/#forget/#error/#message are all supported.
- #commands may be indented.
- Predefined symbols __TIME__ __DATE__ __FILE__ __LINE__
are available.
- MCP has much more symbol table space than the MCC*
internal pre-
processor.
2: The Micro-C Compiler (MCC*.EXE) has a limited built-in
preprocessor
If you DO NOT specify the -P option to the CC* command,
or DO NOT enable
the "Preprocess" option in DDSIDE, MCP will
**NOT** run, and you will have
only the limited preprocessor which is built into the
Micro-C compiler
itself (MCC*.EXE). This preprocessor exists only as a
convenience from the
days when running the separate MCP step on floppy disks
took a long time...
Most people will want to **always** run MCP now, however
not running it
can still save a bit of time on slower systems...
The limitations of the "built-in" preprocessor
are:
- #include filenames do not recognize "" or
<>, and do not know about
the Micro-C home directory:
#include filename.h
<= Include from current directory
#include c:\mc\stdio.h
<= Include from 'C:\MC'
#include "xxx.h"
<= Tries to open '"xxx.h"' (fails)
#include <yyy.h>
<= Tries to open '<yyy.h>' (fails)
- #define does not support parameters, and accepts only
up to the
first whitespace character. Also, comments
are not recognized:
#define ABC 123
<= Defines 'ABC' as '123'
#define DEF(a) a+1
<= Defines 'DEF(a)' as 'a+1'
#define GHI (a) a+1
<= Defines 'GHI' as '(a)'
#define JKL /* null */
<= Defines 'JKL' as '/*'
#define MNO ...\
<= Defines 'MNO' as '...\'
- Only #ifdef/#ifndef/#else/#endif conditionals are
supported, and
these do NOT nest!
- #if/#elif/#undef/#forget/#error/#message are NOT
supported.
- #commands are only recognized beginning in column #1.
- Predefined symbols are NOT available.
- The internal preprocessor has much less symbol table
space than
the external one.

The use of #include <path\file> is a common misuse of the
prerprocessor
which many other compilers appear to allow, however Micro-C does
not.
The angle brackets are used around a filename to denote a file
which is
to be included from the compiler's own header file library.
Therefore
when <filename> is used, the Micro-C preprocessor
automatically inserts
the Micro-C home directory to preceed the filename.
To include a file with an arbitrary path, use DOUBLE QUOTES
around the
filename, thus:
#include <myfile.h> - Get MYFILE.H
from Micro-C home directory.
#include "myfile.h" - Get
MYFILE.H from current directory.
#include "\x\myfile.h" - Get MYFILE.H from
"\X" directory

The "printf()" function REQUIRES a function prototype
which is located
in the standard IO header file. This file is called STDIO.H for
Micro-C/PC,
and <cpu>IO.H in the embedded developers kits. Make sure
you are including
this file in any source modules which use printf() (or any
"printf" type
function).
The reason that the prototype is required, is that Micro-C has a
language
extension whereby functions declared with the
"register" attribute will
receive a count of the number of passed arguments whenever they
are called.
The "printf(), fprintf(), sprintf(), wprintf(), w_printf()
etc." functions
supplied with Micro-C all make use of the feature, and therefore
must be
prototyped with the "register" attribute.
Please refer to the prototype descriptions in the library
documentation.

The details of accessing parameters differs from one CPU to the
next,
but usually they are accessed by constant offsets from the stack
pointer.
Please refer to the section entitled "Assembly Language
Interface" in
the Micro-C Technical Manual.
For examples of accessing parameters in assembly language
functions
which are written entirely in assembly language (ie: a .ASM
source file),
please refer to the Micro-C library source code. There are many
examples
there of assembly language functions accepting various
parameters.
For examples of accessing parameters from inline assembly
language portions
of functions written in 'C' (including functions which are
entirely inline
assembly language with only the 'C' function
"wrapper"), it is best to see
how the compiler accesses the parameters. To do so, compile a
small function
which has the parameters you wish to use in the inline assembly
function,
and simple reference each parameter once in the main body:
myfunc(int p1, char p2, char *p2, unsigned p4)
{
/* Local variables (if required)
- see note below */
p1;
p2;
p3;
p4;
}
Compile this with the CCxx -CA option and look at the resulting
assembly
language output file. This will show each reference, and the
code generated
to access the parameter.
NOTE: Some CPU implementations require that the offsets to the
function
parameters be adjusted by the size of local variable allocation.
If you
are referencing the parameters with an inline assembly block in
a 'C'
function which has local variables, include the EXACT local
variable
definitions in your example/test function above, to insure that
the
offsets generated in the output .ASM file will be correct.

There could be many reasons for this...
Micro-C "Developers Kits" are designed to be used with
virtually any
embedded system that can be immagined. They are NOT designed to
work
with any one "off the shelf" system. This means that
you will quite
likely have to configure the compiler's library to know about
such
things as the memory map of your target system before programs
will
execute properly.
See the LIBxx\README.TXT file for details on configuring the
library.
Some "off the top" reasons why "good" code
might not run:
 | Execution address:
 | The libraries shipped with my tools are configured to
run under the "most common" configuration of
my MONxx debuggers (or EMILY52 package). In this
configuration, the code loads into RAM, and is executed
by the ROM debugger. It is quite likely that this
starting RAM address does not match the requirements of
your system. |
 | For some targets which require initialization of a
reset vector, you
may have to add code to the library
"suffix" file to setup the vector. |
|
 | Data/Stack addresses:
 | My libraries default to common memory layouts for very
generic test systems (ie: large memory maps), and it is
quite likely that the data memory allocation (including
stack) does not match the memory available on your
target system. |
|
 | Peripheral Devices
 | My libraries use common devices and I/O addresses for
such things as the serial port etc., which may not match
the devices or addresses of your target system. |
|
 | Serial Port Initialization
 | Many of my examples are written with the assumption
that they will be running under my MONxx debuggers, and
therefore assume that the system serial port has already
been initialized. If run on "bare metal", or
under a different environment which does not initialize
the serial port, these examples appear not to work. You
will need to add a "serinit(...)" function
call (see library docs for exact function name and
syntax) to initialize the serial port in these cases. |
|
 | Library prototypes
 | Some functions, such as "printf()" require
prototypes in <cpuIO.H>... If you have not
included these prototypes, the function will not work
correctly, and the program will not generate the
expected output. |
|
 | Other reasons:
 | There are many other factors which may make code run
on one target system but not another. To isolate the
problem, I recommend:
 | Begin Simple!
 | Compile in "Tiny" or whatever is the
simplest memory model available in your toolset.
Start with a simple main function contining only
a single "putch(...)" or "putstr(...)"
statement. Add global and local variables only
when you begin to get things working. This will
help you narrow down the configuration issue
causing the problem. |
|
 | Look at the listing!
 | Compile the code with the CCxx ... -L option,
to obtain a full assembly listing. LOOK at the
code, it's location in memory, the starting
address, the RESET vector (if applicable). LOOK
at the data layout, the start and end of data
memory. LOOK at the locations of initialized and
uninitialized variables. LOOK at the stack
location ... Verify that all of the above are
suitable for your particular target. |
|
 | Single-Step!
 | If you are using a debugger which supports
single-stepping, begin with a simple program and
listing file as described above, and try
stepping through the code. You should be able to
determine exactly where (and why) the execution
path goes wrong. |
|
|
|

The amount of stack and heap used by your program is called "dynamic"
memory, which means memory that is allocated by the program logic, not
by the compiler. This memory usage is highly dependant on runtime
conditions including the exact function call tree executed by your
program (including recursion), and the usage of malloc/free.
These things all happen at runtime under the control of your program
logic, which is not known to the tools (sorry, but they aren't **really**
intelligent), hence they cannot make a reasonable estimate of the amount
of dynamic memory which will be used.
To determine the dynamic memory used by your program, first compile the
program with the -L option, and look to see the initial addresses of the
heap and stack. Then fill in the unallocated area with a recognizable
pattern (I usually use 0xAA), either by using a Fill command in a debugger,
or with a memset(...) call at the start of your program. Be careful not
to overwrite the initial 0x00 byte which terminates the heap.
Then, run your program and put it through it's paces. Excercise all
possible features and functions. When you are finished, examine the
memory block and see where your previously filled in pattern has been
changed. The sizes of the changed areas will represent the actual
program usage for the heap and stack.

All DDS products which operate under DOS and use serial communications
are designed to work with any 8250 compatible UART device (8250, 16450,
16550 etc.) which resides at one of the four standard COM addresses:
COM1 = Address: 3F8 IRQ: 4 (80x86 Int 0x0C)
COM2 = Address: 2F8 IRQ: 3 (80x86 Int 0x0B)
COM3 = Address: 3E8 IRQ: 4 (80x86 Int 0x0C)
COM4 = Address: 2E8 IRQ: 3 (80x86 Int 0x0B)
To verify that the serial device is actually present, the comm functions
perform one simple test. After setting up the device and initializing the
baud rate divisor, the baud rate divisor is read back from the device and
verified to match the original value written. Since the baud rate divisor
register is read/write on all 8250 compatible devices the value read back
should match the value written. If it does not, the comm functions will
indicate that the selected serial port is not present.
If you are having trouble getting DDS software to recognize your serial
port, then the problem is most likely one of:
- Your serial port is not operating correctly.
 | Verify that the serial device works correctly
with other applications. If not, there is either a hardware or configuration problem with your
PC which will have to be repaired.
NOTE: that there is a lot of PC hardware on
the market which conflicts with the COM4 I/O address (0x2E8)... For example, ATI "Mach" Video Cards
use this address! |
Your serial port is not configured at the correct address.
 | Verify that the serial port is configured at the correct COM address
as noted above. For
DOS computers, you can run MSD (MicroSoft Diagnostics) available from Microsoft's
web
site to view the hardware configuration of
your computer. |
 | Windows 95+ will often configure it's
Plug&PLay serial ports at different
addresses than the DOS standard ones.
Go to Control-Panel/System/Ports, and view
the resource settings of the serial ports. If
they are not residing at the I/O addresses
listed above, you will have to reconfigure
them to those addresses. You may need to
consult your PC vendor for assistance in
doing this. Also, if there are any options for
"DOS compatibility", then turn them ON. |
Your serial port is not an 8250 compatible device.
 | Under DOS, where due to poor BIOS support, all applications which used
the serial port communicated directly with the hardware, all serial
devices were 8250 compatible (otherwise
they would not work). |
 | Under Windows 95+, serial devices do not **have** to be 8250 compatible
however most are, as this provides
compatibility with DOS software and "off the
shelf" serial drivers. |
 | If your Windows 95+ system has serial ports
which are not 8250 compatible, you will not
be able to use them with **ANY** DOS
software. Look for an option listed as "DOS Compatibility", "Enable DOS operation"
or something similar. If this options does not
exist, you may simply be out of luck.
|
Interrupts:
-----------
You will note that COM1 and COM3 share the same interrupt, as do COM2 and
COM4 ...
Under DOS, you can only have ONE of COM1 or COM3 enabled with interrupts
at the same time, in the same manner, you can only have ONE of COM2 or COM4
enabled with interrupts at the same time.
The interrupts on the serial ports are assigned with the "OUT2" general
purpose I/O output of the 8250 compatible uart device. Hardware in the
serial port circuitry will connect the UART's interrupt output to the
system BUS only when the OUT2 signal is turned on.
If both COM1 and COM3 or both COM2 and COM4 have their OUT2 signal turned
on, the serial interrupts will not work correctly.
Windows 95+ needs an interrupt for each serial port, so if COM1 and COM3
are both installed, or COM2 and COM4 are both installed, Windows will often
reassign the interrupts of it's Plug&Play serial ports so that different
interrupts are used for each port. This allows all of the ports to work
with windows, but it prevents them from being used with DOS software.
To work around this, you must decide which serial ports will be used with
DOS software, and make sure that they are configured so that the I/O
addresses and interrupts match the standard DOS settings as noted above.
Ports which you will NOT be using with DOS software should be configured
with addresses and interrupts which will not conflict with the DOS ports.

Detailed information regarding these (and other) questions can be found
in the DDS application notes. The application notes are available
from the download area of
our web page. The notes are also available online in our Technical
Support Area.
In all cases the INDEX file contains a listing of the application notes
and subject covered by each one.
The DB/FCB directives are used to encode individual BYTES. A string is
viewed as a multi-byte quantity, and only the lowest order byte (ie:
the LAST byte) is encoded by DB/FCB.
To encode a variable length string, you must use the STR/FCC directives.
Please refer to the XASM documentation for complete descriptions of the
functions performed by each directive.

|
|
|
|