Products > Programming
x86 assembly, uart-16450, simple putch
DiTBho:
--- Code: ---; Serial Port 16450 IO
; ====================
;base DLAB access Abbreviation Register Nam
; +0 0 Write THR ** Transmitter Holding Buffer
; +0 0 Read RBR ** Receiver Buffer
; +0 1 Read/Write DLL ** Divisor Latch Low Byte
; +1 1 Read/Write DLM ** Divisor Latch High Byte
; +1 0 Read/Write IER Interrupt Enable Registe
; +2 x Read IIR Interrupt Identification Register
; +3 x Read/Write LCR ** Line Control Register
; +4 x Read/Write MCR ** Modem Control Register
; +5 x Read LSR Line Status Register
; +6 x Read MSR Modem Status Register
; baud rate setting
; latch low byte
; 0x00 0x01 = 115200 bps
; 0x00 0x02 = 56700 bps
; 0x00 0x03 = 38400 bps
; 0x00 0x06 = 19200 bps
; 0x00 0x0C = 9600 bps
; 0x00 0x18 = 4800 bps
; 0x00 0x30 = 2400 bps
serial_base equ (0x3f8)
serial_cmd0 equ (serial_base + 0)
serial_cmd1 equ (serial_base + 1)
serial_cmd2 equ (serial_base + 2)
serial_cmd3 equ (serial_base + 3)
serial_cmd4 equ (serial_base + 4)
serial_status equ (serial_base + 5)
console_init:
push dx
push ax
; Settings
mov dx, serial_cmd3
mov al, 0x80 ; DLAB ON
out dx, al ; get it on its way.
mov dx, serial_cmd0 ; 115200 bps
mov al, 0x01 ; baud rate - Divisor Latch low byte
out dx, al ; get it on its way.
mov dx, serial_cmd1
mov al, 0x00 ; baud rate - divisor latch high byte
out dx, al ; get it on its way.
mov dx, serial_cmd3
mov al, 0x03 ; 8 bits, No parity, 1 stop bit
out dx, al ; get it on its way.
mov dx, serial_cmd2
mov al, 0xC7 ; FIFO control register
out dx, al ; get it on its way.
mov dx, serial_cmd4
mov al, 0x0B ; turn on DTR, RTS, and OUT2
out dx, al ; get it on its way.
; clear the Divisor Latch Access Bit
; in order to use the Transmitter Holding Register
mov dx, serial_cmd3 ; Line Control Register
in al, dx
and al, 0x7f ; 0111_1111b, Set DLAB=0, DLAP is bit7
out dx, al
pop ax
pop dx
ret
; reg al: received character
ch_get:
; to be implemented
mov al, 0x00
ret
; reg al: char to transmit
ch_put:
push dx
push ax
push cx
ch_put_wait:
mov dx, serial_status ; Line Status Register
mov cx, ax
in al, dx
test cx, 0x20 ; 0010_0000b, use bit 5 to see if THR is empty
jz ch_put_wait
mov ax, cx
mov dx, serial_cmd0 ; Transmitter Holding Register
out dx, al
pop cx
pop ax
pop dx
ret
--- End code ---
(serial.s)
--- Code: --- cli ; disable interrupts
mov bp, 0x9000
mov sp, bp
call console_init
main:
mov al, 'h'
call ch_put
mov al, 'a'
call ch_put
mov al, 'l'
call ch_put
mov al, 'l'
call ch_put
mov al, 'o'
call ch_put
jmp main
--- End code ---
(main.s)
do you see any error with this simple code?
The serial doesn't correctly show chars :o :o :o
edit:
nasm syntax
Andy Watson:
I'm not familiar with the 16450, however, one common problem is not waiting for the character flag of the transmit register. Once the character is put into the Tx register the tx-full flag will be set, BUT usually this is a state controlled operation that is operating at the speed of the UART clock. Hence it is possible to put a character into tx reg, return from the subroutine, and then re-enter with the next character before the flag is set. The solution, is to use interupts or to wait for the flag to be set after putting the character in the Tx reg. If using the non-interrupt version, you might want to bracket the tx insertion and subsequent wait loop with disabled interupts - so that you don't miss the flag setting completely.
DiTBho:
--- Code: ---ch_put_wait:
mov dx, serial_status ; Line Status Register
mov cx, ax
in al, dx
test cx, 0x20 ; 0010_0000b, use bit 5 to see if THR is empty
jz ch_put_wait
--- End code ---
this part? it waits and loops until the status register reports "THR is empty"
Andy Watson:
You still need the empty check.
Consider what happens when you have multiple characters to transmit. Your present code is:
Loop until Tx empty - fill Tx 1 - go away and fetch next character - Loop until Tx empty - fill Tx 2 - etc..
The problem is that the setting of the UART flags is asynchronos and can be much slower than the "go away and fetch next charater" such that when the code returns with the second character it can find the Tx is still being flagged as empty.
The non-interrupt solution is:
Loop until Tx empty - (disable interrupts) - fill Tx 1 - Loop until Tx full - (re-eneable interrupts) - go away to fetch nect character - etc..
You need the fill tx and loop until full to be atomic, hence the disabling/enabling of interrupts - if they are being used.
DiTBho:
but interrupts are always disabled in that code.
Navigation
[0] Message Index
[#] Next page
Go to full version