460 NOTES on SERIAL INTERFACE
1. RS232C Serial Protocol (25 Signal lines)
DTE DCE
------ ---------
Pin 2 <------ Rx <------ 2
3 ======> Tx ====> 3
4 ======> RTS ====> 4
5 <------ CTS <------ 5
6 <------ DSR <------ 6
7 -------- Ground ------- 7
8 <------ DCD <------ 8
20 ======> DTR ====> 20
*****************************************
Protocol Timing Sequence
DTE DCE
--------- ----------
(1). DTR ========>
<------- DSR (2)
<------- DCD (8)
(3). RTS ========>
<------- CTS (4)
(5). Send data ........> while (DSR, DCD, CTS)
Receive data <------- send data while DTR.
********************************************
2. Serial Data:
Space Space
--------- -------------
| 7 6 5 4 3 2 1 0 |
|---|---.---.---.---.---.---.---.---.|---|
start|< --- 8 data bits -------------> Stop
bit bit
Bits timing is controlled by a (local) clock, which determines the
Baud rate = number of signal level changes per second; 9600, 19200, etc.
With binary signals, baud = bits/sec.
ASCII code = 7 bits ===> may use a Even/Parity bit at bit 7.
3. PC Serial Ports:
COM1: 3f8-3ff, COM2: 2f8-2ff
IRQ : 4 3
COM1; 3f8 Data register : Txbuf,Rxbuf
3f9 division#, InterruptEnable
3fa InterruptID
3fb LineControl
3fc ModemControl
3fd LineStatus
3fe ModemStatus
3fB: LineControl
7 6 5 4 3 2 1 0 word bits
---->00 = 5 01= 6, 10 = 7, 11 = 8
2 ----> number of stop bits 0 = one, 1=two
3 ------> parity enable
4 --------> 0 = odd, 1 = even parity
5 -----------> stick parity
6 ---------------> set break
7 ------------------> divisor latch access bit:
1 to use 3f9,3f8 as divisor
e.g. 3f9,3f8 = 12 ===> 9800 bauds.
3fD: line Status
7 6 5 4 3 2 1 0
--> Rxbuf full (data char ready)
1 ---> ovrrun error
2 ------> parity error
3 ---------> frame error
4 ------------> break interrupt
5 ---------------> TxReg empty (may write another char)
6-------------------> TxShiftReg empty
7 ---------------------> always 0
3fA: InterruptId
7 6 5 4 3 2 1 0
0 ----> 0 if interrupt pending
2, 1 ------> Interrupt ID bits
|<-all 0 -->|
3f9: interrupt enable
7 6 5 4 3 2 1 0
0 ----> Rx enable
1 -------> Tx enable
2 ----------> Line status interrupt
3 -------------> Modem status changed
7, 6, 5, 4 ---------------> all 0.
3fC: Modem control
7 6 5 4 3 2 1 0
0 ----> DTR
1 -------> RTS
1 -------------> enable hardware interrupts
----------------------------> ignore these bits
3fE: Modem Status
7 6 5 4 3 2 1 0
4 -----------------> CTS
5 --------------------> DSR
6 -----------------------> Ring Indicator
7 --------------------------> receive line detect
**********************************************************************
PC's Serial Ports are DTE's by default. As such, they are intended to connect
to and control DCE's such as modems, serial printers, etc.
We are going to connect a TVI serial terminal to a PC's COM1 port.
The TVI terminal is a DTE, so is the PC's COM1 port. This poses a problem
since we cannot connect two DTE's directly; one must be a DCE, or at least
each DTE thinks the other side is a DCE.
There are two possible ways to do this:
(1). Change one of them to DCE. ===> The TVI terminal cannot be changed.
So we must change the COM port of the PC to DCE. Then, we may use
ordinary DTE to DCE cable, which is wired striaght-through.
(2). Fool both DTE to think the other side is a DCE. ==> cross some wires
in the cable. The simplest fooling, which requires only 3 wires,
is shown below. Two DTE's connected this way don't even know whether
the other side is there.
Rx 2 <--- 3 ----> 2
Tx 3 <--- 2 ----> 3
RTS 4 4
CTS 5 <-- | | ----> 5
DSR 6 <---| | ----> 6
DCD 8 <---| | 8
DTR 20 ----> <------ 20
QUESTION:
Show how to use a 4-wire cable to connect two DTE's such that either side
can break up the connection, e.g. stop the other party from sending data.
===============================================================================
The COM1 Serial Port is at the I/O address 0x3F8 to 0x3FF:
1. Serial Port Initialization:
---------------------------------------------------
Port I/O requires reading from/writing to the Port addresses, each of which
is an 8-bit register. The following utility functions may be called from C:
char c;
c = in_byte(PORT) & 0x7F; /* read a byte from PORT */
out_byte(PORT, c); /* write a byte to PORT */
---------------------------------------------------
Initialization Values to COM1 Port, in the order as shown:
0x80 to 3FB: ===> bit#7 = 1 ===> Use 3F9,3F8 as divisor
0x00 to 3F9 ===> 0 value
0x0C to 3F8 ===> divisor = 12 ==> 9600 baud
0x03 to 3FB ===> line control = 0001 1010 ==> EvenParity,7_bit data
0000 0011 ==> NoParity, 8_bit data
0x0B to 3FC ===> Modem control= 0000 1011
IRQ4,RTS,DTR on
0x01 to 3F9 ===> InterruptControl = 0000 0001 ==> Tx off, Rx on.
0000 0011 ==> Tx on, Rx on
2. Set Interrupt Vector for COM1, which uses IRQ4:
IRQ4 is fed to a 8259 InterruptEncoder chip, which is programmed to generate
vector# = 8 + IRQ#. ===> An IRQ4 interrupt to the CPU is the same as INT 12
(decimal). ===> Fix vector 12 contents to point at the handler routine,
which can be installed by the INTH macro (in ts.s) as
_sinth: INTH(shandler)
/*****************************************************************
3. Implement the shandler() function such that
(a). it first determines which type of interrupt has occurred:
The types of interrupts can be found in
3FA: InterruptID Register: bits 2 1 0 More Info in
---------- --------------
1 1 0 : errors LSR 3FD
1 0 0 : Rx
0 1 0 : Tx
1 1 0 : ModemStatusChanged
3FD: Line Status Register:
7 6 5 4 3 2 1 0
0 ---> RxBufFull ===> read char from 3F8.
5 -------------------> TxBufEmpty ==> may write char to 3F8.
// Serial interrupt handler in C, called from assembly entry point
int shandler()
{
int IntID, LineStatus, ModemStatus, intType;
IntID = in_byte(0x3FA); /* read IntID Reg */
LineStatus = in_byte(0x3FD);
ModemStatus = in_byte(0x3FE);
intType = IntID & 7; /* mask in lowest 3 bits */
switch(int_type){
case 6 : do_errors(); break;
case 4 : do_rx(); break;
case 2 : do_tx(); break;
case 0 : do_Modem(); break;
}
out_byte(0x20, 0x20); /* re-enable the 8259 Int. Controller */
}
-------------------------------------------------------------------------------
4. For simplicity, we shall ignore the interrupts due to error and
ModemStatusChanges. So the problem becomes "how to implment
do_rx() and do_tx()?".
------------------------------------------------------------------------------