Hallo! Ich versuche gerade die EFSL (Embedded File System Library) auf meinem PIC18F6680 zum laufen zu bekommen. Ich verwende dabei den MCC18-Compiler. Ich bekomme beim Übersetzen eines der Sourcefiles (ui.c) eine Fehlermeldung, dass der "stack frame" zu groß währe. Ich vermute dass das mit einem zu großen lokalen Datenobjekt zu tun hat, denn der Compiler weißt direkt auf die Stelle im Code hin wo das Objekt angelegt wird (Array der Größe 512 vom Typ unsigned char). Allerdings ist mir das nicht so ganz schlüssig, weil IMO lokale Datenobjekt auf dem Heap und nicht auf dem Stack abgelegt werden und ich deswegen keinen Grund sehe, warum der stack frame zu groß werden sollte. Nichts desto trotz lese ich auch im Compiler-Handbuch, dass man für Objekte, die die Größe einer Memory Bank überschreiten spezielle Vorkehrungen treffen muss. Es muss eine eigene Speicher-Section deklariert werden im Linkerscript ein geeigent großer Bereich definiert werden und die Section dorthin platziert werden. Allerdings gilt das IMHO auch nur für globale Datenstrukturen. Um meine Frage auf den Punkt zu bringen: Wie kann ich innerhalb einer Funktion lokale Datenobjekte verwenden, die die Größe einer Memory-Bank überschreiten? Oder ist das überhaupt kein Problem und der Fehler liegt woanders? Gruß, Martin
Damit du eine Antwort auf diese Frage bekommst, solltest du sie auf www.fernando-heitor.de post. Dort kann dir sicher jemand was dazu sagen. mehr kann ich auch nicht machen. mfg Schoasch
@ Schoasch Es gibt auch hier PIC-User - und das soll, so finde ich, auch so bleiben. @ Martin weil IMO lokale Datenobjekt auf >> ... dem Heap und nicht auf dem Stack abgelegt werden Soweit ich weiß (also ein ganz großes IMHHHO) werden beim PIC18F nur der Hardware-Stack, der Software-Stack und die speziellen Rückgaberegister verwendet. Wenn ich richtig liege, dann musst du nur in den Build-Einstellungn auf das Multi-Stack-Bank-Modell umschalten und im Linkerskript die Stackgröße erhöhen. Ich habe das so gemacht: DATABANK NAME=gpr6 START=0x600 END=0x7FF //DATABANK NAME=gpr7 START=0x700 END=0x7FF ... STACK SIZE=0x200 RAM=gpr6 Dabei fehlt laut C18-Handbuch ein PROTECTED, es ging aber trotzdem. Viele Grüße, Bernhard
Hi Ja ich weis,ich bin selbst auch PIC-User. Ich bin halt nur ein ziemlicher Fan vom oben erwähnten Forum. Es hat zwar nicht eine so hohe Frequenz wie dieses, aber man lernt sehr sehr viel(find ich halt). Ausserdem ist der Umgangston dort etwas angenehmern... hier wird man ja als PIC benutzer eher niedergemacht als einem Hilfreiche tipps gegeben werden.
Ich muss dazu sagen, dass ich nicht ganz freiwillig die PICs verwende. Ich finde das Adressierungsmodell in der Tat etwas anachronistisch. ontopic: Ich habe versucht das File mit der -ls Option (large stack) zu kompilieren, aber es tritt immer noch der gleiche Fehler auf. Ich habe allerdings das Linker-File noch nicht modifiziert. Muss ich das denn überhaupt beim Erzeugen des Object-Files schon machen? Ich meine ich linke ja noch gar nicht.
PIC oder nicht, ein C-Compiler legt lokale Objekte entweder auf dem Stack ab (Standard) oder, wenn die Microcontroller-Architektur sich damit schwer tut, statisch. Letzteres ist nicht Standard-konform und ist nicht reentant, deshalb finden sich dann entsprechende Optionen im Compiler. Lokale Objekte automatisch auf dem Heap abzulegen wär mir mal was neues und ergibt nicht allzu viel Sinn. Aber egal wo der Compiler die Objekte auch immer ablegt, die PIC18 Architektur hat so ihre Probleme mit indirekter Adressierung von Objekten grösser als 256 Bytes. Ohne den Compiler zu kennen nehme ich daher an, dass mit der -ls Option zwar der Stack insgesamt grösser als 256 Bytes werden darf, aber dennoch die Grösse einzelner Objekte beschränkt bleibt um diese noch mit halbwegs vernünftigem Aufwand adressieren zu können. Da es ausserdem recht untypisch für Microcontroller-Programmierung ist, grosse Objekte auf dem Stack zu plazieren, wirst du dir wohl ein anderes Verfahren einfallen lassen müssen.
>> die PIC18 Architektur hat so ihre Probleme mit indirekter >> Adressierung von Objekten grösser als 256 Bytes. Für direkte Adressierung trifft das sicher zu: movwf 8-Bit-Adresse (plus 4 Bit aus Bankselect oder im "access" Bereich). Indirekt wird mit fsr(0..2) adressiert und die haben je 12 Bit. Für die Übergabe von Variablen wird der Compiler mit hoher Wahrscheinlichkeit einen Softwarestack anlegen, da interrupt, call und return einen 32 Ebenen tiefen Hardware-Stack benutzen.
Yep, natürlich benutzt PIC einen Software-Stack für lokale Variablen, geht ja nicht anders. Auch AVRs scheinen übrigens mit Hinblick auf getrennte Stacks für Variablen und Return-Adressen konzipiert zu sein, warum auch immer (sonst gäbe es die Möglichkeit, den Stack-Pointer atomar zu manipulieren).
Ok. Das mit dem Heap war zugegebener Weise Quatsch. Um die Sache nochmal etwas zu illustrieren ein kleiner Codeausschnitt der betreffenden Problemstelle: short listFiles(FileSystem *fs, char *dirname) { unsigned long startCluster; unsigned char fileEntryCount; unsigned short counter=0; unsigned long offset=0; FileRecord fileEntry; FileLocation loc; unsigned char buf[512]; File dir; unsigned short i; ... [SNIP] ... Der lokale Parameter fs ist ein Pointer auf eine 423 Byte große Struktur, wird ja aber nur per Referenz übergeben und dürfte deswegen doch auch auf dem Callstack nicht mehr Platz als üblich einnehmen. Das struct FileLocation ist 48 Bytes groß und FileRecord 256 Byte. Damit wären die Bank-Grenzen schon locker überschritten. Ich habe den Code jetzt mal mit der -sco (storage class overlay) compiliert. Dabei werden die lokalen Variablen als static deklariert, aber bei jedem Funktionseintritt neu initialisiert. Außerdem versucht der Linker später Variablen gleichen Typs aus unterschiedlichen Funktionen im gleichen Datenbereich zu speichern. Haltet ihr das für eine mögliche Lösung der Problematik? Gruß, Martin
Du solltest Ausschau halten, wie oft grosse Datenstrukturen wie dieser 512-Byte-Puffer und FileRecord vorkommen. Ist das häufig genug, dann leg die nicht in jeder Funktion lokal sondern einmal global an. Das mag nicht bester Programmierstil sein, auf dem PC würde ich davon dringend abraten, ist aber genau die Sorte Kompromiss die man bei Schmalspurmaschinen wie 8bit-µCs nunmal eingehen muss.
PS: Stack-Frames von überschaubarer Grösse erleichtern oft auch die Erkenntnis, wann das RAM nicht mehr ausreicht. Ebenso die -sco Variante. Die Gesamtgrösse der statischer Daten kennt man nach dem Linken, beim Stack ist das meist schwieriger zu erkennen. Auch dies ist so ein strategischer Unterschied zwischen PC und Controller.
@A.K. "Ist das häufig genug, dann leg die nicht in jeder Funktion lokal sondern einmal global an." Das muß dann ne PIC-C Eigenart sein. Beim Keil C51 wird man jedenfalls bestaft, wenn man dem Overlayer ins Handwerk pfuscht und unnötiger Weise globale statt lokale Variablen verwendet. Nur wenn man Funktionspointer verwendet, die erst zur Laufzeit berechnet werden, kann der Overlayer nicht mehr richtig den Calling-Tree parsen. Aber auch dann ist es besser, die zu überlagernden Funktionen im Linker-Script anzugeben, statt die Variablen global zu machen. Peter
@PeDa: Wenn das der Compiler selber sauber hinkriegt ist das prima. Man macht sich halt von spezifischen Eigenschaften des Compilers abhängig. Kann hier aber schon sinnvoll sein, denn es geht ja um die Übernahme fremden Codes.
Also. Um das ganze nochmal klar zu bekommen. Der Datenspeicher des PICs wird über einen 8-Bit Pointer adressiert, womit sich bis zu 256 Byte ansprechen lassen. Dazu gibt es für die direkte Adressierung noch ein Bank Select Register (BSR), mit dem 15 verschiedene Memory Banks ausgewählt werden können. Es lassen sich also insgesamt 4096 Bytes adressieren. Für die indirekte Adressierung gibt es entsprechend über die File Select Register (FSR = FSRH + FSRL) einen 12-Bit-Pointer, mit dem sich genau dieser Datenbereich anwählen lässt. Wenn ich das richtig versetehe, dann wird beim normalen Zugriff auf den Datenspeicher der 8-Bit-Pointer verwendet, wobei dann ja irgendwie hard-kodiert der Wechsel zu einer anderen Memory Bank festgelegt werden muss, sobald die 256 Byte einer Bank ausgeschöpft sind. Nun zu der Frage mit dem Stack. Der Return Stack ist hier ja nicht gemeint, weil der weder im Daten-, noch im Programmspeicher liegt und eine fixe größe von 32x21 Bit hat. Der Stack zum Speichern der lokalen Variablen einer Funktion befindet sich also im Datenspeicher. Ist denn jetzt das Problem, dass der Stack Pointer nicht über die Grenze einer Bank inkrementiert werden kann, oder warum gibt es Ärger, wenn die Größe der lokalen Variablen 256 Bytes überschreiten? Wenn ich nun über die Compiler-Option -sco die default storage class auf overlay festlege, ist dann der Compiler oder der Linker schlau genug, die richtigen Partner für das "Memory Sharing" auszuwählen? Gruß, Martin
Ich habe noch eine Frage zu der Thematik mit den Memory Banks: Wenn ich im Linkerscript eine Datensection anlege, die mehrere Banks umfasst, wie ist der PIC dann überhaupt in der Lage die Section komplett zu adressieren, wenn er nur eine 8-Bit-Adresse verwendet?
Hallo für solch RAM-hungrige Programme sind die neuen PICS (dsPIC30- oder PIC24-Derivate) besser geeignet. Da gibts RAM bis 16k. Gerhard
Da in C häufig mit Pointern gearbeitet wird nehme ich mal stark an dass die Adressierung mit einem der 3 fsr (12 Bit) erfolgt. Damit erreicht man alle 16 Bänke (zu je 256 Byte).
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.