Hi,
ich programmiere einen Atmel 1284p mit dem Atmel-Studio 6 und steuere
dabei ein OLED-Display (SEPS525) an.
Dabei habe ich mir einen eigenen Zeichensatz erstellt mit dem ich die
Zahlen 0-9 ausgeben kann.
Diesen Zeichensatz speichere ich in Arrays auf dem uC ab:
1
volatileuint8_tNumberArray_1[]=
2
{
3
/*----------------------------------------
4
;hexcode: 0031
5
;width x height: 16 x 24
6
;size: 48 bytes
7
------------------------------------------*/
8
48,16,24,
9
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
10
0x01,0x80,0x01,0x80,0x0F,0x80,0x0F,0x80,
11
0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,
12
0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,
13
0x01,0x80,0x01,0x80,0x0F,0xF0,0x0F,0xF0,
14
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
15
};
16
17
volatileuint8_tNumberArray_3[]=
18
{
19
/*----------------------------------------
20
;hexcode: 0033
21
;width x height: 13 x 24
22
;size: 39 bytes
23
------------------------------------------*/
24
39,14,24,
25
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xF8,
26
0x1F,0xE0,0x83,0x80,0x0C,0x00,0x60,0x06,
27
0x01,0xE0,0x0F,0x00,0x0C,0x00,0x30,0x01,
28
0x80,0x0C,0x00,0x61,0x06,0x0F,0xF0,0x3E,
29
0x00,0x00,0x00,0x00,0x00,0x00,0x00,
30
};
31
32
.....usw
Beim Debuggen sehe ich das dieses Array "NumberArray_3" auf die Adresse
0x4079 (fortlaufend) abgespeichert wird.
Nun passiert im Laufe des Programms, dass einzelne Werte der Adressen
des Arrays mit irgendwelchen Zahlen überschrieben werden obwohl absolut
nicht (weder lesend/schreibend) auf das Array zugegriffen werden soll.
Wenn ich nun auf das "NumberArray_3" lesend zugreife (um eine Zahl auf
dem Display auszugeben), dann kommt natürlich nur Müll raus
Interessanterweise trifft dies aber nur bei der Zahl 3 zu - alle andere
Zeichen werden korrekt ausgegeben.
Meine Frage lautet: Wie kann es in dem uC passieren, dass einfach
verschiedene Werte von bereits initialisierten Arrays überschrieben
werden??
Compiler-Optimierung hab ich von -O0 bis -Os alles durchprobiert - keine
Veränderung.
Auch sollte ich noch genügend freien Speicher haben
1
Task "RunCompilerTask"
2
C:\Program Files (x86)\Atmel\Atmel Studio 6.1\shellUtils\make.exe all
3
make: Nothing to be done for `all'.
4
Done executing task "RunCompilerTask".
5
Task "RunOutputFileVerifyTask"
6
Program Memory Usage : 2894 bytes 2,2 % Full
7
Data Memory Usage : 502 bytes 3,1 % Full
8
Done executing task "RunOutputFileVerifyTask".
Ich suche schon seit 8 Stunden den Fehler und bin mitterlweile absolut
ratlos und weiß nicht weiter...
Kennt jemand die Ursache für dieses Symptom?
mfg
Das kann über Zeigerarithmetik fast überall passieren, z.B. indem auf
ein davor liegendes Feld mit einem zu großen Index zugegriffen wird oder
auf ein dahinter liegendes mit einem zu kleinen Index (ein negativer
Index ist kein Problem).
Beliebt ist auch, über einen nicht initialisierten Zeiger auf Speicher
zuzugreifen.
Was es bei dir genau ist, sieht man natürlich nicht mangels Quelltext.
Ich glaube so wirst Du nicht viel sinvolle Hilfe bekommen.
Zeig doch mal den Rest des Programmes.
In NumberArray_3[] steht als Kommentar ";size: 39 bytes"
Im Array sind aber 39+3 Bytes drin.
Das sagt noch nichts. Wir wissen nicht was Du mit dem Array machst.
Deutet aber schon mal drauf hin, dass etwas mit den Arraygroessen und
Zuggriffen nicht stimmen könnte.
Ohne weitere Info - keine Idee.
NurEinGast schrieb:> Ich glaube so wirst Du nicht viel sinvolle Hilfe bekommen.> Zeig doch mal den Rest des Programmes.>> In NumberArray_3[] steht als Kommentar ";size: 39 bytes"> Im Array sind aber 39+3 Bytes drin.> Das sagt noch nichts. Wir wissen nicht was Du mit dem Array machst.> Deutet aber schon mal drauf hin, dass etwas mit den Arraygroessen und> Zuggriffen nicht stimmen könnte.>> Ohne weitere Info - keine Idee.
Jo, ich hab mal mein gesamtes Projekt gepackt und hochgeladen, es ist
etwas umfangreich, deswegen wollte ich es am Anfang nicht gleich
mitgeben falls es sich um was ganz triviales handelt.
In Zeile 47 von TempSensor.cpp wird das erste mal die Methode aufgerufen
die die Zahlen "321" ausgibt.
Nur die Ziffer 3 wird fehlerhaft ausgegeben, alle andere Zahlen passen.
Der Kommentar ";size: 39 bytes" bezieht sich auf die Nutzdaten, welche
die Zahl darstellen.
Die 3 Bytes davor geben meiner Ausgabefunktion Informationen, aus
wievielen Bytes die Ziffer besteht, wie Breit und wie Hoch diese ist.
Alles nachfolgende stellt die Ziffer an sich dar.
Allerdings vermute ich dass das wenig mit dem Fehler zu tun hat, denn
alle Ziffern werden über dieselbe Funktion ausgegeben - und nur bei der
"3" tritt der Fehler auf.
Ich lasse mich aber sehr sehr gern eines besseren belehren! :)
Hallo
Ich würde vorschlagen diese Arrays in den Flash (Progmem) zu verlagern,
dort werden sie garantiert nicht überschrieben und der RAM wird nicht
belegt.
RAM ist bei AVRs knapp und die Fehlerbeschreibung klingt so als wäre er
dir bereits ausgegenagen.
da1l6
da1l6 schrieb:> Hallo>> Ich würde vorschlagen diese Arrays in den Flash (Progmem) zu verlagern,> dort werden sie garantiert nicht überschrieben und der RAM wird nicht> belegt.>> RAM ist bei AVRs knapp und die Fehlerbeschreibung klingt so als wäre er> dir bereits ausgegenagen.>> da1l6
Hi da116,
super, danke für den Denkanstoß :)
RAM hab ich laut Datenblatt 16kB, ich dachte das der Compiler eventuell
eine Warning ausgibt falls es dort zu absehbaren Engpässen kommt (??)
Daran hab ich nicht gedacht.
Das worauf du abzielst bezieht sich auf das hier, richtig?
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmspeicher_.28Flash.29
Gibt es Vor/Nachteile zwischen progmem/__flash ?
Ich probiers nach ein wenig Schlaf gleich mal aus und berichte ob es
daran lag - Vielleicht ist es ja eine Hilfestellung für andere Personen
mfg
Thomas D. schrieb:> super, danke für den Denkanstoß :)
Nein ist es nicht.
Du hast definitiv im Programm irgendwo einen Schreibzugriff, der nicht
so sein sollte. Mit der verlagerung dieser Daten ins Flash, verschiebst
du nur das Problem, aber du löst es nicht.
Anstelle deiner Font-Daten wird eben dann irgendwas anderes im Speicher
niedergebügelt.
Solche Probleme müssen GELÖST werden und nicht KASCHIERT!
Sei froh, dass du einen reproduzierbaren Fall hast, mit dem du
feststellen kannst, ob eine Änderung im Programm (die kann ganz woanders
sein), das Problem jetzt gelöst hat oder nicht! Einen Fehler
reproduzierbar zu haben ist das Um und Auf beim Debuggen. Zerstör dir
diese Reproduzierbarkeit jetzt um keinen Preis noch nicht. Wenn du den
eigentlichen Fehler gefunden hast, DANN ist es Zeit über eine
Verlagerung ins Flash nachzudenken. Aber nicht jetzt. Jetzt muss erst
mal der fehlerhafte Zugriff gefunden werden.
Karl Heinz Buchegger schrieb:> Thomas D. schrieb:>>> super, danke für den Denkanstoß :)>> Nein ist es nicht.>> Du hast definitiv im Programm irgendwo einen Schreibzugriff, der nicht> so sein sollte. Mit der verlagerung dieser Daten ins Flash, verschiebst> du nur das Problem, aber du löst es nicht.> Anstelle deiner Font-Daten wird eben dann irgendwas anderes im Speicher> niedergebügelt.>> Solche Probleme müssen GELÖST werden und nicht KASCHIERT!>> Sei froh, dass du einen reproduzierbaren Fall hast, mit dem du> feststellen kannst, ob eine Änderung im Programm (die kann ganz woanders> sein), das Problem jetzt gelöst hat oder nicht! Einen Fehler> reproduzierbar zu haben ist das Um und Auf beim Debuggen. Zerstör dir> diese Reproduzierbarkeit jetzt um keinen Preis noch nicht. Wenn du den> eigentlichen Fehler gefunden hast, DANN ist es Zeit über eine> Verlagerung ins Flash nachzudenken. Aber nicht jetzt. Jetzt muss erst> mal der fehlerhafte Zugriff gefunden werden.
Da stimm ich dir vollkommen zu. Also du bist davon überzeugt das der
Speicherbereich von den Daten-Arrays nicht durch "zu wenig RAM"
manipuliert wird, sondern das im Programm explizit darauf
zugegriffen/geschrieben wird?
Soweit ich das beurteilen konnte wurde immer derselbe Speicherbereich
verändert, in dem warscheinlich durch Zufall immer das Daten-Array für
die Ziffer "3" stand.
Kann ich mir beim Debugging irgendwie anzeigen lassen welche Zeiger
aktuell auf eine bestimmte Adresse zeigen?
mfg
Sagt mal .......
Im constructor werden Variablen
"volatile uint8_t NumberArray_0[]"
"volatile uint8_t NumberArray_1[]" etc.
definiert und initialisiert.
Diese Variablen sind nur im constructor definiert.
In der Klassendefinition nicht.
Nun wird die Variable initialisiert und (deren Pointer) in ein anderes
Array kopiert.
this->NumberArray[0] = NumberArray_0;
Nun wird der constructor verlassen, die Variablen aber weiter verwendet.
( Über das this->NumberArray[] )
Dann kann doch nicht gut gehen ? Oder ?
Junger Mann.
Deine Arrays hier im Konstruktor sind alle funktionslokale Variablen.
D.h. nach Beendigung der Funktion existieren diese nicht mehr. Du hast
dir soeben im Konstruktor Pointer auf Objekte gemerkt, die nicht mehr
vorhanden sind, wenn du sie brauchst. In der Zwischenzeit ist aber der
Speicher schon wieder für was weiß ich alles benutzt worden. Kein
Wunder, dass du deine Daten da drinnen nicht mehr wiederfindest.
NurEinGast schrieb:> Sagt mal .......>> Im constructor werden Variablen> "volatile uint8_t NumberArray_0[]"> "volatile uint8_t NumberArray_1[]" etc.> definiert und initialisiert.>> Diese Variablen sind nur im constructor definiert.> In der Klassendefinition nicht.>> Nun wird die Variable initialisiert und (deren Pointer) in ein anderes> Array kopiert.> this->NumberArray[0] = NumberArray_0;>> Nun wird der constructor verlassen, die Variablen aber weiter verwendet.> ( Über das this->NumberArray[] )>> Dann kann doch nicht gut gehen ? Oder ?
Zefix, grad kam mir was ins Hirn geschossen.
Ist es möglich dass ich durch diese "Initialisierung" den Speicher der
Arrays nach Verlassen des Konstruktors wieder freigegeben habe ??!
Ich dachte da ein Zeiger darauf existiert bleibt dieser fest reserviert?
Karl-Heinz!!! 1000 Dank für den Hinweis, wie kann man nur so blöd
sein...
Manchmal sieht man den Wald vor lauter Bäumen nicht, gepaart mit
jugendlichen Leichtsinn und zuviel Java-Programmierung.
Ich geh mich jetzt schämen....
mfg ;)
Thomas D. schrieb:> Zefix, grad kam mir was ins Hirn geschossen.>> Ist es möglich dass ich durch diese "Initialisierung" den Speicher der> Arrays nach Verlassen des Konstruktors wieder freigegeben habe ??!>> Ich dachte da ein Zeiger darauf existiert bleibt dieser fest reserviert?
Sei mir nicht böse.
Aber das ist 'Lebensdauer von Variablen' - Kenntnisstufe 0.9
Funktionslokale Variablen, werden innerhalb der Funktion erzeugt und bei
Verlassen der FUnktion wieder zerstört
1
voidfoo()
2
{
3
inti;
4
5
for(i=0;i<8;i++)
6
;
7
}
i existiert nur solange, solange die Funktion läuft. Wird die Funktion
beendet, dann wird die Variable zerstört (ihr Speicher zur weiteren
Benutzung wieder freigegeben).
Warum soll ein Pointer daran was ändern? Wann soll denn dann der
Speicher wieder freigegeben werden?
In C++ gibt es keinen 'Speicher Managemenet ist so kompliziert, drumm
brauch ich eine Garbage Collection die hinter mir aufräumt' Mechanismus.
Thomas D. schrieb:> Meine Frage lautet: Wie kann es in dem uC passieren, dass einfach> verschiedene Werte von bereits initialisierten Arrays überschrieben> werden??
Ganz einfach: Indem man Scheiße programmiert.
> Auch sollte ich noch genügend freien Speicher haben
Das nützt rein garnix, wenn wegen eines Bugs in deinem Programm
eigentlich belegter Speicher überschrieben wird.
> Kennt jemand die Ursache für dieses Symptom?
Nahezu immer das Teil vor dem Monitor. Sehr viel seltener Fehler in
Compilern, Assemblern oder der Hardware.
Prima!
Nachdem alle anderen hier nicht die leiseste Ahnung haben, wo das
Problem liegen könnte, hast du als erster einen hilfreichen Beitrag
geliefert.
Das ist natürlich mein Vorschlag für den "Beitrag des Monats".
Richtige Programme kann man sowieso nur in ASM schreiben. Nur so ist
sichergestellt, daß nichts durch den C-Compiler falsch gemacht werden
kann und auch das (temporäre) nichtbeherschen der Sprache C keine
Probleme verursacht.
Im konkrete Fall würde ja schon das Schreiben einer simplen Java-VM das
ursprüngliche Problem lösen. Dann würden Java-like Arrays funktionieren.
(wer Ironie findet, darf sie behalten)
Was ist die soziale Imkompetenz bei der ironischen Überspitzung der
typischen Aussage des Kollegen "c-hater" unter Verwendung eines
nicknames, der klarstellt, was ich von c-hater halte?
Oder gilt: c-hater==spess53==holger ?
>>Bitte Namen lesen und verstehen!>>Keine Entschuldigung für soziale Inkompetenz.
Die Auflösung:
Post von C-hater
Bla bla bla
Und dann
C-hater-hater
Also jemand der C-hater
nicht mag;)
C-hater-hater schrieb:> Was ist die soziale Imkompetenz bei der ironischen Überspitzung der> typischen Aussage des Kollegen "c-hater" unter Verwendung eines> nicknames, der klarstellt, was ich von c-hater halte?
Wenn du lesen könntest, dann wöre dir aufgefallen, daß es in meinem
Posting überhaupt nicht um C ging.
Es ging vielmehr darum, daß vor allem unerfahrene Programmierer dazu
neigen, die Fehler zuallerletzt im eigenen Code zu suchen.
c-hater schrieb:> Es ging vielmehr darum, daß vor allem unerfahrene Programmierer dazu> neigen, die Fehler zuallerletzt im eigenen Code zu suchen.
... und das wiederum war gar nicht das Problem des TO.
Wenn du lesen könntest, wäre dir das vielleicht aufgefallen :-)