Hallo, ich hab mal wieder ein Problem mit dem SDCC. Ich habe jetzt vom Memory Model Medium zu Large gewechselt, danach hat natürlich das Programm nicht mehr funktioniert. Jetzt ist mit aber aufgefallen das die Variablen nicht mehr initialisiert werden. Die Zeile unsigned char MenuePos=0; sorgt nicht mehr dafür, das MenuePos nach dem Start auf 0 steht, sondern auf dem Wert der vom letzten Programmlauf noch im RAM steht, kann natürlich auch der Wert einer anderen Variablen sein. In dem Abschnitt ; global & static initialisations der .lst werden nur noch die Bit-Variablen initialisiert. Weiß jemand ob und wie man das erzwingen kann ? vielleicht muß ich auch nur eine "Optimierung" ausschalten Ich muß doch hoffentlich nicht allen Variablen beim Programm einen Wert zuweisen.
Kannst du mal deine Compileoptionen mitteilen, kann das so nicht nachvollziehen.
Ich rufe einfach die SDCC.exe auf mit --model-large gefolgt vom dem Dateinamen des Sourcecodes, also "C:\Programme\SDCC\bin\sdcc.exe --model-large D:\8051\C\SDCCTest.c". Ich hab jetzt auch nochmal den neuesten SDCC vom Dezember installiert, aber keine Besserung. Aber wenn ich die Variablen mit __data unsigned char MenuePos=0; deklariere, werden die wieder initialisiert. Betrifft dann doch nur die Variablen im XRAM.
Für large mußt Du erstmal externen SRAM ranpappen. Large bedeutet nur, es wird als default externes SRAM benutzt, d.h. der Code wird größer und langsamer. Vorteile hat large überhaupt keine. Ich benutze ausschließlich small als default, dann kann man ja trotzdem große Datenfelder als pdata oder xdata deklarieren, hat also keinerlei Nachteile bezüglich der Variablengröße. Peter
Mein Programm benötigt inzwischen leider soviel RAM, das PDATA nicht mehr ausreicht. Large gibt mir also den Vorteil mein Programm weiter erweitern zu können. Kompiliert mit Medium sind es 20KByte, mit Large werden es 24 KByte. Der AT89C51ED2 hat 1 kByte XRAM, also auch von daher kein Problem. RAM sparen kann ich nur, in dem ich weniger Funktionen, oder mehr globale Variablen benutze.
Verwendest du nur 1792 Bytes des internen XRAM ? Beim AT89C51ED2 verwende ich dann folgende Compileroptionen. --code-loc 0x0000 --xram-size 0x6FF --model-small --stack-auto --vc Im Sourcecode gibtst du dann noch an: unsigned char _sdcc_external_startup () { AUXR = 0x11; return 0; } schaltet das interne RAM frei und ALE off. Model Large wird nicht benötigt.
Ich versuche es nochmal von vorne. Ich hab ein Programm das für Variablen den internen RAM (128 Byte Rest ist für den Stack) und den externen RAM der über R0 adressiert werden kann (256 Byte) belegt, SDCC nennt den PDATA, belegt. Jetzt brauche ich noch mehr. Kompliliert mit --modell-small, bekomme ich die Fehlermeldung, das DSEG nicht gross genug ist. Kompiliere ich mit --modell-medium, bekomme ich die Fehlermeldung, das PSEG nicht gross genug ist. Jetzt kompiliere ich mit --modell-large und habe ein neues Problem. Es werden die Variablen nicht initialisiert. Bei --modell-small macht er aus "unsigned char MenuePos=0;" .area DSEG (DATA) _MenuePos:: .ds 1 und mov _MenuePos,#0x00 bei --modell-medium .area PSEG (PAG,XDATA) _MenuePos:: .ds 1 und mov r0,#_MenuePos clr a movx @r0,a bei --modell-large aber nur .area XISEG (XDATA) _MenuePos:: .ds 1 Ich behaupte ich benötige --modell-large, damit SDCC genug Platz für die variablen findet.
Ne, du bist auf dem Holzweg, machs mal so wie ich es dir gesagt hab. Ich kann dir versichern das es so funktioniert.
Joe hat Recht, das kompilieren funktioniert. Danke. Aber das funktioniert jetzt nur, weil die Parameter der Funktionen über den Stack übergeben werden und für die lokalen Variablen in den Funktionen Register verwendet werden. Damit reicht der interne RAM aus. Heute Abend muß ich dann mal versuchen, ob das Programm noch das tut was es soll.
Wollte nochmal das Ergebnis bekanntgeben. Das Programm läuft. Bis auf eine Funktion, die Funktion soll Long-Werte in Strings umwandeln, liefert aber immer 2D und 77 zurück.
Wenn du mir ein bischen Beispielcode zukommen läßt würde ich es mir mal ansehen, du machst es einem nicht leicht dir zu helfen ;-))
Ein wenig Spaß will ich ja auch haben :-) Habs aber auch schon gefunden char *Umwandeln(int value, unsigned char base) { static char s[10]; s[0]='-'; s[1]='1'; s[2]='3'; s[3]='\0'; return s; } das static hat gefehlt. Bisher gab es für den Rückgabewert ja einen Platz im internen Speicher, jetzt über den Stack funktionierte es natürlich nicht mehr. Nochmals Danke. P.S. das Beispiel ist natürlich nicht die ursprüngliche Funktion
> Ein wenig Spaß will ich ja auch haben :-)
Den gönne ich dir durchaus, na dann viel Spaß und genieße es.
Und weiter gehts. Eine neue Variable = ein neuer Fehler ?ASlink-Error-Could not get 1 consecutive byte in internal RAM for area DSEG. Ich vermute den Fehler hier 005D 689 _Step:: 005D 690 .ds 1 691 ;-------------------------------------------------------- 692 ; overlayable items in internal ram 693 ;-------------------------------------------------------- 694 .area OSEG (OVR,DATA) 695 ;-------------------------------------------------------- 696 ; Stack segment in internal ram 697 ;-------------------------------------------------------- 698 .area SSEG (DATA) 0000 699 __start__stack: 0000 700 .ds 1 kann mich aber auch irren, wie ich heute schonmal erfahren musste. Verstehe aber nicht warum die Adresse 005D schon belegt sein sollte. Wird die Stackgrösse berechnet und geprüft ? Ich hab den Code unter www.mfluhr.de\Elektronik\Download\SDCCTest.zip bereit gestellt, sind aber 577kB.
Michael Fluhr wrote: > char *Umwandeln(int value, unsigned char base) > { > static char s[10]; > > s[0]='-'; > s[1]='1'; > s[2]='3'; > s[3]='\0'; > > return s; > } > > das static hat gefehlt. Warum machst Du denn bloß sowas ? Damit wird doch der Speicher für die gesamte Laufzeit blockiert, auch wenn Du grad nichts umwandeln willst. Ist also genauso schlimm, wie globale Variablen. Willst Du was in nen String schreiben, laß ihn den Aufrufer bereitstellen, verwenden und dann wieder vernichten (aber bloß nicht mit malloc !). Sind hier zwar nur 4 Byte, aber wenn Du das überall so machst, läppert sich ganz schön was zusammen. Immer wenn möglich lokale nicht statische Variablen benutzen, dann passen sogar ne Menge davon in den DATA-Bereich, d.h. sind schön schnell und codesparend. Lies Dir mal den C51-Primer durch. Peter
@Peter Ich bitte um Beispielcode bzw. Ideen. Zu Rückgabe von Zeigern habe ich diesen Link gefunden: http://www.pronix.de/pronix-743.html Als einzige Möglichkeit sehe ich, das ich den Wert per Parameter zurückgebe, wie ich es sonst auch überall gemacht habe. Da ich aber nur diesen einen Rückgabewert habe finde ich das unsinnig. @All Viel schlimmer finde ich was SDCC aus diesem hier macht const unsigned char *Wochentag[7]={"Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"}; Die Daten landen im Code, aber gleichzeitig werden im internen RAM 21 Byte belegt. 629 ;-------------------------------------------------------- 630 ; internal ram data 631 ;-------------------------------------------------------- 632 .area DSEG (DATA) 0000 633 _PageNo:: ... 0018 661 _Wochentag:: 0018 662 .ds 21 Das versteh ich noch nicht, wie ich das ändern kann.
Michael Fluhr wrote: > @Peter > Ich bitte um Beispielcode bzw. Ideen.
1 | aufrufer() |
2 | {
|
3 | ...
|
4 | {
|
5 | char s[10]; // Feld erzeugen |
6 | Umwandeln( s, 1234, 10 ); // übergeben |
7 | puts( s ); // verwenden |
8 | } // vernichten |
9 | ...
|
10 | }
|
11 | |
12 | void Umwandeln(char *s, int value, unsigned char base) |
13 | {
|
14 | s[0]='-'; |
15 | s[1]='1'; |
16 | s[2]='3'; |
17 | s[3]='\0'; |
18 | }
|
Peter
Danke Peter, dasselbe meinte ich mit > Als einzige Möglichkeit sehe ich, das ich den Wert per Parameter > zurückgebe, wie ich es sonst auch überall gemacht habe. Da ich aber nur > diesen einen Rückgabewert habe finde ich das unsinnig. Das mit den 21 Bytes hab ich inzwischen auch raus bekommen. Das Array ist ein Array von Zeigern und jeder (generic) Zeiger benötigt 3 Bytes. 7 * 3 = 21 Alles logisch, aber muß ich ändern.
Michael Fluhr wrote: >> Als einzige Möglichkeit sehe ich, das ich den Wert per Parameter >> zurückgebe, wie ich es sonst auch überall gemacht habe. Da ich aber nur >> diesen einen Rückgabewert habe finde ich das unsinnig. Nein, Du gibst keinen Wert zurück, sondern einen Pointer. Daher ist es vom Code kaum ein Unterschied, ob vom Aufrufer zur Funktion oder umgekehrt. Der Unterschied ist eben bloß, daß statische Variablen auf Ewigkeit blockiert bleiben, und das ist wirklich unsinnig. Auch sämtliche Bibliotheksfunktionen machen es ja so, daß sie den zu beschreibenden Pointer immmer vom Aufrufer geliefert bekommen, z.B. itoa(), sprintf() usw. > Das Array ist ein Array von Zeigern Daher würde ich einfach ein Array mit fester Größe definieren:
1 | const unsigned char Wochentag[7][11]; |
Peter
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.