Forum: Compiler & IDEs strings aus dem programmspeicher von AVRs lesen


von miro (Gast)


Lesenswert?

Hallo,
ich will eine "bitmap" aus dem Flashspeicher in einen LCD-buffer 
übertragen. Dazu habe ich die Funktion pgm_to_buf() geschrieben:
1
void pgm_to_buf (const prog_uchar * string_table[]) {
2
  uint8_t page,;
3
  for (page = 0; page < 8; page++)
4
    memcpy_P(lcd_data[page], (prog_void *)pgm_read_word(&(string_table[page])), 128);
5
}
in main() wird die so aufgerufen:
1
pgm_to_buf (lcd_frame);
Die "bitmap" ist ein array mit pointern auf strings, beides ist im Flash 
gespeichert:
1
const unsigned char p1_lcd_frame[] PROGMEM = \
2
  {201,205,205,205,205,205,205,203,205,205,205,205,205,205,205,187,'\0'};
3
const unsigned char p2_lcd_frame[] PROGMEM = \
4
  {186, 32, 32, 32, 32, 32, 32,186, 32, 32, 32, 32, 32, 32, 32,186,'\0'};
5
const unsigned char p3_lcd_frame[] PROGMEM = \
6
  {186, 32, 32, 32, 32, 32, 32,186, 32, 32, 32, 32, 32, 32, 32,186,'\0'};
7
const unsigned char p4_lcd_frame[] PROGMEM = \
8
  {186, 32, 32, 32, 32, 32, 32,186, 32, 32, 32, 32, 32, 32, 32,186,'\0'};
9
const unsigned char p5_lcd_frame[] PROGMEM = \
10
  {186,205,205,205,205,205,205,186,205,205,205,205,205,205,205,186,'\0'};
11
const unsigned char p6_lcd_frame[] PROGMEM = \
12
  {186, 32, 32, 32, 32, 32, 32,186, 32, 32, 32, 32, 32, 32, 32,186,'\0'};
13
const unsigned char p7_lcd_frame[] PROGMEM = \
14
  {186, 32, 32, 32, 32, 32, 32,186, 32, 32, 32, 32, 32, 32, 32,186,'\0'};
15
const unsigned char p8_lcd_frame[] PROGMEM = \
16
  {200, 32, 32, 32, 32, 32, 32,202, 32, 32, 32, 32, 32, 32, 32,189,'\0'};
17
const prog_uchar * lcd_frame[] PROGMEM = {
18
  p1_lcd_frame,
19
  p2_lcd_frame,
20
  p3_lcd_frame,
21
  p4_lcd_frame,
22
  p5_lcd_frame,
23
  p6_lcd_frame,
24
  p7_lcd_frame,
25
  p8_lcd_frame
26
};
der LCD-buffer hat denselben Aufbau, befindet sich aber im RAM:
1
unsigned char p1[128];
2
unsigned char p2[128];
3
unsigned char p3[128];
4
unsigned char p4[128];
5
unsigned char p5[128];
6
unsigned char p6[128];
7
unsigned char p7[128];
8
unsigned char p8[128];
9
unsigned char * lcd_data [8] = {p1,p2,p3,p4,p5,p6,p7,p8};
Die ganzen Ansteuerroutinen fürs LCD funktionieren problemlos, zB 
Ausgabe von strings im RAM, aber mit Flash und Pointern habe ich 
irgendwie Probleme :( Weiß vielleicht jemand, wo sich bei mir der Fehler 
versteckt hat?

von Karl H. (kbuchegg)


Lesenswert?

1
    memcpy_P(lcd_data[page], (prog_void *)pgm_read_word(&(string_table[page])), 128);

wieso 128?
Pro Page hast du doch nur 16 Bytes!
1
const unsigned char p1_lcd_frame[] PROGMEM = \
2
  {201,205,205,205,205,205,205,203,205,205,205,205,205,205,205,187,'\0'};


(Eigentlich 17, aber die abschliessende \0 werte ich mal als 'denn sie 
wissen nicht was sie tun')

von miro (Gast)


Lesenswert?

Oh, Entschuldigung, habe vergessen zu erwähnen:
mein LCD hat 8 horizontale "pages", die in 128 vertikale Segmente 
aufgeteilt sind, also nehme ich 8 unsigned char-arrays mit jeweils 128 
bytes und verbinde die in einem pointer array mit 8 pointern.
LCD wird pageweise beschrieben:
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7 usw...

von Karl H. (kbuchegg)


Lesenswert?

miro schrieb:

> aufgeteilt sind, also nehme ich 8 unsigned char-arrays mit jeweils 128
> bytes

????

Jedes deiner Arrays hat aber keine 128 Bytes, sondern nur 16 (17).

>und verbinde die in einem pointer array mit 8 pointern.

das hab ich schon verstanden. Das ist auch in Ordnung so, wie du das 
gemacht hast. Nur eben dass du versuchst Daten durch die Gegend zu 
kopieren, die nicht existieren.


Kann es sein, dass du denkst, dass memcpy_P in einem Array aufhört zu 
kopieren, wenn es auf ein \0 stößt? Dem ist nicht so.

   memcpy_P( ziel, quelle, wieviele_Bytes );

Die Anzahl Bytes wird umkopiert. Egal welcher Byteinhalt.

Es gibt in C 2 Funktionsfamilien, die ähnlich sind. Die str... 
Funktionen und die mem... Funktionen. Die str... Funktionen sind für 
Strings, also Abfolgen von Zeichen, die mit einem \0 beendet werden. Die 
str... Funktionen wissen das und richten sich danach. Den mem.... 
Funktionen hingegen ist es völlig egal, was die Bytes bedeuten. Beim 
Aufruf wird die Anzahl der Bytes angegeben und genau auf dieser Anzahl 
Bytes arbeiten sie. Ungeachtet des Inhalts oder irgendwelcher Bedeutung 
der Bytes.
Dein memcpy_P kopiert 128 Bytes. Und wenn deine Arrays zu Ende sind, 
dann holt sich memcpy_P eben die nächsten Bytes aus dem Flash, was auch 
immer gerade dort steht. Solange bis es 128 Bytes umkopiert hat.


Jetzt erklärt sich plötzlich das ansonsten unverständliche \0 in den 
Arrays und auch die Verwendung des Terminus "String" in deiner 
Überschrift.

von miro (Gast)


Lesenswert?

Problem gelöst,
ich habe übersehen, dass die Bytes zuerst in die entsprechenden Fonts 
konvertiert werden und so natürlich nicht direkt kopiert werden können, 
Entschluldigung für diesen verwirrdenden Beitrag!
MfG miro

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> prog_void

Das kann man sich vorsorglich schon mal abgewöhnen; wird in zukünftigen 
avr-lic-Versionen wahrscheinlich deprecated.  Einfach deshalb, weil 
avr-gcc das nicht unterstützt.

von Falk B. (falk)


Lesenswert?

@Johann L. (gjlayde) Benutzerseite

>> prog_void

>Das kann man sich vorsorglich schon mal abgewöhnen;

Das ist der offizielle Weg für sowas?

MFG
Falk

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
> @Johann L. (gjlayde) Benutzerseite
>
>>> prog_void
>
>>Das kann man sich vorsorglich schon mal abgewöhnen;
>
> Das ist der offizielle Weg für sowas?

Ich versteh die Frage nicht.

Natürlich bin ich nicht Sprecher der avr-libc o.ä.,
und Release-Notes für 1.8.0 finde ich auch keine.

Jedoch ist progmem in einem typedef in avr-gcc nicht
dokumentiert, war es wohl auch nie und funktioniert
mehr oder weniger per Zufall — ungefähr so wie
nicht-dokumentierte Opcodes in einem Prozessorkern.

Der entsprechende Bugreport wurde als WON'T FIX geschlossen.
Erstens gibt es quasi keine avr-gcc Entwickler und die Resourcen
sind sinnvoller in wirklichen Bugs, Optimierungen oder neuen
Features wie Built-Ins investiert anstatt ein was zu implementieren,
das undokumentiert ist, lediglich qua glücklichem Umstand (noch)
funktioniert und keine neue Funktionalität bringt.
progmem in einer Deklaration ist dokumentiert und wird natürlich
auch weiterhin unterstützt.

WON'T FIX bedeutet in dem Falle auch, daß der Compiler keine
Diagnostic ausgibt bei der Verwendung von progmem in typedef.

Zweitens gibt es keinen Grund für progmem in einem Typen.
progmem sagt was über die Ablage, nicht über das Typelayout wie
z.b. packed.

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.