Forum: Mikrocontroller und Digitale Elektronik PROGMEM Problem


von Electronics'nStuff (Gast)


Lesenswert?

Hallo Zusammen!

Ich habe in meinem Programm in einem Header ein ca. 6kbyte Array 
gespeichert.
Direkt ins Flash also so:

const uint8_t rawData[7668] PROGMEM = {...}

In meinem main will ich nun verschiedene Werte abfragen, was sich etwas 
schwierig gestaltet.

Wenn ich nun rawData[1] verwende, so kann ich diesen Wert auslesen.
Wenn ich z.B. rawData[x] verwende und x in meinem Hauptprogramm 
deklariere (globale Variable), so funktioniert der Zugriff nicht.

Wenn ich in meinem Header diese Zeile einfüge:

prog_uint16_t x = 0;

Dann funktioniert zwar der Zugriff aus dem Main, allerdings hat ein x++, 
Beispielsweise kein Ereignis zur Folge.

Was mich also interessieren würde, wie kann ich eine Variable, die im 
Flash gespeichert ist überschreiben?

Ich hoffe das Problem ist verständlich erklärt.

Gruss

von Thomas E. (thomase)


Lesenswert?

Electronics'nStuff schrieb:
> Was mich also interessieren würde, wie kann ich eine Variable, die im
> Flash gespeichert ist überschreiben?
Gar nicht.
ROM = Read Only Memory.

mfg.

von Wusel D. (stefanfrings_de)


Lesenswert?

> prog_uint16_t x = 0;
> Dann funktioniert zwar der Zugriff aus dem Main, allerdings hat ein x++,
> Beispielsweise kein Ereignis zur Folge.

Ist ja logisch, ein Pointer im Programm Speicher ist read-only.

b=rawData[x] Addiert x zum Pointer auf rawdata. Dann wird die RAM(!) 
Zelle gelesen, auf die der Pointer Zeigt. Die Daten liegen aber gar 
nicht im RAM.

Lies Dir mal diese Seite durch: 
http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html

Für den Zugriff auf dem Programmspeicher brauchst Du die dort 
beschriebenen Funktionen.

von Quatschkopf (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> Electronics'nStuff schrieb:
>> Was mich also interessieren würde, wie kann ich eine Variable, die im
>> Flash gespeichert ist überschreiben?
> Gar nicht.
> ROM = Read Only Memory.
>
> mfg.

Das ist nicht richtig.

---

Schau' im Datenblatt deines Controllers in das Kapitel "Flash 
Programming". Bei einigen Controllermn ist es möglich aus der Anwendung 
den Flashspeicher zu verändern. Ist aber nur sinnvoll für seltene 
Änderungen, da der Flash-Speicher z. B. nur 10.000 mal neu beschrieben 
werden kann.

von Electronics'nStuff (Gast)


Lesenswert?

Hmm..

Also wenn ich das so habe:

const uint8_t rawData[7668] PROGMEM = {..};

uint16_t y = 0;
uint16_t x = 0;

spalte1[x] =pgm_read_word(rawData[y]);

Dann bekomme ich in spalte1[x] eig. nur Schrott.
Wie muss ich die Variable y deklarieren? Mit dem ROM habt ihr natürlich 
recht, aber wohin kommt die dann?

Gruss

von Electronics'nStuff (Gast)


Lesenswert?

EDIT:

sollte natürlich heissen:

spalte1[x] =pgm_read_byte(rawData[y]);

von Quatschkopf (Gast)


Lesenswert?

Electronics'nStuff schrieb:
> EDIT:
>
> sollte natürlich heissen:
>
> spalte1[x] =pgm_read_byte(rawData[y]);

spalte1[x] =pgm_read_byte(rawData + y);

von J.-u. G. (juwe)


Lesenswert?

Electronics'nStuff schrieb:
> spalte1[x] =pgm_read_byte(rawData[y]);

pgm_read_byte braucht eine Adresse:
1
spalte1[x] =pgm_read_byte(&rawData[y])

Bitte nochmal das hier:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmspeicher_.28Flash.29
durcharbeiten.

von Electronics'nStuff (Gast)


Lesenswert?

Quatschkopf schrieb:
> spalte1[x] =pgm_read_byte(rawData + y);

Wow, super, danke!
Ehrlich gesagt habe ich aber keine Ahnung was das für ein Unterschied 
macht?

Kann ich das irgendwo nachlesen? Diese Schreibweise habe ich nämlich 
noch nie gesehen.

Gruss & nochmals Danke!

von Karl H. (kbuchegg)


Lesenswert?

Electronics'nStuff schrieb:
> Quatschkopf schrieb:
>> spalte1[x] =pgm_read_byte(rawData + y);
>
> Wow, super, danke!
> Ehrlich gesagt habe ich aber keine Ahnung was das für ein Unterschied
> macht?
>
> Kann ich das irgendwo nachlesen?

In jedem noch so grindigem C-Buch

von Mac (Gast)


Lesenswert?

Electronics'nStuff schrieb:
> Quatschkopf schrieb:
>> spalte1[x] =pgm_read_byte(rawData + y);

> Kann ich das irgendwo nachlesen? Diese Schreibweise habe ich nämlich
> noch nie gesehen.

Dann wird's aber Zeit. Das heisst Pointerarithmetik.

von Thomas E. (thomase)


Lesenswert?

Quatschkopf schrieb:
> Das ist nicht richtig.
Das ist zu 100% richtig.
Das ist und bleibt ein ROM. Völlig unabhängig davon, ob man das mit 
irgendeinem Verfahren löschen und neu beschreiben kann.
Funktioniert das: i++? Nein. Also Nur Lesen.

mfg.

von Karl H. (kbuchegg)


Lesenswert?

Electronics'nStuff schrieb:
> Quatschkopf schrieb:
>> spalte1[x] =pgm_read_byte(rawData + y);
>
> Wow, super, danke!
> Ehrlich gesagt habe ich aber keine Ahnung was das für ein Unterschied
> macht?

der Name eines Arrays für sich alleine steht für seine Startadresse.
D.h. du nimmst

     rawData                die Startadresse von rawData im Speicher
     rawData + y            und zählst da noch dazu, wieviele Array-
                            Elemente die Adresse weiter gesetzt werden
                            soll


-> Ergebnis: du hast die Speicheradresse an der das y-te Element von 
rawData gespeichert ist.

Und diese Adresse übergibst du an pgm_read_byte, welches das dort 
gespeicherte Byte besorgt und liefert.



Die Indexoperation ist in C so definiert


     a[i]  <==>  *( a  + i )

d.h. das unterscheidet sich nur dadurch, dass nach der Adressberechnung 
durch den * dann auch gleich noch der Wert geholt wird. Was ja auch 
sinnvoll ist, in

    j = a[i];

denn da will man ja den Wert haben und in j speichern.

Nur bei dir geht das natürlich nicht, weil ja der * den Wert aus dem 
SRAM holen würde, deine Daten aber nicht im SRAM sind sondern im Flash. 
D.h. du musst die ganze Operation

   j = a[i];

2-teilen. Da
    a[i]
identisch ist zu
    *(a+i)

und du den * durch einen Aufruf der Funktion pgm_read_byte ersetzen 
musst, ergibt sich ganz zwanglos

    j = pgm_read_byte( a + i );

Das pgm_read_byte übernimmt ganz einfach den Part der Dereferenzierung.

Alternativ hätte man auch

    j = pgm_read_byte( &a[i] );

schreiben könnnen. Wenn man das auflöst, dann zeigt sich, dass auch das 
wieder auf dasselbe hinausläuft, denn & und * sind komplementäre 
Operationen. Ein

       &(*(a+i))

ist dasselbe wie a+i


Wie gesagt: In jedem noch so grindigem C-Buch, wenn es um Arrays geht 
und wie die intern behandelt werden. Das ist nämlich wichtig, weil es 
auch reinspielt, wie eigentlich Arrays an Funktionen übergeben werden. 
Und natürlich hängt damit aufs Engste auch das ganze Kapitel 
Pointerarithmetik zusammen.

wenn dir also bei

   const uint8_t a[20] PROGMEM = {...}

   j = pgm_read_byte( a + i );

nicht auf Anhieb klar ist, was bei den Funtkionsargumenten passiert, 
dann hast du ein enormes Defizit in deinem C-Sprachverständnis. Und das 
musst du beheben! Mit dem Durcharbeiten eines C-Buchs.

von Quatschkopf (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> Quatschkopf schrieb:
>> Das ist nicht richtig.
> Das ist zu 100% richtig.
> Das ist und bleibt ein ROM. Völlig unabhängig davon, ob man das mit
> irgendeinem Verfahren löschen und neu beschreiben kann.
> Funktioniert das: i++? Nein. Also Nur Lesen.
>
> mfg.

Du hast geschrieben: Zitat (siehe 
Beitrag "Re: PROGMEM Problem"):

"Gar nicht."

Und das ist falsch!

von Karl H. (kbuchegg)


Lesenswert?

Quatschkopf schrieb:
> Du hast geschrieben: Zitat (siehe
> Beitrag "Re: PROGMEM Problem"):
>
> "Gar nicht."
>
> Und das ist falsch!

Man kann auf fast allem solange auf Details rumreiten, bis die Erklärung 
niemandem mehr hilft.
Für seine Zwecke, in seinem Programm, ist das Flash ein ROM und nicht 
beschreibbar.

Lies dir mal das durch und sieh dir das Video an.
http://scienceblogs.de/astrodicticum-simplex/2013/03/02/die-tyrannei-der-prazession-behindert-die-wissenschaftskommunikation/
In vielen, wenn nicht den meisten Fällen, ist einem Schüler mehr 
geholfen, wenn man erst mal mit einer vereinfachten Sicht der Dinge an 
das Problem rangeht. Selbst dann, wenn das nicht 100% präzise ist.

von Electronics'nStuff (Gast)


Lesenswert?

@ Karl Heinz, vielen Dank für deine sehr ausführliche Erklärung!

Karl Heinz Buchegger schrieb:
> a[i]  <==>  *( a  + i )

Karl Heinz Buchegger schrieb:
> rawData                die Startadresse von rawData im Speicher

Das sind die zwei Dinge, die ich einfach nicht wusste.


Gruss

von Thomas E. (thomase)


Lesenswert?

Quatschkopf schrieb:
> Und das ist falsch!
Ich habe dir doch schon mitgeteilt, daß es zu 100% richtig ist.

Man kann im Flash keine Variablen überschreiben, sondern nur im RAM.
1. gibt es im Flash keine Variablen
2. muss die Speicherstelle erst gelöscht werden und kann dann neu 
beschrieben werden.

Du versuchst hier Zusammenhänge herzustellen, die einfach nicht 
existieren.

mfg.

von Quatschkopf (Gast)


Lesenswert?

Sorry Thomas, habe oben eine Zeile in einem deiner Beiträge überlesen.

von Karl H. (kbuchegg)


Lesenswert?

Electronics'nStuff schrieb:
> @ Karl Heinz, vielen Dank für deine sehr ausführliche Erklärung!
>
> Karl Heinz Buchegger schrieb:
>> a[i]  <==>  *( a  + i )
>
> Karl Heinz Buchegger schrieb:
>> rawData                die Startadresse von rawData im Speicher
>
> Das sind die zwei Dinge, die ich einfach nicht wusste.

Und genau das musst du abstellen.

Denn das erste ist der Grund dafür, warum man in C schreiben kann
1
   int* a = malloc( anzahl * sizeof(int) );
2
3
   a[i] = 5;       // a[i] <--> *(a+i)   a ist ein Pointer
4
                   //                    der Rest ist Pointerarithmetik (+)
5
                   //                    bzw. Dereferenzierung (*)
und das zweite ist der Grund dafür, warum
1
void foo( int* k )
2
{
3
  k[0] = 8;
4
}
5
6
int main()
7
{
8
  int a[5];
9
10
  foo( a );   // a ist die Startadresse des Arrays
11
              //   und foo will eine Adresse haben - passt also
12
}
genau so funktioniert, wie es funktioniert.
Das sind also ziemliche Basis-Dinge in C, sobald man mit Arrays 
arbeitet.

von Electronics'nStuff (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Das sind also ziemliche Basis-Dinge in C, sobald man mit Arrays arbeitet.

Ich muss zugeben, ich habe Arrays bis jetzt nur sehr oberflächlich 
benutzt und noch nie für grössere Datenmengen.

Bis jetzt habe ich sie eig. ausschliesslich für Ausmaskierungen etc. 
verwendet. Also zwei, drei Werte und gut ist.

Ein gutes Buch wäre allerdings bestimmt nicht verkehrt!

von Karl H. (kbuchegg)


Lesenswert?

Electronics'nStuff schrieb:

> Ein gutes Buch wäre allerdings bestimmt nicht verkehrt!

Allerdings.
Denn das ist nur die Spitze des Eisbergs (wenn auch ein sehr wichtiger). 
Da wartet noch vieles darauf entdeckt zu werden.

von Electronics'nStuff (Gast)


Lesenswert?

Ist es korrekt, dass der Zugriff auf's Flash vehältnismässig eeeewig 
dauert?

von Falk B. (falk)


Lesenswert?

@  Electronics'nStuff (Gast)

>Ist es korrekt, dass der Zugriff auf's Flash vehältnismässig eeeewig
>dauert?

Nö. Beim Lesen 3 Takte, RAM-Zugriffe brauchen 2.
Schreiben dauert natürlich eher lang, im Bereich von einigen 
Millisekunden pro Page.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Nö. Da im Flash auch das Programm liegt, wird darauf mit voller 
Prozessorgeschwindigkeit zugegriffen. Die avrlib Routinen (z.B. 
'pgm_read_byte()') dauern ein klein wenig, aber kannste eigentlich 
vergessen. EEPROM ist eigentlich das langsamste wegen der ganzen 
Registervorbereitung.

von Electronics'nStuff (Gast)


Lesenswert?

Ob es wohl sonst einen Grund gibt, dass:
1
 int result; 
2
 result = spalte_nr/2;
3
 y = y + result;
4
    
5
  while (spalte_position < 60)
6
  { 
7
     if(result*2 != spalte_nr) //ungerade zahlen
8
     {
9
        zifferh = (pgm_read_byte(rawData + y)) % 16;
10
  spalte[spalte_position] = zifferh;
11
     }
12
13
     if (result*2 == spalte_nr) //gerade zahlen 
14
     {
15
    spalte[spalte_position] = ((pgm_read_byte(rawData + y))-(zifferh)) /16;
16
     }      
17
18
      spalte_position++;
19
      y = y +128;
20
  }  
21
    
22
  spalte_position= 0;

knapp 220µs dauert bei einer Taktrate von 8Mhz?

von Falk B. (falk)


Lesenswert?

@  Electronics'nStuff (Gast)

>knapp 220µs dauert bei einer Taktrate von 8Mhz?

Messfehler? DIV 8 Fuse gesetzt? AVR Fuses falsch eingestellt?

von Falk B. (falk)


Lesenswert?

@  Matthias Sch. (Firma: Matzetronics) (mschoeldgen)

>Prozessorgeschwindigkeit zugegriffen. Die avrlib Routinen (z.B.
>'pgm_read_byte()') dauern ein klein wenig,

Nö, das sind schon lange INLINE Funktionen.

von Electronics'nStuff (Gast)


Lesenswert?

Falk Brunner schrieb:
> Messfehler? DIV 8 Fuse gesetzt? AVR Fuses falsch eingestellt?

DIV 8 kann ich definitiv ausschliessen. Ist zwar der interne Oszillator 
aber der sollte ja wohl trotzdem so um die 8MHz haben.

Messfehler?

Hmm.. habe einfach einen Pin getoggelt am Anfang und am Ende des 
Programms.. mit DSO gemessen (das ist eig. ziemlich genau sonst).

Gruss

von Falk B. (falk)


Lesenswert?

@  Electronics'nStuff (Gast)

>Hmm.. habe einfach einen Pin getoggelt am Anfang und am Ende des
>Programms..

Togglen kann schief gehen, dann misst man Mist. Du must definert am 
Anfang setzen und am Ende löschen.

von Falk B. (falk)


Lesenswert?

Ach so, Optimierungstufe ist beim Compiler eingeschaltet? Normalerweise 
-Os.

von Electronics'nStuff (Gast)


Lesenswert?

Jo, ist eingestellt.

Das Array aus dem Flash habe ich über einen Header eingebunden, das 
sollte eig. keinen Einfluss haben nehme ich an?

von Harun (Gast)


Lesenswert?

> knapp 220µs dauert bei einer Taktrate von 8Mhz?

Welchen Wert hat "spalte_position"?

von Thomas E. (thomase)


Lesenswert?

Electronics'nStuff schrieb:
> Das Array aus dem Flash habe ich über einen Header eingebunden, das
> sollte eig. keinen Einfluss haben nehme ich an?
Das ist egal.

Electronics'nStuff schrieb:
> knapp 220µs dauert bei einer Taktrate von 8Mhz?
Für die ganze Schleife?
Ein Durchlauf ca. 30 Takte. Finde ich bei der Rechnerei da drin nicht so 
erstaunlich.

mfg.

von Electronics'nStuff (Gast)


Lesenswert?

Harun schrieb:
> Welchen Wert hat "spalte_position"?

Wird von 0-60 heraufgezählt also ein 60 Durchläufe.

Thomas Eckmann schrieb:
> Ein Durchlauf ca. 30 Takte. Finde ich bei der Rechnerei da drin nicht so
> erstaunlich.

Dauert die echt so lange?
Gibt es da noch was einfacheres?

Ich will z.B. aus 0xBE zwei Variabeln kreieren -> 0x0B und 0x0E.
Funktioniert auf diese Weise ohne Probleme aber geht es auch einfacher?

Gruss

von Harun (Gast)


Lesenswert?

> Wird von 0-60 heraufgezählt also ein 60 Durchläufe.

Kein Wunder.

> Gibt es da noch was einfacheres?

Da ungerade & gerade immer nacheinander folgen: Ja.

von Electronics'nStuff (Gast)


Lesenswert?

Harun schrieb:
> Da ungerade & gerade immer nacheinander folgen: Ja.

Tut mir leid, daraus werde ich nicht ganz schlau?

von Thomas E. (thomase)


Lesenswert?

Electronics'nStuff schrieb:
> Dauert die echt so lange?
Das ist das, was du gemessen hast.

Electronics'nStuff schrieb:
> Ich will z.B. aus 0xBE zwei Variabeln kreieren -> 0x0B und 0x0E.
Das verstehe ich jetzt nicht so ganz.

mfg.

von Electronics'nStuff (Gast)


Lesenswert?

Naja.. ich habe in meinem Array (rawData) lauter 8-Bit "Worte" in hex 
gespeichert.

Also irgendwie 0x45, 0xBE, 0x75 etc.. ich möchte diese nun umwandeln.
Im Array spalte[] sollen die gleichen Werte vorkommen, allerdings 
"aufgeteilt".

Also so: 0x45 -> 0x04 und 0x05
         0xBE -> 0x0B und 0x0E
         0x75 -> 0x07 und 0x05

Ich will quasi die 8-Bit Worte einfach auftrennen und dann in meinem 
Array unterbringen.

Gruss

von Thomas E. (thomase)


Lesenswert?

Electronics'nStuff schrieb:
> Ich will quasi die 8-Bit Worte einfach auftrennen und dann in meinem
> Array unterbringen.

Also aus rawdata[0] = 0x45

soll spalte[0] = 0x04 und spalte[1] = 0x05 werden?

mfg.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Electronics'nStuff schrieb:
> Ich will quasi die 8-Bit Worte einfach auftrennen und dann in meinem
> Array unterbringen.
Dafür hast du dieses Monster PROGMEM aufgezogen? Glaub ich jetzt mal 
nicht.
1
spalte[0] = (rawdata[0] >> 4) & 0x0f;
2
spalte[1] = rawdata[0] & 0x0f;

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.