hallo zusammen,
ich habe seit gestern ein problem mit meinem timer1 (atmega 1284p).
zuerst meine konfig:
1 | #define CLK_PRELOAD_10MS 2499L
| 2 |
| 3 | void sys_clk_init(void)
| 4 | {
| 5 | /* Compare Match */
| 6 | TCCR1A = 0;
| 7 | TCCR1B |= (1<<WGM12) | (1<<CS11) | (1<<CS10);
| 8 | OCR1A = CLK_PRELOAD_10MS;
| 9 | TIMSK1 |= (1<<OCIE1A);
| 10 | }
|
die ISR vom timer löst jede 10ms aus, soweit so gut. in der ISR erhöhe
ich eine variable ticks vom typ uint32_t.
diese lasse ich mir in der main(), jede sekunde ausgeben - die ausgabe
ist dann:
100
200
300
400
...usw.
nun bekomme ich ein fehlverhalten bei festen zeiten, was mir nicht so
ganz einleuchtet.
z.b. von dem wert 9300 auf 9316. egal wie oft ich die steuerung neu
starte, der fehler tritt immer an den gleichen stellen auf...auch im
späteren verlauf.
meine main(): 1 | int main(void)
| 2 | {
| 3 | init();
| 4 |
| 5 | char num[7];
| 6 |
| 7 | DDRA = 0xff;
| 8 | DDRD = 0xff;
| 9 |
| 10 | uint32_t tick = get_uptime(TICKS) + 100;
| 11 |
| 12 | while(1)
| 13 | {
| 14 | if(tick <= get_uptime(TICKS))
| 15 | {
| 16 | tick = get_uptime(TICKS) + 100;
| 17 | PORTA ^= (1<<PINA0);
| 18 | PORTD ^= (1<<PIND5);
| 19 |
| 20 | ultoa( (tick), num, 10);
| 21 | uart_puts(num);
| 22 | uart_putc(10);
| 23 | uart_putc(13);
| 24 | }
| 25 | }
| 26 | return 0;
| 27 | }
|
ist im moment nur eine testausgabe, hoffe nicht das der fehler in der
abfrage der ticks liegt, dass er dort zu früh/spät abfragt und einen
falschen wert erkennt. die andere möglichkeit was mir noch einfällt
könnte der vorladewert des timers sein?!
hoffe ihr habt eine idee.
gruß adam
Adam P. schrieb:
> die ISR vom timer löst jede 10ms aus, soweit so gut. in der ISR erhöhe
> ich eine variable ticks vom typ uint32_t.
Und die ist hoffentlich volatile und und die Ausleseanweisung ist mit
einem cli()/sei() gekapselt, zwecks atomarem Zugriff.
Adam P. schrieb:
> hoffe nicht das der fehler in der
> abfrage der ticks liegt
Hoffen und Harren macht manchen zum Narren.
Immer diese Zumutung, nur durch Schlüsselloch gucken zu dürfen.
Mach die Tür auf und zeig alles (als Anhang)!
Peter
Karl Heinz Buchegger schrieb:
> Und die ist hoffentlich volatile und und die Ausleseanweisung ist mit
> einem cli()/sei() gekapselt, zwecks atomarem Zugriff.
du meinst die tick variable? wie du siehst ist die in main nicht
volatile.
den wert den ich erhöhe wird in einem array abgelegt das diverse daten
enthält, die fkt. get_uptime liest dann von dem index x aus dem array
den wert, den die ISR erhöht.
also wenn ich nun in der main z.b. cli()/sei() einbaue, dann sollte es
gut sein? aber damit halte ich doch die abarbeitung der ISR auf und habe
somit doch im laufe der zeit eine zeitverschiebung oder?
Adam P. schrieb:
> Karl Heinz Buchegger schrieb:
>> Und die ist hoffentlich volatile und und die Ausleseanweisung ist mit
>> einem cli()/sei() gekapselt, zwecks atomarem Zugriff.
>
> du meinst die tick variable?
Nö.
Wie kommt get_uptime(TICKS) zu seinen Erkentnissen?
Dort wird ja wohl die Variable in irgendeiner Form ausgewertet, die von
der ISR hochgezählt wird.
> wie du siehst ist die in main nicht
> volatile.
Ich sehe nur, dass du die relevanten Dinge wieder mal nicht zeigst, zu
gunsten von Dingen die eh keinen interessieren. Dass du ein ultoa
fehlerfrei hinkriegst, davon sollte man eigentlich ausgehen können.
> den wert den ich erhöhe wird in einem array abgelegt das diverse daten
> enthält, die fkt. get_uptime liest dann von dem index x aus dem array
> den wert, den die ISR erhöht.
Ach.
Da gibt es also noch zusätzlich jede Menge anderes Zeug, dass du
verbockt haben könntest?
Nur gut, dass du uns das alles gezeigt hast!
Oops. Hast du ja gar nicht.
...ein moment, bitte :)
p.s. ich habe kein problem euch das zu zeigen, es hätte nur sein können,
dass jemand eine spontane idee hätte.
1 | uint32_t get_uptime(uint8_t format)
| 2 | {
| 3 | cli(); // ********* <--------------------
| 4 |
| 5 |
| 6 | switch(format)
| 7 | {
| 8 | case TICKS:
| 9 | return reg_read32(SYS_TICKS);
| 10 | break;
| 11 |
| 12 | case SECOND:
| 13 | return reg_read32(UPTIME_SS);
| 14 | break;
| 15 |
| 16 | case MINUTE:
| 17 | return reg_read32(UPTIME_MM);
| 18 | break;
| 19 |
| 20 | case HOUR:
| 21 | return (uint32_t)(reg_read(UPTIME_HH));
| 22 | break;
| 23 |
| 24 | case DAY:
| 25 | return (uint32_t)(reg_read(UPTIME_DD));
| 26 | break;
| 27 |
| 28 | default:
| 29 | return 0;
| 30 | break;
| 31 | }
| 32 |
| 33 | sei(); // *********** <---------------------
| 34 | }
|
mal als Erstabhilfe. Ob sonst nach was im argen liegt hab ich jetzt
nicht kontrolliert.
ok, vielen dank! werde ich direkt mal ausprobieren.
bekomme ich denn dadurch keine zeitverschiebung in meinem 10ms takt?
falls die ISR genau in diesem moment den wert erhöhen möchte.
falls doch, welche möglichkeiten gäbe es dieses problem zu umgehen?
bin für jede anregung dankbar!
Adam P. schrieb:
> ok, vielen dank! werde ich direkt mal ausprobieren.
>
> bekomme ich denn dadurch keine zeitverschiebung in meinem 10ms takt?
> falls die ISR genau in diesem moment den wert erhöhen möchte.
Dann findet das Erhöhen halt um ein paar µs später statt und beim
nächsten ISR Aufruf stimmts dann wieder.
Nur weil Interrupts mittels cli() gesperrt sind, bedeutet das ja nicht,
dass Interrupts automatisch unterschlagen werden. Die ISR wird dann eben
erst zum Zeitpunkt aufgerufen, an dem mittels sei() die Interrupts
wieder freigegeben werden. Und da der Timer in der Zwischenzeit
unbeeindruckt weitergezählt hat, kommt der nächste Interrupt dann auch
wieder pünktlich.
> falls doch, welche möglichkeiten gäbe es dieses problem zu umgehen?
Bissi lernen, wie die Dinge wirklich funktionieren.
vielen danke karl heinz!
ist ja nicht so das ich erst seit gestern µc programmieren, aber
manchmal steh ich da und seh den wald vor lauter bäumen nicht mehr.
aber das mit dem sperren ist ja irgendwie klar beim lesen, da ich
mehrere 16bit array-plätze nutze und beim schreiben auch eine
bit-verschiebung stattfindet etc.
somit bedanke ich mich bei euch! :-)
Dein Programm ist mir viel zu kompliziert.
Wenn Du mehrere Variablen zusammenfassen willst, mach ne Struct daraus.
Aber nicht sowas komisches zu Fuß.
Ne 32Bit Division im Interrupt wäre mir etwas grenzwertig.
Die Umrechnung der Ticks in was Du willst kann doch in aller Ruhe das
Main machen. Das muß dann auch nicht tausende Register sichern und
restoren für nen Funktionsaufruf.
Peter
die 32bit division gehört dort nicht hin...ist nur testweise.
das mit den registern hat damit zu tun, dass sie später über uart
zugänglich sein sollen. z.b. übers terminal mit "getreg xy".
bei variablen stelle ich mir das recht schwer vor.
Adam P. schrieb:
> bei variablen stelle ich mir das recht schwer vor.
Nö.
Du kannst die Elemente einer Struct auch Byte- oder Wortweise
ansprechen, indem Du ne Union draus machst.
Peter
eine union mit mehreren variablen? dann ist die doch nur so groß wie die
größte variable die sie enthält.
kann mir das gerad nicht so ganz vorstellen wie du das meinst, hast du
ein kleines code-bsp. vllt. ist es ja wirklich einfacher, dann werde ich
mein ansatz mit den registern verwerfen :-D
Peter Dannegger schrieb:
> Adam P. schrieb:
>> bei variablen stelle ich mir das recht schwer vor.
>
> Nö.
> Du kannst die Elemente einer Struct auch Byte- oder Wortweise
> ansprechen, indem Du ne Union draus machst.
Und selbst wenn nicht, das Zauberwort heisst UART. Wenn du über UART auf
die 'Register' zugreifst, hast du alle Zeit der Welt (ok, übertrieben),
die Dinge auseinanderzupfriemeln - die UART Übertragung ist langsamer
als das.
Du verlangsamst jetzt den häufigsten Fall nur um im Ausnahmefall
schneller zu sein. So was nennt man Pessimierung und nicht Optimierung.
Was ist der absolut häufigste Fall?
Der, dass du einfach nur Ticks brauchst. Wenn du wissen willst, wieviel
Zeiteinheiten das entspricht, dann kannst du das dort, wo du die Zeiten
brauchst (normalerweise nur im Benutzerinterface) immer noch umrechnen.
Und gibt dir der Benutzer eine Zeit vor, dann kannst du diese Zeit
einfach in Ticks zurückrechnen und bist wieder auf der Ebene, in der du
einfach nur mit Ticks hantierst.
du hast recht keine frage, die berechnung sei mal vernachlässigt...
ist jetzt auch nicht die endlösung.
die ganze geschichte so wie sie im moment ist, habe ich nur zu
testzwecken aufgebaut um die konfig des timers zu prüfen.
der häufigste fall ist sicherlich der, dass ich die ticks brauche -
da ich einen zeitlich definierten ablauf von funktionsaufrufen benötige.
Adam P. schrieb:
> eine union mit mehreren variablen? dann ist die doch nur so groß wie die
> größte variable die sie enthält.
Hier mal der Klassiker einer struct-union: 1 | union b_w {
| 2 | struct{
| 3 | uint8_t l;
| 4 | uint8_t h;
| 5 | }b;
| 6 | uint16_t w;
| 7 | };
|
Peter
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|