ich habe eine Software für einen ATMega162 mit externem RAM. avr-size gibt mir folgende Meldung:
1
AVRMemoryUsage
2
----------------
3
Device:atmega162
4
5
Program:6270bytes(38.3%Full)
6
(.text+.data+.bootloader)
7
8
Data:3846bytes(375.6%Full)
9
(.data+.bss+.noinit)
Wenn ich die Software mit dem "avr-gcc (WinAVR 20100110) 4.3.3" compiliere, läuft die einwandfrei. Es spielt auch keine Rolle, ob ich beim Linker "-Wl,-Tdata=0x800500,--defsym=__heap_end=0x807fff" angebe oder weglasse.
Sobald ich die aber mit der Version 7.3.0 compiliere, bekomme ich die Fehlermeldung "section .data' is not within region data'" bzw. "section .bss' is not within region data'".
Beim Linken habe ich folgende Parameter angegeben:
a)-Wl,--section-start,.data=0x800500,--defsym=__heap_end=0x807fff
b) -Wl,-Tdata=0x800500,--defsym=__heap_end=0x807fff
Es werdem dazu noch die Adressen 0x800650 und
also:
address 0x800650 of Multitasking.elf section .data' is not within region data'
bzw.:
address 0x801440 of Multitasking.elf section .bss' is not within region data'
Meine Vermutung ist, dass es mit der Angabe des externen Rams zu tun hat. Ich weiss aber nicht, was ich dem Linker genau angeben muss bzw. wo der Fehler liegt.
Meine Vermutung ist, dass es mit der Angabe des externen Rams zu tun
hat. Ich weiss aber nicht, was ich dem Linker genau angeben muss bzw. wo
der Fehler liegt.
Du hast 3k8 RAM, der Prozessor scheinbar nur etwa 1k, deshalb zu >>100% voll
Früher™ nahm der Linker per default sehr viel RAM an, egal wieviel der konkrete AVR wirklich hatte. Jetzt ist das genauer herunter gebrochen worden, mit der exakten Menge an RAM für jeden AVR.
Probier mal, ob
1
-Wl,--defsym=__DATA_REGION_LENGTH__=32768
funktioniert. Das wäre zumindest das Symbol, auf das der Linkerscript zurück greift. Kann auch sein, dass man das über den Compiler mitteilen kann – vielleicht schlägt Johann ja hier auf und weiß aus dem Hut mehr dazu.
Probier mal, ob
-Wl,--defsym=DATA_REGION_LENGTH=32768
funktioniert. Das wäre zumindest das Symbol, auf das der Linkerscript
zurück greift. Kann auch sein, dass man das über den Compiler mitteilen
kann – vielleicht schlägt Johann ja hier auf und weiß aus dem Hut mehr
dazu.
Perfekt. Du bist der Beste. Es ist nicht nur so, dass die Software sich fehlerfrei compilieren und linken lässt, sie läuft auch.
Siehe zum Beispiel die AVR-LibC Doku zu "Symbols in the Default Linker
Script":
Erstmal auch Dir danke für Deine Bemühungen.
Aber irgendwie funktioniert das nicht oder ich habe es nicht verstanden. Es gibt immer noch Fehler beim Linken. Folgendes habe ich ausprobiert und beim Linken übergeben:
Nur zwecks der Neugier: Früher hätte man sowas per Linker Script geregelt, einfach und übersichtlich. Ist das hier AVR-spezifisch oder so eine neumodische IDE-Erfindung?
Diese Symbole werden im Linker Script gesetzt und können im Programm verwendet werden. Zum Beispiel braucht der Startup Code diese Symbole, um Static Storage korrekt initialisieren zu können. Diese Symbole umzudefinieren ist so, als würdest du schreiben
1
#define INT_MAX 2147483647
und dann erwarten, dass int ein 32-Bit Typ ist.
Wie es geht, hat Jörg bereits geschrieben:
Das Layout der data Region kann durch Definieren der genannten Symbole angepasst werden
wobei START die Startadresse der Region ist und LEN deren Länge in Bytes, also zum Beispiel LEN=32k.
__DATA_REGION_ORIGIN__wurde erst mit Binutils v2.40 / 2023-01-14 / PR29741 eingeführt; mit älteren Versionen endet die data Region also vor dem physikalischen Ende vom XRAM. Eine mögliche Abhilfe ist, LEN so zu vergrößern, dass data bis zum Ende vom XRAM reicht.
Dann bleibt noch die Frage, wo der Stapel liegen soll. Üblicherweise nutzt der das interne SRAM, und daher wird SP mit RAMEND weak initialisiert. Falls SP einen anderen Startwert erhalten soll, dann kann man Symbol __stack entsprechend setzen.
Nur zwecks der Neugier: Früher hätte man sowas per Linker Script
geregelt, einfach und übersichtlich. Ist das hier AVR-spezifisch oder so
eine neumodische IDE-Erfindung?
Ein Symbol zu definieren ist immer noch einfacher, als ein eigenes Linker Script zu maintainen. Die o.g. Symbole werden ja vom default ld Script verwendet, also gibt es keinen Grund, das Rad neu zu erfinden.
Das Layout der data Region kann durch Definieren der genannten Symbole
angepasst werden-Tdata=START -Wl,--defsym,DATA_REGION_ORIGIN=START
-Wl,--defsym,DATA_REGION_LENGTH=LEN
wobei START die Startadresse der Region ist und LEN deren Länge in
Bytes, also zum Beispiel LEN=32k.
Danke Dir. Werde ich nächste Woche ausprobieren. Dieses Wochenende schaffe ich es nicht mehr.
Ein Symbol zu definieren ist immer noch einfacher, als ein eigenes
Linker Script zu maintainen.
Das war auch mein Horror. Ich hatte nur nach der Fehlermeldung gegoogelt und dort wurde mehrfach erwähnt, das Linkerscript anzupassen. Damit wäre ich aber wahrscheinlich hoffnungslos überfordert gewesen.
Damit wäre ich aber wahrscheinlich hoffnungslos überfordert gewesen.
Ist keine Raketenwissenschaft. Insgesamt aber finde ich den Ansatz der AVR-GNU-Toolchain, generische Linkerscripts mitzuliefern und damit alles "aus der Dose 'raus" aus einer Hand zu haben viel besser als das Gewurschtel bei ARM (jetzt mal auf Cortex-M bezogen), wo jede IDE jedes Herstellers ihr eigenes Linkerscript und natürlich dazu passend ihren eigenen Startup-Code mitliefert.
Ein Symbol zu definieren ist immer noch einfacher, als ein eigenes
Linker Script zu maintainen.
Ich weiss nicht. Was gibt es da gross zu maintainen? Ich hab
fuer alle meine Projekte immer ein eigenes Linkerscript.
Beim aufsetzen kopiere ich das schamlos von einem alten
Projekt, lese das einmal mit eingeschaltetem Verstand durch
und passe 1-2 Werte an und nur wenn sich was ernstes
an meinem Projekt aendert gehe ich da nochmal rein.
compilieren, und das bestehende ELF-File kannst du wie es ist flashen. Bequemer geht's nicht, finde ich. Der einzige nennenswerte Unterschied zum Compilieren eines Host-Programms ist die Angabe des MCU-Typs.
¹ Natürlich nur, wenn das Setup keine Besonderheiten hat wie eben hier der externe RAM.
Das Layout der data Region kann durch Definieren der genannten Symbole
angepasst werden-Tdata=START -Wl,--defsym,DATA_REGION_ORIGIN=START
-Wl,--defsym,DATA_REGION_LENGTH=LEN
wobei START die Startadresse der Region ist und LEN deren Länge in
Bytes, also zum Beispiel LEN=32k.
Ich wollte mich bei Euch beiden nochmal bedanken. Ich habe es heute morgen getestet. Die Software funktioniert mit Euren Angaben perfekt.
Allerdings habe ich noch was (zumindest für mich) erstaunliches festgestellt.
Wenn ich die Software mit der Version 4.3.3 compiliere und linke, dann funktioniert die auch, wenn ich beim linken nicht angebe, dass der externe RAM vorhanden ist. An Ram wird über avr-size angegeben, dass 322,3% benötigt werden. Sobald ich aber den RAM nur geringfügig erhöhe (329,7%) läuft meine Software nicht mehr. Selbst wenn ich beim Linken angebe, dass der externe RAM vorhanden ist.
Wird exakt dieselbe Software mit dem avr-gcc 7.3.0 erstellt, läuft die Software einwandfrei. Beim Linken muss aber:
Dieselbe Software für den AT90CAN128 funktioniert aber auch mit der Version 4.3.3. Hier ist jedoch kein externer Ram angeschlossen und auch nicht beim Linken eingestellt, weil der genug internen hat.
Es wird also Zeit, dass ich mal auf eine neue Version umsteige. Bisher habe ich das immer vermieden, da es mit dem Eclipse-Plugin so schön einfach war. Aber das funktioniert seit einiger Zeit, aufgrund von Änderungen bei avr-dude, sowieso nicht mehr vollständig.
Aber trotzdem vielen Dank. Ihr habt mir richtig weitergeholfen. Ohne Euch wäre ich aufgeschmissen gewesen.
Habe ich vor ein paar Wochen festgestellt, als ich auf eine neue Version von avr-dude umsteigen musste. Normalerweise könnte man das über das Eclipse-Plugin ganz komfortabel einstellen und die Software auch übertragen. Das geht jetzt nicht mehr. Hab irgendwo gelesen, dass in den config-Dateien von avrdude was geändert wurde und deshalb das eclipse-plugin nicht mehr funktioniert. Dafür habe ich mir eine Batch-Datei erstellt. Ist nur nervig, wenn man den Controller wechselt.
Der Programmierer des Plugins, Thomas Holland, war damals auch hier im Forum aktiv. Aber ich glaube das letzte Update ist schon was länger her.
Wenn ich die Software mit der Version 4.3.3 compiliere und linke, dann
funktioniert die auch, wenn ich beim linken nicht angebe, dass der
externe RAM vorhanden ist.
Kommt auf die Distro an. Bei v4.3.3 vermutlich WinAVR-20100110 o.ä.
Wie gesagt ist die Compilerversion unerheblich, was zählt ist die Binutils-Version und welche Patches da reingepackt sind. Ein Binutils Install enthält Kopien die default ld-Skripte in $prefix/avr/lib/ldscripts
Interessant ist hier die Definition der data Region: Zunächst war es
1
data (rw!x) : ORIGIN = $DATA_ORIGIN, LENGTH = $DATA_LENGTH
dann 2015
1
data (rw!x) : ORIGIN = $DATA_ORIGIN, LENGTH = __DATA_REGION_LENGTH__
und 2023 schließlich
1
data (rw!x) : ORIGIN = __DATA_REGION_ORIGIN__, LENGTH = __DATA_REGION_LENGTH__
Dabei sind die $-Werte architekturspezische (genau genommen Emulation-spezifische) Konstanten, die idR so definiert sind, dass
$DATA_ORIGIN + $DATA_LENGTH = 64 KiB.
Die __-Werte sind Symbole, deren default-Wert der jeweilige $-Wert ist. Wenn also niemand (zB Startup-Code oder Anwender) die Symbole definiert, dann ändert sich auch nix an deren Wert.
Exakte Werte sind nützlich, damit der Likner meckert wenn eine Region überläuft und damit nicht in die Hardware passt. Ist die Region zu groß, damm stört das den Linker nicht; es kann aber sein, dass ein nicht funktionierender Code erstellt wird. Und das ist natürlich mühsam zu debuggen.
An Ram wird über avr-size angegeben, dass 322,3% benötigt werden.
Also eine hornalte Version von avr-size mit Patches, die es nie ins offizielle Repo geschafft hat.
Sobald ich aber den RAM nur geringfügig erhöhe
(329,7%) läuft meine Software nicht mehr. Selbst wenn ich beim Linken
angebe, dass der externe RAM vorhanden ist.
Was heißt "RAM erhöhen" ?
Wie gesagt: Aufs Linken an sich hat da keinen Einfluss, lediglich auf Diagnostics.
Stimmt, genau die. Die hatte ich damals installiert, ich glaube als ich angefangen habe eclipse zu verwenden. Da die bisher immer funktioniert hatte, habe bin ich meinen Grundsätzen (Never touch a running system) treu geblieben. Aber jetzt geht es wohl nicht mehr.
Es funktioniert aber nicht. Möglicherweise habe ich das aber auch nicht richtig verstanden und die Definitionen sind falsch. Die Software läuft dann nicht mehr an, wenn ich den "RAM erhöhe" (Erklärungen dazu später).
RAM erhöhen war von mir bescheuert ausgedrückt. Es hätte wohl besser "Ram-Verbrauch erhöhen" heissen müssen. Kurz zur Erklärung, wie ich das meinte. Ich habe ein Array, darin sind die einzelnen Elemente Strukturen. Diese Strukturen bestehen aus einer Vielzahl von Elementen mit unsigned int und unsigned char. Wenn ich das Array um 2 Einträge erhöhe, dann läuft die Software nicht mehr. Das ist allerdings nur bei WinAVR2010 so, bzw. wie Du geschrieben hattest, bei der dazugehörigen Version von Binutils. Erstelle ich das Ganze mit avr 7.3.0 und nehme auch die entsprechend Binutils-Version, dann klappt es.
Selbst wenn ich avr-size aus der avr-version 7.3.0 nehme, habe ich diese
Angabe.
"avr-version 7.3.0", was genau ist das?
Vermutlich Microchips mit privaten Patches zusammen gefrickelte Toolchain.
In den regulären Tools gibt jeweils separate Versionen für GCC, Binutils und AVR-LibC, da diese auch separat gepflegt werden.
In den regulären Binutils hat das size-Kommando ebendiese AVR-Patches nie gesehen, und deren ursprünglicher Autor (dürte noch von Eric Weddington stammen) hatte damals auch gleich gesagt, dass er gar nicht die Absicht hatte, das als offizielle Patches einzureichen – eben weil ihm klar war, dass so ein Hack da nie offiziell Bestand haben würde.
In den regulären Binutils hat das size-Kommando ebendiese AVR-Patches
nie gesehen, und deren ursprünglicher Autor (dürte noch von Eric
Weddington stammen) hatte damals auch gleich gesagt, dass er gar nicht
die Absicht hatte, das als offizielle Patches einzureichen – eben weil
ihm klar war, dass so ein Hack da nie offiziell Bestand haben würde.
Das habe ich nicht verstanden. Ich das avr-size nicht schlecht, wenn es mir den benötigten Flash und Ram anzeigt. Warum war ihm klar, dass das nichts offizielles wird?
In den regulären Tools gibt jeweils separate Versionen für GCC, Binutils
und AVR-LibC, da diese auch separat gepflegt werden.
Wo finde ich die?
Beispielsweise in den Ausgaben der einzelnen Tools:
1
$ avr-gcc --version
2
avr-gcc (GCC) 14.1.0
3
Copyright (C) 2024 Free Software Foundation, Inc.
4
This is free software; see the source for copying conditions. There is NO
5
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
6
7
$ avr-ld --version
8
GNU ld (GNU Binutils) 2.40
9
Copyright (C) 2023 Free Software Foundation, Inc.
10
This program is free software; you may redistribute it under the terms of
11
the GNU General Public License version 3 or (at your option) a later version.
12
This program has absolutely no warranty.
Schwieriger ist es für die AVR-LibC, da es für diese keine installierten ausführbaren Kommandos gibt. Hier musst du entweder deine Paketquellenverwaltung fragen, oder wenn du weißt, wo die Dateien installiert sind, kannst du dir den Inhalt von version.h anzeigen lassen:
1
$cat/usr/local/avr/include/avr/version.h
2
/* Copyright (c) 2005, Joerg Wunsch -*- c -*-
3
All rights reserved.
4
…
5
6
/** \ingroup avr_version
7
String literal representation of the current library version. */
8
#define __AVR_LIBC_VERSION_STRING__ "2.3.0git"
(In meinem Falle ist es also eine Entwicklerversion direkt aus dem Git, die ich installiert habe.)
Das habe ich nicht verstanden. Ich das avr-size nicht schlecht, wenn es
mir den benötigten Flash und Ram anzeigt. Warum war ihm klar, dass das
nichts offizielles wird?
Weil die GNU Binutils generisch für eine riesige Palette von CPUs (und MCUs) sind, der Hack aber lediglich AVRs beinhaltete, und davon dann halt auch noch eine eigene Kopie dieser Information.
Wenn man es hätte richtig machen wollen, hätte man eine Kopie dieser Information irgendwo im Dateisystem hinterlegt und dann sowohl GCC, ggf. den Linker und eben das size-Kommando darauf zugreifen lassen, und hätte dies für alle möglichen MCUs zumindest bereitstellen sollen. Die gesamte Klasse der Cortex-M MCUs hat ja nicht weniger Bedarf an derartiger Information.
Da Eric dazu keine Motivation hatte, blieb es halt ein Hack, den er in sein WinAVR eingebaut hat, ohne dass der jemals offizialisiert worden wäre.
Beispielsweise in den Ausgaben der einzelnen Tools:
Das hatte ich falsch ausgedrückt. Mit
"Wo finde ich die?"
meinte ich, wo ich die regulären Tools zum Download finde. Bei Dir steht dort z.B. "avr-gcc (GCC) 14.1.0". Bei mir 4.3.3.
Im Rahmen meiner Fehlersuche habe ich versucht die aktuellen, offiziellen Versionen der Tools und allem drumherum zu finden. Dabei habe ich nur die von mir genannten gefunden.
Mit
"Wo finde ich die?"
meinte ich, wo ich die regulären Tools zum Download finde.
Beim Packager deines geringsten Misstrauens.
Tools wie GCC oder GNU Binutils oder AVR-LibC liefern erst einmal nur Sourcecode.
Den kannst du jetzt selbst compilieren, oder du suchst dir jemanden, der ihn für dich compiliert.
Ich kann dir leider nicht sagen, wer sowas aktuell für Windows macht. Bei den typischen Linux-Distributionen oder auch bei FreeBSD (wo ich eher zu Hause bin) hast du mehr oder minder aktuelle Versionen in deren jeweiligen Vertriebskanälen dabei, die das für dich vorcompilieren.
Diese Symbole werden im Linker Script gesetzt und können im Programm
verwendet werden. Zum Beispiel braucht der Startup Code diese Symbole,
um Static Storage korrekt initialisieren zu können. Diese Symbole
umzudefinieren ist so, als würdest du schreiben
1
#define INT_MAX 2147483647
und dann erwarten, dass int ein 32-Bit Typ ist.
Hab die Doku mal angepasst. Wenn jemand so einen Fehler macht, dann ist das keine Fehler des Anwenders, sondern der Doku...
Hab die Doku mal angepasst. Wenn jemand so einen Fehler macht, dann ist
das keine Fehler des Anwenders, sondern der Doku...
Meinst Du mich damit? Ich verstehe nicht, wo ich das in der Doku anpassen soll. Hatte auch erst jetzt wieder Zeit reinzusehen, sonst hätte ich mich eher gemeldet.