was natürlich nicht geht, weil mit:
draw_bitmap(pgm_read_byte(&bspbmp[0]),0,0);
das erste Inhalts-Byte des Array geliefert wird und nicht die Adresse.
Im Moment sehe ich auch nach langer Suche die Lösung nicht. Hat jemand
einen Tipp, wie ich die Anfangsadresse im Flash ermitteln kann?
Matthias K. schrieb:
> So dachte ich es mir in den Flash zu bekommen:> [c]> // Beispielbitmap> const char bspbmp[] PROGMEM = {0x1F,0x19,0x90,0x60,0xB8,0x6F};>
sweit so gut.
> Im Moment sehe ich auch nach langer Suche die Lösung nicht.
Dabei ist sie so einfach.
> Hat jemand> einen Tipp, wie ich die Anfangsadresse im Flash ermitteln kann?
Die hast du schon. &bspbmp[0] oder ganz einfacher kürzer bspbmp gibt
dir diese Adresse.
Aber DrawBitmap muss den pgm_read_byte benutzen um an die Bytes zu
kommen und nicht der Aufrufer.
Wenn du etwas ins Flash verlagerst, dann muss die Funktion, die die
Daten letztendlich verarbeitet umgeschrieben werden. Die Pointer bleiben
gleich, aber anstelle eines *ptr oder ptr[x] kommt dann
pgm_read_byte(ptr) zum Einsatz.
Und nein. Die Funktion kann anhand des Pointerwertes nicht unterscheiden
ob der Pointer ins SRAM oder ins Flash zeigt. Sie muss dem Aufrufer
trauen, dass er ihr schon den richtigen gibt. Daher ist es Uses, dass
man dies kenntlich macht, indem man an den Funktionsnamen ein _p
anhängt, wenn der übergebene Pointer ein Pointer ins Flash sein soll.
Wenn es sonst keine zwingenden Gründe dafür gibt würde ich das die
ermittlung der Adresse in PROG_MEM nicht ausserhalb von draw_bitmap
machen sondern innerhalb und draw_bitmap einfach nur den Index
übergeben. Um das tatsächliche auslesen aus PROG_MEM in einen Buffer im
RAM kommst Du ja sowieso nicht drumrum.
Wenn es aber so sein muss, ich habe das noch nie machen müssen, ist es
notwendig ausserhalb die Daten in einen RAM-Buffer auszulesen und diesen
Zeiger dann an draw_bitmap zu übergeben.
Klar?
Karl heinz Buchegger schrieb:
> Aber DrawBitmap muss den pgm_read_byte benutzen um an die Bytes zu> kommen und nicht der Aufrufer.
Das wollte ich ersparen, weil es noch weitere Arrays gibt und ich die
Funktion universell halten würde.
So bleibt wahrscheinlich nur die Variante von Grrrr mit einen
RAM-Buffer, wo das jeweilige Array vorher reinkopiert wird.
Matthias K. schrieb:
> So bleibt wahrscheinlich nur die Variante von Grrrr mit einen> RAM-Buffer, wo das jeweilige Array vorher reinkopiert wird.
Nicht ganz. Karl Heinz hat ja auch diese Alternative genannt:
Grrrr schrieb:
> Den Zeigerwert selbst kann man natürlich auch> übergeben, wenn pgm_read_byte innerhalb von draw_bitmap verwendet wird.
>Das wollte ich ersparen, weil es noch weitere Arrays gibt und ich die>Funktion universell halten würde.
Das ist aber die einzige sinnvolle Lösung. Von allen Funktionen, die
sowohl auf SRAM, als auch auf Flash-Daten arbeiten, wirst du zwei
Versionen anlegen müssen. Gerade bei Grafik- und Textfunktionen kommt
man da nicht drumrum. Das klingt zwar zunächst nach viel Aufwand, ist es
aber meistens gar nicht.
>So bleibt wahrscheinlich nur die Variante von Grrrr mit einen>RAM-Buffer, wo das jeweilige Array vorher reinkopiert wird.
Was allerdings wegen knappem Speicher nicht immer geht.
Oliver
Grrrr schrieb:
> Nicht ganz. Karl Heinz hat ja auch diese Alternative genannt:
Die habe noch nicht ganz verstanden. Aber mit der RAM-Buffer-Variante
kann ich im konkreten Fall leben.
Warum gibts bei GCC eigentlich nicht die Pointer-Typen, wie bei den C
8051-Versionen (SDCC/Keil usw.), also Festlegung der Speicherziele durch
XDATA oder CODE und die damit verbundene eindeutige Zuordnung der
Pointer, die dann natürlich 3 Byte lang wären? Die
AVR-Harward-Architektur würde das doch hergeben.
Ich ärgere mich jedes mal über die vermurkste Lösung.
Matthias K. schrieb:
>> Nicht ganz. Karl Heinz hat ja auch diese Alternative genannt:>>>> Die habe noch nicht ganz verstanden.
Die Lösung ist die, wie sie auch in der avrlibc, und fast überall
woanders genutzt wird.
Du brauchst zwei Varianten jeder Funktion, einmal eine für Daten im
Sram, und einmal eine für Daten im Flash.
Beispiel:
printf
printf_P
>Warum gibts bei GCC eigentlich nicht die Pointer-Typen, wie bei den C>8051-Versionen (SDCC/Keil usw.),
Vewrmutlich, weil gcc sich strikt an den C-Standard hält, und solche
"Erweiterungen" darin nicht vorgesehen sind.
>Ich ärgere mich jedes mal über die vermurkste Lösung.
Wenn man die erst einmal verstanden hat, ist es gar nicht so schlimm.
Oliver
Matthias K. schrieb:
> Grrrr schrieb:>> Nicht ganz. Karl Heinz hat ja auch diese Alternative genannt:>> Die habe noch nicht ganz verstanden. Aber mit der RAM-Buffer-Variante> kann ich im konkreten Fall leben.
BIst du dir da sicher?
Gerade bei Graphikfunktionen möchte man soviel Speed wie man nur kriegen
kann. Die RAM-Buffer Variante verdoppelt die Draw Zeit mit einem Schlag
:-)
> Warum gibts bei GCC eigentlich nicht die Pointer-Typen, wie bei den C> 8051-Versionen (SDCC/Keil usw.), also Festlegung der Speicherziele durch> XDATA oder CODE und die damit verbundene eindeutige Zuordnung der> Pointer, die dann natürlich 3 Byte lang wären?
Eben weil sie dann 3 Bytes lang wären. (Speicherverbrauch)
Zuzüglich muss dann bei jedem Zugriff über den Pointer extra noch einmal
unterschieden werden, wohin der Pointer zeigt.
Ein simlpes *ptr wird dann für das Programm zur Abfrageorgie
> Die> AVR-Harward-Architektur würde das doch hergeben.>> Ich ärgere mich jedes mal über die vermurkste Lösung.
Ganz im Gegenteil.
Du kannst ja zb deiner DrawBitmap Funktion noch einen Parameter mehr
mitgeben (das 3-te Byte des Pointers) der DrawBitmap darüber aufklärt,
ob das ein Flash oder ein SRAM Pointer ist. Dann siehst du am eigenen
Leib, was der Compiler bei dieser automatischen Unterscheidung im
Verborgenen treiben muss, nur damit du dir 5 Sekunden nachdenken und ein
wenig buchführen, was wo im Speicher liegt, ersparst.
>BIst du dir da sicher?
Ja, Zeit ist nicht kritisch im konkreten Fall.
>Eben weil sie dann 3 Bytes lang wären. (Speicherverbrauch)
Dürfte kaum ins Gewicht fallen, wenn man bedenkt, was das momentane
PROGMEM-Handling verschlingt, mit Sicherheit mehr als ein Byte.
Matthias K. schrieb:
> Dürfte kaum ins Gewicht fallen, wenn man bedenkt, was das momentane> PROGMEM-Handling verschlingt, mit Sicherheit mehr als ein Byte.
Das ist ein Trugschluss, denn das eigentliche Handling, nämlich das
laden der Daten mittels LPM, initialisierung von Z (ggf. RAMPZ) und
umspeichern von R0 und R1 (oder was immer) muss ja auf jeden Fall getan
werden. Ob in Deinem Programmtext nun das Wort PROG_MEM auftaucht oder
nicht ist da egal.
Grrrr schrieb:
> Karl heinz Buchegger schrieb:>> nachdenken>> Das ist wieder so ein ominöses Metaprogramm von Dir, oder? :-)
LOL
Aber es wirkt :-)
Ich skizziere mal
Was der Keil kann, können wir auch. Noch ein bischen Makro Magic
drüberstreuen, damit die Definitionen der Bitmaps ein wenig anders
aussehen und die 'Erweiterte Pointervariable' gleich mitanlegen.
Ich hab mich jetzt, aus Speed Gründen (und da sind wir dann sogar besser
als der Keil) dazu entschieden 2 getrennte Funktionen zu machen. Aber
natürlich könnte man die Unterscheidung beim Zugriff auch in die draw
Funktion selber reinpacken. Oder die draw_bitmap_p lädt die Bitmap
zuerst ins SRAM und ruft dann die draw_bitmap_s auf oder ...
Die Info dazu ist ja jetzt da :-)
Matthias K. schrieb:
>>BIst du dir da sicher?> Ja, Zeit ist nicht kritisch im konkreten Fall.>>>Eben weil sie dann 3 Bytes lang wären. (Speicherverbrauch)> Dürfte kaum ins Gewicht fallen, wenn man bedenkt, was das momentane> PROGMEM-Handling verschlingt, mit Sicherheit mehr als ein Byte.
Du vergisst:
Wenns was vernünftiges sein soll, dann ist JEDER Pointer 3 Bytes gross!
Zudem sind das 3 Bytes im SRAM anstelle von 2. Ein Array von 100 Pointer
auf Strings braucht dann 300 Bytes anstelle von 200!
Die pgm_read_byte Funktion liegt aber im Flash. Die paar Bytes, die
diese Funktion braucht, stören nicht weiter. Flash hast du genug. Aber
SRAM hast du keines.
Karl heinz Buchegger schrieb:
> Ich skizziere mal
Danke Dir für Deine Mühe und Aufwand. Ich probiere es morgen mal aus.
Bei KEIL wäre die einzige Änderung das Wörtchen CODE gewesen;-) und alle
Pointer würden automatisch stimmen.
Karl heinz Buchegger schrieb:
> Wenns was vernünftiges sein soll dann ist JEDER Pointer 3 Bytes gross
Andernfalls müsstest Du irgendeinen anderen Qualifier für lange
Zeigertypen erfinden. Und voila wieder bist Du bei PROGMEM und
address_xxxx.
Matthias K. schrieb:
> Karl heinz Buchegger schrieb:>> Ich skizziere mal>> Danke Dir für Deine Mühe und Aufwand. Ich probiere es morgen mal aus.>> Bei KEIL wäre die einzige Änderung das Wörtchen CODE gewesen;-) und alle> Pointer würden automatisch stimmen.
Ganz ehrlich:
Dann nimm doch deinen Keil.
Ich glaub du hast immer noch nicht verstanden, dass du dir diesen
Komfort teuer erkaufen musstest.
Sowohl durch Speicher als auch durch Laufzeit. Und das ist so ziemlich
die schlimmste Konstellation, die du antreffen kannst. "Space for Time"
ist ok. "Time for Space" ist auch ok. Aber "Space AND Time for the
programmers comfort" ist nicht akzeptabel.
Oder findest du es ok, wenn Audi die Handbremse ständig angezogen lässt,
damit du aus Komfortgründen am Berg nicht daran denken musst, sie
anzuziehen.
Matthias K. schrieb:
> Bei KEIL wäre die einzige Änderung das Wörtchen CODE gewesen;-) und alle> Pointer würden automatisch stimmen.
Sag ich doch. Na gut, der ruft dann noch read_prog_mem für Dich auf.
Schnick Schnack.
Grrrr schrieb:
> Den Zeigerwert selbst kann man natürlich auch> übergeben, wenn pgm_read_byte innerhalb von draw_bitmap verwendet wird.
Die Verlagerung von pgm_read_byte(....
direkt in die draw_bitmap Funktion hat das gewünschte Ergebnis gebracht.
Danke