česky english Vítejte, dnes je čtvrtek 28. březen 2024

Vývoj aplikací s moduly SQM4: Začínáme s Xilinx Zynq – 4. díl

DPS 2/2016 | Články
Autor: Michal Hanák

V minulých dílech jsme se věnovali popisu platformy Zynq®-7000 Xilinx® All Programmable SoC, která kombinuje procesorové jádro Cortex-A9 s výkonnou programovatelnou logikou na jednom čipu. Také jsme vás seznámili s modulem SQM4-ZY7, díky kterému je možné tuto unikátní technologii použít v menších prototypových řešeních i v hobby projektech, aniž by bylo nutné investovat čas a peníze do návrhu složitých schémat a desek plošných spojů. Čtenáře jsme seznámili i s vývojovými nástroji Vivado a s jazykem Verilog, vhodným pro návrh a syntézu logických obvodů.

Zopakujeme také cíl celého našeho seriálu, kterým je návrh jednoduché aplikace pro modul SQM4-ZY7 s obvodem XCZ7020 a desku SQM4-EasyBoard, vhodnou pro testování všech typů modulů řady SQM4. Procesorová část aplikace bude komunikovat s uživatelem pomocí sériové konzole a periferní obvod syntetizovaný v části programovatelné logiky zajistí generování správných signálů pro displej tak, aby se na něm promítl šachovnicový vzor ve zvolené barvě.

Řadič displeje

Z nedostatku fantazie nazveme periferii prostě „Simple Display“, zkrácené projektové jméno bude například „sdisp“. Pro návrh obvodu je vhodné v systému Vivado založit zcela nový projekt a v něm provést návrh i testování modulu odděleně od hlavního projektu aplikace, který jsme založili v minulém dílu a ve kterém jsme již vytvořili blokový návrh (BD) procesorového systému. V dnešním článku již nebudeme popisovat práci s Vivadem příliš detailně, zaměříme se raději na zdrojový kód a principy návrhu v jazyce Verilog. Výsledek celé práce, hotové projektové i zdrojové soubory jsou již dnes k dispozici na stránkách www.sqm4.com.

Aby byl řadič kompatibilní se sběrnicí AXI a aby bylo možné jej spojit s hlavním procesorovým systémem, je v deklaraci modulu Verilog nutné přidat k výstupům řízení displeje (LCD), které nás zajímají především, i poměrně velkou skupinu tzv. „Slave-AXI“ (S_AXI) signálů. Do obrázku č.1 se nám vešla jen část celé deklarace. Celkem je ve zjednodušené verzi (tzv. „AXI-Lite“) až 19 vstupních a výstupních signálů. V plné verzi S_AXI, s dodatečnou podporou vysokorychlostních „burst“ a „cache“ režimů, je těchto signálů dokonce více než 40.

1

V deklaraci modulu můžete také vidět použití tzv. pre-procesorových direktiv a maker jazyka Verilog. Jsou velmi podobné direktivám běžného C kompilátoru, jen místo speciálního znaku ‚#‘ je použit poměrně exotický znak zpětného apostrofu. Stejně jako v C se konstanty definují direktivou `define a používají se pro parametrizaci kódu během kompilace nebo k podmíněné kompilaci. I ve Verilogu se typicky pojmenovávají velkými písmeny, aby je bylo možné odlišit od symbolů použitých pro signály a registry. Konstanty mohou být definovány v tzv. header souborech s příponou .vh, které je možné do zdrojového kódu vložit direktivou `include. Na rozdíl od C je speciální znak zpětného apostrofu nutno uvést i u každé konstanty použité v kódu.

Konstanty použité během kompilace mohou mít ve Verilogu ještě jednu podobu. V našem kódu není tento způsob použit, ale v knihovních prvcích Xilinx je jejich využití opravdu extrémní. Jména konstant, nebo zde lépe použít slovo ‚parametrů‘, mohou být uvedena přímo v deklaraci modulu spolu s výchozími hodnotami. Libovolný parametr je pak možné změnit u každé instance modulu. Jednotlivé instance modulů, a to dokonce i stejných typů, jsou totiž ve Verilogu kompilovány zvlášť – podobně jako tzv. inline funkce v C. Různé instance stejného modulu mohou tedy být nastaveny různě. Jsou-li takto parametrizovatelné instance modulů použity v blokovém schématu (BD), nabízí dokonce Vivado možnost měnit parametry pohodlně přímo v grafickém prostředí.

Dekódování signálů AXI je poměrně snadné, alespoň tedy co se týká zjednodušené „AXI-Lite“ varianty. Nové verze nástrojů Vivado disponují i grafickým průvodcem, který dokonce obslužný kód pro implementaci Slave-AXI a periferních registrů generuje automaticky. Pro účely naší aplikace jsme vytvořili jednoduchý dekodér vlastními silami. Rozebírat kód dekodéru do detailů by nebylo příliš zábavné, proto se podíváme na jeho použití přímo v modulu grafického řadiče.

Dekodér S_AXI redukuje zpracování AXI na velmi jednoduché řízení dvěma signály reg_write a reg_read, téměř jako kdyby se jednalo o klasickou mikroprocesorovou sběrnici. Tyto signály indikují požadavek na čtení nebo zápis registru identifikovaného signálem reg_index. Stejně jako celá AXI sběrnice jsou i dekódované signály plně synchronní a jsou platné vždy s nástupnou hranou S_AXI_ _ACLK.

2,3

Čtyři periferní registry řadiče jsme si navrhli už v minulém dílu: CTRL, HSYNC, VSYNC a BKGND. V kódu řadiče jsme se rozhodli zavést jednoduchou konvenci, kdy všechny interní signály související s periferními registry označíme malými písmeny a předponou ‚r_‘. Máme tedy čtyři 32bitové registry r_ctrl, r_hsync, r_vsync a r_bkgnd. Pátým periferním registrem je stavový r_status, jehož prostřednictvím lze číst různé vnitřní stavy logiky řadiče. Obrázky 2 a 3 ukazují velmi jednoduchý kód, který registry připojí k S_AXI dekodéru pro čtení i zápis.

4

Jak je v mikroprocesorovém světě běžné, periferní registry sdružují řídicí bity a skupiny bitů s různým významem. Ve Verilogu je velmi vhodné definovat si pro každou takovou skupinu vlastní symbol. Díky pre-procesorovým konstantám je pak rozložení bitů v registru možné definovat docela elegantně, jak ukazuje obr. 4 na příkladu registru HSYNC. Všimněte si, že základní „úložiště“ registru je řešeno jako skutečný objekt typu ‚reg‘, odvozené skupiny bitů jsou pak na něj připojeny jako běžné signály ‚wire‘.

Generování signálů HSYNC a VSYNC

Jak má vypadat správný signál HSYNC, jsme si ukázali již v minulém dílu. Zde si na závěr popíšeme stavový stroj z obr. 5, jenž, jak uvidíme příště, lze zcela jednoduše převést do podoby zdrojového kódu v modulu ‚sdisp‘. Na internetu jsou dokonce i volně šiřitelné grafické nástroje, které pro nakreslený stavový stroj umí generovat Verilog nebo VHDL kód automaticky. To ale pro náš jednoduchý příklad nebude potřeba. Tři stavy, kterými signál HSYNC prochází, jsou všechny prakticky stejné: při vstupu do každého z nich nulujeme čítač, který pak inkrementujeme do doby, než dosáhne svého maxima a poté přechází do stavu následujícího. Maxima pro každý stav jsou vlastně hodnoty uvedené v registru HSYNC a jsou to doby trvání fází Back Porch (r_hsync_bp), Data Phase (r_hsync_res) a Front Porch (r_hsync_fp).

Obr. 5

V reálné implementaci se ovšem nevyhneme drobné komplikaci, a to odvození správného časování celého stavového stroje. Periferie ‚sdisp‘ má k dispozici globální AXI hodinový vstup, který ve finálním projektu připojíme ke zdroji hodin procesorového systému (FCLK_CLK1) a nastavíme mu běžnou hodnotu, např. 100 MHz. Pro časování stavového stroje HSYNC pak použijeme frekvenci vydělenou ze 100 MHz celočíselným dělitelem, zadaným v kontrolním registru CTRL. Zdrojový kód frekvenční děličky je prakticky stejný jako u čítače simple_counter z prvního dílu našeho seriálu a nebudeme se jím proto detailně zabývat.

Logika stavového stroje pro generování signálu VSYNC je naprosto stejná. Jediný rozdíl je v časování, kdy pro stroj VSYNC použijeme k taktování místo vstupní frekvence celé periody signálu HSYNC.

Na závěr je ještě na místě připomenout jednu užitečnou zásadu při práci s hradlovými poli. Je velmi důležité zachovat celý systém nebo alespoň jeho co největší část, tzv. plně synchronní vůči poskytnutému hodinovému vstupu. Jakékoli změny hodnot registrů by se měly odehrávat globálně ve stejném čase se stejnou hranou hodin.

V systémech AXI je to vždy nástupná hrana hodin. Začátečnické pomocné pravidlo pro návrh periferních obvodů AXI by tedy mohlo znít asi takto: „Pokud cítíte pokušení použít v konstrukci always@ cokoliv jiného než (posedge S_AXI_CLK), začněte nad kódem přemýšlet znovu. Pokud takový kód ve svém designu již máte, odstraňte jej a začněte přemýšlet znovu!“

Příště

Příště dokončíme modul ‚sdisp‘, vložíme jej do hlavního projektu aplikace a propojíme s procesorovým systémem. V následujících pokračováních se pak už budeme věnovat softwaru pro platformu Zynq a vývojovému prostředí Xilinx SDK.