Forum: Mikrocontroller und Digitale Elektronik STM32F4 CCMRAM Linker Script


von Matthias F. (frank91)


Angehängte Dateien:

Lesenswert?

Hallo alle zusammen,

ich verwende den Controller STM32f407VG.
Dieser besitzt 128kB Flash + 64kB CCMRAM.
Da momentan der Flash schon zu 60% voll ist wollte ich jetzt Variablen 
auf den CCMRAM verschieben.

Informiert habe ich mich darüber auf:
http://www.openstm32.org/Using%2BCCM%2BMemory
und
https://www.mikrocontroller.net/articles/STM32_-_Einstieg_mit_Em::Blocks
(Abschnitt: Core-Coupled-RAM verwenden)

Hierbei habe ich allerdings noch einige Fragen.

1.---------------------------------------------------------------------- 
--
Allgemein:

Im Internet habe ich gelesen, dass aus dem CCMRAM sogar noch schneller 
gelesen / geschrieben werden kann. Allerdings kann der DMA hier nicht 
darauf zugreifen.
Ist dies so richtig? Gibt es sonst noch etwas was ich bei diesem 
Speicher berücksichtigen muss?

2.---------------------------------------------------------------------- 
--
Variablen ohne Initialisierungswert:

Nun zur Verwendung des CCMRAM:

Im Linkerscript ist dieser von vorne rein so definiert:
1
  _siccmram = LOADADDR(.ccmram);
2
3
  /* CCM-RAM section 
4
  * 
5
  * IMPORTANT NOTE! 
6
  * If initialized variables will be placed in this section,
7
  * the startup code needs to be modified to copy the init-values.  
8
  */
9
  .ccmram :
10
  {
11
    . = ALIGN(4);
12
    _sccmram = .;       /* create a global symbol at ccmram start */
13
    *(.ccmram)
14
    *(.ccmram*)
15
    
16
    . = ALIGN(4);
17
    _eccmram = .;       /* create a global symbol at ccmram end */
18
  } >CCMRAM AT> FLASH

Ich meinem Quellcode habe ich ein 30kB großes Array mit 
"__attribute__((section(".ccmram")))" gekennzeichnet. Dieses Array 
bestitzt keine Initialisierungswerte.
Ich kann erkennen, dass das Array erfolgreich im CCMRAM abgelegt wird.
Allerdings verbraucht der Flash nun 30kB mehr Speicher, wie zuvor.
Wie ist das zu erklären?

Ändere ich den Linker Script ab auf:
1
  _siccmram = LOADADDR(.ccmram);
2
3
  /* CCM-RAM section 
4
  * 
5
  * IMPORTANT NOTE! 
6
  * If initialized variables will be placed in this section,
7
  * the startup code needs to be modified to copy the init-values.  
8
  */
9
  .ccmram :
10
  {
11
    . = ALIGN(4);
12
    _sccmram = .;       /* create a global symbol at ccmram start */
13
    *(.ccmram)
14
    *(.ccmram*)
15
    
16
    . = ALIGN(4);
17
    _eccmram = .;       /* create a global symbol at ccmram end */
18
  } >CCMRAM
Werden diese 30kB im Flash nicht mehr benötigt.
Den Hintergrund verstehe ich hierbei nicht wirklich.

3.---------------------------------------------------------------------- 
--
Variablen mit Initialisierungswert:

Ich benötige bei meinen CCMRAM Variablen keine Startwerte. Dennoch 
wollte ich dies zum Verständniss verstehen.
hierbei steht im Linker Script in den Kommentaren dass man für 
Initialisierungswerte den Startup Code anpassen muss.
Hierbei habe ich im Internet ein Beispielcode gefunden:
1
/* Copy the ccm segment initializers from flash to SRAM */
2
  movs  r1, #0
3
  b  LoopCopyCcmInit
4
5
CopyCcmInit:
6
  ldr  r3, =_sccmram
7
  ldr  r3, [r3, r1]
8
  str  r3, [r0, r1]
9
  adds  r1, r1, #4
10
11
LoopCopyCcmInit:
12
  ldr  r0, =_sccmram
13
  ldr  r3, =_eccmram
14
  adds  r2, r0, r1
15
  cmp  r2, r3
16
  bcc  CopyCcmInit
So wie ich das verstehe muss im Startup Code noch beschrieben werden, 
dass zu Beginn die Startwerte aus dem Flash in das CCMRAM auch geladen 
werden.
Zum testen erstellte ich mir eine neue Variable und stelle per Debugging 
fest, dass Startwerte hier wirklich nicht übernommen werden.
Dies macht soweit Sinn für mich.
Wenn ich den Startup Code wie oben beschrieben ändere habe ich 
allerdings immer noch keine Startwerte.

Wenn ich den Linker Script allerdings abändere und das "AT> FLASH " 
weglasse, werden die Startwerte wie gewollt übernommen.
Wieso ist das so?

4.---------------------------------------------------------------------- 
--
Build Analyser:

Wie die einzelnen Speicher belegt sind kann ich im Build Analyser von 
Atollic True Studio nachlesen.
Für die die diesen Analyser noch nicht gesehen haben habe ich im Anhang 
ein Bild eingefügt.

Wenn ich folgende Variable einbinde
1
char test[100] ="abcdefghijklmnopqrstuvwxyz";

Werden sowohl im Flash als auch im Ram 100 Byte benötigt. Das ist 
logisch, da der Flash ja die Startwerte beeinhalten muss.

Schreibe ich stattdessen:
1
#define CCMRAM __attribute__((section(".ccmram")))
2
CCMRAM char test[100] ="abcdefghijklmnopqrstuvwxyz";
werden diese 100byte weiterhin im Flash untergebracht (auch wenn es wie 
oben beschrieben nicht funktioniert).

Ändere ich allerdings den Linker Script ab und lass das "AT> FLASH " weg 
werden im Flash diese 100byte nicht berechnet. Trotzdem sind die 
Startwerte vorhanden^^
Kann das sein oder ist das möglicherweiße ein Fehler von meiner 
Entwicklungsumgebung Atollic True Studio?

: Bearbeitet durch User
von Curby23523 N. (Gast)


Lesenswert?

Ist es eine selbstgeätzte Leiterplatte? Wenn nein oder Änderung noch 
möglich, dann nehme einfach einen µC mit mehr Speicher.

von Matthias F. (frank91)


Lesenswert?

Könnte ich, will ich aber eigentlich nicht :P
Weil mit dem CCMRAM habe ich auch für kommende Änderungen viel mehr 
Speicher wie das ich je benötigen werde übrig.

Außerdem will ich ja auch neue Dinge dazulernen :P

von Martin B. (ratazong)


Lesenswert?

zu 1)

So wie ich das verstanden habe kann die DMA nicht ins CCMRAM 
schreiben/lesen.

DMA wird mit einer round Robin Logik betrieben.
Das Ganze ist so gebaut, dass der Prozessor immer Zugriff auf das CCMRAM 
hat. Der Zugriff kann nicht von der DMA engine verzögert werden. Daher 
ist das im Mittel schneller.
Ich habe das noch nie genutzt, interessiert mich aber auch.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Matthias F. schrieb:
> Im Internet habe ich gelesen, dass aus dem CCMRAM sogar noch schneller
> gelesen / geschrieben werden kann. Allerdings kann der DMA hier nicht
> darauf zugreifen.
> Ist dies so richtig?

Ja. Der RAM ist 'Core-Coupled' und benötigt keine Waitstates, ist aber 
dem Zugriff des DMA entzogen.

> Gibt es sonst noch etwas was ich bei diesem
> Speicher berücksichtigen muss?

M.W.n. nicht. Ist als 'normaler' Platz für Variablen unauffällig und 
läuft. Ich benutze den auch, habe aber keinen erhöhten Flashbedarf 
festgestellt.

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Martin B. schrieb:
> zu 1)
>
> So wie ich das verstanden habe kann die DMA nicht ins CCMRAM
> schreiben/lesen.
>
> ...
> Ich habe das noch nie genutzt, interessiert mich aber auch.

STM POD reference manual, Stichwort "Bus Matrix" (u.A. erklärt... ja ich 
weiss... in Kap. 2 meines Buches, oder in den Cortex Unterlagen).

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

> Da momentan der Flash schon zu 60% voll ist wollte ich jetzt Variablen
> auf den CCMRAM verschieben.
Das hingegen versteh ich nicht. Der Flash ist vom RAM unabhängig. 
Verstehen würde ich, wenn dir der RAM ausgeht und du deswegen aufs CCRAM 
zugreifen möchtest.

von Matthias F. (frank91)


Lesenswert?

Matthias S. schrieb:
>> Da momentan der Flash schon zu 60% voll ist wollte ich jetzt Variablen
>> auf den CCMRAM verschieben.
> Das hingegen versteh ich nicht. Der Flash ist vom RAM unabhängig.
> Verstehen würde ich, wenn dir der RAM ausgeht und du deswegen aufs CCRAM
> zugreifen möchtest.

Oh ok, du hast Recht!!!
Ich meinte an dieser stelle den Ram.

von A. B. (Gast)


Lesenswert?

Matthias F. schrieb:
> Im Linkerscript ist dieser von vorne rein so definiert:
>   _siccmram = LOADADDR(.ccmram);
>
>   /* CCM-RAM section
>   *
>   * IMPORTANT NOTE!
>   * If initialized variables will be placed in this section,
>   * the startup code needs to be modified to copy the init-values.
>   */
>   .ccmram :
>   {
>     . = ALIGN(4);
>     _sccmram = .;       /* create a global symbol at ccmram start */
>     *(.ccmram)
>     *(.ccmram*)
>
>     . = ALIGN(4);
>     _eccmram = .;       /* create a global symbol at ccmram end */
>   } >CCMRAM AT> FLASH
> [/c]
>
> Ich meinem Quellcode habe ich ein 30kB großes Array mit
> "__attribute__((section(".ccmram")))" gekennzeichnet. Dieses Array
> bestitzt keine Initialisierungswerte.
> Ich kann erkennen, dass das Array erfolgreich im CCMRAM abgelegt wird.

Das ist missverständlich. Das Array wird eben (noch) NICHT im CCRAM 
abgelegt, es wird lediglich ein entsprechender Bereich im CCRAM 
reserviert und die Start- bzw. Endadresse den Symbolen _sccmram bzw. 
_eccmram zugewiesen. Das sind die "relocation addresses", also die 
Adressen, die zur Laufzeit (und damit für Adressberechnung des Linkers, 
für Zeiger oder Sprungziele) verwendet werden. Absicht ist also, dieses 
Array im CCMRAM abzulegen, daher ">CCMRAM", das könnte man als "soll 
nach ... gehen"

Das "AT> FLASH" besagt, dass diese Sektion tatsächlich aber in den Flash 
(ab des aktuellen location counters) geladen wird (daher "load 
address"), also belegt sie dort natürlich den Platz. Könnte man als 
"wird erstmal dort platziert" lesen. Diese "load address" wird dem 
Symbol _siccmram zugewiesen. Der startup code muss also den Bereich ab 
_siccmram
(mit der Länge _eccmram-_sccmram) nach _sccmram kopieren.

In dem zitierten Beispiel zum Initialisierungscode kommt _siccmram gar 
nicht vor, das kann als kaum funktionieren.

Lässt man das "AT> FLASH" weg, landet die Sektion halt sofort da, wo sie 
zur Laufzeit auch hin soll (mangels Initialisierung aber "leer").

> Allerdings verbraucht der Flash nun 30kB mehr Speicher, wie zuvor.
> Wie ist das zu erklären?

von Matthias F. (frank91)


Lesenswert?

Schonmal danke für eure Hilfe :-)

A. B. schrieb:
> In dem zitierten Beispiel zum Initialisierungscode kommt _siccmram gar
> nicht vor, das kann als kaum funktionieren.

ah ok, du hast recht.
Ich habe mir folgende Application Note angesehen:
http://www.st.com/content/ccc/resource/technical/document/application_note/bb/09/ca/83/14/e9/44/c5/DM00083249.pdf/files/DM00083249.pdf/jcr:content/translations/en.DM00083249.pdf
Seite 20-21 findet man hier ein Beispiel.
Mit diesem funktioniert es.

A. B. schrieb:
> Lässt man das "AT> FLASH" weg, landet die Sektion halt sofort da, wo sie
> zur Laufzeit auch hin soll (mangels Initialisierung aber "leer").

Also könnte ich dies auch stattdessen einfach weglassen?
Was hier noch nicht verstehe ist wieso der benötigte Flash Speicher in 
diesem Fall um die Größe der Initialiserungswerte kleiner wird.

von A. B. (Gast)


Lesenswert?

Matthias F. schrieb:
> A. B. schrieb:
>> Lässt man das "AT> FLASH" weg, landet die Sektion halt sofort da, wo sie
>> zur Laufzeit auch hin soll (mangels Initialisierung aber "leer").
>
> Also könnte ich dies auch stattdessen einfach weglassen?
> Was hier noch nicht verstehe ist wieso der benötigte Flash Speicher in
> diesem Fall um die Größe der Initialiserungswerte kleiner wird.

Die Initialisierungswerte laden dann halt nur da, wo sie letztlich auch 
hin sollen (im CCMRAM), also nicht im Flash, und verbrauchen so dort 
auch keinen Platz. Faktisch sind sie dann aber einfach komplett weg, 
denn das RAM ist halt flüchtig (ein angeschlossener Debugger könnte sie 
natürlich ins RAM laden, aber sonst ...). Es bleibt nur die Reservierung 
des entsprechenden Platzes im (CCM-) RAM (und für den Linker die 
Adressbezüge).

Das ist genau das, was sonst mit nicht (explizit) initialisierten 
Datenbereichen (bss Sektion) auch passiert, etwa

  .bss :
  {
    /* Used by startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    _bss_start_ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    _bss_end_ = _ebss;
  } >RAM

Das "initialize" meint hier nur Nullen.

von Nop (Gast)


Lesenswert?

Matthias F. schrieb:

> Ist dies so richtig? Gibt es sonst noch etwas was ich bei diesem
> Speicher berücksichtigen muss?

Das CCM ist nur über den Datenbus angebunden, nicht über den 
Instruktionsbus. Das bedeutet, Du kannst keinen Code ins CCM laden und 
dort ausführen. Beim "normalen" RAM kann man das machen, sollte man aber 
normalerweise nicht tun - insbesondere nicht aus Gründen der 
Performance.

von Matthias F. (frank91)


Lesenswert?

A. B. schrieb:
> Die Initialisierungswerte laden dann halt nur da, wo sie letztlich auch
> hin sollen (im CCMRAM), also nicht im Flash, und verbrauchen so dort
> auch keinen Platz. Faktisch sind sie dann aber einfach komplett weg,
> denn das RAM ist halt flüchtig (ein angeschlossener Debugger könnte sie
> natürlich ins RAM laden, aber sonst ...). Es bleibt nur die Reservierung
> des entsprechenden Platzes im (CCM-) RAM (und für den Linker die
> Adressbezüge).

ahhhhh ok, jetzt verstehe ich es :-)
Ich habe immer mit dem Debugger den Startwert ausgelesen.
wenn ich aber stattdessen den Stand der Variablen mittels einer LED 
auslese erkenne ich dass diese auf dem Startwert ist wenn die Platine 
gerade programmiert wurde.
Sobald die Platine aber aus- und wieder eingeschalten wird ist irgendein 
anderer Wert übernommen wurden.
Der Initialiserungswert wird also nicht gespeichert.

Ich denke das ich jetzt alles verstanden habe.
Meine Fragen wurden zumindest alle beantwortet :-)

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.