Sunteți pe pagina 1din 39

Universitatea Transilvania Braşov

Facultatea de Inginerie Electrică şi


Ştiinţa Calculatoarelor

Îndrumar

Zoltán Gáspár
<>

BRAŞOV
ii
Cuprins

1 Introducere 1
1.1 Crearea unui proiect in Xilinx EDK 12.1 . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.1 Crearea unei noi aplicaţii software . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.2 Hello world . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Adăugarea unui nou periferic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 De la crearea proiectului in EDK la funcţionarea lui pe placă . . . . . . . . . . . . . . 5

2 Lucrul cu periferice 7
2.1 Perifericul de uz general pentru intrări-ieşiri (GPIO) . . . . . . . . . . . . . . . . . . . 8
2.1.1 Organizarea regiştrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.2 Lucrul cu ı̂ntreruperile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.1.3 Folosirea butonului rotativ cu GPIO . . . . . . . . . . . . . . . . . . . . . . . . 12
2.1.4 Exerciţii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2 Perifericul pentru comunicaţii seriale (UART Lite) . . . . . . . . . . . . . . . . . . . . 15
2.2.1 Organizarea regiştrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2.2 Exemple de folosire a perifericului . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2.3 Exerciţii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.3 PS/2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.3.1 Organizarea regiştrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.3.2 Adăugarea perifericului . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.3.3 Tastatura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.3.4 Mouseul . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3.5 Exerciţii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.4 Perifericul de comandă a afişajului LCD . . . . . . . . . . . . . . . . . . . . . . . . . . 25

iii
2.4.1 Organizarea regiştrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.4.2 Adăugarea perifericului . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.4.3 Aplicaţii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.4.4 Exerciţii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.5 Controller-ul VGA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.5.1 Organizarea regiştrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.5.2 Adăugarea perifericului . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.5.3 Aplicaţii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.5.4 Exerciţii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

iv
CAPITOLUL 1

Introducere

1.1 Crearea unui proiect in Xilinx EDK 12.1

Pentru crearea unui proiect ı̂n mediul Xilinx Platform Studio din cadrul pachetului EDK, cea mai
simplă metodă este folosirea wizard-ului Base System Builder, accesibil la pornirea aplicaţiei (Fig.
1-1). După selectarea acestei opţiuni, wizard-ul ne va trece prin o serie de ferestre ı̂n care putem
configura sistemul pe care dorim să ı̂l creăm.
Primul pas ı̂n crearea proiectului este selectarea directorului de lucru ı̂n care se vor crea automat
fişierele necesare. Se recomandă ca numele directorului de lucru şi a tuturor directoarelor din calea
către acesta să nu conţină spaţii sau caractere diacritice. Numele proiectului trebuie să fie system.xmp.
În prima fereastră a Base System Builder selectaţi opţiunea I would like to create a new design şi
apăsaţi butonul Next conform Fig. 1-2a.

Figura 1-1: Pornirea wizard-ului Base System Builder.

1
1 Introducere 2

(a) Prima fereastră (b) Selectarea plăcii de dezvoltare

Figura 1-2: Crearea unui proiect nou

(a) Sistem uniprocesor (b) Configurarea procesorului

Figura 1-3: Crearea unui proiect nou

În cadrul ferestrei de selectare a plăcii de dezvoltare (Board selection) se lasă opţiunea selectată
implicit I would like to create a system for the following developement board. La opţiunea Board
vendor se selectează Xilinx, la opţiunea Board name se selectează Spartan-3E Starter Board, iar la
Board revision opţiunea ”C” (Fig.1-2b). În cazul ı̂n care ı̂n lista Board name nu găsiţi opţiunea
Spartan-3E Starter Board urmaţi paşii descrişi la ”Instalarea şi configurarea Xilinx EDK”.
În următoarea fereastră lăsaţi selectată opţiunea implicită de sistem uniprocesor (Single-Procesor
system), conform Fig.1-3a. Folosirea sistemelor cu mai multe procesoare va fi descrisă ı̂ntr-un capitol
ulterior.
Fereastra de configurare a procesorului (Fig.1-3b) permite selectarea frecvenţei ceasului de referinţă,
alegerea tipului de procesor (ı̂n cazul Spartan-3E singura opţiune disponibilă este MicroBlaze), se-
lectarea frecvenţei ceasului de sistem şi a dimensiunii memoriei locale (BRAM) utilizate. De asemenea,
ı̂n cazul procesorului MicroBlaze, se poate opta pentru adăugarea unei unităţi de calcul ı̂n virgulă
mobilă (Floating Point Unit - FPU). Majoritatea programelor prezentate ulterior vor rula pe sisteme
configurate cu opţiunile implicite din această fereastră.
Următoarea fereastră (Fig.1-4a) permite selectarea perifericelor ce vor fi adăugate automat la sistem.
Configurarea unor parametri ai perifericului se realizează printr-un click pe numele acestuia.
3 Crearea unui proiect in Xilinx EDK 12.1

(a) Adăugarea perifericelor (b) Configurarea aplicaţiilor

Figura 1-4: Crearea unui proiect nou

Dacă s-au selectat ca şi periferice memorii externe (DDR, Flash etc.) se poate selecta opţiunea să
fie accesate printr-un cache. Din considerente de simplitate, pentru moment lăsaţi această opţiune
neselectată.
Ca şi aplicaţii software, implicit se generează două aplicaţii de test, pentru memorie şi periferice,
cu ajutorul cărora se poate valida funcţionarea corectă a hardware-ului. Pentru folosirea terminalului
XMD (recomandat) la parametrul Standard IO selectaţi opţiunea mdm 0, conform Fig. 1-4b.
Ultima fereastră din cadrul wizard-ului Base System Builder prezintă un sumar al sistemului creat,
incluzând o listă a componentelor sistemului şi adreselor lor, precum şi o listă a fişierelor generate ı̂n
cadrul proiectului. Un click pe butonul Finish va determina finalizarea generării proiectului.

1.1.1 Crearea unei noi aplicaţii software

Având structura sistemului harware definit, se poate trece la definirea aplicaţiilor care vor rula pe
acest hardware. Trebuie menţionat faptul că pentru o structură hardware se pot defini mai multe
aplicaţii software care să ruleze pe aceasta. Pentru selectarea aplicaţiei software care va rula pe
procesor din memoria BRAM se dă click dreapta pe numele aplicaţiei şi se selectează opţiunea Mark
to Initialize BRAMs.
Pentru crearea unei noi aplicaţii software, ı̂n tabul Applications se apasă pe opţiunea Add Software
Application Project (ı̂n layout-ul standard se găseşte ı̂n partea de stânga sus a ferestrei). În fereastra
de dialog nou deschisă se introduce numele aplicaţiei şi se selectează procesorul pe care va rula aceasta.
Opţiunea Project is ELF-only Project se lasă deselectată. După crearea noii aplicaţii software trebuie
create (sau adăugate) fişierele .c sau .cpp care conţin codul sursă al aplicaţiei. Aceasta se realizează
printr-un click dreapta pe itemul Sources din cadrul aplicaţiei şi selectarea uneia dintre opţiunile Add
Existing Files sau Add New File.
Implicit compilatorul este setat pe modul de optimizare Medium (-O2). Se recomandă setarea
lui pe nivelul No optimization pentru a evita unele situaţii neplăcute, ı̂n care compilatorul modifică
funcţionarea aşteptată a programului. Această setare se poate face dând click dreapta pe numele
aplicaţiei şi selectarea opţiunii Set Compiler Options. În fereastra nou deschisă, se selectează al doilea
1 Introducere 4

Figura 1-5: Crearea unei aplicaţii software - Setarea modului de optimizare a compilatorului

tab: Debug and Optimization, iar setarea se face la opţiunea Optimization Level, conform Fig.1-5.

1.1.2 Hello world

O primă aplicaţie care se poate realiza este cea de a trasmite serial un text către calculator: un
program ”Hello world”, prezentat mai jos. Se poate remarca folosirea funcţiei xil printf ı̂n locul funcţiei
printf din bilbioteca standard C. Motivul este cel de a avea un cod sursă de dimensiuni reduse, lucru
esenţial când programul rulează din memoria BRAM.

int main(void)
{
xil_printf("Hello world!");
return 1;
}

Un alt lucru de remarcat este că mediul de dezvoltare EDK adaugă implicit un set de biblioteci
standard, motiv pentru care acestea nu trebuie incluse neapărat la ı̂nceputul codului sursă.
Pentru a vizualiza textul ”Hello world!” este necesară deschiderea unui terminal de comunicaţii
seriale emulat prin interfaţa de debug. Acest lucru se face prin selectarea opţiunii Debug-> Launch
XMD din fereastra principală a Xilinx Platform Studio. După un click pe butonul Ok din fereastra nou
apărută (XMD Debug Options) se va deschide consola de debug XMD (Fig. 1-6a). Comenzile pot fi
introduse ı̂n această consolă după prompterul XMD%. Introducerea comenzii terminal va determina
deschiderea unui terminal de comunicaţii seriale (Fig. 1-6b), cu ajutorul căruia se poate vizualiza
rezultatul rulării aplicaţiei ”Hello world”.

1.2 Adăugarea unui nou periferic

Adăugarea unui periferic nou la un proiect generat ı̂n prealabil va fi exemplificată prin adăugarea
unui periferic de intrare/ieşire de uz general (General Purpose Input/Output - GPIO) pentru interfaţarea
cu butonul rotativ disponibil pe placa de dezvoltare Spartan-3E. O prezentare mai detaliată a funcţionării
GPIO şi a utilizării butonului rotativ poate fi găsită ı̂n secţiunea 2.1.
După deschiderea proiectului, perifericul se instanţiază din tab-ul IP Catalog, printr-un dublu click
pe opţiunea General Purpose IO -> XPS General Purpose IO. După instanţiere:
5 De la crearea proiectului in EDK la funcţionarea lui pe placă

(a) Consola de debug XMD (b) Terminalul de comunicaţii seriale XMD

Figura 1-6: Utilitare pentru depanarea software

(a) Generarea listei de conexiuni (b) Generarea bitstream-ului

Figura 1-7: Generarea platformei hardware

1. În tab-ul System Assembly View-> Bus Interfaces conectaţi perifericul la magistrala standard a
sistemului mb plb.
2. În tab-ul System Assembly View -> Addresses specificaţi mărimea şi locaţia spaţiului de adrese
ı̂n care se va mapa acest periferic sau apăsaţi butonul Generate Addresses şi ele vor fi configurate
automat.
3. În tab-ul System Assembly View -> Ports, configuraţi perifericul GPIO printr-un dublu click pe
numele instanţei perifericului, setând ı̂n tab-ul User, meniul Channel 1 parametrul GPIO Data
Channel Width cu valoarea 2 şi Channel 1 is Input Only cu valoarea TRUE.
4. În tab-ul System Assembly View -> Ports specificaţi portul de intrare GPIO IO I al perifericului
ca fiind extern prin schimbarea opţiunii No Connection ı̂n Make External.
5. În tab-ul Project deschideţi fişierul UCF (dublu click pe data/system.ucf ) şi adăugaţi liniile de
mai jos pentru a asigna pinii circuitului FPGA la portul extern al perifericului.

Net xps_gpio_0_GPIO_IO_I_pin<0> LOC=K18 | IOSTANDARD = LVCMOS33 | PULLUP;


Net xps_gpio_0_GPIO_IO_I_pin<1> LOC=G18 | IOSTANDARD = LVCMOS33 | PULLUP;

1.3 De la crearea proiectului in EDK la funcţionarea lui pe placă

La apăsarea butonului de download bitstream ı̂n EDK se initiază o serie de operaţii care sinte-
tizează partea hardware şi compilează partea software, procese care sunt ı̂nglobeate ı̂ntr-un aşa numit
bitstream care va fi ı̂ncărcat ı̂n FPGA.
Procesul de generare a platformei hardware este prezentat ı̂n Fig. 1-7.
1 Introducere 6

(a) Generarea fişierului exe- (b) Actualizarea bitstream-ului


cutabil

Figura 1-8: Adăugarea părţii software la bitstream

Platforma hardware este descrisă ı̂n fişierul MHS (Microprocessor Hardeware Specification) din
cadrul proiectului. Această descriere este procesată de utilitarul Platgen, care generează descrierea
HDL top level a sistemului. Împreună cu modulele HDL ale procesorului şi perifericelor utilitarul XST
(Xilinx Synthesis Technology) generează lista de conexiuni (fişier NGC).
Generarea fişierului bitstream se face cu ajutorul utilitarelor Xilinx ISE care sunt apelate prin
intermediul XFlow conform Fig. 1-7b. În cadrul acestui proces se folosesc constrângerile, referitoare
la maparea semnalelor la pinii FPGA, descrise ı̂n fişierul UCF.
Platforma, din punct de vedere software, este descrisă ı̂n fişierul MSS (Microprocessor Software
Specification). Descrierea este procesată de utilitarul LibGen care generează o serie de biblioteci
aferente procesorului şi drivere asociate perifericelor din sistem. Fişierele sursă sunt compilate cu
ajutorul utilitarului GCC, iar linkeditorul generează fişierul executabil ELF.
Ca şi ultim pas al procesului utilitarul Data2Mem actualiează proţiunile din bistream care corespund
memorilor cu codul executabil conform Fig. 1-8b.
CAPITOLUL 2

Lucrul cu periferice

7
2 Lucrul cu periferice 8

2.1 Perifericul de uz general pentru intrări-ieşiri (GPIO)

Perifericul de uz general de intrări-ieşiri (General Purpose Input/Output - GPIO) permite accesul


la pinii de intrare-ieşire ai circuitului FPGA prin intermediul magistralei PLB. Folosind acest periferic
se pot defini grupuri de pini de lungime maximă de 32 de biţi care să poată fi citiţi sau scrişi
prin intermediul software. Acest periferic poate fi folosit la comanda LED-urilor, respectiv citirea
stării butoanelor sau a switch-urilor. În afară de comanda acestor periferice simple, modulul oferă
posibilitatea emulării din software a unor protocoale complexe prin accesul direct la pini pe care ı̂l
oferă.
Perifericul GPIO se poate configura ca având unul sau două canale. Fiecare canal poate avea de
la 1 la 32 de biţi, numărul şi direcţia (pin de intrare sau ieşire) configurabile individual pe canal,
respectiv bit. De asemenea, se pot configura valorile la reset pentru fiecare bit din ambele canale. O
altă facilitate oferită de acest periferic este capacitatea de a genera ı̂ntreruperi la schimbările valorilor
de intrare a pinilor. Structura internă a perifericului este prezentată ı̂n Fig. 2-1.
Pentru a folosi portul ca intrare se vor seta toţi biţii din registrul GPIO TRI ı̂n 1 pentru a seta buffer-
ul tri-state ı̂n starea de ı̂naltă impedanţă, iar valorile pinilor se vor regăsi ı̂n registrul READ REG IN.
În cazul folosirii portului ca unul de ieşire biţii din registrul GPIO TRI se vor seta ı̂n valoarea 0,
permiţând scrierea datelor din registrul GPIO DATA către pini. Ca o consecinţă, dacă portul este
setat ca unul de ieşire, datele din READ REG IN vor coincide cu GPIO DATA.
Un exemplu minimal pentru un sistem care foloseşte perifericul GPIO pentru a comanda ledurile
de pe placa de dezvoltare este prezentat ı̂n Fig. 2-2. Acest sistem conţine un microprocesor, cu
memoria aferentă, iar comunicarea dintre procesor şi perifericul GPIO (LEDs 8Bit) este realizată prin
intermediul magistralei PLB.

2.1.1 Organizarea regiştrilor

Perifericul prezintă 4 regiştri către exterior, prezentaţi ı̂n Tabelul 2-1, câte doi pentru fiecare canal.
Regiştrii interni GPIO DATA şi READ REG IN sunt accesaţi din exterior ca un singur registru, citirea
făcându-se din READ REG IN iar scrierea ı̂n GPIO DATA.
Tabelul 2-1: Maparea regiştriilor GPIO ı̂n spaţiul de adrese

Nume registru Descriere Adresă Tip acces


GPIO DATA Valoarea de la canalul 1 Adresă de bază + 0x00 Scriere/ Citire
GPIO TRI Registrul tri-state aferent canalului 1 Adresă de bază + 0x04 Scriere/ Citire
GPIO DATA1 Valoarea de la canalul 2 Adresă de bază + 0x08 Scriere/ Citire
GPIO TRI1 Registrul tri-state aferent canalului 2 Adresă de bază + 0x0C Scriere/ Citire

Mărimea porturilor este de maxim 32 de biţi, adică de 4 byte. Spaţiul de adresare este aliniat la 1
byte, motiv pentru care regiştrii succesivi ai perifericului sunt aliniaţi la multipli de 4 byte.
În cazul setării perifericului ca având un singur canal, citirea regiştrilor GPIO DATA1 şi GPIO TRI1
va avea ı̂ntotdeauna ca rezultat valoarea 0.
Urmatorul program prezintă un mod simplu de a accesa perifericul GPIO ai cărui pini sunt conectaţi
la ledurile disponibile pe platforma de dezvoltare. Arhitectura minimală a sistemului pe care rulează
acest exemplu este cea din Fig. 2-2.

//Cod C pentru configurarea ledurilor


9 Perifericul de uz general pentru intrări-ieşiri (GPIO)

Figura 2-1: Structura internă a GPIO

unsigned *led = (unsigned *)0x81400000; //pointer la adresa de baza


//a perifericului LEDs_8Bit

int main(void)
{
//led[0] -> accesarea registrului 0 al perifericului LEDs_8Bit
//registrul 0 contine datele de pe portul de iesire
//0xAA = 10101010 in binar, unde 1 reprezinta led aprins iar 0 led stins
led[0] = 0xAA;

return 1;
}

Un exemplu de citire a datelor de la perifericul GPIO este prezentat mai jos:

//Cod C pentru citirea switchurilor

unsigned *led = (unsigned *)0x81400000; //pointer la adresa de baza


//a perifericului LEDs_8Bit
2 Lucrul cu periferice 10

Figura 2-2: Structura unui sistem cu GPIO

unsigned *switchuri = (unsigned *)0x81420000; //pointer la adresa de baza


//a perifericului DIP_Switches_4Bit

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.1.2 Lucrul cu ı̂ntreruperile

Pentru a facilita lucrul cu ı̂ntreruperile, perifericul GPIO conţine hardware dedicat care detectează
orice modificare la oricare dintre pinii aferenţi unui canal. Setarea implicită a perifericului nu oferă
această funcţionalitate, ea trebuind să fie setată manual de către utilizator. Aceasta se realizează
din System Assembly View printr-un dublu click pe numele perifericului GPIO, apoi bifarea opţiunii
GPIO Supports Interrupts ı̂n tab-ul User, meniul Common din fereastra nou deschisă.
11 Perifericul de uz general pentru intrări-ieşiri (GPIO)

Regiştrii care controlează funcţionarea ı̂n ı̂ntreruperi a GPIO sunt prezentaţi ı̂n Tabelul 2-2.

Tabelul 2-2: Maparea regiştriilor de ı̂ntreruperi GPIO ı̂n spaţiul de adrese

Nume registru Descriere Adresă Tip acces


GIER Global Interrupt Enable Register Adresă de bază + 0x11C Scriere/ Citire
IP IER IP Interrupt Enable Register Adresă de bază + 0x128 Scriere/ Citire
IP ISR IP Interrupt Status Register Adresă de bază + 0x120 Citire/ TOW

În modul Toggle on Write (TOW), scrierea unui bit de 1 produce bascularea valorii bitului din
registru de pe poziţia corespunzătoare, realizându-se practic o operaţie de sau-exclusiv pe biţi ı̂ntre
cuvântul stocat ı̂n registru şi cuvântul scris. De exemplu, dacă un registru conţine valoarea 0110 ı̂n
binar şi este scris ı̂n mod TOW cu valoarea 0011, rezultatul va fi 0101 (ultimii doi biţi ı̂şi schimbă
valoarea).
Registrul GIER oferă activarea/dezactivarea primară a ieşirii de ı̂ntrerupere a perifericului. Acti-
varea se face prin setarea ı̂n 1 a bitului 31 (MSB) a GIER (valoare 0 pentru dezactivare).
Activarea ı̂ntreruperilor pentru fiecare canal este realizată cu ajutorul registrului IER, prin setarea ı̂n
1 a bitului 0 (LSB) pentru canalul 1, respectiv a bitului 1 pentru canalul 2. Dezactivarea se realizează
prin setarea ı̂n 0 a biţilor corespunzători.
Întreruperile de la pinii de intrare ai GPIO sunt semnalizate prin intermediul registrului ISR.
Valoarea 1 ı̂nscrisă pe poziţia 0 (LSB), respectiv 1 din registru semnalează o ı̂ntrerupere primită
pe canalul 1, respectiv 2. Aceşti biţi pot fi resetaţi ı̂n modul TOW.
Un exemplu de citire a switchurilor folosind ı̂ntreruperi este prezentat ı̂n codul de mai jos . Programul
presupune că perifericul GPIO DIP Switches 4Bit este singura sursă de ı̂ntreruperi din sistem, nefiind
necesară adăugarea şi configurarea unui controller de ı̂ntreruperi. Pentru o astfel de funcţionare ı̂n
ı̂ntreruperi, este necesară realizarea unei conexiuni ı̂n tab-ul System Assembly View -> Ports ı̂ntre
portul IP2INTC Irpt al perifericului şi portul Interrupt al procesorului MicroBlaze.

//Cod C pentru citirea switchurilor folosind ^


ıntreruperi

#include "xparameters.h"
#include "mb_interface.h"

//variabile globale
unsigned *switchuri =(unsigned *)XPAR_DIP_SWITCHES_4BIT_BASEADDR;
unsigned *led =(unsigned *)XPAR_LEDS_8BIT_BASEADDR;

//periferic[adresa/4]
//impartire la 4 pentru ca fiecare registru este pe 32 biti
//iar pointerul la unsigned incrementeaza adresele din 4 in 4

void rutina_intrerupere(void *callBackHandler)


{
led[0]=switchuri[0]; //citeste starea switch-urilor si o afiseaza pe led-uri
}

int main(void)
2 Lucrul cu periferice 12

//1. setarea intreruperilor pentru perifericul GPIO

//adresa Global Interrupt Enable Register= 0x11C


switchuri[0x11C/4] = 0x80000000; //bitul 31 in 1

// adresa IP Interrupt Enable Register = 0x128


switchuri[0x128/4] = 0xFFFFFFFF;
//intreruperea se declanseaza la modificarea oricarui switch

//2. setarea intreruperilor pentru procesorul microblaze

// se defineste functia de tratare a intreruperilor pentru switchuri


microblaze_register_handler(
(XInterruptHandler)rutina_intrerupere,//pointer la functia de tratare a intreruperii
(void *)0
);

//activeaza intreruperile pentru procesor


microblaze_enable_interrupts();

led[0]=switchuri[0];

while(1)//bucla infinita care va fi intrerupta de intreruperi

return 1;
}

2.1.3 Folosirea butonului rotativ cu GPIO

(a) Structura internă (b) Succesiunea de stări la rotirea la dreapta a butonului

Figura 2-3: Butonul rotativ

Butonul rotativ codifică mişcarea circulară folosind două semnale A şi B generate de două butoane.
Aceste două butoane, din construcţia internă prezentată ı̂n Fig. 2-3a, sunt acţionate de rotirea unui
disc descentrat. Mişcarea de rotire cu un pas, ı̂ntr-un sens sau altul, generează o succesiune specifică
de stări ale semnalelor A şi B prezentate ı̂n Fig. 2-3b. La ı̂nceputul rotirii cu un pas, depinzând de
sensul mişcării, unul din butoane va fi ı̂n poziţie deschisă ı̂naintea celuilalt. De asemenea, la sfârşitul
efectuării pasului, primul buton se va ı̂nchide ı̂naintea celui de-al doilea.
13 Perifericul de uz general pentru intrări-ieşiri (GPIO)

Programul prezentat mai jos realizează decodificarea semnalelor. Ideea de bază constă ı̂n modelarea
unui automat de stări prin care se poate detecta parcurgerea succesiunii de semnale aferente rotirii la
dreapta sau la stânga.

//Cod C pentru folosirea butonului rotativ

unsigned *led = (unsigned *)0x81400000; //pointer la adresa de baza


//a perifericului LEDs_8Bit
unsigned *buton_rot = (unsigned *)0x81420000; //pointer la adresa de baza
//a perifericului But_Rot_2Bit

int main(void)
{
unsigned valoare_led = 0x80; //initializam cu un singur bit in 1
unsigned stare_buton; //starea butonului rotativ
unsigned stare; //starea curenta a automatului
unsigned stare_ant; //starea anterioara a automatului

while(1) //bucla infinita


{
led[0]=valoare_led; //afiseaza valoarea pe leduri
stare_buton=buton_rot[0]; //citeste starea butonului rotativ

//automatul de stare care determina directia rotirii


if(stare_buton==0x3) stare=0;
if(stare_buton==0x1 && stare==0) stare=1;
if(stare_buton==0x0 && stare==1) stare=2;
if(stare_buton==0x2 && stare==2) stare=3;
if(stare_buton==0x2 && stare==0) stare=4;
if(stare_buton==0x0 && stare==4) stare=5;
if(stare_buton==0x1 && stare==5) stare=6;

//rotirea valorii catre dreapta


if(stare==3 && stare_ant==2)
{
if(valoare_led == 1)
valoare_led = 0x80;
else valoare_led = valoare_led>>1;
}

//rotirea valorii catre stanga


if(stare==6 && stare_ant==5)
{
if(valoare_led == 0x80)
valoare_led = 1;
else valoare_led = valoare_led<<1;
}

stare_ant = stare; //starea actuala devine starea anterioara


}
2 Lucrul cu periferice 14

return 1;
}

2.1.4 Exerciţii
1. Scrieţi un program care să afişeze pe leduri succesiv două valori, fiecare valoare fiind menţinută
aproximativ 1 secundă.
(a) aaaa aaaa - ssss ssss
(b) aaaa ssss - ssss aaaa
(c) asas asas - sasa sasa
a - Ledul este aprins
s - Ledul este stins
2. Scrieţi un program care să afişeze pe leduri succesiunea de numere de la 0 la 255 ı̂n binar.
Frecvenţa de schimbare a valorilor să fie de aproximativ 1 Hz.
3. Scrieţi un program care să afişeze pe leduri succesiunea de numere de la 0 la 255 ı̂n cod Gray.
Frecvenţa de schimbare a valorilor să fie de aproximativ 2 Hz.
4. Scrieţi un program care să afişeze pe leduri o succesiune de valori. Frecvenţa de schimbare a
valorilor să fie de aproximativ 2 Hz.
(a) 0x00 - 0x01 - 0x03 - 0x07 - 0x0F - 0x1F - 0x3F - 0x7F - 0xFF - 0x7F - 0x3F - 0x1F - 0x0F
- 0x07 - 0x03 - 0x01
(b) 0x00 - 0x81 - 0xC3 - 0xE7 - 0xFF - 0xE7 - 0xC3 - 0x81 - 0x00 - 0x81 - 0xC3 - 0xE7 - 0xFF
- 0x7E - 0x3C - 0x18
(c) 0x00 - 0x01 - 0x02 - 0x04 - 0x08 - 0x10 - 0x20 - 0x40 - 0x80 - 0x40 - 0x20 - 0x10 - 0x08 -
0x04 - 0x02 - 0x01
5. Scrieţi un program care să implementeze un numărător ı̂n binar. Afişarea valorii să fie pe leduri.
Incrementarea să se facă la o apăsare a butonului rotativ (center) de pe placa de dezvoltare.
6. Scrieţi un program care să afişeze pe leduri pătratul valorii citite de la switchuri.
7. Scrieţi un program care să citească o valoare de pe switchuri. Bitul 0 citit să fie afişat pe ledurile
0 şi 4, bitul 1 pe ledurile 1 şi 5, bitul 2 pe ledurile 2 şi 6 iar bitul 3 pe ledurile 3 şi 7.
8. Scrieţi un program care să citească o valoare de la switchuri. Biţii 0 - 2 ai valorii citite reprezintă
pattern-ul care trebuie rotit pe leduri. Bitul 3 reprezintă direcţia rotirii:
- 0 rotire spre stânga
- 1 rotire spre dreapta
15 Perifericul pentru comunicaţii seriale (UART Lite)

2.2 Perifericul pentru comunicaţii seriale (UART Lite)

Perifericul UART Lite, conectat la magistrala PLB, oferă o interfaţă pentru realizarea de transferuri
de date seriale asincrone full-duplex. Modulul realizează conversia paralel-serială a caracterelor primite
de la magistrala PLB, respectiv conversia serial-paralelă a caracterelor recepţionate de la unul din
porturile RS-232 prezente pe placa de dezvoltare.
Perifericul dispune de câte un buffer de tip FIFO cu capacitatea de 16 caractere pentru transmisie
(Tx FIFO), respectiv recepţie (Rx FIFO), existând şi opţiunea de a genera ı̂ntreruperi la recepţionarea
unui caracter sau la golirea Tx FIFO. Numărul de biţi pe caracter este configurabil, putându-se opta
pentru valori ı̂ntre 5 şi 8. Transferul se realizează utilizând un singur bit de stop. De asemenea, modulul
UART Lite mai permite configurarea baud rate-ului utilizat şi se poate opta pentru utilizarea bitului
de paritate, cu paritate pară sau impară. Modificarea baud rate-ului, a numărului de biţi pe caracter,
respectiv a bitului de paritate se realizează din System Assembly View printr-un dublu click pe numele
perifericului UART Lite şi setarea valorilor ı̂n ı̂n tab-ul User din fereastra nou deschisă.

2.2.1 Organizarea regiştrilor

Regiştrii perifericului UART Lite, fiecare a câte 32 de biţi, sunt prezentaţi ı̂n Tabelul 2-3.

Tabelul 2-3: Maparea regiştriilor UART Lite ı̂n spaţiul de adrese

Nume registru Descriere Adresă Tip acces


Rx FIFO Buffer FIFO de recepţie Adresă de bază + 0x00 Citire
Tx FIFO Buffer FIFO de transmisie Adresă de bază + 0x04 Scriere
STAT REG Registru de stare Adresă de bază + 0x08 Citire
CTRL REG Registru de control Adresă de bază + 0x0C Scriere

Bufferul Rx FIFO, având capacitatea de 16 cuvinte, conţine datele recepţionate de periferic. Cuvântul
recepţionat este reprezentat pe cei mai puţin semnificativi biţi ai registrului. Citirea ı̂n cazul ı̂n care
bufferul este gol va rezulta ı̂ntr-o eroare de magistrală. Bufferul TxFIFO, de asemenea cu capacitatea
de 16 cuvinte, conţine datele ce urmează a fi transmise.
Registrul STAT REG oferă informaţii de stare asupra bufferelor, ı̂ntreruperilor şi erorilor rezultate.
Structura registrului este prezentată ı̂n Tabelul 2-4.
Registrul CTRL REG permite activarea sau dezactivarea modului de lucru ı̂n ı̂ntreruperi şi resetarea
bufferelor de transmisie şi recepţie. Structura registrului este prezentată ı̂n Tabelul 2-5. Perifericul
UART Lite poate genera o ı̂ntrerupere atunci când există un caracter valid ı̂n Rx FIFO sau când Tx
FIFO se goleşte.

2.2.2 Exemple de folosire a perifericului

Aplicaţia de echo (fiecare cuvânt primit de periferic este retrimis nemodificat) este un exemplu de
utilizare a perifericului pentru comunicaţii seriale, prezentat ı̂n codul de mai jos. În bucla infinită din
programul principal se aşteaptă până când se primesc date (prin citirea repetată a registrului de stare
şi testarea bitului care indică dacă bufferul de recepţie nu mai este gol - Rx FIFO Valid Data), datele
recepţionate fiind apoi introduse ı̂n bufferul de transmisie. Un pas opţional este aşteptarea până când
data a fost transmisă (prin citirea repetată a registrului de stare şi testarea bitului care indică dacă
bufferul de transmisie este gol - Tx FIFO Empty).
2 Lucrul cu periferice 16

Tabelul 2-4: Structura registrului STAT REG din cadrul perifericului UART Lite

Bit Descriere
31-8 Valoare ’0’
7 Parity Error
6 Frame Error
5 Overrun Error
4 Interrupt Enabled
3 Tx FIFO Full
2 Tx FIFO Empty
1 Rx FIFO Full
0 Rx FIFO Valid Data

Tabelul 2-5: Structura registrului CTRL REG din cadrul perifericului UART Lite

Bit Descriere
31-5 Biţi rezervaţi
4 Enable Interrupt
3-2 Biţi rezervaţi
1 Reset Rx FIFO
0 Reset Tx FIFO

//Exemplu de folosire a perifericului pentru comunicaţii seriale ^


ın mod polling

#include "xparameters.h"
unsigned *serial=(unsigned *) XPAR_RS232_DCE_BASEADDR;
int main(void)
{
unsigned serial_data;
while(1)
{
//STAT_REG 0x8
//bit 0 Rx Fifo valid data
while((serial[0x8/4] & 0x01) ==0);//asteptam pana primim date
//Rx FIFO 0x0
serial_data=serial[0x0/4];
//Tx FIFO 0x4
serial[0x4/4]=serial_data;
//STAT_REG bit 2 Tx FIFO Empty
while((serial[0x8/4] & 0x04) ==0);//asteptam pana fifoul Tx este gol

}
return 1;
}
17 Perifericul pentru comunicaţii seriale (UART Lite)

O variantă a aplicaţiei de echo ce utilizează ı̂ntreruperile este prezentată mai jos. Programul
presupune că perifericul serial este singura sursă de ı̂ntreruperi din sistem, nefiind necesară adăugarea
şi configurarea unui controller de ı̂ntreruperi. Pentru o astfel de funcţionare ı̂n ı̂ntreruperi, este
necesară realizarea unei conexiuni ı̂n tab-ul System Assembly View -> Ports ı̂ntre portul Interrupt al
perifericului RS232 şi cel al procesorului MicroBlaze.

//Exemplu de folosire a perifericului pentru comunicaţii seriale ^


ın ^
ıntreruperi

#include "xparameters.h"
#include "mb_interface.h"
unsigned *serial=(unsigned *) XPAR_RS232_DCE_BASEADDR;
void rutina_intrerupere(void *callBackHandler)
{
unsigned registru_stare;
unsigned serial_data;
//STAT_REG 0x8
registru_stare = serial[0x8/4];
if((registru_stare & 0x01) != 0)//avem date valide
{
//Rx FIFO 0x0
serial_data = serial[0x0/4];
//Tx FIFO 0x4
serial[0x4/4] = serial_data;
}

int main(void)
{

//1. setarea intreruperilor pentru controllerul rs232

//adresa CTRL_REG= 0xC Bit 4 Enable Intr


serial[0xC/4] = 0x00000010; //Bit 4 Enable Intr in 1

//2. setarea intreruperilor pentru procesorul microblaze

// se defineste functia de tratare a intreruperilor pentru switchuri


microblaze_register_handler(
(XInterruptHandler)rutina_intrerupere,//pointer la functia de tratare a intreruperii
(void *)0
);

//activeaza intreruperile pentru procesor


microblaze_enable_interrupts();

while(1);//bucla infinita care va fi intrerupta de intreruperi


return 1;
}
2 Lucrul cu periferice 18

La crearea unui proiect nou perifericul implicit pentru intrarea şi ieşirea standard (STDIN şi
STDOUT) al mediului de programare C este perifericul pentru comunicări seriale. Funcţiile de citire
şi afişare scanf şi printf vor folosi acest periferic pentru comunicare. Datorită complexităţii acestor
funcţii, mărimea programului generat va fi mai mare decât memoria BRAM disponibilă pe FPGA-ul
Spartan-3E. Lucrul cu aceste funcţii este posibil doar când programul este ı̂ncărcat ı̂n memoria DDR.
Pentru a facilita procesul de depanare a fost dezvoltată funcţia xil printf, care se foloseşte similar
cu funcţia printf, având ı̂nsă dimensiuni reduse. Variabilele acceptate de xil printf sunt pe 8, 16 şi
32 de biţi de orice tip ı̂n afară de float. În codul următor se prezintă exemple de utilizare a funcţiei
xil printf.

//Exemplu de folosire a xil_printf

int main(void)
{
unsigned i=10;
char c=’c’;
xil_printf("Hello world");//exemplu de afisare de text
xil_printf("Variabila i este = %d",i);// afisare a unui numar ^
ın baza 10
xil_printf("Variabila i este = %x",i);// afisare a unui numar ^
ın baza 16
xil_printf("Variabila c este = %c",c);// afisare a unui caracter
xil_printf("Un string este = %s","un string");// afisare a unui sir de caractere

return 1;
}

2.2.3 Exerciţii
1. Scrieţi un program care
(a) La primirea caracterului ’s’ va deplasa un led spre stânga
(b) La primirea caracterului ’d’ va deplasa un led spre dreapta
(c) La primirea unui număr de la 0 la 7 va aprinde ledul de pe poziţia corespunzătoare
2. Scrieţi o funcţie care primeşte ca parametru un pointer la un şir de caractere şi realizează
transmiterea şirului pe interfaţa serială. Sfârşitul şirului este semnalat cu caracterul având
valoarea 0.
19 PS/2

2.3 PS/2

Perifericul PS/2, conectat la magistrala PLB, oferă o interfaţă pentru folosirea tastaturii şi a mouse-
ului. Comunicarea cu placa Spartan-3E se face serial cu ajutorul a 2 pini: data(PS2 DATA) şi
ceas(PS2 CLK). Atât mouse-ul cât şi tastatura comunică pe interfaţa PS/2 prin cadre de 11 biţi şi au
acelaşi timing, dar pachetele de date vehiculate sunt diferite. Este permisă o comunicare bidirecţională:
atât de la periferic către gazdă, cât şi invers.
Transferul ı̂ncepe prin scrierea unui bit de START(’0’ logic) pe linia de date, după care urmează
cuvântul de date de 8 biţi (LSB transmis primul) şi un bit de control al parităţii. Încheierea transferului
se face cu un bit de STOP(’1’ logic). Fig. 2-4 prezintă diagrama de timp a transferului de informaţii
ı̂ntre mouse/tastatură şi host.

Figura 2-4: Diagrama de timp pe bus-ul PS/2

2.3.1 Organizarea regiştrilor

Perifericul dispune de 8 regiştri interni, prezentaţi ı̂n Tabelul 2-6, câte patru pentru fiecare din cele
două canale. Regiştrii sunt pe 32 de biţi şi sunt fixaţi la un offset multiplu de 4 faţă de adresa de
bază. În cazul ı̂n care perifericul este setat pe un singur canal, citirea regiştrilor canalului doi va avea
ca rezultat 0.
Tabelul 2-6: Maparea regiştriilor interni PS/2 ı̂n spaţiul de adrese

Nume registru Descriere Adresă Tip acces


SRST 1 Registru resetare software (canal 1) Adresă de bază + 0x0000 Scriere
STATUS REG1 Registru stare (canal 1) Adresă de bază + 0x0004 Citire
RX1 DATA Registru date primite (canal 1) Adresă de bază + 0x0008 Citire
TX1 DATA Registru date trimise (canal 1) Adresă de bază + 0x000C Scriere
SRST 2 Registru resetare software (canal 2) Adresă de bază + 0x1000 Scriere
STATUS REG2 Registru stare (canal 2) Adresă de bază + 0x1004 Citire
RX2 DATA Registru date primite (canal 2) Adresă de bază + 0x1008 Citire
TX2 DATA Registru date trimise (canal 2) Adresă de bază + 0x100C Scriere

Registrul SRST x este folosit pentru resetarea canalului PS/2 corespunzător, aceasta făcându-se
prin scrierea cuvântului 0x0000000A ı̂n acest registru. STATUS REGx este folosit pentru a afla
starea canalului x, semnificaţia biţilor din registru fiind prezentată ı̂n Tabelul 2-7. RXx DATA şi
TXx DATA sunt utilizaţi pentru comunicarea cuvintelor cu perifericul controlat, structura acestora
fiind prezentată ı̂n Tabelul 2-8.
2 Lucrul cu periferice 20

Tabelul 2-7: Semnificaţia biţilor registrului STATUS REGx

Bit Nume Descriere


0 OBF Indică dacă buffer-ul de transmisie este plin
1 IBF Indică dacă buffer-ul de recepţie este plin
2-31 - Neutilizaţi

Tabelul 2-8: Structura unui cuvânt transmis/recepţionat

Bit Descriere
0-7 Biţi de date
8-31 Neutilizaţi

Pentru a facilita lucrul cu ı̂ntreruperile, perifericul dispune de 6 regiştri suplimentari, câte trei pentru
fiecare canal, descrişi ı̂n Tabelul 2-9.

Tabelul 2-9: Maparea regiştrilor de ı̂ntreruperi PS/2 ı̂n spaţiul de adrese

Nume registru Descriere Adresă Tip acces


GIE 1 Global Interrupt Enable Register (C1) Adresă de bază + 0x002C Scriere/ Citire
IPISR 1 IP Interrupt Status Register (C1) Adresă de bază + 0x0030 Citire/ TOW
IPIER 1 IP Interrupt Enable Register (C1) Adresă de bază + 0x0038 Scriere/ Citire
GIE 2 Global Interrupt Enable Register (C2) Adresă de bază + 0x102C Scriere/ Citire
IPISR 2 IP Interrupt Status Register (C2) Adresă de bază + 0x1030 Citire/ TOW
IPIER 2 IP Interrupt Enable Register (C2) Adresă de bază + 0x1038 Scriere/ Citire

Activarea/dezactivarea primară a ı̂ntreruperilor se face cu ajutorul registrului GIE x. Pentru


activare se ı̂nscrie ’1’, iar pentru dezactivare ’0’ pe poziţia 31 (bitul MSB) a registrului.
Activarea individuală a ı̂ntreruperilor se face cu ajutorul registrului IPIER x, structura acestuia
fiind prezentată ı̂n Tabelul 2-10.
Registrul IPISR x, a cărui structură corespunde cu cea a registrului IPIER x prezentată ı̂n Tabelul
2-10, conţine informaţia de stare a ı̂ntreruperilor individuale aferente canalului x.

2.3.2 Adăugarea perifericului

Acest periferic nu se poate instanţia utilizând Base System Builder. După generarea sistemului, el
poate fi instanţiat din tab-ul IP Catalog, opţiunea Communication Low - Speed -> XPS PS2 Interface.
După instanţiere:
1. În tab-ul System Assembly View-> Bus Interfaces conectaţi portul SPLB al perifericului la
magistrala standard a sistemului mb plb.
2. În tab-ul System Assembly View -> Addresses specificaţi mărimea şi locaţia spaţiului de adrese
ı̂n care se va mapa acest periferic sau apăsaţi butonul Generate Addresses şi ele vor fi configurate
automat.
3. În tab-ul System Assembly View -> Ports specificaţi semnalele PS2 1 DATA şi PS2 1 CLK ca
fiind semnale externe.
4. În tab-ul Project deschideţi fişierul UCF (dublu click pe data/system.ucf ) şi adăugaţi următoarele
21 PS/2

Tabelul 2-10: Semnificaţia biţilor registrului IPIER şi IPISR

Bit Nume Descriere


31-6 - Neutilizaţi
5 RXx FULL RX Data Register Full
4 RXx ERR RX Data Error
3 RXx OVF RX Data Register Overflow
2 TXx ACKF TX Data Acknowledge Received
1 TXx NOACK TX Data Acknowledge not Received
0 WDTx TOUT Watch Dog Timer Timeout

constrângeri:

Net xps_ps2_0_PS2_1_DATA LOC=G13 | IOSTANDARD = LVCMOS33;


Net xps_ps2_0_PS2_1_CLK LOC=G14 | IOSTANDARD = LVCMOS33;

2.3.3 Tastatura

Lucrul cu perifericul ı̂ncepe prin resetarea controllerului PS2, aceasta făcându-se prin scrierea
cuvântului 0x0000000A ı̂n registrul SRST x. Următorul pas este resetarea tastaturii prin trimiterea
cuvântului 0xFF. Tastatura răspunde cu 0xFA şi intră ı̂n modul BAT (Basic Assurance Test) la
finalul căruia se ı̂ncarcă parametrii impliciţi de funcţionare. În cazul unei erori ı̂n cadrul testelor BAT
tastatura va trimite 0xFC ı̂n caz contrar va trimite 0xAA semnalând intrarea ı̂n modul standard de
funcţionare.
Un exemplu de lucrul cu tastatura este prezentat ı̂n codul de mai jos. Cu ajutorul funcţiei send keyboard
se pot trimite cuvinte către tastatură. Datele care urmează a fi trimise sunt depuse ı̂n TXx DATA,
după care se aşteaptă până când bufferul de intrare şi/sau ieşire este golit.

#include "xparameters.h"

unsigned *keyboard = (unsigned *)XPAR_XPS_PS2_0_0_BASEADDR;

void send_keyboard(unsigned data)


{
unsigned keyboard_status;
// keyboard[3] reprezinta TX1_DATA
keyboard[3]=data;

// se asteapta pana cand bufferul de transmisie nu mai este plin


do
keyboard_status=keyboard[1];
while (keyboard_status%2==1);
}

int main(void)
{
unsigned key;
2 Lucrul cu periferice 22

Figura 2-5: Codul tastelor unei tastaturi

keyboard[0]=0x0000000A;
send_keyboard(0xFF);//reset
xil_printf("Sending reset command\r\n");
for (j = 0; j < 2; j++)
{
key = keyboard[2];
while(keyboard[1] == 0);
xil_printf("%x\r\n", key);
}
while(1); // buclă infinită
return 1;
}

Fiecare tastă are un cod unic, ce este trimis atunci când aceasta este apăsată, vezi Fig. 2-5. Există
trei tipuri de coduri:
1. cod propriu-zis (una din cele prezentate ı̂n Fig.2-5)
2. E0 (tastă extinsă - ca de ex. Ctrl, Alt)
3. F0 (tastă ridicată)
Dacă o tastă este ţinută apăsată, codul este retrimis la fiecare 100ms. Atunci când tasta este ridicată
se trimite codul special ”F0” urmat de codul propriu-zis al tastei.
În cazul apăsării tastelor extinse se transmit două cuvinte: primul reprezintă codul special ”E0”,
al doilea codul propriu-zis al tastei. La ridicarea tastelor extinse se vor transmite următoarele trei
cuvinte: codul ”E0”, urmat de ”F0” şi de codul propriu-zis al tastei.
Cele mai importante comenzi trimise de la controller către tastatură sunt:
1. ED - Se foloseşte pentru aprinderea/stingerea ledurilor Num Lock, Caps Lock, Scroll Lock.
Tastatura confirmă trimiţând ”FA”, după care controllerul trimite un byte având structura prezentată
ı̂n Fig.2-6 (pentru iluminarea unui LED se setează bit-ul respectiv pe ’1’). Recepţionarea cuvântului
de date este confirmată de către tastatură prin trimiterea cuvântului ”FA”.
2. EE - Comandă de ecou,la care tastatura răspunde cu acelaşi cod ”EE”.
3. F3 - Setarea ratei de repetare a transmiterii codurilor unice. Tastatura răspunde cu ”FA”, după
care controllerul transmite un byte conţinând rata ce urmează a fi setată.
4. FE - La primirea acestei comenzi tastatura retrimite ultimul cod transmis.
5. FF - Prin trimiterea acestui cod controllerul resetează tastatura.
23 PS/2

Figura 2-6: Semnificaţie byte pentru stare LED-uri

Figura 2-7: Cuvinte de date transmise de mouse

2.3.4 Mouseul

Lucrul cu perifericul ı̂ncepe similar ca la tastatură, prin resetarea controllerului şi a mouseului
prin scrierea cuvântului 0x0000000A ı̂n registrul SRST x. Următorul pas este resetarea mouseului
prin trimiterea cuvântului 0xFF. Mouseul răspunde cu un acknowledge(0xFA) şi intră ı̂n modul
BAT (Basic Assurance Test) la finalul căruia se ı̂ncarcă parametrii impliciţi de funcţionare. În
cazul unei erori ı̂n cadrul testelor BAT tastatura va trimite 0xFC ı̂n caz contrar va trimite 0xAA
urmat de id-ul mouseului semnalând intrarea ı̂n modul standard de funcţionare. După aceasta este
necesară transmiterea cuvântului 0xF4 pentru activarea raportării, la care mouseul răspunde cu 0xFA.
Trimiterea şi recepţionarea de cuvinte se face similar ca la tastatură.
În mod standard (prezentat ı̂n continuare) ID-ul mouseului este 0x00 şi sunt transmise mişcările
mouse-ului, respectiv apăsarea butoanelor stânga, dreapta şi centru. Cu ajutorul extensiei Intellimouse
ı̂nsă se poate lucra cu scroll-ul şi cu celelalte butoane disponibile eventual pe mouse (extensia este
prezentată pe http://www.computer-engineering.org/ps2mouse).
Transferul se date se face atunci când mouse-ul este mişcat sau se apasă butoanele acestuia, caz ı̂n
care sunt trimise trei cuvinte: primul indică starea, al doilea rata mişcării pe axa X, iar al treilea rata
mişcării pe axa Y. Semnificaţia biţilor celor 3 octeţi este prezentată ı̂n Fig. 2-7. Dacă mouseul este
mişcat ı̂n continuu un set de trei cuvinte este transmis la fiecare 50 ms.
Mouseul PS/2 foloseşte un sistem de coordonate relativ la poziţia curentă, ca ı̂n Fig. 2-8. O mişcare
la stânga este codificată cu o valoare negativă, iar o miscare la dreapta cu o valoare pozitivă pentru
axa X. În mod similar mişcarea ı̂n jos este codificată cu o valoare negativă iar cea in sus cu o valoare
pozitivă pentru axa Y.

Figura 2-8: Sistemul relativ de coordinate a mouse-ului


2 Lucrul cu periferice 24

Semnificaţia biţilor din cuvântul de stare este:


1. L şi R indică apăsarea butoanelor mouseului, L - butonul stâng, R - butonul drept (1 logic pentru
buton apăsat).
2. XS respectiv YS indică sensul deplasării pe axa X şi Y.
3. XV şi YV indică dacă rata mişcării pe axa X respectiv Y a depăşit limita maximă(overflow).

2.3.5 Exerciţii
1. Scrieţi un program care afişează pe terminal un mesaj ı̂n cazul ı̂n care se apasă tasta Ctrl Left
şi alt mesaj când se apasă Ctrl Right.
2. Scrieţi un program care aprinde toate ledurile de pe tastatură.
3. Scrieţi un program care la apăsarea tastei ’Caps Lock’ aprinde, respectiv stinge ledul core-
spunzător de pe tastatură.
4. Scrieţi un program care afişează un mesaj corespunzător pe terminal atunci când este apăsat
unul din butoanele mouseului (stânga, dreapta, centru).
5. Scrieţi un program care deplasează un led aprins de pe placa de dezvoltare conform mişcării
scroll-ului.
25 Perifericul de comandă a afişajului LCD

Figura 2-9: Corespondenţa dintre regiştrii de caracter şi afişajul LCD

2.4 Perifericul de comandă a afişajului LCD

Perifericul de comandă a afişajului LCD (LCD Driver) realizează o interfaţă simplă pentru afişarea
de caractere pe ecranul LCD disponibil pe placa de dezvoltare utilizând magistrala PLB. Modulul
permite afişarea de caractere ASCII pe ecranul de 2 linii a câte 16 caractere.

2.4.1 Organizarea regiştrilor

Modulul dispune de 32 de regiştri de caracter (numerotaţi de la 0 la 31) corespunzători celor 32


de poziţii ale ecranului LCD, conform Fig. 2-9. Pentru afişarea unui caracter este necesară scrierea
valorii acestuia ı̂n registrul de caracter corespunzător. Prin citirea unui registru se va returna codul
ASCII al caracterului afişat pe LCD. Structura unui registru de caracter este prezentată ı̂n Tabelul
2-11.

Tabelul 2-11: Structura unui registru de caracter din cadrul perifericului LCD Driver

Biţi Descriere
31-8 Biţi rezervaţi (valoare ’0’)
7-0 Valoare caracter

Setul de caractere al afişajului LCD şi codurile aferente sunt prezentate ı̂n Fig. 2-10. Perifericul
LCD Driver nu permite afişarea de caractere personalizate.

2.4.2 Adăugarea perifericului

Acest periferic nu este disponibil ı̂n distribuţia standard Xilinx EDK, motiv pentru care el trebuie
copiat manual ı̂n directorul pcores al proiectului. După copiere el poate fi instanţiat din tab-ul IP
Catalog, opţiunea Project Local pcores -> User -> LCD DRIVER. După instanţiere:
1. În tab-ul System Assembly View-> Bus Interfaces conectaţi perifericul la magistrala standard a
sistemului mb plb.
2. În tab-ul System Assembly View -> Addresses specificaţi mărimea şi locaţia spaţiului de adrese
ı̂n care se va mapa acest periferic sau apăsaţi butonul Generate Addresses şi ele vor fi configurate
automat.
3. În tab-ul System Assembly View -> Ports specificaţi toate semnalele aferente perifericului LCD
ca fiind semnale externe.
4. În tab-ul Project deschideţi fişierul UCF (dublu click pe data/system.ucf ) şi adăugaţi con-
strângerile din Fig. 2-11.
2 Lucrul cu periferice 26

Figura 2-10: Setul de caractere al afişajului LCD

2.4.3 Aplicaţii

Un exemplu simplu de utilizare a perifericului LCD Driver este prezentat ı̂n Fig. 2-12. Programul
va afişa textul ”Hello world!” pe prima linie a ecranului LCD.

2.4.4 Exerciţii
1. Scrieţi o funcţie care primeşte ca parametru un pointer la un şir de caractere şi afişează şirul pe
ecranul LCD. Sfârşitul şirului este semnalat cu caracterul având valoarea 0.
27 Perifericul de comandă a afişajului LCD

Net lcd driver 0 lcd e pin LOC=M18 | IOSTANDARD = LVCMOS33;


Net lcd driver 0 lcd rs pin LOC=L18 | IOSTANDARD = LVCMOS33;
Net lcd driver 0 lcd rw pin LOC=L17 | IOSTANDARD = LVCMOS33;
Net lcd driver 0 lcd sf ce0 pin LOC=D16 | IOSTANDARD = LVCMOS33;

Net lcd driver 0 lcd data pin< 0 > LOC=R15 | IOSTANDARD = LVCMOS33;
Net lcd driver 0 lcd data pin< 1 > LOC=R16 | IOSTANDARD = LVCMOS33;
Net lcd driver 0 lcd data pin< 2 > LOC=P17 | IOSTANDARD = LVCMOS33;
Net lcd driver 0 lcd data pin< 3 > LOC=M15 | IOSTANDARD = LVCMOS33;
Figura 2-11: Exemplu de constrângeri UCF pentru perifericul LCD

#include ”xparameters.h”
unsigned *lcd=(unsigned *)XPAR LCD DRIVER 0 MEM0 BASEADDR;
//pointer la adresa de baza a perifericului LCD Driver

int main(void)
{
//scrie caracterele in registrii de caracter
//corespunzatori pozitiilor 0-11 de pe ecranul LCD
lcd[0]=’H’;
lcd[1]=’e’;
lcd[2]=’l’;
lcd[3]=’l’;
lcd[4]=’o’;
lcd[5]=’ ’;
lcd[6]=’w’;
lcd[7]=’o’;
lcd[8]=’r’;
lcd[9]=’l’;
lcd[10]=’d’;
lcd[11]=’ !’;

return 1;
}
Figura 2-12: Exemplu de utilizare a perifericului LCD Driver pentru afişarea de caractere

2. Scrieţi un program care să rotească ı̂ntr-un sens un text afişat pe ecranul LCD. Deplasarea se
va face cu câte un pas la aproximativ o secundă.
2 Lucrul cu periferice 28

Figura 2-13: Sistem pentru lucrul cu monitorul

2.5 Controller-ul VGA

Controller-ul video (xps tft controller) este perifericul care facilitează afişarea de imagini pe un
monitor. Fiecărui pixel de pe monitor ı̂i corespunde un cuvânt de 32 de biţi din memorie din care pe
placa Spartan-3E Starter Board sunt folosiţi doar 3 biţi (8 culori posibile pentru un pixel). Folosind
acest periferic se pot desena, afişa diferite imagini sau crea animaţii din program.
Acest controller se conectează ca un master pe magistrala PLB v4.6, citeşte datele video din memoria
ataşată pe magistrală şi le afişează pe monitor. Controller-ul este folosit pentru monitoare cu rezoluţie
de 640x480 şi poate reda până la 256K culori (8 culori cu placa Spartan-3E Starter Board). Pe lângă
interfaţa master controller-ul mai dispune de interfaţa slave PLB care permite accesul la regiştrii
interni.
O structură minimă a unui sistem care foloseşte controller-ul video este prezentată ı̂n Fig. 2-13.
Acest sistem conţine un microprocesor cu memoria BRAM aferentă (pentru stocarea instrucţiunilor
şi datelor), controller şi memorie DDR (pentru stocarea imaginii de afişat), controller-ul video şi un
monitor pe care se poate observa imaginea.
Controller-ul video conţine un circuit de generare a două semnale de sincronizare (HSYNC si
VSYNC). Semnalul HSYNC specifică timpul necesar pentru a parcurge un rând al ecranului de la
stânga la dreapta, iar semnalul VSYNC specifică timpul necesar pentru a traversa ı̂ntregul ecran, de
sus ı̂n jos.
HSYNC are o perioadă de 800 de tacte de ceas (la o frecvenţă de 25MHz). Această perioadă poate
fi considerată ca fiind formată din 4 regiuni: display, retrace, front porch şi back porch. Display este
regiunea ı̂n care pixelii sunt afişati pe ecran şi lungimea ei este de 640 tacte de ceas (un tact pentru
fiecare pixel). În Fig. 2-14 este reprezentată diagrama de timp a semnalului.
Forma de undă a semnalului VSYNC este prezentată ı̂n Fig. 2-15. Perioada semnalului este egală cu
512 perioade ale semnalului HSYNC, regiunea de display având o lungime de 480 astfel de perioade.
29 Controller-ul VGA

Figura 2-14: Diagrama de timp a semnalului HSYNC

Controller-ul video are nevoie de 16.8 ms pentru afişarea unui cadru la o rezoluţie de 640x480 şi o
rată de refresh de 60Hz. Pentru afişarea completă a unui cadru nu trebuie modificată adresa de start
a memoriei video ı̂nainte de trecerea acestui timp.
Controller-ul video mai dispune de trei semnale de ieşire, care colectiv formează “semnalul RGB”,
reprezentând culoarea unui pixel, o combinaţie ı̂ntre roşu, verde şi albastru prezentată ı̂n Fig. 2-16.
Fiecare pixel este stocat ı̂ntr-un cuvânt 32 de biţi. Formatul unui pixel este de forma:
0xUURRGGBB
unde:
U – unused
R- red pixel data
G-green pixel data
B-blue pixel data
În plus, deşi controller-ul video foloseşte numai o rezoluţie de 640x480, fiecare linie trebuie stocată
ca o serie de 1024 pixeli. Astfel există 384 de pixeli neutilizaţi la fiecare sfârşit de linie. În consecinţă,
pentru afişarea unei imagini cu o rezoluţie de 640x480 sunt necesari 1024*480*4(bytes) = 1966080
bytes de memorie. Din considerente de simplitate a hardware-ului ı̂nceputul zonei de memorie trebuie
sa fie la adrese multiplu de 2 MB.

2.5.1 Organizarea regiştrilor

Perifericul dispune de 2 regiştri accesibili prin interfaţa slave PLB, prezentaţi ı̂n Tabelul 2-12.
Registrul de adresă ofera utilizatorului posibilitatea de a schimba adresa de bază a memoriei video
din care citeşte controller-ul. Prin aceasta se poate rezolva efectul vizual neplacut al descărcarii unui
cadru video din memorie pe ecran, efect datorat vitezei scăzute de citire a datelor din memorie ı̂n
comparaţie cu viteza de afişare a datelor pe ecran. Utilizatorul poate schimba adresa de bază a
memoriei video, afişând un alt cadru atunci când o imagine este citită.
2 Lucrul cu periferice 30

Figura 2-15: Diagrama de timp a semnalului VSYNC

Tabelul 2-12: Maparea regiştriilor controller-ului video ı̂n spaţiul de adrese

Nume registru
AR
CR Registrul de control [31:2] Biţi rezervaţi [1] Display Scan Control Bit 0 = afişaj normal 1 = a

2.5.2 Adăugarea perifericului

Acest periferic nu se poate instanţia utilizând Base System Builder. După generarea sistemului, el
poate fi instanţiat din tab-ul IP Catalog, opţiunea IO Modules -> XPS TFT. După instanţiere:
1. În tab-ul System Assembly View-> Bus Interfaces conectaţi porturile MPLB şi SPLB ale per-
ifericului la magistrala standard a sistemului mb plb.
2. În tab-ul System Assembly View -> Addresses specificaţi mărimea şi locaţia spaţiului de adrese
ı̂n care se va mapa acest periferic sau apăsaţi butonul Generate Addresses şi ele vor fi configurate
automat.
3. Semnalul de ceas al perifericului se configurează din meniul Hardware -> Launch Clock Wizard.
În fereastra nou deschisă selectaţi Peripherals -> xps tft 0 -> SYS TFT Clk şi setaţi frecvenţa
la 25 MHz.
4. În tab-ul System Assembly View -> Ports daţi dublu click pe numele perifericului şi debifaţi
31 Controller-ul VGA

Figura 2-16: Culorile afişabile pe montor folosind placa Spartan 3E

opţiunea ”Select TFT Interface” din fereastra nou deschisă.


5. În tab-ul System Assembly View -> Ports specificaţi semnalele TFT HSYNC, TFT VSYNC,
TFT VGA R, TFT VGA G şi TFT VGA B ale perifericului ca fiind semnale externe.
6. În tab-ul Project deschideţi fişierul UCF (dublu click pe data/system.ucf ) şi adăugaţi con-
strângerile din Fig. 2-17.

Net xps tft 0 TFT HSYNC pin LOC=F15 | IOSTANDARD = LVCMOS33;


Net xps tft 0 TFT VSYNC pin LOC=F14 | IOSTANDARD = LVCMOS33;

Net xps tft 0 TFT VGA R pin< 0 > LOC=H14 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA G pin< 0 > LOC=H15 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA B pin< 0 > LOC=G15 | IOSTANDARD = LVCMOS33;

#biţii de culoare neutilizaţi pe placa Spartan-3E trebuie conectaţi la pini de uz general


Net xps tft 0 TFT VGA R pin< 1 > LOC=B6 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA R pin< 2 > LOC=E7 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA R pin< 3 > LOC=F7 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA R pin< 4 > LOC=D7 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA R pin< 5 > LOC=C7 | IOSTANDARD = LVCMOS33;

Net xps tft 0 TFT VGA G pin< 1 > LOC=F8 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA G pin< 2 > LOC=E8 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA G pin< 3 > LOC=F9 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA G pin< 4 > LOC=E9 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA G pin< 5 > LOC=D11 | IOSTANDARD = LVCMOS33;

Net xps tft 0 TFT VGA B pin< 1 > LOC=B4 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA B pin< 2 > LOC=A4 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA B pin< 3 > LOC=D5 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA B pin< 4 > LOC=C5 | IOSTANDARD = LVCMOS33;
Net xps tft 0 TFT VGA B pin< 5 > LOC=A6 | IOSTANDARD = LVCMOS33;

Figura 2-17: Exemplu de constrângeri UCF pentru perifericul xps tft


2 Lucrul cu periferice 32

//pointer la adresa controller-ului vga


unsigned *vga ctrl = (unsigned *) 0x86E00000;
//pointer la inceputul zonei de memorie din care citeste controller-ul
unsigned *vga mem = (unsigned *) 0x83000000;
int main (void)
{ //primul registru al controller-ului retine adresa de la care se citeste
vga ctrl[0]=0x83000000;
//registru de control, initializat cu 1 pentru citire
vga ctrl[1]=1;
int i,j;
unsigned color;
//parcurgerea ecranului si colorarea pixelilor
for(i=0;i<480;i++)
for(j=0;j<640;j++)
{ color=0x00000000 ;
if((i/60)%2)color=color | 0x00FF0000;//ecranul este impartit in 8 zone; fiecare zona cu numar impar
va avea culoarea rosie activa
if((i/120)%2)color=color | 0x0000FF00;//ecranul este impartit in 4 zone; fiecare zona cu numar impar
va avea culoarea verde activa
if((i/240)%2)color=color | 0x000000FF;//ecranul este impartit in 2 zone; partea de jos va avea culoarea
albastra activa
vga mem[i*1024+j]=color; }
while(1);//creeaza o bucla infinita pentru mentinerea programului in executie
return 1; }
Figura 2-18: Exemplu de afişare a unei mire pe ecran

//declararea unei matrici care contine imaginea


short myImage[]={0,111,111,0};

//cod pentru initializarea controllerului si stergerea ecranului


//...

for(i=0;i<2;i++)
for(j=0;j<2;j++)
vga mem[i*1024+j]=myImage[i*2+j];

Figura 2-19: Exemplu de declarare şi afişare a unei imagini pe ecran

2.5.3 Aplicaţii

Programul din Fig. 2-18 afişează o miră de culori orizontală pe ecran.


Pentru afişarea unei imagini pe ecran trebuie să definim o imagine şi să o copiem ı̂n memoria video
care conţine cadrul. O posibiliate pentru a efectua acest lucru este să definim o matrice (de short) ı̂n
memorie pe care o iniţializăm cu imaginea noastră. Utilitarul xxxxxxxx (disponibil ı̂n directorul
”utilitare”) citeşte o imagine ı̂n format BitMap (.bmp) şi generează codul c pentru iniţializarea
memoriei imaginii. Utilitarul crează un număr format din trei cifre (dacă cifrele cele mai semnificative
sunt zero nu se mai scriu), cifre care corespund culorilor RGB. De exemplu 111 reprezintă culoarea
albă (R=1 G=1 B=1), 0 reprezintă culoarea neagră (R=0 G=0 B=0) iar 10 reprezintă culoarea verde
(R=0 G=1 B=0). Exemplul din Fig. 2-19 creează o imagine 2x2 colorată cu textura tablei de şah pe
care o copiază ı̂n colţul stânga sus.
33 Controller-ul VGA

2.5.4 Exerciţii
1. Desenaţi o miră de culori verticală pe ecran.
2. Desenaţi un pătrat cu suprafaţa colorată ı̂n alb având latura de 100 de pixeli ı̂n mijlocul ecranului.
3. Desenaţi un triunghi dreptunghic isoscel cu unghiul dreptunghic ı̂n unul dintre colţurile ecranului
având catetele de lungimi 300 de pixeli.
4. Desenaţi conturul unui pătrat şi diagonalele de culoare albă. Punctul de intersecţie al diago-
nalelor se va afla ı̂n centrul ecranului.
5. Fişierul exemple/video/ascii.c defineşte o imagine care conţine toate caracterele din tabela
ASCII. Fiecare caracter are 9 pixeli lăţime şi ı̂nălţimea de 16 pixeli. Imaginea este de ....x....
pixeli.
(a) Afişaţi imaginea pe ecran.
(b) Afişaţi porţiunea de imagine care corespunde literei ’A’ ı̂n colţul din dreapta sus.
(c) Implementaţi funcţia care afişează un caracter:
void print char(short *ascii,char c,int x, int y)
c este caracterul de afişat iar x şi y coordonatele punctului din stânga sus a poziţiei
caracterului
(d) Implementaţi o funcţie care afişează un string pe ecran.
6. Afişaţi imaginea lena.bmp pe ecran.
2 Lucrul cu periferice 34
Bibliografie

35

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