Forum: Mikrocontroller und Digitale Elektronik Problem mit RTC bei STM32F103


von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ich versuche, an einem STM32F103 die RTC mit dem 32-kHz-Quarz in Betrieb 
zu nehmen.

Ich habe mir aus Datenblatt sowie Beispielcode das hier als 
Initialisierung heraus gepuzzelt:
1
void init_RTC(void)
2
{
3
    PWR->CR |= PWR_CR_DBP;
4
5
    while ((RTC->CRL & RTC_CRL_RTOFF) == 0) { /* wait */ }
6
    RTC->CRL |= RTC_CRL_CNF;
7
8
    RTC->PRLH = 0;
9
    RTC->PRLL = 0x7FFF; // 1-second prescaler
10
    RTC->CRL &= ~RTC_CRL_SECF;
11
    RTC->CRH = RTC_CRH_SECIE;
12
13
    RTC->CRL &= ~RTC_CRL_CNF;
14
15
    PWR->CR &= ~PWR_CR_DBP;
16
17
    while ((RTC->CRL & RTC_CRL_RTOFF) == 0) { /* wait */ }
18
19
    NVIC_ClearPendingIRQ(RTC_IRQn);
20
    NVIC_EnableIRQ(RTC_IRQn);
21
}

Problem: wenn ich das so durchlaufen lasse, wird das RTOFF-Bit in der 
zweiten Schleife nie gesetzt. Wenn ich mit dem Debugger 
einzelschrittweise durch die Zeilen steppe, bleibt es dagegen die ganze 
Zeit gesetzt, und alles funktioniert am Ende wie gewünscht.

Ist also offenbar irgendeine zeitliche Restriktion, die ich übersehen 
haben muss, aber welche?

ps: Bitte keine Antworten a la "mit Framework XYZ funktioniert das" – 
ich möchte gern die Hardware verstanden haben. Da hilft mir irgendein 
Framework nicht.

: Bearbeitet durch Moderator
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Ich vermisse das Anschalten des LSE im RCC_BDCR Register (Bit LSEON). 
Danach sollte man in einer Schleife nach LSE_RDY fragen, bis der 
Oszillator soweit ist. (Im RM0008 auf Seite 115).
 Letztlich schaltet man da auch die RTC ein (Bit 15 im RCC_BDCR).

Machst du das woanders?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Matthias S. schrieb:
> Machst du das woanders?

Ja, im init_clock() zuvor. Scheint ja auch funktioniert zu haben, denn 
wenn ich die obigen Zeilen Einzelschritt durchgehe, dann läuft es ja 
hernach wie erwartet.
1
void init_clock(void)
2
{
3
    // Conf clock : 64MHz using HSE 16MHz crystal w/ PLL X 4 (16MHz x 4 = 64MHz)
4
    FLASH->ACR      |= FLASH_ACR_LATENCY_2; // Two wait states, per datasheet
5
    RCC->CFGR       |= RCC_CFGR_PPRE1_2;    // prescale AHB1 = HCLK/2
6
    RCC->CR         |= RCC_CR_HSEON;        // enable HSE clock
7
    while( !(RCC->CR & RCC_CR_HSERDY) );    // wait for the HSEREADY flag
8
9
    RCC->CFGR       |= RCC_CFGR_PLLSRC;     // set PLL source to HSE
10
    RCC->CFGR       |= RCC_CFGR_PLLMULL4;   // multiply by 4
11
    RCC->CR         |= RCC_CR_PLLON;        // enable the PLL
12
    while( !(RCC->CR & RCC_CR_PLLRDY) );    // wait for the PLLRDY flag
13
14
    RCC->CFGR       |= RCC_CFGR_SW_PLL;     // set clock source to pll
15
16
    while( !(RCC->CFGR & RCC_CFGR_SWS_PLL) );    // wait for PLL to be CLK
17
18
    SystemCoreClockUpdate();                // calculate the SYSCLOCK value
19
20
    // disable write protection on backup domain registers
21
    RCC->APB1ENR    |= RCC_APB1ENR_PWREN;   // enable clock for Power interface
22
    PWR->CR         |= PWR_CR_DBP;
23
    RCC->BDCR       |= RCC_BDCR_LSEON;      // enable LSE clock (32 kHz crystal)
24
    while( !(RCC->BDCR & RCC_BDCR_LSERDY) ); // wait for LSE clock stabilized
25
    RCC->BDCR       |= RCC_BDCR_RTCSEL_LSE | RCC_BDCR_RTCEN; // select LSE as RTC clock source
26
    PWR->CR         &= ~PWR_CR_DBP;         // write-protect
27
}

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Jörg W. schrieb:
> Ja, im init_clock() zuvor.
Gut :-)

Hmm, leider bin ich mit der RTC im F103 nicht so bewandert. Ich weiss 
nur, das ich beim F429 erst die Clocksource wähle und später dann die 
Uhr freigebe:
1
// use the low freq. crystal
2
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
3
  RCC_RTCCLKCmd(ENABLE);
Das ist mit SPL, aber das Prinzip bleibt. Vllt. darf man nicht beides 
gleichzeitig machen.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Matthias S. schrieb:
> Das ist mit SPL, aber das Prinzip bleibt. Vllt. darf man nicht beides
> gleichzeitig machen.

Ich glaube, ich hatte das vorher getrennt. Das gemeinsame Setzen habe 
ich mir vom Keil-Beispielcode abgeguckt, bisschen in der Hoffnung, dass 
das was ändern würde (da man ja für das Ändern der Clocksource später 
einen backup domain reset bräuchte).
1
  if ((__RTC_CLKSRC_VAL & RCC_BDCR_RTCSEL) == 0x00000100) {     // LSE is RTC clock source
2
    RCC->BDCR |= RCC_BDCR_LSEON;                                // enable LSE
3
    while ((RCC->BDCR & RCC_BDCR_LSERDY) == 0);                 // Wait for LSERDY = 1 (LSE is ready)
4
  }
5
6
  if ((__RTC_CLKSRC_VAL & RCC_BDCR_RTCSEL) == 0x00000200) {     // LSI is RTC clock source
7
    RCC->CSR |= RCC_CSR_LSION;                                  // enable LSI
8
    while ((RCC->CSR & RCC_CSR_LSIRDY) == 0);                   // Wait for LSERDY = 1 (LSE is ready)
9
  }
10
11
  RCC->BDCR |= (__RTC_CLKSRC_VAL | RCC_BDCR_RTCEN);             // set RTC clock source, enable RTC clock

__RTC_CLKSRC_VAL ist bei denen entweder 0x100 für LSE oder 0x200 für 
LSI.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Wenn ich ihn nach den Einzelschritten weiter laufen lasse, ist er 
durchaus stabil. Der Zähler zeigt eine Periode von 1,9999289 s an 
(Periodendauer der blinkenden LED), die Anzeige wackelt höchstens mal in 
der letzten Stelle. Das sieht schon nach Quarz aus, nicht nach LSI oder 
sowas. Die Frequenz ist 35 ppm zu niedrig, hmm. Muss ich mal gucken, ob 
er noch anschwingt, wenn ich die Last-Cs kleiner mache.

von Sonntag (Gast)


Lesenswert?

Ich hatte den Fall, dass der RTC nicht immer anlief, wenn die 
Onboard-LED leuchtete. Die Ströme sind extrem niedrig. Bei schlechten 
Schwingkreisen reichen dann kleinste Kleinigkeiten. Kannst Du den Test 
mit einen anderen STM32 wiederholen?

von Johannes S. (Gast)


Lesenswert?

zum Quarz gibt es eine AN von ST, da sind die STM32 sehr 
unterschiedlich. Bei den neueren Serien kann man sogar den Treiber für 
verschiedene Lasten konfigurieren.

von Stefan F. (Gast)


Lesenswert?

Du machst einige Registerzugriffe in einer anderen Reihenfolge als ich 
und hast weniger "waits" drin. Vergleiche das mal mit meinem Beispiel: 
http://stefanfrings.de/stm32/stm32f1.html#rtc

Falls du ein Blue-Pill Board verwendest, entferne die beiden Stifte an 
den Pins PC14 und PC15.

Beitrag #6810827 wurde vom Autor gelöscht.
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Das ist kein Bluepill, sondern der Controller ist 'ne Nummer größer 
(pinzahlmäßig), aber ich habe mich weitgehend an die Schaltung vom 
Bluepill gehalten.

Dass der Controller sehr mimosenhaft bezüglich des 32-kHz-Quarzes ist, 
ist mir schon aufgefallen: eine Serie SMD-Quarze aus der Bastelkiste, 
von denen ich ein paar Dutzend habe und die mit AVRs immer klaglos 
funktioniert haben, funktioniert hier gar nicht, der Quarz schwingt 
nicht an. Jetzt habe ich zwei verschiedene ausgelötete benutzt und 2 x 
10 pF als Last-Cs. Der eine ist ein SMD-Quader, der schafft es offenbar 
nicht immer, aber meist gerade so mit dem Anschwingen. Der andere ist 
ein (THT-)Stabquarz, vermutlich mal aus 'ner alten Uhr ausgeschlachtet, 
der tut's besser.

Beide schwingen aber zu langsam, der Stabquarz liegt so bei -22 ppm. 
Wenn ich die Last-Cs ganz weglasse, schwingen sie jedoch auch nicht.

Mit bissel Experimentieren mit dem Breakpoint im Debugger, habe ich nun 
gefunden, dass diese Reihenfolge offenbar geht:
1
    RTC->CRL &= ~RTC_CRL_CNF;
2
3
    while ((RTC->CRL & RTC_CRL_RTOFF) == 0) { /* wait */ }
4
5
    PWR->CR         &= ~PWR_CR_DBP;

Also erst das CNF in RTC->CRL löschen, dann warten bis RTOFF gesetzt, 
dann das DBP in PWR->CR zurück nehmen. Dass man DBP setzen muss, um an 
den RTC-Registern etwas zu ändern, ist dokumentiert. Dass das vorzeitige 
Zurücknehmen jedoch offensichtlich auch interne Schreibzugriffe (das 
Setzen von RTOFF) verhindert und nicht etwa nur die von der CPU, steht 
dagegen nirgends. Wäre allerdings nach all dem die logische Erklärung 
dafür. Lesbar sind die RTC-Register ja auch danach immer noch.

Danke an alle für die Rückmeldungen!

von Stefan F. (Gast)


Lesenswert?

Jörg W. schrieb:
> Dass das vorzeitige Zurücknehmen jedoch offensichtlich
> auch interne Schreibzugriffe (das Setzen von RTOFF) verhindert
> und nicht etwa nur die von der CPU, steht dagegen nirgends.

Mit solchen Überraschungen geizen die STM32 alle nicht. AVR sind mir in 
dieser Hinsicht deutlich angenehmer.

von 900ss (900ss)


Lesenswert?

Jörg W. schrieb:
> der Stabquarz liegt so bei -22 ppm.

Es gibt da ein Register für das Finetuning der RTC zum Ausgleichen der 
Abweichung.
Bei meiner Scopeuhr hab ich das damals genutzt und es funktionierte 
recht gut. Aber frag mich nicht, welches Register, ist zu lange her ;)

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ja, in Software tunen geht irgendwie immer.

Wundert mich nur, dass sie trotz recht kleiner Cs so weit im Minus 
liegen.

von 900ss (900ss)


Lesenswert?

Jörg W. schrieb:
> Software tunen

Nee, hier geht es auch in Hardware. Dafür haben sie ein Register 
eingebaut, der lässt Finetung der RTC Counter zu. Da brauchst du zum 
Tunen keine SW.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Da sehe ich beim STM32F103 nichts in so einer Richtung. Es gibt 
prescaler load, prescaler divider, counter und alarm als Register in der 
RTC.

Vielleicht haben größere STM32 da mehr Spielraum.

Aber, ich sehe gerade, Denkfehler: die Frequenz ist zu hoch. Man könnte 
also mit größeren Cs noch was machen, allerdings dürfen die Cs laut 
Datenblatt maximal 15 pF groß werden. Das schränkt schon ziemlich stark 
ein.

: Bearbeitet durch Moderator
von 900ss (900ss)


Lesenswert?

Ja, stimmt. Hab jetzt nachsehen können.
Hab bei mir folgendes gefunden, also über den Prescaler hab ich es 
gemacht.
1
/* Set RTC prescaler: set RTC period to 1sec */
2
  RTC_SetPrescaler(32770); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
3
                           /* Attention: add 3 due to a too fast clock speed */

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

900ss D. schrieb:
> Hab bei mir folgendes gefunden, also über den Prescaler hab ich es
> gemacht.

Naja, eine Änderung von 1 im Prescaler entspricht einer Justage von 30 
ppm. Das ist schon arg grob.

von 900ss (900ss)


Lesenswert?

Bei mir passte es damit. Hatte ich Glück. Ist es halt Grobtuning ;)

von Stefan F. (Gast)


Lesenswert?

Dafür hat der STM32F103 zwei andere Register mit denen man viel feiner 
abstimmen kann: http://stefanfrings.de/stm32/stm32f1.html#rtc_calibrate

von 900ss (900ss)


Lesenswert?

Sonst gibt es ja noch den Artikel "die genaue Sekunde" von peda glaube 
ich ;)

von Stefan F. (Gast)


Lesenswert?

Sorry, es ist nur ein "weiteres" Register.

von 900ss (900ss)


Lesenswert?

Stefan ⛄ F. schrieb:
> viel feiner abstimmen kann

Irgendwie war mir auch so, ich hab es aber mit dem Prescaler 
hinbekommen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

BKP->RTCCR - ja. Nur seltsam, warum das Dingens in BKP sitzt und nicht 
in RTC. In der gesamten RTC-Dokumentation kein Hinweis drauf. Pah.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

So, habe nochmal Cs getauscht. Fühle mich ruhiger, wenn der Quarz nahe 
am Sollwert ist, denn dann ist die Chance gut, dass er die korrekte Last 
sieht. Das eine Board ist mit dem Maximum von 2 x 15 pF immer noch bei 
+14 ppm, das andere (mit dem Stab-Quarz) ist mit 15/12 pF bei +3 ppm.

von Stefan F. (Gast)


Lesenswert?

Jörg W. schrieb:
> Nur seltsam, warum das Dingens in BKP sitzt und nicht in RTC.

Beim STM32F103 ist einiges seltsam. Man merkt dass es der erste 
"Versuch" dieses Herstellers war. Der STM32F303 ist schon deutlich 
logischer aufgebaut.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Jörg W. schrieb:
> Fühle mich ruhiger, wenn der Quarz nahe
> am Sollwert ist, denn dann ist die Chance gut, dass er die korrekte Last
> sieht.

Wenn du einen hochohmigen Tastkopf hast, könntest du den Pegel ja live 
überprüfen und auch zuschauen, wie er anschwingt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Matthias S. schrieb:
> Wenn du einen hochohmigen Tastkopf hast, könntest du den Pegel ja live
> überprüfen und auch zuschauen, wie er anschwingt.

Habe ich, aber den erst auszubuddeln, war ich zu faul. ;-)

von Christian J. (Gast)


Lesenswert?

Jörg W. schrieb:
> So, habe nochmal Cs getauscht. Fühle mich ruhiger, wenn der Quarz nahe
> am Sollwert ist, denn dann ist die Chance gut, dass er die korrekte Last
> sieht

Jörsch,
frickel nicht so viel da herum.... ich habe die Pillen seit Frühjahr im 
Auto vorne am Laufen beim GPS Logger. So ab ca 30 Grad Temperatur laufen 
die Quarze gar nicht mehr an. Und bei jedem gefühlt 100.ten Einschalten 
auch nicht.
Das ist eben so..... lieber einen Quarzoscillator nehmen wenn es drauf 
ankommt. Ist bei meinem GPS aber wumpe, die Uhrzeit kommt aus dem SAT 
und wird jeden Tag neu gestellt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Das gehörte noch zum sportlichen Ehrgeiz. ;-)

Habe bei der Gelegenheit mal wieder üben dürfen, wie ich mit dem alten 
Ч3-54 Periodendauern messe. Vielleicht kann ich mir's ja merken, bis ich 
die Funktion das nächste Mal benötige …

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.