Forum: Mikrocontroller und Digitale Elektronik STM32F103: Low Powes Modes - wie rein und wie raus?


von Chris J. (Gast)


Lesenswert?

Hallo,

das Thema ist im Netz leider nur recht verwirrend dargestellt und teils 
sogar falsch, daher frage ich mal.

Ich möchte bei meinem F103 in den Stop oder StandbyMode und er soll per 
RTC Sekunden Interrupt wieder rauskommen.

Nur wie? Die Modes sind nicht debugbar. Einmal drin kann ich den Chip 
erstmal löschen und vorher Reset drücken, damit er wieder durch den 
st-link beschreibar wird. Und dann finden sich noch so Dinge wie

void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry)
void PWR_EnterSTANDBYMode(void)

aber auch

void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState)

die damit etwas zu tun haben zu scheinen. In einer App Note wird zudem 
gesagt, dass ein EXTI auf die NVIC Line 17  gelegt werden soll. Aber den 
RTC Alarm nutze ich nicht.

Wie sieht das denn nun ganz einfach aus? Mehr ein paar Codezeilen 
dürften da ja nicht sein, den durch den RTC Int aufwachen zu lassen. Bei 
meinen Versuchen weckte der Systick die CPU auf, schalte ich den ab 
wacht sie nicht mehr auf.

        EXTI->PR = 0xFFFFFFFF;
        PWR_ClearFlag(PWR_FLAG_WU);
        PWR_EnterSTOPMode(PWR_Regulator_ON,PWR_STOPEntry_WFE);
        SystemInit();

Gruss,
Christian

von mts (Gast)


Lesenswert?

Chris J. schrieb:
> Aber den RTC Alarm nutze ich nicht.

nutze den RTC Alarm..

von Chris J. (Gast)


Lesenswert?

mts schrieb:
> nutze den RTC Alarm..

Funktioniert aber nicht, kein Einsprung in die ISR :-(
1
/* ----- Alarm Interrupt setzen ------- */
2
3
   /* Alarm Interrupt an NVIC koppeln, Kanal 17 */
4
   EXTI_ClearITPendingBit(EXTI_Line17);
5
   NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn;
6
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 13;
7
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
8
   NVIC_Init(&NVIC_InitStructure);
9
10
    /* Int zulassen */
11
   RTC_WaitForLastTask();
12
   RTC_ClearITPendingBit(RTC_FLAG_ALR);
13
   NVIC_EnableIRQ(RTCAlarm_IRQn);
14
15
   RTC_WaitForLastTask();
16
   RTC_SetAlarm(RTC_GetCounter() + 5);
17
   RTC_WaitForLastTask();
18
   RTC_ITConfig(RTC_IT_ALR, ENABLE);
19
20
21
22
void RTC_IRQHandler(void)
23
{
24
   #define MEZ +1
25
   static _Bool merker = false;
26
   static _Bool led_switch = false;
27
   struct tm *ptr;      // Zeiger auf Zeit Strktur
28
   time_t value;        // 32 Bit Unixzeit
29
30
31
  if (RTC_GetITStatus(RTC_IT_ALR) != RESET)
32
  {
33
     RTC_WaitForLastTask();
34
     RTC_SetAlarm(RTC_GetCounter() + 3);
35
    /* Wait until last write operation on RTC registers has finished */
36
    RTC_ClearITPendingBit(RTC_IT_ALR);
37
    EXTI_ClearITPendingBit(EXTI_Line17);   // Remove LINE interrupt flag bit
38
  }
39
40
  if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
41
  { ....

von A. B. (Gast)


Lesenswert?

Chris J. schrieb:
> das Thema ist im Netz leider nur recht verwirrend dargestellt und teils
> sogar falsch, daher frage ich mal.

Im "Netz" vagabundiert halt vieles herum. Und??? Es soll (rein 
gerüchtehalber ...) ein Reference Manual geben, das man sich angeblich 
bei ST kostenlos herunter laden kann.

> Ich möchte bei meinem F103 in den Stop oder StandbyMode und er soll per
> RTC Sekunden Interrupt wieder rauskommen.

Hm, in besagten Manual (Figure 179. RTC simplified block diagram) ist 
klar beschrieben, dass RTC_Second nur nach RTC_CR geht, und da steht 
ausdrücklich "not powered in Standby" drunter. Im Standby ist's also 
nix.
Steht auch in "Table 15. Standby mode". Also jede Sekunde den Alarm für 
die nächste Sekunde setzen ...

Zum Stop-Mode siehe "Table 14. Stop mode".

> Wie sieht das denn nun ganz einfach aus? Mehr ein paar Codezeilen
> dürften da ja nicht sein, den durch den RTC Int aufwachen zu lassen.

Und wenn man gründlich im Reference Manual liest, findet man auch 
heraus, wie die ggf. aussehen müssen. Aber eine fertige Copy-And-Paste 
Lösung gibt's halt nicht.

Selber machen macht Spass - und gibt hinterher ein echtes 
Erfolgserlebnis. ;-)

von Chris J. (Gast)


Angehängte Dateien:

Lesenswert?

A. B. schrieb:
> ein Reference Manual geben, das man sich angeblich
> bei ST kostenlos herunter laden kann.

Sorry, aber ich stelle hier nur was ein, wenn ich absolut nicht mehr 
weiter weiss und alle Quellen zur Rate gezogen habe. Der INT springt 
nicht an, auch im Stop Mode nicht und auch so wird kein Alarm Int 
erzeugt. Der benutzt ja wohl die gleiche Routine wie die anderen RTC 
Ints und wird nur über sein Bit unterschieden... einen EXTI_17 Handler 
gibt es nicht.

Die Schose spielt einwandfrei
1
   /* ------------------------------------------------ */
2
   /* ----- Normalen Sekunden Interrupt setzen ------- */
3
   /* ------------------------------------------------ */
4
5
   /* ----- 1s RTC Interrupt an NVIC koppeln --------*/
6
   NVIC_InitTypeDef NVIC_InitStructure;
7
   NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
8
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 14;
9
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
10
   NVIC_Init(&NVIC_InitStructure);
11
   /* Int zulassen */
12
    NVIC_EnableIRQ(RTC_IRQn);
13
14
   /* RTC Second Interrupt einschalten*/
15
   RTC_WaitForLastTask();
16
   RTC_ITConfig(RTC_IT_SEC, ENABLE);

Die aber nicht, null Reaktion.
1
   /* ------------------------------------ */
2
   /* ----- Alarm Interrupt setzen ------- */
3
   /* ------------------------------------ */
4
5
   /* Alarm Interrupt an NVIC koppeln, Kanal 17 */
6
   EXTI_ClearITPendingBit(EXTI_Line17);
7
   NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn;
8
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 13;
9
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
10
   NVIC_Init(&NVIC_InitStructure);
11
   NVIC_EnableIRQ(RTCAlarm_IRQn);                /* Int zulassen */
12
13
   RTC_WaitForLastTask();
14
   RTC_SetAlarm(RTC_GetCounter() + 5);
15
   RTC_WaitForLastTask();
16
   RTC_ITConfig(RTC_IT_ALR, ENABLE);

von Chris J. (Gast)


Lesenswert?

Habs schon...

Das Zauberwort hiess: PWR_BackupAccessCmd(ENABLE);

Ohne das geht nix mit der RTC.

Und dieser aus dem Netz abgeschrieben Code läuft auch nicht, da da 
unbedingt ein RTC_WaitForLastTask() zwischen die beiden Operationen 
muss,
sonst wird die AL Time nicht gesetzt.

FALSCH:
RTC_SetAlarm(RTC_GetCounter() + 3);

RICHTIG:
     PWR_BackupAccessCmd(ENABLE);
     RTC_WaitForSynchro();
     RTC_WaitForLastTask();
     uint32_t val = RTC_GetCounter();
     RTC_WaitForLastTask();
     RTC_SetAlarm(val + 3);
     RTC_WaitForLastTask();
     PWR_BackupAccessCmd(DISABLE);

Ob das nötig ist weiss ich nicht, es spielt mit und ohne in der ISR

EXTI_ClearITPendingBit(EXTI_Line17);   // Remove LINE interrupt flag bit

Das Aufwachen aus dem Stoop läuft leider immer noch nicht, weder mit WFI 
noch mit WFE und im Release rennt er sogar in den Hardfault Handler :-(

von Chris J. (Gast)


Lesenswert?

Funzt nicht :-(

Das Ding geht und geht nicht in den Sleep Mode, die anderen Modes 
brauche ich nicht. Und das ewige manuelle Um-Jumpern und Löschen, weil 
die swd Schnittstelle sich aufhängt nervt auch.

        SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; /* Enable deepsleep */
        SetRedLED(ENABLE);
        __WFI(); /* Enter sleep mode */
        SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
        SetRedLED(DISABLE);
        SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
        __WFI(); /* Enter sleep mode */

von pegel (Gast)


Lesenswert?

Deshalb liebe ich HAL. :)
Dafür gibt es ein Beispiel Namens:

RTC_LowPower_STANDBY

Kannst ja mal suchen ob es das auch ohne HAL gibt.

von Chris J. (Gast)


Lesenswert?

pegel schrieb:
> Deshalb liebe ich HAL. :)

Damit fange ich nicht mehr an, diese Klicki-Bunti CubeMX Welt ist mir 
suspekt, das Alte tut es ja auch ;-) Ging aber auch so, habs mal 
zusammen geschrieben im Code Bereich.

von noreply@noreply.com (Gast)


Lesenswert?

Ich hab zwar keine Ahnung, aber bei SLEEPDEEP würde ich auf Stop oder 
Standby-Mode tippen. Und dann wäre noch zu klären, wo nach Beendigung 
eines Ereignisses die Ausführung weiter geht.

von Ich (Gast)


Lesenswert?

Da du die SPL nutzt, würde ich dir raten mal in die zahlreichen Examples 
zu schauen. Damit habe ich den Stop- und Standby-Mode in kurzer Zeit 
lauffähig bekommen, allerdings mit EXTI zum aufwecken.
Das ist vielleicht eine bessere Quelle zum abtippen, als irgendwas aus 
dem "Netz"

von Alexander B. (Firma: brickwedde.dev) (alexbrickwedde)


Lesenswert?

Auch wenn Du den RTC jetzt am laufen hast, kleiner Tip am Rande: Du 
kannst den RTC Interrupt auch ohne Sleep/Standby debuggen. Mach erstmal 
das RTC Krams mit dem Debugger rund und dann, wenn der Alarm 
funktioniert, gehst Du in den Sleep.

Vor dem Sleep deaktiviere ich Systick, danach aktiviere ich ihn wieder 
und setze ich die Clock neu.  (Bei mir passte der HAL_Delay sonst 
nicht). Du solltest auch I2C usw. deaktivieren, sonst bleibt der 
Verbrauch relativ hoch.

Noch ein Tip: Nach einem Reset lasse ich den Controller mindestens 5 
Sekunden wach (lasse LED blinken, dann seh' ich es). Währenddessen kann 
man mit dem Debugger neu aufspielen. Dann reicht es Reset zu drücken, 
dann Debug in der IDE.

...Alex

: Bearbeitet durch User
von Chris J. (Gast)


Lesenswert?

noreply@noreply.com schrieb:
> Ich hab zwar keine Ahnung, aber bei SLEEPDEEP würde ich auf Stop oder
> Standby-Mode tippen.

Nee.... das ist wirklch SLEEP Mode, der hat nur diverse Modi.

Ich schrieb:

> Da du die SPL nutzt, würde ich dir raten mal in die zahlreichen Examples
> zu schauen.

Ja, nach 7 Stunden fiel mir ein, dass ich die irgendwo mal kopiert hatte 
und das Vergessene, nämlich der EXTI17 fiel vom Himmel. Nicht aber, dass 
dann plötzlich ein anderer Handler angesprungen wird als vorher.

Es laufe nur SLEEP und STOP, aus Standby kommt er nur mit einem echten 
Pin Int wieder raus und startet dann komplett neu per Reset, zumindest 
bei mir.

Alexander B. schrieb:
> Mach erstmal
> das RTC Krams mit dem Debugger rund und dann, wenn der Alarm
> funktioniert, gehst Du in den Sleep.

Genauso habe ich es gemacht, dass der Sleep und Stop funktionieren sah 
ich auch nur an den Blinki-LEDs. Nur sagt einem keiner, dass bei allen 
Modi SysClock und SysTick neu konfiguriert werden müssen, ebenso die 
Clock fürs ADC und SPI etc. Alle gelöscht, watt ein Mist :-( Und dass 
Systick auch den Sleep sofort beendet und daher abgeschaltet werden 
muss. Eigentlich kann man den Systick sogar dafür nehmen, wenn man mit 
24 Bit zufrieden ist.
Und der Watchdog funkt einem auch noch dazwischen, den juckt das nämlich 
nicht, wenn der abläuft wird resettet.

Mühsam, mühsam.... dabei will ich nur von den 50mA, die das Board normal 
braucht auf ca 5-6, damit der 18650 Akku etwas länger hält. Echte Low 
Power Anwendungen habe ich lieber mit dem Attiny 84 gemacht an der 
Arduino IDE, direkt an eine Mignon mit DC/DC Step up (200uA) da hält ne 
Mignon fast 1/2 Jahr für den Sensor und Funkmodul.

> Nach einem Reset lasse ich den Controller mindestens 5
> Sekunden wach (lasse LED blinken, dann seh' ich es). Währenddessen kann
> man mit dem Debugger neu aufspielen. Dann reicht es Reset zu drücken,
> dann Debug in der IDE

Auf die Idee kam ich auch später, vorher artig immer umgestöpselt und 
mit ST Utility gelöscht, bis das so nervig wurde, dass ich auch auf 
diese Idee kam.

von Alexander B. (Firma: brickwedde.dev) (alexbrickwedde)


Lesenswert?

Ist zwar HAL, aber ich teile mal meinen Code:
https://gist.github.com/alexbrickwedde/21bd84693f0749a6ac8121bb72026dd1

Ich lasse den Controller max 10 Sekunden schlafen und bediene dann den 
IWDG. Über den Tageswechsel erkenne ich dann recht einfach, dass der 
Sleep beendet sein soll. Egal, ob und wie oft er vorher durch irgendwas 
anderes aufwacht.

I2C, SPI usw. (de)aktivieren fehlt hier noch (ist in der DoSomeAction).

: Bearbeitet durch User
von noreply@noreply.com (Gast)


Angehängte Dateien:

Lesenswert?

Quelle: en.CD00171190.pdf

Table 11 on site 71

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.