Hallo liebe Community,
seit längerem bin ich ein stiller Mitleser hier im Forum und habe hier
schon oft Lösungen für viele Probleme gefunden.
Heute bin ich auf ein Problem gestoßen, für das ich keine existierenden
Beiträge gefunden habe:
Ich schicke mein STM32 Nucleo L476 Board in den "Standby" Low Power
Mode. Laut Ref Manual kann man den SRAM2 beim L476 im Standby Mode
weiterhin mit Strom versorgen sodass zBsp. Variablen erhalten bleiben.
Dies mache ich mit der folgenden HAL Funktion und es funktioniert auch:
1
HAL_PWREx_EnableSRAM2ContentRetention()
Ich habe einen Bereich ".mydata" im Linkerfile angelegt und auf RAM 2
zugewiesen.
1
/* My Variables go to RAM2 which is kept during Standby Mode */
2
.mydata:
3
{
4
_smydata=.;/* define a global symbol at mydata start */
5
*(.mydata)
6
_emydata=.;/* define a global symbol at mydata end */
7
}>RAM2
Die Variable lege ich dann im Bereich ".mydata" an und sie bleibt auch
nach dem Standby Mode erhalten:
Wird der Stecker vom MC gezogen habe ich allerdings Zufällige Werte in
den Variablen weil der SRAM2 defaultmäßig nicht initialisiert wird.
Ich habe versucht, den Bereich ".mydata" im Startup File
"startup_stm32l476xx.s folgendermaße zu initialisieren:
1
LoopCopyDataInit:
2
ldr r0, =_sdata
3
ldr r3, =_edata
4
adds r2, r0, r1
5
cmp r2, r3
6
bcc CopyDataInit
7
ldr r2, =_sbss
8
b LoopFillZerobss
9
10
ldr r2, =_smydata
11
b LoopFillZeroMyData
12
13
/* Zero fill the MyData segment. */
14
FillZeroMyData:
15
movs r3, #0
16
str r3, [r2], #4
17
18
LoopFillZeroMyData:
19
ldr r3, = _emydata
20
cmp r2, r3
21
bcc FillZeroMyData
Hier habe ich eigendlich die Init Funktionen für den bss Bereich
(FillZerobss und LoopFillZerobss) welche defaultmäßig implementiert sind
einfach übernommen, weshalb es funktionieren sollte. Zusätzlich habe ich
in der Funktion
1
LoopCopyDataInit
die folgenden Zeilen hinzugefügt:
1
ldr r2, =_smydata
2
b LoopFillZeroMyData
Dies funktioniert jedoch nicht, weil ich immer noch willkürliche Zahlen
in der Variable habe wenn der MC vom Strom genommen wird.
Außerdem habe ich versucht das ganze über die FLASH option bytes zu
lösen:
Zu den Konfigurationsmöglichkeiten findet man folgendes im Reference
Manual S. 108:
1
Bit 25 SRAM2_RST: SRAM2 Erase when system reset
2
0: SRAM2 erased when a system reset occurs
3
1: SRAM2 is not erased when a system reset occurs
4
5
Bit 13 nRST_STDBY
6
0: Reset generated when entering the Standby mode
7
1: No reset generate when entering the Standby mode
Das Setzen dieser Bits funktioniert erfolgreich (und kann auch über das
ST-Link-Utility->Target->Option Bytes gemacht werden) allerdings habe
ich folgende Ergebnisse:
1. SRAM2_RST = 1, nRST_STDBY = 1: Variable bleibt erhalten aber
willkürliche Werte nach vom Strom nehmen
2. SRAM2_RST = 0, nRST_STDBY = 1: Varibale bleibt nicht mehr erhalten,
RAM2 wird somit auch im Standby gelöscht, obwohl ich das nRST_STDBY = 1
so verstanden hatte das das Reset Flag nicht gestzt wird.
3. nRST_STDBY = 0: Jedes Mal wenn ich den Prozessor in den Standby
schicke wird automatisch ein Reset durchgeführt, heißt neu gestartet.
Somit habe ich mit den Option Bytes leider nicht das gewünschte
Ergebniss erhalten.
Hat irgendwer von euch eine Idee, wie ich den RAM2 bei einem
Reset/Neustart neu Initialisieren- , im Standby Mode jedoch erhalten
kann?
Mir gehen gerade die Ideen aus wie ich das ganze umsetzen könnte, ich
wäre für jeden Tipp dankbar!
Das hier ist mein erster aktiver Beitrag hier, ich habe alles nach
bestem Gewissen hier beschrieben. Sollte etwas nicht passen, dann seit
bitte nachsichtig mit mir, ich werde es umgehend anpassen!
Grüße,
Chris
Da du nur einen Ausschnitt von deinem Startup-Code gepostet hast, bleibt
mir nur eine grobe Mutmaßung. Folgendes ist ein Auszug aus dem
Startup-Code eines F411xe aus dem CubeFW Paket. Ich gehe mal davon aus,
dass der entsprechende Ausschnitt für einen L476 genauso aussieht.
1
Reset_Handler:
2
ldr sp, =_estack /* set stack pointer */
3
/* Copy the data segment initializers from flash to SRAM */
4
movs r1, #0
5
b LoopCopyDataInit
6
7
CopyDataInit:
8
ldr r3, =_sidata
9
ldr r3, [r3, r1]
10
str r3, [r0, r1]
11
adds r1, r1, #4
12
13
LoopCopyDataInit:
14
ldr r0, =_sdata
15
ldr r3, =_edata
16
adds r2, r0, r1
17
cmp r2, r3
18
bcc CopyDataInit
19
ldr r2, =_sbss
20
b LoopFillZerobss
21
/* Zero fill the bss segment. */
22
FillZerobss:
23
movs r3, #0
24
str r3, [r2], #4
25
26
LoopFillZerobss:
27
ldr r3, = _ebss
28
cmp r2, r3
29
bcc FillZerobss
30
31
/* Call the clock system intitialization function.*/
32
bl SystemInit
33
/* Call static constructors */
34
bl __libc_init_array
35
/* Call the application's entry point.*/
36
bl main
Du springst also zunächst zu "LoopCopyDataInit" und darin dann zu
"CopyDataInit" zurück, so lange r3 > r2 ist.
Danach geht es weiter in LoopFillZerobss, von wo aus es wieder so lange
zurück zu "FillZerobss" geht, wie r3 > r2 ist. Wird nicht zurück zu
"FillZerobss" gesprungen geht es einfach mit dem Aufruf von SystemInit
und danach mit dem Aufruf von main weiter. Es spielt also keine Rolle,
was in deiner "LoopCopyDataInit" hinter "b LoopFillZerobss" steht, weil
das sowieso nie ausgeführt wird.
Konkret lösen kannst du das Dilemma indem du den folgenden Ausschnitt
ans Ende von "LoopFillZerobss" setzt, anstatt ans Ende von
"LoopCopyDataInit":
1
ldr r2, =_smydata
2
b LoopFillZeroMyData
3
4
/* Zero fill the MyData segment. */
5
FillZeroMyData:
6
movs r3, #0
7
str r3, [r2], #4
8
9
LoopFillZeroMyData:
10
ldr r3, = _emydata
11
cmp r2, r3
12
bcc FillZeroMyData
Also insgesamt sollte es in etwa so aussehen:
1
Reset_Handler:
2
ldr sp, =_estack /* set stack pointer */
3
/* Copy the data segment initializers from flash to SRAM */
4
movs r1, #0
5
b LoopCopyDataInit
6
7
CopyDataInit:
8
ldr r3, =_sidata
9
ldr r3, [r3, r1]
10
str r3, [r0, r1]
11
adds r1, r1, #4
12
13
LoopCopyDataInit:
14
ldr r0, =_sdata
15
ldr r3, =_edata
16
adds r2, r0, r1
17
cmp r2, r3
18
bcc CopyDataInit
19
ldr r2, =_sbss
20
b LoopFillZerobss
21
/* Zero fill the bss segment. */
22
FillZerobss:
23
movs r3, #0
24
str r3, [r2], #4
25
26
LoopFillZerobss:
27
ldr r3, = _ebss
28
cmp r2, r3
29
bcc FillZerobss
30
/* Ab hier ist "(Loop-)FillZerobss" fertig */
31
ldr r2, =_smydata
32
b LoopFillZeroMyData
33
34
/* Zero fill the MyData segment. */
35
FillZeroMyData:
36
movs r3, #0
37
str r3, [r2], #4
38
39
LoopFillZeroMyData:
40
ldr r3, = _emydata
41
cmp r2, r3
42
bcc FillZeroMyData
43
/* Ab hier ist "(Loop-)FillZeroMyData" fertig */
44
45
/* Call the clock system intitialization function.*/
46
bl SystemInit
47
/* Call static constructors */
48
bl __libc_init_array
49
/* Call the application's entry point.*/
50
bl main
Noch so als abschließenden Tip:
Mit Hilfe eines Debuggers, den du ja auf dem Nucleo ohnehin drauf hast,
kannst du so Dinge relativ schnell ausfindig machen. Mal einen
Breakpoint an der richtigen Stelle setzen und schon siehst du was
passiert (oder halt auch nicht passiert, wie in diesem Fall).
Christian M. schrieb:> 1. SRAM2_RST = 1, nRST_STDBY = 1: Variable bleibt erhalten aber> willkürliche Werte nach vom Strom nehmen
Mit dieser Variante sollte es dann wie gewünscht funktionieren.
Hallo,
erst Mal an Christopher vielen Dank für deine ausführliche Antwort.
Der Startup Code sieht bei mir identisch aus wie bei dir, und mit der
Änderung funktioniert es auch! Macht Sinn wie du das geschrieben hast,
da hatte ich einen Fehler.
Nun ist es aber so, dass der ".mydata" Sektor und somit auch meine darin
abgespeicherten Variablen immer auf Null initialisiert wird, auch wenn
ich den MC in den Standby schicke und wieder wecke. So wie ich das
verstanden habe ist der Standby Mode wie ein Reset und der komplette
Programmcode wird nochmal durchlaufen. Es macht allerdings doch keinen
Sinn dass man den SRAM2 konfigurieren kann dass der Speicherinhalt nicht
gelöscht wird es aber nicht möglich ist diesen einmalig zu
initialisieren?
Bei mir ist es konkret so, dass ich einen Variable für die Menüführung
meines Programms benutze. Wenn diese beim Startup mit Zufallswerten
beschrieben ist dann funktioniert das nicht, genauso wenn sie nach jedem
Wake-Up aus dem Standby Mode wieder auf Null initialisiert wird.
Hatte wer von euch schon ein ähnliches Problem oder steh ich gerade auf
der Leitung?
Grüße und einen schönen Sonntag,
Chris
Christian M. schrieb:> Nun ist es aber so, dass der ".mydata" Sektor und somit auch meine darin> abgespeicherten Variablen immer auf Null initialisiert wird, auch wenn> ich den MC in den Standby schicke und wieder wecke. So wie ich das> verstanden habe ist der Standby Mode wie ein Reset und der komplette> Programmcode wird nochmal durchlaufen. Es macht allerdings doch keinen> Sinn dass man den SRAM2 konfigurieren kann dass der Speicherinhalt nicht> gelöscht wird es aber nicht möglich ist diesen einmalig zu> initialisieren?
SBF in PWR_CSR checken und entsprechend Initialisierung überspringen.
Vielen Dank für die schnelle Hilfe!
Mit dem SBF-Flag konnte ich es nicht lösen, da es beim Standby Mode
sowie als auch bei einem Reset gesetzt wird. Durch das Abfragen des
RCC_FLAG_PINRST Flags konnte ich aber zwischen einem Wake up aus dem
Standby oder einem Pin Reset unterscheiden!
Viele Grüße,
Chris