Forum: Compiler & IDEs ATMega Flash: Array


von Peder (Gast)


Lesenswert?

Hallo,

zum Thema Flash findet man eigentlich einen Haufen Zeug im Netz, aber 
ich werde trotzdem nicht so ganz schlau.
Ich möchte das digitalisierte Abbild einer (mathematischen) Funktion in 
den Flash-Speicher des ATMega16 schreiben. Dazu lass ich mir zunächst 
100 Funktionswerte berechnen, ich rastere die Funktion quasi ab. Diese 
Funktionswerte sollen dann als 1D-Array im Flash gespeichert werden.

Als reinen Test, ob ich überhaupt den Flash ansprechen kann, habe ich 
erst ein festes Array definiert und es später ausgelesen, was 
einwandfrei funktioniert:
1
const static uint16_t flash_table[5] PROGMEM = {0,1,2,3,4}; // schreiben
2
uint16_t *flash_pointer = flash_table;                      // Pointer initialisieren
3
4
for (uint16_t i=0; i<5; i++)
5
{
6
 SPDR = (uint8_t)(pgm_read_word(&flash_pointer[i]) >> 8);   // high byte lesen
7
 SPDR = (uint8_t)(pgm_read_word(&flash_pointer[i]));        // low byte lesen
8
}


Nun ist meine Idee, erst ein leeres Array zu initialisieren und einen 
Pointer zu definieren, der auf den Array-Anfang zeigt, was auch 
funktioniert:
1
const static uint16_t flash_table[100] PROGMEM = {};
2
uint16_t *flash_pointer = flash_table;
Zumindest sehe ich im Debugger, dass der Bereich reserviert und mit 
Nullen belegt ist und auch der Zeiger zeigt auf die Startadresse.

Danach möchte ich über den Pointer die reservierten Adressen mit den 
Funktionswerten beschreiben, was aber ignoriert wird:
1
for (uint16_t i=0; i<100; i++)
2
    {
3
     *flash_pointer = function(i);
4
    }

Das Programm wird so kompiliert, aber in den Adressen ändert sich 
trotzdem nichts, der gesamte Bereich bleibt auf 0x00. Soweit ich gelesen 
habe, können Flash und SRAM die gleichen Adressen haben und man muss sie 
durch PROGMEM unterscheiden, aber wenn ich dieses Wort hinzufüge, bricht 
der Compiler ab mit "expected ';' before '__attribute'".

Oder ist schlicht meine C-Syntax falsch? Wie geht man das normalerweise 
an?


Grüße

Peter

von Karl H. (kbuchegg)


Lesenswert?

Peder schrieb:

> Danach möchte ich über den Pointer die reservierten Adressen mit den
> Funktionswerten beschreiben, was aber ignoriert wird:


Es wird nicht ignoriert. Das Flash ist zur Laufzeit nicht beschreibbar.

D.h. das stimmt nicht ganz. Es gibt schon eine Möglichkeit, Bootloader 
müssen das ja auch können. Aber es geht nicht so banal wie du dir das 
vorstellst. In einem AVR ist das Flash nur seitenweise beschreibbar, was 
für einen Bootloader keine große Rolle spielt, denn der sammelt einfach 
eintreffenden Programmcode, bis er eine Seite beisammen hat und schreibt 
dann die Seite in einem Rutsch. Aber für ein normales Programm, ist das 
nicht brauchbar, zumal dieses Flash Beschreiben auch nur dann 
funktioniert, wenn der Code, der es macht in der Bootloader Sektion vom 
AVR steht.

Ergo:
Vergiss es. Denk dir was anderes aus. Für dich ist das Flash 'nicht 
beschreibbar'. Das Flash ist der Programmspeicher und als solcher für 
das Programm unantastbar. Genau das ist es, was eine 
'Harvard-Architektur' ausmacht.

Wenn du Daten brauchst die eine Stromabschaltung überleben, dann gibt es 
da noch das EEPROM. D.h. wenn es groß genug für deine Zwecke ist.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Die Antwort ist simpel: Du kannst aus Deiner Anwendung heraus kein Flash 
beschreiben, nur daraus lesen.

Ja, das hat der böse Hersteller mit Absicht verhindert.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Wenn du Daten brauchst die eine Stromabschaltung überleben, dann gibt es
> da noch das EEPROM. D.h. wenn es groß genug für deine Zwecke ist.

Wenn die Daten immer dieselben (d.h. konstant) sind, dann soll er auf 
dem PC und (nicht auf dem µC) den Abschnitt
1
for (uint16_t i=0; i<100; i++)
2
{
3
    *flash_pointer = function(i);
4
}

laufen lassen und das Ergebnis als Datei imflash.c in C-Syntax ausgeben. 
Diese C-Datei kann er dann zu seinem Projekt hinzulinken und schon hat 
er sein Array beim nächsten "Brennen" auch im Flash ;-)

von Peder (Gast)


Lesenswert?

Der EEPROM ist mir leider zu klein. Ich brauche mindestens 2kB, aber die 
Daten sind dann auch tatsächlich konstant.

Dass man EEPROM und Flash irgendwie aus dem AVR Studio beschreiben kann, 
ist mir auch mal aufgefallen, allerdings hab ich dazu recht wenig Infos 
gefunden. Aber wenn das ginge, wäre das auch eine Lösung.
Nun wird aber der Programm-Code auch im Flash gespeichert. Wenn ich dann 
mein Funktionswerte in den Flash schreiben will, überschreibe ich nicht 
den Programm-Code?

Und ich hoffe, die Frage klingt nicht zu sehr nach "Schreibt mir mal 
mein Programm", aber wie funktioniert das mit der C-Syntax und dem 
Dazulinken? Das einzige Mal, dass ich von Hand linken musste, ist gut 
fünf Jahre her und das war per Konsole.
Wenn ich die for-Schleife einfach in eine Datei gebe, in welchem Format 
sollte ich das tun? Einfach lückenlos eine Zahl nach der anderen?

von Oliver (Gast)


Lesenswert?

Peder schrieb:
> Wenn ich die for-Schleife einfach in eine Datei gebe, in welchem Format
> sollte ich das tun? Einfach lückenlos eine Zahl nach der anderen?

Am Ende muß genau so etwas da stehen:

> const static uint16_t flash_table[5] PROGMEM = {0,1,2,3,4};

Oliver

von convert (Gast)


Lesenswert?

Frank M. schrieb:
> Die Antwort ist simpel: Du kannst aus Deiner Anwendung heraus kein
> Flash
> beschreiben, nur daraus lesen.
>
> Ja, das hat der böse Hersteller mit Absicht verhindert.

Das ist so generell ist das natürlich Blödsinn.

Natürlich kann man Flash beschreiben. Nur halt nicht so "einfach".
Man braucht: eine Flash lib oder halt die Flashfunktionen selber 
schreiben.

Diese landen dann im RAM und können Flash schreiben.
Manche uCs können auch Code aus einer Flashpage ausführen und eine 
andere beschreiben - Kopie ins RAM dann nicht zwingend.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

convert schrieb:

> Das ist so generell ist das natürlich Blödsinn.

Ich bezog mich auf den Thread-Titel: "ATMega Flash: Array"

> Natürlich kann man Flash beschreiben. Nur halt nicht so "einfach".
> Man braucht: eine Flash lib oder halt die Flashfunktionen selber
> schreiben.

Beim ATmega kannst Du das Flash-Memory nur über einen Bootloader 
beschreiben.

> Diese landen dann im RAM und können Flash schreiben.

Geht beim ATmega nicht - außer über Bootloader. Der ist aber eine Nummer 
zu groß für den TO.

> Manche uCs können auch Code aus einer Flashpage ausführen und eine
> andere beschreiben - Kopie ins RAM dann nicht zwingend.

Wir reden über ATmega. Mein Posting hatte keinen allgemeingültigen 
Anspruch.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peder schrieb:

> Und ich hoffe, die Frage klingt nicht zu sehr nach "Schreibt mir mal
> mein Programm", aber wie funktioniert das mit der C-Syntax und dem
> Dazulinken? Das einzige Mal, dass ich von Hand linken musste, ist gut
> fünf Jahre her und das war per Konsole.

Du fügst im AVR Studio die erzeugte C-Datei einfach dem Projekt hinzu.
Alternativ kannst Du auch eine Header-Datei erzeugen, die Du dann in 
main.c einfach "includierst". Ist sogar noch einfacher.

> Wenn ich die for-Schleife einfach in eine Datei gebe, in welchem Format
> sollte ich das tun? Einfach lückenlos eine Zahl nach der anderen?

Nein, so:

meinflash.h (diese Datei musst Du per C-Programm auf dem PC erzeugen):
1
static const uint16_t flash_table[100] PROGMEM =
2
{
3
    1,
4
    2,
5
    ....
6
};


In main.c Deines µC-Programms schreibst Du dann einfach:

#include "meinflash.h"

Und schon kannst Du auf alle Werte zugreifen.

Dein C-Programm für den PC kann folgendermaßen aussehen:
1
#include <stdio.h>
2
3
int
4
function (int i)
5
{
6
    // hier deine Funktionswerte zurückliefern:
7
    return i;
8
}
9
10
int
11
main ()
12
{
13
    FILE *      fp = fopen ("meinflash.h", "w");
14
    int         i;
15
    int         rtc = 1;
16
17
    if (fp)
18
    {
19
        fputs ("static const uint16_t flash_table[100] PROGMEM =\n", fp);
20
        fputs ("{\n", fp);
21
22
        for (i = 0; i < 100; i++)
23
        {
24
            fprintf (fp, "    %d,\n", function(i));
25
        }
26
        fputs ("};\n", fp);
27
        fclose (fp);
28
        rtc = 0;
29
    }
30
    else
31
    {
32
       perror ("meinflash.h");
33
    }
34
35
    return rtc;
36
}

Der Quellcode ist auf Unix/Linux getrimmt, evtl. musst Du noch windows.h 
hinzufügen, damit es auch unter Windows läuft.

@Oliver: Dein "static" wird in einer separaten C-Datei nicht 
funktionieren.

von Peder (Gast)


Lesenswert?

Für die Überschrift muss ich mich fast noch entschuldigen, die war 
einfach nur nicht fertig und nach dem Beitrag hab ich die glatt 
vergessen.

Ansonsten hab ich das Konzept denke ich verstanden. Ich werd das am 
Montag mal ausprobieren, dann geb ich Bescheid, wie es lief.

Danke!

von Stephan B. (matrixstorm)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Es wird nicht ignoriert. Das Flash ist zur Laufzeit nicht beschreibbar.

[...]

Karl Heinz Buchegger schrieb:
> Für dich ist das Flash 'nicht
> beschreibbar'. Das Flash ist der Programmspeicher und als solcher für
> das Programm unantastbar. Genau das ist es, was eine
> 'Harvard-Architektur' ausmacht.


Hallo.
Da möchte ich doch diese Gelegenheit nocheinmal nutzen, um für mein 
Beispiel in
Beitrag "Re: [ATMega] Programm aus externem EEprom laden"
zu werben.

Dort habe ich ein Beispiel demonstriert wie man solches eben doch machen 
kann.
(Auch aus RWW Sektionen.)

MfG matrixstorm

p.s.: Ich stehe für Fragen gern zur Verfügung.

von Peder (Gast)


Lesenswert?

Die Idee mit der separaten C-Datei ist eigentlich so sonnenklar, dass 
man auch selbst hätte drauf kommen können. Ich habe das Ganze soweit 
umgesetzt und es hat einwandfrei funktioniert.

Ich verstehe nur nach wie vor nicht, warum es trotzdem möglich war, zur 
Laufzeit und sogar innerhalb der main() (!) ein konstantes Array in den 
Flash zu schreiben.

Aber sei es drum, für meine Zwecke reicht es, wenn ich mir merke, dass 
es so ist.


Danke

von Karl H. (kbuchegg)


Lesenswert?

Peder schrieb:

> Ich verstehe nur nach wie vor nicht, warum es trotzdem möglich war, zur
> Laufzeit und sogar innerhalb der main() (!) ein konstantes Array in den
> Flash zu schreiben.

Kommt auf dein Testprogramm an.

Des Compilers Optimizer sind ausgefuchster als du denkst. Der findet 
raus,wie du dein Array beschreibst und kann in manchen Fällen dann die 
Werte aus seinen während der Programmanalyse gemerkten Werten einsetzen, 
die nie im Flash gelandet sind und vom Programm auch nie ausgelesen 
wurden.

von Karl H. (kbuchegg)


Lesenswert?

wenn du die 100 loswerden willst, dann würde ich das so machen.

Das PC-C-Programm erzeugt nur noch die Datenwerte
Daten.inc
1
22, 38, 35, 40, 53, 78
2
23, 45, 23, 92

und dein AVR-C-File sieht so aus
1
.....
2
const static uint16_t flash_table[] PROGMEM =
3
{
4
#include "Daten.inc"
5
};
6
7
#define TABLE_SIZE (sizeof(flash_table)/sizeof(*flash_table))
8
....
9
10
11
  for (uint16_t i=0; i<TABLE_SIZE; i++)
12
  {
13
    SPDR = (uint8_t)(pgm_read_word(&flash_table[i]) >> 8);   // high byte lesen
14
    SPDR = (uint8_t)(pgm_read_word(&flash_table[i]));        // low byte lesen
15
  }
16
...

damit hast du das PC Programm davon befreit, dass es 100 Datenpaare 
anlegen muss. Es kann beliebig viele machen und muss auch nicht wissen, 
wie im AVR Programm die Variable heißt. Das PC Programm erzeugt einfach 
nur die Daten, die im AVR Programm zur Initialisierung benutzt werden. 
Um alles andere muss es sich nicht mehr kümmern.

Denn: Dem #include ist es egal, was in der anderen Datei steht. Der 
Präprozessor ersetzt einfach nur die Zeile mit dem #include durch den 
Inhalt der angegebenen Datei. Und erst danach muss wieder gültiges C 
rauskommen. Denn der eigentliche C-Compiler sieht dein 'Machwerk' ja 
erst, nachdem der Präprozessor alle Textersetzungen vorgenommen hat. 
Wenn du willst, kannst du auch so programmieren


int.h
1
int
main.h
1
main
klammer_auf.h
1
(
klammer_zu.h
1
)

test.c
1
#include "int.h"
2
#include "main.h"
3
#include "klammer_auf.h"
4
#include "klammer_zu.h"

wenn der Präprozessor alle #include durch die Inhalte der jeweiligen 
Dateien ersetzt hat, dann kommt da raus
1
int
2
main
3
(
4
)
und das ist ja ein gültiges C-Programm, welches anstandslos durch den 
Compiler gehen wird.

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.