STm32Fxxx: Kleiner Gefallen vom einem Profi erbeten

Gast #4356286
Lesenswert?

Hallo,

könnte mir jemand das angehängte Linkerscript (Code im Flash) für den 
STM32F07 so umbauen, dass die nachfolgenden Sections einzeln ansprechbar 
sind durch Schlüsselworte in der __attribute_sections Anweisung. Ich 
brauche die Sections einzeln. Alles ohne SSchlüsselwort soll im SRAM1 
landen, Stack und Heap genauso.

CCM
SRAM1
SRAM2
SRAM3
BURAM

mit den Grenzen:

Backup RAM  0x4002.4FFF - 0x4002.4000

SRAM3  0x2002.FFFF- 0x2002.0000

SRAM2  0x2001.FFFF - 0x2001.C000

SRAM1  0x2001.BFFF - 0x2000.0000

CCM Core RAM  0x1000.0000 - 0x1000.FFFF

und das Ganze wieder hier posten? :-)

Gruss
C.J.
Angehängte Dateien:
Gast #4356295
Lesenswert?

Das gehört wohl auch noch dazu.....
1
.preinit_array     :
2
  {
3
    PROVIDE_HIDDEN (__preinit_array_start = .);
4
    KEEP (*(.preinit_array*))
5
    PROVIDE_HIDDEN (__preinit_array_end = .);
6
  } >rom
7
  .init_array :
8
  {
9
    PROVIDE_HIDDEN (__init_array_start = .);
10
    KEEP (*(SORT(.init_array.*)))
11
    KEEP (*(.init_array*))
12
    PROVIDE_HIDDEN (__init_array_end = .);
13
  } >rom
14
  .fini_array :
15
  {
16
    PROVIDE_HIDDEN (__fini_array_start = .);
17
    KEEP (*(SORT(.fini_array.*)))
18
    KEEP (*(.fini_array*))
19
    PROVIDE_HIDDEN (__fini_array_end = .);
20
  } >rom
Gast #4356730
Lesenswert?

Steffen R. schrieb:
> Du willst es doch sicherlich lernen.

Es soll nur funktionieren. Ich kann nicht jedes Fass aufmachen, was mir
auf dem Weg zum Ziel begegnet.

Ist einfach nur sinngemaess kopiert, ohne zu wissen was da genau 
passiert
und warum >BKRAM AT> ROM da stehen muss. Jedenfalls legt er es nicht da 
hin, sondern es erzeugt einen Fehler wegen *Überlappung mit dem ROM.

.bkram :
      {
        . = ALIGN(4);
        _sbkram = .;       /* create a global symbol at bkram start */
        *(.bkram)
        *(.bkram*)
        . = ALIGN(4);
        _ebkram = .;       /* create a global symbol at bkram end */
      } >BKRAM AT> ROM

PS: Ok, nimmt man das AT > ROM weg erzeugt er folgendes, was zu passen 
scheint:

*(.bkram)
 .bkram         0x40024000        0x4 obj\release\src\main.o
                0x40024000                testvar
 *(.bkram*)

und

*(.ccram)
 .ccram         0x10000000        0x4 obj\release\src\main.o
                0x10000000                ccramvar
 *(.ccram*)

Da ich keinen ARM Assembler kann ist die Intialisierung vorbelegter 
static Variablen leider noch ein Wunschtraum.

Vom Gefühl her müsste das hier aber nur kopiert werden meine ich:
1
/*     Loop to copy data from read only memory to RAM. The ranges
2
 *      of copy from/to are specified by following symbols evaluated in
3
 *      linker script.
4
 *      __etext: End of code section, i.e., begin of data sections to copy from.
5
 *      __data_start__/__data_end__: RAM address range that data should be
6
 *      copied to. Both must be aligned to 4 bytes boundary.  */
7

8
    ldr    r1, =__etext
9
    ldr    r2, =__data_start__
10
    ldr    r3, =__data_end__
11
/* Here are two copies of loop implemenations. First one favors code size
12
 * and the second one favors performance. Default uses the first one.
13
 * Change to "#if 0" to use the second one */
14
.flash_to_ram_loop:
15
    cmp     r2, r3
16
    ittt    lt
17
    ldrlt   r0, [r1], #4
18
    strlt   r0, [r2], #4
19
    blt    .flash_to_ram_loop
20
#else
21
    subs    r3, r2
22
    ble    .flash_to_ram_loop_end
23
.flash_to_ram_loop:
24
    subs    r3, #4
25
    ldr    r0, [r1, r3]
26
    str    r0, [r2, r3]
27
    bgt    .flash_to_ram_loop
28
.flash_to_ram_loop_end:
Gast #4356983
Lesenswert?

Tja, und nun ist guter Rat teuer, warum die Variable nicht im BKRAM zu 
finden ist :-( Alle anderen Sections funktionieren, nur die nicht.

Map File:

*(.bkram)
 .bkram         0x40024000        0x4 obj\debug\src\graphik.o
                0x40024000                testvar
 *(.bkram*)
                0x40024004                . = ALIGN (0x4)
                0x40024004                _ebkram = .

Linker file:

* Memory Spaces Definitions */
MEMORY
{
    ROM  (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
    RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
  CCRAM (rwx) : ORIGIN = 0x10000000, LENGTH = 64K
  BKRAM (rwx) : ORIGIN = 0x40024000, LENGTH = 4K
}

 .bkram :
      {
        . = ALIGN(4);
        _sbkram = .;       /* create a global symbol at bkram start */
        *(.bkram)
        *(.bkram*)
        . = ALIGN(4);
        _ebkram = .;       /* create a global symbol at bkram end */
      } >BKRAM
Angehängte Dateien:
Persönliche Seite #4357043
Lesenswert?

Am Beispiel des STM32F407VG. Anpassung der Adressen/Größen ist ggf. 
erforderlich:

Die Spezifikation von Speicherbereichen der Hardware geht so:
1
MEMORY
2
{
3
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 1024K
4
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
5
CCMRAM (rw)      : ORIGIN = 0x10000000, LENGTH = 64K
6
}

Dann muss per Output-Sections definiert werden, was in welche Region 
soll. Der folgende Code nimmt alle "normalen" Variablen (ohne 
section-Attribut) und packt sie in den angebenen Speicher, also hier 
"RAM". Die im C(++)-Code angegebenen Initialwerte werden in den Speicher 
"FLASH" geschrieben:
1
.ram_data :
2
{
3
  . = ALIGN(4);
4
  _sdata1 = .;
5
  *(.data)
6
  *(.data*)
7
  
8
  . = ALIGN(4);
9
  _edata1 = .;
10
} >RAM AT> FLASH
11
_sidata1 = LOADADDR(.ram_data);

In den Symbolen _sdata1, _edata1, und _sidata1 werden die Start-Adresse 
dieser Daten im RAM, Endadresse sowie Anfangsadresse der Initial-Werte 
im Flash abgelegt. Die Symbole werden im Folgenden der Einfachheit wegen 
durchnummeriert, die genauen Namen sind aber prinzipiell egal.

Ähnliche Output Sections kann man dann z.B. für den CCM oder den 
Backup-RAM anlegen:
1
.ccm : 
2
{
3
  . = ALIGN(4);
4
  _sdata2 = .;
5
  *(.ccm)
6
  *(.ccm*)
7
   . = ALIGN(4);
8
  _edata2 = .;
9
} >CCMRAM AT> FLASH
10
_sidata2 = LOADADDR(.ccm);
Auch hier werden die Initialwerte im Flash abgelegt.

Da man für die mit 0 oder gar nicht initialisierten Variablen nicht jede 
Menge 0en im Flash ablegen möchte, fügt man eine BSS-Section hinzu:
1
.bss :
2
{
3
  . = ALIGN(4);
4
  _sbss1 = .;
5
  *(.bss)
6
  *(.bss*)
7
  *(COMMON)
8
 . = ALIGN(4);
9
  _ebss1 = .;
10
} >RAM
Standardmäßig schreibt der Compiler alle 0-Variablen in diese Section, 
die hier im RAM landet. Über _sbss1 und _ebss1 geben wir Anfang & Ende 
dieser Daten im RAM an. Man kann auch weitere bss-Sections definieren, 
falls man 0-Variablen in verschiedenen Speicherbereichen hat (dann muss 
man diese aber explizit per section-Attribut zuweisen).

Um eine spezifische Variable im Code in den CCM zu Packen, muss man sie 
in die Section ".ccm" schieben:
1
int myCCMVar __attribute__((section (".ccm"))) = 42;

Was jetzt noch fehlt, ist die Initialisierung der Werte über den 
Startupcode. Zunächst schreiben wir eine einfache Assembler-Funktion die 
Word-aligned Daten kopiert:
1
/*
2
  r0 = Destination begin
3
  r1 = Destination end
4
  r2 = Source begin
5

6
  Clobber: r3
7
*/
8
.section  .text.Reset_InitCopy
9
.type  Reset_InitCopy, %function
10
Reset_InitCopy:
11
  cmp r0, r1
12
  bhs CopyDataEnd
13

14
  CopyDataLoop:
15
    ldr r3, [r2], #4
16
    str r3, [r0], #4
17

18
    cmp r0, r1
19
    blo CopyDataLoop
20

21
  CopyDataEnd:
22
  bx lr
Und eine Funktion die einen Bereich auf 0 setzt:
1
/*
2
  r0 = Destination begin
3
  r1 = Destination end
4

5
  Clobber: r2
6
*/
7
.section  .text.Reset_InitZeri
8
.type  Reset_InitZero, %function
9
Reset_InitZero:
10
  mov r2, #0
11

12
  cmp r0, r1
13
  bhs ZeroEnd
14

15
  ZeroLoop:
16
    str r2, [r0], #4
17

18
    cmp r0, r1
19
    blo ZeroLoop
20

21
  ZeroEnd:
22
  bx lr

Jetzt müssen diese Funktionen lediglich noch mit den richtigen 
Parametern, die aus den Symbolen des Linkerscripts stammen, aufgerufen 
werden. Der Startupcode sieht dann so aus:
1
.word  _sidata1
2
.word  _sdata1
3
.word  _edata1
4
.word  _sbss1
5
.word  _ebss1
6

7
.word  _sidata2
8
.word  _sdata2
9
.word  _edata2
10

11
.section  .text.Reset_Handler
12
.weak  Reset_Handler
13
.type  Reset_Handler, %function
14
Reset_Handler:  
15

16
  ldr sp, =_estack
17

18
  // Enable CCM & Backup SRAM
19
  ldr r0, =0x40023830
20
  mov r1, 0x00140000
21
  str r1, [r0]
22

23
  // Copy first data section from flash to RAM
24

25
  ldr  r0, =_sdata1    // Begin in RAM
26
  ldr  r1, =_edata1    // End in RAM
27
  ldr  r2, =_sidata1  // Start in Flash
28
  bl Reset_InitCopy
29

30
  // Copy second data section from flash to CCM
31

32
  ldr  r0, =_sdata2    // Begin in CCM
33
  ldr  r1, =_edata2    // End in CCM
34
  ldr  r2, =_sidata2  // Start in Flash
35
  bl Reset_InitCopy
36

37
  // Zero-Initialize first bss section
38

39
  ldr r0, =_sbss1  // Begin BSS
40
  ldr r1, =_ebss1  // End ESS
41
  bl Reset_InitZero
42

43
  // Globale Konstruktoren aufrufen
44
  bl __libc_init_array
45
  
46
  // main()-Funktion aufrufen
47
  bl  main
48
.size  Reset_Handler, .-Reset_Handler

Wie zu sehen ist werden CCM und Backup-SRAM zuvor aktiviert indem im 
RCC_AHB1ENR-Register die Bits CCMDATARAMEN und BKPSRAMEN gesetzt werden, 
denn sonst funktionieren die Zugriffe nicht.

Gegebenenfalls macht es Sinn alle normalen Variablen in den CCM zu 
legen, und nur explizit markierte im "RAM" (nämlich die, auf die per DMA 
zugegriffen werden soll, denn das geht im CCM nicht). Gleichermaßen 
könnte man den im CCM ablegen:
1
_estack = 0x10010000;

Und wo wir gerade dabei sind:
Möchtest du den Code per JTAG/SWD im RAM ausführen, musst du lediglich 
das >FLASH durch >RAM austauschen. Die Variablen müssen dann aber nicht 
mehr durch den Startupcode initialisiert werden, denn das macht der 
Debugger von selbst. Daher lassen sich die entsprechenden Sections 
vereinfachen:
1
.ram_data :
2
{
3
  . = ALIGN(4);
4
  *(.data)
5
  *(.data*)
6
  
7
  . = ALIGN(4);
8
} >RAM AT> FLASH
Das _sidata1 wird hier nicht mehr gebraucht. Die Initialisierung im 
startupcode kann ersatzlos gestrichen werden. Lediglich das 0-Setzen vom 
.bss würde ich vielleicht beibehalten. Damit Interrupts funktionieren, 
kannst du noch das VTOR im Startupcode beschreiben:
1
ldr r0, =0xE000ED08
2
ldr r1, =g_pfnVectors
3
str r1, [r0]
Hierbei wird angenommen, dass g_pfnVectors im Startupcode den Anfang des 
ISR-Vektors anzeigt. Dies funktioniert dann auch korrekt, wenn normal im 
Flash ausgeführt wird. Somit muss nur das Linkerscript angepasst werden 
um zwischen Ausführung im RAM / Flash umzuschalten. Das funktioniert 
aber so leider nur bei Cortex-M3/4.
Gast #4357130
Lesenswert?

Hallo Niklas,

vielen Dank, gleich ausgedruckt !!!!!!! Probiere ich heute abend direkt 
aus. Weisst Du auch wieso bei mir Zuweisungen nicht im BKRAM landen? Die 
Variablen bleiben Null, wenn ich sie beschreibe. Bei allen anderen 
Sections geht es aber.

Ist das die Begründung?

>Wie zu sehen ist werden CCM und Backup-SRAM zuvor aktiviert indem im
>RCC_AHB1ENR-Register die Bits CCMDATARAMEN und BKPSRAMEN gesetzt >werden, denn 
sonst funktionieren die Zugriffe nicht.

Kann ich sinngemaess

.ccm :
{
  . = ALIGN(4);
  _sdata2 = .;
  *(.ccm)
  *(.ccm*)
   . = ALIGN(4);
  _edata2 = .;
} >CCMRAM AT> FLASH
_sidata2 = LOADADDR(.ccm);

auch für BKRAM umschreiben, was müsste dann anstelle von .ccm da stehen?

.buram :
{
  . = ALIGN(4);
  _sdata3 = .;
  *(.buram)
  *(.buram*)
   . = ALIGN(4);
  _edata3 = .;
} >BKRAM AT> FLASH
_sidata3 = LOADADDR(.buram);

???

Gruss,
Christian
#4357244
Lesenswert?

Niklas hat ja sehr ausführlich erläutert. Meine Antworten hier nur der 
Vollständigkeit halber. Meine folgenden Angaben dienen nur dem 
Verständnis und sind nicht angepasst an Niklas seine gute Beschreibung! 
Nicht mischen!

Christian J. schrieb:
> Steffen R. schrieb:
>> Du willst es doch sicherlich lernen.
>
> Es soll nur funktionieren. Ich kann nicht jedes Fass aufmachen, was mir
> auf dem Weg zum Ziel begegnet.

Ja, aber genau deswegen kannst Du auch dein Problem nicht lösen, warum 
die Daten nicht dort landen. Ich hatte auch schon verschiedenste 
Varianten und muss gestehen, dass ich das Linkerfile an die *.map File 
Ausgabe angepasst habe.

Christian J. schrieb:
> warum >BKRAM AT> ROM da stehen muss.

Das war von Dir nicht gefordert und in deinem Linkerfile auch nicht 
enthalten. Warum machst Du es dann? Dies schreibst Du erst in deinen 
späteren Posts. Du willst die Initialisierungsdaten dort ablegen. Nimmst 
Du diese weg, fehlen die Initialisierungsdaten für das spätere 
Umkopieren.

Diese Zeile entspricht der .data Section. D.h. du legst die Daten in den 
Bereich ROM. Ausführen möchtest du sie aber später im Bereich BKRAM.
Mit solchen Konstrukten habe ich auch so meine Probleme. Ich nutzen dann 
die Lösung für .data in abgewandelter Form:
1
__etext = .;  
2
.data : AT (__etext)
3
{
4
} > RAM
Und die Sektion hinter den ganzen ROM Sections legen.

Christian J. schrieb:
> Da ich keinen ARM Assembler kann ist die Intialisierung vorbelegter
> static Variablen leider noch ein Wunschtraum.

Die static Variablen werden normalerweise in .data gelegt. Da klappt 
auch die Initialisierung ohne zusätzlichen Code (ist im startup bereits 
enthalten - wie du selbst zeigst).
Nebenbei: Coocox macht diesen Schritt in C. Es muss also nicht alles 
Assembler sein.

Christian J. schrieb:
> Map File:
>
> *(.bkram)
>  .bkram         0x40024000        0x4 obj\debug\src\graphik.o
>                 0x40024000                testvar

Das zeigt ja, dass testvar im bkram liegt. Die Lage ist nicht dein 
Problem.
Gast #4357282
Lesenswert?

Hallo,

ich denke, dass ich mit diesen Infos was zuwege bekomme. Und die 
Geschichte mit der Initialierung beschränke ich auf den "normalen" SRAM, 
das ist ja auch schon fertig im mitgelieferten Startup Code. Eine 
Initialisierung im Backup RAM kann ja nicht stattfinden, da dieses erst 
freigeschaltet werden muss. Klar kann man das auch im Startup machen 
aber ich habe es lieber "bewusst" in meiner Anwendung.

/* Enable Backup Register */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
  PWR_BackupAccessCmd(ENABLE);

Und den Startup in C habe ich mir von CooCox geklaut, ist mir 
sympathischer als der in Asm und leichter anzupassen.
Angehängte Dateien:
#4357402
Lesenswert?

Christian J. schrieb:
> Und den Startup in C habe ich mir von CooCox geklaut, ist mir
> sympathischer als der in Asm und leichter anzupassen.

Nimm ihn nur zur Ansicht und nur für deine zusätzlichen Bereiche.
startup und linkerfile müssen zusammenpassen. Da du ein "normales" gcc 
Linkerfile nutzt, solltest du für den Hochlauf auch das "normale" gcc 
startup nutzen! Niklas hat Dir ja schon alles für genau deine Umgebung 
aufgeschrieben.
Mische nicht die Lösungen von unterschiedlichen Umgebungen!


Ich wollte damit eigentlich nur ausdrücken, dass Du auch per C die 
Initialisierungsdaten vom Flash in deine Backup Daten kopieren kannst.
Gast #4357446
Lesenswert?

Steffen R. schrieb:
> Ich wollte damit eigentlich nur ausdrücken, dass Du auch per C die
> Initialisierungsdaten vom Flash in deine Backup Daten kopieren kannst.

Ich überlege grad, nachdem ich diverse Lösungen im Netz studiert habe, 
ob das Einmappen des Backup Ram überhaupt sinnig ist. Die meisten 
schreiben 2-3 Routinen und übergeben ihre Daten als Struct zum 
wegschreiben. Danach wird Schreibschutz wieder aktiviert. Aber Variablen 
da rein zu mappen macht keiner.

Klar muss Startup zum .ld passen! Aber die habe ich schon angepasst, der 
C Code läuft genauso wie der Asm Code auf dem gleichen Linker File.
Gast #4357552
Lesenswert?

Ich frickel grad etwas in der Firma (Freitag....) ohne eine 
Entwicklungsumgebung zu haben, nur aus dem Kopf.

Mich irritiert grad etwas das __etext, welches im Linkerfile bei

__etext = .;

  .data : AT (__etext)
  {
    _data_start_ = .;
    *(vtable)
    *(.data*)
[....]

auftaucht. Was muesste da beim CCM stehen?
1
// Enable CCM & Backup SRAM
2
    ldr r0, =0x40023830
3
    mov r1, 0x00140000
4
    str r1, [r0]
5
 
6
 // RAM initialisieren
7
    ldr    r1, =__etext
8
    ldr    r2, =__data_start__
9
    ldr    r3, =__data_end__
10

11
 .flash_to_ram_loop:
12
    cmp     r2, r3
13
    ittt    lt
14
    ldrlt   r0, [r1], #4
15
    strlt   r0, [r2], #4
16
    blt    .flash_to_ram_loop
17

18
// CCM initialisieren
19

20
    ldr    r1, =__etext        //// ??????????
21
    ldr    r2, =__ccm_start__
22
    ldr    r3, =__ccm_end__
23

24
 .flash_to_ccm_loop:
25
    cmp     r2, r3
26
    ittt    lt
27
    ldrlt   r0, [r1], #4
28
    strlt   r0, [r2], #4
29
    blt    .flash_to_ccm_loop
Gast #4357563
Lesenswert?

Aus einem anderen Projekt habe ich funktionierenden CCRAM Linker Script 
Code eben geladen. (schön, wenn der eigene Rechner daheim per ssh 
erreichbar ist :-)
1
  // CCM-RAM section
2

3
  _siccram = LOADADDR(.ccram);
4
  .ccram :
5
  {
6
    . = ALIGN(4);
7
    _sccram = .;       /* create a global symbol at ccmram start */
8
    *(.ccram)
9
    *(.ccram*)
10

11
    . = ALIGN(4);
12
    _eccram = .;       /* create a global symbol at ccmram end */
13
  } >ccram AT> flash

Der dazu passende Startup Code müsste dann ja wie folgt lauten:

// CCM initialisieren

    ldr    r1, =_siccram        // Quelle der Initialdaten im Flash
    ldr    r2, =_sccram         // Ziel Startadresse im CCRAM
    ldr    r3, =_eccram         // Ziel Endadresse im CCRAM

 .flash_to_ccm_loop:            // ... und kopieren!
    cmp     r2, r3
    ittt    lt
    ldrlt   r0, [r1], #4
    strlt   r0, [r2], #4
    blt    .flash_to_ccm_loop

Ist

ldr    r1, =_siccram

richtig als Quelle der Initialdaten?
Persönliche Seite #4357585
Lesenswert?

Christian J. schrieb:
> Weisst Du auch wieso bei mir Zuweisungen nicht im BKRAM landen? Die
> Variablen bleiben Null, wenn ich sie beschreibe. Bei allen anderen
> Sections geht es aber.
Vermutlich weil du den BK-RAM nicht aktiviert hast im RCC_AHB1ENR 
Register?

Christian J. schrieb:
> auch für BKRAM umschreiben, was müsste dann anstelle von .ccm da stehen?
Das erste .ccm hat praktisch keine Bedeutung, da kannst du auch 
.hanswurst hinschreiben. Es muss nur gleich zu dem sein, was in LOADADDR 
steht. Schlau ist natürlich es so zu nennen, dass du es wieder erkennst, 
also z.B. ".bkram". Das zweite .ccm in meinem Code entspricht der 
Input-Section, also dem was du im Section-Attribut im C(++)-Code 
schreibst.
Dein Beispiel mit ".buram." sollte passen. Im C(++)-Code dann 
section(".buram") verwenden.

Steffen R. schrieb:
> Ich nutzen dann
> die Lösung für .data in abgewandelter Form:__etext = .;
> .data : AT (__etext)
> {
> } > RAM
> Und die Sektion hinter den ganzen ROM Sections legen.
Ist mehr oder weniger gleich zur Variante mit LOADADDR, aber du solltest 
unbedingt ein .=ALIGN(4) vor dieses Konstrukt packen...

Steffen R. schrieb:
> Da du ein "normales" gcc
> Linkerfile nutzt, solltest du für den Hochlauf auch das "normale" gcc
> startup nutzen!
Nur woher gibts ein "normales" gcc File für STM32?? Die klaut man doch 
bei ST oder schreibst sie sich selber...

Steffen R. schrieb:
> Mische nicht die Lösungen von unterschiedlichen Umgebungen!
!!!

Christian J. schrieb:
> auftaucht. Was muesste da beim CCM stehen?
Nimm doch meine Lösung aus meinem ersten Post...

Christian J. schrieb:
> Aus einem anderen Projekt habe ich funktionierenden CCRAM Linker Script
> Code eben geladen.
Meins funktioniert auch...

Christian J. schrieb:
> Ich überlege grad, nachdem ich diverse Lösungen im Netz studiert habe,
> ob das Einmappen des Backup Ram überhaupt sinnig ist.
Klar, so kannst du bequem den Linker prüfen lassen ob die Daten 
überhaupt reinpassen, und du brauchst keine Adressfrickelei im 
C(++)-Code. So kannst du auch einfach mehrere BKRAM-Variablen im ganzen 
Projekt in verschiedenen .c Dateien unterbringen, indem du denen das 
section-Attribut verpasst. Es gibt keinen Zwang die alle in einen struct 
zu packen:
> Die meisten
> schreiben 2-3 Routinen und übergeben ihre Daten als Struct zum
> wegschreiben. Danach wird Schreibschutz wieder aktiviert. Aber Variablen
> da rein zu mappen macht keiner.
Die können wahrscheinlich einfach nur keine Linkerscripte schreiben :]
Gast #4357596
Lesenswert?

Supi!

Warte scon sehnsüchtig auf Dienstschluss um das alles auszuprobieren. 
Ist mein letzter Code denn so sinnig? Ich habe mir meine Files 
geschnappt. Zu Hause werde ich dann noch alles schön kommentieren (in 
Deutsch!) und dann sauber ablegen als Muster.

>>Die können wahrscheinlich einfach nur keine Linkerscripte schreiben :]
Das dürften viele nicht können, da das nunmal echtes Kauderwelsch ist. 
Man nimmt das was passt, frickelt sich was dazu, bzw schreibt es 
irgendwo ab... so ist die Welt :-)
Persönliche Seite #4357624
Lesenswert?

Christian J. schrieb:
> Ist mein letzter Code denn so sinnig? Ich habe mir meine Files
> geschnappt.
Ich vermute meiner ist minimal schneller. Wenn viele Daten kopiert 
werden und die Startzeit des Controllers kritisch ist, kann das evtl. 
einen Unterschied machen.

Christian J. schrieb:
> Das dürften viele nicht können, da das nunmal echtes Kauderwelsch ist.
Das ist C aber auch. Aber es ist ja dokumentiert:
https://sourceware.org/binutils/docs/ld/index.html
#4357678
Lesenswert?

Christian J. schrieb:
> Mich irritiert grad etwas das __etext, welches im Linkerfile bei

Niklas verwendet hierfür _sidata2. Da du aber am Anfang auch das Problem 
mit dem überlappenden Flash Bereichen hattest wäre hier meine Veriante 
die Alternative.
1
__etext = .;
2

3
  .data : AT (__etext)
"berechnet" die aktuelle Adresse, bei der der Linker steht und beginnt 
dort die nächste Adresse (alles im Flash gerechnet).

Bei Niklas klappt dies automatisch korrekt.
Niklas holt sich die Anfangsadresse hinterher.
1
_sidata2 = LOADADDR(.ccm);

Warum die Automatik manchmal nicht funktioniert, weiß ich nicht. Dies 
äußert sich dann dadurch, dass für mehrere Sektionen am Anfang der 
Memory Bereiche angefangen wird.

Niklas G. schrieb:
> Ist mehr oder weniger gleich zur Variante mit LOADADDR, aber du solltest
> unbedingt ein .=ALIGN(4) vor dieses Konstrukt packen...

Danke. Hatte bisher noch keine "krummen" Adressen bekommen. Aber sicher 
ist sicher.

Niklas G. schrieb:
> Steffen R. schrieb:
>> Da du ein "normales" gcc
>> Linkerfile nutzt, solltest du für den Hochlauf auch das "normale" gcc
>> startup nutzen!
> Nur woher gibts ein "normales" gcc File für STM32?? Die klaut man doch
> bei ST oder schreibst sie sich selber...

Wußte auch nicht, wie ich es anders schreiben sollte. Ich denke 90% der 
gcc Anwender nutzen linker und startup files, ähnlich wie sie auch ST 
mit dem CMSIS liefert. Ich wollte darauf hinaus, dass Coocox hier sehr 
weit weg davon ist mit Ihrem eigenen Definitionen. Da sie aber genauso 
den Standard gcc nutzen, konnte ich dies sprachlich nicht richtig 
auflösen.

Christian J. schrieb:
>>>Die können wahrscheinlich einfach nur keine Linkerscripte schreiben :]
> Das dürften viele nicht können, da das nunmal echtes Kauderwelsch ist.
> Man nimmt das was passt, frickelt sich was dazu, bzw schreibt es
> irgendwo ab... so ist die Welt :-)

Genau das Ansehen solcher Frickelei hat mich am Anfang total verwirrt. 
Genau dort kommst du an das Grübeln, warum etwas gemacht wird, obwohl es 
nach Handbuch unsinnig ist.
#4357695
Lesenswert?

Niklas, ich hänge mich mal in einer speziellen Frage hier rein.
z.B. hat ein int ein Alignment von 4.
Wird die nächst passende Adresse mit der RUN Adresse oder als Offset zum 
Sectionsanfang gerechnet?

Ich beziehe mich hier auf deinen Hinweis, die Section immer aligned(4) 
beginnen zu lassen.
1
.ccm : 
2
{
3
  . = ALIGN(4);
4
  _sdata2 = .;

Das braucht das startup, weil die Kopierroutine 32bit-weise kopiert, 
richtig?

Christian, für dich die Anmerkung von Niklas eigebaut:
1
. = ALIGN(4);
2
__etext = .;
3

4
  .data : AT (__etext)
5
  {
6
    _data_start_ = .;
7
    *(vtable)
8
    *(.data*)
9
[....]
Gast #4358249
Lesenswert?

Klappt alles nicht :-( Bin zu blöd dafür.

>RAM AT> FLASH

führt zu einem Crash des Programs in den Exception Handler. Nehme ich es 
weg sind die RAM Variablen nicht initialiert, nicht mal die normalen.

Mir ist das ehrlich gesagt zu hoch.

../arm-none-eabi/bin/ld.exe: section .ccram loaded at 
[08009908,0800990b] overlaps section .data loaded at [08009908,08009a53]

:-(
Gast #4358314
Lesenswert?

PS:

Ok, auf jeden Fal kann ich erstmal Werte manuell auf die Variablen 
zuweisen, die in den verschiedenen Regionen liegen und der Debugger 
zeigt mir auch, dass sie die richtigen Adressen haben. Backup RAM muss 
manuell eingeschaltet werden, dann sind da auch die Zahlen drin, die ich 
reinschreiben. Initialierung ist noch nicht fertig, eines nach dem 
anderen.

Mein Linkerscript sieht erstmal so aus und wird auch nicht angemeckert, 
alles liegt dann da wo es soll, nur ramvar ist richtig initialisiert, 
der Rest muss noch...
1
volatile int ramvar RAM = 47;
2
volatile int bkramvar BKRAM = 123;
3
volatile int ccramvar CCRAM = 567;
4

5
void main () {
6

7
    SystemInit();
8

9
    /* Enable Backup Register */
10
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
11
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
12
    PWR_BackupAccessCmd(ENABLE);
13

14
    temp = 78;
15
    ramvar = 12;
16
    bkramvar = 567;
17
    ccramvar = 1000;
18

19
}

PS: 2 Tassen Kaffee und ne Ziggi später: Läuft :-)
1
Reset_Handler:
2
/*     Loop to copy data from read only memory to RAM. The ranges
3
 *      of copy from/to are specified by following symbols evaluated in
4
 *      linker script.
5
 *      __etext: End of code section, i.e., begin of data sections to copy from.
6
 *      __data_start__/__data_end__: RAM address range that data should be
7
 *      copied to. Both must be aligned to 4 bytes boundary.  */
8

9
    ldr    r1, =__etext
10
    ldr    r2, =__data_start__
11
    ldr    r3, =__data_end__
12

13
.flash_to_ram_loop:
14
    cmp     r2, r3
15
    ittt    lt
16
    ldrlt   r0, [r1], #4
17
    strlt   r0, [r2], #4
18
    blt    .flash_to_ram_loop
19

20
/* Kopiere CCRAM Inhalte vom Flash ins CCRAM */
21

22
    ldr    r1, =_siccram
23
    ldr    r2, =_sccram
24
    ldr    r3, =_eccram
25

26
.flash_to_ccram_loop:
27
    cmp     r2, r3
28
    ittt    lt
29
    ldrlt   r0, [r1], #4
30
    strlt   r0, [r2], #4
31
    blt    .flash_to_ccram_loop
Angehängte Dateien:
#4360729
Lesenswert?

Christian J. schrieb:
> Mir ist das ehrlich gesagt zu hoch.
>
> ../arm-none-eabi/bin/ld.exe: section .ccram loaded at
> [08009908,0800990b] overlaps section .data loaded at [08009908,08009a53]

Genau wegen diesem Problems gehe ich immer den Weg, den du in deinem 
Skript für .data gewählt hast. Das Warum kann ich aber auch nicht 
beantworten.

Christian J. schrieb:
> PS: 2 Tassen Kaffee und ne Ziggi später: Läuft :-)

Hast Du auch dieses Problem gelöst?
Gast #4360761
Lesenswert?

Das hier
1
  /* CCM-RAM section */
2
     _siccram = LOADADDR(.ccram);
3
     .ccram :
4
     {
5
        . = ALIGN(4);
6
        _sccram = .;       /* create a global symbol at ccmram start */
7
        *(.ccram)
8
        *(.ccram*)
9

10
        . = ALIGN(4);
11
        _eccram = .;       /* create a global symbol at ccmram end */
12
      } >CCRAM

mit dem
1
/* Kopiere CCRAM Inhalte vom Flash ins CCRAM */
2

3
    ldr    r1, =_siccram
4
    ldr    r2, =_sccram
5
    ldr    r3, =_eccram
6

7
.flash_to_ccram_loop:
8
    cmp     r2, r3
9
    ittt    lt
10
    ldrlt   r0, [r1], #4
11
    strlt   r0, [r2], #4
12
    blt    .flash_to_ccram_loop

sorgt genau dafür, dass

a) CCRAM wird auch wirklich verwendet
b) Initialisierte globale Variablen stehen dann auch initialisiert drin.
c) Lokale, dynamische Variablen lasse sich nicht auf CCRAM zuweisen, das 
meckert der Compiler an. Ich vermute, dass die auf dem Stack liegen.

Beim Flashen mit dem Stlink Tool wird ein 2.ter Fortschritts-Streifen 
eingeblendet, was der bedeutet weiss ich aber nicht, das geht zu schnell 
wieder zu das Fenster.

Die Initialisierung des Backup Ram macht keinen Sinn.
Gast #4360920
Lesenswert?

Steffen R. schrieb:
> Das overlap Problem, auf welches ich darüber eingegangen bin.

Nein, ich habe durch die Verwendung von LOADADDR und Vermeidung von RAM 
> AT FLASH dieses Problem umgangen. Ich vermute, dass die beiden 
irgendwie das Gleiche ausdrücken sollen.

Ich gestehe, dass ich da auch mehr probiert und gefrickelt habe bis 
irgendwann das rauskam was ich haben wollte.

Obwohl oben steht:

ccm :
{
  . = ALIGN(4);
  _sdata2 = .;
  *(.ccm)
  *(.ccm*)
   . = ALIGN(4);
  _edata2 = .;
} >CCMRAM AT> FLASH
_sidata2 = LOADADDR(.ccm);

also beides. Das läuft aber nicht durch, dann wird gemeckert, dass da 
was doppelt verwendet wird.

Und das hat ja auch was zu bedeuten:

.data : AT (__etext)
  {

dieses AT dahinter.

Was mir fehlt wäre so ein Buch "Linkerscript für Dummies", von Adam und 
Eva angefangen.
Gast #4361186
Lesenswert?

Mir hat das hier geholfen:
http://www.delorie.com/gnu/docs/binutils/ld_6.html
Damit habe ich die Linkerskripte des STM32F4 verstanden und konnte sie
für meine Zwecke anpassen.

Mich nervt, dass es für ARM und GCC nur englische Literatur gibt. Klar 
kann ich Englisch lesen aber brauche die 1,5-fache Zeit dafür als wenn 
ich ein deutsches Buch vor mir hätte. Selbst bei Amazon gibt es nicht 
ein einziges Buch in deutsch über diese Themen.
Gast #4369689
Lesenswert?

Hallo,

ich wollte nicht extra einen neuen Thread dafür aufmachen.

Problem: Speicherinitialisierung im Code (nicht im Startup!)

Speicherbereich BackupRam: 0x40024000 - .... 4kb

definiert als

MEMORY
{
    ROM  (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
    RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
  CCRAM (rwx) : ORIGIN = 0x10000000, LENGTH = 64K
  BKRAM (rw)  : ORIGIN = 0x40024000, LENGTH = 4K
}

und

  /* Backup RAM section */
   .bkram (NOLOAD):
   {
       . = ALIGN(4);
       *(.bkram)
       *(.bkram*)
       . = ALIGN(4);
   } >BKRAM

für globale Variablenzweisungen bekannt unter

#define BKRAM __attribute__((section(".bkram")))

Frage:

Wie kann ich durch einen einfachen Befehl oder Schleife
zb mit memset die gesamten 4k ausnullen?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren