Forum: Mikrocontroller und Digitale Elektronik Variableninitialisierung mit SDCC


von Michael F. (fury)


Lesenswert?

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.

von Joe (Gast)


Lesenswert?

Kannst du mal deine Compileoptionen mitteilen, kann das so nicht 
nachvollziehen.

von Michael F. (fury)


Lesenswert?

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.

von Joe (Gast)


Lesenswert?

Variable im XRAM:

xdata unsigned char MenuePos=0;


von Peter D. (peda)


Lesenswert?

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


von Michael F. (fury)


Lesenswert?

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.

von Joe (Gast)


Lesenswert?

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.

von Michael F. (fury)


Lesenswert?

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.

von Joe (Gast)


Lesenswert?

Ne, du bist auf dem Holzweg, machs mal so wie ich es dir gesagt hab. Ich 
kann dir versichern das es so funktioniert.

von Michael F. (fury)


Lesenswert?

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.

von Joe (Gast)


Lesenswert?

Falls noch was klemmt laß von dir hören.

von Michael F. (fury)


Lesenswert?

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.

von Joe (Gast)


Lesenswert?

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

von Michael F. (fury)


Lesenswert?

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

von Joe (Gast)


Lesenswert?

> Ein wenig Spaß will ich ja auch haben :-)

Den gönne ich dir durchaus, na dann viel Spaß und genieße es.

von Michael F. (fury)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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

von Michael F. (fury)


Lesenswert?

@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.

von Peter D. (peda)


Lesenswert?

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

von Michael F. (fury)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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
Noch kein Account? Hier anmelden.