- Úvod do PLD a jazyka VHDL
- Základní konstrukce ve VHDL
- CPLD a první aplikace
V předchozím článku jsem lehce nastínil co to jsou PLD a stručně představil jazyk VHDL, který se používá k popisu hardware v těchto obvodech. V tomto pokračování se podíváme na první aplikaci s obvodem CPLD XC9572XL. Tento obvod je velmi malý, takže nečekejte žádné zázraky, ale na druhou stranu je vhodný (hlavně cenou) pro začátečníky.
CPLD s kterým budeme pracovat je XC9572XL. Je od firmy Xilinx, obsahuje 72 makrobuněk a je na svých vstupech tolerantní na 5 V logiku (i přes to, že zařízení samotné pracuje na 3,3 V).
K práci budeme potřebovat obvod samotný. Vyrábí se v několika pouzdrech, já jsem zvolil pouzdro PLCC44. Dále bude potřeba vývojové prostředí ISE Webpack, které lze stáhnout zdarma (ovšem je nutná registrace). V současné době je Webpack ve verzi 14.1 pro Windows a Linux. Já zatím používám starší verzi 13.4 pro Windows. A samozřejmě JTAG programátor (já mám USB Platform Cable od Xilinx, dá se sehnat na eBay do 1000 Kč), zdroj hodin (třeba NE555 jako astabilní KO) a jednu LED s vhodným rezistorem.
Vývojové prostředí nainstalováno, CPLD (v patici) s nepájivým polem a 3,3V zdroj na stole — můžeme začít. Naším cílem bude vytvořit obvod, který po zapojení hodinového signálu začne blikat LED.
Založení projektu
Po zapnutí aplikace ISE Webpack musíme založit nový projekt. Zvolte jeho umístění a název. Jelikož chceme blikat LEDkou, zvolil jsem název blink. Ještě se ujistěte, že Top-level source type je HDL a zvolte Next.
Následuje jedna ze složitějších nabídek. Zde je potřeba zvolit kategorii General Purpose (tahle volba zapne/vypne nějaké optimalizace, vpodstatě pro nás zatím nemá význam), rodinu obvodů — XC9500XL CPLDs a poté konkrétní obvod — XC9572XL. Vyberte typ pouzdra PC44 a rychlost obvodu — já mám −10. Ještě ověřte, že Preferred Language je nastaven na VHDL.
Následuje okno Project Summary, kde si ještě můžeme naposledy zkontrolovat všechna nastavení a pak zbývá kliknout na Finish. Objeví se okno vývojového prostředí.
V tomto okamžiku můžeme začít přidávat nové soubory se zdrojovým kódem. Chceme vytvořit LED blikač. K tomu budeme potřebovat jeden 8b čítač. Ten bude řízen hodinovým signálem a jakmile dojde k přetečení, výstup čítače se překlopí. Tento výstup pak přímo napojíme na výstupní pin a tím pádem i na LED. Založíme tedy VHDL soubor s názvem counter.vhd.
Pravým tlačítkem klikněte na xc9572XL-10PC44, která je vlevo nahoře a zvolte položku Add New Source.
Teď musíme vypsat všechny vstupy a výstupy našeho čítače. Budeme potřebovat jeden vstup pro hodinový signál a jeden výstup, který se bude překlápět při každém přetečení. Já jsem ještě přidal vstup clk_en, který v logické jedničce spustí čítač a v logické zase čítání zastaví.
V tomto okamžiku se předvygeneroval soubor s názvem counter, který obsahuje některé základní konstrukce VHDL jazyka. Teď máme vše přichystáno pro samotný zdrojový kód.
Zdrojový kód
Zdrojový kód čítače může vypadat třeba takto:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity counter is Port ( clk : in std_logic; -- Hodinový signál. clk_en : in std_logic; -- Zastavení čítače v logické nule. ovf : out std_logic -- výstup, přetečení ); end counter; architecture Behavioral of counter is signal overflow: std_logic := '0'; -- V této proměnné se bude ukládat čítané číslo. signal number: std_logic_vector(7 downto 0) := (others => '0'); begin process(clk) begin -- Budeme reagovat na náběžnou hranu hodinového signálu if rising_edge(clk) then -- A budeme čítat pouze když clk_en = 1 if clk_en = '1' then number <= number + '1'; -- jakmile načítáme hodnotu 0xFE, překlopíme výstup. if number = X"FE" then overflow <= not overflow; end if; end if; end if; end process; -- Spoj vnitřní proměnnou 'overflow' s výstupem 'ovf'. ovf <= overflow; end Behavioral;
Pokud jste již někdy programovali, bude vám tento kód okamžitě jasný. Programování PLD má však některé odlišnosti od obyčejného programování. Na pořadí jednotlivých řádků nezáleží, všechno mimo blok process
se vykonává paralelně. Výjimkou je pouze blok process
, který se vykonává sekvenčně od shora dolů. Tohle je nutné si zapamatovat a počítat s tím. Z tohoto pravidla totiž vyplývá, že podobná konstrukce nelze zkompilovat:
ovf <= '1'; ovf <= '0';
Překladač by totiž vytvořil zapojení, ve kterém by zkratoval napájení se zemí, což není žádané.
Také je nutné si uvědomit, že tyto dvě konstrukce jsou funkčně identické:
-- 1 C <= A + B; Z <= C; -- 2 Z <= C; C <= A + B;
Další věc, co je potřeba znát: proměnné typu std_logic
a std_logic_vector
mohou nabývat logické ‚1‘ a ‚0‘ nebo ‚L‘ a ‚H‘, ale také vysoké impedance ‚Z‘, mohou být nedefinované ‚X‘ nebo ‚U‘, anebo můžeme překladači naznačit, že je nám jedno, jakou budou mít hodnotu ‚-‚.
Tím jsme napsali kód pro čítač. Teď musíme vytvořit jeho instanci a přiřadit jeho vstupy a výstupy reálným pinům. Stejným postupem jako před chvílí založte nový soubor s názvem main, který bude mít vstup clk
a výstup led
. Jeho obsah bude:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity main is Port ( clk : in STD_LOGIC; led : out STD_LOGIC ); end main; architecture Behavioral of main is -- Definice našeho čítače. component counter is Port ( clk : in std_logic; clk_en : in std_logic; ovf : out std_logic ); end component; begin -- Instance čítače se bude nazývat cnt1. cnt1: counter port map ( clk => clk, clk_en => '1', -- Zatím přiřadíme clk_en log. jedničku. ovf => led ); end Behavioral;
Mezi klíčová slova begin
a architecture
je potřeba vložit definici našeho čítače. Tu zkopírujte ze zdrojového kódu v counter.vhd, pouze změňte klíčové slovo z entity
na component
. Pokud se vám toto kopírování a zbytečné opakování zdá hloupé, pak vězte že žádné jiné rozumné řešení není. Nic jako include
nelze v tomto případě použít. Vítejte ve světě VHDL :)
Signál clk_en
zatím nepoužijeme, a proto jej nastavíme na log. jedničku. Není ale problém jej v budoucnu přiřadit nějakému vstupnímu pinu a zastavovat tak blikání nějakým přepínačem.
Ještě před samotnou kompilací musíme vytvořit jeden soubor. Tentokrát se ale nebude jednat o VHDL Module, ale o User Constrains File s názvem pins. Tento soubor mapuje signály v kódu na reálné piny obvodu. My použijeme pouze dva:
# Hodinový signál NET "clk" BUFG = "CLK" | LOC = "P5"; # Výstup na LED NET "led" LOC = "P1";
Signál clk
bude na pinu číslo 5 a přiřadíme jej ke globálnímu signálu CLK
. Co to znamená? V předchozím článku jsem ukázal blokové schéma jedné makrobuňky. Tam si můžete všimnout několika globálních signálů (hodiny a set/reset), které jsou přivedeny na všechny makrobuňky. Jelikož je hodinový signál většinou potřeba v celé struktuře, přiřadíme jej k jednomu z těchto signálů a tím se zajistí, aby překladač optimalizoval výsledný hardware. Stejným způsobem můžeme použít globální signál pro reset, nebo pro další hodinové signály. Pin číslo 1 bude výstupní a připojíme k němu LED.
Jakmile máme hotovo, můžeme projekt přeložit. V levém okně, tam kde jsou vidět všechny naše zdrojové soubory, klikněte na soubor main. Pod tímto oknem je nabídka akcí, které jsou s tímto souborem možné. Jelikož je main tzv. top level source, je k němu přístupná akce Implement Design. Tu rozklikněte a dvakrát poklepejte na volbu Generate Programming File. V tom okamžiku se začne projekt kompilovat.
Pokud jste nikde neudělali chybu, měl by se vám na konci zobrazit CPLD Report stejný jako na obrázku níže.
Zde si můžeme všimnout, že náš projekt zabral 9 makrobuňek a z toho 8 P-termů. Pokud si připomenete tabulku z minulého článku, pak je tento výsledek očekávaný. Projekt obsahuje jeden 8b čítač a jeden 8b registr. Čítač zabere 1 P-term na jeden bit, což jsou 2 makrobuňky. Zbytek makrobuňek zabere registr a kombinační logika kolem. Je to přesně jak jsem psal – sekvenční logika je v CPLD obvodech dosti neefektivní a zabere spoustu místa.
V tomto okamžiku můžeme naprogramovat samotný obvod. To uděláme pomocí JTAG programátoru. Nejdříve ale zapojte obvod. Na obrázku níže je vidět funkce jednotlivých pinů obvodu při pohledu na pouzdro shora. JTAG programátor připojte k pinům TDI
, TDO
, TMS
a TCK
. Napájení 3,3 V připojte k oběma Vccio
, Vaux
a Vcc
. Nakonec, LED připojte k pinu IO1
a hodiny zapojte k IO5
. Frekvenci hodin jsem zvolil cca 500Hz (500Hz = 2ms na periodu, máme 8b čítač, to je 256 stavů což dává přibližně 0.5s).
Jakmile máme zapojeno, ve stejné nabídce jako je Generate Programing File najdete i Configure Target Device. Klikněte na něj a otevře se okno určené pro práci s JTAGem. Pokud máte JTAG programátor, který umí spolupracovat s Xilinx Webpackem (například USB Platform Cable II nebo Pralalel Cable), můžete obvod naprogramovat rovnou z této aplikace. Pokud máte programátor, který s tímto vývojovým prostředím nespolupracuje, budete muset vygenerovat SVF nebo XSVF (to je případ programátoru Asix Presto).
V prvním případě (programátor kompatibilní s Webpackem) klikněte na Boundary Scan, v prázdném okně pravým tlačítkem vyvolejte menu a zvolte Initialize Chain. Pokud je vše v pořádku, měl by se nalézt programátor a detekovat připojené zařízení XC9572XL. Potvrďte nabídku, která se objeví a vyberte zkompilovaný soubor main.jed v adresáři s projektem. Poté již stačí kliknout na Program. Po skončení byste měli vidět blikající LEDku. Naše první aplikace s CPLD je hotová a funkční!
V tomto okamžiku můžete začít experimentovat. Zkuste zprovoznit clk_en, blikejte více LED, změňte šířku čítače, fantasii se meze nekladou.
Závěr
Naše první aplikace je hotová. Doufám, že jsem neodradil velkým množstvím informací. Bohužel, Webpack je dost složitá aplikace, která není zrovna uživatelsky přívětivá. Množství bugů, které obsahuje také práci zrovna neulehčuje. Je potřeba se nenechat odradit težkým začátkem.
V dalších článcích bych chtěl popsat jak na simulace, což se hodí v případě větších projektů, kde je téměř nemožné ladit chyby na reálném hardware. Také bych chtěl více popsat jazyk VHDL a nejčastější konstrukce.
Zrovna pracuji na vývojové desce s obvodem XC9572XL. Návrh už mám hotový, zrovna čekám na výrobu DPS. Jakmile budu mít hotovo a odladěno, napíšu o tom článek.