home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.tar / ftp.whtech.com / club100 / ref / lcdtip.doc < prev    next >
Text File  |  2006-10-19  |  14KB  |  302 lines

  1. LCD Graphics Display Input/Output Tips
  2. Mike Safonov 70506,1473
  3. *******************************************************************************
  4.  
  5.     The readily available information on techniques for manipulating, saving 
  6. and loading screen graphics and custom characters to and from the LCD is 
  7. precious little.  Following is a discussion of various techniques including 
  8. some little-known but useful ROM calls for manipulating, displaying and 
  9. retrieving 6x8 blocks of LCD graphics data.  The discussion is organized as 
  10. follows:
  11.  
  12.      I. THEORY:  HOW GRAPHICS DATA IS DISPLAYED ON AND READ FROM THE LCD
  13.  
  14.     II. USEFUL LCD ROM CALLS FOR GRAPHICS READ AND WRITE
  15.  
  16.    III. PRINTER INTERFACING:  UPSIDE-DOWN BIT-IMAGE PROBLEMS
  17.  
  18. *******************************************************************************
  19.  
  20.  
  21. I. THEORY:  HOW GRAPHICS DATA IS DISPLAYED ON AND READ FROM THE LCD
  22.  
  23.     Each 6x8 character location of the screen is represented by six one-byte 
  24. (i.e., six eight-bit) numbers ranging from 0 to 255.  The six numbers contain 
  25. the data for the six columns of a the character.  For example the letter T is 
  26. printed when the computer sends the following six decimal numbers to the LCD:
  27.  
  28. Decimal:        1   1  127  1   1  0
  29.  
  30. Binary: bit 0   1   1   1   1   1  0
  31.         bit 1   0   0   1   0   0  0
  32.         bit 2   0   0   1   0   0  0
  33.         bit 3   0   0   1   0   0  0
  34.         bit 4   0   0   1   0   0  0
  35.         bit 5   0   0   1   0   0  0
  36.         bit 6   0   0   1   0   0  0
  37.         bit 7   0   0   0   0   0  0
  38.  
  39. Note how the ones in the binary representation of the six numbers form the 
  40. letter T.  Each bit of the binary number represents one pixel.  The bit is one 
  41. is the pixel is set and it is zero otherwise.
  42.  
  43.     Pixel data is sent to and from the LCD one byte at a time, with each byte 
  44. containing the data for one eight-bit tall column of pixels.  The actual 
  45. mechanism for sending and retrieving this data to and from the screen involves 
  46. the use of the use of CPU ports 185, 186, 254, and 255.  It is somewhat 
  47. complex, but not altogether incomprehensible.  The process proceeds in the 
  48. following sequence:  First, a short machine code sequence (CALL 30300) is used 
  49. to disable interupts until the transfer of data to/from the LCD is complete.  
  50. Second, ports 185 and 186 are used to select one of ten hardware drivers, each 
  51. of which addresses a subset of the 6x320 bytes that make-up the LCD.  The 
  52. portions of the LCD controlled by each of the drivers 0-9 is indicated by the 
  53. following diagram:
  54.  
  55.         -----------------------------------
  56.         |   0  |   1  |   2  |   3  |  4  |
  57.         -----------------------------------
  58.         |   5  |   6  |   7  |   8  |  9  |
  59.         -----------------------------------
  60.  
  61. Fig. 1  Portions of LCD controlled
  62.         by each of the 9 hardware drivers
  63.  
  64. A BASIC subroutine for selecting driver DZ% (where DZ% is the driver number 0 
  65. to 9) is:
  66.  
  67.   10 CALL 30300
  68.   20 M%=2^DZ%
  69.   30 M1=PEEK(VARPTR(M%)):    REMARK M1=((2^N) AND 255)
  70.   40 M2=PEEK(VARPTR(M%)+1):  REMARK M2=INT(2^(N-8))
  71.   50 OUT 185,M1
  72.   60 P=(INP(186) AND 252) OR M2
  73.   70 OUT 185,P
  74.   80 RETURN
  75.  
  76. There is a ROM call at 30011 which implements lines 30-70 in machine code.  An 
  77. equivalent program is:
  78.  
  79.   10 CALL 30300
  80.   20 M%=2^DZ%
  81.   30 CALL30011,0,VARPTR(M%)
  82.   80 RETURN
  83.  
  84.     After one of the ten drivers has been selected, OUT254,xxx is used to 
  85. select which eight-pixel-tall byte in the driver is to be used.  The portion of 
  86. the LCD associated with each of the ten drivers is 32 pixels high and 50 pixels 
  87. wide (except drivers 4 and 9 for which the width is only 40).  The height of 32 
  88. pixels is divides into four rows (numbered 0 to 3) of eight-pixel-tall columns.
  89.  
  90.     Each eight pixel tall column in a row contains one byte of LCD image data.  
  91. A BASIC subroutine to select byte number CZ% (0 to 50) in row RZ% (0 to 3) in 
  92. the previously selected driver is:
  93.  
  94.   70 M3=CZ%+64*RZ%
  95.   80 OUT254,M3
  96.   90 RETURN
  97.  
  98.     Before actually sending/retrieving a byte of bit-image data to/from the 
  99. selected LCD screen location, one must first check that INP(254)<128.  If not, 
  100. then the LCD is still responding to the previous commands and one must wait 
  101. before attempting to send or receive a byte of display data.
  102.  
  103.     Once the driver DZ%, row RZ% and column CZ% have been selected, a byte 
  104. containing the bit-image of data to be displayed at the selected location is 
  105. sent via OUT255,byte.  A BASIC subroutine for doing this is:
  106.  
  107.  100 IF INP(254)>127 THEN 100
  108.  110 OUT 255,byte:  REMARK byte is between 0 and 255
  109.  120 RETURN
  110.  
  111. If instead of displaying data one wishes to read the data that is currently on 
  112. the LCD at the selected LCD screen location, then byte=INP(255) is substituted 
  113. for OUT255,byte in line 110.  In either case, the LCD automatically increments 
  114. the selected byte column CZ% by one after each INP(255) or OUT255,byte 
  115. instruction, so several bytes may be imput or output in succession without 
  116. repeating the driver, row, and column select procedures PROVIDED THAT ALL BYTES 
  117. ARE TO BE DISPLAYED IN THE AREA UNDER THE CONTROL OF THE SAME DRIVER.  It is an 
  118. unfortunate fact that 24 of the 320 6-byte print postions on the LCD straddle 
  119. two adjacent drivers.
  120.  
  121.     For additional insight into the process of sending data to the LCD, see 
  122. the file CHRDEF.BA in DL4 (which contains a .BA program for displaying a six 
  123. byte custom character on the LCD using CPU ports 185,186, 254, and 255).
  124.  
  125.     Fortunately, there are machine code routines in the M100's ROM which can 
  126. be used efficiently handle to task of sending blocks of six-bytes to and from 
  127. the LCD and to handle the somewhat involute process of selecting right 
  128. locations on the screen and switching drivers when the 6-bytes straddle two 
  129. adjacent drivers.  Consequently, in most applicatons there is no need for 
  130. actually using any of the BASIC subroutines above (or for using the relatively 
  131. involute CHRDEF.BA) to read/write custom characters or graphics to/from the 
  132. LCD.
  133.  
  134.  
  135. II. USEFUL LCD ROM CALLS FOR GRAPHICS READ AND WRITE
  136.  
  137.     A crude but popular method used by various graphics screen dump and pixel 
  138. tester programs is to read graphic data from the LCD is to flash the cursor on 
  139. then off, which reads the six byte bit-image of that portion of the LCD under 
  140. the cursor to RAM memory locations 65616 to 65621 (equivalently, locations -20 
  141. to -15)  The data can then be PEEK'ed from these locations.  For example, a 
  142. BASIC program to read the six bytes a screen location 37 is:
  143.  
  144.   10 PRINT@37,CHR$(27)"P"  'cursor on at 37
  145.   20 FOR I=1TO10:NEXT  'delay while LCD cathches up
  146.   30 PRINTCHR$(27)"Q"; cursor off
  147.   40 FOR I=1TO10:NEXT  'delay while LCD catches up
  148.   50 FOR I=0TO5:BYTE(I)=PEEK(I-20):NEXT 'read six bytes LCD bit-image data
  149.   60 RETURN
  150.  
  151. See, for example, PGMTIP.008 for a discussion of how to use this for testing 
  152. whether or not a given pixel on the LCD is set.  One criticism of this method 
  153. is that it is relatively slow and can be unreliable.  It seems that even BASIC 
  154. is faster than the LCD and so that a program without appropriate additional 
  155. delays inserted may occassionally attempt to PEEK the character data before the 
  156. LCD has finished sending it.  Another unpleasant feature of the approach to 
  157. reading graphics data from the LCD is the cursor flash which is visible and can 
  158. be distracting or even annoying in some applications.
  159.  
  160.     A closely related technique which is much faster and completely reliable  
  161. involves the ROM call, CALL 17786, which INVERSES the six byte bit image at the 
  162. current cursor position, storing a copy or the inverse bit image at RAM 
  163. locations -20 to -15.  The following BASIC program will read the six byte bit 
  164. image of the LCD at location 49:
  165.  
  166.   10 PRINT@49,;  'move cursor to location 49
  167.   20 CALL 17786  'inverse 6 bytes on screen & save
  168.                  'in RAM locations -20 to -15
  169.   30 CALL 17786  'do it again to re-invert it
  170.   50 FOR I=0TO5:BYTE(I)=PEEK(I-20):NEXT 'read six bytes LCD bit-image data
  171.   60 RETURN
  172.  
  173. The machine code call 17786 has built-in a check on INP(254)<128 which seems to 
  174. circumvent the need for adding delays, but it still suffers from the 
  175. distracting cursor flash.
  176.  
  177.     There is a simple to use ROM routine than this for sending data from the 
  178. LCD.  It is CALL 29744.  The following BASIC program prints a six-byte custom 
  179. cahracter (an upside-down "T") at screen location 53 (which is more or less 
  180. what CHRDEF.BA in DL4 does, but in a more involute fashion):
  181.  
  182.   10 PRINT@53,;  'more cursor to desired display location
  183.   20 'store six byte bit image in integer array B%(I)
  184.   30 FOR I=0TO2:READ B1,B2:B%(I)=B1+256*B2:NEXT
  185.   40 CALL30300   'disable interupts
  186.   50 CALL29744,0,VARPTR(B%(0))  'display 6 byte bit-image of the vector B%
  187.   60 RETURN
  188.   70 DATA 64,64,127,64,64,0
  189.  
  190. The machine code CALL 29744,0,HL transfers 6 bytes beginng at RAM memory 
  191. location HL and displays them at the row(0 to 7) and column (0 to 39) position 
  192. on the LCD specified by the current contents of RAM memory locations -12 and 
  193. -11 respectively.  The contents of these locations is automatically set to the 
  194. current cursor position by any print command (in this case PRINT@53,;).  
  195. However, the any row and column can be POKE'd to these locations directly if 
  196. desired.
  197.  
  198.     The first machine code instruction of in CALL 29744,0,HL is in 8085 
  199. assembly language MVI D,1 (which means load the D-register of the CPU with the 
  200. number 1).  The actual machine code consists of the two integers (22,1) which 
  201. are stored in ROM at memory locations 29744 and 29755.
  202.  
  203.     It turns out that the foregoing routine can be used to READ six-bytes FROM 
  204. the LCD TO memory locations HL to HL+5 if the D-register is first loaded with 0 
  205. instead of 1, and then one uses CALL29746,0,HL bypassing the MVI D,1 
  206. instruction.  This may be accomplished by the following position-independent 
  207. machine code sequence 22,0,205,50,116,201,0.  This can be poked anywhere in ROM 
  208. and then called.  For those familiar with 8085 assembly language, this code 
  209. translates as:
  210.  
  211.      22 MVI D,0     'load 0 into D-register
  212.       0
  213.     205 CALL 29746  '29746=50+116*256
  214.      50
  215.     116
  216.     201 RET         'return
  217.  
  218. The following BASIC subroutine loads this 6 byte machine code program into RAM 
  219. at memory location VARPTR(MZ%(0)) so that it may be executed by the BASIC 
  220. command CALL VARPTR(MZ%(0)),0,HL
  221.  
  222.   10 MZ%(0)=22      ' =22+0*256
  223.   20 MZ%(1)=13005   ' =205+50*256
  224.   30 MZ%(2)=-13964  ' =(116+201*256) MOD 65536
  225.   40 RETURN
  226.  
  227. CALL VARPTR(MZ%(0)),0,HL pokes the 6 byte bit-image of LCD to the six RAM 
  228. locations HL to HL+5.
  229.  
  230.     This program can be easily modified to display the data at HL to HL+5 on 
  231. the LCD (exactly like CALL 29744,0,HL) if one changes line 10 to read:
  232.  
  233.   10 MZ%(0)=278     ' =22+1*256
  234.  
  235.     As an example, consider the following BASIC program which reads and writes 
  236. the entire LCD image including graphics to and from the 1921 byte machine code 
  237. data file IMAGE.CO.
  238.  
  239.    0 CLEAR256,MAXRAM-1921
  240.   10 '  ...  (any program generating a plot, picture or
  241.   20 '  ...   text on the LCD goes here)
  242.   30 INPUT$"[S]ave LCD image";QZ$
  243.   40 GOSUB 100
  244.   90 END
  245.  100 POKE HIMEM,201  'POKE a machine code "return" at beginning of file
  246.  101 HL=HIMEM+1
  247.  102 IFQZ$="S"THEN MZ%(0)=22 ELSE LOADM"IMAGE":MZ%(0)=278
  248.  103 MZ%(1)=13005
  249.  104 MZ%(2)=-13964
  250.  105 FOR RZ%=0TO6
  251.  106     FORCZ%=0TO39
  252.  107         CALL30300
  253.  108         POKE-12,RZ%
  254.  109         POKE-11,CZ%
  255.  110         CALLVARPTR(MZ%(0)),0,HL
  256.  111         HL=HL+6
  257.  112     NEXT
  258.  113 NEXT
  259.  114 IFQZ$="S" THEN SAVEM "IMAGE",HIMEM,HIMEM+1921
  260.  115 RETURN
  261.  
  262. If QZ$="S" on entry then this program copies the LCD to the machine code file 
  263. IMAGE.CO, otherwise it does the reverse, i.e., it displays the 1920 bytes of 
  264. bit-image data in the file IMAGE.CO on the LCD.  (Note: a similar routine is 
  265. used for saving pictures from the LCD by CVSMOD.002 in DL3).
  266.  
  267.  
  268. III. PRINTER INTERFACING:  UPSIDE-DOWN BIT-IMAGE PROBLEMS
  269.  
  270.     Many dot matrix printers accept bit-image graphics exactly as it comes from 
  271. the LCD.  An exception is certain popular EPSON printers, e.g., the EPSON RX-80 
  272. and the EPSON FX-80.  These printers display graphics data "upside-down" 
  273. relative to the M100's LCD bit-image because the EPSON's think bit 0 is at the 
  274. bottom of each 8-bit-tall column of pixels whereas the M100 thinks it is at the 
  275. top.  Basic programs for turning a byte "upside-down" are much too slow for 
  276. efficient dumping of LCD image data to such printers--unless you like watching 
  277. radishes grow and other leisurely activities.
  278.  
  279.     One solution is the following machine code BASIC subroutine to quickly 
  280. turn a byte "upside down".  It temporarily defines a machine code routine CALL 
  281. 65024,A,HL which takes a one-byte number A (0 to 255) and stores its "upside-
  282. down" bit-image at memory address HL.
  283.  
  284.  400 RESTORE 403
  285.  401 FORI=0TO31:READZ:POKE65024+I,Z:NEXT
  286.  402 RETURN
  287.  403 DATA 0,87,62,0,6,1,14,128,54,0,183,216,120,162,120,23,71,121,31,79,202,11,254
  288.  404 DATA 245,23,182,119,241,195,11,254,0
  289.  
  290. After this subroutine has been run and until the routine is overwritten or 
  291. destroyed by a PRINT command, CALL65024,A%,VARPTR(A%) takes an integer A% 
  292. (0 to 255) as input and on exit A% is replaced its the "upside-down" inverse 
  293. (i.e., bit 0 goes to bit 7, bit 1 to bit 6, etc.).  The machine code subroutine 
  294. resides at locations 65024-65055 and is NOT relocatable.  This area of RAM is 
  295. the first line of the LCD screen-image memory, not to be confused with the 
  296. screen itself--it merely contain's a copy of the ASCII characters PRINT'ed on 
  297. the LCD).  The machine code program POKE'd here does not affect the LCD display 
  298. in any way and remains until it is detroyed by either an ASCII character being 
  299. PRINT'ed on the first line of the LCD or by the LCD being scrolled.  (Note:  
  300. This routine is used in the BASIC program EPSCHR.101 in DL0 which copies the 
  301. M100's special character set to an EPSON FX80 printer).
  302.