Forum: Mikrocontroller und Digitale Elektronik STM32 Nucleo L476RG SRAM2 Nutzung im Standby Mode


von Christian M. (meiestro)


Lesenswert?

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:
1
__attribute__ ((section(".mydata"))) volatile uint8_t mD = 0;

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

von Christopher J. (christopher_j23)


Lesenswert?

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.

von Christian M. (meiestro)


Lesenswert?

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

von Dr. No (Gast)


Lesenswert?

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.

von Christian Mayer (Gast)


Lesenswert?

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

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.