www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Probleme mit pgm_read_word in Schlaufe


Autor: George R. (caco3)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen

Ich habe ein Projekt, mit dem ich ich mit einem Atmega16 eine 
IR-Fernbedienung einlese. Der eingelesene Code wird dann mit einer 
Lookup-Tabelle verglichen um den gedrückten Button herauszufinden.
Das hat bis jetzt auch ganz gut geklappt. Da mein RAM langsam zu eng 
wird, will ich die Tabelle nun ins Flash verlegen.

Hier meine Lookup-Daten:
unsigned const int IR_KEY_LIST[][8] PROGMEM ={
  {0x1, 0xFD75, 0x5575, 0xDDDD, 0xDD55, 0x55DD, 0xDDDD, 0xDDFF},  // 1: On/Off Key
  {0x1, 0xFD75, 0x5575, 0xDDDD, 0xDDDD, 0x5555, 0xDDDD, 0xDDFF},  //Key 1
 //...
};


Das auslesen und anzeigen auf meinem Display klappt auch korrekt, sofern 
ich jede Zelle einzeln auslese:
q=0;
display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
display_string(" ");

q=1;
display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
display_string(" ");

q=2;
display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
display_string(" ");

q=3;
display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
display_string(" ");

q=4;
display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
display_string(" ");

//...

Logisch macht dies nicht sehr viel Sinn und sollte in eine Schleife 
gepackt werden:
unsigned int q;
for(q=0;q<8;q++){
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
  display_string(" ");
}

Hier kriege ich nun nur noch Mülldaten. Auch stoppt die Schleife nicht 
mehr :(

Bis jetzt habe ich folgendes herausgefunden:
Wenn ich q nur von 0..1 zähle, klappt es.
Anschliessend kann ich in einer neuen Schleife von 2..3, 4..5 usw. 
zählen.

Aus irgend einem Grund wird mir da offenbar q irgendwie zerschossen oder 
es hat einen Überlauf.
merkwürdigerweise klappt es aber, wenn ich die Schlaufe wie zuoberst 
zerlege.

Hier ein Beispiel wie es klappt:
for(q=0;q<2;q++){
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
  display_string(" ");
}
for(q=2;q<4;q++){
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
  display_string(" ");
}
for(q=4;q<6;q++){
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
  display_string(" ");
}
for(q=6;q<8;q++){
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
  display_string(" ");
}

Woran könnte das wohl liegen?

Vielen Dank für eure Tipps!

Autor: Helmut Lenzen (helmi1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
unsigned const int IR_KEY_LIST[][8] PROGMEM
                              ^^^^^

Warum machst du hier ein 2 Dimensionales Array auf?

Es reicht doch:

unsigned const int IR_KEY_LIST[8] PROGMEM

Die Groesse deiner Elemente ist doch fest "int".

Autor: George R. (caco3)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich verstehe dich nicht ganz.

Ein eindimensionales Array wäre so:
unsigned const int IR_KEY_LIST[] PROGMEM ={0x1, 0xEFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};


Aber ich benötige ein zweidimensionales Array:
unsigned const int IR_KEY_LIST[][8] PROGMEM ={
{0x1, 0xEFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF},
{0x1, 0xFD75, 0x5575, 0xDDDD, 0xDD55, 0x55DD, 0xDDDD, 0xDDFF}
};


Ausserdem ist das wohl kaum das Problem, da ich die Felder ja korrekt 
auslesen kann.

Autor: Helmut Lenzen (helmi1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok hatte ich jetzt nicht ganz gesehen. Was macht das Programm denn wenn 
du die eine Dimension mit angibst?

Autor: George R. (caco3)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was meinst Du damit?

Natürlich könnte ich die Feldgrösse ausrechnen und angeben, aber das 
kann der Compiler ja auch selber machen.
Ausserdem habe ich in einer anderen Konstante definiert, wie gross das 
Array ist.
Der Grund dass ich das hier nicht angebe ist nur, weil ich es dann auch 
im Headerfile angeben müsste.

Aber wie gesagt, einzeln auslesen geht ja, deshalb sollte das kaum das 
Problem sein.

Autor: Guru (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, der Code sollte eigentlich so funktionieren. Ich sehe keinen 
Fehler.

Was mich stutzig macht, ist das Du schreibst:

>Da mein RAM langsam zu eng wird ...

Poste doch mal die Speicherangaben nach dem Compiliervorgang. (Du 
benutzt doch AVRStudio nehme ich an)?

Ich habe Zweifel daran, dass es an zuwenig RAM liegt, aber sicher ist 
sicher.

Reduziere dann auch mal den Code auf das absolut Notwendigste, so das 
der Fehler noch auftritt und poste am besten das ganze Projekt (nach 
einem Clean).

Autor: George R. (caco3)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier die GCC ausgabe:
Device: atmega16

Program:   15806 bytes (96.5% Full)
(.text + .data + .bootloader)

Data:        539 bytes (52.6% Full)
(.data + .bss + .noinit)

EEPROM:       17 bytes (3.3% Full)
(.eeprom)

Das RAM sollte definitiv kein Problem sein.

Untenstehend ein Minimalbeispiel, bei dem das Problem immer noch 
auftritt.
Wenn ich die 8 in der for-Schleife auf 2 verkleinere, geht es.
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "display.h"


unsigned const int IR_KEY_LIST[][8] PROGMEM ={
    {0x1, 0xEFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF},
    {0x1, 0xFD75, 0x5575, 0xDDDD, 0xDD55, 0x55DD, 0xDDDD, 0xDDFF}
};


int main(void){
  unsigned int q;

  display_init();


  //////// WORKS ////////////////////////
  /* Expected output on display:
   * 1 FD75 5575 DDDD DD55
   * 55DD DDDD DDFF
   * Result: As espected
   */

  display_pos(0, 2);
  q=0;
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
  display_string(" ");

  q=1;
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
  display_string(" ");

  q=2;
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
  display_string(" ");

  q=3;
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
  display_string(" ");

  q=4;
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
  display_string(" ");

  display_pos(0, 3);
  q=5;
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
  display_string(" ");

  q=6;
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
  display_string(" ");

  q=7;
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
  display_string(" ");
  /////////////////////////////////////////////



  //////// DOES NOT WORK ////////////////////////
  /* Expected output on display:
   * 1 FD75 5575 DDDD DD55
   * 55DD DDDD DDFF
   * Result:
   * 1 FD75 C03 33A 33A 33
   * A 33A 33A 33A 33A 33A.....
   * Symptoms:
   * It stays in the for loop forever
   */
  display_pos(0, 5);
  for(q=0;q<8;q++){
    display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
    display_string(" ");
  }
  /////////////////////////////////////////////


  while(1);
}

Autor: George R. (caco3)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ab dem 3. Word scheint er also plötzlich Unsinn einzulesen.

Autor: Guru (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Untenstehend ein Minimalbeispiel, bei dem das Problem immer noch
auftritt.

Du hast es vielleicht übersehen:

>Reduziere dann auch mal den Code auf das absolut Notwendigste, so das
>der Fehler noch auftritt und poste am besten das ganze Projekt (nach
>einem Clean).

Der Code muss natürlich für uns kompilierbar sein. Deswegen solltest Du 
das ganze Projekt posten. Wie gesagt ist das Verhalten am Code allein 
nicht erklärbar. Dein letzter Post bringt uns also nicht weiter.

P.S.
Der Kommentar stimmt übrigens nicht: Symptom ist das was Du beobachtest, 
nicht das was Du vermutest.

Autor: George R. (caco3)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bhu, ich habe den Hund gefunden.

Das Problem war anscheinend meine Funktion display_int_hex, welche den 
integer in einen string umwandelt und ausgibt:
void display_int_hex(unsigned int i){
  char string[ sizeof(i)+1 ];
  itoa(i, string, 16);
  display_string(string);
}

Natürlich ist das ganze mit dem "sizeof(i)+1" Unsinn.
Keine Ahnung, wie ich auf das kam, aber bis jetzt hat es nie Probleme 
gegeben.

Korrekt heisst es:
void display_int_hex(unsigned int i){
  char string[6]; //max on int (16bit) is FFFF + prefix, so use 6
  itoa(i, string, 16);
  display_string(string);
}

Mir unerklärlich ist aber trotzdem, wieso es nur auftritt, wenn ich 
pgm_read_word verwende. Ich vermute mal, das durch glückliche Umstände 
jeweils ein Stringterminator an der richtigen Stelle im ungenutzten RAM 
stand.

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.