W Xmega obwody dystrybucji sygnału zegarowego są bardzo rozbudowane. Użytkownik ma do dyspozycji różne źródła sygnału zegarowego, takie jak umieszczone w strukturze generatory: szybki (32 MHz), energooszczędny (32 kHz) oraz normalny (2 MHz). Ten ostatni domyślnie uruchamia się po włączeniu zasilania. Częstotliwości wyjściowe generatorów można podzielić preskalerem lub pomnożyć wbudowanym układem PLL. Oprócz tego, można dołączyć różne kwarce, a w razie uszkodzenia kwarcu, procesor samoczynnie przełączy się na wbudowany generator RC. Mało tego – podczas pracy możemy zmieniać nie tylko częstotliwość zegara, ale również źródło sygnału. Różne peryferia mogą być taktowane z różnymi częstotliwościami, a niektóre z nich mogą pracować nawet z częstotliwością 128 MHz!
Uproszczony schemat układu dystrybucji sygnałów zegarowych przedstawiono na rysunku 1. Po wybraniu jednego z pięciu dostępnych źródeł, do dyspozycji są aż trzy preskalery umożliwiające taktowanie poszczególnych peryferiów mikrokontrolera z różnymi częstotliwościami sygnału zegarowego.
CLKCPU to przebieg zegarowy dla rdzenia mikrokontrolera, który może mieć częstotliwość maksymalną 32 MHz. CLKPER taktuje większość peryferiów. CLKPER2 i CLKPER4 służą do taktowania peryferiów zdolnych do pracy z taktowaniem szybszym od CLKCPU. Oprócz tego, mamy jeszcze osobne przebiegi zegarowe dla RTC i USB, jeśli mikrokontroler jest wyposażony w te peryferia.
Sposób wyboru źródła sygnału zegarowego sprowadza się do realizacji następujących kroków wymaganych do wykonania stabilnej zmiany:
- Konfigurowanie i uruchomienie generatora.
- Oczekiwanie na ustabilizowanie się częstotliwości wyjściowej.
- Wybór źródła.
W tej części kursu napiszemy kilka funkcji, umożliwiających przełączenie źródła sygnału taktującego oraz obserwowanie efektów tej zmiany za pomocą migającej diody LED i wyświetlacza LCD. Wykorzystamy wewnętrzny generator RC 2 MHz, 32 MHz, a także zewnętrzny generator kwarcowy i układ PLL.
Schemat układu używanego podczas ćwiczeń przedstawiono na rysunku 2, a jego wygląd na fotografii 3.
Oprogramowanie testowe
Na listingu 1 zamieszczono funkcję main(). Na początek zajmijmy się jej analizą. Zwróćmy uwagę na funkcję opóźniającą _delay_ms(50); Powoduje ona, że procesor kręci się w pustej pętli nic nie robiąc, aż upłynie żądany czas. Jednak funkcja _delay_ms() oblicza ilość potrzebnych cykli na podstawie definicji #define F_CPU 62000000UL. W przypadku, kiedy częstotliwość taktowania zmienia się, to pamiętajmy, że standardowe funkcje opóźniające nie uwzględniają tej zmiany, w związku z czym odmierzony czas nie będzie prawidłowy. Zaobserwujemy ten problem w naszym programie testowym – dioda podłączona do E0 będzie mrugać z różną częstotliwością, mimo że w pętli głównej jest _delay_ms(50) ze stałym argumentem równym 50.
Taktowanie za pomocą generatora RC o częstotliwości 32 MHz lub 2 MHz
Po wciśnięciu przycisku FLIP dołączonego na płytce X3-DIL64 do pinu E5, zostanie wywołana funkcja uruchamiająca wbudowany generator 32 MHz. Projektanci mikrokontrolerów Xmega zaimplementowali generator RC, który bez dołączania żadnych dodatkowych elementów umożliwia osiągnięcie maksymalnej mocy obliczeniowej. Poza tym, nie wymaga on żadnego konfigurowania, więc możemy od razu przystąpić do jego uruchomienia. Aby to zrobić, musimy wpisać odpowiednią wartość do rejestru kontrolnego oscylatora, a mianowicie do OSC.CTRL. Zwróćmy uwagę na fragment dokumentacji pokazany na rysunku 4.
Aby uruchomić generator 32 MHz, powinniśmy do rejestru OSC.CTRL wpisać wartość OSC_RC32MEN_bm. Dokumentacja zawiera ostrzeżenie, że musimy poczekać aż częstotliwość oscylatora ustabilizuje się, zanim użyjemy go w charakterze źródła sygnału zegarowego. W tym celu musimy w pętli sprawdzać rejestr OSC.STATUS i czekać tak długo, aż bit OSC_RC32MRDY_bm zostanie ustawiony (listing 2). Po wykonaniu tej funkcji, na wyświetlaczu zostanie wyświetlony komunikat o taktowaniu procesora przebiegiem o częstotliwości 32 MHz, a dioda dołączona do pinu E0 będzie migała szybciej.
Uruchomienie wbudowanych generatorów 2 MHz oraz 32 kHz wykonuje się bardzo podobnie – wystarczy zmienić tylko RC32M na RC2M lub RC32K (listing 3).
Generator kwarcowy
Sercem generatora tego typu jest rezonator kwarcowy, w skrócie zwany kwarcem. Dołączamy go do nóżek R0 i R1 portu R. Są to piny ogólnego przeznaczenia i jeśli nie korzystamy z generatora kwarcowego, możemy ich użyć w innym celu. Oprócz kwarcu, musimy także zastosować kondensatory o niewielkiej pojemności widoczne na schemacie na rys. 2, w sposób znany z mikrokontrolerów ATmega i ATtiny.
Większość producentów płytek testowych narzuca częstotliwość kwarcu lutując go do płytki na stałe. Odlutowanie kwarcu, w szczególności SMD, może spowodować jego uszkodzenie lub oderwanie miedzianych ścieżek od laminatu. Moduł prototypowy X3-DIL64 wyposażono w podstawkę pod kwarc, dzięki czemu użytkownik może szybko i bez lutowania podłączyć taki kwarc, jaki uzna za najlepszy do swoich potrzeb. Wygląd podstawki pokazano na fotografii 5.
W mikrokontrolerach XMEGA możemy korzystać z kwarców zegarkowych 32 kHz oraz kwarców o częstotliwości od 0,4 MHz do 16 MHz. Chcąc uzyskać częstotliwość taktowania procesora większą od 16 MHz, musimy zastosować układ PLL, który zostanie omówiony później.
Konfiguracja generatora kwarcowego jest trochę bardziej skomplikowana niż generatory omawiane dotychczas, aczkolwiek nie jest to problem, z którym sobie nie poradzimy. Za nastawy generatora kwarcowego jest odpowiedzialny rejestr OSC. XOSCCTRL. Zwróćmy uwagę na fragment dokumentacji na rysunku 6.
Pierwszy z parametrów, FRQRANGE, określa przedział, wewnątrz którego musi znajdywać się częstotliwość kwarcu. X32KLPM służy do uruchamiania trybu oszczędzania energii dla kwarcu 32 kHz. XOSCPWR zwiększa prąd w obwodzie rezonatora, co w większości przypadków nie jest potrzebne. XOSCSEL wyznacza m. in. czas potrzebny do ustabilizowania się generatora. W tym przykładzie zastosujemy kwarc o częstotliwości 16 MHz. Jego typowy czas startu wynosi 16 tys. cykli zegarowych. Aby poprawnie skonfigurować generator, wystarczy umieścić w programie następujące polecenie:
OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc| //
wybór kwarcu od 12 do 16 MHZ
OSC_XOSCSEL_XTAL_16KCLK_gc; //
czas na uruchomienie generatora
Następnie, uruchamiamy generator kwarcowy. OSC.CTRL = OSC_XOSCEN_bm; // uruchomienie generatora kwarcowego
Powinniśmy teraz poczekać, aż częstotliwość wyjściowa generatora ustabilizuje się. Jednak nie możemy czekać w pustej pętli na ustawienie się odpowiedniego bitu w rejestrze statusowym, bo jeśli generator się nie uruchomi, to procesor będzie czekał w nieskończoność. Dlatego musimy wprowadzić pętlę, która odliczy przykładowo 255 cykli i sprawdzi status 255 razy – jeśli w tym czasie generator nie ustabilizuje się, program uzna, że z jakiś powodów generator nie daje się uruchomić (np. uszkodzony rezonator kwarcowy) i będzie mógł powiadomić użytkownika o błędzie (listing 4).
Mikrokontrolery Xmega wyposażono w szereg rozwiązań zwiększających bezpieczeństwo i stabilność pracy. Jednym z nich jest układ nadzorujący pracę generatora kwarcowego. Jeśli zostanie wykryta nieprawidłowość w pracy generatora, układ zgłosi przerwanie niemaskowalne (wektor OSC_OSCF_vect) i samoczynnie przełączy źródło sygnału na wbudowany generator RC 2 MHz. Starsze mikrokontrolery ATtiny i ATmega w takiej sytuacji zawieszały się, a w skrajnych wypadkach nawet nie mogły nawiązać połączenia z programatorem.
Zanim zostanie uruchomiony układ detekcji błędu generatora kwarcowego musimy wpisać wartość CCP_ IOREG_gc do rejestru CPU_CCP, aby zezwolić na modyfi kowanie rejestrów kluczowych dla funkcjonowania procesora. Następnie, do rejestru XOSCFAIL wpisujemy wartość OSC_XOSCFDEN_bm i układ detekcji zostanie uruchomiony. Trzeba zaznaczyć, że tego układu nie można wyłączyć bez restartu procesora.
//odblokowanie możliwości modyfikowania ważnych rejestrów
CPU_CCP = CCP_IOREG_gc;
//włączenie układu detekcji błędu
OSC.XOSCFAIL = OSC_XOSCFDEN_bm;
W razie stwierdzenia usterki generatora, zostanie wygenerowane przerwanie OSC_OSCF_vect, a generator RC 2 MHz włączy się automatycznie.
ISR(OSC_OSCF_vect) {
OSC.XOSCFAIL |= OSC_XOSCFDIF_bm; //
kasowanie flagi przerwania
LcdClear();
Lcd("Awaria!");
}
Generator z pętlą PLL
PLL, czyli pętla synchronizacji fazy, jest przeciwieństwem preskalera i służy do zwiększania częstotliwości sygnału. W mikrokontrolerach Xmega to rozwiązanie jest dostępne we wszystkich modelach, nawet w tych najtańszych.
Generator PLL w Xmega umożliwia podwyższenie częstotliwości przebiegu wybranego generatora do 31 razy. Do wyboru są następujące generatory:
- wbudowany RC 2 MHz,
- wbudowany RC 32 MHz, ale wstępnie podzielony przez 4, czyli 8 MHz,
- kwarcowy 0,4...16 MHz,
- zewnętrzny sygnał zegarowy.
Układ PLL nie może współpracować z generatorami 32 kHz.
Niewłaściwie konfigurując układ PLL można mocno przekroczyć dopuszczalna częstotliwość taktowania mikrokontrolera, co może prowadzić do jego niestabilnej pracy. Rdzeń mikrokontrolera może pracować taktowany przebiegiem o częstotliwości do 32 MHz. Częstotliwość na wyjściu układu PLL nie powinna być niższa niż 10 MHz, ani wyższa niż 200 MHz. W razie potrzeby można zastosować preskalery (widoczne na rys. 1), aby zmniejszyć częstotliwość przebiegu.
Napiszemy program, który pozwala zmienić konfigurację układu PLL podczas pracy procesora. Wciskając przycisk dołączony do wyprowa dzenia F4 na płytce X3-DIL64, będziemy zwiększali mnożnik PLL w zakresie 1...31. Jako źródło sygnału zastosujemy generator 2 MHz, a częstotliwości uzyskane dzięki PLL będą sięgały nawet 62 MHz, co daleko przekracza dopuszczalny limit. Zmiany sygnału zegarowego będziemy obserwować dzięki mrugającej diodzie, a dodatkową informacją będzie wyświetlenie częstotliwości na wyświetlaczu LCD.
Prześledźmy, co dzieje się w funkcji OscPLL. Pierwszym krokiem jest uruchomienie generatora, który będzie źródłem sygnału dla PLL i ustawienie go jako źródła. Trzeba w tym momencie wyraźnie zaznaczyć, że nie można zmieniać konfiguracji układu PLL podczas, gdy jest on uruchomiony, a tym bardziej kiedy jest źródłem sygnału zegarowego (listing 5).
Następnie, możemy przystąpić do konfiguracji układu PLL. Jednak jeśli jest on już włączony, to koniecznie musimy go najpierw wyłączyć. W przeciwnym razie próba zmiany konfiguracji będzie nieskuteczna. Kluczowy w tym fragmencie jest rejestr OSC.PLLCTRL, którego opis przedstawiono na rysunku 7. Musimy wybrać źródło sygnału, współczynnik mnożący (zmienna pllfactor jest argumentem funkcji OscPLL), a opcjonalnie możemy częstotliwość sygnału wyjściowego podzielić przez dwa (listing 6).
Podobnie jak w przypadku innych generatorów, poczekać musimy aż sygnał zegarowy się ustabilizuje, poprzez sprawdzanie czy już został ustawiony odpowiedni bit w rejestrze statusowym. Dopiero wtedy możemy przełączyć źródło sygnału taktującego mikrokontroler:
//oczekiwanie na ustabilizowanie się generatora
while(!(OSC.STATUS & OSC_PLLRDY_bm));
//odblokowanie możliwości zmiany źródła sygnału zegarowego
CPU_CCP = CCP_IOREG_gc;
//wybór źródła sygnału zegarowego PLL
CLK.CTRL = CLK_SCLKSEL_PLL_gc;
Układ PLL może stracić synchronizację, jeśli sygnał zegarowy będzie zbyt wolny, zbyt szybki lub niestabilny. Dlatego mikrokontrolery Xmega mają możliwość monitorowania układu PLL, podobnie jak generatora kwarcowego. W razie stwierdzenia nieprawidłowości, jako źródło przebiegu taktującego zostanie wybrany generator 2 MHz oraz zostanie zgłoszone przerwanie OSC_OSCF_vect.
// układ nadzorujący PLL
//odblokowanie możliwości modyfikowania ważnych rejestrów
CPU_CCP = CCP_IOREG_gc;
//włączenie układu detekcji błędu sygnału zegarowego
OSC.XOSCFAIL = OSC_PLLFDEN_bm;
Podczas ćwiczeń przekroczyliśmy częstotliwość taktowania rdzenia mikrokontrolera prawie dwukrotnie. Zgodnie z danymi firmy Atmel, układ powinien być taktowany w zakresie od 10 MHz (minimalna częstotliwość wyjściowa PLL) do 32 MHz (maksymalna częstotliwość rdzenia). Jestem ciekaw, czy Czytelnicy zauważyli jakieś nieprawidłowości w działaniu mikrokontrolera poza tym zakresem. W moim przypadku wszystko działało bez zarzutu. Mimo tego, w normalnych zastosowaniach nigdy nie należy przekraczać dopuszczalnych zakresów podanych przez producenta układu. Na listingu 7 pokazano program demonstrujący możliwości układu generowania i dystrybucji sygnałów zegarowych.
Na zakończenie
W ramach pojedynczego artykułu nie sposób wyczerpać tematu wszystkich zagadnień związanych z sygnałów zegarowych w mikrokontrolerach Xmega. Oprócz opisanych wyżej zagadnień, użytkownik Xmegi ma do dyspozycji następujące bloki i funkcje:
- układ synchronizujący DFLL,
- zegar czasu rzeczywistego RTC,
- generatory energooszczędne,
- generator sygnału zegarowego do USB,
- kalibrację generatorów.
Te możliwości zostały opisane np. w książce Tomasza Francuza "AVR. Praktyczne projekty" oraz w dokumentacji technicznej.
Dominik Leon Bieczyński
http://leon-instruments.blogspot.com