sisteme pe baz a de microprocesor - etc.unitbv.roetc.unitbv.ro/~gaspar/master_apc/indrumar.pdf ·...

101
Universitatea Transilvania din Bra¸ sov Zolt´ an G ´ asp ´ ar Radu-Mihai Coliban Alexandra Stanciu Sisteme pe baz˘ a de microprocesor Implement˘ ari pe placa de dezvoltare Xilinx Spartan 3E 2012

Upload: others

Post on 08-Sep-2019

17 views

Category:

Documents


0 download

TRANSCRIPT

Universitatea Transilvania din Brasov

Zoltan Gaspar

Radu-Mihai Coliban Alexandra Stanciu

Sisteme pe baza de microprocesorImplementari pe placa de dezvoltare Xilinx Spartan 3E

2012

ii

Cuprins

1 Introducere 1

1.1 Crearea unui proiect ın Xilinx EDK 12.1 . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.1.1 Crearea unei noi aplicatii software . . . . . . . . . . . . . . . . . . . . . . . . . 3

1.1.2 ”Hello world” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.2 Adaugarea unui nou periferic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.3 De la crearea proiectului ın EDK la functionarea lui pe placa . . . . . . . . . . . . . . 5

2 Utilizarea perifericelor 7

2.1 Perifericul de uz general pentru intrari-iesiri (GPIO) . . . . . . . . . . . . . . . . . . . 7

2.1.1 Organizarea registrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.1.2 Utilizarea ıntreruperilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.1.3 Instantierea perifericului . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.1.4 Folosirea butonului rotativ cu GPIO . . . . . . . . . . . . . . . . . . . . . . . . 12

2.1.5 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2.2 Perifericul pentru comunicatii seriale asincrone (UART Lite) . . . . . . . . . . . . . . 15

2.2.1 Organizarea registrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

2.2.2 Exemple de folosire a perifericului . . . . . . . . . . . . . . . . . . . . . . . . . 15

2.2.3 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

2.3 Perifericul pentru comunicatii seriale sincrone (SPI) . . . . . . . . . . . . . . . . . . . 19

2.3.1 Organizarea registrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

2.3.2 Utilizarea ıntreruperilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

2.3.3 Periferice SPI pe platforma Spartan 3E . . . . . . . . . . . . . . . . . . . . . . 22

2.3.4 Instantierea perifericului . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

2.3.5 Convertorul digital-analog (DAC) . . . . . . . . . . . . . . . . . . . . . . . . . . 24

iii

2.3.6 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

2.4 Controller-ul PS/2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

2.4.1 Organizarea registrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

2.4.2 Instantierea perifericului . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

2.4.3 Tastatura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

2.4.4 Mouse-ul . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

2.4.5 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

2.5 Perifericul de comanda a afisajului LCD . . . . . . . . . . . . . . . . . . . . . . . . . . 33

2.5.1 Organizarea registrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

2.5.2 Instantierea perifericului . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

2.5.3 Aplicatii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

2.5.4 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

2.6 Controller-ul VGA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

2.6.1 Organizarea registrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

2.6.2 Instantierea perifericului . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

2.6.3 Aplicatii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

2.6.4 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

2.7 Perifericul timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

2.7.1 Organizarea registrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

2.7.2 Modul de generare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

2.7.3 Modul de capturare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

2.7.4 Modul de generare PWM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

2.7.5 Instantierea perifericului . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

2.7.6 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

2.8 Controllerul de ıntreruperi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

2.8.1 Tratarea ıntreruperilor la microprocesorul MicroBlaze . . . . . . . . . . . . . . 48

2.8.2 Controllerul de ıntreruperi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

2.8.2.1 Organizarea registrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

2.8.2.2 Folosirea controllerului de ıntreruperi fara driver . . . . . . . . . . . . 52

2.8.2.3 Folosirea controllerului de ıntreruperi cu driver . . . . . . . . . . . . . 54

2.8.2.4 Instantierea perifericului . . . . . . . . . . . . . . . . . . . . . . . . . 56

2.8.3 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

3 Sisteme complexe 57

3.1 Crearea unei aplicatii de retea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

3.1.1 Arhitectura hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

iv

3.1.2 Arhitectura software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

3.1.3 Programul Echo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

3.1.4 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

3.2 Sisteme dual-processor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

3.2.1 Crearea unui sistem dual-processor . . . . . . . . . . . . . . . . . . . . . . . . . 66

3.2.2 Perifericul XPS Mailbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

3.2.2.1 Organizarea registrilor . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

3.2.2.2 Exemplu de utilizare a perifericului . . . . . . . . . . . . . . . . . . . 71

3.2.3 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

4 Crearea modulelor IP 75

4.1 Crearea si adaugarea unor noi periferice pe bus-ul PLB . . . . . . . . . . . . . . . . . 75

4.1.1 Periferic Slave PLB cu registri accesibili din software . . . . . . . . . . . . . . . 75

4.1.2 Periferic Slave PLB cu suport pentru ıntreruperi . . . . . . . . . . . . . . . . . 80

4.1.3 Periferic Master PLB cu suport pentru transfer ın regim burst . . . . . . . . . 87

4.1.4 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

4.2 Simularea proiectelor EDK ın ModelSim . . . . . . . . . . . . . . . . . . . . . . . . . . 90

4.2.1 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93

Bibliografie 95

v

vi

CAPITOLUL 1

Introducere

1.1 Crearea unui proiect ın Xilinx EDK 12.1

Pentru crearea unui proiect ın mediul Xilinx Platform Studio din cadrul pachetului EmbeddedDevelopment Kit [1], cea mai simpla metoda este folosirea wizard-ului Base System Builder, accesibilla pornirea aplicatiei (Fig. 1-1). Dupa selectarea acestei optiuni, se vor parcurge o serie de ferestreprin care se configureaza sistemul ce se doreste a fi creat.

Primul pas ın crearea proiectului este selectarea directorului de lucru ın care se vor crea automatfisierele necesare. Se recomanda ca numele directorului de lucru si al tuturor directoarelor din caleacatre acesta sa nu contina spatii sau caractere diacritice. Numele proiectului trebuie sa fie system.xmp.

In prima fereastra a Base System Builder selectati optiunea I would like to create a new design siapasati butonul Next conform Fig. 1-2a.

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

1

1 Introducere 2

(a) Prima fereastra (b) Selectarea placii de dezvoltare

Figura 1-2: Crearea unui proiect nou.

(a) Sistem uniprocesor (b) Configurarea procesorului

Figura 1-3: Crearea unui proiect nou - Selectarea procesorului.

In cadrul ferestrei de selectare a placii de dezvoltare (Board selection) se lasa optiunea selectataimplicit I would like to create a system for the following development board. La optiunea Board vendorse selecteaza Xilinx, la optiunea Board name se selecteaza Spartan-3E Starter Board [2], iar la Boardrevision optiunea ”C” (Fig. 1-2b).

In urmatoarea fereastra lasati selectata optiunea implicita de sistem uniprocesor (Single-Procesorsystem), conform Fig. 1-3a. Folosirea sistemelor cu mai multe procesoare va fi descrisa ıntr-un capitolulterior.

Fereastra de configurare a procesorului (Fig. 1-3b) permite selectarea frecventei ceasului de referinta,alegerea tipului de procesor (ın cazul Spartan-3E singura optiune disponibila este MicroBlaze [3]),selectarea frecventei ceasului de sistem si a dimensiunii memoriei locale (BRAM) utilizate. Deasemenea, ın cazul procesorului MicroBlaze, se poate opta pentru adaugarea unei unitati de calcul ınvirgula mobila (Floating Point Unit - FPU). Majoritatea programelor prezentate ulterior vor rula pesisteme configurate cu optiunile implicite din aceasta fereastra.

Urmatoarea fereastra (Fig. 1-4a) permite selectarea perifericelor ce vor fi adaugate automat lasistem. Configurarea unor parametri ai perifericului se realizeaza printr-un click pe numele acestuia.

3 Crearea unui proiect ın Xilinx EDK 12.1

(a) Adaugarea perifericelor (b) Configurarea aplicatiilor

Figura 1-4: Crearea unui proiect nou - Specificarea perifericelor si a aplicatiilor.

Daca s-au selectat ca periferice memorii externe (DDR, Flash etc.) se poate selecta ın urmatoareafereastra optiunea ca acestea sa fie accesate printr-o memorie de tip cache. Din considerente desimplitate, pentru moment lasati aceasta optiune neselectata.

Ca aplicatii software, implicit se genereaza doua aplicatii de test, pentru memorie si periferice, cuajutorul carora se poate valida functionarea corecta a hardware-ului. Pentru folosirea terminaluluiXMD (recomandat) la parametrul Standard IO selectati optiunea mdm 0, conform Fig. 1-4b.

Ultima fereastra din cadrul wizard-ului Base System Builder prezinta un sumar al sistemului creat,incluzand o lista a componentelor sistemului si adreselor lor, precum si o lista a fisierelor generate ıncadrul proiectului. Un click pe butonul Finish va determina finalizarea generarii proiectului.

1.1.1 Crearea unei noi aplicatii software

Avand structura sistemului hardware definita, se poate trece la crearea aplicatiilor care vor rula peacest sistem cu microprocesor. Trebuie mentionat faptul ca pentru o structura hardware se pot definimai multe aplicatii software care sa ruleze pe aceasta. Pentru selectarea aplicatiei software care varula pe procesor din memoria BRAM se da click dreapta pe numele aplicatiei si se selecteaza optiuneaMark to Initialize BRAMs.

Pentru crearea unei noi aplicatii software, ın tabul Applications se da click pe optiunea Add SoftwareApplication Project (ın layout-ul standard se gaseste ın partea de stanga sus a ferestrei). In fereastra dedialog nou deschisa se introduce numele aplicatiei si se selecteaza procesorul pe care va rula aceasta.Optiunea Project is an ELF-only Project se lasa deselectata. Dupa crearea noii aplicatii softwaretrebuie create (sau adaugate) fisierele .c sau .cpp care contin codul sursa al aplicatiei. Aceasta serealizeaza printr-un click dreapta pe itemul Sources corespunzator aplicatiei si selectarea uneia dintreoptiunile Add Existing Files sau Add New File.

Implicit compilatorul este setat pe modul de optimizare Medium (-O2). Se recomanda setarealui pe nivelul No optimization pentru a evita unele situatii neplacute, ın care compilatorul modificafunctionarea asteptata a programului. Aceasta setare se poate face dand click dreapta pe numeleaplicatiei si selectand Set Compiler Options. In fereastra nou deschisa, se selecteaza al doilea tab:

1 Introducere 4

Figura 1-5: Crearea unei aplicatii software - Setarea nivelului de optimizare al compilatorului.

Debug and Optimization, iar setarea se face la optiunea Optimization Level, conform Fig. 1-5.

1.1.2 ”Hello world”

O prima aplicatie ce se poate realiza este cea de a transmite serial un text de la placa de dezvoltarecatre calculator: un program ”Hello world”, prezentat mai jos. Se poate remarca folosirea functieixil printf ın locul functiei printf din biblioteca standard C. Motivul este acela de a avea un codexecutabil de dimensiuni reduse, lucru esential cand programul ruleaza din memoria BRAM.

int main(void)

{

xil_printf("Hello world!");

return 1;

}

Un alt lucru de remarcat este ca mediul de dezvoltare EDK adauga implicit un set de bibliotecistandard, motiv pentru care acestea nu trebuie incluse neaparat la ınceputul codului sursa (ın cazulde fata nu este necesara includerea headerului stdio.h).

Pentru a vizualiza textul ”Hello world!” este necesara deschiderea unui terminal de comunicatiiseriale emulat prin interfata de debug. Acest lucru se face prin selectarea optiunii Debug -> LaunchXMD din fereastra principala a Xilinx Platform Studio. Dupa un click pe butonul Ok din fereastra nouaparuta (XMD Debug Options) se va deschide consola de debug XMD (Fig. 1-6a). Comenzile pot fiintroduse ın aceasta consola dupa prompterul XMD%. Introducerea comenzii terminal va determinadeschiderea unui terminal de comunicatii seriale (Fig. 1-6b), cu ajutorul caruia se poate vizualizarezultatul rularii aplicatiei ”Hello world”.

1.2 Adaugarea unui nou periferic

Adaugarea unui periferic nou la un proiect generat ın prealabil va fi exemplificata prin adaugareaunui periferic de intrare/iesire de uz general (General Purpose Input/Output - GPIO) pentru interfatareacu butonul rotativ disponibil pe placa de dezvoltare Spartan-3E. O prezentare mai detaliata a functionariiGPIO si a utilizarii butonului rotativ poate fi gasita ın sectiunea 2.1.

Dupa deschiderea proiectului, perifericul se instantiaza din tab-ul IP Catalog, printr-un dublu clickpe optiunea General Purpose IO -> XPS General Purpose IO. Dupa instantiere:

5 De la crearea proiectului ın EDK la functionarea lui pe placa

1. In tab-ul System Assembly View -> Bus Interfaces conectati perifericul la magistrala standarda sistemului mb plb.

2. 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 configurateautomat.

3. In tab-ul System Assembly View -> Ports, configurati perifericul GPIO printr-un dublu click penumele instantei perifericului, setand ın tab-ul User, meniul Channel 1 parametrul GPIO DataChannel Width cu valoarea 2 si Channel 1 is Input Only cu valoarea TRUE.

4. In tab-ul System Assembly View -> Ports specificati portul de intrare GPIO IO I al perifericuluica fiind extern prin schimbarea optiunii No Connection ın Make External.

5. In tab-ul Project deschideti fisierul UCF (dublu click pe data/system.ucf ) si adaugati liniile demai 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;

(a) Consola de debug XMD (b) Terminalul de comunicatii seriale XMD

Figura 1-6: Utilitare pentru depanarea software.

1.3 De la crearea proiectului ın EDK la functionarea lui pe placa

La apasarea butonului Download Bitstream ın EDK se initiaza o serie de operatii care sintetizeazapartea hardware si compileaza partea software, rezultatul acestor procese fiind ınglobat ıntr-un asanumit bitstream care va fi ıncarcat ın FPGA.

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

Figura 1-7: Generarea platformei hardware [1].

1 Introducere 6

Procesul de generare a platformei hardware este prezentat ın Fig. 1-7. Platforma hardware (sistemulcu microprocesor) este descrisa ın fisierul MHS (Microprocessor Hardware Specification) din cadrulproiectului. Aceasta descriere este procesata de utilitarul Platgen, care genereaza descrierea HDL toplevel a sistemului. Impreuna cu modulele HDL ale procesorului si perifericelor, utilitarul XST (XilinxSynthesis Technology) genereaza lista de conexiuni (fisier NGC).

Generarea fisierului bitstream se face cu ajutorul utilitarelor Xilinx ISE care sunt apelate prinintermediul XFlow conform Fig. 1-7b. In cadrul acestui proces se folosesc constrangerile referitoarela maparea semnalelor la pinii FPGA, descrise ın fisierul UCF.

Platforma, din punct de vedere software, este descrisa ın fisierul MSS (Microprocessor SoftwareSpecification). Descrierea este procesata de utilitarul LibGen care genereaza o serie de biblioteciaferente procesorului si drivere asociate perifericelor din sistem. Fisierele sursa sunt compilate cuajutorul utilitarului GCC, iar linkeditorul genereaza fisierul executabil ELF (Fig. 1-8a).

Ca ultim pas al procesului, utilitarul Data2Mem actualizeaza portiunile din bitstream care corespundmemoriilor cu codul executabil, conform Fig. 1-8b.

(a) Generarea fisierului executa-bil

(b) Actualizarea bitstream-ului

Figura 1-8: Adaugarea partii software la bitstream [1].

CAPITOLUL 2

Utilizarea perifericelor

2.1 Perifericul de uz general pentru intrari-iesiri (GPIO)

Perifericul de uz general pentru intrari-iesiri (General Purpose Input/Output - GPIO) [4] permiteaccesul la pinii de intrare-iesire ai circuitului FPGA prin intermediul magistralei PLB. Folosind acestperiferic se pot defini grupuri de pini de lungime maxima de 32 de biti care sa poata fi cititi sau scrisiprin intermediul software-ului. Acest periferic poate fi folosit la comanda LED-urilor, respectiv citireastarii butoanelor sau a switch-urilor. In afara de comanda acestor periferice simple, modulul oferaposibilitatea emularii din software a unor protocoale complexe, prin accesul direct la pini pe care ılofera.

Perifericul GPIO se poate configura ca avand unul sau doua canale. Fiecare canal poate avea de la1 la 32 de biti, numarul si directia (pin de intrare sau iesire) fiind configurabile individual pe canal,respectiv bit. De asemenea, se pot configura valorile la reset pentru fiecare bit din ambele canale. Oalta facilitate oferita de acest periferic este capacitatea de a genera ıntreruperi la schimbarile valorilorde intrare ale pinilor. Structura interna a perifericului GPIO este prezentata ın Fig. 2-1.

Pentru a folosi portul ca intrare se vor seta toti bitii din registrul GPIO TRI ın 1 pentru a seta buffer-ul tri-state ın starea de ınalta impedanta, iar valorile pinilor se vor regasi ın registrul READ REG IN.In cazul folosirii portului ca unul de iesire bitii din registrul GPIO TRI se vor seta ın valoarea 0,permitand scrierea datelor din registrul GPIO DATA catre pini. Ca o consecinta, daca portul estesetat ca unul de iesire, datele din READ REG IN vor coincide cu GPIO DATA.

Un exemplu minimal de sistem care foloseste perifericul GPIO pentru a comanda ledurile de peplaca de dezvoltare este prezentat ın Fig. 2-2. Acest sistem contine un microprocesor cu memoria afe-renta, iar comunicarea dintre procesor si perifericul GPIO (LEDs 8Bit) este realizata prin intermediulmagistralei PLB.

2.1.1 Organizarea registrilor

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, citireafacandu-se din READ REG IN iar scrierea ın GPIO DATA. Marimea porturilor este de maxim 32 debiti, adica de 4 octeti. Spatiul de adresare este aliniat la 1 octet, motiv pentru care registrii succesivi

7

2 Utilizarea perifericelor 8

ai perifericului sunt aliniati la multipli de 4 octeti. In cazul configurarii perifericului ca avand unsingur canal, citirea registrilor GPIO DATA1 si GPIO TRI1 va avea ıntotdeauna ca rezultat valoarea0.

Figura 2-1: Structura interna a GPIO [4].

Tabelul 2-1: Maparea registrilor GPIO ın spatiul de adrese.

Nume registru Descriere Adresa Tip acces

GPIO DATA Valoarea de la canalul 1 Adresa de baza + 0x00 Scriere/ Citire

GPIO TRI Registrul tri-state aferent canalului 1 Adresa de baza + 0x04 Scriere/ Citire

GPIO DATA1 Valoarea de la canalul 2 Adresa de baza + 0x08 Scriere/ Citire

GPIO TRI1 Registrul tri-state aferent canalului 2 Adresa de baza + 0x0C Scriere/ Citire

Urmatorul program prezinta un mod simplu de accesare a perifericului GPIO ai carui pini suntconectati la ledurile disponibile pe platforma de dezvoltare. Arhitectura minimala a sistemului pecare ruleaza acest exemplu este cea din Fig. 2-2.

//Cod C pentru configurarea ledurilor

#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

//a perifericului LEDs_8Bit

9 Perifericul de uz general pentru intrari-iesiri (GPIO)

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;

}

Figura 2-2: Structura unui sistem cu GPIO.

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

#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 perifericelor 10

2.1.2 Utilizarea ıntreruperilor

Pentru a facilita lucrul cu ıntreruperile, perifericul GPIO contine hardware dedicat care detecteazaorice modificare la oricare dintre pinii aferenti unui canal. Configuratia implicita a perifericului nuofera aceasta functionalitate, ea trebuind sa fie setata manual de catre utilizator. Aceasta se realizeazadin System Assembly View printr-un dublu click pe numele perifericului GPIO, apoi bifarea optiuniiGPIO Supports Interrupts ın tab-ul User, meniul Common din fereastra nou deschisa.

Registrii care controleaza functionarea ın ıntreruperi a GPIO sunt prezentati ın Tabelul 2-2.

Tabelul 2-2: Maparea registrilor de ıntreruperi GPIO ın spatiul de adrese.

Nume registru Descriere Adresa Tip acces

GIER Global Interrupt Enable Register Adresa de baza + 0x11C Scriere/ Citire

IP IER IP Interrupt Enable Register Adresa de baza + 0x128 Scriere/ Citire

IP ISR IP Interrupt Status Register Adresa de baza + 0x120 Citire/ TOW

In modul Toggle on Write (TOW), scrierea unui bit de 1 produce bascularea valorii bitului de pepozitia corespunzatoare din registru, realizandu-se practic o operatie de sau-exclusiv pe biti ıntrecuvantul stocat ın registru si cuvantul scris. De exemplu, daca un registru contine valoarea 0110 ınbinar si este scris ın mod TOW cu valoarea 0011, rezultatul va fi 0101 (ultimii doi biti ısi schimbavaloarea).

Registrul GIER ofera activarea/dezactivarea primara a iesirii de ıntrerupere a perifericului. Activa-rea 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 ın1 a bitului 0 (LSB) pentru canalul 1, respectiv a bitului 1 pentru canalul 2. Dezactivarea se realizeazaprin 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 primitape 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. Programulpresupune ca perifericul GPIO DIP Switches 4Bit este singura sursa de ıntreruperi din sistem, nefiindnecesara 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 ıntreportul IP2INTC Irpt al perifericului si portul Interrupt al procesorului MicroBlaze.

//Cod C pentru citirea switchurilor folosind ıntreruperi

#include "xparameters.h"

#include "mb_interface.h"

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

11 Perifericul de uz general pentru intrari-iesiri (GPIO)

void rutina_intrerupere(void *callBackHandler)

{

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

//inainte de a iesi din rutina de tratare a intreruperilor se invalideaza

//toate sursele de intreruperi venite de la switchuri (vezi descrierea TOW)

switchuri[0x120/4]=switchuri[0x120/4];

}

int main(void)

{

//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

return 1;

}

2.1.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 lamagistrala standard a sistemului mb plb.

2. In tab-ul System Assembly View -> Bus Interfaces dati dublu click pe numele perifericului. Infereastra nou deschisa ın tab-ul User, meniul Channel 1 setati numarul de biti corespunzatoriaplicatiei la optiunea GPIO Data Channel Width.

2 Utilizarea perifericelor 12

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 configurateautomat.

4. In tab-ul System Assembly View -> Ports specificati semnalele GPIO IO I ın cazul folosiriiperifericului pentru intrari, respectiv GPIO IO O ın cazul folosirii perifericului pentru iesiri cafiind semnale externe.

5. In tab-ul Project deschideti fisierul UCF (dublu click pe data/system.ucf ) si adaugati con-strangerile care mapeaza semnalele externe la pinii FPGA-ului. Mai jos sunt prezentate con-strangerile necesare pentru folosirea butonului rotativ.

Net xps_gpio_0_GPIO_IO_I_pin<0> LOC=K18 | IOSTANDARD = LVCMOS33 | PULLUP; #ROT-A

Net xps_gpio_0_GPIO_IO_I_pin<1> LOC=G18 | IOSTANDARD = LVCMOS33 | PULLUP; #ROT-B

2.1.4 Folosirea butonului rotativ cu GPIO

Butonul rotativ codifica miscarea circulara folosind doua semnale A si B generate de doua butoane[2]. Aceste doua butoane, din constructia interna prezentata ın Fig. 2-3a, sunt actionate de rotirea unuidisc descentrat. Miscarea de rotire cu un pas, ıntr-un sens sau altul, genereaza o succesiune specificade stari ale semnalelor A si B prezentate ın Fig. 2-3b. La ınceputul rotirii cu un pas, depinzand desensul miscarii, unul din butoane va fi ın pozitie deschisa ınaintea celuilalt. De asemenea, la sfarsitulefectuarii pasului, primul buton se va ınchide ınaintea celui de-al doilea.

(a) Structura interna (b) Succesiunea de stari la rotirea la dreapta a butonului

Figura 2-3: Butonul rotativ [2].

Pentru folosirea butonului rotativ se vor urma pasii descrisi la Instantierea perifericului, setandnumarul de biti necesari, ın acest caz, la 2.

Programul prezentat mai jos realizeaza decodificarea semnalelor. Ideea de baza consta ın modelareaunui automat de stare prin care se poate detecta parcurgerea succesiunii de semnale aferente rotirii ladreapta sau la stanga.

//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

13 Perifericul de uz general pentru intrari-iesiri (GPIO)

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

}

return 1;

}

2.1.5 Exercitii

1. Scrieti un program care sa afiseze pe leduri succesiv doua valori, fiecare valoare fiind mentinutaaproximativ 1 secunda (a - led aprins, s - led stins).(a) aaaa aaaa - ssss ssss(b) aaaa ssss - ssss aaaa(c) asas asas - sasa sasa

2. Scrieti un program care sa afiseze pe leduri succesiunea de numere de la 0 la 255 ın binar.Frecventa de schimbare a valorilor sa fie de aproximativ 1 Hz.

2 Utilizarea perifericelor 14

3. Scrieti un program care sa afiseze pe leduri succesiunea de numere de la 0 la 255 ın cod Gray.Frecventa de schimbare a valorilor sa fie de aproximativ 2 Hz.

4. Scrieti un program care sa afiseze pe leduri succesiunile de valori de mai jos. Frecventa deschimbare a valorilor sa 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 - 0x015. Scrieti un program care sa implementeze un numarator ın binar, afisarea valorii facandu-se pe

leduri. Incrementarea valorii se va face la o apasare a butonului rotativ (center) de pe placa dedezvoltare.

6. Scrieti un program care sa afiseze pe leduri reprezentarea ın binar a patratului valorii citite dela switchuri.

7. Scrieti un program care sa citeasca o valoare de pe switchuri. Bitul 0 citit sa fie afisat pe ledurile0 si 4, bitul 1 pe ledurile 1 si 5, bitul 2 pe ledurile 2 si 6 iar bitul 3 pe ledurile 3 si 7.

8. Scrieti un program care sa citeasca o valoare de la switchuri. Bitii 0 - 2 ai valorii citite reprezintapattern-ul care trebuie rotit pe leduri. Bitul 3 reprezinta sensul rotirii:- 0 rotire spre stanga- 1 rotire spre dreapta

15 Perifericul pentru comunicatii seriale asincrone (UART Lite)

2.2 Perifericul pentru comunicatii seriale asincrone (UART Lite)

Perifericul UART Lite [5], conectat la magistrala PLB, ofera o interfata pentru realizarea de trans-feruri de date seriale asincrone full-duplex. Modulul realizeaza conversia paralel-serial a caracterelorprimite de pe magistrala PLB, respectiv conversia serial-paralel a caracterelor receptionate de la unuldin porturile RS-232 prezente pe placa de dezvoltare.

Perifericul dispune de cate un buffer de tip FIFO cu capacitatea de 16 caractere pentru transmisie(Tx FIFO), respectiv receptie (Rx FIFO), existand si optiunea de a genera ıntreruperi la receptionareaunui caracter sau la golirea Tx FIFO. Numarul de biti pe caracter este configurabil, putandu-se optapentru valori ıntre 5 si 8. Transferul se realizeaza utilizand un singur bit de stop. De asemenea, modululUART Lite mai permite configurarea baud rate-ului utilizat si se poate opta pentru utilizarea bituluide paritate, cu paritate para sau impara. Modificarea baud rate-ului, a numarului de biti pe caracter,respectiv a bitului de paritate se realizeaza din System Assembly View printr-un dublu click pe numeleperifericului UART Lite si setarea valorilor ın ın tab-ul User din fereastra nou deschisa.

2.2.1 Organizarea registrilor

Registrii perifericului UART Lite, fiecare a cate 32 de biti, sunt prezentati ın Tabelul 2-3.

Tabelul 2-3: Maparea registrilor UART Lite ın spatiul de adrese.

Nume registru Descriere Adresa Tip acces

Rx FIFO Buffer FIFO de receptie Adresa de baza + 0x00 Citire

Tx FIFO Buffer FIFO de transmisie Adresa de baza + 0x04 Scriere

STAT REG Registru de stare Adresa de baza + 0x08 Citire

CTRL REG Registru de control Adresa de baza + 0x0C Scriere

Bufferul Rx FIFO, avand capacitatea de 16 cuvinte, contine datele receptionate de periferic. Cuvantulreceptionat este reprezentat pe cei mai putin semnificativi biti ai registrului. Citirea ın cazul ın carebufferul este gol va rezulta ıntr-o eroare de magistrala. Bufferul Tx FIFO, de asemenea cu capacitateade 16 cuvinte, contine datele ce urmeaza a fi transmise.

Registrul STAT REG ofera informatii de stare asupra bufferelor, ıntreruperilor si erorilor rezultate.Structura registrului este prezentata ın Tabelul 2-4.

Registrul CTRL REG permite activarea sau dezactivarea modului de lucru ın ıntreruperi si resetareabufferelor de transmisie si receptie. Structura registrului este prezentata ın Tabelul 2-5. PerifericulUART Lite poate genera o ıntrerupere atunci cand exista un caracter valid ın Rx FIFO sau cand TxFIFO se goleste.

2.2.2 Exemple de folosire a perifericului

Aplicatia ”echo” (fiecare cuvant primit de periferic este retrimis nemodificat) prezentata mai joseste un exemplu de utilizare a perifericului pentru comunicatii seriale. In bucla infinita din programulprincipal se asteapta pana cand se primesc date (prin citirea repetata a registrului de stare si testareabitului care indica daca bufferul de receptie nu mai este gol - Rx FIFO Valid Data), datele receptionatefiind apoi introduse ın bufferul de transmisie. Un pas optional este asteptarea pana cand data a fosttransmisa (prin citirea repetata a registrului de stare si testarea bitului care indica daca bufferul detransmisie este gol - Tx FIFO Empty).

2 Utilizarea perifericelor 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 Biti rezervati

4 Enable Interrupt

3-2 Biti rezervati

1 Reset Rx FIFO

0 Reset Tx FIFO

//Exemplu de folosire a perifericului pentru comunicatii 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 Tx FIFO este gol

}

return 1;

}

17 Perifericul pentru comunicatii seriale asincrone (UART Lite)

O varianta a aplicatiei ”echo” ce utilizeaza ıntreruperile este prezentata mai jos. Programul presu-pune ca perifericul serial este singura sursa de ıntreruperi din sistem, nefiind necesara adaugareasi configurarea unui controller de ıntreruperi. Pentru o astfel de functionare ın ıntreruperi, estenecesara realizarea unei conexiuni ın tab-ul System Assembly View -> Ports ıntre portul Interrupt alperifericului UART si cel al procesorului MicroBlaze.

//Exemplu de folosire a perifericului pentru comunicatii 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 perifericul UART

//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 UART

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

return 1;

}

2 Utilizarea perifericelor 18

La crearea unui proiect nou, perifericul implicit al mediului de programare C pentru intrarea siiesirea standard (STDIN si STDOUT) este perifericul pentru comunicatii seriale. Functiile de citiresi afisare scanf si printf vor folosi acest periferic pentru comunicare. Din cauza complexitatii acestorfunctii, marimea executabilului generat va fi mai mare decat memoria BRAM disponibila pe FPGA-ulSpartan-3E. Lucrul cu aceste functii este posibil doar cand programul este ıncarcat ın memoria DDR.

Pentru a facilita procesul de depanare a fost dezvoltata functia xil printf, care se foloseste similarcu functia printf, avand ınsa dimensiuni reduse. Variabilele acceptate de functie sunt pe 8, 16 si 32de biti, de orice tip ın afara de float. In codul urmator se prezinta exemple de utilizare a functieixil printf.

//Exemplu de folosire a xil_printf

int main(void)

{

unsigned i=10;

char c=’c’;

xil_printf("Hello world \r\n");//exemplu de afisare de text

xil_printf("Variabila i este = %d \r\n",i);// afisarea unui numar in baza 10

xil_printf("Variabila i este = %x \r\n",i);// afisarea unui numar in baza 16

xil_printf("Variabila c este = %c \r\n",c);// afisarea unui caracter

xil_printf("Un string este = %s \r\n","un string");// afisarea unui sir de caractere

return 1;

}

2.2.3 Exercitii

1. Scrieti un program care:(a) La primirea caracterului ’s’ va crea efectul de deplasare a unui led aprins spre stanga;(b) La primirea caracterului ’d’ va crea efectul de deplasare a unui led aprins spre dreapta;(c) La primirea unui numar de la 0 la 7 va aprinde ledul de pe pozitia corespunzatoare.

2. Scrieti o functie care primeste ca parametru un pointer la un sir de caractere si realizeazatransmiterea sirului pe interfata seriala. Sfarsitul sirului este semnalat cu caracterul avandvaloarea 0.

19 Perifericul pentru comunicatii seriale sincrone (SPI)

2.3 Perifericul pentru comunicatii seriale sincrone (SPI)

Perifericul pentru comunicatii seriale sincrone (Serial Peripheral Interface - SPI) [6] permite transfe-rul full-duplex de mesaje cu circuite externe FPGA-ului prin intermediul magistralei PLB. Avantajelecomunicatiei seriale sunt reprezentate de numarul redus de pini utilizati, viteza mare de transfer silogica simpla pentru implementarea interfetei. Din aceste motive interfata SPI este des ıntalnitala circuite integrate specializate, cum ar fi convertorul analog digital (ADC) sau convertorul digitalanalog (DAC).

Comunicatia seriala este realizata ıntre doua entitati: un master, care initiaza tranzactiile, respectivun slave, care este adresat de master. In cadrul fiecarei tranzactii se trimit date ın ambele sensuri, dela master catre slave si de la slave catre master. Lungimea cuvintelor transferate este configurabila,ıntre 8 si 32 de biti, acest numar fiind ın general multiplu de 8.

Semnalele prin care se realizeaza comunicatia seriala sunt:

• Semnalul de ceas (CLK) - generat de master. Fronturile acestui semnal indica momentele ıncare se realizeaza operatiile de scriere si citire de date.

• Master Output Slave Input (MOSI) - generat de master. Prin intermediul acestui semnal setrimit datele catre dispozitivul slave.

• Master Input Slave Output (MISO) - generat de slave. Prin intermediul acestui semnal se trimitdatele catre dispozitivul master.

• Slave Select (SS) - generat de master. In general activ ın stare low, semnalul indica validareadatelor de intrare pentru dispozitivul slave. In majoritatea sistemelor ın care masterul trebuie sacomunice cu mai multe dispozitive slave, semnalele CLK, MOSI si MISO sunt folosite ın comunde toate dispozitivele slave, pentru a reduce numarul de pini necesari comunicarii. Fiecaredispozitiv slave primeste ınsa un semnal SS individual, astfel ıncat cel mult un slave este activla un moment dat. Doar dispozitivul slave selectat va transmite date pe semnalul MISO, toatecelelalte dispozitive avand aceasta iesire ın starea de ınalta impedanta.

Un exemplu de transfer serial pe 8 biti este prezentat ın Fig. 2-4. Master-ul scrie datele pe frontulnegativ al semnalului de ceas, iar slave-ul le citeste pe frontul pozitiv al semnalului de ceas. Intr-unmod asemanator, slave-ul scrie datele pe frontul pozitiv al semnalului de ceas, iar master-ul le citestepe frontul negativ.

Figura 2-4: Exemplu de transfer serial sincron.

2 Utilizarea perifericelor 20

2.3.1 Organizarea registrilor

Perifericul prezinta 8 registri catre exterior, prezentati ın Tabelul 2-6.

Tabelul 2-6: Maparea registrilor SPI ın spatiul de adrese.

Nume registru Descriere Adresa Tip acces

SRR Software reset register Adresa de baza + 0x40 Scriere

SPICR SPI control register Adresa de baza + 0x60 Scriere/ Citire

SPISR SPI status register Adresa de baza + 0x64 Citire

SPIDTR SPI data transfer register Adresa de baza + 0x68 Scriere

SPIDRR SPI data receive register Adresa de baza + 0x6C Citire

SPISSR SPI slave select register Adresa de baza + 0x70 Scriere/ Citire

Tx FIFO OCY Tx Fifo ocupancy register Adresa de baza + 0x74 Citire

Rx FIFO OCY Rx Fifo ocupancy register Adresa de baza + 0x78 Citire

Pentru resetarea perifericului SPI se va scrie valoarea 0x0000000A ın registrul SRR. Semnificatiabitilor din registrul SPICR este prezentata ın Tabelul 2-7.

Tabelul 2-7: Semnificatia bitilor din SPICR.

Bit Nume Descriere

31-10 - Neutilizati

9 LSB First Tipul transferului: 0 - MSB First, 1 - LSB First

8 Master Transac-tion Inhibit

Dezactivarea tranzactiilor de date ın mod master: 0 -Activare tranzactii, 1 - Dezactivare tranzactii

7 Manual SlaveSelect AssertionEnable

Modul de generare a semnalului SS: 0 - Semnalul SS nu estegenerat de perifericul SPI, 1 - Semnalul SS este generat deperifericul SPI ın functie de registrul SPISSR

6 Rx FIFO Reset Resetare FIFO receptie: 0 - FIFO receptie neresetat, 1 -FIFO receptie resetat

5 Tx FIFO Reset Resetare FIFO transmisie: 0 - FIFO transmisie neresetat, 1- FIFO transmisie resetat

4 CPHA Selectia frontului de ceas pentru citirea datelor: 0 - MISOeste citit pe frontul pozitiv al CLK, 1 - MISO este citit pefrontul negativ al CLK

3 CPOL Selectia nivelului de ceas ıntre transferuri: 0 - CLK este 0ıntre transferuri, 1 - CLK este 1 ıntre transferuri

2 Master Modul de lucru al perifericului: 0 - Slave, 1 - Master

1 SPE Activarea perifericului: 0 - Toate semnalele sunt ın ınaltaimpedanta, 1 - Mod normal de functionare

0 LOOP Citirea iesirilor: 0 - Mod normal de operare, 1 - MOSI esteconectat la MISO

Semnificatia bitilor din SPISR este prezentata ın Tabelul 2-8.

21 Perifericul pentru comunicatii seriale sincrone (SPI)

Tabelul 2-8: Semnificatia bitilor registrului SPISR.

Bit Nume Descriere

31-5 - Neutilizati

4 Rx FIFO full Specifica daca mai este loc ın buffer-ul de receptie: 0 - maieste loc pentru receptionarea de mesaje, 1 - buffer-ul esteplin

3 Tx FIFO under-run

Specifica daca perifericul a ıncercat transmiterea unei date,fara ca ea sa existe ın buffer-ul de iesire (doar ın cazulfunctionarii ın mod slave): 0 - nu a avut loc un asemeneaeveniment, 1 - a avut loc un asemenea eveniment

2 Tx FIFO empty Semnaleaza daca buffer-ul de transmisie este gol: 0 - maisunt mesaje ın curs de transmisie, 1 - buffer-ul este gol

1 Slave MODF Semnaleaza daca, ın mod slave, semnalul de SS a devenitinactiv ınaintea receptionarii complete a unui mesaj: 0 - nuau avut loc erori de comunicatie, 1 - au avut loc erori decomunicatie

0 MODF Semnaleaza daca, ın mod master, semnalul de SS a devenitactiv din exterior: 0 - nu au avut loc erori, 1 - au avut locerori.

Numarul de biti utilizati din registrii SPIDTR si SPIDTRR este egal cu lungimea cuvintelor de datetransmise pe SPI, bitii neutilizati avand valoarea 0 la citire.

Tx FIFO OCY si Rx FIFO OCY se genereaza doar ın cazul folosirii FIFO-urilor de transmisie sireceptie. Registrii specifica numarul de cuvinte din FIFO-urile de transmisie si receptie printr-o valoareıntre 0 si 15.

2.3.2 Utilizarea ıntreruperilor

Pentru a facilita transferurile prin interfata seriala, perifericul SPI defineste o serie de registriaditionali dedicati pentru setarea ıntreruperilor, prezentati ın Tabelul 2-9.

Tabelul 2-9: Maparea registrilor de ıntrerupere ai perifericului SPI ın spatiul de adrese.

Nume registru Descriere Adresa Tip acces

DGIER Global interrupt register Adresa de baza + 0x1C Scriere/ Citire

IPISR Interrupt status register Adresa de baza + 0x20 TOW/ Citire

IPIER Interrupt enable register Adresa de baza + 0x28 Scriere/ Citire

Registrul DGIER este utilizat pentru activarea sau dezactivarea ıntreruperilor de la periferic, uti-lizandu-se bitul cel mai semnificativ, conform Tabelului 2-10.

Semnificatia bitilor din IPISR este prezentata ın Tabelul 2-11. In cazul scrierii ın acest registru aunui bit de 1, bitul corespunzator din registru ısi va schimba starea (Toggle On Write). De exemplu,daca un registru contine valoarea 0110 ın binar si este scris ın mod TOW cu valoarea 0011, rezultatulva fi 0101 (ultimii doi biti ısi schimba valoarea).

Fiecare ıntrerupere definita ın IPISR are un bit de validare ın registrul IPIER, conform Tabelului2-12.

2 Utilizarea perifericelor 22

Tabelul 2-10: Semnificatia bitilor din DGIER.

Bit Nume Descriere

31 Global interrupt Validarea globala a ıntreruperilor: 0 - ıntreruperile suntinvalidate, 1 - ıntreruperile sunt validate

30 - 0 - Neutilizati

Tabelul 2-11: Semnificatia bitilor din IPISR.

Bit Nume Descriere

31-7 - Neutilizati

6 Tx FIFO Halfempty

Locatii ocupate din FIFO-ul de transmisie : 0 - mai putinde jumatate, 1 - mai mult de jumatate

5 Rx FIFO overrun Specifica daca au fost pierdute date la receptie: 0 - toatedatele receptionate au fost/pot fi citite, 1 - cel putin o dataa fost suprascrisa ınainte de a fi citita

4 Rx FIFO full Specifica daca mai este loc ın buffer-ul de receptie: 0 - maieste loc pentru receptionarea de mesaje, 1 - buffer-ul esteplin

3 Tx FIFO under-run

Specifica daca perifericul a ıncercat transmiterea unei date,fara ca ea sa existe ın buffer-ul de iesire (doar ın cazulfunctionarii ın mod slave): 0 - nu a avut loc un asemeneaeveniment, 1 - a avut loc un asemenea eveniment

2 Tx FIFO empty Semnaleaza daca buffer-ul de transmisie este gol: 0 - maisunt mesaje ın curs de transmisie, 1 - buffer-ul este gol

1 Slave MODF Semnaleaza daca, ın mod slave, semnalul de SS a devenitinactiv ınaintea receptionarii complete a unui mesaj: 0 - nuau avut loc erori de comunicatie, 1 - au avut loc erori decomunicatie

0 MODF Semnaleaza daca, ın mod master, semnalul de SS a devenitactiv din exterior: 0 - nu au avut loc erori, 1 - au avut locerori.

2.3.3 Periferice SPI pe platforma Spartan 3E

Pe placa de dezvoltare Spartan 3E sunt conectate o serie de periferice care folosesc ın comunsemnalele de CLK, MOSI si MISO, avand ınsa semnale de Slave Select separate [2]. Selectia se faceprin activarea semnalului SS corespunzator perifericului dorit si dezactivarea semnalelor SS aferentecelorlalte periferice de pe magistrala SPI. Tabelul 2-13 prezinta semnalele de Slave Select pentru fiecareperiferic si locatiile pinilor corespunzatori.

Locatiile semnalelor comune pe bus-ul SPI sunt prezentate ın Tabelul 2-14.

2.3.4 Instantierea perifericului

Perifericul se poate instantia din tab-ul IP Catalog, optiunea Communication Low Speed -> XPSSPI Interface. Dupa instantiere:

23 Perifericul pentru comunicatii seriale sincrone (SPI)

1. In tab-ul System Assembly View -> Bus Interfaces conectati portul SPLB al perifericului lamagistrala standard a sistemului mb plb.

2. In tab-ul System Assembly View -> Bus Interfaces dati dublu click pe numele perifericului. Infereastra nou deschisa setati raportul de divizare ıntre ceasul sistemului si ceasul SPI (valoareaimplicita este 2). Daca nu exista constrangeri asupra ariei ocupate de sistem, lasati optiuneaInclude both Receiver and transmitter FIFOs pe valoarea implicita TRUE. La optiunea Numberof SPI transfer bits setati numarul corect, ın functie de perifericul cu care se doreste comunicarea.

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 configurateautomat.

4. In tab-ul System Assembly View -> Ports specificati semnalele SCK, MOSI si MISO ca fiindsemnale externe.

5. In tab-ul Project deschideti fisierul UCF (dublu click pe data/system.ucf ) si adaugati con-strangerile care mapeaza semnalele externe la pinii FPGA-ului.

Tabelul 2-12: Semnificatia bitilor registrului IPIER.

Bit Nume Descriere

31-7 - Neutilizati

6 Tx FIFO Halfempty

Validare Tx FIFO Half empty: 0 - ıntrerupere invalidata, 1- ıntrerupere validata

5 Rx FIFO overrun Validare Rx FIFO overrun: 0 - ıntrerupere invalidata, 1 -ıntrerupere validata

4 Rx FIFO full Validare Rx FIFO full: 0 - ıntrerupere invalidata, 1 -ıntrerupere validata

3 Tx FIFO under-run

Validare Tx FIFO underrun: 0 - ıntrerupere invalidata, 1 -ıntrerupere validata

2 Tx FIFO empty Validare Tx FIFO empty: 0 - ıntrerupere invalidata, 1 -ıntrerupere validata

1 Slave MODF Validare Slave MODF: 0 - ıntrerupere invalidata, 1 -ıntrerupere validata

0 MODF Validare MODF: 0 - ıntrerupere invalidata, 1 - ıntreruperevalidata

Tabelul 2-13: Periferice SPI pe platforma Spartan 3E.

Nume periferic Locatie SS Valoare dezactivare

Convertor digital analog DAC CS(N8) 1

Preamplificator analogic AMP CS(N7) 1

Convertor analog digital AD CONV(P11) 0

SPI Serial Flash SPI SS B(U3) 1

StrataFlash Parallel Flash PROM SF CE0(D16) 1

Platform Flash PROM FPGA INIT B(T3) 1

2 Utilizarea perifericelor 24

Tabelul 2-14: Semnale SPI comune de pe platforma Spartan 3E.

Nume semnal Locatie pin

CLK U16

MOSI T4

MISO N10

2.3.5 Convertorul digital-analog (DAC)

Platforma de dezvoltare Spartan 3E contine convertorul digital-analog LTC2624, a carui functionalitateeste descrisa ın [7]. Acest convertor are patru canale de iesire (A, B, C si D), A si B generand tensiunide pana la 3.3V, iar C si D pana la 2.5V.

Pentru a comanda convertorul digital analog se trimit pachete de date de 32 de biti, dupa structuraprezentata ın Fig. 2-5. Cuvantul de comanda cel mai des folosit este 0x03, utilizat pentru modificareainstantanee a iesirilor cu noile valori.

Figura 2-5: Structura mesajului trimis catre DAC [2].

Semnalul Adc Conv este un semnal activ ın 1, spre deosebire de celelalte semnale de Slave Select aleperifericelor SPI disponibile pe placa de dezvoltare. Din acest motiv, generarea semnalelor de SlaveSelect nu se preteaza a fi implementata direct ın perifericul SPI. Astfel, ın exemplul de mai jos se vafolosi si un periferic GPIO pe 7 biti, prin intermediul caruia semnalele de Slave Select vor fi comandatedirect din software.

Programul de mai jos genereaza un semnal dinte de fierastrau pe toate iesirile convertorului digitalanalog.

#include "xparameters.h"

volatile unsigned *spi = (unsigned *)XPAR_XPS_SPI_0_BASEADDR;

volatile unsigned *spi_cs = (unsigned *)XPAR_XPS_GPIO_0_BASEADDR;

#define SPI_CS_DEFAULT 0x7B

#define SPI_DAC_CS 0x40

#define SPI_DAC_CLR 0x20

25 Perifericul pentru comunicatii seriale sincrone (SPI)

int main(void)

{

int i,incr=32;

unsigned dac_transmit;

//dezactiveaza toate perifericele de pe bus-ul SPI

spi_cs[0]=SPI_CS_DEFAULT;

//reseteaza DAC-ul

for(i=0;i<10;i++)

spi_cs[0]=SPI_CS_DEFAULT & (~SPI_DAC_CLR);

i=0;

//dezactiveaza toate perifericele de pe bus-ul SPI

spi_cs[0]=SPI_CS_DEFAULT;

//reseteaza perifericul SPI

spi[0x40/4]=0x0000000A;

//configureaza perifericul SPI

spi[0x60/4]=0x07E;

while(1)

{

//comanda = 0011 - modificarea instantanee a valorilor iesirilor

//adresa = 1111 - selectarea tuturor iesirilor

dac_transmit=0x003F0000;

//adauga valoarea de iesire la cuvantul de transmis

dac_transmit=dac_transmit | ((i<<4) & 0x0000FFF0);

//transmite cuvantul catre DAC

spi_cs[0]=SPI_CS_DEFAULT &(~SPI_DAC_CS);

spi[0x68/4]=dac_transmit;

//asteapta golirea bufferului de transmisie

while((spi[0x64/4] & 0x4)==0);

spi_cs[0]=SPI_CS_DEFAULT;

//actualizeaza valoarea de iesire

i+=incr;

}

return 1;

}

Pentru acest proiect setarile din fisierul UCF sunt urmatoarele:

#Semnalele comune pe bus-ul SPI

Net xps_spi_0_SCK LOC=U16 | IOSTANDARD = LVCMOS33;

Net xps_spi_0_MISO LOC=N10 | IOSTANDARD = LVCMOS33;

Net xps_spi_0_MOSI LOC=T4 | IOSTANDARD = LVCMOS33;

2 Utilizarea perifericelor 26

#Semnalele corespunzatoare perifericelor de pe bus-ul SPI

#DAC CS - Semnal de selectie pentru DAC, activ in stare low

#Conversia digital-analogica incepe cand semnalul revine in stare high

Net xps_gpio_0_GPIO_IO_O_pin<0> LOC=N8 | IOSTANDARD = LVCMOS33;

#DAC_CLR - Semnal de reset asincron pentru DAC, activ in stare low

Net xps_gpio_0_GPIO_IO_O_pin<1> LOC=P8 | IOSTANDARD = LVCMOS33;

#SPI_SS_B - Valoare dezactivare = 1

Net xps_gpio_0_GPIO_IO_O_pin<2> LOC=U3 | IOSTANDARD = LVCMOS33;

#AMP_CS - Valoare dezactivare = 1

Net xps_gpio_0_GPIO_IO_O_pin<3> LOC=N7 | IOSTANDARD = LVCMOS33;

#AD_CONV - Valoare dezactivare = 0

Net xps_gpio_0_GPIO_IO_O_pin<4> LOC=P11 | IOSTANDARD = LVCMOS33;

#SF_CE0 - Valoare dezactivare = 1

Net xps_gpio_0_GPIO_IO_O_pin<5> LOC=D16 | IOSTANDARD = LVCMOS33;

#FPGA_INIT_B - Valoare dezactivare = 1

Net xps_gpio_0_GPIO_IO_O_pin<6> LOC=T3 | IOSTANDARD = LVCMOS33;

2.3.6 Exercitii

1. Scrieti un program care sa modifice doar iesirea A a convertorului digital analog.2. Scrieti un program care sa genereze un semnal dinte de fierastrau de frecventa 1.2KHz (dublul

frecventei din exemplu).3. Scrieti un program care sa genereze un semnal triunghiular pe iesirea A a convertorului digital

analog.4. Scrieti un program care sa genereze un semnal triunghiular pe iesirea A a convertorului digital

analog si un semnal dreptunghiular de frecventa dubla, cu un factor de umplere de 50%, peiesirea B.

5. Folosind perifericul timer pentru declansarea trimiterii urmatorului esantion, creati un semnalsinusoidal de 32 de esantioane.

6. Proiect. Creati o aplicatie care sa aiba 4 buffere de 128 de elemente din care se transmitesantioanele catre cele 4 iesiri ale convertorului digital analog. Folosind butoanele, switchurile,butonul rotativ si afisajul LCD realizati o interfata prin care se poate seta pentru fiecare canal:

• Frecventa semnalului ıntre 1 si 10000 de Hz.

• Forma semnalului: dinte de fierastrau, dreptunghiular, triunghiular sau sinusoidal.

• Valoarea minima de tensiune.

• Valoarea maxima de tensiune.

27 Controller-ul PS/2

2.4 Controller-ul PS/2

Controller-ul PS/2 [8], conectat la magistrala PLB, ofera o interfata pentru folosirea tastaturii si amouse-ului. Comunicarea cu placa Spartan-3E se face serial cu ajutorul a 2 pini: data (PS2 DATA)si ceas (PS2 CLK). Atat mouse-ul cat si tastatura comunica pe interfata PS/2 prin cadre de 11 bitiavand aceeasi temporizare. Comunicarea este bidirectionala: atat de la periferic catre gazda, cat siinvers.

Transferul unui cadru ıncepe prin transmiterea unui bit de START (’0’ logic) pe linia de date,dupa care urmeaza cuvantul de date de 8 biti (LSB transmis primul) si un bit de control al paritatii.Incheierea transferului se face cu un bit de STOP (’1’ logic). Fig. 2-6 prezinta diagrama de timp atransferului de informatii ıntre mouse/tastatura si gazda.

Figura 2-6: Diagrama de timp pentru bus-ul PS/2 [2].

2.4.1 Organizarea registrilor

Perifericul dispune de 8 registri interni de 32 de biti, prezentati ın Tabelul 2-15, cate patru pentrufiecare din cele doua canale disponibile. In cazul ın care perifericul este setat pe un singur canal,citirea registrilor canalului 2 va avea ca rezultat valoarea 0.

Tabelul 2-15: Maparea registrilor interni PS/2 ın spatiul de adrese.

Nume registru Descriere Adresa Tip acces

SRST 1 Registru resetare software (C1) Adresa de baza + 0x0000 Scriere

STATUS REG1 Registru stare (C1) Adresa de baza + 0x0004 Citire

RX1 DATA Registru date primite (C1) Adresa de baza + 0x0008 Citire

TX1 DATA Registru date trimise (C1) Adresa de baza + 0x000C Scriere

SRST 2 Registru resetare software (C2) Adresa de baza + 0x1000 Scriere

STATUS REG2 Registru stare (C2) Adresa de baza + 0x1004 Citire

RX2 DATA Registru date primite (C2) Adresa de baza + 0x1008 Citire

TX2 DATA Registru date trimise (C2) Adresa de baza + 0x100C Scriere

Registrul SRST x este folosit pentru resetarea canalului PS/2 corespunzator, aceasta facandu-seprin ınscrierea ın registru a cuvantului 0x0000000A. STATUS REGx este folosit pentru citirea stariicanalului x, semnificatia bitilor din registru fiind prezentata ın Tabelul 2-16. RXx DATA si TXx DATAsunt utilizati pentru transferul de cuvinte cu perifericul controlat, structura acestora fiind prezentataın Tabelul 2-17.

2 Utilizarea perifericelor 28

Tabelul 2-16: Semnificatia bitilor registrului STATUS REGx.

Bit Nume Descriere

31-2 - Biti neutilizati

1 IBF Indica daca buffer-ul de receptie este plin

0 OBF Indica daca buffer-ul de transmisie este plin

Tabelul 2-17: Structura unui cuvant transmis/receptionat.

Bit Descriere

31-8 Biti neutilizati

7-0 Biti de date

Pentru a facilita lucrul cu ıntreruperile, perifericul dispune de 6 registri suplimentari, cate trei pentrufiecare canal, descrisi ın Tabelul 2-18.

Tabelul 2-18: Maparea registrilor de ıntreruperi PS/2 ın spatiul de adrese.

Nume registru Descriere Adresa Tip acces

GIE 1 Global Interrupt Enable Register (C1) Adresa de baza + 0x002C Scriere/ Citire

IPISR 1 IP Interrupt Status Register (C1) Adresa de baza + 0x0030 Citire/ TOW

IPIER 1 IP Interrupt Enable Register (C1) Adresa de baza + 0x0038 Scriere/ Citire

GIE 2 Global Interrupt Enable Register (C2) Adresa de baza + 0x102C Scriere/ Citire

IPISR 2 IP Interrupt Status Register (C2) Adresa de baza + 0x1030 Citire/ TOW

IPIER 2 IP Interrupt Enable Register (C2) Adresa de baza + 0x1038 Scriere/ Citire

Activarea/dezactivarea primara a ıntreruperilor se face cu ajutorul registrului GIE x. Pentruactivare se ınscrie ’1’, iar pentru dezactivare ’0’ pe pozitia 31 (bitul MSB) a registrului.

Activarea individuala a ıntreruperilor se face cu ajutorul registrului IPIER x, structura acestuiafiind prezentata ın Tabelul 2-19.

Registrul IPISR x, a carui structura corespunde cu cea a registrului IPIER x, contine informatia destare a ıntreruperilor individuale aferente canalului x.

Tabelul 2-19: Semnificatia bitilor registrilor IPIER x si IPISR x.

Bit Nume Descriere

31-6 - Biti neutilizati

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

29 Controller-ul PS/2

2.4.2 Instantierea perifericului

Acest periferic nu se poate instantia utilizand Base System Builder. Dupa generarea sistemului, elpoate fi instantiat din tab-ul IP Catalog, optiunea Communication Low - Speed -> XPS PS2 Interface.Dupa instantiere:

1. In tab-ul System Assembly View -> Bus Interfaces conectati portul SPLB al perifericului lamagistrala standard a sistemului mb plb.

2. 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 configurateautomat.

3. In tab-ul System Assembly View -> Ports specificati semnalele PS2 1 DATA si PS2 1 CLK cafiind semnale externe.

4. In tab-ul Project deschideti fisierul UCF (dublu click pe data/system.ucf ) si adaugati urmatoareleconstrangeri:

Net xps_ps2_0_PS2_1_DATA LOC=G13 | IOSTANDARD = LVCMOS33;

Net xps_ps2_0_PS2_1_CLK LOC=G14 | IOSTANDARD = LVCMOS33;

2.4.3 Tastatura

Lucrul cu perifericul ıncepe prin resetarea controllerului PS/2, aceasta facandu-se prin scriereacuvantului 0x0000000A ın registrul SRST x. Urmatorul pas este resetarea tastaturii prin trimitereacuvantului 0xFF. Tastatura raspunde cu 0xFA si intra ın modul BAT (Basic Assurance Test), lafinalul caruia se ıncarca parametrii impliciti de functionare. In cazul unei erori ın cadrul testelor BATtastatura va trimite cuvantul 0xFC, iar ın caz contrar va trimite 0xAA, semnaland intrarea ın modulstandard de functionare.

Un exemplu de lucru cu tastatura este prezentat ın codul de mai jos. Cu ajutorul functiei send keyboardse pot trimite cuvinte catre tastatura. Datele care urmeaza a fi trimise sunt depuse ın registrulTX1 DATA, dupa care se asteapta pana cand bufferul de intrare si/sau iesire este golit.

//Exemplu de lucru cu tastatura

#include "xparameters.h"

unsigned *keyboard = (unsigned *)XPAR_XPS_PS2_0_0_BASEADDR;

void send_keyboard(unsigned data)

{

unsigned keyboard_status;

//scrie cuvantul de date in TX1_DATA

keyboard[0x0C/4] = data;

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

do

keyboard_status = keyboard[0x04/4];

while (keyboard_status%2 == 1);

}

2 Utilizarea perifericelor 30

int main(void)

{

unsigned key;

keyboard[0] = 0x0000000A;

send_keyboard(0xFF);//reset

xil_printf("Sending reset command\r\n");

for (j = 0; j < 2; j++)

{

key = keyboard[0x08/4];

while(keyboard[0x04] == 0);

xil_printf("%x\r\n", key);

}

while(1); // bucla infinita

return 1;

}

Fiecare tasta are un cod unic (Fig. 2-7), ce este trimis de la tastatura catre controller atunci candtasta este apasata. Exista trei tipuri de coduri:

1. cod propriu-zis

2. E0 (tasta extinsa - ca de ex. Ctrl, Alt)

3. F0 (tasta ridicata)

Figura 2-7: Codul tastelor unei tastaturi [2].

Daca o tasta este tinuta apasata, codul sau este retrimis la fiecare 100 ms. Atunci cand tasta esteridicata se trimite codul special ”F0” urmat de codul propriu-zis al tastei.

In cazul apasarii tastelor extinse se transmit doua cuvinte: primul reprezinta codul special ”E0”,al doilea codul propriu-zis al tastei. La ridicarea tastelor extinse se vor transmite urmatoarele treicuvinte: codul ”E0”, urmat de ”F0” si de codul propriu-zis al tastei.

Cele mai importante comenzi trimise de la controller catre tastatura sunt:

1. ED - Se foloseste pentru aprinderea/stingerea ledurilor Num Lock, Caps Lock si Scroll Lock.Tastatura confirma trimitand ”FA”, dupa care controllerul trimite un byte avand structura prezentataın Fig. 2-8 (pentru iluminarea unui led se seteaza bit-ul respectiv pe ’1’). Receptionarea cuvantuluide date este confirmata de catre tastatura prin trimiterea cuvantului ”FA”.

2. EE - Comanda de ecou, la care tastatura raspunde cu acelasi cod ”EE”.

3. F3 - Setarea ratei de repetare a transmiterii codurilor unice. Tastatura raspunde cu ”FA”, dupacare controllerul transmite un byte continand rata ce urmeaza a fi setata.

31 Controller-ul PS/2

4. FE - La primirea acestei comenzi tastatura retrimite ultimul cod transmis.

5. FF - Prin trimiterea acestui cod controllerul reseteaza tastatura.

Figura 2-8: Semnificatia cuvantului de stare a ledurilor tastaturii [2].

2.4.4 Mouse-ul

Lucrul cu perifericul ıncepe ın mod similar cu tastatura, prin resetarea controllerului, aceastafacandu-se prin scrierea cuvantului 0x0000000A ın registrul SRST x. Urmatorul pas este resetareamouse-ului prin trimiterea cuvantului 0xFF. Mouse-ul raspunde cu un acknowledge (0xFA) si intra ınmodul BAT (Basic Assurance Test), la finalul caruia se ıncarca parametrii impliciti de functionare. Incazul unei erori ın cadrul testelor BAT mouse-ul va trimite 0xFC, iar ın caz contrar va trimite 0xAAurmat de ID-ul mouse-ului semnaland intrarea ın modul standard de functionare. Dupa acest paseste necesara transmiterea cuvantului 0xF4 pentru activarea raportarii, la care mouse-ul raspunde cu0xFA. Trimiterea si receptionarea de cuvinte se face similar ca la tastatura.

In modul standard (prezentat ın continuare) ID-ul mouse-ului este 0x00 si sunt transmise miscarilemouse-ului, respectiv apasarea butoanelor stanga, dreapta si centru. Cu ajutorul extensiei Intellimousese poate lucra si cu scroll-ul si alte butoane disponibile eventual pe mouse (extensia este prezentatape http://www.computer-engineering.org/ps2mouse).

Transferul se date se face atunci cand mouse-ul este miscat sau se apasa butoanele acestuia, caz ıncare sunt trimise trei cuvinte: primul indica starea, al doilea rata miscarii pe axa X, iar al treilea ratamiscarii pe axa Y. Semnificatia bitilor celor 3 octeti este prezentata ın Fig. 2-9. Daca mouse-ul estemiscat ın continuu un set de trei cuvinte este transmis la fiecare 50 ms.

Figura 2-9: Cuvinte de date transmise de mouse [2].

Mouse-ul PS/2 foloseste un sistem de coordonate relativ la pozitia curenta, conform Fig. 2-10. Omiscare la stanga este codificata cu o valoare negativa, iar o miscare la dreapta cu o valoare pozitivapentru axa X. In mod similar, miscarea ın jos este codificata cu o valoare negativa, iar cea ın sus cuo valoare pozitiva pentru axa Y.

2 Utilizarea perifericelor 32

Figura 2-10: Sistemul relativ de coordonate al mouse-ului [2].

Semnificatia bitilor din cuvantul de stare este:

1. L si R indica apasarea butoanelor mouse-ului, L - butonul stang, R - butonul drept (’1’ logicpentru buton apasat).

2. XS respectiv YS indica sensul deplasarii pe axa X si Y.

3. XV si YV indica daca rata miscarii pe axa X respectiv Y a depasit limita maxima (overflow).

2.4.5 Exercitii

1. Scrieti un program care afiseaza pe terminal un mesaj ın cazul ın care se apasa tasta Ctrl Leftsi alt mesaj cand se apasa Ctrl Right.

2. Scrieti un program care aprinde toate ledurile de pe tastatura.3. Scrieti un program care la apasarea tastei ’Caps Lock’ aprinde, respectiv stinge ledul cores-

punzator de pe tastatura.4. Scrieti un program care afiseaza un mesaj corespunzator pe terminal atunci cand este apasat

unul din butoanele mouse-ului (stanga, dreapta, centru).5. Scrieti un program care deplaseaza un led aprins de pe placa de dezvoltare conform miscarii

scroll-ului.

33 Perifericul de comanda a afisajului LCD

2.5 Perifericul de comanda a afisajului LCD

Perifericul de comanda a afisajului LCD (LCD Driver) realizeaza o interfata simpla pentru afisareade caractere pe ecranul LCD disponibil pe placa de dezvoltare [2] utilizand magistrala PLB. Modululpermite afisarea de caractere ASCII pe ecranul de 2 linii a cate 16 caractere.

2.5.1 Organizarea registrilor

Modulul dispune de 32 de registri de caracter (numerotati de la 0 la 31) corespunzatori celor 32de pozitii ale ecranului LCD, conform Fig. 2-11. Pentru afisarea unui caracter este necesara scriereavalorii acestuia ın registrul de caracter corespunzator. Prin citirea unui registru se va returna codulASCII al caracterului afisat pe LCD. Structura unui registru de caracter este prezentata ın Tabelul2-20.

Figura 2-11: Corespondenta dintre registrii de caracter si afisajul LCD.

Setul de caractere al afisajului LCD si codurile aferente sunt prezentate ın Fig. 2-12. PerifericulLCD Driver nu permite afisarea de caractere personalizate.

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

Biti Descriere

31-8 Biti rezervati (valoare ’0’)

7-0 Cod caracter

2.5.2 Instantierea perifericului

Acest periferic nu este disponibil ın distributia standard Xilinx EDK, motiv pentru care el trebuiecopiat manual ın directorul pcores al proiectului. Dupa copiere el poate fi instantiat din tab-ul IPCatalog, optiunea Project Local pcores -> User -> LCD DRIVER. Dupa instantiere:

1. In tab-ul System Assembly View -> Bus Interfaces conectati perifericul la magistrala standarda sistemului mb plb.

2. 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 configurateautomat.

3. In tab-ul System Assembly View -> Ports specificati toate semnalele aferente perifericului LCDca fiind semnale externe.

4. In tab-ul Project deschideti fisierul UCF (dublu click pe data/system.ucf ) si adaugati con-strangerile prezentate mai jos.

2 Utilizarea perifericelor 34

#Constrangeri UCF pentru perifericul 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-12: Setul de caractere al afisajului LCD [2].

2.5.3 Aplicatii

Un exemplu simplu de utilizare a perifericului LCD Driver este prezentat mai jos. Programul vaafisa textul ”Hello world!” pe prima linie a ecranului LCD.

//Exemplu de utilizare a perifericului LCD Driver pentru afisarea de caractere

#include "xparameters.h"

//pointer la adresa de baza a perifericului LCD Driver

unsigned *lcd=(unsigned *)XPAR_LCD_DRIVER_0_MEM0_BASEADDR;

35 Perifericul de comanda a afisajului LCD

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;

}

2.5.4 Exercitii

1. Scrieti o functie care primeste ca parametru un pointer la un sir de caractere si afiseaza sirul peecranul LCD. Sfarsitul sirului este semnalat cu caracterul avand valoarea 0.

2. Scrieti un program care sa roteasca ıntr-un sens un text afisat pe ecranul LCD. Deplasarea seva face cu cate un pas la aproximativ o secunda.

2 Utilizarea perifericelor 36

2.6 Controller-ul VGA

Controller-ul video (xps tft controller) [9] este perifericul care faciliteaza afisarea de imagini pe unmonitor. Fiecarui pixel de pe monitor ıi corespunde un cuvant de 32 de biti din memorie din care peplaca Spartan-3E Starter Board sunt folositi doar 3 biti (8 culori posibile pentru un pixel). Folosindacest periferic se pot desena si afisa diferite imagini sau crea animatii din program.

Acest controller se conecteaza ca master pe magistrala PLB v4.6, citeste datele video din memoriaatasata la magistrala si le afiseaza pe monitor. Controller-ul este folosit pentru monitoare cu rezolutiede 640x480 si poate reda pana la 256K culori (8 culori cu placa Spartan-3E Starter Board). Pe langainterfata master, controller-ul mai dispune de interfata slave PLB care permite accesul la registriiinterni.

O structura minimala a unui sistem care foloseste controller-ul video este prezentata ın Fig. 2-13.Acest sistem contine un microprocesor cu memoria BRAM aferenta (pentru stocarea instructiunilorsi datelor), controller si memorie DDR (pentru stocarea imaginii de afisat), controller-ul video si unmonitor pe care se poate vizualiza imaginea.

Figura 2-13: Sistem pentru lucrul cu monitorul.

Controller-ul video contine un circuit de generare a doua semnale de sincronizare (HSYNC siVSYNC). Semnalul HSYNC specifica timpul necesar pentru a parcurge un rand al ecranului de lastanga la dreapta, iar semnalul VSYNC specifica timpul necesar pentru a traversa ıntregul ecran, desus ın jos.

HSYNC are o perioada de 800 de tacte de ceas (la o frecventa de 25MHz). Aceasta perioada poatefi considerata ca fiind formata din 4 regiuni: display, retrace, front porch si back porch. Displayeste regiunea ın care pixelii sunt afisati pe ecran si lungimea ei este de 640 tacte de ceas (un tactpentru fiecare pixel). In Fig. 2-14 este reprezentata diagrama de timp a semnalului. Forma de unda asemnalului VSYNC este prezentata ın Fig. 2-15. Perioada semnalului este egala cu 512 perioade alesemnalului HSYNC, regiunea de display avand o lungime de 480 astfel de perioade.

37 Controller-ul VGA

Figura 2-14: Diagrama de timp a semnalului HSYNC [9].

Controller-ul video are nevoie de 16.8 ms pentru afisarea unui cadru la o rezolutie de 640x480 si orata de refresh de 60Hz. Pentru afisarea completa a unui cadru nu trebuie modificata adresa de starta memoriei video ınainte de trecerea acestui timp.

Controller-ul video mai dispune de trei semnale de iesire, care colectiv formeaza “semnalul RGB”,reprezentand culoarea unui pixel, o combinatie ıntre rosu, verde si albastru prezentata ın Fig. 2-16.

Fiecare pixel este stocat ıntr-un cuvant 32 de biti. Formatul unui pixel este de forma:0xUURRGGBB, unde:U – unusedR – red pixel dataG – green pixel dataB – blue pixel data

In plus, desi controller-ul video foloseste numai o rezolutie de 640x480, fiecare linie trebuie stocataca o serie de 1024 pixeli. Astfel, exista 384 de pixeli neutilizati la fiecare sfarsit de linie. In consecinta,pentru afisarea unei imagini cu o rezolutie de 640x480 sunt necesari 1024*480*4(bytes) = 1966080bytes de memorie. Din considerente de simplitate a hardware-ului ınceputul zonei de memorie trebuiesa fie la o adresa multiplu de 2 MB.

2.6.1 Organizarea registrilor

Perifericul dispune de 2 registri accesibili prin interfata slave PLB, prezentati ın Tabelul 2-21.

Registrul de adresa ofera utilizatorului posibilitatea de a schimba adresa de baza a memoriei videodin care citeste controller-ul. Prin aceasta se poate rezolva efectul vizual neplacut al descarcarii unuicadru video din memorie pe ecran, efect datorat vitezei scazute de citire a datelor din memorie ıncomparatie cu viteza de afisare a datelor pe ecran. Utilizatorul poate schimba adresa de baza amemoriei video, afisand un alt cadru atunci cand o imagine este citita.

2 Utilizarea perifericelor 38

Figura 2-15: Diagrama de timp a semnalului VSYNC [9].

2.6.2 Instantierea perifericului

Acest periferic nu se poate instantia utilizand Base System Builder. Dupa generarea sistemului, elpoate fi instantiat din tab-ul IP Catalog, optiunea IO Modules -> XPS TFT. Dupa instantiere:

1. In tab-ul System Assembly View -> Bus Interfaces conectati porturile MPLB si SPLB aleperifericului la magistrala standard a sistemului mb plb.

2. 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 configurateautomat.

3. Semnalul de ceas al perifericului se configureaza din meniul Hardware -> Launch Clock Wizard.In fereastra nou deschisa selectati Peripherals -> xps tft 0 -> SYS TFT Clk si setati frecventala 25 MHz.

4. In tab-ul System Assembly View -> Ports dati dublu click pe numele perifericului si debifatioptiunea ”Select TFT Interface” din fereastra nou deschisa.

5. In tab-ul System Assembly View -> Ports specificati semnalele TFT HSYNC, TFT VSYNC,TFT VGA R, TFT VGA G si TFT VGA B ale perifericului ca fiind semnale externe.

6. In tab-ul Project deschideti fisierul UCF (dublu click pe data/system.ucf ) si adaugati con-strangerile de mai jos.

39 Controller-ul VGA

Figura 2-16: Culorile afisabile pe monitor folosind placa Spartan 3E [2].

Tabelul 2-21: Maparea registrilor controller-ului video ın spatiul de adrese.

Nume Descriere Adresa Tip acces

AR Registrul de adrese Adresa de baza + 0x00 Scriere/ Citire

[31:20] Bitii MSB ai adresei de ınceput

[19:0] Intotdeauna 0. Adresa de bazaıncepe la multipli de 2MB

CR Registrul de control Adresa de baza + 0x04 Scriere/ Citire

[31:2] Biti rezervati

[1] Display Scan Control Bit

0 = Afisaj normal

1 = Afisaj rotit cu 180 de grade

[0] TFT Display Enable Bit

0 = Dezactivare afisare pe monitor. De-termina intrarea ın sleep mode

1 = Activare afisare pe monitor

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;

#bitii de culoare neutilizati pe placa Spartan-3E trebuie conectati 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;

2 Utilizarea perifericelor 40

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;

2.6.3 Aplicatii

Programul de mai jos afiseaza o mira de culori orizontala pe ecran.

//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;

//registrul de control este 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;

//ecranul este impartit in 8 zone;

//fiecare zona cu numar impar va avea culoarea rosie activa

if((i/60)%2) color = color | 0x00FF0000;

//ecranul este impartit in 4 zone;

// fiecare zona cu numar impar va avea culoarea verde activa

if((i/120)%2) color = color | 0x0000FF00;

//ecranul este impartit in 2 zone;

//partea de jos va avea culoarea albastra activa

if((i/240)%2)color = color | 0x000000FF;

vga_mem[i*1024+j]=color;

}

41 Controller-ul VGA

while(1);//creeaza o bucla infinita pentru mentinerea programului in executie

return 1;

}

2.6.4 Exercitii

1. Desenati o mira de culori verticala pe ecran.2. Desenati un patrat cu suprafata colorata ın alb avand latura de 100 de pixeli ın mijlocul ecranului.3. Desenati un triunghi dreptunghic isoscel cu unghiul dreptunghic ıntr-unul din colturile ecranului

avand catetele de lungime 300 de pixeli.4. Desenati conturul unui patrat si diagonalele de culoare alba. Punctul de intersectie al diagona-

lelor se va afla ın centrul ecranului.

2 Utilizarea perifericelor 42

2.7 Perifericul timer

Modulul xps timer [10], care se ataseaza la bus-ul PLB, contine 2 timere, configurabile din punctde vedere al numarului de biti (ıntre 8-32) si al valorii de la/pana la care numara. Fiecare timerpoate fi configurat pentru generare de semnale/ıntreruperi sau pentru a detecta evenimente (semnaleexterne). 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. 2-17.

Figura 2-17: Exemplu de sistem cu timer.

Pentru o mai buna ıntelegere a organizarii si a modului de functionare a perifericului, prezentamstructura sa interna ın Fig. 2-18.

Fiecaruia din cele doua timere ıi este aferent cate un counter pe 32 de biti, cate un registru deıncarcare (Load Register) si de control/stare (Control/Status). Ambele timere pot detecta semnaledin exterior (CaptureTrig0, CaptureTrig1) si pot genera ın comun un semnal PWM.

2.7.1 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 seface fie prin scrierea registrului TCSRx cu bitul LOAD setat ın 1, fie automat la overflow (underflow)daca timerul este ın mod autoreload.

43 Perifericul timer

Figura 2-18: Organizarea interna a perifericului timer [10].

Tabelul 2-22: Maparea registrilor perifericului timer ın spatiul de adrese.

Nume registru Descriere Adresa Tip acces

TCSR0 Registru de control/stare 0 Adresa de baza + 0x00 Citire/Scriere

TLR0 Registru de ıncarcare 0 Adresa de baza + 0x04 Citire/Scriere

TCR0 Registru numarator 0 Adresa de baza + 0x08 Citire

TCSR1 Registru de control/stare 1 Adresa de baza + 0x10 Citire/Scriere

TLR1 Registru de ıncarcare 1 Adresa de baza + 0x14 Citire/Scriere

TCR1 Registru numarator 1 Adresa de baza + 0x18 Citire

Registrul de numarare contine valoarea curenta la care a ajuns numaratorul. Acest registru poatesa fie doar citit, scrierea lui cu o valoare facandu-se prin intermediul registrului de ıncarcare.

2.7.2 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 citirearepetata 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 saudescrescator. Este important de stiut ca ın functie de cum este setata directia de numarare, intervalulde timp va avea valori diferite. Daca timerul este setat sa numere descrescator:

Intervalul timp = (TLRx + 2)× PLBclockperiod (2-1)

Daca timerul este setat sa numere crescator:

Intervalul timp = (valoare maxima− TLRx + 2)× PLBclockperiod (2-2)

undevaloare maxima = 2numar biti − 1 (2-3)

iar numarul de biti poate sa fie setat pentru fiecare timer (valoarea implicita este 32). PLBclockperiodeste perioada ceasului magistralei la care este conectat perifericul (ın general 20 ns).

Numararea dureaza pana cand se depaseste valoarea maxima (overflow - ın cazul numararii crescatoare)sau se scade sub 0 (underflow - ın cazul numararii descrescatoare). In functie de cum a fost setat bitul

2 Utilizarea perifericelor 44

Tabelul 2-23: Semnificatia bitilor pentru registrii TCSR0 si TCSR1 .

Bit Nume Descriere

31-11 - Neutilizati

10 ENALL Scrierea cu 1 activeaza ambele timere prin setarea bitilorENT corespunzatori. Scrierea cu 0 nu are nici un efectasupra bitilor ENT.

9 PWMA Scrierea cu 1 activeaza semnalul PWM iar pentru valoarea0 semnalul PWM se dezactiveaza.

8 TINT Indica aparitia unei conditii de ıntrerupere. Daca timerulfunctioneaza ın mod de capturare, bitul indica detectiafrontului semnalului. La citire: 0 - nu a aparut nici oıntrerupere; 1 - a aparut o ıntrerupere. La scriere: 0 - nuare nici un efect; 1 - invalideaza ıntreruperea

7 ENT 0 - dezactiveaza timerul; 1 - activeaza timerul

6 ENIT 0 - dezactiveaza semnalul de ıntrerupere; 1 - activeazasemnalul de ıntrerupere

5 LOAD 0-nu ıncarca registrul TCR cu valoarea din registrul TLR;1-ıncarca registrul TCR cu valoarea din registrul TLR

4 ARHT Daca timerul este ın mod generare, acest bit deter-mina reınceperea numararii daca s-a ajuns la un over-flow/underflow. In modul captura, acest bit determina dacavaloarea capturata va fi suprascrisa ın momentul ın careva aparea un nou eveniment extern: 0-pastreaza valoareagenerata sau captata; 1-modifica/suprascrie

3 CAPT Activeaza semnalul de detectat: 0-dezactiveaza; 1-activeaza

2 GENT Activeaza generarea semnalelor externe: 0-dezactiveaza; 1-activeaza

1 UDT Seteaza modul de numarare: 0-crescator; 1-descrescator

0 MDT Seteaza modul de lucru al timerului: 0-mod de generare;1-mod captura

ARHT, timerul reıncarca valoarea din TLRx si reıncepe numaratoarea, sau se opreste. Daca timeruleste setat sa genereze ıntreruperi, la terminarea numararii se genereaza o ıntrerupere, iar bitul TINTdin registrul TCSRx va fi ın 1 la citirea acestuia. In rutina de tratare a ıntreruperii, ıntrerupereapoate 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;

45 Perifericul timer

//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;

}

2.7.3 Modul de capturare

Prin folosirea acestui mod se poate masura intervalul de timp dintre doua fronturi (crescatoare saudescrescatoare) ale unui semnal extern. Aceasta valoare este stocata ın registrul TLRx. Terminareamasurarii este semnalata prin setarea bitului TINT, generandu-se o ıntrerupere (ın cazul ın care suntactivate ıntreruperile).

In acest mod, daca ARHT=0 si TINT=1, valoarea din registrul TLRx nu va fi suprascrisa devaloarea numaratorului la detectarea unui front al semnalului extern. In toate celelalte cazuri TLRxva fi suprascris la aparitia unui nou eveniment de captura.

Semnalul extern este esantionat de catre periferic cu frecventa ceasului magistralei PLB. Prin setareaparametrului TRIGx Active Level (printr-un dublu click pe numele perifericului din System AssemblyView -> Bus Interfaces) se poate selecta tipul frontului care va fi detectat: prin setarea ın 1 se vadetecta 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 decapturare.

//exemplu C pentru folosirea timerului pentru capturarea evenimentelor externe

#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;

2 Utilizarea perifericelor 46

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;

}

2.7.4 Modul de generare PWM

Prin folosirea acestui mod perifericul poate genera un semnal extern cu o modulatie ın latime detipul celui din Fig. 2-19. Pentru a folosi acest mod de lucru este nevoie de folosirea ambelor canale:registrul TLR0 specifica perioada semnalului iar registrul TLR1 intervalul de timp din cadrul uneiperioade ın care semnalul este ın 1.

Figura 2-19: Forma semnalului PWM generat de timer.

Perioada si factorul de umplere se calculeaza astfel:

• In cazul numararii crescatoare:

PWM PERIOD = (valoare maxima− TLR0 + 2)× PLBclockperiod (2-4)

PWM HIGH TIME = (valoare maxima− TLR1 + 2)× PLBclockperiod (2-5)

• In cazul numararii descrescatoare:

PWM PERIOD = (TLR0 + 2)× PLBclockperiod (2-6)

PWM HIGH TIME = (TLR1 + 2)× PLBclockperiod (2-7)

In cele ce urmeaza este prezentat un exemplu de setare a perifericului pentru generarea unui semnalPWM.

//exemplu C pentru generarea semnalului PWM

#include "xparameters.h"

unsigned *timer = (unsigned *) XPAR_XPS_TIMER_0_BASEADDR;

int main(void)

47 Perifericul timer

{

//semnal PWM cu f=1Hz si factor de umplere 50%

timer[0x04/4]=50000000;

timer[0x14/4]=25000000;

//configurarea timerului in mod PWM prin setarea urmatorilor biti

//PWMA pentru a activa semnalul PWM

//ENT pentru a activa timerul

//GENT pentru a activa semnalul extern

//UDT0 timerul functioneaza ca un numarator descrescator

timer[0x00/4]=0x286;

timer[0x10/4]=0x286;

while(1);

return 1;

}

2.7.5 Instantierea perifericului

Acest periferic se poate instantia utilizand Base System Builder sau, dupa generarea sistemului, elpoate fi instantiat din tab-ul IP Catalog, optiunea DMA and Timer -> XPS Timer/Counter. Dupainstantiere:

1. In tab-ul System Assembly View -> Bus Interfaces conectati portul SPLB al perifericului lamagistrala standard a sistemului mb plb.

2. 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 configurateautomat.

3. In cazul folosirii perifericului ın mod PWM ın tab-ul System Assembly View -> Ports specificatisemnalul PWM0 ca fiind semnal extern si editati ın mod corespunzator fisierul UCF.

4. In cazul folosirii perifericului ın mod captura ın tab-ul System Assembly View -> Ports specificatisemnalul CaptureTrig0, respectiv CaptureTrig1 daca sunt folosite ambele canale ca fiind semnaleexterne si editati ın mod corespunzator fisierul UCF.

Mai jos se prezinta un exemplu de constrangeri UCF prin care se conecteaza semnalul PWM la unled si butonul West de pe placa de dezvoltare la intrarea CaptureTrig0.

Net xps_timer_0_PWM0_pin LOC=F9 | IOSTANDARD = LVCMOS33;

Net xps_timer_0_CaptureTrig0_pin LOC=D18 | IOSTANDARD = LVCMOS33;

2.7.6 Exercitii

1. Realizati un program care sa aprinda si stinga un led la un interval de exact 1 secunda.2. Realizati un program care sa comande un led cu:

(a) o frecventa de 2 Hz si factor de umplere 10%(b) o frecventa de 2 Hz si factor de umplere 90%(c) o frecventa de 4 Hz si factor de umplere 50%

3. Creati un sistem cu doua periferice timer. Primul timer setati-l ın mod PWM (frecventa de1Hz si factor de umplere de 40%) iar al doilea ın mod captura avand semnalul de intrare iesireaPWM a primului timer. Folosind al doilea timer masurati frecventa si factorul de umplere alsemnalului PWM.

2 Utilizarea perifericelor 48

2.8 Controllerul de ıntreruperi

2.8.1 Tratarea ıntreruperilor la microprocesorul MicroBlaze

Procesorul MicroBlaze are un singur port la care se pot conecta surse externe de ıntreruperi, numitInterrupt. Exista doua modalitati prin care se pot conecta sursele de ıntrerupere la procesor [1],prezentate ın Fig. 2-20:

• Semnalul de ıntrerupere de la periferic se conecteaza direct la portul Interrupt. Aceasta configuratiese utilizeaza ın cazul existentei unei singure surse de ıntreruperi ın sistem.

• Semnalul de ıntrerupere de la periferic se conecteaza la un controller de ıntreruperi, ın timpce semnalul de ıntrerupere al controllerului se conecteaza la portul Interrupt al procesorului.Aceasta a doua configuratie permite existenta mai multor surse de ıntrerupere ın sistem.

Figura 2-20: Conectarea surselor de ıntrerupere la microprocesor [1].

Tratarea unei ıntreruperi se realizeaza parcurgandu-se mai multe niveluri de abstractizare, prezen-tate ın Fig. 2-21, ultimul nivel fiind cel de aplicatie.

In cele ce urmeaza detaliem pasii pentru tratarea ıntreruperilor ın sistemele cu procesor MicroBlaze:

1. Se activeaza ıntreruperile pentru procesor prin setarea bitului IE (Interrupt Enable) din registrulMSR (Machine Status Register).

2. La aparitia unei ıntreruperi externe, procesorul dezactiveaza ıntreruperile, apoi se efectueaza unsalt la adresa 0x00000010.

3. La aceasta adresa se afla o instructiune de salt catre rutina de servire a ıntreruperii furnizata deplatforma software, care va prelua controlul.

4. Rutina platformei salveaza continutul registrilor procesorului pe stiva, apoi consulta tabelainterna de vectori de ıntrerupere pentru a gasi adresa rutinei de ıntrerupere de nivel superior,pe care o apeleaza.

49 Controllerul de ıntreruperi

Figura 2-21: Niveluri de abstractizare pentru tratarea unei ıntreruperi [1].

Figura 2-22: Tratarea unei ıntreruperi ıntr-un sistem cu controller de ıntreruperi [1].

5. In cadrul sistemelor cu controller de ıntreruperi (Fig. 2-22), rutina de nivel superior este ceafurnizata de driverul controllerului. Aceasta va interoga controllerul de ıntreruperi cu privire laıntreruperile active din sistem, pentru fiecare din aceasta consultand apoi tabela de vectori, carecontine rutinele corespunzatoare ınregistrate de utilizator. In cazul ın care nu se gaseste o rutinaınregistrata de utilizator, se va ınregistra o rutina implicita de tip do-nothing. Se apeleaza apoirutinele finale corespunzatoare de servire a ıntreruperilor, ın ordinea prioritatilor.

2 Utilizarea perifericelor 50

Figura 2-23: Tratarea unei ıntreruperi ıntr-un sistem fara controller de ıntreruperi [1].

6. In cadrul sistemelor fara controller de ıntreruperi (Fig. 2-23), rutina de nivel superior este ceafinala furnizata de aplicatie.

7. Se executa rutina finala, care va realiza tratarea efectiva a ıntreruperii. La sfarsitul executiei,controlul revine rutinei platformei.

8. Rutina platformei reface continutul registrilor salvati pe stiva si se revine la executia instructiuniila care a avut loc ıntreruperea. De asemenea, se reactiveaza ıntreruperile pentru procesor.

2.8.2 Controllerul de ıntreruperi

Controllerul de ıntreruperi [11] este un periferic care faciliteaza crearea unor sisteme cu surse multiplede ıntreruperi. La acest periferic se pot conecta un numar maxim de 32 de surse de semnale deıntrerupere, iar perifericul are ca iesire un singur semnal de ıntrerupere. Acest semnal, ın general,se conecteaza la intrarea de ıntreruperi a microprocesorului. In cazul unui sistem cu mai mult de 32surse de ıntreruperi se pot cascada mai multe astfel de controllere de ıntreruperi.

Nivelul logic si tipul semnalarii (palier sau front) corespunzator semnalului de ıntrerupere generatpoate fi configurat prin setarea optiunilor IRQ Output Use Level, respectiv The Sense of IRQ Output,ın fereastra deschisa printr-un dublu click ın tab-ul System Assembly View -> Ports pe numeleperifericului.

2.8.2.1 Organizarea registrilor

Perifericul prezinta 8 registri catre exterior, prezentati ın Tabelul 2-24.

Interrupt Status Register (ISR)

La citire, continutul registrului indica prezenta unei ıntreruperi active. Fiecare bit setat ın 1 dinacest registru indica o ıntrerupere activa pe intrarea corespunzatoare. Registrul ISR poate fi scrisdin software cat timp valoarea bitului de activare ıntreruperi hardware (Hardware Interrupt Enable- HIE) din registrul MER este 0. Fiecare bit din ISR setat din software ın 1 activeaza ıntrerupereacorespunzatoare, simuland aparitia unei ıntreruperi hardware pe intrarea respectiva. Dupa setarea

51 Controllerul de ıntreruperi

Tabelul 2-24: Maparea registrilor controllerului de ıntreruperi ın spatiul de adrese.

Nume registru Descriere Adresa Tip acces

ISR Interrupt Status Register Adresa de baza + 0x00 Scriere/ Citire

IPR Interrupt Pending Register Adresa de baza + 0x04 Citire

IER Interrupt Enable Register Adresa de baza + 0x08 Scriere/ Citire

IAR Interrupt Acknowledge Register Adresa de baza + 0x0C Scriere

SIE Set Interrupt Enable Bits Adresa de baza + 0x10 Scriere

CIE Clear Interrupt Enable Bits Adresa de baza + 0x14 Scriere

IVR Interrupt Vector Register Adresa de baza + 0x18 Citire

MER Master Enable Register Adresa de baza + 0x1C Scriere/ Citire

bitului HIE din registrul MER scrierea din software a registrului ISR nu are nici un efect. Dacanumarul de surse de ıntreruperi este mai mic de 32, scrierea bitului corespunzator unei surse deıntrerupere inexistente nu are nici un efect, iar la citire valoarea bitului va fi 0.

Interrupt Pending Register (IPR)

IPR indica prezenta unei ıntreruperi active care este si validata. Acest registru este unul optional,putand fi dezactivat printr-un dublu click ın tab-ul System Assembly View -> Ports pe numeleperifericului, debifandu-se optiunea Support IPR din fereastra nou deschisa.

Interrupt Enable Register (IER)

Bitii setati ın 0 din registrul IER mascheaza ıntreruperile corespunzatoare. Activarea unei surse deıntreruperi mascate nu va seta bitul corespunzator din registrul ISR.

Interrupt Acknowledge Register (IAR)

Scrierea unui bit cu valoare 1 ın IAR confirma tratarea ıntreruperii, avand ca efect setarea ın 0 abitului corespunzator din ISR. Scrierea unui bit cu valoarea 0 sau scrierea unui bit cu valoarea 1 la opozitie la care nu este asignata o sursa de ıntrerupere nu are nici un efect.

Set Interrupt Enable Bits (SIE)

SIE este o locatie folosita pentru setarea ın 1 a bitilor din IER ıntr-o singura operatie atomica, ınloc de folosirea unei secvente de citire, modificare si scriere a registrului IER. Scrierea unui bit cuvaloarea 1 ın SIE va seta ın 1 bitul corespunzator din registrul IER. Scrierea unui bit cu valoarea 0,precum si scrierea unui bit caruia nu ıi corespunde o intrare de ıntrerupere nu are nici un efect.

Acest registru este unul optional, putand fi dezactivat dand dublu click ın tab-ul System AssemblyView -> Ports pe numele perifericului si debifand optiunea Support SIE din fereastra nou deschisa.

Clear Interrupt Enable Bits (CIE)

CIE este o locatie folosita pentru setarea ın 0 a bitilor din IER ıntr-o singura operatie atomica, ınloc de folosirea unei secvente de citire, modificare si scriere a registrului IER. Scrierea unui bit cuvaloarea 1 ın CIE va seta ın 0 bitul corespunzator din registrul IER. Scrierea unui bit cu valoarea 0,precum si scrierea unui bit caruia nu ıi corespunde o intrare de ıntrerupere nu are nici un efect.

Acest registru este unul optional, putand fi dezactivat dand dublu click ın tab-ul System AssemblyView -> Ports pe numele perifericului si debifand optiunea Support CIE din fereastra nou deschisa.

Interrupt Vector Register (IVR)

Acest registru optional contine numarul celei mai prioritare surse de ıntrerupere active si nemascate.

2 Utilizarea perifericelor 52

INT0 (corespunzatoare LSB) are ıntotdeauna cea mai ınalta prioritate, iar prioritatea celorlalte sursede ıntrerupere scade cu cat sunt mai la stanga. In cazul ın care nu este activa nici o ıntrerupere, totibitii din IVR vor avea valoarea 1.

Acest registru poate fi dezactivat dand dublu click ın tab-ul System Assembly View -> Ports penumele perifericului si debifand optiunea Support IVR din fereastra nou deschisa.

Master Enable Register (MER)

Structura registrului este prezentata ın Tabelul 2-25.

Tabelul 2-25: Structura registrului MER.

Bit Nume Descriere

31-2 - Neutilizati

1 HIE Hardware Interrupt Enable

0 ME Master IRQ Enable

Daca bitul HIE este setat ın 0 se pot simula ıntreruperi setand din software biti ın registrul ISR.Odata cu setarea bitului HIE ın 1, se activeaza ıntreruperile hardware, iar scrierea din software aoricarei valori ın registrul ISR nu are nici un efect.

Bitul ME valideaza generarea semnalului de iesire al controllerului de ıntreruperi. Daca bitul MEare valoarea 0 controllerul nu va genera ıntreruperi, iar ın cazul ın care bitul este setat ın 1 controllerulgenereaza ıntreruperi ın functie de sursele de ıntreruperi si setarile din registrul IER.

2.8.2.2 Folosirea controllerului de ıntreruperi fara driver

Acesta este modul de lucru cu ıntreruperile prin care utilizatorul are acces direct la controller sipoate sa implementeze orice algoritm de prioritizare a ıntreruperilor. De asemenea, studiul acestuimod de lucru este util pentru a ıntelege implementarea driverului controllerului de ıntreruperi.

In codul care urmeaza se prezinta un exemplu de folosire a controllerului de ıntreruperi fara driver.In sistem este o singura sursa de ıntreruperi: perifericul GPIO conectat la switchuri. Rutina de tratarea ıntreruperii va afisa pe leduri valoarea citita de la switchuri.

#include "xparameters.h"

#include "mb_interface.h"

//variabile globale

unsigned valoare_led;

unsigned *switchuri = (unsigned *)XPAR_DIP_SWITCHES_4BIT_BASEADDR;

unsigned *led = (unsigned *)XPAR_LEDS_8BIT_BASEADDR;

unsigned *intr = (unsigned *)XPAR_XPS_INTC_0_BASEADDR;

//declararea prototipului de functie de tratare a intreruperilor

typedef void (*RutinaIntr) ();

//se declara un tablou de functii de intrerupere

RutinaIntr functii_intrerupere[32];

53 Controllerul de ıntreruperi

void rutina_controler_intreruperi(void *rutina_controler_intreruperi)

{

//Interrupt Status Register este la adresa 0x00

unsigned intr_status=intr[0x0/4];

//se declara un pointer la functia de tratare a intreruperii

RutinaIntr *rutina_sursa_intr;

//la implementarea unei rutine de control a intreruperilor in mod normal

//- exista o bucla care trece peste toate sursele posibile de intrerupere (32)

// de la cele mai prioritare catre cele cu cea mai mica prioritate

//- se testeaza daca sursa respectiva este activa - bit din Interrupt Status Register

//- se testeaza daca sursa respectiva este validata - bit din Interrupt Enable Register

//- daca ambele conditii sunt adevarate se selecteaza functia adecvata de tratare

//cazul curent fiind o simplificare a cazului general se va executa intotdeauna

//functia de tratare a intreruperii de pe pozitia 0

rutina_sursa_intr=&(functii_intrerupere[0]);

//se apeleaza functia selectata

(*rutina_sursa_intr)();

//acknowledge la tratarea intreruperii prin scrierea Interrupt Ack Register

intr[0xC/4]=intr_status;

}

void rutina_switch(void *parametru)

{

valoare_led=switchuri[0];//citirea valorii switchurilor

led[0]=valoare_led; //afisarea acestei valori

//adresa IP Interrupt Status Register = 0x120

//se sterg toate flagurile de intrerupere

//registrul este Toggle on Write deci daca scriem cu aceeasi valoare

//rezultatul va fi 0 pe toti bitii

switchuri[0x120/4]=switchuri[0x120/4];

}

int main(void)

{

/*

1. se configureaza gpio pentru intreruperi

2. se configureaza controllerul de intreruperi

3. se defineste rutina de controllerului de intreruperi pentru microblaze

4. se valideaza intreruperile pentru microblaze

*/

//1. setarea intreruperilor pentru perifericul GPIO

//adresa Global Interrupt Enable Register= 0x11C

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

2 Utilizarea perifericelor 54

// adresa IP Interrupt Enable Register = 0x128

//intreruperea se declanseaza la modificarea oricarui switch

switchuri[0x128/4] = 0xFFFFFFFF;

//2. se configureaza controllerul de intreruperi

//validam toate sursele posibile de intreruperi in Interrupt Enable Register (IER)

intr[0x08/4] = 0xFFFFFFFF;

//setarea flagurilor de hardware interrupt enable

//si master interrupt enable ale controllerului

//adresa Master Enable Register= 0x1C

intr[0x1C/4] = 0x03;

//setarea functiei callback pentru sursa de intreruperi 0

functii_intrerupere[0]=&rutina_switch;

//3. se defineste rutina de controllerului de intreruperi pentru microblaze

microblaze_register_handler(

//pointer la functia de tratare a intreruperii

(XInterruptHandler)rutina_controler_intreruperi,

(void *)0

);

//4. se activeaza intreruperile pentru procesor

microblaze_enable_interrupts();

return 1;

}

Codul prezentat mai sus realizeaza urmatorii pasi esentiali:

• Definirea unui prototip de functie pentru tratarea unei ıntreruperi.

• Declararea unui vector ın care se salveaza pointerii la functiile de tratare a ıntreruperilor.

• Definirea unei rutine pentru controllerul de ıntreruperi. Aceasta rutina apeleaza rutinele detratare a ıntreruperilor (specifice pentru fiecare sursa de ıntreruperi).

• Salvarea pointerului catre functia de tratare a ıntreruperilor de la switch-uri ın tabelul de pointericatre functiile de ıntrerupere, ın functia main.

2.8.2.3 Folosirea controllerului de ıntreruperi cu driver

Prin lucrul cu ıntreruperile folosind functiile predefinite ın biblioteca xintc l.h se ofera programato-rului o viziune simplificata a tratarii ıntreruperilor.

Codul de mai jos este echivalent cu cel prezentat ın sectiunea anterioara, putandu-se observafacilitatile oferite de functiile din biblioteca xintc l.h.

55 Controllerul de ıntreruperi

#include "xparameters.h"

#include "xintc_l.h"

#include "xil_exception.h"

//variabile globale

unsigned valoare_led;

unsigned *switchuri = (unsigned *)XPAR_DIP_SWITCHES_4BIT_BASEADDR;

unsigned *led = (unsigned *)XPAR_LEDS_8BIT_BASEADDR;

unsigned *intr = (unsigned *)XPAR_XPS_INTC_0_BASEADDR;

void rutina_intrerupere(void *callBackHandler)

{

valoare_led=switchuri[0];//citirea valorii switchurilor

led[0]=valoare_led; //afisarea acestei valori

//adresa IP Interrupt Status Register = 0x120

//se sterg toate flagurile de intrerupere

//registrul este Toggle on Write deci daca scriem cu aceeasi valoare

//rezultatul va fi 0 pe toti bitii

switchuri[0x120/4]=switchuri[0x120/4];

}

int main(void)

{

//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

//intreruperea se declanseaza la modificarea oricarui switch

switchuri[0x128/4] = 0xFFFFFFFF;

//2. setarea/configurarea intreruperilor pentru controllerul de intreruperi

//se defineste functia de tratare a intreruperilor pentru switchuri

XIntc_RegisterHandler(

XPAR_XPS_INTC_0_BASEADDR,//adresa de baza a controllerului de interuperi

0, //locatia sursei de intreruperi in controller

//pointer la functia de tratare a intreruperii

(XInterruptHandler)rutina_intrerupere,

(void *)0

);

//se seteaza masca de intreruperi in controller

XIntc_EnableIntr(

XPAR_XPS_INTC_0_BASEADDR,

0x01//avem intreruperi de la o singura sursa: switchurile

);

2 Utilizarea perifericelor 56

//setarea flagurilor de hardware interrupt enable

//si master interrupt enable ale controllerului

//adresa Master Enable Register= 0x1C

intr[0x1C/4] = 0x03;

//3. setarea intreruperilor pentru procesorul microblaze

Xil_ExceptionInit();//initializeaza tabela de exceptii.

Xil_ExceptionRegisterHandler(

//inregistreaza rutina de tratare a driverului cu tabela de exceptii

XIL_EXCEPTION_ID_INT,

(Xil_ExceptionHandler)XIntc_DeviceInterruptHandler,

0 //numarul driverului controllerului de intreruperi

//(daca sunt mai multe controllere in sistem)

);

//activeaza intreruperile pentru procesor

Xil_ExceptionEnable();

return 1;

}

2.8.2.4 Instantierea perifericului

Acest periferic se instantiaza automat daca, ın Base System Builder, cel putin un periferic genereazaıntreruperi sau, dupa generarea sistemului, el poate fi instantiat din tab-ul IP Catalog, optiunea Clock,Reset and Interrupt -> XPS Interrupt Controller. Dupa instantiere:

1. In tab-ul System Assembly View -> Bus Interfaces conectati portul SPLB al perifericului lamagistrala standard a sistemului mb plb.

2. 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 configurateautomat.

3. In tab-ul System Assembly View -> Ports dati click pe simbolul ”+” din dreptul numeluiperifericului. Dand click pe casuta text de la optiunea Intr se deschide o fereastra ın carese pot specifica sursele de ıntrerupere pentru controller. Ordinea de specificare a surselor deıntrerupere este importanta, ea definind prioritatile ıntreruperilor. Daca la optiunea Intr estesetata valoarea No connection, selectati optiunea New connection. Selectarea acestei optiuniva genera un nou semnal iar numele acestui semnal va fi afisat la optiunea Intr. Dati click pesimbolul ”+” din dreptul numelui procesorului (microblaze 0), iar la optiunea INTERRUPTselectati numele semnalului generat anterior.

2.8.3 Exercitii

1. Folosind functiile din biblioteca xintc l.h, definiti 5 functii de tratare a ıntreruperilor si ınregistrati-le la pozitii diferite ale controllerului de ıntreruperi. Generati din software ıntreruperi (prinscrierea ın registrul ISR, avand bitul HIE din registrul MER setat la 0) si observati tratarea lor.

2. Modificati implementarea de la exercitiul 1 astfel ıncat sa nu mai folositi functiile din bibliotecaxintc l.h.

3. Modificati implementarea de la exercitiul 2 astfel ıncat tratarea ıntreruperilor sa fie facuta dupaalgoritmul Round Robin. Conform algoritmului Round Robin, sursele de ıntreruperi vor fi tratateuna dupa alta ın mod ciclic, toate ıntreruperile avand acelasi grad de prioritate.

CAPITOLUL 3

Sisteme complexe

3.1 Crearea unei aplicatii de retea

In cadrul acestui subcapitol vom prezenta crearea unei clase de aplicatii de retea. Sistemul va folosiperifericul Ethernet pentru comunicare si un sistem de operare care permite folosirea thread-urilor.Aplicatiile folosesc functiile implementate ın cadrul bibliotecii lwip, care realizeaza comunicarea cuperifericul Ethernet si implementeaza nivelurile inferioare ale stivei TCP/IP [12].

3.1.1 Arhitectura hardware

Arhitectura hardware necesara pentru comunicarea prin Ethernet este prezentata ın Fig. 3-1.

Microprocesorul Microblaze comunica cu perifericele folosind magistrala PLB a sistemului. Pentrua putea rula programe de dimensiuni mari, sistemului i s-a adaugat controllerul DDR care faciliteazastocarea programului executabil si a variabilelor ın memoria DDR externa. Pentru a putea rula unsistem de operare este nevoie de adaugarea a cel putin unui timer ın sistem. Perifericul Ethernetasigura comunicarea cu circuitul media access controller (MAC) disponibil pe placa de dezvoltare.Avand mai multe surse de ıntreruperi (timer si controllerul Ethernet), ın sistem este nevoie si de uncontroller de ıntreruperi.

O serie de alte periferice aditionale (doua controllere GPIO) au fost introduse pentru citirea stariiswitchurilor si afisarea unui cuvant de opt biti pe leduri. Conform necesitatilor aplicatiei se pot adaugasi alte periferice.

Pentru crearea acestui sistem se recomanda folosirea wizard-ului Base System Builder, ın cadrulcaruia, la pasul Peripheral Configuration, realizati urmatoarele setari:

• Eliminati perifericele care nu vor fi folosite (Flash, RS232 etc.).

• Selectati perifericul Ethernet si bifati optiunea Use interrupt.

• Adaugati perifericul xps timer si bifati optiunea Use interrupt.

Continuati crearea proiectului urmand pasii descrisi ın capitolul 1.

57

3 Sisteme complexe 58

Figura 3-1: Arhitectura sistemului pentru comunicarea prin Ethernet.

3.1.2 Arhitectura software

La proiectarea unei aplicatii web sunt folosite o serie de niveluri de abstractizare, prezentate ın Fig.3-2.

Figura 3-2: Nivelurile de abstractizare software.

Nivelul inferior este reprezentat de cel hardware, la care se realizeaza scrieri si citiri din registriiperifericelor. Peste acest nivel este construit nivelul sistemului de operare. Acesta ofera o seriede facilitati cum ar fi thread-urile de executie sau functiile pentru alocarea dinamica a memoriei.

59 Crearea unei aplicatii de retea

Folosind facilitatile oferite de sistemul de operare, s-au creat o serie de biblioteci de functii standardcare implementeaza stiva TCP/IP (biblioteca LwIP130) si un sistem de fisiere ın memorie (xilmfs).

Avand la dispozitie aceste componente software standard, proiectantul trebuie doar sa implementezelogica de nivel ınalt a aplicatiei, dar poate avea acces oricand si la nivelurile inferioare (sistem deoperare si hardware).

Pentru crearea unei noi aplicatii software se alege optiunea Add Software Application Project... dintab-ul Applications. Dupa crearea noii aplicatii software trebuie realizati urmatorii pasi:

• Se seteaza rularea aplicatiei din memoria DDR si se mareste zona alocata pentru heap si stack,prin click dreapta pe numele aplicatiei si selectarea optiunii Generate linker script. Pentru fiecarezona de program (.text, .rodata, .sdata2, .sbss2, .data, .sdata si .sbss) si pentru zonele de date(heap si stack) se da dublu click pe numele controllerului aferent (implicit ilmb ctrl dlmb ctrl)si se selecteaza controllerul DDR (DDR SDRAM C MPMC BASEADDR). Se mareste zonaalocata pentru heap si stack la valori suficient de mari (ex. 0x10000).

• Se specifica folosirea sistemului de operare si a bibliotecilor lwip130 si xilmfs. Din meniul Softwareselectati optiunea Software Platform Settings. In fereastra nou deschisa, ın tabul SoftwarePlatform (implicit selectat), ın cadrul sectiunii OS & Library Settings selectati la optiuneaOS valoarea xilkernel. Bifati folosirea bibliotecilor lwip130 si xilmfs.

• Se configureaza parametrii sistemului de operare si cei ai bibliotecilor folosite. In SoftwarePlatform Settings (din meniul Software selectati optiunea Software Platform Settings), selectatitabul OS and Lib Configuration. In sectiunea Configuration for OS dati click pe simbolul ”+”de langa numele sistemului de operare (xilkernel) si faceti urmatoarele setari:

– La subcategoria systmr spec:

∗ La optiunea systmr dev selectati perifericul timer din sistem (xps timer 0 ).

∗ La optiunea systmr freq setati valoarea 50000000.

– La subcategoria config pthread support :

∗ La optiunea pthread stack size setati valoarea 32768.

∗ La optiunea config pthread mutex setati valoarea TRUE.

∗ La optiunea max pthread mutex setati valoarea 20.

∗ La optiunea static pthread table dati click pe casuta corespunzatoare valorii curente.In fereastra nou deschisa apasati butonul Add si ın casuta pthread start func setativaloarea main thread. Casuta pthread prio se lasa fara valoare setata. Confirmatisetarea prin apasarea butonului OK.

– La subcategoria config sched :

∗ La optiunea max readyq setati valoarea 20.

– La subcategoria config time:

∗ Setati subcategoria de la valoarea implicita FALSE la valoarea TRUE.

∗ La optiunea max tmrs setati valoarea 20.

– La subcategoria config sema:

∗ Setati subcategoria de la valoarea implicita FALSE la valoarea TRUE.

∗ La optiunea max sem setati valoarea 50.

∗ La optiunea max sem waitq setati valoarea 20.

– La subcategoria enhanced features:

∗ Setati subcategoria de la valoarea implicita FALSE la valoarea TRUE.

3 Sisteme complexe 60

∗ La optiunea config yield setati valoarea TRUE.

– La optiunea stdin selectati valoarea mdm 0.

– La optiunea stdout selectati valoarea mdm 0.

– La optiunea sysintc spec selectati controllerul de ıntreruperi al sistemului (xps intc 0 ).

• In sectiunea Configuration for Libraries dati click pe simbolul ”+” de langa numele biblioteciixilmfs.

– La optiunea numbytes setati valoarea 900000.

– La optiunea base address setati valoarea 0x87000000.

– La optiunea init type selectati valoarea MFSINIT IMAGE.

– La optiunea need utils setati valoarea TRUE.

• In sectiunea Configuration for Libraries dati click pe simbolul ”+” de langa numele biblioteciilwip130.

– La optiunea api mode selectati valoarea SOCKET API.

3.1.3 Programul Echo

Aplicatia Echo implementeaza un server care asculta pe un port TCP si trimite ınapoi orice dateprimite de la clienti. Folosind aceasta aplicatie simpla, vom prezenta structura de baza pe care trebuiesa o aiba orice aplicatie de retea.

Punctul de ıncepere al aplicatiei este ca ıntotdeauna functia main. In aceasta functie se seteazafolosirea memoriilor cache (daca au fost definite ın hardware), se initializeaza ıntreruperile si seporneste sistemul de operare prin apelarea functiei xilkernel main. Sistemul de operare va pornithread-ul main thread. Acesta realizeaza initializarea metodelor din cadrul bibliotecii lwip, dupa careporneste thread-ul network thread.

Primele operatii realizate ın cadrul network thread sunt asignarea unei adrese MAC si configurareaparametrilor IP (adresa IP, subnet mask si gateway IP). Urmatorii pasi sunt asignarea si pornireainterfetei de retea prin care se va realiza comunicarea, dupa care se lanseaza doua thread-uri: primulpentru receptia pachetelor (xemacif input thread), iar al doilea pentru tratarea pachetelor primite(echo application thread).

In cele ce urmeaza este prezentat codul din cadrul fisierului main.c [12].

#include <stdio.h>

#include "xmk.h"

#include "xenv_standalone.h"

#include "xparameters.h"

#include "lwip/sockets.h"

#include "lwip/sys.h"

#include "netif/xadapter.h"

#ifdef XPAR_ETHERNET_MAC_BASEADDR

#define EMAC_BASEADDR XPAR_ETHERNET_MAC_BASEADDR

#elif XPAR_LLTEMAC_0_BASEADDR

#define EMAC_BASEADDR XPAR_LLTEMAC_0_BASEADDR

61 Crearea unei aplicatii de retea

#else

#error

#endif

#define APP_ECHOSERVER

void print_ip(char *msg, struct ip_addr *ip)

{

print(msg);

xil_printf("%d.%d.%d.%d\n\r", ip4_addr1(ip), ip4_addr2(ip),

ip4_addr3(ip), ip4_addr4(ip));

}

void

print_ip_settings(struct ip_addr *ip, struct ip_addr *mask, struct ip_addr *gw)

{

print_ip("Board IP: ", ip);

print_ip("Netmask : ", mask);

print_ip("Gateway : ", gw);

}

int main()

{

#ifdef __MICROBLAZE__

microblaze_init_icache_range(0, XPAR_MICROBLAZE_0_CACHE_BYTE_SIZE);

microblaze_init_dcache_range(0, XPAR_MICROBLAZE_0_DCACHE_BYTE_SIZE);

microblaze_enable_exceptions();

#endif

/* enable caches */

XCACHE_ENABLE_ICACHE();

XCACHE_ENABLE_DCACHE();

/* start the kernel - does not return */

xilkernel_main();

return 0;

}

void print_echo_app_header();

void echo_application_thread(void *);

struct netif server_netif;

void network_thread(void *p)

{

struct netif *netif;

struct ip_addr ipaddr, netmask, gw;

3 Sisteme complexe 62

/* the mac address of the board. this should be unique per board */

unsigned char mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };

netif = &server_netif;

/* initialize IP addresses to be used */

IP4_ADDR(&ipaddr, 192, 168, 1, 10);

IP4_ADDR(&netmask, 255, 255, 255, 0);

IP4_ADDR(&gw, 192, 168, 1, 1);

/* print application headers */

print_echo_app_header();

/* print out IP settings of the board */

print("\n\r\n\r");

print_ip_settings(&ipaddr, &netmask, &gw);

/* Add network interface to the netif_list, and set it as default */

if (!xemac_add(netif, &ipaddr, &netmask, &gw, mac_ethernet_address, EMAC_BASEADDR))

{

xil_printf("Error adding N/W interface\n\r");

return;

}

netif_set_default(netif);

/* specify that the network if is up */

netif_set_up(netif);

/* start packet receive thread - required for lwIP operation */

sys_thread_new("main",(void(*)(void*))xemacif_input_thread, netif,500,

DEFAULT_THREAD_PRIO);

/* now we can start application threads */

/* start echo server thread */

sys_thread_new("echo server",echo_application_thread, 0,500,

DEFAULT_THREAD_PRIO);

return;

}

int main_thread()

{

/* initialize lwIP before calling sys_thread_new */

lwip_init();

/* any thread using lwIP should be created using sys_thread_new */

sys_thread_new("network thread",network_thread, NULL,500,

63 Crearea unei aplicatii de retea

DEFAULT_THREAD_PRIO);

return 0;

}

Thread-ul echo application thread creeaza un punct de capat al conexiunii (socket), la care seataseaza tipul si numarul portului folosit de aplicatie prin functia lwip bind. Se anunta capacitatea dea accepta conexiuni prin functia lwip listen, dupa care se asteapta cererile de conexiune prin functialwip accept. Pentru fiecare conexiune se porneste cate un thread process echo request care, ıntr-o buclainfinita, va citi datele primite de la client si le va transmite ınapoi nemodificate. Intreruperea buclei siınchiderea conexiunii apar la incapacitatea de a citi sau scrie pe socket sau la receptionarea cuvantuluiquit.

In cele ce urmeaza este prezentat codul pentru aplicatia Echo din cadrul fisierului echo.c [12].

#include <stdio.h>

#include <string.h>

#include "lwip/inet.h"

#include "lwip/sockets.h"

#include "lwip/sys.h"

#include "lwipopts.h"

u16_t ECHO_PORT = 7;

void print_echo_app_header()

{

xil_printf("\n\r-----lwIP echo server ------\n\r");

xil_printf("You can connect to the echo server @ port %d\n\r", ECHO_PORT);

}

/* thread spawned for each connection */

void process_echo_request(void *p)

{

int sd = (int)p;

int RECV_BUF_SIZE = 2048;

char recv_buf[RECV_BUF_SIZE];

int n, nwrote;

xil_printf("echo server processing requests for sd: %d\n\r", sd);

while (1) {

/* read a max of RECV_BUF_SIZE bytes from socket */

if ((n = read(sd, recv_buf, RECV_BUF_SIZE)) < 0) {

xil_printf("%s: error reading from socket\r\n", __FUNCTION__);

close(sd);

return;

}

/* break if the recved message = "quit" */

if (!strncmp(recv_buf, "quit", 4))

3 Sisteme complexe 64

break;

/* handle request */

if ((nwrote = write(sd, recv_buf, n)) < 0) {

xil_printf("%s: ERROR responding to client echo request. \n\r",

__FUNCTION__);

xil_printf("Closing socket %d\n\r", sd);

close(sd);

return;

}

}

/* close connection */

close(sd);

}

void echo_application_thread()

{

int sock, new_sd;

struct sockaddr_in address, remote;

int size;

if ((sock = lwip_socket(AF_INET, SOCK_STREAM, 0)) < 0)

return;

address.sin_family = AF_INET;

address.sin_port = htons(ECHO_PORT);

address.sin_addr.s_addr = INADDR_ANY;

if (lwip_bind(sock, (struct sockaddr *)&address, sizeof (address)) < 0)

return;

lwip_listen(sock, 5);

size = sizeof(remote);

while (1) {

new_sd = lwip_accept(sock, (struct sockaddr *)&remote, &size);

sys_thread_new("echo server",process_echo_request, (void*)new_sd,500,

DEFAULT_THREAD_PRIO);

}

}

Rularea aplicatiei se face prin urmatorii pasi:

• Compilarea proiectului printr-un click dreapta pe numele aplicatiei software si selectarea optiuniiBuild Project.

• Pornirea consolei de debug XMD. Din meniul Debug selectati optiunea Launch XMD... .

• Transferul executabilului ın memoria DDR. In consola de debug introduceti comanda dow{director aplicatie}/executable.elf .

65 Crearea unei aplicatii de retea

• Deschiderea terminalului mdm. In consola de debug introduceti comanda terminal .

• Pornirea aplicatiei. In consola de debug introduceti comanda run .

3.1.4 Exercitii

1. Creati o aplicatie de retea prin care sa se poata controla led-urile si sa se poata citi switch-uriledupa cum urmeaza:

• Primul caracter receptionat reprezinta comanda: ’l’ pentru a seta o noua valoare pentruled-uri si ’s’ pentru a citi valoarea switch-urilor.

• Dupa comanda ’l’ sunt trimise maximum 3 caractere urmate de ’Enter’. Verificati dacatoate caracterele introduse sunt cifre, ın caz favorabil setati pe led-uri valoare primita, ıncaz contrar cereti introducerea unei noi comenzi.

• Dupa primirea comenzii ’s’ se va citi valoarea setata pe switch-uri si se va trimite un caracterhexazecimal reprezentand starea led-urilor.

2. Creati o aplicatie web care sa returneze o pagina HTML statica. Portul folosit va fi portul 80.3. Creati o aplicatie web care sa afiseze starea switch-urilor si sa permita setarea led-urilor. Portul

folosit va fi portul 80.

3 Sisteme complexe 66

3.2 Sisteme dual-processor

Xilinx EDK permite crearea de arhitecturi ce ınglobeaza doua subsisteme de procesare, fiecare dinacestea constand dintr-un procesor, memorie locala BRAM si un set de periferice locale conectateprintr-o magistrala PLB. Cele doua subsisteme pot fi complet independente sau pot fi conectate prinmodule partajate cum ar fi Mailbox, memorie DDR multi-port si Mutex [13].

Mailbox-ul este un modul hardware ce permite transmiterea bidirectionala de mesaje ıntre douaprocesoare. Modulul pune la dispozitie cate un canal FIFO pentru fiecare sens de comunicatie.Functionarea perifericului XPS Mailbox va fi detaliata ın sectiunile urmatoare.

Memoria partajata (shared memory) reprezinta cea mai buna metoda de comunicatie ıntre pro-cesoare ın cazul unui volum mare de informatii. Fiecare procesor poate accesa direct orice locatiedin memoria partajata, comunicarea realizandu-se prin instructiunile de load si store. Partajareamemoriei DDR se face prin utilizarea controllerului de memorie multi-port MPMC. Fiecare port alcontrollerului este mapat la aceeasi zona de memorie, procesoarele conectate avand automat accespartajat la memoria DDR.

Mutex-ul permite realizarea sincronizarii ıntre procesoare ın cazul accesului la resurse partajate,cum ar fi memoria DDR. Modulul hardware functioneaza dupa principii similare mutex-ului din cadrulsistemelor de operare. Perifericul XPS Mutex pune la dispozitie un set de registri mutex, fiecare dinacestia continand un bit de valoare (corespunzator celor doua stari : locked si unlocked) si ID-ulprocesorului care detine controlul curent asupra mutex-ului.

3.2.1 Crearea unui sistem dual-processor

Cea mai simpla metoda pentru crearea unui sistem dual-processor este folosirea wizard-ului BaseSystem Builder, accesibil la pornirea aplicatiei Xilinx Platform Studio. Dupa selectarea directoruluide salvare a proiectului si a placii de dezvoltare folosite, se selecteaza ın fereastra urmatoare optiuneaDual-Processor System, conform Fig. 3-3.

Figura 3-3: Selectarea optiunii Dual-Processor System.

Fereastra de configurare a celor doua procesoare (Fig. 3-4) permite selectarea frecventei ceasuluide referinta, alegerea tipului de procesor (ın cazul Spartan-3E singura optiune disponibila fiind Mi-croBlaze), selectarea frecventei ceasului de sistem si a dimensiunii memoriei locale (BRAM) pentrufiecare din cele doua procesoare.

67 Sisteme dual-processor

Figura 3-4: Configurarea celor doua procesoare.

Urmatoarea fereastra (Fig. 3-5) permite selectarea perifericelor ce vor fi adaugate automat lasistem. La acest pas se selecteaza perifericele corespunzatoare fiecarui procesor, precum si perifericelepartajate. O observatie importanta este aceea ca fiecare procesor trebuie sa aiba asociat un dispozitivUART, utilizat ca STDIN si STDOUT. In cazul ın care se adauga un astfel de dispozitiv (RS232 DCEsau DTE) doar la unul din cele doua procesoare, celalalt procesor va utiliza implicit modulul de debugMDM pentru comunicatiile seriale.

Figura 3-5: Selectarea perifericelor din sistem.

Generarea proiectului se finalizeaza cu configurarea memoriei cache pentru cele doua procesoare,configurarea aplicatiilor de test si prezentarea sumarului sistemului creat.

Aplicatiile software create pe sistemul generat vor trebui sa aiba asociat unul din cele doua procesoaredin sistem. Selectarea procesorului se poate face fie la adaugarea aplicatiei (Add Software ApplicationProject), conform Fig. 3-6a, fie ulterior printr-un click dreapta pe campul Processor corespunzator

3 Sisteme complexe 68

(a) La adaugarea aplicatiei (b) Ulterior adaugarii aplicatiei

Figura 3-6: Asocierea procesorului.

aplicatiei, ca ın Fig. 3-6b. Pentru selectarea celor doua aplicatii software care vor rula simultan pe celedoua procesoare din memoriile BRAM corespunzatoare se da click dreapta pe numele fiecarei aplicatiisi se selecteaza optiunea Mark to Initialize BRAMs.

3.2.2 Perifericul XPS Mailbox

Perifericul XPS Mailbox [14] implementeaza un canal bidirectional de comunicatie ıntre doua proce-soare. Mailbox-ul reprezinta o legatura prin care se pot transmite date ıntre doua sisteme de procesareseparate. De asemenea, perifericul permite generarea de ıntreruperi ıntre procesoare. Un exemplu deschema bloc a unui sistem cu Mailbox este prezentat ın Fig. 3-7.

Transmiterea datelor ın fiecare sens este realizata prin buffere de tip FIFO. Adancimea FIFO(numarul maxim de cuvinte ce pot fi stocate ın buffer) poate fi configurata, dupa adaugarea peri-fericului la sistem, printr-un dublu click pe numele perifericului ın tab-ul System Assembly View,apoi introducerea numarului dorit ın campul Mailbox FIFO Depth ın tab-ul User, meniul Mailbox dinfereastra nou deschisa. Valoarea implicita a acestui parametru este 16.

Figura 3-7: Sistem cu Mailbox.

69 Sisteme dual-processor

3.2.2.1 Organizarea registrilor

Cele doua interfete PLB ale perifericului XPS Mailbox prezinta seturi identice de registri, ınsainformatiile din fiecare set sunt specifice interfetei corespunzatoare. Setul de registri pentru o interfataeste prezentat ın Tabelul 3-1. Adresa de baza este diferita pentru cele doua interfete.

Tabelul 3-1: Maparea registrilor Mailbox ın spatiul de adrese.

Nume registru Descriere Adresa Tip acces

WRDATA Write Data Register Adresa de baza + 0x00 Scriere

RDDATA Read Data Register Adresa de baza + 0x08 Citire

STATUS Status Register Adresa de baza + 0x10 Citire

ERROR Error Register Adresa de baza + 0x14 Citire

SIT Send Interrupt Threshold Register Adresa de baza + 0x18 Scriere/Citire

RIT Receive Interrupt Threshold Register Adresa de baza + 0x1C Scriere/Citire

IS Interrupt Status Register Adresa de baza + 0x20 Scriere/Citire

IE Interrupt Enable Register Adresa de baza + 0x24 Scriere/Citire

IP Interrupt Pending Register Adresa de baza + 0x28 Citire

O valoare scrisa ın registrul WRDATA va fi introdusa ın buffer-ul FIFO de transmisie, urmand aputea fi citita din registrul RDDATA de pe cealalta interfata. Daca se ıncearca scrierea unei valori ınregistru atunci cand buffer-ul este plin (flag-ul Full din registrul STATUS are valoarea 1), va rezultao eroare semnalata prin ınscrierea ın 1 a bitului Full Error din registrul ERROR. Latimea registruluiWRDATA este egala cu latimea magistralei de date (implicit 32 de biti).

Prin citirea unei valori din registrul RDDATA se extrage o valoare din FIFO-ul de receptie. Dacase ıncearca citirea unei valori din registru atunci cand buffer-ul este gol (flag-ul Empty din registrulSTATUS are valoarea 1), va rezulta o eroare semnalata prin ınscrierea ın 1 a bitului Empty Errordin registrul ERROR. Latimea registrului RDDATA este de asemenea egala cu latimea magistralei dedate (implicit 32 de biti).

Registrul STATUS contine bitii de stare ai perifericului pe interfata curenta. Structura registruluieste prezentata ın Tabelul 3-2.

Tabelul 3-2: Structura registrului STATUS.

Bit Nume Descriere

31-4 - Biti neutilizati

3 RTA Receive Threshold Active - indica starea FIFO-ului de receptie:

0 - Nivelul FIFO este mai mic sau egal cu pragul RIT

1 - Nivelul FIFO este mai mare decat pragul RIT

2 STA Send Threshold Active - indica starea FIFO-ului de transmisie:

0 - Nivelul FIFO este mai mare decat pragul SIT

1 - Nivelul FIFO este mai mic sau egal cu pragul SIT

1 Full Valoarea 1 indica faptul ca FIFO-ul de transmisie este plin

0 Empty Valoarea 1 indica faptul ca FIFO-ul de receptie este gol

Registrul ERROR contine bitii care indica erori la accesul de pe magistrala PLB. Dupa realizarea

3 Sisteme complexe 70

unei operatii de citire a registrului, bitii sunt resetati la valoarea 0. Structura registrului este prezentataın Tabelul 3-3.

Tabelul 3-3: Structura registrului ERROR.

Bit Nume Descriere

31-2 - Biti neutilizati

1 Full Error Eroare la scrierea ın WRDATA atunci cand FIFO-ul de transmisie este plin

0 Empty Error Eroare la citirea din RDDATA atunci cand FIFO-ul de receptie este gol

Registrul SIT contine pragul de umplere al FIFO-ului de transmisie la care se va genera o ıntrerupere.Latimea maxima a acestui registru este de 32 de biti, din care sunt folositi cei mai putin semnificativiN biti, unde N = log2(Adancime FIFO). Mai concret, daca adancimea FIFO este, de exemplu, de16 elemente, se vor utiliza cei mai putin semnificativi 4 biti, deci se poate ınscrie ın registrul SIT ovaloare de la 0 la 15. Depinzand de nivelul de umplere al bufferului FIFO, scrierea unei noi valori ınregistrul SIT poate genera o ıntrerupere daca aceasta este validata ın registrul IE.

Registrul RIT contine pragul de umplere al FIFO-ului de receptie la care se va genera o ıntrerupere.Principiul de utilizare este identic cu cel al registrului SIT.

Perifericul XPS Mailbox poate genera trei tipuri de ıntrerupere pe o interfata:

1. Intrerupere ERR (Mailbox Error Interrupt), generata atunci cand oricare din bitii registruluiERROR ia valoarea 1.

2. Intrerupere RTI (Receive Threshold Interrupt), generata ın momentul ın care bitul RTA dinregistrul STATUS ia valoarea 1 (numarul de elemente din FIFO-ul de receptie depaseste pragulsetat ın registrul RIT).

3. Intrerupere STI (Send Threshold Interrupt), generata ın momentul ın care bitul STA din registrulSTATUS ia valoarea 1 (numarul de elemente din FIFO-ul de transmisie scade sub pragul setatın registrul SIT).

Registrii IS, IE si IP au aceeasi structura, prezentata ın Tabelul 3-4, fiecare dintre cei mai putinsemnificativi 3 biti corespunzand unuia din cele 3 tipuri de ıntrerupere prezentate mai sus.

Tabelul 3-4: Structura registrilor IS, IE si IP.

Bit Nume Descriere

31-3 - Biti neutilizati (valoare ’0’)

2 ERR Mailbox Error Interrupt

1 RTI Receive Threshold Interrupt

0 STI Send Threshold Interrupt

Registrul IS contine starea curenta a ıntreruperilor pe interfata. Citirea unui bit de 1 indica faptul cas-a produs ıntreruperea corespunzatoare. Scrierea unui bit de 1 confirma ıntreruperea corespunzatoaresi o sterge ın cazul ın care este activa.

Registrul IE este utilizat pentru activarea ıntreruperilor, continand masca pentru ıntreruperile depe interfata curenta. Un bit de valoare 1 activeaza ıntreruperea corespunzatoare, ın timp de valoarea0 o dezactiveaza.

Registrul IP indica ıntreruperile ın asteptare. Bitii din registru sunt obtinuti prin aplicarea uneioperatii AND ıntre bitii registrilor IS si IE. Semnalul de ıntrerupere generat catre procesorul de peinterfata curenta este rezultatul unei operatii OR aplicate asupra bitilor din registrul IP.

71 Sisteme dual-processor

3.2.2.2 Exemplu de utilizare a perifericului

In cele ce urmeaza este prezentat un exemplu simplu de sistem dual-processor pentru a ilustrafunctionarea perifericului XPS Mailbox: procesorul MicroBlaze 1 citeste starea switchurilor de peplaca de dezvoltare, o transmite prin Mailbox catre procesorul MicroBlaze 0, acesta urmand sa oafiseze pe leduri. Lista perifericelor necesare pentru rularea exemplului este prezentata ın Tabelul 3-5.

Tabelul 3-5: Perifericele din sistemul dual-processor.

Procesor Periferice

MicroBlaze 0 LEDs 8Bit

dlmb cntlr

ilmb cntlr

MicroBlaze 1 DIP Switches 4Bit

dlmb cntlr 1

ilmb cntlr 1

RS232 DCE

Periferice partajate XPS Mailbox

Procesorul MicroBlaze 1 va citi starea switchurilor prin ıntreruperi. Perifericul DIP Switches 4Biteste singura sursa de ıntreruperi din sistemul MicroBlaze 1, nefiind necesara adaugarea si configurareaunui controller de ıntreruperi. Pentru o astfel de functionare ın ıntreruperi, este mai ıntai necesaraconfigurarea perifericului, printr-un dublu click pe numele perifericului ın System Assembly View sibifarea optiunii GPIO Supports Interrupts. Al doilea pas este realizarea unei conexiuni ın tab-ul SystemAssembly View -> Ports ıntre portul IP2INTC Irpt al perifericului si portul Interrupt al procesoruluiMicroBlaze 1.

De asemenea, procesorul MicroBlaze 0 va comunica cu perifericul Mailbox utilizand ıntreruperile.In acest caz, trebuie realizata o conexiune ın tab-ul System Assembly View -> Ports ıntre portulInterrupt 0 al Mailbox-ului si portul Interrupt al procesorului MicroBlaze 0.

Aplicatia care ruleaza pe procesorul MicroBlaze 1 face ıntai setarile necesare pentru functionareaın ıntreruperi, apoi va astepta ıntr-o bucla infinita ıntreruperile de la switchuri. La aparitia uneiıntreruperi, se asteapta 1 ms pentru stabilizarea starii switchurilor, apoi se trimite starea prin Mailboxcatre procesorul MicroBlaze 0. Codul C al aplicatiei este prezentat mai jos.

//Codul C pentru procesorul MicroBlaze_1

#include "xparameters.h"

#include "mb_interface.h"

unsigned *switchuri = (unsigned *)XPAR_DIP_SWITCHES_4BIT_BASEADDR;

unsigned *mailbox = (unsigned *)XPAR_MBOX_0_BASEADDR;

void delay_1ms() //realizeaza o intarziere de aproximativ 1 ms

{

int i;

for(i = 0; i < 50000; i++);

}

3 Sisteme complexe 72

void rutina_intrerupere(void *callBackHandler)

{

delay_1ms(); //se asteapta stabilizarea starii switchurilor

mailbox[0]=switchuri[0]; //citeste starea switchurilor si o transmite prin mailbox

//catre procesorul microblaze_0

//inainte de a iesi din rutina de tratare a intreruperilor se confirma (sterg)

//prin TOW toate intreruperile venite de la switchuri

switchuri[0x120/4]=switchuri[0x120/4];

}

int main(void)

{

//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; //intrerupere la modificarea oricarui switch

//2. setarea intreruperilor pentru procesorul microblaze_1

// se defineste functia de tratare a intreruperilor pentru switchuri

microblaze_register_handler(

(XInterruptHandler)rutina_intrerupere,//pointer la functia de tratare

(void *)0

);

//activeaza intreruperile pentru procesorul microblaze_1

microblaze_enable_interrupts();

while(1);//bucla infinita

return 1;

}

Aplicatia care ruleaza simultan pe procesorul MicroBlaze 0 face, de asemenea, ın primul rand,setarile pentru functionarea ın ıntreruperi, apoi asteapta ıntr-o bucla primirea de mesaje prin Mailbox.Pragul de ıntrerupere RIT este setat la 0, astfel ıncat Mailbox-ul va genera o ıntrerupere atunci candexista o valoare ın FIFO la receptie. La aparitia unei ıntreruperi, aplicatia citeste valoarea din buffersi o afiseaza pe leduri. Codul C al aplicatiei este prezentat ın cele ce urmeaza.

//Codul C pentru procesorul MicroBlaze_0

#include "xparameters.h"

#include "mb_interface.h"

73 Sisteme dual-processor

unsigned *led = (unsigned *)XPAR_LEDS_8BIT_BASEADDR;

unsigned *mailbox = (unsigned *)XPAR_MBOX_0_BASEADDR;

void rutina_intrerupere(void *callBackHandler)

{

led[0] = mailbox[0x08/4]; //citeste valoarea primita in FIFO-ul de receptie

//si o afiseaza pe leduri

mailbox[0x20/4] = 0x2; //confirmare intrerupere (acknowledge)

//seteaza in 0 bitul RIT din registrul Interrupt Status

}

int main(void)

{

//1. setarea intreruperilor pentru Mailbox pe interfata cu microblaze_0

//adresa Receive Interrupt Threshold Register = 0x1C

mailbox[0x1C/4] = 0; //se va genera o intrerupere atunci cand

//se receptioneaza o valoare in FIFO

// adresa Mailbox Interrupt Enable Register = 0x24

mailbox[0x24/4] = 0x2; //bitul RTI in 1

//se vor genera intreruperi doar la receptie

//2. setarea intreruperilor pentru procesorul microblaze_0

// se defineste functia de tratare a intreruperilor pentru Mailbox

microblaze_register_handler(

(XInterruptHandler)rutina_intrerupere,//pointer la functia de tratare a intreruperii

(void *)0

);

//activeaza intreruperile pentru procesorul microblaze_0

microblaze_enable_interrupts();

while(1);//bucla infinita

return 1;

}

3.2.3 Exercitii

1. Creati un sistem dual-processor care sa permita controlarea prin Ethernet a switchurilor si aledurilor. Perifericul Ethernet va fi atasat la bus-ul PLB 0 (aferent procesorului 0), iar perifericeleGPIO pentru leduri si switchuri vor fi atasate la PLB 1 (aferent procesorului 1).

2. Creati un sistem care sa realizeze comunicarea ıntre procesoare folosind memoria DDR.

3 Sisteme complexe 74

CAPITOLUL 4

Crearea modulelor IP

4.1 Crearea si adaugarea unor noi periferice pe bus-ul PLB

Biblioteca EDK pune la dispozitia utilizatorului o multitudine de periferice care pot fi folositepentru a crea sisteme cu grad ridicat de complexitate, ınsa ın cadrul anumitor aplicatii poate apareanecesitatea utilizarii unor alte module care nu se regasesc ın biblioteca. Spre exemplu, ın cazulinterfatarii unei camere video CMOS sau a unui DAC de frecventa mare cu sistemul incorporat ındispozitivul FPGA, este necesar un controller care sa implementeze protocolul de comunicatie specific.

Wizard-ul “Create and Import Peripheral” ofera suport utilizatorilor pentru crearea unor perifericenoi si inserarea acestora ın sistemele EDK, alaturi de microprocesorul Microblaze sau PowerPC si IPcore-urile din biblioteca standard. Intr-o prima faza, utilizatorul specifica o serie de parametri, care vorfi folositi pentru crearea interfetei perifericului cu magistrala selectata (PLB sau FSL). In urma rulariiwizard-ului se genereaza un set de fisiere, ce pot fi editate pentru implementarea functionalitatii dorite.In final este necesara o a doua rulare a wizard-ului pentru a importa modificarile facute perifericului.

Sectiunile urmatoare prezinta trei exemple de creare si importare ın sistem a unor periferice cuinterfata PLB. In cadrul expunerii se presupune ca a fost creat ın prealabil un sistem minimal cuprocesor Microblaze si memorii BRAM.

4.1.1 Periferic Slave PLB cu registri accesibili din software

Pentru crearea si adaugarea unui periferic care realizeaza suma a doua numere pe 32 de biti,initializarea operanzilor si citirea rezultatului facandu-se din software, trebuie parcursi urmatorii pasi:

1. Se lanseaza wizard-ul din meniul Hardware -> Create or Import Peripheral.2. Se specifica daca se doreste crearea sau adaugarea unui nou periferic. La prima rulare a wizard-

ului se selecteaza Create Templates for a New Peripheral.3. In fereastra Repository or Project, se pastreaza optiunea implicita To an XPS project pentru

salvarea fisierelor aferente perifericului ın directorul proiectului curent.4. In fereastra Name and Version se introduce numele perifericului my adder.5. Urmatoarea fereastra permite alegerea interfetei folosite. In cadrul exemplelor se va utiliza

interfata PLB, selectata implicit. In partea de jos a ferestrei exista o serie de link-uri catrespecificatiile pentru perifericele Slave si Master PLB, ce pot fi consultate pentru o mai buna

75

4 Crearea modulelor IP 76

ıntelegere a protocolului.6. In urmatoarea fereastra se selecteaza elementele de interfata ale perifericului. Se lasa bifata doar

optiunea User logic software register.7. In fereastra Slave Interface nu se fac modificari, ın exemplul de fata nefiind necesara adaugarea

suportului pentru mod de transfer burst.8. In fereastra User S/W register se specifica numarul de registri de interfata necesari. Perifericul

sumator are nevoie de 3 registri: doi ın care se scriu operanzii si unul pentru rezultat. Se alegevaloarea 3.

9. Se lasa nemodificate optiunile din urmatoarele ferestre ale wizard-ului, pana la Peripheral Im-plementation Support, unde se bifeaza Generate stub ‘user logic’ template in Verilog insteadof VHDL, pentru generarea ın limbajul Verilog a fisierului ın care va fi inclusa modelareafunctionalitatii perifericului.

In urma finalizarii rularii wizard-ului vor fi generate fisierele template pentru crearea unui perifericslave PLB. In folder-ul pcores din proiect se gaseste un nou folder my adder v1 00 a, care contineaceste fisiere. Fisierul user logic.v, din folder-ul hdl/verilog, contine descrierea modulului user logic,ce include doar o implementare simpla (ın exemplul de fata, modulul va contine o implementare alogicii de citire-scriere a registrilor accesibili din software). In acest fisier se va instantia modulul addersi se vor face unele modificari pentru ca perifericul sa realizeze functionalitatea dorita.

Modificarile ce trebuie aduse fisierului user logic.v sunt enumerate mai jos:

1. Se fac urmatoarele declaratii de semnale:reg [C_SLV_DWIDTH-1 : 0] my_slv_reg0;

reg [C_SLV_DWIDTH-1 : 0] my_slv_reg1;

reg [C_SLV_DWIDTH-1 : 0] my_slv_reg2;

reg [C_SLV_DWIDTH-1 : 0] my_slv_ip2bus_data;

wire [C_SLV_DWIDTH-1 : 0] my_Bus2IP_Data;

De asemenea, semnalul slv ip2bus data se modifica din reg ın wire.2. Bus2IP Data reprezinta semnalul de intrare de date, conectat la magistrala PLB. Se fac urmatoarele

atribuiri pentru inversarea sensului indexarii vectorului (bitul LSB va fi la indicele 0):assign my_Bus2IP_Data[31] = Bus2IP_Data[0];

assign my_Bus2IP_Data[30] = Bus2IP_Data[1];

assign my_Bus2IP_Data[29] = Bus2IP_Data[2];

assign my_Bus2IP_Data[28] = Bus2IP_Data[3];

assign my_Bus2IP_Data[27] = Bus2IP_Data[4];

assign my_Bus2IP_Data[26] = Bus2IP_Data[5];

assign my_Bus2IP_Data[25] = Bus2IP_Data[6];

assign my_Bus2IP_Data[24] = Bus2IP_Data[7];

assign my_Bus2IP_Data[23] = Bus2IP_Data[8];

assign my_Bus2IP_Data[22] = Bus2IP_Data[9];

assign my_Bus2IP_Data[21] = Bus2IP_Data[10];

assign my_Bus2IP_Data[20] = Bus2IP_Data[11];

assign my_Bus2IP_Data[19] = Bus2IP_Data[12];

assign my_Bus2IP_Data[18] = Bus2IP_Data[13];

assign my_Bus2IP_Data[17] = Bus2IP_Data[14];

assign my_Bus2IP_Data[16] = Bus2IP_Data[15];

assign my_Bus2IP_Data[15] = Bus2IP_Data[16];

assign my_Bus2IP_Data[14] = Bus2IP_Data[17];

assign my_Bus2IP_Data[13] = Bus2IP_Data[18];

assign my_Bus2IP_Data[12] = Bus2IP_Data[19];

assign my_Bus2IP_Data[11] = Bus2IP_Data[20];

assign my_Bus2IP_Data[10] = Bus2IP_Data[21];

77 Crearea si adaugarea unor noi periferice pe bus-ul PLB

assign my_Bus2IP_Data[9] = Bus2IP_Data[22];

assign my_Bus2IP_Data[8] = Bus2IP_Data[23];

assign my_Bus2IP_Data[7] = Bus2IP_Data[24];

assign my_Bus2IP_Data[6] = Bus2IP_Data[25];

assign my_Bus2IP_Data[5] = Bus2IP_Data[26];

assign my_Bus2IP_Data[4] = Bus2IP_Data[27];

assign my_Bus2IP_Data[3] = Bus2IP_Data[28];

assign my_Bus2IP_Data[2] = Bus2IP_Data[29];

assign my_Bus2IP_Data[1] = Bus2IP_Data[30];

assign my_Bus2IP_Data[0] = Bus2IP_Data[31];

3. Se rescriu procedurile de scriere si citire din registri ca mai jos:always @( posedge Bus2IP_Clk )

begin: SLAVE_REG_WRITE_PROC

if ( Bus2IP_Reset == 1 )

begin

my_slv_reg0 <= 0;

my_slv_reg1 <= 0;

// my_slv_reg2 <= 0;

end

else

case ( slv_reg_write_sel )

3’b100 :

my_slv_reg0 <= my_Bus2IP_Data;

3’b010 :

my_slv_reg1<= my_Bus2IP_Data;

// 3’b001 :--nu se doreste scrierea din software a registrul 2,

// my_slv_reg2 <= my_Bus2IP_Data;-- aici vom pune rezultatul

default : ;

endcase

end // SLAVE_REG_WRITE_PROC

// implement slave model register read mux

always @( slv_reg_read_sel or slv_reg0 or slv_reg1 or slv_reg2)

begin: SLAVE_REG_READ_PROC

case ( slv_reg_read_sel )

3’b100 : my_slv_ip2bus_data <= my_slv_reg0;

3’b010 : my_slv_ip2bus_data <= my_slv_reg1;

3’b001 : my_slv_ip2bus_data <= my_slv_reg2;

default : my_slv_ip2bus_data <= 0;

endcase

end

4. Se instantiaza modulul adder. Mai jos este prezentat continutul fisierului adder.v, ce trebuieinclus ın directorul hdl/verilog :module adder(

clk,

reset,

opA_i,

opB_i,

res_o

);

4 Crearea modulelor IP 78

parameter width = 32;

input clk;

input reset;

input [width-1 : 0] opA_i;

input [width-1 : 0] opB_i;

output [width : 0] res_o;

reg [width : 0] res_o;

always @(posedge clk or posedge reset)

if (reset) res_o <= {width{1’b0}};

else res_o <= opA_i + opB_i;

endmodule

Instantierea modulului ın fisierul user logic.v se face precum urmeaza:wire[C_SLV_DWIDTH:0] res_o;

always @(posedge Bus2IP_Clk )

my_slv_reg2 <= res_o[31:0];

adder adder_inst(

.clk(Bus2IP_Clk),

.reset(Bus2IP_Reset),

.opA_i(my_slv_reg0),

.opB_i(my_slv_reg1),

.res_o(res_o)

);

5. In final este necesara adaugarea urmatoarelor linii de cod ın modulul user logic:assign slv_ip2bus_data[31] = my_slv_ip2bus_data[0];

assign slv_ip2bus_data[30] = my_slv_ip2bus_data[1];

assign slv_ip2bus_data[29] = my_slv_ip2bus_data[2];

assign slv_ip2bus_data[28] = my_slv_ip2bus_data[3];

assign slv_ip2bus_data[27] = my_slv_ip2bus_data[4];

assign slv_ip2bus_data[26] = my_slv_ip2bus_data[5];

assign slv_ip2bus_data[25] = my_slv_ip2bus_data[6];

assign slv_ip2bus_data[24] = my_slv_ip2bus_data[7];

assign slv_ip2bus_data[23] = my_slv_ip2bus_data[8];

assign slv_ip2bus_data[22] = my_slv_ip2bus_data[9];

assign slv_ip2bus_data[21] = my_slv_ip2bus_data[10];

assign slv_ip2bus_data[20] = my_slv_ip2bus_data[11];

assign slv_ip2bus_data[19] = my_slv_ip2bus_data[12];

assign slv_ip2bus_data[18] = my_slv_ip2bus_data[13];

assign slv_ip2bus_data[17] = my_slv_ip2bus_data[14];

assign slv_ip2bus_data[16] = my_slv_ip2bus_data[15];

assign slv_ip2bus_data[15] = my_slv_ip2bus_data[16];

assign slv_ip2bus_data[14] = my_slv_ip2bus_data[17];

assign slv_ip2bus_data[13] = my_slv_ip2bus_data[18];

assign slv_ip2bus_data[12] = my_slv_ip2bus_data[19];

assign slv_ip2bus_data[11] = my_slv_ip2bus_data[20];

assign slv_ip2bus_data[10] = my_slv_ip2bus_data[21];

79 Crearea si adaugarea unor noi periferice pe bus-ul PLB

assign slv_ip2bus_data[9] = my_slv_ip2bus_data[22];

assign slv_ip2bus_data[8] = my_slv_ip2bus_data[23];

assign slv_ip2bus_data[7] = my_slv_ip2bus_data[24];

assign slv_ip2bus_data[6] = my_slv_ip2bus_data[25];

assign slv_ip2bus_data[5] = my_slv_ip2bus_data[26];

assign slv_ip2bus_data[4] = my_slv_ip2bus_data[27];

assign slv_ip2bus_data[3] = my_slv_ip2bus_data[28];

assign slv_ip2bus_data[2] = my_slv_ip2bus_data[29];

assign slv_ip2bus_data[1] = my_slv_ip2bus_data[30];

assign slv_ip2bus_data[0] = my_slv_ip2bus_data[31];

Pentru ca ın procesul de sinteza a perifericului sa fie inclus si fisierul adder.v, este necesara adaugarealiniilor de mai jos ın cadrul fisierelor din folderul data.

• In fisierul .prj: verilog my_adder_v1_00_a "../hdl/verilog/adder.v"

• In fisierul .pao: lib my_adder_v1_00_a adder verilog

Dupa ce functionalitatea perifericului a fost implementata, urmeaza re-rularea wizard-ului ”Createand Import Peripheral” si adaugarea perifericului:

1. In fereastra Peripheral Flow se bifeaza Import Existing peripheral, se apasa Next.2. Repository or Project - se selecteaza To an XPS Project, se apasa Next.3. Name and Version - se introduce numele perifericului my adder, se apasa Next.4. Se deschide o casuta de dialog prin care se sugereaza ca deja exista un periferic cu acest nume,

se apasa Yes.5. Source File Types - se bifeaza HDL source files, se apasa Next.6. HDL Source Files

(a) La HDL language used to implement your peripheral, se alege optiunea Mixed.(b) Se bifeaza Use data (* .mpd) collected during a previous invocation of this tool. Se alege

calea catre fisierul .mpd din folderul pcores/my adder v1 00 a/data.(c) Se selecteaza Use an XST project file ( .prj). Se alege fisierul .prj din folderul data.(d) Se apasa Next.

7. HDL Analysis Information - se apasa Next.8. Bus Interfaces - la sectiunea Processor Local Bus se bifeaza PLBV46 Slave (SPLB). Se apasa

Next.9. SPLB: Port - este prezentata interfata perifericului. Se apasa Next.

10. SPLB: Parameter - sunt prezentati parametrii perifericului. Se apasa Next.11. Identify Interrupt Signal - ın exemplul de fata nu exista nici un semnal de ıntrerupere. Se apasa

Next.12. Parameter Attributes - Se apasa Next.13. Port Attributes - Se apasa Next.14. Finish.

Perifericul creat (MY ADDER) va fi disponibil ın tab-ul IP Catalog, sectiunea Project Local Pcores-> User. Ultimul pas este instantierea perifericului ın sistem, conectarea acestuia la magistrala PLBsi generarea adreselor.

Pentru testarea functionarii perifericului se poate folosi codul C de mai jos.

//adresa de baza a perifericului my_adder

unsigned *my_adder = (unsigned *) 0xC0A00000;

int i;

4 Crearea modulelor IP 80

int main()

{

//se scrie valoarea primului operand in registrul 0

my_adder[0] = 12;

//se scrie valoarea celui de-al doilea operand in registrul 1

my_adder[1] = 34;

//se afiseaza valorile celor 2 registri

//precum si rezultatul adunarii, disponibil in registrul 2

xil_printf("%d %d %d\n", my_adder[0], my_adder[1], my_adder[2]);

return 1;

}

4.1.2 Periferic Slave PLB cu suport pentru ıntreruperi

In cele ce urmeaza va fi prezentat un exemplu pentru crearea si adaugarea unui periferic de debouncecare va comunica cu procesorul Microblaze prin magistrala PLB. Perifericul va avea un singur registruadresabil care va retine starea butoanelor de pe placa Spartan 3E si va transmite o ıntrerupere catreprocesor la apasarea unuia dintre butoane. Se presupune ca a fost creat ın prealabil un sistem EDKcu Microblaze, memorii BRAM si controller de ıntreruperi. Pentru crearea unui periferic capabil dea genera ıntreruperi se porneste wizard-ul ”Create and Import Peripheral” si se creeaza un perifericswitch debouncer urmand pasii prezentati ın sectiunea precedenta, cu urmatoarele diferente:

1. In fereastra IPIF (IP Interface) Services - sectiunea Slave service and configuration, se bifeazaInterrupt control si User logic software register, conform Fig. 4-1.

2. In fereastra Interrupt Service:(a) Sectiunea Device ISC, se debifeaza Use Device ISC.(b) Sectiunea User logic interrupt, se seteaza Number of interrupts generated by user logic - 1;

Capture mode – Rising Edge Detect (vezi Fig. 4-2).Ca urmare a acestor setari, perifericul va instantia si un modul de control al ıntreruperilor, curegistrii prezentati ın Tabelul 4-1. Dintre acesti registri se vor folosi ultimii 3, pentru a activaıntreruperile perifericului si pentru a sterge ıntreruperile tratate.

3. In fereastra User S/W Register, parametrul Number of software accesible registers trebuie setat ın1 (modulul de debounce contine un singur registru adresabil, ın care se retine starea butoanelor).

4. In fereastra Peripheral Implementation Support, se bifeaza Generate stub ‘user logic’ templatein Verilog instead of VHDL.

5. In fereastra finala, se observa la sectiunea Address Block Summary adresa la care se gasescregistrii modulului de control al ıntreruperilor (Fig. 4-3).

Tabelul 4-1: Maparea registrilor modulului de control al ıntreruperilor ın spatiul de adrese.

Nume registru Descriere Adresa Tip acces

DEVICE ISR Device Interrupt Status Register Adresa de baza + 0x00 Citire/Scriere

DEVICE IPR Device Interrupt Pending Register Adresa de baza + 0x04 Citire

DEVICE IER Device Interrupt Enable Register Adresa de baza + 0x08 Scriere/ Citire

DEVICE IIR Device Interrupt ID Register Adresa de baza + 0x18 Citire

DEVICE GIE Global Interrupt Enable Adresa de baza + 0x1C Citire/Scriere

IPISR IP Interrupt Status Register Adresa de baza + 0x20 Citire/Scriere

IPIER IP Interrupt Enable Register Adresa de baza + 0x28 Citire/Scriere

81 Crearea si adaugarea unor noi periferice pe bus-ul PLB

Figura 4-1: IPIF Services.

Pentru modulul ce implementeaza functia de debounce se poate folosi codul Verilog de mai jos:

module switch_debouncer_core

(

clk_i,

reset_i,

sw_array_i,

sw_array_o,

new_sw_state_o,

ack_i

);

parameter NUM_SW = 4;

parameter DELAY = 10000;

input clk_i;

input reset_i;

input [NUM_SW-1:0]sw_array_i;

output[NUM_SW-1:0] sw_array_o;

output new_sw_state_o;

input ack_i;

reg [30:0] debounce_counter;

reg [NUM_SW-1:0] input_reg;

reg [NUM_SW-1:0] output_reg;

reg int_new_switch_state;

always @(posedge clk_i or posedge reset_i)

if (reset_i) input_reg <= ’b0;

else if (sw_array_i !=input_reg) input_reg <= sw_array_i;

always @(posedge clk_i or posedge reset_i)

if (reset_i) debounce_counter <= ’b0;

else if (sw_array_i !=input_reg) debounce_counter <= DELAY;

else if (sw_array_i == input_reg) debounce_counter <= debounce_counter - 1;

4 Crearea modulelor IP 82

always @(posedge clk_i or posedge reset_i)

if (reset_i) output_reg <= ’b0;

else if (debounce_counter == 0) output_reg <= input_reg;

always @(posedge clk_i or posedge reset_i)

if (reset_i) int_new_switch_state <= ’b0;

else if (debounce_counter == 0) int_new_switch_state <= 1’b1;

else if (int_new_switch_state == 1 & ack_i == 1) int_new_switch_state <= 1’b0;

assign sw_array_o = output_reg;

assign new_sw_state_o = int_new_switch_state;

endmodule

Figura 4-2: Interrupt Service.

In fisierul user logic.v se fac urmatoarele modificari:

1. Se declara:wire [C_SLV_DWIDTH-1 : 0] my_Bus2IP_Data;

reg [C_SLV_DWIDTH-1 : 0] my_slv_ip2bus_data;

2. Se fac asignarile ıntre vectorii my Bus2IP Data si Bus2IP Data ca ın exemplul din sectiuneaprecedenta.

3. Se sterge procedura de scriere a registrului adresabil - este nevoie doar de citirea starii butoanelorpentru a detecta, eventual, butonul care a fost apasat.

4. Se fac urmatoarele declaratii:wire [NUM_SWITCHES - 1 : 0] output_switch_array;

wire new_switch_state;

5. Se instantiaza modulul de debounce:

83 Crearea si adaugarea unor noi periferice pe bus-ul PLB

Figura 4-3: Interrupt Service.

switch_debouncer_core #(.NUM_SW(4), .DELAY(10000)) switch_debouncer_core_inst

(

.clk_i(Bus2IP_Clk),

.reset_i(Bus2IP_Reset),

.sw_array_i(INPUT_SWITCH_ARRAY),

.sw_array_o(output_switch_array),

.new_sw_state_o(new_switch_state),

.ack_i(new_switch_state)

);

6. Se modifica procedura de citire a registrului, astfel ıncat sa citim ıntotdeauna starea butoanelor:reg[C_SLV_DWIDTH-1 : 0] my_slv_ip2bus_data;

always @( slv_reg_read_sel or slv_reg0 )

begin: SLAVE_REG_READ_PROC

case ( slv_reg_read_sel )

1’b1 : my_slv_ip2bus_data <= output_switch_array; //slv_reg0;

default : my_slv_ip2bus_data <= 0;

endcase

end

7. Se fac asignarile ıntre vectorii slv ip2bus data si my slv ip2bus data conform exemplului dinsectiunea anterioara.

8. Se realizeaza urmatoarea conexiune:assign IP2Bus_IntrEvent[0] = new_switch_state;

9. In exemplul de fata exista un port de intrare ın modulul user logic, la care vor fi legate butoanelede pe placa de dezvoltare, precum si 2 parametri folositi de perifericul de debounce. Declarareaacestora se face ca ın Fig. 4-4.

In fisierul .prj se adauga urmatoarea linie:

verilog switch_debouncer_v1_00_a "../hdl/verilog/switch_debouncer_core.v"

In fisierul .pao se adauga urmatoarea linie:

lib switch_debouncer_v1_00_a switch_debouncer_core verilog

4 Crearea modulelor IP 84

Figura 4-4: Declararea parametrilor.

In fisierul switch debouncer.vhd trebuie facute urmatoarele modificari:

1. La declararea entitatii modulului user logic se includ portul de intrare si cei doi parametri, caın Fig. 4-5.

2. La definirea componentei user logic, se adauga portul si parametrii ca ın Fig. 4-6.3. In arhitectura modulului switch debouncer, la sectiunea IP Interconnect (IPIC) signal declara-

tions se declara semnalul:signal user_INPUT_SWITCH_ARRAY : std_logic_vector((NUM_SWITCHES-1) downto 0);

4. La sectiunea Connect internal signals se adauga linia:user_INPUT_SWITCH_ARRAY <= INPUT_SWITCH_ARRAY;

(semnalului declarat anterior i se atribuie valoarea butoanelor)5. La instantierea modulului user logic se adauga declaratiile de porturi si parametri, conform Fig.

4-7.

Figura 4-5: Entitatea modulului user logic.

85 Crearea si adaugarea unor noi periferice pe bus-ul PLB

Figura 4-6: Componenta modulului user logic.

Figura 4-7: Instanta modulului user logic.

Specificarea portului de intrare se face ın fisierul .mpd prin adaugarea liniei:

PORT INPUT_SWITCH_ARRAY = "", DIR = I, VEC = [(NUM_SWITCHES-1):0], ENDIAN = LITTLE

Importarea perifericului se face similar cu exemplul din sectiunea precedenta, prin re-rularea wizard-ului, cu deosebirea ca ın fereastra Identify Interrupt Signals, la sectiunea Interupt sensitivity ofport: IP2INTC Irpt se alege optiunea Rising edge sensitive. Conectarea semnalului de ıntrerupere alperifericului la controllerul de ıntreruperi din sistem se realizeaza urmand pasii prezentati ın sectiunea2.8. Pentru testarea perifericului din software se poate folosi urmatorul program C:

include "stdio.h"

include "xparameters.h"

include "xintc_l.h"

include "xil_exception.h"

unsigned *intr = (unsigned *)XPAR_XPS_INTC_0_BASEADDR;

unsigned *switch_deb = (unsigned *) 0xC3600000;

4 Crearea modulelor IP 86

int interrupt_flag;

int button_state;

//rutina de intrerupere

void rutina_intrerupere(void * callBackHandler)

{

int switch_status;

interrupt_flag = 1;

//Interrupt Status Register -- citire/toogle la scriere

switch_status = switch_deb[0x120/4];

switch_deb[0x120/4] = switch_status;

//se citeste starea butoanelor

button_state = switch_deb[0];

}

int main()

{

//trebuie activate intreruperile pentru periferic

//vezi capitolul cu controller de intreruperi

//Global Interrupt Enable

switch_deb[0x11c/4] = 0x80000000;

//Interrupt Enable Register

switch_deb[0x128/4] = 0x1;

//trebuie activat controller-ul de intreruperi

XIntc_RegisterHandler(

XPAR_XPS_INTC_0_BASEADDR,

0,

(XInterruptHandler)rutina_intrerupere,

(void *)0

);

XIntc_EnableIntr(

XPAR_XPS_INTC_0_BASEADDR,

0x01

);

intr[0x1c/4] = 0x03;

Xil_ExceptionInit();

Xil_ExceptionRegisterHandler(

XIL_EXCEPTION_ID_INT,

(Xil_ExceptionHandler)XIntc_DeviceInterruptHandler,

0

);

Xil_ExceptionEnable();

while (1)

{//daca a fost activata intreruperea

if (interrupt_flag)

{//in functie de butonul care a fost apasat, se afiseaza un mesaj

switch(button_state)

{

case 0x4:

87 Crearea si adaugarea unor noi periferice pe bus-ul PLB

xil_printf("North Button Pressed");

break;

case 0x8:

xil_printf("Center Button Pressed");

break;

case 0x2:

xil_printf("East Button Pressed");

break;

case 0x1:

xil_printf("West Button Pressed");

break;

}

interrupt_flag = 0;

}

};

return 1;

}

4.1.3 Periferic Master PLB cu suport pentru transfer ın regim burst

Perifericele create ın exemplele precedente nu ofera posibilitatea de a initia transferuri pe bus-ulPLB. Exista scenarii ın care este necesara o functionare de tip master PLB: consideram ca pe placade dezvoltare FPGA este implementat un sistem cu Microblaze care primeste date ın timp real de lao camera video; pentru a afisa pe un monitor frame-urile video receptionate, datele corespunzatoareunui frame trebuie initial stocate ın memorie, de unde vor fi citite de controllerul video si afisatepe monitor. Astfel, se poate crea un controller pentru camera cu un buffer de dimensiune mica. Inmomentul ın care bufferul atinge un anumit nivel de umplere, perifericul, ca si master PLB, poatecere un transfer al datelor din buffer ın memoria DDR. Pentru a asigura o functionare ın timp real asistemului, este necesar ca transferurile sa se faca ın mod burst.

Ca si ın cazul perifericelor slave PLB, crearea si adaugarea unui master PLB cu suport burstimplica realizarea a trei pasi: pornirea wizard-ului ”Create and Import Peripheral” pentru creare,editarea fisierelor template generate la primul pas, respectiv re-rularea wizard-ului pentru adaugareaperifericului cu modificarile de la pasul 2.

Crearea unui master PLB folosind wizard-ul se face prin urmatoarele etape:

1. In fereastra Peripheral Flow, sectiunea Select Flow se bifeaza optiunea Create templates for anew peripheral.

2. In fereastra Repository or Project, ramane bifata optiunea To an XPS project.3. In fereastra Name and Version, se introduce numele perifericului: plb master.4. In fereastra Bus Interface, se alege optiunea Processor Local Bus (PLB v4.6). Pentru o mai

buna ıntelegere a functionarii perifericului se poate citi documentul: Master IPIF Specificationfor burst data transfer.

5. In fereastra IPIF (IP Interface) Services:(a) In sectiunea Slave service and configuration se bifeaza doar optiunea User logic Software

register.(b) In sectiunea Master service and configuration, se bifeaza optiunea User logic master.

6. Optiunile din fereastra Slave Interface se lasa nemodificate.7. In fereastra User S/W Register, optiunea Number of software accesible registers se seteaza cu

valoarea 1.8. In fereastra Master Interface se bifeaza Burst support.

4 Crearea modulelor IP 88

9. Optiunile din ferestrele IP Interconnect (IPIC) si Peripheral Simulation Support se lasa nemo-dificate.

10. In fereastra Peripheral Implementation Support, se poate bifa Generate template driver files tohelp you implement software interface.

11. Click pe Finish.

Modulul VHDL user logic contine implementarea necesara pentru ca perifericul sa functioneze caun master cu suport pentru transfer burst. Registrul mst reg inclus ın modul, pe 16 octeti, permitecontrolul interfetei master de catre utilizator. Campurile ce alcatuiesc registrul sunt urmatoarele:

1. Byte-ul 0 - Registru de control (sunt definiti 4 MSB):(a) Rd: operatie de citire a datelor de la un slave de pe magistrala.(b) Wr: operatie de scriere a datelor catre un slave de pe magistrala.(c) Buslock: blocheaza transferul pe magistrala.(d) Assert: indica un transfer ın mod burst (nu este necesar pentru transferul unui ıntreg -

single beat master (4 bytes)).2. Byte-ul 1 - Registru de stare (sunt definiti 4 MSB):

(a) Done - Transferul este complet.(b) Busy - Transferul este ın progres.(c) Error - Eroare la desfasurarea transferului.(d) Timeout - Transferul nu a putut fi efectuat.

3. Byte-ul 2 si byte-ul 3 nu sunt folositi.4. Bytes 4-7: adresa slave-ului la care se face scrierea sau de la care se face citirea.5. Bytes 8-9: pentru activarea transferului.6. Bytes 10-11: nefolositi.7. Bytes 12-13: lungimea transferului ın bytes; pentru single beat master, ıntotdeauna este setat

la 4.8. Byte 14: nefolosit.9. Byte 15: initiaza transferul de la master.

Mai jos este prezentat un exemplu de functie C de scriere ce utilizeaza perifericul:

void MASTER_PLB_MasterSendByte(Xuint32 BaseAddress, Xuint32 DstAddress, int Size)

{

//Se seteaza registrul de control pentru scriere

XIo_Out8(BaseAddress+MASTER_PLB_MST_CNTL_REG_OFFSET, MST_BRWR);

//Se seteaza registrul de adresa cu adresa destinatiei

XIo_Out32(BaseAddress+MASTER_PLB_MST_ADDR_REG_OFFSET, DstAddress);

//Se seteaza master byte enable

XIo_Out16(BaseAddress+MASTER_PLB_MST_BE_REG_OFFSET, 0xffff);

//Se seteaza lungimea transferului in bytes

XIo_Out16(BaseAddress+MASTER_PLB_MST_LEN_REG_OFFSET, (Xuint16) Size);

//Se porneste transferul

XIo_Out8(BaseAddress+MASTER_PLB_MST_GO_PORT_OFFSET, MST_START);

}

Functia de citire este prezentata mai jos:

void MASTER_PLB_MasterRecvByte(Xuint32 BaseAddress, Xuint32 DstAddress, int Size)

{

//Se seteaza directia transferului (citire)

XIo_Out8(BaseAddress+MASTER_PLB_MST_CNTL_REG_OFFSET, MST_BRRD);

//Se seteaza adresa destinatie

89 Crearea si adaugarea unor noi periferice pe bus-ul PLB

XIo_Out32(BaseAddress+MASTER_PLB_MST_ADDR_REG_OFFSET, DstAddress);

// Se seteaza byte enable

XIo_Out16(BaseAddress+MASTER_PLB_MST_BE_REG_OFFSET, 0xFFFF);

//Se seteaza lungimea transferului in bytes

//XIo_Out16(BaseAddress+MASTER_PLB_MST_LEN_REG_OFFSET, Size);

// Se porneste transferul

XIo_Out8(BaseAddress+MASTER_PLB_MST_GO_PORT_OFFSET, MST_START);

}

Codul C urmator realizeaza o citire de date din memorie ın mod burst:

#include "stdio.h"

#include "master_plb.h"

//adresa de baza a memoriei DRAM

unsigned *sdram = (unsigned *)0x87000000;

//adresa de baza a perifericului

unsigned *master_plb = (unsigned *)0xCC600000;

int nr;

int main()

{

//se apeleaza functia de citire din memorie in mod burst a 8 bytes de date

MASTER_PLB_MasterRecvByte(master_plb, (Xuint32) 0x87000000, 8);

while(1);

return 1;

}

Fisierul master plb.h este generat automat si contine o serie de macro-uri folosite ın implementareafunctiilor de citire/scriere a datelor.

4.1.4 Exercitii

1. Creati un periferic PLB care sa realizeze ımpartirea cu rest a doua numere pe 32 de biti, avandinterfata prezentata ın Tabelul 4-2. Operatia de ımpartire este pornita prin ınscrierea valorii0x1 ın registrul de control. Citirea registrului de stare va returna valoarea 0x1 daca perifericulse afla ın cursul realizarii unei ımpartiri si valoarea 0 ın caz contrar.

2. Creati un periferic care sa realizeze ınmultirea a doua numere pe 128 de biti. Rezultatul ınmultiriiva fi reprezentat pe 256 biti.

Tabelul 4-2: Maparea registrilor perifericului de ımpartire ın spatiul de adrese.

Nume registru Adresa Tip acces

Deımpartit Adresa de baza + 0x00 Citire/Scriere

Impartitor Adresa de baza + 0x04 Citire/Scriere

Rezultat Adresa de baza + 0x08 Citire

Rest Adresa de baza + 0x0C Citire

Registru de control Adresa de baza + 0x10 Scriere

Registru de stare Adresa de baza + 0x14 Citire

4 Crearea modulelor IP 90

4.2 Simularea proiectelor EDK ın ModelSim

ModelSim SE este un mediu de simulare si depanare a functionalitatii proiectelor hardware, indife-rent de gradul de complexitate al acestora. Posibilitatea de a simula ıntregul sistem EDK este un bene-ficiu major pentru testarea individuala a componentelor, precum si pentru verificarea functionalitatiiın ansamblu a sistemului.

Cerinte software:

• Xilinx 12.1 sau o versiune mai noua

• ModelSim 6.5c sau o versiune mai noua

Cerinte hardware:

Se considera deja creat un sistem minimal, ce cuprinde:

• microprocesorul Microblaze

• controller-ele dlmb si ilmb

• memorii BRAM

• un periferic GPIO configurat ca port de iesire

Sistemele EDK create pentru placa de dezvoltare Spartan 3E nu suporta simularea cu ModelSim.Pentru a simula functionalitatea proiectului dorit, se poate alege o alta placa de dezvoltare, cum ar fide exemplu: Atlys, Nexys 3, Virtex 5

Pasul I: Configurarea software-ului EDK pentru simularea cu ModelSim

Xilinx EDK ofera urmatoarele biblioteci pentru simularea primitivelor si IP core-urilor existente:

• UNISIM - pentru simularea functionala a primitivelor Xilinx

• UniMACRO - pentru simularea functionalitatii macro-urilor Xilinx

• XilinxCoreLib - pentru simularea functionalitatii componentelor generate cu CoreGen

• Xilinx EDK - pentru simularea comportamentala a IP-urilor din EDK

• SIMPRIM - pentru verificarea cerintelor de timp si a functionalitatii perifericelor (timing simu-lation)

Inainte de a simula un proiect, bibliotecile de simulare trebuie compilate si mapate simulatorului cucare se lucreaza (ModelSim). Pentru alegerea simulatorului se urmeaza pasii de mai jos:

1. In fereastra principala XPS se selecteaza Edit -> Preferences; se deschide o fereastra ca cea dinFig. 4-8.

2. La sectiunea Category se alege Simulation.3. La sectiunea Select Simulator se alege ModelSim.4. La sectiunea Simulator Path se introduce calea catre vsim.exe (executabilul se afla ın subdirec-

torul win32, din directorul ın care este instalat ModelSim).5. La sectiunea Simulation Library Path se introduce calea catre directorul ın care se va face

stocarea bibliotecilor compilate. Se poate crea un subdirector Sim Libs chiar ın directorul ıncare este instalata suita Xilinx.

91 Simularea proiectelor EDK ın ModelSim

Figura 4-8: Edit - Preferences.

Pasii de urmat pentru compilarea bibliotecilor sunt:

1. Se selecteaza Simulation -> Compile Simulation Libraries. Va porni Simulation Library Com-pilation Wizard, ce va fi folosit pentru setarea procesului de compilare (Fig. 4-9).

2. Se alege simulatorul. EDK suporta doua tipuri de simulatoare, ModelSim si NCSim. Seselecteaza ModelSim si se apasa Next.

3. Se selecteaza limbajul HDL folosit de simulator. ModelSim 6.5 suporta atat VHDL cat si Verilog.Se selecteaza optiunea Both VHDL and Verilog si apoi Next.

4. Se alege directorul ın care se vor compila bibliotecile simulatorului (Fig. 4-10). Calea trebuiesa fie aceeasi cu cea setata la Simulation Library Path din Edit -> Preferences -> Simulation.Dupa alegerea directorului se apasa butonul Compile, pentru a porni procesul de compilare albibliotecilor.

Pasul II: Realizarea modelului de simulare

Avand deschis proiectul ce se doreste a fi simulat, se selecteaza Simulation -> Generate Simula-tion HDL Files din meniul XPS. In urma acestei operatii, se vor genera fisierele necesare pentrua simula sistemul EDK si fiecare componenta ın parte. Aceste fisiere vor fi stocate ın directorulsimulation/behavioral al proiectului.

Pasul III: Simularea comportamentala a sistemului

In cele ce urmeaza se va realiza simularea comportamentala a sistemului EDK, ın scopul verificariifunctionalitatii. Exista si posibilitatea realizarii unei simulari de timing, ın scopul verificarii respectariiconstrangerilor temporale de catre sistemul proiectat.

1. Se ıncarca memoriile BRAM cu programul pe care dorim sa-l rulam, prin apasarea butonuluiBRAM INIT din fereastra principala XPS.

2. Se porneste ModelSim, prin selectarea Simulation -> Launch HDL Simulator.3. In directorul simulation/behavioral este prezent fisierul system setup.do, din care se copiaza

urmatoarele secvente:

4 Crearea modulelor IP 92

Figura 4-9: Simulation Library Compilation Wizard - Welcome.

do system.do; set xcmdc 1

vsim -novopt -t ps system; set xcmds 1

do system_list.do

do wave.do

# Set up clock waveforms

proc clk_setup {} {

if { [info exists PathSeparator] } { set ps $PathSeparator } else { set ps "/" }

if { ![info exists tbpath] } { set tbpath "${ps}system" }

force -freeze $tbpath${ps}fpga_0_clk_1_sys_clk_pin 0, 1 {5 ns} -rep 10 ns

}

# Set up reset waveforms

proc rst_setup {} {

if { [info exists PathSeparator] } { set ps $PathSeparator } else { set ps "/" }

if { ![info exists tbpath] } { set tbpath "${ps}system" }

force -freeze $tbpath${ps}fpga_0_rst_1_sys_rst_pin 0, 1 {160 ns}

}

clk_setup; rst_setup;

Se salveaza aceste comenzi ıntr-un alt fisier, de exemplu, system setup alx.do. Pentru pornireasimularii, ın fereastra Transcript a simulatorului se introduce comanda do system_setup_alx.do .

93 Simularea proiectelor EDK ın ModelSim

Figura 4-10: Simulation Library Compilation Wizard - HDL Support.

Astfel se vor rula toate comenzile de mai sus, prin care:

1. se compileaza design-ul;2. se ıncarca design-ul pentru simulare;3. se seteaza lista semnalelor pe care dorim sa le vedem ın fereastra de forme de unda;4. se seteaza fereastra de forme de unda;5. se genereaza semnalele de clock si reset.

Pentru rularea simularii timp de 1 ms, se introduce comanda: run 1ms .

4.2.1 Exercitii

1. Realizati un proiect care sa contina instanta unei memorii BRAM de 4K (pe langa memoriileBRAM folosite de Microblaze pentru instructiuni si date) si un periferic master ın regim burst.Programul C care va rula pe Microblaze va instantia un vector de 1024 de valori ıntregi si vacontine o rutina de configurare a perifericului master pentru transferul vectorului ın memoriaBRAM. Vizualizati continutul memoriei BRAM folosind simularea comportamentala a sistemuluiın ModelSim.

2. Verificati prin simulare cu ModelSim functionalitatea perifericelor create ın sectiunea Crearea siadaugarea unor noi periferice pe bus-ul PLB.

4 Crearea modulelor IP 94

Bibliografie

[1] Xilinx, Embedded System Tools Reference Manual EDK 12.1, UG111 April 19, 2010

[2] Xilinx, Spartan-3E FPGA Starter Kit Board User Guide, UG230 (v1.1) June 20, 2008

[3] Xilinx, MicroBlaze Processor Reference Guide, UG081 (v11.0) April 19, 2010

[4] Xilinx, XPS General Purpose Input/Output (GPIO) (v2.00.a), DS569 April 19, 2010

[5] Xilinx, XPS UART Lite (v1.01a), DS571 April 19, 2010

[6] Xilinx, XPS Serial Peripheral Interface (SPI) (v2.01b), DS570 April 19, 2010

[7] Linear Technology, LTC2604/LTC2614/LTC2624, 2004

[8] Xilinx, LogiCORE IP XPS PS2 Controller (v1.01b), DS707 April 19, 2010

[9] Xilinx, XPS Thin Film Transistor (TFT) Controller (v2.01a), DS695 May 03, 2010

[10] Xilinx, LogiCORE IP XPS Timer/Counter (v1.02a), DS573 April 19, 2010

[11] Xilinx, LogiCORE IP XPS Interrupt Controller (v2.01a), DS572 April 19, 2010

[12] Siva Velusamy, LightWeight IP (lwIP) Application Examples, XAPP1026 (v1.0) April 7, 2008

[13] Vasanth Asokan, Designing Multiprocessor Systems in Platform Studio, WP262 (v2.0) November21, 2007

[14] Xilinx, XPS Mailbox (v2.00b), DS632 December 2, 2009

95