I've connected the 16550 much like this example with some chip selection differences (CS0 and CS1 tied to +5v, and controlled by /CS2). The input is fed directly to the 16550's serial in (SIN) pin through a CP2101 USB<->Serial adapter, and the output (SOUT) fed directly back to the CP2101. For some reason, I'm not getting predictable results...in fact, the input is correct but the output is...weird.
I've attached two images showing a logic analyzer capture of the serial lines. In one, it's clear that the letter 'a' was typed, but the output was TWO 'a' characters. Sometimes they appear as 'aa', others as 'Aa'. It gets weirder with other characters such as 'U', which outputs a 0xFF plus the original 'U' character. I've attached the captures as images to this post.
To me this smells like something to do with flow control, but I've gone over my code many times and I can't pinpoint the problem. I'm hoping someone here might have had the same experience, or can immediately spot what is happening.
I've probed the RD and WR logic, which works just fine with the attached SRAM, and I can verify that I am receiving the character correctly as well as transmitting the same single character to the 16550. Something in the chip is wonky. I've tried three different 16550s, and each display the same issue. It's not completely unheard of to get a bad batch of chips though. I've also as a last resort attempted to set up a small delay between character transmits, to no avail.
Anyway, any pointers would be very well received. I'm open to trying anything. My code (using ca65) is below.
Code: Select all
.setcpu "65816"
.smart on
UART_RXTX = $df10 ; DLAB=0
UART_IER = $df11 ; DLAB=0
UART_DLL = $df10 ; divisor latch low, DLAB=1
UART_DLH = $df11 ; divisor latch high, DLAB=1
UART_IIR = $df12 ; Irq Ident. Reg., read only
UART_FCR = $df12 ; FIFO Ctrl Reg., write only
UART_LCR = $df13 ; Line Ctrl Reg
UART_MCR = $df14 ; Modem Ctrl Reg
UART_LSR = $df15 ; Line Status Reg
UART_MSR = $df16 ; Modem Status Reg
UART_SCR = $df17 ; 'scratchpad', i.e. unused
;;;
;;; macros
;;;
.macro longa
rep #%00100000
.endmacro
.macro longr
rep #%00110000
.endmacro
.macro longx
rep #%00010000
.endmacro
.macro shorta
sep #%00100000
.endmacro
.macro shortr
sep #%00110000
.endmacro
.macro shortx
sep #%00010000
.endmacro
.segment "CODE"
.proc main: near
cld ; clear decimal mode
sei ; no interrrupts
clc
xce ; go to native mode
shorta
longx
.a8
.i16
ldx #$01ff
txs ; reset stack pointer
; ordered according to Intel's docs
lda #%00000111
sta UART_FCR ; Enable and clear FIFOs, trigger at 1 byte
lda #%00000011
sta UART_LCR ; 8N1
stz UART_IER ; no interrupts (polled mode)
ora #%10000000
sta UART_LCR ; turn on DLAB flag to set baud rate
lda #3 ; divisior of 3 ($03) is 38400 with 1.8432 MHz xtal
sta UART_DLL
lda #0
sta UART_DLH
lda UART_LCR
and #%01111111
sta UART_LCR ; turn off DLAB flag
stz UART_MCR ; reset DTR, RTS
; input
in_loop:
lda UART_LSR
bit #%00000001 ; bit 0 set = data available
beq in_loop
lda UART_RXTX
; output
pha
out_loop:
lda UART_LSR
bit #%00100000 ; bit 5 set = tx ready
beq out_loop
pla
sta UART_RXTX
ldx #$80
break_loop:
dex
bne break_loop
jmp in_loop
.endproc