Documente Academic
Documente Profesional
Documente Cultură
de timp real
Obiectiv disciplină:
C MPLAB
SO
C
BIOS
FreeRTOS
8253
8259 Placa dezvoltare cu
PC DsPIC33
SO
gestionarea intreruperilor) PC
8253
8259
BIOS
8253
8259
PC
C
3. Facilitati C. Tehnici de programare in intreruperi SO
BIOS
C 8253
8259
SO PC
BIOS
8253
8259
PC
I. 1. Caracteristicile ahitecturii IBM-PC, importante
pentru gestionarea intreruperilor
Magistrala adrese:
magistrala adrese IO: 16b (cei mai nesemnificativi)
mag adrese: 20b
MAXIMUM MINIMUM
MODE MODE
GND 1 40 Vcc
AD14 AD15
Mod minim (monoprocesor)-
AD13 A16,S3 - semnalelede control magistrala sunt
AD12 A17,S4 generate direct de 8086
AD11 A18,S5 - magistrala poate fi patajata cu DMA prin
AD10 A19,S6 HOLD/HLDA
AD9 /BHE,S7
AD8 MN,/MX
AD7 /RD
AD6 /RQ,/GT0 HOLD
AD5
8086 /RQ,/GT1 HLDA
Mod maxim (multiprocessor sau cu coprocessor
AD4 /LOCK /WR matematic)
AD3 /S2 IO/M - semnalele de control magistrala sunt
AD2 /S1 DT/R produse de un controller special (8288)
AD1 /S0 /DEN - RQ/GT0 si RQ/GT1 - accesare magistrala
AD0 QS0 ALE de catre procesoare; LOCK blocare acces la
NMI QS1 /INTA
magistrala
INTR /TEST
CLK
- QS0 si QS1 pentru monitorizarea starii cozii
READY
GND 20 21 RESET
de instructiuni
Registri:
generali: de date 16b:AX,BX,CX,DX; 8b: AL,AH, etc
de pointer şi index: SP, BP, SI, DI
segment: CS, DS, ES, SS
pointer de instrucţiuni: IP (adresa instr. CS:IP)
indicatori de control şi stare: 6 indicatori stare (CF, AF, ZF, SF, OF, PF) şi 3
indicatori de control:
DF=1 – la instr pe şiruri se foloseşte decrementarea (de la adrese mari la adrese
mici, de la dreapta la stânga)
TF=1 – procesorul execută o instrucţiune de depanare după fiecare instrucţiune
IF=1 – sunt recunoscute cereri de întrerupere mascabile
Gestionare memorie:
- până la 1MB (2^20)
- paginată pe segmente continue de 64kB (2^16)
Adrese fizice
- se folosesc regiştri pe 16b
1kB ……...
Adr_segment (2B)
vector intrerupere pentru INT x
Adr_deplas (2B) (4 octeti)
4x
……..
0
Intrerupere interna Tipul este depistat
& software intern Construieste
vectorul de
intrerupere
Intreruperi
externe/hardware
INTR Vectorul de
(cu IF=1) intrerupere este
format cu ajutorul
8259
Executie instructiune INT x
- Salvează reg indicatori in stivă
- TF←0, IF←0
- Salvează CS în stivă, salvează IP în stivă
- Înscrie CS şi IP cu vectorul de întrerupere de la adresa fizică 4x
Urmează salt la rutina de tratare
CS
IP
1kB
CS stiva
Adr_segment (2B)
------------
IRET
0
Adr_deplas (2B)
4x
Rutina veche de tratare
intrerupe re x
0
Probl. de reentranţă!!! – marcare sectiune critica (SC) şi forţare IF=0 pe durata SC!!
I. 1. 2 Configuratia intreruperilor la sisteme IBM PC
Software:
Exceptii:
INT 0 – S/BIOS– împărţire cu depăşire
INT 1 – S/BIOS – trasare pas cu pas
INT 3 – S/BIOS - breakpoint
INT 4 – S/BIOS - depăşire OF=1
Hardware:
INT 2 – NMI – BIOS – eroare paritate de memorie sau pentru coprocesor
ACCES NEPERMIS UTILIZATORILOR!!
INT 08H – IRQ0_8259_I – BIOS – ceas de timp real (implicit nemascată de 8259)
INT 09H – IRQ1_8259_I – BIOS – tastatura (implicit nemascată de 8259)
INT 0AH – IRQ2_8259_I - rezervata
INT 0BH – IRQ3_8259_I – BIOS – COM (implicit mascată de 8259)
INT 0CH – IRQ4_8259_I – BIOS – COM (implicit mascată de 8259)
INT 0DH – IRQ5_8259_I – BIOS – LPT, disc
INT 0EH – IRQ6_8259_I – BIOS – disc flexibil
INT 0FH – IRQ7_8259_I – BIOS – LPT
8259_I
8259_II
IRQ7
IRQ7
.
.
. INT INTR
. IRQ2
. INT
.
IRQ0 IRQ1
IRQ0
Prioritati:
= interfată SO – hardware
Întreruperi BIOS
5, 8, 9, 10-1C, 4A, 70
1D, 1E, 1F, 41, 46 – vectori de întrerupere ce pointeaza spre tabele BIOS
INT 5H
- tipareşte continutul ecranului la imprimantă dacă se apasă Shift + PrintScreen
INT 13H – servicii disc – pachet de funcţii ce permit acces la nivel de sector
Înainte de generarea întreruperii:
se înscrie AH cu numărul funcţiei
se înscrie în DL – număr unitate
Exemple:
funcţia 00H: poziţionare la 0 a controlerului de disc + calibrare
funcţia 01H: citire stare după ultima operaţie efectuată
(în AL se returnează un cod de eroare)
funcţia 02H: citire sectoare
funcţia 03H: scriere sectoare
INT 41H Tabel parametri disc dur (16B) – folosita de INT 13H
INT 46H Tabel parametri al doilea disc dur (16B) – folosita de INT 13H
- cu spaţiu IN/OUT dedicat (IO MAP) – registrii sunt adresati prin operatii IO
(spatiu adrese separate pentru memorie si porturi)
- cu pagini memorie pentru IO (Memory MAP) – porturile sunt accesate ca
locatii de memorie
Componente
Registru de comanda
3 numaratoare (#0, #1, #2) pe 16 biti, cu decrementare
GATEi
CLKi
CONTOR i
OUTi
WR Logica de GATE1
citire/scriere
CS CLK1
CONTOR 1
A0,A1 OUT1
GATE2
Reg cuvant
CLK2
comanda CONTOR 2
OUT2
Moduri de lucru
7 6 5 4 3 2 1 0
SC1 SC0 RL1 RL0 M2 M1 M0 BCD
Selectie contor: Scriere/citire Mod lucru:
00=contor 0 00=memorare continut contor 000 (mod0) 0=binar,
01=contor 1 01=scriere/citire LSB(MSB=0) 001(mod1) 1=BCD
10= contor 2 10=scriere/citire MSB(LSB=0) x10(mod2)
11=nepermis 11=scriere/citire LSB, apoi MSB x11(mod3)
100(mod4)
101(mod5)
Adrese regiştri:
registru comanda – adresa 0x43
registri date contor 0 – adresa 0x40 ; contor 1 – adresa 0x41 ; contor 2– adresa 0x42
Mod conectare:
- contor 0:
Gate0=5V;
CLK0 la 1,19MHz;
OUT0 la IRQ0-8259-INT08H
mod 2 sau 3, constanta 0 (T = 55msec, f=18.150Hz)
REPROGRAMARE PERMISA:
- se va reface programarea implicita la final
- se va rescrie rutina de tratare a intreruperii de ceas INT08 si se vor
asigura vechile servicii cu periodicitate aprox. 55msec
- contor 1:
Gate1=5V;
CLK1 la 1,19MHz;
OUT1 pentru refresh DRAM
mod 2, constanta 18 (T = 15 microsec)
INTERZISA UTILIZAREA pentru APLICATII
- contor 2:
Gate2=D0 port 0x61;
CLK2 la 1,19MHz;
OUT2 AND D1 port 0x61 – intrare BELL
mod 3, constanta 1190 (f=10Hz)
PENTRU APLICATII
Port0x61
D7 D6 D5 D4 D3 D2 D1 D0
BELL GATE2
I. 2. 1. Programarea 8259
Rol
gestioneaza cererile de intreruperi de la 8 surse de intreruperi (prin cascadare pânǎ la
64 intreruperi) in functie de prioritati
Componente
ISR registru intreruperi in servire
IMR registru mascare intreruperi
PR registru prioritati
IRR registru cereri intreruperi
- dacǎ apare o cerere IRQi, si IMMi≠1, atunci bitul i din IRR devine 1;
- dacǎ IRR≠0, se lanseaza cerere de intrerupere la procesor pe linia INT; daca
cererea este acceptata, procesorul trimite un INTA=0 şi atunci se seteaza bitul i
din ISR si se sterge bitul i din IRR
INTA INT
Tampon
D7..D0 date Logica comanda
RD
WR Logica de
citire/scriere IRR
CS ISR
PR IRQ0, ..IRQ7
A0
CAS0,CAS1, Logica
IMR
CAS2 comparare.
cascadare
SP/EN
-
la master SP=1; la slave SP=0
Initializare
IC1 A0 D7 D6 D5 D4 D3 D2 D1 D0
0 A7 A6 A5 1 LTM ADI S IC4
IC2 A0 D7 D6 D5 D4 D3 D2 D1 D0
1 A15 A14 A13 A12 A11 A10 A9 A8
LTM=0 daca IRQ active pe front crescator; LTM=1 daca IRQ active pe
palier
IC4 A0 D7 D6 D5 D4 D3 D2 D1 D0
1 1 0 0 SFNM BUF M/S AEOI µP
SFNM = 0 o unica cerere de pe slave inregistrata (prima); =1 sunt inregistrate
simultan de pe slave toate cererile de intreruperi (ca la un 8259 cu mai multe linii
IRQi)
BUF=1 bufferat, caz in care SP/EN devine enable si M/S stabileste master
slave.
AEOI=0 resetare bit ISR printr-un cuvant de comanda de la µP; =1 resetare bit
ISR dupa ce µP primeste adresa completa pentru rutina de tratare intrerupere
µP=0 cu 8080; =1 cu 80x86
Moduri de lucru:
- cu prioritati fixe (Fully Nested): IRQ0 >…> IRQ7
- cu rotire prioritati (Rotating Mode):
o rotire normala – dupǎ tratarea unei cereri de intreruperi pe de IRQi, linia
devine de prioritate minimǎ
o rotire speciala- se transmite prin program linia de prioritate minimǎ
- cu mascare
o speciala: inhiba cereri de pe liniile mascate si valideaza solicitarile de pe
linii nemascate, indiferent de prioritate
- mod cu interogare
se citeste un octet cu A0=x:
D7 D6 D5 D4 D3 D2 D1 D0
=1?? W2 W1 W0
Daca D7=1, atunci s-a inregistrat cererea de intrerupere pe linia i = W2W1W0
Citirea va fi intrepretata ca acceptare de intrerupere (INTA=0),
=> se seteaza bit ISR
Cuvinte comanda
OC1 A0 D7 D6 D5 D4 D3 D2 D1 D0
1 M7 M6 M5 M4 M3 M2 M1 M0
OC2 A0 D7 D6 D5 D4 D3 D2 D1 D0
0 R SEOI EOI 0 0 L2 L1 L0
Situatii posibile:
R SEOI AEOI explicatie
0 0 1 Achitare intrerupere nespecific (sterge bit prioritate
maxima din ISR)
0 1 1 Achitare intrerupere specific (sterge din ISR bitul indicat
de L2L1L0)
1 0 1 Rotire prioritati si achitare intrerupere nespecific
1 1 1 Rotire prioritati si achitare intrerupere specific
1 1 0 Rotire specific
1 0 0 Rotire nespecific, setare AEOI
0 0 0 nimic
OC3 A0 D7 D6 D5 D4 D3 D2 D1 D0
0 x ESMM SMM 0 1 P RR RIS
Conversatie 8259-procesor
- apare o cerere pe linia IRQi 8259S; 8259M va trimite INT=1 spre procesor;
procesorul raspunde cu INTA=0 cǎtre 8259M si 8259S; se pozitioneaza bit ISR
la master si slave;
- 8259M trimite cod de CALL date spre processor si cod CAS spre slave
(verificare: 8259S trimite cod ID2…0 spre master)
- procesorul trimite inca doua impulsuri INTA=0 spre 8259S; acesta depune pe
rand, pe magistrala de date, octet low si high al adresei vectorului de
intreruperi;
- ……………..
- la sfarsit tratare intrerupere: procesorul achita intreruperea la 8259M si 8259S
Initializare pe mod fara rotire prioritati, fara restare automata bit ISR
- la primirea comenzii achitare intrerupere se va reseta bitul ISR de prioritate
maxima; achitarea unei intreruperi cu OC2:
8259M: outportb(0x20,0x20) 0010 0000
Adrese regsitri:
ISR, IRR – citire de la adresa 20H imediat dupa trimiterea unui OC3
corespunzator
outportb(0x20,0x6b) // citire ISR 0110 1011
ISR=inportb(0x20)
outportb(0x20,0x6a) // citire IRR 0110 1010
IRR=inportb(0x20)
IMR – citire de la dresa 21H: IMR=inportb(0x21)
Facilităţi DOS.H
DOS.H3) Functii de gestiune a vectorilor de intrerupere
Ex
Modificator : interrupt
Asigură suplimentar salvarea/refacerea in/din stiva a registrilor:
AX,BX, CX,DX, ES,DS,SI,DI,BP,
Implicit INTEL asigura: flags, CS,IP
= total 12 registri pe 16b
Revenire in context gresit: prin modificare SS, SP
void interrupt (*getvect (int intrno))()
IN: intrno
Efect: citeşte vector întrerupere intrno
OUT: returneaza vectorul de întrerupere (pointer la rutina de tratare de tip interrupt)
void enable(void);
Efect: seteaza IF=1
void disable(void);
Efect: seteaza IF=0
Ex1. //exemplu utilizare interrupt,setvect, getvect
//instalez o rutina proprie pentru tratarea cererii de intrerupere
// de la tastatura
//=============================================================
#include <stdio.h>
#include <dos.h>
#include <conio.h>
int astept=1; //variabila globala
void interrupt (*oldvect)();
void interrupt newtast(void)
{
char codscan; codscan=inportb(0x60);
if (codscan==0x12) astept=0;
(*oldvect)();
}
void main(void){
clrscr();
oldvect=getvect(0x09);setvect(0x09,newtast);
printf("este rescrisa rutina de tratare INT09H\n");
printf("apasa tasta e, altfel programul sta in bucla\n");
while(astept);
printf("am citit tasta e");
setvect(0x09,oldvect);}
Ex2. //exemplu utilizare interrupt,setvect, getvect
//instalez o rutina proprie pentru tratarea cererii de intrerupere
// de la tastatura
//===============================================================
#include <stdio.h>
#include <dos.h>
#include <conio.h>
int numar=0; //variabila globala
void interrupt (*oldvect)();
void interrupt newtast(void) {
numar++;
(*oldvect)();}
void main(void){
int urm_numar=1;
clrscr();
oldvect=getvect(0x09);
setvect(0x09,newtast);
void main(void){
int urm_numar=1;
clrscr();
oldvect=getvect(0x09);setvect(0x09,newtast);
printf("este rescrisa rutina de tratare INT09H\n");
printf("apasa niste taste, cu asteptare intre 2 taste consecutive\n");
while (numar<10 {
if (urm_numar<numar)
{
printf("ai apasat o tasta, continua\n");
urm_numar=urm_numar+2;
}
}
setvect(0x09,oldvect);
printf("ai apasat %d taste",numar/2);
}
Ex4.
//exemplu utilizare interrupt,setvect, getvect
//instalez o rutina proprie pentru tratarea cererii de intrerupere
// de ceas
//===============================================================
#include <stdio.h>
#include <dos.h>
#include <conio.h>
int contor=20; //variabila globala
void interrupt (*oldvect)();
void interrupt newceas(void) {
contor--;
(*oldvect)();}
void main(void){
clrscr();
oldvect=getvect(0x08);setvect(0x08,newceas);
printf("este rescrisa rutina de tratare INT08\n");
printf("programul asteapta...\n");
while(astept);
setvect(0x08,oldvect);
puts("gata");}
Ex5.
//exemplu utilizare interrupt,setvect, getvect
//instalez o rutina proprie pentru tratarea cererii de intrerupere
// de ceas
//===================================================================
#include <stdio.h>
#include <dos.h>
#include <conio.h>
int contor=20,flag=0; //variabila globala
void interrupt (*oldvect)();
void interrupt newceas(void){ contor--;}
void main(void){
int urm_flag=0;
clrscr();
oldvect=getvect(0x1c);setvect(0x1c,newceas);
printf("este rescrisa rutina de tratare INT08\n");
printf("programul asteapta...\n");
while(contor);
setvect(0x1c,oldvect);
puts("gata");
}
Ex6.
//exemplu utilizare interrupt,setvect, getvect
//instalez o rutina proprie pentru tratarea cererii de intrerupere
// de la tastatura
//===================================================================
#include <stdio.h>
#include <dos.h>
#include <conio.h>
clrscr();
oldvect=getvect(0x08);
setvect(0x08,newceas);
while(flag<5)
{
if (urm_flag!=flag)
{
printf("a mai trecut o per ");
urm_flag++;
if (urm_flag%2==0) printf("para\n");
else printf("impara\n");
}
}
setvect(0x08,oldvect);
puts("gata");
}
Ex7
//modul in care rutinele de tip interrupt lucreaza cu stiva
//valorile IF
//==============================================================
#include <stdio.h>
#include <dos.h>
#include<conio.h>
void main(void){
clrscr();
disable();
printf("dupa disable: IF= %x, ar trebui sa fie 0\n",(_FLAGS & 0x0200)>>9);
oldceas=getvect(0x08);setvect(0x08,newceas);
ssmain=_SS;spmain=_SP;
enable();
printf("dupa enable: IF= %x, ar trebui sa fie 1\n\n\n",((_FLAGS & 0x0200)>>9));
while (!flag);
setvect(0x08,oldceas);
printf("inainte de a intra in rutina de tratare intrerupere:\n");
printf(" varf stiva %04x:%04x\n\n",ssmain,spmain);
printf("in propria rutina de trat.intrer., inainte de apel veche rutina:\n");
printf(" varf stiva %04x:%04x, IF=%x\n",ss1,sp1,if1);
printf("in propria rutina de trat. intrer., dupa apel veche rutina:\n");
printf(" varf stiva %04x:%04x, IF=%x\n\n",ss2,sp2,if2);
dif=ssmain*16+spmain-ss1*16-sp1;
printf("au fost salvati: %d octeti\n",dif);
printf("\nla finalul programului principal:\n");
printf(" varf stiva %x:%04x,",_SS,_SP);
printf(" IF=%x\n",(_FLAGS&0x0200)>>9);
}
#include <stdio.h>
#include <conio.h>
#include <dos.h>
#define VIDEO 0x10
int main(void){
clrscr();
movetoxy(35, 10);
printf("calculatorul este harnicut!!\n");
movetoxy(48, 20);
printf("este prietenul meu!!\n");
sleep(2);
defil(10,48,5,70,20);
sleep(5);
return 0;
}
DOS.H3) Functii de citire/scriere a locatiilor de memorie si a
porturilor de intrare/iesire
int inport(int portid);
unsigned char inportb(int portid);
void outport(int portid,int value);
void outportb(int portid,unsigned char value);
/* ==================*/
b=b+a;
printf("suma %f\n",b);
/* ========================*/
outportb(0x61,inportb(0x61)&0xfe);/*invalidare numarare*/
//outport(0x43,0x80);/*citire continut numarator prin memorarare*/
k=inportb(0x42);/*octet low*/
j=inportb(0x42);/*octet high*/
k=k|(j<<8);k=0xffff-k; k=(double)(k)/1.19;
printf("durata de executie a secventei marcate este %f microsec\n",(float)k);
}
Ex3. 8253 implementarea unei functii delay proprii cu rezolutia de msec
#include <stdio.h>
#include <dos.h>
void interrupt (*old)();
int CONTOR;
void interrupt my1c(void){
if (CONTOR!=0) CONTOR--;}
void interrupt my08(void){
if (CONTOR!=0) CONTOR--;
outportb(0x20,0x20);}
//===================================================
void Ddelay(int time){/*TIME IN MSEC*/
int low,high;
high=time/55;low=time%55;
CONTOR=high;old=getvect(0x1c);setvect(0x1c,my1c);
while(CONTOR);
setvect(0x1c,old);
int port=0x40;
char octet=0;
if(canal==1) return 0;
port+=canal;
disable();
octet=octet| (0xc0 & (canal<<6));
octet=octet| (0x0e & (mod<<1 ) );
octet=octet| (0x01&bcd);
octet=octet| 0x30;
outportb(0x43,octet);
outportb(port,(char)(div&0xff));/*div, octet low*/
outportb(port,(char)(div>>8)); /*div, octet high*/
enable();
}
//=====================================================
void speaker_on(void){outportb(0x61,inportb(0x61)|0x03);}
//======================================================
void speaker_off(void){outportb(0x61,inportb(0x61)&0xfc);}
//======================================================
void beep(int frecventa,int durata){
int div;
div=(int)(1190000L/frecventa);
P_8253(2,3,0,div);
speaker_on();
Ddelay(durata);
speaker_off();
}
//=======================================================
void main(void){
beep(2500,4000);}
EX4 8259 ilustreaza modul de lucru al 8259 cu regsitrii ISR si IRR
/*preiau intreruperea de la tastatura;
in timpul rutinei de tratare a intreruperii de la tastatura
citesc registrii IRR si ISR pentru a verifica modul de functionare
a controllerului 8259;
Rezultate:
-----------
In registrul ISR bitul 1 este pozitionat ===rutina in curs de executie
(ISR=0x02); IRR=00;
======================================================*/
#include <stdio.h>
#include <conio.h>
#include <dos.h>
unsigned int ISR,IRR,flag;
void interrupt (*oldtast)();
void main(void){
clrscr();
oldtast=getvect(0x09);
setvect(0x09,newtast);
while(flag<2);
setvect(0x09,oldtast);
printf("ISR=%02x, IRR=%02x\n",ISR,IRR);
}
EX5. Ilustreaza modul de lucru cu 8259 slave
/* Lucrul cu rutina 70H = IRQ0, al doilea 8259
- in timpul rutinei de intreruperi registrul ISR1 indica IRQ2
in deservire si registrul ISR2 indica IRQ0 in deservire
- pentru achitare intrerupere se achita intreruperea IRQ0 -II
si IRQ2 - I; aceste achitari sunt incluse de vechea rutina 70H
(altfel sistemul se blocheaza;)
Pentru demascare:
- IRQ0II si IRQ2I la 8259 trebuie demascat in IMR
- bitul D6, registrul de stare CMOS (adresa 0bH) trebuie pus pe 1
#include <stdio.h>
#include <dos.h>
#include <conio.h>
int flag;
unsigned char ISR1,ISR2;
void interrupt(*old70)();
void interrupt my70(void){
flag++;
outportb(0x20,0x0b); ISR1=inportb(0x20);
outportb(0xa0,0x0b); ISR2=inportb(0xa0);
void main(void){
char c;
clrscr();
outportb(0xa1,((inportb(0xa1))&0xfe));/*demascare IRQ0-II*/
outportb(0x21,((inportb(0x21))&0xfb));/*demascare IRQ2-I*/
/*outportb(0xa1,((inportb(0xa1))|0x01));*//*mascare IRQ0-II */
old70=getvect(0x70);setvect(0x70,my70);
sleep(3);
setvect(0x70,old70);
printf("in intreruperea CMOS ISR1=%02x, ISR2=%02x\n",ISR1,ISR2);
if(flag>0) printf("intreruperea CMOS a fost deservita de %d ori\n",flag);
else printf("intreruperea CMOS nu a fost executata\n");
EX6
/* informatii despre memorie*/
//=======================================
#include <dos.h>
#include <stdio.h>
#include <conio.h>
void main(void){
union{
struct {
unsigned char octetl, octeth;
} oct; //ATENTIE LA ORDINE!!
unsigned int var;
} vv;
clrscr();
/*dimensiunea memoriei de baza*/
outportb(0x70,0x15);
vv.oct.octetl=inportb(0x71);
outportb(0x70,0x16);
vv.oct.octeth=inportb(0x71);
printf("dimensiune memorie de baza -citit din CMOS:");
printf("%d KB\n", vv.var);
/*varianta 3- cu INT12H*/
geninterrupt(0x12);
printf("dimens mem de baza disp pentru DOS si apl. -cu INT12H:%dKB\n", _AX);
}
DOS.H6) Functii diverse
unsigned FP_OFF(farpointer);
unsigned FP_SEG(farpointer);
void far *MK_FP(unsigned seg,unsigned ofs);
cmd = 1 testeazã dacã au fost apăsate taste şi codul lor este disponibil
returnează: 0 – nu sunt taste disponibile
nenul – sunt taste disponibile – pot fi citite
la urmatorul apel bioskey folosind cmd=0
-1 : s-a apasat Ctrl+Brk
Nu se vor prelua exceptiile (INT 0H, INT1H, INT3H, INT4H) si NMI (INT2H)
Scrierea rutinelor proprii
Executie
T1 T2
T1: cererea sta în coada la 8259
T2: dupa ce cererea este acceptata de procesor: salvare registri, formare
adresa rutina
Observatii
- implementare asteptare in main()
- testare “tasta calda”
- variabile de urmarire
#include <stdio.h>
#include <conio.h>
#include <dos.h>
int CONTOR=20;
int flag;
void main(void)
{
clrscr();
oldvect=getvect(0x1c);
setvect(0x1c,ceas);
while (flag!=4)
if (CONTOR==0)
{
>>>>>>>>>>>>>
CONTOR=20; //nerecomandat --> sectiune critica
flag++;
printf("flag=%d\n",flag);
}
setvect(0x1c,oldvect);
}
int CONTOR=20;
int flag, cflag;
void main(void)
{
clrscr();
oldvect=getvect(0x1c);
setvect(0x1c,ceas);
while (flag!=4)
if (cflag==1)
{
cflag=0;
flag++;
printf("flag=%d\n",flag);
}
setvect(0x1c,oldvect);
}
int CONTOR=20;
int flag;
void main(void)
{
int ancflag=flag;
clrscr();
oldvect=getvect(0x1c);
setvect(0x1c,ceas);
while (flag!=4)
if (ancflag!=flag)
{
ancflag=flag;
printf("flag=%d\n",ancflag);
}
setvect(0x1c,oldvect);}
void main(void)
{
int flag_urm=-1;
float rez;
float u[4]={0.1, 0.2, 0.3,0.4};
float y[4]={1,2,3,4};
clrscr();
oldvect=getvect(0x1c);
setvect(0x1c,ceas);
while (flag<4)
if (flag_urm!=flag)
{
flag_urm=flag;
rez=u[flag_urm]+y[flag_urm];
printf("flag=%d, suma u+y=%f\n",flag_urm,rez);
//disable();
//……………………
//rez=u[flag]+y[flag];
//printf("flag=%d, suma+y=%f\n",flag,rez);
//…………
//enable();
}
setvect(0x1c,oldvect);
}
Implementare asteptare - cu sau fara flag
#include <stdio.h>
#include <conio.h>
#include <dos.h>
int CONTOR=20;
int flag;
void main(void)
{
clrscr();
oldvect=getvect(0x1c);
setvect(0x1c,ceas);
while (flag!=1);//asteptare
sau
while (CONTOR);//asteptare
setvect(0x1c,oldvect);
}
Placa dezvoltare cu
DsPIC33
MPLAB
Placa dezvoltare cu
DsPIC33
MPLAB
Placa dezvoltare cu
particularizare dsPIC 33, C - MPLAB DsPIC33
MPLAB
RTOS
Placa dezvoltare cu
MPLAB DsPIC33
4. Planificarea in RTOS clock driven C
FreeRTOS
Placa dezvoltare cu
DsPIC33
II.1. Noţiuni introductive privind aplicaţiile
multi-tasking de timp real
Sistem numeric:
= hardware (resurse) + sistem de operare + aplicaţie utilizator (rutine/metode)
Sistem de timp real - un sistem care trebuie să răspundă unor restricţii de timp
prestabilite
← procesele ocupa
Context task
= conţinut regiştri + adresa de început task + stare task +adresa stivei iniţiale +
var. specifice ale SOTR
o Un proces care ocupa resursa trebuie să îşi poată finaliza în timp finit
operaţiile, fără a pierde consistenţa acestora
in curs de executie
(“running”)
Cere asteptarea
unui eveniment Se termina de
executat
Pierde Primeste
procesorul procesorul
in asteptare (“preempt”) (“start)
(“waiting”) suspendata
Pot exista diferente intre SOTR cu privire la modul de trecere del a o stare la alta sau
denumirea stării
II. 1. 1. 3. Moduri execuţie a taskurilor
o preemtiv
activare T1 Terminare T1
T1
suspendat in executie suspendat
v
in executie “ready” in executie
T2
o nepreemtiv
T1
suspendat ready” in executie
v
in executie suspendat
T2
Terminare T2
>> pot fi admise moduri mixte: unele procese preemtive, altele nepreemtive
II. 1. 1. 4. Planificator
clock driven:
planificatorul se activează periodic (o perioadă = frame)
+ procesul in executie cere acces la planificator, se termina sau intra in
asteptare
event driven:
planificatorul se activează cand apare un eveniment ce modifică coada
ready
+ procesul in executie cere acces la planificator, se termina sau intra in
asteptare
o algoritmul de planificare – cum alege taskul câştigător:
uzual pe bază de prioritate
priorităţile pot fi statice (un task are aceeaşi priroitate pe durata
execuţiei aplicaţiei) sau dinamice (un task îşi modifică prioritatea)
• la multe SOTR: statice (stabilite de designer)
II. 1. 1. 5. Execuţia ISR
Di
(deadline relativ)
procesi timp
ri di
activare ei termen limita
(release) (executie) (deadline absolut)
li Taski
rezerva
(laxity, slack)
intarziere
(tardeness)
Taski
Timpul de activare ri
poate incorpora şi restricţii de precedenţa (procesul se poate executa doar dacă
alte procese s-au executat)
Timpul de executie ei
este calculat pentru un proces care se executa fara a fi intrerupt-preemtat, avand
toate resursele necesare disponibile si toate restrictiile de precedenta indeplinite
Depinde de viteza resurselor active
Nu depinde de secventa de executie a taskurilor
Poate fi diferit daca exista instructiuni conditionale,
daca se foloseste memorie cash
ei ∈ [ei− , ei + ] >> se va considera in analiza ei +
Obs:
In aplicatiile de timp real exista multe procese periodice
Aplicaţii on-line: Tdeadline < ∞ ; aplicaţii off-line: Tdeadline → ∞
Functia de utilitate
Indica daca este utila executia procesului chiar si dupa expirarea termenului limita
utilitate
intarziere
0
Timp = resursa STR ⇒ corectitudine în funcţionarea STR
- servicii generoase de depanare: trace, detectie depasire stiva, kit dezvoltare sub
Win.
- asigura flexibilitate:
nu exista limite pentru nr taskuri, nr prioritati,
taskurile se pot crea dinamic, accepta mod preemtiv-cooperativ (corutine),
pot fi mai multe taskuri pe acelasi nivel de pioritate.
Simplu de înţeles
Uşor de utilizat
T2 T1 T1T2 T2 T2T3 T3
Avantaje abordare multitasking:
- Extensie simpla – adaugare taskuri - in cele mai multe situatii,
- Prioritati diferite periodic FreeRTOS va decide ce
- Temporizari & restrictii de timp mai task preia procesorul
flexibil de gestionat independent
pentru fiecare task
Distributie
Structura directoare
FreeRTOS
¦
+-Demo
¦ ¦
¦ +-Common Fisiere demo commune tuturor arhitecturilor.
¦ +-Dir x Fisiere demo specifice arhitecturii x
¦ +-Dir y Fisiere demo specifice arhitecturii y
¦
+-Source Cod Kernel
¦
+-Portable cod kernel specific arhitecturii.
Fisierele kernel principale:
tasks.c,
queue.c
list.c \ FreeRTOS\ Source
corutine.c
vTaskSuspend()
vTaskCreate()
Implementare taskuri - generalitati:
- un task poate avea acces doar la stiva proprie (mod User) sau la intreaga
memorie (mod Privileged – folosind Memory Unit Protection)
- orice task poate modifica on-line prioritatea unui alt task sau prioritatea sa
Setari in FreeRTOSConfig.h:
#define configUSE_PREEMPTION 1
#define configTICK_RATE_HZ ((portTickType)1000)
etc
Folosirea planificatorului FreeRTOS:
- se configurează frame- ul
>> gestionat intern cu o rutina de tratare a unei intreruperi venite
de la un numărator de timp
- se activează planificatorul.
T2 se
blocheaza,
Inceput de frame= punct de Se deblochează T2
punct de replanificare
replanificare
Taskuri ready T2 si
T3
T2 T1 T1T2 T2 T2T3 T3 T3I I T2
T1 T2 T3 T1 T2 T3 T1T2 T3 T2 T3
T1 se
blocheaza,
T2 in curs de punct de Se deblochează T2
executie, T3 ready replanificare
T2 T2 T2T1 T1 T1T3 T3 T3 I I T2
Un punct replanificare
execeptional, de exemplu un
task mai putin prioritar sters
Se deblocheaza un task
prioritar T4, dar el va astepta in
lista ready pana la urmatorul
punct de replanificare
Observatii:
- apariţia unui task prioritar în lista ready prin deblocare este considerată doar dacă se
lucrează in mod preemtiv
iesirea din blocare este decisa de rutina de ceas a sistemului de operare,
- replanificarea are loc imediat doar dacă se lucrează in mod preemtiv.
- in mod nepreemtiv, acesta nu este punct de replanificare - taskurile deblocate
prioritare nu pot prelua imediat procesorul
- apariţia unui task prioritar în lista ready prin xTaskCreate sau revenire din starea
suspendata forţează replanificare, indiferent de modul de lucru preemptiv/
nepreemptiv
acest punct de replanificare este decis de taskul in curs de executie
(este un apel voit la planificator)
avantaj: tratarea rapida a proceselor prioritare noi sau revenite din
suspendare
Totusi, la introducerea in lista de taskuri ready a unui task nou prin
xTaskCreate sau revenire din starea suspendata, acest task nu poate
preempta un task de aceeasi prioritate.
acest lucru este posibil doar cand toate taskurile de prioritate mai
mare sunt in blocare
Procesorul este mereu cedat catre ISR, daca IF permite
T1 T1 ISR T2 T2
şi influenţează
#if configUSE_PREEMPTION == 1
portYIELD(); //(portasm_dsPIC.s)
// - fortează o comutare de context
#endif
}
}
Atentie, la SOTR trebuie asigurat un compromis intre doua obiective conflictuale:
Idle task este implementat ca bucla infinita for (;;){......} - la fiecare ciclu,
apeleaza Idle Hook, care poate fi scrisa de utilizator pentru a implementa servicii
proprii.
for( ;; ){
Verifica daca anumite taskuri au fost sterse, eliberează memoria si
decrementeaza uxCurrentNumberOfTasks
#if ( configUSE_IDLE_HOOK == 1 ){
vApplicationIdleHook();
}
#endif
}
IdleTaskHook
IdleHook este implicit aplelata in taskul idle la fiecare parcugere a buclei for, dacă
configUSE_IDLE_HOOK =1 (in FreeRTOSConfig.h).
Mod de implementare:
T1 T2 I T1 T3 T3 T3T2 I T1 T2
T2 deblocat
Idle hook apelat la
fiecare ciclu for
I T1 T1T2 T2 T2 T2 T2I I I I
Punct de replanificare
T1 deblocat cerut de T1 prin blocare
Replanificare ceruta
de idle task
Exemplu
- planul este admisibil (restrictiile de timp sunt respectate) doar daca prioritatile
au fost corect alocate de programator!!!
- pentru variabile:
o tip char - prefix c
o tip short - prefix s Exemple:
o tip long - prefix l ucPriority, pcPointerChar
o tip float - prefix f
o tip double - prefix d
o enumeratii - prefix e
o alte tipuri (ex. struct, union) - prefix x
o pointeri - prefix suplimentar p
o unsigned – prefix suplimentar u
-pentru funcţii:
o Serviciu API – prefix în funcţie de tip
o Numele funcţiei începe cu numele fişierului în care apare definiţia
(vTaskDelete - tip void, in task. C)
Tipuri de date predefinite
#if( configUSE_16_BIT_TICKS == 1 )
typedef unsigned portSHORT portTickType;
#define portMAX_DELAY ( portTickType ) 0xffff
#else
typedef unsigned portLONG portTickType;
#define portMAX_DELAY ( portTickType ) 0xffffffff
#endif
Pentru a folosi o anumita configuratie a SOTR, sunt necesare setari specifice in
FreeRTOSConfig.h:
#include <p33FJ128MC802.h> // legatura cu arhitectura hardware
#define configMAX_TASK_NAME_LEN ( 4 )
//maxim 4 car. pentru numele unui task
// (inclusiv terminatorul NULL)
1. Creare/stergere taskuri
portBASE_TYPE xTaskCreate(
pdTASK_CODE pvTaskCode, const portCHAR * const pcName,
unsigned portSHORT usStackDepth,
void *pvParameters, unsigned portBASE_TYPE uxPriority,
xTaskHandle *pvTask );
Returnează : pdPASS pentru executie cu succes, un cod de eroare la executie esuata - vezi projdefs. h – exemplu
#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 )
void vTaskDelete( xTaskHandle pxTask );
uxCurrentNumberOfTasks++;
vTaskDelete
{
Elimina taskul din lista
Actualizează nr. taskuri sterse
Asigura servicii de monitorizare (dacă sunt activate)
#endif
2. Activare/dezactivare planificator
care asigura
- stergerea tuturor taskurilor şi oprirea planificatorului
- oprirea “modulului” de gestionare tick,
- eliberarea resurselor ocupate de SOTR.
Exemplu de utilizare:
void vAFunction( void ) {
// Start planificator.
vTaskStartScheduler();
xSchedulerRunning = pdTRUE;
xTickCount = ( portTickType ) 0;
xSchedulerRunning = pdFALSE;
vPortEndScheduler();
}
3. Suspendare/ revenire din starea suspendată
#if ( INCLUDE_vTaskSuspend == 1 ){
void vTaskResume( xTaskHandle pxTaskToResume )
{
Insereaza taskul in lista de taskuri ready si sterge-l din lista de taskuri
suspendate
Asigura servicii de monitorizare
Daca prioritate acestui task este >= cu cea a taskului curent, asigura
replanificare
}
} #endif
#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
{
portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
{
Insereaza taskul in lista de taskuri ready si sterge-l din lista de taskuri
suspendate
Asigura servicii de monitorizare
Daca taskul este de prioritate >= prioritatea taskului intrerupt, marcheaza ca
necesara o replanificare
)
}
#endif
4. Modificare prioritati
Cerinta: INCLUDE_uxTaskPriorityGet = 1
Cerinta: INCLUDE_vTaskPrioritySet = 1
Exemplu de utilizare:
Cu INCLUDE_uxTaskPriorityGet = 1, INCLUDE_vTaskPrioritySet = 1
xTaskHandle xHandle;
#if (INCLUDE_uxTaskPriorityGet = 1)
unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask ){
returnează prioritate taskului pxTask }
#endif
5. Asteptare pe durata unui anumit un interval de timp
Explicaţii:
taskul va intra imediat in blocare pentru nr. de tickuri precizat;
nr tickuri = interval exprimat in msec / portTick_RATE_MS
Observatie:
În portmacro.h exista
#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ ),
iar configTICK_RATE_HZ este setat in FreeRTOSConfig.h
Exemplu:
void vTaskFunction( void * pvParameters ) {
const portTickType xDelay = 500 / portTICK_RATE_MS;//astept 500 msec
for( ;; ){
vToggleLED();
vTaskDelay( xDelay );}
}
void vTaskDelayUntil( portTickType *pxPreviousWakeTime,
portTickType xTimeIncrement );
pxPreviousWakeTime Pointer la o variabila care indica momentul la care taskul a fost ultima data
deblocat. Variabila trebuie initializata (de exemplu cu momentul actual de timp
inainte de prima utilizare a functiei). Apoi variabila este actualizata de apelurile
successive ale acestui serviciu API.
xTimeIncrement Taskul va intra in blocare pana la momentul (*pxPreviousWakeTime +
xTimeIncrement), cand se va debloca. Momentul deblocarii este automat memorat
in *pxPreviousWakeTime, pentru utilizari viitoare.
Daca (*pxPreviousWakeTime + xTimeIncrement) este din trecut, taskul nu este
blocat.
Exemplu:
void vTaskFunction( void * pvParameters ){
portTickType xLastWakeTime; const portTickType xPer = 10;
xLastWakeTime = xTaskGetTickCount();
for( ;; ) {
vTaskDelayUntil( &xLastWakeTime, xPer );
// aici - instructiuni diverse.
}}
#if ( INCLUDE_vTaskDelay == 1 )
void vTaskDelay( portTickType xTicksToDelay ){
if( xTicksToDelay > ( portTickType ) 0 ){//e necesara intarzierea
Blocheaza planificatorul
Asigura servicii de monitorizare
Calculeaza momentul de deblocare:
xTimeToWake = xTickCount + xTicksToDelay;
Elimina taskul din lista taskurilor ready
Adauga taskul la lista de taskuri blocate, verificand daca pana la
deblocare nu va aparea overflow pe numarator
- if( xTimeToWake < xTickCount )
Deblocheaza planificatorul
}
Forteaza replanificarea
}
#endif
#if ( INCLUDE_vTaskDelayUntil == 1 )
void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType
xTimeIncrement ) {
Blocheaza planificatorul
Calculeaza momentul de deblocare:
xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
Verifica daca e overflow si marchez daca intarzierea poate avea loc
Actualizeaza *pxPreviousWakeTime = xTimeToWake;
if (e necesara intarzierea){
Asigura servicii de monitorizare
Elimina taskul din lista taskurilor ready
Insereaza taskul in lista de taskuri blocate (eventual intaziere cu
overflow la contorul timp)
}
Deblocheaza planificatorul
Forteaza replanificarea
}
#endif
Iesirea taskurilor din starea blocat este decisa din rutina de ceas a sistemului
- la fiecare frame este verificata lista de taskuri blocate si se stabileste care trebuie
trecut in starea ready
void vTaskIncrementTick( void )
{
if( planificator activ si nesuspendat )
{
++xTickCount;
if( xTickCount == ( portTickType ) 0 )//overflow contor de timp
{ xNumOfOverflows++;
Aleg lista de taskuri blocate cu intarzieri ce conduceau la
overflow
}
Alege taskurile care trebuie deblocate
Elimina aceste taskuri din lista taskurilor in asteptare
Trece aceste taskuri in lista de taskuri ready
}
#if ( configUSE_TICK_HOOK == 1 )
vApplicationTickHook();
#endif
}
Asigura servicii de monitorizare
}
6 Alte servicii pentru controlul kernelului
Exemplu
void vTask1( void * pvParameters ){
for( ;; ) {
xTaskSuspendAll ();
………………// nicio comutare de context nu poate avea loc
if( !xTaskResumeAll () ) { taskYIELD (); }
}
}
void vTaskIncrementTick( void )
{
if( planificator activ si nesuspendat )
{
++xTickCount;
if( xTickCount == ( portTickType ) 0 )//overflow contor de timp
{ xNumOfOverflows++;
Aleg lista de taskuri blocate cu intarzieri ce conduceau a
overflow
}
Alege taskurile care trebuie deblocate
Elimina aceste taskuri din ista taskurilor in asteptare
Trece aceste taskuri in lista de taskuri ready
}
#if ( configUSE_TICK_HOOK == 1 )
vApplicationTickHook();
#endif
}
Asigura servicii de monitorizare
}
Numarul de tickuri pierdute pe perioada
cat planificatorul este blocat este
contorizat si folosit pentru actualizarea
corecta a lui xTickCount la
revalidarea planificatorului
7. Servicii APIce oferă informaţii despre SOTR:
FreeRTOSConfig.h
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
#include <p33FJ128MC802.h>
portTickType no_ticks;
void initPLL(void){
// Configure PLL prescaler, PLL postscaler, PLL divisor
PLLFBD = 41; // M = 43 FRC
CLKDIVbits.PLLPOST=0; // N1 = 2
CLKDIVbits.PLLPRE=0; // N2 = 2
// Initiate Clock Switch to Internal FRC with PLL (NOSC = 0b001)
__builtin_write_OSCCONH(0x01); // FRC
__builtin_write_OSCCONL(0x01);
vTaskStartScheduler();
return 0; Ce se schimba pe
} mod nepreemtiv?
Observatii:
- pe mod preemptiv:
P_T1=P_T2, T1 nu va preempta T2, fiind de aceeasi prioritate (la breakpointul
indicat se va gasi t2first=1 si no_ticks=50).
P_T1>P_T2, T1 va preempta T2 (la breakpointul indicat se va gasi t2first=0 si
no_ticks=50).
Exemplu 2: idem, inlocuind P_ T1=P_T2=P_idle si:
void Task1(void *params) {
portTickType xLastTime = xTaskGetTickCount()-1;
for (;;){
no_ticks=xTaskGetTickCount();
if (xLastTime!=no_ticks){varaux1=varaux1+1;xLastTime=no_ticks;}
if ((no_ticks/15)*15 == no_ticks) {vParTestToggleLED(15);}
}}
– demo site:
#include <stdlib.h>
/* Variable used by the created tasks to calculate the LED number to use, and
the rate at which they should flash the LED. */
static volatile unsigned portBASE_TYPE uxFlashTaskNumber = 0;
!
portENTER_CRITICAL();{/* Calculate the LED and flash rate. */
uxLED = uxFlashTaskNumber;
uxFlashTaskNumber++;}
portEXIT_CRITICAL();
xLastFlashTime = xTaskGetTickCount();
for(;;)
{
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
vParTestToggleLED( uxLED );//led on
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
vParTestToggleLED( uxLED );//led oFF
}
}
DEATH.C //creare si stergere taskuri
#include <stdlib.h>
#include "FreeRTOS.h"
#include "task.h"
#include "death.h"
#define deathSTACK_SIZE ( configMINIMAL_STACK_SIZE + 60 )
/* A variable which is incremented every time the dynamic tasks are created.
This is used to check that the task is still running. */
static volatile unsigned short usCreationCount = 0;
/* Used to store the number of tasks that were originally running so the creator
!
task can tell if any of the suicidal tasks have failed to die.
static volatile unsigned portBASE_TYPE uxTasksRunningAtStart = 0;
/* Tasks are deleted by the idle task. Under heavy load the idle task might
not get much processing time, so it would be legitimate for several tasks to
remain undeleted for a short period. */
static const unsigned portBASE_TYPE uxMaxNumberOfExtraTasksRunning = 2;
xTaskHandle xCreatedTask;
!
void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority ){
unsigned portBASE_TYPE *puxPriority;
/*From FreeRTOS V3.0 on, the idle task is started when the scheduler is
started. Therefore the idle task is not yet accounted for. We correct
!
this by increasing uxTasksRunningAtStart by 1. */
uxTasksRunningAtStart++;
}
static portTASK_FUNCTION( vCreateTasks, pvParameters ){
for( ;; ) {
/* Just loop round, delaying then creating the four suicidal tasks. */
vTaskDelay( xDelay );
xCreatedTask = NULL;
xTaskCreate( vSuicidalTask, ( signed char * ) "SUICID1",
configMINIMAL_STACK_SIZE, NULL, uxPriority, &xCreatedTask );
xTaskCreate( vSuicidalTask, ( signed char * ) "SUICID2",
configMINIMAL_STACK_SIZE, &xCreatedTask, uxPriority, NULL );
++usCreationCount;
} pvParameters
}
static portTASK_FUNCTION( vSuicidalTask, pvParameters ){
for( ;; ) {
/* Do something random just to use some stack and registers. */
l1 = 2;l2 = 89;l2 *= l1;
vTaskDelay( xDelay );
if( xTaskToKill != NULL ) {
vTaskDelete( xTaskToKill );
vTaskDelete( NULL ); /* Kill ourselves. */
}
}
}
/* This is called to check that the creator task is still running and that
there are not any more than four extra tasks. */
Functiile trace trebuie sa fie cu timp foarte mic de executie, fara apeluri la sistem.
In FreeRTOSconfig.h:
#define configUSE_TRACE_FACILITY 1
1. numarare comutări:
In main.c:
unsigned int nr_switch_T2;
void vMainMineIn(void){
if ( handT2 == pxCurrentTCB ) nr_switch_T2++;
}
2. numarare comutari de la T2 la T1
void vMainMineOut(void){
if ( handT2 == pxCurrentTCB) ies_T2=1;
}
void vMainMineIn(void){
if ( handT1 == pxCurrentTCB && ies_T2==1 ) nr_switch_T2++;
ies_T2=0;
}
3. numarare comutari de la T2 la T2
unsigned int nr_switch_T2, ies_T2;
void vMainMineOut(void){
if ( handT2 == pxCurrentTCB) ies_T2=1;
}
void vMainMineIn(void){
if ( handT2 == pxCurrentTCB && ies_T2==1 ) nr_switch_T2++;
ies_T2=0;
}
4. semnalare cazuri cu mai multe de 2 comutari in cadrul aceluiasi ciclu for
void vMainMineOut(void){
static unsigned int urmflagT2=-1;
if ( handT2 == pxCurrentTCB) {
urmflag++;
if(urmflagT2!=flagT2) com_in_for_T2++;
Modificare:
void Task2(void *params) {
portTickType xLastTime = xTaskGetTickCount();//la primul frame valoarea este 0
for (;;){
flagT2++;
no_ticks=xTaskGetTickCount();
if (xLastTime!=no_ticks){varaux2=varaux2+1;xLastTime=no_ticks;}
if (no_ticks <50) { vParTestSetLED( 14, 0 );}
if (no_ticks ==50) {
if (uxCurrentNumberOfTasks==2)
xTaskCreate(Task1, (signed portCHAR *) "T1",
configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+1, &handT1);
vParTestSetLED( 14, 1 );
}
if (no_ticks >50){
vParTestToggleLED(14);
vTaskDelayUntil(&xLastTime,35);
vParTestToggleLED(14);
vTaskDelayUntil(&xLastTime,35);
vParTestToggleLED(14);
vTaskDelayUntil(&xLastTime,35);
vParTestToggleLED(14);
vTaskDelayUntil(&xLastTime,35); }
}}
Servicii API de trace
care pot lista anumite informatii despre taskuri, dar care trebuie folosite cu precautie.
Cerinta: configUSE_APPLICATION_TASK_TAG = 1
Exemplu: RECOMANDAT
#define traceTASK_SWITCHED_OUT() xTaskCallApplicationTaskHook( pxCurrentTCB, 0 )
In FreeRTOSConfig.h:
#define configUSE_APPLICATION_TASK_TAG 1
#define traceTASK_SWITCHED_IN() xTaskCallApplicationTaskHook( pxCurrentTCB, 0 )
In main:
Timpii de executie asociati unui task in cadrul unui frame sau pe portiuni de cod pot
fi determinati
Aceste servicii sunt deja oferite foarte simplu de FreeRTOS care poate evidenţia
timpii de execuţie ai proceselor ca valoare absoluta şi % din timp total de execuţie.
Necesar: configGENERATE_RUN_TIME_STATS = 1
In FreeRTOSConfig.h
#define configTICK_RATE_HZ ( ( portTickType ) 100 )
#define configGENERATE_RUN_TIME_STATS 1
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ( 0UL )
#define portGET_RUN_TIME_COUNTER_VALUE() 5000UL
In Main.c se modifica
void Task2(void *params) {
if (no_ticks >50){
uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
vTaskGetRunTimeStats( &myBuffer[0] );
vParTestToggleLED(14);
vTaskDelayUntil(&xLastTime,35);
}
}
1. Verificare rapidă:
(trebuie configCHECK_FOR_STACK_OVERFLOW = 1)
Depăşirea este verificată doar la comutarea de context din starea running (atunci se
salveaza contextul în stivă şi e un caz nefavorabil). Daca pointerul de varf de stiva
este in domeniul nepermis, este apelat hook-ul de depăşire stivă.
2. Verificare suplimentară:
(trebuie setat configCHECK_FOR_STACK_OVERFLOW = 2)
o intre taskuri,
Mesajele sunt copiate prin valoare, nu prin referinta – pentru a evita probleme legate
de consistenta datelor.
Daca nici atunci accesul la coada nu e posibil, serviciul API returnează eroare.
Ready T3 si T4
Task 3 a scris 2 mesaje in coada (in front), intra in
M3 M4 M5
S R asteptare un interval de timp
Ready: T1, T4
S Task 1 a scris 1 mesaj in coada (back) si doreste sa
M6 M3 M4 M5
R mai scrie unul, dar coada este plina si intra in blocare
Ready T2 si T4
M6 M3 M4 Task 2 citeste un mesaj in intervalul de blocare maxim
R S acceptat de Task 1.
Ready T4
Ready T2 si T4
Task 2 citeste mesajul, ar dori sa mai citeasca unul dar
S R nu mai exista mesaje in coada si intra in blocare. Se
executa in continuare T4.
Ready T1, T4
M8 Task 1 devine ready si scrie un mesaj in coada, dupa
S R care intra in asteptare un interval de timp.
1. Creare/ştergere coadă
xQueueHandle xQueueCreate(
unsigned portBASE_TYPE uxQueueLength,
unsigned portBASE_TYPE uxItemSize
);
- creează o nouă coadă (alocă spaţiu) + returnează handlerul.
portBASE_TYPE xQueueSend(
xQueueHandle xQueue,
const void * pvItemToQueue,
portTickType xTicksToWait
);
portBASE_TYPE xQueueSendToToFront(
xQueueHandle xQueue,
const void * pvItemToQueue,
portTickType xTicksToWait
);
portBASE_TYPE xQueueSendToBack(
xQueueHandle xQueue,
const void * pvItemToQueue,
portTickType xTicksToWait
);
4. Citire mesaje din coadă
portBASE_TYPE xQueueReceive(
xQueueHandle xQueue,
void *pvBuffer,
portTickType xTicksToWait
);
Mesajul este citit prin valoare şi şters din coadă. Spaţiul de memorie unde este copiat după citire
trebuie rezervat de programator. Dacă se găseşte coada goală, taskul intră în blocare pentru maxim
xTicksToWait tickuri.
portBASE_TYPE xQueuePeek(
xQueueHandle xQueue,
void *pvBuffer,
portTickType xTicksToWait
);
signed portBASE_TYPE xQueueGenericSend( ....... ){
for( ;; ){
taskENTER_CRITICAL();
if (exista loc liber in coada){
Scrie mesajul nou si actualizeaza pointer scriere;
if (exista un task care asteapta citirea din acesta coada){
deblocheaza taskul din capul listei(trece-l in ready);
forteaza replanificare (taskul deblocat poate fi mai
prioritar);
}
taskEXIT_CRITICAL();
return pdPASS;// succes
}
else{
if( timpul de asteptare este 0 ) {
taskEXIT_CRITICAL();
trace + return esec scriere; } Pot interveni ISR‚ taskuri care
else seteaza timp asteptare sa modifice starea cozii
taskEXIT_CRITICAL();
if (timpul de asteptare nu a expirat)
if (coada este plina)
trece taskul in lista de taskuri blocate la sciere pt aceasta coada
(lista este gestionata pe baza de prioritati)
asigura trace
forteaza replanificare }
else eroare scriere (trace+return)
}}
signed portBASE_TYPE xQueueGenericReceive( ....... ){
for( ;; ){
taskENTER_CRITICAL();
if( coada nu e goala ){
citeste mesajul din capul cozii si sterge-l (eventual);
actualizeaza pointer;
asigura trace;
if (exista taskuri blocate la scriere in coada){
deblocheaza taskul din capul listei
forteaza replanificare;
taskEXIT_CRITICAL();
return pdPASS;}
T1 – perioada 1sec, semnalizare LED 15, scrie mesaj „1” dupa fiecare schimbare a
starii ledului; T2 idem, pentru LED 14, cu perioada 2 sec, mesaj „2”
T3 – perioada 2 sec – verifica daca se executa ok actualizarile de leduri
Pentru verificare >> se poate schimba perioada la T2 la 2.5 sec (simuland intarzieri
nedorita)
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "croutine.h"
#include "partest.h"
_FOSCSEL(FNOSC_FRC); // Select Internal FRC at POR
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF); // Enable Clock Switching and Configure
// FRC + PLL
unsigned int flag_corect=1;
unsigned int nr;
xQueueHandle xMineQueue;
void initPLL(void){
// Configure PLL prescaler, PLL postscaler, PLL divisor
PLLFBD = 41; // M = 43 FRC
CLKDIVbits.PLLPOST=0; // N1 = 2
CLKDIVbits.PLLPRE=0; // N2 = 2
#include <stdlib.h>
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "BlockQ.h"
pxQueueParameters1->xBlockTime = xBlockTime;
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
for( ;; ){
else {
if( sErrorEverOccurred == pdFALSE ) {
( *pxQueueParameters->psCheckVariable )++; }
++usValue;}
}
}
static portTASK_FUNCTION( vBlockingQueueConsumer, pvParameters )
{
unsigned short usData, usExpectedValue = 0;
xBlockingQueueParameters *pxQueueParameters;
short sErrorEverOccurred = pdFALSE;
for( ;; ){
if( xQueueReceive( pxQueueParameters->xQueue, &usData,
pxQueueParameters->xBlockTime ) == pdPASS ){
else{
if( sErrorEverOccurred == pdFALSE ) {
( *pxQueueParameters->psCheckVariable )++;}
++usExpectedValue;}
}
}
}
portBASE_TYPE xAreBlockingQueuesStillRunning( void ){
static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( unsigned
short ) 0, ( unsigned short ) 0, ( unsigned short ) 0 };
static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( unsigned
short ) 0, ( unsigned short ) 0, ( unsigned short ) 0 };
portBASE_TYPE xReturn = pdPASS, xTasks;
return xReturn;
}
II. 2. 4. 3. Probleme in gestionarea resurselor pasive partajabile
Probleme principale:
Reentranta: continuarea unor operaţii pe o resursa partajata, după ce resursa a
fost „furată” de alt proces şi apoi cedată
un exemplu este acela in care resursa partajată este un dispozitiv periferic
care acceptă mai multe moduri de lucru
Proces 1 ocupa procesorul.
Proces 1 Proces 2 Pe durata folosirii resursei
pe modul 1 pierde
procesorul care este preluat
.............. .............. de Proces 2.
Setez mod de lucru 1 Setez mod de lucru 2 Proces 2 instalează alt mod
Folosesc resursa pe mod 2 de lucru pe resursa.
Folosesc resursa pe mod 1 Refacerea contextului la
........................ ........................ revenirea in procesul 1 nu e
suficenta pentru continurea
corecta a executiei aplicatiei
Exemple resurse
- citire AD
- iesire pe PWM
- citire/setare IN/OUT digitale
- o variabila din memorie (de orice tip)
- un numator
- un canal serial
etc
Reentranta neadecvat gestionată poate conduce si la pierderea consistenţei
datelor – stocate în memorie, registri IO, etc.
Reguli:
- o SC este executată de un singur task
- un task aşteaptă un timp finit înainte de o secţiune critică
- în afara secţiunii critice nu există alte blocaje
Metode de excludere mutuală
1. blocarea planificatorului înainte de intrarea în secţiunea critică
3. prin semafoare
Inversiunea de prioritate:
- un task mai putin prioritar conduce la întârzierea unui alt task mai prioritar.
- in acest caz ocupând o resursă la care cere ulterior acces şi taskul
mai prioritar
Task1 Resursa 1
Resursa 2
Task2
Soluţia:
eliberarea resurselor ocupate înainte de a cere acces la alta
II. 2. 4. 3. 1. Facilităţi FreeRTOS pentru lucrul cu semafoare
Semafor binar
Este util pentru excludere mutuală – un singur task poate ocupa la un moment
dat o resursa
Task1 Taskurile pot ajunge în orice ordine la
{ secvenţa critică.
..........
Take R Primul task care are nevoie de resursă, o
.....// instructiuni ce folosesc resursa R
ocupă şi pune semaforul pe roşu, până
termină operaţiile necesare cu acea
Give R resursă.
..............
} Dacă între timp alte taskuri au nevoie de
resursă, acestea găsesc semaforul pe roşu,
Task2 întră în blocare (conform detaliilor
{ precizate la cozi de mesaje).
..........
Take R La eliberarea resursei, toate taskurile
solicitante cu timeout convenabil devin
.....// instructiuni ce folosesc resursa R
gata de execuţie, cel mai prioritar va ocupa
Give R resursa.
.............. !!! Un task cu timeout mic poate
} pierde resursa, indiferent de
prioritate
Exercitii
Mod preemtiv, P_T1>P_T2>P_T3. Alte situatii P_T3=P_T1>P_T2,
P_T3=P_T2>P_T1.
T1 se blocheaza
(temporizare)
T3 si T1 blocate Se deblochează T2
T2 ready
T2 foloseste Take R
T2 foloseste GiveR
Se deblocheaza T1, T3. T1 este deblocat
T1 doreste Take R, intra (timeout nedepasit), T2 se blocheaza
in blocare executa Take R, cateva (temporizare)
instructiuni specifice si
apoi Give R.
T2 se blocheaza
(temporizare)
Se deblocheaza T1, T3.
T1 doreste Take R, intra T1 este deblocat
in blocare (timeout depasit, R
nefolosit in T1)
T2 foloseste GiveR si intra
in blocare
T2 foloseste T3 se deblocheaza
resursa
T1 si T2 blocate
T1 se blocheaza
T3 ready
(temporizare)
T3 foloseste Take R
T1 foloseste Give R,
T2 se deblocheaza (timeout
inca nedepasit), dar T2 nu
primeste procesorul
Probleme
Daca mai multe taskuri folosesc aceeasi resursa, pot exista probleme in
stabilirea timeout (mai ales daca exista si alte taskuri mai prioritare)
→ semafoarele binare sunt greu de gestionat daca sunt multe taskuri &
taskuri care partajeaza resursa
1.
T1 (prioritate 2) asigura un joc de leduri: aprinde ledurile 15, 14, 13 pentru 300 msec
apoi le stinge pentru alte 300msec, apoi aprinde doar ledul 14 pentru 300msec. Acest
joc nu trebuie distorsionat de alte taskuri, dar dupa o sectiune de joc, ledurile pot fi
folosite pentru alte semnalizari dorite. Sesiunea de joc este repetata la fiecare 4 sec.
T2 (prioritate 3) asigura alt joc de leduri: aprinde ledul 13 pentru 300 msec si apoi il
stinge pentru 300 msec. Sesiunea este reluata la fiecare 2 sec.
T3 (prioritate 4) cere schimbarea starii ledului 15 la fiecare 4 sec.
2. Semafoare de tip contor
Iniţial coada este plină, iar numărul resurselor = nr maxim de mesaje din
coada.
1. T1 (de prioritate 2) perioada 1 sec, T2 (de prioritate 3) – perioada 2 sec si T3 (de prioritate 4) –
perioada 1 sec – cer ocuparea unui canal serial pentru transmitere unor blocuri de date. Exista doar
2 canale seriale disponibile.
2. Se considera un cluster de resurse de tip led (led 15, 14, 13, 12). Ocuparea se face in aceasta
ordine (prioritar se ocupa led 15; led 12 este ocupat doar cand nu exista alte leduri libere)
T1 (de prioritate 2) – perioada 1 sec, T2 (de prioritate 2) – perioada 2 sec, T3 (de prioritate 3) –
perioada 1 sec, T4 (de prioritate 3) – perioada 2 sec, T5 (de prioritate 4) – perioada 1 sec - cer
ocuparea unui led (pentru o setare specifica): T1, T2 aprind ledul ocupat, T3, T4, T5 il sting.
3. T1 (de prioritate 2) - perioada 1 sec - citeste codul achizitionat de la AD1 si efectueaza niste
calcule. T2 (de prioritate 3) – perioada 3 sec - actualizeaza valoarea maxima achizitionata pana
atunci de la AD1.
Dacă un task (T1) care intră în blocare (atunci când cere acces la o resursă deja
ocupată) are prioritate mai mare decât taskul ce ocupă resursa (T2), atunci T2 este
temporar crescut în prioritate, pentru a grăbi execuţia sa şi eliberarea resursei.
Mutex recursiv
Un task poate trimite cereri suplimentare de ocupare a unei resurse, in timp ce este
deja proprietar pe ea. Pentru fiecare cerere de ocupare va exista o cerere de eliberare
pereche.
Resursa poate fi folosita de alte taskuri dupa rezolvarea tuturor acestor cereri de
ocupare (preluate de la taskul proprietar deja pe resursa).
Exercitiu: diferenta dintre semafor binar si mutex
T2 se blocheaza
(temporizare) T1 se blocheaza
T2 si T1 blocate
T3 ready (temporizare)
T3 foloseste Take R
T3 foloseste GiveR
Se deblocheaza T1, T2. T1 este deblocat
T1 doreste Take R, va (timeout nedepasit), T3 se blocheaza
intra in blocare executa Take R, cateva (temporizare)
instructiuni specifice si
apoi Give R.
Mutex. P_T1>P_T2>P_T3.
T1 se blocheaza T2 se blocheaza
(temporizare) (temporizare)
T2 si T1 blocate
T3 ready
T3 foloseste Take R
T3 T1T3T1 T1 T1T2 T2 T2 T3 T3 I I I
T1 se blocheaza T2 se blocheaza
(temporizare) (temporizare)
T2 si T1 blocate
T3 ready
T3 foloseste Take R
T3 T1T3T1 T1 T1T2 T2 T2 T3 T3 I I I
T1 (prioritate 2) asigura un joc de leduri: aprinde ledurile 15, 14, 13 pentru 300 msec
apoi le stinge pentru alte 300msec, apoi aprinde doar ledul 14 pentru 300msec. Acest
joc nu trebuie distorsionat de alte taskuri, dar dupa o sectiune de joc, ledurile pot fi
folosite pentru alte semnalizari dorite. Sesiunea de joc este repetata la fiecare 4 sec.
Din 12 in 12 secunde este dorita aplicarea (nepreemtata) a 2 sesiuni de joc succesive.
T2 (prioritate 3) asigura alt joc de leduri: aprinde ledul 13 pentru 300 msec si apoi il
stinge pentru 300 msec. Sesiunea este reluata la fiecare 2 sec si nu trebuie
distorsionata de alte taskuri.
T3 (prioritate 4) cere schimbarea starea ledului 15 la fiecare 8 sec.
Servicii API pentru lucrul cu semafoare (vezi queue.h si queue.c)
Creare semafor
Exemplu:
xSemaphoreHandle xSemaphore;
void vATask( void * pvParameters ){
vSemaphoreCreateBinary( xSemaphore );
if( xSemaphore != NULL ) {
// semafor creat cu succes.
}
}
xSemaphoreHandle xSemaphoreCreateCounting( unsigned portBASE_TYPE
uxMaxCount, unsigned portBASE_TYPE uxInitialCount )
uxMaxCount Valoare maxima contor. Daca aceasta valoare este atinsa, operatiile Give determina
intrarea in starea de blocare
uxInitialCount Valoare initiala
Exemplu:
void vATask( void * pvParameters ) {
xSemaphoreHandle xSemaphore;
xSemaphore = xSemaphoreCreateCounting( 10, 0 );
if( xSemaphore != NULL ) {
// semafor creat cu succes.
}
}
xSemaphoreHandle xSemaphoreCreateMutex( void )
Exemplu
xSemaphoreHandle xMutex;
xSemaphoreGiveRecursive( xMutex );
xSemaphoreGiveRecursive( xMutex );
xSemaphoreGiveRecursive( xMutex );}
else {
// mutex recursiv neprimit
}
}
}
Protecţii suplimentare pentru secţiuni critice
void initPLL(void){
// Configure PLL prescaler, PLL postscaler, PLL divisor
PLLFBD = 41; // M = 43 FRC
CLKDIVbits.PLLPOST=0; // N1 = 2
CLKDIVbits.PLLPRE=0; // N2 = 2
Situatii de discutat:
- cu/fara T3;
- cu timeout mai mic < del
- ce influenta poate avea valoarea lui del
xSemaphoreHandle xMineSemaphore;
portTickType no_tick;
void Task1(void *params) {
portTickType xLastTime = xTaskGetTickCount();
static unsigned int led;
for (;;){
if( xSemaphoreTake(xMineSemaphore,(portTickType) 15) == pdTRUE ){
//exista sigur cel putin un led liber; le ocup in ordinea 14, 13
if (led_14 ==1) {led_14=0; led=14;} else {led=13; led_13=0;}
vParTestToggleLED(led);
! vTaskDelay(10);
if (led==14) {led_14=1;} else led_13=1;
xSemaphoreGive( xMineSemaphore );}
vTaskDelayUntil(&xLastTime,1000);} Asigura ca taskul nu poate fi
} preemtat in ▄ de altul care doreste
acces la aceeasi resursa
void Task2(void *params) {
portTickType xLastTime = xTaskGetTickCount();
for (;;){
if( xSemaphoreTake(xMineSemaphore,(portTickType) 5) == pdTRUE ){
//exista sigur cel putin un led liber; le ocup in ordinea 14, 13
if (led_14 ==1) {led=14; led_14=0;} else {led=13; led_13=0;}
vParTestToggleLED(led);
vTaskDelay(10);
if (led==14) {led_14=1;} else led_13=1;
xSemaphoreGive( xMineSemaphore );}
vTaskDelayUntil(&xLastTime,2000);}
}
void Task3(void *params) {
portTickType xLastTime = xTaskGetTickCount();
for (;;){
if( xSemaphoreTake(xMineSemaphore,(portTickType) 5 ) == pdTRUE ){
//exista sigur cel putin un led liber; le ocup in ordinea 14, 13
if (led_14 ==1) {led=14; led_14=0;} else {led=13; led_13=0;}
vParTestToggleLED(led);
vTaskDelay(10);
if (led==14) {led_14=1;} else led_13=1;
xSemaphoreGive( xMineSemaphore );}
vTaskDelayUntil(&xLastTime,1000);
}}
void initPLL(void){
// Configure PLL prescaler, PLL postscaler, PLL divisor
PLLFBD = 41; // M = 43 FRC
CLKDIVbits.PLLPOST=0; // N1 = 2
CLKDIVbits.PLLPRE=0; // N2 = 2
Este permisă eliberarea unei zone de memorie ce a fost alocată, dar nu pot fi
concatenate blocuri de memorie.
o Taskurile pot fi create/ sterse dupa apelul vTaskStartScheduler(), dar
trebuie sa fie folosite cu aceeasi dimensiune a stivei
o Cozile pot fi create/ sterse dupa apelul vTaskStartScheduler(), dar
trebuie sa aibă aceeasi lungime.
→ memoria poate deveni fragmentată
3. (heap_3.c)
Cere în compilator implementări pentru malloc şi free.
+
Cere la linker să poată seta memoria heap
Taskuri
- periodice
- apriodice & sporadice
event driven:
când intervine un eveniment care modifică lista de taskuri ready
2. algoritmul de planificare - ce task primeşte procesorul într-un punct de
replanificare
Di
(deadline relativ)
procesi timp
ri di
activare ei termen limita
(release) (executie) (deadline absolut)
li Taski
rezerva
(laxity, slack)
intarziere
(tardeness)
Taski
Plan
La priorităţi dinamice:
verificare realizată de programator pe cazul cel mai nefavorabil – mai
dificil
există teroeme utile pentru cazuri simple, particulare.
II. 4. 2. Variante de planificare clock driven
Preemptiune la intervale egale de timp (un interval între două preemţiuni succesive
este numit cadru – „frame” şi are lungimea f)
Observatii:
- la algoritmii statici deciziile sunt stabilite offline.
- la algoritmii dinamici deciziile planificatorului sunt reînnoite la fiecare inceput
de cadru, în funcţie de taskurile găsite ready la acel moment;
la momentele de preempţiune, algoritmul de planificare poate
considera priorităţile taskurilor neschimbate (statice) sau le
poate actualiza (dinamice).
Pentru alegerea lui f pot fi respectate condiţiile:
Inceput t’+Di
cadru
t t’ = ri t+f t+2f
Ex: 0 2 4 6 8 10 12
T T (p = 10, f = 4)
F F F F
pentru t ' = t
taskul redevine ready la început de cadru ⇒ f ≤ Di
Exemple
f ≥ max ei ⇒ f ≥ 3
i =1,.., n
f ≤ Di : f ≤ 14 , f ≤ 6 , f ≤ 20
⇒ f ∈{3, 4, 5}
Aleg f = 5.
Secventa de executie pentru f = 5 si planificare dinamică (e1=1, e2= 3, e3=3)
f ≥ max ei ⇒ f ≥ 5
i =1,.., n
f divizor al unei perioade de task: ∈{1, 2, 4, 5, 10, 20}
f ≤ Di : f ≤ 4 , f ≤ 7 , f ≤ 20
⇒ imposibil:
F1-T2(2); F2-T1(1),T3(1); F3- T1 (1), T3(1); F4 –T2(2); F5 T1, T3(1); F6-T2; F7-
T1; F8-T3(2); F9-T2, F10- T1 plan admisibil
II. 4. 2. 2. Gestionarea priorităţilor taskurilor
1. T1: p1=2 sec, are de executat niste operatii cu e1 = 1 sec; D1 = 1.5 (sau 2)
T2: p2=1 sec, are de executat niste operatii cu e2 = 0.5sec; D2 = 0.7 (sau 1).
2. T1: p1=2 sec, are de executat niste operatii cu e1 = 1 sec; D1 = 1.5 (sau 2)
T2: p2=2 sec, are de executat niste operatii cu e2 = 0.5sec; D2 = 1.7 (sau 2).
3. T1: p1=2 sec, are de executat niste operatii cu e1 = 1 sec; D1 = 1.1 (sau 2)
T2: p2=2.5 sec, are de executat niste operatii cu e2 = 0.5sec; D2 = 1 (sau 2.5).
n e
U = ∑ i , cu
i =1 pi U ≤1
ei = timp executie task Ti
pi = perioada taskului Ti
n = numar taskuri
1 1 1 1
(pentru exemplul 1: + = + = 1)
p1 p 2 2 2
Algoritm EDF:
= asigneaza prioritatea maxima pentru taskul cu deadline-ul
absolut (di) cel mai apropiat, faţă de punctul de replanificare
curent.
Algoritm MLF:
= asigneaza prioritatea maxima pentru taskul cu rezerva (laxity)
mai mică, calculul acesteia fiind realizat în punctul de
replanificare curent.
Ex: r1 = 0, d1 = 10, e1 = 3
r2 = 2, d 2 = 14, e2 = 6
r3 = 4, d 3 = 12, e3 = 4 pentru f = 1.
Exemple MLF: T2 se poate executa dupa teminarea executiei pentru T1
T1, l1=3
e1=3 e2=2
T1 r1=0 T2 r2=5 T3, l3=3
d1=6 d2=8
1 3 2
e3=2 k
r3=2 T3
d3=7 l= d–r-e
T2, l2=1
T3
e1=3 e2=2
T1 r1=0 T2 r2=5
d1=6 d2=8
1 3 2
k
T3
e1=2 e2=2
T1 r1=0 T2 r2=5
d1=10 d2=8 3 2 3 1
k k
T2
e3=4
T3 l1=6 l1=3
r3=2
l3=3 l3=3 l1=1
d3=9
l2=1 l3=1
Demo:
Orice plan admisibil poate fi transformat intr-un plan admisibil produs cu EDF
rk dk di
Ti Tk
rk dk di
Tk Tk Ti
Pentru taskuri nonpreemptive EDF nu este optimal
Ex: r1 = 0, d1 = 10, e1 = 3
r2 = 2, d 2 = 14, e2 = 6
r3 = 4, d 3 = 12, e3 = 4
Teorema2:
Ipoteze: caz monoprocesor, mod preemptiv, taskuri independente.
MLF (Earliest Deadline First) este optimal
Exercitii
2. 5 taskuri: A, B, C, D, E: faza 0, Di = pi
A, B, C: perioada 2, timp executie 1
D, E perioada 8, timp executie 6
a) indicati planul MLF pe 3 procesoare
b) gasiti un plan admisibil pe 3 procesoare
c) refaceti a) pentru taskuri cu aceeasi perioada 2 si timp de executie 1.
Tratarea taskurilor non-periodice
Ipoteze:
1. STR are n taskuri periodice, n= fix
2. parametrii taskurilor sunt cunoscuti
3. niciun task aperiodice nu este critic (nu exista taskuri sporadice)
Variante de lucru:
Taskurile aper. ready sunt introduse într-o listă separată, fără activarea
planificatorului
Procesorul execută taskuri aperiodice din această listă, DOAR atunci cand
nu trebuie executate taskuri periodice.
1. Taskurile aper. sunt introduse în listă fără a le verifica indeplinirea deadline-
ului.
A4: 5 >4.5
Reject A1
A4(44,5)
A1:4.5> 4
S2
3.5 7 10 15 23.5 27 30
19 35 39
4 8 12 16 20 24 28 36
32 40
1 2 3 4 5 6 7 8
hiperperioada hiperperioada
Accept A2
A2: 4 < 5,5
Accept A3
A3: 1,5 <=2 Notatie: A(d, e)
A2: rest 2, rezerva cu A3 1,5
EDF ciclic este optimal:
= poate gasi un plan admisibil pentru taskurile aperiodice
preemptive acceptate,
daca testul de acceptanta este facut la inceputul fiecarui cadru
ATENTIE!!!!:
EDF ciclic nu este optimal daca e comparat cu algoritmi care fac testul de
acceptanta oriunde (ex: se poate accepta S1),
dar e avantajos pentru takurile periodice (nu se ajunge la nr. mare
de preemptiuni)