Kampis Elektroecke

XMega – Taktsystem

XMega Blockdiagramm

Der XMega besitzt, im Gegensatz zum Mega8, 16 und 32, ein sehr umfangreiches System um den Systemtakt zu generieren. Es werden folgende Taktquellen angeboten:

  • Internen 2 MHz
  • Interner 32 MHz Oszillator
  • Einen ULP Oszillator für den Watchdog Timer
  • Eine PLL mit einem Multiplikator von 1 – 31
  • Internen 32k Hz Takt 
  • Desweiteren besteht die Möglichkeit einen 0,4 MHz – 16 MHz Quarz
  • Ein 32 kHz Quarz
  • Externer Taktgeber

Dieser Takt kann außerdem noch mit einen Clock Prescaler um einen Faktor bis zu 2048 heruntergeteilt werden. Die internen Taktquellen können zudem im laufenden Betrieb kalibriert werden. Dies wird durch verschiedene Kalibrationswerte, die im Signaturregister stehen, ermöglicht. Diese Signaturregister werden bei der Produktion im Werk beschrieben und können ausgelesen werden um verschiedene Peripheriegeräte zu kaibrieren.
Bevor ich weiter auf das Clocksystem eingehen werde, ist ein Blick in das Datenblatt des Herstellers äußerst hilfreich.

XMega Clocksystem

Auf Seite 80 dieses Datenblattes gibt es das Bild in der Originalgröße.

Anders als beim ATTiny/ATMega kann man bei einem XMega den Takt nicht mittels Fusebits einstellen. 
Ich fange zuerst mit den internen Oszillatoren an. Nach einem Reset ist automatisch der interne 2 MHz Oszillator aktiv.
Die Einstellungen für den Takt befinden sich im Clock-Control-Register und im Oscillator-Control-Register.

Verwenden einer internen Taktquelle:

Um eine interne Taktquelle auszuwählen, verwende ich folgenden Codeschnipsel:

Als erstes schreibt man mit Hilfe des Befehls

eine 0x01 an die 2. Stelle des Oscillator-Control Registers.
Dieses Bit nennt sich 32 MHz Internal RC Oscillator Enable und es aktiviert den internen 32 MHz Oszillator.
Durch die Zeile

wartet das Programm solange bis der Controller im Oscillator-Status-Register das 32 MHz Internal RC Oscillator Ready-Bit setzt. Erst dann läuft der Oszlliator stabil und kann weiter verwendet werden.
Anschließend schreibt man mit Hilfe von

0xD8 in das CCP Register. Dies dient dazu um die I/O Register zu schützen und Interrupts für 4 Taktzyklen zu deaktivieren.
Als letztes wird noch mit

eine 0x01 an die erste Stelle des System-Clock-Control-Register geschrieben, wodurch der interne 32 MHz Oszillator als Taktquelle ausgewählt wird.
Um wieder den 2 MHz Oszillator auszuwählen kann dasselbe Programm verwendet werden, nur muss das Bitmuster auf das der 2 MHz Taktquelle geändert werden.

Verwenden einer externen Taktquelle:

Eine externe Taktquelle wird ähnlich eingestellt wie die interne Taktquelle. Es müssen nur die Bits im System-Clock-Control-Register sowie im Oscillator-Control-Register und im Oscillator-Status-Register umgeändert werden.
Zusätzlich muss aber im XOSC-Control-Register noch die Frequenz des externen Taktes sowie die Start-up Time eingestellt werden.
Für einen externen 16 MHz Quarz mit einer Start-up Time von 16CLK sieht der Codeschnipsel wie folgt aus:

Konfigurieren der PLL:

Der XMega besitzt eine interne PLL womit der Takt jeder beliebigen Taktquelle (sowohl intern als auch extern) um den Faktor 1 – 31 erhöht werden kann. In meinen Versuchen habe ich festgestellt, dass der XMega allerdings nur bis zu einer Frequenz von 49 MHz arbeitet (die PLL kann theoretisch 200 MHz). In Kombination mit einem externen 16 MHz Quarz bietet sich so die Möglichkeit sich einen 32 MHz Takt zu erzeugen der auch noch genauer ist als der interne RC-Oszillator mit 32 MHz.
Wenn man die PLL nutzen will, muss als erstes die Taktquelle, die den Eingangstakt für die PLL liefert, richtig eingestellt und initialisiert werden.
Für das nächste Beispiel verwende ich den internen 32 MHz takt, der auch schon erfolgreich initialisiert und einsatzbereit ist.
Der Codeschnipsel für die PLL sieht folgendermaßen aus:

Als erstes wird mit der Zeile

eine 0x02 an die 8. und die 7. Stelle des PLL-Control-Registers geschrieben. Dadurch wird der interne 32 MHz Takt als Taktquelle für die PLL ausgewählt. Anschließend wird eine 0x06 in das Register geschrieben. Die 0x06 steht für den Multiplikator mit dem die PLL den Eingangstakt multipliziert.

Vorsicht!
Wer sich das oben stehende Bild vom Clock System aufmerksam angschaut hat, wird sicher auch schon festgestellt haben, dass der interne 32 MHz Takt erst durch 4 geteilt wird bevor er in den Eingangsmultiplexer der PLL geht. Dies sorgt für eine feinere Auflösung beim Einstellen des Taktes in höheren Bereichen.
Verwendet man diesen Takt jedoch als direkte Taktquelle wird direkt der 32 MHz Takt benutzt.

Die nächste Codezeile

setzt im Oscillator-Control-Register das PLL-Enable Bit auf High und aktiviert damit die PLL.
Es ist wichtig das man ERST den Multiplikator und die Taktquelle festlegt bevor man die PLL aktiviert, weil es sonst zu Problemen führen kann.
Mit der Zeile

wartet das Programm wieder darauf dass das PLLRDY Bit im Oscillator-Status-Register gesetzt wird und die PLL damit einsatzbereit ist.
Die Zeilen

sichern die I/Os und deaktivieren die Interrupts. Anschließend wird die PLL als Taktquelle ausgewählt.
Wenn man nun alles richtig gemacht hat, arbeitet die CPU im Chip mit einer Frequenz von 48 MHz.

Zurück zu AVR

9 Kommentare

    1. Hey,

      ja das ist doof formuliert.
      Die Zeile die dies erledigt heißt:

      CLK.CTRL = 0×01;

      Hab mich da wohl beim kopieren vertan.
      Danke für den Hinweis! Wird korrigiert.

      Gruß
      Daniel

  1. #include

    main(void)
    {
    void Clock_init(void)
    {
    OSC.CTRL |= OSC_RC32MEN_bm;
    while(!(OSC.STATUS & OSC_RC32MRDY_bm));
    CCP = CCP_IOREG_gc;
    CLK.CTRL = 0x01;
    }

    PORTC.DIR = (1<<PIN7);
    PORTCFG.CLKEVOUT = 0x01;
    while(1)
    {
    //TODO:: Please write your application code
    }
    }
    ich habe ober Prg. testen.bei PC7 gemessen. nur 2Mhz nicht 32 Mhz .wo ist die Hack? damit P7 32 MHz messen kann?

    1. Du legst mit

      void Clock_init(void)
      {
      OSC.CTRL |= OSC_RC32MEN_bm;
      while(!(OSC.STATUS & OSC_RC32MRDY_bm));
      CCP = CCP_IOREG_gc;
      CLK.CTRL = 0×01;
      }

      ein Unterprogramm fest, welches „Clock_init“ heißt aber du rufst es nie auf. Dadurch kann der Controller nicht auf den internen Oszillator wechseln.
      Schreib das mal so:

      main(void)
      {

      OSC.CTRL |= OSC_RC32MEN_bm;
      while(!(OSC.STATUS & OSC_RC32MRDY_bm));
      CCP = CCP_IOREG_gc;
      CLK.CTRL = 0×01;

      PORTC.DIR = (1<

  2. PLL getest, zeigt aber keine 48MHz.
    main(void)
    {

    /*OSC.CTRL |= OSC_RC32MEN_bm;
    while(!(OSC.STATUS & OSC_RC32MRDY_bm));
    CCP = CCP_IOREG_gc;
    CLK.CTRL =CLK_SCLKSEL_RC32M_gc;
    CCP = CCP_IOREG_gc;*/
    OSC.PLLCTRL = OSC_PLLSRC_RC32M_gc|0x06;
    OSC.CTRL|= OSC_PLLEN_bm;
    while (!(OSC.STATUS & OSC_PLLRDY_bm));

    CCP = CCP_IOREG_gc;
    CLK.CTRL = CLK_SCLKSEL_PLL_gc;

    PORTC.DIR = (1<<PIN7);
    PORTCFG.CLKEVOUT = 0x01;
    while(1)
    {
    //TODO:: Please write your application code
    }
    }

    1. Du musst für die PLL ja auch erst den 32MHz Takt initialisieren und danach erst die PLL.
      Wie soll die PLL den mit dem 32MHz Oszillator arbeiten wenn du diesen nicht einschaltest?

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.