tundra authored on 18 Jan
CHANGELOG move stable code to git 1 month ago
Makefile move stable code to git 1 month ago
leddrvr2-board.jpg move stable code to git 1 month ago
leddrvr2-license.txt move stable code to git 1 month ago
leddrvr2-sch.brd move stable code to git 1 month ago
leddrvr2-sch.gif move stable code to git 1 month ago
leddrvr2-sch.png move stable code to git 1 month ago
leddrvr2-sch.ps move stable code to git 1 month ago
leddrvr2-sch.sch move stable code to git 1 month ago
leddrvr2.asm move stable code to git 1 month ago
leddrvr2.hex move stable code to git 1 month ago
leddrvr2.lst move stable code to git 1 month ago
leddrvr2.xrf move stable code to git 1 month ago
readme.txt move stable code to git 1 month ago
readme.txt
leddrvr2 - Copyright (c) 2002 Tundraware Inc., All Rights Reserved
$Id: readme.txt,v 1.3 2002/05/02 18:58:17 tundra Exp tundra $


************************************************************************

PLEASE NOTE: Before using anything in this archive, you must read, and
             agree to abide by, the licensing terms found in:

                         leddrvr2-license.txt

************************************************************************


FILE DESCRIPTIONS
=================


Makefile                 Unix-style makefile which runs under DJGPP and
                         should also work under MKS and Cygwin.

README.txt               This file.

leddrvr2-sch.brd         leddrvr2 PCB board layout in Eagle format.

leddrvr2-license.txt     Licensing terms for using this software.

leddrvr2-sch.gif         leddrvr2 schematic in GIF format.

leddrvr2-sch.png         leddrvr2 schematic in png format.

leddrvr2-sch.ps          leddrvr2 schematic in PostScript format.

leddrvr2-sch.sch         leddrvr2 schematic in Eagle format.

leddrvr2.asm             leddrvr2 software written in PIC assembler.

leddrvr2.hex             The assembled leddrvr2 software.

leddrvr2.lst             leddrvr2 listing file generated by assembler.

leddrvr2.xrf             leddrvr2 cross-reference file generated by assmbler.



WHAT IS 'leddrvr2'?
==================


'leddrvr2' is a simple 7-segment LED display driver system using PIC
technology.  The idea is to use minimum parts count to drive up to 8,
7-segment LEDs using only 3 I/O pins on the PIC chip.

This is also a useful introduction to some of the PIC microprocessor
programming techniques insofar as 'leddrvr2' exercises many of the
basic features of these chips including:

     - Programming & use of the TMR0 timer & prescaler
     - Timer-based interrupt handling
     - Asynchronous application/interrupt interaction.
     - Display multiplexing
     - Serial interfacing to external 'glue' logic.

I wrote this code so *I* could learn the PICs and in the process
actually do something semi-useful.  I've tried to document the
hardware and software sufficiently to make 'leddrvr2' useful as a
learning tool for others.

In order to fully understand 'leddrvr2', it is useful to first
examine its predecessor design, 'leddrvr' which can be found at:

        http://www.tundraware.com/Software/PIC/leddrvr/

The following sections assume such familiarity and only comment upon
the newly implemented features found in 'leddrvr2'.


HOW DOES THE HARDWARE WORK?
===========================

The original 'leddrvr' design works quite nicely but has one huge
drawback: it uses all but 1 of the PIC's I/O pins.  This really limits
its usefulness for all but the simplest of applications.  The idea
behind 'leddrvr2' be able to drive an array of 7-segment LEDs using a
minimum number of I/O pins - in this case the design ultimately only
ends up needing *3* pins to drive up to 8 LEDs.  (In fact, the design
can be extended for many more LEDs simply by adding more shift
registers and adjusting the code accordingly, all without the need for
any more I/O pins!)

'leddrvr2' is able to do all this with only 3 I/O pins because of two
outboard serial shift registers which are chained together - the
output of one drives the second.  Instead of loading the segment and
LED selection bits in parallel as is done in 'leddrvr', this
implementation writes the bits out *serially* (via RA0-RA2) to the
shift registers.  The shift registers take this serial stream and
convert it into the equivalent parallel control word to properly drive
the display hardware.

One consequence of this design is that 7404 drivers had to be added.
The PIC can drive enough current to light an LED segment, but the
CD4094 shift registers cannot.  The 7404s take the logical output
level of the shift register and provide the necessary current drive to
light the LED segments.


HARDWARE NOTES
==============

This release of 'leddrvr2' includes a Printed Circuit Board layout
In Eagle format.  This board has actually been built and works fine.

Most of the parts used in this project are pretty standard and you
should be able to find them at any good electronic supply store.

However, there are a couple of specific parts used here you should
know about.  First, the 7-segment LED displays used are common cathode
devices.  The board is laid out for the Jameco #24782 (LSD3211-11)
part.  

There is also provision for an On-Off switch.  If you use an
off-board switch, any standard SPST or SPDT switch should work.  If
you want to actually mount the switch to board as I have, use the
Jameco #71597 (MTS-102-A4) part.

You can see both the blank and the finished PCB at:

  http://www.tundraware.com/Software/PIC/leddrvr2/leddrvr2-board.jpg

The original design included pulldown resistors (RN2) for the FET
inputs so that I could connect and disconnect the gates from the rest
of the circuit as I was debugging the hardware.  In this final
circuit, the gates are hardwired to the shift register outputs and
this resistive termination is not needed.  I left provision for RN2 in
the schematic and finished PCB, but I don't actually use it.  This is
why you see an empty SIP socket in the upper right side of the
finished PCB.  In any case, it does no harm to put a 10K termination
pack there if you like.  One nice think about leaving the resistors
out is that you can use that socket to inspect the signal at each of
the FET bases with an oscilloscope.


WHERE TO GET THE PRINTED CIRCUIT BOARD
======================================

I recommend:

     http://www.olimex.com/pcb

This is a very nice PCB prototype house.  They are located in Bulgaria
so shipping can take a couple of weeks to the US or Canada unless you
are willing to pay a premium for expedited delivery.  However, their
prices for boards are the lowest I've found and their product quality
and turn around time are excellent judging from my experience.  The
board layout provided here is designed to fit twice on their standard
prototype panel, so you actually get *two* boards for their standard
price.  As of 5/2002, I was able to get 2 boards delivered to the US
for just over $40!  This is *very* inexpensive.

You send them the Eagle .brd file via email and they will respond with
a price estimate.  You then sign the order, provide Credit Card
information and FAX it to them.  Several weeks later, you should have
your boards.  I especially like the fact that I do not have to fiddle
with post-production tasks like producing Gerber files, drill files,
silk screen layer information, and so on.  They do it all for you from
the Eagle .brd file.

Try these guys out - I think you will really be happy.  I was.


HOW DOES THE SOFTWARE WORK?
===========================

The 'leddrvr2' software is structurally quite similar to the original
'leddrvr' code, though it should be noted that some of the variable
names have changed.  A few other core differences are worth noting:

      - Be forewarned: 'dsply_val' is the register set which holds the
        current value to display.  It is allocated to be (num_led/2)
        bytes in size.  This assembly-time allocation works so long as
        num_led is *even* but will fail if it is odd.  Subsequent use
        of this array in 'display_led' also expects there to be the
        correct number of bytes of storage here, so make sure you have
        it right if you're using an odd number of LEds.

      - 'led_lookup' has been expanded to accomodate 8 LEDs.

      - The overall code works pretty much the same way it did in
        'leddrvr' with one big exception: 'display_led' no longer
        actually writes to the LED control hardware.  Instead,
        'display_led' now computes the desired segment selection bit
        pattern and stores it in 'led_seg'.  Similarly, it computes
        the LED selection bit pattern and stores it in 'led_sel'.

	'display_led' then calls a new routine, 'led_wrt' which reads
	these values and shifts them out in correct order to the
	outboard shift registers, thereby illuminating the LEDs as
	desired.

      - In 'leddrvr', 'display_led' did some explict offset arithmetic
        to figure out what value to display on each LED.  This has
        been changed in 'leddrvr2'.  Now, 'display_led' does pointer
        arithmetic to compute an offset from the base of the
        'dsply_val' array.  This is a more general approach which
        should work without modification as more LEDs are added.

      - Most of 'led_wrt' should be fairly self-explanatory, but a few
        clarifying comments might be helpful:

		   a) The 'STR' (strobe) input of the shift registers
   		      allows data to be moved into the register
   		      without actually having it appear on the output.
   		      When the registers are finished being loaded,
   		      the parts are strobed and the LED display is
   		      thus changed.

		      I experimented with pulling the 'STR' pins
		      high permanently (and thereby freeing up another
		      I/O pin). This effectively causes all changes to
		      the shift register to be immediately reflected
		      on the LEDs.  This does still work, but there is
		      an annoying flicker in the unused LED segments
		      which are being lit as data shifts across the
		      registers. So, I went back to using the STR line.

		    b) Clocking occurs when the 'CLK' pin of the
		       CD4094 goes from low to high with one
		       exception: The output of the high bit (Q8) does
		       not propagate to the shift register ripple out
		       (QS*) until the clock transitions from high to
		       low.  This delay is necessary so that bit
		       ripple is properly implemented without race
		       condition timing concerns.  In any case, this
		       is transparent to the software, which sees the
		       two shift registers as a single 16-bit logical
		       device.

                    c) Data is shifted into the shift register by
                       placing the bit value on the 'D' input (RA1)
                       and then clocking it into the register by first
                       raising and then lowering the 'CLK' pin
                       (RA0). After all 16 bits have thus been shifted
                       into the shift registers, the devices are
                       strobed via 'STR' (RA2) as described above.
                       This causes the new bit values to actually
                       propagate to the LED hardware.

        - One word of caution: 'display_led' is called as a subroutine
          from the TMR0 Interrupt Service Routine.  It, then, in turn,
          calls 'led_wrt' as a subroutine.  This is kind of dangerous
          because the PIC has very limited stack space.  So long as
          you are certain that you will not see another interrupt
          while servicing the TMR0 interrupt, this should work.
          However, if you end up building a system that needs to be
          able to interrupt during ISR handling, you should
          restructure this code to be inline in the TMR0 ISR and *not*
          use subroutine calls.


TIMING ISSUES
=============

The basic TMR0 interrupt rate of 1ms found in the original 'leddrvr'
design is preserved here.  'leddrvr' only drove 4 LEDs so each one got
updated every for 4ms - an effective multiplex/refresh rate of 250 Hz.

The 'leddrvr2' design is extended to handle 8 LEDs.  This means the
multiplex/refresh rate is 125 Hz.  This is probably as slow as you
want to go or you'll begin to see some display flicker.

If the design is extended for more than 8 LEDs (by adding more shift
registers), the multiplex/refresh rate will degrade in direct
proportion to the number of LEDs supported.  This will certainly
introduce unacceptable display flicker almost immediately.  This
problem can be solved by changing the TMR0 interrupt rate to something
faster than 1ms.

If you do this, note that the 'wait' subroutine assumes a basic timing
interval of 1ms.  This routine will have to be modified to accommodate
any TMR0 timing change you make.


DESIGN TRADEOFFS
================

As a matter of practicality, this design is way better than the
original 'leddrvr' approach.  However it raises the parts count and
therefore the real estate and cost to build a real system.  Even so,
this higher parts count is still somewhat cheaper than using a
specialty chip like a MAX7219.

This approach also caused the code size to grow somewhat (from 117 to
150 bytes) but this is probably a small price to pay for the vastly
reduced pin count.

As a matter of simplicity and minimizing parts count/board size, using
a dedicated part like the MAX7219 is probably preferred.  But where cost
is concerned, this design is probably somewhat better.

Like all engineering, these are *tradeoffs*, not absolutes...


I'D LIKE TO THANK THE ACADEMY...
================================

Lots of nice people on Usenet answered my stupid questions as I've
been learning the PIC.  Their help is very much appreciated.

You should feel free to poke around the code, change things, and
generally experiment with what is there.  It's the best way I know to
learn something new.  If you have any other thoughts / fixes /
questions / improvements for 'leddrvr2', please let 
tundra@tundraware.com know.  

Happy Hacking! ...