Hallo Experten, ich möchte für ein Projekt eine große Anzahl an Daten (50 kByte Audiosamples) im Flashspeicher eines AVRs ablegen. Wie ich feststellen musste, unterstützt der AVR-GCC jedoch nur Arrays bis zu einer Größe von 32768 Bytes, da die Zeigerberechnung des Compilers mit vorzeichenbehafteter 16-Bit-Arithmetik durchgeführt wird und somit nicht der gesamte 16-Bit-Adressraum verfügbar ist. Da ich den Zugriff auf die Daten im Flashspeicher und dessen Berechnung aufgrund von Geschwindigkeitsoptimierung jedoch nicht in C mittels pgm_read_byte() durchführe, sondern proprietär durch inline-Assembler umgesetzt habe, spielt die GCC-Zeigerberechnung soweit keine Rolle. Mein erster Ansatz war natürlich einfach zwei Arrays anzulegen und zu hoffen, dass der Linker beide Arrays nahtlos im Speicher platziert. Die Betrachtung der erstellen map- und lss-Datei ergab, dass beide Arrays tatsächlich hintereinander platziert werden, allerdings entspricht die Reihenfolge nicht jener der Deklaration. Welche Reihung der Linker hier vornimmt, konnte ich nicht feststellen. Auch wurden teils Füllbytes eingefügt, sodass kein Nahtloser Übergang gewährleistet ist. Alles in allem eine unzureichende und vor allem unsichere Lösung. Eine Recherche brachte mich zum Attribut „session“ wodurch dem Linker mitgeteilt wird, wo die Daten des Arrays zu platzieren sind. Teilt man nun jedem Teilarray eine eigene Session zu, sollte der Linker die Daten in gewünschter Reihenfolge platzieren. Da man dafür aber das Linkerskript für jede verwendete AVR-Familie ändern muss (neue Sessions hinzufügen), überzeugt mich diese Methode auch nicht unbedingt. Ein dritter Ansatz war, die Daten direkt als Assembler-Array (.s Datei mit .byte-Anweisungen) in das Projekt einzubinden. Dies ließ sich zwar fehlerfrei kompilieren, jedoch fand ich die Daten dann nicht im Speicher. Auch ist mir nicht klar, wie dann aus dem C-Code und dem inline-Assembler auf dieses Array zugegriffen werden kann. In einem Forumsbeitrag fand ich auch eine Methode, die Rohdaten in eine Objektdatei umzuwandeln und direkt dem Linker anzugeben. Ein durchaus interessanter Ansatz, aber aufgrund der Vorübersetzung in eine Objektdatei auch nicht ganz anwendungsfreundlich. Ich möchte Euch nun gerne Fragen, welche Möglichkeit es gibt, auf einfache Weise mehr als 32kByte an zusammenhängenden Daten im Flashspeicher abzulegen? Gibt es eine direkte Methode dem Linker mitzuteilen, zwei Arrays in vorgegebener Reihenfolge im Flashspeicher zu platzieren oder ist der Ansatz die Daten in eine eigene Assemblerdatei auszulagern doch zielführend? Vielen Dank im Voraus, Roland.
Das hier ist zwar schon 15 Jahre alt, das Prinzip hat sich aber nicht geändert: https://www.avrfreaks.net/forum/how-get-linker-create-new-memory-section Oliver
Hallo Oliver, danke für Deine Antwort. Im Zuge der Recherche des von Dir angeführten Links habe ich eine Erklärung bezüglich der Verknüpfung von C Variablen mit Assemblerreferenzen gefunden, wodurch ich meinen dritten Ansatz noch einmal probierte. Das Auslagern der Daten in eine .s-Datei und eine darauf aus C referenzierende Variable führte schließlich zum Ziel. Um die zusätzliche Assemblerdatei einzusparen, probierte ich die Assembler-Daten als inline-Assembler zu integrieren, was ebenfalls zielführend war. In beiden Fällen werden nun die Daten vom Linker direkt nach der Interrupt-Vektortabelle eingefügt, gefolgt von den anderen, normal in C Deklarierten Flash-Arrays. Ein zwar nicht relevanter, aber dennoch eigenartiger Unterschied besteht lediglich in der Darstellung der Section in der .lss-Datei. Während bei der Auslagerung der Assemblerdaten in eine eigene .s-Datei in der .lss-Datei die Datensection korrekt mit <ASMSampleData> bezeichnet wird, die Section <__trampolines_end> nicht vorhanden ist und die Daten auch als solche dargestellt werden, sind die Daten bei der inline-Assembler-Variante trotz der Definition ".type ASMSampleData, @object" als Section <__trampolines_end> gekennzeichnet und werden als Code interpretiert.
1 | extern const uint8_t Data[] asm("ASMSampleData"); |
2 | asm
|
3 | (
|
4 | ".section .progmem.data.ASMSampleData,"a",@progbits \n\t" |
5 | ".type ASMSampleData, @object \n" |
6 | "ASMSampleData: \n\t" |
7 | ".byte 1, 2, 3, ... \n\t" |
8 | ".byte 1, 2, 3, ... \n\t" |
9 | ".byte 1, 2, 3, ... \n\t" |
10 | .
|
11 | .
|
12 | .
|
13 | );
|
Grüße, Roland.
Roland schrieb: > Um die zusätzliche Assemblerdatei einzusparen, probierte > ich die Assembler-Daten als inline-Assembler zu integrieren, > was ebenfalls zielführend war. Du kannst auch mit avr-objdump eine beliebige Datei in ein Object-File konvertieren und das schlicht mitlinken. In deinem Code referenzierst du dann ein aus dem Dateinamen generiertes Symbol (gibt auch eins für die Länge). Dann kannst du deine Audiodatei einfach neben die Sourcen legen und den Rest im Makefile erledigen. Die Daten als Inline-Assembler einzubinden ist... schon eher trollig. ;-)
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Dateien_direkt_im_Flash_einbinden https://www.mikrocontroller.net/articles/Bin%C3%A4re_Daten_zum_Programm_hinzuf%C3%BCgen https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#RAM Variablenzugriff >64kB
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.