Hallo, kennt sich jemand aus mit der Konfiguration des Timers für den ATMega128. Mein Timer muss falsch eingestellt sein, da die erzeugten Tasks nicht die Periode einhalten, die ich angegeben habe. Z.B. soll die Periode 1ms sein, jedoch ist sie tatzächlich 2,5ms? meine Konfig sieht so aus: #define CPU_CLOCK_HZ 3686400L #define OS_TICKS_PER_SEC 50 OS_ENTER_CRITICAL(); TCCR0=TCCR0VAL; /* Set TIMER0 prescaler to CLK/1024*/ TIMSK=_BV(TOIE0); /* Enable TIMER0 overflow interrupt*/ /* Set the counter initial value*/ TCNT0=256-(CPU_CLOCK_HZ/OS_TICKS_PER_SEC/1024); OS_EXIT_CRITICAL(); DDRB = 0xff; /*Output Port*/ Mit diesen Einstellungen scheint eine Periode von einer ms nicht zu funktionieren! Könnte es vielleicht auch an etwas anderem liegen? Gruß Juergen
Müsse OS_TICKS_PER_SEC nicht 100 sein statts 50? T von 100HZ = 1ms, T von 50 HZ =2ms
Hier fehlt das '/2': /* Set the counter initial value*/ TCNT0=256-(CPU_CLOCK_HZ/OS_TICKS_PER_SEC/1024/2); Wenn du die Timerinitialisierung so machst, sparst du dir das erneute Setzen der TCNT0 Registers in der Interruptroutine /*Timer0 clocked from clki/0 */ ASSR &=~ 0x08; /*Output Compare Register -> Tickrate*/ OCR0 = (CPU_CLOCK_HZ OS_TICKS_PER_SEC 1024 / 2); /*Clock Prescaler = 1024*/ TCCR0 |= 0x03; TCCR0 |= 0x0C; /*Timer0 Output Compare Match Interrupt Enable*/ TIMSK |= 0x02;
Hi, mal eine grundsätzliche Frage: die Interrupt-Zyklen berechne ich foldend??? CPU_CLOCK_HZ/Prescaler/(256-TCNT0) = Frequenz dann: 1/Frequenz*1000 = Interrupt-Zyklen (in ms) Beispiel: CPU_CLOCK_HZ = 3686400Hz OS_TICKS_PER_SEC = 50 Prescaler = 1024 TCNT0 = 256-(CPU_CLOCK_HZ/OS_TICKS_PER_SEC/1024) = 184 ==> 368640/1024/(256-184) = 50Hz ==> 1/50*1000 = 20ms (jede 20ms wird ein Interrupt ausgelöst??) die 50 Ticks pro sec bedeutet dann, dass 1 Tick 20ms entspricht? Müssen nun die 20ms aus beiden Rechnungen ein Vielfaches oder das Gleiche sein? Wenn ja: im uC/OS steht, dass die Ticks pro sec zwischen 1...100 sein sollen. D.h. doch, dass die kleinste Auflösung 10ms ist. Also ist die Delay-Zeit einer Task im minimalsten Fall 10ms??? Oder? Jetzt bin ich mal gespannt, ob das wircklich so ist oder ob ich da was falsch verstehe!!! thx Juergen
Was ich nicht verstehe... Warum verwendest Du den Overlow Interrupt bei dem Du jedesmal TCNT0 in der Interruptroutine neu laden musst? Nimm doch ganz einfach den CTC Mode? Für 1ms bei 16MHz sieht das bei mir so aus: ... #define PRESCALE_64 (1<<CS02) ... #define PRESCALE_BITS PRESCALE_64 #define PRESCALER_FACTOR ((unsigned long)64) OCR0 = CPU_CLOCK_HZ/TICK_RATE_HZ/PRESCALER_FACTOR -1; TCCR0 = (1<<WGM01) | PRESCALE_BITS; gibt 16.000.000/(1000*64)-1 = 249 = OCR0 und SIG_OUTPUT_COMPARE0 ist Dein Interrupt.
Moin Werner, das mit dem Timer einstellen für eine Taskzeit von 1ms scheint zu klappen, jedoch haberts bei der Ausführung der Task. Stelle ich die Taskzeit auf >=5ms ein funktioniert es problemlos. Nehme ich ne kleinere Zeit (1ms sind nötig für einen Servo) dann stimmen die Zyklenzeiten nicht mehr! Könnte es sein, dass das uC/OS-II nicht mehr hinterher kommt! Der Timer löst doch, je nach Eintellung, einen Interrupt aus, wenn der Zähler mit OCR0 übereinstimmt. Und dann wir doch eine Routine ausgeführt. Dauert nun die Routine länger, als die Zeit von Interrupt zu Interrupt, kann die Task nicht mehr funktionieren. Sollte es so sein, haste ne Idee dies zu lösen? Fordert dies ne eigene Interrupt-Prozedur? thx juergen
1. Ich habe keine Ahnung von uC/OS-II, das Codeschnipsel ist aus FreeRTOS. 2. Bei 1ms Zykluszeit hat jeder Task Zeit für ca. 64*250=16000 Befehle (bei 16MHz), abzüglich der Befehle für die Taskumschaltung. Bei 3.68MHz eben entsprechend weniger (ca. 3600). 3. Jeder Task erhält (grob gesagt) 1ms Zeit um etwas zu tun. Je mehr Tasks laufen um so länger dauert es bis jede einzelne wieder drankommt. Falls eine Task weniger als 1ms "benötigt" kann üblicherweise (ob bei uC/OS-II) auch = ?) der Task den Prozessor vorzeitig abgeben und die restliche Zeit erhält der nächste Task als Gesamtlauftzeit in diesem zyklus. Exakte Timings sind auf diese weise nicht erreichbar, es gibt immer einen Jitter. Den Proz mit 5*3,68MHz übertakten. Ich habe sonst keinerlei Ansatz für eine Lösung, sorry.
Morgen Werner, ich habe nochmal im Handbuch von uC/OS nachgelesen. Es steht zwar nicht exakt drin, dass die Grenze 1ms ist aber es wird schon darauf hingewiesen, dass die Ticks pro Sekunde ziwschen 1...100Hz liegen sollten. Man kann auch auf 1000Hz gehen aber dann ist dann auch wirklich Feierabend. Ausserdem sind ausnahmslos alle Beispiele, die es so gibt, mit Zeiten zwischen 10ms...20ms gewählt. Meine Tests haben ergeben, kleiner 1ms geht einfach nicht! Somit schließ ich jetzt einfach mal daraus, dass die Grenze 1ms ist und weniger geht nicht. Gebe dir aber recht, je schneller der Prozessor (übertakten) um so kleiner können die Zeiten gemacht werden. Von einem anderen User habe ich den Tipp bekommen die Tasks nicht mit Sleeps zu versehen, sondern mit Semaphore zu kontrollieren. Timer auf 1ms stellen, ISR gibt Semaphore frei und die Task läuft. So spart man sich anscheinend Funktionsaufrufe. Und du verwendest FreeRTOS? Erzähl mal, taugt das was? Wie weit kannst du runtergehen mit den Sleepzeiten. Ist FreeRTOS für Linux/Windows oder beide. Ist die Portierung für den ATMega128 eine Baustelle oder gibt es hier Beispiele bzw. Portierungspeispiele. Bei uC/OS ist es so, dass du ca. 10 *.c prozessorunabhänige Dateien und ca. 3 *.c/*.asm prozessorabhänige Dateien hast. Die Prozessorabhänige muss man dann auf seinen Prozessor zuschneiden und hat dann somit ein RTOS für seinen Prozessor. Ist dies bei FreeRTOS auch so? Nur das Compilieren bzw. Linken machte bei mir große Probleme. Unter Windows mit ICC ging nix und unter Linux mit avr-gcc scheint es zu gehen. Bist du zufrieden mit FreeRTOS? Gruß und thx Juergen
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.