Forum: Compiler & IDEs Bitfelder und Direktzugriffe mittels inlines Assembler


von Nick Spick (Gast)


Lesenswert?

Hallo alle zusammen,

bisher habe ich mich darauf beschränkt heimlich, still und leise im 
Forum rum zu stöbern und Euer Wissen zu schnorren ;o). Nun geht mir aber 
schlicht der Stoff aus, und ich sehe mich vor einem Problem, was wohl 
nur mit Erfahrung gut gelöst werden kann. Ich hab immer mal wieder 
diverse Controller programmiert, meist in Assembler. Eigentlich nie was 
Großes, eher so Gebastel und Spielereien. Nun habe ich eine konkrete 
Anwendung und habe beschlossen das in C zu programmieren, weil ja viel 
einfacher, und weil ich mich an ein größeres Projekt hier aus dem Forum 
wagen möchte, was eben so programmiert ist. Zum Einstieg habe ich daher 
erstmal was eigenes kleines angefangen, da ich zwar in C auch schon 
relativ viel Erfahrung habe, nur leider nicht auf Controller Basis.

Soweit zu mir, jetzt zum eigentlichen Problem:

Ich habe einen Bitstream von einem DCF77 Modul den ich auswerten möchte. 
Also   habe ich zunächst in einem Array mit 60 Byte die einzelnen Bits 
als Boolean abgelegt und dann ausgewertet. Natürlich relativ 
ungeschickt, da ich für ein Bit ein ganzes Byte opfere und zudem das 
ganze in BCD rein kommt und es ziemlich dumm ist, ein nibbel zunächst in 
vier Boolean zu zerlegen, wenn man es anschließen dann wieder als nibbel 
haben will. Also habe ich in dem großen AVR Tutorial gestöbert und das 
geniale Konstrukt des Bitfeldes für mich endeckt um damit den Stream 
abzubilden. Die Idee: Über das dcfIn-Bit (sieh unten) jedes eingehende 
Bit über alle 8 Byte mit Hilfe des Carry-Bits weiter zu schiften 
(Inline-Assembler) bis das Telegramm vollständig ist, und dann ganz 
bequem über den .-Operator auf die einzelnen BCD-Werte zuzugreifen. 
Soweit die Theorie.

Das Bitfeld

//Bitfeld für 64 Bit
typedef struct{
unsigned long long dcfRes:2;      //Reservebits
unsigned long long dcfNewPackage:1;  //Neues Packet wurde empfangen
unsigned long long dcfValid:1;    //DCF Packet ist gültig
unsigned long long dcfIn:1;      //Eingangsbit zum Schiften
unsigned long long dcfPDatum:1;     //Letztes DCF Bit
unsigned long long dcfJahr:8;
unsigned long long dcfMon:5;
unsigned long long dcfWd:3;
unsigned long long dcfTag:6;
unsigned long long dcfPStd:1;
unsigned long long dcfStd:6;
unsigned long long dcfPMin:1;
unsigned long long dcfMin:7;
unsigned long long dcfSb:1;      //Startbit
unsigned long long dcfSs:1;      //Schaltsekunde
unsigned long long dcfMez:1;
unsigned long long dcfMesz:1;
unsigned long long dcfSwitch:1;  //erstes DCF Bit
unsigned long long dcfRuf:1;
unsigned long long dcf0_14:15;
}typeDcf77Stream;

Die Variable:

typeDcf77Stream dcfBuffer;

Das Schiften der 8 Byte mittels Inline-Assembler, wobei vorher das 
letzte Eingangsbit in das dcfIn hinterlegt wurde:

asm volatile (
/*asm*/
"ldi r16 , 0x08"          "\n\t"  //Über 8 Byte
"clc"         "\n\t"
"0:"         "\n\t" // In einer Schleife
"ld r2 , %a0"            "\n\t" // den Inhalt des Adresszeigers
"ror r2"      "\n\t" // über Carry nach rechts schiften
"st %a0+, r2"            "\n\t" // und wieder abspeichern
"dec r16"                  "\n\t"
"brne 0b"      "\n\t" // bis alle 8 Bytes durch
""                          "\n\t"
: /*Output*/
: /*Input*/ "b"(&dcfBuffer)
: /*Changed*/"r2", "r16" ,"memory"
              );


Der komfortable Zugriff:

printf("\n%d: %d.%d.%d %d:%d",dcfBuffer.dcfPDatum,dcfBuffer.dcfTag, 
dcfBuffer.dcfMon,dcfBuffer.dcfJahr,dcfBuffer.dcfStd,dcfBuffer.dcfMin);



Praktisch habe ich dann festellen müssen, dass meine Annahme, dass der 
Compiler das Bitfeld schön artig in der gegebenen Reihenfolge 
aufsteigende im Speicher ablegt, nicht zutrifft, wie ich dann später 
auch in einigen Posts hier gelesen habe. Idee soweit gescheitert. Hier 
habe ich auch den Hoffnungsvollen hinweis gelesen, dass es wohl 
Anweisungen gibt den Compiler hier zu beeinflussen, wobei da nichts 
weiter zu finden war.

Meine Frage ist also, ob, und ggf. wie ich den Compiler hier 
beeinflussen kann, und ob es eine noch geschicktere Variante gibt, wie 
ich den Bitstream sammeln und comfortabel auf die Einzelnen Nibbel 
zugreifen kann.

Vielen Dank schonmal,

MfG, Nico




von Peter D. (peda)


Lesenswert?

Mal nur so ne Idee:

Die DCF-77 Bits kommen ja mit ner atemberaubenden ultra high speed von 
sagenhaften 1 Baud rein.

Was spricht dagegen, jedes einzelne Bit "on the fly", also direkt nach 
Empfang auszuwerten ?

Dann kann man ne wesentlich effektivere Struktur aus einzelnen Bytes 
(Minuten ... Jahre) definieren.

So mache ich es jedenfalls.


Peter


P.S.:
Der AVR-GCC kann zwar theoretisch long long, macht es aber jedoch sehr 
ungeschickt (ist sogar wesentlich teurer als float).

von Nico S. (nick_spick)


Lesenswert?

Hallo Peter,

währe eine Idee. Bevor ich auf die Probleme mit der Reihenfolge im 
Speicher gestoßen bin, hielt ich dies für eine geschickte Lösung, da ich 
mir damit erspare mich im Telegramm zu orientieren und bei der 
Auswertung die einzelnen Bestandteile zu unterscheiden, da ja alle an 
einer definierten Stelle liegen. Du musst zugeben, das hat seinen Scharm 
;o).
Ich müsste dann nur die Werte in die Uhr rüber kopieren, wenn ich das 
Telegramm vollständig erhalten habe und habe somit immer ein 
konsistentes Abbild.

Außerdem will ich das dann über I2C an eine RTC rausschieben, und den 
Bitstream wollte ich ähnlich zusammenbauen, wobei ich mir dazu noch 
keine weiteren Gedanken gemacht habe.

Und wenn es so auch mit Tricks gehen würde, fänd ich die Lösung echt 
gut.

MfG, Nico

von Peter D. (peda)


Lesenswert?

Nico Spieckermann wrote:

> Ich müsste dann nur die Werte in die Uhr rüber kopieren, wenn ich das
> Telegramm vollständig erhalten habe und habe somit immer ein
> konsistentes Abbild.

Das mußt Du in jedem Fall machen, denn die empfangene Zeit wird ja erst 
zum 0. Sekundenimpuls des nächsten Datenpakets gültig.

Nicht, daß Du noch die Silvesterraketen zu früh abfeuerst.


Peter

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.