mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Problem mit Speicherverwaltung? (8051)


Autor: Dida N. (quader)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich bin im Moment an einem Schulprojekt. Ziel ist es ein einfaches 
Oszilloskop zu erstellen. Die Anwendung schlussendlich ist eigentlich 
nicht wichtig, es geht nur ums Prinzip. Nun habe ich aber ein komischs 
Problem.

Ich benutze einen 80C537-N als Controller, die Ausgabe erfolgt über ein 
T6963C-Display.
Das Speichermodell ist small, einige Variabeln sind als data andere als 
idata und ein grosses Array ist als xdata definiert. Um Variabeln auch 
im Interrupt zu gebrauchen habe ich globale Variabeln verwendet. Habe 
ich dies üerhaupt richtig gelöst?

IN MAIN.C:
char xdata ScopeMem[220];  // Speicherung der ADC-Daten in externem Speicher
char MemFlag = 0;      // Flag für Timer0-Überlauf
unsigned char MemPos = 0;    // Position in ScopeMem

IN INTERRUPT.C:
extern char xdata ScopeMem[220];  // Speicherung der ADC-Daten in externem Speicher
extern char MemFlag;    // Flag für Timer0-Überlauf
extern unsigned char MemPos;  // Position in ScopeMem

Im main() sollte eigentlich gar nicht viel gemacht werden, dieses wurde 
um den Fehler zu suchen stark vereinfacht.

Das Problem ist, dass auf dem Display in Abhängigkeit des Interrupts 
eine andere Ausgabe erfolgt. Eigentlich sollte das Display nur 
intialisiert werden und auf ihm ein Raster gezeichnet werden. Ist im 
Interrupt aber folgende Zeile aktiv, so wird noch eine weitere Funktion 
ausgeführt.

Besagte Zeile, welche auskommentiert wird oder nicht (befindet sich in 
interrupt.c):
ScopeMem[MemPos] = ADDAT;  // AD-Wert zwischenspeichern

Funktion, die fälschlicherweise aufgerufen wird, wenn obere Zeile 
ausgefürt wird (befindet sich in T6963C.c):
void T6963cPutADCline(int idata delay, int idata zoom)

Ich glaube, dass diese Funktion nur einmal am Anfang aufgerufen wird.
Nun, ich sehe nicht ganz wo das Problem liegt, allerdings kenne ich mich 
mit Memorybereichen etc. auch nicht sonderlich gut aus. Im Anhang habe 
ich noch das MemoryMap des Projektes angehängt.
Dieses sieht zwar je nach Code-Optimierungslevel (welches im Moment auf 
Level 0 'constant folding' eingestellt ist) ein bisschen anders aus, der 
Fehler wirkt sich aber gleich aus.

Es wird wohl irgendwas in der Speicherzuordnung (Stack, Adressierung der 
Funktionen, o.ä.) nicht stimmen.
Wäre sehr dankbar wenn mir jemand helfen könnte. Bin am verzweifeln!

[Anhängend in einer Datei:]
- main.c
- interrupt.c

Autor: Dida N. (quader)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hier noch das MemoryMap. Die Datei kann mit jedem Texteditor geöffnet 
werden.

[Anhängend in einer Datei:]
- MemoryMap

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
char xdata ScopeMem[220];
....

if(MemPos>219) MemPos = 0; 

Hier ein mögliches Problem:

ScopeMem[220];
reserviert 220 Werte, aber von 0...219

if(MemPos>219) MemPos = 0;
MemPos wird bei Dir aber 220, das darf es nicht, also auf >218 testen 
sonst überschreibst Du irgendwas im Speicher.

Autor: Dida N. (quader)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Matthias wrote:
> MemPos wird bei Dir aber 220, das darf es nicht, also auf >218 testen
> sonst überschreibst Du irgendwas im Speicher.

Es wird zwar 220, in dem Fall wird es aber gleich darauf wieder 
gelöscht. Es kommt nie zum Aufruf ScopeMem[220]. Die Reihefolge ist ja: 
inkrementieren, prüfen, schreiben.
ScopeMem[MemPos] = ADDAT;  // AD-Wert zwischenspeichern
MemFlag = 1;        // neuer Wert gespeichert
MemFlag++;          // neuer Wert gespeichert
MemPos++;          // Position f�r n�chstes mal inkrementieren

if(MemPos>219)        // Falls Array voll ist, wieder bei erster Position beginnen
   MemPos = 0; 

Ich habe aber noch etwas herausgefunden: Bestimme ich die Position in 
ScopeMem nicht mit einer Variabeln, sondern mit einer Konstante (sei es 
0, 50, 219, oder was auch immer) so tritt der Fehler nicht auf.
Wenn ich es aber doch mit einer Variable mache, dann funktioniert es 
nur, wenn ich diese nicht inkrementiere. Ich kann die Variable aber mit 
anderen Werten laden (0...219).

Beispiele die funktionieren:

Mit einer Konstante:
ScopeMem[0] = ADDAT;  // AD-Wert zwischenspeichern (0...219)
MemFlag = 1;        // neuer Wert gespeichert
MemFlag++;          // neuer Wert gespeichert
MemPos++;          // Position für nächstes mal inkrementieren

  if(MemPos>219)        // Falls Array voll ist, wieder bei erster Position beginnen
    MemPos = 0;

Mit Variabel aber ohne Inkrementierung:
ScopeMem[MemPos] = ADDAT;  // AD-Wert zwischenspeichern
MemFlag = 1;        // neuer Wert gespeichert
MemFlag++;          // neuer Wert gespeichert
MemPos = 0;          // Position für nächstes mal inkrementieren (0...219)

if(MemPos>219)        // Falls Array voll ist, wieder bei erster Position beginnen
    MemPos = 0;

Bin echt überfordert mit der Sache...

Autor: Dida N. (quader)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, noch eine Erkenntniss...

Hab das ganze mal ausserhalb des Interrupts realisiert, der Fehler blieb 
gleich.

Die Übergabe von MemPos an ScopeMem[] scheint wirklich das Problem zu 
sein.
Ist MemPos als data definiert funktioniert es nicht. Bei idata oder 
xdata jedoch schon:

funktioniert nicht:
unsigned char MemPos = 0;        // Position in ScopeMem
oder
unsigned char data MemPos = 0;        // Position in ScopeMem
funktioniert:
unsigned char idata MemPos = 0;        // Position in ScopeMem
oder
unsigned char xdata MemPos = 0;        // Position in ScopeMem

Könnt ihr euch vorstellen, woran das liegt? Kann man mit einer 
'data'-Variable kein kein Feld eines 'xdata'-Arrays bestimmen?
Kanns ja nicht sein. Und die Variable nun als idata oder xdata zu 
definieren will ich eigentlich nicht, da diese rel. oft gebraucht wird.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es gibt mehrere Unbekannte:

Wo wird das Programm abgelegt?
Wird es vielleciht im RAM abgelget, der glechzeitig als Codespeicehr 
dient?
Dann überschreibst Du Dir die ersten 220Byte Deines Programms.


Wo ist das Displayprogramm, wie ist das Display angeschlossen (memory 
mapped)?

Vielleicht schreibst Du ja statt in den SRAM, ins Display.

Schau Dir mal die Board-Doku an, wie welche Speicherbereiche 
angeschlossen sind.


Peter

Autor: Helmi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Setze mal in main

MemPos = 0;

Es kann sein das der Startup Code die Variable nicht auf 0 setzt und 
dann da etwas undefniertes drinsteht

Gruss Helmi

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was steht im .LNP-File (Linker-Einstellungen)?

Autor: Dida N. (quader)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
@Helmi
Hab ich probiert, allerdings leider ohne Erfolg.

@Peter Dannegger
Keil sollte das eigentlich intern selbst regeln. Ich muss gestehen, dass 
ich in diesem Bereich leider nicht gereade viel Erfahrung habe.
Aber der 8051 sollte ja eigentlich verschiedene Speicherbereiche haben, 
für code, data, xdata, etc.
Solange ich nicht selbst etwas mit dem Memory-Typ 'code' überschreibe 
sollte eigentlich nichts passieren. Ganz sicher bin ich mir aber nicht.

Das Display ist Parallel an Port4 und Port5 angehängt. Dass ich direkt 
in das RAM des Displays schreibe habe ich auch schon gedacht, aber das 
kann ich mir nicht wirklich vorstellen.
memory mapped habe ich zwar schon gehört, habe damit aber noch nie was 
gemacht. Und so ausversehen das Display so anzusteuern ist wohl nicht 
möglich, oder schon?
Habe meine Funktion denen von Simon Küppers angepasst, und in diesem 
Thread steht, dass es nicht memory mapped ist.
Beitrag ""Bessere" T6963c Library"

Doku hab ich vom uC schon gelesen, aber nichts spezielles gefunden :|

@Matthias
Auszug aus ScopeMeter.lnp:
"main.obj",
"T6963C.obj",
"timer.obj",
"interrupt.obj" 
TO "ScopeMeter" 
RAMSIZE(256) 

Im Anhang nochmals die neueste Memory Map.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da in Deiner .lnp die Angabe zum XDATA-Bereich fehlt, wird der Linker 
XDATA bei Adresse 0x0000 beginnen. Liegt Dein XDATA wirklich ab Adresse 
0000H?

Auch gibt es keine Angabe zu der XDATA Größe.

In der .lnp sollte noch dies stehen:
XDATA(0X0000-0X3FFF)
nur als Bsp., hier Xdata ab 0000H und 16kB Lang

Diese Einstellung musst Du bei Keil (Device-Optionen) machen und wird 
dann automatisch in die .lnp übernommen.

Autor: Dida N. (quader)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Matthias
Es klappt nun tatsächlich, danke!
Ich hatte wohl wirklich Tomaten vor den Augen, dass ich dies im Memory 
Map nicht realisiert hatte.

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.