mikrocontroller.net

Forum: Compiler & IDEs Riesiges Array im Flash


Autor: Stefan H. (schnufff)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

für ein Verschlüsselungsverfahren muss ich riesige Matrizen speichern.
Wenn ich versuche sie per:
const uint8_t matrix[] PROGMEM={0x11,0x22,...,0x11};
in den Flash legenzu lassen, bekomme ich immer den Fehler:
"Größe der Variablen "matrix" ist zu hoch."
Ich benutze einen atmega128 und die matrix ist 81Kbyte( ja 81*1024 
bytes)
gross, sollte also in den Flash passen.

G++gle und Forumssuche hat leider nicht erbracht.
Was läuft da schief?

Danke
Stefan

Autor: ich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wahrscheinlich is das einfach zu groß;)

versuch doch mal die große matrix in 4 kleine aufzuteilen etc?!

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der avr-gcc adressiert Arrays über 16-bit-Pointer, damit ist die Größe 
auf 32kB begrenzt. Warum es nicht 64kB sind, wurde hier mal diskutiert, 
wenn du das genauer wissen willst, musst du mal danach suchen. 81kB 
funktiert auf keinen Fall.

Oliver

Autor: Stefan H. (schnufff)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah, das erklärt es natürlich.
Aber wenn ich die Matrix in ein 2-dimensionales Array mit 81 Zeilen und 
1024 Spalten zerlege, dann sollte das funktionieren, oder? Jeder Pointer 
für sich muss dann ja weniger als 32kbyte "überstreichen" können.

Danke für die schnelle Antwort
Stefan

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Stefan H. (Firma privat) (schnufff)

>Aber wenn ich die Matrix in ein 2-dimensionales Array mit 81 Zeilen und
>1024 Spalten zerlege, dann sollte das funktionieren, oder?

NEIN! Weil das auch als zusammenhängendes Objekt verwaltet wird. Du 
braucht getrennte Arrays kleiner gleich 32kB.

MfG
Falk

Autor: Stefan H. (schnufff)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, die einzelnen Arrays müssen kleiner 32Kbyte sein.
Wenn ich die Zeilen der Matrix als 1024 Arrays speichere:
const uint8_t Matrix0[] PROGMEM={0x01,...};
...
const uint8_t Matrix1023[] PROGMEM={0x01,...};

wobei jede Zeile 81 Bytes enthält und dann die Zeilen in einem
Array von Pointern auf Arrays verwalte:
const uint16_t* Matrix[] PROGMEM={Matrix0,..Matrix1023[]};

Komme ich dann mit:
myByte=pgm_read_byte_far((pgm_read_byte_far(&Matrix[Zeile])[Spalte]);
an das Element in Zeile,Spalte?

Nur zur Info: Ich habe mehrere Matrizen die in Summe knapp 200Kbyte 
gross sind und 3 davon sind grösser als 64K.Alle Matrizen sind statisch 
und werden nur gelesen. Ich weiss das ich besser auf einen kleinen ARM7 
umsteigen kann, aber das ist nunmal nicht die Zielplattform.

danke
Stefan

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst das Array ja auch mit Assembler füllen und in C nur einen
Zeiger darauf verwalten.  Arrayzugriffe erfolgen in C per definitionem
(gemäß dem Standard) immer mit dem Typ "signed int", daher sind
diese hier ungeeignet.

Autor: Stefan H. (schnufff)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Jörg, aber die Matrizen werden auf einem PC mit einem 
CoputeralgebraProgramm vorberechnet und dann etwas formatiert und in 
meiner config.c eingebunden. Sie sind also zur kompletten Laufzeit des 
Programms fest.

Ich hatte mittlerweile versucht das Beispiel aus dem libc manual 
nachzubauen:
char string_1[] PROGMEM = "String 1";
char string_2[] PROGMEM = "String 2";
char string_3[] PROGMEM = "String 3";
char string_4[] PROGMEM = "String 4";
char string_5[] PROGMEM = "String 5";
Then use the new symbols in your table, like so:
PGM_P string_table[] PROGMEM = 
{
    string_1,
    string_2,
    string_3,
    string_4,
    string_5
};
Auslesen wollte ich dann per:
myChar=pgm_read_byte_far((PGM_P)pgm_read_word(&(string_table[i]))[j]);

Allerdings meckert er jetzt" pointer targets in init differ in 
signedness".
Selbst wenn der pointer "signed int" ist, muss er doch immer noch 
+32Kbyte adressieren können.Also sollte das für eine Zeile der MAtrix 
reichen, oder hab ich was flasch verstanden?

Gruss
Stefan

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan H. wrote:

> Danke Jörg, aber die Matrizen werden auf einem PC mit einem
> CoputeralgebraProgramm vorberechnet und dann etwas formatiert und in
> meiner config.c eingebunden. Sie sind also zur kompletten Laufzeit des
> Programms fest.

Ja, eben, daher kannst du sie ja genauso gut durch eine Folge von
.byte-Anweisungen in einer Assemblerdatei anlegen lassen.

Autor: Stefan H. (schnufff)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, asm für avr hab ich schon programiert, aber noch nie c und asm 
gemischt.
Ich hab grad 2 probleme. wie binde ich die *.asm datei ein und wie 
greife ich dann über C auf die bytes/words zu?

Autor: Stefan H. (schnufff)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, ich hab jetzt alle Array in Stücke kleiner 32K aufgeteilt und will 
mit pgm_read_byte/word_far drauf zugreifen.
Definiert sind die Array wie gehabt per
const uint8_t Matrix0[] PROGMEM={0x01,...};

aber keine der heir gefunden Möglichkeiten auf die hexwerte in 
Matrix[i]zuzugreifen scheint richtig zu funktionierten:
myByte=pgm_read_byte_far(FAR(Matrix[i]);
myByte=pgm_read_byte_far(FAR(Matrix+i));
myByte=pgm_read_byte_far(FAR(Matrix)+i));
liefern entweder nur 00 oder FF.

Bin ich denn so blöd?
Ich will einfach nur konsistent auf den kompletten flash eines Mega256 
zugreifen können und mir auf ewig konstante bytes/words auslesen können.

Gruss
Stefan

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan H. wrote:

> Ich hab grad 2 probleme. wie binde ich die *.asm datei ein und wie
> greife ich dann über C auf die bytes/words zu?

Die Assemblerdatei benennst du mit einer auf .S (großes S) versehenen
Endung und gibst sie einfach dem Compiler mit.  Der kann damit dann
was anfangen.

In der Assemblerdatei musst du die extern bekannt zu machenden Symbole
mit .global deklarieren:
.section .progmem.data,"a",@progbits
.global bigarray
bigarray:
    .byte 42, 23, 1, 5, 18

In der C-Datei deklarierst du dies einfach als externes Array:
extern uint8_t bigarray[];

*Aber*:

Du kannst nicht mit normalen Array- oder Zeigerzugriffen darauf
zugreifen, denn dann stolperst du ja sofort wieder darüber, dass
ein Zeiger im AVR-GCC nur 16 bits groß ist und dass der Arrayindex
per definitionem vom Typ signed int ist.  Du musst stattdessen per
Typecast vom Arraynamen einen uint32_t-Wert bilden und den an Stelle
eines Zeigers benutzen.  Die ganze Adressrechnung, die dir sonst
der Compiler abnimmt, musst du also zu Fuß erledigen.  Die sich
ergebende uint32_t-Zahl kannst du dann als Adresse an ein
pgm_read_byte_far() übergeben.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.