Forum: Compiler & IDEs STm32Fxxx: Kleiner Gefallen vom einem Profi erbeten


von Christian J. (Gast)


Angehängte Dateien:

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.

von Christian J. (Gast)


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

von Steffen R. (steffen_rose)


Lesenswert?

Du willst es doch sicherlich lernen.

passenden Memorybereich definieren
1
MEMORY
2
{
3
    RAM3 (rwx) : ORIGIN = 0x20020000, LENGTH = 64K
4
}

Dann die Sektion. Der Name ist wichtig für das Attribut.
1
SECTIONS
2
{
3
    SRAM3 : { } > RAM3
4
}

Christian J. schrieb:
> Alles ohne SSchlüsselwort soll im SRAM1
> landen, Stack und Heap genauso.

Im Script RAM in SRAM1 ändern

von Christian J. (Gast)


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:

von Christian J. (Gast)


Angehängte Dateien:

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

von Niklas G. (erlkoenig) Benutzerseite


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.

von Christian J. (Gast)


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

von Steffen R. (steffen_rose)


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.

von Christian J. (Gast)


Angehängte Dateien:

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.

von Steffen R. (steffen_rose)


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.

von Christian J. (Gast)


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.

von Christian J. (Gast)


Lesenswert?

Was bedeutet eigentlich das hier:

_sidata1 = LOADADDR(.ram_data);

von Steffen R. (steffen_rose)


Lesenswert?

_sidata1 wird die Flashadresse der Sektion .ram_data
zugewiesen.

von Christian J. (Gast)


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

von Christian J. (Gast)


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?

von Niklas G. (erlkoenig) Benutzerseite


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 :]

von Christian J. (Gast)


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 :-)

von Niklas G. (erlkoenig) Benutzerseite


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

von Steffen R. (steffen_rose)


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.

von Steffen R. (steffen_rose)


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
[....]

von Christian J. (Gast)


Lesenswert?

Frage völlig am Thema vorbei:

Ich finde die Doku der StdPeriph Libs für den 32F4xxx ums Verrecken 
nicht im Netz bei ST. Wo haben die die als pdf versteckt ???

von Steffen R. (steffen_rose)


Lesenswert?

http://www.st.com/web/en/catalog/tools/PF257901

Ist die nicht in dem Downloadpaket enthalten?
Du meinst doch: stm32f4xx_dsp_stdperiph_lib_um.chm

von Christian J. (Gast)


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]

:-(

von Christian J. (Gast)


Angehängte Dateien:

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

von Steffen R. (steffen_rose)


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?

von Christian J. (Gast)


Lesenswert?

Steffen R. schrieb:
> Hast Du auch dieses Problem gelöst?

Welches?

von Christian J. (Gast)


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.

von Steffen R. (steffen_rose)


Lesenswert?

Christian J. schrieb:
> Steffen R. schrieb:
>> Hast Du auch dieses Problem gelöst?
>
> Welches?

Das overlap Problem, auf welches ich darüber eingegangen bin.

Christian J. schrieb:
> Die Initialisierung des Backup Ram macht keinen Sinn.

Oder so.

von Christian J. (Gast)


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.

von Little B. (lil-b)


Lesenswert?

Christian J. schrieb:
> Was mir fehlt wäre so ein Buch "Linkerscript für Dummies", von Adam und
> Eva angefangen.

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.

von Christian J. (Gast)


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.

von Christian J. (Gast)


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?

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.