Issue
162 January 2004
Remote
Observation Station
FIRMWARE
I
developed the firmware for this project in assembly
language using Metrowerks’s CodeWarrior HC08 version
2.1. You may download the firmware files (CharGenData.inc,
qtqy_registers.inc, and PVCC.asm) from the Circuit Cellar
ftp site. During development, I programmed the ’QY4’s
flash memory via a MON08 interface header using a MON08MULTILINK
pod from P&E Microcomputer.
I
devised three modes of operation: Configuration mode,
Charge mode with OSD, and Charge mode without OSD. I
implemented them in three separate software loops. Functionality
common to more than one mode was implemented in subroutines
that could be called from any mode.
Just
after startup, the ’QY4 checks the current configuration
data stored in flash memory for validity by performing
a 16-bit cyclical redundancy check (CRC). That CRC value
is then compared to the CRC value stored in the first
2 bytes of the configuration data. If the values do
not match, the configuration data is assumed to be corrupt,
and it’s overwritten with the manufacturer’s default
values stored in another region of the flash memory.
Configuration
mode allows you to configure the behavior of the PVCC
board. In this mode, the MCU waits indefinitely for
a single byte command from the PC. If a valid command
is received, the microcontroller carries out the command
and returns to wait for the next command. This mode
is exited by removing the shorting block on JP5 and
then power cycling. Configuration mode makes heavy use
of ROM resident communications and flash memory programming
routines, which are listed in Table 2. These functions
are used to establish a communications link between
a PC and the PVCC board. I wrote a simple Windows-compatible
program (called ConfigPVCC) that allows for easy set
up of the PVCC board.
| Table
2—With the ’QY4’s limited flash memory, these
built-in ROM routines come in handy. |
The
communications data rate generated by these routines
with a correctly trimmed oscillator is approximately
12,800 bps when the MC68HC908QY4 microcontroller is
using the internal oscillator and is in User mode. The
PC achieves this data rate using a UART clock divisor
of nine. Although 12,800 bps isn’t a standard data rate,
all PC UARTs are capable of this speed.
When
you select Charge mode without OSD, the clock is derived
from the MC68HC908QY4’s internal oscillator. After initializing
the I/O ports, oscillator trim value, A/D converter,
and system timer, the microcontroller enters Wait mode,
during which power consumption lowers. Wait mode is
exited periodically in order to reset the COP timer
and check a semaphore to see if the user-defined sample
period has elapsed. If the user-defined sample period
has elapsed, the battery’s voltage and temperature are
sampled.
The
battery voltage is read via input AD1. Resistors R22
and R23 form a resistor divider to scale 20 V down to
the 5 V needed by the analog input. The temperature
sensed by the DS1820 1-Wire sensor is read and checked
against a user-defined battery temperature limit. The
sampled battery voltage is compared to the user-defined
set points, and the charging circuit is turned on or
off accordingly.
When
the unit is operating in Charge mode with OSD enabled,
the MCU clock is derived from an external 32-MHz oscillator.
The on-screen display logic is active and responsible
for “drawing” nine characters on the video signal generated
by the camera module. The video signal and firmware
synchronize via the video’s horizontal sync component.
This component signal is obtained from an LM1881 video
sync separator whose output is connected to the MCU’s
IRQ input. The sync pulses are counted in order to determine
when drawing should begin on the screen in a particular
frame. The vertical sync signal indicates when a new
video frame is beginning, and that the scan line counter
is to be reset to prepare for the new frame.
I
had to take several creative steps to produce overlay
text with minimal jitter and enough resolution to be
useful. The ’QY4’s response to the horizontal sync (Hsync)
pulse had to be as consistent as possible (from scan
line to scan line). A variation of only three clock
cycles (at 8 MHz) would be noticeable to the viewer
as a side-to-side jitter. Logically, the IRQ input had
the best chance of reducing jitter because of its inherent
repeatability. Nevertheless, even the IRQ mechanism
has a variable latency based on the instruction that
is being executed.
The
HC08 CPU family enforces a run to completion (RTC) interrupt
semantic. This means a possible response variation of
one to nine clock cycles, with an average variation
of about three clock cycles for most code. To eliminate
this variation, I used a tricky, but effective, technique.
When
the scan line counter, which is incremented by each
Hsync pulse in the IRQ interrupt service routine (ISR),
reaches the “starting scan line” minus one, the IRQ
ISR modifies the stack to prevent it from returning
to the interrupted background code. Instead, the stack
is modified to return to a wait instruction, which initiates
Wait mode. When the next IRQ interrupt occurs approximately
62.5 µs later, the system exits Wait mode, and the interrupt
is serviced again. This is repeated for the next 16
interrupts (scan lines) as the text is “drawn” onto
the video signal. After the text overlay is completed
for the current frame, the IRQ ISR again modifies the
stack and returns to the originally interrupted code.
The
entire process takes approximately 16 × 62.5 µs, or
1 ms. Because of the consistency of interrupting the
wait instruction, this technique produces nearly jitterless
overlay text, and the background code is only interrupted
for 1 ms out of every 16 ms. You can see the result
in Photo 4.
|
|
Photo
4—I took this shot while testing in my backyard.
The "vc" character indicates
that the system wants to charge the battery. |
The
OSD feature currently displays nine characters in an
8 × 7 dot format. Obtaining enough resolution to be
useful for my system meant finding a fast way to shift
the character data, or “dots,” out of port PTB7. When
the IRQ ISR has determined that it is time to begin
drawing on the video signal, the background code already
has converted the ASCII characters to be displayed,
via a look-up table, into character font data. That
data is placed into a “Video RAM” area. The data is
arranged so that one scan line of each character (for
nine consecutive characters) is located in nine contiguous
bytes. The next scan line follows these 9 bytes. This
repeats until the bottom scan line of the character
cell is reached. It is then a simple matter for the
interrupt routine to shift nine consecutive bytes from
RAM out port PTB7.
Any
time spent indexing to the next byte in RAM will show
up on the screen as a space between the characters.
To minimize this space, I first unrolled all loops to
get rid of the overhead of checking for loop termination
conditions. Next, I pushed all of the data for one scan
line’s display onto the stack in the reverse order.
Stack instructions take only two clock cycles and require
no overhead to increment index registers. The resulting
display resolution was approximately 167 dots per line.
Because
the TV uses some of that scan time to over-scan off
the edges of the screen, the resolution is somewhere
in the 140-to-150 range. The total time for one character
and its inter-character space is 22 clock cycles at
8 MHz, or 2.75 µs. This means one line could, in theory,
display approximately 18 to 20 characters. Alas, my
technique uses 7 bytes of RAM for each character being
displayed, so I elected to display nine characters,
consuming 63 bytes of RAM—half the total RAM on the
MC68HC908QY4—for the video OSD feature.
Ambient
temperature affects batteries, so I added simple linear
temperature compensation to the charge control algorithm
to adjust the full-charge set point based on the battery’s
temperature. This allows for more accurate charging
and less chance of undercharging or overcharging when
the ambient temperature increases or decreases far from
room temperature. In cold weather, for example, the
full-charge set point must be slightly higher because
of the slower chemical reactions caused by cooler temperatures.