Das Clocksystem

XMega Blockdiagramm

Der XMega besitzt, im Gegensatz zum Mega8, 16 und 32, ein sehr umfangreiches System um den Systemtakt zu generieren. Es besteht die Möglichkeit einen internen 2MHz und 32MHz Oszillator, einen ULP Oszillator für den Watchdog Timer, eine PLL mit einem Multiplikator von x1-x31 oder einen internen 32kHz Takt zu verwenden. Dieser Takt kann außerdem noch mit einen Clock Prescaler um einen Faktor bis zu 2048 heruntergeteilt werden. Desweiteren besteht die Möglichkeit einen 0,4MHz – 16MHz Quarz, ein 32kHz Quarz oder einen externen Taktgeber anzuschließen. Die internen Taktquellen können außerdem 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 auf dieses Bild äußerst ratsam:

XMega ClocksystemAuf 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. Das komplette Handling des Clocksystems geschieht per Software (ein Vorteil ist, dass man sich nun nicht mehr mit dem Clock-Fusebit vertun kann, weil es das ja nicht mehr gibt ;) ).
Ich fange zuerst mit den internen Oszillatoren an. Nach einem Reset ist automatisch der interne 2MHz Oszillator aktiv.
Die Einstellungen für den Takt befinden sich im Clock-Control-Register und im Oscillator-Control-Register.

-> Auswählen 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 32MHz 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 32MHz Oszillator als Taktquelle ausgewählt wird.
Um wieder den 2MHz Oszillator auszuwählen kann dasselbe Programm verwendet werden, nur muss das Bitmuster auf das der 2MHz Taktquelle geändert werden.

-> Auswählen 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 16MHz Quarz mit einer Start-up Time von 16CLK sieht der Codeschnipsel dementsprechend 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 49MHz arbeitet (die PLL kann theoretisch 200MHz). In Kombination mit einem externen 16MHz Quarz bietet sich so die Möglichkeit sich einen 32MHz Takt zu erzeugen der auch noch genauer ist als der interne RC Oszillator mit 32MHz.
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 32MHz 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 32MHz 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.

Achtung!
Wer sich das oben stehende Bild vom Clock System aufmerksam angschaut hat, wird sicher auch schon festgestellt haben, dass der interne 32MHz 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 (danke an den User robin aus dem Roboternetz).
Verwendet man diesen Takt jedoch als direkte Taktquelle wird direkt der 32MHz Takt benutzt.
Aus diesem Grund erzeugt die PLL mit einem Multiplikator von 6 auch keinen Takt von 6 x 32MHz also 192MHz, sondern einen Takt von 6 x (32MHz/4) = 48MHz.
Beim internen 2MHz Takt muss man dies nicht beachten. Falls mir jemand eine Erklärung dafür geben kann warum nur der 32MHz Takt durch 4 geteilt wird bevor er in die PLL geht kann er sie mir gerne per E-Mail senden. Ich kann mir leider keinen Reim darauf machen ;).

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 48MHz (und wie aus dem Bild des Clocksystems zu erkennen ist, wird dieser Takt auch für die Timer usw. verwendet. Dies sollte man bei der Berechnung der Registerwerte für z.B. Timer nicht vergessen ;) ).

 

-> Zurück zum XMega Tutorial

9 thoughts on “Das Clocksystem
    • 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?

    • 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
    }
    }

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

Time limit is exhausted. Please reload CAPTCHA.