mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik STM32F103 Blue Pill Board: Verwendung der RTC mit 32khz


Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

bei diesen kleinen Boards ist etwas strubbelig mit der RTC in den 
Beispielen der StdPeriphLibs.

Der unten stehende Code ist von mir ergänzt worden um die Möglichkeit 
den EXTERNEN Quarz zu verwenden statt den internen RC Oszillator. Nur 
klappt es eben nicht. Vor allem verstehe ich nicht wieso die den 
Prescaler auf 40000 setzen.

Lasse ich die Befehle weg, die den internen RC betreffen startet der 32 
Bit Counter nicht und er hängt ewig in der WaitForSycro Schleife fest.

Hat da jemand funktionierenden Code?

Gruss,
Christian

void Init_RTC()
{
      /* Enable PWR and BKP clocks */
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

      /* Allow access to BKP Domain */
      PWR_BackupAccessCmd(ENABLE);

      /* Enable the LSI OSC */
      RCC_LSICmd(ENABLE);
      RCC_LSEConfig(RCC_LSE_ON);

      /* Wait till LSI is ready */
//      while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET) {}
      while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) {} // TEST!!!

      /* Select the RTC Clock Source EXTERNAL 32Khz */
//      RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
      RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); // TEST!!!

      /* Enable RTC Clock */
      RCC_RTCCLKCmd(ENABLE);

      /* Wait for RTC registers synchronization */
      RTC_WaitForSynchro();

      /* Wait until last write operation on RTC registers has finished */
      RTC_WaitForLastTask();

      /* Enable the RTC Second */
      RTC_ITConfig(RTC_IT_SEC, ENABLE);

      /* Wait until last write operation on RTC registers has finished */
      RTC_WaitForLastTask();

      /* Set RTC prescaler: set RTC period to 1sec */
      RTC_SetPrescaler(40000);

      /* Wait until last write operation on RTC registers has finished */
      RTC_WaitForLastTask();

      NVIC_InitTypeDef NVIC_InitStructure;

      /* Enable the RTC Interrupt - 1 x 1s */
      NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);

}




: Bearbeitet durch User
Autor: Erdowahn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Vor allem verstehe ich nicht wieso die den
> Prescaler auf 40000 setzen.

Verstehe ich auch nicht, denn in einem funktionierenden Code steht da 
bei mir:
  /* Set RTC prescaler: set RTC period to 1sec */
  RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und wie sieht der ganze funktionierende Code aus?

Mit 32768 läuft sie zu schnell und wird wahrscheinlich auch von der RC 
angetrieben, denn von der LSE kriege ich sie nicht zum rennen :-(

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Grundsätzlioch bin ich nach diesern schönen Anleitung vorgegangen.

http://embedded-lab.com/blog/stm32s-internal-rtc/

Nur leider rennt der Weckker einfach nicht los, sobald ich auf LSE 
schalte.
Das Board in der Doku ist genau das gleiche wie ich es habe. Sein Code 
ist sehr umständlich, das Gleiche geht viel einfacher mit 4 Zeilen, wenn 
man mit der Funktion struct tm *localtime(const time_t *timer) aus der 
time.h Lib arbeitet, die aus der Epoch Time direkt einen struct füllt, 
der das römische Datum hat.
struct tm {
   int tm_sec;         /* seconds,  range 0 to 59          */
   int tm_min;         /* minutes, range 0 to 59           */
   int tm_hour;        /* hours, range 0 to 23             */
   int tm_mday;        /* day of the month, range 1 to 31  */
   int tm_mon;         /* month, range 0 to 11             */
   int tm_year;        /* The number of years since 1900   */
   int tm_wday;        /* day of the week, range 0 to 6    */
   int tm_yday;        /* day in the year, range 0 to 365  */
   int tm_isdst;       /* daylight saving time             */  
};

: Bearbeitet durch User
Autor: Erdowahn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Und wie sieht der ganze funktionierende Code aus?

Tja, Du mußtest leider ein bisserl warten, war auf Arbeit.
void NVIC_Configuration(void) {
  NVIC_InitTypeDef NVIC_InitStructure;
#ifdef  VECT_TAB_RAM  
  /* Set the Vector Table base location at 0x20000000 */ 
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 
#else  /* VECT_TAB_FLASH  */
  /* Set the Vector Table base location at 0x08000000 */ 
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
#endif

  /* Configure one bit for preemption priority */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

//...

  /* Enable the RTC Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

void init_RTC(void) {
  volatile uint16_t i;

  /* Enable PWR and BKP clocks */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

  /* LSI clock stabilization time */
  for(i=0;i<5000;i++) { ; }

  if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) {
    /* Backup data register value is not correct or not yet programmed (when
  the first time the program is executed) */

    /* Allow access to BKP Domain */
    PWR_BackupAccessCmd(ENABLE);
  
    /* Reset Backup Domain */
    BKP_DeInit();
  
    /* Enable LSE */
    RCC_LSEConfig(RCC_LSE_ON);

    /* Wait till LSE is ready */
    while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) { ; }
  
    /* Select LSE as RTC Clock Source */
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
  
    /* Enable RTC Clock */
    RCC_RTCCLKCmd(ENABLE);
  
    /* Wait for RTC registers synchronization */
    RTC_WaitForSynchro();
  
    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();

    /* Set RTC prescaler: set RTC period to 1sec */
    RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
  
    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();

    /* Adjust time */
    Time_Adjust();
  
    /* Allow access to BKP Domain (Time_Adjust disables the access) */
    PWR_BackupAccessCmd(ENABLE);
  
    BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);

    /* Lock access to BKP Domain */
    PWR_BackupAccessCmd(DISABLE);

  } else {

    /* Wait for RTC registers synchronization */
    RTC_WaitForSynchro();

  }

  /* Enable the RTC Second */
  RTC_ITConfig(RTC_IT_SEC, ENABLE);
  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();

#ifdef RTCClockOutput_Enable
  /* Enable PWR and BKP clocks */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

  /* Allow access to BKP Domain */
  PWR_BackupAccessCmd(ENABLE);

  /* Disable the Tamper Pin */
  BKP_TamperPinCmd(DISABLE); /* To output RTCCLK/64 on Tamper pin, the tamper
                                 functionality must be disabled */

  /* Enable RTC Clock Output on Tamper Pin */
  BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);
#endif

  /* Clear reset flags */
  RCC_ClearFlag();
}

Ich hoffe, ich habe nichts vergessen.

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

das sieht ja fast aus wie meines, sogar die Kommentare sind identisch. 
Nur halt, dass da noch eine Zahl im BKUP RAM abgespeichert wird, um 
Doppel Inits zu vermeiden. Und das läuft auch?

 /* Wait for RTC registers synchronization */
    RTC_WaitForSynchro();

Hier ist bei mir nämlich Schluss, da hängt er sich endlos auf. Dass 
diese blauen Boards nicht ok sind glaube ich eigentlich nicht. Der 
kleine schwarze Kasten ist ein 32khz Oszillator oder Quartz. Das hätte 
natürlich Auswirkungen, wennn das ein Oszillator ist, da man dann die 
Verstärker Mimik nicht aktivieren darf, sondern das als external Clock 
betrachten muss. Die 40.000 kommen daher, dass die RC intern mit 40khz 
angegeben wird, bzw. zwischen 30 - 60 khz.

Nicht vergessen darf man, dass die RTC Mimik erst durch den RC Clock 
getrieben wird, völlig unabhängig von dem Rest ist. Vielleicht muss man 
ja doch erst RC aktivieren und danach umschalten auf LSE? Bei den alten 
LPC21xxx ARM TDMI war das so.

Im Netz gibts dazu so gut wie nichts, die RTC scheint wenig beliebt zu 
sein.

PS: Sehe grad, dass ich keinen reset der BKP Domain habe und das 
Reference Manual das ausdrücklich fordert.

The RTCCLK clock source can be either the HSE/128, LSE or LSI clocks. 
This is selected by programming the RTCSEL[1:0] bits in the Backup 
domain control register (RCC_BDCR). This selection cannot be modified 
without resetting the Backup domain.

Insgesamt finde ich diese RTC einen echten Krampf, Gatter sparen um 
jeden Preis :-(

Gruss,
Christian

: Bearbeitet durch User
Autor: Erdowahn (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Den Code habe ich seinerzeit von Martin Thomas stm32_chan_fat-Projekt 
geklaut.
Die entsprechenden Dateien habe ich mal angehängt.

Gruß und viel Erfolg.

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was soll ich sagen ? DAS SCHEISS DING GÄÄÄÄÄHT :-)

das war es: BKP_DeInit(); Ohne das geht es nicht. Und jetzt nicht mehr 
anfassen, alles so stehen lassen und freuen :-)

Autor: Oje (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch wenn gleich einer den Knüppel rausholt: Bluepill RTC mit CubeMX 
generierten Code (HAL) geht auf Anhieb.

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Komm ich nicht mit klar. Selbst bei der Clock Config ist alles 
ausgegraut und ich weiss nicht wie ich das umstellen soll. Diese ganze 
Klickerei hat mit Programmieren eher nichts mehr zu tun.

Sagt mir wenig... ich nutze keine HAL. Das Bewährte funktioniert ja..

/* RTC init function */
void MX_RTC_Init(void)
{
  RTC_TimeTypeDef sTime;
  RTC_DateTypeDef DateToUpdate;

    /**Initialize RTC and set the Time and Date 
    */
  hrtc.Instance = RTC;
  hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
  hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
  HAL_RTC_Init(&hrtc);

  sTime.Hours = 0x1;
  sTime.Minutes = 0x0;
  sTime.Seconds = 0x0;

  HAL_RTC_SetTime(&hrtc, &sTime, FORMAT_BCD);

  DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
  DateToUpdate.Month = RTC_MONTH_JANUARY;
  DateToUpdate.Date = 0x1;
  DateToUpdate.Year = 0x0;

  HAL_RTC_SetDate(&hrtc, &DateToUpdate, FORMAT_BCD);

}

: Bearbeitet durch User

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.