Documente Academic
Documente Profesional
Documente Cultură
Figura 1
Un exemplu minimal de sistem care foloseste perifericul GPIO pentru a comanda ledurile de
pe placa de dezvoltare este prezentat ın Fig. 2. Acest sistem contine un microprocesor cu memoria
aferenta, iar comunicarea dintre procesor si perifericul GPIO (LEDs 8Bit) este realizata prin
intermediul magistralei PLB.
Figura 2
Perifericul prezinta 4 registri catre exterior, prezentati ın Tabelul 2-1, cate doi pentru fiecare
canal.Registrii interni GPIO DATA si READ REG IN sunt accesati din exterior ca un singur registru,
citirea facandu-se din READ REG IN iar scrierea ın GPIO DATA. Marimea porturilor este de maxim
32 de biti, adica de 4 octeti. Spatiul de adresare este aliniat la 1 octet, motiv pentru care registrii
succesivi ai perifericului sunt aliniati la multipli de 4 octeti. In cazul configurarii perifericului ca avand
un singur canal, citirea registrilor GPIO DATA1 si GPIO TRI1 va avea ıntotdeauna ca rezultat
valoarea 0.
Urmatorul program prezinta un mod simplu de accesare a perifericului GPIO ai carui pini sunt
conectati la ledurile disponibile pe platforma de dezvoltare. Arhitectura minimala a sistemului pe
care ruleaza acest exemplu este cea din Fig.2
#include "xparameters.h"
//xparameters.h contine o serie de constante reprezentand parametri ai sistemului,
//inclusiv adresele de baza ale perifericelor componente
unsigned *led = (unsigned *)XPAR_LEDS_8BIT_BASEADDR; //pointer la adresa de baza
#include "xparameters.h"
//pointer la adresa de baza a perifericului LEDs_8Bit:
unsigned *led = (unsigned *)XPAR_LEDS_8BIT_BASEADDR;
//pointer la adresa de baza a perifericului DIP_Switches_4Bit:
unsigned *switchuri = (unsigned *)XPAR_DIP_SWITCHES_4BIT_BASEADDR;
int main(void)
{
while(1)
{
//switchuri[0] contine valoarea switch-urilor
led[0] = switchuri[0]; //citeste starea switch-urilor si o afiseaza pe led-uri
}
return 1;
}
2. Utilizarea intreruperilor
Pentru a facilita lucrul cu ıntreruperile, perifericul GPIO contine hardware dedicat care
detecteaza orice modificare la oricare dintre pinii aferenti unui canal. Configuratia implicita a
perifericului nu ofera aceasta functionalitate, ea trebuind sa fie setata manual de catre utilizator.
Aceasta se realizeaza din System Assembly View printr-un dublu click pe numele perifericului GPIO,
apoi bifarea optiunii GPIO Supports Interrupts ın tab-ul User, meniul Common din fereastra nou
deschisa.
Registrii care controleaza functionarea cu ıntreruperi a GPIO sunt prezentati ın Tabelul 2-2.
In modul Toggle on Write (TOW), scrierea unui bit de 1 produce bascularea valorii bitului de
pe pozitia corespunzatoare din registru, realizandu-se practic o operatie de sau-exclusiv pe biti ıntre
cuvantul stocat ın registru si cuvantul scris. De exemplu, daca un registru contine valoarea 0110 ın
binar si este scris ın mod TOW cu valoarea 0011, rezultatul va fi 0101 (ultimii doi biti ısi schimba
valoarea).
Registrul GIER ofera activarea/dezactivarea primara a iesirii de ıntrerupere a perifericului. Activarea
se face prin setarea ın 1 a bitului 31 (MSB) a GIER (valoare 0 pentru dezactivare).
Activarea ıntreruperilor pentru fiecare canal este realizata cu ajutorul registrului IER, prin setarea ın
1 a bitului 0 (LSB) pentru canalul 1, respectiv a bitului 1 pentru canalul 2. Dezactivarea se realizeaza
prin setarea ın 0 a bitilor corespunzatori. Intreruperile de la pinii de intrare ai GPIO sunt semnalizate
prin intermediul registrului ISR. Valoarea 1 ınscrisa pe pozitia 0 (LSB), respectiv 1 din registru
semnaleaza o ıntrerupere primita pe canalul 1, respectiv 2. Acesti biti pot fi resetati ın modul TOW.
Un exemplu de citire a switchurilor folosind ıntreruperi este prezentat ın codul de mai jos. Programul
presupune ca perifericul GPIO DIP Switches 4Bit este singura sursa de ıntreruperi din sistem, nefiind
necesara adaugarea si configurarea unui controller de ıntreruperi. Pentru o astfel de functionare ın
ıntreruperi, este necesara realizarea unei conexiuni ın tab-ul System Assembly View -> Ports ıntre
portul IP2INTC Irpt al perifericului si portul Interrupt al procesorului MicroBlaze.
#include "xparameters.h"
#include "mb_interface.h"
3. Instantierea perifericului
Perifericul GPIO se poate instantia utilizand Base System Builder sau, dupa generarea sistemului,
el poate fi instantiat din tab-ul IP Catalog, optiunea General Purpose IO -> General Purpose IO.
Dupa instantiere:
1. In tab-ul System Assembly View -> Bus Interfaces conectati portul SPLB al perifericului la
magistrala standard a sistemului mb plb.
2. In tab-ul System Assembly View -> Bus Interfaces dati dublu click pe numele perifericului. In
fereastra nou deschisa ın tab-ul User, meniul Channel 1 setati numarul de biti corespunzatori
aplicatiei la optiunea GPIO Data Channel Width.
3. In tab-ul System Assembly View -> Addresses specificati marimea si locatia spatiului de adrese
ın care se va mapa acest periferic sau apasati butonul Generate Addresses si ele vor fi configurate
automat.
4. In tab-ul System Assembly View -> Ports specificati semnalele GPIO IO I ın cazul folosirii
perifericului pentru intrari, respectiv GPIO IO O ın cazul folosirii perifericului pentru iesiri ca
fiind semnale externe.
Butonul rotativ codifica miscarea circulara folosind doua semnale A si B generate de doua
butoane. Aceste doua butoane, din constructia interna prezentata ın Fig.3a, sunt actionate de rotirea
unui disc descentrat. Miscarea de rotire cu un pas, ıntr-un sens sau altul, genereaza o succesiune
specifica de stari ale semnalelor A si B prezentate ın Fig.3b. La ınceputul rotirii cu un pas, depinzand
de sensul miscarii, unul din butoane va fi ın pozitie deschisa ınaintea celuilalt. De asemenea, la
sfarsitul efectuarii pasului, primul buton se va ınchide ınaintea celui de-al doilea.
Figura 3
Pentru folosirea butonului rotativ se vor urma pasii descrisi la Instantierea perifericului,
setand numarul de biti necesari, ın acest caz, la 2.
Programul prezentat mai jos realizeaza decodificarea semnalelor. Ideea de baza consta ın
modelarea unui automat de stare prin care se poate detecta parcurgerea succesiunii de semnale aferente
rotirii la dreapta sau la stanga.
5. Perifericul timer
Modulul xps timer, care se ataseaza la bus-ul PLB, contine 2 timere, configurabile din punct
de vedere al numarului de biti (ıntre 8-32) si al valorii de la/pana la care numara. Fiecare timer
poate fi configurat pentru generare de semnale/ıntreruperi sau pentru a detecta evenimente (semnale
externe). Daca cele doua timere sunt vazute ca o pereche, se poate obtine o functionare ın mod PWM.
Un exemplu de structura a unui sistem care foloseste acest modul este prezentat ın Fig. 4.
Figura 4
Figura 5
6. Organizarea registrilor
Registrii perifericului timer, fiecare a cate 32 de biti, sunt prezentati ın Tabelul 2-22.
Semnificatia bitilor din registrii TCSRx este descrisa ın Tabelul 2-23. Registrul de ıncarcare contine
valoarea cu care se va ıncarca registrul de numarare. Incarcarea se face fie prin scrierea registrului
TCSRx cu bitul LOAD setat ın 1, fie automat la overflow (underflow) daca timerul este ın mod
autoreload.
Registrul de numarare contine valoarea curenta la care a ajuns numaratorul. Acest registru poate
sa fie doar citit, scrierea lui cu o valoare facandu-se prin intermediul registrului de ıncarcare.
7. Modul de generare
Prin setarea unui timer ın modul de generare (bitul MDT din TCSR ın 1) se poate masura timpul,
exprimat ın numar de tacte de ceas. Cel mai des scenariu de utilizare este implementarea unei ıntarzieri
(delay) cu valoare exacta (de exemplu 1 secunda). Terminarea numararii poate fi detectata prin citirea
repetata a registrului de numarare (polling) sau prin generarea unei ıntreruperi de catre periferic.
In functie de setarea bitului UDT din registrul de control/stare, timerul numara crescator sau
descrescator. Este important de stiut ca ın functie de cum este setata directia de numarare, intervalul
de timp va avea valori diferite. Daca timerul este setat sa numere descrescator:
unde
iar numarul de biti poate sa fie setat pentru fiecare timer (valoarea implicita este 32). PLBclockperiod
este perioada ceasului magistralei la care este conectat perifericul (ın general 20 ns).
Numararea dureaza pana cand se depaseste valoarea maxima (overflow -in cazul numararii
crescatoare) sau se scade sub 0 (underflow - ın cazul numararii descrescatoare). In functie de cum a
fost setat bitul ARHT, timerul reıncarca valoarea din TLRx si reıncepe numaratoarea, sau se opreste.
Daca timerul este setat sa genereze ıntreruperi, la terminarea numararii se genereaza o ıntrerupere, iar
bitul TINT din registrul TCSRx va fi ın 1 la citirea acestuia. In rutina de tratare a ıntreruperii,
ıntreruperea poate fi invalidata prin scrierea registrului TCSRx cu bitul TINT ın 1.
In cele ce urmeaza este prezentat un exemplu de folosire a perifericului ın mod de generare.
#include "xparameters.h"
unsigned *led=(unsigned *) XPAR_LEDS_8BIT_BASEADDR;
unsigned *timer=(unsigned *) XPAR_XPS_TIMER_0_BASEADDR;
int main(void)
{
unsigned valoare_led=0xFF;
//asignam o valoare registrului de incarcare
timer[0x04/4]=50000000;
while(1)
{
led[0]=valoare_led;
//incarcam registrul numarator prin scrierea bitului LOAD
timer[0]=0x020;
//pornim timerul
//urmatorii biti din registrul de stare/control sunt setati in 1
//bitul 1 (UDT0), timerul numara descrescator
//bitul 7 (ENT0), pentru a activa timerul
timer[0]=0x082;
while(timer[0x08/4]!=-1);
//in cazul numararii descrescatoare timerul se opreste dupa ce scade sub 0
valoare_led=valoare_led^0xFF;
}
return 1;
}
8. Modul de capturare
Prin folosirea acestui mod se poate masura intervalul de timp dintre doua fronturi (crescatoare sau
descrescatoare) ale unui semnal extern. Aceasta valoare este stocata ın registrul TLRx. Terminarea
masurarii este semnalata prin setarea bitului TINT, generandu-se o ıntrerupere (ın cazul ın care sunt
activate ıntreruperile). In acest mod, daca ARHT=0 si TINT=1, valoarea din registrul TLRx nu va fi
suprascrisa de valoarea numaratorului la detectarea unui front al semnalului extern. In toate celelalte
cazuri TLRx va fi suprascris la aparitia unui nou eveniment de captura. Semnalul extern este
esantionat de catre periferic cu frecventa ceasului magistralei PLB. Prin setarea
parametrului TRIGx Active Level (printr-un dublu click pe numele perifericului din System Assembly
View -> Bus Interfaces) se poate selecta tipul frontului care va fi detectat: prin setarea ın 1 se va
detecta un front crescator iar prin setarea ın 0 se va detecta un front descrescator al semnalului extern.
In cele ce urmeaza este prezentat un exemplu de cod C pentru folosirea perifericului ın mod de
capturare.
#include "xparameters.h"
unsigned *timer = (unsigned *)XPAR_XPS_TIMER_0_BASEADDR;
int aux = 0;
int main(void)
{
//configurarea registrului de stare/control
//ENALL activeaza timer-ul 0 si timer-ul 1
//ENT0 activeaza timer-ul 0
//ARTH0 suprascrierea valorii captate
//CAPT0 activeaza semnalul de captura
//MDT0 setarea timer-ului in mod captura
timer[0x00/4] = 0x499;
timer[0x04/4] = 0;
while(1) //bucla infinita
{
if (aux != timer[0x04/4])
{
//cand este apasat butonul "BtnWest" D18
//valoarea din counter este trecuta in registrul de incarcare
xil_printf("Valoarea veche: %d ",aux);
xil_printf("Valoarea noua: %d ",timer[1]);
aux = timer[0x04/4];
}
}
return 1;
}