Forum: Compiler & IDEs avr-gcc progmem immer noch?


von markus (Gast)


Lesenswert?

Muss man beim avr-gcc immer noch mittels Progmem auf konstante Tabellen 
zugreifen oder geht auch:?
1
const uint8_t test[]={1,2,3};
2
3
x=test[0];

von Karl H. (kbuchegg)


Lesenswert?

fast.
mit den neuesten gcc kannst du auch die Attributierung __flash benutzen

AVR-GCC-Tutorial
Im Abschnitt über die Flash Zugriffe (14.2)

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ein einfaches "const" allein kann auf einer Harvard-Maschine dafür
übrigens nicht genügen.  OK, zumindest nicht, solange man keine
generic pointers hat, aber die wiederum verursachen Overhead sowohl
hinsichtlich Speicherverbrauch als auch Laufzeit, daher ist das auf
einem Controller wenig wünschenswert.

von markus (Gast)


Lesenswert?

Ok, vielen Dank für eure Antworten. Ich dachte mal gehört zu haben, dass 
es mittlerweile ohne "PROGMEM" geht. Für die Portierbarkeit von Code auf 
einen ARM ist das manchmal ein wenig lästig.

von Walter Tarpan (Gast)


Lesenswert?

Nö.

Inhalt meiner pgmspace.h:
1
/*
2
 * Hilfsdefinitionen fuer die Kompatibilitaet mit AVR-Code
3
 * Progmem und Abhängigkeiten
4
 *
5
 * Created: 22.12.2013
6
 *  Author: Nicolas
7
 */
8
9
 #ifndef PGMSPACE_H
10
  #define PGMSPACE_H
11
12
13
  #include "com.h"
14
15
  #ifdef AVR
16
    #define flash __flash
17
    #include <avr/pgmspace.h>  
18
  #elif defined(STM32)
19
    #define PROGMEM 
20
    #define pgm_read_byte(a) (*a)
21
    #define flash
22
    #define PSTR(a) (a)
23
    #define strlen_P strlen
24
    #define strncpy_P strncpy
25
    #define snprintf_P snprintf
26
    #define printf_P printf
27
  #elif defined _MSC_VER
28
    #define PROGMEM 
29
    #define pgm_read_byte(a) (*a)
30
    #define flash
31
    #define PSTR(a) (a)
32
    #define strlen_P strlen
33
    #define strncpy_P strncpy
34
    #define snprintf_P _snprintf // _snprintf nicht ganz kompatibel zu
35
    #define snprintf _snprintf   // snprintf, aber hier reicht es
36
    #define printf_P mprintf
37
    #define printf mprintf
38
         
39
  #else
40
     #warning No MCU defined  
41
  #endif
42
43
#endif
Funktioniert auf AVR, ARM und unter Windows mit dem MSVC.

Viele Grüße
W.T.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Walter Tarpan schrieb:
>     #define pgm_read_byte(a) (*a)

Besser:

      #define pgm_read_byte(a) (*(a))

Das könnte sonst bei pgm_read_byte (adr + offset) in die Hose gehen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

markus schrieb:
> Ich dachte mal gehört zu haben, dass es mittlerweile ohne "PROGMEM"
> geht.

Es geht ohne die pgm_read_...-Funktionen, wenn man die (neue)
Deklarationsmethode mit __flash benutzt.  Anders als die frühere
Variante mit __attribute__((section(".progmem"))) kann der Compiler
den qualifier __flash intern am Datentyp mitführen und weiß daher,
dass er die entsprechenden Daten mittels LPM lesen muss statt mit LDS.

Aber es geht nicht ohne __flash.

von Walter Tarpan (Gast)


Lesenswert?

Frank M. schrieb:
> Besser:
>
>       #define pgm_read_byte(a) (*(a))
>
> Das könnte sonst bei pgm_read_byte (adr + offset) in die Hose gehen.

Stimmt. Ich sollte all meinen Quelltext stückweise in Foren posten :-)

von hal9000 (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Ein einfaches "const" allein kann auf einer Harvard-Maschine dafür
> übrigens nicht genügen.  OK, zumindest nicht, solange man keine generic
> pointers hat, aber die wiederum verursachen Overhead sowohl hinsichtlich
> Speicherverbrauch als auch Laufzeit, daher ist das auf einem Controller
> wenig wünschenswert.

DIe Aussage ist ja wohl der Groesste Unsinn. KEIL C51 kann das schon
seit 30 Jahren. Und das sehr Effizient

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

hal9000 schrieb:

> DIe Aussage ist ja wohl der Groesste Unsinn.

Soso.

> KEIL C51 kann das schon
> seit 30 Jahren. Und das sehr Effizient

Klar, mit generic pointers.  Man muss sich im Zeiger noch ein Bit
mit merken, welches aussagt, ob der Zeiger nun in RAM oder Flash
zeigt.  Dann muss jede damit befasste Routine zur Laufzeit
entscheiden, ob sie nun aus dem Flash oder RAM liest.

Beim AVR würde das bedeuten, dass man nicht mehr mit 16 Bit für einen
RAM-Zeiger auskommt, denn der RAM selbst braucht schon 16 Bit für die
Adressierung.  Damit braucht man dann ein ganzes Byte pro Zeiger mehr.

von Falk B. (falk)


Lesenswert?

@Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>Klar, mit generic pointers.  Man muss sich im Zeiger noch ein Bit
>mit merken, welches aussagt, ob der Zeiger nun in RAM oder Flash
>zeigt.  Dann muss jede damit befasste Routine zur Laufzeit
>entscheiden, ob sie nun aus dem Flash oder RAM liest.

Schon mal nicht schlecht, so muss man sich nicht selber drum kümmern.

>Beim AVR würde das bedeuten, dass man nicht mehr mit 16 Bit für einen
>RAM-Zeiger auskommt, denn der RAM selbst braucht schon 16 Bit für die
>Adressierung.  Damit braucht man dann ein ganzes Byte pro Zeiger mehr.

Dieses Opfer könnte man bringen, schließlich werden nicht tausende von 
Pointern in typischen AVR-Programmen verwendet.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
> Dieses Opfer könnte man bringen,

Müsste man es nur noch dem GCC beibiegen ...

> schließlich werden nicht tausende von
> Pointern in typischen AVR-Programmen verwendet.

Naja, hinreichend viele, wobei natürlich genügend davon wieder
wegoptimiert werden.

Andererseits: der Typ eines Zeigers ändert sich im Allgemeinen zur
Laufzeit nicht mehr.  Der Programmierer weiß also bereits vorher,
ob das Ding ins Flash oder in den RAM zeigt.  Dann kann man es doch
aber auch gleich passend deklarieren und sich den Overhead sparen,
oder?

von Falk B. (falk)


Lesenswert?

@ Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>Müsste man es nur noch dem GCC beibiegen ...

Jaja, der berühmte Spruch, "Wir müssten mal . . " ;-)

>aber auch gleich passend deklarieren und sich den Overhead sparen,
>oder?

Naja, es geht ja darum, dass man beim AVR RAM und Flash mit getrennten 
Zeigern und Zugriffen explizit handhaben muss. Das würde entfallen, so 
wie beim PC oder ähnlichen Systemen (ARM, MPS430, etc.) Ausserdem könnte 
man dann endlich mal die Speicheraddressierung jenseits von 64kB Flash 
sauber machen, ohne das "Hackermakro".

AVR-GCC-Tutorial -> Variablenzugriff >64kB

Oder man steigt gleich auf STM32 um ;-)
(Hallo mmvisual)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
> ohne das "Hackermakro".

Brauchst du für __flash nicht (denke ich jedenfalls, müsste es
verifizieren).

> Oder man steigt gleich auf STM32 um ;-)

Oder eben einen beliebigen anderen ARM.

von Max B. (theeye)


Lesenswert?

Karl Heinz schrieb:
> mit den neuesten gcc kannst du auch die Attributierung __flash benutzen
>
> AVR-GCC-Tutorial
> Im Abschnitt über die Flash Zugriffe (14.2)

Ich versuche mich gerade mit PROGMEM, bin nun allerdings über __flash 
gestolpert und würde hier direkt umschwenken wollen. Konkret in 
Verbindung mit einem Menü (für HD44780). Hat da jemand gute Tutorials, 
Beispielcode oder ähnliches? Bisher habe ich da nicht schönes zur 
Erklärung gefunden. Das AVR-GCC-Tutorial hier gibt auch nicht so viel 
her:
> Ein Zugriff auf Konstanten im Programmspeicher ist mittels avr-gcc erst
> ab Version 4.7 "transparent" möglich. Um Daten aus dem Flash zu lesen,
> muss die AVR-Instruktion LPM (Load from Program Memory) erzeugt werden,
> bei Controllern mit mehr als 64kiB Flash auch ELMP.
Danach geht es um PROGMEM.

Da das noch alles Neuland für mich ist, bin ich etwas verloren :-)

Gruß Max

edit:
Wer nach unten scrollt ist klar im Vorteil! Unter "Flash mit __flash und 
Embedded-C" stehen schonmal interessante Infos. Mal sehen, ob es so 
besser klappt :). Bin natürlich weiterhin an entsprechenden Infos etc. 
interessiert.

: Bearbeitet durch User
von Karol B. (johnpatcher)


Lesenswert?

Gibt es mit diesem neuen Qualifier eigentlich eine Möglichkeit einen 
String direkt (ohne eine Variable erstellen zu müssen) im Flash 
abzulegen, also ein Äquivalent zum PSTR() Makro?

Edit: Auch ich hätte wohl erstmal genau gucken sollen. Die Antwort 
findet sich im Wiki und lautet: FSTR(), wobei es trotzdem noch einmal 
Unterschiede zu PSTR() gibt.

So ganz einschätzen kann ich dieses Feature aber noch nicht. Wenn ich 
das richtig sehe, dann gibt es jetzt drei Möglichkeiten, um eine 
Funktion zu implementieren, welche Daten aus dem RAM und Flash 
entgegennehmen kann:

- Wie bisher, d.h. jeweils zwei Versionen mit einer "_P" Version, wenn 
man Daten aus dem Flash lesen möchte, wobei man den Parameter direkt mit 
dem __flash Qualifier versehen kann und sich dadurch das pgm_read* 
Gedöns erspart.

- Eine Funktion mit einem zusätzlichen Parameter, welcher Auskunft 
darüber gibt, ob es sich um Daten aus dem Flash handelt. Abhängig davon 
kann man die Argumente entsprechend Casten.

- Verwenden des __memx Addressbereichs. Dadurch werden Zeiger ein Byte 
länger (24 Byte) und es kann zur Laufzeit festgestellt werden auf 
welchen Bereich man sich bezieht. Nachteil: Overhead

Hat das jemand schon einmal im größeren Maßstab umgesetzt? Würde das 
alles gerne mal in einem größeren Projekt sehen und wie man die dabei 
auftretenden Probleme gelöst bekommt. Ich empfand die Lösung über das 
PROGMEM Attribut zwar nie als wirklich schön (vor allem bei mehrfacher 
Indirektion muss man sehr viel "Herumtricksen"), aber irgendwie hat man 
sich über die Jahre dann doch daran gewöhnt ;).

Btw: Würde ein solcher Qualifier nicht auf das EEPROM Sinn machen?

Mit freundlichen Grüßen,
Karol Babioch

: Bearbeitet durch User
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.