16Bit Compiler Frage
-
Hallo Leute,
ich programmiere an einem Microcontroller 16bit mit C-compiler gcc!
ein Timer kann mit 32 Bit arbeiten, und zählt mit hilfe von 2x 16bit registern.
Wenn ich nun diese in ein long 32bit wert wandle, hab ich folgede 2 möglichkeiten probiert:
int A=0x1234, B=0x5678; long lx=0; // Variante A ((int*)&lx)[1]=A; ((int*)&lx)[0]=B; //Variante B lx=A<<16; lx|= B;
Der C-Compiler kennt "long" wobei long ja eigentlich 32 Bit ist, und der PIC Mircochipg 30F4011 ja nur 16Bit architektur hat, muss der compiler ja mit 2*16Bit variablen arbeiten oder? Würde dann der oben stehende code überhaupt funktionieren?
Die Frage ist nun ich hab einen 32Bit Wert geteit in ein HiWord und LoWord
nun will ich die differenz von zwei dieser Werten bilden, ohne sie in 32 bit werten casten zu müssen...das ist mir zu hoch
grüße
-
BorisDieKlinge schrieb:
Würde dann der oben stehende code überhaupt funktionieren?
Er sollte, wobei ich Dir zu Variante B rate, sie erzeugt immer die richtige 32- Bit- Zahl, ohne sich auf die Architektur der Hardware verlassen zu müssen. Damit kann der Compiler entscheiden, wo Lo und Hi hingehören. Gute Compiler erkennen sogar, daß sie bei bündigem Shiften durch Umspeichern Zeit sparen können.
BorisDieKlinge schrieb:
Die Frage ist nun ich hab einen 32Bit Wert geteit in ein HiWord und LoWord nun will ich die differenz von zwei dieser Werten bilden, ohne sie in 32 bit werten casten zu müssen...
Dann hättest Du zwar nur 16- Bit- Subtraktionen, aber dafür das Carry- Problem am Hals.
Selbst mit dem Cast auf 32 Bit wird der Compiler wahrscheinlich flotteren Code erzeugen als wenn Du mit Teilsubtraktionen runfrickelst.
-
BorisDieKlinge schrieb:
int A=0x1234, B=0x5678; long lx=0; //Variante B lx=A<<16; lx|= B;
wenn A 16 bits hat, dann macht dir A<<16 die variable A komplett leer.
probier mal so:lx = ((unsigned long)A)<<16 | B;
-
coole sache;)
-
Noch was:
die Anweisung:
lx = ((unsigned long)A)<<16 | B;
ist ja nich atomar soweit ich weis, dahinter stecken 2 atomare operatioen oder sogar 3..
während er diese Anweisung ausführt können A und B welche die Zähler werte eines parallel laufenden chips sind verändert werden oder?
wie könnte ich das so machen das entweder die gesamte operation ausgeführt wird oder gar nich, quaise die gesamte anweisung als atomar bearbeitet? wird wohl nich gehen..
-
^^timer anhalten vor'm auslesen und danach wieder starten. eventuell die timerfrequenz schneller machen, um die zeit zu kompensieren, die die rechenoperationen brauchen.
-
timer-freak schrieb:
^^timer anhalten vor'm auslesen und danach wieder starten.
Das ist häßlich,
weil der systematische Fehler bleibt und für genaue Timer kompensiert werden müßte. Zudem sollte man dann auch Interrupts sperren.
Ich weiß jetzt nicht, wie das beim PIC ist, aber lies' mal nach, ob der Timer nicht gepuffert ist. Gepuffert heißt, daß beim Lese- Zugriff z.B. auf das Lo- Register zeitgleich das Hi- Register gepuffert wird. Findet man oft bei 8-Bittern, dann kommt es nur auf die Reihenfolge des Auslesens an -> Doku zum Prozessor lesen.Falls nicht, geht's auch einfach ohne stoppen:
unsigned long int sureread(void) { unsigned long int a,b; do { a = gettimer(); b = gettimer(); } while (a != b); return a; }
Noch ein Hinweis: Die Timer- Register müssen unbedingt "volatile" sein, sonst haut das schon mit dem Auslesen nicht sicher hin
EDIT: Natürlich kannst Du b auch sparen und direkt mit gettimer vergleichen
-
hey ,
ja ich hab die variablen "volatile" deklariert... ich glaub das hier
do { a = gettimer(); b = gettimer(); } while (a != b);
das programm in der schleife bleibt, die timer haben ein 1:1 prescale, d.h. dertimer wird jeden zykus erhöht, d.h. a und b werden imm unterschiedlich sein, weil dazwischen imemr inkrementiert ist ... seh ich das richt?
-
BorisDieKlinge schrieb:
das programm in der schleife bleibt, die timer haben ein 1:1 prescale, d.h. dertimer wird jeden zykus erhöht, d.h. a und b werden imm unterschiedlich sein, weil dazwischen imemr inkrementiert ist ... seh ich das richt?
ja, wenn der timer jeden clockimpuls zählt dann ist jedes programm zu langsam dafür. aber wie pc() schon sagte, guck mal in die doku. da ist bestimmt ein latch zwischengeschaltet.
-
naja ich möchte frequenen von 0-30KHz messen, d.h. bei ner zyklus zeit von ~67nano sekunden, dauert eine periode biw 30KHz 497 timer inkremationen, würde ich den prescaler auf 1:16 htte ich zyklen zeit um die werte zu lesen, allerding wäre dann die frequenzmessung etwas ungeauer..
-
ahh.. dann hat sich meine "was ist ein latch" frage auch erledigt, d.h. im latch ist immer der wert des letzen timer zyklus gespeichert?
-
BorisDieKlinge schrieb:
... , die timer haben ein 1:1 prescale, d.h. dertimer wird jeden zykus erhöht, d.h. a und b werden imm unterschiedlich sein, weil dazwischen imemr inkrementiert ist ... seh ich das richt?
Siehst Du richtig, aber die Frage ist, ob Du den Timer erfindungsgemäß verwendest.
Wenn der mit einem Nanosekundenzyklus dahinrast, läßt man ihn üblicherweise beim Unterlauf einen Interrupt auslösen und zählt dann z.B. einen anderen Zähler weiter oder macht das, was (zumeist zyklisch) nach einer definierten Zeit getan werden muß.Als Uhr zum "zwischendurch Draufschauen" sind die Dinger nicht gedacht. Mit unkompensiertem Stoppen und Wiederstarten würdest Du Deine riesige Auflösung ja auch zerstören.
Wozu brauchst Du das eigentlich so genau?
-
BorisDieKlinge schrieb:
ahh.. dann hat sich meine "was ist ein latch" frage auch erledigt, d.h. im latch ist immer der wert des letzen timer zyklus gespeichert?
Nicht ganz. Ist ein getriggertes Register, mal salopp gesagt. Und der Trigger ist das Auslesen des Lo- oder Hi- Teil des Timers, daß der andere mitgespeichert wird.
-
BorisDieKlinge schrieb:
naja ich möchte frequenen von 0-30KHz messen, d.h. bei ner zyklus zeit von ~67nano sekunden, dauert eine periode biw 30KHz 497 timer inkremationen, würde ich den prescaler auf 1:16 htte ich zyklen zeit um die werte zu lesen, allerding wäre dann die frequenzmessung etwas ungeauer..
Je nachdem, wie oft Du ein Meßergebnis brauchst, empfehlen sich u.U. spezielle Timer- Modi:
- Meist haben Timer auch die Möglichkeit, "gated" zu arbeiten, behelfsweise kann man sich ein Gate auch aus 'nem normalen Interruptpin schnitzen.
- Eventuell kommt auch ein Event Counter Modus in Frage, dessen Stand Du gegen einen internes Zeitnormal vergleichst.
- Oft können sie von sich aus Pulsweiten messen.Echt, hilft nur eins ->> Doku lesen!!
-
hey pointer.. ja ich hab mal bischen gelesen;) da gibts Input Capture Timer modi, welcher den timerwert bei steigender flanke und/oder wieder bei fallender flanke in einem interrupt zurück gibt o.ä. ! Gated accumulation mode stoppt und startet den timer ..
das ist ja schon mal wunderbar, aber ich würde gern ein 32bit timer haben, mein PIC 30F4011 kann aus zwei 16bit timer ein 32bit timer (emulieren) leider funktioniert die kombination 32bit timer und "input capture" bzw. "gated accumukation" nicht.
-
BorisDieKlinge schrieb:
... aber ich würde gern ein 32bit timer haben, mein PIC 30F4011 kann aus zwei 16bit timer ein 32bit timer (emulieren) leider funktioniert die kombination 32bit timer und "input capture" bzw. "gated accumukation" nicht.
Kommt drauf an, was Du brauchst. Bei 67 ns Zyklus kommst Du mit 16 Bit auf so 230 Hz runter (1/(65536 * 67,5 ns), bevor er in den Unterlauf kommt.
Wenn Du weiter runter willst: Guck' mal nach, ob er auch bei Unterlauf einen Interrupt generiert. Mittels dieses Interrupts kannst Du Dir einen Merkzähler generieren.
Beim Flankeninterrupt (gated) sollte der Timer stehen bleiben, Du kannst einfach das, was im Zähler steht plus Merkzähler * 65536 als Gesamtticks annehmen. Vorteil: Du kriegst ohne Frickelei genaue Ergebnisse
Achtung:Aufpassen, wie Du Dein Gate einstellst, Standard ist einmal fallend = los geht's, einmal steigend = Stop. Das ist eine Pulsweitenmessung und bei unsymmetrischen Signalen mißt Du dann natürlich Käse. Besser über die volle Periode messen, das wäre z.B. zweimal fallend, wenn das geht.
Wenn Du partout auf den 32 Bit- Betrieb nicht verzichten magst, legst Du Dein Meßsignal auf einen normalen externen Interruptpin, der flankengetriggert betrieben Dein Gate darstellt. Beim ersten Auslösen resettest und startest Du den Timer, beim zweiten stoppst Du ihn wieder. Hat einen Nachteil: Das resetten und Starten sowie das Stoppen stellen einen Zeitoffset dar, der im oberen Frequenzbereich relevant wird und kompensiert werden sollte. Vorteil: Du mißt definitiv über eine volle Periode des Meßsignals.
Aber wie gesagt, es müssen nicht immer 32 Bit sein
-
genau, hab mir auch schon überlegt ob ich bei 16Bit bleibe, und bei jedem überlauf interrupt eine merker hochszähle. dann "Merker* 0xFFFF + TimerWert". die Variante ist ja rel. einfach.. aber ist sie auch sauber? ich weis das beim differenzbildung zweiter timerwerte bzw. rücksetzen des timers zeit verloren geht, aber die geht ja (wenn ich ne periode messe) bei beiden flanken gleichviel verloren, d.h. es gibt ne verschiebung, welche aber dennoch stimmt oder?
ich will so 10hz -30khz messen. ich kann den pic auch noch hochtackten dann hab ich ne zykluszeit von ~37,5nanosekunden. Würd ich den Merker auf auf ein byte beschränken könnte ich max. (0xFF*0xFFFF) + 0xFFFF) == 16776960*37,5 == 639,136ms == ~1,56Hz runter und max. wenn ich die oprationen bei jedem interrupt brücksichte dich vll. 2mircosekunde gehen ca. 50 operationen + 1mircosekunden reserver == 3 mricosekunden kürzeste periodendauer zwischen zwei flankeninterrupte =333Khz d.h. wenn ich bi s30kz messen will wird die messung ziemlich genau sein?
seh ich dar richtig... kostet es mehr zeit den timer zurückzusetzen bei jeder periodenmessung, oder den timer durchlaufen zu lassen und immer differenz bilden?
grüße
EDIT: Zuweisung eines wertes an eien variable dauer 2 zyklen oder?
1. Wert in in accu setzen
2. accu des registers zuweisen?Zurückstzen eines Variable dauer ein zyklus oder CLR?
1. CLR befehl auf register
differenzbildung (16bit) 4 zyklen?
1. Wert A in accu1
2. Wert B in accu2
3. Werte subrtrahieren in accu1
4. Accu1 zurückscreiben in wert?P.S.: hab mich sehr wenig mit assambler beschäftig bzw. ist schon lange her.. die anzahl er zyklen ist hier mal spekulation;)
Muss ich den timer anhalten bevor ich ihn zurücksetze?
-
BorisDieKlinge schrieb:
genau, hab mir auch schon überlegt ob ich bei 16Bit bleibe...
wenn du was 32 bittiges suchst, dann empfehle ich 'nen LPC2xxx von NXP. ARM7-basiert und so. sehr zuverlässige teile. für deine anwendung vielleicht etwas überdimensioniert, aber kosten auch nicht die welt (10€ etwa).
-
BorisDieKlinge schrieb:
genau, hab mir auch schon überlegt ob ich bei 16Bit bleibe, und bei jedem überlauf interrupt eine merker hochszähle. dann "Merker* 0xFFFF + TimerWert". die Variante ist ja rel. einfach.. aber ist sie auch sauber?
Sie ist es, wenn der Timer nicht stehenbleibt, sondern bis zum Periodenende weiterläuft. Es ist die präzisetste Methode, wenn der Timer zwei gleiche Flanken als Start und Stop triggern kann, dann kriegst Du eine Periode.
BorisDieKlinge schrieb:
ich weis das beim differenzbildung zweiter timerwerte bzw. rücksetzen des timers zeit verloren geht, aber die geht ja (wenn ich ne periode messe) bei beiden flanken gleichviel verloren, d.h. es gibt ne verschiebung, welche aber dennoch stimmt oder?
Kannst Du nicht so pauschal behaupten. Vor allem: Welche Differenzen willst Du bilden, eine Periode ergibt einen Meßwert. Da Du eh nur jede zweite Periode messen kannst, hast Du alle Zeit der Welt, alles Mögliche zu berechnen und die Hardware für die nächste Messung klarzumachen.
BorisDieKlinge schrieb:
... wenn ich bi s30kz messen will wird die messung ziemlich genau sein?
Ja, ziemlich.
BorisDieKlinge schrieb:
seh ich dar richtig... kostet es mehr zeit den timer zurückzusetzen bei jeder periodenmessung, oder den timer durchlaufen zu lassen und immer differenz bilden?
Schau, richtig ohne Gemurkse messen kannst Du nur jede zweite Periode, entweder Dein Timer beherrscht das Gate über die Periode oder Du setzt einen Frequenzteiler davor.
Alternative: Du bastelst das mit einem Interruptpin und startest/stoppst den Timer per Software, dann kannst Du auch guten Gewissens den 32 Bit- Modus hernehmen.
Differenzen aus Snapshots zu bilden, haut bei Dir nicht sinnvoll hin.BorisDieKlinge schrieb:
Muss ich den timer anhalten bevor ich ihn zurücksetze?
Ich habe die PICs Mitte der 90er ganz weit aus dem Fenster geworfen und nie wieder angeschaut ==> Manual lesen
-
pointercrash() schrieb:
richtig ohne Gemurkse messen kannst Du nur jede zweite Periode...
wieso das? von einer flanke bis zur nächsten mit der selben steigung ist's genau eine ganze periode.