Zugriff auf PROGMEM-Array

Hi,
um RAM zu sparen hab ich ein int-array in den Flash “verbannt”.
Bloss wie kann ich jetzt aus meiner Funktion darauf zugreifen?

Da steh ich jetzt aber voll auf dem Schlauch.

Hier dazu der entsprechende Code

Ohne PROGMEN läuft er einwandfrei. Mit PROGMEM bekomme ich keine Daten

    const int Code17[] PROGMEM ={
    135,57,17,16,17,51,17,16,17,16,17,16,17,16,17,16,17,16,17,16,
    17,16,17,16,17,16,17,16,17,51,17,16,17,16,17,16,17,16,17,16,
    17,16,17,16,17,51,17,51,17,51,17,16,17,16,17,51,17,16,17,16,
    ....}

void SendPanasonic17b() {
  Serial.println("SendPanasonic17b");  
    for(int x=0; x <= 133; x=x+2) {
        pulseIR(Code17[x]*26);           
        delayMicroseconds(Code17[x+1]*26); 
    } 
}

gruß/hk007

Das hatten wir doch schon ein paar mal :slight_smile:

Du kannst nicht direkt darauf zugreifen, sondern brauchst bestimmte Makros um die Daten aus dem Flash auszulesen:
pgm_read_byte() → byte
pgm_read_word() → int oder Zeiger
pgm_read_dword() → long
pgm_read_float() → float

Denen übergibt man die Adresse im RAM und bekommt die Daten zurück.

pulseIR(pgm_read_word(&Code17[x]) * 26);

Wichtig ist das &. Du musst die Adresse übergeben. Nicht die Daten.

Alternativ mit Zeigerarithmetik:

pulseIR(pgm_read_word(Code17 + x) * 26);

Hi Serenifly,

du bist wieder meine Rettung.

Serenifly:
Das hatten wir doch schon ein paar mal :slight_smile:

Aber du hast recht. Letzes mal waren es Strings. Dachte mit Integer geht das ganz anders.
Das werd ich wohl nie so richtig verinnerlichen (Schäm)

Mit deinen Infos hab ich auch jetzt die PROGMEM-Referenz gefunden.

Noch zwei Fragen:
A.)
Gibts da einen Unterschied: pgm_read_word() <-> pgm_read_word_near()
B.)

As mentioned above, it is important to use the datatypes outlined in pgmspace.h.

Also besser so definieren?

    const prog_uint16_t Code17[] PROGMEM ={
    135,57,17,16,17,51,17,16,17,16,17,16,17,16,17,16,17,16,17,16,

hk007:
Aber du hast recht. Letzes mal waren es Strings. Dachte mit Integer geht das ganz anders.

Das ist genau das gleiche. Bei Strings hat man auch nur Bytes. Lediglich bei Arrays aus Strings wird es etwas komplizierter.

Gibts da einen Unterschied: pgm_read_word() <-> pgm_read_word_near()

Nein. pgm_read_word() ist lediglich ein Makro für pgm_read_word_near(). Das wird deutlich wenn man andere IDEs wie Visual Studio verwendet, die einem anzeigen zu was die Makros expandiert werden.

Der Unterschied zwischen near und far ist nur relevant wenn man Flash Daten über die 64kB Grenze schreibt. Dann wird es wirklich kompliziert, da ein 16-Bit Zeiger nur 32 64k adressieren kann und man noch ein paar extra Tricks braucht um das zu umgehen.

As mentioned above, it is important to use the datatypes outlined in pgmspace.h.

Das ist veraltet und wird von von avr-gcc eigentlich nicht unterstützt:
http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html#gaa475b6b81fd8b34de45695da1da523b6

Bei der nicht-BETA Arduino IDE sind antike Versionen des Compilers und der avr libc dabei. In der aktuellen Version (die in 1.5.7. BETA dabei ist) ist das deprecated und man muss die Daten const deklarieren. Anders als in der Referenz gesagt wird, funktioniert const + normaler Datentyp aber genauso in der alten Version.

Serenifly:
Der Unterschied zwischen near und far ist nur relevant wenn man Flash Daten über die 64kB Grenze schreibt. Dann wird es wirklich kompliziert, da ein 16-Bit Zeiger nur 32 64k adressieren kann und man noch ein paar extra Tricks braucht um das zu umgehen.

Das heisst, ich kann eine Software mit PROGMEM-Elementen vom Uno nicht auf dem Mega verwenden? 32K Flash <-> 256k Flash
Oder kümmert sich da der Compiler drum?

Doch, das geht klar. Sonst würden viele Libs nicht auf dem Mega laufen. Wenn du weniger als 64k Flash Daten hast geht es genauso. Keine Änderung nötig. :) Und mit "Flash Daten" meine ich wirklich Arrays die du explizit im Flash ablegst. Nicht das ganze Programm!

Wenn es mehr als 64k sind (was sehr selten ist und was du wahrscheinlich nie machen wirst), muss man wie gesagt etwas mehr Aufwand betreiben: http://forum.arduino.cc/index.php?topic=174084.msg1294539#msg1294539

Man braucht dann noch ein Assembler Makro um die Far-Adressse zu berechnen. Man muss die Arrays in bestimmte Daten-Sektionen schreiben, und man muss die Far-Versionen der pgm_read_xxx Makros verwenden. Und bei den Flash Funktionen gehen die _P Versionen nicht mehr (z.B. für memcpy(), strcpy() und ähnliches), da die keine Far Pointer verarbeiten können.

Anmerkung zu letzterem: jurs sagt in dem Post, dass die _PF Versionen (die mit Far Pointern umgehen können) nicht vorhanden sind obwohl sie in der Doku aufgelistet sind. Das liegt auch an der antiken avr libc die in der Arduino IDE dabei ist. Mit 1.5.7. BETA geht das alles. :)

Aber das Prinzip ist genau das gleiche wie bei PROGMEM. Man hat lediglich andere Makros und Funktionen und durch die Far Pointer eine weitere Zwischenstufe bei den Adressen.

Ach so, da gehts um die Größe des PROGMEM-Blocks. Ich dachte es geht um die Größe des Flash.

Deren Größe und deren Lage im Flash. Man kann theoretisch auch kleine Blöcke in den far Bereich schreiben. Das bringt nur nichts.

Das ist alles etwas weit ausgeholt und die wirst es wahrscheinlich nie brauchen. Aber ich wollte erklären weshalb es überhaupt das "near" gibt. :)