Hallo,
da es fast nichts Brauchbares zu dem Thema gibt und es mich einen ganzen
Tag gekostet hat heraus zu finden, wie es nun wirklich funktioniert
schreibe ich es mal für die Suchmaschinen hier rein. Da diese Modes sich
über SWD mit ST-Link nicht debuggen lassen umso schwieriger zu wissen,
ob es wirklich funktioniert.
Hardware: Bluepill Board mit StdPeriph Library
Der F103 hat 3 Modi: Sleep (+Options), STOP (+Options), Standby
(+Options), wobei Sleep der einfachste Mode ist, nur der Core bleibt
stehen, alles andere bleibt an.
Achtung: Stop Mode und Standby Mode, aber auch Sleep schießen die swd
Schnittstelle ab! Danach ist kein Zugriff mehr auf den Chip möglich! Er
muss dann durch Umjumpern auf Boot-Mode mit dem Tool ST Utility gelöscht
werden! Debuggen funktioniert nur begrenzt, da der Debugger auf den Takt
des Core angewiesen ist.
Beim Aufwecken aus dem Standby Mode startet der Chip komplett neu, es
wird ein Reset ausgelöst. Dieser Fall wird hier nicht betrachtet.
Um den STM32F103 periodisch über die RTC aufzuwecken ist die Aktivierung
des RTC Alarms notwendig. Der "normale" Sekunden Interrupt vermag dieses
nicht.
Für die Auslösung des Alarms ist es normalerweise nicht notwendig einen
EXTI zu definieren. Die RTC Interrrupts werden in einer Routine
gesammelt und dort durch ihre Auslöse Bits unterschieden. Da reicht
jedoch nicht aus, um den STOP Mode oder Sleep Mode wieder zu verlassen!
Dafür gibt es den EXTI 17, der speziell für diesen Zweck gemacht wurde.
Er bindet intern den "INT Pin" der RTC an den NVIC an und löst damit
einen Interrupt aus, der dem eines Pins gleicht.
Durch die Aktivierung des EXTI_17 Kanals wird bei einem Alarm NICHT mehr
der normale RTC Handler RTC_IRQHandler(void) angesprungen, sondern void
RTCAlarm_IRQHandler ().
Der neue Alarmhandler setzt die Alarmzeit auf eine Zeit in der Zukunft,
löscht die IRQ Flags und wird wieder verlassen.
1
voidRTCAlarm_IRQHandler()
2
{
3
static_Boolled_switch=false;
4
5
if(RTC_GetITStatus(RTC_IT_ALR)!=RESET)
6
{
7
PWR_BackupAccessCmd(ENABLE);
8
9
RTC_WaitForSynchro();
10
RTC_WaitForLastTask();
11
uint32_tval=RTC_GetCounter();
12
RTC_WaitForLastTask();
13
RTC_SetAlarm(val+SLEEPTIME);
14
RTC_WaitForLastTask();
15
RTC_ClearITPendingBit(RTC_IT_ALR);
16
PWR_BackupAccessCmd(DISABLE);
17
18
EXTI_ClearITPendingBit(EXTI_Line17);// Remove LINE interrupt flag bit
19
}
20
21
}
Ob der letzte Befehl nötig ist das EXTI IRQ Flag zu löschen weiss ich
nicht sicher, es geht mit und ohne. RTC_WaitForLastTask() muss zwingend
zwischen jeden Befehl, lässt man es weg klappt es nicht mehr.
Die Sequenz um die CPU in den Stop Mode zu schicken sieht so aus
Nach Ausführung von
PWR_EnterSTOPMode(PWR_Regulator_ON,PWR_STOPEntry_WFI) ist die CPU "weg"
und wacht erst wieder auf, wenn der RTC Alarm ausgelöst wird. IN diesem
Fall wird sofort hinterher die ISR Routine aufgerufen und ausgeführt.
Achtung! Nach dem Stop stimmt die Taktfrequenz nicht mehr, da PLL und
Teiler zurückgesetzt wurden! Es muss zwingend der SystemInit aufgerufen
werden, der das System neu einstellt.
Die Sequenz um den SLEEP Mode einzuleiten, der in den StdPeriphLibs
nicht extra erwähnt wird lautet
Ich hänge nochmal die Doku dazu. Quelle: Quelle: en.CD00171190.pdf,
Table 11 on site 71
Ich würde mir auch noch überlegen, ob im Stop-Mode die Initialisierung
der Takte über SystemInit() nicht in void RTCAlarm_IRQHandler () besser
aufgehoben ist. Man hat ja Flags über die Vorgeschichte.
Chris J. schrieb:> Achtung: Stop Mode und Standby Mode, aber auch Sleep schießen die swd> Schnittstelle ab!
Ich verwende in nahezu jedem Programm den Sleep Modus (einfach nur
Aufruf von __WFI()) und konnte bisher immer noch problemlos weiter über
SWD oder JTAG debuggen (bei F103, F407, F373, F302, ...). Lediglich der
Aufbau einer neuen Verbindung funktioniert mit dem ST-Link nicht
(Aktivieren der Option "Connect under Reset" soll helfen), beim J-Link
aber schon (es wird aber der Controller ganz resettet). Musste noch nie
was umjumpern.
Dr. Sommer schrieb:> Ich verwende in nahezu jedem Programm den Sleep Modus (einfach nur> Aufruf von __WFI()) und konnte bisher immer noch problemlos weiter über> SWD oder JTAG debuggen
Da würde ich aber mal untersuchen, ob er wirklich im Sleep etc bleibt
und nicht direkt wieder raus kommt, denn aus dem normalen Sleep holt ihn
jeder Systick, jeder Timer, jedes Event wieder raus.... da reicht es
wenn gewisse Flags (EXTI->PR = 0xFFFFFFFF;) vorher nicht ausdrücklich
gelöscht wurden, dann überrennt er den WFI oder WFE einfach.
Der nach den englischen ARM Doku Seiten richtige Aufruf für direktes
Schlafen ist
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; /* Enable deepsleep */
__WFI(); /* Enter sleep mode */
Und die swd ist nicht ansprechbar, wenn man nicht eine Warteschleife
einbaut, die nach dem Reset für die nötige Zeit zum Connect sorgt. Ich
habe da alles durch, jede Möglichkeit etc.
Chris J. schrieb:> Da würde ich aber mal untersuchen, ob er wirklich im Sleep etc bleibt
Ja, tut er. Sieht man an der Leistungsaufnahme und z.B. im Segger
SystemView Tool.
Chris J. schrieb:> denn aus dem normalen Sleep holt ihn> jeder Systick, jeder Timer, jedes Event wieder raus....
Korrekt, das ist ja der Sinn der Sache! Da man __WFI() ja in einer
Schleife aufruft geht er danach direkt wieder schlafen.
Chris J. schrieb:> da reicht es> wenn gewisse Flags vorher nicht ausdrücklich gelöscht wurden, dann> überrennt er den WFI einfach.
Logisch. Da muss man aufpassen.
Chris J. schrieb:> Und die swd ist nicht ansprechbar, wenn man nicht eine Warteschleife> einbaut, die nach dem Reset für die nötige Zeit zum Connect sorgt.
Richtig. Aber wenn die SWD-Verbindung erst einmal steht, kann man
problemlos weiter debuggen auch wenn zwischendurch __WFI() kommt. Und
wie gesagt, vernünftige™ Debugger haben auch kein Problem wenn __WFI()
sofort nach dem Start aufgerufen wird, weil sie das Timing vom Reset
selbst besorgen ;-)
Dr. Sommer schrieb:> Ja, tut er. Sieht man an der Leistungsaufnahme und z.B. im Segger> SystemView Tool.
Das Bluepill Board kriegt man von 55mA runter auf ca 15, tiefer leider
nicht. Da hängt ja noch mehr drauf, zb ein 3V Regler usw. Reicht mir
aber auch.
Dr. Sommer schrieb:> Korrekt, das ist ja der Sinn der Sache! Da man __WFI() ja in einer> Schleife aufruft geht er danach direkt wieder schlafen.
Und die Takte alle wieder richtig eingestellt danach? Ich kann Dir
Screensshots schicken, von RCCGetClocks..... danach ist alles verstellt.
Das funzt zumnindest, wahlweise sleep oder stop.
Chris J. schrieb:> SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; /* Enable deepsleep */> __WFI(); /* Enter sleep mode */
Moment, das löst beim STM32 den Stop/Standby-Modus aus. Ich rede vom
ordinären Sleep-Modus, ganz oben in der Tabelle die von
noreply@noreply.com gepostet wurde.
Chris J. schrieb:> Und die Takte alle wieder richtig eingestellt danach? Ich kann Dir> Screensshots schicken, von RCCGetClocks..... danach ist alles verstellt.
Das ist dann nicht mehr der normale Sleep-Modus.
Das Programm lässt die LED an PA5 mit 0.1Hz blinken. Ob man die
__WFI-Zeile auskommentiert oder nicht ändert nichts am Verhalten des
Programms oder an der Debugbarkeit. Der einzige feststellbare
Unterschied besteht darin, dass der Stromverbrauch unterschiedlich ist:
Mit WFI 16mA, ohne 28mA.
Zu beachten ist dass hierbei der Quarzoszillator anbleibt und munter
Strom frisst - nur mit HSI ginge es bis auf 8mA runter.
Das zeigt dass der ganz normale Sleep-Modus mit __WFI() unproblematisch
ist. Das sieht bei den anderen Sleep-Modi natürlich anders aus.
Chris J. schrieb:>>>Das ist dann nicht mehr der normale Sleep-Modus.>> Nein? Argh.... wo sind meine Herztabletten? :-(
Das SLEEPDEEP-Bit ist notwendige Voraussetzung für Stop bzw.
Standby-Mode. Stop und Standby-Mode unterscheiden sich dann noch in
weiteren gesetzten Bit's. Siehe meine Tabelle oben.
Chris J. schrieb:> Und die Takte alle wieder richtig eingestellt danach? Ich kann Dir> Screensshots schicken, von RCCGetClocks..... danach ist alles verstellt.
Es gibt noch einen System-Reset, der durch einen "Low-power management
reset" (Quelle: en.CD00171190.pdf, Kapitel 7) ausgelöst wird. Das könnte
die notwendige Neukonfiguration der Takte erklären.
Man kann hier mal nachschauen.
"The reset source can be identified by checking the reset flags in the
Control/Status register,
RCC_CSR (see Section 7.3.10: Control/status register (RCC_CSR))."
Wenn ihr den Tiefschlaf wollt, dann müsst ihr dafür sorgen, dass dem SWD
nicht sein Takt geraubt wird.
-> DBGMCU_CR Register bespaßen
The core does not allow FCLK or HCLK to be turned off during a debug
session. As these
are required for the debugger connection, during a debug, they must
remain active. The
MCU integrates special means to allow the user to debug software in
low-power modes.
For this, the debugger host must first set some debug configuration
registers to change the
low-power mode behavior:
• In Sleep mode, DBG_SLEEP bit of DBGMCU_CR register must be previously
set by
the debugger. This will feed HCLK with the same clock that is provided
to FCLK
(system clock previously configured by the software).
• In Stop mode, the bit DBG_STOP must be previously set by the debugger.
This will
enable the internal RC oscillator clock to feed FCLK and HCLK in STOP
mode.
Nochmal für nen alten Mann zu Mitschreiben:
Wenn ich nur den leichten Schlaf möchte, weil mir das reicht muss ich
nur WFI setzen, dann holt mir jeder Int, zb an meinem Funk RF Pin oder
der 1s INT der RTC die CPU zurück ins Leben?
In der Hauptschleife habe ich nur die Statemachine laufen und unten WFI,
mehr nicht. Da rennt er dann immer wieder rein. Wegen der Funkdaten
brauche ich ein recht fixes Aufwachen, sonst läuft mir der Fifo voll
ohne dass er bedient wird.
Chris J. schrieb:> Wenn ich nur den leichten Schlaf möchte, weil mir das reicht muss ich> nur WFI setzen, dann holt mir jeder Int, zb an meinem Funk RF Pin oder> der 1s INT der RTC die CPU zurück ins Leben?
Ja genau. Wobei die RTC- und Externen- Interrupts halt schon speziell
sind, weil sie auch in den tieferen Schlafmodi gehen. Im normalen
"Sleep"-Modus, der durch Einfaches Aufrufen von __WFI() gestartet wird,
weckt jeder Interrupt sofort auf. Das siehst du auch in meinem Beispiel
- da ist es ein Timer-Interrupt. Ich würde normalerweise auch eher einen
Timer für sowas nehmen als die RTC, der ist flexibler.
Chris J. schrieb:> In der Hauptschleife habe ich nur die Statemachine laufen und unten WFI,> mehr nicht.
Du kannst in die Hauptschleife auch ein while(1) __WFI(); packen, und
die Statemachines in Interrupts. So kannst du alle Warte-Schleifen
vermeiden und den Prozessor so viel wie möglich schlafen lassen.
Das ist sowieso die Grundidee von WFI - auf Ereignisse (Interrupts)
warten, ohne den Prozessor sinnlos im Kreis drehen zu lassen
(Warteschleifen). Da der Prozessor hier auch keine Zeit zum Aufwecken
braucht (Oszillator bleibt an), ergibt sich keinerlei Nachteil gegenüber
Warteschleifen.
Ist ungefähr so, aber ich bin nur Theoretiker. ;-)
Noch zum Stromverbrauch:
- Ich würde es erstmal wie Dr. Sommer machen. HSI ohne PLL verwenden und
versuchen mit 8 MHz Taktfrequenz für HCLK auskommen.
- Danach würde ich versuchen, den HCLK mit dem Vorteiler noch weiter
runterzubekommen.
- Danach würde ich versuchen HCLK situativ anzupassen.
- Die Kür wäre dann Stop-Mode, wobei der Prozessor mit diversen EXTI
wieder zum Leben erweckt wird. z.B. Auswerten der Signale der
Funkschnittstelle->Seriell? am Prozessor über das Interrupt-System.
noreply@noreply.com schrieb:> Die Kür wäre dann Stop-Mode, wobei der Prozessor mit diversen EXTI> wieder zum Leben erweckt wird. z.B. Auswerten der Signale der> Funkschnittstelle->Seriell? am Prozessor über das Interrupt-System.
Macht nur bei einem Lochraster Aufbau wo noch ein FTDI und ein RF
Empfänger versorgt werden nicht soooo viel Sinn, denn unter 40mA komme
ich nie. Ist schon ok so, er sleept jetzt und damit bin ich zufrieden,.
Notfalls noch einen Akku mehr dran pappen.
noreply@noreply.com schrieb:> - Ich würde es erstmal wie Dr. Sommer machen. HSI ohne PLL verwenden und> versuchen mit 8 MHz Taktfrequenz für HCLK auskommen.
HSI ist halt leider ungenau und für manche Interfaces braucht man dann
doch hohe Taktraten (braucht PLL) :-/
Wie gesagt nutze ich __WFI() in fast jedem Projekt, das ist IMO Schritt
Nr. 1 zur Reduktion der Leistungsaufnahme. Alles in Interrupts zu machen
und explizite Zustände zu modellieren zwingt auch zur sauberen
Programmierung der Abläufe ;-) In meinem Beispiel hat das den Verbrauch
fast halbiert...
Chris J. schrieb:> Macht nur bei einem Lochraster Aufbau wo noch ein FTDI und ein RF> Empfänger versorgt werden nicht soooo viel Sinn, denn unter 40mA komme> ich nie.
Na, dann reicht vielleicht die schlichte __WFI()-Variante. Wenn du den
intergrierten USB-Controller statt FTDI-IC verwendest sparst du
vielleicht noch mehr (den bei Bedarf abschalten o.ä.).
Dr. Sommer schrieb:> Na, dann reicht vielleicht die schlichte __WFI()-Variante. Wenn du den> intergrierten USB-Controller statt FTDI-IC verwendest sparst du> vielleicht noch mehr (den bei Bedarf abschalten o.ä.).
Wenn ich bloss wüsste wie man den als RS232 verwenden kann gern.... nur
habe ich von USB Programmierung Null Ahnung, von Ethernet noch viel
weniger.
Mw E. schrieb:> Wenn ihr den Tiefschlaf wollt, dann müsst ihr dafür sorgen, dass dem SWD> nicht sein Takt geraubt wird.> -> DBGMCU_CR Register bespaßen
Genau so sieht es nämlich aus und zwar sowohl für Sleep- als auch für
Stop-Mode. Siehe auch Kapitel 31.16 im Handbuch.
Mit dem Stop-Mode kommt man schon ziemlich weit runter mit dem
Stromverbrauch, d.h. 24µA wenn "voltage regulator on" und 14µA wenn
"voltage regulator low-power". Die Aufwachzeit aus WFE beträgt dann
gerade einmal 3,5µs/5,4µs (VR on/low-power) und der Inhalt des RAM und
der Register bleibt komplett erhalten. Wie man ihn schlafen legen kann
und wie man ihn dann wieder wach bekommt steht alles in Kapitel 5.3 im
Handbuch.
In der AN2629 finden sich viele weitere Infos zu den Power-Modi der
F1-Serie:
www.st.com/resource/en/application_note/cd00171691.pdf
Chris J. schrieb:> Wenn ich bloss wüsste wie man den als RS232 verwenden kann gern.... nur> habe ich von USB Programmierung Null Ahnung, von Ethernet noch viel> weniger.USB-Tutorial mit STM32: Virtueller COM-Port,
UART auf USB: Eigenbau oder mit der ST-eigenen Bibliothek... Die
Emulation von RS232 ist aber IMO unnötig und verursacht nur zusätzliche
Probleme.
Christopher J. schrieb:> In der AN2629 finden sich viele weitere Infos zu den Power-Modi der> F1-Serie:> www.st.com/resource/en/application_note/cd00171691.pdf
Ja, aber die Firmware dazu ist nicht aufzutreiben, diese AN hatte ich
auch schon in der Hand. Aber wo sind die Beispiele?
Dr. Sommer schrieb:> Emulation von RS232 ist aber IMO unnötig und verursacht nur zusätzliche> Probleme.
Ok..... und wenn ich den Text so überfliege und mir überlege wie einfach
es ist eine UART zu bedienen, die mir über den FTDI dann ein VT100
Terminal Programm mit Ausgaben füttert, mir sogar Eingaben erlaubt dann
überlege ich, ob es ein Hobby das wert ist mich da ein zu arbeiten, weil
ich es nicht mehr beruflich mache, HW/SW Entwicklung habe ich 2006
zugunsten einer höher bezahlten Tätigkeit (Internationale Normung und
Zertifizierung) aufgegeben ;-)
In den Libs usw findet sich nichts zu USB, sehr wohl aber viele
kostenpflichtige Anbieter, zb Segger die ihre Stacks verkaufen wollen.
Chris J. schrieb:> In den Libs usw findet sich nichts zu USB, sehr wohl aber viele> kostenpflichtige Anbieter, zb Segger die ihre Stacks verkaufen wollen.
Doch, ST liefert bei der HAL einen USB-Device-Stack und auch Beispiele
für VCP (virtueller Com-Port).
Eben... genauso wie FPGAs lasse ich das die machen, die den ganzen Tag
8h dafür Zeit haben und dafür bezahlt werden, während meine Freizeit
Bastelei ein paar Daten Bytes quer durchs Haus zu schicken und auf einer
SD Karte mit der sehr einfach zu ändernden Chan Fat zu speichern weiter
auf die alten Konzepte setzt. Gab neulich im Forum auch so einen
Knallfrosch, der eine eigene Koptersteuerung entwickeln wollte.... bis
ihm jemand erklärte, dass die Ardupilot Pixhawk so rund 300 Mannjahre
intus hat, die man für 80 Euro kaufen kann und es nur wenige Menschen
gibt, einen Kalman-Filter auch nur erklären können......
Chris J. schrieb:> Ok..... und wenn ich den Text so überfliege und mir überlege wie einfach> es ist eine UART zu bedienen, die mir über den FTDI dann ein VT100
Verstehe ich jetzt nicht ganz. Der STM32F1 hat doch genug
UART/USART-Schnittstellen. Oder ist der Engpaß das VT100-Terminal
(Laptop ohne serielle Schnittstelle?).
noreply@noreply.com schrieb:> Verstehe ich jetzt nicht ganz. Der STM32F1 hat doch genug> UART/USART-Schnittstellen.
Hat er..... RX und TX + evtl noch CTS auf einen FTDI Chip für 2 Euro,
FTDI in USB Port, minicom unter Linux aufrufen und schon habe ich meine
Ausgaben ;-)
Serielle hat der PC natürlich nicht mehr und selbst wenn ohne eine Pumpe
MAX232 dazwischen gehts ja eh nicht.
Das klappte schon beim Z80, den ich gebaut habe mit der SIO, die mir
zusammen mit mcurses ein komplettes Betriebssyystem auf dem VT100
erzeugt mit Eingaben usw.
@Chris J.
Wir diskutieren hier aber über Low-Power-Modes vom STM32F1. Der
Leistungsverbrauch vom FTDI wird aber doch normalerweise vom Laptop
bestritten.
Danke für den Hinweis, da hatte ich noch einen Verdrahtungsfehler, der
FTDI wurde bei mir vom Bopard versorgt, +5V war abgeklemmt zum PC.
Ich werde die ganzen Erkenntnisse mal für die Nachwelt aufbereiten ;-)
https://www.youtube.com/watch?v=Bif_tIH7bMk