[pso] [tema2lin]pierdere intreruperi

Octavian Voicu octavian.voicu at gmail.com
Tue Apr 13 21:24:45 EEST 2010


2010/4/13 Alexandru Palade <alexandru.palade at loopback.ro>:
> Ca sa generalizez un pic, ma gandesc la urmtoarul scenariu:
> - vine o intrerupere cum ca trebuie sa citesc
> - citesc o parte din caractere si mi se umple buffer-ul
> - ma opresc (?) din citit in handler si trezesc pe cei ce vor sa citeasca
> - ies din handler
>
> Cum fac sa reiau cititul in handler? Am observat ca daca la sfarsitul
> fiecarui read din operatia din driver adaug ce e scris in FAQ pentru write,
> adica:
>
> outb(0x00, IER);
> outb(0x03, IER);
>
> functioneaza. Dar nu prea are sens, cel putin in capul meu. Ce alta
> modalitate mai am (in afara de a mari buffer-ul, care clar functioneaza) sa
> nu pierd datele ramase dintr-o intrerupere care n-au putut fi salvate din
> prima?

IER (Interrupt Enable Register) e registrul care controleaza ce
intreruperi sunt activate.

Comportamentul corect e urmatorul: orice intrerupere trebuie activata
*numai* atunci cand ai ceva util de facut in ea. In momentul in care
in IRQ handler primesti o intrerupere RDAI (Receive Data Available
Interrupt) si receive bufferul tau s-a umplut, trebuie sa dezactivezi
intreruperea RDAI setand pe 0 bitul corespunzator din registrul IER.
Daca nu faci asta vei primi intreruperi in continuare, dar nu vei avea
unde sa stochezi datele noi; in plus, daca le citesti in acel moment
in handler si nu le stochezi, le vei pierde. RDAI trebuie reactivata
odata ce ai eliberat cel putin un byte din buffer (in functia read a
driverului)

Acelasi lucru se aplica si pentru THREI (Transmitter Holding Register
Empty Interrupt). Aceasta intrerupere trebuie sa fie activata *numai*
daca bufferul de trimitere are cel putin un byte in el. In IRQ
handler, daca a venit intreruperea THREI, vei scrie in buffer cat timp
bitul Empty Transmitter Holding Register din LSR (Line Status
Register) este setat si nu ai golit bufferul. Daca dupa scrierea
bufferul tau de send e gol, dezactivezi intreruperea THREI.
Intreruperea trebuie reactivata cand bufferul de transmitere va avea
din nou cel putin un byte (deci in functia write a driverului).

Nerespectarea acestui comportament face ca intreruperile sa vina
foarte repede (in special valabil pentru THREI) ocupand foarte mult
din cpu si astfel codul proces nu se mai executa (cel care goleste
read bufferul, de exemplu).

De aceea, in functia init a modulului doar intreruperea RDAI trebuie
activata -- nu aveti nimic de trimis inca, deci n-are sens sa activati
si THREI.

O alta observatie legata de modul corect de activare / dezactivare a
unei intreruperi. Pentru a dezactiva intreruperea RDAI, secventa
urmatoare este gresita:

outb(0x00, IER); // bad! dezactivam toate intreruperile, nu numai RDAI

Corect este:

#define IER_RDAI  0x01
outb(inb(IER) & ~IER_RDAI, IER); // dezactiveaza *doar* bitul RDAI

Similar, pentru a reactiva intreruperea RDAI se procedeaza asa:

outb(inb(IER) | IER_RDAI, IER); // activeaza *doar* bitul RDAI

> Mentionez ca nu folosesc FIFO si oricum nu cred ca reprezinta o solutie la
> problema asta. Dar sunt deschis la contra-argumente.

Cu FIFO dezactivat, portul serial va putea stoca un singur byte in
bufferul de transmit si tot unul in bufferul de receive. Pentru data
rate-uri mari, sistemul nu va face frecventei foarte mare de
intreruperi si e foarte posibil ca pana citesti byte-ul din registrul
de receive, sa mai vina altii care sa fie pierduti. Cu FIFO ai un
buffer de 16 bytes si poti seta sa primesti intreruperea cand ai
primit 1, 4, 8 sau 14 bytes. De aceea recomand sa activezi FIFO cu
trigger la 14 bytes, setand bitii Enable FIFO, Clear Receive FIFO,
Clear Transmit FIFO si Interrupt Trigger Level = 14 din registrul FCR
(FIFO Control Register).

Un link util care explica registrele portului serial aveti in
sectiunea resurse utile din laboratorul 6 [1] si anume Interfacing the
Serial / RS232 Port [2]

Octavian


[1] http://elf.cs.pub.ro/so2/wiki/laboratoare/lab06
[2] http://www.beyondlogic.org/serial/serial.htm


More information about the pso mailing list