mikrocontroller.net

Forum: Projekte & Code uC/OS auf ATMega128 Timereinstellung


Autor: Jürgen H. (juergen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Thomas Weisenburger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Müsse OS_TICKS_PER_SEC nicht 100 sein statts 50?
T von 100HZ = 1ms, T von 50 HZ =2ms

Autor: Dirk (noch einer) (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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;

Autor: Jürgen H. (juergen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Werner B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Werner B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
äää...nicht zu vergessen...

TIMSK |= (1<<OCIE0);

Autor: Jürgen H. (juergen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Werner B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Jürgen H. (juergen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.