Stand de Programare Fpga Pentru Sisteme Dedicate de Conducere a Proceselor

CAPITOLUL 1. INTODUCERE ȘI MOTIVAREA TEMEI

1.1. Introducere

Tema de licență este structurată în 5 capitole:

Capitolul 1 – Introducere și motivarea temei

Capitolul 2 – Circuite integrate digitale. Aici sunt dezvoltate noțiuni despre circuitele combinaționale și circuitele secvențiale. Subcapitolul de circuite combinaționale conține detalii despre porțile logice, inversoare, multiplexoare și demultiplexoare. Subcapitolul de circuite secvențiale conține detalii despre bistabili, numărătoare și regiștri de deplasare

Capitolul 3 – Circuite integrate VLSI. În acest capitol s-au dezvoltat noțiunile de CPLD, FPGA.

Capitolul 4 – Programarea FPGA. Aici s-au dat detalii despre cum se poate dezvolta un proiect utilizând Xilinx ISE, cum se poate realiza simularea comportamentului unui fișier de tip VHDL și cum se poate programa FPGA-ul utilizând IMPACT.

Capitolul 5 – Realizarea practică. În acest capitol s-a descris dezvoltarea plăcii ce implementează un PLC în FPGA utilizând EAGLE, modul de realizare a comunicației seriale cu calculatorul utilizând UART dar și modul de realizare a interfeței cu utilizatorul. De asemenea, ultimul subcapitol descrie rezultatele experimentale

În acest proiect se dorește dezvoltarea unui PLC utilizând un FPGA. Un PLC (Programmable Logic Controller) se utilizează pentru automatizarea anumitor procese industriale. Ele conțin mai multe intrărișiieșiri, pot implementa diferite funcții logice și sunt rezistente la vibrații și șocuri mecanice. Cei mai cunoscuți producători de PLC-uri sunt: MITSUBISHI, ABB, SIEMENS, BOSCH, HITACHI si MOTOROLA însă sunt alte zeci de firme care realizează PLC-uri și le comercializează[1].

Avantajele unui PLC sunturmătoarele:

Flexibilitate

Ușor de depanat

Eficiențaspațiuluiutilizat

Cost redus

Testat, evaluat

Toate aceste proprietăți sunt incluse și într-un FPGA, diferența în utilizare fiind în faptul că pentru a programa un FPGA este nevoie și de anumite cunoștințe de electronică digitală. Astăzi FPGA-urile au ajuns să poată lucra la frecvențe uriașe de pana la 700MHz, lucru ce face ca aceste dispozitive să fie cu mult mai rapide decât un PLC. Pentru a demonstra cat de puternic este un FPGA voi preciza faptul că pe aceste capsule pot fi dezvoltate procesoare (cum este microBlaze dezvoltat de Xilinx) ce pot fi programate utilizând limbajul C ce pot rula la maxim 200 MHz[2]. Pot fi realizate mult mai multe lucruri cu un FPGA, având în vedere faptul că un PLC conține relee și datorită acestui fapt, PLC-urile nu pot să genereze un semnal cu perioadă foarte mare.

1.2. Motivarea temei

Ca urmare a studiului pe care l-am in facultate in acești patru ani cu circuite logice atât combinaționale cât si secvențiale am încercat să aprofundez circuitele logice integrate pe scară largă și în speță FPGA. Scopul lucrării a fost de a crea o platformă de programare pentru FPGA de tipul Spartan 3 folosind mediul de programare integrat 14.7 folosit de firma Xilinx.

Pentru programare am ales un modul de tipul xc3s200. Am ales acest tip de modul având în vedere faptul că în configurația modului de programare exista o memorie de tip flash astfel încât pot sa citească din memoria flash programele scrise.

CAPITOLUL 2. CIRCUITE INTEGRATE DIGITALE

Circuitele logice digitale sunt implementate utilizând logica booleană. Această logică utilizează ca si nivel logic așa numitul ‘0’ si ‘1’ logic, unde ‘0’ reprezintă valoarea de adevăr falsă iar ‘1’ logic reprezintă valoarea de adevăr adevărată.

2.1. Circuitele combinaționale

Prin circuite electronice, in special rezistori si circuite bazate pe semiconductori, pot fi implementate dispozitive ce implementează logica booleană cum ar fi inversoare si porți logice and, or, xor, nor, xnor, cu o gamămare al numărului de intrări. De exemplu, in imaginea următoare se poate găsi o poartă logică NAND si o poartă NOR implementate cu tranzistori MOS:

Figura 2.1: a) Poarta logică NAND

b) Poarta logică NOR

Vor fi date câteva exemple de porți logice găsite in comerț, dar si logica ce este implementată de acestea.

Figura 2.2: Inversor – se găsește in cipul HC7404

Figura 2.3: Poarta logică AND – se găsește in cipul HC7408

Figura 2.4: Poarta logică AND – se găsește in cipul HC7400

Figura 2.5: Poarta logică OR – se găsește in cipul HC7432

Figura 2.6: Poarta logică NOR – se găsește in cipul HC7402

Figura 2.7: Poarta logică NOR – se găsește in cipul HC7402

O componentă importantă din logica combinațională este sumatorul. Când se dorește să se adune două numere formate din 3 biți fiecare, atunci va trebui să se ținăcont de transportul de la operația de adunare a biților din rangul inferior. Acest transport poartă numele de carry. Astfel dacă se dorește adunarea a doua cuvinte pe 3 biți, și , atunci se va utiliza tehnica din următoarea figură:

Figura 2.8: Sumator pe 3 biți

Aici este carry-ul de la suma dintre și iar este carry-ul de la suma dintre , și . De asemenea este suma rezultată. Se poate observa ca reprezintă XOR și este AND .

Împreună, si formeazăașa numitul half adder – sumator pe jumătate. Pentru implementarea unui full adder – sumator complet, va trebui adăugat si carry-ul anterior la sumator.

In figura următoare se poate vedea schema unui circuit half adder cu porți logice NAND si NOR:

Figura 2.9: Half adder implementat cu porți logice NOR si NAND

De regulă se recurge la această abordare de a implementa circuitele combinaționale cu NAND si NOR deoarece din aceste două tipuri de porți logice se poate obține orice circuit logic combinațional. De exemplu utilizând porțile logice AND, nu pot fi obținute inversoare. În schimb dacă se utilizează o poartă logică NAND, acest inversor poate fi obținut dacă sunt legate intrările intre ele.

Un full adder poate fi construit utilizând două blocuri half adder si o poartă logică OR, după cum se poate observa in figura ce urmează:

Figura 2.10: Schema unui full adder

Aici se poate observa ca acesta are la intrare , și iar la iesirea lui se găsește și .

Utilizând porți logice pot fi realizate multiplexoare.Un multiplexor cu două intrări, un pin de selecție si unul de ieșire are simbolul din figura următoare:

Figura 2.11: Schema și utilizarea unui multiplexor.

Un multiplexor cu 2 intrări are următorul comportament:

Figura 2.12: Comportamentul unui multiplexor cu 2 intrări și o ieșire

Implementarea unui multiplexor cu 2 intrări utilizând porți logice se poate observa în următoarea figură:

Figura 2.13: Implementarea cu porți logice a unui multiplexor cu două intrări

Avantajul acestor tipuri de circuite este că poate fi mărit numărul de intrări / linii de selecție utilizând mai multe tipuri de multiplexoare cu 2 intrări, ca în figura următoare:

Figura 2.14: Modul de extindere a unui multiplexor

Așa cum există noțiunea de multiplexor, există și noțiunea de demultiplexor. Simbolul unui astfel de dispozitiv se poate observa în următoarea figură:

Figura 2.15: Simbolul unui demultiplexor

Demultiplexorul va avea la ieșirea selectată semnalul de la intrare. Practic doar unul dintre pinii de ieșire poate fi 1 logic la un moment dat.

2.2. Circuitele secvențiale

Circuitele secvențiale sunt circuitele care depind de un anumit semnal de clock si sunt sensibile in funcție de starea acestui semnal.

Un latch este un circuit ce este sensibil la palier. In următoarea imagine este implementată schema si comportamentul unui latch RS:

,

Figura 2.16: Implementarea si comportamentul unui latch RS

Din comportamentul latch-ului RS se poate observa că, exceptând cazul în care R’ este diferit de S’ atunci P este egal cu Q negat, acesta fiind motivul pentru care de cele mai multe ori semnalul P este asociat cu . De asemenea numele de RS al acestui latch vine de la faptul că în momentul în care R’ = 1 atunci Q = 1 si când S’ = 1 atunci Q = 0. Deoarece R’ este inversul semnalului R si Q’ esteinversul semnalului Q, atunci când Set este 0 atunci Q = 0 si când Reset = 0 atunci Q = 1 cu condiția ca situația R = S = 1 să nu se utilizeze niciodată. Aceastăcondiție nici nu are sens deoarece nu este posibil ca set si reset să fie in același timp 1. De asemenea in diagrama de comportament se observă două grupări identice cu comportament diferit. Acesta este cazul R = S = 0. În momentul în care această combinație apare din combinația R = 0 si S = 1, atunci valorile de la ieșire sunt Q = 1 și P = 0 ceea ce însemnal că valorile de la ieșire rețin valoarea stării anterioare, iar atunci când apare această combinație când R = 1 și S = 0, valoarea de la ieșire este Q = 0 si P = 1 ceea ce însemnă că valorile de la ieșire rețin valoarea stării anterioare de asemenea.

Dacă se dorește ca acest latch sa fie sensibil la un clock atunci poate fi utilizată următoarea schemă:

Figura 2.17: Schema bistabilului RS

Comportamentul acestui bistabil se poate observa în următorul tabel, unde trebuie precizat faptul că ieșirile sunt sensibile doar în cazul în care apare front pozitiv al clock-ului.

Figura 2.18: Comportamentul bistabilului RS

În acest caz se poate observa ca Q devine 1 când S = 1 iar Q devine 0 când R devine 0. La fel ca si in cazul anterior, aici nu se utilizează cazul R = S = 1 deoarece nu are sens.

De asemenea acest bistabil poate fi sensibil la front negativ dacă se introduce un inversor pe clock.

Pentru a fi eliminată starea neutilizată în care R = S = 1, s-a creat bistabilul JK în care această combinație nu poate fi realizată. Schema acestui bistabil poate fi observată în figura ce urmează:

Figura 2.19: Schema unui bistabil JK

Comportamentul acestui bistabil poate fi observat în următorul tabel:

Figura 2.20: Comportamentul unui bistabil JK

Aici se observă că apare noțiunea de starea următoare, aceasta fiind . Astfel, de exemplu, când JK = 11 se poate observa în tabel că starea următoare al bistabilului va fi starea curentă negată. De asemenea în momentul în care JK = 00, atunci starea următoare memorează starea curentă, iar când JK sunt diferiți atunci valoarea pinilor JK este copiată la ieșiri.

Cel mai utilizat bistabil este bistabilul de tip D care este bazat pe un bistabil RS în care D, intrarea, este S și R este D negat. În figura următoare se poate observa implementarea bazată pe un bistabil RS dar și comportamentul acestui bistabil:

Figura 2.21: Implementarea bazată pe bistabilul

RS și comportamentul unui bistabil D

Acest bistabil funcționează ca o memorie pentru un ciclu de tact.

Alt tip de bistabil existent este bistabilul de tip T. Acesta este realizat dintr-un bistabil JK în care pinii J și K sunt legați împreună.

Figura 2.22: Bistabilul T și comportamentul acestuia

Practic acest bistabil complementează bistabilul de tip D. Comportamentul și schema bistabilului T pot fi observate în figura anterioară.

Utilizând aceste tipuri de bistabili se pot implementa diferite circuite secvențiale. Cele mai cunoscute sunt automatele secvențiale, la aceste tipuri de circuite sunt necesare utilizarea și a unor porți logice pentru ca stările dorite să poată fi implementate. Un exemplu clasic automat secvențial este un numărător, însă în acest numărător nu trebuie utilizate alte porți logice deoarece poate fi implementat direct doar cu bistabili de tip D. Schema unui numărător (“counter” în engleză) pe 4 biți se poate vedea în figura următoare:

Figura 2.23: schema unui numărător implementat cu bistabili de tip D

Un alt element important din categoria dispozitivelor secvențiale este registrul de shiftare. Acesta poate deplasa biții un anumit cuvânt la stânga sau la dreapta. Acesta poate fi atât paralel cât și serial, însă varianta cea mai utilizată este cea paralelă deși toată teoria acestora a pornit de la registrele de shiftare seriale. În cele ce urmează va fi descrisă funcționarea unui registru de shiftare serial. În figura următoare se poate vedea un astfel de dispozitiv pe 64 de biți:

Figura 2.24: Registrul de shiftare

De asemenea acestea pot fi și cu ieșire paralelă, în care datele fiecărui bistabil prezent în lanț va fi scoasă la ieșire. Un exemplu de funcționare al registrului de deplasare pe 4 biți cu ieșire paralelă poate fi găsit în figura următoare:

Figura 2.25: Semnalele unui registru de deplasare pe 4 biți

În acest exemplu poate fi văzut clar cum data este deplasată de la către la fiecare front crescător al semnalului de clock[http://ep.etc.tuiasi.ro/files/CID/registre.pdf].

Când este necesară utilizarea unor porți logice, atunci este de dorit să se utilizeze metodele de minimizare cunoscute cum ar fi diagramele Veitch-Karnaugh, dacă nu există altă metodă mai bună pentru un anumit caz particular de implementare. De asemenea trebuie știut faptul că legile lui De Morgan cunoscute în logica simbolică se aplică și în circuitele combinaționale.

CAPITOLUL 3. CIRCUITE INTEGRATE VLSI

De-a lungul timpului s-au realizat tot felul de structuri programabile cum ar fi memoriile RAM, ROM, dar și dispozitivele ce rețin o anumită structură hardware cum ar fi PLA, PAL, FPGA și CPLD. Unele dintre aceste structuri au fost inițial programabile prin elemente fuzibile iar altele prin elemente de memorare ce pot fi rescrise. Din categoria celor fuzibile fac parte PLA (Programmable Logic Array) și PAL (Programmable Array Logic). Structura celor două poate fi văzută în următoarea imagine:

Figura 3.1: a) Structura unui PLA

b) Structura unu PAL

Aici se poate observa că în PLA planul de porți OR este programabil pe când planul OR dintr-un PAL este fix. În schimb, avantajul unui PAL este că acesta conține microcelule cu bistabili, acestea fiind asemănătoare cu un CLB dintr-un FPGA de unde este eliminată tabela LUT. Trebuie specificat faptul că aceste două structuri sunt asociate cu PLD (programmable logic device).

3.1. Arhitectura unui CPLD

Un CPLD (Complex PLD) conține mai multe blocuri PLD conectate între ele prin interconexiuni programabile și de asemenea conectate și la pinii de ieșire. Această structură la nivel de schemă bloc poate fi vizualizată în următoarea poză:

Figura 3.2: Structura unui CPLD

Pentru detaliere, vom alege familia de CPLD-uri 9500 de la Xilinx. Această familie are următoarea arhitectură:

Figura 3.3: Arhitectura CPLD-urilor din familia 9500

Se poate observa că CPLD-ul prezentat are 4 blocuri ce pot îndeplini diferite funcții logice, o matrice de realizare a conexiunilor și blocurile de intrare/ieșire, toate programabile. Practic după ce utilizatorul își realizează codul/schema pe PC în programul indicat de producător, trebuie pornită sintetizarea și implementarea și rutarea. Aceste trei procese reușesc să determine ce conexiuni vor fi realizate între intrări si blocurile funcționale dar tot aici se decide și data ce va fi scrisă în blocul funcțional pentru a realiza implementarea dorită de utilizator.

3.2. Arhitectura unui FPGA

Un FPGA este o componentă electronică ce conține LUT-uri (Look-Up Table) si cu ajutorul cărora pot fi implementate porți logice. In Figura următoare se poate vedea structura de baza a unui FPGA:

Figura 3.4: Structura unui FPGA

Aici se poate vedea poziționarea IOB – blocuri de intrare/ieșire, CLB – blocuri logice configurabile, PSM – matrice de conectare programabile. În plus, un FPGA mai conține de regulă 4 blocuri DCM – digital clock manager, fiecare în câte un colț al FPGA-ului, care permite realizarea unui clock cu perioada necesara utilizatorului. Ca de exemplu, dacă utilizatorul are un oscilator ce are la ieșire frecvența de 100 MHz și utilizatorul are nevoie de frecvența de 65 MHz, atunci va fi utilizat un DCM care are factorul de multiplicare a frecvenței de 13 și factorul de divizare de 20. Astfel aplicând formula = M / D de unde deduce că = 100 13 / 20 = 65 MHz. Acest bloc utilizează un PLL cu ajutorul căruia își realizează frecvența dorită de utilizator. De asemenea un FPGA mai conține și multiplicatoare hardware cu ajutorul cărora se poate realiza operația de înmulțire utilizată mai ales in procesoarele realizate in interiorul capsulei de FPGA.

Un CLB conțineun LUT – Look-Up Table, un bistabil D si un multiplexor, așa cum se poatevedea și in figura următoare:

Figura 3.5: Structura unui CLB

Schema unui CLB din familia SPARTAN poate fi observată în următoarea figură:

Figura 3.6: Structura unui CLB în familia SPARTAN

Aici se poate observa că LUT-ul de fapt este format din G-LUT, F-LUT și H-LUT iar bistabilul este de fapt alcătuit din 2 bistabili. De asemenea, multiplexorul are o structură mult mai complexă.

CAPITOLUL 4. PROGRAMAREA FPGA

4.1. Mediul de dezvoltare HDL

Deoarece este utilizat un FPGA de la XILINX, pentru dezvoltarea proiectului actual a fost utilizat tool-ul pus la dispoziție de această firmă, și anume Xilinx ISE. Cu ajutorul acestui tool se pot dezvolta proiecte în VHDL, Verilog sau chiar în scheme logice. Verilog și VHDL sunt limbaje de descriere hardware (HDL) și acestea nu au nici un dezavantaj față de lucrul cu scheme logice. Mai mult decât atât, uneori este mult mai simplu utilizatorului să realizeze anumite operații scriind codul HDL decât utilizând schemele logice. Imaginați-vă că se dorește realizarea operației de adunare între două semnale cu numele “in1” si “in2”, rezultatul fiind semnalul “out”. Pentru realizarea acestei adunări utilizând schemele logice trebuie aleasă componenta, pusă într-o poziție potrivită în schemă, iar apoi trebuie trasate legăturile, în schimb utilizând limbajul VHDL acest lucru va fi realizat utilizând codul “out <= in1 + in2”.

4.1.1. Utilizarea tool-ului Xilinx ISE

Pentru crearea unui proiect nou în Xilinx ISE mai întâi trebuie deschis acest tool din Start -> All Programs -> Xilinx Design Tools -> ISE Design Suite -> ISE Design Tools -> Project Navigator. După ce se deschide Xilinx ISE se va naviga în meniul File -> New Project… după care apare fereastra New Project Wizard. Aici se introduce locația unde va fi creat proiectul, folderul de lucru dar și numele proiectului și se dă click pe Next după care urmează fereastra Project Settings unde se va alege familia FPGA-ului (Spartan3 în câmpul family), tipul FPGA-ului (XC3S200 în câmpul Device) și tipul capsulei (FT256 în câmpul Package) după care se va da click pe Next iar în Project Summary unde se repetă datele introduse pentru confirmare se va da click pe Finish.

Crearea unei noi componente se va realiza dând click dreapta în fereastra Hierarchy din partea stângă și se alege New Source. Aici apare fereastra Select Source Type din New Source Wizard unde se alege tipul de fișier ce se dorește să se utilizeze. În acest proiect se lucrează cu fișiere de tip VHDL deci aici se va alege VHDL module și se introduce numele fișierului (a componentei ce va fi implementată) după care se va da click pe Next. După ce a apărut fereastra Define Module se vor defini intrările și ieșirile astfel: în coloana Port Name se va introduce numele pinului de intrare/ieșire, în coloana Direction se va specifica dacă acest pin este de intrare, ieșire sau intrare/ieșire, în coloana bus se bifează dacă se dorește ca să se utilizeze o magistrală și dacă aceasta este bifată se activează MSB și LSB după care se dă click pe Next și după aceasta se deschide fereastra Summary unde se vor repeta elementele introduse anterior pentru confirmare. Aici se va da click pe Finish.

Figura4.1: Meniul Hierarchy în Xilinx ISE

Pentru a se alege fișierul Top Module (modulul pentru care se va crea fișierul BIT) se va da click dreapta pe fișierul respectiv si se alege opțiunea Set as Top Module care în figura 4.1 este invalidă deoarece nici un fișier nu este selectat.

Dacă se dorește adăugarea unui proiect deja existent la proiect atunci se alege Add Source după ce se dă click dreapta în Hierarchy, după care se selectează calea și fișierul respectiv.

Pentru generarea fișierului .bit se va da click pe fișierul top module din fereastra Hierarchy după care în fereastra Process se va da dublu click pe Generate Programming File. Se așteaptă până se termină de generat fișierul, timpul acesta putând diferi de la un FPGA la altul dar și resursele calculatorului pe care se lucrează contează destul de mult[4].

Figura4.2: Fereastra Process

4.1.2. Testarea componentelor utilizând Test Banch și ISim

Există mai multe metode de a testa componentele create. Acest lucru poate fi realizat atât prin simulare cât și prin scrierea directă a programului pe FPGA. Pachetul Xilinx ISE vine cu un simulator numit ISim cu ajutorul căruia se pot testa componentele create. Acest simulator este similar cu MODELSIM și este ușor de utilizat prin crearea fișierelor de tip TestBanch.

Pentru a crea un astfel de fișier se dă click dreapta în Hierarchy după care se alege opțiunea New Source… Din fereastra New Source Wizard se alege VHDL Test Banch, se introduce numele fișierului nou creat și se dă Next. Mai departe se va alege fișierul pentru care se dorește realizarea testării, “config_gate” în cazul de față, apoi se dă click din nou pe Next. Ca la orice fișier nou creat, la urmă apare o fereastră de confirmare la care trebuie dat click pe Finish.

Ca fișierele de simulare să fie vizibil, chiar deasupra ferestrei Hierarchy este “View:” în care se poate bifa utilizând un radio button, una din opțiunile “Implementation” sau “Simulation”. Dacă se va alege opțiunea de simulare atunci vor fi vizibile toate fișierele, inclusiv cele de simulat. Se va deschide fișierul “test_B_config_gate” dând dublu click pe el, acesta fiind creat pentru simularea porții logice configurabile. Se deschide deoarece se dorește editarea lui pentru a realiza simularea dorită. El vine deja preeditat ceea ce ușurează mult munca. Tot ceea ce trebuie făcut este sa se introducă stimuli la finalul fișierului, imediat după textul “– insert stimulus here”[5].

Testarea se va face utilizând următoareasecvență de stimuli:

Y <= "00";

wait for clk_period*3;

Y <= "01";

wait for clk_period*3;

Y <= "10";

wait for clk_period*3;

Y <= "11";

wait for clk_period*3;

Y <= "00";

S <= "00";

memorize<= '1';

wait for clk_period;

memorize<= '0';

wait for clk_period;

S <= "00";

Această secvență se va repeta de 4 ori cu precizarea ca înloc de secvența

Y <= "00";

S <= "00";

memorize<= '1';

se va găsi tot timpul “S” incrementat pana când ajunge la “11”, adică vom avea 4 astfel de secvențe. În simulare este permisă utilizarea noțiunii de timp și de introducere a unui delay utilizând această noțiune de timp. Astfel se poate ajunge să se utilizeze sintaxa “wait for 100 ns;” dar si “wait for clk_period*3;”, unde clk_period este definită de utilizator ca fiind o diviziune de timp. Practic în simulare se va executa fiecare linie de cod, ca în programare, si se va lua fiecare instrucțiune și se va executa de către calculator. Fișierele de tip test banch nu sunt luate în considerare în realizarea fișierului .bit (cel utilizat la programarea FPGA-ului), deoarece ele nu fac parte din ierarhia componentei de bază, ci sunt fișiere total independente. Ele nu sunt utile în realizarea schemei ci doar la simulare, pentru testarea componentelor.

Rularea simulării se realizează astfel: se dă click pe fișierul “test_B_config_gate” după care se dă dublu click pe “Simulate Behavioral Model” din fereastra Process, chiar sub fereastra Hierarchy.

Figura4.3: Indicații pentru simulare

In urma rulării simulării, s-a deschis o fereastră a simulatorului ISim din care s-a extras următoarea figură:

Figura4.4: Rezultatul simulării porții logice

Aici se poate observa că atunci când vine impulsul de 1 logic pe semnalul “memorize”, va fi reținut în memoria internă tipul porții logice astfel: daca S = “00” atunci poarta logică va fi AND, dacă S = “01” atunci poarta logica va fi OR, daca S = “10” atunci poarta logică va fi NOR și dacă S = “11” atunci va fi implementat un bistabil de tip D cu clock enable. Intrările în porțile logice sunt Y[1:0] iar la bistabilul de tip D se va utiliza ca intrare pinul Y[0] iar ca și clock enable se va utiliza pinul Y[1], lucru care poate fi dedus cu ușurință din fișierul “config_gate.vhd”. Pentru bistabil, perioada de clock este semnalul “clk” ce se poate vedea în imaginea de simulare a porții logice, lucru vizibil și în figura ce descrie poarta logică.

Pe același principiu s-a creat și simularea pentru temporizator. Se știe faptul că acesta când ajunge la timpul prestabilit, va da un impuls de 1 logic. Ca stimuli, în acest caz am folosit următoarea secvență:

delay_time <= "00000010";

memorize <= '1';

wait for clk_count_period;

memorize <= '0';

wait for clk_count_period * 10;

delay_time <= "00000100";

memorize <= '1';

wait for clk_count_period;

memorize <= '0';

wait for clk_count_period * 15;

Se observă că inițial se utilizează o perioadă de delay de “10”, concret acesta va da un impuls de 1 logic după 3 milisecunde, se așteaptă o perioadă pentru a vedea daca aceasta are comportamentul așteptat, după care se va schimba perioada de delay la 5 milisecunde.

Simulând această componentă cu stimuli respectivi, am obținut următorul comportament:

Figura4.5: Rezultatul simulării temporizatorului

Se poate observa că ambele componente au comportamentul așteptat deci se poate spune că în simulare comportamentul componentelor create este cel care ne așteptăm.

Nu tot timpul simularea garantează comportamentul așteptat de noi, adică dacă simularea este bună pot apărea anumite conflicte ce generează anumite erori care duc la alte rezultate decât cele așteptate. Aici depinde și de tipul FPGA-ului deoarece sinteza este realizată diferit de la un FPGA la altul, în funcție de arhitectura acestuia.

4.1.3. Programarea FPGA-ului

Pentru a programa FPGA-urile de la Xilinx se va utiliza tool-ul IMPACT care va fi instalat în același timp cu ISE. Acesta se va deschide din Start -> All Programs -> Xilinx Design Tools -> ISE Design Suite -> ISE Design Tools -> Tools ->IMPACT. După ce se deschide, apare fereastra Automatically Create And Save The Project unde se va da click pe No, după care în fereastra New IMPACT Project se va da click pe Cancel. În fereastra ISE iMPACT se va da dublu click pe Boundary Scan din partea stângă apoi unde scrie Right click to Add Device or Initialize JTAG chain se va da click dreapta și se alegeopțiunea Initialize Chain. Dacă FPGA-ul este conectat prin cablul JTAG la PC, atunci va apărea lanțul JTAG ce conține componentele. Aici trebuie să fie neapărat chipul de FPGA dar poate apărea și memoria Flash, dacă aceasta este conectată în lanțul JTAG.

Figura 4.6: Lanțul JTAG pentru chipul utilizat

Trebuie avut grijă sa fie selectat programatorul corect, acest lucru verificându-se din Output -> Cable Setup după care se verifică în fereastra Cable Communication Setup dacă este selectat programatorul potrivit. Dacă se utilizează un programator ce trebuie conectat la portul paralel atunci se va selecta Parallel Calbe IV, dacă se utilizează un cablu Digilent atunci se va selecta respectivul și mai există posibilitatea de a se utiliza un cablu pe USB de la Xilinx pentru care se va selecta Platform Cable USB[6].

Figura4.7: Fereastra Cable Communication Setup

CAPITOLUL 5. REALIZARE PRACTICĂ

5.1. Crearea plăcilor PCB utilizând EAGLE

5.1.1. Dezvoltarea plăcii

Dezvoltarea plăcii ce realizează un PLC în FPGA a fost realizat în mediul EAGLE. Acest mediu de dezvoltare în care se pot realiza placi PCB – placi de circuit printate – este foarte ușor de utilizat și intuitiv. Am utilizat ultima versiune de EAGLE, versiunea 7.2. Va fi prezentat în detaliu cum se va dezvolta un proiect de la 0.

Am realizat un program pentru un FPGA de tip Spartan3 pe un modul echipat cu un cip de tip XC3S200.

Figura 5.1: Modulul FPGA utilizat in proiect

După instalarea mediului EAGLE se va porni și ca urmare se va deschide fereastra Control Panel – EAGLE. Din meniul File -> New -> Schematic se va crea un nou fișier de tip schemă. După ce se va realiza schema se va genera și placa (layout – ul).

Figura 5.2: Schema electrica pentru programator

Trebuie precizat faptul că în EAGLE indiferent de ce tool este utilizat se poate face zoom utilizând rotița de scroll de la mouse. Acesta este un avantaj mare deoarece nu trebuie sa mai utilizăm tastatura pentru a da anumite comenzi sau nu trebuie să căutăm butoanele de zoom din meniuri așa cum este cazul altor tool-uri.

5.1.2. Crearea librăriilor

Se poate întâmpla ca să nu existe librarii create pentru anumite componente și ca urmare, acestea trebuiesc realizate pentru a urma pașii firești în dezvoltarea proiectului. Crearea unei librarii noi se va realiza după cum urmează: din fereastra Control Panel EAGLE se va naviga in meniul File -> New și se va alege Library. In noua fereastră deschisă, Library, există cele 3 butoane ce ne vor ajuta la dezvoltarea componentei – butoanele Device, Package și Symbol de la stânga la dreapta:

Figura 5.3: Butoanele Device, Package și Symbol

Vom exemplifica cum se poate realiza o componentă știind dimensiunile acesteia. Pentru a se înțelege cum se poate realiza acest lucru, va fi aleasă o componentă ce nu este utilizată în acest proiect însă va fi un bun exemplu de a învăța cum se creează o componentă. Aici vom crea un șir de 2X4 pini.

Inițial va fi apăsat butonul Symbol ca urmare se va deschide fereastra de editare a unui simbol în care se va introduce numele acesteia care este sir2X4 se apasă OK și apoi în fereastra Worning ce se va deschide anunțând ca urmează a fi creată o nouă componentă se va apăsa butonul Yes.

Aici se vor plasa cei 8 pini, 4 în partea stângă și 4 în partea dreaptă, așa cum dorește utilizatorul să folosească acest simbol în schema sa. Pentru a plasa pinii se va apăsa butonul Pin chiar din partea stânga-jos din fereastra de butoane:

Figura 5.4: Butonul Pin și afișarea coordonatelor

Se vor plasa acești pini simetric față de centru. În partea de sus a schemei se vede dimensiunea laturii unui pătrățel (grid) și respectiv distanța față de centru. Astfel primul pin se va plasa la distanța (-0.4 0.3) față de centru. Al doilea va fi plasat cu un inch mai jos, al treilea va fi deplasat cu un inch mai jos decât al doilea și aceeași distanță va fi păstrată între pinul 3 și 4. Aceeași regulă va fi păstrată și pentru pinii 5-8 care vor fi poziționați simetric față de pinii 1-4 cu specificația că pinul 5 va fi plasat pe poziția (0.4 0.3) așa cum se poate vedea in următoarea imagine:

Figura 5.5: Simbolul șirului de pini de dimensiune 2X4

Inițial pinii au denumirea de tipul P$* unde steluța reprezintă numărul pinului. Pentru redenumirea pinului se va apasă pe butonul Name care se afla sub butonul Delete.

După ce a fost creat simbolul se va trece la crearea pachetului prin apăsarea butonului Packet despre care am discutat încă de la începutul acestui capitol. Ca și în cazul simbolului, în câmpul New se va introduce SIR2X4 și se va apăsa butonul OK. După ce s-a deschis fereastra de creare a pachetului, se vor așeza găurile de plasare a componentei la distanță de un inch una față de cealaltă. Pentru a plasa aceste găuri de plasare a componentei (pad) se va selecta butonul Pad din fereastra de butoane. De regulă prima gaură este pătrată pentru a se ști care reprezintă pinul numărul 1 dintre pinii componentei și pentru a se ști cum este plasată componenta în găurile respective. Alegerea tipului de pad se face din fereastra de sus cu butoane:

Figura 5.6: Butoanele pentru alegerea pad-ului și tipului de pad

După ce s-a ales pad-ul pătrat, acesta se va plasa la coordonatele (-0.05 0.15) pentru a păstra simetrie față de centru. După aceasta, se va alege pad-ul circular și se vor plasa 3 pad-uri consecutive la distanță de un inch unul față de celălalt pe axa Oy în jos. După ce au fost plasate primele 4 pad-uri, urmează a fi plasate următoarele 4, simetric față de primele 4, respectiv la coordonatele (0.05 0.15), (0.05 0.05), (0.05 -0.05), (0.05 -0.15). Rezultatul trebuie să fie cel din figura 5.6.

Am reușit să creăm simbolul și pachetul. Acum trebuie sa realizăm dispozitivul cu care vom lucra efectiv (device-ul). Pentru aceasta se va apăsa butonul Device ce face parte din cele 3 butoane prezentate în figura 5.3. După apăsarea acestui buton se va introduce în câmpul New din fereastra Edit, numele device-ului, care în cazul nostru este SIR2X4. Se va apăsa OK în fereastra de worning ce apare după aceasta și apoi apare fereastra pentru crearea device-ului. Aici trebuie adăugat simbolul utilizând butonul add din fereastra de butoane din partea stângă și apăsând pe butonul New din partea de jos va fi adăugat pachetul la device-ul respectiv. Rezultatul se poate vedea în figura 5.7.

Figura 5.7: Pachetul șirului de pini de dimensiune 2X4

Figura 5.8: Fereastra pentru crearea device-ului

După aceasta, trebuie realizate conexiunile între Simbol și Pachet. Acest lucru se realizează apăsând butonul Connect din dreapta butonului New. Acum a apărut fereastra Connect și trebuie realizate conexiunile între pini și pad-uri. Trebuie observat faptul că există 3 coloane: Pin, Pad și Connection. Inițial în fereastra Pin avem pinii din simbol, în fereastra Pad avem pad-urile din pachet iar fereastra Connection inițial trebuie să fie goală. Inițial se va selecta din prima fereastra pinul G$1.1 iar din fereastra a 2-a se va selecta pad-ul P$1 și se apasă pe butonul Connect de sub prima fereastră[7]. Acum se poate observa că în fereastra Connection a apărut această conexiune. La fel se procedează cu toți pinii rămași, până se realizează toate conexiunile între pini și pad-uri apoi se va apăsa butonul OK. După ce se va apăsa butonul Save (se dă un nume sugestiv librăriei ca de exemplu libr) se va putea închide fereastra de librărie și putem afirma că am creat o componentă ce se va putea utiliza mai departe în realizarea proiectului. Avantajul creării unei librarii este faptul că noi putem să ne creăm anumite componente, să le modificăm ulterior după bunul plac și nu în ultimul rând vom ști tot timpul de unde trebuie să adăugam componenta de care avem nevoie în acel moment în proiect. Eagle vine deja cu foarte multe librării create ce conțin o sumedenie de componente, și ca urmare acest lucru ne ajută prin faptul că nu trebuie să realizăm noi toate componentele utilizate deoarece multe dintre ele se găsesc.

5.1.3. Dezvoltarea schemei

Înainte de a începe dezvoltarea schemei, adăugarea componentelor și crearea conexiunilor între ele, trebuie știut ce dorim să realizăm cu proiectul respectiv. Pentru acest proiect avem la dispoziție chipul cu FPGA pentru care am realizat o componentă într-o librărie EAGLE și pe lângă aceasta vom mai avea și 8 switch-uri ce vor fi pe post de intrări în PLC, dar și 8 leduri ce vor fi pe post de ieșiri din PLC. Pentru a realiza comunicația serială cu un PC trebuie de asemenea o componentă a cărei schemă nu se va găsi nicăieri, deci va trebui realizată o componentă și pentru aceasta. Trebuie ținut cont și de faptul că pentru fiecare led trebuie utilizat câte o rezistență iar la fel ca și în cazul switch-urilor. La switch-uri trebuie menționat faptul că pentru a nu se crea dubii în privința funcționării, se pot utiliza 2 rezistente deoarece nu se știe cum sunt acestea create și astfel se va evita realizarea unui scurt circuit pe placă, lucru care ar putea fi decisiv în funcționalitatea corectă a dispozitivului. În figura 5.10 se poate vedea cum s-au realizat conexiunile cu rezistorii pentru switch-uri și pentru leduri. Aici avem etichetele VCC3V3 ce reprezintă tensiunea de 3.3 volți, GND_SW ce reprezintă masa ce este conectată la switch-uri și la leduri, SW1… SW8 reprezintă semnalele de intrare ce vor merge către PFGA (sunt intrările în PLC) iar LED1… Led8 reprezintă semnalele de ieșire din FPGA, adică semnalele de ieșire din PLC-ul implementat în FPGA.

Pe lângă aceste elemente de bază de intrare/ieșire, am pus pe placă și o mufă VGA pentru a afișa semnalele de ieșire pe un monitor cu mufa VGA. Această parte are un capitol separat despre care se va discuta cum se realizează afișarea și transmiterea semnalelor pentru a se putea comunica cu un monitor cu mufa VGA.

Figura 5.9: Conexiunea ledurilor și a switch-urilor

Vor fi date explicații pas cu pas despre cum se poate dezvolt un astfel de proiect. Aici vom presupune că toate componentele se găsesc deja în librarii, iar dacă nu, presupunem că a fost creată o librărie nouă în care au fost adăugate noile componente.

Vor fi date explicații necesare pentru a crea un proiect simplu iar în urma acestor explicații vor putea fi dezvoltate alte proiecte mai complicate. Schema ce urmează a fi creată pentru exemplificare va fi un soclu de 2X4 pini ce este conectat către un șir de pini 2X4.

Pentru a crea o schemă nouă va trebui deschisă fereastra Control Panel și din meniul File -> New se alege Schematic. Se deschide fereastra Schematic iar în partea stângă al acesteia se află fereastra de butoane. Pentru adăugarea de componente existente în librării în această schemă se va apăsa butonul Add din partea stângă sau se va scrie cuvântul Add în bara de sus urmat de tasta enter. Se va deschide fereastra ADD de unde se va alege componenta dorită. În bara de search se va scrie cuvântul “sochet” iar apoi din rezultatele apărute se va căuta care componentă corespunde cu ceea ce avem noi nevoie. Aici se observă că în pachetul ic-package se găsește componenta DIL8, de care avem noi nevoie pentru a ne realiza schema propusă. Se dă click pe ea apoi se va apăsa pe OK. După ce va fi plasată componenta undeva în zona de plasare a componentelor se va apăsa ESC și ca urmare va apărea din nou fereastra ADD. Aici în bara de start se va scrie “pin” și ce vom avea nevoie de această dată se va găsi în librăria con-lstb, componentă cu numele MA4-2 care se va adăuga și ea lângă soclu.

Dacă se dorește rotirea unei componente, acest lucru se poate face utilizând click dreapta. Dacă această componentă este deja fixată, atunci va trebui sa dăm click pe butonul Move din fereastra de butoane și apoi se poate realiza rotirea.

Crearea conexiunilor între aceste două componente se poate realiza în două moduri: fie prin trasarea directă a firelor, fie prin etichetarea firelor. Aici vom utiliza metoda cu trasarea directă a firelor deoarece se vede mai bine conexiunea între fire. Pentru aceasta se apasă pe butonul wire din fereastra de butoane și apoi se realizează conexiunile de la soclu spre șirul de pini astfel: 1-7, 2-5, 3-3, 4-1, 5-2, 6-4, 7-6, 8-8. Când se dorește ca firul sa nu mai fie mutat de către cursor, se va apăsa pe butonul ESC sau se va utiliza dublu click. Rezultatul este următorul:

Figura 5.10: Exemplu schemă

5.1.4. Crearea layout-ului

După realizarea schemei se va genera layout-ul apăsând pe butonul “Generate/switch to board” din partea de sus al ecranului. Deoarece nu avem un layout generat până acum, va apărea o fereastră de Worning ce va întreba dacă într-adevăr dorim să generăm placa. Vom apăsa Yes și astfel să generat placa cu cele 2 componente ce trebuie mutate (apăsând butonul Move) în interiorul chenarului deja existent. După mutarea componentelor va trebui trasate firele de legătura. Acesta este procesul de rutare și se va realiza apăsând butonul Route. Se vor realiza conexiunile și apoi dimensiunea chenarului va fi micșorată/ajustată astfel încât să încapă componenta în interiorul său. Într-un final, componenta va trebui să arate aproximativ ca în următoarea imagine:

Figura 5.11: Exemplu layout

Toate aceste comenzi date utilizând butoanele din partea stângă se pot realiza utilizând meniul Edit. De asemenea se poate lucra și în multi layer utilizând butonul Layer settings.. ce se poate accesa și din meniul View. De aici se pot alege layerele cu care se dorește să se lucreze în momentul respectiv.

Layout-ul plăcii finale poate fi văzut în figura 5.11iar schema este în figura 5.12.

Figura 5.12: Layout pentru placa PLC-FPGA

De asemenea au fost făcute niște poze și în timpul lipirii componentelor pe această placă:

b)

c) d)

Figura 5.13: Placa ce implementează PLC în FPGA în timpul lipirii componentelor:

a – placa fără componente – viziune pe spate

b – placa ce conține rezistentele și mufa VGA – viziune spate

c – placa ce conține rezistentele și mufa VGA – viziune față

d – placa finalizata – viziune față

5.2.Afișarea pe VGA

Acest proiect este compatibil din punct de vedere al conexiunii VGA cu toate monitoarele care dispun de o astfel de mufă, și anume: CRT, LCD și LED.

Pentru acest proiect se utilizează rezoluția de 1024×768. Transmisia semnalelor către monitor se realizează prin mufa VGA, iar semnalele transmise către această mufă – pentru a se putea realiza afișarea pe monitor – sunt semnalele RGB cu ajutorul cărora se realizează colorarea pixelilor dar și semnalele de sincronizare pe orizontală și pe verticală, acestea fiind importante în determinarea rezoluției.

Întâi de toate trebuie știut că la un moment dat doar un singur pixel este aprins, însă deoarece baleierea se face cu o frecvență foarte mare, ochiul uman nu poate sesiza acest lucru. Acest pixel este determinat cu ajutorul a doua numărătoare: unul pentru reținerea poziției pixelului pe orizontală și celălalt pentru reținerea poziției pixelului pe verticală.

Deși rezoluția utilizată este 1024×768, două numărătoare de 10 biți nu sunt de ajuns deoarece la VGA, pe lângă partea vizibilă care este dată de rezoluția utilizată, există și partea invizibilă. Astfel numărătorul pentru orizontală trebuie să fie de 11 biți.

Figura: 5.14: Zonele unui monitor

Pentru a funcționa corect componenta VGA, în partea invizibilă semnalele RGB trebuie să fie “000”, altfel pot exista probleme la afișare la unele dispozitive care nu permit ca aceste semnale să fie diferite de “000” pe porțiunea parții invizibile.

Realizarea rezoluției de 1024×768 cu o rată de refresh la 60KHz, așa cum s-a utilizat în proiect, se realizează cu o frecvență de 65MHz. Lungimea semnalelor ce prezintăinteres se poate găsi în următorul table:

Tabel 5.1: Semnalele utilizate pentru baleiere și lungimea lor

Pentru a realiza o compatibilitate cu metoda clasică, este nevoie de gruparea pixelilor de pe orizontală în caractere. Astfel primii 8 pixeli alcătuiesc primul caracter, următorii 8 pixeli formează al doilea caracter și așa mai departe.

Ca aceste semnale să se vadă mai bine, am realizat figura 5.15, în care se pot vedea și adresele la care încep și se termină fiecare din aceste semnale:

Fig: 5.15: Semnalele și adresele lor corespunzătoare baleierii pe orizontală

Adresele respective sunt reprezentate în baza 16 (sunt numere în hexazecimal) și așa cum sunt reprezentate aici se poate intui foarte ușor ce trebuie făcut pentru realizarea baleierii pe orizontală: se utilizează un numărător care se incrementează la fiecare front crescător. Frecvența utilizată pentru acest numărător este de 65MHz/8, adică 8125KHz. Această frecvență trebuie divizată cu 8 deoarece așa cum am spus mai devreme, se vor utiliza caractere și nu pixeli, iar orice caracter conține 8 pixeli. Pașii de urmat pentru realizarea componentei VGA pentru baleierea pe orizontală sunt următorii:

Când acest numărător ajunge la 80h se vor invalida semnalele RGB. Pentru aceasta se va utiliza un dispozitiv cu ajutorul căruia se validează, sau nu, semnalele de la intrare. Practic acest dispozitiv va fi alcătuit din 3 porți AND. În intrarea fiecărei porți se va găsi semnalul de validare, dar și unul din semnalele RGB.

Numărătorul ajunge la 83h – semnalul HSYNC utilizat la sincronizarea pentru baleierea pe orizontală este trecut în 0. Până în acest moment acest semnal va fi 1 logic.

Când acest numărător ajunge la valoarea 94h atunci semnalul HSYNC va fi trecut înapoi în ‚1’ logic.

Când numărătorul ajunge la valoarea A7h, numărătorul va fi resetat. Aceasta înseamnă că baleierea se va întoarce înapoi la pixelul 0, însă în acest moment trebuie incrementat și numărătorul ce reține poziția pixelului pe verticală deoarece baleierea trebuie realizată pentru adresa următoare. În același timp vor fi validate semnalele RGB pentru că s-a ajuns din nou în zona vizibilă.

Se poate face ușor o corelație între tabelul 4 și figura 8. De fapt figura 8 este realizată utilizând tabelul 4, însa este mai intuitiv și mai ușor de văzut adresele utilizând o figură ca cea redată. Aici zona vizibilă conține 128 de caractere, între adresa 00h și 7Fh. În această zonă sunt validate semnalele RGB știind că semnalul HBLNK este 0. Începând cu adresa 80h, acest semnal HBLNK va fi ‚1’ logic deoarece baleierea a ajuns în zona invizibilă ceea ce înseamnă că este invalidată afișarea semnalelor RGB. Semnalul HSYNC are o lungime de 17 caractere. Așa cum am specificat și mai sus, acesta va fi ‚0’ logic între adresele 83h și 94h.

Pentru baleierea pe verticală, gândirea este similară, doar că se utilizează partea a 2-a al tabelului 4. Pentru a se vedea mai bine semnalele necesare pentru baleierea pe verticală, am realizat figura 9 în care se poate vedea dimensiunea zonei vizibile, a zonei invizibile și al semnalului de sincronizare. Trecerea la linia nouă și implicit incrementarea numărătorului ce reține poziția pixeluilui pe verticală se va face atunci când se termină de baleiat o linie întreagă. Acest lucru face ca frecvența de tact să fie egală cu cea a HBLNK și ca urmare clock-ul numărătorului utilizat pentru baleierea pe verticală poate fi HBLNK, adică se trece la linie nouă în momentul în care adresa caracterului ajunge la 80h. Aceasta implică faptul că zona invizibilă de la baleierea pe orizontală o să fie la începutul zonei de baleiere pe verticală.

Figura5.16: Semnalele și adresele lor corespunzătoare baleierii pe verticală

Frecvența de baleiere pe verticală, VHCLK, este de 168 de ori mai mare decât CHCLK deoarece o perioadă a VHCLK trebuie să dureze atâta timp cât durează un ciclu complet al baleierii pe orizontală, adică 168 de tacte de caracter.

Aici, semnalele de interes sunt: zona vizibilă, unde se face afișarea pe monitor, zona invizibilă (VBLNK) și semnalul de sincronizare, VSYNC. Semnalul VBLNK se utilizează ca enable pentru a nu se afișa nimic în zona aceasta. În zona vizibilă, semnalul VBLNK = 0 iar în zona invizibilă, VBLNK = 1[8].

Utilizând tabelul 4 sau figura 9, se poate observa că zona vizibilă durează 768 de linii. Astfel adresele liniilor în această zonă sunt cuprinse între 000h și 2FFh, inclusiv. Semnalul VBLNK este format, conform tabelului 4, din FRONT PORCH, SYNC PULSE și BACK PORCH. Acestea adunate durează 38 de linii, deci și VBLNK durează tot 38 de linii, având adresele liniilor semnalului VBLNK cuprinse între 300h și 325h.

Semnalul VSYNC durează 6 perioade a tactului de linie și conține adresele cuprinse între 303h și 308h. Acest semnal este 0 logic între aceste adrese, și 1 în rest.

Pașii de urmat pentru realizarea componentei VGA pentru baleierea pe verticală sunt următorii:

Când LA (Line Address = adresa de baleiere pe linie) este 300h se vor invalida semnalele RGB pentru că s-a ajuns în zona invizibilă.

Când LA ajunge la 303h semnalul VSYNC este trecut în ‚0’. Acest semnal este inițial ‚1’ ca și în cazul baleierii pe orizontala.

După adresa 308 va fi marcat sfârșitul semnalului VSYNC acesta fiind din nou trecut ca în starea inițială, adică în ‚1’ logic.

Pasul final este că la adresa 325 se va da un semnal de reset sincron (aceasta înseamnă că resetarea va fi realizată la următorul front pozitiv al clock-ului). după ce adresa a ajuns la „000h” înseamnă că tot mecanismul de baleiere trebuie reluat.

Ce înseamnă rata de refresh?

În acest proiect rata de refresh este de 60Hz. De fapt acest lucru reprezintă frecvența cu care fascicolul de lumina care baleiază ecranul se va găsi pe același pixel.

Cum se calculează rata de refresh?

In acest proiect se utilizează frecvența de PXCLK = 65MHz. Pentru a se determina frecvența cu care este baleiat un caracter se va împărți această frecvență la 8, deci CACLK = 65MHz/8. Pentru a se determina frecvența de baleiere a unei linii se împarte CACLK la 168, deci LACLK = CACLK / 168. Pentru a determina timpul în care se realizează baleierea tuturor liniilor se va împărți LACLK la 806 (326h = 806), deci refresh rate = LACLK / 806.

Astfel vom avea refresh rate = 65MHz/8/168/806 = 60.0038Hz.

In figura 5.17 se pot observa cele doua baleieri.

b)

Figura 5.17: a) baleierea pe orizontală

b) baleierea pe verticală

Pentru invalidarea semnalelor RGB transmise către mufa VGA se utilizează o schema ca în figura următoare:

Figura 5.18: Schema de invalidare a semnalelor RGB pe zona invizibilă

Pentru a se realiza afișarea pe ecran trebuie realizată o interogare a pixelului pe care se află baleierea. Astfel dacă de exemplu se dorește afișarea de culoare roșie a pixelului de pe linia 100, coloana 30, atunci se utilizează codul VHDL:

If CA = 30 and LA = 100 Then

RGB <= „100”;

End If;

Pentru a putea folosi o mufă VGA trebuie știut faptul că pinul 1 este semnalul Red, pinul 2 este Green, pinul 3 este Blue, pinul 13 este Hsync și pinul 14 este Vsync. De asemenea trebuie precizat faptul că pinii 5, 6, 7, 8, 9 și 10 trebuie conectați la masă, așa cum se poate vedea în următoarea figură:

Figura 5.19: Schema cu conexiunile conectorului VGA

Aici, R29, R30 și R31 au valori identice de 150 de ohmi iar rezistențele R27 și R28 au valoarea de 220 ohmi. Semnalele VGA_R, VGA_G și VGA_B reprezintă semnalele RGB ce se duc spre FPGA iar HSYNC și VSYNC sunt semnalele de sincronizare conectate la FPGA.

Am realizat afișarea semnalelor pe ecran așa cum se vede în figura 5.20. Fiecare semnal este afișat pe 32 de linii (pixeli pe verticală), distanța dintre ele fiind de 64 de linii. Distanța de la marginea superioară a ecranului și primul semnal este de 32 de linii ca și distanța de la al optulea semnal și marginea inferioară a ecranului. În partea dreaptă a figurii 5.20 se vede adresa de start și cea de stop al fiecărui semnal. Dintre cele 32 de linii ce aparțin fiecărui semnal pentru a fi afișat, linia a 6-a este folosită pentru a afișa semnalul de 1 logic și linia a 26-a este folosită pentru a afișa semnalul de 0 logic. Am ales linia a 26-a pentru semnalul de 0 logic pentru că avem la dispoziție 32 de linii iar pentru a avea loc o simetrie, va trebui ca nivelul de 0 logic să fie afișat tot pe linia a 6-a însă numărătoarea începând de la linia 32 în jos. Astfel 32 – 6 = 26.

Pentru a se putea distinge nivelul de 0 și 1 logic a semnalelor atunci când nu apare nici o tranziție (trecere de la 0 la 1 logic sau invers) a semnalelor respective, am preferat utilizarea unui contur astfel încât semnalul să fie vizibil indiferent de starea sa. Astfel conturul semnalelor ce cuprinde cele 32 de linii corespunzătoare semnalului respectiv va fi afișat cu alb, iar semnalul va fi afișat cu negru.

Figura 5.20: Modul de vizualizare a semnalelor pe monitor

Implementarea analizorului logic

Utilizând mufa VGA am realizat un analizor logic în stare incipientă. Acesta reprezintă un echipament ce afișează simultan evoluția în timp a unor semnale logice (8,16). Am preferat implementarea unui analizor logic pe 8 canale deoarece tot atâtea ieșiri vom avea la PLC.

Pentru implementarea acestui analizor am utilizat o componentă de tip RAMD (RAM Dual Port) care memorează datele ce vor fi de ieșire și cu ajutorul căreia se vor prelucra datele pregătindu-le pentru afișarea pe VGA. Aceasta are două porturi, A și B. Pe fiecare din aceste două porturi se pot atât scrie cât și citi date în același timp. Pinul WE validează scrierea datelor pe portul respectiv. Se poate observa în figura 5.21 că portul A este utilizat doar pentru citirea datelor, iar portul B este utilizat pentru scrierea datelor în memorie. Adresa portului A este generată cu un numărător pe 10 biți, iar adresa portului B este captată de la adresa de pixel și de la adresa de caracter. Scrierea datelor în memorie este realizată la fiecare milisecundă astfel fiecare pixel pe orizontală pe care este afișat semnalul reprezintă o milisecundă. Astfel dacă distanța dintre două fronturi este de 3 pixeli, se poate spune că aceste două fronturi au apărut la un interval de timp de 3 ms.

A fost aleasă o memorie de 1K cuvinte de 8 biți deoarece există 8 semnale iar fiecare semnal este afișat pe 1024 de pixeli, ca urmare, cele 8 semnale afișate pe 1024 de pixeli pot fi reținute perfect într-o memorie de 1024 de cuvinte în care fiecare cuvânt este pe 8 biți.

Figura 5.21: RAMD

5.3. Codarea datelor și comunicația serială

UART (Universal Asynchronous Receiver/Transmitter) este un protocol de comunicație serială. Numărul de biți al cuvântului transmis poate diferi în funcție de dorințele utilizatorului.De regulă sunt utilizați 8 biți de date însă aici există și bitul de start dar și cel de stop. De obicei se folosește un bit de start însă lungimea celui de stop poate să varieze. Se poate folosi jumătate de bit de stop (aceasta este și cea mai rapidă metodă), 1, 1.5 sau 2 biți de stop.

Acest protocol utilizează următorul format:

Tabelul 5.2: Formatul unui cuvânt transmis pe UART

După protocolul UART sunt implementate mai multe moduri de comunicație care diferă în funcție de tensiunile utilizate. Acestea sunt: RS-232, RS-422 și RS-485.

RS-485

Acest protocol utilizează ca fire de transmisie a datei două fire cu tensiune diferențială, firul A și firul B. Când pe firul A se găsește tensiune pozitivă iar pe firul B tensiune negativă, atunci este transmis bit de ‘0’ logic, iar pentru a fi transmis bit de ‘1’ logic trebuie ca pe firul A să se găsească tensiune negativă și pe firul B tensiune pozitivă. De regulă RS-485 este utilizat într-un mediu industrial atunci când există multe perturbații, deoarece atunci când o perturbație (ca de exemplu un câmp Electro-magnetic) va distorsiona semnalul transmis, atunci ambele fire vor fi afectate însă diferența de tensiune va fi aceeași.

RS-232

Transmisia pe RS-232 se realizează utilizând două fire, Tx – pentru transmisie – și Rx – pentru recepție. Acest protocol utilizează o configurare de tip Master-Slave astfel încât există un dispozitiv master și unul sau mai multe dispozitive slave. Astfel dispozitivul master va da comanda iar dispozitivele slave vor executa comanda respectivă.

Bitul de ‚1’ logic este reprezentat de o tensiune cuprinsă între -5V și -15V iar bitul de ‚0’ logic este cuprins între +5V și +15V.

În acest proiect transmisia serială este utilizată pentru a realiza comunicația între o placă ce conține o capsulă de FPGA și un PC. Aici PC-ul este dispozitivul master iar FPGA-ul este slave. Comunicația are loc doar într-un sens, de la PC către FPGA. Acest lucru înseamnă că PC-ul transmite informațiile și FPGA-ul va executa comenzile. Comenzile controlează cursorul ce se găsește pe ecran, aceasta fiind cea de-a 2-a metodă de control al cursorului. Acesta poate fi controlat direct de către utilizator prin mouse sau indirect, prin intermediul unui PC, în funcție de deciziile luate.

Baud Rate este un termen specific transmisiei seriale și acesta reprezintă numărul de biți transmiși pe secundă – cu ajutorul baud rate se poate determina viteza cu care se transmit datele și poate varia în funcție de distanța de la master la slave dar și în funcție de perturbațiile care pot apărea în mediul utilizat. Aici este utilizat un baud rate de 9600, acesta fiind și cel mai frecvent utilizat.

Codarea datelor

Pentru a nu avea probleme la recepția semnalului, este de dorit ca tactul utilizat pentru recepție să fie de cel puțin 8 ori mai mare decât frecvența de transmisie a biților pe UART. De obicei este utilizat un tact de 12 ori mai mare decât frecvența de transmisie a biților.

Pentru comunicația între FPGA și PC am preferat în acest proiect să fie utilizată comunicația UART. Am preferat să utilizez o comunicație simplă însă codată astfel încât să se potrivească foarte bine pe ceea ce trebuie realizat în acest proiect. De regulă codarea este realizată astfel încât se transmite un șir de caractere și în funcție de poziția caracterului trimis se va determina care parametru va fi modificat în funcție de cuvântul respectiv. Nu am utilizat această variantă deoarece acest șir de caractere ar fi trebuit să fie foarte mare și astfel transmisia datelor ar fi fost realizată foarte încet. În plus ar fi fost consumate mai multe resurse din FPGA pentru a determina al câtelea caracter este cel primit în momentul respectiv.

Componenta utilizată în proiect are următoarea sintaxă:

component UART_manager

Port ( CLK50MHz : instd_logic; –Master Clock

dataRX : in std_logic_vector(7 downto 0);

dataRX_activ : instd_logic;

RD_strobe : outstd_logic;

byte1 : out std_logic_vector(7 downto 0);

byte2 : out std_logic_vector(7 downto 0);

byte3 : out std_logic_vector(7 downto 0);

byte4 : out std_logic_vector(7 downto 0);

byte5 : out std_logic_vector(7 downto 0);

rdy : out std_logic);

end component;

Aceasta poartă numele UART_manager pentru că datele ce sunt recepționate de componenta ce gestionează comunicația UART, Rs232RefComp, sunt transmise către UART_manager unde sunt gestionate.

Componenta Rs232RefComp poate să realizeze comunicația UART la un baud rate de 9600, însă acest lucru poate fi modificat dacă se va modifica parametrul constant baudDivide din interiorul acestei componente. În cazul de față, acest parametru are valoarea “11010100”, aceasta însemnând 212 în zecimal acest număr fiind obținut împărțind frecvența la baud rate si apoi la 32. Astfel dacă se dorea obținerea unui baud rate de 1000 (acesta nu este standard însa este un bun exemplu), atunci acesta se calcula împărțind 65000000 la 1000 apoi la 32 și am fi obținut coeficientul baudDivide de valoarea 2031. Această componentă transmite un semnal de ‘1’ logic imediat după ce s-a terminat citirea datelor, prin semnalul cu numele dataRX_activ iar reactivarea componentei pentru recitirea următoarei transmisii va fi făcută atunci când semnalul RD_strobe va fi ‘1’. Această componentă nu este producție proprie și este un bun exemplu de utilizare al unui cod deja existent. Pe de altă parte, dacă un anumit cod creat pentru controlul unei anumite componente, cum ar fi în acest caz, controlul RS232, sau alte exemple cum ar fi controlul mouse-ului sau a tastaturii pe PS2, sau controlul VGA, nu are sens să creăm alta deoarece ar fi o pierdere de timp.

Componenta UART_manager trebuie să gestioneze 5 tipuri de semnale primite de la componenta Rs232RefComp. Aceste semnale oferă informații despre tipul porții logice, legăturile ce se realizează între porțile logice, intrări, ieșiri și timere dar și despre durata timpului la un anumit temporizator. Aici, data fiecărui tip de semnal va fi reținut într-un byte însă fiecare va fi creat în urma primirii a 2 bytes de la componenta Rs232RefComp astfel:

dacă primii 4 biți din dataRX vor fi "0010", atunci următorii 4 biți vor reprezenta primii 4 biți din primul tip de semnal

dacă primii 4 biți din dataRX vor fi "0011", atunci următorii 4 biți vor reprezenta ultimii 4 biți din primul tip de semnal

dacă primii 4 biți din dataRX vor fi "0100", atunci următorii 4 biți vor reprezenta primii 4 biți din al doilea tip de semnal

dacă primii 4 biți din dataRX vor fi "0101", atunci următorii 4 biți vor reprezenta ultimii 4 biți din al doilea tip de semnal

dacă primii 4 biți din dataRX vor fi "0110", atunci următorii 4 biți vor reprezenta primii 4 biți din al treilea tip de semnal

dacă primii 4 biți din dataRX vor fi "0111", atunci următorii 4 biți vor reprezenta ultimii 4 biți din al treilea tip de semnal

dacă primii 4 biți din dataRX vor fi "1100", atunci următorii 4 biți vor reprezenta primii 4 biți din al patrulea tip de semnal

dacă primii 4 biți din dataRX vor fi "1101", atunci următorii 4 biți vor reprezenta ultimii 4 biți din al patrulea tip de semnal

dacă primii 4 biți din dataRX vor fi "1110", atunci următorii 4 biți vor reprezenta primii 4 biți din al cincilea tip de semnal

dacă primii 4 biți din dataRX vor fi "1111", atunci următorii 4 biți vor reprezenta ultimii 4 biți din al cincilea tip de semnal

Cele cinci tipuri de semnale sunt reprezentate de byte1, byte2, byte3, byte4 și byte5, semnale de ieșire din componentă. Aceste 5 semnale reprezintă gate_type, gate_memorize, mux_paths_sel, mux_paths_mem și respectiv TMP_delay de la componenta config_alg, aceste semnale având conexiune directă de la componenta UART_manager la componenta TMP_delay.

Este bine ca protocolul de comunicație utilizat să fie bine definit și să nu existe confuzii de interpretare la receptor. Concret, trebuie bine știut ce este transmis și ce se recepționează, iar data recepționată trebuie să fie cea corectă pentru a se realiza comanda așteptată de transmițător. S-ar fi putut utiliza și o comunicație codată pe mai multe cuvinte transmise într-un șir, însă aici nu are sens deoarece transmisia este realizată prin fir și nu există mai multe dispozitive cu același nume. În cazul utilizării mai multor PLC-uri, s-ar putea implementa o astfel de comunicație în care primul lucru realizat este verificarea dispozitivului sau al ID-ului dispozitivului, însă nici aici nu este cazul să se implementeze o astfel de comunicație.

5.4. Prelucrarea datelor pe PC utilizând VBScript

Transferul datelor se va putea realiza de la PC către calculator utilizând fișierul AxSerial.vbs. Extensia vbs este specifică fișierelor scrise într-un limbaj de scripting numit Visual Basic Script. Acesta este un limbaj de nivel înalt care poate fi editat chiar și în notepad. În acest proiect, ca editor a fost utilizat Notepad++, acesta oferind o viziune mai bună a codului.

Visual Basic Script, denumit și VBScript, este un limbaj de scripting activ dezvoltat de Microsoft, și are ca mare facilitate faptul că poate fi executat, în windows, dând doar dublu click pe fișierul în care este dezvoltat scriptul respectiv. Pentru a fi executat acest fișier, trebuie să aibă extensia vbs, iar pentru a fi creat un astfel de fișier se poate crea un nou fișier .txt căruia îi va fi schimbată extensia în .vbs.

Acesta este un limbaj foarte intuitiv și ușor de folosit acesta fiind motivul pentru care am preferat utilizarea lui pentru dezvoltarea proiectului. Pentru a demonstra cât de simplu este, va fi dat un exemplu în acest sens. Inițial trebuie creat un fișier “demo.txt”, după care se va da rename și se va schimba denumirea în “demo.vbs”. Aici practic am schimbat extensia din .txt în .vbs. Acest fișier redenumit va fi deschis cu Notepad sau Notepad++ și în fișier se va scrie:

MsgBox “Exemplu”

după care va fi salvat fișierul, se va închide și apoi se va da dublu click pe el. După aceasta, va apărea pe ecran următoarea fereastră:

Figura 5.22: Exemplu de fereastră afișată cu VBScript

Astfel am arătat că VBScript este un script “prietenos”, ușor de folosit.

Fișierul creat pentru a executa transferul de date are denumirea AxSerial_V4.vbs și pentru a funcționa va trebui instalat un program numit AxSeria cepoate fi downloadat de la următorul link:http://www.activexperts.com/download/?p1=ax003

Inițial vor fi date niște detalii despre cum funcționează PLC-ul pentru a putea descrie cum a fost implementată partea de script. Am utilizat cea mai simplă metodă de a realiza interfața cu utilizatorul, și anume descrierea comportamentului PLC-ului într-un fișier .txt.

5.4.1. Interfața cu utilizatorul

În acest fișier va fi descris comportamentul PLC-ului într-un format asemănător diagramelor ladder. Fiecare linie din acest fișier va reprezenta un șir de comenzi trimise de către PC către FPGA care vor implementa descrierea comenzii respective. Există 3 tipuri de comenzi:

Comenzi ce vor implementa porțile logice. Acestea au următorul standard:

|A––––B–––-C| param = D

Aici C reprezintă poarta logică ce va fi utilizată. Acest parametru poate fi “gate0”, “gate1”…”gate15”.

A și B reprezintă prima și respectiv a doua intrare în poarta logică C. Aceștia pot fi: "T1ms", "in0", "in1", "in2", "in3", "in4", "in5", "in6", "in7", "tmr0", "tmr1", "tmr2", "tmr3", "tmr4", "tmr5", "tmr6", "tmr7", "gate0", "gate1", "gate2", "gate3", "gate4", "gate5", "gate6", "gate7", "gate8", "gate9", "gate10", "gate11", "gate12", "gate13", "gate14", "gate15".

D reprezintă un parametru ce va dă tipul porții logice. Acesta poate fi “and”, “or”, “nor”, “fdd”.

Comenzi ce vor implementa temporizatoare. Acestea au următorul standard:

|I––––––––T| param = P

Aici I reprezintă timerul utilizat. Acest parametru poate fi "tmr0", "tmr1", "tmr2", "tmr3", "tmr4", "tmr5", "tmr6", "tmr7".

I reprezintă intrarea în timer, ceea ce va da timpul la care se va număra o unitate. De regulă, acest parametru este "T1ms", dar poate să fie și "tmr0", "tmr1", "tmr2", "tmr3", "tmr4", "tmr5", "tmr6", "tmr7" în caz de cascadare.

P este parametrul care va indica momentul în care temporizatorul se va reseta și astfel va da impulsul ce indică faptul că a fost realizată temporizarea așteptată. P poate să fie maxim 127 deoarece temporizatorul utilizează un timer pe 8 biți ce poate să numere până la maxim 127. Astfel dacă I va fi T1ms (impuls la fiecare o milisecundă), atunci temporizatorul va putea implementa maxim 128 de milisecunde deoarece atunci când P este 0 va implementa o milisecundă, deci pentru P = 127, vor fi implementate 128 de milisecunde.

Comenzi ce vor implementa ieșirile. Acestea au următorul standard:

|X–––––––-Q|

Se poate observa că aici lipsește parametrul deoarece nu este nevoie de o astfel de variabilă. X reprezintă ieșirea din poarta logică sau din temporizator ce se dorește a fi trimisă către una din ieșiri, ca urmare acesta poate fi: "in0", "in1", "in2", "in3", "in4", "in5", "in6", "in7", "tmr0", "tmr1", "tmr2", "tmr3", "tmr4", "tmr5", "tmr6", "tmr7", "gate0", "gate1", "gate2", "gate3", "gate4", "gate5", "gate6", "gate7", "gate8", "gate9", "gate10", "gate11", "gate12", "gate13", "gate14", "gate15"

Q reprezintă ieșirea către care va fi realizată legătura pentru a fi afișat X

5.4.2. Funcțiile și parametrii utilizați

Vor fi enumerate toate funcțiile utilizate în script, și vor fi date explicații legate de utilitatea acestora. Funcțiile utilizate sunt următoarele:

InitUART are rolul de a inițializa comunicația UART, de a deschide portul pe care va fi realizată transmisia de date și de a seta baud rate-ul la 9600.

GateProgram are rolul de a programa o anumită poartă logică. Cu ajutorul acestei funcții se va programa tipul porții logice.

muxProgram are rolul de a programa unul dintre multiplexoare. Această funcție va fi folosită mai departe de alte funcții.

TMPProgram are rolul de a programa un anumit temporizator pentru a genera un anumit timp.

muxOutputProgram are rolul de a crea legătura între porțile logice și ieșirile PLC-ului. Aici este utilizată funcția muxProgram.

muxGatePathProgram creează legătura între porți logice programând multiplexoarele aflate la intrări. Acest lucru este realizat utilizând funcția muxProgram.

Ret_Current_Directory va returna calea la care se află fișierul AxSerial_V4. Acest lucru este foarte util deoarece nu este necesar ca în script să fie dată explicit locația fișierului.

Ret_TXT_file returnează un șir de caractere ce se află într-un anumit fișier. Astfel fișierul plc.txt în care va fi realizată diagrama ladder poate fi citit și ca urmare datele conținute de acesta pot fi prelucrate.

Sort implementează un algoritm simplu de sortare pentru a aranja într-o anumită ordine elementele de pe o linie din fișierul plc.txt

ExtractLineItems returnează un șir în care se vor găsi elementele ce sunt conținute într-o linie din fișierul plc.txt

RetPosInArray returnează poziția unui element dintr-un vector de elemente.

SendData utilizează funcțiile explicate mai sus pentru determinarea conținutului fișierului plc.txt, determinarea elementelor din fiecare linie și apoi trimiterea datelor respective către FPGA prin comunicația UART.

Pentru determinarea mai ușoară a cuvintelor cheie din fișierul plc.txt, vor fi utilizate niște constante ce rețin anumiți parametri, și anume:

outputs = Array("out0", "out1", "out2", "out3", "out4", "out5", "out6", "out7")

gates = Array("T1ms", "in0", "in1", "in2", "in3", "in4", "in5", "in6", "in7", "tmr0", "tmr1", "tmr2", "tmr3", "tmr4", "tmr5", "tmr6", "tmr7", "gate0", "gate1", "gate2", "gate3", "gate4", "gate5", "gate6", "gate7", "gate8", "gate9", "gate10", "gate11", "gate12", "gate13", "gate14", "gate15")

andGate = 0

orGate = 1

norGate = 2

fddGate = 3

Cea mai importantă funcție este SendData deoarece aici este realizată citirea datelor din fișierul plc.txt, prelucrarea datelor și transmisia pe UART. Aici se va determina fiecare comandă din fișierul plc.txt, prin interogări repetate. Va fi determinată fiecare poartă logică, fiecare timer și fiecare intrare/ieșire, și acestea vor fi programate împreună cu, căile realizate. Astfel transmițând comenzile corecte către FPGA, PLC-ul ce este implementat în FPGA va implementa comportamentul descris în fișierul plc.txt. În acest proiect, funcția SendData este echivalentul unei funcții main din limbajele de nivel mai scăzut.

5.5. Schema configurabilă, timere si porți logice programabile

Pentru realizarea circuitului reconfigurabil avem nevoie în primul rând de o poartă logică programabilăși un timer programabil.

Ce reprezintă o poartă logică programabilă?

O poartă logică programabilă este un dispozitiv care poate fi programat, ce implementează poarta logică dorită de utilizator. Aceasta ar putea fi implementată cu un LUT sau utilizând direct porțile logice:

Pentru a se înțelege mai bine, se va exemplifica cu un LUT cu 2 intrări prezentat în figura următoare:

Figura 5.23: Exemplu de LUT cu 2 intrări

5.5.1. Metoda 1 de realizare a unei porți logice programabile

Se observă că LUT-ul din figura 5.23 implementează comportamentul unei porți logice XOR. Acest lucru este demonstrat în tabelul5.3. Aici sunt intrările și ieșirile corespunzătoare LUT-ului din figura 5.23, iar pe ultima coloană se găsește ieșirea porții logice XOR ce are la intrări IN0 și IN1[3].

Tabel 5.3: Ieșirea de la LUT și ieșirea unei porți XOR în funcție de IN1, IN0

Dacă designerul nu are la dispoziție un LUT, acesta poate să folosească un FDD4 și un MUX cu 4 intrări și 2 linii de selecție. Spre deosebire de varianta anterioară, această abordare are un mare avantaj că poate fi programată în timpul funcționării, lucru ce nu este valabil și pentru un LUT.

Figura 5.24: Alternativă la LUT

În această abordare, când CE = ‘1’, bistabilul copiază intrările, iar sel0 și sel1 selectează care din cele 4 ieșiri din bistabil vor fi trimise către ieșirea mux-ului. “Scriind” bistabilul cu valorile corespunzătoare, pot fi implementate porți logice cu 2 intrări. Astfel pentru implementarea porții logice AND cu 2 intrări se va proceda astfel: se scrie la intrarea în bistabil valoarea D3 D2 D1 D0 = “1000”, după care CE se setează. După acest moment, bistabilul a reținut valoarea “1000” care se va găsi și la ieșire. Cu ajutorul multiplexorului se va selecta care din cele 4 valori va fi trimisă către ieșire. În această abordare, sel0 și sel1 trebuie considerate ca fiind cele 2 intrări în poarta logică.

Astfel, utilizând o configurație de tip LUT, se pot implementa porți logice sau chiar structuri mai complexe, pe partea de electronică digitală.

5.5.2. Metoda 2 de realizare a unei porți logice reconfigurabile

O altă metodă de a implementa o poartă logică cu 2 intrări este utilizarea unui multiplexor, așa cum se poate observa în figura 5.24, exemplificând poarta logică programabilă cu două intrări ce poate implementa porțile logice AND, OR, NOR și XOR.

Utilizând sel0 și sel1 (pinii de selecție de la multiplexor), se poate alege care din cele 4 porți logice va fi validată. Aceasta este o abordare total diferită față de cea anterioară, motiv pentru care prezintă atât avantaje cât și dezavantaje. De asemenea, toată schema aceasta poate fi înlocuită cu un LUT cu 4 intrări, însa în această ultimă abordare vor exista probleme dacă se va dori înlocuirea uneia din acele porți logice din figura 5.24 cu un bistabil.

Figura 5.25: Metoda a 2-a de a “configura” o poartă logică

Avantajul principal al schemei din figura 5.25 este acela că se pot utiliza bistabili în locul porților logice fără a adăuga alte componente suplimentare, lucru realizat în proiect. Practic în locul porții logice XOR s-a utilizat un FDD. Acest lucru este util deoarece permite o abordare secvențială și dacă se dorește crearea unui automat secvențial acest lucru poate fi realizat fără probleme. Dacă s-ar utiliza o implementare de tip LUT, atunci pentru a adăuga bistabili ar trebui să se utilizeze un multiplexor, așa cum este realizată structura de tip CLB din figura 5.26. Acest lucru ar complica lucrurile și ar trebui o abordare cu totul diferită atunci când se dorește utilizarea unei porți logice sau al unui bistabil, lucru ce este mult mai simplu utilizând schema similară figurii 5.25.

Figura 5.26: Structura unui CLB

Dezavantaje: În această abordare, multiplexorul trebuie să aibă număr de intrări de date cel puțin la fel de multe cât numărul tipurilor de porți logice utilizat (dacă avem 6 porți logice, trebuie utilizat un mux cu cel puțin 6 linii de intrare, uzual fiind 8 linii de intrare deoarece multiplexoarele de regulă au număr de intrări egal cu putere a lui 2). Cu toate că metoda 1 nu oferă direct posibilitatea utilizării unui bistabil (acest lucru putând fi realizat prin utilizarea unui multiplexor așa cum este schema unui CLB – vezi figura 5.26), această metodă nu utilizează porți logice aici poarta logică fiind dată de conținutul LUT-ului.

5.5.3. Implementarea porții logice programabile

Pe lângă avantajele specificate mai sus, am preferat a 2-a variantă și pentru că aceasta este mai intuitivă. Codul VHDL ce implementează această componentă este următorul:

library IEEE; –librăriile utilizate

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_ARITH.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity config_gate is –definirea pinilor de I/O

Port ( Y : in STD_LOGIC_VECTOR (1 downto 0);

S : in STD_LOGIC_VECTOR (1 downto 0);

clk: in std_logic;

memorize: in std_logic;

Q : out STD_LOGIC);

end config_gate;

architecture Behavioral of config_gate is

signal and_q: std_logic:='0'; –definireasemnalelor din interiorul componentei

signal or_q: std_logic:='0';

signal nor_q: std_logic:='0';

signal FDD_Q: std_logic:='0';

signal gate_type: std_logic_vector(1 downto 0) := (others => '0');

begin

–descrierea comportamentului componentei

gate_type <= s when memorize = '1'; –memorarea tipului de poartă logică

and_q <= Y(0) and Y(1); –definirea porții logice AND

or_q <= Y(0) or Y(1); –definirea porții logiceOR

nor_q <= Y(0) nor Y(1); –definirea porții logice NOR

fdd_implement: process(clk) –definirea FDD

begin

if clk'event and clk = '1' then

–Y(1) este ca si CE pentru bistabil

if Y(1) = '1' then

FDD_Q <= Y(0);

end if;

end if;

end process;

Q <= and_q when gate_type = "00" else–realizarea ieșirii

or_q when gate_type = "01" else

nor_q when gate_type = "10" else

FDD_Q when gate_type = "11" else

'0';

end Behavioral; –sfârșitul definirii componentei

Se observă că la această componentă avem semnalele Y (magistrală formată din două semnale), S (tot magistrală formată din două semnale), clk, memorize și semnalul Q. Semnalul de tip magistrală, Y, reprezintă cele două intrări în poarta logică. Practic Y0 și Y1 reprezintă semnalele IN1 și respectiv IN2 ce se pot vedea în figura 5.25.

Semnalul S reprezintă semnalul de select și în funcție de acesta se va realiza programarea porții logice. Poarta logică ce va fi implementată este dat de tabelul următor:

Tabel 5.4: Porțile logice implementate în funcție de semnalul S

Semnalul clk reprezintă clock-ul sistemului. Aici acesta este de 65 MHz, frecvență necesară afișării cu rezoluția 1024×768.

Semnalul memorize reprezintă impulsul ce trebuie dat de utilizatorul componentei pentru a reține semnalul S și pentru ca această componentă să rețină poarta logică ce se dorește a fi implementată. Astfel, dacă utilizatorul dorește să implementeze poarta logică NOR, trebuie mai întâi să facă semnalul S = “10” (conform tabelului 5.4) după care va trebui să pună semnalul memorize pe 1 logic după care, după o scurtă perioadă de timp, semnalul memorize va fi trecut din nou în 0 logic. Aceștia sunt pașii ce trebuie urmați pentru a se realiza memorarea semnalului dat de utilizatorși implementarea porții logice dorite. După ce semnalul memorize esteîn 0 logic, semnalul S își poate schimba starea însă poarta logică va rămâne aceeași.

5.5.4. Implementarea temporizatorului (timerului)

Temporizatorul are o schemă mai simplă decât cea a porții logice programabile. Acest temporizator va da un impuls pe o perioadă a clockului de 65 MHz când expiră timpul contorizat. Acesta poate fi programat să contorizeze de la 1 la 128 de ms însă pentru a putea obține timpi mai mari, acestea se pot cascada. La cascadare, timpii se înmulțesc. Astfel la cascadarea a două temporizatoare se va putea obține un temporizator ce contorizează maxim 128×128 ms ceea ce înseamnă 4.096 secunde. Trebuie avut grijă că nu toți timpii pot fi obținuți datorită acestei înmulțiri. Acești timpi sunt dați de numerele prime ca de exemplu 131. Astfel, timpul de 131 de milisecunde nu poate fi obținut prin cascadare.

Pentru a putea implementa temporizatorul trebuie avut un counter (numărător) ce se incrementează la fiecare clock. Acest clock este un semnal de 1ms sau ieșirea unui alt numărător. De asemenea este necesară o memorie ce memorează timpul ce se dorește a fi contorizat dar și un comparator ce compară data din memoria respectivă cu data din comparator. Când acestea sunt egale atunci se va trimite un impuls de 1 logic la ieșire și se va reseta counterul. Schema se poate vedea în figura 5.27.

Figura 5.27: Schema temporizatorului

Blocul MEM din figura 5.25 implementează o memorie la care sunt conectate alte două semnale și anume delay_time și memorize. Pentru simplificarea schemei am omis aceste semnale. Ca și în cazul precedent, semnalul memorizeva fi utilizat pentru a reține în memorie un anumit semnal, doar că de această dată va fi semnalul delay_time ce va da timpul contorizat de temporizator.

Algoritmul configurabil realizat va avea posibilitatea de a conecta ieșirile tuturor porților logice și timerelor la intrările tuturor porților logice. Acest lucru este realizat cu ajutorul unui multiplexor și astfel fiecare intrare din fiecare poartă logică programabilă va avea la intrare ieșirea unui multiplexor. La pinii de intrare al acestui multiplexor sunt conectate ieșirile tuturor porților logice programabile și a tuturor timerelor. Schema bloc utilizând doar 2 porți logice și 2 intrări se poate vedea în figura 5.28. În această figură se vede cum fiecare intrare din fiecare poartă logică poate să fie ieșirea celeilalte porți logice sau poate sa fie una din cele 2 intrări în sistem, Input0 sau Input1.

Linia de selecție al fiecărui MUX este conectată la o memorie ce lipsește aici pentru simplificarea schemei. În cazul de față, linia de selecție al fiecăruia din cele 4 multiplexoare va fi o magistrală cu 2 fire, S0 și S1. În schema din figura 5.28, dacă dorim ca Output1 să fie Output0 OR Input1, atunci primul lucru care trebuie făcut este să fie scrisă poarta logică programabilă corespunzătoare, și anume Gate1, astfel încât să implementeze o poartă logică OR. Conform tabelului 5.4, memoria porții logice va trebui scrisă cu valoarea “01” pentru a implementa poarta logică dorită.

Figura 5.28: Schema bloc al algoritmului configurabil utilizând 2 porți logice.

În continuare pentru a realiza conexiunea dorită va trebui să programăm memoriile ce sunt conectate la liniile de selecție al celor două multiplexoare conectate la intrările porții logice. Astfel, pentru a avea la IN1 de la Gate1 semnalul ce vine de la poarta logică Gate0, va trebui ca multiplexorul corespunzător să aibă la linia de selecție valoarea “00”. Această valoare trebuie scrisă în memoria conectată la liniile de selecție al acestui multiplexor pentru a se realiza conexiunea așteptată.Mai departe trebuie scrisă și memoria multiplexorului conectat la cea de-a doua intrare de la Gate1. Ca la această intrare să fie conectat semnalul Input1, linia de selecție al acestui multiplexor trebuie scrisă cu valoarea “11” pentru a se realiza legătura. Astfel memoria conectată la linia de selecție al acestui multiplexor va fi scrisă cu valoarea “11”, și am realizat semnalul Output1 care este, așa cum ne-am propus de la început Output0 OR Input1.

Aici, trebuie avut în vedere că Output0 și Output1 este semnalul de ieșire de la porțile logice programabile Gate0 și respectiv Gate1. Acestea vor putea fi transmise afară, la ieșirea PLC-ului utilizând un număr de alte 8 multiplexoare ce sunt conectate direct la ieșire. Ca și în cazul multiplexoarelor conectate la intrările porților logice, și aceste multiplexoare vor avea conectate la liniile de selecție memorii ce vor decide ieșirea cărei porți logice programabile sau timer vor fi transmise către ieșirea PLC-ului.

În proiect vor exista 8 intrări în PLC, 8 ieșiri din PLC, iar PLC-ul va putea implementa 16 porți logice și 8 temporizatoare. Deoarece avem 8 intrări in PLC, 8 temporizatoare și 16 porți logice, trebuie să utilizăm multiplexoare cu 32 de intrări ce sunt utilizate la intrările porților logice. Trebuie specificat faptul că va fi utilizat încă un semnal care dă un impuls la fiecare milisecundă, pentru a putea implementa temporizatorul. Astfel ne trebuie 32 + 1= 33 de intrări în acele multiplexoare, deci vom utiliza multiplexoare de 64 de intrări, cu 6 linii de selecție si o singură ieșire.

Am preferat utilizarea unui multiplexor ce poate fi și el programat, deoarece este mai ușor ca fiecare componentă să aibă memoria în interiorul său decât în exterior. Acest lucru este realizat deoarece complexitatea componentei ce implementează algoritmul configurabil nu va fi foarte mare datorită eliminării acestor memorii.

Un multiplexor programabil utilizează un multiplexor și o memorie. Acesta are următoarea schemă:

Figura 5.29: Schema multiplexorului programabil unde memoria

reține semnalele de selecție.

Entitatea acestei componente este următoarea:

entitymux_memory is

Port ( memorize : in STD_LOGIC;

Y : in STD_LOGIC_VECTOR (32 downto 0);

S : in STD_LOGIC_VECTOR (5 downto 0);

Q : out STD_LOGIC);

endmux_memory;

Aici se pot vedea semnalele de intrare și ieșire dar și lungimea acestora. Semnalul memorize are același comportament ca și în cazurile precedente, iar în memorie se va reține semnalul S. Semnalul de ieșire, Q, este dat de unul din semnalele Y dat de numărul reprezentat de semnalul S. Astfel dacă semnalul S este “00001”, Q va avea valoarea semnalului Y(1), dacă S este “00010”, Q va avea valoarea semnalului Y(2), și așa mai departe.

Entitatea circuitului configurabil este următoarea:

entityconfig_algis

Port ( inputs : in STD_LOGIC_VECTOR (7 downto 0);

clk : in std_logic;

gate_memorize: in STD_LOGIC_VECTOR (5 downto 0);

gate_type: in std_logic_vector(1 downto 0);

mux_paths_mem: in std_logic_vector(6 downto 0);

mux_paths_sel: in std_logic_vector(5 downto 0);

TMP_delay: in std_logic_vector(7 downto 0);

clk_1ms: in std_logic;

outs: out std_logic_vector(7 downto 0));

endconfig_alg;

Vor fi descrise toate semnalele în amănunt pentru a nu exista confuzii cu privire la utilizarea acesteia:

inputs reprezintă intrarea globală, adică semnalele de intrare în PLC.

clk este semnalul de clock de 65 MHz utilizat la componenta VGA

gate_memorizereprezintă numărul porții ce va fi memorată. Aici sunt incluse porțile logice programabile a cărui număr le corespunde valoarea începând de la 17 și până la 32, dar și temporizatorilor corespunzând numerele începând de la 9 și până la 16.

gate_type reprezintă tipul porții logice care va dori userul să fie implementat de către poarta logică corespunzătoare.

mux_path_mem este semnalul de memorare ce este transmis către multiplexoarele programabile

mux_path_sel este semnalul care este conectat la semnalele de selecție de la toate multiplexoarele

TMP_delayeste semnalul ce va fi reținut de memoria temporizatorului pentru a implementa temporizarea respectivă.

clk_1ms este semnalul de clock ce vine la fiecare milisecundă.

5.6. Rezultate experimentale

Am reușit dezvoltarea proiectului propus utilizând VHDL ca și limbaj de descriere hardware, Eagle pentru dezvoltarea plăcii electronice, Visual Basic Script pentru dezvoltarea scriptului ce realizează comunicația și Notepad sau Notepad++ ca și editor de text pentru descrierea comportamentului PLC-ului implementat.

PLC-ul conține:

8 intrări, fiecare fiind conectată în acest proiect la câte un switch

8 ieșiri, fiecare dintre ele fiind conectată la câte un led

8 temporizatoare pe 8 biți

16 porți logice programabile

T1ms – semnal ce dă un impuls la fiecare milisecundă

O mufă VGA cu ajutorul căruia se va face afișarea semnalelor de ieșire din PLC pe un monitor, aici fiind implementat un analizor logic.

În figura 5.30 se poate vedea codul corespunzător fișierului plc.txt ce comandă PCL-ul să avem la ieșirea 0 și 1 leduri ce se aprind alternativ cu o perioadă de 200 ms:

Figura 5.30: Codul utilizat pentru comanda alternativă a 2 leduri

În figura 5.30 există 5 linii ce conțin comenzi transmise către FPGA. Liniile goale vor fi ignorate. Vor fi descrise fiecare dintre acestea pentru a demonstra că are comportamentul descris:

în prima linie este descrisă poarta logică gate0 ce va fi utilizată pe post de FDD, și are ca intrare semnalul de ieșire din gate1 și ca semnal de clock enable semnalul ce vine de la temporizatorul tmr0.

a doua linie utilizează poarta logică gate1 pe post de NOR ce are conectat în ambele intrări semnalul venit de la ieșirea porții logice gate0.

în a 3-a linie este utilizat temporizatorul tmr0 ce are ca impuls de numărare semnalul de o milisecundă dat de T1ms, acest temporizator numărând până la 99, deci va număra 100 de milisecunde.

în a 4-a linie se transmite semnalul de ieșire de la poarta logica gate0 către ieșirea out0 la care este conectat ledul 0.

în a 5-a linie se transmite semnalul de ieșire de la poarta logica gate1 către ieșirea out1 la care este conectat ledul 1.

Această descriere este echivalentă cu implementarea următoarei scheme:

Figura 5.31: Schema echivalentă implementată de PLC în urma

transmiterii codului din figura 5.28

Aici se utilizează poarta logică NOR ca și inversor, conectând cele două intrări între ele.

În urma cercetării, a fost realizat proiectul ce a fost propus de la bun început, și anume PLC în FPGA utilizând VHDL și VBScript

Bibliografie

[1]W. Bolton, “Programmable Logic Controllers”, Fifth Edition, Newnes, Chapter 1

[2]Xilinx Inc., “MicroBlaze Processor Reference Guide”, V9.0, core reference UG081, 2008

[3]Basic FPGA Architecture (Virtex-6): http://www.xilinx.com/training/downloads virtex-6-slice-and-io-resources.pptx

[4] ISE 10.1 Quick Start Tutorial, 2008

[5]Digilent Inc., “Xilinx ® ISE Simulator (ISim) VHDL Test Bench Tutorial”, February 27, 2010

[6] Xilinx Inc.,” iMPACT User Guide”, V4.1, 2008

[7] Eagle Inc., “Tutorial Version 7”, 2nd Edition, 2014

[8] George Mason University, “ECE 448 – FPGA and ASIC Design with VHDL”,

Similar Posts