PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : xmega rtc + pll



Thalhammer
22.02.2013, 19:33
Hallo,
Ich habe ein Problem mit meinem Xmega 32a4:
Ich wollte heute die RTC ausprobieren, was in einem Standalone Programm auch funktionierd hat.
Dann hab ich sie in mein Programm eingebaut und plötzlich geht nichts mehr.
Die RTC löscht das Busy Flag nicht mehr, also Fehler suche:
Jetzt bin ich so weit, das ich den Fehler auf die PLL eingrenzen konnte.
In meinem Hauptprogramm verwende ich diese um aus meinem 16MHz externem Quarz die 32 MHz für den uc bereitzustellen.
Verwende ich eine andere Taktquelle,(2MH intern/32MHz intern/16MHz Quarz) so macht sie was sie soll, nur bei der PLL bleibt sie stehen.
Wie kann das sein ?
Die RTC verwendet doch eine ganz andere Taktquelle(bei mir 32khz intern) ?
Ich habe im Datenblatt keinen Hinweis der gleichen gefunden.
Mein Hauptprogramm:
// Init clocking (32Mhz generated from 16Mhz external)
// Init clocking (32khz generated internaly for RTC)
Clock_init(CLOCK_EXTERNAL);
PLL_init();
Clock_init_rtc();
// Wait and init RTC clock
while ( RTC_Busy() ){};
RTC_Initialize( 1024, 0, 0, RTC_PRESCALER_DIV1_gc );
RTC_SetIntLevels( RTC_OVFINTLVL_LO_gc, RTC_COMPINTLVL_OFF_gc );
// Enable all interrupt levels
PMIC.CTRL |= PMIC_LOLVLEN_bm;
// Enable global interrupts
sei();
// Set Led as output
PORTE.DIRSET=(1<<PIN3);
while(1)
{
}
}

/*! \brief RTC overflow interrupt service routine.
*
* Called every second
*/
ISR(RTC_OVF_vect)
{
PORTE.OUTTGL=(1<<PIN3);
}

Meine Clock routinen:


void Clock_init(uint8_t source)
{
if(source==CLOCK_INTERNAL_2){
/*Internal 32MHz */
OSC.CTRL |= OSC_RC2MEN_bm;
while(!(OSC.STATUS & OSC_RC2MRDY_bm));
CCP = CCP_IOREG_gc;
CLK.CTRL = CLK_SCLKSEL_RC2M_gc;
}else if(source==CLOCK_INTERNAL_32){
/*Internal 32MHz */
OSC.CTRL |= OSC_RC32MEN_bm;
while(!(OSC.STATUS & OSC_RC32MRDY_bm));
CCP = CCP_IOREG_gc;
CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
}else if(source==CLOCK_EXTERNAL){
/* External Clock */
OSC_XOSCCTRL = OSC_XOSCSEL_XTAL_16KCLK_gc | OSC_FRQRANGE_12TO16_gc;
OSC.CTRL |= OSC_XOSCEN_bm;
while(!(OSC.STATUS & OSC_XOSCRDY_bm));
CCP = CCP_IOREG_gc;
CLK.CTRL = CLK_SCLKSEL_XOSC_gc;
}
CCP = CCP_IOREG_gc;
CLK.PSCTRL=0x00;
}

void PLL_init()
{
OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 0x08;
OSC.CTRL |= OSC_PLLEN_bm;
while (!(OSC.STATUS & OSC_PLLRDY_bm));
CCP = CCP_IOREG_gc;
CLK.PSCTRL=0x03;
CCP = CCP_IOREG_gc;
CLK.CTRL = CLK_SCLKSEL_PLL_gc;
}

/* \brief Initiates the 32khz clock needed for the RTC.
*/
void Clock_init_rtc()
{
/* Turn on internal 32kHz. */
OSC.CTRL |= OSC_RC32KEN_bm;

do {
/* Wait for the 32kHz oscillator to stabilize. */
} while ( ( OSC.STATUS & OSC_RC32KRDY_bm ) == 0);


/* Set internal 32kHz oscillator as clock source for RTC. */
CLK.RTCCTRL = CLK_RTCSRC_RCOSC_gc | CLK_RTCEN_bm;
}

Was mache ich an der PLL falsch ?
Die RTC Routinen sind aus der Atmel Appnote und funktionieren auch.

MFG Thalhammer

Kampi
22.02.2013, 19:46
Hey,

schau mal hier habe ich eine Anleitung geschrieben wie man die RTC vom XMega nutzt:

http://kampis-elektroecke.de/?page_id=1879

Das Thema PLL wird hier abgehandelt:

http://kampis-elektroecke.de/?page_id=883

Vielleicht hilft dir das ja weiter :)

Thalhammer
22.02.2013, 19:51
Genau genommen hab ich nach deinen Tutorials und den Appnotes gearbeitet(Vileicht fällt dir auch die namens gleichheit mit dem Hinweis auf den Fehlenden USART Beispielcode auf :)).
Das Problem ist halt das es nur solange funktionierd wie ich den PLL nicht nutze.
kommentiere ich die Zeile aus läuft es prima, sobald sie drin ist bleibt er bei der RTC_busy schleife stehen.

Kampi
22.02.2013, 20:07
Ich nehme mal an du kommentierst die Zeile "PLL_init();" aus?

Thalhammer
22.02.2013, 20:11
Ich nehme mal an du kommentierst die Zeile "PLL_init();" aus?
Ja genau.
So ich konnte jetzt den Fehler noch weiter eingrenzen:
Ich habe die PLL auf 128MHz konfiguriert (Multi 8) und dann einen Prescaler von 4 um auf
32MHz CPU Takt zu kommen, da ich für die Hires Erweiterung 128MHz Per4 Takt brauche.
Hab jetzt testweise die PLL auf Multi 2 gestellt und den Prescaler auf 0 und dann geht die RTC auch.
Es liegt also garnicht an der PLL direkt sondern an der Kombi aus Multi 8 und Prescaler.
Aber eigentlich dürfte doch keinen Einfluss haben ?

Kampi
22.02.2013, 20:21
Schau dir mal auf Seite 80 das Bild an:

http://www.atmel.com/Images/doc8077.pdf

Außerdem dividiert die Zeile

CLK.PSCTRL = 0x03

durch 4 und nicht durch 8 (siehe Seite 88).
Durch 8 wäre 101 = 5.
Laut Bild sollte der RTC Clock aber komplett unabhängig von dem SysCLK sein....

Edit:

Mir ist gerade eingefallen, dass der XMega nur bis zu einem bestimmten Takt zuverlässig läuft. Vielleicht waren die 128MHz einfach zu fix und die PLL konnte sich nicht stabilisieren?
Der Multiplikator ist auch, denk ich mal, nur dafür ausgelegt um aus einem langsamen Takt 32MHz machen zu können und nicht um 32MHz auf was weiß ich hoch zu drehen.
Ich vermute ganz stark, dass die PLL einfach nur nicht das PLL-Ready Bit gesetzt hat, weil der Takt vielleicht nicht sauber war.

Thalhammer
22.02.2013, 20:32
Außerdem dividiert die Zeile
CLK.PSCTRL = 0x03
durch 4 und nicht durch 8 (siehe Seite 88).
Soll sie ja auch:
Ich hab ein Quarz mit 16Mhz--->PLLSRC=XTAL,16MHz
Rauskommen soll 32Mhz CPU plus 128MHz PER
--->16Mhz mal 8(PLL Multi)=128MHz
--->128MHz geteilt durch 4 (CPU_CLOCk Prescaler) =32MHz
folglich CPU=32MHz
PER=128Mhz


Laut Bild sollte der RTC Clock aber komplett unabhängig von dem SysCLK sein....
Und genau das ist ja was ich die ganze Zeit versuche zu erklären!!!!!!!!!
Sie sollte, ist sie bei mir aber nicht, denn sobald ich den PLL auf 128MHz setze und die Frequenz runterteile bleibt das Programm bei der RTC stehen.
Für die Prescaler siehe abbildung 7-5 auf seite 83.
Demnach ist 0x03=ob00000011=Prescaler B und C je 2----->
Per4=128MHz
Per2=128MHz/2=64MHz
PER+CPU=128MHz/2/2=64MHz/2=32MHz

//EDIT:
Hab jetzt ein wenig rumgespielt: biszu einer PLL von 7 läuft alles Perfekt stelle ich jedoch auf 8 so läuft die RTC replizierbar nciht an.
Ich werde morgen eine 2.te Platine Ätzen und schaun obs dort geht, aber ich gehe nicht davon aus.
Ich frage mich nur wie das sein kann, da die RTC ja eigentlich vollkommen unabhängig vom normalen Takt sein sollte.

Kampi
22.02.2013, 20:37
Soll sie ja auch:
Ich hab ein Quarz mit 16Mhz--->PLLSRC=XTAL,16MHz
Rauskommen soll 32Mhz CPU plus 128MHz PER
--->16Mhz mal 8(PLL Multi)=128MHz
--->128MHz geteilt durch 4 (CPU_CLOCk Prescaler) =32MHz
folglich CPU=32MHz
PER=128Mhz


Und genau das ist ja was ich die ganze Zeit versuche zu erklären!!!!!!!!!
Sie sollte, ist sie bei mir aber nicht, denn sobald ich den PLL auf 128MHz setze und die Frequenz runterteile bleibt das Programm bei der RTC stehen.
Für die Prescaler siehe abbildung 7-5 auf seite 83.
Demnach ist 0x03=ob00000011=Prescaler B und C je 2----->
Per4=128MHz
Per2=128MHz/2=64MHz
PER+CPU=128MHz/2/2=64MHz/2=32MHz

Ok das mit dem Teilen habe ich missverstanden.
Dachte du meintest der würde da schon durch 8 teilen :)
Aber ich habe meinen Beitrag noch editiert....vielleicht ist das die Lösung. Sicher bin ich mir da nicht aber es klingt (in meinen Augen) logisch.
Weiß auch nicht mehr wo ich das gelesen habe mit der max. Frequenz vom Chip....ich glaube bei AVR Freaks.
Das Problem ist definitiv nicht die RTC sondern die PLL und wie gesagt das kann gut daran liegen, dass die sich nicht locken kann.

Thalhammer
22.02.2013, 20:52
Das Problem ist definitiv nicht die RTC sondern die PLL und wie gesagt das kann gut daran liegen, dass die sich nicht locken kann.
Die PLL läuft ja mit 128MHz, was sie laut Datenblatt auch kann (siehe seite 71):

PLL with 20MHz - 128MHz output frequency

– Internal and external clock options and 1x to 31x multiplication

• Clock prescalers with 1x to 2048x division

• Fast peripheral clocks running at 2 and 4 times the CPU clock


Demnach kann die PLL biszu 128MHz erzeugen und der Peripherie bereitstellen, was auch funktionierd.
Das Programm bleibt aja auch nicht bei der aktivierung der PLL hängen, sondern direkt danach bei der zeile:
while ( RTC_Busy() ){};
Wass daran liegt, dass die RTC sich nicht mit der CPU synchronisieren kann. (Seite 190 Abbildung 7.3.2).
Ich stell jetzt mal die PLL auf den internen 2MHz um und schau was passiert.
Also beim internen 2Mhz läuft das ganze mit 31x PLL noch, was aber daran liegt das da nur 62Mhz PLL frequenz rauskommen.

Ich glaub ich finde mich damit ab, das die RTC bei so hohen PER clocks nicht mehr geht und lager die Funktion auf meinen ARM aus.
Mal schaun wie das bei den Atxmega128A1 ist, den ich hier hab und der darauf wartet zu einem Devboard verarbeitet zu werden, aber für meinen Dimer ist mir der Aufwand hier zu groß. zumal ich feststellen musste, das die RTC (wennse den mal geht) ohne Calibrirung nach 30minuten schon 15sekunden nach ging, das sind 1 sek abweichung pro 2 minuten oder 12 minuten pro tag!
Aber danke für deine Hilfe, ich komm vielleicht nochmal drauf zurück :-)

Kampi
22.02.2013, 21:14
Ändere mal

do {
} while ....

in

while (OSC.STATUS & (OSC_RC32KEN_bm))

bzw. die Busy-Zeile in

while(RTC.STATUS & RTC_SYNCBUSY_bm)

um und probier es nochmal.

Edit:
Die Busy Zeile sieht so aus als ob du da eine Funktion aufrufst?
RTC_Busy() ist doch ein Unterprogramm oder Funktionsaufruf?

Thalhammer
22.02.2013, 21:22
Die RTC_busy ist ein Makro und damit genau was du gepostet hast:


/*! \brief This macro checks the RTC busy flag.
*
* \return Non-Zero if RTC is busy, zero otherwise.
*/
#define RTC_Busy() ( RTC.STATUS & RTC_SYNCBUSY_bm )

Ich kanns ändern, kann mir aber nicht vorstellen das es was bringt.
//EDIT: Wie erwartet, keine änderung.
Läge es daran würde es ja mit weniger Takt auch nicht gehen oder ?

Kampi
22.02.2013, 21:37
Die RTC_busy ist ein Makro und damit genau was du gepostet hast:


/*! \brief This macro checks the RTC busy flag.
*
* \return Non-Zero if RTC is busy, zero otherwise.
*/
#define RTC_Busy() ( RTC.STATUS & RTC_SYNCBUSY_bm )

Ich kanns ändern, kann mir aber nicht vorstellen das es was bringt.
//EDIT: Wie erwartet, keine änderung.
Läge es daran würde es ja mit weniger Takt auch nicht gehen oder ?

Auch wieder wahr.....
Kann mir auch keinen Reim drauf machen.
Ich hatte das bei mir mit PLL und etwa 48MHz internen Osz getestet und es ging super....hatte aber auch einen externen Takt an der RTC.
Liegt es vielleicht daran?

- - - Aktualisiert - - -


Auch wieder wahr.....
Kann mir auch keinen Reim drauf machen.
Ich hatte das bei mir mit PLL und etwa 48MHz internen Osz getestet und es ging super....hatte aber auch einen externen Takt an der RTC.
Liegt es vielleicht daran?

Edit:
Wobei was evtl. sein kann....
Wenn du sagst, dass die PLL bis zu einem Faktor 7 arbeitet und dann auch noch die RTC funktioniert und du sagst, dass danach die RTC beim Busy Flag hängt, kann es dann nicht auch einfach nur sein, dass die RTC sich nicht mit dem SysClock synchronisieren kann?
Ich meine du bastelst da am Takt rum und die RTC läuft nur mit einem internen Oszillator (der, wie du festgestellt hast, nicht sehr genau ist ^.^).
Das wäre eine weitere Theorie von mir.....würde mich interessieren ob das Problem weg ist wenn du ein externes Uhrenquarz an die RTC hängst.
Weil wie du auf dem Bild gesehen hast, sind die beiden Clocks komplett unabhängig....das heißt eine Änderung des Multiplikators der PLL dürfte sowas nicht machen.
Nur der Synch ist die Stelle wo beide Clocks aufeinander treffen....

Thalhammer
22.02.2013, 21:50
.....würde mich interessieren ob das Problem weg ist wenn du ein externes Uhrenquarz an die RTC hängst.

Kann ich leider nicht testen, da 1. die Pins nciht rausgefürt hab auf der Platine und 2. keine entsprechenden Quarz da hab.
Naja ob ich die CPU nun mit 32MHz intern oder 32MHz extern mit PLL 2 und Prescaler 1 oder 32Mhz extern mit PLL 8 und prescaler 4 habe dürfte ja eigentlich keinen unterschied machen, da die CPU jedesmal mit 32Mhz läuft, ich keine werte des xmegas überschritten hab und der Takt der RTC eigentlich auch jedesmal gleich sein sollte.
Wie dem auch sei, für ein zusätzliches Quarz hab ich weder platz noch geld(ich müsste nach bestellen, und wenn ich mal über dem sortiment von reichelt sitz kommen immer leicht 80-100€ zusammen) und auserdem hab ich ne fritzbox als Host, die zwar auch kein Uhrenquarz hat, aber dafür alle 10minuten die Zeit vom Internet holt.
Fakt ist jedenfalls das mein code keinen Fehler hat und das wollte ich eigentlich nur wissen, warum dieses blöde ding im zusammenhang mit hohen per4 frequenzen nicht geht ist mir dann auch relativ egal, den ich denke die meisten die eine RTC brauchen, werden die Hires oder Awex module eh nicht nutzen und was anderes braucht keinen so hohen takt.
Danke für deine Hilfe auch wenns das Problem nicht gelöst hat, aber dafür kannst du ja nichts ;)

Kampi
22.02.2013, 21:57
Naja einen Unterschied zwischen intern 32Mhz und extern 16Mhz * 2 hast du nur durch die Genauigkeit des Taktes ;)
Der CPU ist es egal wie du die 32MHz generierst da hast du recht.
Schade das du das mit der RTC nicht testen kannst :( aber gut....war halt nur Neugierig ;)
Wie schon gesagt u.U. sind es vlt einfach nur Toleranzen? Fehler habe ich jetzt keine gesehen....habe den Code 3x mit meinem funktionierenden RTC Code für einen XMega128 abgeglichen und bis auf die Taktquellen ist alles gleich.
Und wie du schon sagtest, wenn du ne FritzBox als Host hast würde ich die eher nehmen....weil 15 Sekunden vor gehen nach 30 Minuten hört sich nicht nach RTC, sondern nach einem Schätzeisen an...und ich bezweifel das es durch eine Kalibration komplett verschwindet. Für wirklich genaue Zeitmessungen ist dann schon ein Quarz wichtig.

Thalhammer
22.02.2013, 22:05
Es wäre halt in verbindung mit einer SD Karte ne schöne funktion gewesen um ein vordefiniertes Programm abzufahren.
Wobei mir da so eine Idee kommt:
Kann man den Compare des Timers irgendwie so schalten, das der dazu gehörige Ausgang nicht verändert wird ?
Den der Xmega hat ja 5 Timer mit 16 Output Compare, 15 davon hab ich auf 5 RGB Kanäle aufgeteilt, den 16. hab ich auf die Onboard LED gelegt, da ich keine Verwendung dafür hatte, die Timer laufen mit vollem CPU Takt und mit einem entsprechendem OC Wert sollte sich doch eine ISR mit einer festen Hz Zahl aufrufen lassen können oder ?
Die dürfte dann auch wesentlich genauer als die RTC sein, da sie ja mit am Quarz hängt.
Ich glaube in den Timer muss ich mich nochmal einlesen.

MFG Thalhammer
PS: Giebts dann auf http://dothal.de zu lesen.
Meine Seite ist zwar noch nicht so umfangreich, aber ich arbeite daran:-)

Kampi
22.02.2013, 22:12
Klar kannst du den Timer für eine RTC verwenden.
Die RTC ist im Grunde nichts anderes außer das diese vom Teiler und vom Eingangstakt für die Aufgabe optimiert wurde (32768kHz Takt bei einer Teilung von 32768 bzw. einem Teiler von 2^15).
Die 32MHz kannst du allerdings nicht so schön auf 1Hz runter teilen, aber je nachdem wie geschickt du die Compare Value wählst und einen Zähler innerhalb der ISR kannst du damit sicher was relativ genaues realisieren (dank Quarz auch genauer als die RTC :D).
Den Compare Ausgang kannst du glaube ich auch abschalten. Ich meine es ist glaube ich nicht Standard das dieser aktiv ist sobald ein Timer aktiv ist. Und ansonsten lass die LED doch blinken :D

Thalhammer
22.02.2013, 22:37
Ne die Led brauch halt für was anderes, das ist das Problem aber ansonsten hab ich ja noch den Overflow interrupt, der hat zwar ne noch bescheuertere Frequenz von 488,28125 Hz aber das könnte man ja rausrechnen.