LinkedIn YouTube Facebook
Szukaj

Newsletter

Proszę czekać.

Dziękujemy za zgłoszenie!

Wstecz
Artykuły

Mikrokontrolery AVR XMEGA w praktyce, część 7. Sygnały zegarowe

W mikrokontrolerach ATmega i ATtiny układ dystrybucji sygnałów zegarowych był tak prosty, że wręcz aż prymitywny. W szczególności w procesorach starej generacji, takich jak ATmega8, mogliśmy wybrać źródło sygnału zegarowego przy pomocy fusebitów i podczas pracy procesora w żaden sposób nie można było go zmienić. Ponadto, błędne ustawienie fusebitów mogło prowadzić do zablokowania procesora. Najwyższy czas, by porzucić poczciwą ósemkę i przejść na mikrokontrolery nowej generacji!

W XMEGA układ zegarowy jest zdecydowanie bardziej rozbudowany. Mamy do dyspozycji różne źródła sygnału zegarowego, takie jak wbudowany generator szybki 32 MHz, energooszczędny 32 kHz oraz normalny 2 MHz, który uruchamia się zawsze po włączeniu zasilania. Możemy te częstotliwości podzielić preskalerem lub pomnożyć wbudowanym układem PLL. Oprócz tego, możemy oczywiście podłączyć różne kwarce, a w razie uszkodzenia kwarcu, procesor samoczynnie przełączy się na wbudowany generator. 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 różnymi zegarami, 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ł, mamy do dyspozycji aż trzy preskalery, umożliwiające taktowanie poszczególnych peryferiów mikrokontrolera różnymi zegarami. CLKCPU to zegar dla rdzenia procesora i może mieć maksymalnie 32MHz. CLKPER taktuje większość peryferiów. CLKPER2 i CLKPER4 służą do taktowania peryferiów zdolnych do pracy z zegarem szybszym od CLKCPU. Oprócz tego, mamy jeszcze osobne zegary dla RTC i USB, jeśli mikrokontroler jest wyposażony w te peryferia.

 

  Rys. 1. Układ dystrybucji sygnałów zegarowych

Rys. 1. Układ dystrybucji sygnałów zegarowych

 

Sposób wyboru źródła sygnału zegarowego sprowadza się do trzech punktów:

  1. Konfiguracja i uruchomienie generatora,
  2. Oczekiwanie na stabilizację generatora,
  3. Przełączenie źródła.

W tej części kursu napiszemy kilka funkcji, umożliwiających przełączenie źródła sygnału taktującego oraz obserwację efektów tej zmiany przy pomocy migającej diody i wyświetlacza LCD ze sterownikiem HD44780. Wykorzystamy wewnętrzny generator RC 2 MHz, 32 MHz, a także zewnętrzny generator kwarcowy i układ PLL. Schemat układu, wykorzystywanego podczas ćwiczeń, przedstawiono na rysunku 2, a jego zdjęcie jest na rysunku 3.

 

Rys. 2. Schemat układu demonstracyjnego

Rys. 2. Schemat układu demonstracyjnego

 

Rys. 3. Układ demonstracyjny zbudowany na płytce stykowej

Rys. 3. Układ demonstracyjny zbudowany na płytce stykowej

 

Zacznijmy od przeanalizowania funkcji main().

#define F_CPU 62000000UL
#include 
#include 
#include 
#include "hd44780.h"

int main(void) {
    
    // zmienna
    uint8_t pll         = 4;
    
    // diody
    PORTE.DIR           =    PIN0_bm;                        // dioda LED
                    
    // przyciski
    PORTA.DIRCLR        =    PIN0_bm;                        // przycisk - RC 2MHz
    PORTA.PIN0CTRL      =    PORT_OPC_PULLUP_gc;             // podciągnięcie do zasilania
    PORTE.DIRCLR        =    PIN5_bm;                        // przycisk FLIP - RC 32MHz
    PORTE.PIN5CTRL      =    PORT_OPC_PULLUP_gc;             // podciągnięcie do zasilania
    PORTE.DIRCLR        =    PIN6_bm;                        // przycisk - XTAL
    PORTE.PIN6CTRL      =    PORT_OPC_PULLUP_gc;             // podciągnięcie do zasilania
    PORTF.DIRCLR        =    PIN4_bm;                        // przycisk - PLL
    PORTF.PIN4CTRL      =    PORT_OPC_PULLUP_gc;             // podciągnięcie do zasilania
    
    // wyświetlacz LCD
    LcdInit();
    
    // komunikat o źródłe sygnału zegarowego
    LcdClear();
    Lcd("RC 2MHz");
    
    // włączenie przerwań
    sei();
    
    while(1) {
        PORTE.OUTTGL    =    PIN0_bm;
        _delay_ms(50);
        
        if(!(PORTA.IN & PIN0_bm)) Osc2MHz();
        if(!(PORTE.IN & PIN5_bm)) Osc32MHz();
        if(!(PORTE.IN & PIN6_bm)) OscXtal();
        if(!(PORTF.IN & PIN4_bm)) {    
            pll++;                                           // zwiększ zmienną pll
            if(pll > 31) pll = 1;                            // jeśli pll większe od 31 to ustaw na 1
            OscPLL(pll);                                     // funkcja konfigurująca PLL
        }
    }
}

Zwróćmy uwagę na funkcję opóźniającą _delay_ms(50); Co w niej jest nie tak? Funkcja powoduje, ż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 się zmienia, to pamiętajmy, że standardowe funkcje opóźniające nie uwzględniają aktualnej częstotliwości, 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.

Pliki źródłowe omawianego programu można pobrać na dole strony – będziemy używać biblioteki do obsługi wyświetlacza autorstwa Radosława Kwietnia, którą opisałem w 5 części kursu. W kolejnych odcinkach przedstawię, jak działają poszczególne generatory i jak skonfigurować ich rejestry kontrolne.

Dystrybutorem zestawu X3-DIL64 jest KAMAMI.pl.

Dominik Leon Bieczyński

www.leon-instruments.pl

 

Do pobrania