Hallo zusammen,
ich beschäftige mich gerade mit dem Thema Konstanten im Flash-Speicher
zu versenken.
Hierbei habe ich folgenden Array-Aufbau:
0 1 2 3 4... 7
0 struct ...
1 struct ...
2 struct ...
.
.
.
8
Der Aufbau der Struktur (struct) ist folgender:
1
structsegmap
2
{
3
volatileuint8_t*port;
4
uint8_tbitmask;
5
};
Ich benötige immer eine bestimmte Spalte des Arrays.
Sprich ich habe hier nur ein Word und ein Byte. Für mich stellt sich
jetzt die Frage, ob ich mich hinsetzen soll, um Hilfsfunktionen zu
programmieren oder lieber aus dem einen Array einfach 2 Arrays mache,
die dann einen Word bzw. einen Byte Inhalt haben.
Die Struktur-Variante ist doch rechenlastiger oder, da zusätzlich noch
Hilfsfunktionen ausgeführt werden müssen.
Für die beiden Arrays habe ich dann leider aber auch nicht mehr die
bequemen und auch schnellen Zugriffe.
Wie soll ich es eurer Meinung nach machen?
Vielen Dank für eure Hilfe
Marcel
Strukturvariante.
Sollte besser lesbar sein und damit weniger bugträchtig und besser zu
warten.
Die "Hilfsfunktionen" sind einfache Offsets, d.h. Additionen fester
Größen. Ich bezweifele, dass ein selbstgebauter Code mit zwei Arrays
weniger Overhead hätte.
Stefan B. schrieb:
> Die "Hilfsfunktionen" sind einfache Offsets, d.h. Additionen fester> Größen. Ich bezweifele, dass ein selbstgebauter Code mit zwei Arrays> weniger Overhead hätte.
O.K., also werd ich mich an die StrukturVariante dranmachen
----------|----------|----------|
| | |
PORTADRESSE | BITMASK |
1Byte | 1Byte | 1Byte |
----------|----------|----------|
| | |
PORTADRESSE | BITMASK |
1Byte | 1Byte | 1Byte |
----------|----------|----------|
1
structsegmap
2
{
3
volatileuint8_t*port;
4
uint8_tbitmask;
5
};
6
7
8
inlinefloatpgm_read_struct(structsegmap*addr)
9
{
10
11
structsegmapi[9];// Array einer Spalte aus dem Flash
12
13
14
returni[9];
15
}
Doch wie genau addiere ich den Pointer? Ich möchte ja eine Spalte des
Arrays auslesen
Vielen Dank für eure Hilfe Marcel
Marcel schrieb:
> O.K., also werd ich mich an die StrukturVariante dranmachen
Strktur ist immer gut.
Dinge die zusammengehören sollen auch zusammen bleiben.
> Doch wie genau addiere ich den Pointer?
Was meinst du mit addieren?
Wieso willst du Pointer addieren?
Karl heinz Buchegger schrieb:
> Was meinst du mit addieren?> Wieso willst du Pointer addieren?
Das war schlecht von mir ausgedrückt -Entschuldige. Ich meinte eher das
Inkrementieren der Pointer.
1
addr++
beispielsweise
Ich habe mir das AVR-GCC Tutorial angeschaut. Hier ist jedoch nur eine
Float-Porting aus dem Flash und leider kein Struktur-Beispiel.
Darum habe ich gerade Probleme wie ich die Struktur denn auf den RAM
portieren soll.
Nochmal zusammengefasst:
Ich habe ein zweidimensionales Array, wovon ich eine bestimmte Spalte
benötige. Die Werte des Arrays sind von einer Struktur namens "segmap"
(s.o.)
Vielen Dank
Marcel
Marcel schrieb:
> Ich habe ein zweidimensionales Array, wovon ich eine bestimmte Spalte> benötige.
Inwiefern benötigst du die? Wozu brauchst du sie?
Brauchst du tatsächlich alle Elemente einer Spalte als eigene
'Datenstruktur' oder genügt es eine Funktion zu haben, die einfach alle
Elemente einer Spalte einzeln abarbeitet?
> Die Werte des Arrays sind von einer Struktur namens "segmap"> (s.o.)
Ja, Warum kannst du nicht einfach zugreifen?
Zur Frage: Warum brauche ich diese.
Ich habe ein LCD-Glas mit 8darstellbaren Zahlen ( jeweils 7Segment
Anzeige).
Ich nutze den Mega169 Dieser ist in der Lage das LCD Glas anzusteuern.
Alles läuft sehr gut wenn ich diesen Array im Ram habe. Doch benötige
ich jetzt nochmals Platz für ein 300 Byte großes Array (UART Empfang).
Dazu muss ich das LCD-Array ins Flash packen.
Zur Frage: Brauchst du alle Elemente einer Datenstruktur als
geschlossen?
Nein das nicht. Mir reicht es auch Element für Element zu lesen und dann
wieder zu verarbeiten... Die Struktur beinhaltet einen Pointer welcher
auf das IO Register zeigt und einen Wert 00010000 z.B. Welcher dann sagt
dass an der Stelle des Registers Digit 1 Segment A angesprochen werden
kann.
Ich werde einfach nicht schlau wie ich ein Element des Arrays aus dem
Flash hole. Wie schaffe ich das mit Read _word und Byte?
Merci beaucoup Marcel
Marcel schrieb:
> Ich werde einfach nicht schlau wie ich ein Element des Arrays aus dem> Flash hole. Wie schaffe ich das mit Read _word und Byte?
Du brauchst eigentlich einen pgm_read_block.
Die gibt es aber so nicht. Macht aber nichts. Denn eine Struktur ist ja
auch nichts anderes als eine Abfolge von Bytes. Wenn man also in einer
Schleife einfach sizeof( Struktur ) Bytes vom Flash in bereitsgestellten
SRAM Speicher kopiert, dann hat man eine komplette Struktur vom Flash in
den SRAM kopiert. An dieser Stelle sieht man die Dinger pragmatisch: Es
ist völlig egal, ob das was du kopieren willst eine Struktur ist oder
irgendwas anderes. Es hat eine Länge in Bytes und diese Anzahl Bytes
werden vom Flash ins SRAM umkopiert.
Die Lösung 3, von einem Post weiter oben, macht genau das. Sie benutzt
memcopy_P um die Umkopieraktion durchzuführen.
Zeig doch mal, wie deine Funkion aussehen würde, wenn alles im SRAM ist.
Dann ist es leichter über die Dinge zu reden, als wenn das alles immer
nur hypothetisch abgehandelt wird.
Karl heinz Buchegger schrieb:
> Zeig doch mal, wie deine Funkion aussehen würde, wenn alles im SRAM ist.> Dann ist es leichter über die Dinge zu reden, als wenn das alles immer> nur hypothetisch abgehandelt wird.
So nun bin ich wieder zu Hause.
Im SRAM sieht das wie folgt aus: :)
Hier ist das 2D Array, wovon ich jeweils die Daten eines Digits brauche
1
conststructsegmapdigits[8][9]=
2
{
3
{/* digit 1 */
4
{&LCDDR12,0x40},/* segment 1A */
5
{&LCDDR12,0x20},/* 1B */
6
{&LCDDR7,0x20},/* 1C */
7
{&LCDDR2,0x40},/* 1D */
8
{&LCDDR7,0x80},/* 1E */
9
{&LCDDR12,0x80},/* 1F */
10
{&LCDDR7,0x40},/* 1G */
11
{&LCDDR2,0x20},/* 1DP */
12
{&LCDDR2,0x80},/* 1AN */
13
},
14
15
{/* digit 2 */
16
{&LCDDR12,0x08},/* segment 2A */
17
{&LCDDR12,0x04},/* 2B */
18
{&LCDDR7,0x04},/* 2C */
19
{&LCDDR2,0x08},/* 2D */
20
{&LCDDR7,0x10},/* 2E */
21
{&LCDDR12,0x10},/* 2F */
22
{&LCDDR7,0x08},/* 2G */
23
{&LCDDR2,0x04},/* 2DP */
24
{&LCDDR2,0x10},/* 2AN */
25
},
26
...
Und hier ist die Funktion die eine Zahl/Buchstaben "schreibt":
PS: Der
1
LCD_character_table[]
gibt nur den Code Zurück welche Segmente angeschaltet bzw.
ausgeschaltet werden müssen:
1
constunsignedintLCD_character_table[54]={// Character definitions table.
2
3
0x00,// '' (Not defined)
4
0x00,// '+' (Not defined)
5
0x00,// ',' (Not defined)
6
0x00,// '-' (Not defined)
7
0x00,// '.' (Not defined)
8
0x00,// '/' (Not defined)
9
0b00111111,// '0'
10
0b00000110,// '1'
11
0b01011011,// '2'
12
0b01001111,// '3'
13
0b01100110,// '4'
14
0b01101101,// '5'
15
0b01111101,// '6'
16
0b00000111,// '7'
17
0b01111111,// '8'
18
0b01101111,// '9'
19
....
1
voidLCD_out(uint8_tdigit,uint8_tcharacter)
2
{
3
4
//Konvertiere character in den LCD-Code
5
6
uint8_tlcdcode=LCD_character_table[character-42];
7
8
//Routine, um LCD-Code in die Register zu schieben
Vielen Dank Karl heinz! :)
Beim rüberfliegen über deine Lsg ist mir noch nen klitzekleiner Fehler
aufegafallen :-P
Karl heinz Buchegger schrieb:
> if (lcdcode & mask)> {> sm->port |= sm->bitmask;> }>> else> {> sm->port &= ~(sm->bitmask);
sm ist ja jetzt kein Pointer mehr ;)
Das war ja echt einfacher als ich gedacht hatte ^^
Du hast mir echt die Augen geöffnet und die "Angst" vom Flash-Speicher
genommen...
Grüße Marcel
Marcel schrieb:
> Vielen Dank Karl heinz! :)>> Beim rüberfliegen über deine Lsg ist mir noch nen klitzekleiner Fehler> aufegafallen :-P>> Karl heinz Buchegger schrieb:>> if (lcdcode & mask)>> {>> sm->port |= sm->bitmask;>> }>>>> else>> {>> sm->port &= ~(sm->bitmask);>> sm ist ja jetzt kein Pointer mehr ;)
LOL
Du hast recht.
Ich hab nur den ersten * entfernt, aber das ist ja klarerweise noch
nicht alles, bzw. genau falsch. Sorry
*(sm.port) |= sm.bitmask;
> Das war ja echt einfacher als ich gedacht hatte ^^
Der Trick besteht im Grunde darin, dass du dir alles aus dem Flash erst
mal ins SRAM kopieren musst, damit du damit arbeiten kannst. Sobald es
dann erst mal im SRAM ist, geht alles wie gewohnt.
So habs jetzt eben compiliert und läuft :)
Für die Forumsdurchsucher, die ähnliche Probleme mit dem Flash haben,
hab ich noch nen kleinen Fehler in Karl heinz Code gefunden:
void * memcpy_P ( void * dest, PGM_VOID_P src, size_t n)
Sprich das
Karl heinz Buchegger schrieb:
> memcpy_P( sm, & (digits[digit][i]), sizeof( struct segmap ) );
muss umgeändert werden in
> memcpy_P( &sm, & (digits[digit][i]), sizeof( struct segmap ) );
(fürs Verständnis aber unerheblich!)
Vielen Dank nochmal Karl heinz, Du hast mir echt weitergeholfen! :)
Grüße Marcel
Man kann auch noch 1 Byte / Eintrag sparen, wenn man statt dem pointer
(2 Byte) die Register-Adresse abspeichert (LCDDR0-18 liegen im speicher
<= 0xFE). Im Flash abgelegt werden kann die Adresse mit dem Macro
_SFR_MEM_ADDR(sfr). Beim Auslesen muss anschließend der uint8-Wert nur
noch in einen Zeiger typecastet werden.
Ohne den Typecast nach uint16_t würde der Compiler berechtigterweise die
die Warnung "cast to pointer from integer of different size" (d.h. man
versucht aus einer Variablen mit mehr/weniger als 16bit einen Zeiger zu
convertieren) ausspucken. Anschließend castet man (fast analog zu den
Definitionen von _MMIO_BYTE/_MMIO_WORD in avr/sfr_defs.h) die Variable
in einen Zeiger und greift auf dessen Inhalt zu.
Ich weiß, ist ein wenig Bit-Hunting mäßig und der Code wird auch
unleserlicher, aber immer gut im Hinterkopf zu behalten, wenn einem mal
der Flash-Speicher ausgeht (und es nur um 10-20 Byte net reinpassen
will).
gruß
Mobius