Forum: Compiler & IDEs Zugriff aufs Flash: Lesen von falschen Adressen/zu komplexer Code


von Matthias L. (matze88)


Lesenswert?

Hallo!

Ich stehe gerade mal wieder auf dem Schlauch, hatte gerade schon ein 
Thema zu diesem Problem gemacht es aber wieder gelöscht, da es etwas 
dran vorbei geht. Also hier jetzt erstmal mein C-Code:
1
const uint8_t led_degree[] PROGMEM = {119, 135, 103, 121, 76, 110, 52, 88, 30, 64, 19, 37, 5, 21, 0, 13, 127, 139};
2
// displays course with leds, absolute = 1 -> direct, absolute = 0: add current heading
3
void display_course(uint8_t course, uint8_t direct)
4
{
5
  if(!direct)
6
  {
7
    uint16_t temp = course + current_gps_heading;
8
    if(temp > 139) temp -= 140;
9
    course = temp;
10
  }
11
12
  // led display: 
13
  uint8_t led_t = 0;
14
  
15
  
16
  uint8_t i = 0x80, j = 0;
17
  uint8_t temp, temp2;
18
  do
19
  {
20
    temp = pgm_read_byte(&led_degree[j]);
21
    temp2 = pgm_read_byte(&led_degree[j+1]);
22
    j+=2;
23
    /* gleiches ergebnis auch wenn ich jeweils j++ schreibe */
24
    if(temp <= course && temp2 >= course)
25
      led_t |= i;
26
    if(i > 1)
27
      i = i >> 1;
28
    //j --;
29
  } while(j <= 17);
30
  led = led_t;
31
}

Gcc macht daraus:
1
0000008f <led_degree>:
2
      8f:  77 87 67 79 4c 6e 34 58 1e 40 13 25 05 15 00 0d     w.gyLn4X.@.%....
3
      9f:  7f 8b       
4
5
148:  ef e8         ldi  r30, 0x8F  ; 143
6
     14a:  f0 e0         ldi  r31, 0x00  ; 0
7
     14c:  20 e0         ldi  r18, 0x00  ; 0
8
     14e:  90 e8         ldi  r25, 0x80  ; 128
9
  
10
  uint8_t i = 0x80, j = 0;
11
  uint8_t temp, temp2;
12
  do
13
  {
14
    temp = pgm_read_byte(&led_degree[j]);
15
     150:  84 91         lpm  r24, Z+
16
  temp2 = pgm_read_byte(&led_degree[j+1]);
17
     152:  31 96         adiw  r30, 0x01  ; 1
18
     154:  34 91         lpm  r19, Z+
19
     156:  31 97         sbiw  r30, 0x01  ; 1
20
  j+=2;
21
  //if(pgm_read_byte(&led_degree[j--]) >= course)
22
  //  if(pgm_read_byte(&led_degree[j]) <= course)
23
  if(temp <= course && temp2 >= course)
24
     158:  48 17         cp  r20, r24
25
     15a:  18 f0         brcs  .+6        ; 0x162 <display_course+0x36>
26
     15c:  34 17         cp  r19, r20
27
     15e:  08 f0         brcs  .+2        ; 0x162 <display_course+0x36>
28
    led_t |= i;
29
     160:  29 2b         or  r18, r25
30
    if(i > 1) i = i >> 1;
31
     162:  92 30         cpi  r25, 0x02  ; 2
32
     164:  08 f0         brcs  .+2        ; 0x168 <display_course+0x3c>
33
     166:  96 95         lsr  r25
34
     168:  32 96         adiw  r30, 0x02  ; 2
35
    //j --;
36
  } while(j <= 17);
37
     16a:  80 e0         ldi  r24, 0x00  ; 0
38
     16c:  e1 3a         cpi  r30, 0xA1  ; 161
39
     16e:  f8 07         cpc  r31, r24
40
     170:  79 f7         brne  .-34       ; 0x150 <display_course+0x24>
(nur der interessante teil, wo es ums Lesen vm Flash und so geht)

So, warum liest er nur jedes 2. Byte? (lpm rXX, Z+ UND adiw Z, 1)
Warum zieht er nach dem 2. lesen wieder 1 von Z ab, obwohl er extra mit 
Z+ liest? Warum addiert er am Ende der Schleife 2 drauf anstatt das 
gleich zu tun?

Die erste dieser Fragen ist ja das wirkliche Problem, er tut etwas, was 
er garnicht darf. Oder habe ich hier nen Programmierfehler?

Kurze Funktionsbeschreibung:
Anzeige des aktuellen Kurses (GPS) oder der Richtung zu einem Wegpunkt 
(Winkel [pos->WP] + Kurs) auf 8 im Kreis angeordneten LEDs, volatile 
uint8_t led; hat für jede LED 1 Bit. Winkelangabe ist in (Grad * 100) >> 
8, die Funktion dient zum Übersetzen der Winkelangaben auf die 
jeweilig(en) LEDs, es leuchten meistens 2, außer wenn der Fehler zu 
einer LED ziemlich klein ist, dann nur eine. (LED 0 kommt 2x vor, da sie 
von 127-13 leuchten soll)
Ob die Funktion so in der Praxis jetzt funktioniert weiß ich nichtmal, 
aber eigentlich dürfte sie das ja nicht, da er die falschen Bytes liest?

cu
Matze

von Oliver (Gast)


Lesenswert?

>Ob die Funktion so in der Praxis jetzt funktioniert weiß ich nichtmal,
>aber eigentlich dürfte sie das ja nicht, da er die falschen Bytes liest?

Tut sie aber.

Steck es in den nächsten Simulator, und schau es dir an. Oder mach eine 
UART-Ausgabe dahinter, oder sonstwas.

Oliver

von Stefan E. (sternst)


Lesenswert?

> So, warum liest er nur jedes 2. Byte? (lpm rXX, Z+ UND adiw Z, 1)

Tut er nicht. Es ist offenbar ein Fehler des Disassemblers, denn der 
Opcode "84 91" bedeutet "lpm  r24, Z". Für Z+ wäre es 85 statt 84.

von Matthias L. (matze88)


Lesenswert?

Oehm, ja, ihr habt ja so recht...

Oh man, ich sollte Code immer erst simulieren, bevor ich solche Beiträge 
verfasse, spart mir auch Zeit :-)

Bleiben 2 Probleme:
a) Fehler im Listfile, Bugmeldung irgendwie bei den GCC Entwicklern 
machen? Muss ich mich mal schlau googeln. Der Disassembler vom AVR 
Studio Simulator zeigts dann auch wieder richtig an, ist ja auch zu 
erwarten, die beiden Programme haben nichts miteinander zu tun

b) Warum benutzt er nicht LPM, rXX, Z+ und spart sich damit 2x adiw und 
1x sdiw? Das sind 3 Words bzw. 6 Cycles...

Matze

Edit:
http://sourceforge.net/tracker/index.php?func=detail&aid=1996284&group_id=68108&atid=520074

Bug also bei WinAVR bereits gemeldet.

von Stefan E. (sternst)


Lesenswert?

> Warum benutzt er nicht LPM, rXX, Z+

Weil der LPM-Befehl gar nicht vom Compiler generiert wird, sondern durch 
die AVR-Libc per Inline-Assembler. Würde dort Z+ verwendet werden, würde 
das den Z-Pointer verändern, ohne dass der Compiler davon weiß.
Das wäre gar nicht gut. ;-)

von Matthias L. (matze88)


Lesenswert?

Heißt das, dass der Compiler dort in keinem Fall optimieren kann? Dann 
wäre es eventuell schlauer, wenn ich das ganze direkt per 
Inlineassembler mache, falls ich irgendwann mal diese 3 Words brauche 
:-) (Es sieht schon fast danach aus, als könnte das in naher Zukunft 
passieren)

Gut, dann Vielen Dank nochmal für alles.

Matze

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.