www.mikrocontroller.net

Forum: Compiler & IDEs Problem mit pgm_read_byte_far


Autor: Tom Berger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

bitte kann mir jemand helfen?

Ich habe in meinem Mega128 sehr viel statische Daten die im Flash
liegen. Mittlerweile sind es weit über 100k. So viel ich weis, kann ich
die nicht mehr mit der Funktion pgm_read_byte auslesen, da diese
Funktion nur eine short Adresse hat.

Jetzt bin ich gezwungen auf die Funktion pgm_read_byte_far
umszusteigen, die eine long Adresse hat. Doch leider bringt der
Compiler Fehlermeldungen z.B. warning: cast from pointer to integer of
diffrent size oder error: SFR_IO_ADDR undeclared (fist use this
function).
Was jemand was da schief läuft.

Hier mein Code (pseudo)

long pos;
unsigned char temp;

const unsigned char Array [xxx] PROGMEM = { "Datenbytes" };

temp = pgm_read_byte_far (&Array[pos]);

Autor: mthomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zuerst: ist keine "Fehlermeldung", sondern "nur" eine Warnung. Aber
das hilft nicht wirklich. Soweit erinnert, verwaltet avr-gcc alle
Pointer mit 16bit, so auch die auf Flash/Progmem. Die *_far Funktionen
erwartet eine 32bit-Angabe (vgl. pgmspace.h). Ein Cast duerfte die
Warnung unterdruecken. Aber das ist wohl nur die "halbe Miete":
Soweit ich weiss, koennen mit PROGMEM nur Konstanten in den ersten 64kB
des Flash-Speichers angelegt werden, duerfte also bei 100kB noch von
anderer Stelle zu Problemen kommen.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Ich habe in meinem Mega128 sehr viel statische Daten die im Flash
liegen. Mittlerweile sind es weit über 100k."

Eine andere µC-Familie (z.B. ARM7) mag in der Grössenordnung sinnvoller
sein. Grosse Daten/Programme sind nicht die Stärke von 8-Bit
Prozessoren.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Tom,

ist zwar ne Weile her bei dir, aber ich habe gerade genau das gleiche
Problem. Hattest du damals eine Lösung gefunden?

Besten Dank,
Peter

Autor: Günter R. (galileo14)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"pgm_read_byte_far" will einen uint32_t-Wert als Parameter, daher
diese Warnung. Der normale Pointer-Mechanismus funktioniert hier nicht.
Man muß die Adresse in einen uint32_t packen und damit dann
"pgm_read_byte_far" aufrufen.

Autor: Peter Sager (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hierzu braucht's folgendes Makro, welches einen 32 Bit Pointer auf die
Progmem Daten zurück liefert:

//----------------------------------------------------------
// Macros to access data defined in PROGMEM above 64kB
//----------------------------------------------------------
#define FAR(var)                                      \
({                                                    \
    uint_farptr_t tmp;                                \
                                                      \
    _asm_ __volatile__(                             \
                                                      \
            "ldi    %A0, lo8(%1)"           "\n\t"    \
            "ldi    %B0, hi8(%1)"           "\n\t"    \
            "ldi    %C0, hh8(%1)"           "\n\t"    \
            "clr    %D0"                    "\n\t"    \
        :                                             \
            "=d" (tmp)                                \
        :                                             \
            "p"  (&(var))                             \
    );                                                \
    tmp;                                              \
})
//----------------------------------------------------------

Dann kannst Du z.B. auf die folgende Weise auf die Daten zugreifen:

MyByte = pgm_read_byte_far(FAR(MyProgMemPointer));


@jörg (falls Du zufällig hier reinschauen solltest)

Ich sehe immer wieder Threads mit Leuten, die über dieses Problem
stolpern. Wäre es nicht sinnvoll, dieses Makro in <pgmspace.h>
aufzunehmen?

MfG Peter

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Besten Dank euch beiden!

In der Zwischenzeit hatte ich mir eine proprietäre Lösung gebastelt,
aber der Ansatz über das FAR Makro mit der Direktive hh8(...) ist
natürlich schöner.

Macht's gut,
Peter

Autor: Tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich versuche nun schon eine ganze Weile das oben genannte Makro

//----------------------------------------------------------
// Macros to access data defined in PROGMEM above 64kB
//----------------------------------------------------------
#define FAR(var)                                      \
({                                                    \
    uint_farptr_t tmp;                                \
                                                      \
    asm volatile(                           \
                                                      \
            "ldi    %A0, lo8(%1)"           "\n\t"    \
            "ldi    %B0, hi8(%1)"           "\n\t"    \
            "ldi    %C0, hh8(%1)"           "\n\t"    \
            "clr    %D0"                    "\n\t"    \
        :                                             \
            "=d" (tmp)                                \
        :                                             \
            "p"  (&(var))                             \
    );                                                \
    tmp;                                              \
})
//----------------------------------------------------------

zu verwenden um auf Konstanten mittels pgm_read_byte_far zuzugreifen.


Ich bekomme jedoch in dieser Zeile

uint8_t b = pgm_read_byte_far(FAR(&array[X]));

immer die Fehlermeldung

error: invalid lvalue in unary '&'

Was ist falsch an dieser Zeile ? Ich habe testweise auch mal

uint8_t b = pgm_read_byte_far(FAR(array[X]));

probiert, was aber nur zur dreifachen Ausgabe von

undefined reference to `r30'
undefined reference to `r30'
undefined reference to `r30'

führt. Wäre schön wenn mir hier jemand helfen könnte.

Gruss, Tobias

Autor: Bernhard M. (boregard)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
probier mal:
uint8_t b = pgm_read_byte_far(FAR(&(array[X])));

Autor: Tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke erstmal, aber das führt leider zum gleichen Fehler..

invalid lvalue in unary '&'

Noch eine Idee ?

Autor: Tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Weiss denn wirklich niemand was ich falsch mache ?

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie hast du das Array deklariert, bzw. liegen die Array-Daten wirklich 
im FLASH? Das ist nämlich nicht ganz so trivial. Wenn man nicht gut 
aufpasst liegt zwar der Array-Pointer im Flash, nicht aber die Daten, 
oder umgekehrt.

Weitere Infos dazu findest Du in der Dokumentation zur Avr_LibC, im 
speziellen im Kapitel "9.10 Frequently Asked Questions"

Falls Dein "array" wirklich ein Pointer auf die gewünschte 
Progmem-Adresse ist, dann müsste es folgendermassen funktionieren:
uint8_t b = pgm_read_byte_far(FAR(array)+X);

So kannst Du sogar die Limitierung umgehen, dass mit dem Array-Index 
maximal 32kByte Adressierbar

Viel Erfolg

Autor: Josef Kaeufl (josefk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe das gleiche Problem wie Tobi. Ich glaube aber meinen String 
richtig im Flash liegen zu haben:
const char spi_start[] PROGMEM = "Aktiviere SPI...";
//...
void funktion(PGM_P s)
{
//...
  c= pgm_read_byte_far(FAR(s));
}

Hat da jemand schon eine Lösung?

Autor: Michael Betz (betz)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hy!
Versuche gerade einen Bootloader mit dem Usb Treiber von Objective 
Development auf einem Mega128 zum laufen zu kriegen.
Ich bekomme mit dem Makro leider auch Probleme, erhalte 3 malig die 
Fehlermeldung:
undefined reference to `r30'

Aufgebaut hab ich das so:
#define GET_FAR_ADDRESS(var)                          \
({                                                    \
    uint_farptr_t tmp;                                \
                                                      \
    __asm__ __volatile__(                             \
                                                      \
            "ldi    %A0, lo8(%1)"           "\n\t"    \
            "ldi    %B0, hi8(%1)"           "\n\t"    \
            "ldi    %C0, hh8(%1)"           "\n\t"    \
            "clr    %D0"                    "\n\t"    \
        :                                             \
            "=d" (tmp)                                \
        :                                             \
            "p"  (&(var))                             \
    );                                                \
    tmp;                                              \
}) 
#define PRG_RDB(addr)   pgm_read_byte_far( GET_FAR_ADDRESS(addr) )

Der Aufruf sieht dann folgendermaßen aus:
uchar *r = usbMsgPtr;
uchar c = PRG_RDB(r);

Wie kommt der Compiler da auf die Idee r30 anzumeckern?

Viele Grüsse

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es muss sichergestellt sein, daß (&(var)) oben zu einem Symbol auflöst, 
d.h die Adresse muss spätestens zur Link-Zeit feststehen. Ansonsten 
versucht gcc da wohl ein GPR einzusetzen, und dann stekt sowas da wie 
lo8(r30) oder so.

Autor: Michael Betz (betz)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm leider fehlt mir das nötige wissen über inline Assembler um da 
richtig durchzublicken.

Ich hab jetzt eine andere Lösung gefunden die für mich funktioniert:
#define PRG_RDB(addr)   pgm_read_byte_far(0x10000UL + (uint32_t) (uint16_t) addr)

Autor: subitus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit

  'pgm_read_byte_far(0x10000UL + (uint32_t) (uint16_t) addr)'

lässt sich nur der Flash-Speicher zwischen 64k..128k adressieren.


MfGruß,

subitus

Autor: Thomas K. (muetze1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... und wozu der doppelte cast?

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>... und wozu der doppelte cast?

Für jedes Jahr seit dem letzten Beitrag in diesem Thread einen...

Oliver

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.