www.mikrocontroller.net

Forum: Projekte & Code [avr-gcc]. post-increment Version von avr/pgmspace.h


Autor: Johann L. (gjlayde) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi, für manche Projekte kann folgender Header praktisch sein, wenn man 
mehrere aufeinander folgende Daten mit den pgm_read_xxx-Makros aus 
avr/pgmspace.h aus dem AVR-Flash lesen will.

Weil avr-gcc keine Memory-Qualifier wie "flash" etc. kennt, müssen die 
pgm_read-Sachen als Inline-Assembler umgesetzt werden.

Nach den Aufruf weiß der Compiler daher nicht mehr, welchen Wert das 
Z-Register (über das der Flash ausgelesen wird) hat und kann es daher 
nicht wiederverwenden.

Bei platz- und zeitkritischen Sachen kann es daher sinnvoll sein, die 
Makros aus dem beigefügten Header einzusetzen.

Entsprechen die pgm_read_xxx(addr)  Makros einem *addr, so entsprechen 
die pgm_read_xxx_inc(addr) Makros einem *addr++, wobei addr als 
Byte-Zeiger angesehen wird, wenn ein Byte gelesen wird, als Word-Zeiger 
bei einem Word, etc..

addr muss natürlich ein L-Value sein und darf keine Nebeneffekte haben.
addr zeigt nach dem Aufruf um so viele Bytes weiter, wie gelesen wurden.

Beispiel:
#include "pgmread-inc.h"

uint32_t wert32;
uint16_t wert16;
uint8_t  wert8;

void lese_3_bytes (const void* addr)
{
    wert8  = pgm_read_byte_inc (addr);
    wert16 = pgm_read_word_inc (addr);
    wert32 = pgm_read_dword_inc (addr);
}

// Mit den vertrauten Makros:
void lese_3_bytes (const uint8_t * addr)
{
    wert8  = pgm_read_byte (addr++);
    wert16 = pgm_read_word (addr);
    addr += 2;
    wert32 = pgm_read_dword (addr);
}

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

Bewertung
0 lesenswert
nicht lesenswert
Wäre schön, wenn du das als Patch zur avr-libc einreichen könntest,
vorzugsweise einschließlich einer Erweiterung der Dokumentation
(wobei es bei avr-libc für die ganze pgmspace.h-Geschichte außer
avr/pgmspace.h noch eine separate Doku gibt).

https://savannah.nongnu.org/patch/?func=additem&gr...

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei mir macht die Verwendung dieser Makros den Code zwar meistens fixer 
und kleiner, das ist aber nicht immer der Fall.

Es war eher als Hack gedacht wenn jemand Zeit- und/oder Platzprobleme 
hat.

Es ist etwas heimtückisch, weil es nicht, macht was man eigentlich 
denkt:

Das pgm_read_byte_inc macht zum Beispiel nicht
   (*(p)++)

sondern
   (*((const uint8_t*) p)++)

d.h. es erhöht p nicht wie einen Zeiger um 1, sondern wie einen int um 
1. Analog für die anderen _inc Makros.

Ausserdem darf p keine Nebeneffekte haben, wie
 *((++p,p))++

Immerhin gibt das ne Warnung.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Eigentlich würde mir so ne Lösung wie im Anhang ja besser gefallen...

Autor: Johann L. (gjlayde) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
...für simple Beispiele sieht das auch Klasse aus.

Aber schon für
void  u4 (char *u, unsigned char * q)
{
    *u++ = __builtin_pgm_read_byte (q++);
    *u++ = __builtin_pgm_read_byte (q++);
    *u++ = __builtin_pgm_read_byte (q++);
    *u++ = __builtin_pgm_read_byte (q++);
}

ist der Code echt unbrauchbar.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich versteh noch nicht so ganz wo du drauf hinaus willst.

Du kannst doch auch
void u4 (char *u, unsigned char *q)
{
    memcpy_P(u, q, 4);
}
oder
void u4 (char *u, unsigned char *q)
{
    *u = pgm_read_dword(q);
}
benutzen.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon K. wrote:
> Ich versteh noch nicht so ganz wo du drauf hinaus willst.
>
> Du kannst doch auch
> [...]
> benutzen.

Natürlich kann ich das. Ich weiß, wie ich als Anwender guten Code aus 
gcc + Inline asm rausbekomme und kenne die DOs und DONTs.

Momentan sehe ich das Thema aber aus der Sicht des Compilers und da 
stellt sich die Frage: Wie kann man sowas effektiv umsetzen?

Aus Sicht des Compilers ist die libc ja auch "nur" ein Anwender, und die 
anvisierten Builtins würden so benutzt werden wie die Inline-asm Makros 
aus der libc. Für den Anwender würde sich also nichts ändern.

Der Vorteil eines Builtins ist, daß man dem Compiler auf algebraischer 
Ebene sagen kann, was im Code geschieht. Ein asm hingegen ist eine 
BlackBox die dem Compiler bis auf deren Wirkung auf die Welt 
verschlossen ist. Was im asm selbst passiert, kann er nicht wissen und 
von daher auch nicht optimieren oder gewinnbringend verwenden.

Aus Sicht einer Optimierung interessant ist die Möglichkeit des 
post-increment und die Weiterverwendung von Z. Das wird zwar auch durch 
meine obigen Makros erreicht, aber

-- der Code wird dadurch nicht hübscher
-- man muss sich von hand drum kümmern wann man das einsetzt oder nicht
-- gcc weiß immer noch nicht was abgeht

Bei mehreren zu lesenden Daten erfordert das pgm_read_dword die 
Einführung einer Union; krumme Anzahlen sind nicht effektiv behandelbar.

Nehmen wir mal an, du willst 4 aufeinander folgende Bytes lesen ohne die 
Sachen in ne Union (in ner Union müssen die Sachen zudem genauso stehen 
wie im Flash) zu packen:
x = pgm_read_byte (p++);
y = pgm_read_byte (p++);
k = pgm_read_byte (p++);
v = pgm_read_byte (p++);

Und freu dich an dem Code, den avr-gcc daraus macht.

Der Königsweg neuer (Target-abhängiger) Qualifier wie "flash" oder 
"pgmspace" wird gcc -- wenn das überhaupt jemals unterstützt wird -- 
nicht in absehbarer Zeit liefern.

Damit gingen dann Sachen wie
char foo (const pgmspace char * p)
{
    return *p; // Kein pgm_read-Zeugs mehr
}

const pgmspace mytype_t ding = 
{
    char c;
    const pgmspace char * string;
};

char bar (const pgmspace mytype_t * p)
{
    return p->c + p->string[4];
}

und gcc könnte die passenden Dereferenzierungen erzeugen. Zurzeit gibt 
es nur ein Attribut, keinen Qualifier.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. wrote:
> Ausserdem darf p keine Nebeneffekte haben, wie
>
>
>  *((++p,p))++
> 

Ok, das kann man fixen mit "+z" anstatt "=z" + "1"

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.