Forum: Mikrocontroller und Digitale Elektronik STM32L100 RTC lässt sich nicht einrichten


von Phantomix X. (phantomix)


Lesenswert?

Hallo,

Ich stehe heut wieder mal wie der Ochs' vorm Berg und finde den Fehler 
nicht. Dabei ist es eigentlich eine einfache Sache. Als Controller 
verwende ich STM32F100RB / RC (bei beiden geht es nicht):

Um die RTC einzurichten muss man
- Das INIT bit im ISR-Register setzen
- Auf das INITF bit im ISR-Register warten
- ...
(AN 3371 Rev 4 Seite 7 sowie RM0038 Rev 12 Seite 511)

Eigentlich eine einfache Anweisung, funktioniert aber nicht; das INITF 
bit kommt einfach nicht, egal was ich tue. Das einzige, was ich bis 
jetzt nicht probiert habe, wäre einen Uhrenquarz dranzulöten, es muss 
aber auch mit dem HSE laufen.
1
int main(void)
2
{
3
    init_usart(&debug_uart);
4
    SysTick_Config(SystemCoreClock / 1000);
5
    if(time_rtc_init() == ERROR)
6
    {
7
        DEBUG_PUTS("RTC Error\n");
8
    }
9
    while(1);
10
}
11
12
ErrorStatus time_rtc_init(void)
13
{
14
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
15
16
    PWR_RTCAccessCmd(ENABLE);
17
    RCC_RTCResetCmd(ENABLE);
18
    RCC_RTCResetCmd(DISABLE);
19
                                        // See AN 3371 (Doc ID 018624) Rev 4, p. 7
20
    rtc_write_enable();                 // (1) Write 0xCA, 0x53 into the RTC_WPR register
21
    RTC->ISR |= RTC_ISR_INIT;           // (2) Set INIT bit to '1' in RTC_ISR register
22
23
    tick1ms = 0; //wird im SysTick hochgezaehlt
24
    while(!(RTC->ISR & RTC_ISR_INITF))  // (3) Poll INITF bit of in RTC_ISR until it is set
25
    {
26
        if(tick1ms > 1000) return ERROR;
27
    }
28
29
    #if defined(RTC_HSE) && (RTC_HSE)
30
        RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div16);   //Input = HSE_VALUE/16  -> 1 MHz
31
        RTC->PRER = (uint32_t)(7999);   // (4) Write first the synchronous value and then write the asynchronous
32
        RTC->PRER |= (uint32_t)(124 << 16);
33
    #else
34
        RCC_LSEConfig(RCC_LSE_ON);
35
        tick1ms = 0;
36
        while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
37
        {
38
            if(tick1ms > 1000) return ERROR;
39
        }
40
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
41
42
        RTC->PRER = (uint32_t)(255);    // (4) Write first the synchronous value and then write the asynchronous
43
        RTC->PRER |= (uint32_t)(127 << 16);
44
    #endif
45
46
47
    timestamp_t default_time = { 2015, 01, 01, 00, 00, 00, WDAY_SATURDAY};  //01.01.2000, 00:00:00
48
    rtc_store_time_int(&default_time);  // (5) Set RTC_TR and RTC_DR registers
49
50
    RTC->CR &= ~RTC_CR_FMT; //24h       // (6) Set FMT bit in RTC_CR register
51
    RTC->ISR &= ~RTC_ISR_INIT;          // (7) Clear the INIT bit in the RTC_ISR register
52
    rtc_write_protect();                // (8) Write "0xFF" into the RTC_WPR register
53
    return SUCCESS;
54
}
55
56
void rtc_store_time_int(const timestamp_t* timestamp)
57
{
58
    RTC->DR =       byte_to_bcd(timestamp->year - 2000) << 16
59
                |   timestamp->wday << 13                   //always < 10, so BCD == BIN
60
                |   byte_to_bcd(timestamp->month) << 8
61
                |   byte_to_bcd(timestamp->day);
62
    RTC->TR =       byte_to_bcd(timestamp->hour) << 16
63
                |   byte_to_bcd(timestamp->minute) << 8
64
                |   byte_to_bcd(timestamp->second);
65
}


ST macht in ihrem Code (RTC_EnterInitMode) im Prinzip das gleiche (und 
der Aufruf der Funktion funktioniert bei mir auch nicht - als ob es die 
RTC nicht gäbe, dabei sind die Register da und ich bilde mir ein, sie 
schonmal mit 8facher Geschwindigkeit laufen gesehen zu haben...)

von Phantomix X. (phantomix)


Angehängte Dateien:

Lesenswert?

In einem zweiten Schritt habe ich mal mein STM32L100 discovery board 
geschnappt, dort X3 samt Brücken und Lastkapazitäten bestückt
http://www.st.com/web/catalog/tools/PF259096

ein komplett neues Projekt aufgemacht, (EM-Blocks, siehe Anhang)

und den democode von ST probiert, sowohl mit LSI als auch mit LSE

Ergebnis: trommelwirbel funktioniert NICHT :(
1
void RTC_Config(void)
2
{
3
4
  RTC_InitTypeDef RTC_InitStructure;
5
  RTC_TimeTypeDef  RTC_TimeStruct;
6
7
  /* Enable the PWR clock */
8
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
9
10
  /* Allow access to RTC */
11
  PWR_RTCAccessCmd(ENABLE);
12
13
  /* Reset RTC Domain */
14
  RCC_RTCResetCmd(ENABLE);
15
  RCC_RTCResetCmd(DISABLE);
16
17
  //Enable the LSE OSC
18
  RCC_LSEConfig(RCC_LSE_ON);
19
20
  //Wait till LSE is ready
21
  while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
22
  {
23
  }
24
25
  //Select the RTC Clock Source
26
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
27
28
/*
29
//Start LSI
30
RCC_LSICmd(ENABLE);
31
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
32
{
33
}
34
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
35
*/
36
37
  /* Configure the RTC data register and RTC prescaler */
38
  RTC_InitStructure.RTC_AsynchPrediv = 0x7F;
39
  RTC_InitStructure.RTC_SynchPrediv  = 0xFF;
40
  RTC_InitStructure.RTC_HourFormat   = RTC_HourFormat_24;
41
  RTC_Init(&RTC_InitStructure);
42
43
  /* Set the time to 00h 00mn 00s AM */
44
  RTC_TimeStruct.RTC_H12     = RTC_H12_AM;
45
  RTC_TimeStruct.RTC_Hours   = 0x00;
46
  RTC_TimeStruct.RTC_Minutes = 0x00;
47
  RTC_TimeStruct.RTC_Seconds = 0x00;
48
  RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
49
    /* Enable the RTC Clock */
50
  RCC_RTCCLKCmd(ENABLE);
51
52
  /* Wait for RTC APB registers synchronisation */
53
  RTC_WaitForSynchro();
54
}
55
56
int main(void)
57
{
58
    RTC_Config();
59
60
    while(1)
61
    {
62
63
    }
64
}


Edith: Der LSE funktioniert natürlich, ich komm beim debuggen über die 
Schleife drüber. Er hängt wie gehabt im RTC_EnterInitMode in der SPL, 
bzw. verlässt diese mit ERROR, da das INITF-Flag nicht gesetzt wird.

von Phantomix X. (phantomix)


Lesenswert?

Fehler gefunden!

Die RTC muss eingeschaltet werden, bevor der InitMode benutzt werden 
kann

also direkt nach der Clock config muss ausgeführt werden:
RCC_RTCCLKCmd(ENABLE);

Das taucht weder im Reference Manual, noch in der Application Note von 
ST auf, in den Examples der SPL ist es auch falsch.
So muss es aussehen:
1
...
2
  //Wait till LSE is ready
3
  while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
4
  {
5
  }
6
7
  //Select the RTC Clock Source
8
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
9
10
  RCC_RTCCLKCmd(ENABLE);  //SPL-Comment: "This function must be used only after the RTC clock source was selected"
11
...

von le compileur (Gast)


Lesenswert?

Stimmt, beim ARM ist es völlig unnormal, ein Peripheral einzuschalten 
und mit Takt zu versorgen. Da ist RTC eine totale Ausnahme. Alles andere 
hat 7 Gang Automatik. :-( :-( :-(

von Phantomix (Gast)


Lesenswert?

le compileur schrieb:
> Stimmt, beim ARM ist es völlig unnormal, ein Peripheral
> einzuschalten
> und mit Takt zu versorgen. Da ist RTC eine totale Ausnahme. Alles andere
> hat 7 Gang Automatik. :-( :-( :-(

Deiner unterschwelligen Ironie zum trotz möchte ich einmal entgegnen, 
dass der normale Ablauf ist: Clock einschalten (Siehe erste Zeile, PWR 
peripheral kriegt APB1 Clock), Peripheral initialisieren, Peripheral 
anschalten.

Bei der RTC ists halt anders rum: Peripheral einschalten, Peripheral 
initialisieren.

Genau genommen ist es natürlich logisch, dass er den Init Mode erst 
erreicht, wenn im Hintergrund schon die asynchrone RTC clock läuft 
(nicht nur die PWR clock)

von le compileur (Gast)


Lesenswert?

Spiderman, befreie uns vom Phantom. :-)

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.