lpt_driver Documentation

An Linux LPT user-space driver for hacking with external LCD displays and DS1620 Temp Sensors.

30 May 98     Version 0.27

Carl D. Walker
Copywrite (c) under GPL
NOTE: RUN AS ROOT! (Needed for ioperm() call to work)

Command Line:
lpt_driver [-offset [-][degrees_c]]

The -offset switch, followed by a offset in degrees C, can be used to bias the
reported temp. from a DS1620, if one is found when the program starts up.

***** NOTE *****
This project needs a better name than 'lpt_driver'. If you think of one, please drop
me an email (lpt_driver@icmp.com). Thanks.

Version 0.28 Another cleanup release. Fixed some minor text display bugs, for things
             like up-time over 1000 Hours and - temp. Nothing major.

Version 0.27 Added some new display modes for text based load display, Min/Max Temp.,
             current PID of the driver. Cleaned up some things. This still needs work
             regarding the display line size. There is support for 20x2 and 24x2 type
             displays, but the development is done with the 24x2. If it's a problem
             using a 20x2 display, then you should shorten some of the strings that 
             are displayed.  I will look into doing a better job for the next
             major version.


This still needs a lot of work to be useful:

1: Signal handler functions
        *** 4/26/98 Added clean-up signals & temp display mode change signal CW ***

2: Signal to change default temp reporting F/C (And display mode control)
        *** 4/26/98 Done. Send a SIGHUP to the process to change the temp display mode.
        SIGHUP can be sent from the command line with 'kill -HUP pid#'
        SIGHUP may not be the best signal to use here, but I am open to sugestions CW ***
        *** Added DISPLAY_MODE control 4/27/98 CW ***
        There is now a DISPLAY_MODE control function for two basic modes: The default mode
        shows Uptime and Procs on the top line of the display. The second mode displays the date
        and time on the first line. Both modes display the temp and system load on the lower line
        of the display. DISPLAY_MODE switching is done by sending the driver a SIGUSR1 signal.
        SIGUSR1 can be sent from the command line with 'kill -USR1 pid#'

3: Named pipe input for display. If pipe goes inactive for 2 seconds, display default
   information. Auto-restore pipe info display when active again
        *** 2/25/98 Named pipe added '/dev/lpt_driver_in' CW ***
        *** 3/23/98 Added the pipe driver code CW ***
        Note: The pipe driver code still needs some work to make sure that nothing 'funny'
        can happen if the FIFO gets bombarded with data, or the writing applications
        stalls between writing lines (non-Atomic).  The code now assumes that there will be two
        lines of data to display in the buffer.  It will take the first two lines from
        the pipe, and display them, discarding anything else that may be in the pipe after
        them. (Lines are terminated by '\n')       

3.5: String filtering. Take data from the FIFO and filter out control chars that can't
   function normally on the LCD display. Things like /n, /r, form-feed, etc.  Change the
   chars to display control functions where it can be done.
        *** 3/23/98 Added this function with the pipe driver code. CW ***
        Note: The String Filtering only strips chars that are < 0x20 | > 0x7e.        

4: Smart display of data on various types of displays. Now setup for 2x40 display,
   but it should also handle 2x16 and 2x20 display types for installation in normal
   PC disk-drive bay
        *** There is now a simple flag for 2x20 or 2x40 displays, set at compile
        time.  This area still needs some work.

5: Load-up the char gen ram in the display, and make a bar-graph display of system load
        *** 2/16/98 Done.  CW ***
        *** Fixed a problem in main.c that overflowed the display when the temp was neg.
            CW 04/12/98 ***

6: temp logging to the syslog at some predefined interval. Also logging on demand using
   a signal to trigger the event
   *** 4/27/98 Signal SIGUSR2 now makes the driver log the temp to the syslog in whatever display
   mode we are now using (C|F)  CW ***

7: A new mode to handle graphic type LCD displays (I have to order some to play with)

8: General clean-up of the code, replace magic numbers with defines, etc.
   *** 5/25/98 Cleaned up a bunch of things in the code. Added better way to define display size.
   Now supporting 20x2 and 24x2 displays (see the header file for the enums). Need to add support
   for 40x2 displays as well. CW ***


Compile like this;
gcc -O -o lpt_driver main.c

Or, to debug add the -g option
gcc -O -g -o lpt_driver main.c

(There is also a Makefile. use;
make prog       for the normal program, or
make debug      for one with the debugging options enabled)

Files used in this program:
main.c  io.c    misc.c  dallas.c        fifo.c  lpt_driver.h    Makefile

*****************************************************************************************
The lpt port looks something like this.....

Addr            d7      d6      d5      d4      d3      d2      d1      d0
-----           -----   -----   -----   -----   -----   -----   -----   -----
Base            data7   data6   data5   data4   data3   data2   data1   data0

Base+1          ~busy   ack     pap_out select  error   -       -       -
(status)
Base+2          -       -       -       -       ~select init    ~autfed ~strobe
(control)

NOTE:   Status7, Control3, Control1, & Control0 are inverted in the hardware

And, the way we have wired the port up to the display is:

Addr            d7      d6      d5      d4      d3      d2      d1      d0
-----           -----   -----   -----   -----   -----   -----   -----   -----
Base            data7   data6   data5   data4   data3   data2   data1   data0

Base+1          -       -       -       -       -       -       -       -
(status)
Base+2          -       -       ext_mod -    data/~cntrl Enable ~R/W    -
(control)

ext_mod = extended mode control (r/w for the port hardware).
WRITE ONLY, A READ WILL RETURN JUNK! (Don't blame me, talk to IBM!)
0 = Write, 1 = Read.

NOTE:   I should make changes to add a shadow register for bits like ext_mod.....

ANOTHER NOTE:   Signal sense takes account of inversions in the hardware!


The display does not know about things like CR/LF (\r\n). It only knows about homing
(to the upper-left) with the cursor, and using set-address for the cursor.
The display addresses for a 2 line X 40 Char display looks like this:

0x00 0x01 0x02 0x03 0x04 0x05 ..... 0x26 0x27
0x40 0x41 0x42 0x43 0x44 0x45 ..... 0x66 0x67

Form-Feed can be simulated by sending a 'clear/home' command to the display
(This command takes about 1mS, so I don't like to use it)

Some of the more common commands for the LCD displays follow:

Function:               Byte Value:     Action:
--------------------------------------------------------------------------------------
display_control         0000_0001       CLEAR DISPLAY, HOME CURSOR

display_control         0000_001x       HOME CURSOR, MAINTAIN DISPLAY DATA

display_control         0000_001 I/D S  I=1 D=0 Increment/Decrement cursor after write
                                        S=1 Shift display S=0 No shift display

display_control         0000_1DCB       D=1 Display on, D=0 Display off
                                        C=1 Cursor on C=0 Cursor off
                                        B=1 Blinking block cursor on
                                        B=0 Blinking block cursor off

display_control         0001_S/C R/L xx S/C=1 Display shift
                                        S/C=0 Cursor move
                                        R/L=1 Shift to the Right
                                        R/L=0 Shift to the Left
                                        
display_control         0011_10xx       Display 8 bit mode, 2 lines, 5x7 font
                                        (Standard for this connection, use this
                                        mode)

display_control         01aa_aaaa       Set Char Gen. RAM address
                                        aaaaaa = Binary char. gen. ram address
                                        C.G. ram is sent/rcvd after this command
                                                                                
display_control         1aaa_aaaa       Set display data ram address. Used to pos. cursor.
                                        display ram is sent/rcvd after this command
                                        
display_data            ASCII Char      


display_read            BF aaaaaaa      BF=1 Busy BF=0 Not busy
                                        aaaaaaa = Binary char. ram address (current char)

CG RAM looks something like this.
Bit:    7       6       5       4       3       2       1       0

Byte0:  -       -       -       x       x       x       x       x       << 5x7 char matrix

Byte1:  -       -       -       x       x       x       x       x

Byte2:  -       -       -       x       x       x       x       x

Byte3:  -       -       -       x       x       x       x       x

Byte4:  -       -       -       x       x       x       x       x

Byte5:  -       -       -       x       x       x       x       x

Byte6:  -       -       -       x       x       x       x       x

Byte7:  0       0       0       0       0       0       0       0

Where the x's are the pattern to load, bits 7-5 are always zero, and byte 7 is always zero.

Fill the CG ram by setting the CG address to 0 (command 0x40) and loading all 8 chars with
64 bytes of write.

Then the char's loaded in this way will be displayed as char data 0x00 to 0x07.

Exit the CG ram load mode by setting the mode to data-display (command 0x80)
(This is the same as doing a 'display address 0x00')

Simple, 'eh?                            

(You can also load a custom char by itself, just by setting the CG ram address, sending the
eight bytes of CG char data, and setting the display back to data-display mode.)

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

(Take a look at the Dallas driver functions in this driver. All of the following
primitive functions are there)

If a Dallas DS1620 is connected to the display assembly, you can use the following bits:

Dallas          Port            Sense
DQ              D0              Normal
~RST            D1              Normal
CLK             ~STROBE         bit set in port = Dallas clock low (set to clock, reset
                                of bit is the rising edge of the clock)

                                
Example access of the DS1620:

With the port in the normal output mode, and no display transactions ongoing;

take the ~rst bit (D1) low
set D1 hi
Send the 'protocol' 8 bits, LSB first;
set strb bit hi (DS1620 clk goes low)
set data bit on D0
set strb bit low
continue until done with 8 protocol bits

if writing:
continue as above until all data bits have been sent after the protocol
goto done:

if reading:
turn port around by setting bit D5 of the port control byte
set strb bit hi
wait 1uS
shift in data from D0
set strb bit low
continue until all data bits are shifted in

done: clear bit D5 of the control byte
take port bit D1 low
set D1 hi

YOU ARE DONE!
*****************************************************************************************
Connection information:

parallel Port                   LCD Display                     DS1620
DB-25                           14 Pin                          8 Pin DIP
-------------                   -----------                     ---------

1 ------------------------------------------------------------- 2
2 ----------------------------- 7 ----------------------------- 1
3 ----------------------------- 8 ----------------------------- 3
4 ----------------------------- 9                -------------- 4
5 ----------------------------- 10              |   ----------- 8
6 ----------------------------- 11              |  |
7 ----------------------------- 12              |  |
8 ----------------------------- 13              |  |
9 ----------------------------- 14              |  |
16 ---------------------------- 6               |  |
17 ---------------------------- 4               |  |
14 ---------------------------- 5               |  |
18-25 ------------------------- 1 ---------------  |
                +5 ------------ 2 -----------------
         Gnd -- Vdisp --------- 3
                
Vdisp is used for LCD display power. The display logic is powered from the normal
+5 volt connection.  Normal display current is about 3mA maximum.

  There is no power available from the parallel port connection.
The easy way to obtain power in a system is from a disk drive connector.
If you want to connect to the internal 26 pin connector instead of the external DB-25 printer
connector, you can use the following table to translate the pin connections:
26 Pin Connector DB-25 pin Signal Name 26 Pin Connector DB-25 pin Signal Name

1

1

~Strobe

2

14

~AutoFF

3

2

D0

4

15

~Error

5

3

D1

6

16

~Init

7

4

D2

8

17

~Select

9

5

D3

10

18

Ground

11

6

D4

12

19

...

13

7

D5

14

20

...

15

8

D6

16

21

...

17

9

D7

18

22

...

19

10

~ACK

20

23

...

21

11

Busy

22

24

...

25

12

Paper out

24

25

Ground

*****************************************************************************************
It is interesting to note the following port information: A Kouwell parallel printer card,
Model KW-508E, comes with the following addresses for LPT1-6;
LPT1    0x3bc-0x3be
LPT2    0x378-0x37a
LPT3    0x278-0x27a
LPT4    0x268-0x26a
LPT5    0x27c-0x37e (Typo? It _must_ be 0x27c-0x27e?)
LPT6    0x26c-0x26e
*****************************************************************************************
For detailed information on the devices (DS1620 and LCD displays) used in this project,
have a look at:
www.dalsemi.com         (Dallas Semiconductor homepage)
www.hantronix.com       (Makers of LCD displays)

If you find that this program is of use, or you would like to contribute to code development,
please drop me an email. Thanks ;-)
Enjoy!

Carl Walker
cwalker@icmp.com