HTML

Műszer

Hobby és amatőr elektronika, műszerépítés a XXI. században

Címkék

Friss topikok

  • Nite: @fromi: Ha egy bejegyzéssel kapcsolatos kérdésed van, akkor jobb odaírni kommentbe, mert esetleg m... (2010.11.26. 15:17) FAQ

Licenc

Creative Commons Licenc

VHDL gyorstalpaló

Nite 2010.02.22. 10:00

 Emlékszem annak idején, még a 90-es években összeraktam egy dobókocka emulátort, csupa-csupa diszkrét logikai IC-ből. Akkoriban jó poénnak tűnt, és esélyem sem volt (nem hogy pénzem) bármiféle PIC vagy egyéb processzor beszerzésére. Azóta az idők megváltoztak, manapság már biztosan PIC-el építeném, még egy USB portot is tennék rá, hogy egyszerűen lehessen tuningolni az egyes számok dobásának esélyeit :)

 Vannak persze ebben is, mint a diszkrét elemekből épülő DDS-ben olyan feladatok, amiknél az ember elgondolkozik, hogy érdemes-e erre egy akkora tudású processzort berakni, csak azért, hogy unatkozzon. Egy számláló meg két logikai kapu kedvéért PIC-et használni túlzásnak tűnik, de ha azt mondom hogy ennek 100MHz-n kell működnie, akkor ráadásul már elég drága processzor kell, ami ezt elbírja. Viszont ha kicsit bonyolódik a logika, diszkrét elemekből megépítve sok alkatrész fog kelleni, és ronda lesz a NYÁK, ami magával hozza a szórt kapacitásokat, induktivitásokat, gerjedést és rossz határfrekvenciát.

 Szerencsére a feladatra kitalálták már a megfelelő célszerszámot, ami ebben az esetben a CPLD (vagy FPGA). Nézzük, milyen előnyei vannak neki:

-  Sok diszkrét logikai elem helyettesíthető egy alkatrésszel

- A lábai általában szabadon programozhatóak a funkciókhoz, így szép (= gyors) NYÁK tervezhető neki

- Bármikor újraprogramozható, így a funkcionalitás frissíthető vagy javítható

 Többet most nem sorolnék fel. Kedvenc CPLD gyártóm jelenleg a Xilinx, mivel széles termékpalettával dolgoznak, a fejlsztő eszközeik ingyenesek, és alkatrészeik könnyen beszerezhetőek a Chipcad-nél. Ha nem akarunk FPGA-kkal foglalkozni, mert a feladat annyira nem bonyolult, nyugodtan használhatjuk például az XC9500 sorozatukból valamelyik CPLD-t. 

 Ha vetünk egy pillantást a család adatlapjára, gyorsan megérthetjük a felépítését egy CPLD-nek: külön vannak választva az IO-blokkok, amik a lábakhoz kapcsolódnak, és a logikát megvalósító Function Block-ok (bocs ezeket nem fordítom le), ezeket egy kapcsoló mátrixal lehet összerendelni. A Function Block áll a Product Term Allocator-ból, ami nagyrészt a logika megvalósításáért felelős, és a Macrocell-ből, ami legfontosabb eleme egy flip-flop, amivel regisztereket lehet megvalósítani. Én a működésébe körülbelül itt hülyültem bele, szerencsére ennél sokkal többet nem is kell tudni arról, hogy mi van benne.

 Az egész cucc JTAG interfészen programozható (és tesztelhető), ehhez a Xilinx van olyan kedves és biztosít dokumentációt, melyben az Appendix B-ben található egy párhuzamos portra készült JTAG kábel kapcsolási rajza is. Ezt könnyen megépíthetjük, működik, szinte a legbonyolultabb dolog olyan PC-t találni amin van még párhuzamos port.

 Nyilván nem fogjuk tudni fejben megírni azt a kódot, amit a JTAG-on le kell tölteni, erre a feladatra adja a Xilinx az ISE fejlesztőeszközét. Már csak azt kellene kitalálnunk, hogy milyen nyelven lehet leírni egy ilyen célhardvert, mint pl a counter vagy a logikai kapuk - és itt érkeztünk el a VHDL-hez.

 A VHDL-t eredetileg azért fejlesztették ki, hogy logikai elemek viselkedését leírják vele, és eleinte tesztelésre használták annak vizsgálatára, hogy a szállított elem megfelel-e a követelményeknek. Később szintézis eszközöket készítettek, hogy ugyanebből a nyelvből létre lehessen hozni magát az alkatrészt. A VHDL-ről érdemes elolvasni az angol wiki-t, amiből viszonylag könnyű az alapokat ellesni, még példakódok is találhatóak benne. Ha valakinek nem szimpatikus a VHDL, programozhat Verilog-ban is, én per pillanat csak a teszteket írtam ebben. Az ISE Webpack fejlesztőeszköz egy elég jó varázslóval rendelkezik a VHDL forrásokhoz, be kell vinnünk neki, hogy a logikánknak milyen bemenetei illetve kimenetei vannak, és ebből a fájl egy részét legenerálja nekünk. A címben említett gyorstalpalás kedvéért fussunk végig egy VHDL-ben megvalósított számláló kódján. A példakódot innen le lehet tölteni.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

 Valahogy így kezdődik a kód, ez nekünk nem annyira lényeges, a VHDL nem kezel gyárilag olyan kimeneteket/bemeneteket, amikkel a CPLD-nk rendelkezik (pl. 3-state), így ezeket a library-ket hozzá kell adni a kódhoz a use utasítással.

entity Counter is
   Port ( Reset : in STD_LOGIC;
      Clock : in STD_LOGIC;
      ClkDivEn : in STD_LOGIC;
      ClkDivRng : in STD_LOGIC;
      Address : out STD_LOGIC_VECTOR (7 downto 0));
end Counter;

 Itt definialtuk az alkatrészünk bemeneteit és kimeneteit. Lesz rajta egy órajel bemenet (Clock), nyolc kimenet, ahol binárisan számol (Address), egy Reset, és hogy valami logika is legyen benne, a számláló frekvenciaosztását szabályozhatjuk a ClkDivEn-el, ami ha nulla, akkor nem osztunk frekvenciát, ha egy, akkor osztunk. Ha a ClkDivRng 0, akkor öttel osztjuk, ha 1, akkor tízzel.

architecture Behavioral of Counter is

signal Divider : integer range 0 to 10;
signal DividerClk: STD_LOGIC;
signal DividedClk : STD_LOGIC;
signal AddrCntr: integer range 0 to 255;

begin

 Egy alkatrészünk állhat több architecture-ból, a mi counterünkben csak egy van, ezt elnevezte nekünk az ISE Behavioral-nak. Még a begin előtt definiálhatunk olyan belső segéd jeleket (signal), amiket egy-az-egyben nem kötünk bemenetre vagy kimenetre, de a leíráshoz szükség van rájuk. Ugyan az Address kimenet típusa STD_LOGIC_VECTOR, én az AddrCntr signal-t integer-nek vettem, mégiscsak egy számot ábrázol.

 Ezután elkezdjük kitölteni az architecture-t az alkatrészünk viselkedését leíró kóddal.

process (Clock, ClkDivEn, ClkDivRng, Reset, DividerClk, Divider)

 A process blokkok írják le, hogy egyes bemenetek függvényében minek kell történnie. A zárójelben fel van sorolva az összes olyan bemenet (vagy signal), amit ez a process blokk feldolgoz.

if (Clock'event ) then 
if (Clock'event and Clock='1') then
if rising_edge(Clock) then

 Ezek a feltételek a Clock lábat vizsgálják. Az első esetben minden esemény érdekel minket, ami a Clock lábon történik, legyen az felfutó vagy lefutó él. A többi eset csak felfutó élre csinál valamit.

if (Reset = '1') then
    DividerClk <= '0';
    Divider <= 0;

 Szóval, ha valami változik a Clock-on, megvizsgáljuk a Reset-et. Ha ez 1, akkor reseteljük a számlálókat.

else
   if (ClkDivRng = '0') then
       if (Divider = 5) then
           Divider <= 0;
           DividerClk <= not DividerClk;
       else
           Divider <= Divider + 1;
       end if;
   else
       if (Divider = 10) then
           Divider <= 0;
           DividerClk <= not DividerClk;
       else
           Divider <= Divider + 1;
       end if;  
   end if; 
end if;

 Ez a rész tulajdonképpen az órajel frekvenciaosztását végzi, akkor ha a Reset nem 1. Ahogy már írtam, ha a ClkDivRng 0, öttel oszt, egyébként tízzel. Az osztáshoz számlálóként a Divider-t használjuk, a leosztott órajel a belső DividerClk signal-on jelenik meg.

process (Clock, ClkDivEn, DividerClk, DividedClk)
begin

   if (ClkDivEn = '0') then
       DividedClk <= Clock;
   else
       DividedClk <= DividerClk;
   end if;

end process;

 Ez a process blokk vizsgálja a ClkDivEn jelet, és ettől függően állapítja meg a számláló belső órajelét, a DividedClk-t. Ha az osztás engedélyezett, akkor a leosztott DividerClk jelenik itt meg, egyébként az eredeti Clock jel.

process (AddrCntr, DividedClk, Reset)
begin
   if (DividedClk'event and DividedClk='1') then
       if (Reset = '1') then
           AddrCntr <= 0;
       else
           AddrCntr <= AddrCntr + 1;
       end if;
       Address <= conv_std_logic_vector(AddrCntr, 8);
   end if;
end process;

 Ez a process végzi tulajdonképpen a számlálást. A DividedClk órajelet figyeli, és számolja. Itt ami érdekes, az az integer átalakítása STD_LOGIC_VECTOR-rá.

 Ha ezt a vhdl fájlt betöltjük a Xilinx ISE fejlesztőeszközbe, egy gyors fordítás után már tölthetjük is le egy JTAG madzaggal a CPLD-nkbe. Ha nehezen hisszük el, hogy működik, az ISE képes letesztelni is emulátorban. Ezt nekem valamiért egy Verilog Test Fixture nevű cuccal sikerült kiviteleznem, úgyhogy az alábbiak a Verilog szépségeit mutatják be. Egyébként teszteléshez jeleket egész egyszerű ezzel a nyelvvel leírni:

module CounterTest;

// Inputs
reg Reset;
reg Clock;
reg ClkDivEn;
reg ClkDivRng;

// Outputs
wire [7:0] Address;

// Instantiate the Unit Under Test (UUT)
Counter uut (
.Reset(Reset),
.Clock(Clock),
.ClkDivEn(ClkDivEn),
.ClkDivRng(ClkDivRng),
.Address(Address)
);
Ezt a részt az ISE generálja nekünk, nagyon nem érdemes vele foglalkozni.

initial begin
  // Initialize Inputs
  Reset = 0;
  Clock = 0;
  ClkDivEn = 0;
  ClkDivRng = 0;

  #100 Reset = 1;
       
  #200 Reset = 0;
  
  #500 ClkDivEn = 1;
  
  #700 ClkDivRng = 1;
end
 Az initial részbe írhatjuk azokat az eseményeket, amik a teszt elindítása után egy meghatározott pillanatban történnek. Először is a bemenetek megkapják a kezdeti értéküket, utána a # után írt számú nanoszekundum eltelte után következik a következő esemény. Jelen esetben 100 ns után a Reset 1 lesz, majd 200 ns-al az indulás után ismét 0. 500 ns-nál a ClkDivEn-t engedélyezzük, 700 ns-nál pedig a range-t 10-es osztásra állítjuk.

 always
  #5 Clock = ~Clock; // every ten nanoseconds invert  
 Az always részbe leírt dolgok folyamatosan történnek. Itt fent azt láthatjuk, hogy a Clock minden ötödik nanoszekundumban invertálódik (a kommentet nem írtam át, bocs), ezzel egy 100MHz-es órajelet adva.

 Ezt a tesztet lefuttatva ellenőrizhetjük a CPLD-nk működését.

 Ennyi fért a gyorstalpalóba, remélem tudtam segíteni elindulni. Nyilván azért is van sikere a VHDL nyelvnek a CPLD/FPGA-k leírásában, mert a nyelv alapjait viszonylag könnyű megtanulni, és egyszerű modelleket gyorsan össze lehet benne hajigálni. Abba azért belegondolni is rossz, hogy ezekkel a nyelvekkel konkrétan processzorok működését is le lehet írni, ehhez már valószínüleg nem lesz elég az alap tudás. Ez is egy szakma, amit teljesen elsajátítani évek alatt lehet - viszont hobby szinten pár nap is elég.

 

Címkék: fpga cpld vhdl

Szólj hozzá!

A bejegyzés trackback címe:

https://muszer.blog.hu/api/trackback/id/tr361780238

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása