From: gardner@iccgcc.decnet.ab.com
Newsgroups: comp.os.msdos.programmer,comp.sys.ibm.pc.programmer
Subject: H E L P!!! Serial Communications Blues... (UART).
Date: 19 Nov 92 14:33:45 EST

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Hello,
;
;I was torn about whether to ZOO and UUENCODE the following little program, 
;but I really need help and didn't want to proclude anyone from assisting by
;requiring special software tools.  So, to those of you who are upset by my
;loading a 5K file with this message, I apologize.
;
;Now, for the question...
;
; I am teaching myself about the 8250 UART and am having problems doing
; somthing that "appears" to be very easy...  All I want to do is create
; a TSR (no problem) that is kicked every time a byte arrives in COM2.
; The interrupt service routine that is invoked by the 0BH (COM2) vector
; will retrieve the byte from the RECEIVER REGISTER and display it directly 
; to video memory (I've implemented the video code but haven't tested it).
; 
; The program that follows is my attempt at doing this.  When I loaded this
; TSR and ran a separate program to send a byte to COM2.  It appears that 
; the UART knows a byte has arrived and raises the RECEIVED DATA INTERRUPT.
; However, the PIC never generates an interrupt to my COM2 isr...
;
; W H Y ?!?!?!?!?!?!?!?!?!?!
;
; The separate program that sends data to COM2 simply OUT's the byte to
; the COM2 transmit register (2F8H) and waits 10 seconds and then sends
; another.
;
; I've compared what I am doing with several programs that are published
; in books...  I must be missing something very simple...  Any ideas?
;
; I'd appreciate any help that you may offer...  Frankly, this has been
; driving me nuts!
;
; Thanks,
;
;       Mike Gardner
;
; P.S. I wrote this using Turbo Assembler.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

title COM2 TSR Program
%PAGESIZE 60,132
ideal

;*****************************************************************************
; AUTHOR:      Mike Gardner
; CREATED:     19-NOV-1992
;*****************************************************************************

; Various boolean values...
FALSE          equ     0
OFF            equ     0
ON             equ     1
TRUE           equ     1

; The COM port address
COM              =      2F8H
TXR              =      COM+0
RXR              =      COM+0
DLL              =      COM+0
DLH              =      COM+1
IER              =      COM+1
IIR              =      COM+2
LCR              =      COM+3
MCR              =      COM+4
LSR              =      COM+5
MSR              =      COM+6

; The PIC port address
PIC_CONTROL     equ     20H
PIC_MASK        equ     21H
END_OF_INTERRUPT equ    20H

; The COM communication parameters
C9600BAUD_MSB   equ     0CH
C9600BAUD_LSB   equ     00H
C8_1_NO         equ     03H
C7_1_NO         equ     02H

; The various UART int sources
MODEM_STATUS    equ     0
TX_REG_EMPTY    equ     2
RX_DATA_READY   equ     4
RLINE_STATUS    equ     6

macro IO_DELAY n
        rept n
        local IO_DELAY_TARGET
        jmp short IO_DELAY_TARGET
IO_DELAY_TARGET:
        endm
endm

macro OUTCH ch
        ASSUME ES:VIDEO_SEGMENT
        push    es
        push    ax
        mov     ax, VIDEO_SEGMENT
        mov     es, ax
        pop     ax
        mov     [cmd], ch
        mov     [attr], 7H
        ASSUME ES:VECTORS_SEGMENT
        pop     es
endm

; The video segment...  It assumes VGA/CGA.
SEGMENT VIDEO_SEGMENT AT 0H
    ORG 0B800H
    cmd db ?
    attr db ?
ENDS

; A segment to access the interrupt table vector entry
SEGMENT VECTORS_SEGMENT AT 0H
    ORG 0BH * 4         ; COM2 communications interrupt vector
    int0BOff            dw      ?
    int0BSeg            dw      ?
ENDS


SEGMENT CODE_SEGMENT
        ASSUME CS:CODE_SEGMENT, DS:CODE_SEGMENT, ES:VECTORS_SEGMENT
        ORG     100H

START:  
        ; Initialize and launch the tsr...
        jmp     LAUNCH

       ; Original COM2 interrupt vector.
       label oldint0B dword
       oldint0BOff    dw  0
       oldint0BSeg    dw  0

       ; The received byte
       theChar        db  0

; The COM2 isr...
proc int0Bisr near
        push    ax
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        push    bp
        push    ds
        push    es

        ; Set up my data segment.
        push    cs
        pop     ds

	; See if there are any interrupts pending in the IIR.  
	; I am only really interested (and have only enabled)
	; the received data interrupt.

@@ANY_INTS_PENDING:
        mov     dx, IIR
        in      al, dx  ; See if any interrupts have arrived in IIR
        mov     cl, al
        test    al, 1
        jnz      @@EXIT_SERIAL_INT

        ; Read and place the character into the buffer
        IO_DELAY 2
        mov     dx, RXR
        in      al, dx
        mov     ah, 0

	; The real version will do buffering...  For now
	; just store the byte...
	mov	[theChar], al

        ; And display it.
        OUTCH al

        jmp     @@ANY_INTS_PENDING

@@EXIT_SERIAL_INT:

	; Inform the PIC that we are done with the COM interrupt
        mov     dx, 20H
        mov     al, 20H
        out     dx, al

        pop     es
        pop     ds
        pop     bp
        pop     di
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax

        iret
endp


;*****************************************************************************
LAUNCH:
        jmp START_LAUNCH

       ; Disposable data

       ; Our startup message
        label ABMsg  byte
        db  13, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 7, 7, 7, 7, 7
        db  10, 13, "              *******************************************"
        db  10, 13, "              *           A TEST OF A COM2 TSR          *"
        db  10, 13, "              *                Version 1.00             *"
        db  10, 13, "              *******************************************"
        db  10, 13, 10, 10, 10, 10, 10, 10, '$'

START_LAUNCH:
        push    cs
        pop     ds
        mov     ax, VECTORS_SEGMENT
        mov     es, ax

    ; lets say hello
    lea        dx,[ABMsg]
    mov        ah,9
    int        21h
OUTCH 'Z'
    cli

    ; Get the original COM2 vector    
    mov       ax,[int0BOff]
    mov       [oldint0BOff],ax
    mov       ax,[int0BSeg]
    mov       [oldint0BSeg],ax

    ; lets set our new COM2 vector
    lea       ax,[int0Bisr]
    mov       [int0BOff],ax
    mov       [int0BSeg],cs


    ; Initialize the COM port
    mov al, 80H
    mov dx, LCR
    out dx,al   ; Turn on DLAB to set the baud rate

    IO_DELAY 3
    mov dx, DLL
    mov al, C9600BAUD_MSB
    out dx,al
    IO_DELAY 3
    mov dx, DLH
    mov al, C9600BAUD_LSB
    out dx,al   ; Set the baud rate to 9600

    IO_DELAY 3
    mov dx, LCR
    mov al, C8_1_NO
    out dx, al  ; Set the port to 8 bits, 1 stop, no parity

    IO_DELAY 3
    in  al, dx
    and al, 7FH
    IO_DELAY 3
    out dx, al  ; Turn off the DLAB ... Done setting baud rate.

    ; Enable receiver interrupts from the COM port, DTR, RTS
    IO_DELAY 3
    mov dx, MCR
    mov al, 0BH
    out dx, al  ; Turn on OUT2, DTR, RTS to enable communication interrupts

    IO_DELAY 3
    mov dx, IER
    mov al, 01H
    out dx, al  ; Turn on the received data interrupt

    ; Read the receiver register to make sure any garbage is removed.
    IO_DELAY 3
    mov dx, RXR
    in al, dx

    ; Enable the PIC to generate COM interrupt
    IO_DELAY 3
    mov dx, PIC_MASK
    in al, dx
    and al, 0F7H
    IO_DELAY 3
    out dx, al  ; Permit the generation of COM interrupt

    sti


    ; Go tsr...  Jettison everything from the LAUNCH label to the end...
    mov         dx, offset LAUNCH
    int         27H

ENDS

END START
Newsgroups: comp.os.msdos.programmer,comp.os.ms-windows.programmer.misc