Skocz do zawartości

Kurs FPGA - własne programy


Elvis

Pomocna odpowiedź

W komentarzach wątku Kurs FPGA - #7 - symulacja działania układu pojawił się pomysł rozszerzenia kursu o własne doświadczenia i wiadomości. Pozwólcie, że rozpocznę bardzo krótkim programikiem.

W części #4 kursu opisywany był przykładowy program z migającą diodą. Tym co mnie nieco zaskoczyło było używanie if-a do wykrywania zakresu licznika. Takie rozwiązanie jest bardzo dobre, bo pozwala na dowolny wybór zakresu licznika, ale wydawało mi się że jest mało optymalne w układach cyfrowych.

Czytając nieco o FPGA znalazłem inną implementację, którą chciałbym opsiać. Zamiast zliczać do pewnej wartości, tworzymy n-bitowy licznik.

Taki licznik po przekroczeniu sam wróci do zera. Zobaczmy jakie wartości miałby licznik 3-bitowy:

000

001

010

011

100

101

110

111

Kolejna wartość to zero i licznik sam zacznie działać od początku.

A jak taki licznik można wykorzystać jako dzielnik częstotliwości? Wystarczy, że weźmiemy najwyższy bit. Mając odpowiednio większy licznik możemy migać diodami nie używając if-a.

Mój programik wygląda następująco:

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

entity blink2 is Port (
clk : in std_logic;
led :  out std_logic_vector(7 downto 0)
);
end blink2;

architecture Behavioral of blink2 is

constant NBit : integer := 24;
signal licznik : std_logic_vector(NBit-1 downto 0);

begin
blink: process(clk) 
begin
	if rising_edge(clk) then      
		licznik <= licznik + 1; 
	end if;		
end process;

led <= (others => licznik(NBit-1)); 
end Behavioral; 

Nie wiem, czy jest w czymkolwiek lepszy niż oryginał ale chciałem go zaprezentować na początek żeby pokazać dlaczego potęgi dwójki w dzielnikach, czy częstotliwościach są często używane w układach cyfrowych. To po prostu wiele ułatwia 🙂

  • Lubię! 1
Link do komentarza
Share on other sites

"Wystarczy, że weźmiemy najwyższy bit.."

Tylko że nikt tak nie robi. Biorąc stan któregokolwiek bitu jako sygnał do taktowania czegoś innego (bo obserwacja LEDów to tylko zabawa), wchodzisz w obszar układów asynchronicznych a to bardzo niepopularne i niebezpieczne. Odpowiednikiem tego jest dodawanie krótkich delay'ów w skomplikowanym programie by ten zaczął działać gdy nie umiesz w inny sposób zapewnić prawidłowej synchronizacji procesów. Na jednej maszynie się uda, ale na drugiej program zwiśnie.

Oczywiście dzielniki częstotliwości są często wykorzystywane, ale nawet jeśli masz podział przez 2^n robisz to wyłącznie za pomocą detektora ostatniego (same jedynki) lub pierwszego (same zera) stanu licznika, który to detektor także jest przerzutnikiem synchronicznym taktowanym tym samym zegarem co licznik. Dostajesz wtedy impulsy o długości jednego zegara umieszczone co 2^n taktów. Dopiero to możesz swobodnie wykorzystać do odpalania kolejnych bloków w tej domenie zegara, ale wciąż jako sygnał kwalifikatora a nie zegar. Możesz też np. zrobić wybór bitu licznika multiplekserem (asynchronicznym blokiem kombinacyjnym), ale jego wyjście musisz znowu przepuścić przez synchronizator by odtworzyć czasy ustalania i przetrzymywania (setup/hold time) dla następnych stopni. A następnym stopniem powinien być rzecz jasna detektor zbocza narastającego (dwa przerzutniki), z którego dostajesz już wyżej opisany krótki impuls co 2^n zegarów. To właśnie z tego powodu FPGA są tak bogate w przerzutniki i to z tego powodu podstawowe komórki FPGA wyglądają jak funkcja kombinacyjna kilku zmiennych zakończona przerzutnikiem. Dodawanie stopni synchronizacji nic nie kosztuje (bo i tak tam są) a skutkuje szybszą, przewidywalną i bezproblemową pracą całości.

Podejście asynchroniczne jest trudno testowalne i bardzo podatne na problem wyścigów szczególnie wtedy gdy sygnały z różnych domen zaczynasz łączyć razem. Najlepiej w swoich projektach załóż sobie jako warunek konieczny, by wszystkie sygnały jakie generujesz były synchroniczne do jednego, głównego, wspólnego zegara. Nigdy nie produkuj z niego żadnych innych wolniejszych zegarów do asynchronicznego taktowania czegokolwiek. Dopiero gdy nabierzesz wprawy, gdy już swobodnie będziesz korzystał z symulacji i rozumiał działanie nawet skomplikowanych bloków cyfrowych możesz próbować świadomie generować i stosować różne zegary. I to wciąż z dużą uwagą i przemyśleniem czy to naprawdę jest konieczne. A praktycznie nigdy nie jest.

Link do komentarza
Share on other sites

Jak zwykle Marku dużo napiasłeś, dziękuję. Możliwe że nieprecyzyjnie się wyraziłem, nie chodziło mi o używanie najwyższego bitu jako wygnału zegarowego. Faktycznie, tak kiedyś próbowałem robić, ale to nie było dobre rozwiązanie.

Ale dlatego chciałem założyć wątek o FPGA - żeby można było podyskutować lepsze i gorsze rozwiązania 🙂

Chociaż faktycznie, może i użycie tego bitu do sterowania led-em to nie najlepszy pomysł.

[ Dodano: 26-11-2017, 16:55 ]

A skoro jesteśmy przy temacie poprawniej implementowanych dzielników. Marku, czy chodziło Ci mniej więcej o coś takiego?

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

entity divider is
generic(N : natural);
port (clk_in : in std_logic;
	clk_out : out std_logic);
end divider;

architecture Behavioral of divider is

signal cnt : integer range 0 to N-1;

begin
process(clk_in) is
begin
if rising_edge(clk_in) then
	if cnt = N-1 then
		cnt <= 0;
		clk_out <= '1';
	else
		cnt <= cnt + 1;		
		clk_out <= '0';
	end if;
end if;
end process;

end Behavioral;
Link do komentarza
Share on other sites

W projektach używam Veriloga a VHDL jest dla mnie językiem read-only, mimo kilku podejść i szczerych chęci jakoś nigdy go nie polubiłem..

O ile dobrze rozumiem co napisałeś, to tak. Synchroniczne zmiany wyjścia clk_out są tym o co postulowałem. Sama nazwa sygnału jest trochę myląca, ale to już kwestia gustu. Trzy literki 'clk' zawsze zostawiam dla prawdziwych zegarów.

EDIT: Użycie do sterowania LEDem jest OK, przecież to tylko wprawko-zabawa. Ponieważ jednak jest to jakieś odniesienie do forbotowego kursu i czytają to rzesze młodych (jeszcze niezrażonych) entuzjastów FPGA 🙂 warto chyba takie szczegóły podkreślać. Inaczej można się szybko zaplątać w szczegóły implementacji liczników czy rejestrów (niech już będzie) przesuwnych tracąc z oczu kwestie podstawowe. Nawet wyjadacze z czasów kostek TTL mają manię optymalizacji każdej bramki czy przerzutnika, bo tam każdy scalak to było miejsce na PCB, prąd i koszt. Dlatego zegarki (stołowe) były robione na asynchronicznych 7490 a interfejsy enkoderów kwadraturowych na dziwnych kombinacjach dwóch przerzutników. To zostaje ludziom na całe życie a podejście do projektowania systemów w FPGA jest zupełnie inne, często dla takich ludzi zaskakujące. Moim zdaniem warto - oprócz pompowania wiedzy merytorycznej - takie podstawy w kursach podkreślać.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Dla mnie FPGA to tylko hobby, więc nie przywiązuję należytej uwagi do nazw niestety. Ale będę się bardziej starać od teraz 🙂 Faktycznie verilog jest mniej przegadany, tyle że jakoś wciągnęłem się w VHDL, więc na razie nie będę zmieniał. Chciałem zachęcić innych użytkowników do dzielenia się eksperymentami wykonanymi przy okazji kursu - dzielnik gdzieś podpatrzyłem i podobał mi się ze względu na minimalizm.

Ale ogólnie fakt, że lepiej uważać na co się patrzy w internecie - więc zapomnijmy o wykorzystywaniu najwyższych bitów, postaram się w kolejnym lub kolejnych postach wkleić nieco poprawniejszy przykład z licznikiem i wyświetlaczem 7-segmentowym. Wszelkie uwagi mile widziane 🙂

Link do komentarza
Share on other sites

Kolumbryna22, nie bardzo rozumiem w czym jest problem - sam kod będzie właściwie identyczny, cała sztuczka to zmiana pliku ograniczeń.

Mógłbyś nieco dokładniej opisać co chcesz zrobić i w czym jest problem?

Link do komentarza
Share on other sites

Program się kompiluje bez błędów, ale wciśnięcie przycisku nic nie zmienia (sprawdzałem napięcie potencjometrem na pinach)

Program w VHDL

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity obslugagpiodioda is
port( DPSwitch: in STD_LOGIC;
	dioda: out STD_LOGIC);
end obslugagpiodioda;

architecture Behavioral of obslugagpiodioda is
begin
dioda <= not DPSwitch;
end Behavioral;

Przypisanie pinów w pliku ucf

NET "DPSwitch"        LOC = P70   | PULLUP  | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "dioda"           LOC = P31   | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; 

__________

Komentarz dodany przez: Treker

Kody programów należy umieszczać przez narzędzie KOD (znajdziesz je w edytorze pod ikonką "<>"). Dzięki niemu składania programów jest automatycznie kolorowana, a wtedy wszystkim znacznie łatwiej analizować wklejone programy. Proszę to poprawić - z góry dziękuję za zrozumienie i pomoc przy utrzymaniu porządku na forum.

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.