Hallo Leute, folgende Situation: Es soll in einem C-Programm (WinAVR, Tiny13) die Haupschleife: ========= volatile uint16_t counter; int main() { while (1==1) { counter++; } } ========= durch eine InLine-ASM-Funktion ersetzt werden. Der Wert der Counter-Variable muss dabei ständig aktuell gehalten werden, da diese in diversen Interrupts verwendet wird. Ich habe folgenden Code konstruiert: ========= int main() { asm volatile("loop: \n\t " \ "ADIW %0,1 \n\t" \ "rjmp loop" : : "w" (counter) : "memory"); } ========= der funktioniert allerdings nicht, =========== int main() { asm volatile("loop: \n\t " \ "ADIW %0,1 \n\t" \ "rjmp loop" :"=w"(counter) : "0" (counter)); } =========== geht genausowenig. Mir ist leider unklar welche Parameter der volatile-Funktion noch übergeben werden müssen. Wer kann mir helfen? Danke schön Dominik
1. Warum willst Du ohne Grund Assembler verwenden ? 2. Wenn Du Assembler verwenden willst, mußt Du erstmal Assembler und AVR-GCC Internas können. ADIW funktioniert nur mit ganz bestimmten Registerpaaren und nicht mit SRAM. Alle diese Registerpaare werden aber vom Compiler benötigt. Peter
Hy, oki, danke für den Hinweis, ich gebe zu, dass ich in ASM nicht ganz der Profi bin. Ich habe allerdings folgendes Problem unter C++: Ich benötige zur Zeitmessung einen möglichst genauen Timer (Werte zwischen 0,5 und 1,5 ms). Der Tiny13 hat ja nur einen Timer und dieser ist bereits für PWM belegt kann also nicht genutzt werden. Ich will es deshalb mit einer Schleife und einem Zählerwert machen den ich bei Bedarf in den Interrupts auslesen und auf 0 setzten kann (Timer neustarten). Bis jetzt habe ich das mit der o.a. while-schlaufe gemacht. Leider ist die Zeit die der Kompiler für einen Durchlauf benötigt nicht ganu zu bestimmen und ist bei Optimisation-Level S bei ca. 30 Befehlen, was eindeutig zu viel ist, zumal mein Tiny nur mit 1,2Mhz läuft. Evtl fällt ja jemand eine bessere Lösung ein als eine selbstgemachte Timer-Schleife. Gruß und Danke schonmal Dominik
> Der Tiny13 hat ja nur einen Timer und dieser ist bereits für PWM > belegt kann also nicht genutzt werden. Warum sollte man ihn deshalb nicht auch noch als Timer nehmen können? Die Basisfrequenz des PWM-Timers ist doch konstant, insofern kann man doch auch seine Zählerwerte auslesen und als Zeitmaß benutzen. > Ich will es deshalb mit einer Schleife und einem Zählerwert machen > den ich bei Bedarf in den Interrupts auslesen und auf 0 setzten kann > (Timer neustarten). Mit all den Interrupt-Latenzen (während derer ja deine Main-Loop nicht weiterzählt) dürfte das drastisch weniger genau werden, als den Timer vernünftig zu benutzen. Davon abgesehen, stellt sich natürlich die Frage, ob die Wahl eines ATtiny13 dann die allerbeste war... Was meinst du eigentlich, was an while (1 == 1) besser sei als an z. B. while (1) oder for (;;) ? Ich fand's irgendwie lustig...
Hy, das mit dem Timer muss ich checken, ich weiß nichtmehr genau wiso ich das ausgeschlossen hatte. Die wahl ist auf den Tiny gefallen weil ich eine möglichst kleine Platine basteln musste und die I/O-Ports gereicht haben. Im nachhinein betrachtet vermutlich nicht die beste Lösung, aber jetzt will ich nicht mein ganzen Platinen-Layout und alles nochmal über den Haufen werfen. Die While-Schleife fand ich lustig, keine Ahung ob die anderen wirklich besser gewesen wären. Ich danke dir erstmal, ich werde wohl das mit dem Timer nocheinmal checken. Danke Dominik
> Die wahl ist auf den Tiny gefallen weil ich eine möglichst kleine > Platine basteln musste und die I/O-Ports gereicht haben. Nun, ich hoffe dann, du hast kein DIL-Gehäuse genommen. In die Grundfläche des ATtiny13-DIL passt ja fast ein ATmega8-TQFP rein. ;-) Ansonsten: ATtiny25/45/85? Gleiches Pinout wie ATtiny13, aber deutlich besserer Satz an Features, u.a. zwei Timer-Kanäle.
Hy, nein, selbstverständlich ist alles in SMD, sonst könnte ich mir den Aufwand ja sparen. Ich muss mal durchrechnen ob die GEnauigkeit von meinem PWM-Timer genügt, sonst werde ich mir wohl oder übel mal die Alternativen Tinies anschauen müssen! Danke auf jeden Fall
Also, ich habe es gerade durchgerechnet: Ich kann ja einerseits den aktuellen Wert des Timers auslesen. Da ich Phase-Correct-Mode eingestellt habe läuft dieser immer 0-255-0-255-0 usw. Andererseits kann ich mit einem Iterrup die Anzahl der Überläufe zählen, der Interrupt tritt wohl jedesmal ein wenn der Timer den Wert 0 hat. Ich habe keine Prescaler eingestellt, der Timer nimmt also mit 1,2Mhz zu/ab. Das Problem ist: Wenn ich jetzt den Timer-Wert nehme um die Zeit zu stoppen (voher speichern, nacher speichern), dann reicht das nicht, denn die Zeit die bei einem Zyklus (0-255) geht ist viel zu gering. Wenn ich dagegen die Anzahl der Zyklen zähle, dann habe ich das Problem, dass die Ungenauigkeit sehr hoch ist, da mein Zyklus-Counter ja nur alle 512 Befehle erhöht wird. Beides zusammenführen geht von dem nicht, weil ich weder vorher noch nacher weiß ob sich der Timer am steigen oder am fallen befunden hat. Versteht jemand was ich meine? Ich würde es gerne mit dem Tiny13 machen, auch wenn mir klar ist, das es mit einem anderen MC besser gehen würde. Danke schonmal TO
Hmm, wenn ich das richtig sehe, müsstest du OC0B auf 255 setzen können und bekommst dann einen Interrupt, wenn er beim Hochzählen die 255 erreicht, beim Runterzählen dann einen overflow-Interrupt, wenn er wieder 0 wird. Damit hast du die Information, wie die aktuelle ,,Uhrzeit'' aus Überlaufwert + aktuellem Zählerwert zu ermitteln ist. Ist natürlich ziemlich popelig, keine Frage. Die ISRs würde ich in Assembler schreiben und für die entsprechenden Flag-Werte im C-Code ein oder zwei Register opfern (r2 und r3), damit die ISRs nicht erst noch mit dem Stack operieren müssen.
Hy, danke für die Hilfestellung, leider geht es so nicht, weil ich den Timer ja für die PWM-Generation benötige und OC0B deshalb nicht 255 sein kann. Ich versuche es gerade mit einem 8-Bit Zähler nach der ganz oben von mir genannten Methode zu realisieren, mal sehen ob das überhaupt funktioniert! Wäre auch sonst für jeden Hinweis dankbar! Gruß Dominik
> ...weil ich den Timer ja für die PWM-Generation benötige und OC0B > deshalb nicht 255 sein kann. Das musst du näher erklären. Man kann doch OC0A für die PWM-Generierung benutzen und OC0B separat davon z. B. für einen Interrupt beim Erreichen von TOP. Oder willst du die PWM-Zählweite gegenüber 255 noch zusätzlich reduzieren (WGM2 = 1)?
Hy, ich habe gerade selbst erkannt das ich ja die zwei Compare-Units separat verwenden kann. Evtl hilft mir das, ich bin gerade dabei auszutüfteln wie ich die Laufzeit berechne aus folgenden Variablen: - timeroben (Anzahl wie oft der Timer 255 erreicht hat seit dem Start) - timerunten (Anzahl wie oft der Timer 0 erreicht hat) - start (Timer-Wert beim Start) - stop (Timer-Wert beim Stop) Ich hoffe eine Formel zu finden die ohne eine Bedingung auskommt, mal sehen ob mir das gelingt! Danke auf jeden Fall Dominik
Magst du eigentlich ein Wort drüber verlieren, was du damit genau vorhast? Hintergrund: ich suche noch nach einer irgendwie sinnvollen ,,Story'', um in der avr-libc ein Beispiel für die Kombination aus C- und Assembler-Quellen zu beschreiben. Nun kann ich mir leicht vorstellen, dass man vielleicht eine Assembler-ISR à la .global TIM0_OVF_vect TIM0_OVF_vect: sbi PORTB, 0 reti für irgendetwas benutzen könnte (sehr viel kürzer als alles, was der Compiler derzeit dafür generieren würde), nur fehlt mir irgendeine ,,Rahmenhandlung'', die eine praktische Motivation für derartiges Tun darstellt. Kannst dich gern auch per pmail bei mir dazu melden, im Gegenzug biete ich dir an, mich an der gedanklichen Lösung für die Timerfrage auch mit konkretem Code zu beteiligen.
Hy, die Sache ist kein Geheimniss, das ganze wird eh sobald es funktioniert ein OpenSource Projekt, also mit offenem Schaltplan und Quellcode. Es geht um einen Motorcontroller, hauptsächlich für Flugzeug-Motoren. Es werden dabei über einen Tiny13 zwei Brückencontroller mit dahinter geschalteten Mosfets geschaltet. Hinter den Mosfets hängt ein Motor. Via PWM kann nun die Geschwindigkeit des Motors angepasst werden. Das ist bis jetzt alles schon realisiert und funktioniert auch. Der zweite Teil besteht aus dem Eingang des Controllers: Über eine Ader kommt das PWM-Signal eines RC-Empfängers (aus dem Modellbau) herein. Dieses Signal soll dann aufgenommen und interpretiert werden und entsprechend an den Motor wieder ausgegeben werden. Dabei kommen Zusatzfeatures wie Kalibrierung und automatische Motorabschaltung mit rein. Das ganze Projekt ist eigentlich mehr eine Vorstufe zu einem anderen Projekt wo ich auf der Suche nach einem MotorControler war und keinen für das entsprechende Geld gefunden habe, also habe ich einen selbst entwickelt. Die von mir oben angesprochenen Funktionen werden gebraucht um die PWM-Daten vom Empfänger aufzunehmen und zu interpretieren. Ich habe inzwischen folgenden Code gestrickt, er funktioniert zumindest im Trockendurchlauf (Atmel Studio Debuging), morgen wird sich zeigen ob es auch wirklich funktioniert: =============== volatile int8_t timercounter; volatile int8_t timerstart; volatile bool firstint; volatile bool timersteigend; //War beim start steigend //Overflow vom Timer, bei Timer-Wert=0 SIGNAL (SIG_OVERFLOW0) { if (firstint) { firstint=false; timersteigend=false; } timercounter++; } //Timer nimmt den Wert 255 an (OCR0A=255) SIGNAL (SIG_OUTPUT_COMPARE0A) { if (firstint) { firstint=false; timersteigend=true; } timercounter++; } //An PinB4 hängt der Empfänger, der Interrupt tritt bei jeder Zustandsveränderung ein SIGNAL (SIG_PIN_CHANGE0) { int8_t timerstop=TCNT0; if (bit_is_set(PINB,4)) { timercounter=0; timerstart=TCNT0; firstint = true; } else { uint16_t pwm = 0; if (timersteigend == true) { if (timercounter % 2 == 0) { pwm = timercounter*256 - timerstart + timerstop; } else { pwm = timercounter*256 - timerstart + (256 - timerstop); } } else { if (timercounter % 2 == 0) { pwm = timercounter*256 + timerstart - timerstop; } else { pwm = timercounter*256 + timerstart + timerstop - 256; } } //TUE IRGENDWAS MIT DEM PWM WERT } } ============================== Leider ist die Berechnung noch sehr aufwendig, ich bin noch auf der Suche nach einer einfacheren Formel, evtl kannst du, oder jemand anderes mir dabei helfen. Danke schonmal, und wie gesagt, sobald ich die Sache abgeschlossen habe wird das Projekt richtig öffentlich! Gruß Dominik
Bitte sende mir mal 'ne email-Adresse, ich würde das gern erst einmal privat mit dir weiterschwatzen. j at uriah heep sax de
Hy, leider werde ich aus deiner eMail-ADresse nicht schlau, schreib du mir doch einfach eine: http://www.dbruhn.de dort steht meine eMail-Adresse. Gruß TO
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.