Forum: Compiler & IDEs Wie reserviere ich einen Speicherbereich in C?


von Kapitän Nuss (Gast)


Lesenswert?

Hallo,

ich möchte einen 512 Byte großen Speicherbereich im 
Flash-Programmspeicher für Benutzereingaben reservieren.

Wie reserviere ich das in C, so das der Compiler Bescheid weis und es 
keinen Adressen Konflikt gibt?

Mein C-Lehrbuch bezieht sich eher auf C-Programme die auf einem PC 
laufen,
deshalb muss ich die erfahrenen µC-Programmierer hier fragen :-)

Ich benutze den Arm Realview Compiler und µVision3, meine MCU ist ein 
ADuC7126

von Mr.T (Gast)


Lesenswert?

Den Compiler interessiert das nicht. Such mal im Linker Manual, wie Du 
sections im Linkerscript anlegst.

von Kapitän Nuss (Gast)


Lesenswert?

Mr.T schrieb:
> Den Compiler interessiert das nicht. Such mal im Linker Manual, wie Du
> sections im Linkerscript anlegst.

Ich habe mal in einem C-Programm für den 8051 gesehen, wie jemand da 
einen bestimmten Bereich im Programmspeicher reserviert hat.
Da war irgenwas mit
1
_at 0x0200 const unsigned long int lalabla[64]={2,3,5,7,11,13,17,19....};
Ich kriege die Syntax aber aus dem Gedächnis nicht mehr hin, ist Jahre 
her.

von Mr.T (Gast)


Lesenswert?

Das ist aber KEIN ANSI C!

von Bronco (Gast)


Lesenswert?

Kapitän Nuss schrieb:
> Wie reserviere ich das in C, so das der Compiler Bescheid weis und es
> keinen Adressen Konflikt gibt?

Wie das genau geht, ist compiler-/linker-abhängig.

Grundsätzlich kannst Du entweder direkt im C-Code eine fixe Adresse 
angeben (wie in Deinem Beispiel) oder legst im Linker-Script eine eigene 
Section für Deine Zwecke an.
Mit einer eigenen Section legst Du erst im Linker-Script fest, wo diese 
Section liegen soll. Das ist meiner Ansicht nach sauberer.

von Markus B. (rusticus)


Lesenswert?

Hab ich die Frage null total falsch verstanden oder reicht nicht einfach 
ein Char Array mit 512 Stellen?

Der Compiler hält 512 Byte frei und gut ist?!

von Mr.T (Gast)


Lesenswert?

> Der Compiler hält 512 Byte frei und gut ist?!
Und die legt er dir an eine vorher definierte Adresse?

von Kapitän Nuss (Gast)


Lesenswert?

Markus B. schrieb:
> oder reicht nicht einfach
> ein Char Array mit 512 Stellen?

Ja genau!

> Der Compiler hält 512 Byte frei und gut ist?!

So würde ich mir das wünschen,
das diese 512 byte nicht mit dem Programmspeicher kollidieren.
Und das diese 512 Byte an einer 512 Byte Grenze anfangen.

Die syntax kann natürlich auch so gewesen sein:
1
@ 0x0200 const unsigned long int lalabla[64]={2,3,5,7,11,13,17,19....};

von Karl H. (kbuchegg)


Lesenswert?

Mr.T schrieb:
>> Der Compiler hält 512 Byte frei und gut ist?!
> Und die legt er dir an eine vorher definierte Adresse?

Die Frage ist, ob man das überhaupt will. (also jetzt: an eine bestimmte 
konkrete Adresse).

In dein meisten Fällen will man das ja gar nicht. Es reicht, wenn man 
dem Compiler/Linker sagt, dass das Zeug ins Flash soll. Wo genau im 
Flash - das ist Sache der Tools. Und wie das genau geht: Compiler/Linker 
Doku.

von cppler (Gast)


Lesenswert?

Kapitän Nuss schrieb:
> ich möchte einen 512 Byte großen Speicherbereich im
> Flash-Programmspeicher für Benutzereingaben reservieren.

Sollen da die Eingaben des Nutzers abgespeichert werden oder eine 
Benutzerführung angelegt => Menueinträge ?

von Kapitän Nuss (Gast)


Lesenswert?

cppler schrieb:
> Sollen da die Eingaben des Nutzers abgespeichert werden

Ja genau!

von Rolf M. (rmagnus)


Lesenswert?

Mr.T schrieb:
>> Der Compiler hält 512 Byte frei und gut ist?!
> Und die legt er dir an eine vorher definierte Adresse?

Diese Anforderung lese ich aber nirgends. Wo kommt die her?

von Kapitän Nuss (Gast)


Lesenswert?

Kapitän Nuss schrieb:
> ich möchte einen 512 Byte großen Speicherbereich im
> Flash-Programmspeicher für Benutzereingaben reservieren.
>
> Wie reserviere ich das in C, so das der Compiler Bescheid weis und es
> keinen Adressen Konflikt gibt?

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Kapitän Nuss schrieb:

> [ein Zitat]

Nö! Da kommt die Anforderung nicht her!
Ein
1
char userdata[512] <flashattribut>;

macht genau das! Wie man das ins flash verlagert und dort beschreibt ist 
der Dokumentation der (Compiler-) tools oder entsprechenden Beispielen 
zu etnehmen.

von Peter D. (peda)


Lesenswert?

Zuerst müßte man mal klären, ob der Flash des MC überhaupt zur Laufzeit 
gelöscht und geschrieben werden kann (IAP In application programming). 
Und dann, wie.
Dann muß man sich nur noch eine Routine dafür schreiben. Vielleicht gibt 
es auch schon einen API-Call dafür im Bootloader.
Ob man die Routine dann so schreibt, daß sie nur an festen Pagegrenzen 
schreiben kann, oder an beliebigen Adressen, ist jedem selbst 
überlassen.

von Kapitän Nuss (Gast)


Lesenswert?

Ich habe einen C-Code gefunden, der (bei einem 8051) etwas in den 
Programmspeicher schreibt und diesen Speicherbereich freihält:
1
const code unsigned char at 0x80 Beschreibung1[] = "528302B0";
2
const code unsigned char at 0x89 Beschreibung2[] = "Schrittmotorsteuerung und die Anzeige";
3
const code unsigned char at 0xaf Beschreibung3[] = "2003-08-29";
Leider mag mein Compiler (Realview) diese Syntax nicht.
Ich habe allerdings keinen 8051 sondern einen ADuC7126.
Ich könnte schon während der Laufzeit ins Flash schreiben,
man kann immer nur 512 Byte Blöcke schreiben (FEE0ADR Register).
Wär natürlich blöd, wenn ich dabei das eigentliche Programm 
überschreiben würde.

Für das Lesen aus dem Programmspeicher habe ich jetzt diese hinbekommen:
1
  for(Counter = 0;Counter < 2000;Counter++)
2
  {
3
    byte = PEEK(Counter); // #define PEEK(addr) (*(unsigned char *)(addr))
4
5
    if((byte >= 32)&&(byte <= 128))printf("%c",byte);
6
    else printf(" ");
7
    if((Counter & 0x3F) == 0)printf("\n %X  ",Counter);
8
  }
Wie kann ich das ohne PEEK schreiben?

von Kapitän Nuss (Gast)


Lesenswert?

Habe das ohne PEEK jetzt hinbekommen:
1
  printf("\n\n\nHallo Welt! Test Test 123\n");
2
  for(Counter = 0;Counter < 2000;Counter++)
3
  {
4
    byte = (*(unsigned char *)(Counter));
5
6
    if((Counter & 0x3F) == 0)printf("\n%#X  ",Counter);
7
    if((byte >= 32)&&(byte <= 128))printf("%c",byte);
8
    else printf(" ");
9
  }

Aber wie sage ich jetzt dem Compiler, halte mir mal den Speicher
von...bis frei und nenne das z.B. user_daten

von Karl H. (kbuchegg)


Lesenswert?

Kapitän Nuss schrieb:

> Leider mag mein Compiler (Realview) diese Syntax nicht.

Tu dir selbst einen Gefallen und fang endlich damit an, das zu tun, was 
dir seit Stunden vorgeschlagen wird: durchforste die Doku!

Wenn da etwas dafür vorgesehen ist, das man Flash-Bereiche als 
Zwischenspeicher verwenden kann, dann findest du das in der Doku und 
nicht hier im Forum!

> Wie kann ich das ohne PEEK schreiben?

Doku nachsehen!
Das ist wichtig! Du musst MIT dem Compiler/Linker arbeiten und nicht 
GEGEN ihn! Wie das genau geht findet sich, wenn überhaupt, in der 
Compiler/Linker Doku!

von Rolf M. (rmagnus)


Lesenswert?

Kapitän Nuss schrieb:
> Kapitän Nuss schrieb:
>> ich möchte einen 512 Byte großen Speicherbereich im
>> Flash-Programmspeicher für Benutzereingaben reservieren.
>>
>> Wie reserviere ich das in C, so das der Compiler Bescheid weis und es
>> keinen Adressen Konflikt gibt?

Das heißt ja erstmal nur, daß du es im Flash haben willst, aber nicht, 
daß es an einer ganz bestimmten Adresse stehen muß. Wie schon gesagt 
wurde, ist es besser, dem Compiler (bzw. eigentlich dem Linker) die 
Aufgabe zu überlassen, die Adressen zu verteilen und ihm lediglich zu 
sagen, daß es halt im Flash sein soll. Dafür gibt es in C aber keinen 
Standard-Weg. Es ist Compiler-abhängig.

von Peter D. (peda)


Lesenswert?

Kapitän Nuss schrieb:
> Aber wie sage ich jetzt dem Compiler, halte mir mal den Speicher
> von...bis frei und nenne das z.B. user_daten

Das steht in der Doku Deines speziellen Compilers.

Hat Dein Compilerhersteller etwa keine Webseite bzw. Deine 
Compilerinstallation keine Hilfe und kein Manual?

Oftmals haben Compilerhersteller sogar einen Support, Knowledge Base 
oder Forum, wo man spezielle Fragen stellen kann.
Man sollte dort aber erstmal nachlesen, ob die Frage nicht schon 
beantwortet wurde. Es macht keinen guten Eindruck, wenn man eine Frage 
zum 1000-sten mal stellt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Kapitän Nuss schrieb:
> Ich habe einen C-Code gefunden, der (bei einem 8051) etwas in den
> Programmspeicher schreibt und diesen Speicherbereich freihält:
>
> const code unsigned char at 0x80 Beschreibung1[] = "528302B0";
> const code unsigned char at 0x89 Beschreibung2[] =
> "Schrittmotorsteuerung und die Anzeige";
> const code unsigned char at 0xaf Beschreibung3[] = "2003-08-29";

Das ist kein C:

• "code" ist kein Schlüsselwort in C
• "at" ist kein Schlüsselwort in C
• "0x.." ist an der Stelle wo es steht syntaktisch nicht erlaubt in C

Vielleicht ist das ja BASIC oder so?

von Bronco (Gast)


Lesenswert?

Johann L. schrieb:
> Vielleicht ist das ja BASIC oder so?

Offenbar, denn schließlich gibt es ja auch einen "PEEK"-Befehl...

Kapitän Nuss schrieb:
> Aber wie sage ich jetzt dem Compiler, halte mir mal den Speicher
> von...bis frei und nenne das z.B. user_daten

Einfach mit "POKE" an die gewünschte Adresse schreiben...

Lies das Handbuch und leg im Linker-Script eine Section an. Und beleg 
mit der Section vollständige Flash-Page(s), sonst kannst Du die Section 
nicht löschen, ohne Kollateralschaden anzurichten.

von EGS (Gast)


Lesenswert?

Johann L. schrieb:
> Das ist kein C:
>
>
>
> • "code" ist kein Schlüsselwort in C
>
> • "at" ist kein Schlüsselwort in C
>
> • "0x.." ist an der Stelle wo es steht syntaktisch nicht erlaubt in C
>
>
>
> Vielleicht ist das ja BASIC oder so?

Wenn der jeweilige Compiler mit dieser Syntax klar kommt ist es 
spezieller C-Code.

Sieht mir aber her wie der Code aus nem Visual Studio aus.

von Mr.T (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Kapitän Nuss schrieb:
>
>> Leider mag mein Compiler (Realview) diese Syntax nicht.
>
> Tu dir selbst einen Gefallen und fang endlich damit an, das zu tun, was
> dir seit Stunden vorgeschlagen wird: durchforste die Doku!

YMMD :-D

> Wenn da etwas dafür vorgesehen ist, das man Flash-Bereiche als
> Zwischenspeicher verwenden kann, dann findest du das in der Doku und
> nicht hier im Forum!
In der Doku wohl kaum. Wichtig ist, dass man das Flash
- zur Laufzeit beschreiben kann
- sich u.U. Code dafür baut

>> Wie kann ich das ohne PEEK schreiben?
>
> Doku nachsehen!
Auch hier: welche Doku?
Entweder er nimmt das PEEK-Makro (wie das aufgebaut ist steht ja in 
derselben Zeile) oder er überlagert den Flashsektor mit einem pointer 
auf ein char-array z.B. Dann kann er byteweise über Index drauf 
zugreifen.

Sowas orndne ich unter C-Allgemeinwissen ein.

Grundsätzlich stimme ich Dir aber zu: lesen bildet ungemein ;)

von Hans-Georg L. (h-g-l)


Lesenswert?

Ein kurzer Blick ins Datenblatt vom ADuC7126 zeigt, das der Flash in 2 
Blöcke von je 64kB aufgeteilt ist, wobei beim ersten Block nur 62kB zur 
Verfügung stehen. Zum Schreiben in das Flash muss vorher der 
entsprechende Block gelöscht werden.

Das bedeutet für dich:

Du bekommst dein Programm vollständig in einen Block, dann kannst du den 
anderen Block löschen und neu beschreiben.

Wenn sich noch andere Daten im dem zu löschenden Block befinden musst du 
die vorher ins Ram sichern und hinterher wieder ins Flash schreiben. 
Deine Flash Programmieroutine, darf dabei natürlich auch nicht in dem zu 
löschenden Block liegen, sonst muss die auch aus dem Ram laufen.

Siehe Datenblatt unter: NONVOLATILE FLASH/EE MEMORY

Aber so wie es aussieht kann das Flash nur über Bootloader geschrieben 
werden und es gibt noch Fuses um das Flash zu sichern.

Da ändert auch ein C Compiler nichts daran ;)

Bei den Keil 8051/80166 Compilern kann man in bei den Linker 
Einstellungen Speicherbereiche reservieren.

von Ralf G. (ralg)


Lesenswert?

Für mich stellen sich noch andere Fragen:
Warum überhaupt Werte in den Programmspeicher schreiben? Warum nicht mit 
normalen Variablen hantieren und gelegentlich eine Datensicherung in den 
EPROM? Kannst du auch fix 'ne Funktion in Assembler mit einfügen? -> Da 
würde ich gar nichts reservieren, sondern einfach den Speicherblock ans 
Ende vom Flash legen und die Daten über so eine Funktion an die 
entsprechende Stelle schreiben. Da muss der Compiler/ Linker gar nichts 
davon wissen ;-)

Edit: bei einem einfachen AVR sollte das so gehen.

von Kapitän Nuss (Gast)


Lesenswert?

Ich habe das jetzt hinbekommen:
Unter Options für Target1 habe ich die IROM Größe von 0x1F800 auf 
0x1F600 veringert, d.h. es werden 512 Byte frei ab 0x9F600

Ich habe 3 Funktionen geschrieben:
erase_page, save und Hexdump
1
  FEE0MOD = 1 << 3; // Enable erase & write commands for 0x90000
2
  erase_page(0x9F600);
3
  save(0x9F600,0x01234567);
4
  save(0x9F604,0x89ABCDEF);
5
  Hexdump(0x9F600);
6
  while(1){}
7
}
8
//***************************************************************************
9
void Hexdump(unsigned long int Start_addr)
10
{
11
  unsigned long int addr,word;
12
  printf("\nDump des Programmspeichers:");
13
  for(addr = Start_addr;addr < (Start_addr + 0x200);addr += 4)
14
  {
15
    word = (*(unsigned long int *)(addr));
16
    if((addr & 0x1F) == 0)printf("\n%X ",addr);
17
    printf(" ");
18
    printf("%X",(word >> 28) & 0x0F);
19
    printf("%X",(word >> 24) & 0x0F);
20
    printf("%X",(word >> 20) & 0x0F);
21
    printf("%X",(word >> 16) & 0x0F);
22
    printf("%X",(word >> 12) & 0x0F);
23
    printf("%X",(word >>  8) & 0x0F);
24
    printf("%X",(word >>  4) & 0x0F);
25
    printf("%X",(word >>  0) & 0x0F);
26
  }
27
  printf("\n");
28
}
29
//***************************************************************************
30
void save(unsigned long int addr, unsigned long int data)
31
{
32
  if((addr & 0xF0000) == 0x80000)
33
  {
34
    FEE1ADR = addr;        // set data address
35
    FEE1DAT = data;        // set data value
36
    FEE1CON = 0x02;        // single Write command
37
    while (!(FEE1STA & 0x03)){};
38
    FEE1ADR = addr + 2;        // set data address
39
    FEE1DAT = data >> 16;        // set data value
40
    FEE1CON = 0x02;        // single Write command
41
    while (!(FEE1STA & 0x03)){};
42
  }
43
  if((addr & 0xF0000) == 0x90000)
44
  {
45
    FEE0ADR = addr;        // set data address
46
    FEE0DAT = data;        // set data value
47
    FEE0CON = 0x02;        // single Write command
48
    while (!(FEE0STA & 0x03)){};
49
    FEE0ADR = addr + 2;        // set data address
50
    FEE0DAT = data >> 16;        // set data value
51
    FEE0CON = 0x02;        // single Write command
52
    while (!(FEE0STA & 0x03)){};
53
  }
54
}
55
//***************************************************************************
56
void erase_page(unsigned long int addr)
57
{
58
  if((addr & 0xF0000) == 0x80000)
59
  {
60
    FEE1ADR = addr;        // set data address
61
    FEE1CON = 0x05;        // erase page command
62
    while (!(FEE1STA & 0x03)){};
63
  }
64
  if((addr & 0xF0000) == 0x90000)
65
  {
66
    FEE0ADR = addr;        // set data address
67
    FEE0CON = 0x05;        // erase page command
68
    while (!(FEE0STA & 0x03)){};
69
  }
70
}
71
//***************************************************************************

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.