Introduction
This is a description of my use of the PMB
CPU-1A1 68HC11F-based microcontroller and a custom circuit board based on the
Cirrus Logic
CS5523 A/D converter to make a simple data logger.
Software
Development Environment
My entire development hardware is a laptop computer, running Redhat Linux
(currently version 7.2). The only connection to the CPU-1A1 is a serial
port. My current software has lots of little steps, but hopefully it is
all straightforward.
All software is written in C, with a bit in 68HC11 assembly language. I am
using the publically-available
gcc cross compiler and loader
An HC11 assembler is also included in this package. For several reasons,
including historical, I also used the as11 assembler as part of the package
masm written by Forrest Cook.
Special Bootstrap Mode
Software is loaded into the CPU-1A1 using the HC11's "Special
Bootstrap Mode". With LK1 and LK2 shorted (either with the
PMB-supplied jumpers or a special switch I've wired), the HC11 expects
a byte, FF, to set the data rate for further communication at 1200 or
7812 baud, respectively. (For obvious reasons, I've only used 1200.)
Next, the 68HC11F expects a variable number of bytes from the serial
port which are loaded into RAM at $0000. After a timeout reading
serial data, the HC11 begins executing the code at $0000. Note that
power must be cycled to the HC11 before being able to do anything
else.
ftc3
To handle the laptop side of the Special Bootstrap Mode communication, I wrote
a c program based on code supplied by PMB. ftc3 dumps
bytes from a file of S-records. After this file is downloaded, ftc3 reads
the serial port (at 9600 baud) until no characters have been received for
5 seconds. I do this to get some cryptic debugging codes back from the file
which was downloaded.
Although I've written several pieces of code for ftc3 to load, at present
I'm only using two:
- "confige" sets the configuration the way I want
it:
- CONFIG register writable
- RAM starts at $0xxx, length 32K
- Registers start at $1xxx
- EEPROM starts at $FExx and writable
- ROM disabled
- Expanded-nonmultiplexed mode
- "erase" sets the entire FLASH to $FF, which is
required before writing new code to it.
Both of these programs are assembled using as11 to generate a .s19 file.
Thus, when starting with a new board from PMB (or any board in an unknown
state), I first:
- Connect LK1 and LK1 with jumpers
- Power-up the CPU-1A1
- ftc3 < confige.s19 (wait for "B!" to be displayed after about 14 seconds)
- Power-down the CPU-1A1
- Power-up the CPU-1A1
- ftc3 < erase.s19 (wait for "s." to be displayed after about 14 seconds)
- Power-down the CPU-1A1
The CPU-1A1 is now ready to accept the program to be loaded.
ftc
I have a slightly different program to load various parts of memory. Like
ftc2, it loads a short code into RAM using Special Bootstrap Mode. In
this case, the program is "ftc_f1b" (written by PMB), which reads
S records from the serial port and loads them into memory. ftc_f1b will
program RAM, FLASH, or EEPROM depending on the address specified in the
S record.
My code on the laptop side is ftc. ftc reads
a file of S records from stdin and and has 3 optional arguments:
- -b selects the bank (0-3) of FLASH, needed if code is to go into addresses
$8000-$FDFF. I normally use bank 0 for the program code.
- -v selects verify mode, which I think just reads data back from CPU-1A1
memory and compares to what is in the file.
- -d sets debug mode which gives some more information on execution
ftc is run (for example) by:
- Power-up the CPU-1A1 (with LK1 and LK2 jumpered)
- ftc -b 0 < main.s19
- Power-down the CPU-1A1
- If all S records have been loaded, remove LK1 and LK2
Code organization
For several reasons, again partly historical, I have the following
program/memory organization:
- $0000-$00FF. The bottom of RAM is used by the gcc compiler for scratch
memory space (I think).
- $0100-$0FFF. Unused RAM.
- $1000-$103F. The HC11 registers.
- $1040-$1FFF. Unused RAM.
- $2000-$7FFF. RAM. Building up from $2000 is variable space that gcc
allocates (small in my code). Building down from $7FFF is the HC11 stack
(also probably not too big in my case).
- $8000-$FDFF. FLASH, bank 0, holds most of the execution code.
With vectors.s, this is compiled, assembled, and linked into main.s19 from
various pieces of c and assembler code.
- $FE00-$FECO. Low EEPROM holds assembler code
(eeprom) which has several things:
- The reset service routine, which sets CONFIG, OPTIONS, etc; selects
FLASH bank 0; and jumps to the beginning of FLASH (hard coded)
- Subroutines to read from, write to, and erase FLASH. For obvious reasons,
this code can't be executed from FLASH. The pointers to these routines are
created using the "- s" option to as11 and coerced (I don't remember how) into
a .h file for use by other pieces of code.
- $FFB0-$FFBF. The middle of EEPROM (just below the interrupt vectors)
holds program variables which should persist.
- $FFC0-$FFFF. Interrupt vectors (including reset) reside in EEPROM and
are set in vectors.s This file is assembled and linked into main.s19 in my
Makefile. The reset vector is hard coded in this file
to the beginning of EEPROM.
A lot of this is specified in the memory.x file used
by the gnu linker.
Comments
All of the above is too complicated, but it does work.
I think that memory.x and Makefile can be used to define more blocks of memory.
I have tried to define a memory "section" for gcc to use for this purpose, but
haven't been able to get the loader not to ignore it. In particular, I
am trying to define a block of initial EEPROM variables for bulk
initializing of many similar modules. (I have a workaround of "pre-pending"
these values to vector.s and redefining the vector address in Makefile and
memory.x, but this is terribly unclean.)
I also found that loading "printf" overflowed available memory (hard to
believe?). Thus, I've resorted to writing my own special "pd", "put2h",
"put4h", "p10", "p40", etc. routines. I've layered these on the _serial_get
and _serial_send routines provided by PMB for some applications. Other
applications with outside origins (Orion...) use "putchar", "getchar",
"serial_print". What a mess! I should get "putchar" and "getchar" running
again using the SPI interrupt and somehow get gcc's printf and scanf to use
them, like we did with the Orion.
The HC11 can operate at 7812 baud in Special Bootstrap Mode, which would be
significantly faster than 1200 baud, but the "termios" routines used by
ftc and ftc3 don't support this baud rate (not a POSIX.1 standard rate).
Hardware
CPU board
A schematic of the CPU-1A1 was supplied from
PMB. I've also downloaded a datasheet for the FLASH
chip used on the CPU-1A1, which shows its usage.
This CPU board only has TTL serial output directly from the HC11 -- not RS232.
This is desirable for my first application, since I didn't want the extra
power consumption when logging data. I've built separate interface boards with
various MAX232 chips to change the serial signal levels to RS232.
This CPU board also operates on +5VDC only. I've just used LM7805 chips to
convert down when only +12VDC was available.
A/D board
The A/D board uses a Crystal CS5523 A/D chip which
talks to the 68HC11 over its SPI (synchronous serial port). Up to 8 A/D's
can be stacked, selected by the 8 bits of the HC11 PortA. A jumper on the
A/D board selects which bit that board responds to. I have a
schematic diagram and a
component layout corresponding to the silkscreen
for this board. (I notice that some component numbers aren't the same
in these two diagrams. Also, the schematic shows the
LM20 sensors which are not on this board.) Finally,
note that the first run of this board had two
problems which I added manual jumpers to fix.
A 2.5 V voltage reference is used on this board.
I think I've set the board layout to only work with a 0-2.5 voltage range,
but I'll have to check. (Crystal's documentation shows that a bit of external
circuitry is needed to generate a negative supply voltage required to
implement bipolar signals.)
Physically, the boards are designed to stack in a strange manner. The first
is intended to be a daughter board on the underside of the CPU board. More
A/D boards can then be stacked through a 10-pin header connector. I did this
in part to save expense of connectors (and I couldn't find simple stackable
connectors), but also to allow a smaller cable to be run to remotely-placed
auxilliary A/D boards. In fact, I've also envisioned that the first daughter
A/D board might not be stuffed with chips and only be used as a connector
interface board.
Future Plans
A/D boards
It would be nice to rerun the A/D board layout, correcting the two jumper
problems and a problem with the pad size on the CS5523. Also, we should try
to accomodate bipolar voltage inputs.
Radiometer A/D
It should be simple to redo the form factor of the A/D board to allow it to
be put inside one of our pyranometers or pyrgeometers. I then
envision data from a 4-component radiation system as 4 sensors, each with
an integrated A/D board, sending data to one CPU-1A1 board over a simple
SPI connection. This would eliminate a LOT of cabling and should make
calibration simpler as well. We'd probably want to add some method of putting
a unique serial number on each board as well, which could be electronically
queried, to reduce the calibration coefficient problems we've had.