Wykład 4: Sygnały zegarowe

Data: 24.10.2018

Generatory sygnałów zegarowych

Istnieje wiele sposobów na wygenerowanie sygnału zegarowego. Wspomnę tutaj o trzech:

  • oscylator pierścieniowy (ring oscillator)

  • oscylator LC

  • oscylator kwarcowy

Naprostszym typem oscylatora jest oscylator pierścieniowy – jest to po prostu nieparzysta liczba bramek logicznych NOT połączona w pierścień. Jego częstotliwość to 1 / (suma opóźnień bramek i połączeń między nimi). Jest to bardzo niedokładny oscylator (rzędu ±30%) i nie powinien być stosowany w jakiejkolwiek sytuacji wymagającej konkretnej częstotliwości pracy, ale bywa używany gdy potrzebny jest po prostu jakiś zegar. Przykładem oscylatora pierścieniowego jest wewnętrzny zegar konfiguracyjny układu FPGA (jeśli został wybrany tryb konfiguracji w którym to FPGA generuje sygnał zegarowy).

Ostrzeżenie

Nie należy próbować tworzyć własnego oscylatora pierścieniowego używając programowalnej logiki – nie mamy wystarczającej kontroli nad ułożeniem i połączeniem układu, by sensownie kontrolować częstotliwość.

Trochę bardziej skomplikowanym (bo wymagającym zewnętrznych komponentów) generatorem jest generator LC, w którym używamy rezonansu układu złóżonego z kondensatora i cewki do wygenerowania zegara. Częstotliwością takiego zegara jest 1/(tau * sqrt(L*C)). Takim zegarem jest na przykład MCLK na naszej płytce. Wciąż, jest to zegar nieco niedokładny (ma wahania rzędu ±1%) – można to łatwo zobaczyć, próbując użyć go do generowania sygnału VGA i podłączając monitor…

Do generowania sensownie dokładnych (±0.001%) zegarów w elektronice używa się oscylatorów kwarcowych, które używają wibracji kryształu kwarcowego do generowania sygnału zegarowego. Dzięki elektronicznym układom przekształcającym sygnały zegarowe (PLL), wystarcza jeden kryształ (zazwyczaj o częstotliwości rzędu 10MHz) do wygenerowania dowolnej liczby sygnałów zegarowych o dowolnych wartościach.

Dystrybucja i przełączanie sygnałów zegarowych

W układach cyfrowych bardzo pożądane jest, by zbocza sygnału zegarowego dochodziły jednocześnie do wszystkich przerzutników, którymi sterują. Różnica w czasie przyjścia zbocza do różnych miejsc nazywa się clock skew i powoduje szereg problemów:

  • jeśli suma clock skew i czasu hold jest większa niż czas propagacji między wyjściem jednego przerzutnika a wejściem drugiego, mamy naruszenie czasu hold

  • clock skew efektywnie dodaje się do wielu czasów propagacji, zmniejszając maksymalną możliwą częstotliwość zegara

Aby zminimalizować clock skew, w układach FPGA istnieją specjalne sieci dystrybucji sygnałów zegarowych, zaprojektowane tak, by długość ścieżki od źródła sygnału do przerzutników była mniej-więcej stała. W układach Spartan 3E mamy 32 bufory globalne, będące źródłami takich sieci. Narzędzia do syntezy same wywnioskują, które z naszych sygnałów powinny używać buforów globalnych, ale jeśli chcemy, możemy poprosić o to jawnie:

// clk_in jest źródłem sygnału zegarowego, clk_out używamy w przerzutnikach.
BUFG moj_bufor_globalny(.I(clk_in), .O(clk_out));

Przełączanie sygnałów zegarowych

Może się zdarzyć, że będziemy projektować układ, którego częstotliwość powinna się zmieniać w czasie działania (tryb turbo, interfejsy sprzętowe mające wolne/szybkie wersje, różne rozdzielczości VGA, itp). Bufory globalne pozwalają nam bezpiecznie przełączyć się między dwoma sygnałami zegarowymi w trakcie pracy – aby użyć tej funkcjonalności, należy użyć bloku BUFGMUX:

// S wybiera, który z sygnałów zegarowych będzie przesłany na wyjście.
BUFGMUX moj_bufor_globalny(.I0(clk_in_a), .I1(clk_in_b), .S(ktory), .O(clk_out));

Wejście S powinno być zsynchronizowane do zegara clk_out, żeby uniknąć problemów z metastabilnością. BUFGMUX zapewni bezpieczne przełączenie między zegarami – po zmianie stanu S, czeka aż stary zegar będzie w stanie niskim, po czym utrzymuje stan niski na wyjściu aż do wystąpienia opadającego zbocza na nowym zegarze – zapewnia to, że okres zegara wyjściowego jest co najmniej tak długi, jak krótszy z okresów wejściowych.

Wyłączanie sygnałów zegarowych

Często przydaje się możliwość tymczasowego wyłączenia danego sygnału zegarowego (ponieważ dany układ akurat powinien pracować tylko część czasu, bądź dla zaoszczędzenia prądu). Bufory globalne udostępniają również taką możliwość:

// Będzie przekazywać na clk_out tylko te okresy clk_in, dla których enable == 1.
// Pozostałe okresy będą miały stan niski przez cały czas trwania.
BUFGCE moj_bufor_globalny(.I(clk_in), .O(clk_out), .CE(enable));

Jest to równoważne BUFGMUX, w którym jeden z sygnałów wejściowych jest zatrzymany i równy 0.

Komunikacja między domenami zegarowymi

Mając w układzie synchronicznym wiele domen zegarowych napotykamy na problem przekazywania danych między nimi. Dla pojedynczego sygnału (np. linii przerwania) wystarczy synchronizator, ale przekazanie większej ilości danych wymaga bardziej skomplikowanych układów.

Kod Graya

Załóżmy, że chcemy przekazać między dwiema domenami jakąś liczbę, która może zmienić się co najwyżej o 1 (w górę bądź w dół) w kolejnych cyklach zegara. Przekazanie jej bezpośrednio przez tablicę synchronizatorów nie zadziała – przy zmianie, zmiany różnych bitów mogą dojśc w różnych cyklach do nowej domeny zegarowej. Istnieje jednak kodowanie liczb, które rozwiązuje ten problem – zapewnia, że każde kolejne liczby są kodowane do wektorów bitowych różniących się w dokładnie jednej pozycji. Jest to kod Graya. Dla przykładu, kod 4-bitowy:

  • 0: 0000

  • 1: 0001

  • 2: 0011

  • 3: 0010

  • 4: 0110

  • 5: 0111

  • 6: 0101

  • 7: 0100

  • 8: 1100

  • 9: 1101

  • 10: 1111

  • 11: 1110

  • 12: 1010

  • 13: 1011

  • 14: 1001

  • 15: 1000

Aby zakodować liczbę x do kodu graya, wystarczy policzyć x ^ (x >> 1). Dekodowanie jest trochę bardziej skomplikowane, ale dośc efektywnie realizowalne w sprzęcie.

FIFO

Do przekazania dużej ilości danych między domenami zegarowymi najczęściej używa się kolejek FIFO zrealizowanych za pomocą bloków RAMu używanych jako buforów cyklicznych:

  • jeden port działa tylko w trybie zapisu w domenie źródłowej

  • drugi port działa tylko w trybie odczytu w domenie docelowej

  • wskaźniki odczytu i zapisu są przekazywane między domenami zegarowymi w kodzie Graya

Metastabilność

Niestety, w prawdziwym świecie nie istnieją układy w pełni cyfrowe – każdy układ jest tak naprawdę układem analogowym i można wprowadzić go w stany pośrednie (gdzieś pomiędzy 0 i 1). Zapisując taki stan (szczególnie stan bliski 0.5) do zatrzasku lub przerzutnika, możemy go wprowadzić w stan równowagi niestabilnej – dowolne zaburzenie spowoduje, że spadnie w stan 0 lub stan 1, lecz może to zająć dużo więcej czasu niż normalny parametr T_CKO. Takie zjawisko nazywa się metastabilnością.

Metastabilność jest zjawiskiem niebezpiecznym, gdyż dany stan może być różnie zinterpretowany przez podłączone wejścia różnych bramek logicznych, powodując w naszym układzie synchronicznym przejścia niespójne zarówno ze stanem logicznym 0 jak i stanem logicznym 1. Byłoby bardzo niedobrze, gdyby np. różne części składowe procesora nie zgadzały się na temat tego, czy w danym cyklu procesor rozpoczyna obsługę przerwania.

Metastabilność może powstać na dwa sposoby:

  1. Dajemy układowi synchronicznemu stan pośredni jako wejście (należy tego nie robić).

  2. Nie przestrzegamy czasu setup bądź czasu hold.

Metastabilność jest zjawiskiem nieuniknionym, gdy dany układ synchroniczny ma wejścia asynchroniczne (a praktycznie każdy ma) – prędzej czy później, wejście zmieni się odpowiednio blisko zbocza sygnału zegarowego, powodując naruszenie czasu setup bądź hold. Musimy więc sobie jakoś z tym poradzić.

Z drugiej strony, stany metastabilne trwają bardzo krótko – praktycznie zawsze rozwiązują się w ciągu jednego, ewentualnie dwóch cykli zegara. Z tego powodu, na sygnałach asynchronicznych używa się tzw. synchronizatorów – łańcuchów dwóch lub trzech przerzutników:

wire async_in;
reg tmp1, tmp2;
reg out;

always @(posedge clk)
    tmp1 <= async_in;
    tmp2 <= tmp1;
    out <= tmp2;
end

Jeśli przerzutnik tmp1 <= async_in złapie wejście w momencie zmiany stanu i wejdzie w stan metastabilny, z bardzo dużym prawdopodobieństwem stan ten rozpadnie się do stanu 0 bądź 1 zanim jego wyjście zostanie użyte przez kolejny przerzutnik (ma na to cały cykl zegara). Jeśli nawet to się nie uda, na przerzutniku tmp2 <= tmp1 mamy kolejną szansę. Na wyjściu out z bardzo dużym prawdopodobieństwem dostajemy już czyste wyjście bez metastabilności.

Zapobieganie metastabilności ma charakter probabilistyczny, a odporność układu na metastabilność podaje się jako MTBF (mean time between failures) – szacowany średni czas bezawaryjnej pracy. Jeśli osiągniemy MTBF rzędu setek tysięcy lat, możemy go uważać za odporny na metastabilność. MTBF zależy od:

  • Częstotliwości zegara. Większa częstotliwość to:

    • więcej szans, że coś pójdzie nie tak

    • krótszy okres czasu w synchronizatorze na rozpad stanu metastabilnego

  • Technologii wykonania (nowsze układy FPGA mają dedykowane bloki synchronizacyjne z przerzutnikami wykonanymi w specjalnej technologii zoptymalizowanej na zapobieganie metastabilności)

  • Liczby przerzutników w synchronizatorze (MTBF rośnie wykładniczo z liczbą przerzutników). Dwa przerzutniki to absolutne minimum, dla bezpieczeństwa zaleca się trzy.

Synchronizatorów należy używać zawsze na asynchronicznych wejściach. W przypadku wejść z układów synchronicznych pracujących z inną częstotliwością zegara, należy zapewnić jeszcze jeden przerzutnik na początku, używający sygnału zegarowego układu źródłowego – zapobiega to wydostawaniu się stanów pośrednich z logiki kombinacyjnej. Jedyny przypadek, w którym wolno pominąć synchronizator na wejściu to wejście z innego układu synchronicznego pracującego na ściśle związanym sygnale zegarowym (np. naszym sygnale zegarowym podzielonym bądź pomnożonym przez stałą przez układ generowania zegara) – w tym wypadku należy dobrze opisać wzajemną relację tych zegarów, by narzędzia analizy czasowej mogły sprawdzić zachowanie czasów setup i hold.

Zjawisko metastabilności występuje zawsze, gdy dwie konfliktujące zmiany stanów mogą się zdarzyć blisko siebie – w szczególności może też dotyczyć asynchronicznych sygnałów reset, bądź wejścia do zatrzasku (gdy zmienia się jednocześnie ze zmianą 1 na 0 na wejściu E).