Szybkie przebiegi cyfrowe...
„Gwiazda autostrady” niczym kosmiczna Emi mknie do celuhttps://www.youtube.com/watch?v=Y2qZJ3BHzjY
Często zwykłem mówić, że proste rzeczy zostały już zbudowane i przed nami zostały do zbudowania tylko te trudniejsze. W pewnym sensie, to nawet nie jest jakoś specjalnie kosmicznie złożony projekt, ale jednak ma kilka problematycznych punktów do pokonania. Jednym z takich jest zegar taktujący. Układ jest napędzany zegarem o największej częstotliwości 80MHz. Dokładniej, to używa kilku jeszcze mniejszych, więc zachodzi konieczność multipleksowania tego sygnału zegarowego. W układzie są zastosowane dwa generatory: 80MHz i 20MHz. I tu zaczynają się schody: taką częstotliwość jakoś trzeba przepuścić przez układy logiczne. Realizowana funkcja nawet nie jest zbyt skomplikowana, wystarczy zastosować jakikolwiek multiplekser (przykładowo 75HC151 czy 74HC153 ewentualnie 74HC157 lub ich trójstanowe odpowiedniki, czyli 74HC251itp). Problem polega na tym, że ich maksymalne częstotliwości sygnałów jakie mogą być przetwarzane są daleko za małe. Niby można zastosować jakieś bardziej nowoczesne układy z rodziny 74LVC, ale … takie nie walają się w mojej szufladzie natomiast mam (i często stosuję) układy typu CPLD. Jest taka dosyć fajna, wręcz kosmiczna rodzina (układy XILINX XC9500XL), tanie, proste w użyciu, tolerujące +5V na swoich pinach. Nic tylko brać i używać, ale... te 80MHz spędza sen z powiek. I tak w planach był do użycia układ CPLD, bo wymagana funkcja w wykonaniu układów logicznych to spory plac do zamieszkania. No więc zdecydowałem się na układ CoolRunner II (XC2C64 – taki jest w szufladzie). Ten jest wystarczająco prędki. Materiały producenta mówią, że nawet 250MHz jest do pokonania. Ile jest w tym prawdy a ile marketingu, to wie jedynie producent, ale w końcu trzeba uwierzyć jakimś informacjom. A najlepiej swoją wiarę zweryfikować w praktyce.W istotnej koncepcji to wygląda następująco: są dwa generatory, których sygnał wchodzi do układu CPLD. Wewnątrz (czego nie ma już na rysunku), jest rejestr, który steruje multipleksowaniem sygnałów. Układ CPLD ma klasyczną szynę danych, sygnał strobu (typu Chip Select). Praktycznie stanowi klasyczne rozwiązanie portów rodem ze „starożytnych” układów typu Z80. Stan rejestru odpowiednio przekierowuje wejściową falę prostokątną na wyjście: dostarcza ją do miejsca docelowego.
Zawartość CPLD, wysmarowana w VHLD'u to (w istotnym fragmencie):
Kod: Zaznacz cały
library IEEE ;
use IEEE.STD_LOGIC_1164.ALL ;
use IEEE.STD_LOGIC_ARITH.ALL ;
use IEEE.STD_LOGIC_UNSIGNED.ALL ;
entity wapi_logic is port ( PLDRes : in std_logic ;
SysClk1 : in std_logic ;
SysClk2 : in std_logic ;
OutClk : out std_logic ;
PLDDat : in std_logic_vector ( 7 downto 0 ) ;
Strobe1 : in std_logic ;
Strobe2 : in std_logic ;
... ) ;
end wapi_logic ;
architecture Behavioral of wapi_logic is
signal ClkRegister : std_logic_vector ( 7 downto 0 ) ;
signal Clk1Divider : std_logic_vector ( 1 downto 0 ) ;
signal Clk2Divider : std_logic_vector ( 1 downto 0 ) ;
signal DivClk : std_logic ;
begin
--
-- ClkRegister
--+-------+-------+-------+-------+-------+-------+-------+-------+
--| | | | | | | | |
--|ClkEn |SelClk1|SelClk2|SelDiv | MuxB3 | MuxB2 | MuxB1 | MuxB0 |
--| | | | | | | | |
--+-------+-------+-------+-------+-------+-------+-------+-------+
--
ClkRegInstance : process ( PLDRes , Strobe1 )
begin
if PLDRes = '0' then
ClkRegister <= ( others => '0' ) ;
else
if Strobe1'event and Strobe1 = '0' then
ClkRegister <= PLDDat ;
end if ;
end if ;
end process ;
Clk1DivInstance : process ( PLDRes , SysClk1 )
begin
if PLDRes = '0' then
Clk1Divider <= ( others => '0' ) ;
else
if SysClk1'event and SysClk1 = '0' then
Clk1Divider <= Clk1Divider + 1 ;
end if ;
end if ;
end process ;
Clk2DivInstance : process ( PLDRes , SysClk2 )
begin
if PLDRes = '0' then
Clk2Divider <= ( others => '0' ) ;
else
if SysClk2'event and SysClk2 = '0' then
Clk2Divider <= Clk2Divider + 1 ;
end if ;
end if ;
end process ;
with ClkRegister ( 3 downto 0 ) select -- MuxB3:MuxB2:MuxB1:MuxB0
DivClk <= Clk2Divider ( 1 ) when "1000" ,
Clk2Divider ( 0 ) when "0100" ,
Clk1Divider ( 1 ) when "0010" ,
Clk1Divider ( 0 ) when "0001" ,
'0' when others ;
with ClkRegister ( 7 downto 4 ) select
OutClk <= SysClk1 when "1100" ,
SysClk2 when "1010" ,
DivClk when "1001" ,
'0' when others ;
end Behavioral ;