Forum: Mikrocontroller und Digitale Elektronik STM32 - CooCox Fragen & RTC


von Johnny S. (sgt_johnny)


Lesenswert?

Hallo zusammen,

Ich habe heute endlich mal Zeit gefunden mich mit dem STM32 
auseinanderzusetzen. Leider ist das mehr oder weniger eine gezwungene 
Massnahme, da Arduino leider langsam an der Grenze ist bei mir. 
Informationen zur Programmierung STM32 sind oft schwerer zu finden als 
für Arduino :( (Für Arduino findet man für fast alles eines oder 
mehrer Codebeispiele sogar auf der Haupseite. Bei STM32 habe ich bis 
jetz noch keine Codeexamples zu Funktionen endeteckt)

Ich habe mich nun mit der CooCoxIDE und dem Nucleo STM32F401RE versucht

Die LED blinken lassen funktioniert :-)

Da für meine zwecke die RTC von zentraler Bedeutung ist, wollte ich mich 
daran versuchen.


Nun habe ich zwei Probleme:

1.) Die meisten Tutorials benutzen die "Standart Peripheral Libary" nich 
die HAL. In der Aktuellen Version von CooCox ist aber ist diese nicht 
mehr vorhanden und auch das GUI sieht anders aus als bei den Meisten 
Tutorials. Es scheint so als kommt neu immer das Paket 
"STM32_TYP_Cubelib" zum Einsatz welche auf der HAL Library basiert.

Kann man die Standard-Lib nachinstallieren oder ist es sinnvoller diese 
nicht mehr zu benutzen?


2.) Kennt jemand hier ein funktionierendes Beispiel mit HAL wie man die 
RTC in Betrieb nimmt, die Zeit setzt und wieder die Zeit liest?

Ich habe bereits eine Library gefunden, jedoch zweifle ich an deren 
Zweck, da ja in der STM32_HAL_rtc schon befele für "GetDate" vorhanden 
sind.. ebenfalls verhindern Libaries immer das Wissen, denn wenn man 
eine Libary einsetzt weiss man trotzdem nicht was da passiert und wenn 
die library mal nicht mehr geht oder end of life ist sitzt man im Sumpf. 
Für gewisse komplexe Sachen machen libaries auch sinn, aber ich denke 
mal die RTC sollte auch so mit mässigem Aufwand betreibbar sein?


Vielen Dank für eure Antworten

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Welcher STM32 ist es denn? Die STM32Fx HAL (x=1,2,3,4) findet man im 
Internet als Zusatzdownload zum CubeMX (CubeMX braucht man nicht). Bei 
dem Download der HAL sind dann auch Beispiele dabei - auch für die RTC.

Konkrete Hilfe / Code Snippets wirst du erst bekommen, wenn du sagst, 
welchen STM32 du einsetzt, die verhalten sich nämlich z.T. 
unterschiedlich.

Das Benutzen der HAL ist für dich i.O. oder ist das auch schon "zuviel" 
Bibliothek?

Grüße
Lasse

von Jim M. (turboj)


Lesenswert?

Johnny S. schrieb:
> Da für meine zwecke die RTC von zentraler Bedeutung ist, wollte ich mich
> daran versuchen.

Hast mal nachgeschaut ob da der 32768Hz Quarz überhaupt bestückt ist? 
IIRC war das nicht bei allen Versionen der Fall, aber ich kann mich da 
auch irren.

Ohne den Quarz wird aus der RTC ein Schätzeisen...

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Ah, jetzt hab sogar ich's gesehen, STM32F401. Schau da einfach mal in 
den Download der HAL, da sollte ein RTC-Beispiel sein. Für den STM32F303 
nutze ich folgenden Code:
1
{
2
  // lse config
3
  __HAL_RCC_PWR_CLK_ENABLE();
4
  HAL_PWR_EnableBkUpAccess();
5
  __HAL_RCC_BACKUPRESET_FORCE();
6
  __HAL_RCC_BACKUPRESET_RELEASE();
7
  HAL_PWR_DisableBkUpAccess();
8
9
  RCC_OscInitTypeDef lseinit;
10
  lseinit.OscillatorType = RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_LSI;
11
  lseinit.PLL.PLLState = RCC_PLL_NONE;
12
  lseinit.LSEState = RCC_LSE_ON;
13
  lseinit.LSIState = RCC_LSI_OFF;
14
  HAL_StatusTypeDef lsestatus = HAL_RCC_OscConfig(&lseinit);
15
}
16
17
{
18
  RTC_DateTypeDef dateinit;
19
  RTC_TimeTypeDef timeinit;
20
21
  // TODO: Check RTC settings, these are simply copypasted from example
22
  __HAL_RCC_PWR_CLK_ENABLE();
23
  HAL_PWR_EnableBkUpAccess();
24
  __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE); // TODO: change clock source to a low power mode
25
  __HAL_RCC_RTC_ENABLE();
26
27
  // initialize rtc
28
  rtc.Instance = RTC;
29
  rtc.Init.HourFormat = RTC_HOURFORMAT_24;
30
  rtc.Init.AsynchPrediv = 0x7F;
31
  rtc.Init.SynchPrediv  = 0x00FF;
32
  rtc.Init.OutPut = RTC_OUTPUT_DISABLE;
33
  rtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
34
  rtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
35
  HAL_StatusTypeDef init = HAL_RTC_Init(&rtc);

Ist sicherlich noch optimierbar, läuft so aber - bei mir.

von Johnny S. (sgt_johnny)


Lesenswert?

Lasse S. schrieb:
> Welcher STM32 ist es denn?
STM32F401RE, hatte ich bereits oben genannt :)



Jim M. schrieb:
> Johnny S. schrieb:
>> Da für meine zwecke die RTC von zentraler Bedeutung ist, wollte ich mich
>> daran versuchen.
>
> Hast mal nachgeschaut ob da der 32768Hz Quarz überhaupt bestückt ist?
> IIRC war das nicht bei allen Versionen der Fall, aber ich kann mich da
> auch irren.
>
> Ohne den Quarz wird aus der RTC ein Schätzeisen...

Der Quarz fehlt, jedoch ist meinem Verständins nach dieser nur von 
nötigkeit wenn man den STM32 in Batteriebetrieb auf Low-Power benutzen 
möchte. Man kann auch einstellen das die RTC vom normalen Quarz versorgt 
wird. Klar, bei jedem Power-Off ist die RTC dann null.

In Arduino gibt es die Bibliotek "Time.h", welche eine Art virtuelle RTC 
ist. Es geht mir Hauptsächlich darum beim Start eine Zeit zu setzen, und 
diese soll dann selbständig laufen (mit Datumswechsel etc), so dass ich 
wenn nötig mit "GetDate / GetTime" den Wert beziehen kann.

von Stefan F. (Gast)


Lesenswert?

> Man kann auch einstellen das die RTC vom normalen Quarz versorgt wird.

Mag sein, aber dann ist es keine richtige RTC, denn der normale HSE 
Ozillator erreicht normalerweise kaum die Genauigkeit des LSE. Wenn du 
den HSE verwendest, kannst du gleich den Systick Timer anstatt der 
Echtzeituhr benutzen.

von Johnny S. (sgt_johnny)


Lesenswert?

Stefan U. schrieb:
>> Man kann auch einstellen das die RTC vom normalen Quarz versorgt wird.
>
> Mag sein, aber dann ist es keine richtige RTC, denn der normale HSE
> Ozillator erreicht normalerweise kaum die Genauigkeit des LSE. Wenn du
> den HSE verwendest, kannst du gleich den Systick Timer anstatt der
> Echtzeituhr benutzen.

Da hast du recht, mir geht es aber auch nicht um 100% genaue 
Zeitmessung. Ich möchte von Arduino auf STM32 umsteigen. Aktuell benutze 
ich die Library "time.h" auf Arduino. Da der ATmega328 garkeine 
Hardware-RTC hat muss die "Zeitspeicherung" also immer in Software 
passieren.

Es ist halt schöner "getDate()" abzurufen als jedes mal zu rechnen...


Klar könnte ich jeweils beim STM32 mit einem Systick jede Sekunde zählen 
und dann auf Stunden&Tage umrechnen, aber warum mehr aufwand wenn die 
RTC das selbe bietet?

Die Endanwendung ist dann wie folgt:

- Programmstart
- Zeit aus RTC (DS3231) per I2C in die STM RTC Laden
- Falls vorhanden Zeit aus GPS / NTP beziehen, RTC updaten
- Programmlauf...
- Stündliche Kontrolle der Zeit per I2C mit DS3231 oder GPS/NTP. (Update 
der internen RTC falls nötig)

Da GPS und NTP jeweils GMT+0 liefern, speichere ich nur die GMT+0 in der 
DS3231 und benutze dann jeweils Code um die Zeitzone anzupassen, anstatt 
beim Zeitzonenwechsel jeweils wirklich die Zeit in der RTC anzupassen.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Vergiss nicht, Sommer-/Winterzeit Umschaltung und Schaltjahre zu 
berücksichtigen. Das kann nicht jede RTC, ohne Softwareunterstützung.

> Zeit aus RTC (DS3231) per I2C in die STM RTC Laden

Warum macht man das? Schließe doch einfach einen Quarz und eine Batterie 
an den STM32 an.

von Johnny S. (sgt_johnny)


Lesenswert?

Stefan U. schrieb:
> Vergiss nicht, Sommer-/Winterzeit Umschaltung und Schaltjahre zu
> berücksichtigen. Das kann nicht jede RTC, ohne Softwareunterstützung.
Ja, nur haben nicht alle Zeitzonen Sommer/Winterzeit somit ist es ratsam 
die Zeit in "neutral" zu speichern.

Aktuell lese ich beim start alle Benutzereinstellungen aus einem EEprom, 
dort steht auch die Zeitzone und Sommerzeit JA/NEIN


>> Zeit aus RTC (DS3231) per I2C in die STM RTC Laden
>
> Warum macht man das? Schließe doch einfach einen Quarz und eine Batterie
> an den STM32 an.

Man macht es für hohe Genauigkeit. Ein STM32 welcher um die 5€ kostet 
und Hauptsächlich ein uC ist, wird mitnichten so genau sein wie ein 
DS3231 Baustein für um 10€.  Der DS3231 hat +-2ppm.

Klar, die hohe Genauigkeit spielt nur dann eine Rolle wenn weder GPS 
noch NTP zur "dauersynchronisation" vorhanden sind, aber ich möchte 
gerne weiterhin die Möglichkeit bieten.

von Stefan F. (Gast)


Lesenswert?

> Der DS3231 hat +-2ppm.

Nicht schlecht, der STM32 hat zehn mal soviel, soweit ich mich erinnere.

von Johnny S. (sgt_johnny)


Lesenswert?

Ich bin nun mal so weit:
1
   HAL_Init();
2
  
3
  /* Configure the system clock to 84 MHz */
4
  SystemClock_Config();
5
  
6
  /* -1- Enable GPIOA Clock (to be able to program the configuration registers) */
7
  __HAL_RCC_GPIOA_CLK_ENABLE();
8
  __HAL_RCC_PWR_CLK_ENABLE();
9
  __HAL_RCC_RTC_ENABLE();
10
11
    rtc.Instance = RTC;
12
    rtc.Init.HourFormat = RTC_HOURFORMAT_24;
13
    rtc.Init.AsynchPrediv = 0x7F;
14
    rtc.Init.SynchPrediv  = 0x00FF;
15
    rtc.Init.OutPut = RTC_OUTPUT_DISABLE;
16
    rtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
17
    rtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
18
19
    if(HAL_RTC_Init(&rtc) != HAL_OK)
20
     {
21
       /* Initialization Error */
22
       Error_Handler();
23
   }
24
25
    sdatestructure.Year = 0x14;
26
    sdatestructure.Month = RTC_MONTH_FEBRUARY;
27
    sdatestructure.Date = 0x18;
28
    sdatestructure.WeekDay = RTC_WEEKDAY_TUESDAY;
29
30
    if(HAL_RTC_SetDate(&rtc,&sdatestructure,RTC_FORMAT_BCD) != HAL_OK)
31
     {
32
       /* Initialization Error */
33
       Error_Handler();
34
     }
35
     stimestructure.Hours = 0x02;
36
       stimestructure.Minutes = 0x20;
37
       stimestructure.Seconds = 0x00;
38
       stimestructure.TimeFormat = RTC_HOURFORMAT12_AM;
39
       stimestructure.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
40
       stimestructure.StoreOperation = RTC_STOREOPERATION_RESET;
41
42
       if(HAL_RTC_SetTime(&rtc,&stimestructure,RTC_FORMAT_BCD) != HAL_OK)
43
       {
44
         /* Initialization Error */
45
         Error_Handler();
46
     }

Aber der Debugger zeigt mir das der Error_Handler(); schon beim INIT 
anspricht...
Wo mache ich denn den Fehler?

: Bearbeitet durch User
von 4444444444444444444444 (Gast)


Lesenswert?

wie wäre es mit OpenSTM32 IDE
http://openstm32.org/HomePage

das funktioniert auch mit CUBE

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Mit dem fehlschlagenden Init meinst du das HAL_RTC_Init, oder? Hast du 
den Clocksource für die RTC eingestellt, ich weiß nicht, ob der Default 
so funktioniert.

von Stefan F. (Gast)


Lesenswert?

> wie wäre es mit OpenSTM32 IDE

Der Vorschlag ist nett aber ich denke er löst das Problem nicht.

Clock-Source wäre auch mein Vorschlag.

von Johnny S. (sgt_johnny)


Lesenswert?

Sooo.. die Errors sind schonmal weg. Es war ein grundsätzlcihes Problem

Das Nucleo-board hat zwar einen Quarz, aber dieser ist eben genauf für 
die RTC nicht für den Prozessor selber :-)

Der interne Takt wird vom "HSI" produziert. Da kann man lange auf den 
nicht vohandenen HSE intialisieren.

Mit dem LSI (QUarz) läuft nun die RTC bzw. zumindestens die Init schlägt 
nicht fehl, mal sehen wie es nun weiter geht.

von Johnny S. (sgt_johnny)


Angehängte Dateien:

Lesenswert?

Nächstes Problem
1
  while (1)
2
  {
3
    HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
4
    /* Insert delay 100 ms */
5
    HAL_RTC_GetTime(&rtc,&stimestructure,FORMAT_BIN);
6
    int test = stimestructure.Seconds;
7
    HAL_Delay(10000);
8
  }

&stimestructure enthält die Zeitelemente gemäss Screenshot. Ich habe 
beim init 00:00:01 gesetzt. Leider bleibt die Zeit so stehen. Die RTC 
scheint aber zu laufen, da SubSeconds sich verändert.

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Probier mal, die Zeit aus den RTC-Registern selber auszulesen, das 
GetTime aus der HAL hat bei mir auch Probleme gemacht.
1
uint32_t tmpreg = rtc.Instance->TR;
2
3
uint8_t ht = (tmpreg & RTC_TR_HT) >> RTC_TR_HT_Pos;
4
uint8_t hu = (tmpreg & RTC_TR_HU) >> RTC_TR_HU_Pos;
5
uint8_t hours = ht*10 + hu;
6
7
uint8_t mt = (tmpreg & RTC_TR_MNT) >> RTC_TR_MNT_Pos;
8
uint8_t mu = (tmpreg & RTC_TR_MNU) >> RTC_TR_MNU_Pos;
9
uint8_t minutes = mt*10 + mu;
10
11
uint8_t st = (tmpreg & RTC_TR_ST) >> RTC_TR_ST_Pos;
12
uint8_t su = (tmpreg & RTC_TR_SU) >> RTC_TR_SU_Pos;
13
uint8_t seconds = st*10 + su;

von Stefan F. (Gast)


Lesenswert?

Ich weiß nicht ob das auf den STM32F4 auch so passt, aber ich musste 
beim STM32F1 noch einen Teilerfaktor einstellen:
1
    // Enter configuration mode
2
    SET_BIT(RTC->CRL,RTC_CRL_CNF);
3
4
    // Divide oscillator frequency by 32767+1 to get seconds
5
    RTC->PRLL=32767;
6
    RTC->PRLH=0;
7
8
    // Leave configuration mode
9
    CLEAR_BIT(RTC->CRL,RTC_CRL_CNF);
10
11
    // Wait until last write operation is done
12
    while(!READ_BIT(RTC->CRL, RTC_CRL_RTOFF)) {}

Soweit ich verstanden habe, liegt dieser Teiler zwischen dem Oszillator 
und dem Sekundenzähler. Das müsste deinen "SubSeconds" entsprechen. 
Deswegen tippe ich auf den Teilerfaktor.

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Alternativ musst du nach dem Aufruf von HAL_RTC_GetTime zwingend auch 
HAL_RTC_GetDate aufrufen (siehe Doku in der HAL).

von Stefan F. (Gast)


Lesenswert?

Ich sehe gerade, dass der Teilerfaktor offensichtlich bereits durch
1
rtc.Init.AsynchPrediv = 0x7F;
2
rtc.Init.SynchPrediv  = 0x00FF;

eingestellt wurde.

von Johnny S. (sgt_johnny)


Lesenswert?

Lasse S. schrieb:
> Probier mal, die Zeit aus den RTC-Registern selber auszulesen, das
> GetTime aus der HAL hat bei mir auch Probleme gemacht.


Zeigt leider selbes Ergebnis

von pegel (Gast)


Lesenswert?

Lasse S. schrieb:
> nach dem Aufruf von HAL_RTC_GetTime zwingend auch
> HAL_RTC_GetDate aufrufen

von Johnny S. (sgt_johnny)


Lesenswert?

pegel schrieb:
> Lasse S. schrieb:
>> nach dem Aufruf von HAL_RTC_GetTime zwingend auch
>> HAL_RTC_GetDate aufrufen

So ein Quark :(

Naja, jetz läufts...

von Stefan F. (Gast)


Lesenswert?

> Naja, jetz läufts...

Was war denn die Fehlerursache?

von Johnny S. (sgt_johnny)


Lesenswert?

Ich hatte nicht HAL_RTC_GetDate nach HAL_RTC_GetTime aufgerufen... 
scheinbar muss dass immer zusammen abgerufen werden.

von Stefan F. (Gast)


Lesenswert?

Na gut zu wissen. Darauf wäre ich nie gekommen.

Sollte die HAL solche Details nicht eigentlich vereinfachen bzw. weg 
abstrahieren? Je länger ich mit STM32 zu tun habe umso sinnloser 
erscheint mir die HAL.

Nicht dass ich Arduino toll fände, aber das können die Arduino Macher 
besser.

von pegel (Gast)


Lesenswert?

Was ihr nur immer gegen HAL habt.
Ich finde es gut und es funktioniert einfach.

Ich gehe wie folgt vor:

- in CubeMX Takt und Peripherie einstellen
- in SW4STM32 importieren
- für die gewünschte Hardware in die Beispiele schauen
- anpassen und ergänzen
- fertig

Beim RTC Beispiel ist neben dem korrekten Setzen und Lesen des RTC auch 
noch eine Erkennung ob die Uhr beim Reset schon gestellt ist dabei.

von Stefan F. (Gast)


Lesenswert?

> anpassen und ergänzen, fertig

Offensichtlich weicht da die Theorie ein wenig von der Praxis ab.

Mein erster Versuch scheiterte schon an der Initialisierung des 
Taktgebers. nach stundenlangem Suchen bekam ich mit freundlicher Hilfe 
dieses Forums heraus, dass es sich um einen Bug handelte.

Seit dem lese ich das Referenzhandbuch, wodurch die HAL für mich 
überflüssig geworden ist.

von pegel (Gast)


Lesenswert?

War das das HSI HSE Problem in Version 4.20?

von Stefan F. (Gast)


Lesenswert?

> War das das HSI HSE Problem in Version 4.20?

Keine Ahnung ob das mein Problem "das" eine war.

von Johnny S. (sgt_johnny)


Lesenswert?

pegel schrieb:
> Beim RTC Beispiel ist neben dem korrekten Setzen und Lesen des RTC auch
> noch eine Erkennung ob die Uhr beim Reset schon gestellt ist dabei.

Sind das beispiele von ST? Falls ja, kannst du mir bitte die Quelle 
nennen, ich suche seit ewigkeiten nach code Beispielen :/

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Wenn du die HAL herunterlädst, sind dort auch Beispiele vorhanden.

von pegel (Gast)


Lesenswert?

Die sind bei der HAL Lib dabei.

von pegel (Gast)


Lesenswert?

aktuell für dein Board:

STM32Cube_FW_F4_V1.18.0/Projects/STM32F401RE-Nucleo

Aber dank HAL, lassen sich auch Beispiele von anderen Familien 
übernehmen.

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.