Hallo,
ich habe eine Funktion, die ohne Optimierung funktioniert, wird mit
Optimierung compiliert, macht sie definitiv was falsch.
Hier der Code der Funktion:
Die Funktion liest die Datei RC.TXT ein und speichert Namen (je ein Name
pro Zeile in der Datei) im Feld device_name[16][8] ab. Der erste Eintrag
ist immer gleich, erst ab dem zweiten werden die Namen von der Datei
aufgefüllt. Wenn das Dateilesen nicht klappt, wird das bis zu 10-mal
wiederholt, da ich immer noch Probleme mit den Funktionen für den
SD-Kartenzugriff habe. Zwar nicht beim Lesen der kleinen Textdateien,
wohl aber beim Lesen größerer Dateien. Schreiben versuche ich momentan
gar nicht mehr, das funktioniert momentan gar nicht...
Das Problem betrifft die Variable i. Sie wird nach dem f_open auf 1
gesetzt, nach dem Aufruf von aw_readLine(&fp1, buf) ist i = 0, wie ich
mit dem Debugger sehe. Als Folge schreibt die Funktion alle Namen ins
erste Feld, alle anderen bleiben unberührt. Und so passiert das auch,
wenn es ohne Debugger läuft. Ohne Optimierung funktioniert die Funktion
aber normal. Ich wüßte auch nicht, warum ich die Variable i volatile
machen sollte, die Funktion aw_readLine() kann doch nicht die lokale
Variable i verändern. Mache ich i, j und repeat static, wird i richtig
gezählt, dafür wird die Zeile device_name[i][j++] = c; nicht mehr
ausgeführt. Das sieht man daran, daß j auf Null bleibt und nun gar keine
Namen eingetragen werden, auch das Verhalten bleibt ohne Debugger.
device_name ist eine globale Variable.
Hat jemand schon ähnliche Probleme gehabt?
Gruß
Andy
Andreas W. schrieb:> Das Problem betrifft die Variable i. Sie wird nach dem f_open auf 1> gesetzt, nach dem Aufruf von aw_readLine(&fp1, buf) ist i = 0, wie ich> mit dem Debugger sehe.
dann debugge doch einfach mal aw_readLine, irgendwo muss dort dann der
fehler sein.
Vermutlich ist buf aber zu klein, aber dafür fehlt uns der Rest von code
für eine sinnvolle Aussage.
Klingt für mich nach RAM Überlauf. Welchen uC verwendest du? Lokale
Variablen liegen auf dem stack, static Variablen im bss Segement.
Möglicherweise braucht dein Programm (inzwischen) zu viel RAM und
deswegen kracht es. Wie optimierst du? -Os oder -O2?
Hallo,
ich vermute auch, daß es ein RAM oder auch Stacküberlauf sein könnte.
Aber wie kann man das feststellen? Der Prozessor ist ein SAM3X8E
(Arduino Due). Bisher habe ich noch keine Möglichkeit gefunden, z.B. die
Stackgröße irgendwo zu definieren. buf selbst ist ziemlich groß,
momentan mit int8_t buf[4096] definiert. Ich kann ja mal versuchen, das
Feld kleiner zu machen, momentan brauche ich es nicht so groß. Wo kann
man denn die Speicherbelegung sehen, die der Compiler wählt? Sollter der
nicht meckern, wenn das RAM nicht reicht, statt die Daten sich
überlappen zu lassen?
Besonders habe ich auch den Stack in Verdacht, daß der zu klein ist,
aber die Hilfe von Atmel erzählt dazu fast nichts. Besonders nichts, wie
man die reservierte Stackgröße anpassen kann. Weiß da jemand was?
Vielleicht ist das auch der Grund, daß die SD-Kartenfunktionen nicht
einwandfrei laufen.
aw_readLine() funktioniert einwandfrei, auch im optimierten Code und hat
nichts mit der lokalen Variable i zu tun, die danach verändert wurde.
Gruß
Andy
Andreas W. schrieb:> ich habe eine Funktion, die ohne Optimierung funktioniert, wird mit> Optimierung compiliert, macht sie definitiv was falsch.
Dann ist in aller Regel irgendwas in der Funktion falsch. Möglicherweise
ist aber auch außerhalb der Funktion etwas falsch, wirkt sich aber (mehr
oder weniger zufällig) genau nur in der konkreten Funktion aus.
Anhand deiner Beschreibung und der Tatsache, dass in der geposteten
Funktion kein offensichtlicher Fehler zu erkennen ist (vielleicht habe
ich ihn aber auch nur übersehen, C ist ja so dermaßen Scheiße zu lesen)
würde ich letzteres vermuten.
Genau könnte ich sagen, was passiert, wenn du das Hexfile des
Gesamtwerkes postest und zwar in beiden Varianten, mit und ohne
Optimierung.
Ich würde aber mit 99,9%iger Sicherheit auf schlampigen Code tippen. Nur
das winzige verbleibende Promille gäbe ich auf einen tatsächliche
Compilerfehler.
Da wäre dann ggf. zu klären, welchen Compiler in welcher Version du
benutzt. Möglicherweise hast du ja auch "nur" einen bereits bekannten
Optimizer-Fehler getriggert...
spricht sehr dafür. Zusammen mit Variablennamen i und j, die keine
einfachen Schleifenzähler sind, hat das dazu geführt, gar nicht erst
weiter zu lesen. Wer Compilerwarnungen ignoriert, hat offensichtlich
sowieso kein Interesse an funktionierendem Code.
Tom schrieb:> Sowasuint8_t aw_readDeviceNames(void)> uint32_t error;> return error;> spricht sehr dafür.
wo hast du ein Problem mit error? Nur weil es am Anfang nicht
Initalisiert ist? Es wird später in jedem Fall auf einen wert gesetzt,
es gibt keine Möglichkeit das error am ende nicht definiert ist.
Andreas W. schrieb:> Bisher habe ich noch keine Möglichkeit gefunden, z.B. die> Stackgröße irgendwo zu definieren.
Die größen Definitionen von Stack und Heap findest du in den
LinkerScripten.
Peter II schrieb:> ein Problem mit error?
error ist 32 Bit, laut Definition sollen aber 8 Bit zurück gegeben
werden. Da kommt der Compiler ins schwitzen. Welcher Compiler ist es,
der da keine Warnung ausgibt?
Georg G. schrieb:> error ist 32 Bit, laut Definition sollen aber 8 Bit zurück gegeben> werden. Da kommt der Compiler ins schwitzen. Welcher Compiler ist es,> der da keine Warnung ausgibt?
Warnung ist doch ok, hier kann es aber zu keinen Fehler kommen, weil in
Error nur 0 oder 1 steht, damit gehen beim ändern vom Datentype NIE
Daten verloren.
Peter II schrieb:> hier kann es aber zu keinen Fehler kommen
Wie werden Rückgabe Werte übergeben?
Im Register? Der Aufrufer erwartet in R1 die Rückgabe und glaubt, dass
R2 bis R5 unbeschadet bleiben. Die Rückgabe erfolgt aber in R1 bis R4
und schon ist eine lokale Variable im Eimer.
Auf dem Heap? 4 Bytes werden belegt und nur eines wird abgeräumt. Peng.
Dein Vertrauen in den Compiler ehrt dich.
Georg G. schrieb:> Dein Vertrauen in den Compiler ehrt dich.
Ehren?
Wer nicht begreift, dass ein Compiler auch nur ein Stück Software mit
(stark beschränkter) Maschinenintelligenz ist, der braucht wohl keine
Ehrung, sondern eher einen kraftigen Tritt in den verlängerten Rücken.
Oder darf man noch "Arsch" sagen?
Hallo,
das Verkleinern von buf[4096] auf buf[128] hat zumindest die Funktion
auch mit Optimierung wieder richtig laufen lassen. Eine Warnung, daß RAM
zu knapp wird, bekomme ich aber nicht einmal, wenn ich sämtliche
Warnungen incl. "pedantic" aktiviere. Den Stack-size habe ich irgendwann
auch bei mir gefunden, bei mir ist der Pfad aber etwas anders und die
Datei heißt nur flash.ld. Da war die Size auf 0x2000, die habe ich auf
0x3000 heraufgesetzt. Ein Heapsize ist in meiner Datei flash.ld aber
nicht definiert.
Seltsam war, daß das Lesen von Dateien von der SD-Karte mit optimiertem
Code recht gut geht, nur manchmal muß ich bei längeren Dateien (auch nur
wenige kB, aber mehr als ein Sektor) mehrere Versuche machen. Ohne
Optimierung klappte das Lesen fast nie, nur ganz selten. Eigentlich
sollte langsamer doch eher funktionieren? SPI wird allerdings mit der
prozessoreigenen Hardware erledigt, d.h. der SPI-Clock hat die gleiche
Frequenz. Schreiben funktioniert immer noch nicht, aber das scheint auch
ein Timingproblem zu sein, denn ein einzigesmal hat es doch geklappt.
Ich habe auch eine Interruptfunktion, hier der vereinfachte Code:
1
voidSysTick_Handler(void)
2
{
3
uint8_tn;
4
5
n=Timer0;
6
if(n)Timer0=--n;
7
8
return;
9
}
Timer0 ist eine globale Variable und soll für Delays usw. dienen. Die
wird auch von ff.c für die SD-Funktionen genutzt.
Im Hauptprogramm wird sie folgendermaßen initialisiert, ich bin mir aber
nicht sicher, ob das so richtig ist:
1
intmain(void)
2
{
3
uint32_tudata,rc_unit,error,color;
4
int32_ti,j,k,idata,turned_local;
5
uint8_tc;
6
int16_tyn;
7
uint16_txx,yy;
8
uint8_tspi_tx[64];
9
uint8_tspi_rx[64];
10
11
SystemInit();// Initialize the SAM system
12
WDT->WDT_MR=0x00008000;// disable Watchdog
13
if(SysTick_Config(sysclk_get_cpu_hz()/1000))
14
while(1){}//Capture error
15
NVIC_EnableIRQ(SysTick_IRQn);
16
__enable_irq();
17
.....
Die Interruptroutine springt aber nicht sofort an, sondern erst viel
später, nachdem mehrere, eigene Funktionen schon aufgerufen wurden. Ein
Delay, das Timer0 benutzt und früh aufgerufen wird, wird daher nie
beendet, da Timer0 noch nicht herunter gezählt wird.
Obigen Code hatte ich in einem Beispielcode gefunden, die zwei Zeilen
mit NVIC_EnableIRQ() und __enable_irq() habe ich hier mal in einem
Posting gefunden. Scheint aber nicht das richtige zu sein.
Gruß
Andy