6551 RS232 port circuit.
The connector on the top left of the diagram is from my own 6502 boards (see sbc project) and is as it is for two reasons. It’s easy to wire on a stripboard layout and I have a lot of 26 way ribbon, headers and plugs. All the signals are directly from the 6502 except /SEL0 and /SEL1 which are used to select the block $F0xx with /SEL0 = 0 and /SEL1 = 1. The 10 pin IDC plug is to allow use of a standard PC type COM port plug. This was done because it’s easier to wire on stripboard and allows the choice of a 9 or 25 pin connector.
The two capacitors are low ESR electrolytics and are placed near the 6551 and near the MAX232. If you don’t have this type to hand you can use standard electrolytics with some low value ceramic capacitor, say 0.1uF, in parallel.
The 6551 occupies the 256 byte block $F0xx and, as the 6502 this was made for is clocked at 1.832MHz, is clocked by the phase 2 clock. If a different processor clock is being used then the 6551 can be clocked by a 1.832MHz oscillator as shown in the alternate clock diagram. Two jumpers are used to select which interrupt the 6551 is tied to. If interrupts are not required then both jumpers can be left open.
The MAX232 performs level translation between the TTL levels of the 6551 and the bipolar RS232 levels. Only the signals for a 5 wire interface are implemented with DCD and DSR being tied low on the 6551 to allow continuous operation.
The GAL16V8A is optional and is used purely to generate the chip select. This was not fitted to the original because it was not necessary to fully decode this part. For anyone interested the equations for this chip are in acia_01.pld and can be compiled with WinCUPL. The fuse file, acia_01.jed is also included.
The finished board
To use the 6551 as a polled device the software is fairly simple. First the 6551 must be reset and the baud rate, character length and parity must be set.
; set the 6551 register addresses A_rxd = $F000 ; ACIA receive data port A_txd = $F000 ; ACIA transmit data port A_sts = $F001 ; ACIA status port A_res = $F001 ; ACIA reset port A_cmd = $F002 ; ACIA command port A_ctl = $F003 ; ACIA control port ; initialise 6551 ACIA STA A_res ; soft reset (value not important) LDA #$0B ; set specific modes and functions ; no parity, no echo, no Tx interrupt ; no Rx interrupt, enable Tx/Rx STA A_cmd ; save to command register ; all the following 8-N-1 with the baud rate ; generator selected. uncomment the line with ; the required baud rate. ; LDA #$1A ; 8-N-1, 2400 baud ; LDA #$1C ; 8-N-1, 4800 baud LDA #$1E ; 8-N-1, 9600 baud ; LDA #$1F ; 8-N-1, 19200 baud STA A_ctl ; set control register
To send a character all we need do is wait for the Tx buffer to empty then write the byte.
; wait for ACIA and Tx byte PHA ; save A LAB_WAIT_Tx LDA A_sts ; get status byte AND #$10 ; mask transmit buffer status flag BEQ LAB_WAIT_Tx ; loop if tx buffer full PLA ; restore A STA A_txd ; save byte to ACIA data port
To receive a character we need to wait for the Rx buffer to fill then read the byte.
; wait for ACIA and Rx byte LAB_WAIT_Rx LDA A_sts ; get ACIA status AND #$08 ; mask rx buffer status flag BEQ LAB_WAIT_Rx ; loop if rx buffer empty LDA A_rxd ; get byte from ACIA data port