środa, 16 marca 2011

Kurs XMega (07): Sygnały zegarowe

Autor: Dominik Leon Bieczyński
Redakcja: Dondu

Artykuł jest fragmentem cyklu: Kurs mikrokontrolerów XMega by Leon-Instruments

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ć.

Tylko część mikrokontrolerów ATtiny i ATmega ma możliwość prostej zmiany częstotliwości taktowania mikrokontrolera, o czym przeczytasz w artykule: Ustawianie i zmiana częstotliwości taktowania mikrokontrolera w trakcie jego działania

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!

Do pobrania: XMega-sygnaly-zegarowe.zip (kopia)

Uproszczony schemat układu dystrybucji sygnałów zegarowych przedstawiono na rysunku poniżej. 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.


XMega Preskalery.
Preskalery

Sposób wyboru źródła sygnału zegarowego sprowadza się do trzech punktów:
  • Konfiguracja i uruchomienie generatora
  • Oczekiwanie na stabilizację generatora
  • 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.


XMega - schemat.
Schemat

Po zmontowaniu na płytce stykowej uzyskamy mniej więcej taki układ:


XMega - Zdjęcie układu testowego.
Zdjęcie układu


Zacznijmy od przeanalizowania funkcji main().

#define F_CPU 62000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#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.

Ściągnij poniższe pliki źródłowe – będziemy używać biblioteki do obsługi wyświetlacza autorstwa Radosława Kwietnia, którą opisałem w 5 części kursu (wyświetlacz LCD w XMEGA). W kolejnych odcinkach przedstawię, jak działają poszczególne generatory i jak skonfigurować ich rejestry kontrolne.

Dominik Leon Bieczyński
leon-instruments.pl

1 komentarz:

  1. Jak zwykle bardzo dziękuję za cenne informacje. Dodatkowo nasuwa mi się jedno pytanie: A co z drganiami styków? Nie trzeba się przed nimi zabezpieczać?
    Mam jeszcze jedną prośbę: Czy byłaby możliwość dodawania daty do publikowanych artykułów?

    OdpowiedzUsuń