Hallo, ich habe eine neue Entwicklungsumgebung für meinen STM32F4107ZG eingerichtet. Die Entscheidung ist auf Em::Blocks (mit ARM GCC Compiler) gefallen. Soweit läuft alles top ;). An meinem STM32F4107ZG ist ein Externes RAM angeschlossen (ERAM1), woraus im LinkerSkript der folgende Memory Aufbau resultiert: ------------------------------------------------------------------------ - MEMORY { IROM1 (RX) : ORIGIN = 0x08000000, LENGTH = 0x00100000 IRAM2 (RW) : ORIGIN = 0x10000000, LENGTH = 0x00010000 IRAM1 (XRW) : ORIGIN = 0x20000000, LENGTH = 0x00020000 ERAM1 (RW) : ORIGIN = 0x60000000, LENGTH = 0x00080000 } ... .bss : { _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; } >IRAM1 ... ------------------------------------------------------------------------ - Jetzt ist meine .bss-Sektion so groß das sie in keine der RAMs passt. Ich will dem LinkerSkript gerne folgendes sagen: "Schreibe die .bss-Sektion erstmal in IRAM1 bis es voll ist, dann schreibe weiter in IRAM2 bis es voll ist und dann weiter in ERAM1." Ich will sozusagen die RAMs aneinander hängen. Ist das möglich? Wenn ja, wie? Viele Grüße crozeg .
Hi, so weit ich wieß geht das so nicht du wirst deine Variablen auf mehrere bss sections aufteilen müssen. Dann kannst du eine in jedem Ram anlegen. Gruß Tec
Hallo, Schonmal danke für die schnelle Antwort. Ich bin noch neu in LinkerScripting. Kannst du mir verraten wie ich die Variablen auf mehrere .bss-Sektionen aufteile? Viele Grüße crozeg .
.bss2 : { _sbss2 = .; /* define a global symbol at bss start */ bss2_start = _sbss2; *(.bss2) *(.bss2*) *(COMMON) . = ALIGN(4); _ebss2 = .; /* define a global symbol at bss end */ bss2_end = _ebss2; } >ERAM1 und bei den Variablen Deklaration "__attribute__((section(".bss2")))" das sollte dann passen. Vllt gibts auch n Makefile generator von Em:Blocks? Das man sowas über die Ide einstellen kann. Crossworks kann so was.
Ch. Ziegler schrieb: > Jetzt ist meine .bss-Sektion so groß das sie in keine der RAMs passt. > Ich will dem LinkerSkript gerne folgendes sagen: > "Schreibe die .bss-Sektion erstmal in IRAM1 bis es voll ist, dann > schreibe weiter in IRAM2 bis es voll ist und dann weiter in ERAM1." Ich hab's jetzt nicht selbst ausprobiert, das müsste aber eigentlich so gehen:
1 | .bss1 : |
2 | { |
3 | _sbss1 = .; /* define a global symbol at bss start */ |
4 | _bss_start_ = _sbss1; |
5 | dir1/*(.bss) |
6 | dir1/*(.bss*) |
7 | dir1/*(COMMON) |
8 | |
9 | . = ALIGN(4); |
10 | _ebss = .; /* define a global symbol at bss end */ |
11 | _bss_end_ = _ebss1; |
12 | } >IRAM1 |
13 | |
14 | .bss2 : |
15 | { |
16 | _sbss2 = .; /* define a global symbol at bss start */ |
17 | _bss2_start_ = _sbss2; |
18 | dir2/*(.bss) |
19 | dir2/*(.bss*) |
20 | dir2/*(COMMON) |
21 | |
22 | . = ALIGN(4); |
23 | _ebss2 = .; /* define a global symbol at bss end */ |
24 | _bss2_end_ = _ebss2; |
25 | } > IRAM2 |
D.h. Du "sammelst" die Objektdateien in zwei Verzeichnissen, aus denen sich der Linker dann pro Segment bedient. So was wie einen "automatischen Überlauf" gibt's meiner Ansicht nach nicht.
Ja, das nervt, dass die uC-Hersteller das RAM so zerstueckeln :( Generell finde ich es aber sowieso schoener, die sections explizit im C-code anzugeben, damit man mit dem Linker-Script noch jonglieren kann. Wo man den Stack hinlegt wird ja wohl auch zu einer ganz wichtigen Entscheidung - vielleicht wichtiger als die die .bss Variablen. Ich vermeide die .bss-Variablen meist zugunsten von Stack-Variablen, wegen deren Speicher-Wiederverwertung ;-) Aber ich hoffe, dass noch ein Toolchain-Guru hier eine L"osung bietet. Ich koennte sowas n"amlich sinngemaess in der .text brauchen...
Wie und wo sage ich dem LinkerScript welche Dateien/Objekte er in welche Section legen soll? Kennt jemand vielleicht ein gutes Tutorial für die ganze Sache hier? Viele Grüße, crozeg .
Tec Nologic schrieb: > und bei den Variablen Deklaration "__attribute__((section(".bss2")))" Gibt es anstatt "__attribute__((section(".bss2")))" auch ein #pragma für eine ganze C-Datei? Markus F. schrieb: > D.h. Du "sammelst" die Objektdateien in zwei Verzeichnissen, aus denen > sich der Linker dann pro Segment bedient. So was wie einen > "automatischen Überlauf" gibt's meiner Ansicht nach nicht. Wie teilt man die *.o-Dateien auf verschiedene Unterverzeichnisse auf? Die Sourcedateien liegen bereits in verschiedenen Unterordnern, die O-Dateien werden beim Bauen in einem einzigen Ordner abgelegt. Viele Grüße crozeg
Du kannst eine die bss section einer datei im Linkerskript angeben.
1 | .bss2 : |
2 | {
|
3 | _sbss2 = .; /* define a global symbol at bss start */ |
4 | _bss2_start_ = _sbss2; |
5 | dir2/*main.o(.bss .bss*) // hier wird bss von main gesetzt. |
6 | dir2/*(.bss) //
|
7 | dir2/*(.bss*)
|
8 | dir2/*(COMMON)
|
9 | |
10 | . = ALIGN(4);
|
11 | _ebss2 = .; /* define a global symbol at bss end */
|
12 | _bss2_end_ = _ebss2; |
13 | } > IRAM2 |
ich weis aber gerade nicht ob das ganz korrekt ist. Vllt weiß das noch jemand anderes.
Korrektur:
1 | There are two ways to include more than one section: |
2 | |
3 | *(.text .rdata) |
4 | *(.text) *(.rdata) |
5 | |
6 | The difference between these is the order in which the `.text' and `.rdata' input sections will appear in the output section. In the first example, they will be intermingled. In the second example, all `.text' input sections will appear first, followed by all `.rdata' input sections. |
7 | |
8 | You can specify a file name to include sections from a particular file. You would do this if one or more of your files contain special data that needs to be at a particular location in memory. For example: |
9 | |
10 | data.o(.data) |
1 | .bss2 : |
2 | { |
3 | _sbss2 = .; /* define a global symbol at bss start */ |
4 | _bss2_start_ = _sbss2; |
5 | main.o(.bss) // hier wird bss von main gesetzt. |
6 | foo.o(.bss) // usw. |
7 | dir2/*(.bss) // |
8 | dir2/*(.bss*) |
9 | dir2/*(COMMON) |
10 | |
11 | . = ALIGN(4); |
12 | _ebss2 = .; /* define a global symbol at bss end */ |
13 | _bss2_end_ = _ebss2; |
14 | } > IRAM2 |
also clean,
1 | MEMORY |
2 | { |
3 | IROM1 (RX) : ORIGIN = 0x08000000, LENGTH = 0x00100000 |
4 | IRAM2 (RW) : ORIGIN = 0x10000000, LENGTH = 0x00010000 |
5 | IRAM1 (XRW) : ORIGIN = 0x20000000, LENGTH = 0x00020000 |
6 | ERAM1 (RW) : ORIGIN = 0x60000000, LENGTH = 0x00080000 |
7 | } |
8 | |
9 | ... |
10 | |
11 | .bss : |
12 | { |
13 | _sbss = .; /* define a global symbol at bss start */ |
14 | _bss_start_ = _sbss; |
15 | main.o(.bss) |
16 | *(.bss) |
17 | *(.bss*) |
18 | *(COMMON) |
19 | |
20 | . = ALIGN(4); |
21 | _ebss = .; /* define a global symbol at bss end */ |
22 | _bss_end_ = _ebss; |
23 | } >IRAM1 |
24 | |
25 | .bss2 : |
26 | { |
27 | _sbss2 = .; /* define a global symbol at bss start */ |
28 | _bss2_start_ = _sbss2; |
29 | foo.o(.bss) |
30 | *(.bss2) |
31 | *(.bss2*) |
32 | *(COMMON) |
33 | |
34 | . = ALIGN(4); |
35 | _ebss2 = .; /* define a global symbol at bss end */ |
36 | _bss2_end_ = _ebss2; |
37 | } >ERAM1 |
@tecnologic: das wird so nicht funktionieren. Das würde bedeuten, daß der Linker selbstständig das nächste Segment nutzen würde, wenn er feststellt, daß eins "voll" ist (was er leider nicht tut). Es bleibt nichts anderes übrig, als den Überlauf "händisch" zu steuern.
@mfro Jop, er muss jetzt aufpassen das die sections der files in die bss bzw. die bss2 section passen. Das ein riesen Array der Speicher aus dem internen wie externen Ram nehmen soll nicht geht, wurde ja bereits erklärt.
Schonmal vielen dank, ihr habt mir schon viel geholfen. Momentan siehen meine bss-Sektionen wie folgt aus: (Hoffe das stimmt soweit)
1 | ...
|
2 | |
3 | .bss2 : |
4 | {
|
5 | _sbss2 = .; /* define a global symbol at bss start */ |
6 | _bss2_start_ = _sbss2; |
7 | |
8 | obj/main.o(.bss .bss* COMMON) |
9 | obj/hwe.o(.bss .bss* COMMON) |
10 | |
11 | /* FreeRTOS Objects */
|
12 | obj/port.o(.bss .bss* COMMON) |
13 | obj/heap_4.o(.bss .bss* COMMON) |
14 | obj/croutine.o(.bss .bss* COMMON) |
15 | obj/event_groups.o(.bss .bss* COMMON) |
16 | obj/list.o(.bss .bss* COMMON) |
17 | obj/queue.o(.bss .bss* COMMON) |
18 | obj/tasks.o(.bss .bss* COMMON) |
19 | obj/timers.o(.bss .bss* COMMON) |
20 | |
21 | . = ALIGN(4); |
22 | _ebss2 = .; /* define a global symbol at bss end */ |
23 | _bss2_end_ = _ebss2; |
24 | } >IRAM1 |
25 | |
26 | .bss : |
27 | {
|
28 | _sbss = .; /* define a global symbol at bss start */ |
29 | _bss_start_ = _sbss; |
30 | |
31 | *(.bss) |
32 | *(.bss*) |
33 | *(COMMON) |
34 | |
35 | . = ALIGN(4); |
36 | _ebss = .; /* define a global symbol at bss end */ |
37 | _bss_end_ = _ebss; |
38 | } >ERAM1 |
39 | |
40 | ...
|
Aber leider läuft meine Firmware nicht richtig. Was genau scheinbar scheinen einige Dateien andere nicht mehr zu finden/erreichen? Und was genau macht so ein AT befehl in LinkerScripts? Zb im folgenden am ende meiner data-Sektion:
1 | ...
|
2 | .data : |
3 | {
|
4 | . = ALIGN(4); |
5 | _sdata = .; /* create a global symbol at data start */ |
6 | *(.data) /* .data sections */ |
7 | *(.data*) /* .data* sections */ |
8 | |
9 | . = ALIGN(4); |
10 | _edata = .; /* define a global symbol at data end */ |
11 | } >ERAM1 AT> IROM1 |
12 | ...
|
Viele Grüße crozeg
:
Bearbeitet durch User
Ch. Ziegler schrieb: > Und was genau macht so ein AT befehl in LinkerScripts? > Zb im folgenden am ende meiner data-Sektion: >
1 | > ... |
2 | > .data : |
3 | > { |
4 | > . = ALIGN(4); |
5 | > _sdata = .; /* create a global symbol at data start */ |
6 | > *(.data) /* .data sections */ |
7 | > *(.data*) /* .data* sections */ |
8 | >
|
9 | > . = ALIGN(4); |
10 | > _edata = .; /* define a global symbol at data end */ |
11 | > } >ERAM1 AT> IROM1 |
12 | > ... |
> > Viele Grüße > crozeg das AT-Konstrukt packt die Objektdaten an die erste Adresse (ERAM1), reloziert den Code aber so, daß sie ab der zweiten Adresse (IROM1) referenziert werden. Für dich bedeutet das, daß dein ausführbarer Code seine Daten ab der Startadresse IROM1 erwartet (wo sie aber nicht sind, falls Du sie nicht beim Programmstart umkopierst). Das kann so m.E. nicht gut gehen.
:
Bearbeitet durch User
Ach, noch was: wenn Du deinem Linker zusätzlich die Argumente
1 | -Map mapfile.txt --cref |
mitgibst, kannst Du anhand des erzeugten Map-Files über die Crossreferenz nachvollziehen, wo dein Code/deine Daten gelandet sind.
Außerdem brauchst du handling für dein .bss2 im startup code, gucke einfach mal was da für die .bss gemacht wird, üblicher weise nullen usw.
Hallo, danke schonmal, seit dem nullen im startup code läufts schon besser. Zumindest die main.o.
1 | ...
|
2 | . = ALIGN(4); |
3 | .bss_iram1 : |
4 | {
|
5 | _sbss_iram1 = .; /* define a global symbol at bss start */ |
6 | _bss_iram1_start_ = _sbss_iram1; |
7 | |
8 | obj/main.o(.bss .bss* COMMON) |
9 | obj/rm_tcp.o(.bss .bss* COMMON) |
10 | |
11 | /* FreeRTOS Objects */
|
12 | obj/port.o(.bss .bss* COMMON) |
13 | obj/heap_4.o(.bss .bss* COMMON) |
14 | obj/croutine.o(.bss .bss* COMMON) |
15 | obj/event_groups.o(.bss .bss* COMMON) |
16 | obj/list.o(.bss .bss* COMMON) |
17 | obj/queue.o(.bss .bss* COMMON) |
18 | obj/tasks.o(.bss .bss* COMMON) |
19 | obj/timers.o(.bss .bss* COMMON) |
20 | |
21 | . = ALIGN(4); |
22 | _ebss_iram1 = .; /* define a global symbol at bss end */ |
23 | _bss_iram1_end_ = _ebss_iram1; |
24 | } >IRAM1 |
25 | |
26 | |
27 | . = ALIGN(4); |
28 | .bss_eram1 : |
29 | {
|
30 | /* This is used by the startup in order to initialize the .bss secion */
|
31 | _sbss_eram1 = .; /* define a global symbol at bss start */ |
32 | __bss_eram1_start__ = _sbss_eram1; |
33 | |
34 | *(.bss) |
35 | *(.bss*) |
36 | *(COMMON) |
37 | |
38 | . = ALIGN(4); |
39 | _ebss_eram1 = .; /* define a global symbol at bss end */ |
40 | __bss_eram1_end__ = _ebss_eram1; |
41 | } >ERAM1 |
42 | ...
|
Wenn ich die Zeile "obj/rm_tcp.o(.bss .bss* COMMON)" zur bss_iram1 hinzufüge funktioniert nichts mehr. Der Compiler wirft folgendes:
1 | Linking executable: bin\Debug\FreeRTOS4EGM.elf |
2 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `_cleanup_r': |
3 | findfp.c:(.text._cleanup_r+0x0): multiple definition of `_cleanup_r' |
4 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text._cleanup_r+0x0): first defined here |
5 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sfmoreglue': |
6 | findfp.c:(.text.__sfmoreglue+0x0): multiple definition of `__sfmoreglue' |
7 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sfmoreglue+0x0): first defined here |
8 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `_cleanup': |
9 | findfp.c:(.text._cleanup+0x0): multiple definition of `_cleanup' |
10 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text._cleanup+0x0): first defined here |
11 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sinit': |
12 | findfp.c:(.text.__sinit+0x0): multiple definition of `__sinit' |
13 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sinit+0x0): first defined here |
14 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sfp': |
15 | findfp.c:(.text.__sfp+0x0): multiple definition of `__sfp' |
16 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sfp+0x0): first defined here |
17 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sfp_lock_acquire': |
18 | findfp.c:(.text.__sfp_lock_acquire+0x0): multiple definition of `__sfp_lock_acquire' |
19 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sfp_lock_acquire+0x0): first defined here |
20 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sfp_lock_release': |
21 | findfp.c:(.text.__sfp_lock_release+0x0): multiple definition of `__sfp_lock_release' |
22 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sfp_lock_release+0x0): first defined here |
23 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sinit_lock_acquire': |
24 | findfp.c:(.text.__sinit_lock_acquire+0x0): multiple definition of `__sinit_lock_acquire' |
25 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sinit_lock_acquire+0x0): first defined here |
26 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sinit_lock_release': |
27 | findfp.c:(.text.__sinit_lock_release+0x0): multiple definition of `__sinit_lock_release' |
28 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sinit_lock_release+0x0): first defined here |
29 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__fp_lock_all': |
30 | findfp.c:(.text.__fp_lock_all+0x0): multiple definition of `__fp_lock_all' |
31 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__fp_lock_all+0x0): first defined here |
32 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__fp_unlock_all': |
33 | findfp.c:(.text.__fp_unlock_all+0x0): multiple definition of `__fp_unlock_all' |
34 | c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__fp_unlock_all+0x0): first defined here |
35 | collect2.exe: error: ld returned 1 exit status |
36 | Process terminated with status 1 (0 minutes, 5 seconds) |
37 | 0 errors, 165 warnings (0 minutes, 5 seconds) |
Siehe auch angehängtes Bild. Im Bild sieht man auch das der Build mit 0 Errors abgeschlossen wurde, aber ich kann den Code nicht Debuggen/ins Target laden. Viele Grüße crozeg
Das sieht mir jetzt so aus, als ob das mit dem Linkerscript nichts zu tun hätte - Du scheinst zu versuchen, die Newlib doppelt zuzulinken. Laß' mal deinen Linker-Aufruf sehen.
Hallo, ich mache keinen expliziten Linker-Aufruf, da ich ja mit der IDE Em::Blocks arbeite/baue. In den Einstellungen habe ich folgende "extra command-line arguments" gefunden, vielleicht meinst du ja die:
1 | -na -nd --batch-build-notify |
Viele Grüße crozeg
Hallo, seit ich in den Em::Blocks Setting, bei Linker Settings, die "default libraries" angehakt (siehe angehägtes Bild). Jetz bauts und läuft (fürs erste). War das richtig? Viele Grüße crozeg
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.