W dzisiejszej części kursu dotyczącego układów programowalnych(FPGA) zajmiemy się tematem wyboru zestawu startowego, środowiska oraz języka. Poruszymy także kilka spraw teoretycznych.
Zanim przejdziemy do głównej części artykułu, chciałem zapytać Was jeszcze o jedną sprawę. Jakiś czas temu zacząłem prowadzić kanał na YT KLIK. Zacząłem się zastanawiać czy nie prowadzić tej samej serii równocześnie na blogu oraz na kanale. Co o tym myślicie? Dajcie znać w komentarzach 🙂 A tutaj odnośnik do poprzedniej części na YT.
[su_youtube url=”https://www.youtube.com/watch?v=PylkIX424bQ”]
No to bez zbędnego słowa wstępu zajmijmy się wyborem zestawu startowego.
Jednym z głównych problemów dotyczących początków z FPGA jest cena sensownego zestawu do nauki. Jakiś czas temu sklep KAMAMI wypuścił swój zestaw MAXimator, z którego będę korzystał w tym kursie.
Zestaw MAXimator oparty jest na układzie FPGA z rodziny MAX10 firmy Altera. Złącza tej płytki są zgodne są ze złączami Arduino. Dzięki temu możemy korzystać z shieldów przeznaczonych dla Arduino. Bardzo ułatwia to naukę, ponieważ shieldy do Arduino są tanie oraz łatwo dostępne.
Ja będę korzystał z zestawu MAXimator Promo, który dostępny jest TUTAJ
Składa się on z:
– Płytki startowej wyposażonej w złącza HDMI, VGA oraz gniazdo karty microSD
–Płytki rozszerzającej wyposażonej w 4-cyfrowy wyświetlacz 7-segmentowy LED, 2 diody RGB typu WS2812B, sensor temperatury STLM20 oraz dwa przyciski
–Programatora firmy Altera, zgodnego z Altera USB Blaster. Obsługuje on interfejsy JTAG oraz ISP/ICP firmy Altera.
Pierwsze 600 zestawów możemy kupić w promocyjnej cenie 149zł.
Jak już pisałem zestaw ten jest oparty na układzie FPGA 10M08DAF256C8GES firmy Altera z rodziny MAX10
Jego podstawowe właściwości to:
-
8000 komórek LE
- 378 kb konfigurowalnej pamięci M9K
- 1376 kb wewnętrznej pamięci Flash dla aplikacji użytkownika
- wewnętrzna pamięć konfiguracji Flash
- wewnętrzny generator sygnału zegarowego
- wbudowany 12-bitowy przetwornik ADC @1MSPS
- 24 sprzętowe multiplikatory
- 2 wewnętrzne generatory PLL
- wbudowany sensor temperatury
- interfejsy LVDS
- Złącza zgodne z Arduino Uno Rev 3 z translatorami poziomów napięć 3,3/5 V
- 5 kanałów ADC (12 bitów/1 MSPS) z ochroną nadnapięciową (zakres pomiarowy 0…+2,5 V)
- Interfejs HDMI (z warstwą fizyczną CEC oraz DDC)
- Interfejs wideo VGA
- Generator sygnału zegarowego 10 MHz
- 4 diody LED dla aplikacji użytkownika
- 2 diody LED sygnalizacyjne (zasilanie, konfiguracja FPGA)
- Potencjometr analogowy
- Gniazdo karty Flash MicroSD
- Złącze konwertera USB/UART
- Zasilacz na układach Altera Enpirion
- Przycisk globalnego zerowania
- Zasilanie z USB (z bezpiecznikiem polimerowym) lub napięciem 5 V z zewnętrznego zasilacza
- Złącze JTAG zgodne z USB Blasterem
Omówieniem tych parametrów zajmiemy się podczas następnych części kursu.
Środowisko
Jako środowisko będziemy używać ALTERA QUARTUS PRIME LITE (FREE EDITION).
Jest to kompletne środowisko przeznaczone dla tych układów.
Pobieramy je z tej strony. Musimy się zarejestrować oraz pobrać te pliki (zaznaczone na czerwono)
Instalacja jest prosta. Wystarczy podążać za krokami instalatora.
[su_youtube url=”https://www.youtube.com/watch?v=n-E4x7ts9sw&feature=youtu.be”]
Miałem zamiar do tego kursu wybrać jeden język i korzystać tylko z niego jednak z biegiem czasu przekonałem się, że nie jest to najlepszy pomysł. W tym kursie głównie będziemy korzystać z języka VHDL. Głównie nie oznacza tylko. Nie będziemy się ograniczać tylko do jednego języka. Poruszymy także temat schematów
oraz języka Verilog
Troszkę teorii
Przedstawienie języka VHDL
Na początku zajmiemy się krótkim przedstawieniem języka VHDL. Na razie są to tylko podstawy. Więcej wiedzy zdobędziesz w dalszych częściach kursu.
Język VHDL ma podobną składnię do języka Pascal. Nie jest on językiem Case sensitivity czyli nie rozróżnia wielkości liter w kodzie. Dla tego języka istnieją symulatory logiczne, które umożliwiają „czytanie” plików VHDL. Dzięki czemu kod możemy symulować (przykład tego zobaczysz w następnej części kusu).
Składnia
Tutaj bez zbędnego opisywania przedstawię jak wygląda składnia tego języka.
- Komentarz
W języku VHDL komentarze rozpoczynamy dwoma myślnikami — A zakończeniem komentarza jest zakończenie linii
12-- To jest komentarzkod VHDL - Znaki
Znaki jakie możemy używać w VHDL to tylko znaki ASCII. Pojedynczy znak „zamyka się” w apostrofach (’) Wygląda to mniej więcej tak
1'A' '*' 'c' - Ciągi znaków
Ciąg znaków „zamyka się” w cudzysłowie („)
1"To jest jezyk VHDL" - Ciągi bitów
W języku VHDL korzystamy z ciągów bitów, służą one do przypisywania wartości tablicom bitów. Możemy zapisać je w systemie binarnym (B od Binary), ósemkowym (O od Octal) i szesnastkowy (X od heXadecimal)
123B"1010110" -- dlugosc ciagu wynosi 7,O"126" -- dlugosc ciagu wynosi 9, jest to odpowiednik zapisu B"001_010_110",X"56" -- dlugosc ciagu wynosi 8, jest to odpowiednik zapisu B"0101_0110".
Teraz zajmiemy się obiektami danych, rozróżniamy trzy typy obiektów stałe, zmienne oraz sygnały:
- Stałe
Stała jest obiektem, której wartość przypisujemy tylko raz za pomocą deklaracji. Nie możemy później modyfikować wartości stałej. Deklaracja stałej wygląda tak :
1constant identyfikator_stalej : typ_stalej := wartosc; - Zmienne
Zmienna jest obiektem, której wartość możemy modyfikować po jej zadeklarowaniu. Deklaracja zmiennych wygląda tak:
1variable identyfikator_zmiennej : typ_zmiennej; - Sygnały
Sygnały służą do połączenia modułu z całością. Deklarujemy je tak:
1signal identyfikator_sygnalu : typ_sygnalu; - Aliasy
Alias jest zastępczym identyfikatorem obiektu. Deklaruje się go tak:
1alias identyfikator_aliasu : typ_aliasu(zakres_aliasu) is identyfikator_obiektu(zakres_obiektu);
Typy danych
Język VHDL posiada kilka wbudowanych typów danych.
Składnia definiowania typów danych w VHDL wygląda mniej więcej tak:
1 |
type identyfikator_typu is wlasciwosci; |
- Typy całkowite
Jedynym standardowo predefiniowanym typem całkowitym jest typ integer. Jego zakres to od -2147483647 do +2147483647. Tak wygląda przykładowa deklaracja zmiennej typu integer:
1variable zmienna : integer := 1234336; - Typy rzeczywiste
Typy rzeczywiste odzwierciadlają liczby rzeczywiste w akresie od -1E38 do +1E38. Przykładowa deklaracja zmiennej typu real:
1variable zmienna : real := 12.345; - Typy fizykalne
Typ fizykalny jest typem reprezentującym wartości fizyczne. Przykładowa deklaracja typu fizykalnego:
1variable zmienna : time := 1 hr 30 min; - Typy rekordów
Rekordy to zbiory elementów, każdy z nich może być innego typu. Przykładowa deklaracja obektu tego typu:
1variable obiekt_rek : moj_rekord;
W późniejszym czasie powiem jeszcze o typach wyliczeniowych oraz tablicowych.
Moduły projektowe
Kod w języku VHDL składa się z modułów komponentów. Każde urządzenie w tym języku traktujemy jako pojedynczy komponent. Każdy komponent jest często postrzegany przez kompilator jako osobny projekt. Co prowadzi do zależności pomiędzy poszczególnymi komponentami. Zależności te nazywamy hierarchią projektu.
Każdy opis komponentu składa się z dwóch części:
- Opis interfejsu – deklaracja pinów(portów) oraz ich typów
- Opis architektury – opis budowy komponentu
Przykładowy opis interfejsu wygląda tak:
1 2 3 4 5 6 |
entity nazwa_komponentu is [ generic deklaracje_generyczne ] port ( nazwa_portow1 : rodzaj_portow typ_portow; nazwa_portow2 : rodzaj_portow typ_portow ); end nazwa_komponentu; |
Rodzaje portów:
- in – określa port wejściowy komponentu
- out – określa port wyjściowy komponentu
- inout – określa port, który może pełnić role portu wyjściowego, albo wejściowego (nie obu naraz)
- buffer – określa port, który może pełnić role portu wyjściowego, lub wejściowego (obu naraz)
Opis architektury składa się z dwóch części:
- deklaratywnej
- opisowej
Część deklaratywna to ta część, która znajduje się pomiędzy słowami is oraz begin. Wewnątrz tej części możemy umieścić.
- Deklarację sygnału wewnętrznego
1signal nazwa_sygnalow : typ_sygnalow ; - Deklarację podkomponentu
12345component nazwa_podkomponentuport ( nazwa_portow1 : rodzaj_portw typ_portow;nazwa_portow2 : rodzaj_portow typ_portow);end component nazwa_podkomponentu;
Część opisowa to część znajdująca się pomiędzy begin a end. W jej wnętrzu umieszczamy ciało architektury, czyli na przykład coś takiego (więcej o tym powiemy w następnej części):
1 2 3 4 5 6 |
begin a <= p2 XOR p3; b <= p1 NOR a; c <= p2 AND a; q <= b NAND c; end struk; |
Przykładowy kod w tym języku wygląda tak:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
library ieee; -- dolaczenie standardowej biblioteki IEEE use ieee.std_logic_1164.all; -- dolaczenie pakietu 'STD_LOGIC_1164' z biblioteki IEEE definiuje on popularne stany logiczne entity nand2 is -- opis interfejsu bramki polaczenie z otoczeniem port ( a,b : in std_logic; c : out std_logic ); end nand2; architecture logic of nand2 is -- opis wnetrza Bramki begin c <= not (a and b); -- obliczenia wykonywane przez program end logic; |
Jest to kod opisujący dwu wejściową bramkę NAND (więcej o bramkach dowiemy się w kolejnych częściach kursu)
Obecnie może Ci się to wydawać dość skomplikowane jednak w późniejszych częściach kursu przekonasz się, że jest to bardzo proste. Nie od razu zrozumiesz cały kod, jednak jest to normalne. Więc się nie przejmuj. Na razie tylko próbuję objaśnić jak wygląda hierarchia kodu oraz składnia języka VHDL.
Wydaję mi się, że na dziś wystarczy 🙂 Jeśli masz jakieś pytania zadaj je w komentarzach 😉 Zapraszam Cię także do grupy Facebook’owej poświęconej FPGA KLIK oraz Fanpage’a bloga na Facebooku.
Kolejne części kursu powinny pojawiać się regularnie w dwutygodniowych odstępach (taki mam plan). Jednak na razie nie mogę wam tego obiecać. Od połowy kwietnia już ruszamy z regularnymi częściami kursu.
W kolejnych częściach poruszymy temat operacji na zmiennych w języku VHDL, bramek logicznych, podstaw Algebry Boole’a oraz symulacji projektów.
Przygotowując ten artykuł korzystałem z wikibooks.
[su_button url=”https://roboblog.eu/2016/01/16/fpga/” size=”7″]Poprzednia część kursu[/su_button]
[su_button url=”https://roboblog.eu/2016/04/26/fpga-poradnik-2/” size=”7″]Kolejna część kursu[/su_button]