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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Christian M. (meiestro)


Bewertung
0 lesenswert
nicht 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)


Bewertung
1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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

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]
  • [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.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

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