Problem mit RTC bei STM32F103

OP Moderator Persönliche Seite #6810457
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.
OP Moderator Persönliche Seite #6810581
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
}
(Firma: matzetronics) #6810596
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.
OP Moderator Persönliche Seite #6810614
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.
OP Moderator Persönliche Seite #6810630
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.
Gast #6810640
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?
Beitrag #6810827 wurde von einem Moderator gelöscht.
OP Moderator Persönliche Seite #6810838
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!
OP Moderator Persönliche Seite #6810988
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.
#6810992
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 */
Gast #6811694
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren