A Handy Display for Debugging ProgramsJose uses his "Video Stamp" system to debug his programs and
display video from various applications. A PIC18F2520
microcontroller and three resistors form a rudimentary DAC to
generate the NTSC-compatible video signal. Read on for the hardware
and software specifics.
Back in 1971, my first project as a hardware design engineer was
a"dumb" video terminal that displayed 64 characters per row and 32
rows. When finished, the logic and power supply filled a 12″ × 10″
× 8″ metal box. For those who do not remember,it was the time when
the only available active components were discrete TTL and memory
was implemented using recirculating MOS shift registers. Since
then, and for sentimental reasons, every time a new generation of
components has come out, I have mentally tried to redesign and
shrink my first project using the new components.
In the mid-1970s, when microprocessors and bipolar memory became
available, there was a turning point in video display design.
Then,the now legendary Don Lancaster in his book, The Cheap Video
Cookbook,pioneered the unorthodox use of microprocessors to design
video displays.There were also other approaches,such as using a TTL
counter to drive the address lines of a PROM. The PROM‘s data
output then drove the sync signal generation and synchronized the
data flow between the character memory, the character generator,and
the shift register.
This project was an attempt to recreate that spirit. I produced a
design that displays composite video with only a few components.
OBJECTIVEMy project receives serial data in an asynchronous format, 8 bits,
1 stop bit, and no parity bits at 9,600 bps(other rates are
possible) and displays it on a conventional video monitor or a TV
that has a composite video input(see Photo 1)。 The display has a
capacity of 38 characters by 16 rows. An additional row is at the
bottom of the screen. This is the Parameter row. It displays a
blinking dot (I am alive),the last character received (both in
ASCII and Hexadecimal), the receiving data rate, and a message area
20 characters long.
The received data is entered at the screen's current position in
the bottom row. When the thirty-eighth character is received, all
rows in the screen scroll up one position, the bottom row is
cleared, and the following received character will be entered at
position 1 of the bottom row.
All of this is accomplished using only a Microchip Technology
PIC18F2520 microprocessor and three resistors that form a
rudimentary DAC to generate the NTSC-compatible video signal.
Connect one 0.1-μF capacitor between 5 V and Ground for decoupling
purposes and all this can be mounted in a 2″ × 1″ prototyping
board. It is a far cry from my first design (see Photo 2)。
MOTIVATION
As I was considering the Microchip PIC18F2520 for an unrelated
project, I also looked at the possibility of using it as the only
component to implement a video display. As the details fell into
place, I realized that besides the challenge of cramming all of the
functions into this one part, there was a practical reason. I
figured I could use the final design every day as a debugging tool.
When developing a new application,it is very useful to know the
state of several variables when the program runs through a
particular part of the code. It is also useful to see how the
variables change as we change an input. Of course, that can be done
using breakpoints, but it is slow and cumbersome. If you are using
C language,a printf statement or, as in my case, HSEROUT in
PICBASIC PRO,the final product will display four or five variables
to a line in the video display. Then, a trace of several lines will
most likely pinpoint the cause of the problem.
To do this, I plug the Video Stamp into my prototyping board and
then connect the TX side of the microprocessor being debugged to
the RX input in the Video Stamp and connect the video output of the
Video Stamp to a suitable video display. In my case,the video
display is a small camper style TV that I bought at a local
appliance store for $19. Refer to Photo 3 for a picture of the
setup. I also use my PC video display that has a composite video
input, but it is inconvenient to switch inputs and I prefer the
small TV set. Once I have finished the project,I unplug the Video
Stamp and put it in a safe place until next time.

The second situation is to add video display capabilities to a
given project when there is a lot of data to be displayed. That was
the case in a homebrew"environmental/alarm monitoring module" that
displayed about 500 characters of information. For this
application, I added the PIC and the three resistors to the PCB.
For $5, I had a display capability. I then routed the video output
to an unused composite video input in my home TV. By changing the
input with the remote control,I was able to see all the data
collected by the monitoring module.
THE VIDEO SIGNALThe standard NTSC video signal can be interlaced or non-interlaced.
I chose noninterlaced because it simplified the generation of the
horizontal sync and does not change the quality of the display.
Figure 1 shows the characteristics and timing of the horizontal
raster line.
The horizontal line has a duration of 63.5 μs. This gives you a
horizontal scanning rate of 15,748 Hz. To keep the vertical and
horizontal sync locked together, generate the vertical sync based
on a count of 262 horizontal lines. By changing the duration of
line 262, you can obtain an almost perfect rate of 60 Hz for the
vertical sync.
An important limitation is the video signal‘s maximum bandwidth. It
should not exceed 3 or 3.5 MHz. Its value is equal to one-half of
the frequency of the clock that shifts data out of the Video Shift
register. We are very close to this limit, but given the built-in
tolerance in TV design, it does not present a problem in actual
practice. IMPLEMENTATION Conventionally, video generation logic
contains several blocks (see Figure 2).Data memory contains the
data to be displayed. It is addressed by the microprocessor to
write the data to be displayed and by the timing module to read the
data and feed the addresses to the character generator.
The character generator is usually ROM that contains the dot
pattern for each character. It is addressed by the concatenation of
the binary value of the character to be displayed and the timing
module with the current raster line. I chose a 5 × 7 pattern
because legibility is good and it enables me to display more
characters than a 7 × 9 pattern.
The output of the character generator feeds the Video Shift
register and is shifted out in serial form to the DAC. This video
and the vertical sync added together form the NTSC composite video
signal.
My implementation closely follows this model. Note that all of the
different blocks, except for the DAC, are contained inside the
PIC18F2520.
HARDWARE
Figure 3 reveals the extreme simplicity of the hardware: one
PIC18F2520 microprocessor,three resistors, and one capacitor. That
is it.
The PIC18F2520 was selected because it contains all the peripherals
and features needed for this implementation. The clock is
internally generated at 8 MHz and then multiplied with an internal
PLL to reach 32 MHz. At this frequency, the instruction rate is 8
MHz and the instruction cycle is 0.125 μs. This is important
because all the timings are generated using this frequency and it
is very handy to have this kind of granularity. The generated
frequency is accurate and very stable, provided that the 5 V is
well regulated and noise free. It is important to add a 0.1-μF
decoupling capacitor between pins 19 and 20.
The USART module provided serial data communication using the
standard RS-232 protocol for asynchronous communications. It is
programmed at initialization time to work at 9,600 bps,8 data bits,
1 stop bit, and no parity bits. Other configurations are
possible,as noted in the software description. Only the receiver
side of the USART is used.
The Timer0 module can operate as a timer or a counter in 8-bit or
16-bit mode and has an optional prescaler. I selected Timer mode, 8
bits, and no prescaler. The timer is at the heart of all the video
generation timing. It is set up to invoke an interrupt every 63.5
μs.
The master synchronous serial port(MSSP) module is a parallel to
the serial interface that can be programmed to execute two of the
most common serial communication protocols in use today, I2C and
SPI. I configured it to work in SPI Master mode to implement the
Video Shift register. This is somehow an unorthodox
implementation,but it works for my purposes.
The PIC18F2520 has 32 KB of program memory and 1,536 bytes of RAM.
This is more than enough for this application and there is plenty
of room to add more features. Only half of the RAM is used to hold
the program variables and data memory. The program memory holds the
program and the character generator. Again,there is plenty of room
for expansion. For more details on the operation of these modules,
refer to the PIC18F2520 datasheet.
Wiring a three-resistor voltage divider as a simple DAC has been
extensively used in hobby projects. I have recomputed the resistor
values to produce the theoretical voltages required by the NTSC
signal for black,white, and sync levels. Then I chose the closest
standard resistor value available.
SOFTWAREThe program was developed using the PICBASIC PRO (PBP) compiler
tightly integrated into a Microchip Technology MPLAB IDE. This
enabled me to use the editing and debugging facilities of MPLAB and
to write part of the code using the MPLAB assembler. Mixing PBP and
assembler in this particular application was absolutely essential
because of the tight timing constraints in some parts of the code.
With that said, it is not for the faint of heart because many
subtle bugs may be introduced in your program-in particular, when
you are using interrupts. Also, MPLAB enables the use of ICD-2, a
low-cost debugger/programmer sold by Microchip, which helps
immensely in the development cycle.
The program can be divided into three different sections:
initialization,interrupt handler, and main loop. But before I
describe the program, I will describe the data structures
used:"RXdata" is a first in first out (FIFO)circular buffer that is
16 bytes long. It is used to temporarily store the characters
received from the USART during the interrupt. The characters are
retrieved by the background and stored in the ScreenBuff.
"ScreenBuffer" is a linear area of RAM that occupies Bank1, Bank2,
and part of Bank3. This allocation is hardwired and assumes that
the variables and other memory areas allocated by the compiler will
never exceed Bank0. It contains the characters that will be
displayed in the screen.
"ParamsBuffer" is an array 38 bytes long that contains the data to
be displayed in the bottom line of the screen. "Chargen" is the
character generator data that stores the dot pattern that defines
each character. It is located in program memory at an address
beyond the actual program and its location is also hardwired.
Extensive use of indirect addressing is made to access these
locations. The PIC18F series has expanded the number of index
registers and enabled the post-automatic increment of the index
registers value. Without this feature, it would have been more
difficult to implement some of the tight timing in the character‘s
display routines. Data is not moved inside the ScreenBuffer as you
scroll up. Only pointers held in the index registers are modified
to display the correct data. I will now describe the different
sections.
INITIALIZATION
When the program starts, set the internal oscillator to run at 8
MHz and enable the internal PLL to run at a final frequency of 32
MHz. Then, all ports are initialized, although only PORTA is used.
The USART is initialized by default at 9,600 bps, 8 bits, no parity
bits, and 1 stop bit, but an option is given to set a lower speed
by reading some straps located in PORTA. The available speeds are
1,200, 2,400, and 4,800. The SPI is then initialized to Master
mode.
The ScreenBuffer is filled with a welcome screen, copied from a
preset message located in program memory,and the parameter row is
set to display the selected USART speed and other relevant data. In
the data area,the pointers to the Rxdata are reset and the rest of
the variables and pointers are initialized to the starting values.
Finally, Timer0 is enabled. The interrupts are set so only the
interrupt from Timer0 overflow is allowed.
INTERRUPT HANDLERThis piece of code generates the horizontal and vertical sync
signals and displays the video corresponding to the raster line. In
addition, it reads the USART and places the characters received, if
any, into the Rxdata FIFO buffer. It is written entirely in
assembler to meet the tight timing requirements of sync signals and
video generation. It is useful to have the characteristics of the
NTSC video signal available when examining the code(see Figure 1)。
The routine starts by reloading the Timer0 with a value that will
cause the next interrupt after 63.5 μs by overflowing the timer. It
then saves the internal registers used by the interrupt.
Start the generation of the horizontal sync. It must last 4.7 μs
while you check for end of frame. If that is reached, generate the
vertical sync.
You must ignore a certain number of raster lines after the vertical
sync to allow for the blanking interval and to vertically center
the display inside the screen. Also processed here are the"special
lines," such as the white line that separates the video display
from the parameters row.
Once it is determined that a standard display raster line will be
processed, initialize the pointer to access the first of the 38
contiguous characters in the screen buffer and wait to complete a
further 4.7 μs before starting the display. Then, enter a part of
the program that runs 38 times(once per character) the sequence of
instructions exhibited in Listing 1,which is perhaps the most
time-critical of the entire program.

For readers who are not familiar with the PIC18F family, I will
briefly describe the instructions used here. The PIC has three
16-bit wide index registers, which can access the entire range of
RAM available without paging constraints. A special operational
mode enables you to read the data byte pointed to and then
automatically increment the index register. This is the POSTINCx
instruction, where x is the register used, which is FSR0 in this
case.
Another special register, TBLPTRx,points to program memory. It is
also 16 bits wide (both are wider) and formed by the concatenation
of TBLPTRH and TBLPTRL. Executing a tblrd * instruction reads the
location pointed to by TBLPTR and places its content in the
register TABLAT. I use TBLPTR to access the character generator.
TBLPTRH holds the current raster line of the current row and
TBLPTRL holds the binary value of the character at this position.
Therefore, TBLPTR points to the dot pattern that needs to be
displayed next. I then read the dot pattern and move to the W
register.
If you leave the SPI to work as designed, it will shift out eight
dots per character, wasting some of the horizontal space. So, I
disable the SPI when shifting out the sixth bit and reenable it
immediately afterwards. This unorthodox method saves one dot per
character, or 38 dots, and allows six more characters per row to be
displayed. Finally, I move the next dot pattern that I have in
register W to the SPI transmit register and start shifting it out.
Note that there is a NOP in the middle of the sequence. The move
from TABLAT to SSPBUF is done with two instructions when it could
have been done with one. All of this is part of the delicate
equilibrium of the timing in this sequence. The same can be said of
the fact that a loop is not used and the 38 copies of the same
sequence are executed one after the other. Fortunately,there is
plenty of unused program memory.
Just before exiting the interrupt routine, I check if a character
has been received in the USART. If so, it is read and inserted in
the FIFO buffer to be retrieved later by the background. This is
simpler than having a separate vector for a USART interrupt and as
reliable, because we sample every 64 μs and the maximum rate that a
character can arrive is 1 ms. Finally, it exits after restoring all
of the system registers used.
MAIN LOOP
The main loop is the actual program that runs in the background.
Its function is to process the characters that arrive in the USART
and place them in the screen buffer. First, a received character is
displayed in the parameters row, both in ASCII and hexadecimal. If
the received character is a control character (i.e., in the range
of 00 to 20 hexadecimal), it is saved in the screen buffer and
displayed as a white square. The only exceptions are the carrier
return and line feed. Carrier return moves the cursor to position
one of the current row. Line feed scrolls up the entire screen one
row and clears the bottom row. The cursor remains at the same
position.
Although I mentioned the cursor several times, there is no actual
cursor displayed. It would be quite easy to add either as an
underscore or a white box, blinking or static.
Another function of the main loop is to display a blinking dot in
the first location of the parameters row. The implementation is
very simple. A 16-bit counter is incremented at each iteration of
the main loop and depending on the value of bit 15, a different
character is displayed at that location. All it shows is that the
background is up and running at the expected cadence.
DISPLAY AWAYYou now know that it‘s possible to design an inexpensive display
for debugging and other simple applications. All you need are a few
parts and the .hex file that's posted on the Circuit Cellar FTP
site.
Given the simplicity of the hardware,no attempt was made to design
a PCB. A small piece of prototyping board should be sufficient. You
will also find the program listing on the FTP site, but bear in
mind that you will need PICBASIC PRO to compile any changes. There
is still plenty of memory and computing power left to implement a
few more features (e.g.,escape sequences to clear the screen and
position the cursor in any location).You can implement character
attributes such as italics, reverse video, and blinking video or
other fonts (e.g., Cyrillic or Greek).
I will leave that challenge to your inventiveness and ingenuity.
I‘ll be glad to hear about any improvements.
Jose Sanchez started working in computers in his native Spain doing
installation and maintenance on mainframes. After moving to the
U.S. and graduating from Southern Methodist University with an
M.Sc. in Computer Science, he worked for many years developing
embedded applications as a contractor for a lengthy list of
companies. After a long interlude in managerial tasks, Jose retired
and returned to his original calling for fun and profit. You can
email him at bubsemicon@gmail.com.
PROJECT FILESTo download code, go to
ftp://ftp.circuitcellar.com/pub/Circuit_Cellar/2008/213.
RESOURCES
K. Jack, Video Demystified: A Handbook for the Digital
Engineer,Newnes, Burlington, MA, 1955.
D. Lancaster, The Cheap Video Cookbook,Howard W. Sams,
Indianapolis,IN, 1978.
Microchip Technology, Inc.,
"PIC18F2420/2520/4420/4520 Data Sheet," DS39631A, 2004.
SOURCESMPLAB IDE and PIC18F2520 microcontroller
Microchip Technology, Inc.
www.microchip.com
PICBasic PRO Compiler
microEngineering Labs, Inc.
www.melabs.com