Ćwiczenie 1 VHDL - Licznik 4-bitowy. Zadaniem studenta jest zaprojektowanie w układzie CoolRunner2 układu, który dzieli częstotliwość zegara wejściowego generując sygnał taktowania licznika 4-bitowego, którego wartość wyświetla jest na czterech diodach. W celu zaprojektowania układu należy otworzyć środowisko projektowe Xilinx ISE 14.4 z menu rozwijanego wybrać File New projekt następnie nazwać projekt np. jako licznik oraz wybrać jego lokalizację oraz top-level source type jako HDL. Wybrać NEXT po czym pojawi się okienko, w którym należy wybrać opcje jak na następnym rysunku. Przy następnych trzech okienka wybrać NEXT, a przy ostatnim Finish. Następnie z menu rozwijanego Project New source stworzyć nowy plik źródłowy o nazwie przykładowej zegar (typ pliku VHDL module). Gdy pojawi się okno Define Module, definiujemy sygnały wejściowe i wyjściowe do naszego modułu projektowego o nazwie dzielnik jak na rysunku poniżej. Wybieramy Next, a następnie Finish
Wybieramy Next, a następnie Finish. Pojawi się okno pliku źródłowego o zawartości jak poniżej : library IEEE; use IEEE.STD_LOGIC_1164.ALL; ---- Uncomment the following library declaration if instantiating ---- any Xilinx primitives in this code. --library UNISIM; --use UNISIM.VComponents.all; entity dzielnik is Port ( zegar_osc : in STD_LOGIC; zegar_wy : out STD_LOGIC); end dzielnik; architecture Behavioral of dzielnik is Fragment kodu ( jak poniżej ), który jest zaznaczony jako komentarz robimy jako aktywny w celu dołączenia biblioteki komponentów związanych z danym układem.!!!!!!!! --library UNISIM; --use UNISIM.VComponents.all; oraz dodajemy use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; Przed wyrażeniem wstawiamy następujący tekst w celu zdefiniowania dwóch sygnałów pomocniczych :zegar_div_int, dzielenie jako 12-bitowego wektora signal zegar_div_int : std_logic; signal dzielenie : std_logic_vector(11 downto 0):="000000000000";
Następnie należy ciało modłu dzielnik wypełnić treścią (od do end Behavioral). Moduł ten ma za zadanie wytworzenie sygnału zegar_wy z zegara zewnętrznego oscylatora do taktowania licznika. W tym celu z menu rozwijanego Edit Language Templates.. otwieramy nowe okno, w którym wybieramy VHDL Device Primitive Instantiation CPLD Clock components CR-II Clock divider Divide by 16 Simple Divider. W sąsiednim okienku pojawi się tekst, z którego wybieramy poniższy fragment i kopiujemy go do naszego pliku źródłowego po wyrażeniu definiując sprzętowy dzielnik częstotliwości wejściowe sygnału zegarowego przez 16 (patrz schemat macroceli układu CPLD CoolRunner2 ) CLK_DIV16_inst : CLK_DIV16 port map ( CLKDV => CLKDV, -- Divided clock output CLKIN => CLKIN -- Clock input ); Zastępujemy CLKDV => CLKDV na CLKDV => zegar_div_int, oraz CLKIN => CLKIN na CLKIN => zegar_osc (czyli mapujemy nasze sygnały projektowe na sygnały sprzetowego dzielnika układu CoolRunnerII ). Definiujemy proces licznikowy, który ma za zadanie podzielić jeszcze dodatkowo częstotliwość wejściową. otrzymujemy architecture Behavioral of dzielnik is signal zegar_div_int : std_logic; signal dzielenie : std_logic_vector(11 downto 0):="000000000000"; -- wykorzystanie dzielnika częstotliwości przez 16 z biblioteki UNISIM CLK_DIV16_inst : CLK_DIV16 port map ( CLKDV => zegar_div_int, -- Divided clock output CLKIN => zegar_osc -- Clock input ); -- proces dzielnika dodatkowego przez 2^12 process (zegar_div_int) if zegar_div_int='1' and zegar_div_int'event then dzielenie <= dzielenie + 1; end if; end process; zegar_wy <= dzielenie(11);
Tworzymy nowy plik źródłowy o nazwie diody postępujemy podobnie jak poprzednio. Wejścia i wyjścia definiujemy jak na rysunku, a kod powinien wyglądać jak poniżej. entity diody is Port ( zegar_in : in STD_LOGIC; diody : out STD_LOGIC_VECTOR (3 downto 0)); end diody; architecture Behavioral of diody is signal liczenie : std_logic_vector(3 downto 0):="0000"; process (zegar_in) if zegar_in='1 and ' zegar_in'event then liczenie <= liczenie + 1; end if; end process; diody <= liczenie;
Dla sprawdzenia poprawności kodu obu źródeł wybieramy w oknie Processes Checksyntax. W oknie Console powinno się pojawić: Process "Check Syntax" completed successfully. Jak na rysunku na poprzedniej stronie. Moduł główny w tym projekcie zrealizujemy jako plik VHDL w tym celu tworzymy nowy plik źródłowy o nazwie top z jednym wejściem zegar_zew i wyjściami w postaci 4 elementowego wektora (od 3 do 0) diody_zew. Musimy zaznaczyć go jako plik główny projektu. Następnie w oknie Source podświetlamy plik diody, a w oknie Processes wybieramy Design Utilities Create Schematic Symbol. Klikamy dwa razy, w oknie Console pojawi się napis:process "Create Schematic Symbol" completed successfully To samo robimy z plikiem dzielnik. Tworzymy plik VHDL o nazwie top, wypełniajac go jak poniżej: library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity top is Port ( zegar_zew : in STD_LOGIC; diody_zew : out STD_LOGIC_VECTOR (3 downto 0)); end top; architecture Behavioral of top is component dzielnik Port ( zegar_osc : in STD_LOGIC; zegar_wy : out STD_LOGIC); end component; component diody Port ( zegar_in : in STD_LOGIC; diody : out STD_LOGIC_VECTOR (3 downto 0)); end component; signal x_zegar: std_logic; U1:dzielnik Port map( zegar_osc => zegar_zew, zegar_wy => x_zegar);
U2:diody Port map( diody => diody_zew, zegar_in => x_zegar); Co odpowiada schematowi jak poniżej. W oknie projektu należy podświetlić plik top oraz w oknie poniżej zaznaczyć Synthesize i kliknąć dwa razy. Jeżeli w oknie wynikowym Console pojawi się tekst: Process "Synthesis" completed successfully- oznacza to,że proces syntezy przebiegł prawidłowo i można przejść do konfigurowania wejść i wyjść w tym celu najlepiej zamknąć projekt (program ) i otworzyć go ponownie, a następnie należy zaznaczając plik top wybrać Floorplan IO (rysunek poniżej). Otworzy się aplikacja, w której przypiszemy sygnały numerom nóżek układu CPLD. Przypisania opisano poniżej. Zapisujemy ( Ikona dyskietki ) i w otworzonym okienku Bus delimiter zaznaczamy XST Default oraz naciskamy OK. W oknie projektu pojawił się plik glowny.ucf, który podświetlamy oraz w oknie Processes wybieramy opcje Edit Contrains. Pojawia się tekstowa reprezentacja konfiguracji sygnałów jak poniżej. Sprawdzamy czy
wszystkie piny są dobrze usytuowane. Następnie zamykamy plik tekstowy. NET "diody_zew<0>" LOC = "p69" ; NET "diody_zew<1>" LOC = "p68" ; NET "diody_zew<2>" LOC = "p66" ; NET "diody_zew<3>" LOC = "p64" ; NET "zegar_zew" LOC = "p38" ; Przechodzimy do wygenerowania pliku jedec, który służy do zaprogramowania układu w tym celu wybieram w oknie projektu plik top, a w oknie Processes Impement Designe, klikamy dwa razy. Program przechodzi do syntezy układu. Jeżeli proces zakończył się pomyślnie to znaczy, że możemy wgrać strukturę układu. Pojawi się również raport wykorzystania układu. Możemy zaprogramować układ.
Przykład licznika 4 bitowego, który taktuje swoim najstarszym bitem następny licznik 2 bitowy entity zegar is Port ( zegar_osc : in STD_LOGIC; licz_anod : out STD_LOGIC_VECTOR(1 DOWNTO 0)); end zegar; architecture Behavioral of zegar is ----------------------------------------------------- --definicja zmiennych pomocniczych signal zegar_div_int : std_logic; signal licz : std_logic_vector(3 downto 0):="0000"; signal licz2 : std_logic_vector(1 downto 0):="00"; ----------------------------------------------------- -- wykorzystanie dzielnika częstotliwości przez 16 z biblioteki UNISIM CLK_DIV16_inst : CLK_DIV16 port map ( CLKDV => zegar_div_int, -- Divided clock output CLKIN => zegar_osc -- Clock input ); -- proces dzielnika dodatkowego przez 16 process (zegar_div_int) if zegar_div_int='1' and zegar_div_int'event then licz <= licz + 1; end if; end process; -- proces licznika wykorzystywanego do sterowania anod process (licz(3)) if licz(3)='1' and licz(3)'event then licz2 <= licz2 + 1; end if; end process; licz_anod <= licz2;
entity teksty is Port ( anody_licz : in STD_LOGIC_VECTOR (1 downto 0); anody : out STD_LOGIC_VECTOR (3 downto 0); segmenty : out STD_LOGIC_VECTOR (6 downto 0)); end teksty; architecture Behavioral of teksty is signal wybor_tekst : std_logic_vector(1 downto 0); signal litera0 : std_logic_vector(6 downto 0); signal litera1 : std_logic_vector(6 downto 0); signal litera2 : std_logic_vector(6 downto 0); signal litera3 : std_logic_vector(6 downto 0); constant kod_cyferka_0 : std_logic_vector(6 downto 0):="1000000"; constant kod_cyferka_1 : std_logic_vector(6 downto 0):="1111001"; constant kod_cyferka_2 : std_logic_vector(6 downto 0):="0100100"; constant kod_cyferka_3 : std_logic_vector(6 downto 0):="0110000" ; -- struktura kombinacyjna multipleksera sterowania tranzystorów anod with anody_licz select anody <= "1110" when "00", "1101" when "01", "1011" when "10", "0111" when others; -- struktura kombinacyjna multipleksera sterowania segmentow with anody_licz select segmenty <= litera0 when "00", litera1 when "01", litera2 when "10", litera3 when others; -- przypisanie wartości w kodzie 7-seg poszcególnym literom. litera0 <= kod_cyferka_0 ; litera1 <= kod_cyferka_1 ; litera2 <= kod_cyferka_2 ; litera3 <= kod_cyferka_3 ;
Przykład obsługi wyświetlacza 7- segmentowego, w którym mamy transkoder kodu binarnego na kod 7-seg z wyświetlaną kropką na drugiej pozycji, sterowanie anad do wyświetlacza i sterowanie segmantów wyświetlanych entity wyswietlacz is Port ( cyfra_in : in STD_LOGIC_VECTOR (3 downto 0);-- cyfra binarna demux : in STD_LOGIC_VECTOR (1 downto 0);--2 bitowy wskaźnik wyboru, która cyfra się świeci anody : out STD_LOGIC_VECTOR (3 downto 0); kropka : out STD_LOGIC; LED : out STD_LOGIC_VECTOR (6 downto 0)); end wyswietlacz; architecture Behavioral of wyswietlacz is with demux Select anody<= "1110" when "00", "1101" when "01", "1011" when "10", "0111" when others; with demux Select kropka<= '1' when "00", '1' when "01", '0' when "10", '1' when others; with cyfra_in Select LED<= "1111001" when "0001", --1 "0100100" when "0010", --2 "0110000" when "0011", --3 "0011001" when "0100", --4 "0010010" when "0101", --5 "0000010" when "0110", --6 "1111000" when "0111", --7 "0000000" when "1000", --8 "0010000" when "1001", --9 "0001000" when "1010", --A "0000011" when "1011", --b "1000110" when "1100", --C "0100001" when "1101", --d "0000110" when "1110", --E "0001110" when "1111", --F "1000000" when others; --0