Atmel Studio probleme wenn optimization aktiv

OP #4203412
Lesenswert?

Hallo,
ich habe eine Funktion, die ohne Optimierung funktioniert, wird mit 
Optimierung compiliert, macht sie definitiv was falsch.

Hier der Code der Funktion:
1
/////////////////////////////////////////////////////////////////////////
2
//
3
// file function:
4
// read device names from RC.TXT
5
//
6
//  parameters:
7
//
8
// return:
9
// unit8_t                          0 when OK, 1 when EOF or error
10
//
11
/////////////////////////////////////////////////////////////////////////
12
uint8_t aw_readDeviceNames(void)
13
{
14
   FIL         fp1;
15
   FRESULT     res;
16
   uint8_t     c;
17
   uint16_t    i, j, repeat;
18
   uint32_t    error;
19

20
   device_name[0][0] = 'A';
21
   device_name[0][1] = 'M';
22
   device_name[0][2] = 'P';
23
   device_name[0][3] = 0;
24
   device_name[0][4] = 0;
25
   device_name[0][5] = 0;
26
   device_name[0][6] = 0;
27
   device_name[0][7] = 0;
28
   no_devices = 1;
29

30
   repeat = 0;
31
   do 
32
   {
33
      filename[0]  = 'R';
34
      filename[1]  = 'C';
35
      filename[2]  = '.';
36
      filename[3]  = 'T';
37
      filename[4]  = 'X';
38
      filename[5]  = 'T';
39
      filename[6]  = 0;
40
      res = f_open(&fp1, (char*)filename, FA_OPEN_EXISTING | FA_READ);
41
      if (res != FR_OK)
42
      {
43
         error = 1;
44
      }
45
      filesize = (uint32_t)fp1.fsize;
46
      i = 1;
47
      error = 0;
48
      while ((error == 0) && (i < 16))
49
      {
50
         error = aw_readLine(&fp1, buf);
51
         if (error == 0)
52
         {
53
            for (j = 0; j < 8; j++)
54
               device_name[i][j] = 0;
55
            j = 0;
56
            c = buf[j];
57
            while ((c >= 0x20) && (j < 7))     // max 7 characters
58
            {
59
               device_name[i][j++] = c;
60
               c = buf[j];
61
            }
62
            if (j != 0)
63
               i++;
64
         }
65
      }
66
      res = f_close(&fp1);
67
      error = (filesize != 0);
68
      no_devices = i;
69
      repeat++;
70
   } while ((error != 0) && (repeat < 10));
71

72
   return error;
73
}

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
Gast #4203425
Lesenswert?

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.
Gast #4203436
Lesenswert?

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?
OP #4203490
Lesenswert?

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
Gast #4203620
Lesenswert?

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...
Gast #4203640
Lesenswert?

c-hater schrieb:
> Sicherheit auf schlampigen Code tippen

Sowas
1
uint8_t aw_readDeviceNames(void)
2
uint32_t    error;
3
return error;
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.
Gast #4203645
Lesenswert?

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.
Gast #4203699
Lesenswert?

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.
#4203732
Lesenswert?

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.
Gast #4203734
Lesenswert?

Georg G. schrieb:
> Dein Vertrauen in den Compiler ehrt dich.

wenn das ein Compiler hin hinbekommt dann kann man ihn nur entsorgen.
1
uint32_t b = 42;
2
uint8_t a = b;

muss jeder Compiler ordentlich umsetzen, er darf dabei eine Warnung 
werfen das eventuell Daten verloren gehen mehr aber nicht.
Gast #4203735
Lesenswert?

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?
OP #4203738
Lesenswert?

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
void SysTick_Handler(void)
2
{
3
   uint8_t     n;
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
int main(void)
2
{
3
   uint32_t    udata, rc_unit, error, color;
4
   int32_t     i, j, k, idata, turned_local;
5
   uint8_t     c;
6
   int16_t     yn;
7
   uint16_t    xx, yy;
8
   uint8_t     spi_tx[64];
9
   uint8_t     spi_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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren