Forum: Mikrocontroller und Digitale Elektronik Probleme mit pgm_read_word in Schlaufe


von George R. (caco3)


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:
1
unsigned const int IR_KEY_LIST[][8] PROGMEM ={
2
  {0x1, 0xFD75, 0x5575, 0xDDDD, 0xDD55, 0x55DD, 0xDDDD, 0xDDFF},  // 1: On/Off Key
3
  {0x1, 0xFD75, 0x5575, 0xDDDD, 0xDDDD, 0x5555, 0xDDDD, 0xDDFF},  //Key 1
4
 //...
5
};


Das auslesen und anzeigen auf meinem Display klappt auch korrekt, sofern 
ich jede Zelle einzeln auslese:
1
q=0;
2
display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
3
display_string(" ");
4
5
q=1;
6
display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
7
display_string(" ");
8
9
q=2;
10
display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
11
display_string(" ");
12
13
q=3;
14
display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
15
display_string(" ");
16
17
q=4;
18
display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
19
display_string(" ");
20
21
//...

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

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:
1
for(q=0;q<2;q++){
2
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
3
  display_string(" ");
4
}
5
for(q=2;q<4;q++){
6
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
7
  display_string(" ");
8
}
9
for(q=4;q<6;q++){
10
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
11
  display_string(" ");
12
}
13
for(q=6;q<8;q++){
14
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
15
  display_string(" ");
16
}

Woran könnte das wohl liegen?

Vielen Dank für eure Tipps!

von Helmut L. (helmi1)


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".

von George R. (caco3)


Lesenswert?

Ich verstehe dich nicht ganz.

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


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


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

von Helmut L. (helmi1)


Lesenswert?

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

von George R. (caco3)


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.

von Guru (Gast)


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).

von George R. (caco3)


Lesenswert?

Hier die GCC ausgabe:
1
Device: atmega16
2
3
Program:   15806 bytes (96.5% Full)
4
(.text + .data + .bootloader)
5
6
Data:        539 bytes (52.6% Full)
7
(.data + .bss + .noinit)
8
9
EEPROM:       17 bytes (3.3% Full)
10
(.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.
1
#include <avr/io.h>
2
#include <avr/pgmspace.h>
3
#include "display.h"
4
5
6
unsigned const int IR_KEY_LIST[][8] PROGMEM ={
7
    {0x1, 0xEFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF},
8
    {0x1, 0xFD75, 0x5575, 0xDDDD, 0xDD55, 0x55DD, 0xDDDD, 0xDDFF}
9
};
10
11
12
int main(void){
13
  unsigned int q;
14
15
  display_init();
16
17
18
  //////// WORKS ////////////////////////
19
  /* Expected output on display:
20
   * 1 FD75 5575 DDDD DD55
21
   * 55DD DDDD DDFF
22
   * Result: As espected
23
   */
24
25
  display_pos(0, 2);
26
  q=0;
27
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
28
  display_string(" ");
29
30
  q=1;
31
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
32
  display_string(" ");
33
34
  q=2;
35
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
36
  display_string(" ");
37
38
  q=3;
39
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
40
  display_string(" ");
41
42
  q=4;
43
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
44
  display_string(" ");
45
46
  display_pos(0, 3);
47
  q=5;
48
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
49
  display_string(" ");
50
51
  q=6;
52
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
53
  display_string(" ");
54
55
  q=7;
56
  display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
57
  display_string(" ");
58
  /////////////////////////////////////////////
59
60
61
62
  //////// DOES NOT WORK ////////////////////////
63
  /* Expected output on display:
64
   * 1 FD75 5575 DDDD DD55
65
   * 55DD DDDD DDFF
66
   * Result:
67
   * 1 FD75 C03 33A 33A 33
68
   * A 33A 33A 33A 33A 33A.....
69
   * Symptoms:
70
   * It stays in the for loop forever
71
   */
72
  display_pos(0, 5);
73
  for(q=0;q<8;q++){
74
    display_int_hex( pgm_read_word(&(IR_KEY_LIST[1][q])) );
75
    display_string(" ");
76
  }
77
  /////////////////////////////////////////////
78
79
80
  while(1);
81
}

von George R. (caco3)


Lesenswert?

Ab dem 3. Word scheint er also plötzlich Unsinn einzulesen.

von Guru (Gast)


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.

von George R. (caco3)


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:
1
void display_int_hex(unsigned int i){
2
  char string[ sizeof(i)+1 ];
3
  itoa(i, string, 16);
4
  display_string(string);
5
}

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:
1
void display_int_hex(unsigned int i){
2
  char string[6]; //max on int (16bit) is FFFF + prefix, so use 6
3
  itoa(i, string, 16);
4
  display_string(string);
5
}

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.

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.