i am trying to adapt it for windows, then, i will be able to display 64 chars on this lpt lcd mount.
the code works under real mode, and v86 (win98 console)
but it fails in win32 application.
i do that:
testlptdrv:
dd lpt.frame,.buffer
.buffer:
db "0123456789abcdef"
db "0123456789abcdef"
db "0123456789abcdef"
db "0123456789abcdef"
...
windows blaabla code
invoke something
...
call dword[testlptdrv]
...
invoke something_else
and it crashes because of direct access to port 3D8h
lptlcd:
.call=0
.txt=4
push esi
mov esi,[esi+.txt]
call lcd.frame
pop esi
ret
;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;
;16 apparent chars, 24 virtual chars
;frame: rb 16*4+8
;message: ;1st zone
;.0: db 'INTO THE WILD CP' ; xxxxxxxxxxxxxxxx second zone
;.1: db 'U, THE SIGNAL EV' ; third zone xxxxxxxxxxxxxxxx
;.2: db 'OLVE AND TRY TO ' ; xxxxxxxxxxxxxxx fourth zone
;.3: db 'RESOLVE ........' ; pad xxxxxxxxxxxxxxxx pad
;.pad: db ' ' ; xxxxxxxx xxxxxxxx
;.end:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;---------------------------------------------------------------------------------
;LPT connection
;pin 1 = E = .ctrl bit0, 1 inverted
;pin 14 = R/W = .ctrl bit1, 2 inverted
;pin 16 = RS = .ctrl bit2, 4
;pins 2 to 9 = data = .data
;
;LCD connection
;pin 1 = gnd
;pin 2 = +5V
;pin 3 = contrast
;pin 4 = Register Select
;pin 5 = Read /Write
;pin 6 = Enable
;pins 7 to 14 = data
;---------------------------------------------------------------------------------
macro delay .t
{
mov ecx,.t
local .a
.a:
dec ecx
jne .a
}
delaylong:
delay 500'000
ret
delayshort:
delay 7'000
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lcdmsg:
.0=0
.1=10h
.2=20h
.3=30h
.pad=40h
.end=48h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lcd:
.lpt=378h
.data=.lpt+0
.stat=.lpt+1
.ctrl=.lpt+2
.e=1
.rw=2
.rs=4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.frame:
;si=msg 64 bytes
push esi
call lcd.init
call lcd.refresh
pop esi
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.refresh:
push eax ebx esi
xor ebx,ebx;lcdmsg.0 ;start at first char, i first zone
@@:
mov ah,[esi+ebx] ;load char
call .putc ;putchar in lcd
inc ebx ;next char
cmp ebx,lcdmsg.1;message.1 ;next zone?
jne @b
mov ebx,lcdmsg.2;message.2 ;next zone, third zone
@@:
mov ah,[esi+ebx]
call .putc
inc ebx
cmp ebx,lcdmsg.3;message.3
jne @b
mov ebx,lcdmsg.pad;message.pad ;first virtual line padding
@@:
mov ah,0
call .putc
inc ebx
cmp ebx,lcdmsg.end;message.end
jne @b
mov ebx,lcdmsg.1;message.1
@@:
mov ah,[esi+ebx]
call .putc
inc ebx
cmp ebx,lcdmsg.2;message.2
jne @b
mov ebx,lcdmsg.3;message.3
@@:
mov ah,[esi+ebx]
call .putc
inc ebx
cmp ebx,lcdmsg.pad;message.pad ;second virtual line padding
jne @b
@@:
mov ah,0
call .putc
inc ebx
cmp ebx,lcdmsg.end;message.end
jne @b
pop esi ebx eax
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.putc:
push eax ebx ecx edx
call .writedatacheck
pop edx ecx ebx eax
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.init:
push esi
mov ah,38h ;function set
call .writeinstnocheck
call delaylong
mov ah,38h ;function set
call .writeinstnocheck
call delaylong
mov ah,0ch ;display on
call .writeinstcheck
call delaylong
call .clear
mov ah,6 ;entry mode set
call .writeinstcheck
call delaylong
pop esi
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.p1:
mov edx,.data
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.p2:
mov edx,.stat
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.p3:
mov edx,.ctrl
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.clear:
mov ah,1
call .writeinstcheck
call delayshort
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.writedatacheck:
call .busycheck
.writedatanocheck:
call .dr
call .send
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.writeinstcheck:
call .busycheck
.writeinstnocheck:
call .ir
call .send
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.send:
call .wr
call .en
call .p1
mov al,ah
out dx,al
call delayshort
call .dis
call .p1
mov al,0ffh
out dx,al
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.busycheck:
call .ir
call .rd
call .en
call .busy
call .dis
ret
.busy:
call .p1
@@:
in al,dx
and al,80h
je @b
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.dr:
;.datareg:
call .p3
in al,dx
or al,.rs
out dx,al
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.ir:
;.instreg:
call .p3
in al,dx
and al,not .rs
out dx,al
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.dis:
;.disable:
call .p3
in al,dx
or al,.e
out dx,al
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.en:
;.enable:
call .p3
in al,dx
and al,not .e
out dx,al
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.wr:
;.write:
call .p3
in al,dx
or al,.rw
out dx,al
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.rd:
;.read:
call .p3
in al,dx
and al,not .rw
out dx,al
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
it works fine under dos and any real mode interface. but now, it should work in protected mode os.
windows and linux required for fun application.
i test it on a pIII 800Mhz, lpt connected to lcd directly, plus a 5Vdc power to supply energy to the lcd panel.
as you can see, the cpu use is high, it is due to the lcd driver.
the future of this driver is to work inside the timer interrupt, or better, be buffered by a MCU between lpt and lcd.
one solution for the moment would be to call the lcd driver only 2 or 3 times per second, to avoid the saturation of the cpu during delay loops.
the box is made with bristol paper
if it continues to fail, i will make a dos-like command line to do the job. :p