Hallo,
ich habe ein Array im Flash (mit const __flash), das zur Laufzeit
umkopiert wird. Die Zeile mit memcpy bringt mir eine Warnung:
"warning: incompatible implicit declaration of built-in function
'memcpy'"
Wenn ich statt dessen versuche, memcpy_P zu verwenden, kommt diese
Warnung:
"warning: conversion from address space '__flash' to address space
'generic'"
Wie macht man es richtig??
Compiler: avr-gcc
Pupsomat schrieb:> Wie macht man es richtig??
gar nicht würd ich sagen... __flash ist eine C Erweiterung, die memcpy
aus der standardlib nicht kennt. du musst das also "manuell" kopieren
oder deine eigene memcpy funktion schreiben.
lg
Das ist zwar vom mingw, bei der avr-libc dürfts aber auch ned recht viel
anders aussehen.
Da der Speicherbereich (Flash, RAM, EEPROM) nicht aus dem Zeiger
ersichtlich ist sondern über das __flash Attribute mitgeschleppt wird
geht diese Information also beim Aufruf von memcpy verloren.
Dadurch kopierst du irgendwelche Daten, die im RAM zufällig da liegen.
Der Tipp meines Vorposters mit der <string.h> ist falsch.
Du wirst deine eigene memcpy schreiben müssen.
Die muss einen Zeiger auf __flash Daten und einen RAM Zeiger erwarten.
Ohne Gewähr denke ich der Prototyp muss so aussehen:
Das ist schlecht. Ich hatte vor, alle Deklarationen mit PROGMEM im Code
durch welche mit __flash zu ersetzen, um einheitliche Aufrufe verwenden
zu können (wie beworben).
Schade. Jetzt greife ich zumindest in diesem Fall nochmal auf PROGMEM
zurück.
Pupsomat schrieb:> Das ist schlecht. Ich hatte vor, alle Deklarationen mit PROGMEM im Code> durch welche mit __flash zu ersetzen, um einheitliche Aufrufe verwenden> zu können (wie beworben).> Schade. Jetzt greife ich zumindest in diesem Fall nochmal auf PROGMEM> zurück.
Na ja. Was hindet dich jetzt, tatsächlich ein memcpy dafür zu schreiben?
Ist ja nichts anderes als eine entsprechende Schleife. Was anderes macht
ja das normale memcpy auch nicht und auf einem AVR geht auch nichts
anderes, was Speed-Vorteile bringen würde.
> Ohne Gewähr denke ich der Prototyp muss so aussehen:>> void* memcpy (void* __flash, const void*, size_t);> (oder so ähnlich)
vor allen Dingen: so ähnlich
1
void*memcpy(void*dst,__flashvoid*src,size_tsize);
Die Reihenfolge der Argumente bei memcpy und strcpy lehnt sich an die
'Reihenfolge' in
1
dst=src
an. Liest man das als einer, der mit einer westlichen Sprache
aufgewachsen ist, dann stöesst man beim Lesen von links nach rechts
zuerst auf die Angabe vom Ziel ('Destination') und dann auf die von der
Quelle ('Source'). Nicht anders ist das in der Argumentliste von memcpy
und strcpy.
Najaaa, ursprünglich war der Einsatz von memcpy (_P in diesem Fall) eine
Optimierungslösung, weil die Schleifenversion zu viele Bytes gefressen
hat. Ich bin auch ganz zufrieden damit und dachte jetzt, es gibt auch
eine __flash-Alternative.
Pupsomat schrieb:> Najaaa, ursprünglich war der Einsatz von memcpy (_P in diesem Fall) eine> Optimierungslösung, weil die Schleifenversion zu viele Bytes gefressen> hat.
?
Fakt ist, dass ein AVR auf den Flash nur Byteweise zugreifen kann. Egal
wie, egal wann, egal wer optimiert. An
1
for(i=0;i<size;i++)
2
*dst++=*src++;
führt auf einem AVR kein Weg vorbei.
Das war keine Optimierungslösung, sondern ein Ersatz für pgm_readBlock,
welches es so in pgmspace.h nicht gibt, weil es ja bereits die
entsprechenden memcpy Funktionen gibt und memcpy zu einer
standardkonformen Implementierung der C-Standardfunktionen dazugehört.
> Ich bin auch ganz zufrieden damit und dachte jetzt, es gibt auch> eine __flash-Alternative.
Du kannst dir ja eine schreiben. Deswegen musst du noch lange nicht auf
die PROGMEM Variante zurückfallen, nur weil es keine memcpy Variante
gibt, die einen __flash Pointer nimmt (was ich nich überprüfen kann,
weil meine Compilerversion zu alt ist und noch kein __flash kennt. Und
nein, ich update deswegen meinen Compiler nicht)
1
voidmemcpy(void*dst,__flashvoid*src,size_tsize)
2
{
3
uint8_t*dstBytes=(uint8_t*)dst;
4
__flashuint8_t*srcBytes=(__flashuint8_t*)src;
5
size_ti;
6
7
for(i=0;i<size;i++)
8
*dstBytes++=*srcBytes++;
9
}
(wenn sicher ist, dass nie mehr als 255 Bytes involviert sind, könnte
man auch size_t spritzen und durch eine Variante mit einem uint8_t als
Längenangabe gehen.
Ohne i wird es 8 Bytes größer. Wahrscheinlich werden da Register hin-
und herkopiert. Übergaberegister != Arbeitsregister oder sowas. Bin
jetzt zu faul, mir das .lss anzugucken.
Pupsomat schrieb:> Schalter u.a. -flto
auch bei -flto sind beide gleich groß.
Voraussetzung:
Wenn -flto als Compiler-Flag, dann -flto auch als Linker-Flag und
zusätzlich dann auch noch -Os als Linker-Flag.
(Warum man -Os dann auch beim Linken angeben muss, wenn man FLTO nutzt,
wurde hier bereits öfter breitgetreten.)
EDIT:
Gerade auch noch mal mit 4.8.1 getestet: Gleiche Codegröße, kein
Unterschied. Hätte mich auch echt gewundert. Der gcc ist nicht blöd.
Das wird kontextabhängig sein. Da gcc, wie du sagst, nicht blöd ist,
nutzt er Seiteneffekte. Ich habe mal nachgesehen. Weiter unten im Code
brauche ich den Wert von "size" nochmal. Bei der for-Variante ist der
Wert noch irgendwo in Registern vorhanden. Bei der while-Variante
(welche runterzählt) nicht mehr ohne Weiteres.
Jedenfalls ist das jetzt meine Erklärung...