Forum: Compiler & IDEs Große Arrays mit AVR-GCC


von Roland (Gast)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

von Roland (Gast)


Lesenswert?

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.

von S. R. (svenska)


Lesenswert?

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. ;-)

von Falk B. (falk)


Lesenswert?


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.