mikrocontroller.net

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


Autor: Matthias Larisch (matze88)
Datum:

Bewertung
0 lesenswert
nicht 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:
const uint8_t led_degree[] PROGMEM = {119, 135, 103, 121, 76, 110, 52, 88, 30, 64, 19, 37, 5, 21, 0, 13, 127, 139};
// displays course with leds, absolute = 1 -> direct, absolute = 0: add current heading
void display_course(uint8_t course, uint8_t direct)
{
  if(!direct)
  {
    uint16_t temp = course + current_gps_heading;
    if(temp > 139) temp -= 140;
    course = temp;
  }

  // led display: 
  uint8_t led_t = 0;
  
  
  uint8_t i = 0x80, j = 0;
  uint8_t temp, temp2;
  do
  {
    temp = pgm_read_byte(&led_degree[j]);
    temp2 = pgm_read_byte(&led_degree[j+1]);
    j+=2;
    /* gleiches ergebnis auch wenn ich jeweils j++ schreibe */
    if(temp <= course && temp2 >= course)
      led_t |= i;
    if(i > 1)
      i = i >> 1;
    //j --;
  } while(j <= 17);
  led = led_t;
}

Gcc macht daraus:
0000008f <led_degree>:
      8f:  77 87 67 79 4c 6e 34 58 1e 40 13 25 05 15 00 0d     w.gyLn4X.@.%....
      9f:  7f 8b       

148:  ef e8         ldi  r30, 0x8F  ; 143
     14a:  f0 e0         ldi  r31, 0x00  ; 0
     14c:  20 e0         ldi  r18, 0x00  ; 0
     14e:  90 e8         ldi  r25, 0x80  ; 128
  
  uint8_t i = 0x80, j = 0;
  uint8_t temp, temp2;
  do
  {
    temp = pgm_read_byte(&led_degree[j]);
     150:  84 91         lpm  r24, Z+
  temp2 = pgm_read_byte(&led_degree[j+1]);
     152:  31 96         adiw  r30, 0x01  ; 1
     154:  34 91         lpm  r19, Z+
     156:  31 97         sbiw  r30, 0x01  ; 1
  j+=2;
  //if(pgm_read_byte(&led_degree[j--]) >= course)
  //  if(pgm_read_byte(&led_degree[j]) <= course)
  if(temp <= course && temp2 >= course)
     158:  48 17         cp  r20, r24
     15a:  18 f0         brcs  .+6        ; 0x162 <display_course+0x36>
     15c:  34 17         cp  r19, r20
     15e:  08 f0         brcs  .+2        ; 0x162 <display_course+0x36>
    led_t |= i;
     160:  29 2b         or  r18, r25
    if(i > 1) i = i >> 1;
     162:  92 30         cpi  r25, 0x02  ; 2
     164:  08 f0         brcs  .+2        ; 0x168 <display_course+0x3c>
     166:  96 95         lsr  r25
     168:  32 96         adiw  r30, 0x02  ; 2
    //j --;
  } while(j <= 17);
     16a:  80 e0         ldi  r24, 0x00  ; 0
     16c:  e1 3a         cpi  r30, 0xA1  ; 161
     16e:  f8 07         cpc  r31, r24
     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

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias Larisch (matze88)
Datum:

Bewertung
0 lesenswert
nicht 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=deta...

Bug also bei WinAVR bereits gemeldet.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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. ;-)

Autor: Matthias Larisch (matze88)
Datum:

Bewertung
0 lesenswert
nicht 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

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.