Hallo, ich kämpfe hier weiterhin mit einem Problem und hab keine Ahnung, wie ich das lösen soll. Vielleicht kann von Euch jemand einen Tipp geben: Ich hab ein Programm das auf dem ATMega128 läuft. Darin werden neben dem Code ein paar Arrays verwendet. Der avr-gcc packt den code in das .text segment und die arrays in das .bss segment. Das lässt sich soweit gut nachvollziehen. Nun ist das .bss segment aber voll (32k). Sobald ich ein byte mehr im array verwende, wird andere speicher im .bss Segment überschrieben, was sich prima nachprüfen lässt. Auf der anderen Seite gibt es aber im .text Segment noch reichlich platz und des weitere ein .data segment, das leer ist (0byte). Kann mir jemand sagen ob und wie ich die Arrays in das .data oder .text segment bekomme, oder wie ich prinzipiel auf diese Segmente überhaupt zugreife und wie die im Speicher des ATM128 aufgeteilt sind? Gibt es da eine gute Doku zu? Danke schonmal, Christian
Die ,,Segmentgröße'', die du vermutest, ist nicht dein Problem; es gibt eine solche nicht (nicht bei 32 K). Das schrob ich dir doch schonmal. Hier das Stück aus dem Linkerscript (für avr5): MEMORY { text (rx) : ORIGIN = 0, LENGTH = 128K data (rw!x) : ORIGIN = 0x800060, LENGTH = 0xffa0 eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = 64K } Obiges "data" enthält dabei sowohl .data als auch .bss (womit schon klar ist, dass es keinen Sinn hätte, zwischen beiden zu ,,verschieben''). .text ist ROM, ich denke nicht, dass du Variablen in den ROM legen willst. ;-) (Du kannst natürlich konstante Tabellen in den ROM legen, aber da musst du den Zugriff anders formulieren.) Ich stelle nicht in Abrede, dass du irgendwo in ein Problem rennst, aber es ist müßig, wenn du trotz Hinweisen das Problem hartnäckig weiter dort suchst, wo du es selbst vermutest. Entweder musst du deine Suche von 0 anfangen und alle deine bisherigen Vermutungen erstmal in Frage stellen, oder aber du reduzierst das Problem auf die Minimalvariante, mit der auch andere es reproduzieren können, und postest es hier.
Ok, hier ein reduzierter Code, der den Fehler reproduziert. Kommentare im Code: > ein struct zum aufnehmen der Fontdaten für ein Zeichen struct CharacterInfoStruct { unsigned char width; unsigned char height; unsigned char data[font_max_byte]; }; > für alle ASCII Zeichen eine struct struct CharacterInfoStruct font_data[256]; >... und hier der Test: > Auswertung reuziert auf das Zeichen 'A'. Wegen fehlender Textausgabe aufgrund des kaputten Fonts hab ich einfach Linien gezeichnet, funktioniert aber auch DrawLine(100,0,100,20); > eine linie zur kontrolle w = GetCharFromFlash(p, i+3); > zeichen info auslesen if (w != 0x0c) > prüfen, ob wert korrekt { DrawLine(120,0,120,20); } h = GetCharFromFlash(p, i+4); if (h != 0x14) { DrawLine(130,0,130,20); } > die Prüfung oben ergibt in allen Fällen (mit oder ohne den Fehler) eine korrekte Ausgabe der Linien (d.h. w hat den Wert 0x0c und h den Wert 0x14, das habe ich verifiziert). Nun schreiben wir die beiden Werte in den zugehörigen struct: font_data[65].width = w; font_data[65].height = h; > in font_data sollten nun width und height 0x0c und 0x14 gesetzt sein. Die Kontrollausgabe, die nun folgt, gibt aus, dass die Werte für width und height nicht(!) korrekt sind. D.h. dass direkt nach dem Schreiben in die Fontdaten die Werte schon nicht mehr stimmen, oder erst gar nicht geschrieben wurden. DrawLine(200,0,200,20); if (font_data[65].width != 0x0c) { DrawLine(210,0,210,20); } if (font_data[65].height != 0x14) { DrawLine(220,0,220,20); } Das Ganze lässt sich nun (zurück zu meinem ursp. Problem) darauf reduzieren, dass der Fehler nur auftritt, wenn das .bss Segment 32767 byte überschreitet. Es mag sein, dass das Segment größer sein kann, nichts desto trotz steht es direkt damit in Verbindung. Ich will auch nicht ausschliessen, das ich noch was falsch mache, wüsste aber nicht, was das sein sollte. Irgendeine Idee dazu?
Hi Jörg meinte vermutlich irgendein Minimalbeispiel das man compilieren kann. Also idealerweise eine problem.c die sämtlichen nötigen Code enthält. Matthias
Hi, das Beispiel ist glaube ich auch ohne compiler einfach nachzuvolliehen. Die Frage ist doch eigentlich, wie es grundsätzlich passieren kann, das man in Speicher schreibt und in der Anweisung direkt danach der Speicherinhalt nicht mehr stimmt. Das würde bedeuten, das entweder der Speicherzugriff falsch codiert wird (Compilerfehler oder Linkerfehler) oder die Anweisungen nach dem Setzen der Werte selbst den Code modifizieren (also entweder das Drawline, was ich ausschliessen kann, da ich auch das rausgenommen habe) oder aber ein anderer Code asynchron (Interrupt) die Daten überschreibt, welchen ich aber gar nicht habe. Ich werde trotzdem noch mal eine Demo kodieren und posten, wenn das mehr helfen sollte. Grüße, Christian
Daß das Beispiel nachzuvollziehen ist, bezweifelt ja gar keiner. Dein Problem ist es damit aber noch lange nicht! Um irgendwelche möglichen Compiler-/Linkerfehler nachvollziehen zu können, braucht man eben ein Kompilierbares Minimalbeispiel. Mach Dich aber schon mal darauf gefasst, daß der Fehler zu 99,9% ca. 50cm vor dem Bildschirm entsteht ;-)
Ok, hier ein sample, das den Bug reproduzierbar macht. In dem ac_graphic.c passiert das ganze in InitializeGraphics(). Ihr müsst ggf. zum Testen die Ausgabe auf etwas geeignetes bei Euch umsetzen. Ich habe alle urspr. Kommentare entfernt und neue zur Beschreibung eingefügt. Hoffe, das reicht so aus. Es gibt dort einen dummy-buffer, der einfach nur Speicher im .bss belegt. Setzt man den runter auf zB 1000 funktioniert alles. In dem Zustand jetzt tritt der Fehler bei mir auf. Programmieren tue ich das Gerät mit einer eigenen SW, die ich allerdings nicht weitergeben kann, sollte aber auch mit jedem anderen Programmer problemlos gehen. Danke für die Unterstützung, Christian
ac_main.c: In function `main': ac_main.c:16: warning: implicit declaration of function `InitializeGraphics' [...] ac_graphics.c: In function `InitializeGraphics': ac_graphics.c:52: warning: unused variable `j' ac_graphics.c: In function `DrawLine': ac_graphics.c:133: warning: implicit declaration of function `HWL_SetPixel' Linking ac_main.elf avr-gcc -O0 -mmcu=atmega128 -std=gnu89 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=ac_main.o ac_main.o ac_hardware.o ac_font.o ac_hitachi.o ac_graphics.o --output ac_main.elf -L. -L"C:\Programme\WinAVR\lib" -Wl,-Tdata=0x801100,--defsym=__heap_end=0x8090ff -lm -lgcc -lc -litcl32 -litk32 -Wl,-Map=ac_main.map,--cref c:\WinAVR\bin\..\lib\gcc\avr\3.4.3\..\..\..\..\avr\bin\ld.exe: cannot find -litcl32 make: *** [ac_main.elf] Error 1 Sorry, lässt sich nicht kompilieren.
Debugging symbols sind auch keine drin in dem, was du compiliert geliefert hast, sonst könnte man damit ja wenigstens mal gucken.
Hm, die tcl/tk lib sind der Standardinstallation vom avr-gcc enthalten und auch in den mitgelieferten Makefiles drin. Ich verwende WinAVR (3.4.3). Hab die libs rausgeschmissen und nochmal ein Update angehängt, dass diese nicht dazu linkt.
Ahja, ich hab mal die Pfade richtig gesetzt (Dein WinAVR ist nicht im Standard-Pfad installiert!) und ein paar Prototypen bzw. includes ergänzt, jetzt lässt es sich hier zumindest mal kompilieren (Dein erstes .zip-File)...
Hmm, was wolltest du eigentlich mit dem tcl/tk? Da gibt's wohl eine lib mit, aber doch keine für den AVR... Anyway, ich denke, dein Problem liegt einfach mal hier:
1 | void HWL_InitializeDisplay(void) |
2 | {
|
3 | LCDValue = (uint8*)0x8002; |
4 | LCDAddressLowByte = (uint8*)0x8000; |
5 | LCDAddressHighByte = (uint8*)0x8001; |
6 | LCDRead = (uint8*)0x8003; |
7 | LCDStatus = (uint8*)0x8001; |
Wenn du natürlich auf Adresse 0x800x memory-mapped IO machen willst, solltest du wohl nicht versuchen, mehr als 32K - (sizeof register area) an RAM zu benutzen...
Hm, da hast Du wohl recht! :-) Ich kann das leider so nicht verhindern, da die Hardware fertig gebaut ist und ich auf das Zeugs keinen Einfluss habe. Da muss ich mal mit den HW Entwicklern reden. Kann ich vielleicht diesen Bereich irgendwie explizit sperren oder das Problem sonst wie umgehen? Danke für die Hilfe! Grüße, Christian
p.s. tcl/tk habe ich nicht mit eingebunden. Ich hab einfach das WinAVR Template Makefile verwendet, da war das so drin.
>Ich hab einfach das WinAVR Template Makefile verwendet, da war das >so drin. Im Template findet mein emacs aber weder itcl noch itk...
@Patrick: Hast recht. Hab noch mal nachgesehen, die libs und sourcen hatte ich aus dem Vorgängerprojekt der gleichen HW übernommen, da war auch das tcl/tk her. @Matthias: Ja, der hat 128KB. Die wurden bei der letzten Version auch voll genutzt. Leider immer noch und wir warten schon seit längerem auf den ATMega2560.
Hi der Mega128 hat 128kB Flash. Aber wieviel RAM hängt da dran? Der Mega128 hat von sich aus nur 4kB RAM und kann maximal mit 64kB (ein paar 100 Byte weniger) umgehen wenn der Compiler das komplett selber verwalten soll. Alles was darüber hinausgeht mußt du selber verwalten. Matthias
> Kann ich vielleicht diesen Bereich irgendwie explizit sperren oder > das Problem sonst wie umgehen? Nur semi-manuell. Du könntest einen customized linker script zimmern und für data nur den Bereich unterhalb 0x8000 zulassen. Den Bereich oberhalb 0x800f weist du dann einem separaten Segment zu, das du im C-Programm explizit mittels __attribute__((section("xxxx"))) belegst.
Hi, @Jörg: danke für die Infos. Liegen dann bei mir die 2ten 32KB ab 0x8000? @Matthias, Patrick: Die Kiste hat 32KB internes und 32KB externes RAM und 1MB externen Flash. Ich dachte, wir hätten auch bereits 128kb RAM. Grüße, Christian
> Liegen dann bei mir die 2ten 32KB ab > 0x8000? Genau genommen wohl ab 0x8010, nicht?
Wenn die überhaupt da liegen, das war mir halt nicht klar. :-) Zu dem Linker-Script, das Du angesprochen hast: Geht es dort um die EXTMEM Options? Und gibt es eine Doku oder einen Thread hier, wo ich dazu mehr erfahren kann? Grüße, Christian
> Zu dem Linker-Script, das Du angesprochen hast: Geht es dort um die > EXTMEM Options? Nein, um den Linkerscript. Der liegt im Verzeichnis ${prefix}/avr/lib/ldscripts und heißt standardmäßig (für deinen ATmega128) avr5.x. (Was genau ${prefix} bei dir ist, musst du selbst rausfinden.) Den kannst du dir als Template nehmen, um deinen eigenen daraus zu zimmern. Diesen wiederum übergibst du mit der Linkeroption -T. Wenn du selbige vom Compiler an den Linker weiterreichen willst, geht das mit -Wl. Nehmen wir also mal an, du hast einen Linkerscript myproject.x erzeugt, dann wäre das avr-gcc ... -Wl,-T,myproject.x ... Zur Syntax möchte ich dich auf die info-Pages des Linkers verweisen. Wenn du WinAVR benutzt, hast du meines Wissens mit tkinfo einen Reader dafür installiert bekommen, für den's auch ein Icon auf dem Desktop gibt.
Na, das ging aber flott. Danke mal wieder für die Info. (Ich werde vielleicht irgendwann doch nochmal Profi :-)) Aber davon ab: Schläfst Du auch irgendwann mal, oder machst sonst was außer "nervige" Beiträge von unwissenden Leuten zu beantworten? :-) Grüße, Christian
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.