📄 appendxa.htm
字号:
<head>
<title>Appendix A</title>
</head>
<body>
<h1><a name="appendix_a">Appendix A The Cosmic Compiler</a></h1>
<p>
In programming microcontrollers, one of the major tasks of the programmer is to make
use of the peripheral components found on the chip. Most chips have components like
timers, serial communications ports, serial peripheral ports, analog to digital converters,
even electrically erasable programmable read only memory-EEPROM. We will find it
very convenient to treat these components as objects and access them by merely sending
instruction messages to an appropriate object. We have seen before that most treatment
of objects in published material has to do with data structures treated as objects. We
cannot avoid this important use of objects.
<p> In Chapter 2, all of the objects treated were designed to operate on a large
computer. In later chapters, none of the objects will work with a large computer. These
objects are all designed to operate on a micro controller, the M68HC16, to be exact. The
processors considered for use in this text included the M68HC11, the M68HC16 and the
M683XX chips. The M683XX family has one major advantage when it comes to OOP
for a microcontroller. It is a large enough computer that you can buy C++ compilers for
it. The other chips are significantly smaller in internal CPU structure, but they have
peripheral components that are similar, and in the case of the M68HC16, as exactly the
same as those found on the M683XX parts. These chips are so small that there will
probably never be a C++ compiler written for them, but in today's market, these chips are
much more popular than even the M683XX chips. The M68HC16 has an internal
structure that is quite similar to that of the M683XX family. They both have an
intermodule bus which interconnects the CPU with the chip peripherals. The peripherals
are all memory mapped are placed in the highest memory page in both sets of chips. The
peripheral components are exactly the same on the M68HC16 and the M683XX chips.
We can, therefore, create header files to access the registers and bits within the registers
for these chips, and with the exception of an offset to the beginning of each module, the
header files for both the M68HC16 and the M683XX family of chips will be the same.
<p>The compiler used for this text is the Cosmic M68HC16 compiler. This compiler
creates excellent code for the M68HC16. Cosmic also sells compatible compilers for the
M68HC11 and the M683XX chips. It is not the intent of this text to teach you the ins and
outs of any compiler, but enough of the compiler will be discussed to allow you to work
with it. The operation of the compiler is complicated by the nature of the M68HC16
chip. This chip was designed to be compatible with the M68HC11. The major additions
to the M68HC16 was the intermodule bus, the bus peripherals, a truly sixteen-bit CPU
and expanded memory access. The M68HC16 can access up to 1 megabyte of data
memory and 1 megabyte of program memory. This memory is broken into sixteen blocks
of 65 kilobytes each. Such a memory organization requires that the compiler handle
these blocks or pages of memory. The data are addressed either directly (called extended
addressing on this chip) or indexed. In either case, a twenty-bit address is needed to
access any byte in memory. The basic computer has three index registers, a program
counter, and a stack pointer that are each sixteen-bits wide. To give these registers the
necessary width to access the total memory range, the chip designers provided each
register with a four-bit extension register. These registers are known as the XK, YK, ZK,
PK, and SK respectively. Additionally, for extended memory addressing, there is a four-
bit extension register called the EK. These four bits are appended to the address of any
direct data access. The contents of the extension registers are always the most
significant four bits of any address.
<p> Depending on the program, the size of the data memory used, the program
memory used, and so forth, these extension registers are usually set to some value at
initialization of the program and then changed only when necessary while the program
executes. It is possible in some instances to set the extension registers for all data
accesses and never change them during execution. For example, if all of the data storage
can be contained within a single 65 kilobyte page the extensions probably need never be
changed. On the other hand, if the data storage spreads over several pages, the program
will contain many changes to the respective extension registers during normal execution.
<p> The compiler needs a means of identification of data that potentially will require
extension register modification when being accessed by the program. If a variable is to
be placed in a memory location that requires a full twenty-bit address, the variable is
identified by the flag @far when it is declared.
<p> Extensive use is made of header files created specifically for each chip. A
complete set of header files for the M68HC16 can be found in Appendix B. A listing of
a portion of the file gpt.h is shown below. This file allows access to the General Purpose
Timer on the M68HC16. Quite a bit of the file is not shown here because it is repetition
of bit definitions similar to those shown below. Note that this header begins with the
usual conditional compile directives to prevent its inclusion in the code stream more than
one time. Two type definitions of structures create two new types that will be used later.
Note that these types contain individual bit fields, and these fields are named. The names
of the fields are taken directly from the GPT Manual . The names of the registers are
also found in the Manual. Therefore, the GPT Manual is the documentation upon which
all code for the operation of the General Purpose Timer in the M68HC16 will be based.
<p> There are some unused bits in the bit fields defined by the structures. It is
necessary to name these unused fields with unique names. Here, we will use a name
Nul1gpt or Nul2gpt to create names that will probably not be used elsewhere in any
program.
<pre><code>
#ifndef GPT_H
#define GPT_H
typedef struct
{
unsigned Nul1gpt : 4;
unsigned VBA : 4;
unsigned IRL : 3;
unsigned Nul2gpt : 1;
unsigned PAB : 4;
}ICRreg ;
typedef struct
{
unsigned PWA : 8;
unsigned PWB : 8;
} Bytes;
#define GPT_MCR (*(@far MCR_Register*)(GPT_Register+0))
#define ICR (*(@far ICRreg*)(GPT_Register+4))
#define PDDR (*(@far Register*)(GPT_Register+6))
#define OC1M (*(@far Register*)(GPT_Register+8))
#define OC1D OC1M
#define TCNT (*(@far unsigned volatile int*)(GPT_Register+0xa))
#define PACTL (*(@far Register*)(GPT_Register+0xc))
#define PACNT (*(@far unsigned volatile char*)(GPT_Register+0xd))
#define TIC1 (*(@far unsigned int*)(GPT_Register+0xe))
#define TIC2 (*(@far unsigned int*)(GPT_Register+0x10))
#define TIC3 (*(@far unsigned int*)(GPT_Register+0x12))
#define TOC1 (*(@far unsigned int*)(GPT_Register+0x14))
#define TOC2 (*(@far unsigned int*)(GPT_Register+0x16))
#define TOC3 (*(@far unsigned int*)(GPT_Register+0x18))
#define TOC4 (*(@far unsigned int*)(GPT_Register+0x1a))
#define TI4O5 (*(@far unsigned int*)(GPT_Register+0x1c))
#define TCTL1 (*(@far Register*)(GPT_Register+0x1e))
#define TCTL2 TCTL1
#define TMSK1 (*(@far Register*)(GPT_Register+0x20))
#define TMSK2 TMSK1
#define TFLG1 (*(@far volatile Register*)(GPT_Register+0x22))
#define TFLG2 TFLG1
#define CFORC (*(@far Register*)(GPT_Register+0x24))
#define PWMC CFORC
#define PWMA (*(@far Bytes*)(GPT_Register+0x26))
#define PWMA PWMB
#define PWMCNT (*(@far unsigned int*)(GPT_Register+0x28))
#define PWMABUF (*(@far Bytes*)(GPT_Register+0x2a))
#define PWMBBUF PWMABUF
#define PRESCALER (*(@far unsigned int*)(GPT_Register+0x2c))
/* MCR bit definitions 0x0 */
#define STOP bit15
#define FRZ1 bit14
#define FRZ0 bit13
#define STOPP bit12
#define INCP bit11
#define SUPV bit7
/* PDDR bit definitions 0x6 */
#define DDRI4O5 bit15
#define DDRO4 bit14
#define DDRO3 bit13
#define DDRO2 bit12
#define DDRO1 bit11
#define DDRI3 bit10
#define DDRI2 bit9
#define DDRI1 bit8
.
.
.
#endif
</code></pre>
<h4><pre>
Listing 1. <a href="appendxb.htm#gpt_h">General Purpose Timer Header File</a>
</pre></h4>
<p> This file is used in conjunction with a header file designed for the specific chip
being used. One of the addresses defined in the chip header file is the beginning address
of each module in the chip. In this case, GPT_Register is the beginning address of the
General Purpose Timer control registers. All of the registers needed to run the timer are
located at an offset from the GPT_Register. These registers are all located in the top half
of the top page of memory. In other words, the addresses of these registers are above the
address 0xf8000. As such, access to the registers require a full twenty-bit address.
Therefore, when forcing the addresses to have the specific type needed at each memory
location, the @far must be included in the cast operation. Also, note that the type
Register is used as a type for several addresses. This type is defined in the header file for
the chip, and in the case of the M68HC16, a Register is a collection of sixteen bits in a
single memory location. You will also notice that there are several instances where a
memory location is given two names. When this happens, the memory location is made
up of two M68HC11 type registers: one eight-bit register in the most significant bits and
one eight-bit register in the least significant bits of the sixteen-bit register. When the bits
are defined you will find them in the range of 8 through 15 for one register and 0 through
7 for the other.
<p>A header file hc16h.h must be included as the first line of code in any program.
This file contains the basic register definitions along with all of the offsets to the various
peripheral control memory areas. For example, the beginning of the general purpose
timer control registers can be found at the address GPT_Register. This value along with
all of the beginning addresses of the other peripherals are found in this file. Other
peripherals included with this chip are the System Integration Module (sim.h), the
Analog to Digital Converter module (adc.h), the Queued Serial Interface Module
(qsim.h) and the Static Ram Module (sram.h). If the program is to make access to any of
these modules, the appropriate header file must be included.
<p> The compiler is a command line operation. The general command line interface
to the compiler is as follows:
<pre><code>
c [options] <filename.c>
</code></pre>
<p>There are many options that are needed to compile code for our purposes. A batch file
that contains all of the necessary options is quite useful here. The contents of this batch
file are
<pre><code>
c -dlistcs -dxdebug -dmodm +o %1.c
</code></pre>
<p>The option -dlistcs causes the compiler to create a listing file that contains the C
program interleaved with the corresponding assembly code. It is planned to execute and
debug the code on an evaluation board called the EVB16. The software for access to
this board will permit limited source level debugging. To create the files needed to do
the debug operations, the -dxdebug option must be included in the command line. The -
dmodm option causes the compiler to create code with the medium memory module. In
this module, the program can contain up to 1 megabyte of code, but the directly
accessable volatile ram memory must be limited to 65 kilobytes. This arrangement is
usually satisfactory for most applications. The +o option instructs the compiler to create
a relocatable object module, and the %1.c entry is the file name entered on the
commmand line when the batch file is executed.
<p>The -dxdebug command causes the listing file to be greatly increased in size. If
you are trying to get a clean compile and are not planning to debug the program, it is
probably best to leave out the -dxdebug option.
<p> The next phase of the compile procedure is the linking operation. It is in this
phase that program and data modules are placed at specific memory locations. The
linkng operation is probably best controlled by a command file. Listed below is a typical
command file needed to link the code. Note first that a special version of this file is
needed for each program that you want to link. In this case, there are three lines with the
name timetest included. timetest is the name of the program being linked. Also, note
that there is a file vectiot.o being linked into the program. This file also must be written
specially for each program that you will link. Perhaps the start-up routine crts.o will also
have to be written as a unique program for your individual program.
<p> In this linker, a # sign causes the remainder of the line to be a comment. Each
line is commented to help explain the operation that takes place at that point in the link
procedure. The first three lines are essentially book keeping operations. The +h option
causes the program to be linked into multiple output segments. The second line notifies
the linker of the maximum program size, and the third line causes memory banking
options to be implemented. The next two lines control the outputs from the linker. A
map file named timetest.ma will be generated and the output linked file will be named
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -