Popularny post atlantis86 Napisano 28 stycznia Popularny post Udostępnij Napisano 28 stycznia Przeglądając pudełka ze starymi projektami trafiłem na jeszcze jedną konstrukcję, o której zdążyłem już trochę zapomnieć. Prawdę mówiąc i tym razem w pierwszym momencie byłem przekonany, że już zdążyłem opisać ją na forum, jednak sprawdzenie historii mojej aktywności dowiodło, że no cóż... Byłem w błędzie. W takim razie nadrabiam to niedopatrzenie. Konstrukcja zaczęła powstawać kilka lat temu, gdzieś na początku pandemii, gdy powoli zabierałem się do nauki programowania układów CPLD i FPGA. Uznałem, że umiejętność ta może się przydać przy okazji tworzenia projektów retro, gdy będę musiał stworzyć coś bardziej skomplikowanego niż dekoder adresów w układzie GAL. Co prawda zaopatrzyłem się w kilka zestawów deweloperskich i zacząłem robić przykłady opisywane w internetowych kursach, jednak dość szybko dotarło do mnie, że moją ulubioną metodą nauki jest tworzenie własnych projektów. Tak właśnie zaczął powstawać ten (relatywnie) prosty zegar, zaprogramowany w układzie CPLD XC2C128 od Xilinxa. Większość elementów użytych do budowy tego urządzenia została wygrzebana z szuflad i pudełek z podręcznymi zapasami części. Duże, ładne wyświetlacze siedmiosegmentowe były nadwyżką pozostałą po innym projekcie, podobnie jak sterujące nimi drivery ULN2803. Kupić musiałem właściwie tylko sam układ CPLD, generator kwarcowy na częstotliwość zegarową oraz stabilizator 1,6V. Zegar jest zmontowany na dwóch płytkach. Większa zawiera zestaw wyświetlaczy, cztery przyciski, drivery oraz obwód zasilania. Na mniejszej płytce znajduje się CPLD z wszystkimi podzespołami niezbędnymi do jego pracy. Cała "magia" tak naprawdę dzieje się w programie napisanym w VHDL-u. Trochę czasu zajęło mi nauczenie się podstaw tego języka w stopniu, który pozwolił mi na zaimplementowanie mechaniki zegara, ale finalnie udało się. Z góry muszę jednak uprzedzić, że nie ma tutaj żadnych cudów. To nie jest jeden z projektów zegara na współczesnym mikrokontrolerze, który łączy się z Internetem i pobiera sobie czas z NTP. Ten zegar jest tylko zegarem - potrafi tylko odmierzać i wyświetlać czas. Równie dobrze taką konstrukcję można by zrealizować na jakimś układzie scalonym z lat osiemdziesiątych. Jego wartość jest czysto edukacyjna - realizując projekt miałem okazję zapoznać się z nowym językiem i nowym typem układów. Chociaż jeśli mam być szczery, to oryginalne założenia nie były do końca takie. Początkowo planowałem wyposażyć zegar w możliwość synchronizacji czasu w oparciu o system DCF77. Mniejsza płytka posiada nawet złącze pod moduł odpowiedniego odbiornika. Niestety w trakcie pracy nad projektem okazało się, że zasoby dostępne w XC2C128 ledwie wystarczą na zaimplementowanie podstawowej funkcjonalności, nie pozostawiając zbyt wiele miejsca na cokolwiek innego. Przez jakiś czas planowałem nawet zakup większego układu XC2C256, ale wtedy właśnie rozpoczął się pandemiczny kryzys z dostępnością półprzewodników i ceny CPLD wystrzeliły w kosmos, uznałem więc projekt z zakończony w obecnej formie. Kto wie, może za jakiś czas jeszcze do niego wrócę... 5
kroszkanorber 2 lutego Udostępnij 2 lutego (edytowany) @atlantis86 Hej. Też zaczynałem od takiego układu. Jak chcesz to mogę ci dać schemat dla połączenia pamięci konfiguracyjnej spi i układu jtag. Widzę że masz programator. Mam testy za sobą i wiem jak to poskładać. XC3S50A VQ100 i pamięć (M25P16) to koszt twojego CPLD. dcf77. sprawdzałeś czy fale radiowe są w twojej okolicy jeszcze do odczytania przez odbiornik? ( to fale radiowe z Niemiec i według moich informacji i nie są dostępne globalnie, nawet nie na terenie całej Polski). Jak pokażesz kod w vhdl to może można go uprościć by routing był korzystniejszy dla twojego układu. W wielu przypadkach granicą fizyczną układów programowalnych nie jest wykorzystanie zasobów, lecz ograniczone ilości połączeń między nimi i wiem to z doświadczenia. Pozdrawiam. Edytowano 2 lutego przez kroszkanorber 1
atlantis86 3 lutego Autor tematu Udostępnij 3 lutego 12 godzin temu, kroszkanorber napisał: @atlantis86 Hej. Też zaczynałem od takiego układu. Jak chcesz to mogę ci dać schemat dla połączenia pamięci konfiguracyjnej spi i układu jtag. Widzę że masz programator. Mam testy za sobą i wiem jak to poskładać. XC3S50A VQ100 i pamięć (M25P16) to koszt twojego CPLD. Chętnie rzucę okiem. 12 godzin temu, kroszkanorber napisał: dcf77. sprawdzałeś czy fale radiowe są w twojej okolicy jeszcze do odczytania przez odbiornik? ( to fale radiowe z Niemiec i według moich informacji i nie są dostępne globalnie, nawet nie na terenie całej Polski). Tak, DCF77 wykorzystywałem już w kilku różnych projektach, w tym jednym z wykorzystaniem elementów retro. Zasięg nie jest tutaj problemem. Ten system pracuje w niskim zakresie fal długich, które bardzo dobrze się propagują na znaczne odległości. Nadajnik obejmuje swoim zasięgiem praktycznie całą Europę i północną część Afryki. Problem leży gdzie indziej - obecnie to pasmo jest bardzo mocno zakłócane przez rozmaite zasilacze i ładowarki impulsowe. Skrajnie mało prawdopodobne jest więc odebranie poprawnej ramki za pierwszym razem - trzeba czekać. Zwykle udaje się to dopiero w nocy, bo po pierwsze wtedy na paśmie poprawiają się warunki propagacyjne, a po drugie ludzie wyłączają część siejących urządzeń. Większa jest też szansa na poprawne działanie poza miastem (mniejsze zagęszczenie źródeł zakłóceń). Do tego przed ustawieniem czasu trzeba odebrać dwie poprawne ramki pod rząd - transmisja nie zawiera żadnej sumy kontrolnej, więc tylko w ten sposób można mieć pewność, że nie ustawiamy zegara w oparciu o przypadkowe śmieci. 12 godzin temu, kroszkanorber napisał: Jak pokażesz kod w vhdl to może można go uprościć by routing był korzystniejszy dla twojego układu. W wielu przypadkach granicą fizyczną układów programowalnych nie jest wykorzystanie zasobów, lecz ograniczone ilości połączeń między nimi i wiem to z doświadczenia. Pozdrawiam. Możesz rzucić okiem. Kod jest TUTAJ. Zakładam, że może być nieoptymalny - jak wspominam, to był mój pierwszy (i jak to tej pory jedyny) większy projekt na CPLD/FPGA. Będę musiał jeszcze kiedyś do tego wrócić, pewnie przy okazji kolejnej konstrukcji w klimatach retro.
kroszkanorber 3 lutego Udostępnij 3 lutego (edytowany) @atlantis86 to schemat połączeń jtag i kości spi do układu xc3s50A vq100. Nie analizowałem dokładnie twojego kodu. Chyba zrobiłeś równoległe dekodery bin do displ dla każdej cyfry. Można zrobić mux 4x4 z wyborem cyfr binarnie kodowanych do jednego dekodera i 4 sygnały enable dla każdego wyświetlacza np. LEDen1, LEDen2, LEDen3, LEDen4. te sygnały powinny wysterować mux dla dekodera wyświetlacza i odpowiednią cyfrę. wszystkie cyfry połączyć równolegle do wyjścia a do f. wysterować je po kolei przez tranzystor na wspólną anodę lub katodę (zależy od wyświetlacza) w częstotliwości ok200Hz. pozbędziesz się w ten sposób trzech dekoderów dla pozostałych cyfr zastępując je muxem co w konsekwencji zwolni zasoby w cpld. Jaki moduł DCF używasz? Edytowano 3 lutego przez kroszkanorber
kroszkanorber 3 lutego Udostępnij 3 lutego @atlantis86 kod zegarka z wyświetlaczem 7 segmentowym 6 cyfr. mieści się w xc2c64. W twoim xc2c128 będzie miejsce na inną logikę. Ten kod nie jest dla fpga poprawny, a cpld to przerobi bez problemów z timingiem. Zegarek jest w stylu retro . ---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 17:59:57 02/03/2026 -- Design Name: -- Module Name: zegar - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- -- H M S - a -- _ _ _ _ _ _ - b -- |_| |_| |_| |_| |_| |_| - c -- |_| |_| |_| |_| |_| |_| - d -- - e -- | | | | | | - f -- dg1 dg2 dg3 dg4 dg5 dg6 - g -- -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity zegar is Port ( Clk : in STD_LOGIC; -- 32 khz Rst : in STD_LOGIC; a : out STD_LOGIC; b : out STD_LOGIC; c : out STD_LOGIC; d : out STD_LOGIC; e : out STD_LOGIC; f : out STD_LOGIC; g : out STD_LOGIC; dg1 : out STD_LOGIC; dg2 : out STD_LOGIC; dg3 : out STD_LOGIC; dg4 : out STD_LOGIC; dg5 : out STD_LOGIC; dg6 : out STD_LOGIC); end zegar; architecture Behavioral of zegar is signal Cnt1hz : std_logic_vector (14 downto 0); signal CntS9 : std_logic_vector (3 downto 0); signal CntS59 : std_logic_vector (2 downto 0); signal CntM9 : std_logic_vector (3 downto 0); signal CntM59 : std_logic_vector (2 downto 0); signal CntH9 : std_logic_vector (3 downto 0); signal CntH23 : std_logic_vector (1 downto 0); signal En1hz : std_logic; signal EnS9 : std_logic; signal EnS59 : std_logic; signal EnM9 : std_logic; signal EnM59 : std_logic; signal EnH9 : std_logic; signal EnH23 : std_logic; signal Muxen : std_logic; signal RstG : std_logic; signal Mux : std_logic_vector (2 downto 0); signal Bcd : std_logic_vector (3 downto 0); signal Led : std_logic_vector (6 downto 0); begin -- generator 1hz process(Clk, Rst) begin if Rst = '0' then Cnt1hz <= (others => '0'); elsif falling_edge(Clk) then if En1hz = '1' then Cnt1hz <= (others => '0'); else Cnt1hz <= Cnt1hz + 1; end if; end if; end process; En1hz <= '1' when Cnt1hz = "111110011111111" else '0'; -- licznik sekund jednostki process(En1hz, RstG) begin if RstG = '0' then CntS9 <= "0000"; elsif falling_edge(En1hz) then if CntS9 = "1001" then CntS9 <= "0000"; else CntS9 <= CntS9 + 1; end if; end if; end process; EnS9 <= CntS9(CntS9'left); -- licznik sekund dziesiątki process(EnS9, RstG) begin if RstG = '0' then CntS59 <= "000"; elsif falling_edge(EnS9) then if CntS59 = "101" then CntS59 <= "000"; else CntS59 <= CntS59 + 1; end if; end if; end process; EnS59 <= CntS59(CntS59'left); -- licznik minut jednostki process(EnS59, RstG) begin if RstG = '0' then CntM9 <= "0000"; elsif falling_edge(EnS59) then if CntM9 = "1001" then CntM9 <= "0000"; else CntM9 <= CntM9 + 1; end if; end if; end process; EnM9 <= CntM9(CntM9'left); -- licznik minut dziesiątki process(EnM9, RstG) begin if RstG = '0' then CntM59 <= "000"; elsif falling_edge(EnM9) then if CntM59 = "101" then CntM59 <= "000"; else CntM59 <= CntM59 + 1; end if; end if; end process; EnM59 <= CntM59(CntM59'left); -- licznik godzin jednostki process(EnM59, RstG) begin if RstG = '0' then CntH9 <= "0000"; elsif falling_edge(EnM59) then if CntH9 = "1001" then CntH9 <= "0000"; else CntH9 <= CntH9 + 1; end if; end if; end process; EnH9 <= CntH9(CntH9'left); -- licznik godzin dziesiątki process(EnH9, RstG) begin if RstG = '0' then CntH23 <= "00"; elsif falling_edge(EnH9) then if CntH23 = "10" then CntH23 <= "00"; else CntH23 <= CntH23 + 1; end if; end if; end process; -- dekoder reset 24 godziny EnH23 <= '0' when CntH9 = "0100" and CntH23 = "10" else '1'; RstG <= Rst and EnH23; -- zegar dla Mux 256hz Muxen <= Cnt1hz(7); -- licznik Mux process(Muxen) begin if falling_edge(Muxen) then if Mux = "101" then Mux <= "000"; else Mux <= Mux + 1; end if; end if; end process; -- wybór cyfry bcd z licznika zegara with Mux select Bcd <= "00" & CntH23 when "000", CntH9 when "001", '0' & CntM59 when "010", CntM9 when "011", '0' & CntS59 when "100", CntS9 when others; -- wybór wyświetlanej cyfry process(Mux) begin dg1 <= '0'; dg2 <= '0'; dg3 <= '0'; dg4 <= '0'; dg5 <= '0'; dg6 <= '0'; case Mux is when "000" => dg1 <= '1'; when "001" => dg2 <= '1'; when "010" => dg3 <= '1'; when "011" => dg4 <= '1'; when "100" => dg5 <= '1'; when others => dg6 <= '1'; end case; end process; -- dekoder licby bcd do wyświetlacza 7 segmentowego with Bcd 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 "1000000" when others; --0 -- podpięcie sygnałów do wyświetlacza 7 segmentowego a <= Led(0); b <= Led(1); c <= Led(2); d <= Led(3); e <= Led(4); f <= Led(5); g <= Led(6); end Behavioral;
atlantis86 4 lutego Autor tematu Udostępnij 4 lutego (edytowany) 16 godzin temu, kroszkanorber napisał: to schemat połączeń jtag i kości spi do układu xc3s50A vq100. Dzięki. Możliwe, że wykorzystam w którymś z przyszłych projektów. 16 godzin temu, kroszkanorber napisał: Nie analizowałem dokładnie twojego kodu. Chyba zrobiłeś równoległe dekodery bin do displ dla każdej cyfry. Można zrobić mux 4x4 z wyborem cyfr binarnie kodowanych do jednego dekodera i 4 sygnały enable dla każdego wyświetlacza np. LEDen1, LEDen2, LEDen3, LEDen4. te sygnały powinny wysterować mux dla dekodera wyświetlacza i odpowiednią cyfrę. wszystkie cyfry połączyć równolegle do wyjścia a do f. wysterować je po kolei przez tranzystor na wspólną anodę lub katodę (zależy od wyświetlacza) w częstotliwości ok200Hz. pozbędziesz się w ten sposób trzech dekoderów dla pozostałych cyfr zastępując je muxem co w konsekwencji zwolni zasoby w cpld. Prawdę mówiąc w tym projekcie celowo postanowiłem nie korzystać z multipleksingu. Z perspektywy czasu widzę, że jego użycie pozwoliłoby oszczędzić trochę zasobów wewnątrz CPLD, zostawiając miejsce na implementację chociażby dekodowania DCF77. Jednak na tym etapie jego wprowadzenie wymagałoby też przeróbek sprzętowych, więc chyba prościej jednak będzie kupić xc2c256. Jednak dzięki za udostępnienie kodu - możliwe, że wykorzystam kiedyś w jakimś innym projekcie zegara na CPLD. 16 godzin temu, kroszkanorber napisał: Jaki moduł DCF używasz? Prawdę mówiąc już nie pamiętam, jakiś losowy, kupiony na Allegro parę lat temu. Edytowano 4 lutego przez atlantis86
Pomocna odpowiedź
Bądź aktywny - zaloguj się lub utwórz konto!
Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony
Utwórz konto w ~20 sekund!
Zarejestruj nowe konto, to proste!
Zarejestruj się »Zaloguj się
Posiadasz własne konto? Użyj go!
Zaloguj się »