Nanocounter – dokładny miernik częstotliwości wykorzystujący układy FPGA, STM32 oraz aplikację Android
Kalibracja wbudowanego zegara referencyjnego jest ważna, ponieważ zachowanie oscylatora TCXO zależy od temperatury – choć w mniejszym stopniu, niż standardowego oscylatora kryształowego. Co więcej oscylator będzie dryfował w miarę starzenia. Aplikacja pozwala zarejestrować zmianę temperatury i bieżącą temperaturę otoczenia.
Ustawienia kalibracji są zapisywane na stronie pamięci Flash mikrokontrolera – możliwe jest zapisanie historii do 112 ustawień. Po uruchomieniu aplikacja odczytuje tablicę współczynników kalibracji z mikrokontrolera i przywraca najnowsze ustawienia na czas sesji. Ustawienia kalibracji nie się wykorzystywane, gdy wybrane jest zewnętrzne źródło zegara referencyjnego.
Kod źródłowy aplikacji jest dostępny na Githubie. Sama aplikacja jest też dostępna w sklepie Google Play pod nazwą „Nanocounter”.
Program mikrokontrolera
Program mikrokontrolera wykorzystuje bibliotekę stm32 do komunikacji z układami peryferyjnymi. Nie jest ona w tym momencie bezpośrednio kompatybilna z modelami 072, ale używam tylko tych układów, które są dostępne także w modelach 051. Modyfikacja skryptów uruchomienia linkera pozwala obsłużyć większą pamięć dostępną w serii 072.
Program jest w większości asynchroniczny. Zasadniczą pracę wykonuje główna pętla w pliku Program.h:
for(;;) { // check the command processor for activity _commandProcessor.run(); // if the lock is lost then stop if(!_pllLockState && _frequencyCounter.isStarted()) _frequencyCounter.stop(); // if not started, locked and counters have been processed then start if(_pllLockState && !_frequencyCounter.isStarted() && !_countersReady) _frequencyCounter.start(); // new counters available? if(_countersReady) { MillisecondTimer::delay(10); // read from the FPGA _frequencyCounter.readCounters(counters); // stop (reset) the counters inside the FPGA _frequencyCounter.stop(); // set the latest counters inside the command processor _commandProcessor.setCounters(counters); // reset for a new run _countersReady=false; } } for(;;) { // check the command processor for activity _commandProcessor.run(); // if the lock is lost then stop if(!_pllLockState && _frequencyCounter.isStarted()) _frequencyCounter.stop(); // if not started, locked and counters have been processed then start if(_pllLockState && !_frequencyCounter.isStarted() && !_countersReady) _frequencyCounter.start(); // new counters available? if(_countersReady) { MillisecondTimer::delay(10); // read from the FPGA _frequencyCounter.readCounters(counters); // stop (reset) the counters inside the FPGA _frequencyCounter.stop(); // set the latest counters inside the command processor _commandProcessor.setCounters(counters); // reset for a new run _countersReady=false; } }
Metoda procesora run() jedynie zapala diodę link, jeśli w czasie ostatniej sekundy transmisja Bluetooth była aktywna. Komunikaty Bluetooth są wysyłane, odbierane i przetwarzane całkowicie asynchronicznie.
Kanał USART DMA służy do odbioru komunikatu z aplikacji i zgłasza przerwanie, gdy komenda jest gotowa. Wówczas komenda jest przetwarzana podczas obsługi przerwania. Następnie rozpoczyna się nadawanie przez USART DMA i wysłanie odpowiedzi z powrotem do aplikacji.
Urządzenie nie może pracować, jeśli pętla PLL nie jest zsynchronizowana – w przypadku utraty synchronizacji następuje awaryjne zatrzymanie licznika. Dioda lock zapala się tylko wówczas, gdy pętla PLL jest zsynchronizowana. Nie trzeba w tym celu odpytywać układu – program wykorzystuje przerwanie EXTI dostępne w mikrokontrolerach STM32, które jest generowane, gdy zmienia się stan wyprowadzenia GPIO podłączonego do układu PLL.
Pozostała część pętli programu po prostu rozpoczyna zliczanie FPGA, następnie sprawdza jego zakończenie (kolejne przerwanie EXTI), po czym odczytuje ostateczną wartość liczników i przekazuje je do aplikacji.
Cały kod źródłowy jest oczywiście dostępny na Githubie.
Testy
Testowanie okazało się bardzo interesujące. Po zmontowaniu całości podłączyłem programator ST_Link/v2 i sprawdziłem, czy mikrokontroler działa. Działał. Następnie wpisałem kod, który ładuje strumień binarny na FPGA. Również ten krok zakończył się sukcesem.
Następnie muszę zaprogramować układ PLL. Napisałem kod obsługujący SPI, który zapisuje odpowiednie wartości do rejestrów. Te wartości zostały wprowadzone poprawnie, jednak pętla nie chciała się zsynchronizować. To bardzo niedobrze. Układ AD9553 ma tylko podstawowe funkcje debugowania. Pozwala przekierować jeden z wewnętrznych sygnałów zegarowych do wyprowadzenia lock, co może pomóc określić miejsce wystąpienia błędu.
Jedyny zegar, który dawał jakiekolwiek wyniki, było wejście referencyjne detektora fazy (PFD). To pozwalało zobaczyć, że mnożenie i dzielenie zegara wejściowego działało poprawnie, zatem układ nie był całkowicie zepsuty. Obejrzałem układ pod mikroskopem i sprawdziłem pola lutownicze z boku obudowy. Wszystko wyglądało, jak należy. Podejrzenie padło oczywiście na pole zwarte do masy, ponieważ nie jestem w stanie go obejrzeć. Mogłem najwyżej stwierdzić, że lut obecny na tym polu stopił się, ponieważ obudowa osiadła równo na płytce. Co jednak, jeśli lut wpłynął do przelotek? Nie było tego widać od spodu. Spędziłem kilka godzin, manipulując ustawieniami debugowania AD9553 i miałem już się poddać, gdy zadałem pytanie o te symptomy na forum ADI.
Programowanie układu AD9553 wymaga zapisaniu rejestrów, przekazaniu ich ustawień do urządzenia, a następnie kalibracji – po tym pętla powinna chwytać. Jedne z inżynierów zauważył, że kolejność poleceń kalibracji nie była prawidłowa i zaproponował poprawki. Zadziałały! Udało się uzyskać synchronizację pętli fazowej, która od tej pory zawsze pracowała prawidłowo. Dziękuję bardzo inżynierom ADI, którzy poświecili swój czas, aby odpowiedzieć hobbyście zadającemu pytanie na ich forum.
Nadszedł czas na uruchomienie aplikacji Androida, aby sprawdzić działanie całego systemu – od początku do końca. Tak naprawdę trwało to kilka miesięcy, ponieważ pisałem aplikację w wolne wieczory i weekendy.
Na powyższym zdjęciu widać, jak aplikacja mierzy dokładność oscylatora kryształowego o częstotliwości 16 MHz wbudowanego w jedną z płytek Arduino. Płytka tego typu zapewne wykorzystuje najtańsze dostępne elementy, nie oczekiwałem więc dobrej jakości kryształu. Wyniki są pozytywnym zaskoczeniem – układ odbiega od częstotliwości nominalnej jedynie o 31 części na milion. W prawym górnym rogu można odczytać, że poprawka odpowiednia dla zegara milisekundowego wynosi -111 ms na godzinę.
Kalibracja
Kalibracja urządzenia wymaga użycia zewnętrznego źródła częstotliwości o wysokiej jakości. Najprostszym sposobem pomiaru jest podłączenie oscylatora TCXO umieszczonego na płytce do wejścia pomiarowego.
Pomiar wbudowanego oscylatora TCXO za pomocą aplikacji uruchomionej na smartfonie.
Źródłem częstotliwości referencyjnej jest układ GPSDO z wyjściem 10 MHz. Układy GPSDO są bardzo interesującymi urządzeniami i zamierzam opublikować recenzje oraz filmiki ich dotyczące w przyszłym artykule.
Ponieważ częstotliwość referencyjna jest bardzo bliska 10 MHz, wartości wyświetlane na ekranie odpowiadają parametrom wbudowanego oscylatora. Jeśli przekształcimy wzór na częstotliwość referencyjną przed pomnożeniem przez 20 w układzie PLL, otrzymamy:
Porównanie tych dwóch wzorów pokazuje, że częstotliwość wbudowanego oscylatora TCXO wynosi 10 MHz + (10 MHz – wyświetlona wartość). Innymi słowy jest to 10.000.004 Hz w aktualnej temperaturze pomieszczenia 21,6°C. Aby porównać wartość 379 ppb ze specyfikacją podaną przez firmą Connor Winfield możemy zajrzeć do karty katalogowej.
Niestety nie mogę przeprowadzić dokładnych obliczeń, ponieważ wykresy referencyjne odnoszą się do temperatury 25°C. Mogę jednak stwierdzić, że wynik 379 ppb zawiera się z pewnością w fabrycznym zakresie kalibracji +-1 ppm.
Film demonstracyjny
Na tym filmiku można zobaczyć, jak używam Nanocountera w różnych sytuacjach. Zmierzyłem częstotliwość kilku oscylatorów kryształowych, a potem dołączyłem źródło częstotliwości referencyjnej GPSDO dla porównania.
Pliki projektu do pobrania
Dla tych, którzy chcieliby modyfikować pliki projektu lub po prostu przesłać pliki Gerbera do zakładu drukującego płytki, są one dostępne na tej stronie w zakładce „Hardware Schematics and CAM files” w postaci archiwum .zip.
Andy Brown