Hallo! :-) Ich vermute das ich einen Ablauffehler habe durch die Nutzung eines Unterprogrammes im Interrupt und im Main Programm. Ich arbeite mit AVR Studio/GGC und einem ATmega 644. Die Funktion macht einen Vergleich von Variablen und gibt mit 1 oder 0 zurück. Nun nutze ich diese einmal im Interrupt und in einem bestimmten Zustand brauche ich den Vergleich auch im Main Programm. Kann es passieren das da irgenwas aus dem Ruder läuft? Gleizeitiger Zugriff oder der gleichen? Wenn ja, muß ich dieses Unterprogramm zur Sicherheit einmal extra für das Main und einmal für das Interrupt Programm schreiben oder gibt es einen anderen Weg? Vielen Dank für Eure Hilfe. Gruß AVRli...
@ AVRli (Gast) >Nun nutze ich diese einmal im Interrupt und in einem bestimmten Zustand >brauche ich den Vergleich auch im Main Programm. >Kann es passieren das da irgenwas aus dem Ruder läuft? Gleizeitiger >Zugriff oder der gleichen? Ja, siehe Interrupt, atomarer Zugriff. >Wenn ja, muß ich dieses Unterprogramm zur Sicherheit einmal extra für >das Main und einmal für das Interrupt Programm schreiben oder gibt es >einen anderen Weg? Man kann die Interrupts kurzzeitig sperren. MFG Falk
>Kann es passieren das da irgenwas aus dem Ruder läuft? Gleizeitiger >Zugriff oder der gleichen? Ja, siehe ausserdem Reentranz. http://de.wikipedia.org/wiki/Eintrittsinvarianz Wenn du z.B. statische Variablen in der Funktion nutzt, geht es schief, ebenso bei vielen library-Funktionen. >Die Funktion macht einen Vergleich von Variablen und gibt mit 1 oder 0 >zurück. Das klingt jetzt nicht so kompliziert, als daß sich das, falls erforderlich, nicht auch zweimal implementieren ließe. Oliver
Hallo und danke für Eure Antworten, ich werde den Vergleich zweimal schreiben. Einmal für den INT und einmal für das MAIN Programm. Den Platz habe ich schon (nehme ich mir eben)... Was mich aber viel mehr erschrecken ließ ist folgenes: Ich habe ebend mir den Abschnitt Interrupt im Beitrag GGC AVR-GCC-Tutorial durchgelesen. Da stolperte ich über die Aussage das man Variablen als volatile deklarieren muß um diese gleichzeitig im INT als auch im MAIN Programm zu nutzen. Ok das habe ich auch immer gemacht! Nur funktioniert es nach dem was da steht nicht bei Werten die "breiter" als 8 bit sind. Also ein 16 bit Zähler oder einen Struct Variable??? Ohh man da muß ich wohl mein ganzen Programm nochmal durchgehen. :-( Ich habe schon einige 16bit Zähler die im INT und im MAIN Programm benutzt werden. Ist mir bis jetzt auch nie aufgefallen das es zu Problemen führt. Wie handelt man das nun... :-( Gruß AVRli...
AVRli schrieb: > Die Funktion macht einen Vergleich von Variablen und gibt mit 1 oder 0 > zurück. Schreib doch einfach mal die Funktion hin, dann kann man leicht sehen, obs Probleme geben könnte. Ein Quelltext sagt mehr als 1000 Worte !!! Warum die Leute immer ihr Problem erstmal umständlich umschreiben müssen, statt einfach nur copy&paste. Peter
AVRli schrieb: > Ist mir bis jetzt auch nie aufgefallen das es zu Problemen führt. > Wie handelt man das nun... :-( Benutze mal den neuesten WINAVR, da gibt es ne hübsche "atomic.h", das ist genau die richtige Medizin für alle diese Probleme. Aber drauf achten, daß man nicht versehentlich langsame Funktionsaufrufe, Divisionen, float o.ä. in das atomic mit einpackt, also wirklich nur die Parameterübergabe. Peter
Dann mache ich es mal ganz ordentlich... ;-) als erstes meine Funktion mit dem Vergleich...
1 | volatile uint16_t clk_year_long; // Int/Main use |
2 | |
3 | ...
|
4 | |
5 | char not_leap(void) |
6 | {
|
7 | if (!(clk_year_long%100)) |
8 | return (char)(clk_year_long%400); |
9 | else
|
10 | return (char)(clk_year_long%4); |
11 | }
|
12 | |
13 | ...
|
14 | |
15 | //--- Interrupt Aufruf ---
|
16 | ISR(TIMER2_OVF_vect) { |
17 | ...
|
18 | if((clk.mon==2) && (not_leap())) { |
19 | ...
|
20 | }
|
21 | ...
|
22 | }
|
23 | |
24 | ...
|
25 | |
26 | //--- Main Aufruf ---
|
27 | ...
|
28 | if (not_leap()) { |
29 | ...
|
30 | }
|
31 | ...
|
Die Abfrage ist die, die man zweimal schreiben könnte wenn man es dann muß. Und nun noch ein Beiepiel wo ich einen 16bit Zähler verwende...
1 | volatile uint8_t buf_uart_tx[512]; // UART TX-Buffer |
2 | volatile uint16_t pos_in_uart_tx; // UART TX-Buffer Position bis wo Zeichen eingefügt wurden |
3 | volatile uint16_t pos_out_uart_tx; // UART TX-Buffer Position bis wo Zeichen gesendet wurden |
4 | |
5 | //--- ISR - UART Dataregister EMPTY
|
6 | ISR(USART0_UDRE_vect) |
7 | {
|
8 | if (pos_out_uart_tx == pos_in_uart_tx) { |
9 | CLEAR_BIT(UCSR0B,UDRIE0); |
10 | }
|
11 | else { |
12 | UDR0 = buf_uart_tx[pos_out_uart_tx]; |
13 | pos_out_uart_tx ++; |
14 | pos_out_uart_tx = pos_out_uart_tx & 0x1FF; |
15 | }
|
16 | }
|
17 | |
18 | ...
|
19 | |
20 | void tx_char_uart(char chrtx) { |
21 | buf_uart_tx[pos_in_uart_tx] = chrtx; |
22 | pos_in_uart_tx++; |
23 | pos_in_uart_tx = pos_in_uart_tx & 0x1FF; |
24 | SET_BIT(UCSR0B,UDRIE0); |
25 | }
|
Mit tx_char_uart() wird das Zeichen in den Buffer übertragen. Nun bleibt zu hoffen das man versteht was ich da mache... Gruß AVRli...
> Die Abfrage ist die, die man zweimal schreiben könnte wenn man es dann > muß. Das bringt aber nicht wirklich viel, denn auch bei zwei Funktionen muss der Zugriff auf clk_year_long geschützt werden. Der einzige Vorteil ist, dass dieser Schutz dann nur in einer Funktion nötig ist (in der, die von main aufgerufen wird), und der Interrupt dadurch geringfügig schneller ist. Ich würde nur eine Funktion machen, die dann aber inlinen (insbesondere im Interrupt). > char not_leap(void) "char" solltest du nur nehmen, wenn es tatsächlich um Zeichen geht. Ansonsten "unsigned char" oder "signed char". Oder warum nicht uint8_t? uint16_t benutzt du doch auch.
Mein Vorschlag für die Funktion:
1 | #include <util/atomic.h> |
2 | ...
|
3 | uint8_t not_leap (void) { |
4 | |
5 | uint16_t year; |
6 | |
7 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { |
8 | year = clk_year_long; |
9 | }
|
10 | |
11 | if (!(year % 100)) |
12 | return year % 400; |
13 | else
|
14 | return year % 4; |
15 | }
|
Äh, ich frage mich ob eine Berechnung bezüglich eines Jahres nun wirklich in einem Interrupt geschehen muss. Die Jahreszahl ändert sich sooooo langsam. Das kann man entweder vorher, so zur Teezeit am 31.12. berechnen oder irgendwann am 1.1. wenn der Kater verflogen ist. Das alles scheint mir eher auf einen Designfehler hinzudeuten, wenn es auch als Lehrstück bzg. volatile usw. hiflreich sein kann.
> Die Abfrage ist die, die man zweimal schreiben könnte wenn man es dann > muß. Muß man nicht. Probleme gäbe es, wenn die Funktion interne Zustände speichern würde, die dann bei "parallelem" Aufruf überschrieben würden. Das ist bei den paar Zeilen aber nicht der Fall. Oliver
Was spricht dagegen einen einfachen 32 Bit Timestamp im Timerinterrupt hochzuzählen, statt so ne "Orgie" zu veranstalten? Interruptroutinen sollten so klein wie möglich sein.
Danke für Eure Antworten! Kann jemand noch ein Statement zu meiner 16bit Zähler Nutzung geben? Ich habe auch meine Literatur nochmal durchgeblättert. (C Buch für AVR controller), da werden 16bit Zähler auch im Main und Interrupt genutzt und werden auch nur mit volatile "geschützt". Hmm ich glaube ja bald das ich noch nicht ganz begriffen habe wann es zu Problemen kommen kann und wann nicht. Wo kann man sich über die atomic funktion informieren? Gruß AVRli...
@ AVRli (Gast) >Kann jemand noch ein Statement zu meiner 16bit Zähler Nutzung geben? siehe Interrupt. >Ich habe auch meine Literatur nochmal durchgeblättert. (C Buch für AVR >controller), da werden 16bit Zähler auch im Main und Interrupt genutzt >und werden auch nur mit volatile "geschützt". Ist unter BESTIMMTEN Umständen möglich, z.B. im Zusammenhang mit dem Sleep Mode, kann aber auch schief gehen. >Wo kann man sich über die atomic funktion informieren? In der Doku der libc, ist irgendwo im WinAVR Verzeichnis is drinnen. MfG Falk
Hallo, na dann werde ich mal meine ganzen Programme durchforsten wo ich 16 bit Zähler im Int und Main verwende. Ziel ist es dann immer die Int zu sperren wenn man auf die Zähler im Main Programm zugreift. Danke und Gruß AVRli...
>Ziel ist es dann immer die Int zu sperren wenn man auf die Zähler im >Main Programm zugreift. Vorher ein CLI und hinterher ein SEI... So behandelt man doch immer Variablen, die "atomic" behandelt werden müssen.
STK500-Besitzer schrieb: >>Ziel ist es dann immer die Int zu sperren wenn man auf die Zähler im >>Main Programm zugreift. > > Vorher ein CLI und hinterher ein SEI... > So behandelt man doch immer Variablen, die "atomic" behandelt werden > müssen.
1 | #include <util/atomic.h> |
2 | |
3 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) |
4 | {
|
5 | ....
|
6 | }
|
gibts auch noch.
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.