Hi!
Kann es sein, dass der GCC es noch nicht so ganz drauf hat mit 32-Bit
Arithmetik im AVR?
cplex_data ist eine 32-Bit Variable, seconds, minutes und hours sind
8-Bit Variablen. Das ganze ist für eine Binär-Uhr und soll das
Ausgaberegister für den Charlieplexer zusammenbauen.
Diese Zeile jedoch wird vom Compiler mit 300(!!) Bytes an Code
übersetzt.
Eigentlich hat der AVR da kaum Arbeit. cplex_data besteht aus 4
einzelnen 8-bit speicherstellen. Seconds kann man einfach mit der ersten
OR-verknüpfen. Minutes muss in zwei Stücke zerteilt werden, wovon das
erste mit der ersten Speicherstelle OR-verknüpft und das zweite einfach
in die zweite Speicherstelle kopiert wird. Bei Hours ist es nicht
wesentlich komplizierter. Genauergesagt würden 24bit auch ausreichen
aber es gibt standardmäßig keinen 24-bit Datentyp.
Kann man irgendwie auf die einzelnen Speicherstellen zugreifen und das
ganze somit per Hand etwas optimieren?
lg PoWl
Welchen Optimierungs-Level hast Du eingestellt? Ich empfehle zumindest
-O1 zu verwenden. Die anderen Stufen -O2/3/s bringen kaum noch was.
Verwendest Du die für den AVR optimierte MathLib? (Linker Option -lm)
Defaultmässig wird nämlich die generische GCC MathLib gelinkt, die ist
natürlich gross und langsam.
>> Diese Zeile jedoch wird vom Compiler mit 300(!!) Bytes an Code> übersetzt.
Sicher?
Bei mir sind es ganz ohne Optimierungen 112 Bytes und mit "-Os" 86
Bytes.
> Eigentlich hat der AVR da kaum Arbeit.
Der AVR hat keine Asm-Befehle für mehrfaches Schieben, also muss "<< 6"
und "<< 12" über Schleifen realisiert werden und das auch noch mit
32-Bit Werten. Da kommt halt einiges zusammen.
Du kannst den Code etwas reduzieren, indem du den Compiler nicht dazu
zwingst, alles in 32-Bit zu tun:
vielleicht liegts auch daran dass alle variablen volatile sind.
Thx ich versuche mal das aufzuteilen.
Kann man die einzelnen Speicherstellen der 32-Bit Variable irgendwie
einzeln erreichen?
1
cplex_data=((uint16_t)minutes<<6)|seconds;
2
cplex_data|=((uint32_t)hours<<12);
Das wird bei mir bei -Os leider sogar noch 32 Bytes länger als vorher.
> Kann man die einzelnen Speicherstellen der 32-Bit Variable irgendwie> einzeln erreichen?
Klar, aber was soll dir das hier konkret bringen?
> oh tut mir leid.. hab mich wohl irgendwie verguckt?! Bei mir sinds auch> 86 Bytes. Der Zweizeiler bringt es allerdings auf 90.
Wenn cplex_data volatile ist, wird es beim Zweizeiler ja zwischendurch
gespeichert und neu geladen. Das sind immerhin 32 Byte. Du könntest das
mit einer temporären nicht volatile Variable umgehen. Ich frage mich
allerdings, ob cplex_data überhaupt volatile sein muss.
Must du unbedingt so krumme Werte für die Bit-Schieberei nehmen? Wenn du
die Möglichkeit hast, die Daten so abzuspeichern wie du willst, dann
kannst du jeweils ein ganzes Byte für einen Wert nehmen. Das ist
bedeutend effizienter.
@Jörg Wunsch (dl8dtl) (Moderator)
>> vielleicht liegts auch daran dass alle variablen volatile sind.>Aua!
Sicher ist sicher, damit die nicht weglaufen . . . ;-)
> sie müssen volatile sein weil mein programm noch etwas mehr als nur> diese paar zeilen umfasst
Was spricht dagegen, die volatile-Variablen im ersten Schritt in
temporäre (sprich, lokale) nicht-volatile-Variablen zu kopieren und die
shifts dann mit denen zu machen?
Denn es ist ja eh klar, dass 32-Bit-Variablen auch mit volatile nicht
atomar bearbeitet werden können, also immer noch andere
Synchronisationsmechanismen vorhanden sein müssen.
Chris wrote:
> Was spricht dagegen, die volatile-Variablen im ersten Schritt in> temporäre (sprich, lokale) nicht-volatile-Variablen zu kopieren und die> shifts dann mit denen zu machen?
Ist gar nicht nötig (bzw vergrößert den Code nur), da nur lesend auf die
Variablen zugegriffen wird. Nur beim cplex_data stört das volatile,
insbesondere in der Version mit den zwei Zeilen. Lässt sich aber leicht
"entschärfen":
1
uint32_ttemp;
2
temp=((uint16_t)minutes<<6)|seconds;
3
temp|=((uint32_t)hours<<12);
4
cplex_data=temp;
Paul Hamacher wrote:
> sie müssen volatile sein weil mein programm noch etwas mehr als nur> diese paar zeilen umfasst
Sorry, aber ich vertraue deinen C-Kenntnissen nicht weit genug, um das
einfach so zu glauben. Wenn du nämlich cplex_data in einem Interrupt
rausschiftest und im "normalen" Code zusammenstellst (oder einem anderen
Interrupt), sehe ich nicht, warum das zwingend volatile sein muss.
"Zu viel" volatile ist meist der Anschlussfehler zu "gar kein" volatile.
Und warst du nicht erst kürzlich beim Status "gar kein", oder verwechsel
ich dich da?
Das wird sowohl im Interrupt gelesen als auch geschrieben und muss im
gesamten Programm verfügbar sein.
Ja, ich gebe zu, ich würde mich auch eher zu den Anfängern schätzen,
aber Übung macht den Meister.
Danke jedenfalls für die Hilfe!
Paul Hamacher wrote:
> Das wird sowohl im Interrupt gelesen als auch geschrieben und muss im> gesamten Programm verfügbar sein.
Wie gesagt, das alleine macht ein volatile nicht zwingend nötig.
Paul Hamacher wrote:
> Eigentlich hat der AVR da kaum Arbeit. cplex_data besteht aus 4> einzelnen 8-bit speicherstellen.
Was spricht dann dagegen, es als Array aus 4 Bytes zu definieren?
32Bit mag der AVR-GCC nicht, er macht dann immer 4 Byte-Zugriffe.
8Bit kann er wesentlich besser optimieren.
Peter
bitfield benutzer wrote:
> sollte man normalerweise ja aus Portabilitätsgründen meiden
Das ist hochgradiger Quatsch! Bitfelder sind C-definiert.
Portabilitätsbedenken gibts nur, wenn man versucht solche Bitfields
(beispielsweise) über Netzwerk überträgt und die eine Maschine
Big-Endian ist, und die andere Little-Endian.
Oder wenn man ein Bitfield benutzt und das dann um-castet in eine
integrale Variable (int, long, char). Die Position der Bits ist nämlich
nicht bei jeder Maschine gleich.
Wenn man das Bitfeld aber nur zum Speichern von Daten verwendet, die auf
ein und der selben Maschine bleiben und auf die auch nur über die
Elemente des Bitfields zugegriffen wird, stimmt alles.
Also dein Beispiel wäre in Ordnung.
bitfield benutzer wrote:
> Macht 30 byte. Mit einer 24h Uhr wird es für den Compiler etwas> komplexer und er kommt auf 52 bytes.
Also keinerlei Vorteil gegenüber der Lösung ohne Bitfelder.
Simon K. wrote:
> Das ist hochgradiger Quatsch! Bitfelder sind C-definiert.
naja, nur bedingt, wie Du ja so richtig im nächsten Absatz beschrieben
hast. Wenn man Daten mit anderen Systemen austauschen muß, sollte man
Bitfelder meiden, da abhängig von der Kompilerimplementierungen
(schriebst Du ja schon). Hab viel mit solchen Systemen zu tun, deswegen
meine Bemerkung. War vielleicht etwas unvollständig, sorry.
@Stefan Ernst:
Wird schon so sein, sieht aber IMHO mit Bitfeldern etwas übersichtlicher
aus. Und der OP hat ja explizit gefragt, ob es eine Möglichkeit gibt,
direkt auf die Speicherstellen zuzugreifen. Klang für mich nach
Bitfeldern.
Paul Hamacher wrote:
> Wenn ich das volatile weglasse erzeugt der Compiler noch 2 Bytes mehr> code.. gibt sich wohl nicht viel.
Hallo,
das volatile nervt mich auch immer ein wenig. Es soll verhindern, daß
der Wert in registern gehalten wird und im Speicher immer der alte Wert
zu lesen ist.
Es schützt aber meines Wissens nicht wirklich dagegen, daß die Änderung
nur teilweise durchgeführt wurde, bis der Interrupt dazwischen sprang.
Wie ist das mit nem einfachen volatile integer x, kann da der Interrupt
bei einem x -= 100 im Hauptprogramm zwischen die Befehle
dazwischespringen ? D.h. benötige ich nicht eigentlich ein cli() und
sei() drumherum ?
Gruss,
Michael
> Wie ist das mit nem einfachen volatile integer x, kann da der Interrupt> bei einem x -= 100 im Hauptprogramm zwischen die Befehle> dazwischespringen ?
Ja, kann er, weil diese Zuweisung nicht mit einem Maschinenbefehl zu
schaffen ist.
@ Michael Appelt (micha54)
>Es schützt aber meines Wissens nicht wirklich dagegen, daß die Änderung>nur teilweise durchgeführt wurde, bis der Interrupt dazwischen sprang.
Richtig.
>dazwischespringen ? D.h. benötige ich nicht eigentlich ein cli() und>sei() drumherum ?
Ja, siehe Interrupt.
MFG
Falk
hallo,
wenn ich auf die stellen einer 32 bit variabel schreiben möchte, nehme
ich immer einen gecasteten void pointer. so kann man z.b. bequem in 8
bit häppchen schreiben.
hab mal die hier geschriebenen sachen ausprobiert und komme mit meiner
methode auf 28 byte an code...
Daniel Platte wrote:
> hab mal die hier geschriebenen sachen ausprobiert und komme mit meiner> methode auf 28 byte an code...
Schön. Nur dumm, dass dein Code nicht das macht, was der ursprüngliche
Code tut und der OP braucht.