home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / utils / asmutl / hd64180a.lbr / IOLCD440.AZM / IOLCD440.ASM
Assembly Source File  |  1991-08-04  |  15KB  |  652 lines

  1.     title    'CORE Board LCD Drivers - 4 by 40 Char version'
  2. ;----------------------------------------------------------------
  3. ;         LCD Drivers for CORE Board
  4. ;
  5. ; This module provides all the LCD Support for CORE-BOARD
  6. ; and is separate to the I/O driver main module because
  7. ; different LCDs' will definately require different
  8. ; I/O drivers.
  9. ;
  10. ; Written     by      Richard Holmes       17-12-86
  11. ; Last Update by      Richard Holmes       11-08-87
  12. ;----------------------------------------------------------------
  13. ;        Routines in this module
  14. ;
  15. ; ini$lcd    Initialize the LCD display
  16. ; clr$lcd    Clear LCD and home cursor
  17. ; hom$lcd    Home cursor to top L.H. corner
  18. ; cur$lcd    Cursor address lcd. D = X, E = Y
  19. ; eol$lcd    Clear LCD to end of line.
  20. ; put$lcd    Write character in A to LCD.
  21. ; str$lcd    Print string at DE to LCD till a null or $
  22. ;----------------------------------------------------------------
  23. ; This version suits the HanDok 4016H. It is a 40 character by 4 
  24. ; line display.
  25. ; PA 0..7 are data bits into the chip
  26. ;
  27. ; PB 0 = Enable 1. For controller 1
  28. ;    1 = Enable 2. For controller 2
  29. ;    1 = R/W-.               1 = write to LCD
  30. ;    2 = Register select     1 = Data, 0 = control register
  31. ;----------------------------------------------------------------
  32. ;
  33.     maclib    z80
  34.     maclib    core
  35. ;
  36.     public    ini$lcd,hom$lcd,clr$lcd
  37.     public    put$lcd,cur$lcd,eol$lcd
  38.     public    str$lcd
  39. ;
  40. ; ---- Smart LCD I/O ----
  41. ;
  42.     public    xyi$lcd,xyp$lcd,pmu$lcd
  43. ;
  44.     extrn    coe
  45.     extrn    ori$led            ; Restore LED status
  46.     extrn    clrwdt            ; Stop watchdog
  47. ;
  48. ; Equates
  49. ;
  50. data    equ    044h        ; Data port of LCD
  51. cntl    equ    045h        ; Control port of LCD
  52. mode    equ    047h        ; Mode port
  53. ;
  54. idle    equ    0        ; Idle display controllers
  55. wr$cmd2    equ    1        ; Write command 1
  56. wr$cmd1    equ    2        ; Write command 2
  57. ;
  58. wr$dat2    equ    9        ; Write data 1
  59. wr$dat1    equ    0ah        ; Write data 2
  60. ;
  61. rd$st2    equ    5        ; Read status 1
  62. rd$st1    equ    6        ; Read status 2
  63. ;
  64. bs    equ    8        ; Backspace
  65. ;
  66. ;----------------------------------------------------------------
  67. ; Return LCD Status. This is tricky as it must re-initialize
  68. ; the LCD control port and read the LCD status flag BF. It
  69. ; will return a 00 if idling or an FF if busy. NOTE the
  70. ; need to re-load the CS2 line to the ram chip and clock
  71. ; and LED return when finished.
  72. ;----------------------------------------------------------------
  73. ;
  74. lcd$status:    
  75.     push    h        ; Save register to use as a scratch pad
  76. ;
  77. ; Generate the LCD enable signals
  78.     lda    lcd$cmd        ; Command to be used
  79.     ani    0000$0011b    ; Get the controller bits
  80.     ori    0000$0100b    ; Or in the status reading function
  81.     mov    l,a        ; L = device image.
  82. ;
  83.     di            ; STOP interrupts when checking LCD status
  84.     mvi    a,090h        ; Port A inputs
  85.     out    @ledmd        ; LED mode port
  86.     mvi    a,0c0h
  87.     out    @ledd        ; Re-assert ram as soon as possible
  88. ;
  89.     nop
  90.     nop
  91.     nop
  92.     nop            ; Settling time
  93. ;
  94. ;       OK, Port A inputs, B and C outputs. 
  95. ; Note the need to set R/W pin high for a time before the E pin (bit 0).
  96. ;
  97.     mvi    a,0000$0100b    ; Send the Read bit out.
  98.     out    cntl        ; To the control port
  99.     mov    a,l
  100.     out    cntl        ; Send "E" bits also
  101. ;
  102. ; This requires a 40uS delay as per the data sheet
  103. ;
  104.     mvi    a,15        ; Plenty of time 
  105. st$dly:
  106.     dcr    a
  107.     jnz    st$dly
  108. ;
  109.     in    data        ; Read the LCD data
  110.     mov    l,a        ; Save here. Can't see stack can we....
  111. ;
  112. ; Restore 8255 mode
  113.     mvi    a,080h        ; ALL outputs
  114.     out    @ledmd        ; LED mode port
  115. ; Re-load ram control signals
  116.     mvi    a,0C0h        ; Bit 6 and 7 for ram and clock on
  117.     out    @ledd        ; Sends to led port to turn on ram again.
  118. ;
  119.     nop
  120.     nop
  121.     nop
  122.     nop
  123.     xra    a
  124.     out    cntl        ; Clear the port
  125. ;
  126.     ei            ; Restore interrupts after LCD write
  127. ;
  128.     call    ori$led        ; Restore previous LED status
  129. ;
  130.     mov    a,l        ; Restore data
  131.     pop    h        ; Restore register
  132. ;Now. Determine basic state of 00 = idle or FF = busy.
  133.     ani    1000$0000b    ; Leave busy flag
  134.     rz
  135.     mvi    a,0ffh        ; Else load an FF for very busy still.
  136.     ret
  137. ;
  138. ;------------------------------------------------
  139. ; Latch the command in lcd$cmd  and the
  140. ; data in lcd$dat into the LCD.
  141. ;------------------------------------------------
  142. ;
  143. lch$lcd:
  144.     push    h
  145.     push    psw        ; Save registers
  146. ;
  147. ; Now setup timeout counter in HL and look for LCD idle
  148.     lxi    h,400        ; Big delay
  149. lch$cmd$loop:
  150.     call    clrwdt
  151.     call    lcd$status    ; Get LCD status
  152.     ora    a
  153.     jrz    lch$cmd$ok
  154.     dcx    h
  155.     mov    a,l
  156.     ora    h        ; Done ?
  157.     jrnz    lch$cmd$loop    ; Loop on till IDLE (busy flag = 0)
  158. ; ERROR here
  159. ;
  160.     pop    psw
  161.     pop    h
  162.     stc            ; Carry flag = error
  163.     ret
  164. ;
  165. ; Restore registers and do job
  166. ;
  167. lch$cmd$ok:
  168.     pop    psw
  169.     push    psw
  170. ;
  171.     out    data
  172.     lda    lcd$cmd
  173.     out    cntl
  174.     xra    a
  175.     out    cntl
  176. ;
  177.     pop    psw
  178.     pop    h
  179.     ret
  180. ;
  181.     page
  182. ;----------------------------------------------------------------
  183. ;         Initialize the LCD.
  184. ;
  185. ; 1. Data path 8 bits, 2 line display
  186. ; 2. Enable cursor. Blink. Enable display
  187. ; 4. Clear and home cursor.
  188. ; 3. Display stationary, auto increment, right
  189. ;----------------------------------------------------------------
  190. ;
  191. ini$lcd:
  192.     push    psw
  193. ;
  194. ; Select the first controller, command latching.
  195.     mvi    a,wr$cmd1    ; Command for controller 1
  196.     sta    lcd$cmd        ; Save in command port.
  197.     call    ini$cntrlr    ; Initialize the controller
  198. ;
  199.     mvi    a,wr$cmd2    ; Controller 2
  200.     sta    lcd$cmd
  201.     call    ini$cntrlr
  202. ;
  203.     xra    a
  204.     sta    lcd$x
  205.     sta    lcd$y        ; Setup X and Y addresses
  206.     call    cof$lcd        ; Turn off all cursors
  207.     call    con$lcd        ; Turn cursor on.
  208. ;
  209.     pop    psw
  210.     ret
  211. ;
  212. ;----------------------------------------------------------------
  213. ;     ---- Initialize the contoller. ----
  214. ;----------------------------------------------------------------
  215. ;
  216. ini$cntrlr:
  217. ;
  218. ; 1. Enable 8 bit bus, 2 line display
  219.     mvi    a,038h
  220.     call    lch$lcd        ; Latch 8 bit, 2 line display
  221. ;
  222. ; 2. Enable display on, cursor on, blink
  223.     mvi    a,0eh
  224.     call    lch$lcd
  225. ;
  226.     mvi    a,08
  227.     call    lch$lcd
  228. ;
  229. ;
  230. ; 3. Display stationary, Right cursor
  231. ;
  232.     mvi    a,2
  233.     call    lch$lcd
  234. ;
  235.     mvi    a,1
  236.     call    lch$lcd
  237. ;
  238. ; Done.
  239.     ret
  240. ;
  241. ;----------------------------------------------------------------
  242. ;             Clear LCD and home cursor.
  243. ;----------------------------------------------------------------
  244. ;
  245. clr$lcd:
  246.     push    psw
  247. ; Clear controller 1
  248.     mvi    a,wr$cmd1
  249.     sta    lcd$cmd            ; Select a clear command controller 1
  250.     mvi    a,1            ; Clear display totally
  251.     call    lch$lcd
  252. ;
  253. ; Clear controller 2
  254.     mvi    a,wr$cmd2
  255.     sta    lcd$cmd            ; Select a clear command controller 1
  256.     mvi    a,1            ; Clear display totally
  257.     call    lch$lcd
  258. ;
  259.     xra    a            ; Clear cursor address
  260.     sta    lcd$x
  261.     sta    lcd$y
  262.     call    hom$lcd
  263. ;
  264.     pop    psw
  265.     ret
  266. ;
  267. ;----------------------------------------------------------------
  268. ;         Home the cursor
  269. ;----------------------------------------------------------------
  270. ;
  271. hom$lcd:
  272.     push    d
  273.     push    psw
  274. ;
  275.     lxi    d,0            ; Top left hand corner of screen
  276.     call    cur$lcd            ; Home to the top lh lcd corner
  277. ;
  278.     pop    psw
  279.     pop    d
  280.     ret
  281. ;
  282. ;----------------------------------------------------------------
  283. ;     Turn all cursors off.
  284. ;----------------------------------------------------------------
  285. ;
  286. cof$lcd:
  287.     push    psw
  288.     mvi    a,wr$cmd1
  289.     sta    lcd$cmd
  290.     mvi    a,0000$1100b    ; Display on, cursor off
  291.     call    lch$lcd        ; Latch the command and data in.
  292. ;
  293.     mvi    a,wr$cmd2
  294.     sta    lcd$cmd
  295.     mvi    a,0000$1100b    ; Display on, cursor off
  296.     call    lch$lcd        ; Latch the command and data in.
  297.     pop    psw
  298.     ret
  299. ;
  300. ;----------------------------------------------------------------
  301. ;     Turn the current cursor at lcd$x and lcd$y on.
  302. ;
  303. ; This is decided by the current cursor address of the lcd.
  304. ;----------------------------------------------------------------
  305. ;
  306. con$lcd:
  307.     push    b
  308.     push    psw
  309. ;
  310. ; Select the controller and load the write command control word
  311.     mvi    c,wr$cmd1    ; Default to controller 1
  312.     lda    lcd$y        ; Line number
  313.     cpi    2
  314.     jc    con$do        ; Line 0 and 1 user controller 1
  315. ;
  316.     mvi    c,wr$cmd2    ; Controller 2 if line 2 or 3
  317. con$do:
  318.     mov    a,c        ; get
  319.     sta    lcd$cmd        ; Load the command
  320.     mvi    a,0fh        ; cursor on
  321.     call    lch$lcd        ; And do it.
  322. ;
  323.     pop    psw
  324.     pop    b
  325.     ret
  326. ;
  327.     page
  328. ;----------------------------------------------------------------
  329. ; Cursor address.
  330. ;
  331. ; On Entry D = X in the range 0..38  (characters per line)
  332. ;          E = Y in the range 0..3   (lines)
  333. ;
  334. ; If out of range, no change is made.
  335. ; All registers preserved
  336. ;----------------------------------------------------------------
  337. ;
  338. cur$lcd:
  339.     push    b
  340.     push    psw
  341. ;
  342. ; Check if X > possible range.
  343.     mov    a,d
  344.     cpi    40        ; Error if > 16
  345.     jrnc    cur$err
  346. ; Check Line number
  347.     mov    a,e
  348.     cpi    4
  349.     jrnc    cur$err        ; Error if > 3
  350. ;
  351.     sta    lcd$y
  352. ;
  353. ; Turn off cursor(s)
  354.     call    cof$lcd        ; All cursors off. Sets up lcd$cmd also.
  355. ;
  356. ; Now generate the ram address for the LCD
  357.     mvi    c,080h        ; Top bit = cursor address
  358.     mov    a,e        ; Get the line number back
  359.     ani    0000$0001b    ; Do a modulus 2
  360.     jrz    cur$not$1    ; Top row is address 80h..8fh
  361.     mvi    c,0C0h        ; If second row the offset is 0C0h
  362. ;
  363. cur$not$1:
  364.     mov    a,c        ; Address
  365.     add    d        ; Add in the X address
  366.     call    lch$lcd        ; Command in A built up
  367. ; Save the X address also
  368.     mov    a,d        ; X
  369.     sta    lcd$x
  370. ; Turn on the cusor
  371.     call    con$lcd
  372. ;
  373. cur$err:
  374.     pop    psw
  375.     pop    b
  376.     ret
  377. ;
  378. ;----------------------------------------------------------------
  379. ;                Clear LCD to end of line
  380. ;----------------------------------------------------------------
  381. ;
  382. eol$lcd:
  383.     push    b
  384.     push    d
  385.     push    psw
  386. ; Get the current cursor address.
  387.     lda    lcd$y
  388.     mov    e,a
  389.     lda    lcd$x
  390.     mov    d,a        ; Save X
  391. ;
  392. ; A = column number. Send spaces to end of line now.
  393. ;
  394. eol$loop:
  395.     push    psw        ; Save current column number
  396.     mvi    a,' '        ; Erase with a space.
  397.     call    put$lcd        ; Send the character to the LCD
  398.     pop    psw        ; Restore column
  399. ;
  400.     cpi    39        ; Did we just do the last column ?
  401.     jrz    eol$done
  402.     inr    a
  403.     jr    eol$loop
  404. ;
  405. ;
  406. eol$done:
  407.     call    cur$lcd        ; Cursor address to previous row/col position
  408. ;
  409.     pop    psw
  410.     pop    d
  411.     pop    b
  412.     ret
  413. ;
  414.     page
  415. ;----------------------------------------------------------------
  416. ;
  417. ;          Send character in A to the LCD
  418. ;
  419. ; We must decide which controller by checking the lcd$y address
  420. ; and use Y = 0,1 for controller 1, and 2,3 for controller 2.
  421. ;----------------------------------------------------------------
  422. ;
  423. put$lcd:
  424.     push    psw
  425.     push    b
  426. ;
  427. ; Carriage return ?
  428.     cpi    0dh
  429.     jz    put$cr
  430.     cpi    lf
  431.     jz    put$lf
  432.     cpi    bs            ; Back space ?
  433.     jz    put$bs
  434. ;
  435. ; None of these. Bump the column number.
  436.     lda    lcd$x
  437.     inr    a
  438.     sta    lcd$x
  439.     cpi    40            ; End of line ?
  440.     jc    put$lcd1        ; If not, continue.
  441.     xra    a            ; Start of next line
  442.     sta    lcd$x
  443. ;
  444. ; Bump the row now. We must also cusor position.
  445. ; This is used as the line feed entry point so that the
  446. ; line number is advaced without advancing any columns.
  447. ;
  448.     lda    lcd$y
  449.     inr    a
  450.     sta    lcd$y
  451.     cpi    4            ; Only allowed rows 0..3
  452.     jc    put$lcd$xy        ; Not last row and all ok
  453. ;
  454. ; Past last row. Start at top again.
  455.     xra    a
  456.     sta    lcd$y
  457. ;
  458. put$lcd$xy:
  459.     push    d
  460.     lda    lcd$x
  461.     mov    d,a
  462.     lda    lcd$y
  463.     mov    e,a
  464.     call    cur$lcd            ; Setup cursor at end of line to "wrap"
  465.     pop    d
  466. ;
  467. ; Now select the controller to be used (written to).
  468. ;
  469. put$lcd1:
  470.     mvi    c,wr$dat1        ; Default to controller 1
  471.     lda    lcd$y
  472.     cpi    2
  473.     jc    put$lcd$do
  474.     mvi    c,wr$dat2
  475. ;
  476. put$lcd$do:
  477.     mov    a,c
  478.     sta    lcd$cmd
  479. ;
  480.     pop    b
  481.     pop    psw
  482.     jmp    lch$lcd
  483. ;
  484. ; Carriage return = home cursor to left hand column
  485. ;
  486. put$cr:
  487.     xra    a
  488.     sta    lcd$x
  489. ;
  490. ; Cursor address now - Also used by the CR handler
  491. ;
  492. put$lf$cur:
  493.     push    d
  494.     lda    lcd$x
  495.     mov    d,a            ; D = X
  496.     lda    lcd$y
  497.     mov    e,a            ; E = Y
  498.     call    cur$lcd
  499.     pop    d
  500. ;
  501. ;
  502. put$end:
  503.     pop    b            ; Saved at routine start.
  504.     pop    psw
  505.     ret
  506. ;
  507. ; Process a line feed by incrementing the line number by 1
  508. ;
  509. put$lf:
  510.     lda    lcd$y            ; Line number
  511.     inr    a
  512.     sta    lcd$y
  513.     cpi    4
  514.     jc    put$lf$cur        ; Carry = not past end line
  515.     xra    a
  516.     sta    lcd$y
  517.     jmp    put$lf$cur
  518. ;
  519. ; Send a backspace to the LCD by decrementing the current column by 
  520. ; one. NOTE that the backspacing will stop at left hand margin.
  521. ;
  522. put$bs:
  523.     lda    lcd$x
  524.     ora    a            ; At zero ?
  525.     jrz    put$end
  526.     dcr    a
  527.     sta    lcd$x            ; Save the new decremented column
  528.     jmp    put$lf$cur        ; Cursor address now.
  529. ;
  530.     page
  531. ;----------------------------------------------------------------
  532. ; Print the menu at the address in DE into the LCD.
  533. ;----------------------------------------------------------------
  534. ;
  535. pmu$lcd:
  536.     push    d            ; save all
  537.     push    psw
  538. ;
  539. pmenu2:
  540.     call    clrwdt            ; Reset watchdog
  541.     call    xyp$lcd            ; Print the string following to the lcd
  542.     ldax    d            ; is the next character a dollar ?
  543.     cpi    0ffh            ; end of menu ??
  544.     jrnz    pmenu2
  545. ;
  546.     pop    psw
  547.     pop    d
  548.     ret
  549. ;
  550. ;----------------------------------------------------------------
  551. ; Print the following X-Y addressed message to the LCD. The return
  552. ; address has the text in it preceeded by an X-Y address.
  553. ;----------------------------------------------------------------
  554. ;
  555. xyi$lcd:
  556.     xthl            ; HL -> string, old hl in stack
  557.     xchg            ; now DE --> string
  558.     call    setxy        ; set it up
  559.     xchg            ; now hl --> string start again
  560.     call    print
  561.     xthl            ; hl = original value, stack = return address
  562.     ret
  563. ;
  564. ;----------------------------------------------------------------
  565. ; Print the string --> by DE. Use the two bytes at the start of it
  566. ; as a screen address.
  567. ;----------------------------------------------------------------
  568. ;
  569. xyp$lcd:
  570.     push    h
  571.     call    setxy            ; set up screen
  572.     xchg                ; now hl --> string start
  573.     call    print
  574.     xchg                ; Restore DE --> past end of string
  575.     pop    h
  576.     ret
  577. ;
  578. ;       ---- Utility to print a string till a $. ----
  579. ; On return HL -> to next byte after the string (code maybe)
  580. ;
  581. print:
  582.     push    psw
  583.     inx    h
  584.     inx    h        ; skip over cursor address
  585. print2:
  586.     mov    a,m
  587.     inx    h        ; Point to next character
  588.     ora    a        ; null is allowed to end a string
  589.     jz    print3
  590.     cpi    '$'        ; End of string ?
  591.     jz    print3
  592.     call    put$lcd        ; Print the character
  593.     jr    print2
  594. print3:
  595.     pop    psw
  596.     ret
  597. ;
  598. ;----------------------------------------------------------------
  599. ; Set the cursor up according to two bytes in ram which contain
  600. ; the X and Y addresses in them. The bytes --> by DE.
  601. ;----------------------------------------------------------------
  602. ;
  603. setxy:
  604.     push    d            ; save 
  605.     push    h
  606.     xchg                ; HL --> bytes
  607.     mov    d,m            ; load X value
  608.     inx    h
  609.     mov    e,m
  610.     call    cur$lcd            ; Set it up
  611.     pop    h            ; restore all now
  612.     pop    d
  613.     ret
  614. ;
  615. ;
  616. ;----------------------------------------------------------------
  617. ;          Print string till null or $
  618. ;----------------------------------------------------------------
  619. ;
  620. str$lcd:
  621.     push    psw
  622. str$loop:
  623.     call    clrwdt
  624.     ldax    d
  625.     cpi    '$'        ; $ = end
  626.     jrz    str$end
  627.     ora    a        ; 00 = end
  628.     jrz    str$end
  629.     call    put$lcd        ; Send
  630.     inx    d        ; -> next
  631.     jr    str$loop
  632. ;
  633. ;
  634. str$end:
  635.     pop    psw
  636.     ret
  637. ;
  638. ;    ----oooo----
  639. ;
  640.     dseg
  641. ;
  642. lcd$cmd: ds    1        ; Command to write to LCD
  643. ;
  644. ;
  645. lcd$x:    ds    1
  646. lcd$y:    ds    1
  647.     end
  648. ;
  649. ; -- End of module --
  650. ;
  651.