Sunteți pe pagina 1din 10

Laboratorul 2

1. Lucrul cu intreruperi in OSEK

1.1. Categorii de intreruperi


Rutinele de tratare a intreruperilor (ISR – Interrupt Service Routine) sunt de
obicei bucati scurte de cod a caror executie este startata de receptionarea unei
intreruperi.
OSEK defineste doua tipuri de ISR, ambele fiind implementate in kernelul
OSEK. Indiferent de categoria ISR-ului, planificatorul sistemului de operare nu este
apelat in interiorul rutinei de tratare a intreruperii. Operatia de planificare poate avea
loc atata timp cat executia unei intreruperi din categoria 2 s-a incheiat, atata timp cat
nu revine intr-o alta intrerupere si daca nici o alta intrerupere nu se afla in asteptare
(Fig.1).

ISR B REQ

ISR A REQ ISR B

ISR A ISR A

Sch OSEK Tasks OSEK Tasks Sch

Scheduling time intervals

Fig. 1

Categoria 1 de intreruperi
Rutinele de tratare a intreruperilor din aceasta categorie nu apeleaza servicii
ale sistemului de operare. Dupa tratarea intreruperii, executia programului va
continua din punctul in care a fost intrerupta. Aceasta categorie de intreruperi este
cea mai rapida categorie de intreruperi. Acest tip de intreruperi sunt folosite de obicei
pentru setarea unor flag-uri sau umplerea unor buffere.

Categoria 2 de intreruperi
Rutinele de tratare a intreruperilor din aceasta categorie pot apela servicii ale
sistemului de operare. Din acest motiv generatorul sistemului de operare (System
Generator) va pune la dispozitia rutinei un cadru de executie. Dupa ce fisierele
sistemului de operare au fost generate, codul utilizator al rutinei de tratare a
intreruperii va fi inserat in acest cadru. De remarcat este faptul ca in rutina de tratare
a intreruperii nu se pot apela orice servicii sistem. Daca sistemul foloseste un obiect
de tip contor general al sistemului, acesta va fi tratat ca o intrerupere din categoria 2.
Intreruperi imbricate
ProOSEK permite existenta intreruperilor imbricate. Aceasta inseamna ca pe
parcursul executiei unei rutine de tratare a intreruperii poate fi acceptata o alta cerere
de intrerupere. Acest lucru este util atunci cand rutina de tratare a intreruperii
necesita mai mult timp pentru realizarea operatiunilor sau daca sunt alte intreruperi
prioritare. In cazul intreruperilor imbricate fiecare ISR din categoria 2 trebuie sa aiba
o prioritate asociata cu valoare intre 1 si 7. Daca sistemul contine si ISR din
categoria 1, atunci acestea trebuie sa aiba prioritati mai mari decit cele ale
intreruperilor din categoria 2.

1.2. Definirea intreruperilor in ProOSEK Configurator


Lista intreruperilor definite in sistem poate fi afisata in ProOSEK Configurator
prin selectarea tipului de obiect ISR (Fig.2) atunci cind vizualizarea configuratiei este
la nivel de obiecte. In partea dreapta vor fi afisate toate obiectele de tip ISR cu
atributele lor.

Fig.2

Editorul de intreruperi permite modificarea atributelor pentru un obiect de tip


ISR nou creat sau creat anterior (Fig.3).

Fig.3
Meniul contextual al obiectelor de tip ISR permite, pe langa crearea unui nou
obiect de tip ISR si stergerea sau duplicarea unui obiect de tip ISR. Duplicarea
consta in crearea unui obiect nou de tip ISR, cu atribute identice cu cele ale
obiectului initial, urmand ca unele atribute sa fie modificate in obiectul nou creat.
Aceasta operatiune permite crearea rapida a mai multor obiecte ce au atribute
asemanatoare.
Atributele unui obiect de tip ISR sunt:
• Name – numele obiectului de tip ISR; valoarea acestui atribut este unica;
• S12X_Vector - vectorul rutinei de tratare a intreruperii; in cazul in care nu se
introduce o valoare numerica pentru acest atribut, generatorul ProOSEK va
folosi valoarea predefinita pentru fiecare ISR in parte. Generatorul sistemului
de operare va avea grija ca vectorul sa corespunda cu sursa intreruperii,
sursa definita la pasul urmator;
• S12X_VECTOR_NAME - sursa de intreruperi (canale de timp, convertoare
A/D, driver CAN, comunicatie SPI, comunicatie USART);
• S12X_PRIORITY – prioritatea intreruperii. O intrerupere mai prioritara poate
sa intrerupa o intrerupere mai putin prioritara. Acest atribut poate avea
valoarea in intervalul 1..7;
• STACKSIZE – dimensiunea in octeti a stivei ce poate fi folosita de catre
intrerupere. Sistemul va adauga spatiu suplimentar pentru apelul functiilor
sistem, cum ar fi ActivateTask(). Aceasta valoare este utilizata doar de
intreruperile din categoria a 2-a.
• S12X_XGATE_ENABLE - atribut ce activeaza facilitatea de tratare a
intreruperilor de catre coprocesorul Xgate;
• CATEGORY - categoria intreruperii (1 sau 2).

1.3. Tratarea obiectelor de tip ISR de catre sistemul de operare


Pentru o lista a tuturor vectorilor de intrerupere precum si a locatiilor
acesstora, se poate consulta paragraful 1.6.1. Vectors din fisierul
MC9S12XDP512V2.pdf.
S12X permite maparea tabelei vectorilor de intreruperi la locatii diferite. In mod
predefinit, tabela este pozitionata la adresa 0xff00. Tabela vectorilor de intrerupere
este formata din lista tuturor rutinelor de intrerupere definite. Tabela este plasata intr-
un segment de memorie propriu, numit VECTORTABLE si este formata dintr-o
structura numita OSEKOSVectorTable[].
Tabela vectorilor de intreruperi generata de ProOSEK este localizat in fisierul
os.c. Daca nu sunt definite intreruperi pentru vectorii 0,1 si 2, ProOSEK insereaza
apelul serviciului boardStartup() in tabela vectorilor de intrerupere. Toti ceilalti
vectori din tabela sunt initializati cu apelul rutinei boardInvalidInterrupt() daca nu
sunt definite intreruperi pentru vectorii respectivi. Aceste doua rutine sunt definite in
fisierul boards.c din directorul Z:\AC_CONTI\board\xdp512.
Rolul rutinei boardInvalidInterrupt() este acela de a asigura faptul ca, daca
printr-o greseala de programare, o anumita intrerupere care nu e configurata
corespunzator este activata, executia programului va ajunge in aceasta rutina si nu
intr-o zona necunoscuta din memorie. Deoarece intr-o functionare normala executia
aplicatiei nu poate ajunge in aceasta rutina, ea poate fi utilizata si pentru semnalarea
unor erori ce pot aparea pe parcursul executiei programelor. Rutina se incheie cu o
bucla infinita care opreste executia taskurilor, datele folosite de acestea putand fi
compromise altfel. Din aceasta situatie sistemul poate iesi doar printr-un reset
generat de WatchDog deoarece acesta nu va mai fi servit, asa cum se intimpla la
executia task-urilor.
ProOSEK utilizeaza tipuri diferite de definitii pentru cele doua categorii de
intreruperi. Secventa de cod prezentata mai jos contine vectori din tabela vectorilor
de intreruperi din fisierul os.c. numeISR1 este numele unui obiect de tip ISR din
categoria 1 iar numeISR2 este numele unui obiect de tip ISR din categoria 2.
………………………………………………………

(const OSEK_U16)boardInvalidInterrupt,
(const OSEK_U16)OSEKOSisrRoutine_numeISR2,
(const OSEK_U16)OSEKOS_ISR1_numeISR1,
(const OSEK_U16)OSEKOSisrRoutine_SysCounter,
(const OSEK_U16)boardInvalidInterrupt,

………………………………………………………

Dupa cum se poate vedea, rutina intreruperii din categoria 2 este definita
OSEKOSisrRoutine_numeISR2 pe cand rutina intreruperii din categoria 1 este
definita OSEKOS_ISR1_numeISR1. Tot in secventa de cod prezentata se poate
observa tratarea obiectului de tip contor general al sistemului drept o intrerupere din
categoria 2.

Pentru un obiect de tip intrerupere din categoria 2 numit numeISR2, in fisierul


os.c se poate observa cadrul de executie generat de catre ProOSEK, cadru ce este
prezentat in secventa de cod urmatoare:

#ifdef __MWERKS__
#include <default.sgm>
#endif
#ifdef __CSMC__
#pragma section ()
#endif
#ifdef __MWERKS__
#include <non_bank.sgm>
#pragma NO_EXIT
#pragma NO_FRAME
#pragma NO_ENTRY
void __near OSEKOSisrRoutine_PIT2_MyISR_2()
#endif
#ifdef __CSMC__
#ifndef OSEKOS_RELOCATE_DEFAULT
#pragma section @near (non_banked)
#endif
void @near OSEKOSisrRoutine_PIT2_MyISR_2()
#endif
{
#ifdef __CSMC__
#pragma asm
#endif
#ifdef __MWERKS__
asm {
#endif
ldaa 0x0030
psha
ldaa 0x0016
psha
ldaa 0x0010
psha
#ifdef __MWERKS__
inc OSEKOSinintr
ldaa #1
cmpa OSEKOSinintr
bne label68
sts OSEKOSisrInterruptedTaskStackPointer
lds OSEKOSisrStackPointer
#endif
#ifdef __CSMC__
inc _OSEKOSinintr
ldaa #1
cmpa _OSEKOSinintr
bne label68
sts _OSEKOSisrInterruptedTaskStackPointer
lds _OSEKOSisrStackPointer
#endif
label68:
cli
#ifdef __CSMC__
#pragma endasm
#endif
#ifdef __MWERKS__
}
#endif
OSEKOS_ISR_numeISR2();
OSEKOSDisable();
#ifdef __CSMC__
#pragma asm
#endif
#ifdef __MWERKS__
asm {
#endif
#ifdef __CSMC__
dec _OSEKOSinintr
#endif
#ifdef __MWERKS__
dec OSEKOSinintr
#endif
bne next68
#ifdef __CSMC__
call f_OSEKOSAsmIDispatch
#endif
#ifdef __MWERKS__
call OSEKOSAsmIDispatch
#endif
#ifdef __CSMC__
lds _OSEKOSisrInterruptedTaskStackPointer
#endif
#ifdef __MWERKS__
lds OSEKOSisrInterruptedTaskStackPointer
#endif
next68:
pula
staa 0x0010
pula
staa 0x0016
pula
staa 0x0030
rti
#ifdef __CSMC__
#pragma endasm
#endif
#ifdef __MWERKS__
}
#endif
}

Cu rosu este evidentiat apelul functiei ce poate fi folosita de catre utilizator


pentru a executa o sectiune de cod proprie. Dupa cum am prezentaat anterior,
pentru rutinele intreruperilor din categoria 1 nu este generat nimic. Se lasa la
latitudinea utilizatorului codul ce se va executa in corpul rutinei.

1.4. Intreruperi pe pinii registrilor de I/O


Exista posibilitatea ca anumite porturi de I/O sa fie folosite ca surse externe
de intreruperi. Porturile care pot fi configurate astfel sunt Portul P, Portul H si Portul
J.
In cadrul laboratorului vom descrie modul de configurare a portului J ca
sursa de intreruperi externa. Acesta dispune de urmatorii registrii de configurare (cei
care trebuie modificati pentru a putea genera intreruperi):

DDRJ – Port J Data Direction Register

DDRJx (Data Direction Port J)


0 - pinul asociat este configurat ca intrare
1 - pinul asociat este configurat ca iesire

Nota: Pinul ce se doreste a fi folosit ca sursa de intreruperi trebuie configurat ca


intrare!

PPSJ – Port J Polarity Select Register


PPSJx (Polarity Select Port J)
0 - intreruperea este generata pe frontul cazator al semnalului
1 - intreruperea este generata pe frontul crescator al semnalului

PIEJ – Port J Interrupt Enable Register

PIEJx (Interrupt Enable Port J)


0 - intreruperile pentru pinul asociat sunt dezactivate
1 - intreruperile pentru pinul asociat sunt activate

PIFJ – Port J Interrupt Flag Register

PIFJx (Interrupt Flag Port J)


0 - nu a fost detectat nici un front
1 - un front activ a fost detectat pe pinul asociat. Resetarea flagului se face
scriind “1” in locatia asociata.

PERJ – Port J Pull Device Enable Register

PERJx (Pull Device Enable Port)


0 - facilitatea de Pull-up sau Pull-down intern este dezactivata
1 - Pull-up sau Pull-down intern activ. Selectarea tipului de “pull-up” sau
“pull-down” este facuta de catre registrul PPSJ (0 -> pull up, 1 -> pull down).

1.5. Definirea intreruperilor in codul aplicatiei


Pentru intreruperile definite in sistem trebuie sa existe in aplicatie si definirea
rutinelor de tratare a intreruperilor respective.
Pentru a defini o intrerupere din categoria 2 se apeleaza macroul ISR(Nume),
unde Nume va fi inlocuit cu numele ISR-ului din categoria 2 definit in sistem, de
exemplu numeISR_2.
ISR(numeISR2)
{

Pentru a defini o intrerupere din categoria 1 se apeleaza macroul


ISR1(Nume), unde Nume va fi inlocuit cu numele ISR-ului din categoria 1 definit in
sistem, de ex. “numeISR1”.

ISR1(numeISR1)
{

Aceste macrouri sunt definite in os.h si realizeaza concatenarea unor siruri de


caractere:

#define ISR(NAME) void OSEKOS_ISR_##NAME(void)


#define ISR1(name) void __interrupt __near OSEKOS_ISR1_ ## name ( void )

1.6. Servicii OSEK specifice lucrului cu intreruperi


Pentru a dezactiva/reactiva intreruperile din categoria 2 pot fi folosite
urmatoarele functii definite in os.c:

• SuspendOSInterrupts()
• ResumeOSInterrupts()
Aceste servicii folosesc bitul I din registrul CCR pentru a dezactiva/reactiva
intreruperile. Apelurile acestor servicii pot fi imbricate.

Pentru a dezactiva/reactiva intreruperile din categoria 1, in cazul in care


intreruperile imbricate nu sunt permise, pot fi folosite urmatoarele functii definite in
“os.c”:
• DisableAllInterrupts()
• EnableAllInterrupts()
Aceste servicii folosesc bitul I din registrul CCR pentru a dezactiva/reactiva
intreruperile.

Pentru a dezactiva/reactiva intreruperile din categoria 1, in cazul in care


intreruperile imbricate sunt permise.
• SuspendAllInterrupts()
• ResumeAllInterrupts()
Aceste servicii folosesc bitul I din registrul CCR pentru a dezactiva/reactiva
intreruperile. Aceste servicii pot fi imbricate.

Aceste functii sunt utile atunci cand se folosesc operatii atomice care dureaza
relativ mult si care nu trebuie intrerupte (in caz contrar datele ar putea fi corupte). Ele
pot fi folosite si in cazul partajarii unor flaguri/variabile intre aplicatie si intreruperi.
Exercitiul 1:
Sa se modifice aplicatia initiala de laborator astfel incit in task-ul de 1 s sa se testeze
valoarea unei variabile globale astfel:
a. Daca este para, sa se aprinda LED-ul conectat la PORTB6.
b. Daca este impara, sa se stinga LED-ul conectat la PORTB6.
Variabila globala testata in task-ul de 1s va fi incrementata la aparitia unei intreruperi
pe pinul PORTJ2, intrerupere generata cu ajutorul unui comutator.

Efectuati urmatoarele etape pentru a putea gestiona intreruperile care vin de la pinul
PJ2:
1. Activati intreruperile de la portul J din ProOSEK.
2. Configurati Portul J in urmatorul mod:
a. DDRJ2 = 0, pinul PJ2 este configurat ca intrare in microcontroler.
b. PPSJ2 = 1, intreruperile vor fi generate pe frontul crescator
c. PERJ2 = 1, sunt folosite rezistentele de pull-up sau pull-down interne
d. resetati flagul de intrerupere cu instructiunea PIFJ2 = 1
e. PIEJ2 = 1, sunt activate intreruperile de la pinul PJ2
3. In rutina de tratare a intreruperilor portului J din fisierul int_handler.c resetati
flagul de intrerupere PIFJ2 = 1.

Exercitiul 2:
Sa se modifice aplicatia initiala de laborator astfel incit task-ul de 1s sa nu modifice
starea pinului PORTB6 iar intreruperile detectate pe pinul PORTH1 sa produca
trecerea unui task numit Task_A in starea “gata de executie”. Task-ul Task_A
modifica starea LED-ului conectat la pinul PORTB6 si incrementeaza valoarea unei
variabile globale v1. Sa se modifice sistemul astfel incat nucleul sistemului de
operare sa permita lucrul cu functia PreTaskHook(), ce va incrementa o variabila
globala v2. Sa se vizualizeze si sa se compare valorile celor doua variabile v1 si v2
pe parcursul executiei aplicatiei.

Exercitiul 3:
Sa se modifice aplicatia obtinuta la exercitiul 1 astfel incat task-ul de 1s sa nu mai
controleze LED-ul conectat la PORTB6 ci sa starteze un task numit Task_3s. Task-ul
Task_3s va schimba polaritatea intreruperii pe pinul PORTP3 la aproximativ 3
secunde. Aparitia unei intreruperi pe pinul PORTP3 va fi evidentiata prin comutarea
starii LED-ului conectat la PORTB6.

Tema 1

Se considera task-ul Task_1s cu perioada de 1s. Folositi acest task pentru a genera
urmatorul semnal (folositi un port al microcontrolerului care poate fi vizualizat prin
aprinderea unui bec/led):
3s 5s

Generarea acestui semnal incepe la detectarea unui front crescator pe pinul


PJ2. Generarea semnalului se opreste atunci cand este detectat un front
descrescator pe pinul PJ2.
Daca comanda de oprire a generarii semnalului a fost detectata cat semnalul
este pe “ON” atunci secventa de generare va fi oprita la sfarsitul ciclului (secventa nu
este intrerupta de detectarea unei noi comenzi).

Obs:
• Va fi folosita capacitatea portului J de a fi folosit ca sursa externa de
intreruperi.
• Se va verifica existenta obiectului de tip ISR in ProOSEK Configurator.

S-ar putea să vă placă și