volatileunsignedlonglongDATUM_P:1;// Parität Datum
28
};
29
}dcf_struktur;
30
31
externdcf_strukturdcf77_daten;
In der Empfangsroutine wird mit
1
dcf77_daten.dcf_bits=(dcf77_daten.dcf_bits>>1);
2
dcf77_daten.dcf_bits|=0x8000000000000000;// Bit setzen
(Das Bit wird natürlich nur bei empfangener 1 gesetzt,
geschoben wird immer).
Eigentlich bin ich eher angenehm überrascht von dem, was WinAVR da so
erzeugt.
Die 64Bit-Geschichte sieht allerdings schrecklich aus, spielt aber
bisher zuverlässig.
Meine Versuche, so auf die Schnelle den Shift und das Setzen des
höchsten Bits per inline-ASM zu erledigen, sind daran gescheitert, daß
er entweder den Zugriff auf dcf77_daten.dcf77_bits nicht auflösen kann
oder mit den in/out-Registerzuweisungen gemault hat.
Eigentlich gibt es ja keinen in/out...
1
{
2
asmvolatile("lds %A0, dcf77_daten.dcf77bits \n\t"
3
"lsr %A0 \n\t"
4
"sts dcf77_daten.dcf77_bits, %A0 \n\t"
5
6
"lds %A0, dcf77_daten.dcf77bits+1 \n\t"
7
"ror %A0 \n\t"
8
"sts dcf77_daten.dcf77_bits+1, %A0 \n\t"
9
...
10
"lds %A0, dcf77_daten.dcf77bits+7 \n\t"
11
"ror %A0 \n\t"
12
"sts dcf77_daten.dcf77_bits+7, %A0 \n\t"
13
);
Ich will es ja nur an besagte Stellen einfügen (als Macro wäre es
natürlich lsebarer).
Vielleicht kann ja da jemand den passenden Ansatz aus dem Hut zaubern...
Gruß aus Berlin
Michael
Lass das alles bleiben und mach einen Vektor mit 60 ganzen Bytes, das
spart Speicher und Zeit, glaub mir :-)
Beispielsweise das Minuten-Feld so zusammenzufassen ist unsinnig, denn
du mussts nachher ja doch wieder aufdröseln und von Hand
zusammenrechnen, die Bits stellen nämlich KEIN Dualzahlensystem dar,
sondern ein gepacktes BCD.
Ansonsten: Warum sind die Felder der Struktur alle 'long long'?
Außerdem: schmeiß den 'long'- und 'short'-Kram raus und nehm die Typen
aus <stdint.h> (uint_xx_t), das weißt du wenigstens, wie lang sie sind.
Und nein, ein 'int' ist nicht zwangsläufig 32 Bit breit und ein 'long
int' muss auch nicht zwangsläufig größer als ein 'int' sein...
Hallo,
die ganze Geschichte ist eine beinahe 1:1 Kopie meines ASM-Programmes.
Hintergrund ist voresrt einzig eine C-Übung. :-)
Die long long - Geschichten sind noch drin, weil ich auch meine schon
erkannten Fehler noch nicht rauskorrigiert habe.
Ich weiß, das, daß die Datentypen Systemabhängig sind, die Nutzung von
stdint hat mir ein paar Warnings beschert, die ich vorerst nicht klären
konnte. Ist mir im Moment auch relativ egal, die Chance, woanders als
auf dem AVR in C zu programmieren, ist sehr klein.
Zum Format: ich weiß, daß es packed BCD ist, genau deshalb läßt es sich
so gut lesbar (für mich?) zusammenstellen, selbst meine Software-Uhr
läuft auch im packed BCD, das bleibt konsistent. Wandeln muß man
irgendwo ja sowieo, so ist es selbst in der Ausgabe kürzer.
Ist aber eigentlich alles nicht mein augenblickliches Problem, der Shift
in ASM kostet rund 50 Zyklen gegenüber einer Kopie-Mov-Arie, die der GCC
dort erzeugt.
Vielleicht hat da ja doch mal jemand sowas gemacht.
PS: ich habe gerade mal mir den Tyoen in der Struktur rumgespielt: es
ist sowohl dem Speicherbedarf aus auch der Programmgröße völlig egal, ob
ich
Michael U. wrote:
> Ich weiß, das, daß die Datentypen Systemabhängig sind, die Nutzung von> stdint hat mir ein paar Warnings beschert, die ich vorerst nicht klären> konnte.
Zeig die doch mal her.
> Ist mir im Moment auch relativ egal, die Chance, woanders als> auf dem AVR in C zu programmieren, ist sehr klein.
Na... wie groß ist denn ein int und ein long aufm AVR...? :-)
Die Warnings lassen sich klären, dann empfehle ich dir trotzdem wieder
stdint.
> Zum Format: ich weiß, daß es packed BCD ist, genau deshalb läßt es sich> so gut lesbar (für mich?) zusammenstellen, selbst meine Software-Uhr> läuft auch im packed BCD, das bleibt konsistent.
Na wenn du meinst, aber das Bitgefummel haste ja schon bemerkt.
> Vielleicht hat da ja doch mal jemand sowas gemacht.
Jo, haben schon viele gemacht :-)
Viele (mich eingeschlossen) benutzen wirklich Arrays und gut. Die
anderen bemerken das Bitgeflüster beim Schieben vermutlich garnicht.
Was du aber machen kannst (böse, naja): Caste deine Struktur in einen
ganzen Typ (uint64_t, oder mit union) und schiebe den mit Inline-ASM,
dafür isses nämlich wieder in der Anleitung zur AVR-Libc dokumentiert.
Michael U. wrote:
> Meine Versuche, so auf die Schnelle den Shift und das Setzen des> höchsten Bits per inline-ASM zu erledigen
Warum willst Du ohne Not ASM benutzen?
Das DCF77 kommt mit ner Wahnsinns-Speed von 1Bit/s daher, da braucht man
nichts zu beschleunigen.
Wenn Du allerdings Flash sparen willst, dann nimm einfach nen besseren
Ansatz:
Man muß nicht immer sämtliche 59 Bits nutzlos durch die Gegend shiften,
es reicht völlig, wenn man direkt das richtige Bit im richtigen Byte
setzt.
Dazu nimmt man einfach 2 Tabellen, eine liefert die Byteadresse, die
andere die Bit-Wertigkeit.
Hier ist ein Beispiel dafür:
Beitrag "DCF77 Uhr in C mit ATtiny26"
Wenn Du unbedingt packed-BCD nehmen willst, kann man das leicht
umstellen.
Es ist allerdings vollkommen sinnfrei, da C damit nicht umgehen kann.
Alle Rechenoperationen und Zahlenein-/Ausgaben erfolgen ausschließlich
binär.
Du mußt Dir dann auch eigene Rechenfunktionen für packed-BCD schreiben.
Peter
Michael U. wrote:
> Die 64Bit-Geschichte sieht allerdings schrecklich aus, spielt aber> bisher zuverlässig.
Ja ne, 64Bit mag der AVR-GCC überhaupt nicht.
Nimm 8 Byte und gut is:
Hallo,
:-))
Peter, ich weiß daß das Beispiel mit DCF77 auf viele andere Arten und
auch besser zu lösen geht.
Mir geht es im Moment ja auch nur darum, mit C zu diskutieren. ;-)
Da ich sonst ASM mache, interessierte mich eben, wie ich inline ASM mit
Zugriff auf einen Union-Bestandteil hinbekomme.
Da stehen mir eben die Zeiger-Geschichten noch etwas im Weg.
Das es nun gerade DCF77 ist: naja, das kenne ich und weiß, was passieren
soll.
Als normale globale Variable klappt es jetzt erstmal prinzipiell, den
globalen union-Verweis kann der assembler aber nicht auflösen.
Ob das ganze so bleibt, steht in anderen Sternen.
Gruß aus Berlin
Michael
Michael U. wrote:
> Meine Versuche, so auf die Schnelle den Shift und das Setzen des> höchsten Bits per inline-ASM zu erledigen, ...
GCC's Inline-Assembler ist alles andere als leichte Kost. Der greift
so tief in den Compiler ein, dass du dann schon den halben Weg zurück
gelegt hast, die ganze 64-Bit-Geschichte gleich als Pattern für den
Compiler zu schreiben. ;-)
Andererseits ist es in deinem Falle einfach. Erstens könntest du den
Namen "dcf77_daten" tatsächlich direkt im Assemblercode benutzen --
aber natürlich kennt der Assembler nichts von deiner C-Struktur --,
und zweitens ist die Übergabe einer Speicheradresse als Parameter
eine der einfacher zu beherrschenden Constraints:
1
asmvolatile(
2
"lds __tmp_reg__, %0 + 7""\n\t"
3
"lsr __tmp_reg__""\n\t"
4
"sts %0 + 7, __tmp_reg__""\n\t"
5
"lds __tmp_reg__, %0 + 6""\n\t"
6
"ror __tmp_reg__""\n\t"
7
"sts %0 + 6, __tmp_reg__""\n\t"
8
"lds __tmp_reg__, %0 + 5""\n\t"
9
"ror __tmp_reg__""\n\t"
10
"sts %0 + 5, __tmp_reg__""\n\t"
11
"lds __tmp_reg__, %0 + 4""\n\t"
12
"ror __tmp_reg__""\n\t"
13
"sts %0 + 4, __tmp_reg__""\n\t"
14
"lds __tmp_reg__, %0 + 3""\n\t"
15
"ror __tmp_reg__""\n\t"
16
"sts %0 + 3, __tmp_reg__""\n\t"
17
"lds __tmp_reg__, %0 + 2""\n\t"
18
"ror __tmp_reg__""\n\t"
19
"sts %0 + 2, __tmp_reg__""\n\t"
20
"lds __tmp_reg__, %0 + 1""\n\t"
21
"ror __tmp_reg__""\n\t"
22
"sts %0 + 1, __tmp_reg__""\n\t"
23
"lds __tmp_reg__, %0""\n\t"
24
"ror __tmp_reg__""\n\t"
25
"sts %0, __tmp_reg__"
26
:"+m"(dcf77_daten));
Allerdings sieht man an diesem Falle auch, warum man besser nicht
einfach so den C-Code durch Assemblercode ersetzen sollte: die
Reihenfolge deiner Bitschieberei war falsch herum.
Jörg Wunsch wrote:
> GCC's Inline-Assembler ist alles andere als leichte Kost. Der greift> so tief in den Compiler ein, dass du dann schon den halben Weg zurück> gelegt hast, die ganze 64-Bit-Geschichte gleich als Pattern für den> Compiler zu schreiben. ;-)
Wenn es so einfach ist, warum hat das dann noch keiner gemacht?
Auch versteht ja der Inline-Assembler nichtmal die nötigen weiteren 4
Register %E0..%H0.
Peter
Peter Dannegger wrote:
> Wenn es so einfach ist, warum hat das dann noch keiner gemacht?
Weil Opensource-Software so nicht funktioniert. Es passiert genau
das, wo jemandem hinreichend stark ,,der Schuh drückt''. Solange
die wenigen Anwender der 64-Bit-Integer-Datentypen damit leben
können, die automatisch generierten Hilfsfunktionen der libgcc.a
statt expliziter Patterns zu benutzen, wird sich da auch kaum was
ändern.
Bei GCC kommt noch dazu, dass man das ganze Lizenzgeraffel erstmal
auf die Reihe bekommen hat, bevor man dort Code unterbringt. Die
FSF besteht darauf, dass man ihnen das Copyright abtritt (die
offizielle Begründung ist, dass sie auf diese Weise die Rechte
besser verteidigen könnten). Das ist ein wenig Papierkrieg. Als
Deutscher kann man übrigens sein Copyright einfach mal gar nicht
abtreten, d. h. die entsprechende Unterschrift unter da Papier ist
ein völlig sinnloser Akt, aber sie scheint die FSF seelisch zu
beruhigen.
> Auch versteht ja der Inline-Assembler nichtmal die nötigen weiteren 4> Register %E0..%H0.
Der Inline-Assembler versteht hier genau das, was der Compiler intern
versteht. Die Ergänzung der Constraint-Modifier E...H wäre also der
erste (notwendige) Schritt für eine Integration von 64-Bit-Patterns
(allerdings der meiner Meinung nach leichteste Teil davon, den würde
sogar ich mir zutrauen).
Hallo,
Danke, Jörg, voller Erfolg (für mich zumindest).
Ich habe noch das Setzen des höchsten Bits beim Empfang einer 1
reingebaut
( sec und ror statt lsr), läuft alles.
Sind rund 600 Byte gesparter Flash + die Laufzeit.
Bringt also im Spezialfall auch woanders sicher Punkte, sollte ich es
mal brauchen.
Gruß aus Berlin
Michael
Hallo,
Jörg Wunsch wrote:
> Michael U. wrote:>>> Sind rund 600 Byte gesparter Flash>> Ob du jetzt von Atmel Geld zurück bekommst? :-)
Ich werde es mal versuchen. ;-))
Naja, es geht um diese Geschichte hier:
Beitrag "Sensoren mit RFM02/12, FOST02, HP03S (ASM)"
Ich habe in der vorigen Woche mal das Modul mit dem Display komplett
nach C getragen, als erste! Übung. ;)
Die RFM12-Empfamgsroutine läuft komplett transparent im FIFO-IRQ des
RFM12.
DCF77 läuft im 10ms Timer-IRQ.
Im ungünstigsten Fall darf also der 10ms IRQ nicht länger dauern als der
Empfang eine Bytes durch den RFM12 bei 19200 Baud (rund 500µs).
Das reicht unter allen Umständen mit sehr viel Reserve. In ASM...
In C lief es zwar auch stabil, die erzeugte Codelänge der DCF Geschichte
hat mich aber beunruhigt. Nun kann ich wieder ruhig schlafen.
Oder weiter programmieren. ;-)
Der 2. ungünstigste Fall ist die RFM12-IRQ-Routine, wenn das Paket
komplett ist (18 Byte). Die werden dann komplett in die Struktur für die
Sensoren kopiert. Das kann der GCC aber brauchbar.
Gruß aus berlin
Michael
Michael U. wrote:
> Sind rund 600 Byte gesparter Flash + die Laufzeit.
Schön, aber da ist mein obiger C-Code doch besser.
Er braucht nur 36 Byte statt 80 Byte für den Assemblercode.
Es ging mir auch mal so, als ich von Assembler wechselte, daß ich
Assembler mit C mixen wollte.
Aber in 99,9% der Fälle bringt es nix, außer Verschlechterung der
Lesbarkeit und Portabilität.
Schau lieber ins Assemblerlisting, um zu sehen wie der Compiler tickt
(was er mag bzw. was ihm Bauchschmerzen bereitet).
Peter
Peter Dannegger wrote:
> Michael U. wrote:>> Sind rund 600 Byte gesparter Flash + die Laufzeit.>> Schön, aber da ist mein obiger C-Code doch besser.> Er braucht nur 36 Byte statt 80 Byte für den Assemblercode.>>> Es ging mir auch mal so, als ich von Assembler wechselte, daß ich> Assembler mit C mixen wollte.> Aber in 99,9% der Fälle bringt es nix, außer Verschlechterung der> Lesbarkeit und Portabilität.
Sicher richtig.
>> Schau lieber ins Assemblerlisting, um zu sehen wie der Compiler tickt> (was er mag bzw. was ihm Bauchschmerzen bereitet).
Hätte ich das nicht gemacht, wäre ich nicht darüber gestolpert, es lief
ja auch komplett in C stabil.
Mein eigentliches Problem ist ganz simpel:
Ich will mit dem Kram weiter machen.
Mit diesem Modul in C um zu üben.
Ich brauche einen der Webserver mit AVR, der den RFM12-Empfang rein
bekommt (sehe ich kein unlösbares Problem für mich) und der einen
minimalen FTP-Client hat. Sehe ich noch ziemliche Probleme.
Seltsamerweise gibt es ja dutzende Logger für alles mögliche (mit AVR),
die auf SD-Card loggen.
Seltsamerweise gibt es auch genug Webserver (mit AVR), mit denen ich
auch aus Afrika schauen kann, ob hier ein Fenster offen steht oder wie
warm es ist.
Seltsamerweise gibt es aber nur eine mir bekannte Source mit einem
FTP-Client. Allerdings für die flasche Hardware (Realtek 8019).
Fast jeder hat mittlerweile ein NAS, das auch einen FTP-Server bietet.
Es liegt (für mich) also nahe, die lokal geloggten Daten mit dem
Webserver per Funkmodul zu empfangen, zwischenzuspeichern und alle 1-2
Stunden per FTP als Datei auf das NAS zu schieben.
Muß ich also selber machen. in C eben. ;-)))
Gruß aus Berlin
Michael