Interfaţa serie

1. Introducere

Una din componentele universale ale unui calculator este interfaţa serială. La această interfaţă se pot conecta un număr mare de echipamente ce sunt şi foarte utilizate: mouse, modem, cititor de cod de bare, plotter, imprimantă serială, un alt calculator, etc. În ciuda utilizării pe scară larga a echipamentelor periferice seriale, puţine persoane cunosc implementarea portului serial sau pot dezvolta aplicaţii hard şi soft bazate pe această interfaţă.

Prin interfaţa serială se înţelege ansamblul circuitelor şi programelor de bază care asigură comunicaţia între unitatea centrală (procesor) şi un dispozitiv periferic care transferă informaţia bit după bit.

Interfaţa serie se foloseşte atunci când distanţa de comunicaţie este mare (> 1.50 m), deoarece pe distanţe mari riscul de perturbare a informaţiei este crescut şi, cu cât numărul de linii este mai mic, cu atât posibilitatea de perturbare scade.

Vitezele de transfer pe linie au fost standardizate, există anumite trepte de viteză bine determinate, despre care vom discuta ceva mai târziu. Unitatea de măsură a vitezei de transfer pe liniile seriale este 1 bit pe secundă. Există o diferenţă între unităţile de măsură bit pe secundă şi baud: baud înseamnă numărul de schimbări de stare ale liniei pe secundă în timp ce biţi pe secundă reprezintă numărul de biţi de informaţie transferaţi într-o secundă. Diferenţa între cele două unităţi de măsură apare dacă linia de comunicaţie are mai mult de două stări.

2. Implementarea interfetei serie

8250 este un circuit specializat pentru realizarea comunicţiilor seriale. Circuitul este programabil şi suportă doar modul de comunicaţie asincron. Acesta va adăuga biţii de start, biţii de stop şi cei de control al parităţii. Viteza de comunicaţie este programabilă şi este cuprinsă între 50 baud şi 9600 baud. Lungimea cuvântului este şi ea programabilă şi poate fi de 5, 6, 7 sau 8 biţi cu 1, 1 1/2 sau 2 biţi de stop.

Descrierea funcţională a pinilor

Figura 1

CS0, CS1, /CS2 (Chip Select) - când CS0 = CS1 = 1 şi /CS2 = 0, circuitul este selectat. Selectarea circuitului este completă atunci când semnalul de selecţie de la decodificator este însoţit de un semnal /ADS (Address Strobe) activ pe 0. Acesta permite comunicarea între 8250 şi procesor.

DISTR, /DISTR (Data Input Strobe) - dacă semnalele sunt active în timp ce circuitul este selectat are loc citirea informaţiei din registrul de stare sau a unei date din registrul selectat. Numai una din cele două intrări trebuie să fie activă la un moment dat.

DOSTR, /DOSTR (Data Output Strobe) - când unul dintre semnale este activ şi circuitul este selectat procesorul poate înscrie o dată sau un cuvânt de comandă în registrul selectat.

/ADS (Address Strobe)

A0, A1, A2 (Register Select) - intrări pentru selecţia registrelor.

DLAB

A2

A1

A0

Register

0

0

0

0

Receiver Buffer (Read)/ Transmitter Holding Register (Write)

0

0

0

1

Interrupt Enable

x

0

1

0

Interrupt Identification Register (Read Only)

x

0

1

1

Line Control

x

1

0

0

Modem Control

x

1

0

1

Line Status

x

1

1

0

Modem Status

x

1

1

1

None

1

0

0

0

Divisor Latch (Least Significant Byte)

1

0

0

1

Divisor Latch (Most Significant Byte)

Tabelul 1

MR (Master Reset) - intrare de reset. Când este activă şterge toate registrele cu excepţia registrelor de recepţie şi a celor de divizare.

RCLK (Receiver Clock) - intrare de tact pentru recepţie (este 16*rata de transfer).

SIN (Serial Input) - intrare de date de pe linia serială.

/CTS (Clear to Send) - linie de contro în comunicaţia cu modemul.

/DSR (Data Set Ready) - linie de contro în comunicaţia cu modemul.

/RLSD (Received Line Signal Detect) - linie de control în comunicaţia cu modemul.

/RI (Ring Indicator) -

/DTR (Data Terminal Ready) -

/RTS (Request to Send) -

/OUT1, /OUT2 (Output) -

CSOUT (Chip Select Out) - este răspunsul circuitului la o activare a semnalelor CS0, CS1, /CS2. Nu se poate face nici un transfer cu 8250 până când acest semnal nu este activat.

DDIS (Driver Disable) - acest semnal este pus pe 0 când procesorul citeşte date de la circuitul 8250. El poate fi utilizat pentru comanda unui transceiver, dacă există pe magistrala de date între procesor şi 8250.

/BAUDOUT (Baud Out) - semnal de tact pentru transmisie.

INTRPT (Interrupt) - semnal activ pe 1 şi lansează o cerere de întrerupere la procesor când apare unul din următoarele evenimente: eroare la recepţie, dată recepţionată disponibilă, buffer de transmisie gol, modificare stare modem.

SOUT (Serial Output) - linie de transmisie serială de date.

D0-D7 (Data) - linii de conectare la magistrala de date.

XTAL1, XTAL2 (External Clock Input/Output) - intrări pentru semnal de tact extern.

Programarea circuitului 8250

Procesorul poate avea acces la oricare din registrele circuitului 8250.

Registrul de control (Line Control Register)

Figura 2

Biţii 1 şi 0 indică lungimea caracterului transmis:

WLS1

WLS0

Lungimea caracterului

0

0

5 Biţi

0

1

6 Biţi

1

0

7 Biţi

1

1

8 Biţi

Tabelul 2

Bitul 2 indică numărul de biţi de stop:

STB = 0 - 1 bit de stop;

STB = 1 şi lungimea caracterului este de 5 biţi - 1 ˝ biţi de stop;

STB = 1 şi lungimea caracterului este de 6, 7 sau 8 biţi - 2 biţi de stop.

Bitul 3 indică dacă se foloseşte sau nu un bit de paritate în transmisie sau recepţie.

PEN = 0 - nu se foloseşte paritatea;

PEN = 1 - se va genera un bit de paritate când se transmit date sau se va aştepta şi un bit de paritate când se recepţionează date.

Bitul 4 selectează tipul de paritate.

EPS = 0 şi PEN = 1 - paritate impară (un număr impar de 1);

EPS = 1 şi PEN = 1 - paritate pară (număr par de 1).

Bitul 5 - dacă bitul 3 este pe “1” şi bitul 5 este tot pe “1” atunci bitul de paritate este transmis şi este detectat la recepţie ca “0” dacă EPS=1 sau ca şi “1” dacă EPS=0.

Bitul 6 - set break control bit. Când este pe “1”, linia de ieşire serială (SOUT) este forţată pe “0” şi rămâne aşa indiferent de apariţia altor activităţi de tramsmisie. Această stare este dezactivată prin punerea acestui bit pe “0”. Această caracteristică permite procesorului să alerteze un terminal într-un sistem de comunicaţie.

Bitul 7 este bitul de acces la registrul pentru divizarea ratei:

DLAB = 1 - se realizează accesul la registrele de divizare;

DLAB = 0 - se realizează la buffer-ele de recepţie, transmisie şi registrul de validare a întreruperilor.

Registrele de divizare

Generatorul ratei de transfer preia tactul de intrare şi îl împarte cu orice număr cuprins între 1 şi 216 - 1, număr aflat în registrele de divizare. Frecvenţa de ieşire a generatorului este 16x rata.

divisor = (frecvenţa de intrare) / (baud rate x 16)

Numărul cu care se divide tactul este stocat în două registre, care se încarcă în timpul iniţializării, cu valorile corespunzătoare ratei de transfer dorite.

Registrul de stare

Figura 3

Bitul 0 = 1 - s-a recepţionat un caracter şi a fost transferat în buffer-ul de recepţie.

Bitul 1 = 1 - indică faptul că data din buffer-ul de recepţie nu a fost citită de către procesor înaintea recepţionării unui alt caracter. Astfel că acest prim cuvânt a fost pierdut. Bitul OE este pus pe 0 la citirea registrului de stare de către procesor.

Bitul 2 - indică apariţia unei erori de paritate.

Bitul 3 - apariţia unei erori de cadru. Caracterul recepţionat nu are bitul de stop valid. Acest bit este pus pe 1 de fiecare dată când bitul de stop ce urmează după ultimul bit de date sau după bitul de paritate, este 0.

Bitul 4 - indică dacă linia de recepţie este în starea 0 o perioadă de timp mai mare decât timpul necesar transmisiei complete a unui caracter. Înseamnă că transmiţătorul a forţat linia pe 0 (Set Break).

Bitul 5 - indică procesorului că 8250 este pregătit pentru a primi un nou caracter ce trebuie transmis. Acest bit este setat la “1” când un caracter este transferat din buffer-ul de transmisie în registrul de serializare. Bitul este resetat la “0” când procesorul încarcă buffer-ul de transmisie cu un nou caracter.

Bitul 6 - indică faptul că registrul de serializare este gol. Bitul este pus pe “0” odată cu încărcare unui nou caracter din buffer-ul de transmisie.

Registrul de identificare a întreruperii

Figura 4

Modul de lucru al circuitul 8250 cu întreruperile oferă o flexibilitate ridicată şi permite interfaţarea lui cu aproape toate procesoarele cunoscute. Pentru a minimiza încărcarea programului de comunicaţie serială, 8250 realizează o prioritizare a întreruperilor în patru nivele:

- starea liniei de recepţie;

- dată recepţionată;

- registrul de transmisie gol;

- starea modemului.

Când acest registru este citit de către procesor el indică doar cererea de întrerupere cea mai prioritară care este în aşteptare şi numai după ce a fost satisfăcută această cerere el va indica şi celelalte cereri ce aşteaptă dar care au nivel de prioritate mai mic.

Dacă bitul 0 este pe “1” nici o cerere de întrerupere nu este în aşteptare.

Bitul 2

Bitul 1

Bitul 0

Nivel de prioritate

Tipul întreruperii

Sursa întreruperii

Ştergerea întreruperii

0

0

1

-

-

-

-

1

1

0

1

Starea liniei la recepţie

Eroare de ritm

Eroare de paritate

Eroare de cadrare

Break interrupt

Citirea registrului de stare

1

0

0

2

Caracter recepţionat disponibil

Caracter recepţionat disponibil

Citirea buffer-ului de recepţie

0

1

0

3

Buffer de transmisie gol

Buffer de transmisie gol

Citirea IIR sau Scrierea unui nou caracter în buffer-ul de transmisie

0

0

0

4

Stare modem

Clear to Send

Data Set Ready

Ring Indicator

Received Line Signal Detect

Citirea registrului de stare pentru modem

Tabelul 3

Registrul de validare a intreruperilor

Acest registru permite ca cele patru surse de întrerupere să activeze separat linia de cerere de întrerupere INTRPT. Sistemul de întreruperi se poate dezactiva prin resetarea biţilor 3-0 ai acestui registru.

Figura 5

 

3. Detectarea adreselor de bază ale porturilor serie

În mod normal un calculator compatibil PC deţine până la patru interfeţe serie, denumite (în sistemele de operare DOS şi Windows) COM1, COM2, COM3 şi COM4. Fiecare interfaţă serie are alocată câte o zonă de adrese din spaţiul adreselor de porturi şi câte o linie pentru întreruperi. Adresele de bază şi întreruperile alocate, în configuraţia standard, pentru cele patru interfeţe serie sunt prezentate în tabelul 1:

Interfaţa

Adresa de bază

Numărul întreruperii

COM1

0x3F8

IRQ4

COM2

0x2F8

IRQ3

COM3

0x3E8

IRQ4

COM4

0x2E8

IRQ3

Tabelul 4 Porturile serie standard

Aceste adrese, însă, sunt selectabile prin configurarea circuitului specializat pentru periferice, iar la unele calculatoare este posibil ca adresele alocate porturilor interfeţei serie să difere faţă de configuraţia standard.

La iniţializarea sistemului BIOS-ul detectează interfeţele serie prezente şi adresele alocate lor şi sunt salvate în memorie în zona de date BIOS la adresele prezentate în tabelul 5:

Adresa

Conţinut

0000:0400

Adresa de bază pentru COM1

0000:0402

Adresa de bază pentru COM2

0000:0403

Adresa de bază pentru COM3

0000:0406

Adresa de bază pentru COM4

Tabelul 5 Adresele porturilor serie

În cazul în care una dintre interfeţele serie nu este prezentă în sistem, locaţia de memorie corespunzătoare ei va conţine valoarea 0.

Pe baza informaţiilor salvate de BIOS în memorie, programatorul poate determina care dintre interfeţe este prezentă în sistem şi care sunt adresele de bază alocate acestora.

4. Configurarea parametrilor de comunicaţie

Transferul pe liniile seriale se desfăşoară respectând anumiţi parametrii de comunicaţie: rata de transfer, număr de biţi de date, paritate şi număr de biţi de stop. Pentru a se “înţelege”, două aplicaţii sau echipamente ce comunică pe linii serie, trebuie să folosească aceleaşi valori ale parametrilor de comunicaţie. Astfel că, orice aplicaţie ce utilizează interfaţa serie trebuie să configureze parametrii pentru comunicaţia serie cu aceleaşi valori cu care este configurat celălalt partener implicat în comunicaţie.

Configurarea interfeţei serie presupune setarea ratei de transfer, a numărului de biţi de date, a numărului de biţi de stop şi tipul de paritate utilizat. Aceşti parametrii se pot configura prin intermediul registrelor interne circuitului de interfaţă serie.

Pentru setarea ratei de transfer există două registre pe 8 biţi, numite registre de divizare. Generatorul ratei de transfer preia tactul de intrare şi îl împarte cu orice număr cuprins între 1 şi 216 - 1, număr aflat în aceste registre de divizare. Frecvenţa de ieşire a generatorului este 16x rata de transfer.

divizor = (frecvenţa de intrare) / (rata de transfer x 16)

Numărul cu care se divide tactul este stocat în cele două registre de divizare, care se încarcă în timpul iniţializării, cu valorile corespunzătoare ratei de transfer dorite. (Tabelul 3) Frecvenţa de intrare în cazul PC-urilor este 1.8432 MHz, astfel că viteza maximă a interfeţei seriale este 115200 bps.

Viteza (bps)

Rgistrul de divizare mai semnificativ

Registrul de divizare mai puţin semnificativ

50

09h

00h

300

01h

80h

600

00h

C0h

2400

00h

30h

4800

00h

18h

9600

00h

0Ch

19200

00h

06h

38400

00h

03h

57600

00h

02h

115200

00h

01h

Tabelul 6 Divizorii pentru ratele de transfer utilizate

Setarea parametrilor de comunicaţie presupune implementarea următorilor paşi:

5. Programarea prin polling a interfeţei serie

După configurarea interfeţei serie, aceasta poate fi folosită pentru transmisia şi/sau recepţia datelor către/de la dispozitivul conectat la aceasta. Comunicaţia dintre calculator şi echipamentul periferic se poate face în două moduri:

6. Programarea prin întreruperi a interfeţei serie

Cea de-a doua metodă de programare a interfeţei serie presupune folosirea întreruperii alocate interfeţei. Această metodă se pretează în special la aplicaţiile de timp real, cu timpi de răspuns foarte mici. Recomandarea noastră este de a folosi această metodă în toate aplicaţiile interfeţei serie, deoarece este mai rapidă (nu încarcă procesorul cu verificări inutile, evenimentele sunt tratate imediat), este mai flexibilă decât prima metodă şi este o soluţie modulară.

O aplicaţie ce lucrează cu interfaţa serie prin întreruperi trebuie să configureze interfaţa serie şi sistemul pentru a putea utiliza întreruperile iar la terminarea aplicaţiei starea sistemului şi a interfeţei serie trebuie restaurată pe configuraţia dinaintea setării:

Setarea întreruperii interfeţei serie presupune implementarea următorilor paşi:

Dezactivarea întreruperii interfeţei serie necesită implementarea operaţiilor inverse celor prezentate mai sus:

Rutina de tratarea a întreruperii serie poate implementa o parte din atribuţiile aplicaţiei sau poate doar memora într-un buffer caracterele recepţionate. În plus tot în această rutină se poate monitoriza starea interfeţei serie sau se poate face detecţia erorilor. Recomandarea noastră este de a face cât mai puţine operaţii în rutina de tratare a întreruperii şi de a lăsa pe seama aplicaţiei se trateze ceea ce rutina detectează sau monitorizează. Ca şi operaţie necesară orice rutină de tratare a unei întreruperi hardware trebuie, la terminarea ei, să şteargă întreruperea tratată din controller-ul de întreruperi. Acest lucru se face scriind un octet cu valoarea 20H în registrul de comandă al controller-ului (-elor) de întrerupei implicate.

Rutina de tratare a întreruperii interfeţei serie este apelată după fiecare caracter recepţionat (după recepţionarea şi asamblarea fiecărui caracter se generează câte o întrerupere). În rutina de tratare a întreruperii se citeşte caracterul recepţionat din registrul de recepţie al circuitului de interfaţă serie şi se încarcă în buffer-ul de recepţie al aplicaţiei, iar apoi se incrementează indexul buffer-ului de recepţie. Aplicaţia detectează recepţionarea unui caracter verificând dacă indexul buffer-ului de recepţie este mai mare decât zero.

7. Controlul fluxului la comunicaţia serie

Problema care poate apare este datorată diferenţei între viteza cu care sunt transmise caracterele de către transmiţător şi viteza cu care receptorul preia caracterele din buffer-ul de recepţie. Dacă modulul receptor este mai lent sau preia datele din buffer-ul de recepţie (datorită operaţiilor implementate) cu o rată mai mică decât rata cu care datele recepţionate sunt introduse în buffer, atunci buffer-ul de recepţie se poate umple şi se pot pierde o parte din datele recepţionate. Această problemă este mai evidentă la comunicarea prin polling cu interfaţa serie, deoarece este folosit buffer-ul de recepţie implementat în circuitul de interfaţă, având dimensiunea doar de câţiva octeţi.

Soluţia pentru această problemă constă în implementarea unei metode de control al fluxului. Prin aceste metode se oferă posibilitatea receptorului să “anunţe” transmiţătorul că buffer-ul de recepţie este plin şi că trebuie să întrerupă momentan transmisia. Dacă buffer-ul de recepţie se mai goleşte, receptorul poate anunţa transmiţătorul că poate să mai transmită date.

8. Programarea interfeţei serie sub sistemul de operare Windows

Scrierea unei aplicaţii Windows de transfer de date cu un dispozitiv conectat la interfaţa serie se poate realiza la mai multe niveluri:

Funcţiile SDK pentru lucrul cu fişiere (CreateFile, CloseHandle, ReadFile, ReadFileEx, WriteFile şi WriteFileEx) oferă interfaţa de bază pentru deschiderea, utilizarea şi închiderea unei resurse de comunicaţii. Interfaţa serie este văzută sub sistemul de operare Windows ca şi o resursă de comunicaţii. Secvenţa operaţiilor necesare comunicării cu un dispozitiv cuplat la intefaţa serie presupune:

Un proces utilizator foloseşte funcţia CreateFile pentru a deschide o resursă de comunicaţii, obţinând un identificator sau descriptor (handle) al resursei respective. Acest descriptor este folosit de aplicaţie la toate operaţiile ce sunt executate asupra resursei de comunicaţii. Dacă resursa specificată este folosită de un alt proces, funcţia CreateFile eşuează în a deschide resursa respectivă.

Când un proces foloseşte funcţia CreateFile pentru deschiderea unei resurse de comunicaţii, trebuie să-i specifice următoarele atribute:

Ca şi exemplu prezentăm implementarea în limbajul C++ a unei clase pentru comunicaţia prin interfaţa serie. În cadrul clasei sunt implementate metode pentru următoarele operaţii:

- deschiderea interfeţei serie;

- închiderea interfeţei serie;

- aflarea parametrilor de comunicaţie;

- setarea parametrilor de comunicaţie.