[pso] [tema2lin]pierdere intreruperi

Alexandru Palade alexandru.palade at loopback.ro
Wed Apr 14 14:55:28 EEST 2010


In primul rand, tin sa iti multumesc mult pentru raspunsul detaliat si 
la obiect pe care mi l-ai dat, Octavian! Acuma totul are mult mai mult sens.

In al doilea rand, mi-a rezolvat si problema.

Ca o sugestie pentru cine intretine FAQ-ul (Intrebari specifice linux, 
numarul 3), poate n-ar fi lipsit de interes sa se adauge explicatia pe 
care Octavian tocmai a oferit-o, in loc de raspunsul de acum. Poate sunt 
si altii la fel de lenti ca mine si au nevoie de o explicatie mai pe 
indelete :)

Inca o data, multumesc.

On 04/13/10 21:24, Octavian Voicu wrote:
> 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