PROGMEM Problem

Gast #3097494
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
#3097506
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.
Gast #3097515
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.
Gast #3097519
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
#3097556
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.
Gast #3097564
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!
#3097570
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.
#3097579
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.
#3097601
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.
Gast #3097608
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!
(Firma: matzetronics) #3098138
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.
Gast #3098143
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?
Gast #3098159
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
Gast #3098214
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
Gast #3098257
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren