Hallo,
ich habe das Problem, dass ich in einer Funktion der ein Struct als
Parameter übergeben wird keinen Wert zuweisen kann. Mache ich den Umweg
über die lokale Variable temp, so geht's und dann komischerweise auch
für alle anderen Elemente.
Woran könnte das liegen?
Vielen Dank für Eure Hilfe.
Wie genau äussert sich das "geht nicht" ?
Und etwas Hintergrundinfo über den verwendeten Comiler und die
Zielplattform würde auch nicht schaden.
Oliver
Michael8164 schrieb:> Mit "geht nicht" meinte ich wenn ing_error.temp_shutdown> das Bit gesetzt ist, kann ich den Wert nicht inerror->temp_shutdown> kopieren.
Jetzt hast du immer noch nicht geschrieben, was das bedeutet. Also
nochmal gefragt: Wie äußert sich "kann nicht"? Was passiert denn, wenn
du es trotzdem versuchst?
Hm. Hab gerade rausgefunden, dass es wohl daran liegt dass ich die
Elemente im Bitfield mit "volatile" definiert habe. Lasse ich das weg,
ist alles ok. Ich brauche aber das volatile, da die Elemente des
Bitfields auch im Interrupt geschrieben werden können.
Bei mir ist
Michael8164 schrieb:> Ich brauche aber das volatile, da die Elemente des Bitfields auch im> Interrupt geschrieben werden können.
Zum Beispiel auch das Shutdown-Flag wieder auf 0?
Also ich habe eine paar Tests gemacht und m.E. funktioniert es nur wenn
die struct nicht als volatile definiert wird (weder insgesamt noch die
einzelnen Elemente).
Muss mich korrigieren...
Wenn ich die struct als Ganzes volatile definiere, funktioniert die
Zuweisung. Allerdings gibt es dann eine Compilerwarnung wahrscheinlich
weil im Prototyp ein "normales" struct verwendet wird:
warning: (359) illegal conversion between pointer types
pointer to volatile struct bitfield_error_flags -> pointer to struct
bitfield_error_flags
Man sieht zwar nicht wir du die temp-Variable deklariert hast,
allerdings wäre an der Stelle mein Ansatzpunkte.
Der Unterschied zwischen geht und geht nicht ist ja laut deinem Beispiel
der unterschiedliche Datentyp der rechten Seite deiner Zuweisung.
1
volatileuint8_type:1=volatileuint8_type:1//geht nicht
2
volatileuint8_type:1=uint8_type//geht
Versuch doch spaßeshalber mal die Attribute nicht als Bit-Felder zu
deklarieren. Sollte es dann funktionieren, weißt du schon mal das dein
Compiler damit Probleme hat.
1
structbitfield_error_flags
2
{
3
volatileuint8_typetemp_shutdown;
4
volatileuint8_typeicht_error;
5
volatileuint8_typelaser1_locked;
6
volatileuint8_typelaser1_error;
7
volatileuint8_typelaser1_overcurrent;
8
volatileuint8_typeeeprom_error;
9
volatileuint8_typei2c_error;
10
};
Und solltest du das Struct nicht als Teil eines Protokolls verwenden ist
die Speicherplatzersparnis mittels Bit-Felder meist eh zu
vernachlässigen.
Hab's noch nie versucht: kann man auch einen Funktionsparameter volatile
deklarieren?
Eigentlich kam mir die Idee volatile schon in einer Typendeklaration zu
verwenden dirket komisch vor. Der Typ sollte ja nur die Struktur
definieren, und nicht unnötig Eigenschaften der Instanzen davon
erzwingen.
Michael8164 schrieb:> struct bitfield_error_flags g_error = {0U, 0U, 0U, 0U, 0U, 0U,> 0U};
Das ist eine Definition und Initialisierung - die hat in einer
Headerdatei (*.h) absolut gar nichts verloren.
Der Typ soll allerdings auch so unnötige Eigenschaften der Instanz wie
die Attribute festlegen. Wie, Attribute sind nicht unnötig? Volatile
aber auch nicht. Wenn du das volatile, Aufgrund von "Multithreading",
brauchst dann muss es angegeben werden. Ansonsten bekommst du nur
undefiniertes Verhalten.
Man kann einen Zugriff war nachträglich noch als volatile über einen
Pointer festlegen, allerdings ist das nur ein überschüssiges Konstrukt.
Rufus Τ. F. schrieb:> Michael8164 schrieb:>> struct bitfield_error_flags g_error = {0U, 0U, 0U, 0U, 0U, 0U,>> 0U};>> Das ist eine Definition und Initialisierung - die hat in einer> Headerdatei (*.h) absolut gar nichts verloren.
Man müsste sogar mit extern arbeiten
C0S schrieb:> Man kann einen Zugriff war nachträglich noch als volatile über einen> Pointer festlegen, allerdings ist das nur ein überschüssiges Konstrukt.
Hat man nun aber einen Mischmasch, einige Felder müssen volatile sein,
andere nicht. Wäre es überhaupt syntaktisch möglich zu definieren OHNE
das direkt im Struct zu tun?
FrickelFranz schrieb:> Hat man nun aber einen Mischmasch, einige Felder müssen volatile sein,> andere nicht. Wäre es überhaupt syntaktisch möglich zu definieren OHNE> das direkt im Struct zu tun?
Gegenfrage. Ist deine Anwendung so Leistungsorientiert das du es nicht
verschmerzen kannst wenn mehr Variablen als unbedingt nötig nicht
gecacht werden?
Um deine Frage aber zu beantworten: Nein (geht mit Aufwand schon, macht
aber faktisch nie Sinn).
Außerdem spricht ja theoretisch nichts dagegen, volatile in der
Deklaration zu verwenden.
Michael8164 schrieb:> struct bitfield_error_flags g_error = {0U, 0U, 0U, 0U, 0U, 0U,> 0U};> struct bitfield_error_flags g_error_post = {0U, 0U, 0U, 0U, 0U, 0U,> 0U};> struct bitfield_error_flags g_error_bit = {0U, 0U, 0U, 0U, 0U, 0U,> 0U};
Du definierst Variablen im Prototype.h file.
Sobald Du Prototype.h (oder Header.h, in dem Prototype.h includiert
wird) in einem weiteren File includierst, bekommst Du eine
Fehlermeldung, weil die Variablen dann mehrfach definiert werden.
Besser schreibst Du im Prototype.h File
1
externbitfield_error_flagsg_error;
und in EINEM c-File (main.c oder wo immer das am besten hinpasst)
Michael8164 schrieb:
> Ich brauche aber das volatile, da die Elemente des Bitfields auch im> Interrupt geschrieben werden können.
Wie Frank M. gleich danach schon sagte: Könnte es nicht sein, dass der
Interrupt dir die Werte mit 0 überschreibt?
Stefan K. schrieb:> bekommst Du eine Fehlermeldung, weil die Variablen dann mehrfach> definiert werden.
Es gibt leider Compiler (genauer: Linker), die diese
Mehrfachdefinitionen kommentarlos übereinanderlegen, und so tatsächlich
das gewünschte Ergebnis liefern.
Rufus Τ. F. schrieb:> Es gibt leider Compiler (genauer: Linker), die diese> Mehrfachdefinitionen kommentarlos übereinanderlegen, und so tatsächlich> das gewünschte Ergebnis liefern.
Der hier verwendete hat (dank seiner gcc-Abstammung) Optionen, um das
Verhalten zu steuern: -f(no)common . Es liegt also am Anwender ...
FrickelFranz schrieb:> Hat man nun aber einen Mischmasch, einige Felder müssen volatile sein,> andere nicht. Wäre es überhaupt syntaktisch möglich zu definieren OHNE> das direkt im Struct zu tun?
wenn Du mir noch erklärst, was ein Compiler denn wohl Verrücktes
optimieren könnte, wenn nur ein einzelnes Bit eines Bitfeldes volatile
wäre, anstatt alle, dann beschäftige ich mich vielleich mit der Frage
;).
Torben K. schrieb:> Wie Frank M. gleich danach schon sagte: Könnte es nicht sein, dass der> Interrupt dir die Werte mit 0 überschreibt?
Leider nein, denn ich habe den Test im Debugmodus gemacht, direkt Werte
zugewiesen und mit Singlestep geschaut was passiert ohne das da
irgendein Interrupt mitspielt.
Ich hab momentan diese Version, damit habe ich das Problem nicht mehr:
Michael8164 schrieb:> Leider nein, denn ich habe den Test im Debugmodus gemacht,
Wenn Du debuggst, gehe ich davon aus, dass dann auch jegliche
Optimizer-Flags abgeschaltet sind und es damit ziemlich schnuppe ist, ob
Du die Variablen volatile definierst oder nicht.
Was ist denn so geheim an Deiner ISR, dass Du die hier nicht zeigst?
> Ich hab momentan diese Version, damit habe ich das Problem nicht mehr:
Hast Du schon mal drüber nachgedacht, auf diese Bitfields zu verzichten
und auf die klassische Methode mit Bitmasken setzen zurückzugreifen?
Wenn ich das hier sehe:
1
error->temp_shutdown=g_error.temp_shutdown;//geht nicht
dann wird das in einer Bit-Kopier-Shift-Lesen-Shift-Schreiben-Orgie
ausarten. Den vom Compiler erzeugten Code möchte ich hier gar nicht
sehen wollen.
Wo es doch so einfach wäre:
1
volatileuint8_tg_error;
2
3
uint8_typeget_bit_result(uint8_t*error)
4
{
5
*error=g_error;
6
}
Aber manche mögen es ja, sich und den Compiler zu quälen ;-)
Frank M. schrieb:> Aber manche mögen es ja, sich und den Compiler zu quälen ;-)
Da haben wir's wenigstens nie langweilig, mein Compiler und ich ;-)
> Was ist denn so geheim an Deiner ISR, dass Du die hier nicht zeigst?
Nein an der ISR ist nichts Geheimes, nur ist es hier für das Problem
nicht relevant und ich wollte es deswegen weglassen.
> dann wird das in einer Bit-Kopier-Shift-Lesen-Shift-Schreiben-Orgie
ausarten. Den vom Compiler erzeugten Code möchte ich hier gar nicht
sehen wollen.
Da hast Du sicher recht, aber für mich gestaltet sich der Code
übersichtlicher und besser lesbar und ich habe mich für diesen Weg
entschieden. Die Flags werden im Programm an verschiedenen Stellen
gesetzt und an der beschriebenen Stelle lediglich zentral zur Anzeige
verwendet.
Aber Ihr habt mir trotzdem sehr geholfen und mir ein paar Denkanstösse
mit auf den Weg gegeben. Vielen Dank dafür und weiter so in diesem
Forum.