Forum: Mikrocontroller und Digitale Elektronik 32 bit Zeiger auf Flash AVR 8-Bit GCC


von GccNewbiee (Gast)


Lesenswert?

Hallo,

ich habe einen Struktur mit "PROGMEM" definiert. Der Struktur wurde an 
der Adresse 0x1e098 des Flashes gespeichert (durch debuggen abgelesen) 
gespeichtert, nun möchte ich mit Hilfe eines pointers die Adresse des 
Struktures im laufenden Prgramm bestimmen.

1. versuch
1
uint32_t *pbuffer; // pointer auf Struct

2. Versuch
1
prog_uint32_t *pbuffer;

bei beiden Varianten bekomme ich nur die ersten 2 Bytes "e098" zurück!!

weiss jemand was ich falsch mache!!

Danke!

von Falk B. (falk)


Lesenswert?

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmspeicher_.28Flash.29

Pointer sind im AVR eher 16 Bit, nur in Ausnahmen größer.

von GccNewbiee (Gast)


Lesenswert?

ok, danke für den Link. Aber leider bleibt meine Frage immer noch 
unbeantwortet. wenn ein Pointer nur 16 bit Werte annehmen kann, wie ist 
es dann möglich die Adresse der gespeicherten daten am ende eines 128 
Kbyte größen Flashes zu ermitteln?

von Falk B. (falk)


Lesenswert?

Das ist etwas kniffelig, ich glaube da gibt es normale und far Pointer. 
Hab ich aber noch nie gemacht, 64kB sind für alle Zeit ausreichend ;-)

von Falk B. (falk)


Lesenswert?

Hmm, die Doku der avr libc sagt, dass es near pointer (16 bit) und far 
pointer (32 Bit) gibt.

von arash j. (arashjavan)


Lesenswert?

ja das mit 64KB stimmt. Das Problem ist, dass sich meine App im 
bootloader bereich befindet (128 Kb Flash). Deswegen brach ich einen 
Pointer der auch auf oberen Bereich des Flashes zeigen kann. Der 
Farpointer ist soweit ich weiss nur einen anderen Ausdruck für
1
uint32_t
habe die ganze Zeit im Internat nach gegoogelt bis jetzt nichts 
brauchbares gefunden!!!!

von Stephan B. (matrixstorm)


Lesenswert?

Hallo GccNewbiee

PROGMEM Strukturen sind immer "const", da sich die Daten nicht wirklich 
im Arbeitsspeicher sondern lediglich im Flash befinden.
Eine Pointeroperation (Adressaufloesung) mittels "&variablenname" 
liefert zwar einen gültigen Pointer, aber dessen Adresse hat nichts mit 
den Daten im RAM zu tun und könnte sogar höher sein, als der RAM selbst 
groß ist.
(Damit wird um die C-Philosophie: "alles in einen Speicher" 
herumgewerkelt.)
Ein Zugriff auf die Daten ist daher nur mit speziellen AVR-libc 
Funktionen möglich:

http://nongnu.org/avr-libc/user-manual/pgmspace.html


Wenn du mit den PGM Funktionen arbeiten willst, nutze in deinem Code 
bitte das Makro "FLASHEND" um zwischen den FAR und NEAR Version zu 
switchen.
Ein Beispiel aus dem Updater des USBaspLoaders ( 
https://github.com/baerwolf/USBaspLoader/blob/master/updater/updater.c 
):
1
#if (FLASHEND > 65535)
2
      a=pgm_read_word_far((void*)&new_firmware[i]);
3
      b=pgm_read_word_far(NEW_BOOTLOADER_ADDRESS+i);
4
#else
5
      a=pgm_read_word((void*)&new_firmware[i]);
6
      b=pgm_read_word(NEW_BOOTLOADER_ADDRESS+i);
7
#endif

"new_firmware" ist dabei:
1
extern const uint16_t usbasploader[SIZEOF_new_firmware>>1] PROGMEM;
2
const uint8_t *new_firmware  =  (void*)&usbasploader;

Der Pointer den C liefert, müsste immer als 32Bit verwendbar sein, aber 
nach " http://nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html 
" benutzt du dann wahlweise short oder long als Adresse im Flash selbst.
Wo dann deine Firmware im speziellen gelinkt ist, ist egal, da  von 
überall auf überall im Flash gelesen werden kann.
(Insofern du die FAR Funktionen bei Flash > 64KB verwendest. Immer FAR 
verwenden funktioniert aber nicht, das AVRs mit weniger als 64K diese 
FAR Funktionen ggf. nicht anbieten...)

MfG

von arash j. (arashjavan)


Lesenswert?

Hallo Stephan,

Danke für die ausführliche Antowrt, ich kann zwar wie du schon 
beschrieben hast die Flashdaten mit:
1
pgm_read_word_far(adress)
lesen. Was ich aber benötige ist zuerst einen Pointer auf diese Daten, 
etwa wie:
1
// MyStruct ist an der Adresse 0x1e098 gespeichert! 
2
uint32_t *u32_ptrStrukturFlash = (&(MyStruktur.Length)); // Ptr auf Struktur
3
4
for (uint8_t i = 0; i<DataSize; i++)
5
{
6
 // Daten aus dem Struct lesen 
7
 u8_data =pgm_read_byte_far(u32_ptrStrukturFlash++);
8
}

nun weiß ich, dass bei AVR ein Pointer nicht länger als 16-Bit sein 
kann. Die Funktionen in libc sind ja zum lesen von Dateien aus einer 
vorher bestimmten Adresse geeignet. Welchen weg gibt es bei AVR die 
Adresse von Variablen selbst ab zulesen?

Danke voraus

von Stephan B. (matrixstorm)


Lesenswert?

Hi.
Soweit mir bekannt ist, stellt die AVR-toolchain sicher, dass PROGMEMs 
in die oberen 64K deiner firmware gelinkt werden.
Insofern du also deine Firware ab Adresse 0x0000 installierst, müsstest 
du bis zu (fast) 64KB PROGMEMs ganz normal nutzen können.

Wenn du an andere Adressen im Flash installierst (Bootloader), dann 
solltest du ein Makro "BOOTLOADER_ADDRESS" verwenden und überall im Code 
(insofern FLASHEND>65535) die Progmem-Adresse mit 
"(((uint32_t)BOOTLOADER_ADDRESS) & ((uint32_t)0xffff0000))" ODER 
verknüpfen:
1
#if (FLASHEND > 65535)
2
uint32_t realAddress = ((uint32t)(&PROGMEMvariable)) | (((uint32_t)BOOTLOADER_ADDRESS) & ((uint32_t)0xffff0000));
3
#else
4
uint16_t realAddress = &PROGMEMvariable;
5
#endif

Wenn natürlich deine "BOOTLOADER_ADDRESS" nicht 64K aligned ist, hast du 
entsprechend weniger (als 64KB) PROGMEM Speicher zur Verfügung.

MfG

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.