www.mikrocontroller.net

Forum: Compiler & IDEs AVR-GCC: externer SRAM, wie?


Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nun habe ich 32kB ab 0x8000 an den ATmega2560 rangepappt und steh auf
dem Schlauch, wie die beim GCC anmelden.

Wie kann ich dem GCC für bestimmte Variablen (große Arrays) sagen, daß
er sie dorthin legen soll?

Schön wärs, wenn der GCC ihn auch nullen bzw. initialisieren kann.

Die Lücke 0x2200-0x7FFF muß reserviert bleiben!
Da ist nämlich kein SRAM, sondern memory mapped IO.


Peter

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie wär's, einfach einen Zeiger zu benutzen?

Ansonsten kannst du das irgendwie mit sections jonglieren, wenn du
unbedingt willst.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
http://www.nongnu.org/avr-libc/user-manual/FAQ.htm...
http://www.nongnu.org/avr-libc/user-manual/FAQ.htm...

Wäre jetzt mein erster Ansatz. Also eine neue Linker Section anlegen an 
die richtige Adresse und per attribute das große Array dort hinein 
legen.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Wie wär's, einfach einen Zeiger zu benutzen?

Wenns garnicht anders geht, wäre das die Notvariante.
Bloß dann muß ich mir die ganze Plazierung umständlich selber auszählen, 
das wollte ich vermeiden.


> Ansonsten kannst du das irgendwie mit sections jonglieren, wenn du
> unbedingt willst.

Ja, so hatte ich es gedacht.
Bin aber aus den Beispielen nicht schlau geworden. Die wollen immer 
gleich ab 0x2200 anfangen und dann auch nur für malloc-Variablen.
Malloc will ich aber garnicht verwenden, da alle Arrays schon bekannt 
sind.


Peter

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Verwendung per separater Section ist doch recht einfach:
#define EXTMEM __attribute__((section(".extmem")))

uint8_t data[100] EXTMEM;
-Wl,--section-start=.extmem=0x88000

Aber Achtung: keine automatische Nullung!

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Bloß dann muß ich mir die ganze Plazierung umständlich selber auszählen,
> das wollte ich vermeiden.

Hmm, verstehe ich nicht ganz.  Wenn das MMIO ist, dann hat man doch
normalerweise alles auf vorgegebenen Adressen?  Vielleicht erzählst
du uns ja doch noch drei Sätze mehr dazu, was du da genau hast.

Bliebe noch die Variante, alles in einer struct aufzuführen, und
dann einen Zeiger auf diese zu benutzen.

Autor: Eduard Scheske (schneehase)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

ein gutes Beispiel was du machen musst ist auf 
http://www.nongnu.org/avr-libc/user-manual/malloc.html beschrieben ab 
"Tunables for malloc()".

Du musst im Makefile für den Linker die Startadressen von .data und .bss 
ändern ( --section-start,.data=0x808000, --defsym=__heap_end=0x80ffff ). 
Würde dann in etwa so aussehen 
http://www.nongnu.org/avr-libc/user-manual/malloc-x1.png. Und du must 
vor dem Start von main() im µC den Speicher ummappen ( MCUCR, WDTCR ). 
Muss in die Section ".init3" oder ".init4". Ist sehr gut auf 
http://www.avrfreaks.net/index.php?name=PNphpBB2&f... 
beschrieben

Autor: Lazy Leo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab ich schonmal was zu geschrieben. Die Suchen-Funktion ist Dein 
Freund.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Hmm, verstehe ich nicht ganz.  Wenn das MMIO ist, dann hat man doch
> normalerweise alles auf vorgegebenen Adressen?  Vielleicht erzählst
> du uns ja doch noch drei Sätze mehr dazu, was du da genau hast.

Also:
0x0000 - 0x1FFF ist interner RAM für Stack und Variablen.

0x2000 - 0x7FFF sind IO-Chips dran, die werden per Pointer auf Structs 
adressiert.

0x8000 - 0xFFFF ist externer SRAM und da möchte ich große Arrays 
(Menü-Listen) ablegen. Die sollen wenn möglich vorbelegt oder genullt 
werden.



Peter

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eduard Scheske schrieb:

> ein gutes Beispiel was du machen musst ist auf
> ...
> Du musst im Makefile für den Linker die Startadressen von .data und .bss
> ändern ( --section-start,.data=0x808000, --defsym=__heap_end=0x80ffff ).

Unsinn, da steht was er machen kann, nicht was er machen muss. Wie 
ich Peter kenne, will er sicher nicht alle statischen Variablen in das 
externe RAM legen und somit den Zugriff auf diese verlangsamen.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Die sollen wenn möglich vorbelegt oder genullt werden.

Diese Möglichkeit sehe ich nur, wenn du dann doch tatsächlich alles (bis 
auf den Stack) in das externe RAM legst. Oder einfach am Anfang des 
Programms selber initialisieren, z.B. von PROGMEM-Arrays kopieren.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eduard Scheske schrieb:
> ein gutes Beispiel was du machen musst ist auf
> http://www.nongnu.org/avr-libc/user-manual/malloc.html beschrieben ab
> "Tunables for malloc()".

Um mal die Bilder in dem Link zu nehmen, will ich folgendes:

Interner RAM bis 0x1FFF:
.data_1
.bss_1
.stack

Externer RAM ab 0x8000:
.data_2 (mit nem Attribut angelegt)
.bss_2 (mit nem Attribut angelegt)

Einen .heap habe ich nicht.


Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lazy Leo schrieb:
> Hab ich schonmal was zu geschrieben. Die Suchen-Funktion ist Dein
> Freund.

Die Suche nach "Lazy Leo" ergibt 0 Treffer.


Peter

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst schrieb:

>> Die sollen wenn möglich vorbelegt oder genullt werden.
>
> Diese Möglichkeit sehe ich nur, wenn du dann doch tatsächlich alles (bis
> auf den Stack) in das externe RAM legst.

Zustimmung.  gcrt1.S kann nur mit einem zusammenhängenden Block
.data und einem Block .bss umgehen, den Rest muss man ,,zu Fuß''
machen.

Falls genügend externer SRAM vorhanden ist, kann man natürlich wirklich
alles dahin legen und den internen RAM nur noch für den Stack benutzen.
Leider braucht externer SRAM aber einen Takt mehr im Zugriff.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Zustimmung.  gcrt1.S kann nur mit einem zusammenhängenden Block
> .data und einem Block .bss umgehen, den Rest muss man ,,zu Fuß''
> machen.

.bss ist ja der genullte data-Bereich, kann ich nur den nach intern 
legen?


> Falls genügend externer SRAM vorhanden ist, kann man natürlich wirklich
> alles dahin legen und den internen RAM nur noch für den Stack benutzen.
> Leider braucht externer SRAM aber einen Takt mehr im Zugriff.

Werd ich dann wohl so machen müssen.


Peter

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schreib doch ein eigenes Nullungsscript in eine init Section?!

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> .bss ist ja der genullte data-Bereich, kann ich nur den nach intern
> legen?

Nö, das Standard-Linkerscript verkettet .data und .bss zu einer
gemeinsamen Ausgabe-Section namens .data.

Ohne jetzt nachzugucken im gcrt1.S (das kannst du ggf. selbst tun)
würde ich sagen, dass dieses sich auf die Symbole für den Anfang
und das Ende von .bss verlässt, von daher sollte es mit einem
geänderten Linkerscript gehen.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:

> .bss ist ja der genullte data-Bereich, kann ich nur den nach intern
> legen?

Also geht es in erster Linie um die Nullung? Dann würde ich an deiner 
Stelle doch noch mal die Heap-Lösung in Betracht ziehen. Wenn es eher 
wenige große Arrays sind (und nicht viele kleine) ist der zusätzliche 
Speicherverbrauch minimal. Und mit calloc (statt malloc) kannst du die 
Arrays dann auch gleich Nullen.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist aber auch nichts anderes, als wenn er an den Beginn seines
main() schreiben würde:
memset((void *)0x8000, 0, 0x8000);

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, die Nullung wäre halt nur etwas selektiver.

Ich persönlich würde ja auch einfach die Lösung mit der separaten 
Section nehmen, und dann einmal zu Beginn selber Nullen. Aber ich habe 
so den Eindruck, dass ihm das irgendwie nicht zusagt.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Falls genügend externer SRAM vorhanden ist, kann man natürlich wirklich
> alles dahin legen und den internen RAM nur noch für den Stack benutzen.

So habe ich es jetzt gemacht und es funktioniert.
Damit kann man die Menüs vorbelegen. Ich hätte ja die Menüs in den Flash 
gelegt und wäre ohne extra SRAM ausgekommen, aber die Programmierer 
wollen es halt schön bequem haben.


Ne Fallgrube war noch die init3-Routine, die muß used sein, sonst wird 
sie wegoptimiert:
void init_extSRAM(void) __attribute__((used,naked,section(".init3")));
void init_extSRAM(void)
{
  XMCRA = 1<<SRE | 1<<SRL2 | 1<<SRW00;          // 0x2200 - 0x7FFF: 1 Wait
                                                // 0x8000 - 0xFFFF: 0 Wait
  XMCRB = 1<<XMBK;                              // A15 .. A8
}

Und der Linkerschalter:
-Wl,--section-start,.data=0x808000


Danke an alle für die Hilfe.

Peter

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> die muß used sein, sonst wird
> sie wegoptimiert:

Nur, wenn man den "ich bin zu faul, mir beim Programmieren zu
überlegen, welche Funktionen ich wirklich mal benötigen werde"-Knopf
benutzt und daher -gc-sections beim Linken angibst.  Dann mach der
Linker natürlich genau das, was du ihm sagst: du hast die Verantwortung
herauszufinden, was denn wirklich gebraucht wird, ja vom Progammierer
an den Linker übertragen, und der schmeißt dann radikal alles weg,
was unbenutzt aussieht.

Ich verstehe ja, dass C++-Programmierer darunter leiden, dass ihnen
der Compiler aus formalen Gründen zuweilen Dinge generiert, die sie
dann eigentlich gar nicht brauchen, und dass man genau diese mittels
-gc-sections wieder aufgeräumt bekommt, aber warum Programmierer für
Microcontroller nicht in der Lage sein wollen, Funktionen, die sie
gar nicht benötigen, auch gar nicht erst im Sourcecode stehen zu
lassen, das leuchtet mir nach wie vor nicht ein.

YMMV. ;-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.